lib/rpmsx.c

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

Generated on Fri Oct 12 08:44:54 2007 for rpm by  doxygen 1.5.2