mutt stable branch with some hacks
at jcs 453 lines 10 kB view raw
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 74static char *_chs = 0; 75 76static 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 119static 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 388bail: 389 dprint(5,(debugfile,"parse_pub_line: invalid number: '%s'\n", p)); 390 return NULL; 391} 392 393pgp_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}