]> git.llucax.com Git - software/mutt-debian.git/blob - gnupgparse.c
Update and enable NNTP patch
[software/mutt-debian.git] / 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   char *pend, *p;
124   int trust = 0;
125   int flags = 0;
126   struct pgp_keyinfo tmp;
127
128   *is_subkey = 0;
129   if (!*buf)
130     return NULL;
131
132   /* if we're given a key, merge our parsing results, else
133    * start with a fresh one to work with so that we don't
134    * mess up the real key in case we find parsing errors. */
135   if (k)
136     memcpy (&tmp, k, sizeof (tmp));
137   else
138     memset (&tmp, 0, sizeof (tmp));
139
140   dprint (2, (debugfile, "parse_pub_line: buf = `%s'\n", buf));
141
142   for (p = buf; p; p = pend)
143   {
144     if ((pend = strchr (p, ':')))
145       *pend++ = 0;
146     field++;
147     if (field > 1 && !*p)
148       continue;
149
150     switch (field)
151     {
152       case 1:                   /* record type */
153       {
154         dprint (2, (debugfile, "record type: %s\n", p));
155
156         if (!mutt_strcmp (p, "pub"))
157           ;
158         else if (!mutt_strcmp (p, "sub"))
159           *is_subkey = 1;
160         else if (!mutt_strcmp (p, "sec"))
161           ;
162         else if (!mutt_strcmp (p, "ssb"))
163           *is_subkey = 1;
164         else if (!mutt_strcmp (p, "uid"))
165           is_uid = 1;
166         else
167           return NULL;
168
169         if (!(is_uid || (*is_subkey && option (OPTPGPIGNORESUB))))
170           memset (&tmp, 0, sizeof (tmp));
171
172         break;
173       }
174       case 2:                   /* trust info */
175       {
176         dprint (2, (debugfile, "trust info: %s\n", p));
177
178         switch (*p)
179         {                               /* look only at the first letter */
180           case 'e':
181             flags |= KEYFLAG_EXPIRED;
182             break;
183           case 'r':
184             flags |= KEYFLAG_REVOKED;
185             break;
186           case 'd':
187             flags |= KEYFLAG_DISABLED;
188             break;
189           case 'n':
190             trust = 1;
191             break;
192           case 'm':
193             trust = 2;
194             break;
195           case 'f':
196             trust = 3;
197             break;
198           case 'u':
199             trust = 3;
200             break;
201         }
202
203         if (!is_uid && !(*is_subkey && option (OPTPGPIGNORESUB)))
204           tmp.flags |= flags;
205
206         break;
207       }
208       case 3:                   /* key length  */
209       {
210         dprint (2, (debugfile, "key len: %s\n", p));
211
212         if (!(*is_subkey && option (OPTPGPIGNORESUB)) &&
213             mutt_atos (p, &tmp.keylen) < 0)
214           goto bail;
215         break;
216       }
217       case 4:                   /* pubkey algo */
218       {
219         dprint (2, (debugfile, "pubkey algorithm: %s\n", p));
220
221         if (!(*is_subkey && option (OPTPGPIGNORESUB)))
222         {
223           int x = 0;
224           if (mutt_atoi (p, &x) < 0)
225             goto bail;
226           tmp.numalg = x;
227           tmp.algorithm = pgp_pkalgbytype (x);
228         }
229         break;
230       }
231       case 5:                   /* 16 hex digits with the long keyid. */
232       {
233         dprint (2, (debugfile, "key id: %s\n", p));
234
235         if (!(*is_subkey && option (OPTPGPIGNORESUB)))
236           mutt_str_replace (&tmp.keyid, p);
237         break;
238
239       }
240       case 6:                   /* timestamp (1998-02-28) */
241       {
242         char tstr[11];
243         struct tm time;
244
245         dprint (2, (debugfile, "time stamp: %s\n", p));
246
247         if (!p)
248           break;
249         time.tm_sec = 0;
250         time.tm_min = 0;
251         time.tm_hour = 12;
252         strncpy (tstr, p, 11);
253         tstr[4] = '\0';
254         tstr[7] = '\0';
255         if (mutt_atoi (tstr, &time.tm_year) < 0)
256         {
257           p = tstr;
258           goto bail;
259         }
260         time.tm_year -= 1900;
261         if (mutt_atoi (tstr+5, &time.tm_mon) < 0)
262         {
263           p = tstr+5;
264           goto bail;
265         }
266         time.tm_mon -= 1;
267         if (mutt_atoi (tstr+8, &time.tm_mday) < 0)
268         {
269           p = tstr+8;
270           goto bail;
271         }
272         tmp.gen_time = mutt_mktime (&time, 0);
273         break;
274       }
275       case 7:                   /* valid for n days */
276         break;
277       case 8:                   /* Local id         */
278         break;
279       case 9:                   /* ownertrust       */
280         break;
281       case 10:                  /* name             */
282       {
283         if (!pend || !*p)
284           break;                        /* empty field or no trailing colon */
285
286         /* ignore user IDs on subkeys */
287         if (!is_uid && (*is_subkey && option (OPTPGPIGNORESUB)))
288           break;
289
290         dprint (2, (debugfile, "user ID: %s\n", p));
291
292         uid = safe_calloc (sizeof (pgp_uid_t), 1);
293         fix_uid (p);
294         uid->addr = safe_strdup (p);
295         uid->trust = trust;
296         uid->flags |= flags;
297         uid->next = tmp.address;
298         tmp.address = uid;
299
300         if (strstr (p, "ENCR"))
301           tmp.flags |= KEYFLAG_PREFER_ENCRYPTION;
302         if (strstr (p, "SIGN"))
303           tmp.flags |= KEYFLAG_PREFER_SIGNING;
304
305         break;
306       }
307       case 11:                  /* signature class  */
308         break;
309       case 12:                  /* key capabilities */
310         dprint (2, (debugfile, "capabilities info: %s\n", p));
311         
312         while(*p)
313           {
314             switch(*p++)
315               {
316               case 'D':
317                 flags |= KEYFLAG_DISABLED;
318                 break;
319
320               case 'e':
321                 flags |= KEYFLAG_CANENCRYPT;
322                 break;
323
324               case 's':
325                 flags |= KEYFLAG_CANSIGN;
326                 break;
327               }
328           }
329
330         if (!is_uid && 
331             (!*is_subkey || !option (OPTPGPIGNORESUB)
332              || !((flags & KEYFLAG_DISABLED)
333                   || (flags & KEYFLAG_REVOKED)
334                   || (flags & KEYFLAG_EXPIRED))))
335           tmp.flags |= flags;
336
337         break;
338       
339       default:
340         break;
341     }
342   }
343
344   /* merge temp key back into real key */
345   if (!(is_uid || (*is_subkey && option (OPTPGPIGNORESUB))))
346     k = safe_malloc (sizeof (*k));
347   memcpy (k, &tmp, sizeof (*k));
348   /* fixup parentship of uids after mering the temp key into
349    * the real key */
350   if (tmp.address)
351   {
352     for (uid = k->address; uid; uid = uid->next)
353       uid->parent = k;
354   }
355
356   return k;
357
358 bail:
359   dprint(5,(debugfile,"parse_pub_line: invalid number: '%s'\n", p));
360   return NULL;
361 }
362
363 pgp_key_t pgp_get_candidates (pgp_ring_t keyring, LIST * hints)
364 {
365   FILE *fp;
366   pid_t thepid;
367   char buf[LONG_STRING];
368   pgp_key_t db = NULL, *kend, k = NULL, kk, mainkey = NULL;
369   int is_sub;
370   int devnull;
371
372   if ((devnull = open ("/dev/null", O_RDWR)) == -1)
373     return NULL;
374
375   mutt_str_replace (&_chs, Charset);
376   
377   thepid = pgp_invoke_list_keys (NULL, &fp, NULL, -1, -1, devnull,
378                                  keyring, hints);
379   if (thepid == -1)
380   {
381     close (devnull);
382     return NULL;
383   }
384
385   kend = &db;
386   k = NULL;
387   while (fgets (buf, sizeof (buf) - 1, fp))
388   {
389     if (!(kk = parse_pub_line (buf, &is_sub, k)))
390       continue;
391
392     /* Only append kk to the list if it's new. */
393     if (kk != k)
394     {
395       if (k)
396         kend = &k->next;
397       *kend = k = kk;
398
399       if (is_sub)
400       {
401         pgp_uid_t **l;
402         
403         k->flags  |= KEYFLAG_SUBKEY;
404         k->parent  = mainkey;
405         for (l = &k->address; *l; l = &(*l)->next)
406           ;
407         *l = pgp_copy_uids (mainkey->address, k);
408       }
409       else
410         mainkey = k;
411     }
412   }
413
414   if (ferror (fp))
415     mutt_perror ("fgets");
416
417   safe_fclose (&fp);
418   mutt_wait_filter (thepid);
419
420   close (devnull);
421   
422   return db;
423 }
424