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