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

Generated on Mon Nov 29 2010 05:18:44 for rpm by  doxygen 1.7.2