2 * Copyright (C) 1998-2000 Werner Koch <werner.koch@guug.de>
3 * Copyright (C) 1999-2000 Thomas Roessler <roessler@does-not-exist.org>
5 * This program is free software; you can redistribute it
6 * and/or modify it under the terms of the GNU General Public
7 * License as published by the Free Software Foundation; either
8 * version 2 of the License, or (at your option) any later
11 * This program is distributed in the hope that it will be
12 * useful, but WITHOUT ANY WARRANTY; without even the implied
13 * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
14 * PURPOSE. See the GNU General Public License for more
17 * You should have received a copy of the GNU General Public
18 * License along with this program; if not, write to the Free
19 * Software Foundation, Inc., 59 Temple Place - Suite 330,
20 * Boston, MA 02111, USA.
26 * This code used to be the parser for GnuPG's output.
28 * Nowadays, we are using an external pubring lister with PGP which mimics
29 * gpg's output format.
37 #include <sys/types.h>
52 * Read the GNUPG keys. For now we read the complete keyring by
53 * calling gnupg in a special mode.
55 * The output format of gpgm is colon delimited with these fields:
56 * - record type ("pub","uid","sig","rev" etc.)
60 * - 16 hex digits with the long keyid.
61 * - timestamp (1998-02-28)
68 /* decode the backslash-escaped user ids. */
70 static char *_chs = 0;
72 static void fix_uid (char *uid)
77 for (s = d = uid; *s;)
79 if (*s == '\\' && *(s+1) == 'x' && isxdigit ((unsigned char) *(s+2)) && isxdigit ((unsigned char) *(s+3)))
81 *d++ = hexval (*(s+2)) << 4 | hexval (*(s+3));
89 if (_chs && (cd = mutt_iconv_open (_chs, "utf-8", 0)) != (iconv_t)-1)
91 int n = s - uid + 1; /* chars available in original buffer */
97 buf = safe_malloc (n+1);
98 ib = uid, ibl = d - uid + 1, ob = buf, obl = n;
99 iconv (cd, &ib, &ibl, &ob, &obl);
104 memcpy (uid, buf, ob-buf);
107 else if (ob-buf == n && (buf[n] = 0, strlen (buf) < n))
108 memcpy (uid, buf, n);
115 static pgp_key_t parse_pub_line (char *buf, int *is_subkey, pgp_key_t k)
117 pgp_uid_t *uid = NULL;
118 int field = 0, is_uid = 0;
127 dprint (2, (debugfile, "parse_pub_line: buf = `%s'\n", buf));
129 for (p = buf; p; p = pend)
131 if ((pend = strchr (p, ':')))
134 if (field > 1 && !*p)
139 case 1: /* record type */
141 dprint (2, (debugfile, "record type: %s\n", p));
143 if (!mutt_strcmp (p, "pub"))
145 else if (!mutt_strcmp (p, "sub"))
147 else if (!mutt_strcmp (p, "sec"))
149 else if (!mutt_strcmp (p, "ssb"))
151 else if (!mutt_strcmp (p, "uid"))
156 if (!(is_uid || (*is_subkey && option (OPTPGPIGNORESUB))))
157 k = safe_calloc (sizeof *k, 1);
161 case 2: /* trust info */
163 dprint (2, (debugfile, "trust info: %s\n", p));
166 { /* look only at the first letter */
168 flags |= KEYFLAG_EXPIRED;
171 flags |= KEYFLAG_REVOKED;
174 flags |= KEYFLAG_DISABLED;
190 if (!is_uid && !(*is_subkey && option (OPTPGPIGNORESUB)))
195 case 3: /* key length */
198 dprint (2, (debugfile, "key len: %s\n", p));
200 if (!(*is_subkey && option (OPTPGPIGNORESUB)))
201 k->keylen = atoi (p); /* fixme: add validation checks */
204 case 4: /* pubkey algo */
207 dprint (2, (debugfile, "pubkey algorithm: %s\n", p));
209 if (!(*is_subkey && option (OPTPGPIGNORESUB)))
211 k->numalg = atoi (p);
212 k->algorithm = pgp_pkalgbytype (atoi (p));
216 case 5: /* 16 hex digits with the long keyid. */
218 dprint (2, (debugfile, "key id: %s\n", p));
220 if (!(*is_subkey && option (OPTPGPIGNORESUB)))
221 mutt_str_replace (&k->keyid, p);
225 case 6: /* timestamp (1998-02-28) */
230 dprint (2, (debugfile, "time stamp: %s\n", p));
237 strncpy (tstr, p, 11);
239 time.tm_year = atoi (tstr)-1900;
241 time.tm_mon = (atoi (tstr+5))-1;
242 time.tm_mday = atoi (tstr+8);
243 k->gen_time = mutt_mktime (&time, 0);
246 case 7: /* valid for n days */
248 case 8: /* Local id */
250 case 9: /* ownertrust */
255 break; /* empty field or no trailing colon */
257 /* ignore user IDs on subkeys */
258 if (!is_uid && (*is_subkey && option (OPTPGPIGNORESUB)))
261 dprint (2, (debugfile, "user ID: %s\n", p));
263 uid = safe_calloc (sizeof (pgp_uid_t), 1);
265 uid->addr = safe_strdup (p);
269 uid->next = k->address;
272 if (strstr (p, "ENCR"))
273 k->flags |= KEYFLAG_PREFER_ENCRYPTION;
274 if (strstr (p, "SIGN"))
275 k->flags |= KEYFLAG_PREFER_SIGNING;
279 case 11: /* signature class */
281 case 12: /* key capabilities */
282 dprint (2, (debugfile, "capabilities info: %s\n", p));
289 flags |= KEYFLAG_DISABLED;
293 flags |= KEYFLAG_CANENCRYPT;
297 flags |= KEYFLAG_CANSIGN;
303 (!*is_subkey || !option (OPTPGPIGNORESUB)
304 || !((flags & KEYFLAG_DISABLED)
305 || (flags & KEYFLAG_REVOKED)
306 || (flags & KEYFLAG_EXPIRED))))
318 pgp_key_t pgp_get_candidates (pgp_ring_t keyring, LIST * hints)
322 char buf[LONG_STRING];
323 pgp_key_t db = NULL, *kend, k = NULL, kk, mainkey = NULL;
327 if ((devnull = open ("/dev/null", O_RDWR)) == -1)
330 mutt_str_replace (&_chs, Charset);
332 thepid = pgp_invoke_list_keys (NULL, &fp, NULL, -1, -1, devnull,
342 while (fgets (buf, sizeof (buf) - 1, fp))
344 if (!(kk = parse_pub_line (buf, &is_sub, k)))
347 /* Only append kk to the list if it's new. */
358 k->flags |= KEYFLAG_SUBKEY;
360 for (l = &k->address; *l; l = &(*l)->next)
362 *l = pgp_copy_uids (mainkey->address, k);
370 mutt_perror ("fgets");
373 mutt_wait_filter (thepid);