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