X-Git-Url: http://git.madism.org/?a=blobdiff_plain;f=lib-crypt%2Fgnupgparse.c;fp=lib-crypt%2Fgnupgparse.c;h=03bab1ac99923214a48e73a2f9cb2c0b8cd3293e;hb=4761fa78a6dfc9437caa6e6e0aac806e50e01c83;hp=0000000000000000000000000000000000000000;hpb=b8c71f93b0296f815a6538182343ba67e88c0012;p=apps%2Fmadmutt.git diff --git a/lib-crypt/gnupgparse.c b/lib-crypt/gnupgparse.c new file mode 100644 index 0000000..03bab1a --- /dev/null +++ b/lib-crypt/gnupgparse.c @@ -0,0 +1,356 @@ +/* + * Copyright notice from original mutt: + * Copyright (C) 1998-2000 Werner Koch + * Copyright (C) 1999-2000 Thomas Roessler + * + * This file is part of mutt-ng, see http://www.muttng.org/. + * It's licensed under the GNU General Public License, + * please see the file GPL in the top level source directory. + */ + +/* + * NOTE + * + * This code used to be the parser for GnuPG's output. + * + * Nowadays, we are using an external pubring lister with PGP which mimics + * gpg's output format. + * + */ + +#if HAVE_CONFIG_H +# include "config.h" +#endif + +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include +#include + +#include + +#include "mutt.h" +#include "pgp.h" +#include "charset.h" + +#include "lib/debug.h" + +/**************** + * Read the GNUPG keys. For now we read the complete keyring by + * calling gnupg in a special mode. + * + * The output format of gpgm is colon delimited with these fields: + * - record type ("pub","uid","sig","rev" etc.) + * - trust info + * - key length + * - pubkey algo + * - 16 hex digits with the long keyid. + * - timestamp (1998-02-28) + * - Local id + * - ownertrust + * - name + * - signature class + */ + +/* decode the backslash-escaped user ids. */ + +static char *_chs = 0; + +static void fix_uid (char *uid) +{ + char *s, *d; + iconv_t cd; + + for (s = d = uid; *s;) { + if (*s == '\\' && *(s + 1) == 'x' && isxdigit ((unsigned char) *(s + 2)) + && isxdigit ((unsigned char) *(s + 3))) { + *d++ = hexval (*(s + 2)) << 4 | hexval (*(s + 3)); + s += 4; + } + else + *d++ = *s++; + } + *d = '\0'; + + if (_chs && (cd = mutt_iconv_open (_chs, "utf-8", 0)) != (iconv_t) - 1) { + int n = s - uid + 1; /* chars available in original buffer */ + char *buf; + const char *ib; + char *ob; + ssize_t ibl, obl; + + buf = p_new(char, n + 1); + ib = uid, ibl = d - uid + 1, ob = buf, obl = n; + my_iconv(cd, &ib, &ibl, &ob, &obl); + if (!ibl) { + if (ob - buf < n) { + memcpy (uid, buf, ob - buf); + uid[ob - buf] = '\0'; + } + else if (ob - buf == n && (buf[n] = 0, m_strlen(buf) < n)) + memcpy (uid, buf, n); + } + p_delete(&buf); + iconv_close (cd); + } +} + +static pgp_key_t parse_pub_line (char *buf, int *is_subkey, pgp_key_t k) +{ + pgp_uid_t *uid = NULL; + int field = 0, is_uid = 0; + char *pend, *p; + int trust = 0; + int flags = 0; + + *is_subkey = 0; + if (!*buf) + return NULL; + + debug_print (2, ("buf = `%s'\n", buf)); + + for (p = buf; p; p = pend) { + if ((pend = strchr (p, ':'))) + *pend++ = 0; + field++; + if (field > 1 && !*p) + continue; + + switch (field) { + case 1: /* record type */ + { + debug_print (2, ("record type: %s\n", p)); + + if (!m_strcmp(p, "pub")); + else if (!m_strcmp(p, "sub")) + *is_subkey = 1; + else if (!m_strcmp(p, "sec")); + else if (!m_strcmp(p, "ssb")) + *is_subkey = 1; + else if (!m_strcmp(p, "uid")) + is_uid = 1; + else + return NULL; + + if (!(is_uid || (*is_subkey && option (OPTPGPIGNORESUB)))) + k = pgp_new_keyinfo(); + + break; + } + case 2: /* trust info */ + { + debug_print (2, ("trust info: %s\n", p)); + + switch (*p) { /* look only at the first letter */ + case 'e': + flags |= KEYFLAG_EXPIRED; + break; + case 'r': + flags |= KEYFLAG_REVOKED; + break; + case 'd': + flags |= KEYFLAG_DISABLED; + break; + case 'n': + trust = 1; + break; + case 'm': + trust = 2; + break; + case 'f': + trust = 3; + break; + case 'u': + trust = 3; + break; + } + + if (!is_uid && !(*is_subkey && option (OPTPGPIGNORESUB))) + k->flags |= flags; + + break; + } + case 3: /* key length */ + { + + debug_print (2, ("key len: %s\n", p)); + + if (!(*is_subkey && option (OPTPGPIGNORESUB))) + k->keylen = atoi (p); /* fixme: add validation checks */ + break; + } + case 4: /* pubkey algo */ + { + + debug_print (2, ("pubkey algorithm: %s\n", p)); + + if (!(*is_subkey && option (OPTPGPIGNORESUB))) { + k->numalg = atoi (p); + k->algorithm = pgp_pkalgbytype (atoi (p)); + } + break; + } + case 5: /* 16 hex digits with the long keyid. */ + { + debug_print (2, ("key id: %s\n", p)); + + if (!(*is_subkey && option (OPTPGPIGNORESUB))) + m_strreplace(&k->keyid, p); + break; + + } + case 6: /* timestamp (1998-02-28) */ + { + char tstr[11]; + struct tm st_time; + + debug_print (2, ("time stamp: %s\n", p)); + + if (!p) + break; + st_time.tm_sec = 0; + st_time.tm_min = 0; + st_time.tm_hour = 12; + m_strcpy(tstr, sizeof(tstr), p); + tstr[4] = '\0'; + st_time.tm_year = atoi (tstr) - 1900; + tstr[7] = '\0'; + st_time.tm_mon = (atoi (tstr + 5)) - 1; + st_time.tm_mday = atoi (tstr + 8); + k->gen_time = mutt_mktime (&st_time, 0); + 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 */ + + /* ignore user IDs on subkeys */ + if (!is_uid && (*is_subkey && option (OPTPGPIGNORESUB))) + break; + + debug_print (2, ("user ID: %s\n", p)); + + uid = p_new(pgp_uid_t, 1); + fix_uid (p); + uid->addr = m_strdup(p); + uid->trust = trust; + uid->flags |= flags; + 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; + case 12: /* key capabilities */ + debug_print (2, ("capabilities info: %s\n", p)); + + while (*p) { + switch (*p++) { + case 'D': + flags |= KEYFLAG_DISABLED; + break; + + case 'e': + flags |= KEYFLAG_CANENCRYPT; + break; + + case 's': + flags |= KEYFLAG_CANSIGN; + break; + } + } + + if (!is_uid && (!*is_subkey || !option (OPTPGPIGNORESUB) + || !((flags & KEYFLAG_DISABLED) + || (flags & KEYFLAG_REVOKED) + || (flags & KEYFLAG_EXPIRED)))) + k->flags |= flags; + + break; + + default: + break; + } + } + return k; +} + +pgp_key_t pgp_get_candidates (pgp_ring_t keyring, LIST * hints) +{ + 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; + + if ((devnull = open ("/dev/null", O_RDWR)) == -1) + return NULL; + + m_strreplace(&_chs, Charset); + + thepid = pgp_invoke_list_keys (NULL, &fp, NULL, -1, -1, devnull, + keyring, hints); + if (thepid == -1) { + close (devnull); + return NULL; + } + + kend = &db; + k = NULL; + while (fgets (buf, sizeof (buf) - 1, fp)) { + if (!(kk = parse_pub_line (buf, &is_sub, k))) + 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) { + pgp_uid_t **l; + + k->flags |= KEYFLAG_SUBKEY; + k->parent = mainkey; + for (l = &k->address; *l; l = &(*l)->next); + *l = pgp_copy_uids (mainkey->address, k); + } + else + mainkey = k; + } + } + + if (ferror (fp)) + mutt_perror ("fgets"); + + fclose (fp); + mutt_wait_filter (thepid); + + close (devnull); + + return db; +}