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