Commit 1b3511a6 authored by Thomas Roessler's avatar Thomas Roessler

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.
parent 4a933a52
......@@ -127,11 +127,9 @@ static void redraw_pgp_lines (int pgp)
static int pgp_send_menu (int bits, int *redraw)
{
char *p;
char *micalg = NULL;
pgp_key_t *p;
char input_signas[SHORT_STRING];
char input_micalg[SHORT_STRING];
KEYINFO *secring;
struct pgp_vinfo *pgp = pgp_get_vinfo(PGP_SIGN);
......@@ -147,39 +145,27 @@ static int pgp_send_menu (int bits, int *redraw)
break;
case 3: /* sign (a)s */
unset_option(OPTPGPCHECKTRUST);
if(pgp)
if (pgp && (p = pgp_ask_for_key (pgp, _("Sign as: "), NULL, KEYFLAG_CANSIGN, PGP_PUBRING)))
{
if(!(secring = pgp->read_secring(pgp)))
{
mutt_error _("Can't open your secret key ring!");
bits &= ~PGPSIGN;
}
else
{
if ((p = pgp_ask_for_key (pgp, secring, _("Sign as: "),
NULL, KEYFLAG_CANSIGN, &micalg)))
{
snprintf (input_signas, sizeof (input_signas), "0x%s", p);
safe_free((void **) &PgpSignAs);
PgpSignAs = safe_strdup(input_signas);
safe_free((void **) &PgpSignMicalg);
PgpSignMicalg = micalg; /* micalg is malloc()ed by pgp_ask_for_key */
pgp_void_passphrase (); /* probably need a different passphrase */
safe_free ((void **) &p);
bits |= PGPSIGN;
}
pgp_close_keydb(&secring);
*redraw = REDRAW_FULL;
}
snprintf (input_signas, sizeof (input_signas), "0x%s", pgp_keyid (p));
safe_free((void **) &PgpSignAs); PgpSignAs = safe_strdup (input_signas);
safe_free((void **) &PgpSignMicalg); PgpSignMicalg = safe_strdup (pgp_pkalg_to_mic (p->algorithm));
pgp_free_key (&p);
bits |= PGPSIGN;
pgp_void_passphrase (); /* probably need a different passphrase */
}
else
{
bits &= ~PGPSIGN;
mutt_error _("An unkown PGP version was defined for signing.");
}
*redraw = REDRAW_FULL;
break;
case 4: /* (b)oth */
......@@ -187,24 +173,24 @@ static int pgp_send_menu (int bits, int *redraw)
break;
case 5: /* select (m)ic algorithm */
if(!(bits & PGPSIGN))
if (!(bits & PGPSIGN))
mutt_error _("This doesn't make sense if you don't want to sign the message.");
else
{
/* Copy the existing MIC algorithm into place */
strfcpy(input_micalg, NONULL(PgpSignMicalg), sizeof(input_micalg));
strfcpy(input_micalg, NONULL (PgpSignMicalg), sizeof (input_micalg));
if(mutt_get_field (_("MIC algorithm: "), input_micalg, sizeof(input_micalg), 0) == 0)
if (mutt_get_field (_("MIC algorithm: "), input_micalg, sizeof (input_micalg), 0) == 0)
{
if(mutt_strcasecmp(input_micalg, "pgp-md5") && mutt_strcasecmp(input_micalg, "pgp-sha1")
&& mutt_strcasecmp(input_micalg, "pgp-rmd160"))
if (mutt_strcasecmp (input_micalg, "pgp-md5") && mutt_strcasecmp (input_micalg, "pgp-sha1")
&& mutt_strcasecmp (input_micalg, "pgp-rmd160"))
{
mutt_error _("Unknown MIC algorithm, valid ones are: pgp-md5, pgp-sha1, pgp-rmd160");
}
else
{
safe_free((void **) &PgpSignMicalg);
PgpSignMicalg = safe_strdup(input_micalg);
safe_free ((void **) &PgpSignMicalg);
PgpSignMicalg = safe_strdup (input_micalg);
}
}
}
......
/*
* Copyright (C) 1998 Werner Koch <[email protected]>
* Copyright (C) 1999 Thomas Roessler <[email protected]>
*
* 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;
}
......@@ -1406,7 +1406,7 @@ void mutt_body_handler (BODY *b, STATE *s)
else if (b->type == TYPEAPPLICATION)
{
if (mutt_is_application_pgp(b))
handler = application_pgp_handler;
handler = pgp_application_pgp_handler;
}
#endif /* _PGPPATH */
......
......@@ -1314,3 +1314,23 @@ size_t mutt_strlen(const char *a)
{
return a ? strlen (a) : 0;
}
const char *mutt_stristr (const char *haystack, const char *needle)
{
const char *p, *q;
if (!haystack)
return NULL;
if (!needle)
return (haystack);
while (*(p = haystack))
{
for (q = needle; *p && *q && tolower (*p) == tolower (*q); p++, q++)
;
if (!*q)
return (haystack);
haystack++;
}
return NULL;
}
......@@ -51,7 +51,7 @@ static struct pgp_vinfo pgp_vinfo[] =
{ PGP_V2,
"pgp2",
&PgpV2, &PgpV2Pubring, &PgpV2Secring, &PgpV2Language,
pgp_read_pubring, pgp_read_secring,
pgp_get_candidates,
pgp_v2_invoke_decode, pgp_v2_invoke_verify, pgp_v2_invoke_decrypt,
pgp_v2_invoke_sign, pgp_v2_invoke_encrypt, pgp_v2_invoke_import,
pgp_v2_invoke_export, pgp_v2_invoke_verify_key
......@@ -60,7 +60,7 @@ static struct pgp_vinfo pgp_vinfo[] =
{ PGP_V3,
"pgp3",
&PgpV3, &PgpV3Pubring, &PgpV3Secring, &PgpV3Language,
pgp_read_pubring, pgp_read_secring,
pgp_get_candidates,
pgp_v3_invoke_decode, pgp_v3_invoke_verify, pgp_v3_invoke_decrypt,
pgp_v3_invoke_sign, pgp_v3_invoke_encrypt, pgp_v3_invoke_import,
pgp_v3_invoke_export, pgp_v3_invoke_verify_key
......@@ -69,7 +69,7 @@ static struct pgp_vinfo pgp_vinfo[] =
{ PGP_V3,
"pgp5",
&PgpV3, &PgpV3Pubring, &PgpV3Secring, &PgpV3Language,
pgp_read_pubring, pgp_read_secring,
pgp_get_candidates,
pgp_v3_invoke_decode, pgp_v3_invoke_verify, pgp_v3_invoke_decrypt,
pgp_v3_invoke_sign, pgp_v3_invoke_encrypt, pgp_v3_invoke_import,
pgp_v3_invoke_export, pgp_v3_invoke_verify_key
......@@ -78,7 +78,7 @@ static struct pgp_vinfo pgp_vinfo[] =
{ PGP_GPG,
"gpg",
&PgpGpg, &PgpGpgDummy, &PgpGpgDummy, &PgpGpgDummy,
gpg_read_pubring, gpg_read_secring,
gpg_get_candidates,
pgp_gpg_invoke_decode, pgp_gpg_invoke_verify, pgp_gpg_invoke_decrypt,
pgp_gpg_invoke_sign, pgp_gpg_invoke_encrypt, pgp_gpg_invoke_import,
pgp_gpg_invoke_export, pgp_gpg_invoke_verify_key
......@@ -178,15 +178,15 @@ struct pgp_vinfo *pgp_get_vinfo(enum pgp_ops op)
return NULL;
}
char *pgp_keyid(KEYINFO *k)
char *pgp_keyid(pgp_key_t *k)
{
if((k->flags & KEYFLAG_SUBKEY) && k->mainkey)
k = k->mainkey;
if((k->flags & KEYFLAG_SUBKEY) && k->parent)
k = k->parent;
return _pgp_keyid(k);
}
char *_pgp_keyid(KEYINFO *k)
char *_pgp_keyid(pgp_key_t *k)
{
if(option(OPTPGPLONGIDS))
return k->keyid;
......@@ -217,7 +217,7 @@ static void pgp_current_time (STATE *s)
/* Support for the Application/PGP Content Type. */
void application_pgp_handler (BODY *m, STATE *s)
void pgp_application_pgp_handler (BODY *m, STATE *s)
{
int needpass = -1, pgp_keyblock = 0;
int clearsign = 0;
......@@ -1231,22 +1231,19 @@ static BODY *pgp_sign_message (BODY *a)
*/
char *pgp_findKeys (ADDRESS *to, ADDRESS *cc, ADDRESS *bcc)
{
char *key, *keyID, *keylist = NULL;
char *keyID, *keylist = NULL;
size_t keylist_size = 0;
size_t keylist_used = 0;
ADDRESS *tmp = NULL;
ADDRESS **last = &tmp;
ADDRESS *p;
int i;
KEYINFO *db;
KEYINFO *k_info;
struct pgp_vinfo *pgp = pgp_get_vinfo(PGP_ENCRYPT);
pgp_key_t *k_info, *key;
struct pgp_vinfo *pgp = pgp_get_vinfo (PGP_ENCRYPT);
if(!pgp)
if (!pgp)
return NULL;
db = pgp->read_pubring(pgp);
for (i = 0; i < 3; i++)
{
switch (i)
......@@ -1273,32 +1270,34 @@ char *pgp_findKeys (ADDRESS *to, ADDRESS *cc, ADDRESS *bcc)
{
snprintf (buf, sizeof (buf), _("Use keyID = \"%s\" for %s?"), keyID, p->mailbox);
if (mutt_yesorno (buf, M_YES) == M_YES)
k_info = ki_getkeybystr (pgp, keyID, db, KEYFLAG_CANENCRYPT);
k_info = pgp_getkeybystr (pgp, keyID, KEYFLAG_CANENCRYPT, PGP_PUBRING);
}
if (k_info == NULL && (k_info = ki_getkeybyaddr (pgp, p, db, KEYFLAG_CANENCRYPT)) == NULL)
if (k_info == NULL && (k_info = pgp_getkeybyaddr (pgp, p, KEYFLAG_CANENCRYPT, PGP_PUBRING)) == NULL)
{
snprintf (buf, sizeof (buf), _("Enter keyID for %s: "), p->mailbox);
if ((key = pgp_ask_for_key (pgp, db, buf, p->mailbox,
KEYFLAG_CANENCRYPT, NULL)) == NULL)
if ((key = pgp_ask_for_key (pgp, buf, p->mailbox,
KEYFLAG_CANENCRYPT, PGP_PUBRING)) == NULL)
{
pgp_close_keydb (&db);
safe_free ((void **)&keylist);
rfc822_free_address (&tmp);
return NULL;
}
}
else
key = pgp_keyid(k_info);
key = k_info;
keylist_size += mutt_strlen (key) + 4;
keyID = pgp_keyid (key);
pgp_free_key (&key);
keylist_size += mutt_strlen (keyID) + 4;
safe_realloc ((void **)&keylist, keylist_size);
sprintf (keylist + keylist_used, "%s0x%s", keylist_used ? " " : "",
key);
keyID);
keylist_used = mutt_strlen (keylist);
}
rfc822_free_address (&tmp);
pgp_close_keydb (&db);
return (keylist);
}
......
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
......@@ -108,6 +108,8 @@ const char *mutt_attach_fmt (
const char *elsestring,
unsigned long data,
format_flag flags);
const char *mutt_stristr (const char *, const char *);
char *mutt_charset_hook (const char *);
char *mutt_expand_path (char *, size_t);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment