summaryrefslogtreecommitdiffstats
path: root/gnupgparse.c
diff options
context:
space:
mode:
authorThomas Roessler <roessler@does-not-exist.org>1999-01-22 15:24:58 +0000
committerThomas Roessler <roessler@does-not-exist.org>1999-01-22 15:24:58 +0000
commit1b3511a6a1bd35dbaa29b5aba2bac8e4089b3f67 (patch)
tree25faff13721c7017901130514378ae96b19c77fe /gnupgparse.c
parent4a933a52f58b27f86dfc4e587d65424d524f60d5 (diff)
Heavy hacking on mutt's pgp support. We no longer read the complete
key ring into memory. For gpg, performance is heavily improved due to the fact that we are passing a couple of key hints to the key ring parsing back-end.
Diffstat (limited to 'gnupgparse.c')
-rw-r--r--gnupgparse.c340
1 files changed, 192 insertions, 148 deletions
diff --git a/gnupgparse.c b/gnupgparse.c
index 306b6c87..f62bb659 100644
--- a/gnupgparse.c
+++ b/gnupgparse.c
@@ -1,19 +1,23 @@
/*
* Copyright (C) 1998 Werner Koch <werner.koch@guug.de>
+ * Copyright (C) 1999 Thomas Roessler <roessler@guug.de>
*
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
+ * This program is free software; you can redistribute it
+ * and/or modify it under the terms of the GNU General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later
+ * version.
*
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
+ * This program is distributed in the hope that it will be
+ * useful, but WITHOUT ANY WARRANTY; without even the implied
+ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
+ * PURPOSE. See the GNU General Public License for more
+ * details.
*
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ * You should have received a copy of the GNU General Public
+ * License along with this program; if not, write to the Free
+ * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA
+ * 02139, USA.
*/
@@ -48,169 +52,209 @@
* - signature class
*/
-static KEYINFO *parse_pub_line( char *buf, int *is_subkey )
+static pgp_key_t *parse_pub_line (char *buf, int *is_subkey, pgp_key_t *k)
{
- KEYINFO *k=NULL;
- PGPUID *uid = NULL;
- int field = 0;
- char *pend, *p;
- int trust = 0;
-
- *is_subkey = 0;
- if( !*buf )
- return NULL;
- for( p = buf; p; p = pend ) {
- if( (pend = strchr(p, ':')) )
- *pend++ = 0;
- field++;
- if( field > 1 && !*p )
- continue;
-
- switch( field ) {
- case 1: /* record type */
- if( !mutt_strcmp(p,"pub") )
- ;
- else if( !mutt_strcmp(p,"sub") )
- *is_subkey = 1;
- else if( !mutt_strcmp(p,"sec") )
- ;
- else if( !mutt_strcmp(p,"ssb") )
- *is_subkey = 1;
- else
- return NULL;
- k = safe_malloc( sizeof(KEYINFO) );
- memset(k, 0, sizeof(KEYINFO) );
- break;
- case 2: /* trust info */
- switch( *p ) { /* look only at the first letter */
- case 'e': k->flags |= KEYFLAG_EXPIRED; break;
- case 'n': trust = 1; break;
- case 'm': trust = 2; break;
- case 'f': trust = 3; break;
- case 'u': trust = 3; break;
- case 'r': k->flags |= KEYFLAG_REVOKED; break;
- }
- break;
- case 3: /* key length */
- k->keylen = atoi(p); /* fixme: add validation checks */
- break;
- case 4: /* pubkey algo */
- k->algorithm = pgp_pkalgbytype(atoi(p));
- k->flags |= pgp_get_abilities(atoi(p));
- break;
- case 5: /* 16 hex digits with the long keyid. */
- /* We really should do a check here */
- k->keyid = safe_strdup(p);
- break;
- case 6: /* timestamp (1998-02-28) */
- break;
- case 7: /* valid for n days */
+ pgp_uid_t *uid = NULL;
+ int field = 0, is_uid = 0;
+ char *pend, *p;
+ int trust = 0;
+
+ *is_subkey = 0;
+ if (!*buf)
+ return NULL;
+ for (p = buf; p; p = pend)
+ {
+ if ((pend = strchr (p, ':')))
+ *pend++ = 0;
+ field++;
+ if (field > 1 && !*p)
+ continue;
+
+ switch (field)
+ {
+ case 1: /* record type */
+ {
+ if (!mutt_strcmp (p, "pub"))
+ ;
+ else if (!mutt_strcmp (p, "sub"))
+ *is_subkey = 1;
+ else if (!mutt_strcmp (p, "sec"))
+ ;
+ else if (!mutt_strcmp (p, "ssb"))
+ *is_subkey = 1;
+ else if (!mutt_strcmp (p, "uid"))
+ is_uid = 1;
+ else
+ return NULL;
+
+ if (!is_uid)
+ k = safe_calloc (sizeof (pgp_key_t), 1);
+
+ break;
+ }
+ case 2: /* trust info */
+ /*
+ * XXX - is this the owner-trust field?
+ *
+ * Actually, we'd need the trust gpg has into the
+ * association between a user ID and a key.
+ *
+ * - tlr
+ */
+ {
+ switch (*p)
+ { /* look only at the first letter */
+ case 'e':
+ k->flags |= KEYFLAG_EXPIRED;
break;
- case 8: /* Local id */
+ case 'n':
+ trust = 1;
break;
- case 9: /* ownertrust */
+ case 'm':
+ trust = 2;
break;
- case 10: /* name */
- if( !pend || !*p )
- break; /* empty field or no trailing colon */
- k->address = mutt_new_list();
- k->address->data = safe_malloc( sizeof(PGPUID) );
- uid = (PGPUID *)k->address->data;
- uid->addr = safe_strdup(p);
- uid->trust = trust;
+ case 'f':
+ trust = 3;
break;
- case 11: /* signature class */
+ case 'u':
+ trust = 3;
break;
- default:
+ case 'r':
+ k->flags |= KEYFLAG_REVOKED;
break;
}
+ break;
+ }
+ case 3: /* key length */
+ {
+ k->keylen = atoi (p); /* fixme: add validation checks */
+ break;
+ }
+ case 4: /* pubkey algo */
+ {
+ k->algorithm = pgp_pkalgbytype (atoi (p));
+ k->flags |= pgp_get_abilities (atoi (p));
+ break;
+ }
+ case 5: /* 16 hex digits with the long keyid. */
+ {
+ /* We really should do a check here */
+ k->keyid = safe_strdup (p);
+ break;
+
+ }
+ case 6: /* timestamp (1998-02-28) */
+ break;
+ case 7: /* valid for n days */
+ break;
+ case 8: /* Local id */
+ break;
+ case 9: /* ownertrust */
+ break;
+ case 10: /* name */
+ {
+ if (!pend || !*p)
+ break; /* empty field or no trailing colon */
+ uid = safe_calloc (sizeof (pgp_uid_t), 1);
+ uid->addr = safe_strdup (p);
+ uid->trust = trust;
+ uid->parent = k;
+ uid->next = k->address;
+ k->address = uid;
+
+ if (strstr (p, "ENCR"))
+ k->flags |= KEYFLAG_PREFER_ENCRYPTION;
+ if (strstr (p, "SIGN"))
+ k->flags |= KEYFLAG_PREFER_SIGNING;
+
+ break;
+ }
+ case 11: /* signature class */
+ break;
+ default:
+ break;
}
- return k;
+ }
+ return k;
}
-static pid_t gpg_invoke_list_keys(struct pgp_vinfo *pgp,
- FILE **pgpin, FILE **pgpout, FILE **pgperr,
- int pgpinfd, int pgpoutfd, int pgperrfd,
- const char *uids, int secret)
+static pid_t gpg_invoke_list_keys (struct pgp_vinfo *pgp,
+ FILE ** pgpin, FILE ** pgpout, FILE ** pgperr,
+ int pgpinfd, int pgpoutfd, int pgperrfd,
+ pgp_ring_t keyring,
+ LIST * hints)
{
char cmd[HUGE_STRING];
char tmpcmd[HUGE_STRING];
- char *cp;
- char *keylist;
-
+
/* we use gpgm here */
- snprintf(cmd, sizeof(cmd),
- "%sm --no-verbose --batch --with-colons --list-%skeys ",
- NONULL(*pgp->binary), secret? "secret-":"");
+ snprintf (cmd, sizeof (cmd),
+ "%sm --no-verbose --batch --with-colons --list-%skeys ",
+ NONULL (*pgp->binary), keyring == PGP_SECRING ? "secret-" : "");
- keylist = safe_strdup(uids);
- for(cp = strtok(keylist, " "); cp ; cp = strtok(NULL, " "))
+ for (; hints; hints = hints->next)
{
- snprintf(tmpcmd, sizeof(tmpcmd), "%s %s",
- cmd, cp);
- strcpy(cmd, tmpcmd);
+ snprintf (tmpcmd, sizeof (tmpcmd), "%s %s", cmd, (char *) hints->data);
+ strcpy (cmd, tmpcmd);
}
- safe_free((void **) &keylist);
- return mutt_create_filter_fd(cmd, pgpin, pgpout, pgperr,
- pgpinfd, pgpoutfd, pgperrfd);
+
+ return mutt_create_filter_fd (cmd, pgpin, pgpout, pgperr,
+ pgpinfd, pgpoutfd, pgperrfd);
}
-static KEYINFO *read_ring(struct pgp_vinfo *pgp, int secret )
+pgp_key_t *gpg_get_candidates (struct pgp_vinfo * pgp, pgp_ring_t keyring,
+ LIST * hints)
{
- FILE *fp;
- pid_t thepid;
- char buf[LONG_STRING];
- KEYINFO *db = NULL, **kend, *k = NULL, *kk, *mainkey=NULL;
- int is_sub;
- int devnull;
-
- if((devnull = open("/dev/null", O_RDWR)) == -1)
- return NULL;
-
- thepid = gpg_invoke_list_keys(pgp, NULL, &fp, NULL, -1, -1, devnull,
- NULL, secret);
- if( thepid == -1 )
- {
- close(devnull);
- return NULL;
- }
+ FILE *fp;
+ pid_t thepid;
+ char buf[LONG_STRING];
+ pgp_key_t *db = NULL, **kend, *k = NULL, *kk, *mainkey = NULL;
+ int is_sub;
+ int devnull;
- kend = &db;
- k = NULL;
- while( fgets( buf, sizeof(buf)-1, fp ) ) {
- kk = parse_pub_line(buf, &is_sub );
- if( !kk )
- continue;
- if( k )
- kend = &k->next;
- *kend = k = kk;
-
- if( is_sub ) {
- k->flags |= KEYFLAG_SUBKEY;
- k->mainkey = mainkey;
- }
- else
- mainkey = k;
- }
- if( ferror(fp) )
- mutt_perror("fgets");
+ if ((devnull = open ("/dev/null", O_RDWR)) == -1)
+ return NULL;
- fclose( fp );
- mutt_wait_filter( thepid );
+ thepid = gpg_invoke_list_keys (pgp, NULL, &fp, NULL, -1, -1, devnull,
+ keyring, hints);
+ if (thepid == -1)
+ {
+ close (devnull);
+ return NULL;
+ }
- close(devnull);
-
- return db;
-}
+ kend = &db;
+ k = NULL;
+ while (fgets (buf, sizeof (buf) - 1, fp))
+ {
+ kk = parse_pub_line (buf, &is_sub, k);
+ if (!kk)
+ continue;
+ /* Only append kk to the list if it's new. */
+ if (kk != k)
+ {
+ if (k)
+ kend = &k->next;
+ *kend = k = kk;
+
+ if (is_sub)
+ {
+ k->flags |= KEYFLAG_SUBKEY;
+ k->parent = mainkey;
+ }
+ else
+ mainkey = k;
+ }
+ }
+ if (ferror (fp))
+ mutt_perror ("fgets");
-KEYINFO *gpg_read_pubring(struct pgp_vinfo *pgp)
-{
- return read_ring( pgp, 0 );
-}
+ fclose (fp);
+ mutt_wait_filter (thepid);
+ close (devnull);
-KEYINFO *gpg_read_secring(struct pgp_vinfo *pgp)
-{
- return read_ring( pgp, 1 );
+ return db;
}
+