From 1b3511a6a1bd35dbaa29b5aba2bac8e4089b3f67 Mon Sep 17 00:00:00 2001 From: Thomas Roessler Date: Fri, 22 Jan 1999 15:24:58 +0000 Subject: 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. --- gnupgparse.c | 340 +++++++++++++++++++++++++++++++++-------------------------- 1 file changed, 192 insertions(+), 148 deletions(-) (limited to 'gnupgparse.c') 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 + * Copyright (C) 1999 Thomas Roessler * - * 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; } + -- cgit v1.2.3