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.
11 #include <lib-lib/lib-lib.h>
13 #include <lib-mime/mime.h>
14 #include <lib-sys/unix.h>
16 #include <lib-ui/curses.h>
17 #include <lib-ui/enter.h>
18 #include <lib-ui/menu.h>
20 #include "recvattach.h"
28 struct pgp_cache *next;
31 static struct pgp_cache *id_defaults = NULL;
33 static char trust_flags[] = "?- +";
35 static char *pgp_key_abilities (int flags)
39 if (!(flags & KEYFLAG_CANENCRYPT))
41 else if (flags & KEYFLAG_PREFER_SIGNING)
46 if (!(flags & KEYFLAG_CANSIGN))
48 else if (flags & KEYFLAG_PREFER_ENCRYPTION)
58 static char pgp_flags (int flags)
60 if (flags & KEYFLAG_REVOKED)
62 else if (flags & KEYFLAG_EXPIRED)
64 else if (flags & KEYFLAG_DISABLED)
66 else if (flags & KEYFLAG_CRITICAL)
72 static pgp_key_t pgp_principal_key (pgp_key_t key)
74 if (key->flags & KEYFLAG_SUBKEY && key->parent)
81 * Format an entry on the PGP key selection menu.
84 * %k key id %K key id of the principal key
86 * %a algorithm %A algorithm of the princ. key
87 * %l length %L length of the princ. key
88 * %f flags %F flags of the princ. key
89 * %c capabilities %C capabilities of the princ. key
90 * %t trust/validity of the key-uid association
91 * %[...] date of key using strftime(3)
94 typedef struct pgp_entry {
100 pgp_entry_fmt (char *dest, ssize_t destlen, char op,
101 const char *src, const char *prefix,
102 const char *ifstr, const char *elstr,
103 anytype data, format_flag flags)
110 int optional = (flags & M_FORMAT_OPTIONAL);
115 pkey = pgp_principal_key (key);
117 if (isupper ((unsigned char) op))
120 kflags = key->flags | (pkey->flags & KEYFLAG_RESTRICTIONS)
123 switch (ascii_tolower (op)) {
128 char buf2[STRING], *p;
144 while (len > 0 && *cp != ']') {
153 break; /* not enough space */
163 if (do_locales && Locale)
164 setlocale (LC_TIME, Locale);
166 tm = localtime (&key->gen_time);
168 strftime (buf2, sizeof (buf2), dest, tm);
171 setlocale (LC_TIME, "C");
173 snprintf (fmt, sizeof (fmt), "%%%ss", prefix);
174 snprintf (dest, destlen, fmt, buf2);
181 snprintf (fmt, sizeof (fmt), "%%%sd", prefix);
182 snprintf (dest, destlen, fmt, entry->num);
187 snprintf (fmt, sizeof (fmt), "%%%ss", prefix);
188 snprintf (dest, destlen, fmt, _pgp_keyid (key));
193 snprintf (fmt, sizeof (fmt), "%%%ss", prefix);
194 snprintf (dest, destlen, fmt, uid->addr);
199 snprintf (fmt, sizeof (fmt), "%%%ss", prefix);
200 snprintf (dest, destlen, fmt, key->algorithm);
205 snprintf (fmt, sizeof (fmt), "%%%sd", prefix);
206 snprintf (dest, destlen, fmt, key->keylen);
211 snprintf (fmt, sizeof (fmt), "%%%sc", prefix);
212 snprintf (dest, destlen, fmt, pgp_flags (kflags));
214 else if (!(kflags & (KEYFLAG_RESTRICTIONS)))
219 snprintf (fmt, sizeof (fmt), "%%%ss", prefix);
220 snprintf (dest, destlen, fmt, pgp_key_abilities (kflags));
222 else if (!(kflags & (KEYFLAG_ABILITIES)))
227 snprintf (fmt, sizeof (fmt), "%%%sc", prefix);
228 snprintf (dest, destlen, fmt, trust_flags[uid->trust & 0x03]);
230 else if (!(uid->trust & 0x03))
231 /* undefined trust */
239 m_strformat (dest, destlen, ifstr, mutt_attach_fmt, data, 0);
240 else if (flags & M_FORMAT_OPTIONAL)
241 m_strformat (dest, destlen, elstr, mutt_attach_fmt, data, 0);
245 static void pgp_entry (char *s, ssize_t l, MUTTMENU * menu, int num)
247 pgp_uid_t **KeyTable = (pgp_uid_t **) menu->data;
250 entry.uid = KeyTable[num];
253 m_strformat(s, l, NONULL (PgpEntryFormat), pgp_entry_fmt,
255 option(OPTARROWCURSOR) ? M_FORMAT_ARROWCURSOR : 0);
258 static int _pgp_compare_address (const void *a, const void *b)
262 pgp_uid_t **s = (pgp_uid_t **) a;
263 pgp_uid_t **t = (pgp_uid_t **) b;
265 if ((r = m_strcasecmp((*s)->addr, (*t)->addr)))
268 return (m_strcasecmp(_pgp_keyid ((*s)->parent),
269 _pgp_keyid ((*t)->parent)) > 0);
272 static int pgp_compare_address (const void *a, const void *b)
274 return ((PgpSortKeys & SORT_REVERSE) ? !_pgp_compare_address (a, b)
275 : _pgp_compare_address (a, b));
280 static int _pgp_compare_keyid (const void *a, const void *b)
284 pgp_uid_t **s = (pgp_uid_t **) a;
285 pgp_uid_t **t = (pgp_uid_t **) b;
287 if ((r = m_strcasecmp(_pgp_keyid ((*s)->parent),
288 _pgp_keyid ((*t)->parent))))
291 return (m_strcasecmp((*s)->addr, (*t)->addr)) > 0;
294 static int pgp_compare_keyid (const void *a, const void *b)
296 return ((PgpSortKeys & SORT_REVERSE) ? !_pgp_compare_keyid (a, b)
297 : _pgp_compare_keyid (a, b));
300 static int _pgp_compare_date (const void *a, const void *b)
303 pgp_uid_t **s = (pgp_uid_t **) a;
304 pgp_uid_t **t = (pgp_uid_t **) b;
306 if ((r = ((*s)->parent->gen_time - (*t)->parent->gen_time)))
308 return (m_strcasecmp((*s)->addr, (*t)->addr)) > 0;
311 static int pgp_compare_date (const void *a, const void *b)
313 return ((PgpSortKeys & SORT_REVERSE) ? !_pgp_compare_date (a, b)
314 : _pgp_compare_date (a, b));
317 static int _pgp_compare_trust (const void *a, const void *b)
321 pgp_uid_t **s = (pgp_uid_t **) a;
322 pgp_uid_t **t = (pgp_uid_t **) b;
324 if ((r = (((*s)->parent->flags & (KEYFLAG_RESTRICTIONS))
325 - ((*t)->parent->flags & (KEYFLAG_RESTRICTIONS)))))
327 if ((r = ((*s)->trust - (*t)->trust)))
329 if ((r = ((*s)->parent->keylen - (*t)->parent->keylen)))
331 if ((r = ((*s)->parent->gen_time - (*t)->parent->gen_time)))
333 if ((r = m_strcasecmp((*s)->addr, (*t)->addr)))
335 return (m_strcasecmp(_pgp_keyid ((*s)->parent),
336 _pgp_keyid ((*t)->parent))) > 0;
339 static int pgp_compare_trust (const void *a, const void *b)
341 return ((PgpSortKeys & SORT_REVERSE) ? !_pgp_compare_trust (a, b)
342 : _pgp_compare_trust (a, b));
345 static int pgp_key_is_valid (pgp_key_t k)
347 pgp_key_t pk = pgp_principal_key (k);
349 if (k->flags & KEYFLAG_CANTUSE)
351 if (pk->flags & KEYFLAG_CANTUSE)
357 static int pgp_id_is_strong (pgp_uid_t * uid)
359 if ((uid->trust & 3) < 3)
365 static int pgp_id_is_valid (pgp_uid_t * uid)
367 if (!pgp_key_is_valid (uid->parent))
369 if (uid->flags & KEYFLAG_CANTUSE)
375 #define PGP_KV_VALID 1
376 #define PGP_KV_ADDR 2
377 #define PGP_KV_STRING 4
378 #define PGP_KV_STRONGID 8
380 #define PGP_KV_MATCH (PGP_KV_ADDR|PGP_KV_STRING)
382 static int pgp_id_matches_addr (address_t * addr, address_t * u_addr,
387 if (pgp_id_is_valid (uid))
390 if (pgp_id_is_strong (uid))
391 rv |= PGP_KV_STRONGID;
393 if (addr->mailbox && u_addr->mailbox
394 && m_strcasecmp(addr->mailbox, u_addr->mailbox) == 0)
397 if (addr->personal && u_addr->personal
398 && m_strcasecmp(addr->personal, u_addr->personal) == 0)
404 static pgp_key_t pgp_select_key (pgp_key_t keys, address_t * p, const char *s)
407 pgp_uid_t **KeyTable;
410 char helpstr[STRING], buf[LONG_STRING], tmpbuf[STRING];
411 char cmd[LONG_STRING], tempfile[_POSIX_PATH_MAX];
416 int (*f) (const void *, const void *);
423 for (i = 0, kp = keys; kp; kp = kp->next) {
424 if (!option (OPTPGPSHOWUNUSABLE) && (kp->flags & KEYFLAG_CANTUSE)) {
429 for (a = kp->address; a; a = a->next) {
430 if (!option (OPTPGPSHOWUNUSABLE) && (a->flags & KEYFLAG_CANTUSE)) {
437 p_realloc(&KeyTable, keymax);
444 if (!i && unusable) {
445 mutt_error _("All matching keys are expired, revoked, or disabled.");
451 switch (PgpSortKeys & SORT_MASK) {
453 f = pgp_compare_date;
456 f = pgp_compare_keyid;
459 f = pgp_compare_address;
463 f = pgp_compare_trust;
466 qsort (KeyTable, i, sizeof (pgp_uid_t *), f);
469 mutt_make_help (buf, sizeof (buf), _("Exit "), MENU_PGP, OP_EXIT);
470 m_strcat(helpstr, sizeof(helpstr), buf);
471 mutt_make_help (buf, sizeof (buf), _("Select "), MENU_PGP,
472 OP_GENERIC_SELECT_ENTRY);
473 m_strcat(helpstr, sizeof(helpstr), buf);
474 mutt_make_help (buf, sizeof (buf), _("Check key "), MENU_PGP,
476 m_strcat(helpstr, sizeof(helpstr), buf);
477 mutt_make_help (buf, sizeof (buf), _("Help"), MENU_PGP, OP_HELP);
478 m_strcat(helpstr, sizeof(helpstr), buf);
480 menu = mutt_new_menu ();
482 menu->make_entry = pgp_entry;
483 menu->menu = MENU_PGP;
484 menu->help = helpstr;
485 menu->data = KeyTable;
488 snprintf (buf, sizeof (buf), _("PGP keys matching <%s>."), p->mailbox);
490 snprintf (buf, sizeof (buf), _("PGP keys matching \"%s\"."), s);
500 switch (mutt_menuLoop (menu)) {
504 if ((devnull = fopen("/dev/null", "w")) == NULL) {
505 mutt_perror (_("Can't open /dev/null"));
510 fp = m_tempfile (tempfile, sizeof(tempfile), NONULL(Tempdir), NULL);
513 mutt_perror (_("Can't create temporary file"));
518 mutt_message _("Invoking PGP...");
520 snprintf (tmpbuf, sizeof (tmpbuf), "0x%s",
521 pgp_keyid (pgp_principal_key
522 (KeyTable[menu->current]->parent)));
524 if ((thepid = pgp_invoke_verify_key (NULL, NULL, NULL, -1,
525 fileno (fp), fileno (devnull),
527 mutt_perror (_("Can't create filter"));
534 mutt_wait_filter (thepid);
538 snprintf (cmd, sizeof (cmd), _("Key ID: 0x%s"),
539 pgp_keyid (pgp_principal_key
540 (KeyTable[menu->current]->parent)));
541 mutt_do_pager (cmd, tempfile, 0, NULL);
542 menu->redraw = REDRAW_FULL;
548 mutt_message ("%s", KeyTable[menu->current]->addr);
551 case OP_GENERIC_SELECT_ENTRY:
554 /* XXX make error reporting more verbose */
556 if (option (OPTPGPCHECKTRUST))
557 if (!pgp_key_is_valid (KeyTable[menu->current]->parent)) {
558 mutt_error _("This key can't be used: expired/disabled/revoked.");
563 if (option (OPTPGPCHECKTRUST) &&
564 (!pgp_id_is_valid (KeyTable[menu->current])
565 || !pgp_id_is_strong (KeyTable[menu->current]))) {
567 char buff[LONG_STRING];
569 if (KeyTable[menu->current]->flags & KEYFLAG_CANTUSE)
570 q = N_("ID is expired/disabled/revoked.");
572 switch (KeyTable[menu->current]->trust & 0x03) {
574 q = N_("ID has undefined validity.");
577 q = N_("ID is not valid.");
580 q = N_("ID is only marginally valid.");
584 snprintf (buff, sizeof (buff),
585 _("%s Do you really want to use the key?"), _(q));
587 if (mutt_yesorno (buff, M_NO) != M_YES) {
594 kp = pgp_principal_key (KeyTable[menu->current]->parent);
596 kp = KeyTable[menu->current]->parent;
609 mutt_menuDestroy (&menu);
612 set_option (OPTNEEDREDRAW);
617 pgp_key_t pgp_ask_for_key (char *tag, char *whatfor,
618 short abilities, pgp_ring_t keyring)
622 struct pgp_cache *l = NULL;
629 for (l = id_defaults; l; l = l->next)
630 if (!m_strcasecmp(whatfor, l->what)) {
631 m_strcpy(resp, sizeof(resp), NONULL(l->dflt));
639 if (mutt_get_field (tag, resp, sizeof (resp), M_CLEAR) != 0)
644 m_strreplace(&l->dflt, resp);
646 l = p_new(struct pgp_cache, 1);
647 l->next = id_defaults;
649 l->what = m_strdup(whatfor);
650 l->dflt = m_strdup(resp);
654 if ((key = pgp_getkeybystr (resp, abilities, keyring)))
662 /* generate a public key attachment */
664 BODY *pgp_make_key_attachment (char *tempf)
667 char buff[LONG_STRING];
668 char tempfb[_POSIX_PATH_MAX], tmp[STRING];
675 unset_option (OPTPGPCHECKTRUST);
678 pgp_ask_for_key (_("Please enter the key ID: "), NULL, 0, PGP_PUBRING);
683 snprintf (tmp, sizeof (tmp), "0x%s", pgp_keyid (pgp_principal_key (key)));
687 tempfp = m_tempfile (tempfb, sizeof(tempfb), NONULL(Tempdir), NULL);
690 tempfp = safe_fopen(tempf, "a");
694 mutt_perror (_("Can't create temporary file"));
698 if ((devnull = fopen("/dev/null", "w")) == NULL) {
699 mutt_perror (_("Can't open /dev/null"));
707 mutt_message _("Invoking pgp...");
711 pgp_invoke_export (NULL, NULL, NULL, -1,
712 fileno (tempfp), fileno (devnull), tmp)) == -1) {
713 mutt_perror (_("Can't create filter"));
721 mutt_wait_filter (thepid);
727 att->filename = m_strdup(tempf);
730 att->type = TYPEAPPLICATION;
731 att->subtype = m_strdup("pgp-keys");
732 snprintf (buff, sizeof (buff), _("PGP Key %s."), tmp);
733 att->description = m_strdup(buff);
734 mutt_update_encoding (att);
737 att->length = sb.st_size;
742 static string_list_t *pgp_add_string_to_hints (string_list_t * hints, const char *str)
747 if ((scratch = m_strdup(str)) == NULL)
750 for (t = strtok (scratch, " ,.:\"()<>\n"); t;
751 t = strtok (NULL, " ,.:\"()<>\n")) {
753 hints = mutt_add_list (hints, t);
760 static pgp_key_t *pgp_get_lastp (pgp_key_t p)
762 for (; p; p = p->next)
769 pgp_key_t pgp_getkeybyaddr (address_t * a, short abilities, pgp_ring_t keyring)
772 string_list_t *hints = NULL;
777 int this_key_has_strong;
778 int this_key_has_weak;
779 int this_key_has_invalid;
782 pgp_key_t keys, k, kn;
783 pgp_key_t the_valid_key = NULL;
784 pgp_key_t matches = NULL;
785 pgp_key_t *last = &matches;
789 hints = pgp_add_string_to_hints (hints, a->mailbox);
790 if (a && a->personal)
791 hints = pgp_add_string_to_hints (hints, a->personal);
793 mutt_message (_("Looking for keys matching \"%s\"..."), a->mailbox);
794 keys = pgp_get_candidates (keyring, hints);
796 string_list_wipe(&hints);
801 for (k = keys; k; k = kn) {
804 if (abilities && !(k->flags & abilities)) {
808 this_key_has_weak = 0; /* weak but valid match */
809 this_key_has_invalid = 0; /* invalid match */
810 this_key_has_strong = 0; /* strong and valid match */
811 match = 0; /* any match */
813 for (q = k->address; q; q = q->next) {
814 r = rfc822_parse_adrlist (NULL, q->addr);
816 for (p = r; p; p = p->next) {
817 int validity = pgp_id_matches_addr (a, p, q);
819 if (validity & PGP_KV_MATCH) /* something matches */
822 /* is this key a strong candidate? */
823 if ((validity & PGP_KV_VALID) && (validity & PGP_KV_STRONGID)
824 && (validity & PGP_KV_ADDR)) {
825 if (the_valid_key && the_valid_key != k)
828 this_key_has_strong = 1;
830 else if ((validity & PGP_KV_MATCH) && !(validity & PGP_KV_VALID))
831 this_key_has_invalid = 1;
832 else if ((validity & PGP_KV_MATCH)
833 && (!(validity & PGP_KV_STRONGID)
834 || !(validity & PGP_KV_ADDR)))
835 this_key_has_weak = 1;
838 address_list_wipe(&r);
841 if (match && !this_key_has_strong && this_key_has_invalid)
843 if (match && !this_key_has_strong && this_key_has_weak)
847 *last = pgp_principal_key (k);
848 kn = pgp_remove_key (&keys, *last);
849 last = pgp_get_lastp (k);
853 pgp_free_key (&keys);
856 if (the_valid_key && !multi /* && !weak
857 && !(invalid && option (OPTPGPSHOWUNUSABLE)) */ ) {
859 * There was precisely one strong match on a valid ID.
861 * Proceed without asking the user.
863 pgp_remove_key (&matches, the_valid_key);
864 pgp_free_key (&matches);
869 * Else: Ask the user.
871 if ((k = pgp_select_key (matches, a, NULL)))
872 pgp_remove_key (&matches, k);
873 pgp_free_key (&matches);
882 pgp_key_t pgp_getkeybystr (const char *p, short abilities, pgp_ring_t keyring)
884 string_list_t *hints = NULL;
886 pgp_key_t matches = NULL;
887 pgp_key_t *last = &matches;
892 mutt_message (_("Looking for keys matching \"%s\"..."), p);
894 hints = pgp_add_string_to_hints (hints, p);
895 keys = pgp_get_candidates (keyring, hints);
896 string_list_wipe(&hints);
902 for (k = keys; k; k = kn) {
904 if (abilities && !(k->flags & abilities))
909 for (a = k->address; a; a = a->next) {
910 if (!*p || m_strcasecmp(p, pgp_keyid (k)) == 0
911 || (!m_strncasecmp(p, "0x", 2)
912 && !m_strcasecmp(p + 2, pgp_keyid (k)))
913 || (option (OPTPGPLONGIDS) && !m_strncasecmp(p, "0x", 2)
914 && !m_strcasecmp(p + 2, k->keyid + 8))
915 || m_stristr(a->addr, p)) {
922 *last = pgp_principal_key (k);
923 kn = pgp_remove_key (&keys, *last);
924 last = pgp_get_lastp (k);
928 pgp_free_key (&keys);
931 if ((k = pgp_select_key (matches, NULL, p)))
932 pgp_remove_key (&matches, k);
934 pgp_free_key (&matches);