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