]> granicus.if.org Git - mutt/blob - gnupgparse.c
Convert pgp_app_handler to use buffer pool.
[mutt] / gnupgparse.c
1 /*
2  * Copyright (C) 1998-2000,2003 Werner Koch <werner.koch@guug.de>
3  * Copyright (C) 1999-2003 Thomas Roessler <roessler@does-not-exist.org>
4  *
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
9  *     version.
10  *
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
15  *     details.
16  *
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., 51 Franklin Street, Fifth Floor,
20  *     Boston, MA  02110-1301, USA.
21  */
22
23 /*
24  * NOTE
25  *
26  * This code used to be the parser for GnuPG's output.
27  *
28  * Nowadays, we are using an external pubring lister with PGP which mimics
29  * gpg's output format.
30  *
31  */
32
33 #if HAVE_CONFIG_H
34 # include "config.h"
35 #endif
36
37 #include <stdio.h>
38 #include <stdlib.h>
39 #include <string.h>
40
41 #include <sys/types.h>
42 #include <sys/stat.h>
43 #include <unistd.h>
44 #include <fcntl.h>
45 #include <time.h>
46 #include <ctype.h>
47
48 #include "mutt.h"
49 #include "pgp.h"
50 #include "charset.h"
51
52 /* for hexval */
53 #include "mime.h"
54
55 /****************
56  * Read the GNUPG keys.  For now we read the complete keyring by
57  * calling gnupg in a special mode.
58  *
59  * The output format of gpgm is colon delimited with these fields:
60  *   - record type ("pub","uid","sig","rev" etc.)
61  *   - trust info
62  *   - key length
63  *   - pubkey algo
64  *   - 16 hex digits with the long keyid.
65  *   - timestamp (1998-02-28)
66  *   - Local id
67  *   - ownertrust
68  *   - name
69  *   - signature class
70  */
71
72 /* decode the backslash-escaped user ids. */
73
74 static char *_chs = 0;
75
76 static void fix_uid (char *uid)
77 {
78   char *s, *d;
79   iconv_t cd;
80
81   for (s = d = uid; *s;)
82   {
83     if (*s == '\\' && *(s+1) == 'x' && isxdigit ((unsigned char) *(s+2)) && isxdigit ((unsigned char) *(s+3)))
84     {
85       *d++ = hexval (*(s+2)) << 4 | hexval (*(s+3));
86       s += 4;
87     }
88     else
89       *d++ = *s++;
90   }
91   *d = '\0';
92
93   if (_chs && (cd = mutt_iconv_open (_chs, "utf-8", 0)) != (iconv_t)-1)
94   {
95     int n = s - uid + 1; /* chars available in original buffer */
96     char *buf;
97     ICONV_CONST char *ib;
98     char *ob;
99     size_t ibl, obl;
100
101     buf = safe_malloc (n+1);
102     ib = uid, ibl = d - uid + 1, ob = buf, obl = n;
103     iconv (cd, &ib, &ibl, &ob, &obl);
104     if (!ibl)
105     {
106       if (ob-buf < n)
107       {
108         memcpy (uid, buf, ob-buf);
109         uid[ob-buf] = '\0';
110       }
111       else if (n >= 0 && ob-buf == n && (buf[n] = 0, strlen (buf) < (size_t)n))
112         memcpy (uid, buf, n);
113     }
114     FREE (&buf);
115     iconv_close (cd);
116   }
117 }
118
119 static pgp_key_t parse_pub_line (char *buf, int *is_subkey, pgp_key_t k)
120 {
121   pgp_uid_t *uid = NULL;
122   int field = 0, is_uid = 0;
123   int is_pub = 0;
124   int is_fpr = 0;
125   char *pend, *p;
126   int trust = 0;
127   int flags = 0;
128   struct pgp_keyinfo tmp;
129
130   *is_subkey = 0;
131   if (!*buf)
132     return NULL;
133
134   /* if we're given a key, merge our parsing results, else
135    * start with a fresh one to work with so that we don't
136    * mess up the real key in case we find parsing errors. */
137   if (k)
138     memcpy (&tmp, k, sizeof (tmp));
139   else
140     memset (&tmp, 0, sizeof (tmp));
141
142   dprint (2, (debugfile, "parse_pub_line: buf = `%s'\n", buf));
143
144   for (p = buf; p; p = pend)
145   {
146     if ((pend = strchr (p, ':')))
147       *pend++ = 0;
148     field++;
149     if (!*p && (field != 1) && (field != 10))
150       continue;
151
152     if (is_fpr && (field != 10))
153       continue;
154
155     switch (field)
156     {
157       case 1:                   /* record type */
158       {
159         dprint (2, (debugfile, "record type: %s\n", p));
160
161         if (!mutt_strcmp (p, "pub"))
162           is_pub = 1;
163         else if (!mutt_strcmp (p, "sub"))
164           *is_subkey = 1;
165         else if (!mutt_strcmp (p, "sec"))
166           ;
167         else if (!mutt_strcmp (p, "ssb"))
168           *is_subkey = 1;
169         else if (!mutt_strcmp (p, "uid"))
170           is_uid = 1;
171         else if (!mutt_strcmp (p, "fpr"))
172           is_fpr = 1;
173         else
174           return NULL;
175
176         if (!(is_uid || is_fpr || (*is_subkey && option (OPTPGPIGNORESUB))))
177           memset (&tmp, 0, sizeof (tmp));
178
179         break;
180       }
181       case 2:                   /* trust info */
182       {
183         dprint (2, (debugfile, "trust info: %s\n", p));
184
185         switch (*p)
186         {                               /* look only at the first letter */
187           case 'e':
188             flags |= KEYFLAG_EXPIRED;
189             break;
190           case 'r':
191             flags |= KEYFLAG_REVOKED;
192             break;
193           case 'd':
194             flags |= KEYFLAG_DISABLED;
195             break;
196           case 'n':
197             trust = 1;
198             break;
199           case 'm':
200             trust = 2;
201             break;
202           case 'f':
203             trust = 3;
204             break;
205           case 'u':
206             trust = 3;
207             break;
208         }
209
210         if (!is_uid && !(*is_subkey && option (OPTPGPIGNORESUB)))
211           tmp.flags |= flags;
212
213         break;
214       }
215       case 3:                   /* key length  */
216       {
217         dprint (2, (debugfile, "key len: %s\n", p));
218
219         if (!(*is_subkey && option (OPTPGPIGNORESUB)) &&
220             mutt_atos (p, &tmp.keylen) < 0)
221           goto bail;
222         break;
223       }
224       case 4:                   /* pubkey algo */
225       {
226         dprint (2, (debugfile, "pubkey algorithm: %s\n", p));
227
228         if (!(*is_subkey && option (OPTPGPIGNORESUB)))
229         {
230           int x = 0;
231           if (mutt_atoi (p, &x) < 0)
232             goto bail;
233           tmp.numalg = x;
234           tmp.algorithm = pgp_pkalgbytype (x);
235         }
236         break;
237       }
238       case 5:                   /* 16 hex digits with the long keyid. */
239       {
240         dprint (2, (debugfile, "key id: %s\n", p));
241
242         if (!(*is_subkey && option (OPTPGPIGNORESUB)))
243           mutt_str_replace (&tmp.keyid, p);
244         break;
245
246       }
247       case 6:                   /* timestamp (1998-02-28) */
248       {
249         dprint (2, (debugfile, "time stamp: %s\n", p));
250
251         if (strchr (p, '-'))   /* gpg pre-2.0.10 used format (yyyy-mm-dd) */
252         {
253           char tstr[11];
254           struct tm time;
255
256           time.tm_sec = 0;
257           time.tm_min = 0;
258           time.tm_hour = 12;
259           strncpy (tstr, p, 11);
260           tstr[4] = '\0';
261           tstr[7] = '\0';
262           if (mutt_atoi (tstr, &time.tm_year) < 0)
263           {
264             p = tstr;
265             goto bail;
266           }
267           time.tm_year -= 1900;
268           if (mutt_atoi (tstr+5, &time.tm_mon) < 0)
269           {
270             p = tstr+5;
271             goto bail;
272           }
273           time.tm_mon -= 1;
274           if (mutt_atoi (tstr+8, &time.tm_mday) < 0)
275           {
276             p = tstr+8;
277             goto bail;
278           }
279           tmp.gen_time = mutt_mktime (&time, 0);
280         }
281         else                  /* gpg 2.0.10+ uses seconds since 1970-01-01 */
282         {
283           unsigned long long secs;
284
285           if (mutt_atoull (p, &secs) < 0)
286             goto bail;
287           tmp.gen_time = (time_t)secs;
288         }
289         break;
290       }
291       case 7:                   /* valid for n days */
292         break;
293       case 8:                   /* Local id         */
294         break;
295       case 9:                   /* ownertrust       */
296         break;
297       case 10:                  /* name             */
298       {
299         /* Empty field or no trailing colon.
300          * We allow an empty field for a pub record type because it is
301          * possible for a primary uid record to have an empty User-ID
302          * field.  Without any address records, it is not possible to
303          * use the key in mutt.
304          */
305         if (!(pend && (*p || is_pub)))
306           break;
307
308         if (is_fpr)
309         {
310           /* don't let a subkey fpr overwrite an existing primary key fpr */
311           if (!tmp.fingerprint)
312             tmp.fingerprint = safe_strdup (p);
313           break;
314         }
315
316         /* ignore user IDs on subkeys */
317         if (!is_uid && (*is_subkey && option (OPTPGPIGNORESUB)))
318           break;
319
320         dprint (2, (debugfile, "user ID: %s\n", NONULL (p)));
321
322         uid = safe_calloc (sizeof (pgp_uid_t), 1);
323         fix_uid (p);
324         uid->addr = safe_strdup (p);
325         uid->trust = trust;
326         uid->flags |= flags;
327         uid->next = tmp.address;
328         tmp.address = uid;
329
330         if (strstr (p, "ENCR"))
331           tmp.flags |= KEYFLAG_PREFER_ENCRYPTION;
332         if (strstr (p, "SIGN"))
333           tmp.flags |= KEYFLAG_PREFER_SIGNING;
334
335         break;
336       }
337       case 11:                  /* signature class  */
338         break;
339       case 12:                  /* key capabilities */
340         dprint (2, (debugfile, "capabilities info: %s\n", p));
341
342         while (*p)
343         {
344           switch (*p++)
345           {
346             case 'D':
347               flags |= KEYFLAG_DISABLED;
348               break;
349
350             case 'e':
351               flags |= KEYFLAG_CANENCRYPT;
352               break;
353
354             case 's':
355               flags |= KEYFLAG_CANSIGN;
356               break;
357           }
358         }
359
360         if (!is_uid &&
361             (!*is_subkey || !option (OPTPGPIGNORESUB)
362              || !((flags & KEYFLAG_DISABLED)
363                   || (flags & KEYFLAG_REVOKED)
364                   || (flags & KEYFLAG_EXPIRED))))
365           tmp.flags |= flags;
366
367         break;
368
369       default:
370         break;
371     }
372   }
373
374   /* merge temp key back into real key */
375   if (!(is_uid || is_fpr || (*is_subkey && option (OPTPGPIGNORESUB))))
376     k = safe_malloc (sizeof (*k));
377   memcpy (k, &tmp, sizeof (*k));
378   /* fixup parentship of uids after mering the temp key into
379    * the real key */
380   if (tmp.address)
381   {
382     for (uid = k->address; uid; uid = uid->next)
383       uid->parent = k;
384   }
385
386   return k;
387
388 bail:
389   dprint(5,(debugfile,"parse_pub_line: invalid number: '%s'\n", p));
390   return NULL;
391 }
392
393 pgp_key_t pgp_get_candidates (pgp_ring_t keyring, LIST * hints)
394 {
395   FILE *fp;
396   pid_t thepid;
397   char buf[LONG_STRING];
398   pgp_key_t db = NULL, *kend, k = NULL, kk, mainkey = NULL;
399   int is_sub;
400   int devnull;
401
402   if ((devnull = open ("/dev/null", O_RDWR)) == -1)
403     return NULL;
404
405   mutt_str_replace (&_chs, Charset);
406
407   thepid = pgp_invoke_list_keys (NULL, &fp, NULL, -1, -1, devnull,
408                                  keyring, hints);
409   if (thepid == -1)
410   {
411     close (devnull);
412     return NULL;
413   }
414
415   kend = &db;
416   k = NULL;
417   while (fgets (buf, sizeof (buf) - 1, fp))
418   {
419     if (!(kk = parse_pub_line (buf, &is_sub, k)))
420       continue;
421
422     /* Only append kk to the list if it's new. */
423     if (kk != k)
424     {
425       if (k)
426         kend = &k->next;
427       *kend = k = kk;
428
429       if (is_sub)
430       {
431         pgp_uid_t **l;
432
433         k->flags  |= KEYFLAG_SUBKEY;
434         k->parent  = mainkey;
435         for (l = &k->address; *l; l = &(*l)->next)
436           ;
437         *l = pgp_copy_uids (mainkey->address, k);
438       }
439       else
440         mainkey = k;
441     }
442   }
443
444   if (ferror (fp))
445     mutt_perror ("fgets");
446
447   safe_fclose (&fp);
448   mutt_wait_filter (thepid);
449
450   close (devnull);
451
452   return db;
453 }