• Main Page
  • Related Pages
  • Modules
  • Data Structures
  • Files
  • File List
  • Globals

lib/rpmns.c

Go to the documentation of this file.
00001 
00004 #include "system.h"
00005 
00006 #include <rpmio_internal.h>     /* XXX rpmioSlurp */
00007 #include <rpmmacro.h>
00008 
00009 #define _RPMPGP_INTERNAL
00010 #include <rpmpgp.h>
00011 
00012 #include <rpmlib.h>             /* XXX RPMRC_OK */
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         /* XXX ts->pkpkt */
00022 #include <rpmts.h>
00023 
00024 #include "debug.h"
00025 
00026 /*@unchecked@*/
00027 int _rpmns_debug = 0;
00028 
00029 /*@unchecked@*/ /*@observer@*/ /*@relnull@*/
00030 const char *_rpmns_N_at_A = ".";
00031 
00032 /*@-nullassign@*/
00033 /*@unchecked@*/ /*@observer@*/
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 /*@=nullassign@*/
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 /*@unchecked@*/ /*@observer@*/
00071 static struct _rpmnsProbes_s {
00072 /*@observer@*/ /*@relnull@*/
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 /*@-globstate@*/
00171         if (s[0] == '.')
00172             return RPMNS_TYPE_COMPOUND;
00173     }
00174     return RPMNS_TYPE_STRING;
00175 /*@=globstate@*/
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;      /* assume failure */
00271     int xx;
00272 
00273 if (_rpmns_debug)
00274 fprintf(stderr, "==> check(%s, %s, %s, %s)\n", fn, sigfn, pubfn, pubid);
00275 
00276     /* Load the signature. Use sigfn if specified, otherwise clearsign. */
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     /* Load the pubkey. Use pubfn if specified, otherwise rpmdb keyring. */
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     /* Is this the requested pubkey? */
00341     if (pubid && *pubid) {
00342         size_t ns = strlen(pubid);
00343         const char * s;
00344         char * t;
00345         int i;
00346 
00347         /* At least 8 hex digits please. */
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         /* Truncate to key id size. */
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         /* Compare the pubkey id. */
00365         s = (const char *)pubp->signid;
00366         xx = memcmp(t, s + (8 - ns), ns);
00367 
00368         /* XXX HACK: V4 RSA key id's are wonky atm. */
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     /* Do the parameters match the signature? */
00381     if (!(sigp->pubkey_algo == pubp->pubkey_algo
00382 #ifdef  NOTYET
00383      && sigp->hash_algo == pubp->hash_algo
00384 #endif
00385     /* XXX HACK: V4 RSA key id's are wonky atm. */
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     /* Compute the message digest. */
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         /* XXX clearsign sig is PGPSIGTYPE_TEXT not PGPSIGTYPE_BINARY. */
00418         if (!strncmp((char *)b, clrtxt, strlen(clrtxt))) {
00419             const char * be = (char *) (b + blen);
00420             const char * t;
00421 
00422             /* Skip to '\n\n' start-of-plaintext */
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             /* Clearsign digest rtrims " \t\r\n", inserts "\r\n" inter-lines. */
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     /* Load the message digest. */
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     /* Verify the signature. */
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 }

Generated on Mon Nov 29 2010 05:18:44 for rpm by  doxygen 1.7.2