Main Page | Modules | Data Structures | Directories | File List | Data Fields | Globals | Related Pages

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

Generated on Thu Mar 9 12:08:25 2006 for rpm by  doxygen 1.3.9.1