rpm 5.2.1

lib/rpmsx.c

Go to the documentation of this file.
00001 
00004 #include "system.h"
00005 
00006 #include <rpmiotypes.h>
00007 #include <rpmio.h>      /* for yarn.h */
00008 #include <rpmmacro.h>   /* for rpmGetPath() */
00009 #include <yarn.h>
00010 
00011 #include <rpmtypes.h>
00012 
00013 #define _RPMSX_INTERNAL
00014 #include "rpmsx.h"
00015 
00016 #include "debug.h"
00017 
00018 /*@access regex_t @*/
00019 
00020 /*@unchecked@*/
00021 int _rpmsx_debug = 0;
00022 
00027 static void rpmsxSort(rpmsx sx)
00028        /*@modifies sx @*/
00029 {
00030     rpmsxp sxp;
00031     int i, j;
00032 
00033     /* Stable sort for policy regex's and paths. */
00034     sxp = xmalloc(sizeof(*sxp) * sx->Count);
00035 
00036     /* Regex patterns first ... */
00037     j = 0;
00038     for (i = 0; i < sx->Count; i++) {
00039         if (!sx->sxp[i].hasMetaChars)
00040             continue;
00041         memcpy(sxp + j, sx->sxp + i, sizeof(*sxp));
00042         j++;
00043     }
00044 
00045     /* ... then file paths. */
00046     for (i = 0; i < sx->Count; i++) {
00047         if (sx->sxp[i].hasMetaChars)
00048             continue;
00049         memcpy(sxp + j, sx->sxp + i, sizeof(*sxp));
00050         j++;
00051     }
00052 
00053     sx->sxp = _free(sx->sxp);
00054     sx->sxp = sxp;
00055 /*@-compdef@*/  /* XXX *(sx->sxp) annotation */
00056     return;
00057 /*@=compdef@*/
00058 }
00059 
00060 /* Determine if the regular expression specification has any meta characters. */
00061 static void rpmsxpHasMetaChars(rpmsxp sxp)
00062         /*@modifies sxp @*/
00063 {
00064     const char * s = sxp->pattern;
00065     size_t ns = strlen(s);
00066     const char * se = s + ns;
00067 
00068     sxp->hasMetaChars = 0; 
00069 
00070     /* Look at each character in the RE specification string for a 
00071      * meta character. Return when any meta character reached. */
00072     while (s != se) {
00073         switch(*s) {
00074         case '.':
00075         case '^':
00076         case '$':
00077         case '?':
00078         case '*':
00079         case '+':
00080         case '|':
00081         case '[':
00082         case '(':
00083         case '{':
00084             sxp->hasMetaChars = 1;
00085             return;
00086             /*@notreached@*/ /*@switchbreak@*/ break;
00087         case '\\':              /* skip the next character */
00088             s++;
00089             /*@switchbreak@*/ break;
00090         default:
00091             /*@switchbreak@*/ break;
00092 
00093         }
00094         s++;
00095     }
00096     return;
00097 }
00098 
00103 static size_t rpmsxsPStem(const char * const buf)
00104         /*@*/
00105 {
00106     /*@observer@*/
00107     static const char * const regex_chars = ".^$?*+|[({";
00108     const char * tmp = strchr(buf, '/');
00109     const char * ind;
00110 
00111     if (!tmp)
00112         return 0;
00113 
00114     for (ind = buf; ind < tmp; ind++) {
00115         if (strchr(regex_chars, (int)*ind))
00116             return 0;
00117     }
00118     return tmp - buf;
00119 }
00120 
00125 static size_t rpmsxsFStem(const char * const buf)
00126         /*@*/
00127 {
00128     const char * tmp = strchr(buf + 1, '/');
00129 
00130     if (!tmp)
00131         return 0;
00132     return tmp - buf;
00133 }
00134 
00142 static int rpmsxAdd(rpmsx sx, const char ** bpp)
00143         /*@modifies sx, *bpp @*/
00144 {
00145     size_t stem_len = rpmsxsPStem(*bpp);
00146     rpmsxs sxs;
00147     int i;
00148 
00149     if (!stem_len)
00150         return -1;
00151     for (i = 0; i < sx->nsxs; i++) {
00152         sxs = sx->sxs + i;
00153         if (stem_len != sxs->len)
00154             continue;
00155         if (strncmp(*bpp, sxs->stem, stem_len))
00156             continue;
00157         *bpp += stem_len;
00158         return i;
00159     }
00160 
00161     if (sx->nsxs == sx->maxsxs) {
00162         sx->maxsxs = sx->maxsxs * 2 + 16;
00163         sx->sxs = xrealloc(sx->sxs, sizeof(*sx->sxs) * sx->maxsxs);
00164     }
00165     sxs = sx->sxs + sx->nsxs;
00166     sxs->len = stem_len;
00167 #ifdef HAVE_STRNDUP
00168 /*@i@*/    sxs->stem = strndup(*bpp, stem_len);
00169 #else
00170     sxs->stem = xmalloc(stem_len+1);
00171     strncpy((char *)sxs->stem, *bpp, stem_len);
00172 #endif
00173     sx->nsxs++;
00174     *bpp += stem_len;
00175     return sx->nsxs - 1;
00176 }
00177 
00186 static int rpmsxFind(/*@null@*/ const rpmsx sx, const char ** bpp)
00187         /*@modifies *bpp @*/
00188 {
00189     size_t stem_len = rpmsxsFStem(*bpp);
00190     rpmsxs sxs;
00191     int i;
00192 
00193     if (sx != NULL && stem_len > 0)
00194     for (i = 0; i < sx->nsxs; i++) {
00195         sxs = sx->sxs + i;
00196         if (stem_len != sxs->len)
00197             continue;
00198 /*@i@*/ if (strncmp(*bpp, sxs->stem, stem_len))
00199             continue;
00200         *bpp += stem_len;
00201         return i;
00202     }
00203     return -1;
00204 }
00205 
00206 /*@-mustmod@*/
00207 static void rpmsxFini(void * _sx)
00208         /*@modifies _sx @*/
00209 {
00210     rpmsx sx = _sx;
00211     int i;
00212 
00213     if (sx->Count > 0)
00214     for (i = 0; i < sx->Count; i++) {
00215         rpmsxp sxp = sx->sxp + i;
00216         sxp->pattern = _free(sxp->pattern);
00217         sxp->type = _free(sxp->type);
00218         sxp->context = _free(sxp->context);
00219 /*@i@*/ regfree(sxp->preg);
00220 /*@i@*/ sxp->preg = _free(sxp->preg);
00221     }
00222     sx->sxp = _free(sx->sxp);
00223 
00224     if (sx->nsxs > 0)
00225     for (i = 0; i < sx->nsxs; i++) {
00226         rpmsxs sxs = sx->sxs + i;
00227         sxs->stem = _free(sxs->stem);
00228     }
00229     sx->sxs = _free(sx->sxs);
00230 }
00231 /*@=mustmod@*/
00232 
00233 /*@unchecked@*/ /*@only@*/ /*@null@*/
00234 rpmioPool _rpmsxPool;
00235 
00236 static rpmsx rpmsxGetPool(/*@null@*/ rpmioPool pool)
00237         /*@globals _rpmsxPool, fileSystem, internalState @*/
00238         /*@modifies pool, _rpmsxPool, fileSystem, internalState @*/
00239 {
00240     rpmsx sx;
00241 
00242     if (_rpmsxPool == NULL) {
00243         _rpmsxPool = rpmioNewPool("sx", sizeof(*sx), -1, _rpmsx_debug,
00244                         NULL, NULL, rpmsxFini);
00245         pool = _rpmsxPool;
00246     }
00247     return (rpmsx) rpmioGetPool(pool, sizeof(*sx));
00248 }
00249 
00259 static int rpmsxpCheckNoDupes(const rpmsx sx)
00260         /*@*/
00261 {
00262     int i, j;
00263     int rc = 0;
00264 
00265     for (i = 0; i < sx->Count; i++) {
00266         rpmsxp sxpi = sx->sxp + i;
00267         for (j = i + 1; j < sx->Count; j++) { 
00268             rpmsxp sxpj = sx->sxp + j;
00269 
00270             /* Check if same RE string */
00271             if (strcmp(sxpj->pattern, sxpi->pattern))
00272                 /*@innercontinue@*/ continue;
00273             if (sxpj->fmode && sxpi->fmode && sxpj->fmode != sxpi->fmode)
00274                 /*@innercontinue@*/ continue;
00275 
00276             /* Same RE string found */
00277             if (strcmp(sxpj->context, sxpi->context)) {
00278                 /* If different contexts, give warning */
00279 /*@-modfilesys@*/
00280                 fprintf(stderr,
00281                 "ERROR: Multiple different specifications for %s  (%s and %s).\n",
00282                         sxpi->pattern, sxpj->context, sxpi->context);
00283 /*@=modfilesys@*/
00284                 rc = -1;
00285             } else {
00286                 /* If same contexts give warning */
00287 /*@-modfilesys@*/
00288                 fprintf(stderr,
00289                 "WARNING: Multiple same specifications for %s.\n",
00290                         sxpi->pattern);
00291 /*@=modfilesys@*/
00292             }
00293         }
00294     }
00295     return rc;
00296 }
00297 
00298 int rpmsxParse(rpmsx sx, const char * fn)
00299 {
00300     FILE * fp;
00301     char buf[BUFSIZ + 1];
00302     char * bp;
00303     char * regex;
00304     char * type;
00305     char * context;
00306     char * anchored_regex;
00307     int items;
00308     size_t len;
00309     int lineno;
00310     int pass;
00311     int regerr;
00312     int nerr = 0;
00313     
00314 #define inc_err()       nerr++
00315 
00316     if (fn == NULL)
00317         fn = "%{?__file_context_path}";
00318 
00319     {   const char * myfn = rpmGetPath(fn, NULL);
00320 
00321         if (myfn == NULL || *myfn == '\0'
00322          || (fp = fopen(myfn, "r")) == NULL)
00323         {
00324             myfn = _free(myfn);
00325             return -1;
00326         }
00327         myfn = _free(myfn);
00328     }
00329 
00330     /* 
00331      * Perform two passes over the specification file.
00332      * The first pass counts the number of specifications and
00333      * performs simple validation of the input.  At the end
00334      * of the first pass, the spec array is allocated.
00335      * The second pass performs detailed validation of the input
00336      * and fills in the spec array.
00337      */
00338     for (pass = 0; pass < 2; pass++) {
00339         rpmsxp sxp;
00340 
00341         lineno = 0;
00342         sx->Count = 0;
00343         sxp = sx->sxp;
00344         while (fgets(buf, sizeof(buf)-1, fp)) {
00345             buf[sizeof(buf)-1] = '\0';
00346             lineno++;
00347             len = strlen(buf);
00348             if (buf[len - 1] != '\n') {
00349                 fprintf(stderr,
00350                         _("%s:  no newline on line number %d (only read %s)\n"),
00351                         fn, lineno, buf);
00352                 inc_err();
00353                 /*@innercontinue@*/ continue;
00354             }
00355             buf[len - 1] = 0;
00356             bp = buf;
00357             while (isspace(*bp))
00358                 bp++;
00359             /* Skip comment lines and empty lines. */
00360             if (*bp == '#' || *bp == 0)
00361                 /*@innercontinue@*/ continue;
00362 /*@-formatcode@*/
00363 #if defined(__GLIBC__)
00364             items = sscanf(buf, "%as %as %as", &regex, &type, &context);
00365 #else
00366             regex   = malloc(len+1);
00367             type    = malloc(len+1);
00368             context = malloc(len+1);
00369             items = sscanf(buf, "%s %s %s", regex, type, context);
00370 #endif
00371 /*@=formatcode@*/
00372             if (items < 2) {
00373                 fprintf(stderr,
00374                         _("%s:  line number %d is missing fields (only read %s)\n"),
00375                         fn, lineno, buf);
00376                 inc_err();
00377                 if (items == 1)
00378                     free(regex);
00379                 /*@innercontinue@*/ continue;
00380             } else if (items == 2) {
00381                 /* The type field is optional. */
00382                 free(context);
00383                 context = type;
00384                 type = 0;
00385             }
00386 
00387             /* On pass 2, compile and store the specification. */
00388             if (pass == 1) {
00389                 const char * reg_buf = regex;
00390                 sxp->fstem = rpmsxAdd(sx, &reg_buf);
00391                 sxp->pattern = regex;
00392 
00393                 /* Anchor the regular expression. */
00394                 len = strlen(reg_buf);
00395                 anchored_regex = xmalloc(len + 3);
00396                 sprintf(anchored_regex, "^%s$", reg_buf);
00397 
00398                 /* Compile the regular expression. */
00399 /*@i@*/         sxp->preg = xcalloc(1, sizeof(*sxp->preg));
00400                 regerr = regcomp(sxp->preg, anchored_regex,
00401                             REG_EXTENDED | REG_NOSUB);
00402                 if (regerr < 0) {
00403                     char errbuf[BUFSIZ + 1];
00404                     (void) regerror(regerr, sxp->preg, errbuf, sizeof(errbuf)-1);
00405                     errbuf[sizeof(errbuf)-1] = '\0';
00406                     fprintf(stderr,
00407                         _("%s:  unable to compile regular expression %s on line number %d:  %s\n"),
00408                         fn, regex, lineno,
00409                         errbuf);
00410                     inc_err();
00411                 }
00412                 free(anchored_regex);
00413 
00414                 /* Convert the type string to a mode format */
00415                 sxp->type = type;
00416                 sxp->fmode = 0;
00417                 if (!type)
00418                     goto skip_type;
00419                 len = strlen(type);
00420                 if (type[0] != '-' || len != 2) {
00421                     fprintf(stderr,
00422                         _("%s:  invalid type specifier %s on line number %d\n"),
00423                         fn, type, lineno);
00424                     inc_err();
00425                     goto skip_type;
00426                 }
00427                 switch (type[1]) {
00428                 case 'b':       sxp->fmode = S_IFBLK;   /*@switchbreak@*/ break;
00429                 case 'c':       sxp->fmode = S_IFCHR;   /*@switchbreak@*/ break;
00430                 case 'd':       sxp->fmode = S_IFDIR;   /*@switchbreak@*/ break;
00431                 case 'p':       sxp->fmode = S_IFIFO;   /*@switchbreak@*/ break;
00432                 case 'l':       sxp->fmode = S_IFLNK;   /*@switchbreak@*/ break;
00433 /*@i@*/         case 's':       sxp->fmode = S_IFSOCK;  /*@switchbreak@*/ break;
00434                 case '-':       sxp->fmode = S_IFREG;   /*@switchbreak@*/ break;
00435                 default:
00436                     fprintf(stderr,
00437                         _("%s:  invalid type specifier %s on line number %d\n"),
00438                         fn, type, lineno);
00439                     inc_err();
00440                     /*@switchbreak@*/ break;
00441                 }
00442 
00443               skip_type:
00444 
00445                 sxp->context = context;
00446 
00447                 if (strcmp(context, "<<none>>")) {
00448                     if (security_check_context(context) < 0 && errno != ENOENT) {
00449                         fprintf(stderr,
00450                                 _("%s:  invalid context %s on line number %d\n"),
00451                                 fn, context, lineno);
00452                         inc_err();
00453                     }
00454                 }
00455 
00456                 /* Determine if specification has 
00457                  * any meta characters in the RE */
00458                 rpmsxpHasMetaChars(sxp);
00459                 sxp++;
00460             }
00461 
00462             sx->Count++;
00463             if (pass == 0) {
00464 /*@-kepttrans@*/
00465                 free(regex);
00466                 if (type)
00467                     free(type);
00468                 free(context);
00469 /*@=kepttrans@*/
00470             }
00471         }
00472 
00473         if (nerr) {
00474             (void) fclose(fp);
00475             return -1;
00476         }
00477 
00478         if (pass == 0) {
00479             if (sx->Count == 0) {
00480                 (void) fclose(fp);
00481                 return 0;
00482             }
00483             sx->sxp = xcalloc(sx->Count, sizeof(*sx->sxp));
00484             rewind(fp);
00485         }
00486     }
00487     (void) fclose(fp);
00488 
00489    /* Stable sort for policy specifications, patterns before paths. */
00490     rpmsxSort(sx);
00491 
00492     /* Verify no exact duplicates */
00493     if (rpmsxpCheckNoDupes(sx) != 0)
00494         return -1;
00495 
00496     return 0;
00497 
00498 }
00499 
00500 rpmsx rpmsxNew(const char * fn)
00501 {
00502     rpmsx sx = rpmsxGetPool(_rpmsxPool);
00503 
00504     sx->sxp = NULL;
00505     sx->Count = 0;
00506     sx->i = -1;
00507     sx->sxs = NULL;
00508     sx->nsxs = 0;
00509     sx->maxsxs = 0;
00510     sx->reverse = 0;
00511 
00512     (void) rpmsxLink(sx, "rpmsxNew");
00513 
00514     if (rpmsxParse(sx, fn) != 0)
00515         return rpmsxFree(sx);
00516 
00517     return sx;
00518 }
00519 
00520 int rpmsxCount(const rpmsx sx)
00521 {
00522     return (sx != NULL ? sx->Count : 0);
00523 }
00524 
00525 int rpmsxIx(const rpmsx sx)
00526 {
00527     return (sx != NULL ? sx->i : -1);
00528 }
00529 
00530 int rpmsxSetIx(rpmsx sx, int ix)
00531 {
00532     int i = -1;
00533 
00534     if (sx != NULL) {
00535         i = sx->i;
00536         sx->i = ix;
00537     }
00538     return i;
00539 }
00540 
00541 const char * rpmsxPattern(const rpmsx sx)
00542 {
00543     const char * pattern = NULL;
00544 
00545     if (sx != NULL && sx->i >= 0 && sx->i < sx->Count)
00546         pattern = (sx->sxp + sx->i)->pattern;
00547     return pattern;
00548 }
00549 
00550 const char * rpmsxType(const rpmsx sx)
00551 {
00552     const char * type = NULL;
00553 
00554     if (sx != NULL && sx->i >= 0 && sx->i < sx->Count)
00555         type = (sx->sxp + sx->i)->type;
00556     return type;
00557 }
00558 
00559 const char * rpmsxContext(const rpmsx sx)
00560 {
00561     const char * context = NULL;
00562 
00563     if (sx != NULL && sx->i >= 0 && sx->i < sx->Count)
00564         context = (sx->sxp + sx->i)->context;
00565     return context;
00566 }
00567 
00568 regex_t * rpmsxRE(const rpmsx sx)
00569 {
00570     regex_t * preg = NULL;
00571 
00572     if (sx != NULL && sx->i >= 0 && sx->i < sx->Count)
00573         preg = (sx->sxp + sx->i)->preg;
00574     return preg;
00575 }
00576 
00577 mode_t rpmsxFMode(const rpmsx sx)
00578 {
00579     mode_t fmode = 0;
00580 
00581     if (sx != NULL && sx->i >= 0 && sx->i < sx->Count)
00582         fmode = (sx->sxp + sx->i)->fmode;
00583     return fmode;
00584 }
00585 
00586 int rpmsxFStem(const rpmsx sx)
00587 {
00588     int fstem = -1;
00589 
00590     if (sx != NULL && sx->i >= 0 && sx->i < sx->Count)
00591         fstem = (sx->sxp + sx->i)->fstem;
00592     return fstem;
00593 }
00594 
00595 int rpmsxNext(/*@null@*/ rpmsx sx)
00596         /*@modifies sx @*/
00597 {
00598     int i = -1;
00599 
00600     if (sx != NULL) {
00601         if (sx->reverse != 0) {
00602             i = --sx->i;
00603             if (sx->i < 0) {
00604                 sx->i = sx->Count;
00605                 i = -1;
00606             }
00607         } else {
00608             i = ++sx->i;
00609             if (sx->i >= sx->Count) {
00610                 sx->i = -1;
00611                 i = -1;
00612             }
00613         }
00614 
00615 /*@-modfilesys @*/
00616 if (_rpmsx_debug  < 0 && i != -1) {
00617 rpmsxp sxp = sx->sxp + i;
00618 fprintf(stderr, "*** sx %p\t%s[%d]\t%s\t%s\n", sx, "rpmsxNext", i, sxp->pattern, sxp->context);
00619 /*@=modfilesys @*/
00620 }
00621 
00622     }
00623 
00624     return i;
00625 }
00626 
00627 rpmsx rpmsxInit(/*@null@*/ rpmsx sx, int reverse)
00628         /*@modifies sx @*/
00629 {
00630     if (sx != NULL) {
00631         sx->reverse = reverse;
00632         sx->i = (sx->reverse ? sx->Count : -1);
00633     }
00634     /*@-refcounttrans@*/
00635     return sx;
00636     /*@=refcounttrans@*/
00637 }
00638 
00639 const char * rpmsxFContext(rpmsx sx, const char * fn, mode_t fmode)
00640 {
00641     const char * fcontext = NULL;
00642     const char * myfn = fn;
00643 /*@-mods@*/
00644     int fstem = rpmsxFind(sx, &myfn);
00645 /*@=mods@*/
00646     int i;
00647 
00648     sx = rpmsxInit(sx, 1);
00649     if (sx != NULL)
00650     while ((i = rpmsxNext(sx)) >= 0) {
00651         regex_t * preg;
00652         mode_t sxfmode;
00653         int sxfstem;
00654         int ret;
00655 
00656         sxfstem = rpmsxFStem(sx);
00657         if (sxfstem != -1 && sxfstem != fstem)
00658             continue;
00659 
00660         sxfmode = rpmsxFMode(sx);
00661         if (sxfmode && (fmode & S_IFMT) != sxfmode)
00662             continue;
00663 
00664         preg = rpmsxRE(sx);
00665         if (preg == NULL)
00666             continue;
00667 
00668         ret = regexec(preg, (sxfstem == -1 ? fn : myfn), 0, NULL, 0);
00669         switch (ret) {
00670         case REG_NOMATCH:
00671             continue;
00672             /*@notreached@*/ /*@switchbreak@*/ break;
00673         case 0:
00674             fcontext = rpmsxContext(sx);
00675             /*@switchbreak@*/ break;
00676         default:
00677           { static char errbuf[BUFSIZ + 1];
00678             (void) regerror(ret, preg, errbuf, sizeof(errbuf)-1);
00679 /*@-modfilesys -nullpass @*/
00680             errbuf[sizeof(errbuf)-1] = '\0';
00681             fprintf(stderr, "unable to match %s against %s:  %s\n",
00682                 fn, rpmsxPattern(sx), errbuf);
00683 /*@=modfilesys =nullpass @*/
00684           } /*@switchbreak@*/ break;
00685         }
00686         break;
00687     }
00688 
00689     return fcontext;
00690 }