From 83145da7966e63a78a5065ec2c186d182488e494 Mon Sep 17 00:00:00 2001 From: Michael Schroeder Date: Mon, 15 Apr 2013 17:57:43 +0200 Subject: [PATCH] split ugly pubkey handling into separate repo_rpmdb_pubkey.c --- bindings/solv.i | 11 + examples/solv.c | 3 + ext/CMakeLists.txt | 7 + ext/libsolvext.ver | 1 + ext/repo_rpmdb.c | 665 ++---------------------------------------- ext/repo_rpmdb.h | 3 +- ext/repo_rpmdb_pubkey.c | 755 ++++++++++++++++++++++++++++++++++++++++++++++++ ext/repo_rpmdb_pubkey.h | 11 + tools/rpmdb2solv.c | 24 +- 9 files changed, 835 insertions(+), 645 deletions(-) create mode 100644 ext/repo_rpmdb_pubkey.c create mode 100644 ext/repo_rpmdb_pubkey.h diff --git a/bindings/solv.i b/bindings/solv.i index 17ec7e6..7901a5b 100644 --- a/bindings/solv.i +++ b/bindings/solv.i @@ -419,6 +419,9 @@ typedef int bool; #ifdef ENABLE_RPMDB #include "repo_rpmdb.h" #endif +#ifdef ENABLE_RPMDB_PUBKEYS +#include "repo_rpmdb_pubkey.h" +#endif #ifdef ENABLE_DEBIAN #include "repo_deb.h" #endif @@ -1425,6 +1428,14 @@ rb_eval_string( return repo_add_rpm($self, name, flags); } #endif +#ifdef ENABLE_RPMDB_PUBKEYS + bool add_rpmdb_pubkeys(int flags = 0) { + return repo_add_rpmdb_pubkeys($self, flags); + } + Id add_pubkey(const char *key, int flags = 0) { + return repo_add_pubkey($self, key, flags); + } +#endif #ifdef ENABLE_RPMMD bool add_rpmmd(FILE *fp, const char *language, int flags = 0) { return repo_add_rpmmd($self, fp, language, flags); diff --git a/examples/solv.c b/examples/solv.c index 1fa1dc1..fbe7788 100644 --- a/examples/solv.c +++ b/examples/solv.c @@ -64,6 +64,9 @@ #include "repo_rpmdb.h" #include "pool_fileconflicts.h" #endif +#ifdef ENABLE_RPMDB_PUBKEY +#include "repo_rpmdb_pubkey.h" +#endif #ifdef ENABLE_DEBIAN #include "repo_deb.h" #endif diff --git a/ext/CMakeLists.txt b/ext/CMakeLists.txt index 025c3dc..bcd4f81 100644 --- a/ext/CMakeLists.txt +++ b/ext/CMakeLists.txt @@ -11,6 +11,13 @@ IF (ENABLE_RPMDB) pool_fileconflicts.h repo_rpmdb.h) ENDIF (ENABLE_RPMDB) +IF (ENABLE_RPMDB_PUBKEY) + SET (libsolvext_SRCS ${libsolvext_SRCS} + repo_rpmdb_pubkey.c) + SET (libsolvext_HEADERS ${libsolvext_SRCS} + repo_rpmdb_pubkey.h) +ENDIF (ENABLE_RPMDB_PUBKEY) + IF (ENABLE_RPMMD) SET (libsolvext_SRCS ${libsolvext_SRCS} repo_repomdxml.c repo_rpmmd.c diff --git a/ext/libsolvext.ver b/ext/libsolvext.ver index 953aadf..9817339 100644 --- a/ext/libsolvext.ver +++ b/ext/libsolvext.ver @@ -33,6 +33,7 @@ SOLV_1.0 { rpm_installedrpmdbids; rpm_iterate_filelist; rpm_query; + rpm_query_num; rpm_state_create; rpm_state_free; solv_xfopen; diff --git a/ext/repo_rpmdb.c b/ext/repo_rpmdb.c index 4df5774..e84b8ec 100644 --- a/ext/repo_rpmdb.c +++ b/ext/repo_rpmdb.c @@ -2385,6 +2385,14 @@ rpm_query(void *rpmhandle, Id what) name = headstring(rpmhead, TAG_NAME); r = solv_strdup(name); break; + case SOLVABLE_SUMMARY: + name = headstring(rpmhead, TAG_SUMMARY); + r = solv_strdup(name); + break; + case SOLVABLE_DESCRIPTION: + name = headstring(rpmhead, TAG_DESCRIPTION); + r = solv_strdup(name); + break; case SOLVABLE_EVR: r = headtoevr(rpmhead); break; @@ -2392,6 +2400,21 @@ rpm_query(void *rpmhandle, Id what) return r; } +unsigned long long +rpm_query_num(void *rpmhandle, Id what, unsigned long long notfound) +{ + RpmHead *rpmhead = rpmhandle; + unsigned int u32; + + switch (what) + { + case SOLVABLE_INSTALLTIME: + u32 = headint32(rpmhead, TAG_INSTALLTIME); + return u32 ? u32 : notfound; + } + return notfound; +} + int rpm_installedrpmdbids(void *rpmstate, const char *index, const char *match, Queue *rpmdbidq) { @@ -2541,645 +2564,3 @@ rpm_byrpmh(void *rpmstate, Header h) #endif - -#ifdef ENABLE_RPMDB_PUBKEY - -static char * -r64dec1(char *p, unsigned int *vp, int *eofp) -{ - int i, x; - unsigned int v = 0; - - for (i = 0; i < 4; ) - { - x = *p++; - if (!x) - return 0; - if (x >= 'A' && x <= 'Z') - x -= 'A'; - else if (x >= 'a' && x <= 'z') - x -= 'a' - 26; - else if (x >= '0' && x <= '9') - x -= '0' - 52; - else if (x == '+') - x = 62; - else if (x == '/') - x = 63; - else if (x == '=') - { - x = 0; - if (i == 0) - { - *eofp = 3; - *vp = 0; - return p - 1; - } - *eofp += 1; - } - else - continue; - v = v << 6 | x; - i++; - } - *vp = v; - return p; -} - -static unsigned int -crc24(unsigned char *p, int len) -{ - unsigned int crc = 0xb704ceL; - int i; - - while (len--) - { - crc ^= (*p++) << 16; - for (i = 0; i < 8; i++) - if ((crc <<= 1) & 0x1000000) - crc ^= 0x1864cfbL; - } - return crc & 0xffffffL; -} - -static unsigned char * -unarmor(char *pubkey, int *pktlp) -{ - char *p; - int l, eof; - unsigned char *buf, *bp; - unsigned int v; - - *pktlp = 0; - while (strncmp(pubkey, "-----BEGIN PGP PUBLIC KEY BLOCK-----", 36) != 0) - { - pubkey = strchr(pubkey, '\n'); - if (!pubkey) - return 0; - pubkey++; - } - pubkey = strchr(pubkey, '\n'); - if (!pubkey++) - return 0; - /* skip header lines */ - for (;;) - { - while (*pubkey == ' ' || *pubkey == '\t') - pubkey++; - if (*pubkey == '\n') - break; - pubkey = strchr(pubkey, '\n'); - if (!pubkey++) - return 0; - } - pubkey++; - p = strchr(pubkey, '='); - if (!p) - return 0; - l = p - pubkey; - bp = buf = solv_malloc(l * 3 / 4 + 4); - eof = 0; - while (!eof) - { - pubkey = r64dec1(pubkey, &v, &eof); - if (!pubkey) - { - solv_free(buf); - return 0; - } - *bp++ = v >> 16; - *bp++ = v >> 8; - *bp++ = v; - } - while (*pubkey == ' ' || *pubkey == '\t' || *pubkey == '\n' || *pubkey == '\r') - pubkey++; - bp -= eof; - if (*pubkey != '=' || (pubkey = r64dec1(pubkey + 1, &v, &eof)) == 0) - { - solv_free(buf); - return 0; - } - if (v != crc24(buf, bp - buf)) - { - solv_free(buf); - return 0; - } - while (*pubkey == ' ' || *pubkey == '\t' || *pubkey == '\n' || *pubkey == '\r') - pubkey++; - if (strncmp(pubkey, "-----END PGP PUBLIC KEY BLOCK-----", 34) != 0) - { - solv_free(buf); - return 0; - } - *pktlp = bp - buf; - return buf; -} - -static void -parsekeydata(Solvable *s, Repodata *data, unsigned char *p, int pl) -{ - int x, tag, l; - unsigned char keyid[8]; - unsigned int kcr = 0, maxex = 0; - unsigned char *pubkey = 0; - unsigned char *userid = 0; -#if 0 - int pubkeyl = 0; - int useridl = 0; -#endif - - for (; pl; p += l, pl -= l) - { - x = *p++; - pl--; - if (!(x & 128) || pl <= 0) - return; - if ((x & 64) == 0) - { - /* old format */ - tag = (x & 0x3c) >> 2; - x &= 3; - if (x == 3) - return; - l = 1 << x; - if (pl < l) - return; - x = 0; - while (l--) - { - x = x << 8 | *p++; - pl--; - } - l = x; - } - else - { - tag = (x & 0x3f); - x = *p++; - pl--; - if (x < 192) - l = x; - else if (x >= 192 && x < 224) - { - if (pl <= 0) - return; - l = ((x - 192) << 8) + *p++ + 192; - pl--; - } - else if (x == 255) - { - /* sanity: p[0] must be zero */ - if (pl <= 4 || p[0] != 0) - return; - l = p[1] << 16 | p[2] << 8 | p[3]; - p += 4; - pl -= 4; - } - else - return; - } - if (pl < l) - return; - if (tag == 6) - { - pubkey = solv_realloc(pubkey, l); - if (l) - memcpy(pubkey, p, l); -#if 0 - pubkeyl = l; -#endif - kcr = 0; - if (p[0] == 3) - { - unsigned int ex; - void *h; - kcr = p[1] << 24 | p[2] << 16 | p[3] << 8 | p[4]; - ex = 0; - if (p[5] || p[6]) - { - ex = kcr + 24*3600 * (p[5] << 8 | p[6]); - if (ex > maxex) - maxex = ex; - } - memset(keyid, 0, 8); - if (p[7] == 1) /* RSA */ - { - int i, ql; - unsigned char fp[16]; - char fpx[32 + 1]; - unsigned char *q; - - ql = ((p[8] << 8 | p[9]) + 7) / 8; - memcpy(keyid, p + 10 + ql - 8, 8); - h = solv_chksum_create(REPOKEY_TYPE_MD5); - solv_chksum_add(h, p + 10, ql); - q = p + 10 + ql; - ql = ((q[0] << 8 | q[1]) + 7) / 8; - solv_chksum_add(h, q + 2, ql); - solv_chksum_free(h, fp); - for (i = 0; i < 16; i++) - sprintf(fpx + i * 2, "%02x", fp[i]); - repodata_set_str(data, s - s->repo->pool->solvables, PUBKEY_FINGERPRINT, fpx); - } - } - else if (p[0] == 4) - { - int i; - void *h; - unsigned char hdr[3]; - unsigned char fp[20]; - char fpx[40 + 1]; - - kcr = p[1] << 24 | p[2] << 16 | p[3] << 8 | p[4]; - hdr[0] = 0x99; - hdr[1] = l >> 8; - hdr[2] = l; - h = solv_chksum_create(REPOKEY_TYPE_SHA1); - solv_chksum_add(h, hdr, 3); - solv_chksum_add(h, p, l); - solv_chksum_free(h, fp); - for (i = 0; i < 20; i++) - sprintf(fpx + i * 2, "%02x", fp[i]); - repodata_set_str(data, s - s->repo->pool->solvables, PUBKEY_FINGERPRINT, fpx); - memcpy(keyid, fp + 12, 8); - } - } - if (tag == 2) - { - if (p[0] == 3 && p[1] == 5) - { -#if 0 - Id htype = 0; -#endif - /* printf("V3 signature packet\n"); */ - if (l < 17) - continue; - if (p[2] != 0x10 && p[2] != 0x11 && p[2] != 0x12 && p[2] != 0x13 && p[2] != 0x1f) - continue; - if (!memcmp(keyid, p + 6, 8)) - { - /* printf("SELF SIG\n"); */ - } - else - { - /* printf("OTHER SIG\n"); */ - } -#if 0 - if (p[16] == 1) - htype = REPOKEY_TYPE_MD5; - else if (p[16] == 2) - htype = REPOKEY_TYPE_SHA1; - else if (p[16] == 8) - htype = REPOKEY_TYPE_SHA256; - if (htype) - { - void *h = solv_chksum_create(htype); - unsigned char b[3], *cs; - - b[0] = 0x99; - b[1] = pubkeyl >> 8; - b[2] = pubkeyl; - solv_chksum_add(h, b, 3); - solv_chksum_add(h, pubkey, pubkeyl); - if (p[2] >= 0x10 && p[2] <= 0x13) - solv_chksum_add(h, userid, useridl); - solv_chksum_add(h, p + 2, 5); - cs = solv_chksum_get(h, 0); - solv_chksum_free(h, 0); - } -#endif - } - if (p[0] == 4) - { - int j, ql, haveissuer; - unsigned char *q; - unsigned int ex = 0; -#if 0 - unsigned int scr = 0; -#endif - unsigned char issuer[8]; - - /* printf("V4 signature packet\n"); */ - if (l < 6) - continue; - if (p[1] != 0x10 && p[1] != 0x11 && p[1] != 0x12 && p[1] != 0x13 && p[1] != 0x1f) - continue; - haveissuer = 0; - ex = 0; - q = p + 4; - for (j = 0; q && j < 2; j++) - { - if (q + 2 > p + l) - { - q = 0; - break; - } - ql = q[0] << 8 | q[1]; - q += 2; - if (q + ql > p + l) - { - q = 0; - break; - } - while (ql) - { - int sl; - x = *q++; - ql--; - if (x < 192) - sl = x; - else if (x == 255) - { - if (ql < 4 || q[0] != 0) - { - q = 0; - break; - } - sl = q[1] << 16 | q[2] << 8 | q[3]; - q += 4; - ql -= 4; - } - else - { - if (ql < 1) - { - q = 0; - break; - } - sl = ((x - 192) << 8) + *q++ + 192; - ql--; - } - if (ql < sl) - { - q = 0; - break; - } - x = q[0] & 127; - /* printf("%d SIGSUB %d %d\n", j, x, sl); */ - if (x == 16 && sl == 9 && !haveissuer) - { - memcpy(issuer, q + 1, 8); - haveissuer = 1; - } -#if 0 - if (x == 2 && j == 0) - scr = q[1] << 24 | q[2] << 16 | q[3] << 8 | q[4]; -#endif - if (x == 9 && j == 0) - ex = q[1] << 24 | q[2] << 16 | q[3] << 8 | q[4]; - q += sl; - ql -= sl; - } - } - if (ex) - ex += kcr; - if (haveissuer) - { -#if 0 - Id htype = 0; - if (p[3] == 1) - htype = REPOKEY_TYPE_MD5; - else if (p[3] == 2) - htype = REPOKEY_TYPE_SHA1; - else if (p[3] == 8) - htype = REPOKEY_TYPE_SHA256; - if (htype && pubkeyl) - { - void *h = solv_chksum_create(htype); - unsigned char b[6], *cs; - unsigned int hl; - - b[0] = 0x99; - b[1] = pubkeyl >> 8; - b[2] = pubkeyl; - solv_chksum_add(h, b, 3); - solv_chksum_add(h, pubkey, pubkeyl); - if (p[1] >= 0x10 && p[1] <= 0x13) - { - b[0] = 0xb4; - b[1] = useridl >> 24; - b[2] = useridl >> 16; - b[3] = useridl >> 8; - b[4] = useridl; - solv_chksum_add(h, b, 5); - solv_chksum_add(h, userid, useridl); - } - hl = 6 + (p[4] << 8 | p[5]); - solv_chksum_add(h, p, hl); - b[0] = 4; - b[1] = 0xff; - b[2] = hl >> 24; - b[3] = hl >> 16; - b[4] = hl >> 8; - b[5] = hl; - solv_chksum_add(h, b, 6); - cs = solv_chksum_get(h, 0); - solv_chksum_free(h, 0); - } -#endif - if (!memcmp(keyid, issuer, 8)) - { - /* printf("SELF SIG cr %d ex %d\n", cr, ex); */ - if (ex > maxex) - maxex = ex; - } - else - { - /* printf("OTHER SIG cr %d ex %d\n", cr, ex); */ - } - } - } - } - if (tag == 13) - { - userid = solv_realloc(userid, l); - if (l) - memcpy(userid, p, l); -#if 0 - useridl = l; -#endif - } - } - if (maxex) - repodata_set_num(data, s - s->repo->pool->solvables, PUBKEY_EXPIRES, maxex); - solv_free(pubkey); - solv_free(userid); -} - -/* this is private to rpm, but rpm lacks an interface to retrieve - * the values. Sigh. */ -struct pgpDigParams_s { - const char * userid; - const unsigned char * hash; -#ifndef HAVE_PGPDIGGETPARAMS - const char * params[4]; -#endif - unsigned char tag; - unsigned char version; /*!< version number. */ - unsigned char time[4]; /*!< time that the key was created. */ - unsigned char pubkey_algo; /*!< public key algorithm. */ - unsigned char hash_algo; - unsigned char sigtype; - unsigned char hashlen; - unsigned char signhash16[2]; - unsigned char signid[8]; - unsigned char saved; -}; - -#ifndef HAVE_PGPDIGGETPARAMS -struct pgpDig_s { - struct pgpDigParams_s signature; - struct pgpDigParams_s pubkey; -}; -#endif - -static int -pubkey2solvable(Solvable *s, Repodata *data, char *pubkey) -{ - Pool *pool = s->repo->pool; - unsigned char *pkts; - unsigned int btime; - int pktsl, i; - pgpDig dig = 0; - char keyid[16 + 1]; - char evrbuf[8 + 1 + 8 + 1]; - struct pgpDigParams_s *digpubkey; - - pkts = unarmor(pubkey, &pktsl); - if (!pkts) - return 0; - setutf8string(data, s - s->repo->pool->solvables, SOLVABLE_DESCRIPTION, pubkey); - parsekeydata(s, data, pkts, pktsl); - /* only rpm knows how to do the release calculation, we don't dare - * to recreate all the bugs */ -#ifndef RPM5 - dig = pgpNewDig(); -#else - dig = pgpDigNew(RPMVSF_DEFAULT, 0); -#endif - (void) pgpPrtPkts(pkts, pktsl, dig, 0); - -#ifdef HAVE_PGPDIGGETPARAMS - digpubkey = pgpDigGetParams(dig, PGPTAG_PUBLIC_KEY); -#else - digpubkey = &dig->pubkey; -#endif - btime = digpubkey->time[0] << 24 | digpubkey->time[1] << 16 | digpubkey->time[2] << 8 | digpubkey->signid[3]; - sprintf(evrbuf, "%02x%02x%02x%02x-%02x%02x%02x%02x", digpubkey->signid[4], digpubkey->signid[5], digpubkey->signid[6], digpubkey->signid[7], digpubkey->time[0], digpubkey->time[1], digpubkey->time[2], digpubkey->time[3]); - - repodata_set_num(data, s - s->repo->pool->solvables, SOLVABLE_BUILDTIME, btime); - - s->name = pool_str2id(pool, "gpg-pubkey", 1); - s->evr = pool_str2id(pool, evrbuf, 1); - s->arch = 1; - for (i = 0; i < 8; i++) - sprintf(keyid + 2 * i, "%02x", digpubkey->signid[i]); - repodata_set_str(data, s - s->repo->pool->solvables, PUBKEY_KEYID, keyid); - if (digpubkey->userid) - setutf8string(data, s - s->repo->pool->solvables, SOLVABLE_SUMMARY, digpubkey->userid); -#ifndef RPM5 - (void)pgpFreeDig(dig); -#else - (void)pgpDigFree(dig); -#endif - solv_free((void *)pkts); - return 1; -} - -int -repo_add_rpmdb_pubkeys(Repo *repo, int flags) -{ - Pool *pool = repo->pool; - struct rpmdbstate state; - struct rpmdbentry *entries; - int nentries, i; - char *str; - unsigned int u32; - Repodata *data; - Solvable *s; - const char *rootdir = 0; - - data = repo_add_repodata(repo, flags); - if (flags & REPO_USE_ROOTDIR) - rootdir = pool_get_rootdir(pool); - - memset(&state, 0, sizeof(state)); - state.pool = pool; - if (!opendbenv(&state, rootdir)) - return 0; - entries = getinstalledrpmdbids(&state, "Name", "gpg-pubkey", &nentries, 0); - for (i = 0 ; i < nentries; i++) - { - RpmHead *rpmhead = rpm_byrpmdbid(&state, entries[i].rpmdbid); - if (!rpmhead) - continue; - str = headstring(rpmhead, TAG_DESCRIPTION); - if (!str) - continue; - s = pool_id2solvable(pool, repo_add_solvable(repo)); - pubkey2solvable(s, data, str); - u32 = headint32(rpmhead, TAG_INSTALLTIME); - if (u32) - repodata_set_num(data, s - pool->solvables, SOLVABLE_INSTALLTIME, u32); - if (!repo->rpmdbid) - repo->rpmdbid = repo_sidedata_create(repo, sizeof(Id)); - repo->rpmdbid[s - pool->solvables - repo->start] = entries[i].rpmdbid; - } - solv_free(entries); - freestate(&state); - if (!(flags & REPO_NO_INTERNALIZE)) - repodata_internalize(data); - return 0; -} - -Id -repo_add_pubkey(Repo *repo, const char *key, int flags) -{ - Pool *pool = repo->pool; - Repodata *data; - Solvable *s; - char *buf; - int bufl, l, ll; - FILE *fp; - - data = repo_add_repodata(repo, flags); - buf = 0; - bufl = 0; - if ((fp = fopen(flags & REPO_USE_ROOTDIR ? pool_prepend_rootdir_tmp(pool, key) : key, "r")) == 0) - { - pool_error(pool, -1, "%s: %s", key, strerror(errno)); - return 0; - } - for (l = 0; ;) - { - if (bufl - l < 4096) - { - bufl += 4096; - buf = solv_realloc(buf, bufl); - } - ll = fread(buf, 1, bufl - l, fp); - if (ll < 0) - { - fclose(fp); - pool_error(pool, -1, "%s: %s", key, strerror(errno)); - return 0; - } - if (ll == 0) - break; - l += ll; - } - buf[l] = 0; - fclose(fp); - s = pool_id2solvable(pool, repo_add_solvable(repo)); - if (!pubkey2solvable(s, data, buf)) - { - repo_free_solvable(repo, s - pool->solvables, 1); - solv_free(buf); - return 0; - } - solv_free(buf); - if (!(flags & REPO_NO_INTERNALIZE)) - repodata_internalize(data); - return s - pool->solvables; -} - -#endif /* ENABLE_RPMDB_PUBKEY */ diff --git a/ext/repo_rpmdb.h b/ext/repo_rpmdb.h index 117da42..a0d8a81 100644 --- a/ext/repo_rpmdb.h +++ b/ext/repo_rpmdb.h @@ -12,8 +12,6 @@ struct headerToken_s; extern int repo_add_rpmdb(Repo *repo, Repo *ref, int flags); extern Id repo_add_rpm(Repo *repo, const char *rpm, int flags); -extern int repo_add_rpmdb_pubkeys(Repo *repo, int flags); -extern Id repo_add_pubkey(Repo *repo, const char *key, int flags); #define RPMDB_REPORT_PROGRESS (1 << 8) #define RPM_ADD_WITH_PKGID (1 << 9) @@ -54,5 +52,6 @@ struct filelistinfo { }; extern char *rpm_query(void *rpmhandle, Id what); +extern unsigned long long rpm_query_num(void *rpmhandle, Id what, unsigned long long notfound); extern void rpm_iterate_filelist(void *rpmhandle, int flags, void (*cb)(void *, const char *, struct filelistinfo *), void *cbdata); extern Id repo_add_rpm_handle(Repo *repo, void *rpmhandle, int flags); diff --git a/ext/repo_rpmdb_pubkey.c b/ext/repo_rpmdb_pubkey.c new file mode 100644 index 0000000..4920650 --- /dev/null +++ b/ext/repo_rpmdb_pubkey.c @@ -0,0 +1,755 @@ +/* + * Copyright (c) 2007-2013, Novell Inc. + * + * This program is licensed under the BSD license, read LICENSE.BSD + * for further information + */ + +/* + * repo_rpmdb_pubkey + * + * support for pubkeys stored in the rpmdb database + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#ifndef RPM5 +#include +#endif +#include + +#include "pool.h" +#include "repo.h" +#include "hash.h" +#include "util.h" +#include "queue.h" +#include "chksum.h" +#include "repo_rpmdb.h" + +/* FIXME: dedup with repo_rpmdb.c */ +static void +setutf8string(Repodata *repodata, Id handle, Id tag, const char *str) +{ + const unsigned char *cp; + int state = 0; + int c; + unsigned char *buf = 0, *bp; + + /* check if it's already utf8, code taken from screen ;-) */ + cp = (const unsigned char *)str; + while ((c = *cp++) != 0) + { + if (state) + { + if ((c & 0xc0) != 0x80) + break; /* encoding error */ + c = (c & 0x3f) | (state << 6); + if (!(state & 0x40000000)) + { + /* check for overlong sequences */ + if ((c & 0x820823e0) == 0x80000000) + c = 0xfdffffff; + else if ((c & 0x020821f0) == 0x02000000) + c = 0xfff7ffff; + else if ((c & 0x000820f8) == 0x00080000) + c = 0xffffd000; + else if ((c & 0x0000207c) == 0x00002000) + c = 0xffffff70; + } + } + else + { + /* new sequence */ + if (c >= 0xfe) + break; + else if (c >= 0xfc) + c = (c & 0x01) | 0xbffffffc; /* 5 bytes to follow */ + else if (c >= 0xf8) + c = (c & 0x03) | 0xbfffff00; /* 4 */ + else if (c >= 0xf0) + c = (c & 0x07) | 0xbfffc000; /* 3 */ + else if (c >= 0xe0) + c = (c & 0x0f) | 0xbff00000; /* 2 */ + else if (c >= 0xc2) + c = (c & 0x1f) | 0xfc000000; /* 1 */ + else if (c >= 0x80) + break; + } + state = (c & 0x80000000) ? c : 0; + } + if (c) + { + /* not utf8, assume latin1 */ + buf = solv_malloc(2 * strlen(str) + 1); + cp = (const unsigned char *)str; + str = (char *)buf; + bp = buf; + while ((c = *cp++) != 0) + { + if (c >= 0xc0) + { + *bp++ = 0xc3; + c ^= 0x80; + } + else if (c >= 0x80) + *bp++ = 0xc2; + *bp++ = c; + } + *bp++ = 0; + } + repodata_set_str(repodata, handle, tag, str); + if (buf) + solv_free(buf); +} + +static char * +r64dec1(char *p, unsigned int *vp, int *eofp) +{ + int i, x; + unsigned int v = 0; + + for (i = 0; i < 4; ) + { + x = *p++; + if (!x) + return 0; + if (x >= 'A' && x <= 'Z') + x -= 'A'; + else if (x >= 'a' && x <= 'z') + x -= 'a' - 26; + else if (x >= '0' && x <= '9') + x -= '0' - 52; + else if (x == '+') + x = 62; + else if (x == '/') + x = 63; + else if (x == '=') + { + x = 0; + if (i == 0) + { + *eofp = 3; + *vp = 0; + return p - 1; + } + *eofp += 1; + } + else + continue; + v = v << 6 | x; + i++; + } + *vp = v; + return p; +} + +static unsigned int +crc24(unsigned char *p, int len) +{ + unsigned int crc = 0xb704ceL; + int i; + + while (len--) + { + crc ^= (*p++) << 16; + for (i = 0; i < 8; i++) + if ((crc <<= 1) & 0x1000000) + crc ^= 0x1864cfbL; + } + return crc & 0xffffffL; +} + +static unsigned char * +unarmor(char *pubkey, int *pktlp) +{ + char *p; + int l, eof; + unsigned char *buf, *bp; + unsigned int v; + + *pktlp = 0; + while (strncmp(pubkey, "-----BEGIN PGP PUBLIC KEY BLOCK-----", 36) != 0) + { + pubkey = strchr(pubkey, '\n'); + if (!pubkey) + return 0; + pubkey++; + } + pubkey = strchr(pubkey, '\n'); + if (!pubkey++) + return 0; + /* skip header lines */ + for (;;) + { + while (*pubkey == ' ' || *pubkey == '\t') + pubkey++; + if (*pubkey == '\n') + break; + pubkey = strchr(pubkey, '\n'); + if (!pubkey++) + return 0; + } + pubkey++; + p = strchr(pubkey, '='); + if (!p) + return 0; + l = p - pubkey; + bp = buf = solv_malloc(l * 3 / 4 + 4); + eof = 0; + while (!eof) + { + pubkey = r64dec1(pubkey, &v, &eof); + if (!pubkey) + { + solv_free(buf); + return 0; + } + *bp++ = v >> 16; + *bp++ = v >> 8; + *bp++ = v; + } + while (*pubkey == ' ' || *pubkey == '\t' || *pubkey == '\n' || *pubkey == '\r') + pubkey++; + bp -= eof; + if (*pubkey != '=' || (pubkey = r64dec1(pubkey + 1, &v, &eof)) == 0) + { + solv_free(buf); + return 0; + } + if (v != crc24(buf, bp - buf)) + { + solv_free(buf); + return 0; + } + while (*pubkey == ' ' || *pubkey == '\t' || *pubkey == '\n' || *pubkey == '\r') + pubkey++; + if (strncmp(pubkey, "-----END PGP PUBLIC KEY BLOCK-----", 34) != 0) + { + solv_free(buf); + return 0; + } + *pktlp = bp - buf; + return buf; +} + +static void +parsekeydata(Solvable *s, Repodata *data, unsigned char *p, int pl) +{ + int x, tag, l; + unsigned char keyid[8]; + unsigned int kcr = 0, maxex = 0; + unsigned char *pubkey = 0; + unsigned char *userid = 0; +#if 0 + int pubkeyl = 0; + int useridl = 0; +#endif + + for (; pl; p += l, pl -= l) + { + x = *p++; + pl--; + if (!(x & 128) || pl <= 0) + return; + if ((x & 64) == 0) + { + /* old format */ + tag = (x & 0x3c) >> 2; + x &= 3; + if (x == 3) + return; + l = 1 << x; + if (pl < l) + return; + x = 0; + while (l--) + { + x = x << 8 | *p++; + pl--; + } + l = x; + } + else + { + tag = (x & 0x3f); + x = *p++; + pl--; + if (x < 192) + l = x; + else if (x >= 192 && x < 224) + { + if (pl <= 0) + return; + l = ((x - 192) << 8) + *p++ + 192; + pl--; + } + else if (x == 255) + { + /* sanity: p[0] must be zero */ + if (pl <= 4 || p[0] != 0) + return; + l = p[1] << 16 | p[2] << 8 | p[3]; + p += 4; + pl -= 4; + } + else + return; + } + if (pl < l) + return; + if (tag == 6) + { + pubkey = solv_realloc(pubkey, l); + if (l) + memcpy(pubkey, p, l); +#if 0 + pubkeyl = l; +#endif + kcr = 0; + if (p[0] == 3) + { + unsigned int ex; + void *h; + kcr = p[1] << 24 | p[2] << 16 | p[3] << 8 | p[4]; + ex = 0; + if (p[5] || p[6]) + { + ex = kcr + 24*3600 * (p[5] << 8 | p[6]); + if (ex > maxex) + maxex = ex; + } + memset(keyid, 0, 8); + if (p[7] == 1) /* RSA */ + { + int i, ql; + unsigned char fp[16]; + char fpx[32 + 1]; + unsigned char *q; + + ql = ((p[8] << 8 | p[9]) + 7) / 8; + memcpy(keyid, p + 10 + ql - 8, 8); + h = solv_chksum_create(REPOKEY_TYPE_MD5); + solv_chksum_add(h, p + 10, ql); + q = p + 10 + ql; + ql = ((q[0] << 8 | q[1]) + 7) / 8; + solv_chksum_add(h, q + 2, ql); + solv_chksum_free(h, fp); + for (i = 0; i < 16; i++) + sprintf(fpx + i * 2, "%02x", fp[i]); + repodata_set_str(data, s - s->repo->pool->solvables, PUBKEY_FINGERPRINT, fpx); + } + } + else if (p[0] == 4) + { + int i; + void *h; + unsigned char hdr[3]; + unsigned char fp[20]; + char fpx[40 + 1]; + + kcr = p[1] << 24 | p[2] << 16 | p[3] << 8 | p[4]; + hdr[0] = 0x99; + hdr[1] = l >> 8; + hdr[2] = l; + h = solv_chksum_create(REPOKEY_TYPE_SHA1); + solv_chksum_add(h, hdr, 3); + solv_chksum_add(h, p, l); + solv_chksum_free(h, fp); + for (i = 0; i < 20; i++) + sprintf(fpx + i * 2, "%02x", fp[i]); + repodata_set_str(data, s - s->repo->pool->solvables, PUBKEY_FINGERPRINT, fpx); + memcpy(keyid, fp + 12, 8); + } + } + if (tag == 2) + { + if (p[0] == 3 && p[1] == 5) + { +#if 0 + Id htype = 0; +#endif + /* printf("V3 signature packet\n"); */ + if (l < 17) + continue; + if (p[2] != 0x10 && p[2] != 0x11 && p[2] != 0x12 && p[2] != 0x13 && p[2] != 0x1f) + continue; + if (!memcmp(keyid, p + 6, 8)) + { + /* printf("SELF SIG\n"); */ + } + else + { + /* printf("OTHER SIG\n"); */ + } +#if 0 + if (p[16] == 1) + htype = REPOKEY_TYPE_MD5; + else if (p[16] == 2) + htype = REPOKEY_TYPE_SHA1; + else if (p[16] == 8) + htype = REPOKEY_TYPE_SHA256; + if (htype) + { + void *h = solv_chksum_create(htype); + unsigned char b[3], *cs; + + b[0] = 0x99; + b[1] = pubkeyl >> 8; + b[2] = pubkeyl; + solv_chksum_add(h, b, 3); + solv_chksum_add(h, pubkey, pubkeyl); + if (p[2] >= 0x10 && p[2] <= 0x13) + solv_chksum_add(h, userid, useridl); + solv_chksum_add(h, p + 2, 5); + cs = solv_chksum_get(h, 0); + solv_chksum_free(h, 0); + } +#endif + } + if (p[0] == 4) + { + int j, ql, haveissuer; + unsigned char *q; + unsigned int ex = 0; +#if 0 + unsigned int scr = 0; +#endif + unsigned char issuer[8]; + + /* printf("V4 signature packet\n"); */ + if (l < 6) + continue; + if (p[1] != 0x10 && p[1] != 0x11 && p[1] != 0x12 && p[1] != 0x13 && p[1] != 0x1f) + continue; + haveissuer = 0; + ex = 0; + q = p + 4; + for (j = 0; q && j < 2; j++) + { + if (q + 2 > p + l) + { + q = 0; + break; + } + ql = q[0] << 8 | q[1]; + q += 2; + if (q + ql > p + l) + { + q = 0; + break; + } + while (ql) + { + int sl; + x = *q++; + ql--; + if (x < 192) + sl = x; + else if (x == 255) + { + if (ql < 4 || q[0] != 0) + { + q = 0; + break; + } + sl = q[1] << 16 | q[2] << 8 | q[3]; + q += 4; + ql -= 4; + } + else + { + if (ql < 1) + { + q = 0; + break; + } + sl = ((x - 192) << 8) + *q++ + 192; + ql--; + } + if (ql < sl) + { + q = 0; + break; + } + x = q[0] & 127; + /* printf("%d SIGSUB %d %d\n", j, x, sl); */ + if (x == 16 && sl == 9 && !haveissuer) + { + memcpy(issuer, q + 1, 8); + haveissuer = 1; + } +#if 0 + if (x == 2 && j == 0) + scr = q[1] << 24 | q[2] << 16 | q[3] << 8 | q[4]; +#endif + if (x == 9 && j == 0) + ex = q[1] << 24 | q[2] << 16 | q[3] << 8 | q[4]; + q += sl; + ql -= sl; + } + } + if (ex) + ex += kcr; + if (haveissuer) + { +#if 0 + Id htype = 0; + if (p[3] == 1) + htype = REPOKEY_TYPE_MD5; + else if (p[3] == 2) + htype = REPOKEY_TYPE_SHA1; + else if (p[3] == 8) + htype = REPOKEY_TYPE_SHA256; + if (htype && pubkeyl) + { + void *h = solv_chksum_create(htype); + unsigned char b[6], *cs; + unsigned int hl; + + b[0] = 0x99; + b[1] = pubkeyl >> 8; + b[2] = pubkeyl; + solv_chksum_add(h, b, 3); + solv_chksum_add(h, pubkey, pubkeyl); + if (p[1] >= 0x10 && p[1] <= 0x13) + { + b[0] = 0xb4; + b[1] = useridl >> 24; + b[2] = useridl >> 16; + b[3] = useridl >> 8; + b[4] = useridl; + solv_chksum_add(h, b, 5); + solv_chksum_add(h, userid, useridl); + } + hl = 6 + (p[4] << 8 | p[5]); + solv_chksum_add(h, p, hl); + b[0] = 4; + b[1] = 0xff; + b[2] = hl >> 24; + b[3] = hl >> 16; + b[4] = hl >> 8; + b[5] = hl; + solv_chksum_add(h, b, 6); + cs = solv_chksum_get(h, 0); + solv_chksum_free(h, 0); + } +#endif + if (!memcmp(keyid, issuer, 8)) + { + /* printf("SELF SIG cr %d ex %d\n", cr, ex); */ + if (ex > maxex) + maxex = ex; + } + else + { + /* printf("OTHER SIG cr %d ex %d\n", cr, ex); */ + } + } + } + } + if (tag == 13) + { + userid = solv_realloc(userid, l); + if (l) + memcpy(userid, p, l); +#if 0 + useridl = l; +#endif + } + } + if (maxex) + repodata_set_num(data, s - s->repo->pool->solvables, PUBKEY_EXPIRES, maxex); + solv_free(pubkey); + solv_free(userid); +} + +/* this is private to rpm, but rpm lacks an interface to retrieve + * the values. Sigh. */ +struct pgpDigParams_s { + const char * userid; + const unsigned char * hash; +#ifndef HAVE_PGPDIGGETPARAMS + const char * params[4]; +#endif + unsigned char tag; + unsigned char version; /*!< version number. */ + unsigned char time[4]; /*!< time that the key was created. */ + unsigned char pubkey_algo; /*!< public key algorithm. */ + unsigned char hash_algo; + unsigned char sigtype; + unsigned char hashlen; + unsigned char signhash16[2]; + unsigned char signid[8]; + unsigned char saved; +}; + +#ifndef HAVE_PGPDIGGETPARAMS +struct pgpDig_s { + struct pgpDigParams_s signature; + struct pgpDigParams_s pubkey; +}; +#endif + +static int +pubkey2solvable(Solvable *s, Repodata *data, char *pubkey) +{ + Pool *pool = s->repo->pool; + unsigned char *pkts; + unsigned int btime; + int pktsl, i; + pgpDig dig = 0; + char keyid[16 + 1]; + char evrbuf[8 + 1 + 8 + 1]; + struct pgpDigParams_s *digpubkey; + + pkts = unarmor(pubkey, &pktsl); + if (!pkts) + return 0; + setutf8string(data, s - s->repo->pool->solvables, SOLVABLE_DESCRIPTION, pubkey); + parsekeydata(s, data, pkts, pktsl); + /* only rpm knows how to do the release calculation, we don't dare + * to recreate all the bugs */ +#ifndef RPM5 + dig = pgpNewDig(); +#else + dig = pgpDigNew(RPMVSF_DEFAULT, 0); +#endif + (void) pgpPrtPkts(pkts, pktsl, dig, 0); + +#ifdef HAVE_PGPDIGGETPARAMS + digpubkey = pgpDigGetParams(dig, PGPTAG_PUBLIC_KEY); +#else + digpubkey = &dig->pubkey; +#endif + btime = digpubkey->time[0] << 24 | digpubkey->time[1] << 16 | digpubkey->time[2] << 8 | digpubkey->signid[3]; + sprintf(evrbuf, "%02x%02x%02x%02x-%02x%02x%02x%02x", digpubkey->signid[4], digpubkey->signid[5], digpubkey->signid[6], digpubkey->signid[7], digpubkey->time[0], digpubkey->time[1], digpubkey->time[2], digpubkey->time[3]); + + repodata_set_num(data, s - s->repo->pool->solvables, SOLVABLE_BUILDTIME, btime); + + s->name = pool_str2id(pool, "gpg-pubkey", 1); + s->evr = pool_str2id(pool, evrbuf, 1); + s->arch = 1; + for (i = 0; i < 8; i++) + sprintf(keyid + 2 * i, "%02x", digpubkey->signid[i]); + repodata_set_str(data, s - s->repo->pool->solvables, PUBKEY_KEYID, keyid); + if (digpubkey->userid) + setutf8string(data, s - s->repo->pool->solvables, SOLVABLE_SUMMARY, digpubkey->userid); +#ifndef RPM5 + (void)pgpFreeDig(dig); +#else + (void)pgpDigFree(dig); +#endif + solv_free((void *)pkts); + return 1; +} + +int +repo_add_rpmdb_pubkeys(Repo *repo, int flags) +{ + Pool *pool = repo->pool; + Queue q; + int i; + char *str; + Repodata *data; + Solvable *s; + const char *rootdir = 0; + void *state; + + data = repo_add_repodata(repo, flags); + if (flags & REPO_USE_ROOTDIR) + rootdir = pool_get_rootdir(pool); + state = rpm_state_create(repo->pool, rootdir); + queue_init(&q); + rpm_installedrpmdbids(state, "Name", "gpg-pubkey", &q); + for (i = 0; i < q.count; i++) + { + void *handle; + unsigned long long itime; + + handle = rpm_byrpmdbid(state, q.elements[i]); + if (!handle) + continue; + str = rpm_query(handle, SOLVABLE_DESCRIPTION); + if (!str) + continue; + s = pool_id2solvable(pool, repo_add_solvable(repo)); + pubkey2solvable(s, data, str); + solv_free(str); + itime = rpm_query_num(handle, SOLVABLE_INSTALLTIME, 0); + if (itime) + repodata_set_num(data, s - pool->solvables, SOLVABLE_INSTALLTIME, itime); + if (!repo->rpmdbid) + repo->rpmdbid = repo_sidedata_create(repo, sizeof(Id)); + repo->rpmdbid[s - pool->solvables - repo->start] = q.elements[i]; + } + queue_free(&q); + rpm_state_free(state); + if (!(flags & REPO_NO_INTERNALIZE)) + repodata_internalize(data); + return 0; +} + +Id +repo_add_pubkey(Repo *repo, const char *key, int flags) +{ + Pool *pool = repo->pool; + Repodata *data; + Solvable *s; + char *buf; + int bufl, l, ll; + FILE *fp; + + data = repo_add_repodata(repo, flags); + buf = 0; + bufl = 0; + if ((fp = fopen(flags & REPO_USE_ROOTDIR ? pool_prepend_rootdir_tmp(pool, key) : key, "r")) == 0) + { + pool_error(pool, -1, "%s: %s", key, strerror(errno)); + return 0; + } + for (l = 0; ;) + { + if (bufl - l < 4096) + { + bufl += 4096; + buf = solv_realloc(buf, bufl); + } + ll = fread(buf, 1, bufl - l, fp); + if (ll < 0) + { + fclose(fp); + pool_error(pool, -1, "%s: %s", key, strerror(errno)); + return 0; + } + if (ll == 0) + break; + l += ll; + } + buf[l] = 0; + fclose(fp); + s = pool_id2solvable(pool, repo_add_solvable(repo)); + if (!pubkey2solvable(s, data, buf)) + { + repo_free_solvable(repo, s - pool->solvables, 1); + solv_free(buf); + return 0; + } + solv_free(buf); + if (!(flags & REPO_NO_INTERNALIZE)) + repodata_internalize(data); + return s - pool->solvables; +} + diff --git a/ext/repo_rpmdb_pubkey.h b/ext/repo_rpmdb_pubkey.h new file mode 100644 index 0000000..a9f9e73 --- /dev/null +++ b/ext/repo_rpmdb_pubkey.h @@ -0,0 +1,11 @@ +/* + * Copyright (c) 2013, Novell Inc. + * + * This program is licensed under the BSD license, read LICENSE.BSD + * for further information + */ + +#include "repo.h" + +extern int repo_add_rpmdb_pubkeys(Repo *repo, int flags); +extern Id repo_add_pubkey(Repo *repo, const char *key, int flags); diff --git a/tools/rpmdb2solv.c b/tools/rpmdb2solv.c index 0d00331..1a63755 100644 --- a/tools/rpmdb2solv.c +++ b/tools/rpmdb2solv.c @@ -25,6 +25,9 @@ #include "pool.h" #include "repo.h" #include "repo_rpmdb.h" +#ifdef ENABLE_RPMDB_PUBKEY +#include "repo_rpmdb_pubkey.h" +#endif #include "repo_products.h" #include "repo_solv.h" #include "common_write.h" @@ -61,12 +64,15 @@ main(int argc, char **argv) char *proddir = 0; #endif char *outfile = 0; +#ifdef ENABLE_RPMDB_PUBKEY + int pubkeys = 0; +#endif /* * parse arguments */ - while ((c = getopt(argc, argv, "Phnxb:r:p:o:")) >= 0) + while ((c = getopt(argc, argv, "Phnkxb:r:p:o:")) >= 0) switch (c) { case 'h': @@ -95,6 +101,12 @@ main(int argc, char **argv) case 'o': outfile = optarg; break; +#ifdef ENABLE_RPMDB_PUBKEY + case 'k': + nopacks = 1; + pubkeys = 1; + break; +#endif default: usage(1); } @@ -160,6 +172,16 @@ main(int argc, char **argv) exit(1); } } +#ifdef ENABLE_RPMDB_PUBKEY + if (pubkeys) + { + if (repo_add_rpmdb_pubkeys(repo, REPO_USE_ROOTDIR | REPO_REUSE_REPODATA | REPO_NO_INTERNALIZE)) + { + fprintf(stderr, "rpmdb2solv: %s\n", pool_errstr(pool)); + exit(1); + } + } +#endif #ifdef ENABLE_SUSEREPO if (proddir && *proddir) -- 2.7.4