|
|
1.1.1.6 ! root 1: /* keyadd.c - Keyring merging routines for PGP. ! 2: PGP: Pretty Good(tm) Privacy - public key cryptography for the masses. ! 3: ! 4: (c) Copyright 1990-1994 by Philip Zimmermann. All rights reserved. ! 5: The author assumes no liability for damages resulting from the use ! 6: of this software, even if the damage results from defects in this ! 7: software. No warranty is expressed or implied. ! 8: ! 9: Note that while most PGP source modules bear Philip Zimmermann's ! 10: copyright notice, many of them have been revised or entirely written ! 11: by contributors who frequently failed to put their names in their ! 12: code. Code that has been incorporated into PGP from other authors ! 13: was either originally published in the public domain or is used with ! 14: permission from the various authors. ! 15: ! 16: PGP is available for free to the public under certain restrictions. ! 17: See the PGP User's Guide (included in the release package) for ! 18: important information about licensing, patent restrictions on ! 19: certain algorithms, trademarks, copyrights, and export controls. ! 20: */ ! 21: ! 22: #include <stdio.h> ! 23: #include <stdlib.h> ! 24: #ifdef UNIX ! 25: #include <sys/types.h> ! 26: #endif ! 27: #include <time.h> ! 28: #include "mpilib.h" ! 29: #include "crypto.h" ! 30: #include "fileio.h" ! 31: #include "keymgmt.h" ! 32: #include "charset.h" ! 33: #include "mpiio.h" ! 34: #include "language.h" ! 35: #include "pgp.h" ! 36: #include "exitpgp.h" ! 37: #include "keyadd.h" ! 38: #include "keymaint.h" ! 39: ! 40: void gpk_close(void); ! 41: int gpk_open(char *keyfile); ! 42: int get_publickey(long *file_position, int *pktlen, byte *keyID, byte *timestamp, ! 43: byte *userid, unitptr n, unitptr e); ! 44: ! 45: static int ask_to_sign(byte *keyID, char *ringfile); ! 46: static boolean ask_first; ! 47: ! 48: static boolean publickey; /* if TRUE, add trust packets */ ! 49: ! 50: static int newkeys, newsigs, newids, newrvks; ! 51: static byte mykeyID[KEYFRAGSIZE]; ! 52: ! 53: static struct sig_list { ! 54: struct sig_list *next; ! 55: long pos; ! 56: } *siglist; ! 57: static void ! 58: sig_list_add(long pos) ! 59: { ! 60: struct sig_list *p; ! 61: p = xmalloc(sizeof *p); ! 62: p->pos = pos; ! 63: p->next = siglist; ! 64: siglist = p; ! 65: } ! 66: static int ! 67: sig_list_find(long pos) ! 68: { ! 69: struct sig_list *p; ! 70: for (p = siglist; p; p = p->next) ! 71: if (p->pos == pos) ! 72: return 1; ! 73: return 0; ! 74: } ! 75: static void ! 76: sig_list_clear(void) ! 77: { ! 78: struct sig_list *p, *n; ! 79: for (p = siglist; p; p = n) { ! 80: n = p->next; ! 81: free(p); ! 82: } ! 83: siglist = NULL; ! 84: } ! 85: static int mergesigs (FILE *fkey, char *keyfile, long keypos, FILE *fring, ! 86: char *ringfile, long *pringpos, FILE *out) ! 87: /* Merge signatures from userid in fkey (which is keyfile) at keypos with ! 88: * userid from fring (which is ringfile) at ringpos, appending result to out. ! 89: */ ! 90: { ! 91: long ringuseridpos, ringpos; ! 92: int ringpktlen, keypktlen; ! 93: int status; ! 94: byte ctb; ! 95: int copying; ! 96: word32 rstamp, kstamp, xstamp; ! 97: byte keyID[KEYFRAGSIZE]; ! 98: char userid[256]; ! 99: ! 100: /* First, copy the userid packet itself, plus any comments or ctrls */ ! 101: ringuseridpos = ringpos = *pringpos; ! 102: fseek (fring, ringpos, SEEK_SET); ! 103: (void) readkeypacket(fring,FALSE,&ctb,NULL,userid,NULL,NULL, ! 104: NULL,NULL,NULL,NULL,NULL,NULL); ! 105: PascalToC(userid); ! 106: ringpktlen = ftell(fring) - ringpos; ! 107: copyfilepos (fring, out, ringpktlen, ringpos); ! 108: for (;;) { ! 109: ringpos = ftell(fring); ! 110: status = nextkeypacket (fring, &ctb); ! 111: if (status < 0 || is_key_ctb(ctb) || ctb==CTB_USERID || ! 112: is_ctb_type(ctb,CTB_SKE_TYPE)) ! 113: break; ! 114: ringpktlen = ftell(fring) - ringpos; ! 115: copyfilepos (fring, out, ringpktlen, ringpos); ! 116: } ! 117: fseek (fring, ringpos, SEEK_SET); ! 118: ! 119: /* Now, ringpos points just past userid packet and ctrl packet. */ ! 120: /* Advance keypos to the analogous location. */ ! 121: fseek (fkey, keypos, SEEK_SET); ! 122: (void) nextkeypacket (fkey, &ctb); ! 123: for (;;) { ! 124: keypos = ftell(fkey); ! 125: status = nextkeypacket (fkey, &ctb); ! 126: if (status < 0 || is_key_ctb(ctb) || ctb==CTB_USERID || ! 127: is_ctb_type(ctb,CTB_SKE_TYPE)) ! 128: break; ! 129: } ! 130: fseek (fkey, keypos, SEEK_SET); ! 131: ! 132: /* Second, copy all keyfile signatures that aren't in ringfile. ! 133: */ ! 134: ! 135: copying = FALSE; ! 136: for (;;) { ! 137: /* Read next sig from keyfile; see if it is in ringfile; ! 138: * if it is not a signature, ignore it, ! 139: * if it is absent from ringfile, copy it, ! 140: * if it is present, and the timestamp is not newer, ignore it, ! 141: * if present and newer, replace old with new. ! 142: * Loop till hit a new key or userid in keyfile, or EOF. ! 143: */ ! 144: keypos = ftell(fkey); ! 145: status = readkeypacket(fkey,FALSE,&ctb,(byte *)&kstamp,NULL,NULL,NULL, ! 146: NULL,NULL,NULL,NULL,keyID,NULL); ! 147: if (status == -3) /* unrecoverable error: bad packet length etc. */ ! 148: return status; ! 149: keypktlen = ftell(fkey) - keypos; ! 150: if (status == -1 || is_key_ctb (ctb) || ctb==CTB_USERID) ! 151: break; /* EOF or next key/userid */ ! 152: if (status < 0) ! 153: continue; /* bad packet, skip it */ ! 154: if (is_ctb_type(ctb,CTB_SKE_TYPE)) { ! 155: long sig_pos; ! 156: int sig_len; ! 157: /* Set copying true if signature is not in the ringfile */ ! 158: copying = (getpubusersig (ringfile, ringuseridpos, ! 159: keyID, (byte *)&rstamp, ! 160: &sig_pos, ! 161: &sig_len) < 0); ! 162: if (!copying) { ! 163: long save_pos = ftell(fkey); ! 164: fseek(fkey, keypos+6, SEEK_SET); ! 165: fread(&kstamp,1,SIZEOF_TIMESTAMP,fkey); ! 166: fseek(fkey, save_pos, SEEK_SET); ! 167: convert_byteorder((byte *)&kstamp,SIZEOF_TIMESTAMP); ! 168: if (verbose) ! 169: fprintf(pgpout, "ring: %lx key: %lx\n", rstamp, kstamp); ! 170: if (kstamp > rstamp) { /* Update, Maybe*/ ! 171: char *signator; ! 172: if ((signator = user_from_keyID(keyID)) == NULL) { ! 173: fprintf(pgpout, LANG("Replacing signature from keyID %s on userid \"%s\"\n"), keyIDstring(keyID), LOCAL_CHARSET(userid)); ! 174: /* No pubkey for KeyID, no update! */ ! 175: } else { ! 176: long save_keypos; ! 177: long save_ringpos; ! 178: long KeyIDpos, KeyIDlen; ! 179: byte sigClass; ! 180: fprintf(pgpout, LANG("Verifying signature from %s\n"), LOCAL_CHARSET(signator)); ! 181: fprintf(pgpout, LANG("on userid \"%s\"\n"), LOCAL_CHARSET(userid)); ! 182: save_keypos = ftell(fkey); ! 183: save_ringpos = ftell(fring); ! 184: status = getpublickey(GPK_GIVEUP, ringfile, &KeyIDpos, &KeyIDlen, NULL, NULL, userid, NULL, NULL); ! 185: if (!status) ! 186: status = check_key_sig (fring, KeyIDpos, KeyIDlen, userid, fkey, keypos, ringfile, signator, (byte *)&xstamp, &sigClass); ! 187: PascalToC(userid); ! 188: PascalToC(signator); ! 189: if (!status) { ! 190: fprintf(pgpout, LANG("Replacing signature from %s\n"), LOCAL_CHARSET(signator)); ! 191: fprintf(pgpout, LANG("on userid \"%s\"\n"), LOCAL_CHARSET(userid)); ! 192: sig_list_add(sig_pos); ! 193: ++newsigs; ! 194: copying = 1; ! 195: } else ! 196: fprintf(pgpout, LANG("Verification Failed\n")); ! 197: fseek(fring, save_ringpos, SEEK_SET); ! 198: fseek(fkey, save_keypos, SEEK_SET); ! 199: } ! 200: } ! 201: } else { ! 202: char *signator; ! 203: if ((signator = user_from_keyID(keyID)) == NULL) ! 204: fprintf(pgpout, LANG("New signature from keyID %s on userid \"%s\"\n"), ! 205: keyIDstring(keyID), LOCAL_CHARSET(userid)); ! 206: else { ! 207: ! 208: fprintf(pgpout, LANG("New signature from %s\n"), LOCAL_CHARSET(signator)); ! 209: fprintf(pgpout, LANG("on userid \"%s\"\n"), LOCAL_CHARSET(userid)); ! 210: } ! 211: ++newsigs; ! 212: if (batchmode) ! 213: show_update(keyIDstring(mykeyID)); ! 214: } ! 215: } ! 216: if (copying && is_ctb_type(ctb,CTB_SKE_TYPE)) { ! 217: copyfilepos (fkey, out, keypktlen, keypos); ! 218: if (publickey) ! 219: write_trust (out, KC_SIGTRUST_UNDEFINED); ! 220: } ! 221: } ! 222: ! 223: /* Third, for all ring sig's which are not replaced, copy to output */ ! 224: fseek (fring, ringpos, SEEK_SET); ! 225: for (;;) { ! 226: ringpos = ftell(fring); ! 227: if (sig_list_find(ringpos)) { ! 228: /* skip signature packet */ ! 229: nextkeypacket (fring, &ctb); ! 230: ringpos = ftell(fring); ! 231: /* skip trust packet, if present */ ! 232: if (nextkeypacket (fring, &ctb) < 0 || ctb != CTB_KEYCTRL) ! 233: fseek(fring, ringpos, SEEK_SET); ! 234: continue; ! 235: } ! 236: status = nextkeypacket (fring, &ctb); ! 237: ringpktlen = ftell(fring) - ringpos; ! 238: if (status < 0 || is_key_ctb (ctb) || ctb==CTB_USERID) ! 239: break; ! 240: copyfilepos (fring, out, ringpktlen, ringpos); ! 241: } /* End of loop for each sig in ringfile */ ! 242: sig_list_clear(); ! 243: fseek (fring, ringpos, SEEK_SET); ! 244: *pringpos = ringpos; ! 245: return 0; ! 246: } /* mergesigs */ ! 247: ! 248: ! 249: static int mergekeys (FILE *fkey, char *keyfile, long keypos, FILE *fring, ! 250: char *ringfile, long *pringpos, FILE *out) ! 251: /* Merge key from fkey (which is keyfile) at keypos with key from ! 252: * fring (which is ringfile) at ringpos, appending result to out. ! 253: */ ! 254: { ! 255: long ringkeypos, keykeypos, ringpos; ! 256: int ringpktlen, keypktlen; ! 257: int status; ! 258: byte ctb; ! 259: int copying; ! 260: boolean ring_compromise = FALSE; ! 261: byte userid[256]; ! 262: ! 263: /* First, copy the key packet itself, plus any comments or ctrls */ ! 264: ringkeypos = ringpos = *pringpos; ! 265: fseek (fring, ringpos, SEEK_SET); ! 266: (void) nextkeypacket(fring, &ctb); ! 267: ringpktlen = ftell(fring) - ringpos; ! 268: copyfilepos (fring, out, ringpktlen, ringpos); ! 269: for (;;) { ! 270: ringpos = ftell(fring); ! 271: status = nextkeypacket (fring, &ctb); ! 272: if (status < 0 || is_key_ctb(ctb) || ctb==CTB_USERID) ! 273: break; ! 274: if (is_ctb_type(ctb, CTB_SKE_TYPE)) ! 275: ring_compromise = TRUE; /* compromise cert on keyring */ ! 276: ringpktlen = ftell(fring) - ringpos; ! 277: copyfilepos (fring, out, ringpktlen, ringpos); ! 278: } ! 279: fseek (fring, ringpos, SEEK_SET); ! 280: ! 281: /* Now, ringpos points just past key packet and ctrl packet. */ ! 282: /* Advance keypos to the analogous location. */ ! 283: fseek (fkey, keypos, SEEK_SET); ! 284: keykeypos = keypos; ! 285: (void) nextkeypacket (fkey, &ctb); ! 286: keypktlen = ftell(fkey) - keypos; /* for check_key_sig() */ ! 287: for (;;) { ! 288: keypos = ftell(fkey); ! 289: status = nextkeypacket (fkey, &ctb); ! 290: if (status < 0 || ctb == CTB_USERID || is_ctb_type(ctb, CTB_SKE_TYPE)) ! 291: break; ! 292: } ! 293: if (!ring_compromise && is_ctb_type(ctb, CTB_SKE_TYPE)) { ! 294: /* found a compromise cert on keyfile that is not in ringfile */ ! 295: word32 timestamp; ! 296: byte sig_class; ! 297: int cert_pktlen; ! 298: ! 299: cert_pktlen = ftell(fkey) - keypos; ! 300: if (check_key_sig(fkey, keykeypos, keypktlen, (char *)userid, fkey, keypos, ! 301: ringfile, (char *)userid, (byte *)×tamp, &sig_class) == 0 && ! 302: sig_class == KC_SIGNATURE_BYTE) ! 303: { ! 304: PascalToC((char *)userid); ! 305: fprintf(pgpout, LANG("Key revocation certificate from \"%s\".\n"), ! 306: LOCAL_CHARSET((char *)userid)); ! 307: copyfilepos (fkey, out, cert_pktlen, keypos); ! 308: /* Show updates */ ! 309: if (batchmode) ! 310: show_key(fring, *pringpos, SHOW_CHANGE); ! 311: ++newrvks; ! 312: } ! 313: else ! 314: fprintf(pgpout, LANG("\n\007WARNING: File '%s' contains bad revocation certificate.\n"), keyfile); ! 315: } ! 316: fseek (fkey, keypos, SEEK_SET); ! 317: ! 318: /* Second, copy all keyfile userid's plus signatures that aren't ! 319: * in ringfile. ! 320: */ ! 321: ! 322: copying = FALSE; ! 323: for (;;) { ! 324: /* Read next userid from keyfile; see if it is in ringfile; ! 325: * set copying true/false accordingly. If copying is true ! 326: * and it is a userid or a signature, copy it. Loop till hit ! 327: * a new key in keyfile, or EOF. ! 328: */ ! 329: keypos = ftell(fkey); ! 330: status = readkeypacket(fkey,FALSE,&ctb,NULL,(char *)userid,NULL, ! 331: NULL, NULL,NULL,NULL,NULL,NULL,NULL); ! 332: if (status == -3) /* unrecoverable error: bad packet length etc. */ ! 333: return status; ! 334: keypktlen = ftell(fkey) - keypos; ! 335: if (status == -1 || is_key_ctb (ctb)) ! 336: break; /* EOF or next key */ ! 337: if (status < 0) ! 338: continue; /* bad packet, skip it */ ! 339: if (ctb == CTB_USERID) { ! 340: long userid_pos; ! 341: int userid_len; ! 342: PascalToC ((char *)userid); ! 343: /* Set copying true if userid is not in the ringfile */ ! 344: copying = (getpubuserid (ringfile, ringkeypos, userid, &userid_pos, ! 345: &userid_len, TRUE) < 0); ! 346: if (copying) { ! 347: putc('\n', pgpout); ! 348: fprintf (pgpout, LANG("New userid: \"%s\".\n"), ! 349: LOCAL_CHARSET((char *)userid)); ! 350: fprintf(pgpout, LANG("\nWill be added to the following key:\n")); ! 351: show_key(fring, *pringpos, 0); ! 352: fprintf(pgpout, LANG("\nAdd this userid (y/N)? ")); ! 353: if (batchmode || getyesno('n')) { ! 354: ++newids; ! 355: /* Show an update string */ ! 356: if (batchmode) { ! 357: fprintf(pgpout, "\n"); ! 358: show_key(fring, *pringpos, SHOW_CHANGE); ! 359: } ! 360: } else { ! 361: copying = FALSE; ! 362: } ! 363: } ! 364: } ! 365: if (copying) { ! 366: if (ctb==CTB_USERID || is_ctb_type(ctb,CTB_SKE_TYPE)) ! 367: { ! 368: copyfilepos (fkey, out, keypktlen, keypos); ! 369: if (publickey) { ! 370: if (is_ctb_type(ctb,CTB_SKE_TYPE)) ! 371: write_trust (out, KC_SIGTRUST_UNDEFINED); ! 372: else ! 373: write_trust (out, KC_LEGIT_UNKNOWN); ! 374: } ! 375: } ! 376: } ! 377: } ! 378: ! 379: /* Third, for all ring userid's, if not in keyfile, copy the userid ! 380: * plus its dependant signatures. ! 381: */ ! 382: fseek (fring, ringpos, SEEK_SET); ! 383: /* Grab the keyID here */ ! 384: readkeypacket(fring,FALSE,&ctb,NULL,(char *)userid,NULL,NULL, ! 385: NULL,NULL,NULL,NULL,NULL,NULL); ! 386: fseek (fring, ringpos, SEEK_SET); ! 387: for (;;) { ! 388: ringpos = ftell(fring); ! 389: status = readkeypacket(fring,FALSE,&ctb,NULL,(char *)userid,NULL,NULL, ! 390: NULL,NULL,NULL,NULL,NULL,NULL); ! 391: ringpktlen = ftell(fring) - ringpos; ! 392: if (status == -3) ! 393: return status; ! 394: if (status == -1 || is_key_ctb (ctb)) ! 395: break; ! 396: if (ctb == CTB_USERID) { ! 397: long userid_pos; ! 398: int userid_len; ! 399: /* See if there is a match in keyfile */ ! 400: PascalToC ((char *) userid); ! 401: /* don't use substring match (exact_match = TRUE) */ ! 402: if (getpubuserid (keyfile, keykeypos, userid, ! 403: &userid_pos, &userid_len, TRUE) >= 0) ! 404: { ! 405: if ((status = mergesigs (fkey,keyfile,userid_pos,fring,ringfile,&ringpos,out)) < 0) ! 406: return status; ! 407: copying = FALSE; ! 408: } else { ! 409: copying = TRUE; ! 410: } ! 411: } ! 412: if (copying) { ! 413: /* Copy ringfile userid and sigs to out */ ! 414: copyfilepos (fring, out, ringpktlen, ringpos); ! 415: } ! 416: } /* End of loop for each key in ringfile */ ! 417: fseek (fring, ringpos, SEEK_SET); ! 418: *pringpos = ringpos; ! 419: return 0; ! 420: } /* mergekeys */ ! 421: ! 422: ! 423: int _addto_keyring(char *keyfile, char *ringfile) ! 424: /* Adds (prepends) key file to key ring file. */ ! 425: { ! 426: FILE *f, *g, *h; ! 427: long file_position,fp; ! 428: int pktlen; ! 429: byte ctb; ! 430: int status; ! 431: unit n[MAX_UNIT_PRECISION], e[MAX_UNIT_PRECISION]; ! 432: unit n1[MAX_UNIT_PRECISION]; ! 433: byte keyID[KEYFRAGSIZE]; ! 434: byte userid[256]; /* key certificate userid */ ! 435: byte userid1[256]; ! 436: word32 tstamp; ! 437: byte *timestamp = (byte *) &tstamp; /* key certificate timestamp */ ! 438: boolean userid_seen = FALSE; ! 439: int commonkeys = 0; ! 440: int copying; ! 441: struct newkey *nkey, *nkeys = NULL; ! 442: char *scratchf; ! 443: ! 444: /* open file f for read, in binary (not text) mode...*/ ! 445: if ((f = fopen(keyfile,FOPRBIN)) == NULL) { ! 446: fprintf(pgpout,LANG("\n\007Can't open key file '%s'\n"),keyfile); ! 447: return -1; ! 448: } ! 449: ctb = 0; ! 450: if (fread(&ctb, 1, 1, f) != 1 || !is_key_ctb(ctb)) { ! 451: fclose(f); ! 452: return -1; ! 453: } ! 454: rewind(f); ! 455: ! 456: setoutdir(ringfile); ! 457: scratchf = tempfile(0); ! 458: ! 459: /* ! 460: * get userids from both files, maybe should also use the default public ! 461: * keyring if ringfile is not the default ring. ! 462: */ ! 463: setkrent(ringfile); ! 464: setkrent(keyfile); ! 465: init_userhash(); ! 466: ! 467: if (!file_exists(ringfile)) { ! 468: /* ringfile does not exist. Can it be created? */ ! 469: /* open file g for writing, in binary (not text) mode...*/ ! 470: g = fopen(ringfile,FOPWBIN); ! 471: if (g==NULL) { ! 472: fprintf(pgpout,LANG("\nKey ring file '%s' cannot be created.\n"),ringfile); ! 473: fclose(f); ! 474: goto err; ! 475: } ! 476: fclose(g); ! 477: } ! 478: ! 479: /* Create working output file */ ! 480: /* open file g for writing, in binary (not text) mode...*/ ! 481: if ((g = fopen(scratchf,FOPWBIN)) == NULL) { ! 482: fclose(f); ! 483: goto err; ! 484: } ! 485: newkeys = newsigs = newids = newrvks = 0; ! 486: ! 487: /* Pass 1 - copy all keys from f which aren't in ring file */ ! 488: /* Also copy userid and signature packets. */ ! 489: fprintf(pgpout, LANG("\nLooking for new keys...\n")); ! 490: copying = FALSE; ! 491: if (gpk_open(ringfile) < 0) { ! 492: fclose(f); /* close key file */ ! 493: fclose(g); ! 494: goto err; ! 495: } ! 496: for (;;) { ! 497: file_position = ftell(f); ! 498: ! 499: status = readkeypacket(f,FALSE,&ctb,timestamp,(char *)userid,n,e, ! 500: NULL,NULL,NULL,NULL,NULL,NULL); ! 501: /* Note that readkeypacket has called set_precision */ ! 502: if (status == -1) /* EOF */ ! 503: break; ! 504: if (status == -2 || status == -3) { ! 505: fprintf(pgpout,LANG("\n\007Could not read key from file '%s'.\n"), ! 506: keyfile); ! 507: fclose(f); /* close key file */ ! 508: fclose(g); ! 509: goto err; ! 510: } ! 511: if (status < 0) { ! 512: copying = FALSE; ! 513: continue; /* don't merge keys from unrecognized version */ ! 514: } ! 515: ! 516: /* Check to see if key is already on key ring */ ! 517: if (is_key_ctb(ctb)) { ! 518: extract_keyID(keyID, n); /* from keyfile, not ringfile */ ! 519: publickey = is_ctb_type(ctb, CTB_CERT_PUBKEY_TYPE); ! 520: ! 521: /* Check for duplicate key in key ring: */ ! 522: status = get_publickey(&fp, NULL, keyID, timestamp, userid, n1, e); ! 523: if (status == 0) { ! 524: /* key in both keyring and keyfile */ ! 525: if (mp_compare (n, n1) != 0) { ! 526: fprintf(pgpout, LANG("\n\007Warning: Key ID %s matches key ID of key already on \n\ ! 527: key ring '%s', but the keys themselves differ.\n\ ! 528: This is highly suspicious. This key will not be added to ring.\n\ ! 529: Acknowledge by pressing return: "), keyIDstring(keyID), ringfile); ! 530: getyesno('n'); ! 531: } else { ! 532: ++commonkeys; ! 533: } ! 534: copying = FALSE; ! 535: } else if (status == -1) { /* key NOT in keyring */ ! 536: ++newkeys; ! 537: if (interactive_add) { ! 538: show_key(f, file_position, SHOW_ALL); ! 539: fprintf(pgpout, LANG("\nDo you want to add this key to keyring '%s' (y/N)? "), ringfile); ! 540: copying = getyesno('n'); ! 541: } else { ! 542: show_key(f,file_position,SHOW_LISTFMT); ! 543: copying = TRUE; ! 544: } ! 545: ! 546: /* If batchmode, output an update message */ ! 547: if (batchmode) ! 548: show_key(f, file_position, SHOW_CHANGE); ! 549: if (copying) { ! 550: nkey = xmalloc(sizeof(*nkey)); ! 551: memcpy(nkey->keyID, keyID, KEYFRAGSIZE); ! 552: nkey->next = nkeys; ! 553: nkeys = nkey; ! 554: } ! 555: } else { ! 556: /* unknown version or bad key */ ! 557: copying = FALSE; ! 558: } ! 559: } ! 560: /* ! 561: * Now, we copy according to the copying flag ! 562: * The key is prepended to the ring to give it search ! 563: * precedence over other keys with that same userid. ! 564: */ ! 565: if (copying && (is_key_ctb(ctb) || ctb==CTB_USERID || ! 566: is_ctb_type(ctb,CTB_SKE_TYPE))) ! 567: { ! 568: pktlen = (int) (ftell(f) - file_position); ! 569: copyfilepos(f,g,pktlen,file_position); /* copy packet from f */ ! 570: if (publickey) { ! 571: /* Initialize trust packets after keys and signatures */ ! 572: if (is_key_ctb(ctb)) { ! 573: write_trust(g, KC_OWNERTRUST_UNDEFINED); ! 574: userid_seen = FALSE; ! 575: } else if (is_ctb_type(ctb,CTB_SKE_TYPE)) { ! 576: if (userid_seen) { ! 577: write_trust (g, KC_SIGTRUST_UNDEFINED); ! 578: } else { ! 579: /* signature certificate before userid must be compromise cert. */ ! 580: fprintf(pgpout, LANG("Key has been revoked.\n")); ! 581: } ! 582: } else if (is_ctb_type(ctb,CTB_USERID_TYPE)) { ! 583: write_trust (g, KC_LEGIT_UNKNOWN); ! 584: userid_seen = TRUE; ! 585: } ! 586: } ! 587: } ! 588: } ! 589: gpk_close(); ! 590: ! 591: /* ! 592: * Now copy the remainder of the ringfile, h, to g. commonkeys tells ! 593: * how many keys are common to keyfile and ringfile. As long as that ! 594: * is nonzero we will check each key in ringfile to see if it has a ! 595: * match in keyfile. ! 596: */ ! 597: if ((h = fopen(ringfile,FOPRBIN)) != NULL) { ! 598: if (gpk_open(keyfile) < 0) { ! 599: fclose(f); ! 600: fclose(g); ! 601: fclose(h); ! 602: goto err; ! 603: } ! 604: while (commonkeys) { ! 605: /* Loop for each key in ringfile */ ! 606: file_position = ftell(h); ! 607: status = readkeypacket(h,FALSE,&ctb,NULL,(char *)userid,n,e, ! 608: NULL,NULL,NULL,NULL,NULL,NULL); ! 609: if (status == -1 || status == -3) { ! 610: if (status == -1) /* hit EOF */ ! 611: fprintf(pgpout, LANG("\n\007Key file contains duplicate keys: cannot be added to keyring\n")); ! 612: else ! 613: fprintf(pgpout,LANG("\n\007Could not read key from file '%s'.\n"), ! 614: ringfile); ! 615: fclose(f); ! 616: fclose(g); ! 617: fclose(h); ! 618: goto err; ! 619: } ! 620: PascalToC ((char *) userid); ! 621: pktlen = ftell(h) - file_position; ! 622: if (is_key_ctb(ctb)) { ! 623: long tfp; ! 624: /* unknown version or bad data: copy (don't remove packets from ringfile) */ ! 625: copying = TRUE; ! 626: if (status == 0) { ! 627: /* See if there is a match in keyfile */ ! 628: extract_keyID(keyID, n); /* from ringfile, not keyfile */ ! 629: extract_keyID(mykeyID, n); /* save this */ ! 630: publickey = is_ctb_type(ctb, CTB_CERT_PUBKEY_TYPE); ! 631: if (get_publickey(&tfp, NULL, keyID, timestamp, userid1, n1, e) >= 0) ! 632: { ! 633: if (verbose) ! 634: fprintf (pgpout, "Merging key ID: %s\n",keyIDstring(keyID)); ! 635: if (mergekeys (f,keyfile,tfp, h,ringfile,&file_position, g) < 0) ! 636: { ! 637: fclose(f); ! 638: fclose(g); ! 639: fclose(h); ! 640: goto err; ! 641: } ! 642: copying = FALSE; ! 643: --commonkeys; ! 644: } ! 645: } ! 646: } ! 647: if (copying) { ! 648: /* Copy ringfile key to g, without its sigs */ ! 649: copyfilepos (h,g,pktlen,file_position); ! 650: file_position += pktlen; ! 651: } ! 652: } /* End of loop for each key in ringfile */ ! 653: gpk_close(); ! 654: copyfile(h,g,-1L); /* copy rest of file from file h to g */ ! 655: fclose(h); ! 656: } ! 657: fclose(f); ! 658: if (write_error(g)) { ! 659: fclose(g); ! 660: goto err; ! 661: } ! 662: fclose(g); ! 663: if (newsigs == 0 && newkeys == 0 && newids == 0 && newrvks == 0) { ! 664: fprintf(pgpout, LANG("No new keys or signatures in keyfile.\n")); ! 665: rmtemp(scratchf); ! 666: endkrent(); ! 667: return 0; ! 668: } ! 669: ! 670: if (status = dokeycheck(NULL, scratchf, CHECK_NEW)) { ! 671: if (verbose) ! 672: fprintf(pgpout, "addto_keyring: dokeycheck returned %d\n", status); ! 673: goto err; ! 674: } ! 675: endkrent(); ! 676: ! 677: fprintf(pgpout, LANG("\nKeyfile contains:\n")); ! 678: if (newkeys) ! 679: fprintf(pgpout, LANG("%4d new key(s)\n"), newkeys); ! 680: if (newsigs) ! 681: fprintf(pgpout, LANG("%4d new signatures(s)\n"), newsigs); ! 682: if (newids) ! 683: fprintf(pgpout, LANG("%4d new user ID(s)\n"), newids); ! 684: if (newrvks) ! 685: fprintf(pgpout, LANG("%4d new revocation(s)\n"), newrvks); ! 686: ! 687: ask_first = TRUE; ! 688: status = maint_update(scratchf, nkeys); ! 689: if (status >= 0 && !filter_mode && !batchmode) ! 690: for (nkey = nkeys; nkey; nkey = nkey->next) ! 691: if (ask_to_sign(nkey->keyID, scratchf) != 0) ! 692: break; ! 693: if (status && verbose) ! 694: fprintf(pgpout, "addto_keyring: maint_update returned %d\n", status); ! 695: ! 696: free_newkeys(nkeys); ! 697: ! 698: savetempbak(scratchf,ringfile); ! 699: ! 700: return 0; /* normal return */ ! 701: ! 702: err: ! 703: gpk_close(); /* save to call if not opened */ ! 704: endkrent(); ! 705: /* make sure we remove any garbage files we may have created */ ! 706: rmtemp(scratchf); ! 707: return -1; ! 708: } /* addto_keyring */ ! 709: ! 710: ! 711: int addto_keyring(char *keyfile, char *ringfile) ! 712: { ! 713: long armorline = 0; ! 714: char *tempf; ! 715: int addflag = 0; ! 716: ! 717: if (_addto_keyring(keyfile, ringfile) == 0) ! 718: return 0; ! 719: /* check if the keyfile to be added is armored */ ! 720: while (is_armor_file(keyfile,armorline)) { ! 721: tempf = tempfile(TMP_TMPDIR|TMP_WIPE); ! 722: if (de_armor_file(keyfile,tempf,&armorline)) { ! 723: rmtemp(tempf); ! 724: return -1; ! 725: } ! 726: if (_addto_keyring(tempf, ringfile) == 0) ! 727: addflag = 1; ! 728: rmtemp(tempf); ! 729: } ! 730: if (!addflag) { ! 731: fprintf(pgpout, LANG("\nNo keys found in '%s'.\n"), keyfile); ! 732: return -1; ! 733: } else { ! 734: return 0; ! 735: } ! 736: } ! 737: ! 738: ! 739: static int ask_to_sign(byte *keyID, char *ringfile) ! 740: { ! 741: FILE *f; ! 742: word32 timestamp; ! 743: byte ctb, trust; ! 744: unit n[MAX_UNIT_PRECISION], e[MAX_UNIT_PRECISION]; ! 745: byte userid[256]; ! 746: long fpos; ! 747: int status; ! 748: extern char my_name[]; ! 749: ! 750: if (getpublickey(GPK_GIVEUP, ringfile, &fpos, NULL, keyID, ! 751: (byte *)×tamp, userid, n, e) < 0) ! 752: return -1; ! 753: ! 754: if ((f = fopen(ringfile, FOPRBIN)) == NULL) ! 755: return -1; ! 756: ! 757: fseek(f, fpos, SEEK_SET); ! 758: if (is_compromised(f)) { ! 759: fclose(f); ! 760: return 0; ! 761: } ! 762: if (nextkeypacket(f, &ctb) < 0) { ! 763: fclose(f); ! 764: return -1; ! 765: } ! 766: if (ctb != CTB_CERT_PUBKEY) { ! 767: fclose(f); ! 768: return 0; /* don't ask to sign secret key */ ! 769: } ! 770: while (nextkeypacket(f, &ctb) == 0 && !is_key_ctb(ctb)) ! 771: if (ctb == CTB_USERID) /* check first userid */ ! 772: break; ! 773: if (ctb != CTB_USERID) { ! 774: fclose(f); ! 775: return -1; ! 776: } ! 777: ! 778: if ((status = read_trust(f, &trust)) < 0) { ! 779: fclose(f); ! 780: return status; ! 781: } ! 782: if ((trust & KC_LEGIT_MASK) == KC_LEGIT_COMPLETE) { ! 783: fclose(f); ! 784: return 0; ! 785: } ! 786: if (ask_first) { ! 787: /* shortcut for adding big keyfile */ ! 788: fprintf(pgpout, LANG("\nOne or more of the new keys are not fully certified.\n\ ! 789: Do you want to certify any of these keys yourself (y/N)? ")); ! 790: if (!getyesno('n')) { ! 791: fclose(f); ! 792: return 1; ! 793: } ! 794: } ! 795: ask_first = FALSE; ! 796: show_key(f, fpos, SHOW_ALL|SHOW_HASH); ! 797: fclose(f); ! 798: PascalToC((char *)userid); ! 799: fprintf(pgpout, LANG("\nDo you want to certify this key yourself (y/N)? ")); ! 800: if (getyesno('n')) { ! 801: if (signkey((char *)userid, my_name, ringfile) == 0) ! 802: maint_update(ringfile, 0); ! 803: } ! 804: return 0; ! 805: } ! 806: ! 807: ! 808: ! 809: /**** faster version of getpublickey() ****/ ! 810: ! 811: static long find_keyID(byte *keyID); ! 812: ! 813: static FILE *gpkf = NULL; ! 814: ! 815: /* ! 816: * speedup replacement for getpublickey(), does not have the arguments ! 817: * giveup, showkey and keyfile (giveup = TRUE, showkey = FALSE, keyfile ! 818: * is set with gpk_open(). ! 819: * only searches on keyID ! 820: */ ! 821: int get_publickey(long *file_position, int *pktlen, byte *keyID, ! 822: byte *timestamp, byte *userid, unitptr n, unitptr e) ! 823: { ! 824: byte ctb; /* returned by readkeypacket */ ! 825: int status, keystatus = -1; ! 826: long fpos; ! 827: ! 828: if ((fpos = find_keyID(keyID)) == -1) ! 829: return -1; ! 830: fseek(gpkf, fpos, SEEK_SET); ! 831: ! 832: for (;;) { ! 833: fpos = ftell(gpkf); ! 834: status = readkeypacket(gpkf,FALSE,&ctb,timestamp,(char *)userid,n,e, ! 835: NULL,NULL,NULL,NULL,NULL,NULL); ! 836: /* Note that readkeypacket has called set_precision */ ! 837: ! 838: if (status < 0 && status != -4 && status != -6) ! 839: return status; ! 840: ! 841: /* Remember packet position and size for last key packet */ ! 842: if (is_key_ctb(ctb)) { ! 843: if (file_position) ! 844: *file_position = fpos; ! 845: if (pktlen) ! 846: *pktlen = (int)(ftell(gpkf) - fpos); ! 847: if (keystatus != -1) ! 848: return -3; /* should not happen, probably missing userid pkt */ ! 849: keystatus = status; ! 850: } ! 851: if (ctb == CTB_USERID) ! 852: return keystatus; ! 853: } ! 854: } ! 855: ! 856: #define PK_HASHSIZE 256 /* must be power of 2 */ ! 857: #define PK_HASH(x) (*(byte *) (x) & (PK_HASHSIZE - 1)) ! 858: #define HASH_ALLOC 400 ! 859: ! 860: static VOID * allocbuf(int size); ! 861: static void freebufpool(void); ! 862: ! 863: static struct hashent { ! 864: struct hashent *next; ! 865: byte keyID[KEYFRAGSIZE]; ! 866: long offset; ! 867: } **hashtbl = NULL, *hashptr; ! 868: ! 869: static int hashleft = 0; ! 870: ! 871: int ! 872: gpk_open(char *keyfile) ! 873: { ! 874: int status; ! 875: long fpos = 0; ! 876: byte keyID[KEYFRAGSIZE]; ! 877: byte ctb; ! 878: ! 879: if (gpkf) { ! 880: fprintf(pgpout, "gpk_open: already open\n"); ! 881: return -1; ! 882: } ! 883: default_extension(keyfile,PGP_EXTENSION); ! 884: if ((gpkf = fopen(keyfile,FOPRBIN)) == NULL) ! 885: return -1; /* error return */ ! 886: hashtbl = allocbuf(PK_HASHSIZE * sizeof(struct hashent *)); ! 887: memset(hashtbl, 0, PK_HASHSIZE * sizeof(struct hashent *)); ! 888: while ((status = readkpacket(gpkf, &ctb, NULL, keyID, NULL)) != -1) { ! 889: if (status == -2 || status == -3) { ! 890: fprintf(pgpout,LANG("\n\007Could not read key from file '%s'.\n"), ! 891: keyfile); ! 892: fclose(gpkf); /* close key file */ ! 893: return -1; ! 894: } ! 895: if (is_key_ctb(ctb)) { ! 896: if (find_keyID(keyID) != -1) ! 897: fprintf(pgpout, "Warning: duplicate key in keyring '%s'\n", keyfile); ! 898: if (!hashleft) { ! 899: hashptr = allocbuf(HASH_ALLOC * sizeof(struct hashent)); ! 900: hashleft = HASH_ALLOC; ! 901: } ! 902: memcpy(hashptr->keyID, keyID, KEYFRAGSIZE); ! 903: hashptr->offset = fpos; ! 904: hashptr->next = hashtbl[PK_HASH(keyID)]; ! 905: hashtbl[PK_HASH(keyID)] = hashptr; ! 906: ++hashptr; ! 907: --hashleft; ! 908: } ! 909: fpos = ftell(gpkf); ! 910: } ! 911: return 0; ! 912: } ! 913: ! 914: void ! 915: gpk_close(void) ! 916: { ! 917: if (!gpkf) ! 918: return; ! 919: hashleft = 0; ! 920: hashtbl = NULL; ! 921: freebufpool(); ! 922: fclose(gpkf); /* close key file */ ! 923: gpkf = NULL; ! 924: } ! 925: ! 926: /* ! 927: * Lookup file position in hash table by keyID, returns -1 if not found ! 928: */ ! 929: static long ! 930: find_keyID(byte *keyID) ! 931: { ! 932: struct hashent *p; ! 933: ! 934: for (p = hashtbl[PK_HASH(keyID)]; p; p = p->next) ! 935: if (memcmp(keyID, p->keyID, KEYFRAGSIZE) == 0) ! 936: return p->offset; ! 937: return -1; ! 938: } ! 939: ! 940: ! 941: static struct bufpool { ! 942: struct bufpool *next; ! 943: char buf[1]; /* variable size */ ! 944: } *bufpool = NULL; ! 945: ! 946: /* ! 947: * allocate buffer, all buffers allocated with this function can be ! 948: * freed with one call to freebufpool() ! 949: */ ! 950: static VOID * ! 951: allocbuf(int size) ! 952: { ! 953: struct bufpool *p; ! 954: ! 955: p = xmalloc(size + sizeof(struct bufpool *)); ! 956: p->next = bufpool; ! 957: bufpool = p; ! 958: return p->buf; ! 959: } ! 960: ! 961: /* ! 962: * free all memory obtained with allocbuf() ! 963: */ ! 964: static void ! 965: freebufpool(void) ! 966: { ! 967: struct bufpool *p; ! 968: ! 969: while (bufpool) { ! 970: p = bufpool; ! 971: bufpool = bufpool->next; ! 972: free(p); ! 973: } ! 974: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.