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