mutt stable branch with some hacks
at master 445 lines 9.7 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 char tstr[11]; 250 struct tm time; 251 252 dprint (2, (debugfile, "time stamp: %s\n", p)); 253 254 if (!p) 255 break; 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 break; 281 } 282 case 7: /* valid for n days */ 283 break; 284 case 8: /* Local id */ 285 break; 286 case 9: /* ownertrust */ 287 break; 288 case 10: /* name */ 289 { 290 /* Empty field or no trailing colon. 291 * We allow an empty field for a pub record type because it is 292 * possible for a primary uid record to have an empty User-ID 293 * field. Without any address records, it is not possible to 294 * use the key in mutt. 295 */ 296 if (!(pend && (*p || is_pub))) 297 break; 298 299 if (is_fpr) 300 { 301 /* don't let a subkey fpr overwrite an existing primary key fpr */ 302 if (!tmp.fingerprint) 303 tmp.fingerprint = safe_strdup (p); 304 break; 305 } 306 307 /* ignore user IDs on subkeys */ 308 if (!is_uid && (*is_subkey && option (OPTPGPIGNORESUB))) 309 break; 310 311 dprint (2, (debugfile, "user ID: %s\n", NONULL (p))); 312 313 uid = safe_calloc (sizeof (pgp_uid_t), 1); 314 fix_uid (p); 315 uid->addr = safe_strdup (p); 316 uid->trust = trust; 317 uid->flags |= flags; 318 uid->next = tmp.address; 319 tmp.address = uid; 320 321 if (strstr (p, "ENCR")) 322 tmp.flags |= KEYFLAG_PREFER_ENCRYPTION; 323 if (strstr (p, "SIGN")) 324 tmp.flags |= KEYFLAG_PREFER_SIGNING; 325 326 break; 327 } 328 case 11: /* signature class */ 329 break; 330 case 12: /* key capabilities */ 331 dprint (2, (debugfile, "capabilities info: %s\n", p)); 332 333 while(*p) 334 { 335 switch(*p++) 336 { 337 case 'D': 338 flags |= KEYFLAG_DISABLED; 339 break; 340 341 case 'e': 342 flags |= KEYFLAG_CANENCRYPT; 343 break; 344 345 case 's': 346 flags |= KEYFLAG_CANSIGN; 347 break; 348 } 349 } 350 351 if (!is_uid && 352 (!*is_subkey || !option (OPTPGPIGNORESUB) 353 || !((flags & KEYFLAG_DISABLED) 354 || (flags & KEYFLAG_REVOKED) 355 || (flags & KEYFLAG_EXPIRED)))) 356 tmp.flags |= flags; 357 358 break; 359 360 default: 361 break; 362 } 363 } 364 365 /* merge temp key back into real key */ 366 if (!(is_uid || is_fpr || (*is_subkey && option (OPTPGPIGNORESUB)))) 367 k = safe_malloc (sizeof (*k)); 368 memcpy (k, &tmp, sizeof (*k)); 369 /* fixup parentship of uids after mering the temp key into 370 * the real key */ 371 if (tmp.address) 372 { 373 for (uid = k->address; uid; uid = uid->next) 374 uid->parent = k; 375 } 376 377 return k; 378 379bail: 380 dprint(5,(debugfile,"parse_pub_line: invalid number: '%s'\n", p)); 381 return NULL; 382} 383 384pgp_key_t pgp_get_candidates (pgp_ring_t keyring, LIST * hints) 385{ 386 FILE *fp; 387 pid_t thepid; 388 char buf[LONG_STRING]; 389 pgp_key_t db = NULL, *kend, k = NULL, kk, mainkey = NULL; 390 int is_sub; 391 int devnull; 392 393 if ((devnull = open ("/dev/null", O_RDWR)) == -1) 394 return NULL; 395 396 mutt_str_replace (&_chs, Charset); 397 398 thepid = pgp_invoke_list_keys (NULL, &fp, NULL, -1, -1, devnull, 399 keyring, hints); 400 if (thepid == -1) 401 { 402 close (devnull); 403 return NULL; 404 } 405 406 kend = &db; 407 k = NULL; 408 while (fgets (buf, sizeof (buf) - 1, fp)) 409 { 410 if (!(kk = parse_pub_line (buf, &is_sub, k))) 411 continue; 412 413 /* Only append kk to the list if it's new. */ 414 if (kk != k) 415 { 416 if (k) 417 kend = &k->next; 418 *kend = k = kk; 419 420 if (is_sub) 421 { 422 pgp_uid_t **l; 423 424 k->flags |= KEYFLAG_SUBKEY; 425 k->parent = mainkey; 426 for (l = &k->address; *l; l = &(*l)->next) 427 ; 428 *l = pgp_copy_uids (mainkey->address, k); 429 } 430 else 431 mainkey = k; 432 } 433 } 434 435 if (ferror (fp)) 436 mutt_perror ("fgets"); 437 438 safe_fclose (&fp); 439 mutt_wait_filter (thepid); 440 441 close (devnull); 442 443 return db; 444} 445