rpm
4.5
|
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", ®ex, &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, ®_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 }