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
00014
00015
00016 int _rpmsx_debug = 0;
00017
00022 static void rpmsxSort(rpmsx sx)
00023
00024 {
00025 rpmsxp sxp;
00026 int i, j;
00027
00028
00029 sxp = xmalloc(sizeof(*sxp) * sx->Count);
00030
00031
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
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
00053 static void rpmsxpHasMetaChars(rpmsxp sxp)
00054
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
00063
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 break;
00079 case '\\':
00080 s++;
00081 break;
00082 default:
00083 break;
00084
00085 }
00086 s++;
00087 }
00088 return;
00089 }
00090
00095 static size_t rpmsxsPStem(const char * const buf)
00096
00097 {
00098
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
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 sxs->stem = strndup(*bpp, stem_len);
00160 sx->nsxs++;
00161 *bpp += stem_len;
00162 return sx->nsxs - 1;
00163 }
00164
00173 static int rpmsxFind( const rpmsx sx, const char ** bpp)
00174
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 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
00197 if (_rpmsx_debug && msg != NULL)
00198 fprintf(stderr, "--> sx %p -- %d %s at %s:%u\n", sx, sx->nrefs, msg, fn, ln);
00199
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
00210 if (_rpmsx_debug && msg != NULL)
00211 fprintf(stderr, "--> sx %p ++ %d %s at %s:%u\n", sx, sx->nrefs, msg, fn, ln);
00212
00213
00214 return sx;
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
00228 if (_rpmsx_debug < 0)
00229 fprintf(stderr, "*** sx %p\t%s[%d]\n", sx, __func__, sx->Count);
00230
00231
00232
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 regfree(sxp->preg);
00240 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
00251
00252 (void) rpmsxUnlink(sx, __func__);
00253
00254
00255 memset(sx, 0, sizeof(*sx));
00256
00257 sx = _free(sx);
00258
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
00283 if (strcmp(sxpj->pattern, sxpi->pattern))
00284 continue;
00285 if (sxpj->fmode && sxpi->fmode && sxpj->fmode != sxpi->fmode)
00286 continue;
00287
00288
00289 if (strcmp(sxpj->context, sxpi->context)) {
00290
00291
00292 fprintf(stderr,
00293 "ERROR: Multiple different specifications for %s (%s and %s).\n",
00294 sxpi->pattern, sxpj->context, sxpi->context);
00295
00296 rc = -1;
00297 } else {
00298
00299
00300 fprintf(stderr,
00301 "WARNING: Multiple same specifications for %s.\n",
00302 sxpi->pattern);
00303
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
00329 if (fn == NULL)
00330 fn = "/etc/security/selinux/file_contexts";
00331
00332
00333 if ((fp = fopen(fn, "r")) == NULL) {
00334 perror(fn);
00335 return -1;
00336 }
00337
00338
00339
00340
00341
00342
00343
00344
00345
00346
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 continue;
00363 }
00364 buf[len - 1] = 0;
00365 bp = buf;
00366 while (isspace(*bp))
00367 bp++;
00368
00369 if (*bp == '#' || *bp == 0)
00370 continue;
00371
00372 items = sscanf(buf, "%as %as %as", ®ex, &type, &context);
00373
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 continue;
00382 } else if (items == 2) {
00383
00384 free(context);
00385 context = type;
00386 type = 0;
00387 }
00388
00389
00390 if (pass == 1) {
00391 const char * reg_buf = regex;
00392 sxp->fstem = rpmsxAdd(sx, ®_buf);
00393 sxp->pattern = regex;
00394
00395
00396 len = strlen(reg_buf);
00397 anchored_regex = xmalloc(len + 3);
00398 sprintf(anchored_regex, "^%s$", reg_buf);
00399
00400
00401 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
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; break;
00431 case 'c': sxp->fmode = S_IFCHR; break;
00432 case 'd': sxp->fmode = S_IFDIR; break;
00433 case 'p': sxp->fmode = S_IFIFO; break;
00434 case 'l': sxp->fmode = S_IFLNK; break;
00435 case 's': sxp->fmode = S_IFSOCK; break;
00436 case '-': sxp->fmode = S_IFREG; 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 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
00459
00460 rpmsxpHasMetaChars(sxp);
00461 sxp++;
00462 }
00463
00464 sx->Count++;
00465 if (pass == 0) {
00466
00467 free(regex);
00468 if (type)
00469 free(type);
00470 free(context);
00471
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
00486 (void) fclose(fp);
00487
00488
00489 rpmsxSort(sx);
00490
00491
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( rpmsx sx)
00595
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
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
00619 }
00620
00621 }
00622
00623 return i;
00624 }
00625
00626 rpmsx rpmsxInit( rpmsx sx, int reverse)
00627
00628 {
00629 if (sx != NULL) {
00630 sx->reverse = reverse;
00631 sx->i = (sx->reverse ? sx->Count : -1);
00632 }
00633
00634 return sx;
00635
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
00643 int fstem = rpmsxFind(sx, &myfn);
00644
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 break;
00672 case 0:
00673 fcontext = rpmsxContext(sx);
00674 break;
00675 default:
00676 { static char errbuf[BUFSIZ + 1];
00677 (void) regerror(ret, preg, errbuf, sizeof(errbuf)-1);
00678
00679 errbuf[sizeof(errbuf)-1] = '\0';
00680 fprintf(stderr, "unable to match %s against %s: %s\n",
00681 fn, rpmsxPattern(sx), errbuf);
00682
00683 } break;
00684 }
00685 break;
00686 }
00687
00688 return fcontext;
00689 }