rpm  5.2.1
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 {
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;
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;
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:
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:
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:
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 }