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