2 * Copyright notice from original mutt:
3 * Copyright (C) 1996,1997 Michael R. Elkins <me@mutt.org>
4 * Copyright (c) 1998,1999 Thomas Roessler <roessler@does-not-exist.org>
6 * This file is part of mutt-ng, see http://www.muttng.org/.
7 * It's licensed under the GNU General Public License,
8 * please see the file GPL in the top level source directory.
15 #include <lib-lib/mem.h>
16 #include <lib-lib/str.h>
17 #include <lib-lib/ascii.h>
18 #include <lib-lib/macros.h>
19 #include <lib-lib/file.h>
20 #include <lib-lib/debug.h>
22 #include <lib-mime/mime.h>
24 #include <lib-ui/curses.h>
25 #include <lib-ui/enter.h>
26 #include <lib-ui/menu.h>
29 #include "recvattach.h"
47 struct pgp_cache *next;
50 static struct pgp_cache *id_defaults = NULL;
52 static char trust_flags[] = "?- +";
54 static char *pgp_key_abilities (int flags)
58 if (!(flags & KEYFLAG_CANENCRYPT))
60 else if (flags & KEYFLAG_PREFER_SIGNING)
65 if (!(flags & KEYFLAG_CANSIGN))
67 else if (flags & KEYFLAG_PREFER_ENCRYPTION)
77 static char pgp_flags (int flags)
79 if (flags & KEYFLAG_REVOKED)
81 else if (flags & KEYFLAG_EXPIRED)
83 else if (flags & KEYFLAG_DISABLED)
85 else if (flags & KEYFLAG_CRITICAL)
91 static pgp_key_t pgp_principal_key (pgp_key_t key)
93 if (key->flags & KEYFLAG_SUBKEY && key->parent)
100 * Format an entry on the PGP key selection menu.
103 * %k key id %K key id of the principal key
105 * %a algorithm %A algorithm of the princ. key
106 * %l length %L length of the princ. key
107 * %f flags %F flags of the princ. key
108 * %c capabilities %C capabilities of the princ. key
109 * %t trust/validity of the key-uid association
110 * %[...] date of key using strftime(3)
113 typedef struct pgp_entry {
118 static const char *pgp_entry_fmt (char *dest,
123 const char *ifstring,
124 const char *elsestring,
125 unsigned long data, format_flag flags)
132 int optional = (flags & M_FORMAT_OPTIONAL);
134 entry = (pgp_entry_t *) data;
137 pkey = pgp_principal_key (key);
139 if (isupper ((unsigned char) op))
142 kflags = key->flags | (pkey->flags & KEYFLAG_RESTRICTIONS)
145 switch (ascii_tolower (op)) {
150 char buf2[SHORT_STRING], *p;
166 while (len > 0 && *cp != ']') {
175 break; /* not enough space */
185 if (do_locales && Locale)
186 setlocale (LC_TIME, Locale);
188 tm = localtime (&key->gen_time);
190 strftime (buf2, sizeof (buf2), dest, tm);
193 setlocale (LC_TIME, "C");
195 snprintf (fmt, sizeof (fmt), "%%%ss", prefix);
196 snprintf (dest, destlen, fmt, buf2);
203 snprintf (fmt, sizeof (fmt), "%%%sd", prefix);
204 snprintf (dest, destlen, fmt, entry->num);
209 snprintf (fmt, sizeof (fmt), "%%%ss", prefix);
210 snprintf (dest, destlen, fmt, _pgp_keyid (key));
215 snprintf (fmt, sizeof (fmt), "%%%ss", prefix);
216 snprintf (dest, destlen, fmt, uid->addr);
221 snprintf (fmt, sizeof (fmt), "%%%ss", prefix);
222 snprintf (dest, destlen, fmt, key->algorithm);
227 snprintf (fmt, sizeof (fmt), "%%%sd", prefix);
228 snprintf (dest, destlen, fmt, key->keylen);
233 snprintf (fmt, sizeof (fmt), "%%%sc", prefix);
234 snprintf (dest, destlen, fmt, pgp_flags (kflags));
236 else if (!(kflags & (KEYFLAG_RESTRICTIONS)))
241 snprintf (fmt, sizeof (fmt), "%%%ss", prefix);
242 snprintf (dest, destlen, fmt, pgp_key_abilities (kflags));
244 else if (!(kflags & (KEYFLAG_ABILITIES)))
249 snprintf (fmt, sizeof (fmt), "%%%sc", prefix);
250 snprintf (dest, destlen, fmt, trust_flags[uid->trust & 0x03]);
252 else if (!(uid->trust & 0x03))
253 /* undefined trust */
261 mutt_FormatString (dest, destlen, ifstring, mutt_attach_fmt, data, 0);
262 else if (flags & M_FORMAT_OPTIONAL)
263 mutt_FormatString (dest, destlen, elsestring, mutt_attach_fmt, data, 0);
267 static void pgp_entry (char *s, size_t l, MUTTMENU * menu, int num)
269 pgp_uid_t **KeyTable = (pgp_uid_t **) menu->data;
272 entry.uid = KeyTable[num];
275 mutt_FormatString (s, l, NONULL (PgpEntryFormat), pgp_entry_fmt,
276 (unsigned long) &entry, M_FORMAT_ARROWCURSOR);
279 static int _pgp_compare_address (const void *a, const void *b)
283 pgp_uid_t **s = (pgp_uid_t **) a;
284 pgp_uid_t **t = (pgp_uid_t **) b;
286 if ((r = m_strcasecmp((*s)->addr, (*t)->addr)))
289 return (m_strcasecmp(_pgp_keyid ((*s)->parent),
290 _pgp_keyid ((*t)->parent)) > 0);
293 static int pgp_compare_address (const void *a, const void *b)
295 return ((PgpSortKeys & SORT_REVERSE) ? !_pgp_compare_address (a, b)
296 : _pgp_compare_address (a, b));
301 static int _pgp_compare_keyid (const void *a, const void *b)
305 pgp_uid_t **s = (pgp_uid_t **) a;
306 pgp_uid_t **t = (pgp_uid_t **) b;
308 if ((r = m_strcasecmp(_pgp_keyid ((*s)->parent),
309 _pgp_keyid ((*t)->parent))))
312 return (m_strcasecmp((*s)->addr, (*t)->addr)) > 0;
315 static int pgp_compare_keyid (const void *a, const void *b)
317 return ((PgpSortKeys & SORT_REVERSE) ? !_pgp_compare_keyid (a, b)
318 : _pgp_compare_keyid (a, b));
321 static int _pgp_compare_date (const void *a, const void *b)
324 pgp_uid_t **s = (pgp_uid_t **) a;
325 pgp_uid_t **t = (pgp_uid_t **) b;
327 if ((r = ((*s)->parent->gen_time - (*t)->parent->gen_time)))
329 return (m_strcasecmp((*s)->addr, (*t)->addr)) > 0;
332 static int pgp_compare_date (const void *a, const void *b)
334 return ((PgpSortKeys & SORT_REVERSE) ? !_pgp_compare_date (a, b)
335 : _pgp_compare_date (a, b));
338 static int _pgp_compare_trust (const void *a, const void *b)
342 pgp_uid_t **s = (pgp_uid_t **) a;
343 pgp_uid_t **t = (pgp_uid_t **) b;
345 if ((r = (((*s)->parent->flags & (KEYFLAG_RESTRICTIONS))
346 - ((*t)->parent->flags & (KEYFLAG_RESTRICTIONS)))))
348 if ((r = ((*s)->trust - (*t)->trust)))
350 if ((r = ((*s)->parent->keylen - (*t)->parent->keylen)))
352 if ((r = ((*s)->parent->gen_time - (*t)->parent->gen_time)))
354 if ((r = m_strcasecmp((*s)->addr, (*t)->addr)))
356 return (m_strcasecmp(_pgp_keyid ((*s)->parent),
357 _pgp_keyid ((*t)->parent))) > 0;
360 static int pgp_compare_trust (const void *a, const void *b)
362 return ((PgpSortKeys & SORT_REVERSE) ? !_pgp_compare_trust (a, b)
363 : _pgp_compare_trust (a, b));
366 static int pgp_key_is_valid (pgp_key_t k)
368 pgp_key_t pk = pgp_principal_key (k);
370 if (k->flags & KEYFLAG_CANTUSE)
372 if (pk->flags & KEYFLAG_CANTUSE)
378 static int pgp_id_is_strong (pgp_uid_t * uid)
380 if ((uid->trust & 3) < 3)
386 static int pgp_id_is_valid (pgp_uid_t * uid)
388 if (!pgp_key_is_valid (uid->parent))
390 if (uid->flags & KEYFLAG_CANTUSE)
396 #define PGP_KV_VALID 1
397 #define PGP_KV_ADDR 2
398 #define PGP_KV_STRING 4
399 #define PGP_KV_STRONGID 8
401 #define PGP_KV_MATCH (PGP_KV_ADDR|PGP_KV_STRING)
403 static int pgp_id_matches_addr (address_t * addr, address_t * u_addr,
408 if (pgp_id_is_valid (uid))
411 if (pgp_id_is_strong (uid))
412 rv |= PGP_KV_STRONGID;
414 if (addr->mailbox && u_addr->mailbox
415 && m_strcasecmp(addr->mailbox, u_addr->mailbox) == 0)
418 if (addr->personal && u_addr->personal
419 && m_strcasecmp(addr->personal, u_addr->personal) == 0)
425 static pgp_key_t pgp_select_key (pgp_key_t keys, address_t * p, const char *s)
428 pgp_uid_t **KeyTable;
431 char helpstr[SHORT_STRING], buf[LONG_STRING], tmpbuf[STRING];
432 char cmd[LONG_STRING], tempfile[_POSIX_PATH_MAX];
437 int (*f) (const void *, const void *);
444 for (i = 0, kp = keys; kp; kp = kp->next) {
445 if (!option (OPTPGPSHOWUNUSABLE) && (kp->flags & KEYFLAG_CANTUSE)) {
450 for (a = kp->address; a; a = a->next) {
451 if (!option (OPTPGPSHOWUNUSABLE) && (a->flags & KEYFLAG_CANTUSE)) {
458 p_realloc(&KeyTable, keymax);
465 if (!i && unusable) {
466 mutt_error _("All matching keys are expired, revoked, or disabled.");
472 switch (PgpSortKeys & SORT_MASK) {
474 f = pgp_compare_date;
477 f = pgp_compare_keyid;
480 f = pgp_compare_address;
484 f = pgp_compare_trust;
487 qsort (KeyTable, i, sizeof (pgp_uid_t *), f);
490 mutt_make_help (buf, sizeof (buf), _("Exit "), MENU_PGP, OP_EXIT);
491 strcat (helpstr, buf); /* __STRCAT_CHECKED__ */
492 mutt_make_help (buf, sizeof (buf), _("Select "), MENU_PGP,
493 OP_GENERIC_SELECT_ENTRY);
494 strcat (helpstr, buf); /* __STRCAT_CHECKED__ */
495 mutt_make_help (buf, sizeof (buf), _("Check key "), MENU_PGP,
497 strcat (helpstr, buf); /* __STRCAT_CHECKED__ */
498 mutt_make_help (buf, sizeof (buf), _("Help"), MENU_PGP, OP_HELP);
499 strcat (helpstr, buf); /* __STRCAT_CHECKED__ */
501 menu = mutt_new_menu ();
503 menu->make_entry = pgp_entry;
504 menu->menu = MENU_PGP;
505 menu->help = helpstr;
506 menu->data = KeyTable;
509 snprintf (buf, sizeof (buf), _("PGP keys matching <%s>."), p->mailbox);
511 snprintf (buf, sizeof (buf), _("PGP keys matching \"%s\"."), s);
521 switch (mutt_menuLoop (menu)) {
525 mutt_mktemp (tempfile);
526 if ((devnull = fopen ("/dev/null", "w")) == NULL) { /* __FOPEN_CHECKED__ */
527 mutt_perror (_("Can't open /dev/null"));
531 if ((fp = safe_fopen (tempfile, "w")) == NULL) {
533 mutt_perror (_("Can't create temporary file"));
538 mutt_message _("Invoking PGP...");
540 snprintf (tmpbuf, sizeof (tmpbuf), "0x%s",
541 pgp_keyid (pgp_principal_key
542 (KeyTable[menu->current]->parent)));
544 if ((thepid = pgp_invoke_verify_key (NULL, NULL, NULL, -1,
545 fileno (fp), fileno (devnull),
547 mutt_perror (_("Can't create filter"));
554 mutt_wait_filter (thepid);
558 snprintf (cmd, sizeof (cmd), _("Key ID: 0x%s"),
559 pgp_keyid (pgp_principal_key
560 (KeyTable[menu->current]->parent)));
561 mutt_do_pager (cmd, tempfile, 0, NULL);
562 menu->redraw = REDRAW_FULL;
568 mutt_message ("%s", KeyTable[menu->current]->addr);
571 case OP_GENERIC_SELECT_ENTRY:
574 /* XXX make error reporting more verbose */
576 if (option (OPTPGPCHECKTRUST))
577 if (!pgp_key_is_valid (KeyTable[menu->current]->parent)) {
578 mutt_error _("This key can't be used: expired/disabled/revoked.");
583 if (option (OPTPGPCHECKTRUST) &&
584 (!pgp_id_is_valid (KeyTable[menu->current])
585 || !pgp_id_is_strong (KeyTable[menu->current]))) {
587 char buff[LONG_STRING];
589 if (KeyTable[menu->current]->flags & KEYFLAG_CANTUSE)
590 s = N_("ID is expired/disabled/revoked.");
592 switch (KeyTable[menu->current]->trust & 0x03) {
594 s = N_("ID has undefined validity.");
597 s = N_("ID is not valid.");
600 s = N_("ID is only marginally valid.");
604 snprintf (buff, sizeof (buff),
605 _("%s Do you really want to use the key?"), _(s));
607 if (mutt_yesorno (buff, M_NO) != M_YES) {
614 kp = pgp_principal_key (KeyTable[menu->current]->parent);
616 kp = KeyTable[menu->current]->parent;
629 mutt_menuDestroy (&menu);
632 set_option (OPTNEEDREDRAW);
637 pgp_key_t pgp_ask_for_key (char *tag, char *whatfor,
638 short abilities, pgp_ring_t keyring)
641 char resp[SHORT_STRING];
642 struct pgp_cache *l = NULL;
649 for (l = id_defaults; l; l = l->next)
650 if (!m_strcasecmp(whatfor, l->what)) {
651 m_strcpy(resp, sizeof(resp), NONULL(l->dflt));
659 if (mutt_get_field (tag, resp, sizeof (resp), M_CLEAR) != 0)
664 m_strreplace(&l->dflt, resp);
666 l = p_new(struct pgp_cache, 1);
667 l->next = id_defaults;
669 l->what = m_strdup(whatfor);
670 l->dflt = m_strdup(resp);
674 if ((key = pgp_getkeybystr (resp, abilities, keyring)))
682 /* generate a public key attachment */
684 BODY *pgp_make_key_attachment (char *tempf)
687 char buff[LONG_STRING];
688 char tempfb[_POSIX_PATH_MAX], tmp[STRING];
695 unset_option (OPTPGPCHECKTRUST);
698 pgp_ask_for_key (_("Please enter the key ID: "), NULL, 0, PGP_PUBRING);
703 snprintf (tmp, sizeof (tmp), "0x%s", pgp_keyid (pgp_principal_key (key)));
707 mutt_mktemp (tempfb);
711 if ((tempfp = safe_fopen (tempf, tempf == tempfb ? "w" : "a")) == NULL) {
712 mutt_perror (_("Can't create temporary file"));
717 if ((devnull = fopen ("/dev/null", "w")) == NULL) { /* __FOPEN_CHECKED__ */
718 mutt_perror (_("Can't open /dev/null"));
726 mutt_message _("Invoking pgp...");
730 pgp_invoke_export (NULL, NULL, NULL, -1,
731 fileno (tempfp), fileno (devnull), tmp)) == -1) {
732 mutt_perror (_("Can't create filter"));
740 mutt_wait_filter (thepid);
745 att = mutt_new_body ();
746 att->filename = m_strdup(tempf);
749 att->type = TYPEAPPLICATION;
750 att->subtype = m_strdup("pgp-keys");
751 snprintf (buff, sizeof (buff), _("PGP Key %s."), tmp);
752 att->description = m_strdup(buff);
753 mutt_update_encoding (att);
756 att->length = sb.st_size;
761 static string_list_t *pgp_add_string_to_hints (string_list_t * hints, const char *str)
766 if ((scratch = m_strdup(str)) == NULL)
769 for (t = strtok (scratch, " ,.:\"()<>\n"); t;
770 t = strtok (NULL, " ,.:\"()<>\n")) {
772 hints = mutt_add_list (hints, t);
779 static pgp_key_t *pgp_get_lastp (pgp_key_t p)
781 for (; p; p = p->next)
788 pgp_key_t pgp_getkeybyaddr (address_t * a, short abilities, pgp_ring_t keyring)
791 string_list_t *hints = NULL;
796 int this_key_has_strong;
797 int this_key_has_weak;
798 int this_key_has_invalid;
801 pgp_key_t keys, k, kn;
802 pgp_key_t the_valid_key = NULL;
803 pgp_key_t matches = NULL;
804 pgp_key_t *last = &matches;
808 hints = pgp_add_string_to_hints (hints, a->mailbox);
809 if (a && a->personal)
810 hints = pgp_add_string_to_hints (hints, a->personal);
812 mutt_message (_("Looking for keys matching \"%s\"..."), a->mailbox);
813 keys = pgp_get_candidates (keyring, hints);
815 string_list_wipe(&hints);
820 debug_print (5, ("looking for %s <%s>\n", a->personal, a->mailbox));
822 for (k = keys; k; k = kn) {
825 debug_print (5, (" looking at key: %s\n", pgp_keyid (k)));
827 if (abilities && !(k->flags & abilities)) {
828 debug_print (5, (" insufficient abilities: Has %x, want %x\n",
829 k->flags, abilities));
833 this_key_has_weak = 0; /* weak but valid match */
834 this_key_has_invalid = 0; /* invalid match */
835 this_key_has_strong = 0; /* strong and valid match */
836 match = 0; /* any match */
838 for (q = k->address; q; q = q->next) {
839 r = rfc822_parse_adrlist (NULL, q->addr);
841 for (p = r; p; p = p->next) {
842 int validity = pgp_id_matches_addr (a, p, q);
844 if (validity & PGP_KV_MATCH) /* something matches */
847 /* is this key a strong candidate? */
848 if ((validity & PGP_KV_VALID) && (validity & PGP_KV_STRONGID)
849 && (validity & PGP_KV_ADDR)) {
850 if (the_valid_key && the_valid_key != k)
853 this_key_has_strong = 1;
855 else if ((validity & PGP_KV_MATCH) && !(validity & PGP_KV_VALID))
856 this_key_has_invalid = 1;
857 else if ((validity & PGP_KV_MATCH)
858 && (!(validity & PGP_KV_STRONGID)
859 || !(validity & PGP_KV_ADDR)))
860 this_key_has_weak = 1;
863 address_list_wipe(&r);
866 if (match && !this_key_has_strong && this_key_has_invalid)
868 if (match && !this_key_has_strong && this_key_has_weak)
872 *last = pgp_principal_key (k);
873 kn = pgp_remove_key (&keys, *last);
874 last = pgp_get_lastp (k);
878 pgp_free_key (&keys);
881 if (the_valid_key && !multi /* && !weak
882 && !(invalid && option (OPTPGPSHOWUNUSABLE)) */ ) {
884 * There was precisely one strong match on a valid ID.
886 * Proceed without asking the user.
888 pgp_remove_key (&matches, the_valid_key);
889 pgp_free_key (&matches);
894 * Else: Ask the user.
896 if ((k = pgp_select_key (matches, a, NULL)))
897 pgp_remove_key (&matches, k);
898 pgp_free_key (&matches);
907 pgp_key_t pgp_getkeybystr (char *p, short abilities, pgp_ring_t keyring)
909 string_list_t *hints = NULL;
911 pgp_key_t matches = NULL;
912 pgp_key_t *last = &matches;
917 mutt_message (_("Looking for keys matching \"%s\"..."), p);
919 hints = pgp_add_string_to_hints (hints, p);
920 keys = pgp_get_candidates (keyring, hints);
921 string_list_wipe(&hints);
927 for (k = keys; k; k = kn) {
929 if (abilities && !(k->flags & abilities))
934 for (a = k->address; a; a = a->next) {
935 debug_print (5, ("matching \"%s\" against key %s, \"%s\":\n", p, pgp_keyid (k), a->addr));
936 if (!*p || m_strcasecmp(p, pgp_keyid (k)) == 0
937 || (!m_strncasecmp(p, "0x", 2)
938 && !m_strcasecmp(p + 2, pgp_keyid (k)))
939 || (option (OPTPGPLONGIDS) && !m_strncasecmp(p, "0x", 2)
940 && !m_strcasecmp(p + 2, k->keyid + 8))
941 || m_stristr(a->addr, p)) {
942 debug_print (5, ("match.\n"));
949 *last = pgp_principal_key (k);
950 kn = pgp_remove_key (&keys, *last);
951 last = pgp_get_lastp (k);
955 pgp_free_key (&keys);
958 if ((k = pgp_select_key (matches, NULL, p)))
959 pgp_remove_key (&matches, k);
961 pgp_free_key (&matches);