xref: /netbsd-src/crypto/external/bsd/netpgp/dist/src/lib/netpgp.c (revision 1b9578b8c2c1f848eeb16dabbfd7d1f0d9fdefbd)
1 /*-
2  * Copyright (c) 2009 The NetBSD Foundation, Inc.
3  * All rights reserved.
4  *
5  * This code is derived from software contributed to The NetBSD Foundation
6  * by Alistair Crooks (agc@NetBSD.org)
7  *
8  * Redistribution and use in source and binary forms, with or without
9  * modification, are permitted provided that the following conditions
10  * are met:
11  * 1. Redistributions of source code must retain the above copyright
12  *    notice, this list of conditions and the following disclaimer.
13  * 2. Redistributions in binary form must reproduce the above copyright
14  *    notice, this list of conditions and the following disclaimer in the
15  *    documentation and/or other materials provided with the distribution.
16  *
17  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
18  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
19  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
20  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
21  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
22  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
23  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
24  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
25  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
26  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
27  * POSSIBILITY OF SUCH DAMAGE.
28  */
29 #include "config.h"
30 
31 #ifdef HAVE_SYS_CDEFS_H
32 #include <sys/cdefs.h>
33 #endif
34 
35 #if defined(__NetBSD__)
36 __COPYRIGHT("@(#) Copyright (c) 2009 The NetBSD Foundation, Inc. All rights reserved.");
37 __RCSID("$NetBSD: netpgp.c,v 1.92 2011/06/28 03:35:28 agc Exp $");
38 #endif
39 
40 #include <sys/types.h>
41 #include <sys/stat.h>
42 #include <sys/param.h>
43 #include <sys/mman.h>
44 
45 #ifdef HAVE_SYS_RESOURCE_H
46 #include <sys/resource.h>
47 #endif
48 
49 #ifdef HAVE_FCNTL_H
50 #include <fcntl.h>
51 #endif
52 
53 #include <errno.h>
54 #include <regex.h>
55 #include <stdarg.h>
56 #include <stdlib.h>
57 #include <string.h>
58 #include <time.h>
59 
60 #ifdef HAVE_UNISTD_H
61 #include <unistd.h>
62 #endif
63 
64 #include <errno.h>
65 
66 #ifdef HAVE_LIMITS_H
67 #include <limits.h>
68 #endif
69 
70 #include <netpgp.h>
71 
72 #include "packet.h"
73 #include "packet-parse.h"
74 #include "keyring.h"
75 #include "errors.h"
76 #include "packet-show.h"
77 #include "create.h"
78 #include "netpgpsdk.h"
79 #include "memory.h"
80 #include "validate.h"
81 #include "readerwriter.h"
82 #include "netpgpdefs.h"
83 #include "crypto.h"
84 #include "ssh2pgp.h"
85 #include "defs.h"
86 
87 /* read any gpg config file */
88 static int
89 conffile(netpgp_t *netpgp, char *homedir, char *userid, size_t length)
90 {
91 	regmatch_t	 matchv[10];
92 	regex_t		 keyre;
93 	char		 buf[BUFSIZ];
94 	FILE		*fp;
95 
96 	__PGP_USED(netpgp);
97 	(void) snprintf(buf, sizeof(buf), "%s/gpg.conf", homedir);
98 	if ((fp = fopen(buf, "r")) == NULL) {
99 		return 0;
100 	}
101 	(void) memset(&keyre, 0x0, sizeof(keyre));
102 	(void) regcomp(&keyre, "^[ \t]*default-key[ \t]+([0-9a-zA-F]+)",
103 		REG_EXTENDED);
104 	while (fgets(buf, (int)sizeof(buf), fp) != NULL) {
105 		if (regexec(&keyre, buf, 10, matchv, 0) == 0) {
106 			(void) memcpy(userid, &buf[(int)matchv[1].rm_so],
107 				MIN((unsigned)(matchv[1].rm_eo -
108 						matchv[1].rm_so), length));
109 			if (netpgp->passfp == NULL) {
110 				(void) fprintf(stderr,
111 				"netpgp: default key set to \"%.*s\"\n",
112 				(int)(matchv[1].rm_eo - matchv[1].rm_so),
113 				&buf[(int)matchv[1].rm_so]);
114 			}
115 		}
116 	}
117 	(void) fclose(fp);
118 	regfree(&keyre);
119 	return 1;
120 }
121 
122 /* small function to pretty print an 8-character raw userid */
123 static char    *
124 userid_to_id(const uint8_t *userid, char *id)
125 {
126 	static const char *hexes = "0123456789abcdef";
127 	int		   i;
128 
129 	for (i = 0; i < 8 ; i++) {
130 		id[i * 2] = hexes[(unsigned)(userid[i] & 0xf0) >> 4];
131 		id[(i * 2) + 1] = hexes[userid[i] & 0xf];
132 	}
133 	id[8 * 2] = 0x0;
134 	return id;
135 }
136 
137 /* print out the successful signature information */
138 static void
139 resultp(pgp_io_t *io,
140 	const char *f,
141 	pgp_validation_t *res,
142 	pgp_keyring_t *ring)
143 {
144 	const pgp_key_t	*key;
145 	pgp_pubkey_t		*sigkey;
146 	unsigned		 from;
147 	unsigned		 i;
148 	time_t			 t;
149 	char			 id[MAX_ID_LENGTH + 1];
150 
151 	for (i = 0; i < res->validc; i++) {
152 		(void) fprintf(io->res,
153 			"Good signature for %s made %s",
154 			(f) ? f : "<stdin>",
155 			ctime(&res->valid_sigs[i].birthtime));
156 		if (res->duration > 0) {
157 			t = res->birthtime + res->duration;
158 			(void) fprintf(io->res, "Valid until %s", ctime(&t));
159 		}
160 		(void) fprintf(io->res,
161 			"using %s key %s\n",
162 			pgp_show_pka(res->valid_sigs[i].key_alg),
163 			userid_to_id(res->valid_sigs[i].signer_id, id));
164 		from = 0;
165 		key = pgp_getkeybyid(io, ring,
166 			(const uint8_t *) res->valid_sigs[i].signer_id,
167 			&from, &sigkey);
168 		if (sigkey == &key->enckey) {
169 			(void) fprintf(io->res,
170 				"WARNING: signature for %s made with encryption key\n",
171 				(f) ? f : "<stdin>");
172 		}
173 		pgp_print_keydata(io, ring, key, "signature ", &key->key.pubkey, 0);
174 	}
175 }
176 
177 /* check there's enough space in the arrays */
178 static int
179 size_arrays(netpgp_t *netpgp, unsigned needed)
180 {
181 	char	**temp;
182 
183 	if (netpgp->size == 0) {
184 		/* only get here first time around */
185 		netpgp->size = needed;
186 		if ((netpgp->name = calloc(sizeof(char *), needed)) == NULL) {
187 			(void) fprintf(stderr, "size_arrays: bad alloc\n");
188 			return 0;
189 		}
190 		if ((netpgp->value = calloc(sizeof(char *), needed)) == NULL) {
191 			free(netpgp->name);
192 			(void) fprintf(stderr, "size_arrays: bad alloc\n");
193 			return 0;
194 		}
195 	} else if (netpgp->c == netpgp->size) {
196 		/* only uses 'needed' when filled array */
197 		netpgp->size += needed;
198 		temp = realloc(netpgp->name, sizeof(char *) * needed);
199 		if (temp == NULL) {
200 			(void) fprintf(stderr, "size_arrays: bad alloc\n");
201 			return 0;
202 		}
203 		netpgp->name = temp;
204 		temp = realloc(netpgp->value, sizeof(char *) * needed);
205 		if (temp == NULL) {
206 			(void) fprintf(stderr, "size_arrays: bad alloc\n");
207 			return 0;
208 		}
209 		netpgp->value = temp;
210 	}
211 	return 1;
212 }
213 
214 /* find the name in the array */
215 static int
216 findvar(netpgp_t *netpgp, const char *name)
217 {
218 	unsigned	i;
219 
220 	for (i = 0 ; i < netpgp->c && strcmp(netpgp->name[i], name) != 0; i++) {
221 	}
222 	return (i == netpgp->c) ? -1 : (int)i;
223 }
224 
225 /* read a keyring and return it */
226 static void *
227 readkeyring(netpgp_t *netpgp, const char *name)
228 {
229 	pgp_keyring_t	*keyring;
230 	const unsigned	 noarmor = 0;
231 	char		 f[MAXPATHLEN];
232 	char		*filename;
233 	char		*homedir;
234 
235 	homedir = netpgp_getvar(netpgp, "homedir");
236 	if ((filename = netpgp_getvar(netpgp, name)) == NULL) {
237 		(void) snprintf(f, sizeof(f), "%s/%s.gpg", homedir, name);
238 		filename = f;
239 	}
240 	if ((keyring = calloc(1, sizeof(*keyring))) == NULL) {
241 		(void) fprintf(stderr, "readkeyring: bad alloc\n");
242 		return NULL;
243 	}
244 	if (!pgp_keyring_fileread(keyring, noarmor, filename)) {
245 		free(keyring);
246 		(void) fprintf(stderr, "Can't read %s %s\n", name, filename);
247 		return NULL;
248 	}
249 	netpgp_setvar(netpgp, name, filename);
250 	return keyring;
251 }
252 
253 /* read keys from ssh key files */
254 static int
255 readsshkeys(netpgp_t *netpgp, char *homedir, const char *needseckey)
256 {
257 	pgp_keyring_t	*pubring;
258 	pgp_keyring_t	*secring;
259 	struct stat	 st;
260 	unsigned	 hashtype;
261 	char		*hash;
262 	char		 f[MAXPATHLEN];
263 	char		*filename;
264 
265 	if ((filename = netpgp_getvar(netpgp, "sshkeyfile")) == NULL) {
266 		/* set reasonable default for RSA key */
267 		(void) snprintf(f, sizeof(f), "%s/id_rsa.pub", homedir);
268 		filename = f;
269 	} else if (strcmp(&filename[strlen(filename) - 4], ".pub") != 0) {
270 		/* got ssh keys, check for pub file name */
271 		(void) snprintf(f, sizeof(f), "%s.pub", filename);
272 		filename = f;
273 	}
274 	/* check the pub file exists */
275 	if (stat(filename, &st) != 0) {
276 		(void) fprintf(stderr, "readsshkeys: bad pubkey filename '%s'\n", filename);
277 		return 0;
278 	}
279 	if ((pubring = calloc(1, sizeof(*pubring))) == NULL) {
280 		(void) fprintf(stderr, "readsshkeys: bad alloc\n");
281 		return 0;
282 	}
283 	/* openssh2 keys use md5 by default */
284 	hashtype = PGP_HASH_MD5;
285 	if ((hash = netpgp_getvar(netpgp, "hash")) != NULL) {
286 		/* openssh 2 hasn't really caught up to anything else yet */
287 		if (netpgp_strcasecmp(hash, "md5") == 0) {
288 			hashtype = PGP_HASH_MD5;
289 		} else if (netpgp_strcasecmp(hash, "sha1") == 0) {
290 			hashtype = PGP_HASH_SHA1;
291 		} else if (netpgp_strcasecmp(hash, "sha256") == 0) {
292 			hashtype = PGP_HASH_SHA256;
293 		}
294 	}
295 	if (!pgp_ssh2_readkeys(netpgp->io, pubring, NULL, filename, NULL, hashtype)) {
296 		free(pubring);
297 		(void) fprintf(stderr, "readsshkeys: can't read %s\n",
298 				filename);
299 		return 0;
300 	}
301 	if (netpgp->pubring == NULL) {
302 		netpgp->pubring = pubring;
303 	} else {
304 		pgp_append_keyring(netpgp->pubring, pubring);
305 	}
306 	if (needseckey) {
307 		netpgp_setvar(netpgp, "sshpubfile", filename);
308 		/* try to take the ".pub" off the end */
309 		if (filename == f) {
310 			f[strlen(f) - 4] = 0x0;
311 		} else {
312 			(void) snprintf(f, sizeof(f), "%.*s",
313 					(int)strlen(filename) - 4, filename);
314 			filename = f;
315 		}
316 		if ((secring = calloc(1, sizeof(*secring))) == NULL) {
317 			(void) fprintf(stderr, "readsshkeys: bad alloc\n");
318 			return 0;
319 		}
320 		if (!pgp_ssh2_readkeys(netpgp->io, pubring, secring, NULL, filename, hashtype)) {
321 			(void) fprintf(stderr, "readsshkeys: can't read sec %s\n", filename);
322 			return 0;
323 		}
324 		netpgp->secring = secring;
325 		netpgp_setvar(netpgp, "sshsecfile", filename);
326 	}
327 	return 1;
328 }
329 
330 /* get the uid of the first key in the keyring */
331 static int
332 get_first_ring(pgp_keyring_t *ring, char *id, size_t len, int last)
333 {
334 	uint8_t	*src;
335 	int	 i;
336 	int	 n;
337 
338 	if (ring == NULL) {
339 		return 0;
340 	}
341 	(void) memset(id, 0x0, len);
342 	src = ring->keys[(last) ? ring->keyc - 1 : 0].sigid;
343 	for (i = 0, n = 0 ; i < PGP_KEY_ID_SIZE ; i += 2) {
344 		n += snprintf(&id[n], len - n, "%02x%02x", src[i], src[i + 1]);
345 	}
346 	id[n] = 0x0;
347 	return 1;
348 }
349 
350 /* find the time - in a specific %Y-%m-%d format - using a regexp */
351 static int
352 grabdate(char *s, int64_t *t)
353 {
354 	static regex_t	r;
355 	static int	compiled;
356 	regmatch_t	matches[10];
357 	struct tm	tm;
358 
359 	if (!compiled) {
360 		compiled = 1;
361 		(void) regcomp(&r, "([0-9][0-9][0-9][0-9])[-/]([0-9][0-9])[-/]([0-9][0-9])", REG_EXTENDED);
362 	}
363 	if (regexec(&r, s, 10, matches, 0) == 0) {
364 		(void) memset(&tm, 0x0, sizeof(tm));
365 		tm.tm_year = (int)strtol(&s[(int)matches[1].rm_so], NULL, 10);
366 		tm.tm_mon = (int)strtol(&s[(int)matches[2].rm_so], NULL, 10) - 1;
367 		tm.tm_mday = (int)strtol(&s[(int)matches[3].rm_so], NULL, 10);
368 		*t = mktime(&tm);
369 		return 1;
370 	}
371 	return 0;
372 }
373 
374 /* get expiration in seconds */
375 static uint64_t
376 get_duration(char *s)
377 {
378 	uint64_t	 now;
379 	int64_t	 	 t;
380 	char		*mult;
381 
382 	if (s == NULL) {
383 		return 0;
384 	}
385 	now = (uint64_t)strtoull(s, NULL, 10);
386 	if ((mult = strchr("hdwmy", s[strlen(s) - 1])) != NULL) {
387 		switch(*mult) {
388 		case 'h':
389 			return now * 60 * 60;
390 		case 'd':
391 			return now * 60 * 60 * 24;
392 		case 'w':
393 			return now * 60 * 60 * 24 * 7;
394 		case 'm':
395 			return now * 60 * 60 * 24 * 31;
396 		case 'y':
397 			return now * 60 * 60 * 24 * 365;
398 		}
399 	}
400 	if (grabdate(s, &t)) {
401 		return t;
402 	}
403 	return (uint64_t)strtoll(s, NULL, 10);
404 }
405 
406 /* get birthtime in seconds */
407 static int64_t
408 get_birthtime(char *s)
409 {
410 	int64_t	t;
411 
412 	if (s == NULL) {
413 		return time(NULL);
414 	}
415 	if (grabdate(s, &t)) {
416 		return t;
417 	}
418 	return (uint64_t)strtoll(s, NULL, 10);
419 }
420 
421 /* resolve the userid */
422 static const pgp_key_t *
423 resolve_userid(netpgp_t *netpgp, const pgp_keyring_t *keyring, const char *userid)
424 {
425 	const pgp_key_t	*key;
426 	pgp_io_t		*io;
427 
428 	if (userid == NULL) {
429 		userid = netpgp_getvar(netpgp, "userid");
430 		if (userid == NULL)
431 			return NULL;
432 	} else if (userid[0] == '0' && userid[1] == 'x') {
433 		userid += 2;
434 	}
435 	io = netpgp->io;
436 	if ((key = pgp_getkeybyname(io, keyring, userid)) == NULL) {
437 		(void) fprintf(io->errs, "Can't find key '%s'\n", userid);
438 	}
439 	return key;
440 }
441 
442 /* append a key to a keyring */
443 static int
444 appendkey(pgp_io_t *io, pgp_key_t *key, char *ringfile)
445 {
446 	pgp_output_t	*create;
447 	const unsigned	 noarmor = 0;
448 	int		 fd;
449 
450 	if ((fd = pgp_setup_file_append(&create, ringfile)) < 0) {
451 		fd = pgp_setup_file_write(&create, ringfile, 0);
452 	}
453 	if (fd < 0) {
454 		(void) fprintf(io->errs, "can't open pubring '%s'\n", ringfile);
455 		return 0;
456 	}
457 	if (!pgp_write_xfer_pubkey(create, key, noarmor)) {
458 		(void) fprintf(io->errs, "Cannot write pubkey\n");
459 		return 0;
460 	}
461 	pgp_teardown_file_write(create, fd);
462 	return 1;
463 }
464 
465 /* return 1 if the file contains ascii-armoured text */
466 static unsigned
467 isarmoured(pgp_io_t *io, const char *f, const void *memory, const char *text)
468 {
469 	regmatch_t	 matches[10];
470 	unsigned	 armoured;
471 	regex_t		 r;
472 	FILE		*fp;
473 	char	 	 buf[BUFSIZ];
474 
475 	armoured = 0;
476 	(void) regcomp(&r, text, REG_EXTENDED);
477 	if (f) {
478 		if ((fp = fopen(f, "r")) == NULL) {
479 			(void) fprintf(io->errs, "isarmoured: can't open '%s'\n", f);
480 			regfree(&r);
481 			return 0;
482 		}
483 		if (fgets(buf, (int)sizeof(buf), fp) != NULL) {
484 			if (regexec(&r, buf, 10, matches, 0) == 0) {
485 				armoured = 1;
486 			}
487 		}
488 		(void) fclose(fp);
489 	} else {
490 		if (regexec(&r, memory, 10, matches, 0) == 0) {
491 			armoured = 1;
492 		}
493 	}
494 	regfree(&r);
495 	return armoured;
496 }
497 
498 /* vararg print function */
499 static void
500 p(FILE *fp, const char *s, ...)
501 {
502 	va_list	args;
503 
504 	va_start(args, s);
505 	while (s != NULL) {
506 		(void) fprintf(fp, "%s", s);
507 		s = va_arg(args, char *);
508 	}
509 	va_end(args);
510 }
511 
512 /* print a JSON object to the FILE stream */
513 static void
514 pobj(FILE *fp, mj_t *obj, int depth)
515 {
516 	unsigned	 i;
517 	char		*s;
518 
519 	if (obj == NULL) {
520 		(void) fprintf(stderr, "No object found\n");
521 		return;
522 	}
523 	for (i = 0 ; i < (unsigned)depth ; i++) {
524 		p(fp, " ", NULL);
525 	}
526 	switch(obj->type) {
527 	case MJ_NULL:
528 	case MJ_FALSE:
529 	case MJ_TRUE:
530 		p(fp, (obj->type == MJ_NULL) ? "null" : (obj->type == MJ_FALSE) ? "false" : "true", NULL);
531 		break;
532 	case MJ_NUMBER:
533 		p(fp, obj->value.s, NULL);
534 		break;
535 	case MJ_STRING:
536 		if ((i = mj_asprint(&s, obj, MJ_HUMAN)) > 2) {
537 			(void) fprintf(fp, "%.*s", (int)i - 2, &s[1]);
538 			free(s);
539 		}
540 		break;
541 	case MJ_ARRAY:
542 		for (i = 0 ; i < obj->c ; i++) {
543 			pobj(fp, &obj->value.v[i], depth + 1);
544 			if (i < obj->c - 1) {
545 				(void) fprintf(fp, ", ");
546 			}
547 		}
548 		(void) fprintf(fp, "\n");
549 		break;
550 	case MJ_OBJECT:
551 		for (i = 0 ; i < obj->c ; i += 2) {
552 			pobj(fp, &obj->value.v[i], depth + 1);
553 			p(fp, ": ", NULL);
554 			pobj(fp, &obj->value.v[i + 1], 0);
555 			if (i < obj->c - 1) {
556 				p(fp, ", ", NULL);
557 			}
558 		}
559 		p(fp, "\n", NULL);
560 		break;
561 	default:
562 		break;
563 	}
564 }
565 
566 /* return the time as a string */
567 static char *
568 ptimestr(char *dest, size_t size, time_t t)
569 {
570 	struct tm      *tm;
571 
572 	tm = gmtime(&t);
573 	(void) snprintf(dest, size, "%04d-%02d-%02d",
574 		tm->tm_year + 1900,
575 		tm->tm_mon + 1,
576 		tm->tm_mday);
577 	return dest;
578 }
579 
580 /* format a JSON object */
581 static void
582 format_json_key(FILE *fp, mj_t *obj, const int psigs)
583 {
584 	int64_t	 birthtime;
585 	int64_t	 duration;
586 	time_t	 now;
587 	char	 tbuf[32];
588 	char	*s;
589 	mj_t	*sub;
590 	int	 i;
591 
592 	if (pgp_get_debug_level(__FILE__)) {
593 		mj_asprint(&s, obj, MJ_HUMAN);
594 		(void) fprintf(stderr, "formatobj: json is '%s'\n", s);
595 		free(s);
596 	}
597 	if (obj->c == 2 && obj->value.v[1].type == MJ_STRING &&
598 	    strcmp(obj->value.v[1].value.s, "[REVOKED]") == 0) {
599 		/* whole key has been rovoked - just return */
600 		return;
601 	}
602 	pobj(fp, &obj->value.v[mj_object_find(obj, "header", 0, 2) + 1], 0);
603 	p(fp, " ", NULL);
604 	pobj(fp, &obj->value.v[mj_object_find(obj, "key bits", 0, 2) + 1], 0);
605 	p(fp, "/", NULL);
606 	pobj(fp, &obj->value.v[mj_object_find(obj, "pka", 0, 2) + 1], 0);
607 	p(fp, " ", NULL);
608 	pobj(fp, &obj->value.v[mj_object_find(obj, "key id", 0, 2) + 1], 0);
609 	birthtime = (int64_t)strtoll(obj->value.v[mj_object_find(obj, "birthtime", 0, 2) + 1].value.s, NULL, 10);
610 	p(fp, " ", ptimestr(tbuf, sizeof(tbuf), birthtime), NULL);
611 	duration = (int64_t)strtoll(obj->value.v[mj_object_find(obj, "duration", 0, 2) + 1].value.s, NULL, 10);
612 	if (duration > 0) {
613 		now = time(NULL);
614 		p(fp, " ", (birthtime + duration < now) ? "[EXPIRED " : "[EXPIRES ",
615 			ptimestr(tbuf, sizeof(tbuf), birthtime + duration), "]", NULL);
616 	}
617 	p(fp, "\n", "Key fingerprint: ", NULL);
618 	pobj(fp, &obj->value.v[mj_object_find(obj, "fingerprint", 0, 2) + 1], 0);
619 	p(fp, "\n", NULL);
620 	/* go to field after \"duration\" */
621 	for (i = mj_object_find(obj, "duration", 0, 2) + 2; i < mj_arraycount(obj) ; i += 2) {
622 		if (strcmp(obj->value.v[i].value.s, "uid") == 0) {
623 			sub = &obj->value.v[i + 1];
624 			p(fp, "uid", NULL);
625 			pobj(fp, &sub->value.v[0], (psigs) ? 4 : 14); /* human name */
626 			pobj(fp, &sub->value.v[1], 1); /* any revocation */
627 			p(fp, "\n", NULL);
628 		} else if (strcmp(obj->value.v[i].value.s, "encryption") == 0) {
629 			sub = &obj->value.v[i + 1];
630 			p(fp, "encryption", NULL);
631 			pobj(fp, &sub->value.v[0], 1);	/* size */
632 			p(fp, "/", NULL);
633 			pobj(fp, &sub->value.v[1], 0); /* alg */
634 			p(fp, " ", NULL);
635 			pobj(fp, &sub->value.v[2], 0); /* id */
636 			p(fp, " ", ptimestr(tbuf, sizeof(tbuf),
637 					(time_t)strtoll(sub->value.v[3].value.s, NULL, 10)),
638 				"\n", NULL);
639 		} else if (strcmp(obj->value.v[i].value.s, "sig") == 0) {
640 			sub = &obj->value.v[i + 1];
641 			p(fp, "sig", NULL);
642 			pobj(fp, &sub->value.v[0], 8);	/* size */
643 			p(fp, "  ", ptimestr(tbuf, sizeof(tbuf),
644 					(time_t)strtoll(sub->value.v[1].value.s, NULL, 10)),
645 				" ", NULL); /* time */
646 			pobj(fp, &sub->value.v[2], 0); /* human name */
647 			p(fp, "\n", NULL);
648 		} else {
649 			fprintf(stderr, "weird '%s'\n", obj->value.v[i].value.s);
650 			pobj(fp, &obj->value.v[i], 0); /* human name */
651 		}
652 	}
653 	p(fp, "\n", NULL);
654 }
655 
656 /* save a pgp pubkey to a temp file */
657 static int
658 savepubkey(char *res, char *f, size_t size)
659 {
660 	size_t	len;
661 	int	cc;
662 	int	wc;
663 	int	fd;
664 
665 	(void) snprintf(f, size, "/tmp/pgp2ssh.XXXXXXX");
666 	if ((fd = mkstemp(f)) < 0) {
667 		(void) fprintf(stderr, "can't create temp file '%s'\n", f);
668 		return 0;
669 	}
670 	len = strlen(res);
671 	for (cc = 0 ; (wc = (int)write(fd, &res[cc], len - (size_t)cc)) > 0 ; cc += wc) {
672 	}
673 	(void) close(fd);
674 	return 1;
675 }
676 
677 /* format a uint32_t */
678 static int
679 formatu32(uint8_t *buffer, uint32_t value)
680 {
681 	buffer[0] = (uint8_t)(value >> 24) & 0xff;
682 	buffer[1] = (uint8_t)(value >> 16) & 0xff;
683 	buffer[2] = (uint8_t)(value >> 8) & 0xff;
684 	buffer[3] = (uint8_t)value & 0xff;
685 	return sizeof(uint32_t);
686 }
687 
688 /* format a string as (len, string) */
689 static int
690 formatstring(char *buffer, const uint8_t *s, size_t len)
691 {
692 	int	cc;
693 
694 	cc = formatu32((uint8_t *)buffer, (uint32_t)len);
695 	(void) memcpy(&buffer[cc], s, len);
696 	return cc + (int)len;
697 }
698 
699 /* format a bignum, checking for "interesting" high bit values */
700 static int
701 formatbignum(char *buffer, BIGNUM *bn)
702 {
703 	size_t	 len;
704 	uint8_t	*cp;
705 	int	 cc;
706 
707 	len = (size_t) BN_num_bytes(bn);
708 	if ((cp = calloc(1, len + 1)) == NULL) {
709 		(void) fprintf(stderr, "calloc failure in formatbignum\n");
710 		return 0;
711 	}
712 	(void) BN_bn2bin(bn, cp + 1);
713 	cp[0] = 0x0;
714 	cc = (cp[1] & 0x80) ? formatstring(buffer, cp, len + 1) : formatstring(buffer, &cp[1], len);
715 	free(cp);
716 	return cc;
717 }
718 
719 #define MAX_PASSPHRASE_ATTEMPTS	3
720 #define INFINITE_ATTEMPTS	-1
721 
722 /* get the passphrase from the user */
723 static int
724 find_passphrase(FILE *passfp, const char *id, char *passphrase, size_t size, int attempts)
725 {
726 	char	 prompt[BUFSIZ];
727 	char	 buf[128];
728 	char	*cp;
729 	int	 cc;
730 	int	 i;
731 
732 	if (passfp) {
733 		if (fgets(passphrase, (int)size, passfp) == NULL) {
734 			return 0;
735 		}
736 		return (int)strlen(passphrase);
737 	}
738 	for (i = 0 ; i < attempts ; i++) {
739 		(void) snprintf(prompt, sizeof(prompt), "Enter passphrase for %.16s: ", id);
740 		if ((cp = getpass(prompt)) == NULL) {
741 			break;
742 		}
743 		cc = snprintf(buf, sizeof(buf), "%s", cp);
744 		(void) snprintf(prompt, sizeof(prompt), "Repeat passphrase for %.16s: ", id);
745 		if ((cp = getpass(prompt)) == NULL) {
746 			break;
747 		}
748 		cc = snprintf(passphrase, size, "%s", cp);
749 		if (strcmp(buf, passphrase) == 0) {
750 			(void) memset(buf, 0x0, sizeof(buf));
751 			return cc;
752 		}
753 	}
754 	(void) memset(buf, 0x0, sizeof(buf));
755 	(void) memset(passphrase, 0x0, size);
756 	return 0;
757 }
758 
759 /***************************************************************************/
760 /* exported functions start here */
761 /***************************************************************************/
762 
763 /* initialise a netpgp_t structure */
764 int
765 netpgp_init(netpgp_t *netpgp)
766 {
767 	pgp_io_t	*io;
768 	time_t		 t;
769 	char		 id[MAX_ID_LENGTH];
770 	char		*homedir;
771 	char		*userid;
772 	char		*stream;
773 	char		*passfd;
774 	char		*results;
775 	int		 coredumps;
776 	int		 last;
777 
778 #ifdef HAVE_SYS_RESOURCE_H
779 	struct rlimit	limit;
780 
781 	coredumps = netpgp_getvar(netpgp, "coredumps") != NULL;
782 	if (!coredumps) {
783 		(void) memset(&limit, 0x0, sizeof(limit));
784 		if (setrlimit(RLIMIT_CORE, &limit) != 0) {
785 			(void) fprintf(stderr,
786 			"netpgp: warning - can't turn off core dumps\n");
787 			coredumps = 1;
788 		}
789 	}
790 #else
791 	coredumps = 1;
792 #endif
793 	if ((io = calloc(1, sizeof(*io))) == NULL) {
794 		(void) fprintf(stderr, "netpgp_init: bad alloc\n");
795 		return 0;
796 	}
797 	io->outs = stdout;
798 	if ((stream = netpgp_getvar(netpgp, "outs")) != NULL &&
799 	    strcmp(stream, "<stderr>") == 0) {
800 		io->outs = stderr;
801 	}
802 	io->errs = stderr;
803 	if ((stream = netpgp_getvar(netpgp, "errs")) != NULL &&
804 	    strcmp(stream, "<stdout>") == 0) {
805 		io->errs = stdout;
806 	}
807 	if ((results = netpgp_getvar(netpgp, "res")) == NULL) {
808 		io->res = io->errs;
809 	} else if (strcmp(results, "<stdout>") == 0) {
810 		io->res = stdout;
811 	} else if (strcmp(results, "<stderr>") == 0) {
812 		io->res = stderr;
813 	} else {
814 		if ((io->res = fopen(results, "w")) == NULL) {
815 			(void) fprintf(io->errs, "Can't open results %s for writing\n",
816 				results);
817 			free(io);
818 			return 0;
819 		}
820 	}
821 	netpgp->io = io;
822 	/* get passphrase from an fd */
823 	if ((passfd = netpgp_getvar(netpgp, "pass-fd")) != NULL &&
824 	    (netpgp->passfp = fdopen(atoi(passfd), "r")) == NULL) {
825 		(void) fprintf(io->errs, "Can't open fd %s for reading\n",
826 			passfd);
827 		return 0;
828 	}
829 	/* warn if core dumps are enabled */
830 	if (coredumps) {
831 		(void) fprintf(io->errs,
832 			"netpgp: warning: core dumps enabled\n");
833 	}
834 	/* get home directory - where keyrings are in a subdir */
835 	if ((homedir = netpgp_getvar(netpgp, "homedir")) == NULL) {
836 		(void) fprintf(io->errs, "netpgp: bad homedir\n");
837 		return 0;
838 	}
839 	if (netpgp_getvar(netpgp, "ssh keys") == NULL) {
840 		/* read from ordinary pgp keyrings */
841 		netpgp->pubring = readkeyring(netpgp, "pubring");
842 		if (netpgp->pubring == NULL) {
843 			(void) fprintf(io->errs, "Can't read pub keyring\n");
844 			return 0;
845 		}
846 		/* if a userid has been given, we'll use it */
847 		if ((userid = netpgp_getvar(netpgp, "userid")) == NULL) {
848 			/* also search in config file for default id */
849 			(void) memset(id, 0x0, sizeof(id));
850 			(void) conffile(netpgp, homedir, id, sizeof(id));
851 			if (id[0] != 0x0) {
852 				netpgp_setvar(netpgp, "userid", userid = id);
853 			}
854 		}
855 		/* only read secret keys if we need to */
856 		if (netpgp_getvar(netpgp, "need seckey")) {
857 			/* read the secret ring */
858 			netpgp->secring = readkeyring(netpgp, "secring");
859 			if (netpgp->secring == NULL) {
860 				(void) fprintf(io->errs, "Can't read sec keyring\n");
861 				return 0;
862 			}
863 			/* now, if we don't have a valid user, use the first in secring */
864 			if (!userid && netpgp_getvar(netpgp, "need userid") != NULL) {
865 				/* signing - need userid and sec key */
866 				(void) memset(id, 0x0, sizeof(id));
867 				if (get_first_ring(netpgp->secring, id, sizeof(id), 0)) {
868 					netpgp_setvar(netpgp, "userid", userid = id);
869 				}
870 			}
871 		} else if (netpgp_getvar(netpgp, "need userid") != NULL) {
872 			/* encrypting - get first in pubring */
873 			if (!userid && get_first_ring(netpgp->pubring, id, sizeof(id), 0)) {
874 				(void) netpgp_setvar(netpgp, "userid", userid = id);
875 			}
876 		}
877 		if (!userid && netpgp_getvar(netpgp, "need userid")) {
878 			/* if we don't have a user id, and we need one, fail */
879 			(void) fprintf(io->errs, "Cannot find user id\n");
880 			return 0;
881 		}
882 	} else {
883 		/* read from ssh keys */
884 		last = (netpgp->pubring != NULL);
885 		if (!readsshkeys(netpgp, homedir, netpgp_getvar(netpgp, "need seckey"))) {
886 			(void) fprintf(io->errs, "Can't read ssh keys\n");
887 			return 0;
888 		}
889 		if ((userid = netpgp_getvar(netpgp, "userid")) == NULL) {
890 			get_first_ring(netpgp->pubring, id, sizeof(id), last);
891 			netpgp_setvar(netpgp, "userid", userid = id);
892 		}
893 		if (userid == NULL) {
894 			if (netpgp_getvar(netpgp, "need userid") != NULL) {
895 				(void) fprintf(io->errs,
896 						"Cannot find user id\n");
897 				return 0;
898 			}
899 		} else {
900 			(void) netpgp_setvar(netpgp, "userid", userid);
901 		}
902 	}
903 	t = time(NULL);
904 	netpgp_setvar(netpgp, "initialised", ctime(&t));
905 	return 1;
906 }
907 
908 /* finish off with the netpgp_t struct */
909 int
910 netpgp_end(netpgp_t *netpgp)
911 {
912 	unsigned	i;
913 
914 	for (i = 0 ; i < netpgp->c ; i++) {
915 		if (netpgp->name[i] != NULL) {
916 			free(netpgp->name[i]);
917 		}
918 		if (netpgp->value[i] != NULL) {
919 			free(netpgp->value[i]);
920 		}
921 	}
922 	if (netpgp->name != NULL) {
923 		free(netpgp->name);
924 	}
925 	if (netpgp->value != NULL) {
926 		free(netpgp->value);
927 	}
928 	if (netpgp->pubring != NULL) {
929 		pgp_keyring_free(netpgp->pubring);
930 	}
931 	if (netpgp->secring != NULL) {
932 		pgp_keyring_free(netpgp->secring);
933 	}
934 	free(netpgp->io);
935 	return 1;
936 }
937 
938 /* list the keys in a keyring */
939 int
940 netpgp_list_keys(netpgp_t *netpgp, const int psigs)
941 {
942 	if (netpgp->pubring == NULL) {
943 		(void) fprintf(stderr, "No keyring\n");
944 		return 0;
945 	}
946 	return pgp_keyring_list(netpgp->io, netpgp->pubring, psigs);
947 }
948 
949 /* list the keys in a keyring, returning a JSON encoded string */
950 int
951 netpgp_list_keys_json(netpgp_t *netpgp, char **json, const int psigs)
952 {
953 	mj_t	obj;
954 	int	ret;
955 
956 	if (netpgp->pubring == NULL) {
957 		(void) fprintf(stderr, "No keyring\n");
958 		return 0;
959 	}
960 	(void) memset(&obj, 0x0, sizeof(obj));
961 	if (!pgp_keyring_json(netpgp->io, netpgp->pubring, &obj, psigs)) {
962 		(void) fprintf(stderr, "No keys in keyring\n");
963 		return 0;
964 	}
965 	ret = mj_asprint(json, &obj, MJ_JSON_ENCODE);
966 	mj_delete(&obj);
967 	return ret;
968 }
969 
970 DEFINE_ARRAY(strings_t, char *);
971 
972 #ifndef HKP_VERSION
973 #define HKP_VERSION	1
974 #endif
975 
976 /* find and list some keys in a keyring */
977 int
978 netpgp_match_keys(netpgp_t *netpgp, char *name, const char *fmt, void *vp, const int psigs)
979 {
980 	const pgp_key_t	*key;
981 	unsigned		 k;
982 	strings_t		 pubs;
983 	FILE			*fp = (FILE *)vp;
984 
985 	if (name[0] == '0' && name[1] == 'x') {
986 		name += 2;
987 	}
988 	(void) memset(&pubs, 0x0, sizeof(pubs));
989 	k = 0;
990 	do {
991 		key = pgp_getnextkeybyname(netpgp->io, netpgp->pubring,
992 						name, &k);
993 		if (key != NULL) {
994 			ALLOC(char *, pubs.v, pubs.size, pubs.c, 10, 10,
995 					"netpgp_match_keys", return 0);
996 			if (strcmp(fmt, "mr") == 0) {
997 				pgp_hkp_sprint_keydata(netpgp->io, netpgp->pubring,
998 						key, &pubs.v[pubs.c],
999 						&key->key.pubkey, psigs);
1000 			} else {
1001 				pgp_sprint_keydata(netpgp->io, netpgp->pubring,
1002 						key, &pubs.v[pubs.c],
1003 						"signature ",
1004 						&key->key.pubkey, psigs);
1005 			}
1006 			if (pubs.v[pubs.c] != NULL) {
1007 				pubs.c += 1;
1008 			}
1009 			k += 1;
1010 		}
1011 	} while (key != NULL);
1012 	if (strcmp(fmt, "mr") == 0) {
1013 		(void) fprintf(fp, "info:%d:%d\n", HKP_VERSION, pubs.c);
1014 	} else {
1015 		(void) fprintf(fp, "%d key%s found\n", pubs.c,
1016 			(pubs.c == 1) ? "" : "s");
1017 	}
1018 	for (k = 0 ; k < pubs.c ; k++) {
1019 		(void) fprintf(fp, "%s%s", pubs.v[k], (k < pubs.c - 1) ? "\n" : "");
1020 		free(pubs.v[k]);
1021 	}
1022 	free(pubs.v);
1023 	return pubs.c;
1024 }
1025 
1026 /* find and list some keys in a keyring - return JSON string */
1027 int
1028 netpgp_match_keys_json(netpgp_t *netpgp, char **json, char *name, const char *fmt, const int psigs)
1029 {
1030 	const pgp_key_t	*key;
1031 	unsigned		 k;
1032 	mj_t			 id_array;
1033 	int			 ret;
1034 
1035 	if (name[0] == '0' && name[1] == 'x') {
1036 		name += 2;
1037 	}
1038 	(void) memset(&id_array, 0x0, sizeof(id_array));
1039 	k = 0;
1040 	*json = NULL;
1041 	mj_create(&id_array, "array");
1042 	do {
1043 		key = pgp_getnextkeybyname(netpgp->io, netpgp->pubring,
1044 						name, &k);
1045 		if (key != NULL) {
1046 			if (strcmp(fmt, "mr") == 0) {
1047 #if 0
1048 				pgp_hkp_sprint_keydata(netpgp->io, netpgp->pubring,
1049 						key, &pubs.v[pubs.c],
1050 						&key->key.pubkey, psigs);
1051 #endif
1052 			} else {
1053 				ALLOC(mj_t, id_array.value.v, id_array.size,
1054 					id_array.c, 10, 10, "netpgp_match_keys_json", return 0);
1055 				pgp_sprint_mj(netpgp->io, netpgp->pubring,
1056 						key, &id_array.value.v[id_array.c++],
1057 						"signature ",
1058 						&key->key.pubkey, psigs);
1059 			}
1060 			k += 1;
1061 		}
1062 	} while (key != NULL);
1063 	ret = mj_asprint(json, &id_array, MJ_JSON_ENCODE);
1064 	mj_delete(&id_array);
1065 	return ret;
1066 }
1067 
1068 /* find and list some public keys in a keyring */
1069 int
1070 netpgp_match_pubkeys(netpgp_t *netpgp, char *name, void *vp)
1071 {
1072 	const pgp_key_t	*key;
1073 	unsigned		 k;
1074 	strings_t		 pubs;
1075 	FILE			*fp = (FILE *)vp;
1076 
1077 	(void) memset(&pubs, 0x0, sizeof(pubs));
1078 	do {
1079 		key = pgp_getnextkeybyname(netpgp->io, netpgp->pubring,
1080 						name, &k);
1081 		if (key != NULL) {
1082 			char	out[1024 * 64];
1083 
1084 			ALLOC(char *, pubs.v, pubs.size, pubs.c, 10, 10,
1085 					"netpgp_match_pubkeys", return 0);
1086 			(void) pgp_sprint_pubkey(key, out, sizeof(out));
1087 			pubs.v[pubs.c++] = netpgp_strdup(out);
1088 			k += 1;
1089 		}
1090 	} while (key != NULL);
1091 	(void) fprintf(fp, "info:%d:%d\n", HKP_VERSION, pubs.c);
1092 	for (k = 0 ; k < pubs.c ; k++) {
1093 		(void) fprintf(fp, "%s", pubs.v[k]);
1094 		free(pubs.v[k]);
1095 	}
1096 	free(pubs.v);
1097 	return pubs.c;
1098 }
1099 
1100 /* find a key in a keyring */
1101 int
1102 netpgp_find_key(netpgp_t *netpgp, char *id)
1103 {
1104 	pgp_io_t	*io;
1105 
1106 	io = netpgp->io;
1107 	if (id == NULL) {
1108 		(void) fprintf(io->errs, "NULL id to search for\n");
1109 		return 0;
1110 	}
1111 	return pgp_getkeybyname(netpgp->io, netpgp->pubring, id) != NULL;
1112 }
1113 
1114 /* get a key in a keyring */
1115 char *
1116 netpgp_get_key(netpgp_t *netpgp, const char *name, const char *fmt)
1117 {
1118 	const pgp_key_t	*key;
1119 	char			*newkey;
1120 
1121 	if ((key = resolve_userid(netpgp, netpgp->pubring, name)) == NULL) {
1122 		return NULL;
1123 	}
1124 	if (strcmp(fmt, "mr") == 0) {
1125 		return (pgp_hkp_sprint_keydata(netpgp->io, netpgp->pubring,
1126 				key, &newkey,
1127 				&key->key.pubkey,
1128 				netpgp_getvar(netpgp, "subkey sigs") != NULL) > 0) ? newkey : NULL;
1129 	}
1130 	return (pgp_sprint_keydata(netpgp->io, netpgp->pubring,
1131 				key, &newkey, "signature",
1132 				&key->key.pubkey,
1133 				netpgp_getvar(netpgp, "subkey sigs") != NULL) > 0) ? newkey : NULL;
1134 }
1135 
1136 /* export a given key */
1137 char *
1138 netpgp_export_key(netpgp_t *netpgp, char *name)
1139 {
1140 	const pgp_key_t	*key;
1141 	pgp_io_t		*io;
1142 
1143 	io = netpgp->io;
1144 	if ((key = resolve_userid(netpgp, netpgp->pubring, name)) == NULL) {
1145 		return NULL;
1146 	}
1147 	return pgp_export_key(io, key, NULL);
1148 }
1149 
1150 #define IMPORT_ARMOR_HEAD	"-----BEGIN PGP PUBLIC KEY BLOCK-----"
1151 
1152 /* import a key into our keyring */
1153 int
1154 netpgp_import_key(netpgp_t *netpgp, char *f)
1155 {
1156 	pgp_io_t	*io;
1157 	unsigned	 realarmor;
1158 	int		 done;
1159 
1160 	io = netpgp->io;
1161 	realarmor = isarmoured(io, f, NULL, IMPORT_ARMOR_HEAD);
1162 	done = pgp_keyring_fileread(netpgp->pubring, realarmor, f);
1163 	if (!done) {
1164 		(void) fprintf(io->errs, "Cannot import key from file %s\n", f);
1165 		return 0;
1166 	}
1167 	return pgp_keyring_list(io, netpgp->pubring, 0);
1168 }
1169 
1170 #define ID_OFFSET	38
1171 
1172 /* generate a new key */
1173 int
1174 netpgp_generate_key(netpgp_t *netpgp, char *id, int numbits)
1175 {
1176 	pgp_output_t		*create;
1177 	const unsigned		 noarmor = 0;
1178 	pgp_key_t		*key;
1179 	pgp_io_t		*io;
1180 	uint8_t			*uid;
1181 	char			 passphrase[128];
1182 	char			 newid[1024];
1183 	char			 filename[MAXPATHLEN];
1184 	char			 dir[MAXPATHLEN];
1185 	char			*cp;
1186 	char			*ringfile;
1187 	char			*numtries;
1188 	int             	 attempts;
1189 	int             	 passc;
1190 	int             	 fd;
1191 	int             	 cc;
1192 
1193 	uid = NULL;
1194 	io = netpgp->io;
1195 	/* generate a new key */
1196 	if (id) {
1197 		(void) snprintf(newid, sizeof(newid), "%s", id);
1198 	} else {
1199 		(void) snprintf(newid, sizeof(newid),
1200 			"RSA %d-bit key <%s@localhost>", numbits, getenv("LOGNAME"));
1201 	}
1202 	uid = (uint8_t *)newid;
1203 	key = pgp_rsa_new_selfsign_key(numbits, 65537UL, uid,
1204 			netpgp_getvar(netpgp, "hash"),
1205 			netpgp_getvar(netpgp, "cipher"));
1206 	if (key == NULL) {
1207 		(void) fprintf(io->errs, "Cannot generate key\n");
1208 		return 0;
1209 	}
1210 	cp = NULL;
1211 	pgp_sprint_keydata(netpgp->io, NULL, key, &cp, "signature ", &key->key.seckey.pubkey, 0);
1212 	(void) fprintf(stdout, "%s", cp);
1213 	/* write public key */
1214 	cc = snprintf(dir, sizeof(dir), "%s/%.16s", netpgp_getvar(netpgp, "homedir"), &cp[ID_OFFSET]);
1215 	netpgp_setvar(netpgp, "generated userid", &dir[cc - 16]);
1216 	if (mkdir(dir, 0700) < 0) {
1217 		(void) fprintf(io->errs, "can't mkdir '%s'\n", dir);
1218 		return 0;
1219 	}
1220 	(void) fprintf(io->errs, "netpgp: generated keys in directory %s\n", dir);
1221 	(void) snprintf(ringfile = filename, sizeof(filename), "%s/pubring.gpg", dir);
1222 	if (!appendkey(io, key, ringfile)) {
1223 		(void) fprintf(io->errs, "Cannot write pubkey to '%s'\n", ringfile);
1224 		return 0;
1225 	}
1226 	if (netpgp->pubring != NULL) {
1227 		pgp_keyring_free(netpgp->pubring);
1228 	}
1229 	/* write secret key */
1230 	(void) snprintf(ringfile = filename, sizeof(filename), "%s/secring.gpg", dir);
1231 	if ((fd = pgp_setup_file_append(&create, ringfile)) < 0) {
1232 		fd = pgp_setup_file_write(&create, ringfile, 0);
1233 	}
1234 	if (fd < 0) {
1235 		(void) fprintf(io->errs, "can't append secring '%s'\n", ringfile);
1236 		return 0;
1237 	}
1238 	/* get the passphrase */
1239 	if ((numtries = netpgp_getvar(netpgp, "numtries")) == NULL ||
1240 	    (attempts = atoi(numtries)) <= 0) {
1241 		attempts = MAX_PASSPHRASE_ATTEMPTS;
1242 	} else if (strcmp(numtries, "unlimited") == 0) {
1243 		attempts = INFINITE_ATTEMPTS;
1244 	}
1245 	passc = find_passphrase(netpgp->passfp, &cp[ID_OFFSET], passphrase, sizeof(passphrase), attempts);
1246 	if (!pgp_write_xfer_seckey(create, key, (uint8_t *)passphrase, (const unsigned)passc, noarmor)) {
1247 		(void) fprintf(io->errs, "Cannot write seckey\n");
1248 		return 0;
1249 	}
1250 	pgp_teardown_file_write(create, fd);
1251 	if (netpgp->secring != NULL) {
1252 		pgp_keyring_free(netpgp->secring);
1253 	}
1254 	pgp_keydata_free(key);
1255 	free(cp);
1256 	return 1;
1257 }
1258 
1259 /* encrypt a file */
1260 int
1261 netpgp_encrypt_file(netpgp_t *netpgp,
1262 			const char *userid,
1263 			const char *f,
1264 			char *out,
1265 			int armored)
1266 {
1267 	const pgp_key_t	*key;
1268 	const unsigned		 overwrite = 1;
1269 	const char		*suffix;
1270 	pgp_io_t		*io;
1271 	char			 outname[MAXPATHLEN];
1272 
1273 	io = netpgp->io;
1274 	if (f == NULL) {
1275 		(void) fprintf(io->errs,
1276 			"netpgp_encrypt_file: no filename specified\n");
1277 		return 0;
1278 	}
1279 	suffix = (armored) ? ".asc" : ".gpg";
1280 	/* get key with which to sign */
1281 	if ((key = resolve_userid(netpgp, netpgp->pubring, userid)) == NULL) {
1282 		return 0;
1283 	}
1284 	if (out == NULL) {
1285 		(void) snprintf(outname, sizeof(outname), "%s%s", f, suffix);
1286 		out = outname;
1287 	}
1288 	return (int)pgp_encrypt_file(io, f, out, key, (unsigned)armored,
1289 				overwrite, netpgp_getvar(netpgp, "cipher"));
1290 }
1291 
1292 #define ARMOR_HEAD	"-----BEGIN PGP MESSAGE-----"
1293 
1294 /* decrypt a file */
1295 int
1296 netpgp_decrypt_file(netpgp_t *netpgp, const char *f, char *out, int armored)
1297 {
1298 	const unsigned	 overwrite = 1;
1299 	pgp_io_t	*io;
1300 	unsigned	 realarmor;
1301 	unsigned	 sshkeys;
1302 	char		*numtries;
1303 	int            	 attempts;
1304 
1305 	__PGP_USED(armored);
1306 	io = netpgp->io;
1307 	if (f == NULL) {
1308 		(void) fprintf(io->errs,
1309 			"netpgp_decrypt_file: no filename specified\n");
1310 		return 0;
1311 	}
1312 	realarmor = isarmoured(io, f, NULL, ARMOR_HEAD);
1313 	sshkeys = (unsigned)(netpgp_getvar(netpgp, "ssh keys") != NULL);
1314 	if ((numtries = netpgp_getvar(netpgp, "numtries")) == NULL ||
1315 	    (attempts = atoi(numtries)) <= 0) {
1316 		attempts = MAX_PASSPHRASE_ATTEMPTS;
1317 	} else if (strcmp(numtries, "unlimited") == 0) {
1318 		attempts = INFINITE_ATTEMPTS;
1319 	}
1320 	return pgp_decrypt_file(netpgp->io, f, out, netpgp->secring,
1321 				netpgp->pubring,
1322 				realarmor, overwrite, sshkeys,
1323 				netpgp->passfp, attempts, get_passphrase_cb);
1324 }
1325 
1326 /* sign a file */
1327 int
1328 netpgp_sign_file(netpgp_t *netpgp,
1329 		const char *userid,
1330 		const char *f,
1331 		char *out,
1332 		int armored,
1333 		int cleartext,
1334 		int detached)
1335 {
1336 	const pgp_key_t		*keypair;
1337 	const pgp_key_t		*pubkey;
1338 	const unsigned		 overwrite = 1;
1339 	pgp_seckey_t		*seckey;
1340 	const char		*hashalg;
1341 	pgp_io_t		*io;
1342 	char			*numtries;
1343 	int			 attempts;
1344 	int			 ret;
1345 	int			 i;
1346 
1347 	io = netpgp->io;
1348 	if (f == NULL) {
1349 		(void) fprintf(io->errs,
1350 			"netpgp_sign_file: no filename specified\n");
1351 		return 0;
1352 	}
1353 	/* get key with which to sign */
1354 	if ((keypair = resolve_userid(netpgp, netpgp->secring, userid)) == NULL) {
1355 		return 0;
1356 	}
1357 	ret = 1;
1358 	if ((numtries = netpgp_getvar(netpgp, "numtries")) == NULL ||
1359 	    (attempts = atoi(numtries)) <= 0) {
1360 		attempts = MAX_PASSPHRASE_ATTEMPTS;
1361 	} else if (strcmp(numtries, "unlimited") == 0) {
1362 		attempts = INFINITE_ATTEMPTS;
1363 	}
1364 	for (i = 0, seckey = NULL ; !seckey && (i < attempts || attempts == INFINITE_ATTEMPTS) ; i++) {
1365 		if (netpgp->passfp == NULL) {
1366 			/* print out the user id */
1367 			pubkey = pgp_getkeybyname(io, netpgp->pubring, userid);
1368 			if (pubkey == NULL) {
1369 				(void) fprintf(io->errs,
1370 					"netpgp: warning - using pubkey from secring\n");
1371 				pgp_print_keydata(io, netpgp->pubring, keypair, "signature ",
1372 					&keypair->key.seckey.pubkey, 0);
1373 			} else {
1374 				pgp_print_keydata(io, netpgp->pubring, pubkey, "signature ",
1375 					&pubkey->key.pubkey, 0);
1376 			}
1377 		}
1378 		if (netpgp_getvar(netpgp, "ssh keys") == NULL) {
1379 			/* now decrypt key */
1380 			seckey = pgp_decrypt_seckey(keypair, netpgp->passfp);
1381 			if (seckey == NULL) {
1382 				(void) fprintf(io->errs, "Bad passphrase\n");
1383 			}
1384 		} else {
1385 			pgp_keyring_t	*secring;
1386 
1387 			secring = netpgp->secring;
1388 			seckey = &secring->keys[0].key.seckey;
1389 		}
1390 	}
1391 	if (seckey == NULL) {
1392 		(void) fprintf(io->errs, "Bad passphrase\n");
1393 		return 0;
1394 	}
1395 	/* sign file */
1396 	hashalg = netpgp_getvar(netpgp, "hash");
1397 	if (seckey->pubkey.alg == PGP_PKA_DSA) {
1398 		hashalg = "sha1";
1399 	}
1400 	if (detached) {
1401 		ret = pgp_sign_detached(io, f, out, seckey, hashalg,
1402 				get_birthtime(netpgp_getvar(netpgp, "birthtime")),
1403 				get_duration(netpgp_getvar(netpgp, "duration")),
1404 				(unsigned)armored,
1405 				overwrite);
1406 	} else {
1407 		ret = pgp_sign_file(io, f, out, seckey, hashalg,
1408 				get_birthtime(netpgp_getvar(netpgp, "birthtime")),
1409 				get_duration(netpgp_getvar(netpgp, "duration")),
1410 				(unsigned)armored, (unsigned)cleartext,
1411 				overwrite);
1412 	}
1413 	pgp_forget(seckey, (unsigned)sizeof(*seckey));
1414 	return ret;
1415 }
1416 
1417 #define ARMOR_SIG_HEAD	"-----BEGIN PGP (SIGNATURE|SIGNED MESSAGE)-----"
1418 
1419 /* verify a file */
1420 int
1421 netpgp_verify_file(netpgp_t *netpgp, const char *in, const char *out, int armored)
1422 {
1423 	pgp_validation_t	 result;
1424 	pgp_io_t		*io;
1425 	unsigned		 realarmor;
1426 
1427 	__PGP_USED(armored);
1428 	(void) memset(&result, 0x0, sizeof(result));
1429 	io = netpgp->io;
1430 	if (in == NULL) {
1431 		(void) fprintf(io->errs,
1432 			"netpgp_verify_file: no filename specified\n");
1433 		return 0;
1434 	}
1435 	realarmor = isarmoured(io, in, NULL, ARMOR_SIG_HEAD);
1436 	if (pgp_validate_file(io, &result, in, out, (const int)realarmor, netpgp->pubring)) {
1437 		resultp(io, in, &result, netpgp->pubring);
1438 		return 1;
1439 	}
1440 	if (result.validc + result.invalidc + result.unknownc == 0) {
1441 		(void) fprintf(io->errs,
1442 		"\"%s\": No signatures found - is this a signed file?\n",
1443 			in);
1444 	} else if (result.invalidc == 0 && result.unknownc == 0) {
1445 		(void) fprintf(io->errs,
1446 			"\"%s\": file verification failure: invalid signature time\n", in);
1447 	} else {
1448 		(void) fprintf(io->errs,
1449 "\"%s\": verification failure: %u invalid signatures, %u unknown signatures\n",
1450 			in, result.invalidc, result.unknownc);
1451 	}
1452 	return 0;
1453 }
1454 
1455 /* sign some memory */
1456 int
1457 netpgp_sign_memory(netpgp_t *netpgp,
1458 		const char *userid,
1459 		char *mem,
1460 		size_t size,
1461 		char *out,
1462 		size_t outsize,
1463 		const unsigned armored,
1464 		const unsigned cleartext)
1465 {
1466 	const pgp_key_t		*keypair;
1467 	const pgp_key_t		*pubkey;
1468 	pgp_seckey_t		*seckey;
1469 	pgp_memory_t		*signedmem;
1470 	const char		*hashalg;
1471 	pgp_io_t		*io;
1472 	char 			*numtries;
1473 	int			 attempts;
1474 	int			 ret;
1475 	int			 i;
1476 
1477 	io = netpgp->io;
1478 	if (mem == NULL) {
1479 		(void) fprintf(io->errs,
1480 			"netpgp_sign_memory: no memory to sign\n");
1481 		return 0;
1482 	}
1483 	if ((keypair = resolve_userid(netpgp, netpgp->secring, userid)) == NULL) {
1484 		return 0;
1485 	}
1486 	ret = 1;
1487 	if ((numtries = netpgp_getvar(netpgp, "numtries")) == NULL ||
1488 	    (attempts = atoi(numtries)) <= 0) {
1489 		attempts = MAX_PASSPHRASE_ATTEMPTS;
1490 	} else if (strcmp(numtries, "unlimited") == 0) {
1491 		attempts = INFINITE_ATTEMPTS;
1492 	}
1493 	for (i = 0, seckey = NULL ; !seckey && (i < attempts || attempts == INFINITE_ATTEMPTS) ; i++) {
1494 		if (netpgp->passfp == NULL) {
1495 			/* print out the user id */
1496 			pubkey = pgp_getkeybyname(io, netpgp->pubring, userid);
1497 			if (pubkey == NULL) {
1498 				(void) fprintf(io->errs,
1499 					"netpgp: warning - using pubkey from secring\n");
1500 				pgp_print_keydata(io, netpgp->pubring, keypair, "signature ",
1501 					&keypair->key.seckey.pubkey, 0);
1502 			} else {
1503 				pgp_print_keydata(io, netpgp->pubring, pubkey, "signature ",
1504 					&pubkey->key.pubkey, 0);
1505 			}
1506 		}
1507 		/* now decrypt key */
1508 		seckey = pgp_decrypt_seckey(keypair, netpgp->passfp);
1509 		if (seckey == NULL) {
1510 			(void) fprintf(io->errs, "Bad passphrase\n");
1511 		}
1512 	}
1513 	if (seckey == NULL) {
1514 		(void) fprintf(io->errs, "Bad passphrase\n");
1515 		return 0;
1516 	}
1517 	/* sign file */
1518 	(void) memset(out, 0x0, outsize);
1519 	hashalg = netpgp_getvar(netpgp, "hash");
1520 	if (seckey->pubkey.alg == PGP_PKA_DSA) {
1521 		hashalg = "sha1";
1522 	}
1523 	signedmem = pgp_sign_buf(io, mem, size, seckey,
1524 				get_birthtime(netpgp_getvar(netpgp, "birthtime")),
1525 				get_duration(netpgp_getvar(netpgp, "duration")),
1526 				hashalg, armored, cleartext);
1527 	if (signedmem) {
1528 		size_t	m;
1529 
1530 		m = MIN(pgp_mem_len(signedmem), outsize);
1531 		(void) memcpy(out, pgp_mem_data(signedmem), m);
1532 		pgp_memory_free(signedmem);
1533 		ret = (int)m;
1534 	} else {
1535 		ret = 0;
1536 	}
1537 	pgp_forget(seckey, (unsigned)sizeof(*seckey));
1538 	return ret;
1539 }
1540 
1541 /* verify memory */
1542 int
1543 netpgp_verify_memory(netpgp_t *netpgp, const void *in, const size_t size,
1544 			void *out, size_t outsize, const int armored)
1545 {
1546 	pgp_validation_t	 result;
1547 	pgp_memory_t		*signedmem;
1548 	pgp_memory_t		*cat;
1549 	pgp_io_t		*io;
1550 	size_t			 m;
1551 	int			 ret;
1552 
1553 	(void) memset(&result, 0x0, sizeof(result));
1554 	io = netpgp->io;
1555 	if (in == NULL) {
1556 		(void) fprintf(io->errs,
1557 			"netpgp_verify_memory: no memory to verify\n");
1558 		return 0;
1559 	}
1560 	signedmem = pgp_memory_new();
1561 	pgp_memory_add(signedmem, in, size);
1562 	if (out) {
1563 		cat = pgp_memory_new();
1564 	}
1565 	ret = pgp_validate_mem(io, &result, signedmem,
1566 				(out) ? &cat : NULL,
1567 				armored, netpgp->pubring);
1568 	/* signedmem is freed from pgp_validate_mem */
1569 	if (ret) {
1570 		resultp(io, "<stdin>", &result, netpgp->pubring);
1571 		if (out) {
1572 			m = MIN(pgp_mem_len(cat), outsize);
1573 			(void) memcpy(out, pgp_mem_data(cat), m);
1574 			pgp_memory_free(cat);
1575 		} else {
1576 			m = 1;
1577 		}
1578 		return (int)m;
1579 	}
1580 	if (result.validc + result.invalidc + result.unknownc == 0) {
1581 		(void) fprintf(io->errs,
1582 		"No signatures found - is this memory signed?\n");
1583 	} else if (result.invalidc == 0 && result.unknownc == 0) {
1584 		(void) fprintf(io->errs,
1585 			"memory verification failure: invalid signature time\n");
1586 	} else {
1587 		(void) fprintf(io->errs,
1588 "memory verification failure: %u invalid signatures, %u unknown signatures\n",
1589 			result.invalidc, result.unknownc);
1590 	}
1591 	return 0;
1592 }
1593 
1594 /* encrypt some memory */
1595 int
1596 netpgp_encrypt_memory(netpgp_t *netpgp,
1597 			const char *userid,
1598 			void *in,
1599 			const size_t insize,
1600 			char *out,
1601 			size_t outsize,
1602 			int armored)
1603 {
1604 	const pgp_key_t	*keypair;
1605 	pgp_memory_t	*enc;
1606 	pgp_io_t	*io;
1607 	size_t		 m;
1608 
1609 	io = netpgp->io;
1610 	if (in == NULL) {
1611 		(void) fprintf(io->errs,
1612 			"netpgp_encrypt_buf: no memory to encrypt\n");
1613 		return 0;
1614 	}
1615 	if ((keypair = resolve_userid(netpgp, netpgp->pubring, userid)) == NULL) {
1616 		return 0;
1617 	}
1618 	if (in == out) {
1619 		(void) fprintf(io->errs,
1620 			"netpgp_encrypt_buf: input and output bufs need to be different\n");
1621 		return 0;
1622 	}
1623 	if (outsize < insize) {
1624 		(void) fprintf(io->errs,
1625 			"netpgp_encrypt_buf: input size is larger than output size\n");
1626 		return 0;
1627 	}
1628 	enc = pgp_encrypt_buf(io, in, insize, keypair, (unsigned)armored,
1629 				netpgp_getvar(netpgp, "cipher"));
1630 	m = MIN(pgp_mem_len(enc), outsize);
1631 	(void) memcpy(out, pgp_mem_data(enc), m);
1632 	pgp_memory_free(enc);
1633 	return (int)m;
1634 }
1635 
1636 /* decrypt a chunk of memory */
1637 int
1638 netpgp_decrypt_memory(netpgp_t *netpgp, const void *input, const size_t insize,
1639 			char *out, size_t outsize, const int armored)
1640 {
1641 	pgp_memory_t	*mem;
1642 	pgp_io_t	*io;
1643 	unsigned	 realarmour;
1644 	unsigned	 sshkeys;
1645 	size_t		 m;
1646 	char		*numtries;
1647 	int            	 attempts;
1648 
1649 	__PGP_USED(armored);
1650 	io = netpgp->io;
1651 	if (input == NULL) {
1652 		(void) fprintf(io->errs,
1653 			"netpgp_decrypt_memory: no memory\n");
1654 		return 0;
1655 	}
1656 	realarmour = isarmoured(io, NULL, input, ARMOR_HEAD);
1657 	sshkeys = (unsigned)(netpgp_getvar(netpgp, "ssh keys") != NULL);
1658 	if ((numtries = netpgp_getvar(netpgp, "numtries")) == NULL ||
1659 	    (attempts = atoi(numtries)) <= 0) {
1660 		attempts = MAX_PASSPHRASE_ATTEMPTS;
1661 	} else if (strcmp(numtries, "unlimited") == 0) {
1662 		attempts = INFINITE_ATTEMPTS;
1663 	}
1664 	mem = pgp_decrypt_buf(netpgp->io, input, insize, netpgp->secring,
1665 				netpgp->pubring,
1666 				realarmour, sshkeys,
1667 				netpgp->passfp,
1668 				attempts,
1669 				get_passphrase_cb);
1670 	if (mem == NULL) {
1671 		return -1;
1672 	}
1673 	m = MIN(pgp_mem_len(mem), outsize);
1674 	(void) memcpy(out, pgp_mem_data(mem), m);
1675 	pgp_memory_free(mem);
1676 	return (int)m;
1677 }
1678 
1679 /* wrappers for the ops_debug_level functions we added to openpgpsdk */
1680 
1681 /* set the debugging level per filename */
1682 int
1683 netpgp_set_debug(const char *f)
1684 {
1685 	return pgp_set_debug_level(f);
1686 }
1687 
1688 /* get the debugging level per filename */
1689 int
1690 netpgp_get_debug(const char *f)
1691 {
1692 	return pgp_get_debug_level(f);
1693 }
1694 
1695 /* return the version for the library */
1696 const char *
1697 netpgp_get_info(const char *type)
1698 {
1699 	return pgp_get_info(type);
1700 }
1701 
1702 /* list all the packets in a file */
1703 int
1704 netpgp_list_packets(netpgp_t *netpgp, char *f, int armor, char *pubringname)
1705 {
1706 	pgp_keyring_t	*keyring;
1707 	const unsigned	 noarmor = 0;
1708 	struct stat	 st;
1709 	pgp_io_t	*io;
1710 	char		 ringname[MAXPATHLEN];
1711 	char		*homedir;
1712 	int		 ret;
1713 
1714 	io = netpgp->io;
1715 	if (f == NULL) {
1716 		(void) fprintf(io->errs, "No file containing packets\n");
1717 		return 0;
1718 	}
1719 	if (stat(f, &st) < 0) {
1720 		(void) fprintf(io->errs, "No such file '%s'\n", f);
1721 		return 0;
1722 	}
1723 	homedir = netpgp_getvar(netpgp, "homedir");
1724 	if (pubringname == NULL) {
1725 		(void) snprintf(ringname, sizeof(ringname),
1726 				"%s/pubring.gpg", homedir);
1727 		pubringname = ringname;
1728 	}
1729 	if ((keyring = calloc(1, sizeof(*keyring))) == NULL) {
1730 		(void) fprintf(io->errs, "netpgp_list_packets: bad alloc\n");
1731 		return 0;
1732 	}
1733 	if (!pgp_keyring_fileread(keyring, noarmor, pubringname)) {
1734 		free(keyring);
1735 		(void) fprintf(io->errs, "Cannot read pub keyring %s\n",
1736 			pubringname);
1737 		return 0;
1738 	}
1739 	netpgp->pubring = keyring;
1740 	netpgp_setvar(netpgp, "pubring", pubringname);
1741 	ret = pgp_list_packets(io, f, (unsigned)armor,
1742 					netpgp->secring,
1743 					netpgp->pubring,
1744 					netpgp->passfp,
1745 					get_passphrase_cb);
1746 	free(keyring);
1747 	return ret;
1748 }
1749 
1750 /* set a variable */
1751 int
1752 netpgp_setvar(netpgp_t *netpgp, const char *name, const char *value)
1753 {
1754 	char	*newval;
1755 	int	 i;
1756 
1757 	/* protect against the case where 'value' is netpgp->value[i] */
1758 	newval = netpgp_strdup(value);
1759 	if ((i = findvar(netpgp, name)) < 0) {
1760 		/* add the element to the array */
1761 		if (size_arrays(netpgp, netpgp->size + 15)) {
1762 			netpgp->name[i = netpgp->c++] = netpgp_strdup(name);
1763 		}
1764 	} else {
1765 		/* replace the element in the array */
1766 		if (netpgp->value[i]) {
1767 			free(netpgp->value[i]);
1768 			netpgp->value[i] = NULL;
1769 		}
1770 	}
1771 	/* sanity checks for range of values */
1772 	if (strcmp(name, "hash") == 0 || strcmp(name, "algorithm") == 0) {
1773 		if (pgp_str_to_hash_alg(newval) == PGP_HASH_UNKNOWN) {
1774 			free(newval);
1775 			return 0;
1776 		}
1777 	}
1778 	netpgp->value[i] = newval;
1779 	return 1;
1780 }
1781 
1782 /* unset a variable */
1783 int
1784 netpgp_unsetvar(netpgp_t *netpgp, const char *name)
1785 {
1786 	int	i;
1787 
1788 	if ((i = findvar(netpgp, name)) >= 0) {
1789 		if (netpgp->value[i]) {
1790 			free(netpgp->value[i]);
1791 			netpgp->value[i] = NULL;
1792 		}
1793 		netpgp->value[i] = NULL;
1794 		return 1;
1795 	}
1796 	return 0;
1797 }
1798 
1799 /* get a variable's value (NULL if not set) */
1800 char *
1801 netpgp_getvar(netpgp_t *netpgp, const char *name)
1802 {
1803 	int	i;
1804 
1805 	return ((i = findvar(netpgp, name)) < 0) ? NULL : netpgp->value[i];
1806 }
1807 
1808 /* increment a value */
1809 int
1810 netpgp_incvar(netpgp_t *netpgp, const char *name, const int delta)
1811 {
1812 	char	*cp;
1813 	char	 num[16];
1814 	int	 val;
1815 
1816 	val = 0;
1817 	if ((cp = netpgp_getvar(netpgp, name)) != NULL) {
1818 		val = atoi(cp);
1819 	}
1820 	(void) snprintf(num, sizeof(num), "%d", val + delta);
1821 	netpgp_setvar(netpgp, name, num);
1822 	return 1;
1823 }
1824 
1825 /* set the home directory value to "home/subdir" */
1826 int
1827 netpgp_set_homedir(netpgp_t *netpgp, char *home, const char *subdir, const int quiet)
1828 {
1829 	struct stat	st;
1830 	char		d[MAXPATHLEN];
1831 
1832 	if (home == NULL) {
1833 		if (!quiet) {
1834 			(void) fprintf(stderr, "NULL HOME directory\n");
1835 		}
1836 		return 0;
1837 	}
1838 	(void) snprintf(d, sizeof(d), "%s%s", home, (subdir) ? subdir : "");
1839 	if (stat(d, &st) == 0) {
1840 		if ((st.st_mode & S_IFMT) == S_IFDIR) {
1841 			netpgp_setvar(netpgp, "homedir", d);
1842 			return 1;
1843 		}
1844 		(void) fprintf(stderr, "netpgp: homedir \"%s\" is not a dir\n",
1845 					d);
1846 		return 0;
1847 	}
1848 	if (!quiet) {
1849 		(void) fprintf(stderr,
1850 			"netpgp: warning homedir \"%s\" not found\n", d);
1851 	}
1852 	netpgp_setvar(netpgp, "homedir", d);
1853 	return 1;
1854 }
1855 
1856 /* validate all sigs in the pub keyring */
1857 int
1858 netpgp_validate_sigs(netpgp_t *netpgp)
1859 {
1860 	pgp_validation_t	result;
1861 
1862 	return (int)pgp_validate_all_sigs(&result, netpgp->pubring, NULL);
1863 }
1864 
1865 /* print the json out on 'fp' */
1866 int
1867 netpgp_format_json(void *vp, const char *json, const int psigs)
1868 {
1869 	mj_t	 ids;
1870 	FILE	*fp;
1871 	int	 from;
1872 	int	 idc;
1873 	int	 tok;
1874 	int	 to;
1875 	int	 i;
1876 
1877 	if ((fp = (FILE *)vp) == NULL || json == NULL) {
1878 		return 0;
1879 	}
1880 	/* ids is an array of strings, each containing 1 entry */
1881 	(void) memset(&ids, 0x0, sizeof(ids));
1882 	from = to = tok = 0;
1883 	/* convert from string into an mj structure */
1884 	(void) mj_parse(&ids, json, &from, &to, &tok);
1885 	if ((idc = mj_arraycount(&ids)) == 1 && strchr(json, '{') == NULL) {
1886 		idc = 0;
1887 	}
1888 	(void) fprintf(fp, "%d key%s found\n", idc, (idc == 1) ? "" : "s");
1889 	for (i = 0 ; i < idc ; i++) {
1890 		format_json_key(fp, &ids.value.v[i], psigs);
1891 	}
1892 	/* clean up */
1893 	mj_delete(&ids);
1894 	return idc;
1895 }
1896 
1897 /* find a key in keyring, and write it in ssh format */
1898 int
1899 netpgp_write_sshkey(netpgp_t *netpgp, char *s, const char *userid, char *out, size_t size)
1900 {
1901 	const pgp_key_t	*key;
1902 	pgp_keyring_t	*keyring;
1903 	pgp_io_t	*io;
1904 	unsigned	 k;
1905 	size_t		 cc;
1906 	char		 f[MAXPATHLEN];
1907 
1908 	if ((io = calloc(1, sizeof(pgp_io_t))) == NULL) {
1909 		(void) fprintf(stderr, "netpgp_save_sshpub: bad alloc 1\n");
1910 		return 0;
1911 	}
1912 	io->outs = stdout;
1913 	io->errs = stderr;
1914 	io->res = stderr;
1915 	netpgp->io = io;
1916 	/* write new to temp file */
1917 	savepubkey(s, f, sizeof(f));
1918 	if ((keyring = calloc(1, sizeof(*keyring))) == NULL) {
1919 		(void) fprintf(stderr, "netpgp_save_sshpub: bad alloc 2\n");
1920 		return 0;
1921 	}
1922 	if (!pgp_keyring_fileread(netpgp->pubring = keyring, 1, f)) {
1923 		(void) fprintf(stderr, "can't import key\n");
1924 		return 0;
1925 	}
1926 	/* get rsa key */
1927 	k = 0;
1928 	key = pgp_getnextkeybyname(netpgp->io, netpgp->pubring, userid, &k);
1929 	if (key == NULL) {
1930 		(void) fprintf(stderr, "no key found for '%s'\n", userid);
1931 		return 0;
1932 	}
1933 	if (key->key.pubkey.alg != PGP_PKA_RSA) {
1934 		/* we're not interested in supporting DSA either :-) */
1935 		(void) fprintf(stderr, "key not RSA '%s'\n", userid);
1936 		return 0;
1937 	}
1938 	/* XXX - check trust sigs */
1939 	/* XXX - check expiry */
1940 	/* XXX - check start */
1941 	/* XXX - check not weak key */
1942 	/* get rsa e and n */
1943 	(void) memset(out, 0x0, size);
1944 	cc = formatstring((char *)out, (const uint8_t *)"ssh-rsa", 7);
1945 	cc += formatbignum((char *)&out[cc], key->key.pubkey.key.rsa.e);
1946 	cc += formatbignum((char *)&out[cc], key->key.pubkey.key.rsa.n);
1947 	free(io);
1948 	free(keyring);
1949 	return (int)cc;
1950 }
1951