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