rpm 5.2.1

- Main Page
- Related Pages
- Modules
- Data Structures
- Files

- File List
- Globals

rpmsx.c
Go to the documentation of this file.
1
4 #include "system.h"
5
6 #include <rpmiotypes.h>
7 #include <rpmio.h> /* for yarn.h */
8 #include <rpmmacro.h> /* for rpmGetPath() */
9 #include <yarn.h>
10
11 #include <rpmtypes.h>
12
13 #define _RPMSX_INTERNAL
14 #include "rpmsx.h"
15
16 #include "debug.h"
17
18 /*@access regex_t @*/
19
20 /*@unchecked@*/
21 int _rpmsx_debug = 0;
22
27 static void rpmsxSort(rpmsx sx)
28 /*@modifies sx @*/
29 {
30 rpmsxp sxp;
31 int i, j;
32
33 /* Stable sort for policy regex's and paths. */
34 sxp = xmalloc(sizeof(*sxp) * sx->Count);
35
36 /* Regex patterns first ... */
37 j = 0;
38 for (i = 0; i < sx->Count; i++) {
39 if (!sx->sxp[i].hasMetaChars)
40 continue;
41 memcpy(sxp + j, sx->sxp + i, sizeof(*sxp));
42 j++;
43 }
44
45 /* ... then file paths. */
46 for (i = 0; i < sx->Count; i++) {
47 if (sx->sxp[i].hasMetaChars)
48 continue;
49 memcpy(sxp + j, sx->sxp + i, sizeof(*sxp));
50 j++;
51 }
52
53 sx->sxp = _free(sx->sxp);
54 sx->sxp = sxp;
55 /*@-compdef@*/ /* XXX *(sx->sxp) annotation */
56 return;
57 /*@=compdef@*/
58 }
59
60 /* Determine if the regular expression specification has any meta characters. */
61 static void rpmsxpHasMetaChars(rpmsxp sxp)
62 /*@modifies sxp @*/
63 {
64 const char * s = sxp->pattern;
65 size_t ns = strlen(s);
66 const char * se = s + ns;
67
68 sxp->hasMetaChars = 0;
69
70 /* Look at each character in the RE specification string for a
71 * meta character. Return when any meta character reached. */
72 while (s != se) {
73 switch(*s) {
74 case '.':
75 case '^':
76 case '$':
77 case '?':
78 case '*':
79 case '+':
80 case '|':
81 case '[':
82 case '(':
83 case '{':
84 sxp->hasMetaChars = 1;
85 return;
86 /*@notreached@*/ /*@switchbreak@*/ break;
87 case '\\': /* skip the next character */
88 s++;
89 /*@switchbreak@*/ break;
90 default:
91 /*@switchbreak@*/ break;
92
93 }
94 s++;
95 }
96 return;
97 }
98
103 static size_t rpmsxsPStem(const char * const buf)
104 /*@*/
105 {
106 /*@observer@*/
107 static const char * const regex_chars = ".^$?*+|[({";
108 const char * tmp = strchr(buf, '/');
109 const char * ind;
110
111 if (!tmp)
112 return 0;
113
114 for (ind = buf; ind < tmp; ind++) {
115 if (strchr(regex_chars, (int)*ind))
116 return 0;
117 }
118 return tmp - buf;
119 }
120
125 static size_t rpmsxsFStem(const char * const buf)
126 /*@*/
127 {
128 const char * tmp = strchr(buf + 1, '/');
129
130 if (!tmp)
131 return 0;
132 return tmp - buf;
133 }
134
142 static int rpmsxAdd(rpmsx sx, const char ** bpp)
143 /*@modifies sx, *bpp @*/
144 {
145 size_t stem_len = rpmsxsPStem(*bpp);
146 rpmsxs sxs;
147 int i;
148
149 if (!stem_len)
150 return -1;
151 for (i = 0; i < sx->nsxs; i++) {
152 sxs = sx->sxs + i;
153 if (stem_len != sxs->len)
154 continue;
155 if (strncmp(*bpp, sxs->stem, stem_len))
156 continue;
157 *bpp += stem_len;
158 return i;
159 }
160
161 if (sx->nsxs == sx->maxsxs) {
162 sx->maxsxs = sx->maxsxs * 2 + 16;
163 sx->sxs = xrealloc(sx->sxs, sizeof(*sx->sxs) * sx->maxsxs);
164 }
165 sxs = sx->sxs + sx->nsxs;
166 sxs->len = stem_len;
167 #ifdef HAVE_STRNDUP
168 /*@i@*/ sxs->stem = strndup(*bpp, stem_len);
169 #else
170 sxs->stem = xmalloc(stem_len+1);
171 strncpy((char *)sxs->stem, *bpp, stem_len);
172 #endif
173 sx->nsxs++;
174 *bpp += stem_len;
175 return sx->nsxs - 1;
176 }
177
186 static int rpmsxFind(/*@null@*/ const rpmsx sx, const char ** bpp)
187 /*@modifies *bpp @*/
188 {
189 size_t stem_len = rpmsxsFStem(*bpp);
190 rpmsxs sxs;
191 int i;
192
193 if (sx != NULL && stem_len > 0)
194 for (i = 0; i < sx->nsxs; i++) {
195 sxs = sx->sxs + i;
196 if (stem_len != sxs->len)
197 continue;
198 /*@i@*/ if (strncmp(*bpp, sxs->stem, stem_len))
199 continue;
200 *bpp += stem_len;
201 return i;
202 }
203 return -1;
204 }
205
206 /*@-mustmod@*/
207 static void rpmsxFini(void * _sx)
208 /*@modifies _sx @*/
209 {
210 rpmsx sx = _sx;
211 int i;
212
213 if (sx->Count > 0)
214 for (i = 0; i < sx->Count; i++) {
215 rpmsxp sxp = sx->sxp + i;
216 sxp->pattern = _free(sxp->pattern);
217 sxp->type = _free(sxp->type);
218 sxp->context = _free(sxp->context);
219 /*@i@*/ regfree(sxp->preg);
220 /*@i@*/ sxp->preg = _free(sxp->preg);
221 }
222 sx->sxp = _free(sx->sxp);
223
224 if (sx->nsxs > 0)
225 for (i = 0; i < sx->nsxs; i++) {
226 rpmsxs sxs = sx->sxs + i;
227 sxs->stem = _free(sxs->stem);
228 }
229 sx->sxs = _free(sx->sxs);
230 }
231 /*@=mustmod@*/
232
233 /*@unchecked@*/ /*@only@*/ /*@null@*/
234 rpmioPool _rpmsxPool;
235
236 static rpmsx rpmsxGetPool(/*@null@*/ rpmioPool pool)
237 /*@globals _rpmsxPool, fileSystem, internalState @*/
238 /*@modifies pool, _rpmsxPool, fileSystem, internalState @*/
239 {
240 rpmsx sx;
241
242 if (_rpmsxPool == NULL) {
243 _rpmsxPool = rpmioNewPool("sx", sizeof(*sx), -1, _rpmsx_debug,
244 NULL, NULL, rpmsxFini);
245 pool = _rpmsxPool;
246 }
247 return (rpmsx) rpmioGetPool(pool, sizeof(*sx));
248 }
249
259 static int rpmsxpCheckNoDupes(const rpmsx sx)
260 /*@*/
261 {
262 int i, j;
263 int rc = 0;
264
265 for (i = 0; i < sx->Count; i++) {
266 rpmsxp sxpi = sx->sxp + i;
267 for (j = i + 1; j < sx->Count; j++) {
268 rpmsxp sxpj = sx->sxp + j;
269
270 /* Check if same RE string */
271 if (strcmp(sxpj->pattern, sxpi->pattern))
272 /*@innercontinue@*/ continue;
273 if (sxpj->fmode && sxpi->fmode && sxpj->fmode != sxpi->fmode)
274 /*@innercontinue@*/ continue;
275
276 /* Same RE string found */
277 if (strcmp(sxpj->context, sxpi->context)) {
278 /* If different contexts, give warning */
279 /*@-modfilesys@*/
280 fprintf(stderr,
281 "ERROR: Multiple different specifications for %s (%s and %s).\n",
282 sxpi->pattern, sxpj->context, sxpi->context);
283 /*@=modfilesys@*/
284 rc = -1;
285 } else {
286 /* If same contexts give warning */
287 /*@-modfilesys@*/
288 fprintf(stderr,
289 "WARNING: Multiple same specifications for %s.\n",
290 sxpi->pattern);
291 /*@=modfilesys@*/
292 }
293 }
294 }
295 return rc;
296 }
297
298 int rpmsxParse(rpmsx sx, const char * fn)
299 {
300 FILE * fp;
301 char buf[BUFSIZ + 1];
302 char * bp;
303 char * regex;
304 char * type;
305 char * context;
306 char * anchored_regex;
307 int items;
308 size_t len;
309 int lineno;
310 int pass;
311 int regerr;
312 int nerr = 0;
313
314 #define inc_err() nerr++
315
316 if (fn == NULL)
317 fn = "%{?__file_context_path}";
318
319 { const char * myfn = rpmGetPath(fn, NULL);
320
321 if (myfn == NULL || *myfn == '\0'
322 || (fp = fopen(myfn, "r")) == NULL)
323 {
324 myfn = _free(myfn);
325 return -1;
326 }
327 myfn = _free(myfn);
328 }
329
330 /*
331 * Perform two passes over the specification file.
332 * The first pass counts the number of specifications and
333 * performs simple validation of the input. At the end
334 * of the first pass, the spec array is allocated.
335 * The second pass performs detailed validation of the input
336 * and fills in the spec array.
337 */
338 for (pass = 0; pass < 2; pass++) {
339 rpmsxp sxp;
340
341 lineno = 0;
342 sx->Count = 0;
343 sxp = sx->sxp;
344 while (fgets(buf, sizeof(buf)-1, fp)) {
345 buf[sizeof(buf)-1] = '\0';
346 lineno++;
347 len = strlen(buf);
348 if (buf[len - 1] != '\n') {
349 fprintf(stderr,
350 _("%s: no newline on line number %d (only read %s)\n"),
351 fn, lineno, buf);
352 inc_err();
353 /*@innercontinue@*/ continue;
354 }
355 buf[len - 1] = 0;
356 bp = buf;
357 while (isspace(*bp))
358 bp++;
359 /* Skip comment lines and empty lines. */
360 if (*bp == '#' || *bp == 0)
361 /*@innercontinue@*/ continue;
362 /*@-formatcode@*/
363 #if defined(__GLIBC__)
364 items = sscanf(buf, "%as %as %as", &regex, &type, &context);
365 #else
366 regex = malloc(len+1);
367 type = malloc(len+1);
368 context = malloc(len+1);
369 items = sscanf(buf, "%s %s %s", regex, type, context);
370 #endif
371 /*@=formatcode@*/
372 if (items < 2) {
373 fprintf(stderr,
374 _("%s: line number %d is missing fields (only read %s)\n"),
375 fn, lineno, buf);
376 inc_err();
377 if (items == 1)
378 free(regex);
379 /*@innercontinue@*/ continue;
380 } else if (items == 2) {
381 /* The type field is optional. */
382 free(context);
383 context = type;
384 type = 0;
385 }
386
387 /* On pass 2, compile and store the specification. */
388 if (pass == 1) {
389 const char * reg_buf = regex;
390 sxp->fstem = rpmsxAdd(sx, &reg_buf);
391 sxp->pattern = regex;
392
393 /* Anchor the regular expression. */
394 len = strlen(reg_buf);
395 anchored_regex = xmalloc(len + 3);
396 sprintf(anchored_regex, "^%s$", reg_buf);
397
398 /* Compile the regular expression. */
399 /*@i@*/ sxp->preg = xcalloc(1, sizeof(*sxp->preg));
400 regerr = regcomp(sxp->preg, anchored_regex,
401 REG_EXTENDED | REG_NOSUB);
402 if (regerr < 0) {
403 char errbuf[BUFSIZ + 1];
404 (void) regerror(regerr, sxp->preg, errbuf, sizeof(errbuf)-1);
405 errbuf[sizeof(errbuf)-1] = '\0';
406 fprintf(stderr,
407 _("%s: unable to compile regular expression %s on line number %d: %s\n"),
408 fn, regex, lineno,
409 errbuf);
410 inc_err();
411 }
412 free(anchored_regex);
413
414 /* Convert the type string to a mode format */
415 sxp->type = type;
416 sxp->fmode = 0;
417 if (!type)
418 goto skip_type;
419 len = strlen(type);
420 if (type[0] != '-' || len != 2) {
421 fprintf(stderr,
422 _("%s: invalid type specifier %s on line number %d\n"),
423 fn, type, lineno);
424 inc_err();
425 goto skip_type;
426 }
427 switch (type[1]) {
428 case 'b': sxp->fmode = S_IFBLK; /*@switchbreak@*/ break;
429 case 'c': sxp->fmode = S_IFCHR; /*@switchbreak@*/ break;
430 case 'd': sxp->fmode = S_IFDIR; /*@switchbreak@*/ break;
431 case 'p': sxp->fmode = S_IFIFO; /*@switchbreak@*/ break;
432 case 'l': sxp->fmode = S_IFLNK; /*@switchbreak@*/ break;
433 /*@i@*/ case 's': sxp->fmode = S_IFSOCK; /*@switchbreak@*/ break;
434 case '-': sxp->fmode = S_IFREG; /*@switchbreak@*/ break;
435 default:
436 fprintf(stderr,
437 _("%s: invalid type specifier %s on line number %d\n"),
438 fn, type, lineno);
439 inc_err();
440 /*@switchbreak@*/ break;
441 }
442
443 skip_type:
444
445 sxp->context = context;
446
447 if (strcmp(context, "<<none>>")) {
448 if (security_check_context(context) < 0 && errno != ENOENT) {
449 fprintf(stderr,
450 _("%s: invalid context %s on line number %d\n"),
451 fn, context, lineno);
452 inc_err();
453 }
454 }
455
456 /* Determine if specification has
457 * any meta characters in the RE */
458 rpmsxpHasMetaChars(sxp);
459 sxp++;
460 }
461
462 sx->Count++;
463 if (pass == 0) {
464 /*@-kepttrans@*/
465 free(regex);
466 if (type)
467 free(type);
468 free(context);
469 /*@=kepttrans@*/
470 }
471 }
472
473 if (nerr) {
474 (void) fclose(fp);
475 return -1;
476 }
477
478 if (pass == 0) {
479 if (sx->Count == 0) {
480 (void) fclose(fp);
481 return 0;
482 }
483 sx->sxp = xcalloc(sx->Count, sizeof(*sx->sxp));
484 rewind(fp);
485 }
486 }
487 (void) fclose(fp);
488
489 /* Stable sort for policy specifications, patterns before paths. */
490 rpmsxSort(sx);
491
492 /* Verify no exact duplicates */
493 if (rpmsxpCheckNoDupes(sx) != 0)
494 return -1;
495
496 return 0;
497
498 }
499
500 rpmsx rpmsxNew(const char * fn)
501 {
502 rpmsx sx = rpmsxGetPool(_rpmsxPool);
503
504 sx->sxp = NULL;
505 sx->Count = 0;
506 sx->i = -1;
507 sx->sxs = NULL;
508 sx->nsxs = 0;
509 sx->maxsxs = 0;
510 sx->reverse = 0;
511
512 (void) rpmsxLink(sx, "rpmsxNew");
513
514 if (rpmsxParse(sx, fn) != 0)
515 return rpmsxFree(sx);
516
517 return sx;
518 }
519
520 int rpmsxCount(const rpmsx sx)
521 {
522 return (sx != NULL ? sx->Count : 0);
523 }
524
525 int rpmsxIx(const rpmsx sx)
526 {
527 return (sx != NULL ? sx->i : -1);
528 }
529
530 int rpmsxSetIx(rpmsx sx, int ix)
531 {
532 int i = -1;
533
534 if (sx != NULL) {
535 i = sx->i;
536 sx->i = ix;
537 }
538 return i;
539 }
540
541 const char * rpmsxPattern(const rpmsx sx)
542 {
543 const char * pattern = NULL;
544
545 if (sx != NULL && sx->i >= 0 && sx->i < sx->Count)
546 pattern = (sx->sxp + sx->i)->pattern;
547 return pattern;
548 }
549
550 const char * rpmsxType(const rpmsx sx)
551 {
552 const char * type = NULL;
553
554 if (sx != NULL && sx->i >= 0 && sx->i < sx->Count)
555 type = (sx->sxp + sx->i)->type;
556 return type;
557 }
558
559 const char * rpmsxContext(const rpmsx sx)
560 {
561 const char * context = NULL;
562
563 if (sx != NULL && sx->i >= 0 && sx->i < sx->Count)
564 context = (sx->sxp + sx->i)->context;
565 return context;
566 }
567
568 regex_t * rpmsxRE(const rpmsx sx)
569 {
570 regex_t * preg = NULL;
571
572 if (sx != NULL && sx->i >= 0 && sx->i < sx->Count)
573 preg = (sx->sxp + sx->i)->preg;
574 return preg;
575 }
576
577 mode_t rpmsxFMode(const rpmsx sx)
578 {
579 mode_t fmode = 0;
580
581 if (sx != NULL && sx->i >= 0 && sx->i < sx->Count)
582 fmode = (sx->sxp + sx->i)->fmode;
583 return fmode;
584 }
585
586 int rpmsxFStem(const rpmsx sx)
587 {
588 int fstem = -1;
589
590 if (sx != NULL && sx->i >= 0 && sx->i < sx->Count)
591 fstem = (sx->sxp + sx->i)->fstem;
592 return fstem;
593 }
594
595 int rpmsxNext(/*@null@*/ rpmsx sx)
596 /*@modifies sx @*/
597 {
598 int i = -1;
599
600 if (sx != NULL) {
601 if (sx->reverse != 0) {
602 i = --sx->i;
603 if (sx->i < 0) {
604 sx->i = sx->Count;
605 i = -1;
606 }
607 } else {
608 i = ++sx->i;
609 if (sx->i >= sx->Count) {
610 sx->i = -1;
611 i = -1;
612 }
613 }
614
615 /*@-modfilesys @*/
616 if (_rpmsx_debug < 0 && i != -1) {
617 rpmsxp sxp = sx->sxp + i;
618 fprintf(stderr, "*** sx %p\t%s[%d]\t%s\t%s\n", sx, "rpmsxNext", i, sxp->pattern, sxp->context);
619 /*@=modfilesys @*/
620 }
621
622 }
623
624 return i;
625 }
626
627 rpmsx rpmsxInit(/*@null@*/ rpmsx sx, int reverse)
628 /*@modifies sx @*/
629 {
630 if (sx != NULL) {
631 sx->reverse = reverse;
632 sx->i = (sx->reverse ? sx->Count : -1);
633 }
634 /*@-refcounttrans@*/
635 return sx;
636 /*@=refcounttrans@*/
637 }
638
639 const char * rpmsxFContext(rpmsx sx, const char * fn, mode_t fmode)
640 {
641 const char * fcontext = NULL;
642 const char * myfn = fn;
643 /*@-mods@*/
644 int fstem = rpmsxFind(sx, &myfn);
645 /*@=mods@*/
646 int i;
647
648 sx = rpmsxInit(sx, 1);
649 if (sx != NULL)
650 while ((i = rpmsxNext(sx)) >= 0) {
651 regex_t * preg;
652 mode_t sxfmode;
653 int sxfstem;
654 int ret;
655
656 sxfstem = rpmsxFStem(sx);
657 if (sxfstem != -1 && sxfstem != fstem)
658 continue;
659
660 sxfmode = rpmsxFMode(sx);
661 if (sxfmode && (fmode & S_IFMT) != sxfmode)
662 continue;
663
664 preg = rpmsxRE(sx);
665 if (preg == NULL)
666 continue;
667
668 ret = regexec(preg, (sxfstem == -1 ? fn : myfn), 0, NULL, 0);
669 switch (ret) {
670 case REG_NOMATCH:
671 continue;
672 /*@notreached@*/ /*@switchbreak@*/ break;
673 case 0:
674 fcontext = rpmsxContext(sx);
675 /*@switchbreak@*/ break;
676 default:
677 { static char errbuf[BUFSIZ + 1];
678 (void) regerror(ret, preg, errbuf, sizeof(errbuf)-1);
679 /*@-modfilesys -nullpass @*/
680 errbuf[sizeof(errbuf)-1] = '\0';
681 fprintf(stderr, "unable to match %s against %s: %s\n",
682 fn, rpmsxPattern(sx), errbuf);
683 /*@=modfilesys =nullpass @*/
684 } /*@switchbreak@*/ break;
685 }
686 break;
687 }
688
689 return fcontext;
690 }