add repo_add_keyring() and repo_add_keydir() functions
authorMichael Schroeder <mls@suse.de>
Mon, 28 Oct 2013 12:25:15 +0000 (13:25 +0100)
committerMichael Schroeder <mls@suse.de>
Mon, 28 Oct 2013 12:25:15 +0000 (13:25 +0100)
ext/libsolvext.ver
ext/repo_pubkey.c
ext/repo_pubkey.h
tools/rpms2solv.c

index 7722c22..8b096b8 100644 (file)
@@ -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;
index 5f157d1..7cf6da1 100644 (file)
@@ -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))
        {
index dec9e16..731dcef 100644 (file)
@@ -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);
 
-
index 93ee8c3..57c3697 100644 (file)
@@ -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)
        {