diff options
-rw-r--r-- | ext/libsolvext.ver | 2 | ||||
-rw-r--r-- | ext/repo_pubkey.c | 196 | ||||
-rw-r--r-- | ext/repo_pubkey.h | 5 | ||||
-rw-r--r-- | tools/rpms2solv.c | 29 |
4 files changed, 215 insertions, 17 deletions
diff --git a/ext/libsolvext.ver b/ext/libsolvext.ver index 7722c22..8b096b8 100644 --- a/ext/libsolvext.ver +++ b/ext/libsolvext.ver @@ -20,6 +20,8 @@ SOLV_1.0 { repo_add_haiku_package_info; repo_add_haiku_packages; repo_add_helix; + repo_add_keydir; + repo_add_keyring; repo_add_mdk; repo_add_mdk_info; repo_add_products; diff --git a/ext/repo_pubkey.c b/ext/repo_pubkey.c index 5f157d1..7cf6da1 100644 --- a/ext/repo_pubkey.c +++ b/ext/repo_pubkey.c @@ -23,6 +23,7 @@ #include <assert.h> #include <stdint.h> #include <errno.h> +#include <dirent.h> #include <rpm/rpmio.h> #include <rpm/rpmpgp.h> @@ -100,7 +101,7 @@ r64dec1(char *p, unsigned int *vp, int *eofp) static unsigned int crc24(unsigned char *p, int len) { - unsigned int crc = 0xb704ceL; + unsigned int crc = 0xb704ce; int i; while (len--) @@ -108,19 +109,20 @@ crc24(unsigned char *p, int len) crc ^= (*p++) << 16; for (i = 0; i < 8; i++) if ((crc <<= 1) & 0x1000000) - crc ^= 0x1864cfbL; + crc ^= 0x1864cfb; } - return crc & 0xffffffL; + return crc & 0xffffff; } -static unsigned char * -unarmor(char *pubkey, int *pktlp, char *startstr, char *endstr) +static int +unarmor(char *pubkey, unsigned char **pktp, int *pktlp, const char *startstr, const char *endstr) { - char *p; + char *p, *pubkeystart = pubkey; int l, eof; unsigned char *buf, *bp; unsigned int v; + *pktp = 0; *pktlp = 0; if (!pubkey) return 0; @@ -185,8 +187,51 @@ unarmor(char *pubkey, int *pktlp, char *startstr, char *endstr) solv_free(buf); return 0; } + p = strchr(pubkey, '\n'); + if (!p) + p = pubkey + strlen(pubkey); + *pktp = buf; *pktlp = bp - buf; - return buf; + return (p ? p + 1 : pubkey + strlen(pubkey)) - pubkeystart; +} + +#define ARMOR_NLAFTER 16 + +static char * +armor(unsigned char *pkt, int pktl, const char *startstr, const char *endstr, const char *version) +{ + static const char bintoasc[64] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; + char *str = solv_malloc(strlen(startstr) + strlen(endstr) + strlen(version) + (pktl / 3) * 4 + (pktl / (ARMOR_NLAFTER * 3)) + 30); + char *p = str; + int a, b, c, i; + unsigned int v; + + v = crc24(pkt, pktl); + sprintf(p, "%s\nVersion: %s\n\n", startstr, version); + p += strlen(p); + for (i = -1; pktl > 0; pktl -= 3) + { + if (++i == ARMOR_NLAFTER) + { + i = 0; + *p++ = '\n'; + } + a = *pkt++; + b = pktl > 1 ? *pkt++ : 0; + c = pktl > 2 ? *pkt++ : 0; + *p++ = bintoasc[a >> 2]; + *p++ = bintoasc[(a & 3) << 4 | b >> 4]; + *p++ = pktl > 1 ? bintoasc[(b & 15) << 2 | c >> 6] : '='; + *p++ = pktl > 2 ? bintoasc[c & 63] : '='; + } + *p++ = '\n'; + *p++ = '='; + *p++ = bintoasc[v >> 18 & 0x3f]; + *p++ = bintoasc[v >> 12 & 0x3f]; + *p++ = bintoasc[v >> 6 & 0x3f]; + *p++ = bintoasc[v & 0x3f]; + sprintf(p, "\n%s\n", endstr); + return str; } struct pgpsig { @@ -704,8 +749,7 @@ pubkey2solvable(Solvable *s, Repodata *data, char *pubkey) unsigned char *pkts; int pktsl; - pkts = unarmor(pubkey, &pktsl, "-----BEGIN PGP PUBLIC KEY BLOCK-----", "-----END PGP PUBLIC KEY BLOCK-----"); - if (!pkts) + if (!unarmor(pubkey, &pkts, &pktsl, "-----BEGIN PGP PUBLIC KEY BLOCK-----", "-----END PGP PUBLIC KEY BLOCK-----")) { pool_error(s->repo->pool, 0, "unarmor failure"); return 0; @@ -831,6 +875,8 @@ repo_add_pubkey(Repo *repo, const char *key, int flags) solv_free(buf); return 0; } + if (!(flags & REPO_NO_LOCATION)) + repodata_set_location(data, s - pool->solvables, 0, 0, key); solv_free(buf); if (!(flags & REPO_NO_INTERNALIZE)) repodata_internalize(data); @@ -847,6 +893,130 @@ is_sig_packet(unsigned char *sig, int sigl) return 1; } +static int +is_pubkey_packet(unsigned char *pkt, int pktl) +{ + if (!pktl) + return 0; + if ((pkt[0] & 0x80) == 0 || (pkt[0] & 0x40 ? pkt[0] & 0x3f : pkt[0] >> 2 & 0x0f) != 6) + return 0; + return 1; +} + +static void +add_one_pubkey(Pool *pool, Repo *repo, Repodata *data, unsigned char *pbuf, int pbufl) +{ + Solvable *s = pool_id2solvable(pool, repo_add_solvable(repo)); + char *solvversion = pool_tmpjoin(pool, "libsolv-", LIBSOLV_VERSION_STRING, 0); + char *descr = armor(pbuf, pbufl, "-----BEGIN PGP PUBLIC KEY BLOCK-----", "-----END PGP PUBLIC KEY BLOCK-----", solvversion); + setutf8string(data, s - pool->solvables, SOLVABLE_DESCRIPTION, descr); + parsekeydata(s, data, pbuf, pbufl); +#ifdef ENABLE_RPMDB + parsekeydata_rpm(s, data, pbuf, pbufl); +#endif +} + +int +repo_add_keyring(Repo *repo, FILE *fp, int flags) +{ + Pool *pool = repo->pool; + Repodata *data; + unsigned char *buf, *p, *pbuf; + int bufl, l, pl, pbufl; + + data = repo_add_repodata(repo, flags); + buf = (unsigned char *)solv_slurp(fp, &bufl); + if (buf && !is_pubkey_packet(buf, bufl)) + { + /* assume ascii armored */ + unsigned char *nbuf = 0, *ubuf; + int nl, ubufl; + bufl = 0; + for (l = 0; (nl = unarmor((char *)buf + l, &ubuf, &ubufl, "-----BEGIN PGP PUBLIC KEY BLOCK-----", "-----END PGP PUBLIC KEY BLOCK-----")) != 0; l += nl) + { + /* found another block. concat. */ + nbuf = solv_realloc(nbuf, bufl + ubufl); + if (ubufl) + memcpy(nbuf + bufl, ubuf, ubufl); + bufl += ubufl; + solv_free(ubuf); + } + solv_free(buf); + buf = nbuf; + } + /* now split into pubkey parts, ignoring the packets we don't know */ + pbuf = 0; + pbufl = 0; + for (p = buf; bufl; p += pl, bufl -= pl) + { + int tag; + int hl = parsepkgheader(p, bufl, &tag, &pl); + if (!hl) + break; + pl += hl; + if (tag == 6) + { + /* found new pubkey! flush old */ + if (pbufl) + { + add_one_pubkey(pool, repo, data, pbuf, pbufl); + pbuf = solv_free(pbuf); + pbufl = 0; + } + } + if (tag != 6 && !pbufl) + continue; + if (tag != 6 && tag != 2 && tag != 13 && tag != 14 && tag != 17) + continue; + /* we want that packet. concat. */ + pbuf = solv_realloc(pbuf, pbufl + pl); + memcpy(pbuf + pbufl, p, pl); + pbufl += pl; + } + if (pbufl) + add_one_pubkey(pool, repo, data, pbuf, pbufl); + solv_free(pbuf); + solv_free(buf); + if (!(flags & REPO_NO_INTERNALIZE)) + repodata_internalize(data); + return 0; +} + +int +repo_add_keydir(Repo *repo, const char *keydir, int flags, const char *suffix) +{ + Pool *pool = repo->pool; + Repodata *data; + int i, nent, sl; + struct dirent **namelist; + char *rkeydir; + + data = repo_add_repodata(repo, flags); + nent = scandir(flags & REPO_USE_ROOTDIR ? pool_prepend_rootdir_tmp(pool, keydir) : keydir, &namelist, 0, alphasort); + if (nent == -1) + return pool_error(pool, -1, "%s: %s", keydir, strerror(errno)); + rkeydir = pool_prepend_rootdir(pool, keydir); + sl = suffix ? strlen(suffix) : 0; + for (i = 0; i < nent; i++) + { + const char *dn = namelist[i]->d_name; + int l; + if (*dn == '.' && !(flags & ADD_KEYDIR_WITH_DOTFILES)) + continue; + l = strlen(dn); + if (sl && (l < sl || strcmp(dn + l - sl, suffix) != 0)) + continue; + repo_add_pubkey(repo, pool_tmpjoin(pool, rkeydir, "/", dn), flags); + } + solv_free(rkeydir); + for (i = 0; i < nent; i++) + solv_free(namelist[i]); + solv_free(namelist); + if (!(flags & REPO_NO_INTERNALIZE)) + repodata_internalize(data); + return 0; +} + Solvsig * solvsig_create(FILE *fp) { @@ -861,10 +1031,12 @@ solvsig_create(FILE *fp) { /* not a raw sig, check armored */ unsigned char *nsig; - nsig = unarmor((char *)sig, &sigl, "-----BEGIN PGP SIGNATURE-----", "-----END PGP SIGNATURE-----"); + if (!unarmor((char *)sig, &nsig, &sigl, "-----BEGIN PGP SIGNATURE-----", "-----END PGP SIGNATURE-----")) + { + solv_free(sig); + return 0; + } solv_free(sig); - if (!nsig) - return 0; sig = nsig; if (!is_sig_packet(sig, sigl)) { diff --git a/ext/repo_pubkey.h b/ext/repo_pubkey.h index dec9e16..731dcef 100644 --- a/ext/repo_pubkey.h +++ b/ext/repo_pubkey.h @@ -7,8 +7,12 @@ #include "repo.h" +#define ADD_KEYDIR_WITH_DOTFILES (1 << 8) + extern int repo_add_rpmdb_pubkeys(Repo *repo, int flags); extern Id repo_add_pubkey(Repo *repo, const char *key, int flags); +extern int repo_add_keyring(Repo *repo, FILE *fp, int flags); +extern int repo_add_keydir(Repo *repo, const char *keydir, int flags, const char *suffix); /* signature parsing */ typedef struct _solvsig { @@ -28,4 +32,3 @@ Id solvsig_verify(Solvsig *ss, Repo *repo, void *chk); int solv_verify_sig(const unsigned char *pubdata, int pubdatal, unsigned char *sigpkt, int sigpktl, void *chk); Id repo_verify_sigdata(Repo *repo, unsigned char *sigdata, int sigdatal, const char *keyid); - diff --git a/tools/rpms2solv.c b/tools/rpms2solv.c index 93ee8c3..57c3697 100644 --- a/tools/rpms2solv.c +++ b/tools/rpms2solv.c @@ -22,6 +22,7 @@ #include "repo_rpmdb.h" #ifdef ENABLE_PUBKEY #include "repo_pubkey.h" +#include "solv_xfopen.h" #endif #include "repo_solv.h" #include "common_write.h" @@ -65,7 +66,7 @@ main(int argc, char **argv) int pubkeys = 0; #endif - while ((c = getopt(argc, argv, "0kb:m:")) >= 0) + while ((c = getopt(argc, argv, "0kKb:m:")) >= 0) { switch(c) { @@ -82,6 +83,9 @@ main(int argc, char **argv) case 'k': pubkeys = 1; break; + case 'K': + pubkeys = 2; + break; #endif default: exit(1); @@ -127,15 +131,32 @@ main(int argc, char **argv) for (i = 0; i < nrpms; i++) { #ifdef ENABLE_PUBKEY - if (pubkeys) - { + if (pubkeys == 2) + { + FILE *fp = solv_xfopen(rpms[i], "r"); + if (!fp) + { + perror(rpms[i]); + res = 1; + continue; + } + if (repo_add_keyring(repo, fp, REPO_REUSE_REPODATA|REPO_NO_INTERNALIZE)) + { + fprintf(stderr, "rpms2solv: %s\n", pool_errstr(pool)); + res = 1; + } + fclose(fp); + continue; + } + if (pubkeys) + { if (repo_add_pubkey(repo, rpms[i], REPO_REUSE_REPODATA|REPO_NO_INTERNALIZE) == 0) { fprintf(stderr, "rpms2solv: %s\n", pool_errstr(pool)); res = 1; } continue; - } + } #endif if (repo_add_rpm(repo, rpms[i], REPO_REUSE_REPODATA|REPO_NO_INTERNALIZE) == 0) { |