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

rpmdb/rpmns.c

Go to the documentation of this file.
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 }

Generated on Fri Dec 3 2010 20:54:11 for rpm by  doxygen 1.7.2