summaryrefslogtreecommitdiffstats
path: root/pgpkey.c
diff options
context:
space:
mode:
authorThomas Roessler <roessler@does-not-exist.org>1998-06-08 09:16:03 +0000
committerThomas Roessler <roessler@does-not-exist.org>1998-06-08 09:16:03 +0000
commit1a5381e07e97fe482c2b3a7c75f99938f0b105d4 (patch)
treeb4fa4088bbbf5fc9217ee6f87ab60034175e6899 /pgpkey.c
Initial revision
Diffstat (limited to 'pgpkey.c')
-rw-r--r--pgpkey.c589
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 */