rpm
5.2.1
|
00001 00004 #include "system.h" 00005 00006 #define _RPMIOB_INTERNAL /* XXX rpmiobSlurp */ 00007 #include <rpmiotypes.h> 00008 #include <rpmio.h> 00009 #include <rpmmacro.h> 00010 #include <rpmcb.h> 00011 00012 #define _RPMPGP_INTERNAL 00013 #include <rpmpgp.h> 00014 00015 #include <rpmtypes.h> 00016 #include <rpmtag.h> 00017 #define _RPMEVR_INTERNAL 00018 #include <rpmevr.h> 00019 #define _RPMNS_INTERNAL 00020 #include <rpmns.h> 00021 #include <rpmdb.h> 00022 00023 #include <rpmps.h> 00024 #define _RPMTS_INTERNAL /* XXX ts->pkpkt, ts->pkpktlen */ 00025 #include <rpmts.h> 00026 00027 #include "debug.h" 00028 00029 /*@access rpmts @*/ 00030 /*@access pgpDigParams @*/ 00031 00032 /*@unchecked@*/ 00033 int _rpmns_debug = 0; 00034 00035 /*@unchecked@*/ /*@observer@*/ /*@relnull@*/ 00036 const char *_rpmns_N_at_A = "."; 00037 00038 /*@-nullassign@*/ 00039 /*@unchecked@*/ /*@observer@*/ 00040 static const char *rpmnsArches[] = { 00041 "i386", "i486", "i586", "i686", "athlon", "pentium3", "pentium4", 00042 "x86_64", "amd64", "ia32e", 00043 "alpha", "alphaev5", "alphaev56", "alphapca56", "alphaev6", "alphaev67", 00044 "sparc", "sun4", "sun4m", "sun4c", "sun4d", "sparcv8", 00045 "sparcv9", "sparcv9b", "sparcv9v", "sparcv9v2", 00046 "sparc64", "sun4u", "sparc64v", 00047 "mips", "mipsel", "IP", 00048 "ppc", "ppciseries", "ppcpseries", 00049 "ppc64", "ppc64iseries", "ppc64pseries", 00050 "m68k", 00051 "rs6000", 00052 "ia64", 00053 "armv3l", "armv4b", "armv4l", 00054 "armv5teb", "armv5tel", "armv5tejl", 00055 "armv6l", 00056 "s390", "i370", "s390x", 00057 "sh", "sh3", "sh4", "sh4a", "xtensa", 00058 "noarch", "fat", 00059 NULL, 00060 }; 00061 /*@=nullassign@*/ 00062 00063 nsType rpmnsArch(const char * str) 00064 { 00065 nsType rc = RPMNS_TYPE_UNKNOWN; 00066 const char ** av; 00067 00068 #if defined(RPM_VENDOR_WINDRIVER) 00069 const char * known_arch = rpmExpand("%{?_known_arch}", NULL); 00070 const char *p, *pe, *t; 00071 for (p = pe = known_arch ; rc == RPMNS_TYPE_UNKNOWN && pe && *pe ; ) { 00072 while (*p && xisspace(*p)) p++; 00073 pe = p ; while (*pe && !xisspace(*pe)) pe++; 00074 if (p == pe) 00075 break; 00076 t = strndup(p, (pe - p)); 00077 p = pe; 00078 if (!strcmp(str, t)) 00079 rc = RPMNS_TYPE_ARCH; 00080 t = _free(t); 00081 } 00082 known_arch = _free(known_arch); 00083 #endif 00084 00085 if (rc == RPMNS_TYPE_UNKNOWN) 00086 for (av = rpmnsArches; *av != NULL; av++) { 00087 if (strcmp(str, *av)) 00088 continue; 00089 rc = RPMNS_TYPE_ARCH; 00090 break; 00091 } 00092 00093 return rc; 00094 } 00095 00099 /*@unchecked@*/ /*@observer@*/ 00100 static struct _rpmnsProbes_s { 00101 /*@observer@*/ /*@relnull@*/ 00102 const char * NS; 00103 nsType Type; 00104 } rpmnsProbes[] = { 00105 { "rpmlib", RPMNS_TYPE_RPMLIB }, 00106 { "config", RPMNS_TYPE_CONFIG }, 00107 { "cpuinfo", RPMNS_TYPE_CPUINFO }, 00108 { "getconf", RPMNS_TYPE_GETCONF }, 00109 { "uname", RPMNS_TYPE_UNAME }, 00110 { "soname", RPMNS_TYPE_SONAME }, 00111 { "user", RPMNS_TYPE_USER }, 00112 { "group", RPMNS_TYPE_GROUP }, 00113 { "mounted", RPMNS_TYPE_MOUNTED }, 00114 { "diskspace", RPMNS_TYPE_DISKSPACE }, 00115 { "digest", RPMNS_TYPE_DIGEST }, 00116 { "gnupg", RPMNS_TYPE_GNUPG }, 00117 { "macro", RPMNS_TYPE_MACRO }, 00118 { "envvar", RPMNS_TYPE_ENVVAR }, 00119 { "running", RPMNS_TYPE_RUNNING }, 00120 { "sanitycheck", RPMNS_TYPE_SANITY }, 00121 { "vcheck", RPMNS_TYPE_VCHECK }, 00122 { "signature", RPMNS_TYPE_SIGNATURE }, 00123 { "verify", RPMNS_TYPE_VERIFY }, 00124 { "exists", RPMNS_TYPE_ACCESS }, 00125 { "executable", RPMNS_TYPE_ACCESS }, 00126 { "readable", RPMNS_TYPE_ACCESS }, 00127 { "writable", RPMNS_TYPE_ACCESS }, 00128 { "RWX", RPMNS_TYPE_ACCESS }, 00129 { "RWx", RPMNS_TYPE_ACCESS }, 00130 { "RW_", RPMNS_TYPE_ACCESS }, 00131 { "RwX", RPMNS_TYPE_ACCESS }, 00132 { "Rwx", RPMNS_TYPE_ACCESS }, 00133 { "Rw_", RPMNS_TYPE_ACCESS }, 00134 { "R_X", RPMNS_TYPE_ACCESS }, 00135 { "R_x", RPMNS_TYPE_ACCESS }, 00136 { "R__", RPMNS_TYPE_ACCESS }, 00137 { "rWX", RPMNS_TYPE_ACCESS }, 00138 { "rWx", RPMNS_TYPE_ACCESS }, 00139 { "rW_", RPMNS_TYPE_ACCESS }, 00140 { "rwX", RPMNS_TYPE_ACCESS }, 00141 { "rwx", RPMNS_TYPE_ACCESS }, 00142 { "rw_", RPMNS_TYPE_ACCESS }, 00143 { "r_X", RPMNS_TYPE_ACCESS }, 00144 { "r_x", RPMNS_TYPE_ACCESS }, 00145 { "r__", RPMNS_TYPE_ACCESS }, 00146 { "_WX", RPMNS_TYPE_ACCESS }, 00147 { "_Wx", RPMNS_TYPE_ACCESS }, 00148 { "_W_", RPMNS_TYPE_ACCESS }, 00149 { "_wX", RPMNS_TYPE_ACCESS }, 00150 { "_wx", RPMNS_TYPE_ACCESS }, 00151 { "_w_", RPMNS_TYPE_ACCESS }, 00152 { "__X", RPMNS_TYPE_ACCESS }, 00153 { "__x", RPMNS_TYPE_ACCESS }, 00154 { "___", RPMNS_TYPE_ACCESS }, 00155 { NULL, 0 } 00156 }; 00157 00158 nsType rpmnsProbe(const char * str) 00159 { 00160 const struct _rpmnsProbes_s * av; 00161 size_t sn = strlen(str); 00162 size_t nb; 00163 00164 if (sn >= 5 && str[sn-1] == ')') 00165 for (av = rpmnsProbes; av->NS != NULL; av++) { 00166 nb = strlen(av->NS); 00167 if (sn > nb && str[nb] == '(' && !strncmp(str, av->NS, nb)) 00168 return av->Type; 00169 } 00170 return RPMNS_TYPE_UNKNOWN; 00171 } 00172 00173 nsType rpmnsClassify(const char * str) 00174 { 00175 const char * s; 00176 nsType Type = RPMNS_TYPE_STRING; 00177 00178 if (*str == '!') 00179 str++; 00180 if (*str == '/') 00181 return RPMNS_TYPE_PATH; 00182 s = str + strlen(str); 00183 if (str[0] == '%' && str[1] == '{' && s[-1] == '}') 00184 return RPMNS_TYPE_FUNCTION; 00185 if ((s - str) > 3 && s[-3] == '.' && s[-2] == 's' && s[-1] == 'o') 00186 return RPMNS_TYPE_DSO; 00187 Type = rpmnsProbe(str); 00188 if (Type != RPMNS_TYPE_UNKNOWN) 00189 return Type; 00190 for (s = str; *s != '\0'; s++) { 00191 if (s[0] == '(' || s[strlen(s)-1] == ')') 00192 return RPMNS_TYPE_NAMESPACE; 00193 if (s[0] == '.' && s[1] == 's' && s[2] == 'o') 00194 return RPMNS_TYPE_DSO; 00195 if (s[0] == '.' && xisdigit((int)s[-1]) && xisdigit((int)s[1])) 00196 return RPMNS_TYPE_VERSION; 00197 if (_rpmns_N_at_A && _rpmns_N_at_A[0]) { 00198 if (s[0] == _rpmns_N_at_A[0] && rpmnsArch(s+1)) 00199 return RPMNS_TYPE_ARCH; 00200 } 00201 /*@-globstate@*/ 00202 if (s[0] == '.') 00203 return RPMNS_TYPE_COMPOUND; 00204 } 00205 return RPMNS_TYPE_STRING; 00206 /*@=globstate@*/ 00207 } 00208 00209 int rpmnsParse(const char * str, rpmns ns) 00210 { 00211 char *t; 00212 ns->str = t = rpmExpand(str, NULL); 00213 ns->Type = rpmnsClassify(ns->str); 00214 switch (ns->Type) { 00215 case RPMNS_TYPE_ARCH: 00216 ns->NS = NULL; 00217 ns->N = ns->str; 00218 if (ns->N[0] == '!') 00219 ns->N++; 00220 if ((t = strrchr(t, _rpmns_N_at_A[0])) != NULL) 00221 *t++ = '\0'; 00222 ns->A = t; 00223 break; 00224 case RPMNS_TYPE_RPMLIB: 00225 case RPMNS_TYPE_CPUINFO: 00226 case RPMNS_TYPE_GETCONF: 00227 case RPMNS_TYPE_UNAME: 00228 case RPMNS_TYPE_SONAME: 00229 case RPMNS_TYPE_ACCESS: 00230 case RPMNS_TYPE_USER: 00231 case RPMNS_TYPE_GROUP: 00232 case RPMNS_TYPE_MOUNTED: 00233 case RPMNS_TYPE_DISKSPACE: 00234 case RPMNS_TYPE_DIGEST: 00235 case RPMNS_TYPE_GNUPG: 00236 case RPMNS_TYPE_MACRO: 00237 case RPMNS_TYPE_ENVVAR: 00238 case RPMNS_TYPE_RUNNING: 00239 case RPMNS_TYPE_SANITY: 00240 case RPMNS_TYPE_VCHECK: 00241 case RPMNS_TYPE_SIGNATURE: 00242 case RPMNS_TYPE_VERIFY: 00243 ns->NS = ns->str; 00244 if (ns->NS[0] == '!') 00245 ns->NS++; 00246 if ((t = strchr(t, '(')) != NULL) { 00247 *t++ = '\0'; 00248 ns->N = t; 00249 t[strlen(t)-1] = '\0'; 00250 } else 00251 ns->N = NULL; 00252 ns->A = NULL; 00253 break; 00254 case RPMNS_TYPE_UNKNOWN: 00255 case RPMNS_TYPE_STRING: 00256 case RPMNS_TYPE_PATH: 00257 case RPMNS_TYPE_DSO: 00258 case RPMNS_TYPE_FUNCTION: 00259 case RPMNS_TYPE_VERSION: 00260 case RPMNS_TYPE_COMPOUND: 00261 case RPMNS_TYPE_NAMESPACE: 00262 case RPMNS_TYPE_TAG: 00263 case RPMNS_TYPE_CONFIG: 00264 default: 00265 ns->NS = NULL; 00266 ns->N = ns->str; 00267 if (ns->N[0] == '!') 00268 ns->N++; 00269 ns->A = NULL; 00270 break; 00271 } 00272 return 0; 00273 } 00274 00280 static inline unsigned char nibble(char c) 00281 /*@*/ 00282 { 00283 if (c >= '0' && c <= '9') 00284 return (unsigned char)(c - '0'); 00285 if (c >= 'A' && c <= 'F') 00286 return (unsigned char)((int)(c - 'A') + 10); 00287 if (c >= 'a' && c <= 'f') 00288 return (unsigned char)((int)(c - 'a') + 10); 00289 return '\0'; 00290 } 00291 00292 rpmRC rpmnsProbeSignature(void * _ts, const char * fn, const char * sigfn, 00293 const char * pubfn, const char * pubid, 00294 /*@unused@*/ int flags) 00295 { 00296 rpmts ts = _ts; 00297 pgpDig dig = rpmtsDig(ts); 00298 pgpDigParams sigp; 00299 pgpDigParams pubp; 00300 rpmuint8_t * sigpkt = NULL; 00301 size_t sigpktlen = 0; 00302 DIGEST_CTX ctx = NULL; 00303 int printing = 0; 00304 rpmRC rc = RPMRC_FAIL; /* assume failure */ 00305 int xx; 00306 00307 if (_rpmns_debug) 00308 fprintf(stderr, "==> check(%s, %s, %s, %s)\n", fn, 00309 (sigfn ? sigfn : "(null)"), 00310 (pubfn ? pubfn : "(null)"), 00311 (pubid ? pubid : "(null)")); 00312 00313 /* Load the signature. Use sigfn if specified, otherwise clearsign. */ 00314 if (sigfn && *sigfn) { 00315 const char * _sigfn = rpmExpand(sigfn, NULL); 00316 xx = pgpReadPkts(_sigfn, &sigpkt, &sigpktlen); 00317 if (xx != PGPARMOR_SIGNATURE) { 00318 if (_rpmns_debug) 00319 fprintf(stderr, "==> pgpReadPkts(%s) SIG %p[%u] ret %d\n", _sigfn, sigpkt, (unsigned)sigpktlen, xx); 00320 _sigfn = _free(_sigfn); 00321 goto exit; 00322 } 00323 _sigfn = _free(_sigfn); 00324 } else { 00325 const char * _sigfn = rpmExpand(fn, NULL); 00326 xx = pgpReadPkts(_sigfn, &sigpkt, &sigpktlen); 00327 if (xx != PGPARMOR_SIGNATURE) { 00328 if (_rpmns_debug) 00329 fprintf(stderr, "==> pgpReadPkts(%s) SIG %p[%u] ret %d\n", _sigfn, sigpkt, (unsigned)sigpktlen, xx); 00330 _sigfn = _free(_sigfn); 00331 goto exit; 00332 } 00333 _sigfn = _free(_sigfn); 00334 } 00335 xx = pgpPrtPkts((rpmuint8_t *)sigpkt, sigpktlen, dig, printing); 00336 if (xx) { 00337 if (_rpmns_debug) 00338 fprintf(stderr, "==> pgpPrtPkts SIG %p[%u] ret %d\n", sigpkt, (unsigned)sigpktlen, xx); 00339 goto exit; 00340 } 00341 00342 sigp = pgpGetSignature(dig); 00343 00344 if (sigp->version != (rpmuint8_t)3 && sigp->version != (rpmuint8_t)4) { 00345 if (_rpmns_debug) 00346 fprintf(stderr, "==> unverifiable V%u\n", (unsigned)sigp->version); 00347 goto exit; 00348 } 00349 00350 /* Load the pubkey. Use pubfn if specified, otherwise rpmdb keyring. */ 00351 if (pubfn && *pubfn) { 00352 const char * _pubfn = rpmExpand(pubfn, NULL); 00353 /*@-type@*/ 00354 xx = pgpReadPkts(_pubfn, &ts->pkpkt, &ts->pkpktlen); 00355 /*@=type@*/ 00356 if (xx != PGPARMOR_PUBKEY) { 00357 if (_rpmns_debug) 00358 fprintf(stderr, "==> pgpReadPkts(%s) PUB %p[%u] ret %d\n", _pubfn, ts->pkpkt, (unsigned int)ts->pkpktlen, xx); 00359 _pubfn = _free(_pubfn); 00360 goto exit; 00361 } 00362 _pubfn = _free(_pubfn); 00363 xx = pgpPrtPkts((rpmuint8_t *)ts->pkpkt, ts->pkpktlen, dig, printing); 00364 if (xx) { 00365 if (_rpmns_debug) 00366 fprintf(stderr, "==> pgpPrtPkts PUB %p[%u] ret %d\n", ts->pkpkt, (unsigned int)ts->pkpktlen, xx); 00367 goto exit; 00368 } 00369 } else { 00370 if ((rc = pgpFindPubkey(dig)) != RPMRC_OK) { 00371 if (_rpmns_debug) 00372 fprintf(stderr, "==> pgpFindPubkey ret %d\n", xx); 00373 goto exit; 00374 } 00375 } 00376 00377 pubp = pgpGetPubkey(dig); 00378 00379 /* Is this the requested pubkey? */ 00380 if (pubid && *pubid) { 00381 size_t ns = strlen(pubid); 00382 const char * s; 00383 char * t; 00384 size_t i; 00385 00386 /* At least 8 hex digits please. */ 00387 for (i = 0, s = pubid; *s && isxdigit(*s); s++, i++) 00388 {}; 00389 if (!(*s == '\0' && i > 8 && (i%2) == 0)) 00390 goto exit; 00391 00392 /* Truncate to key id size. */ 00393 s = pubid; 00394 if (ns > 16) { 00395 s += (ns - 16); 00396 ns = 16; 00397 } 00398 ns >>= 1; 00399 t = memset(alloca(ns), 0, ns); 00400 for (i = 0; i < ns; i++) 00401 t[i] = (char)((nibble(s[2*i]) << 4) | nibble(s[2*i+1])); 00402 00403 /* Compare the pubkey id. */ 00404 s = (const char *)pubp->signid; 00405 xx = memcmp(t, s + (8 - ns), ns); 00406 00407 /* XXX HACK: V4 RSA key id's are wonky atm. */ 00408 if (pubp->pubkey_algo == (rpmuint8_t)PGPPUBKEYALGO_RSA) 00409 xx = 0; 00410 00411 if (xx) { 00412 if (_rpmns_debug) 00413 fprintf(stderr, "==> mismatched: pubkey id (%08x %08x) != %s\n", 00414 pgpGrab(pubp->signid, 4), pgpGrab(pubp->signid+4, 4), pubid); 00415 goto exit; 00416 } 00417 } 00418 00419 /* Do the parameters match the signature? */ 00420 if (!(sigp->pubkey_algo == pubp->pubkey_algo 00421 #ifdef NOTYET 00422 && sigp->hash_algo == pubp->hash_algo 00423 #endif 00424 /* XXX HACK: V4 RSA key id's are wonky atm. */ 00425 && (pubp->pubkey_algo == (rpmuint8_t)PGPPUBKEYALGO_RSA || !memcmp(sigp->signid, pubp->signid, sizeof(sigp->signid))) ) ) { 00426 if (_rpmns_debug) { 00427 fprintf(stderr, "==> mismatch between signature and pubkey\n"); 00428 fprintf(stderr, "\tpubkey_algo: %u %u\n", (unsigned)sigp->pubkey_algo, (unsigned)pubp->pubkey_algo); 00429 fprintf(stderr, "\tsignid: %08X %08X %08X %08X\n", 00430 pgpGrab(sigp->signid, 4), pgpGrab(sigp->signid+4, 4), 00431 pgpGrab(pubp->signid, 4), pgpGrab(pubp->signid+4, 4)); 00432 } 00433 goto exit; 00434 } 00435 00436 /* Compute the message digest. */ 00437 ctx = rpmDigestInit((pgpHashAlgo)sigp->hash_algo, RPMDIGEST_NONE); 00438 00439 { 00440 static const char clrtxt[] = "-----BEGIN PGP SIGNED MESSAGE-----"; 00441 static const char sigtxt[] = "-----BEGIN PGP SIGNATURE-----"; 00442 const char * _fn = rpmExpand(fn, NULL); 00443 rpmiob iob = NULL; 00444 int _rc = rpmiobSlurp(_fn, &iob); 00445 00446 if (!(_rc == 0 && iob != NULL)) { 00447 if (_rpmns_debug) 00448 fprintf(stderr, "==> rpmiobSlurp(%s) MSG ret %d\n", _fn, _rc); 00449 iob = rpmiobFree(iob); 00450 _fn = _free(_fn); 00451 goto exit; 00452 } 00453 _fn = _free(_fn); 00454 00455 /* XXX clearsign sig is PGPSIGTYPE_TEXT not PGPSIGTYPE_BINARY. */ 00456 if (!strncmp((char *)iob->b, clrtxt, strlen(clrtxt))) { 00457 const char * be = (char *) (iob->b + iob->blen); 00458 const char * t; 00459 00460 /* Skip to '\n\n' start-of-plaintext */ 00461 t = (char *) iob->b; 00462 while (t && t < be && *t != '\n') 00463 t = strchr(t, '\n') + 1; 00464 if (!(t && t < be)) 00465 goto exit; 00466 t++; 00467 00468 /* Clearsign digest rtrims " \t\r\n", inserts "\r\n" inter-lines. */ 00469 while (t < be) { 00470 const char * teol; 00471 const char * te; 00472 if (strncmp(t, "- ", 2) == 0) 00473 t += 2; 00474 if ((teol = te = strchr(t, '\n')) == NULL) 00475 break; 00476 while (te > t && strchr(" \t\r\n", te[-1])) 00477 te--; 00478 xx = rpmDigestUpdate(ctx, t, (te - t)); 00479 if (!strncmp((t = teol + 1), sigtxt, strlen(sigtxt))) 00480 break; 00481 xx = rpmDigestUpdate(ctx, "\r\n", sizeof("\r\n")-1); 00482 } 00483 } else 00484 xx = rpmDigestUpdate(ctx, iob->b, iob->blen); 00485 00486 iob = rpmiobFree(iob); 00487 } 00488 00489 if (sigp->hash != NULL) 00490 xx = rpmDigestUpdate(ctx, sigp->hash, sigp->hashlen); 00491 if (sigp->version == (rpmuint8_t)4) { 00492 rpmuint32_t nb = (rpmuint32_t)sigp->hashlen; 00493 rpmuint8_t trailer[6]; 00494 nb = (rpmuint32_t)htonl(nb); 00495 trailer[0] = sigp->version; 00496 trailer[1] = (rpmuint8_t)0xff; 00497 memcpy(trailer+2, &nb, sizeof(nb)); 00498 xx = rpmDigestUpdate(ctx, trailer, sizeof(trailer)); 00499 } 00500 00501 /* Load the message digest. */ 00502 switch(sigp->pubkey_algo) { 00503 default: 00504 rc = RPMRC_FAIL; 00505 break; 00506 case PGPPUBKEYALGO_DSA: 00507 rc = (pgpImplSetDSA(ctx, dig, sigp) ? RPMRC_FAIL : RPMRC_OK); 00508 break; 00509 case PGPPUBKEYALGO_RSA: 00510 rc = (pgpImplSetRSA(ctx, dig, sigp) ? RPMRC_FAIL : RPMRC_OK); 00511 break; 00512 } 00513 if (rc != RPMRC_OK) { 00514 if (_rpmns_debug) 00515 fprintf(stderr, "==> can't load pubkey_algo(%u)\n", (unsigned)sigp->pubkey_algo); 00516 goto exit; 00517 } 00518 00519 /* Verify the signature. */ 00520 switch(sigp->pubkey_algo) { 00521 default: 00522 rc = RPMRC_FAIL; 00523 break; 00524 case PGPPUBKEYALGO_DSA: 00525 rc = (pgpImplVerifyDSA(dig) ? RPMRC_OK : RPMRC_FAIL); 00526 break; 00527 case PGPPUBKEYALGO_RSA: 00528 rc = (pgpImplVerifyRSA(dig) ? RPMRC_OK : RPMRC_FAIL); 00529 break; 00530 } 00531 00532 exit: 00533 sigpkt = _free(sigpkt); 00534 ts->pkpkt = _free(ts->pkpkt); 00535 ts->pkpktlen = 0; 00536 /*@-nullstate@*/ 00537 rpmtsCleanDig(ts); 00538 /*@=nullstate@*/ 00539 00540 if (_rpmns_debug) 00541 fprintf(stderr, "============================ verify: %s\n", 00542 (rc == RPMRC_OK ? "OK" : 00543 (rc == RPMRC_NOKEY ? "NOKEY" : 00544 "FAIL"))); 00545 00546 return rc; 00547 }