diff options
author | Thomas Roessler <roessler@does-not-exist.org> | 1998-06-08 09:16:03 +0000 |
---|---|---|
committer | Thomas Roessler <roessler@does-not-exist.org> | 1998-06-08 09:16:03 +0000 |
commit | 1a5381e07e97fe482c2b3a7c75f99938f0b105d4 (patch) | |
tree | b4fa4088bbbf5fc9217ee6f87ab60034175e6899 /pgpkey.c |
Initial revision
Diffstat (limited to 'pgpkey.c')
-rw-r--r-- | pgpkey.c | 589 |
1 files changed, 589 insertions, 0 deletions
diff --git a/pgpkey.c b/pgpkey.c new file mode 100644 index 00000000..23120a2d --- /dev/null +++ b/pgpkey.c @@ -0,0 +1,589 @@ +/* + * Copyright (C) 1996,1997 Michael R. Elkins <me@cs.hmc.edu> + * + * 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. + * + * 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. + */ + +#include "mutt.h" +#include "mutt_curses.h" +#include "mutt_menu.h" +#include "mime.h" +#include "pgp.h" +#include "pager.h" + +#include <string.h> +#include <ctype.h> +#include <stdlib.h> +#include <unistd.h> +#include <sys/stat.h> +#include <sys/wait.h> + +#ifdef _PGPPATH + +static struct pgp_cache { + char *what; + char *dflt; + struct pgp_cache *next; +} * id_defaults = NULL; + +typedef struct +{ + KEYINFO *k; + PGPUID *a; +} pgp_key_t; + +static char trust_flags[] = "?- +"; + +static char *pgp_key_abilities(int flags) +{ + static char buff[3]; + + if(!(flags & KEYFLAG_CANENCRYPT)) + buff[0] = '-'; + else if(flags & KEYFLAG_PREFER_SIGNING) + buff[0] = '.'; + else + buff[0] = 'e'; + + if(!(flags & KEYFLAG_CANSIGN)) + buff[1] = '-'; + else if(flags & KEYFLAG_PREFER_ENCRYPTION) + buff[1] = '.'; + else + buff[1] = 's'; + + buff[2] = '\0'; + + return buff; +} + +static void pgp_entry (char *s, size_t l, MUTTMENU *menu, int num) +{ + pgp_key_t *KeyTable = (pgp_key_t *) menu->data; + + snprintf (s, l, "%4d %c%c %4d/0x%s %-4s %2s %s", + num + 1, + trust_flags[KeyTable[num].a->trust & 0x03], + (KeyTable[num].k->flags & KEYFLAG_CRITICAL ? + 'c' : ' '), + KeyTable[num].k->keylen, + _pgp_keyid(KeyTable[num].k), + KeyTable[num].k->algorithm, + pgp_key_abilities(KeyTable[num].k->flags), + KeyTable[num].a->addr); +} + +static int pgp_search (MUTTMENU *m, regex_t *re, int n) +{ + char buf[LONG_STRING]; + + pgp_entry (buf, sizeof (buf), m, n); + return (regexec (re, buf, 0, NULL, 0)); +} + +static int pgp_compare (const void *a, const void *b) +{ + int r; + + pgp_key_t *s = (pgp_key_t *) a; + pgp_key_t *t = (pgp_key_t *) b; + + if((r = strcasecmp (s->a->addr, t->a->addr)) != 0) + return r; + else + return strcasecmp(pgp_keyid(s->k), pgp_keyid(t->k)); +} + +static KEYINFO *pgp_select_key (LIST *keys, ADDRESS *p, const char *s) +{ + int keymax; + pgp_key_t *KeyTable; + MUTTMENU *menu; + LIST *a; + int i; + int done = 0; + LIST *l; + char helpstr[SHORT_STRING], buf[LONG_STRING]; + char cmd[LONG_STRING], tempfile[_POSIX_PATH_MAX]; + FILE *fp, *devnull; + pid_t thepid; + KEYINFO *info; + + + for (i = 0, l = keys; l; l = l->next) + { + int did_main_key = 0; + + info = (KEYINFO *) l->data; + a = info->address; + retry1: + for (; a; i++, a = a->next) + ; + + if(!did_main_key && info->flags & KEYFLAG_SUBKEY && info->mainkey) + { + did_main_key = 1; + a = info->mainkey->address; + goto retry1; + } + } + + if (i == 0) return NULL; + + keymax = i; + KeyTable = safe_malloc (sizeof (pgp_key_t) * i); + + for (i = 0, l = keys; l; l = l->next) + { + int did_main_key = 0; + info = (KEYINFO *)l->data; + a = info->address; + retry2: + for (; a ; i++, a = a->next) + { + KeyTable[i].k = (KEYINFO *) l->data; + KeyTable[i].a = (PGPUID *)a->data; + } + if(!did_main_key && info->flags & KEYFLAG_SUBKEY && info->mainkey) + { + did_main_key = 1; + a = info->mainkey->address; + goto retry2; + } + } + + qsort (KeyTable, i, sizeof (pgp_key_t), pgp_compare); + + helpstr[0] = 0; + mutt_make_help (buf, sizeof (buf), "Exit ", MENU_PGP, OP_EXIT); + strcat (helpstr, buf); + mutt_make_help (buf, sizeof (buf), "Select ", MENU_PGP, + OP_GENERIC_SELECT_ENTRY); + strcat (helpstr, buf); + mutt_make_help (buf, sizeof (buf), "Check key ", MENU_PGP, OP_VERIFY_KEY); + strcat (helpstr, buf); + mutt_make_help (buf, sizeof (buf), "Help", MENU_PGP, OP_HELP); + strcat (helpstr, buf); + + menu = mutt_new_menu (); + menu->max = keymax; + menu->make_entry = pgp_entry; + menu->search = pgp_search; + menu->menu = MENU_PGP; + menu->help = helpstr; + menu->data = KeyTable; + + strfcpy (buf, "PGP keys matching ", sizeof (buf)); + if (p) + strfcpy (buf, p->mailbox, sizeof (buf) - strlen (buf)); + else + strcat (buf, s); + menu->title = buf; + + info = NULL; + + while (!done) + { + switch (mutt_menuLoop (menu)) + { + + case OP_VERIFY_KEY: + + mutt_mktemp (tempfile); + if ((devnull = fopen ("/dev/null", "w")) == NULL) + { + mutt_perror ("Can't open /dev/null"); + break; + } + if ((fp = safe_fopen (tempfile, "w")) == NULL) + { + fclose (devnull); + mutt_perror ("Can't create temporary file"); + break; + } + + mutt_message ("Invoking PGP..."); + + if((thepid = pgp_invoke_verify_key(NULL, NULL, NULL, -1, + fileno(fp), fileno(devnull), + pgp_keyid(KeyTable[menu->current].k))) == -1) + { + mutt_perror ("Can't create filter"); + unlink (tempfile); + fclose (fp); + fclose (devnull); + } + + mutt_wait_filter (thepid); + fclose (fp); + fclose (devnull); + mutt_clear_error (); + snprintf(cmd, sizeof(cmd), "Key ID: 0x%s", pgp_keyid(KeyTable[menu->current].k)); + mutt_do_pager (cmd, tempfile, 0, NULL); + menu->redraw = REDRAW_FULL; + + break; + + case OP_VIEW_ID: + + mutt_message (KeyTable[menu->current].a->addr); + break; + + case OP_GENERIC_SELECT_ENTRY: + + if (option (OPTPGPCHECKTRUST) && + (KeyTable[menu->current].a->trust & 0x03) < 3) + { + char *s = ""; + char buff[LONG_STRING]; + + switch (KeyTable[menu->current].a->trust & 0x03) + { + case 0: s = "This ID's trust level is undefined."; break; + case 1: s = "This ID is not trusted."; break; + case 2: s = "This ID is only marginally trusted."; break; + } + + snprintf (buff, sizeof(buff), "%s Do you really want to use it?", s); + + if (mutt_yesorno (buff, 0) != 1) + { + mutt_clear_error (); + break; + } + } + + info = KeyTable[menu->current].k; + done = 1; + break; + + case OP_EXIT: + + info = NULL; + done = 1; + break; + } + } + + mutt_menuDestroy (&menu); + safe_free ((void **) &KeyTable); + + return (info); +} + +char *pgp_ask_for_key (const char *ringfile, KEYINFO *udb, char *tag, char *whatfor, + short abilities, char **alg) +{ + KEYINFO *db; + KEYINFO *key; + char *key_id; + char resp[SHORT_STRING]; + struct pgp_cache *l = NULL; + + db = udb ? udb : pgp_read_keyring(ringfile); + + resp[0] = 0; + if (whatfor) + { + + for (l = id_defaults; l; l = l->next) + if (!strcasecmp (whatfor, l->what)) + { + strcpy (resp, l->dflt); + break; + } + } + + + FOREVER + { + if (mutt_get_field (tag, resp, sizeof (resp), M_CLEAR) != 0) + { + if (!udb) pgp_closedb (db); + return NULL; + } + + if (whatfor) + { + if (l) + { + safe_free ((void **)&l->dflt); + l->dflt = safe_strdup (resp); + } + else + { + l = safe_malloc (sizeof (struct pgp_cache)); + l->next = id_defaults; + id_defaults = l; + l->what = safe_strdup (whatfor); + l->dflt = safe_strdup (resp); + } + } + + if ((key = ki_getkeybystr (resp, db, abilities))) + { + key_id = safe_strdup(pgp_keyid (key)); + + if (alg) + *alg = safe_strdup(pgp_pkalg_to_mic(key->algorithm)); + + if (!udb) pgp_closedb (db); + return (key_id); + } + BEEP (); + } + /* not reached */ +} + +/* generate a public key attachment */ + +BODY *pgp_make_key_attachment (char * tempf) +{ + BODY *att; + char buff[LONG_STRING]; + char tempfb[_POSIX_PATH_MAX]; + char *id; + FILE *tempfp; + FILE *devnull; + struct stat sb; + pid_t thepid; + + unset_option (OPTPGPCHECKTRUST); + + if (!(id = pgp_ask_for_key (pgp_pubring(PGP_EXTRACT), + NULL, "Please enter the key ID: ", NULL, 0, NULL))) + return NULL; + + if (!tempf) { + mutt_mktemp (tempfb); + tempf = tempfb; + } + + if ((tempfp = safe_fopen (tempf, tempf == tempfb ? "w" : "a")) == NULL) { + mutt_perror ("Can't create temporary file"); + safe_free ((void **)&id); + return NULL; + } + + if ((devnull = fopen ("/dev/null", "w")) == NULL) { + mutt_perror ("Can't open /dev/null"); + safe_free ((void **)&id); + fclose (tempfp); + if (tempf == tempfb) unlink (tempf); + return NULL; + } + + if ((thepid = pgp_invoke_extract_key(NULL, NULL, NULL, -1, + fileno(tempfp), fileno(devnull), id)) == -1) + { + mutt_perror ("Can't create filter"); + unlink (tempf); + fclose (tempfp); + fclose (devnull); + safe_free ((void **)&id); + return NULL; + } + + mutt_wait_filter (thepid); + + fclose (tempfp); + fclose (devnull); + + att = mutt_new_body (); + att->filename = safe_strdup (tempf); + att->unlink = 1; + att->type = TYPEAPPLICATION; + att->subtype = safe_strdup ("pgp-keys"); + snprintf (buff, sizeof (buff), "PGP Key 0x%s.", id); + att->description = safe_strdup (buff); + mutt_update_encoding (att); + + stat (tempf, &sb); + att->length = sb.st_size; + + safe_free ((void **)&id); + return att; +} + +static char *mutt_stristr (char *haystack, char *needle) +{ + 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; +} + +KEYINFO *ki_getkeybyaddr (ADDRESS *a, KEYINFO *k, short abilities) +{ + ADDRESS *r, *p; + LIST *l = NULL, *t = NULL; + LIST *q; + int weak = 0; + int weak_association; + int match; + int did_main_key; + PGPUID *u; + + for ( ; k ; k = k->next) + { + if(k->flags & (KEYFLAG_REVOKED | KEYFLAG_EXPIRED | KEYFLAG_DISABLED)) + continue; + + if(abilities && !(k->flags & abilities)) + continue; + + q = k->address; + did_main_key = 0; + weak_association = 1; + match = 0; + + retry: + + for (;q ; q = q->next) + { + u = (PGPUID *) q->data; + r = rfc822_parse_adrlist(NULL, u->addr); + + for(p = r; p && weak_association; p = p->next) + { + if ((p->mailbox && a->mailbox && + strcasecmp (p->mailbox, a->mailbox) == 0) || + (a->personal && p->personal && + strcasecmp (a->personal, p->personal) == 0)) + { + match = 1; + + if(((u->trust & 0x03) == 3) && + (p->mailbox && a->mailbox && !strcasecmp(p->mailbox, a->mailbox))) + weak_association = 0; + } + } + rfc822_free_address(&r); + } + + if(match) + { + t = mutt_new_list (); + t->data = (void *) k; + t->next = l; + l = t; + + if(weak_association) + weak = 1; + + } + + if(!did_main_key && !match && k->flags & KEYFLAG_SUBKEY && k->mainkey) + { + did_main_key = 1; + q = k->mainkey->address; + goto retry; + } + } + + if (l) + { + if (l->next || weak) + { + /* query for which key the user wants */ + k = pgp_select_key (l, a, NULL); + } + else + k = (KEYINFO *)l->data; + + /* mutt_free_list() frees the .data member, so clear the pointers */ + + for(t = l; t; t = t->next) + t->data = NULL; + + mutt_free_list (&l); + } + + return (k); +} + +KEYINFO *ki_getkeybystr (char *p, KEYINFO *k, short abilities) +{ + LIST *t = NULL, *l = NULL; + LIST *a; + + for(; k; k = k->next) + { + int did_main_key = 0; + + if(k->flags & (KEYFLAG_REVOKED | KEYFLAG_EXPIRED | KEYFLAG_DISABLED)) + continue; + + if(abilities && !(k->flags & abilities)) + continue; + + a = k->address; + + retry: + + for(; a ; a = a->next) + { + + if (!*p || strcasecmp (p, pgp_keyid(k)) == 0 || + (!strncasecmp(p, "0x", 2) && !strcasecmp(p+2, pgp_keyid(k))) || + (option(OPTPGPLONGIDS) && !strncasecmp(p, "0x", 2) && + !strcasecmp(p+2, k->keyid+8)) || + mutt_stristr(((PGPUID *)a->data)->addr,p)) + { + t = mutt_new_list (); + t->data = (void *)k; + t->next = l; + l = t; + break; + } + } + + if(!did_main_key && k->flags & KEYFLAG_SUBKEY && k->mainkey) + { + did_main_key = 1; + a = k->mainkey->address; + goto retry; + } + } + + if (l) + { + k = pgp_select_key (l, NULL, p); + set_option(OPTNEEDREDRAW); + + for(t = l; t; t = t->next) + t->data = NULL; + + mutt_free_list (&l); + } + + return (k); +} + + + +#endif /* _PGPPATH */ |