rpm 5.2.1

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

- File List
- Globals

rpmns.c
Go to the documentation of this file.
1
4 #include "system.h"
5
6 #define _RPMIOB_INTERNAL /* XXX rpmiobSlurp */
7 #include <rpmiotypes.h>
8 #include <rpmio.h>
9 #include <rpmmacro.h>
10 #include <rpmcb.h>
11
12 #define _RPMPGP_INTERNAL
13 #include <rpmpgp.h>
14
15 #include <rpmtypes.h>
16 #include <rpmtag.h>
17 #define _RPMEVR_INTERNAL
18 #include <rpmevr.h>
19 #define _RPMNS_INTERNAL
20 #include <rpmns.h>
21 #include <rpmdb.h>
22
23 #include <rpmps.h>
24 #define _RPMTS_INTERNAL /* XXX ts->pkpkt, ts->pkpktlen */
25 #include <rpmts.h>
26
27 #include "debug.h"
28
29 /*@access rpmts @*/
30 /*@access pgpDigParams @*/
31
32 /*@unchecked@*/
33 int _rpmns_debug = 0;
34
35 /*@unchecked@*/ /*@observer@*/ /*@relnull@*/
36 const char *_rpmns_N_at_A = ".";
37
38 /*@-nullassign@*/
39 /*@unchecked@*/ /*@observer@*/
40 static const char *rpmnsArches[] = {
41 "i386", "i486", "i586", "i686", "athlon", "pentium3", "pentium4",
42 "x86_64", "amd64", "ia32e",
43 "alpha", "alphaev5", "alphaev56", "alphapca56", "alphaev6", "alphaev67",
44 "sparc", "sun4", "sun4m", "sun4c", "sun4d", "sparcv8",
45 "sparcv9", "sparcv9b", "sparcv9v", "sparcv9v2",
46 "sparc64", "sun4u", "sparc64v",
47 "mips", "mipsel", "IP",
48 "ppc", "ppciseries", "ppcpseries",
49 "ppc64", "ppc64iseries", "ppc64pseries",
50 "m68k",
51 "rs6000",
52 "ia64",
53 "armv3l", "armv4b", "armv4l",
54 "armv5teb", "armv5tel", "armv5tejl",
55 "armv6l",
56 "s390", "i370", "s390x",
57 "sh", "sh3", "sh4", "sh4a", "xtensa",
58 "noarch", "fat",
59 NULL,
60 };
61 /*@=nullassign@*/
62
63 nsType rpmnsArch(const char * str)
64 {
65 nsType rc = RPMNS_TYPE_UNKNOWN;
66 const char ** av;
67
68 #if defined(RPM_VENDOR_WINDRIVER)
69 const char * known_arch = rpmExpand("%{?_known_arch}", NULL);
70 const char *p, *pe, *t;
71 for (p = pe = known_arch ; rc == RPMNS_TYPE_UNKNOWN && pe && *pe ; ) {
72 while (*p && xisspace(*p)) p++;
73 pe = p ; while (*pe && !xisspace(*pe)) pe++;
74 if (p == pe)
75 break;
76 t = strndup(p, (pe - p));
77 p = pe;
78 if (!strcmp(str, t))
79 rc = RPMNS_TYPE_ARCH;
80 t = _free(t);
81 }
82 known_arch = _free(known_arch);
83 #endif
84
85 if (rc == RPMNS_TYPE_UNKNOWN)
86 for (av = rpmnsArches; *av != NULL; av++) {
87 if (strcmp(str, *av))
88 continue;
89 rc = RPMNS_TYPE_ARCH;
90 break;
91 }
92
93 return rc;
94 }
95
99 /*@unchecked@*/ /*@observer@*/
100 static struct _rpmnsProbes_s {
101 /*@observer@*/ /*@relnull@*/
102 const char * NS;
103 nsType Type;
104 } rpmnsProbes[] = {
105 { "rpmlib", RPMNS_TYPE_RPMLIB },
106 { "config", RPMNS_TYPE_CONFIG },
107 { "cpuinfo", RPMNS_TYPE_CPUINFO },
108 { "getconf", RPMNS_TYPE_GETCONF },
109 { "uname", RPMNS_TYPE_UNAME },
110 { "soname", RPMNS_TYPE_SONAME },
111 { "user", RPMNS_TYPE_USER },
112 { "group", RPMNS_TYPE_GROUP },
113 { "mounted", RPMNS_TYPE_MOUNTED },
114 { "diskspace", RPMNS_TYPE_DISKSPACE },
115 { "digest", RPMNS_TYPE_DIGEST },
116 { "gnupg", RPMNS_TYPE_GNUPG },
117 { "macro", RPMNS_TYPE_MACRO },
118 { "envvar", RPMNS_TYPE_ENVVAR },
119 { "running", RPMNS_TYPE_RUNNING },
120 { "sanitycheck", RPMNS_TYPE_SANITY },
121 { "vcheck", RPMNS_TYPE_VCHECK },
122 { "signature", RPMNS_TYPE_SIGNATURE },
123 { "verify", RPMNS_TYPE_VERIFY },
124 { "exists", RPMNS_TYPE_ACCESS },
125 { "executable", RPMNS_TYPE_ACCESS },
126 { "readable", RPMNS_TYPE_ACCESS },
127 { "writable", RPMNS_TYPE_ACCESS },
128 { "RWX", RPMNS_TYPE_ACCESS },
129 { "RWx", RPMNS_TYPE_ACCESS },
130 { "RW_", RPMNS_TYPE_ACCESS },
131 { "RwX", RPMNS_TYPE_ACCESS },
132 { "Rwx", RPMNS_TYPE_ACCESS },
133 { "Rw_", RPMNS_TYPE_ACCESS },
134 { "R_X", RPMNS_TYPE_ACCESS },
135 { "R_x", RPMNS_TYPE_ACCESS },
136 { "R__", RPMNS_TYPE_ACCESS },
137 { "rWX", RPMNS_TYPE_ACCESS },
138 { "rWx", RPMNS_TYPE_ACCESS },
139 { "rW_", RPMNS_TYPE_ACCESS },
140 { "rwX", RPMNS_TYPE_ACCESS },
141 { "rwx", RPMNS_TYPE_ACCESS },
142 { "rw_", RPMNS_TYPE_ACCESS },
143 { "r_X", RPMNS_TYPE_ACCESS },
144 { "r_x", RPMNS_TYPE_ACCESS },
145 { "r__", RPMNS_TYPE_ACCESS },
146 { "_WX", RPMNS_TYPE_ACCESS },
147 { "_Wx", RPMNS_TYPE_ACCESS },
148 { "_W_", RPMNS_TYPE_ACCESS },
149 { "_wX", RPMNS_TYPE_ACCESS },
150 { "_wx", RPMNS_TYPE_ACCESS },
151 { "_w_", RPMNS_TYPE_ACCESS },
152 { "__X", RPMNS_TYPE_ACCESS },
153 { "__x", RPMNS_TYPE_ACCESS },
154 { "___", RPMNS_TYPE_ACCESS },
155 { NULL, 0 }
156 };
157
158 nsType rpmnsProbe(const char * str)
159 {
160 const struct _rpmnsProbes_s * av;
161 size_t sn = strlen(str);
162 size_t nb;
163
164 if (sn >= 5 && str[sn-1] == ')')
165 for (av = rpmnsProbes; av->NS != NULL; av++) {
166 nb = strlen(av->NS);
167 if (sn > nb && str[nb] == '(' && !strncmp(str, av->NS, nb))
168 return av->Type;
169 }
170 return RPMNS_TYPE_UNKNOWN;
171 }
172
173 nsType rpmnsClassify(const char * str)
174 {
175 const char * s;
176 nsType Type = RPMNS_TYPE_STRING;
177
178 if (*str == '!')
179 str++;
180 if (*str == '/')
181 return RPMNS_TYPE_PATH;
182 s = str + strlen(str);
183 if (str[0] == '%' && str[1] == '{' && s[-1] == '}')
184 return RPMNS_TYPE_FUNCTION;
185 if ((s - str) > 3 && s[-3] == '.' && s[-2] == 's' && s[-1] == 'o')
186 return RPMNS_TYPE_DSO;
187 Type = rpmnsProbe(str);
188 if (Type != RPMNS_TYPE_UNKNOWN)
189 return Type;
190 for (s = str; *s != '\0'; s++) {
191 if (s[0] == '(' || s[strlen(s)-1] == ')')
192 return RPMNS_TYPE_NAMESPACE;
193 if (s[0] == '.' && s[1] == 's' && s[2] == 'o')
194 return RPMNS_TYPE_DSO;
195 if (s[0] == '.' && xisdigit((int)s[-1]) && xisdigit((int)s[1]))
196 return RPMNS_TYPE_VERSION;
197 if (_rpmns_N_at_A && _rpmns_N_at_A[0]) {
198 if (s[0] == _rpmns_N_at_A[0] && rpmnsArch(s+1))
199 return RPMNS_TYPE_ARCH;
200 }
201 /*@-globstate@*/
202 if (s[0] == '.')
203 return RPMNS_TYPE_COMPOUND;
204 }
205 return RPMNS_TYPE_STRING;
206 /*@=globstate@*/
207 }
208
209 int rpmnsParse(const char * str, rpmns ns)
210 {
211 char *t;
212 ns->str = t = rpmExpand(str, NULL);
213 ns->Type = rpmnsClassify(ns->str);
214 switch (ns->Type) {
215 case RPMNS_TYPE_ARCH:
216 ns->NS = NULL;
217 ns->N = ns->str;
218 if (ns->N[0] == '!')
219 ns->N++;
220 if ((t = strrchr(t, _rpmns_N_at_A[0])) != NULL)
221 *t++ = '\0';
222 ns->A = t;
223 break;
224 case RPMNS_TYPE_RPMLIB:
225 case RPMNS_TYPE_CPUINFO:
226 case RPMNS_TYPE_GETCONF:
227 case RPMNS_TYPE_UNAME:
228 case RPMNS_TYPE_SONAME:
229 case RPMNS_TYPE_ACCESS:
230 case RPMNS_TYPE_USER:
231 case RPMNS_TYPE_GROUP:
232 case RPMNS_TYPE_MOUNTED:
233 case RPMNS_TYPE_DISKSPACE:
234 case RPMNS_TYPE_DIGEST:
235 case RPMNS_TYPE_GNUPG:
236 case RPMNS_TYPE_MACRO:
237 case RPMNS_TYPE_ENVVAR:
238 case RPMNS_TYPE_RUNNING:
239 case RPMNS_TYPE_SANITY:
240 case RPMNS_TYPE_VCHECK:
241 case RPMNS_TYPE_SIGNATURE:
242 case RPMNS_TYPE_VERIFY:
243 ns->NS = ns->str;
244 if (ns->NS[0] == '!')
245 ns->NS++;
246 if ((t = strchr(t, '(')) != NULL) {
247 *t++ = '\0';
248 ns->N = t;
249 t[strlen(t)-1] = '\0';
250 } else
251 ns->N = NULL;
252 ns->A = NULL;
253 break;
254 case RPMNS_TYPE_UNKNOWN:
255 case RPMNS_TYPE_STRING:
256 case RPMNS_TYPE_PATH:
257 case RPMNS_TYPE_DSO:
258 case RPMNS_TYPE_FUNCTION:
259 case RPMNS_TYPE_VERSION:
260 case RPMNS_TYPE_COMPOUND:
261 case RPMNS_TYPE_NAMESPACE:
262 case RPMNS_TYPE_TAG:
263 case RPMNS_TYPE_CONFIG:
264 default:
265 ns->NS = NULL;
266 ns->N = ns->str;
267 if (ns->N[0] == '!')
268 ns->N++;
269 ns->A = NULL;
270 break;
271 }
272 return 0;
273 }
274
280 static inline unsigned char nibble(char c)
281 /*@*/
282 {
283 if (c >= '0' && c <= '9')
284 return (unsigned char)(c - '0');
285 if (c >= 'A' && c <= 'F')
286 return (unsigned char)((int)(c - 'A') + 10);
287 if (c >= 'a' && c <= 'f')
288 return (unsigned char)((int)(c - 'a') + 10);
289 return '\0';
290 }
291
292 rpmRC rpmnsProbeSignature(void * _ts, const char * fn, const char * sigfn,
293 const char * pubfn, const char * pubid,
294 /*@unused@*/ int flags)
295 {
296 rpmts ts = _ts;
297 pgpDig dig = rpmtsDig(ts);
298 pgpDigParams sigp;
299 pgpDigParams pubp;
300 rpmuint8_t * sigpkt = NULL;
301 size_t sigpktlen = 0;
302 DIGEST_CTX ctx = NULL;
303 int printing = 0;
304 rpmRC rc = RPMRC_FAIL; /* assume failure */
305 int xx;
306
307 if (_rpmns_debug)
308 fprintf(stderr, "==> check(%s, %s, %s, %s)\n", fn,
309 (sigfn ? sigfn : "(null)"),
310 (pubfn ? pubfn : "(null)"),
311 (pubid ? pubid : "(null)"));
312
313 /* Load the signature. Use sigfn if specified, otherwise clearsign. */
314 if (sigfn && *sigfn) {
315 const char * _sigfn = rpmExpand(sigfn, NULL);
316 xx = pgpReadPkts(_sigfn, &sigpkt, &sigpktlen);
317 if (xx != PGPARMOR_SIGNATURE) {
318 if (_rpmns_debug)
319 fprintf(stderr, "==> pgpReadPkts(%s) SIG %p[%u] ret %d\n", _sigfn, sigpkt, (unsigned)sigpktlen, xx);
320 _sigfn = _free(_sigfn);
321 goto exit;
322 }
323 _sigfn = _free(_sigfn);
324 } else {
325 const char * _sigfn = rpmExpand(fn, NULL);
326 xx = pgpReadPkts(_sigfn, &sigpkt, &sigpktlen);
327 if (xx != PGPARMOR_SIGNATURE) {
328 if (_rpmns_debug)
329 fprintf(stderr, "==> pgpReadPkts(%s) SIG %p[%u] ret %d\n", _sigfn, sigpkt, (unsigned)sigpktlen, xx);
330 _sigfn = _free(_sigfn);
331 goto exit;
332 }
333 _sigfn = _free(_sigfn);
334 }
335 xx = pgpPrtPkts((rpmuint8_t *)sigpkt, sigpktlen, dig, printing);
336 if (xx) {
337 if (_rpmns_debug)
338 fprintf(stderr, "==> pgpPrtPkts SIG %p[%u] ret %d\n", sigpkt, (unsigned)sigpktlen, xx);
339 goto exit;
340 }
341
342 sigp = pgpGetSignature(dig);
343
344 if (sigp->version != (rpmuint8_t)3 && sigp->version != (rpmuint8_t)4) {
345 if (_rpmns_debug)
346 fprintf(stderr, "==> unverifiable V%u\n", (unsigned)sigp->version);
347 goto exit;
348 }
349
350 /* Load the pubkey. Use pubfn if specified, otherwise rpmdb keyring. */
351 if (pubfn && *pubfn) {
352 const char * _pubfn = rpmExpand(pubfn, NULL);
353 /*@-type@*/
354 xx = pgpReadPkts(_pubfn, &ts->pkpkt, &ts->pkpktlen);
355 /*@=type@*/
356 if (xx != PGPARMOR_PUBKEY) {
357 if (_rpmns_debug)
358 fprintf(stderr, "==> pgpReadPkts(%s) PUB %p[%u] ret %d\n", _pubfn, ts->pkpkt, (unsigned int)ts->pkpktlen, xx);
359 _pubfn = _free(_pubfn);
360 goto exit;
361 }
362 _pubfn = _free(_pubfn);
363 xx = pgpPrtPkts((rpmuint8_t *)ts->pkpkt, ts->pkpktlen, dig, printing);
364 if (xx) {
365 if (_rpmns_debug)
366 fprintf(stderr, "==> pgpPrtPkts PUB %p[%u] ret %d\n", ts->pkpkt, (unsigned int)ts->pkpktlen, xx);
367 goto exit;
368 }
369 } else {
370 if ((rc = pgpFindPubkey(dig)) != RPMRC_OK) {
371 if (_rpmns_debug)
372 fprintf(stderr, "==> pgpFindPubkey ret %d\n", xx);
373 goto exit;
374 }
375 }
376
377 pubp = pgpGetPubkey(dig);
378
379 /* Is this the requested pubkey? */
380 if (pubid && *pubid) {
381 size_t ns = strlen(pubid);
382 const char * s;
383 char * t;
384 size_t i;
385
386 /* At least 8 hex digits please. */
387 for (i = 0, s = pubid; *s && isxdigit(*s); s++, i++)
388 {};
389 if (!(*s == '\0' && i > 8 && (i%2) == 0))
390 goto exit;
391
392 /* Truncate to key id size. */
393 s = pubid;
394 if (ns > 16) {
395 s += (ns - 16);
396 ns = 16;
397 }
398 ns >>= 1;
399 t = memset(alloca(ns), 0, ns);
400 for (i = 0; i < ns; i++)
401 t[i] = (char)((nibble(s[2*i]) << 4) | nibble(s[2*i+1]));
402
403 /* Compare the pubkey id. */
404 s = (const char *)pubp->signid;
405 xx = memcmp(t, s + (8 - ns), ns);
406
407 /* XXX HACK: V4 RSA key id's are wonky atm. */
408 if (pubp->pubkey_algo == (rpmuint8_t)PGPPUBKEYALGO_RSA)
409 xx = 0;
410
411 if (xx) {
412 if (_rpmns_debug)
413 fprintf(stderr, "==> mismatched: pubkey id (%08x %08x) != %s\n",
414 pgpGrab(pubp->signid, 4), pgpGrab(pubp->signid+4, 4), pubid);
415 goto exit;
416 }
417 }
418
419 /* Do the parameters match the signature? */
420 if (!(sigp->pubkey_algo == pubp->pubkey_algo
421 #ifdef NOTYET
422 && sigp->hash_algo == pubp->hash_algo
423 #endif
424 /* XXX HACK: V4 RSA key id's are wonky atm. */
425 && (pubp->pubkey_algo == (rpmuint8_t)PGPPUBKEYALGO_RSA || !memcmp(sigp->signid, pubp->signid, sizeof(sigp->signid))) ) ) {
426 if (_rpmns_debug) {
427 fprintf(stderr, "==> mismatch between signature and pubkey\n");
428 fprintf(stderr, "\tpubkey_algo: %u %u\n", (unsigned)sigp->pubkey_algo, (unsigned)pubp->pubkey_algo);
429 fprintf(stderr, "\tsignid: %08X %08X %08X %08X\n",
430 pgpGrab(sigp->signid, 4), pgpGrab(sigp->signid+4, 4),
431 pgpGrab(pubp->signid, 4), pgpGrab(pubp->signid+4, 4));
432 }
433 goto exit;
434 }
435
436 /* Compute the message digest. */
437 ctx = rpmDigestInit((pgpHashAlgo)sigp->hash_algo, RPMDIGEST_NONE);
438
439 {
440 static const char clrtxt[] = "-----BEGIN PGP SIGNED MESSAGE-----";
441 static const char sigtxt[] = "-----BEGIN PGP SIGNATURE-----";
442 const char * _fn = rpmExpand(fn, NULL);
443 rpmiob iob = NULL;
444 int _rc = rpmiobSlurp(_fn, &iob);
445
446 if (!(_rc == 0 && iob != NULL)) {
447 if (_rpmns_debug)
448 fprintf(stderr, "==> rpmiobSlurp(%s) MSG ret %d\n", _fn, _rc);
449 iob = rpmiobFree(iob);
450 _fn = _free(_fn);
451 goto exit;
452 }
453 _fn = _free(_fn);
454
455 /* XXX clearsign sig is PGPSIGTYPE_TEXT not PGPSIGTYPE_BINARY. */
456 if (!strncmp((char *)iob->b, clrtxt, strlen(clrtxt))) {
457 const char * be = (char *) (iob->b + iob->blen);
458 const char * t;
459
460 /* Skip to '\n\n' start-of-plaintext */
461 t = (char *) iob->b;
462 while (t && t < be && *t != '\n')
463 t = strchr(t, '\n') + 1;
464 if (!(t && t < be))
465 goto exit;
466 t++;
467
468 /* Clearsign digest rtrims " \t\r\n", inserts "\r\n" inter-lines. */
469 while (t < be) {
470 const char * teol;
471 const char * te;
472 if (strncmp(t, "- ", 2) == 0)
473 t += 2;
474 if ((teol = te = strchr(t, '\n')) == NULL)
475 break;
476 while (te > t && strchr(" \t\r\n", te[-1]))
477 te--;
478 xx = rpmDigestUpdate(ctx, t, (te - t));
479 if (!strncmp((t = teol + 1), sigtxt, strlen(sigtxt)))
480 break;
481 xx = rpmDigestUpdate(ctx, "\r\n", sizeof("\r\n")-1);
482 }
483 } else
484 xx = rpmDigestUpdate(ctx, iob->b, iob->blen);
485
486 iob = rpmiobFree(iob);
487 }
488
489 if (sigp->hash != NULL)
490 xx = rpmDigestUpdate(ctx, sigp->hash, sigp->hashlen);
491 if (sigp->version == (rpmuint8_t)4) {
492 rpmuint32_t nb = (rpmuint32_t)sigp->hashlen;
493 rpmuint8_t trailer[6];
494 nb = (rpmuint32_t)htonl(nb);
495 trailer[0] = sigp->version;
496 trailer[1] = (rpmuint8_t)0xff;
497 memcpy(trailer+2, &nb, sizeof(nb));
498 xx = rpmDigestUpdate(ctx, trailer, sizeof(trailer));
499 }
500
501 /* Load the message digest. */
502 switch(sigp->pubkey_algo) {
503 default:
504 rc = RPMRC_FAIL;
505 break;
506 case PGPPUBKEYALGO_DSA:
507 rc = (pgpImplSetDSA(ctx, dig, sigp) ? RPMRC_FAIL : RPMRC_OK);
508 break;
509 case PGPPUBKEYALGO_RSA:
510 rc = (pgpImplSetRSA(ctx, dig, sigp) ? RPMRC_FAIL : RPMRC_OK);
511 break;
512 }
513 if (rc != RPMRC_OK) {
514 if (_rpmns_debug)
515 fprintf(stderr, "==> can't load pubkey_algo(%u)\n", (unsigned)sigp->pubkey_algo);
516 goto exit;
517 }
518
519 /* Verify the signature. */
520 switch(sigp->pubkey_algo) {
521 default:
522 rc = RPMRC_FAIL;
523 break;
524 case PGPPUBKEYALGO_DSA:
525 rc = (pgpImplVerifyDSA(dig) ? RPMRC_OK : RPMRC_FAIL);
526 break;
527 case PGPPUBKEYALGO_RSA:
528 rc = (pgpImplVerifyRSA(dig) ? RPMRC_OK : RPMRC_FAIL);
529 break;
530 }
531
532 exit:
533 sigpkt = _free(sigpkt);
534 ts->pkpkt = _free(ts->pkpkt);
535 ts->pkpktlen = 0;
536 /*@-nullstate@*/
537 rpmtsCleanDig(ts);
538 /*@=nullstate@*/
539
540 if (_rpmns_debug)
541 fprintf(stderr, "============================ verify: %s\n",
542 (rc == RPMRC_OK ? "OK" :
543 (rc == RPMRC_NOKEY ? "NOKEY" :
544 "FAIL")));
545
546 return rc;
547 }