rpm 5.2.1

- Main Page
- Related Pages
- Modules
- Data Structures
- Files

- File List
- Globals

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 }