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

lib/rpmsx.c

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

Generated on Tue Dec 28 15:13:23 2004 for rpm by doxygen 1.3.6