drop mem_alloc and mem_free, use my own hand crafted optmized macros that
[apps/madmutt.git] / gnupgparse.c
1 /*
2  * Copyright notice from original mutt:
3  * Copyright (C) 1998-2000 Werner Koch <werner.koch@guug.de>
4  * Copyright (C) 1999-2000 Thomas Roessler <roessler@does-not-exist.org>
5  *
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.
9  */
10
11 /*
12  * NOTE
13  * 
14  * This code used to be the parser for GnuPG's output.
15  * 
16  * Nowadays, we are using an external pubring lister with PGP which mimics 
17  * gpg's output format.
18  * 
19  */
20
21 #if HAVE_CONFIG_H
22 # include "config.h"
23 #endif
24
25 #include <stdio.h>
26 #include <stdlib.h>
27 #include <string.h>
28
29 #include <sys/types.h>
30 #include <sys/stat.h>
31 #include <unistd.h>
32 #include <fcntl.h>
33 #include <time.h>
34 #include <ctype.h>
35
36 #include <lib-lib/mem.h>
37
38 #include "mutt.h"
39 #include "pgp.h"
40 #include "charset.h"
41
42 /* for hexval */
43 #include "mime.h"
44
45 #include "lib/mem.h"
46 #include "lib/str.h"
47 #include "lib/debug.h"
48
49 /****************
50  * Read the GNUPG keys.  For now we read the complete keyring by
51  * calling gnupg in a special mode.
52  *
53  * The output format of gpgm is colon delimited with these fields:
54  *   - record type ("pub","uid","sig","rev" etc.)
55  *   - trust info
56  *   - key length
57  *   - pubkey algo
58  *   - 16 hex digits with the long keyid.
59  *   - timestamp (1998-02-28)
60  *   - Local id
61  *   - ownertrust
62  *   - name
63  *   - signature class
64  */
65
66 /* decode the backslash-escaped user ids. */
67
68 static char *_chs = 0;
69
70 static void fix_uid (char *uid)
71 {
72   char *s, *d;
73   iconv_t cd;
74
75   for (s = d = uid; *s;) {
76     if (*s == '\\' && *(s + 1) == 'x' && isxdigit ((unsigned char) *(s + 2))
77         && isxdigit ((unsigned char) *(s + 3))) {
78       *d++ = hexval (*(s + 2)) << 4 | hexval (*(s + 3));
79       s += 4;
80     }
81     else
82       *d++ = *s++;
83   }
84   *d = '\0';
85
86   if (_chs && (cd = mutt_iconv_open (_chs, "utf-8", 0)) != (iconv_t) - 1) {
87     int n = s - uid + 1;        /* chars available in original buffer */
88     char *buf;
89     const char *ib;
90     char *ob;
91     size_t ibl, obl;
92
93     buf = p_new(char, n + 1);
94     ib = uid, ibl = d - uid + 1, ob = buf, obl = n;
95     my_iconv(cd, &ib, &ibl, &ob, &obl);
96     if (!ibl) {
97       if (ob - buf < n) {
98         memcpy (uid, buf, ob - buf);
99         uid[ob - buf] = '\0';
100       }
101       else if (ob - buf == n && (buf[n] = 0, str_len (buf) < n))
102         memcpy (uid, buf, n);
103     }
104     p_delete(&buf);
105     iconv_close (cd);
106   }
107 }
108
109 static pgp_key_t parse_pub_line (char *buf, int *is_subkey, pgp_key_t k)
110 {
111   pgp_uid_t *uid = NULL;
112   int field = 0, is_uid = 0;
113   char *pend, *p;
114   int trust = 0;
115   int flags = 0;
116
117   *is_subkey = 0;
118   if (!*buf)
119     return NULL;
120
121   debug_print (2, ("buf = `%s'\n", buf));
122
123   for (p = buf; p; p = pend) {
124     if ((pend = strchr (p, ':')))
125       *pend++ = 0;
126     field++;
127     if (field > 1 && !*p)
128       continue;
129
130     switch (field) {
131     case 1:                    /* record type */
132       {
133         debug_print (2, ("record type: %s\n", p));
134
135         if (!str_cmp (p, "pub"));
136         else if (!str_cmp (p, "sub"))
137           *is_subkey = 1;
138         else if (!str_cmp (p, "sec"));
139         else if (!str_cmp (p, "ssb"))
140           *is_subkey = 1;
141         else if (!str_cmp (p, "uid"))
142           is_uid = 1;
143         else
144           return NULL;
145
146         if (!(is_uid || (*is_subkey && option (OPTPGPIGNORESUB))))
147           k = mem_calloc (sizeof *k, 1);
148
149         break;
150       }
151     case 2:                    /* trust info */
152       {
153         debug_print (2, ("trust info: %s\n", p));
154
155         switch (*p) {           /* look only at the first letter */
156         case 'e':
157           flags |= KEYFLAG_EXPIRED;
158           break;
159         case 'r':
160           flags |= KEYFLAG_REVOKED;
161           break;
162         case 'd':
163           flags |= KEYFLAG_DISABLED;
164           break;
165         case 'n':
166           trust = 1;
167           break;
168         case 'm':
169           trust = 2;
170           break;
171         case 'f':
172           trust = 3;
173           break;
174         case 'u':
175           trust = 3;
176           break;
177         }
178
179         if (!is_uid && !(*is_subkey && option (OPTPGPIGNORESUB)))
180           k->flags |= flags;
181
182         break;
183       }
184     case 3:                    /* key length  */
185       {
186
187         debug_print (2, ("key len: %s\n", p));
188
189         if (!(*is_subkey && option (OPTPGPIGNORESUB)))
190           k->keylen = atoi (p); /* fixme: add validation checks */
191         break;
192       }
193     case 4:                    /* pubkey algo */
194       {
195
196         debug_print (2, ("pubkey algorithm: %s\n", p));
197
198         if (!(*is_subkey && option (OPTPGPIGNORESUB))) {
199           k->numalg = atoi (p);
200           k->algorithm = pgp_pkalgbytype (atoi (p));
201         }
202         break;
203       }
204     case 5:                    /* 16 hex digits with the long keyid. */
205       {
206         debug_print (2, ("key id: %s\n", p));
207
208         if (!(*is_subkey && option (OPTPGPIGNORESUB)))
209           str_replace (&k->keyid, p);
210         break;
211
212       }
213     case 6:                    /* timestamp (1998-02-28) */
214       {
215         char tstr[11];
216         struct tm time;
217
218         debug_print (2, ("time stamp: %s\n", p));
219
220         if (!p)
221           break;
222         time.tm_sec = 0;
223         time.tm_min = 0;
224         time.tm_hour = 12;
225         strncpy (tstr, p, 11);
226         tstr[4] = '\0';
227         time.tm_year = atoi (tstr) - 1900;
228         tstr[7] = '\0';
229         time.tm_mon = (atoi (tstr + 5)) - 1;
230         time.tm_mday = atoi (tstr + 8);
231         k->gen_time = mutt_mktime (&time, 0);
232         break;
233       }
234     case 7:                    /* valid for n days */
235       break;
236     case 8:                    /* Local id         */
237       break;
238     case 9:                    /* ownertrust       */
239       break;
240     case 10:                   /* name             */
241       {
242         if (!pend || !*p)
243           break;                /* empty field or no trailing colon */
244
245         /* ignore user IDs on subkeys */
246         if (!is_uid && (*is_subkey && option (OPTPGPIGNORESUB)))
247           break;
248
249         debug_print (2, ("user ID: %s\n", p));
250
251         uid = mem_calloc (sizeof (pgp_uid_t), 1);
252         fix_uid (p);
253         uid->addr = str_dup (p);
254         uid->trust = trust;
255         uid->flags |= flags;
256         uid->parent = k;
257         uid->next = k->address;
258         k->address = uid;
259
260         if (strstr (p, "ENCR"))
261           k->flags |= KEYFLAG_PREFER_ENCRYPTION;
262         if (strstr (p, "SIGN"))
263           k->flags |= KEYFLAG_PREFER_SIGNING;
264
265         break;
266       }
267     case 11:                   /* signature class  */
268       break;
269     case 12:                   /* key capabilities */
270       debug_print (2, ("capabilities info: %s\n", p));
271
272       while (*p) {
273         switch (*p++) {
274         case 'D':
275           flags |= KEYFLAG_DISABLED;
276           break;
277
278         case 'e':
279           flags |= KEYFLAG_CANENCRYPT;
280           break;
281
282         case 's':
283           flags |= KEYFLAG_CANSIGN;
284           break;
285         }
286       }
287
288       if (!is_uid && (!*is_subkey || !option (OPTPGPIGNORESUB)
289                       || !((flags & KEYFLAG_DISABLED)
290                            || (flags & KEYFLAG_REVOKED)
291                            || (flags & KEYFLAG_EXPIRED))))
292         k->flags |= flags;
293
294       break;
295
296     default:
297       break;
298     }
299   }
300   return k;
301 }
302
303 pgp_key_t pgp_get_candidates (pgp_ring_t keyring, LIST * hints)
304 {
305   FILE *fp;
306   pid_t thepid;
307   char buf[LONG_STRING];
308   pgp_key_t db = NULL, *kend, k = NULL, kk, mainkey = NULL;
309   int is_sub;
310   int devnull;
311
312   if ((devnull = open ("/dev/null", O_RDWR)) == -1)
313     return NULL;
314
315   str_replace (&_chs, Charset);
316
317   thepid = pgp_invoke_list_keys (NULL, &fp, NULL, -1, -1, devnull,
318                                  keyring, hints);
319   if (thepid == -1) {
320     close (devnull);
321     return NULL;
322   }
323
324   kend = &db;
325   k = NULL;
326   while (fgets (buf, sizeof (buf) - 1, fp)) {
327     if (!(kk = parse_pub_line (buf, &is_sub, k)))
328       continue;
329
330     /* Only append kk to the list if it's new. */
331     if (kk != k) {
332       if (k)
333         kend = &k->next;
334       *kend = k = kk;
335
336       if (is_sub) {
337         pgp_uid_t **l;
338
339         k->flags |= KEYFLAG_SUBKEY;
340         k->parent = mainkey;
341         for (l = &k->address; *l; l = &(*l)->next);
342         *l = pgp_copy_uids (mainkey->address, k);
343       }
344       else
345         mainkey = k;
346     }
347   }
348
349   if (ferror (fp))
350     mutt_perror ("fgets");
351
352   fclose (fp);
353   mutt_wait_filter (thepid);
354
355   close (devnull);
356
357   return db;
358 }