xref: /netbsd-src/crypto/external/bsd/netpgp/dist/src/lib/netpgp.c (revision 54c71dee8ce8ff710b7e2b5a511b77d6cae19a0e)
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.63 2010/07/01 04:27:21 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 "ops-ssh.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 	__OPS_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, 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 	return 1;
119 }
120 
121 /* small function to pretty print an 8-character raw userid */
122 static char    *
123 userid_to_id(const uint8_t *userid, char *id)
124 {
125 	static const char *hexes = "0123456789abcdef";
126 	int		   i;
127 
128 	for (i = 0; i < 8 ; i++) {
129 		id[i * 2] = hexes[(unsigned)(userid[i] & 0xf0) >> 4];
130 		id[(i * 2) + 1] = hexes[userid[i] & 0xf];
131 	}
132 	id[8 * 2] = 0x0;
133 	return id;
134 }
135 
136 /* print out the successful signature information */
137 static void
138 resultp(__ops_io_t *io,
139 	const char *f,
140 	__ops_validation_t *res,
141 	__ops_keyring_t *ring)
142 {
143 	const __ops_key_t	*pubkey;
144 	unsigned		 from;
145 	unsigned		 i;
146 	time_t			 t;
147 	char			 id[MAX_ID_LENGTH + 1];
148 
149 	for (i = 0; i < res->validc; i++) {
150 		(void) fprintf(io->res,
151 			"Good signature for %s made %s",
152 			(f) ? f : "<stdin>",
153 			ctime(&res->valid_sigs[i].birthtime));
154 		if (res->duration > 0) {
155 			t = res->birthtime + res->duration;
156 			(void) fprintf(io->res, "Valid until %s", ctime(&t));
157 		}
158 		(void) fprintf(io->res,
159 			"using %s key %s\n",
160 			__ops_show_pka(res->valid_sigs[i].key_alg),
161 			userid_to_id(res->valid_sigs[i].signer_id, id));
162 		from = 0;
163 		pubkey = __ops_getkeybyid(io, ring,
164 			(const uint8_t *) res->valid_sigs[i].signer_id,
165 			&from);
166 		__ops_print_keydata(io, ring, pubkey, "pub", &pubkey->key.pubkey, 0);
167 	}
168 }
169 
170 /* check there's enough space in the arrays */
171 static int
172 size_arrays(netpgp_t *netpgp, unsigned needed)
173 {
174 	char	**temp;
175 
176 	if (netpgp->size == 0) {
177 		/* only get here first time around */
178 		netpgp->size = needed;
179 		if ((netpgp->name = calloc(sizeof(char *), needed)) == NULL) {
180 			(void) fprintf(stderr, "size_arrays: bad alloc\n");
181 			return 0;
182 		}
183 		if ((netpgp->value = calloc(sizeof(char *), needed)) == NULL) {
184 			free(netpgp->name);
185 			(void) fprintf(stderr, "size_arrays: bad alloc\n");
186 			return 0;
187 		}
188 	} else if (netpgp->c == netpgp->size) {
189 		/* only uses 'needed' when filled array */
190 		netpgp->size += needed;
191 		temp = realloc(netpgp->name, sizeof(char *) * needed);
192 		if (temp == NULL) {
193 			(void) fprintf(stderr, "size_arrays: bad alloc\n");
194 			return 0;
195 		}
196 		netpgp->name = temp;
197 		temp = realloc(netpgp->value, sizeof(char *) * needed);
198 		if (temp == NULL) {
199 			(void) fprintf(stderr, "size_arrays: bad alloc\n");
200 			return 0;
201 		}
202 		netpgp->value = temp;
203 	}
204 	return 1;
205 }
206 
207 /* find the name in the array */
208 static int
209 findvar(netpgp_t *netpgp, const char *name)
210 {
211 	unsigned	i;
212 
213 	for (i = 0 ; i < netpgp->c && strcmp(netpgp->name[i], name) != 0; i++) {
214 	}
215 	return (i == netpgp->c) ? -1 : (int)i;
216 }
217 
218 /* read a keyring and return it */
219 static void *
220 readkeyring(netpgp_t *netpgp, const char *name)
221 {
222 	__ops_keyring_t	*keyring;
223 	const unsigned	 noarmor = 0;
224 	char		 f[MAXPATHLEN];
225 	char		*filename;
226 	char		*homedir;
227 
228 	homedir = netpgp_getvar(netpgp, "homedir");
229 	if ((filename = netpgp_getvar(netpgp, name)) == NULL) {
230 		(void) snprintf(f, sizeof(f), "%s/%s.gpg", homedir, name);
231 		filename = f;
232 	}
233 	if ((keyring = calloc(1, sizeof(*keyring))) == NULL) {
234 		(void) fprintf(stderr, "readkeyring: bad alloc\n");
235 		return NULL;
236 	}
237 	if (!__ops_keyring_fileread(keyring, noarmor, filename)) {
238 		free(keyring);
239 		(void) fprintf(stderr, "Can't read %s %s\n", name, filename);
240 		return NULL;
241 	}
242 	netpgp_setvar(netpgp, name, filename);
243 	return keyring;
244 }
245 
246 /* read keys from ssh key files */
247 static int
248 readsshkeys(netpgp_t *netpgp, char *homedir)
249 {
250 	__ops_keyring_t	*pubring;
251 	__ops_keyring_t	*secring;
252 	unsigned	 hashtype;
253 	char		*hash;
254 	char		 f[MAXPATHLEN];
255 	char		*filename;
256 
257 	if ((filename = netpgp_getvar(netpgp, "sshkeyfile")) == NULL) {
258 		(void) snprintf(f, sizeof(f), "%s/id_rsa.pub", homedir);
259 		filename = f;
260 	}
261 	if ((pubring = calloc(1, sizeof(*pubring))) == NULL) {
262 		(void) fprintf(stderr, "readsshkeys: bad alloc\n");
263 		return 0;
264 	}
265 	/* openssh2 keys use md5 by default */
266 	hashtype = OPS_HASH_MD5;
267 	if ((hash = netpgp_getvar(netpgp, "hash")) != NULL) {
268 		/* openssh 2 hasn't really caught up to anything else yet */
269 		if (netpgp_strcasecmp(hash, "md5") == 0) {
270 			hashtype = OPS_HASH_MD5;
271 		} else if (netpgp_strcasecmp(hash, "sha1") == 0) {
272 			hashtype = OPS_HASH_SHA1;
273 		} else if (netpgp_strcasecmp(hash, "sha256") == 0) {
274 			hashtype = OPS_HASH_SHA256;
275 		}
276 	}
277 	if (!__ops_ssh2_readkeys(netpgp->io, pubring, NULL, filename, NULL, hashtype)) {
278 		free(pubring);
279 		(void) fprintf(stderr, "readsshkeys: can't read %s\n",
280 				filename);
281 		return 0;
282 	}
283 	if (netpgp->pubring == NULL) {
284 		netpgp->pubring = pubring;
285 	} else {
286 		__ops_append_keyring(netpgp->pubring, pubring);
287 	}
288 	netpgp_setvar(netpgp, "sshpubfile", filename);
289 	/* try to take the ".pub" off the end */
290 	if (filename == f) {
291 		f[strlen(f) - 4] = 0x0;
292 	} else {
293 		(void) snprintf(f, sizeof(f), "%.*s",
294 				(int)strlen(filename) - 4, filename);
295 		filename = f;
296 	}
297 	if ((secring = calloc(1, sizeof(*secring))) == NULL) {
298 		(void) fprintf(stderr, "readsshkeys: bad alloc\n");
299 		return 0;
300 	}
301 	if (__ops_ssh2_readkeys(netpgp->io, pubring, secring, NULL, filename, hashtype)) {
302 		netpgp->secring = secring;
303 		netpgp_setvar(netpgp, "sshsecfile", filename);
304 	} else {
305 		(void) fprintf(stderr, "readsshkeys: can't read sec %s (%d)\n",
306 				filename, errno);
307 	}
308 	return 1;
309 }
310 
311 /* set ssh uid to first one in pubring */
312 static void
313 set_first_pubring(__ops_keyring_t *pubring, char *id, size_t len, int last)
314 {
315 	uint8_t	*src;
316 	int	 i;
317 	int	 n;
318 
319 	(void) memset(id, 0x0, len);
320 	src = pubring->keys[(last) ? pubring->keyc - 1 : 0].key_id;
321 	for (i = 0, n = 0 ; i < OPS_KEY_ID_SIZE ; i += 2) {
322 		n += snprintf(&id[n], len - n, "%02x%02x", src[i], src[i + 1]);
323 	}
324 	id[n] = 0x0;
325 }
326 
327 /* find the time - in a specific %Y-%m-%d format - using a regexp */
328 static int
329 grabdate(char *s, int64_t *t)
330 {
331 	static regex_t	r;
332 	static int	compiled;
333 	regmatch_t	matches[10];
334 	struct tm	tm;
335 
336 	if (!compiled) {
337 		compiled = 1;
338 		(void) regcomp(&r, "([0-9][0-9][0-9][0-9])[-/]([0-9][0-9])[-/]([0-9][0-9])", REG_EXTENDED);
339 	}
340 	if (regexec(&r, s, 10, matches, 0) == 0) {
341 		(void) memset(&tm, 0x0, sizeof(tm));
342 		tm.tm_year = (int)strtol(&s[(int)matches[1].rm_so], NULL, 10);
343 		tm.tm_mon = (int)strtol(&s[(int)matches[2].rm_so], NULL, 10) - 1;
344 		tm.tm_mday = (int)strtol(&s[(int)matches[3].rm_so], NULL, 10);
345 		*t = mktime(&tm);
346 		return 1;
347 	}
348 	return 0;
349 }
350 
351 /* get expiration in seconds */
352 static uint64_t
353 get_duration(char *s)
354 {
355 	uint64_t	 now;
356 	int64_t	 	 t;
357 	char		*mult;
358 
359 	if (s == NULL) {
360 		return 0;
361 	}
362 	now = strtoull(s, NULL, 10);
363 	if ((mult = strchr("hdwmy", s[strlen(s) - 1])) != NULL) {
364 		switch(*mult) {
365 		case 'h':
366 			return now * 60 * 60;
367 		case 'd':
368 			return now * 60 * 60 * 24;
369 		case 'w':
370 			return now * 60 * 60 * 24 * 7;
371 		case 'm':
372 			return now * 60 * 60 * 24 * 31;
373 		case 'y':
374 			return now * 60 * 60 * 24 * 365;
375 		}
376 	}
377 	if (grabdate(s, &t)) {
378 		return t;
379 	}
380 	return (uint64_t)strtoll(s, NULL, 10);
381 }
382 
383 /* get birthtime in seconds */
384 static int64_t
385 get_birthtime(char *s)
386 {
387 	int64_t	t;
388 
389 	if (s == NULL) {
390 		return time(NULL);
391 	}
392 	if (grabdate(s, &t)) {
393 		return t;
394 	}
395 	return (uint64_t)strtoll(s, NULL, 10);
396 }
397 
398 /* resolve the userid */
399 static const __ops_key_t *
400 resolve_userid(netpgp_t *netpgp, const __ops_keyring_t *keyring, const char *userid)
401 {
402 	const __ops_key_t	*key;
403 	__ops_io_t		*io;
404 
405 	if (userid == NULL) {
406 		userid = netpgp_getvar(netpgp, "userid");
407 	} else if (userid[0] == '0' && userid[1] == 'x') {
408 		userid += 2;
409 	}
410 	io = netpgp->io;
411 	if ((key = __ops_getkeybyname(io, keyring, userid)) == NULL) {
412 		(void) fprintf(io->errs, "Can't find key '%s'\n", userid);
413 	}
414 	return key;
415 }
416 
417 /* append a key to a keyring */
418 static int
419 appendkey(__ops_io_t *io, __ops_key_t *key, char *ringfile)
420 {
421 	__ops_output_t	*create;
422 	const unsigned	 noarmor = 0;
423 	int		 fd;
424 
425 	if ((fd = __ops_setup_file_append(&create, ringfile)) < 0) {
426 		fd = __ops_setup_file_write(&create, ringfile, 0);
427 	}
428 	if (fd < 0) {
429 		(void) fprintf(io->errs, "can't open pubring '%s'\n", ringfile);
430 		return 0;
431 	}
432 	if (!__ops_write_xfer_pubkey(create, key, noarmor)) {
433 		(void) fprintf(io->errs, "Cannot write pubkey\n");
434 		return 0;
435 	}
436 	__ops_teardown_file_write(create, fd);
437 	return 1;
438 }
439 
440 /* return 1 if the file contains ascii-armoured text */
441 static unsigned
442 isarmoured(__ops_io_t *io, const char *f, const char *text)
443 {
444 	unsigned	 armoured;
445 	FILE		*fp;
446 	char	 	 buf[BUFSIZ];
447 
448 	armoured = 0;
449 	if ((fp = fopen(f, "r")) == NULL) {
450 		(void) fprintf(io->errs, "isarmoured: can't open '%s'\n", f);
451 		return 0;
452 	}
453 	if (fgets(buf, sizeof(buf), fp) != NULL) {
454 		armoured = (strncmp(buf, text, strlen(text)) == 0);
455 	}
456 	(void) fclose(fp);
457 	return armoured;
458 }
459 
460 /***************************************************************************/
461 /* exported functions start here */
462 /***************************************************************************/
463 
464 /* initialise a netpgp_t structure */
465 int
466 netpgp_init(netpgp_t *netpgp)
467 {
468 	__ops_io_t	*io;
469 	char		 id[MAX_ID_LENGTH];
470 	char		*homedir;
471 	char		*userid;
472 	char		*stream;
473 	char		*passfd;
474 	char		*results;
475 	int		 coredumps;
476 	int		 last;
477 
478 #ifdef HAVE_SYS_RESOURCE_H
479 	struct rlimit	limit;
480 
481 	coredumps = netpgp_getvar(netpgp, "coredumps") != NULL;
482 	if (!coredumps) {
483 		(void) memset(&limit, 0x0, sizeof(limit));
484 		if (setrlimit(RLIMIT_CORE, &limit) != 0) {
485 			(void) fprintf(stderr,
486 			"netpgp: warning - can't turn off core dumps\n");
487 			coredumps = 1;
488 		}
489 	}
490 #else
491 	coredumps = 1;
492 #endif
493 	if ((io = calloc(1, sizeof(*io))) == NULL) {
494 		(void) fprintf(stderr, "netpgp_init: bad alloc\n");
495 		return 0;
496 	}
497 	io->outs = stdout;
498 	if ((stream = netpgp_getvar(netpgp, "outs")) != NULL &&
499 	    strcmp(stream, "<stderr>") == 0) {
500 		io->outs = stderr;
501 	}
502 	io->errs = stderr;
503 	if ((stream = netpgp_getvar(netpgp, "errs")) != NULL &&
504 	    strcmp(stream, "<stdout>") == 0) {
505 		io->errs = stdout;
506 	}
507 	if ((results = netpgp_getvar(netpgp, "res")) == NULL) {
508 		io->res = io->errs;
509 	} else if (strcmp(results, "<stdout>") == 0) {
510 		io->res = stdout;
511 	} else if (strcmp(results, "<stderr>") == 0) {
512 		io->res = stderr;
513 	} else {
514 		if ((io->res = fopen(results, "w")) == NULL) {
515 			(void) fprintf(io->errs, "Can't open results %s for writing\n",
516 				results);
517 			free(io);
518 			return 0;
519 		}
520 	}
521 	netpgp->io = io;
522 	if ((passfd = netpgp_getvar(netpgp, "pass-fd")) != NULL &&
523 	    (netpgp->passfp = fdopen(atoi(passfd), "r")) == NULL) {
524 		(void) fprintf(io->errs, "Can't open fd %s for reading\n",
525 			passfd);
526 		return 0;
527 	}
528 	if (coredumps) {
529 		(void) fprintf(io->errs,
530 			"netpgp: warning: core dumps enabled\n");
531 	}
532 	if ((homedir = netpgp_getvar(netpgp, "homedir")) == NULL) {
533 		(void) fprintf(io->errs, "netpgp: bad homedir\n");
534 		return 0;
535 	}
536 	/* read from either gpg files or ssh keys */
537 	if (netpgp_getvar(netpgp, "ssh keys") == NULL) {
538 		if ((userid = netpgp_getvar(netpgp, "userid")) == NULL) {
539 			(void) memset(id, 0x0, sizeof(id));
540 			(void) conffile(netpgp, homedir, id, sizeof(id));
541 			if (id[0] != 0x0) {
542 				netpgp_setvar(netpgp, "userid", userid = id);
543 			}
544 		}
545 		if (userid == NULL) {
546 			if (netpgp_getvar(netpgp, "need userid") != NULL) {
547 				(void) fprintf(io->errs,
548 						"Cannot find user id\n");
549 				return 0;
550 			}
551 		} else {
552 			(void) netpgp_setvar(netpgp, "userid", userid);
553 		}
554 		netpgp->pubring = readkeyring(netpgp, "pubring");
555 		if (netpgp->pubring == NULL) {
556 			(void) fprintf(io->errs, "Can't read pub keyring\n");
557 			return 0;
558 		}
559 		netpgp->secring = readkeyring(netpgp, "secring");
560 		if (netpgp->secring == NULL) {
561 			(void) fprintf(io->errs, "Can't read sec keyring\n");
562 			return 0;
563 		}
564 	} else {
565 		last = (netpgp->pubring != NULL);
566 		if (!readsshkeys(netpgp, homedir)) {
567 			(void) fprintf(io->errs, "Can't read ssh pub key\n");
568 			return 0;
569 		}
570 		if ((userid = netpgp_getvar(netpgp, "userid")) == NULL) {
571 			set_first_pubring(netpgp->pubring, id, sizeof(id), last);
572 			netpgp_setvar(netpgp, "userid", userid = id);
573 		}
574 		if (userid == NULL) {
575 			if (netpgp_getvar(netpgp, "need userid") != NULL) {
576 				(void) fprintf(io->errs,
577 						"Cannot find user id\n");
578 				return 0;
579 			}
580 		} else {
581 			(void) netpgp_setvar(netpgp, "userid", userid);
582 		}
583 	}
584 	return 1;
585 }
586 
587 /* finish off with the netpgp_t struct */
588 int
589 netpgp_end(netpgp_t *netpgp)
590 {
591 	unsigned	i;
592 
593 	for (i = 0 ; i < netpgp->c ; i++) {
594 		if (netpgp->name[i] != NULL) {
595 			free(netpgp->name[i]);
596 		}
597 		if (netpgp->value[i] != NULL) {
598 			free(netpgp->value[i]);
599 		}
600 	}
601 	if (netpgp->name != NULL) {
602 		free(netpgp->name);
603 	}
604 	if (netpgp->value != NULL) {
605 		free(netpgp->value);
606 	}
607 	if (netpgp->pubring != NULL) {
608 		__ops_keyring_free(netpgp->pubring);
609 	}
610 	if (netpgp->secring != NULL) {
611 		__ops_keyring_free(netpgp->secring);
612 	}
613 	free(netpgp->io);
614 	return 1;
615 }
616 
617 /* list the keys in a keyring */
618 int
619 netpgp_list_keys(netpgp_t *netpgp, const int psigs)
620 {
621 	if (netpgp->pubring == NULL) {
622 		(void) fprintf(stderr, "No keyring\n");
623 		return 0;
624 	}
625 	return __ops_keyring_list(netpgp->io, netpgp->pubring, psigs);
626 }
627 
628 DEFINE_ARRAY(strings_t, char *);
629 
630 #ifndef HKP_VERSION
631 #define HKP_VERSION	1
632 #endif
633 
634 /* find and list some keys in a keyring */
635 int
636 netpgp_match_keys(netpgp_t *netpgp, char *name, const char *fmt, void *vp, const int psigs)
637 {
638 	const __ops_key_t	*key;
639 	unsigned		 k;
640 	strings_t		 pubs;
641 	FILE			*fp = (FILE *)vp;
642 
643 	if (name[0] == '0' && name[1] == 'x') {
644 		name += 2;
645 	}
646 	(void) memset(&pubs, 0x0, sizeof(pubs));
647 	k = 0;
648 	do {
649 		key = __ops_getnextkeybyname(netpgp->io, netpgp->pubring,
650 						name, &k);
651 		if (key != NULL) {
652 			ALLOC(char *, pubs.v, pubs.size, pubs.c, 10, 10,
653 					"netpgp_match_keys", return 0);
654 			if (strcmp(fmt, "mr") == 0) {
655 				__ops_hkp_sprint_keydata(netpgp->io, netpgp->pubring,
656 						key, &pubs.v[pubs.c],
657 						&key->key.pubkey, psigs);
658 			} else {
659 				__ops_sprint_keydata(netpgp->io, netpgp->pubring,
660 						key, &pubs.v[pubs.c],
661 						"pub",
662 						&key->key.pubkey, psigs);
663 			}
664 			if (pubs.v[pubs.c] != NULL) {
665 				pubs.c += 1;
666 			}
667 			k += 1;
668 		}
669 	} while (key != NULL);
670 	if (strcmp(fmt, "mr") == 0) {
671 		(void) fprintf(fp, "info:%d:%d\n", HKP_VERSION, pubs.c);
672 	} else {
673 		(void) fprintf(fp, "%d key%s found\n", pubs.c,
674 			(pubs.c == 1) ? "" : "s");
675 	}
676 	for (k = 0 ; k < pubs.c ; k++) {
677 		(void) fprintf(fp, "%s%s", pubs.v[k], (k < pubs.c - 1) ? "\n" : "");
678 		free(pubs.v[k]);
679 	}
680 	free(pubs.v);
681 	return pubs.c;
682 }
683 
684 /* find and list some public keys in a keyring */
685 int
686 netpgp_match_pubkeys(netpgp_t *netpgp, char *name, void *vp)
687 {
688 	const __ops_key_t	*key;
689 	unsigned		 k;
690 	strings_t		 pubs;
691 	FILE			*fp = (FILE *)vp;
692 
693 	(void) memset(&pubs, 0x0, sizeof(pubs));
694 	do {
695 		key = __ops_getnextkeybyname(netpgp->io, netpgp->pubring,
696 						name, &k);
697 		if (key != NULL) {
698 			char	out[1024 * 64];
699 
700 			ALLOC(char *, pubs.v, pubs.size, pubs.c, 10, 10,
701 					"netpgp_match_pubkeys", return 0);
702 			(void) __ops_sprint_pubkey(key, out, sizeof(out));
703 			pubs.v[pubs.c++] = netpgp_strdup(out);
704 			k += 1;
705 		}
706 	} while (key != NULL);
707 	(void) fprintf(fp, "info:%d:%d\n", HKP_VERSION, pubs.c);
708 	for (k = 0 ; k < pubs.c ; k++) {
709 		(void) fprintf(fp, "%s", pubs.v[k]);
710 		free(pubs.v[k]);
711 	}
712 	free(pubs.v);
713 	return pubs.c;
714 }
715 
716 /* find a key in a keyring */
717 int
718 netpgp_find_key(netpgp_t *netpgp, char *id)
719 {
720 	__ops_io_t	*io;
721 
722 	io = netpgp->io;
723 	if (id == NULL) {
724 		(void) fprintf(io->errs, "NULL id to search for\n");
725 		return 0;
726 	}
727 	return __ops_getkeybyname(netpgp->io, netpgp->pubring, id) != NULL;
728 }
729 
730 /* get a key in a keyring */
731 char *
732 netpgp_get_key(netpgp_t *netpgp, const char *name, const char *fmt)
733 {
734 	const __ops_key_t	*key;
735 	char			*newkey;
736 
737 	if ((key = resolve_userid(netpgp, netpgp->pubring, name)) == NULL) {
738 		return NULL;
739 	}
740 	if (strcmp(fmt, "mr") == 0) {
741 		return (__ops_hkp_sprint_keydata(netpgp->io, netpgp->pubring,
742 				key, &newkey,
743 				&key->key.pubkey,
744 				netpgp_getvar(netpgp, "subkey sigs") != NULL) > 0) ? newkey : NULL;
745 	}
746 	return (__ops_sprint_keydata(netpgp->io, netpgp->pubring,
747 				key, &newkey, "pub",
748 				&key->key.pubkey,
749 				netpgp_getvar(netpgp, "subkey sigs") != NULL) > 0) ? newkey : NULL;
750 }
751 
752 /* export a given key */
753 char *
754 netpgp_export_key(netpgp_t *netpgp, char *name)
755 {
756 	const __ops_key_t	*key;
757 	__ops_io_t		*io;
758 
759 	io = netpgp->io;
760 	if ((key = resolve_userid(netpgp, netpgp->pubring, name)) == NULL) {
761 		return NULL;
762 	}
763 	return __ops_export_key(io, key, NULL);
764 }
765 
766 #define IMPORT_ARMOR_HEAD	"-----BEGIN PGP PUBLIC KEY BLOCK-----"
767 
768 /* import a key into our keyring */
769 int
770 netpgp_import_key(netpgp_t *netpgp, char *f)
771 {
772 #if 0
773 	__ops_keyring_t	*keyring;
774 #endif
775 	__ops_io_t	*io;
776 	unsigned	 realarmor;
777 #if 0
778 	char		 ringfile[MAXPATHLEN];
779 #endif
780 	int		 done;
781 
782 	io = netpgp->io;
783 	realarmor = isarmoured(io, f, IMPORT_ARMOR_HEAD);
784 	done = __ops_keyring_fileread(netpgp->pubring, realarmor, f);
785 	if (!done) {
786 		(void) fprintf(io->errs, "Cannot import key from file %s\n", f);
787 		return 0;
788 	}
789 #if 0
790 	keyring = netpgp->pubring;
791 	(void) snprintf(ringfile, sizeof(ringfile), "%s/pubring.gpg", netpgp_getvar(netpgp, "homedir"));
792 	if (!appendkey(io, &keyring->keys[keyring->keyc - 1], ringfile)) {
793 		(void) fprintf(io->errs, "Cannot append imported key to pubring %s\n", ringfile);
794 		return 0;
795 	}
796 #endif
797 	return __ops_keyring_list(io, netpgp->pubring, 0);
798 }
799 
800 /* generate a new key */
801 int
802 netpgp_generate_key(netpgp_t *netpgp, char *id, int numbits)
803 {
804 	__ops_output_t		*create;
805 	const unsigned		 noarmor = 0;
806 	__ops_key_t		*key;
807 	__ops_io_t		*io;
808 	uint8_t			*uid;
809 	char			 newid[1024];
810 	char			 filename[MAXPATHLEN];
811 	char			 dir[MAXPATHLEN];
812 	char			*cp;
813 	char			*ringfile;
814 	int             	 fd;
815 
816 	uid = NULL;
817 	io = netpgp->io;
818 	/* generate a new key */
819 	if (id) {
820 		(void) snprintf(newid, sizeof(newid), "%s", id);
821 	} else {
822 		(void) snprintf(newid, sizeof(newid), "RSA %d-bit key <%s@localhost>", numbits, getenv("LOGNAME"));
823 	}
824 	uid = (uint8_t *)newid;
825 	key = __ops_rsa_new_selfsign_key(numbits, 65537UL, uid, netpgp_getvar(netpgp, "hash"));
826 	if (key == NULL) {
827 		(void) fprintf(io->errs, "Cannot generate key\n");
828 		return 0;
829 	}
830 	cp = NULL;
831 	__ops_sprint_keydata(netpgp->io, NULL, key, &cp, "pub", &key->key.seckey.pubkey, 0);
832 	(void) fprintf(stdout, "%s", cp);
833 	/* write public key */
834 	(void) snprintf(dir, sizeof(dir), "%s/%.16s", netpgp_getvar(netpgp, "homedir"), &cp[31]);
835 	if (mkdir(dir, 0700) < 0) {
836 		(void) fprintf(io->errs, "can't mkdir '%s'\n", dir);
837 		return 0;
838 	}
839 	(void) fprintf(io->errs, "netpgp: generated keys in directory %s\n", dir);
840 	(void) snprintf(ringfile = filename, sizeof(filename), "%s/pubring.gpg", dir);
841 	if (!appendkey(io, key, ringfile)) {
842 		(void) fprintf(io->errs, "Cannot write pubkey to '%s'\n", ringfile);
843 		return 0;
844 	}
845 	if (netpgp->pubring != NULL) {
846 		__ops_keyring_free(netpgp->pubring);
847 	}
848 	/* write secret key */
849 	(void) snprintf(ringfile = filename, sizeof(filename), "%s/secring.gpg", dir);
850 	if ((fd = __ops_setup_file_append(&create, ringfile)) < 0) {
851 		fd = __ops_setup_file_write(&create, ringfile, 0);
852 	}
853 	if (fd < 0) {
854 		(void) fprintf(io->errs, "can't append secring '%s'\n", ringfile);
855 		return 0;
856 	}
857 	if (!__ops_write_xfer_seckey(create, key, NULL, 0, noarmor)) {
858 		(void) fprintf(io->errs, "Cannot write seckey\n");
859 		return 0;
860 	}
861 	__ops_teardown_file_write(create, fd);
862 	if (netpgp->secring != NULL) {
863 		__ops_keyring_free(netpgp->secring);
864 	}
865 	__ops_keydata_free(key);
866 	free(cp);
867 	return 1;
868 }
869 
870 /* encrypt a file */
871 int
872 netpgp_encrypt_file(netpgp_t *netpgp,
873 			const char *userid,
874 			const char *f,
875 			char *out,
876 			int armored)
877 {
878 	const __ops_key_t	*keypair;
879 	const unsigned		 overwrite = 1;
880 	const char		*suffix;
881 	__ops_io_t		*io;
882 	char			 outname[MAXPATHLEN];
883 
884 	io = netpgp->io;
885 	if (f == NULL) {
886 		(void) fprintf(io->errs,
887 			"netpgp_encrypt_file: no filename specified\n");
888 		return 0;
889 	}
890 	suffix = (armored) ? ".asc" : ".gpg";
891 	/* get key with which to sign */
892 	if ((keypair = resolve_userid(netpgp, netpgp->pubring, userid)) == NULL) {
893 		return 0;
894 	}
895 	if (out == NULL) {
896 		(void) snprintf(outname, sizeof(outname), "%s%s", f, suffix);
897 		out = outname;
898 	}
899 	return (int)__ops_encrypt_file(io, f, out, keypair, (unsigned)armored,
900 					overwrite);
901 }
902 
903 #define ARMOR_HEAD	"-----BEGIN PGP MESSAGE-----\r\n"
904 
905 /* decrypt a file */
906 int
907 netpgp_decrypt_file(netpgp_t *netpgp, const char *f, char *out, int armored)
908 {
909 	const unsigned	 overwrite = 1;
910 	__ops_io_t	*io;
911 	unsigned	 realarmor;
912 
913 	__OPS_USED(armored);
914 	io = netpgp->io;
915 	if (f == NULL) {
916 		(void) fprintf(io->errs,
917 			"netpgp_decrypt_file: no filename specified\n");
918 		return 0;
919 	}
920 	realarmor = isarmoured(io, f, ARMOR_HEAD);
921 	return __ops_decrypt_file(netpgp->io, f, out, netpgp->secring,
922 				netpgp->pubring,
923 				realarmor, overwrite,
924 				netpgp->passfp, get_passphrase_cb);
925 }
926 
927 /* sign a file */
928 int
929 netpgp_sign_file(netpgp_t *netpgp,
930 		const char *userid,
931 		const char *f,
932 		char *out,
933 		int armored,
934 		int cleartext,
935 		int detached)
936 {
937 	const __ops_key_t	*keypair;
938 	const __ops_key_t	*pubkey;
939 	__ops_seckey_t		*seckey;
940 	const unsigned		 overwrite = 1;
941 	__ops_io_t		*io;
942 	const char		*hashalg;
943 	int			 ret;
944 
945 	io = netpgp->io;
946 	if (f == NULL) {
947 		(void) fprintf(io->errs,
948 			"netpgp_sign_file: no filename specified\n");
949 		return 0;
950 	}
951 	/* get key with which to sign */
952 	if ((keypair = resolve_userid(netpgp, netpgp->secring, userid)) == NULL) {
953 		return 0;
954 	}
955 	ret = 1;
956 	do {
957 		if (netpgp->passfp == NULL) {
958 			/* print out the user id */
959 			pubkey = __ops_getkeybyname(io, netpgp->pubring, userid);
960 			if (pubkey == NULL) {
961 				(void) fprintf(io->errs,
962 					"netpgp: warning - using pubkey from secring\n");
963 				__ops_print_keydata(io, netpgp->pubring, keypair, "pub",
964 					&keypair->key.seckey.pubkey, 0);
965 			} else {
966 				__ops_print_keydata(io, netpgp->pubring, pubkey, "pub", &pubkey->key.pubkey, 0);
967 			}
968 		}
969 		if (netpgp_getvar(netpgp, "ssh keys") == NULL) {
970 			/* now decrypt key */
971 			seckey = __ops_decrypt_seckey(keypair, netpgp->passfp);
972 			if (seckey == NULL) {
973 				(void) fprintf(io->errs, "Bad passphrase\n");
974 			}
975 		} else {
976 			__ops_keyring_t	*secring;
977 
978 			secring = netpgp->secring;
979 			seckey = &secring->keys[0].key.seckey;
980 		}
981 	} while (seckey == NULL);
982 	/* sign file */
983 	hashalg = netpgp_getvar(netpgp, "hash");
984 	if (seckey->pubkey.alg == OPS_PKA_DSA) {
985 		hashalg = "sha1";
986 	}
987 	if (detached) {
988 		ret = __ops_sign_detached(io, f, out, seckey, hashalg,
989 				get_birthtime(netpgp_getvar(netpgp, "birthtime")),
990 				get_duration(netpgp_getvar(netpgp, "duration")),
991 				(unsigned)armored,
992 				overwrite);
993 	} else {
994 		ret = __ops_sign_file(io, f, out, seckey, hashalg,
995 				get_birthtime(netpgp_getvar(netpgp, "birthtime")),
996 				get_duration(netpgp_getvar(netpgp, "duration")),
997 				(unsigned)armored, (unsigned)cleartext,
998 				overwrite);
999 	}
1000 	__ops_forget(seckey, sizeof(*seckey));
1001 	return ret;
1002 }
1003 
1004 #define ARMOR_SIG_HEAD	"-----BEGIN PGP SIGNATURE-----\r\n"
1005 
1006 /* verify a file */
1007 int
1008 netpgp_verify_file(netpgp_t *netpgp, const char *in, const char *out, int armored)
1009 {
1010 	__ops_validation_t	 result;
1011 	__ops_io_t		*io;
1012 	unsigned		 realarmor;
1013 
1014 	__OPS_USED(armored);
1015 	(void) memset(&result, 0x0, sizeof(result));
1016 	io = netpgp->io;
1017 	if (in == NULL) {
1018 		(void) fprintf(io->errs,
1019 			"netpgp_verify_file: no filename specified\n");
1020 		return 0;
1021 	}
1022 	realarmor = isarmoured(io, in, ARMOR_SIG_HEAD);
1023 	if (__ops_validate_file(io, &result, in, out, (const int)realarmor, netpgp->pubring)) {
1024 		resultp(io, in, &result, netpgp->pubring);
1025 		return 1;
1026 	}
1027 	if (result.validc + result.invalidc + result.unknownc == 0) {
1028 		(void) fprintf(io->errs,
1029 		"\"%s\": No signatures found - is this a signed file?\n",
1030 			in);
1031 	} else if (result.invalidc == 0 && result.unknownc == 0) {
1032 		(void) fprintf(io->errs,
1033 			"\"%s\": file verification failure: invalid signature time\n", in);
1034 	} else {
1035 		(void) fprintf(io->errs,
1036 "\"%s\": verification failure: %u invalid signatures, %u unknown signatures\n",
1037 			in, result.invalidc, result.unknownc);
1038 	}
1039 	return 0;
1040 }
1041 
1042 /* sign some memory */
1043 int
1044 netpgp_sign_memory(netpgp_t *netpgp,
1045 		const char *userid,
1046 		char *mem,
1047 		size_t size,
1048 		char *out,
1049 		size_t outsize,
1050 		const unsigned armored,
1051 		const unsigned cleartext)
1052 {
1053 	const __ops_key_t	*keypair;
1054 	const __ops_key_t	*pubkey;
1055 	__ops_seckey_t		*seckey;
1056 	__ops_memory_t		*signedmem;
1057 	__ops_io_t		*io;
1058 	const char		*hashalg;
1059 	int			 ret;
1060 
1061 	io = netpgp->io;
1062 	if (mem == NULL) {
1063 		(void) fprintf(io->errs,
1064 			"netpgp_sign_memory: no memory to sign\n");
1065 		return 0;
1066 	}
1067 	if ((keypair = resolve_userid(netpgp, netpgp->secring, userid)) == NULL) {
1068 		return 0;
1069 	}
1070 	ret = 1;
1071 	do {
1072 		if (netpgp->passfp == NULL) {
1073 			/* print out the user id */
1074 			pubkey = __ops_getkeybyname(io, netpgp->pubring, userid);
1075 			if (pubkey == NULL) {
1076 				(void) fprintf(io->errs,
1077 					"netpgp: warning - using pubkey from secring\n");
1078 				__ops_print_keydata(io, netpgp->pubring, keypair, "pub",
1079 					&keypair->key.seckey.pubkey, 0);
1080 			} else {
1081 				__ops_print_keydata(io, netpgp->pubring, pubkey, "pub", &pubkey->key.pubkey, 0);
1082 			}
1083 		}
1084 		/* now decrypt key */
1085 		seckey = __ops_decrypt_seckey(keypair, netpgp->passfp);
1086 		if (seckey == NULL) {
1087 			(void) fprintf(io->errs, "Bad passphrase\n");
1088 		}
1089 	} while (seckey == NULL);
1090 	/* sign file */
1091 	(void) memset(out, 0x0, outsize);
1092 	hashalg = netpgp_getvar(netpgp, "hash");
1093 	if (seckey->pubkey.alg == OPS_PKA_DSA) {
1094 		hashalg = "sha1";
1095 	}
1096 	signedmem = __ops_sign_buf(io, mem, size, seckey,
1097 				get_birthtime(netpgp_getvar(netpgp, "birthtime")),
1098 				get_duration(netpgp_getvar(netpgp, "duration")),
1099 				hashalg, armored, cleartext);
1100 	if (signedmem) {
1101 		size_t	m;
1102 
1103 		m = MIN(__ops_mem_len(signedmem), outsize);
1104 		(void) memcpy(out, __ops_mem_data(signedmem), m);
1105 		__ops_memory_free(signedmem);
1106 		ret = (int)m;
1107 	} else {
1108 		ret = 0;
1109 	}
1110 	__ops_forget(seckey, sizeof(*seckey));
1111 	return ret;
1112 }
1113 
1114 /* verify memory */
1115 int
1116 netpgp_verify_memory(netpgp_t *netpgp, const void *in, const size_t size,
1117 			void *out, size_t outsize, const int armored)
1118 {
1119 	__ops_validation_t	 result;
1120 	__ops_memory_t		*signedmem;
1121 	__ops_memory_t		*cat;
1122 	__ops_io_t		*io;
1123 	size_t			 m;
1124 	int			 ret;
1125 
1126 	(void) memset(&result, 0x0, sizeof(result));
1127 	io = netpgp->io;
1128 	if (in == NULL) {
1129 		(void) fprintf(io->errs,
1130 			"netpgp_verify_memory: no memory to verify\n");
1131 		return 0;
1132 	}
1133 	signedmem = __ops_memory_new();
1134 	__ops_memory_add(signedmem, in, size);
1135 	if (out) {
1136 		cat = __ops_memory_new();
1137 	}
1138 	ret = __ops_validate_mem(io, &result, signedmem,
1139 				(out) ? &cat : NULL,
1140 				armored, netpgp->pubring);
1141 	__ops_memory_free(signedmem);
1142 	if (ret) {
1143 		resultp(io, "<stdin>", &result, netpgp->pubring);
1144 		if (out) {
1145 			m = MIN(__ops_mem_len(cat), outsize);
1146 			(void) memcpy(out, __ops_mem_data(cat), m);
1147 			__ops_memory_free(cat);
1148 		} else {
1149 			m = 1;
1150 		}
1151 		return (int)m;
1152 	}
1153 	if (result.validc + result.invalidc + result.unknownc == 0) {
1154 		(void) fprintf(io->errs,
1155 		"No signatures found - is this memory signed?\n");
1156 	} else if (result.invalidc == 0 && result.unknownc == 0) {
1157 		(void) fprintf(io->errs,
1158 			"memory verification failure: invalid signature time\n");
1159 	} else {
1160 		(void) fprintf(io->errs,
1161 "memory verification failure: %u invalid signatures, %u unknown signatures\n",
1162 			result.invalidc, result.unknownc);
1163 	}
1164 	return 0;
1165 }
1166 
1167 /* encrypt some memory */
1168 int
1169 netpgp_encrypt_memory(netpgp_t *netpgp,
1170 			const char *userid,
1171 			void *in,
1172 			const size_t insize,
1173 			char *out,
1174 			size_t outsize,
1175 			int armored)
1176 {
1177 	const __ops_key_t	*keypair;
1178 	__ops_memory_t		*enc;
1179 	__ops_io_t		*io;
1180 	size_t			 m;
1181 
1182 	io = netpgp->io;
1183 	if (in == NULL) {
1184 		(void) fprintf(io->errs,
1185 			"netpgp_encrypt_buf: no memory to encrypt\n");
1186 		return 0;
1187 	}
1188 	if ((keypair = resolve_userid(netpgp, netpgp->pubring, userid)) == NULL) {
1189 		return 0;
1190 	}
1191 	if (in == out) {
1192 		(void) fprintf(io->errs,
1193 			"netpgp_encrypt_buf: input and output bufs need to be different\n");
1194 		return 0;
1195 	}
1196 	if (outsize < insize) {
1197 		(void) fprintf(io->errs,
1198 			"netpgp_encrypt_buf: input size is larger than output size\n");
1199 		return 0;
1200 	}
1201 	enc = __ops_encrypt_buf(io, in, insize, keypair, (unsigned)armored);
1202 	m = MIN(__ops_mem_len(enc), outsize);
1203 	(void) memcpy(out, __ops_mem_data(enc), m);
1204 	__ops_memory_free(enc);
1205 	return (int)m;
1206 }
1207 
1208 /* decrypt a chunk of memory */
1209 int
1210 netpgp_decrypt_memory(netpgp_t *netpgp, const void *input, const size_t insize,
1211 			char *out, size_t outsize, const int armored)
1212 {
1213 	__ops_memory_t	*mem;
1214 	__ops_io_t	*io;
1215 	unsigned	 realarmor;
1216 	size_t		 m;
1217 
1218 	io = netpgp->io;
1219 	realarmor = (unsigned) armored;
1220 	if (input == NULL) {
1221 		(void) fprintf(io->errs,
1222 			"netpgp_decrypt_memory: no memory\n");
1223 		return 0;
1224 	}
1225 	realarmor = (strncmp(input, ARMOR_HEAD, sizeof(ARMOR_HEAD) - 1) == 0);
1226 	mem = __ops_decrypt_buf(netpgp->io, input, insize, netpgp->secring,
1227 				netpgp->pubring,
1228 				realarmor, netpgp->passfp,
1229 				get_passphrase_cb);
1230 	m = MIN(__ops_mem_len(mem), outsize);
1231 	(void) memcpy(out, __ops_mem_data(mem), m);
1232 	__ops_memory_free(mem);
1233 	return (int)m;
1234 }
1235 
1236 /* wrappers for the ops_debug_level functions we added to openpgpsdk */
1237 
1238 /* set the debugging level per filename */
1239 int
1240 netpgp_set_debug(const char *f)
1241 {
1242 	return __ops_set_debug_level(f);
1243 }
1244 
1245 /* get the debugging level per filename */
1246 int
1247 netpgp_get_debug(const char *f)
1248 {
1249 	return __ops_get_debug_level(f);
1250 }
1251 
1252 /* return the version for the library */
1253 const char *
1254 netpgp_get_info(const char *type)
1255 {
1256 	return __ops_get_info(type);
1257 }
1258 
1259 /* list all the packets in a file */
1260 int
1261 netpgp_list_packets(netpgp_t *netpgp, char *f, int armor, char *pubringname)
1262 {
1263 	__ops_keyring_t	*keyring;
1264 	const unsigned	 noarmor = 0;
1265 	struct stat	 st;
1266 	__ops_io_t	*io;
1267 	char		 ringname[MAXPATHLEN];
1268 	char		*homedir;
1269 	int		 ret;
1270 
1271 	io = netpgp->io;
1272 	if (f == NULL) {
1273 		(void) fprintf(io->errs, "No file containing packets\n");
1274 		return 0;
1275 	}
1276 	if (stat(f, &st) < 0) {
1277 		(void) fprintf(io->errs, "No such file '%s'\n", f);
1278 		return 0;
1279 	}
1280 	homedir = netpgp_getvar(netpgp, "homedir");
1281 	if (pubringname == NULL) {
1282 		(void) snprintf(ringname, sizeof(ringname),
1283 				"%s/pubring.gpg", homedir);
1284 		pubringname = ringname;
1285 	}
1286 	if ((keyring = calloc(1, sizeof(*keyring))) == NULL) {
1287 		(void) fprintf(io->errs, "netpgp_list_packets: bad alloc\n");
1288 		return 0;
1289 	}
1290 	if (!__ops_keyring_fileread(keyring, noarmor, pubringname)) {
1291 		free(keyring);
1292 		(void) fprintf(io->errs, "Cannot read pub keyring %s\n",
1293 			pubringname);
1294 		return 0;
1295 	}
1296 	netpgp->pubring = keyring;
1297 	netpgp_setvar(netpgp, "pubring", pubringname);
1298 	ret = __ops_list_packets(io, f, (unsigned)armor,
1299 					netpgp->secring,
1300 					netpgp->pubring,
1301 					netpgp->passfp,
1302 					get_passphrase_cb);
1303 	free(keyring);
1304 	return ret;
1305 }
1306 
1307 /* set a variable */
1308 int
1309 netpgp_setvar(netpgp_t *netpgp, const char *name, const char *value)
1310 {
1311 	char	*newval;
1312 	int	 i;
1313 
1314 	/* protect against the case where 'value' is netpgp->value[i] */
1315 	newval = netpgp_strdup(value);
1316 	if ((i = findvar(netpgp, name)) < 0) {
1317 		/* add the element to the array */
1318 		if (size_arrays(netpgp, netpgp->size + 15)) {
1319 			netpgp->name[i = netpgp->c++] = netpgp_strdup(name);
1320 		}
1321 	} else {
1322 		/* replace the element in the array */
1323 		if (netpgp->value[i]) {
1324 			free(netpgp->value[i]);
1325 			netpgp->value[i] = NULL;
1326 		}
1327 	}
1328 	/* sanity checks for range of values */
1329 	if (strcmp(name, "hash") == 0 || strcmp(name, "algorithm") == 0) {
1330 		if (__ops_str_to_hash_alg(newval) == OPS_HASH_UNKNOWN) {
1331 			free(newval);
1332 			return 0;
1333 		}
1334 	}
1335 	netpgp->value[i] = newval;
1336 	return 1;
1337 }
1338 
1339 /* unset a variable */
1340 int
1341 netpgp_unsetvar(netpgp_t *netpgp, const char *name)
1342 {
1343 	int	i;
1344 
1345 	if ((i = findvar(netpgp, name)) >= 0) {
1346 		if (netpgp->value[i]) {
1347 			free(netpgp->value[i]);
1348 			netpgp->value[i] = NULL;
1349 		}
1350 		netpgp->value[i] = NULL;
1351 		return 1;
1352 	}
1353 	return 0;
1354 }
1355 
1356 /* get a variable's value (NULL if not set) */
1357 char *
1358 netpgp_getvar(netpgp_t *netpgp, const char *name)
1359 {
1360 	int	i;
1361 
1362 	return ((i = findvar(netpgp, name)) < 0) ? NULL : netpgp->value[i];
1363 }
1364 
1365 /* increment a value */
1366 int
1367 netpgp_incvar(netpgp_t *netpgp, const char *name, const int delta)
1368 {
1369 	char	*cp;
1370 	char	 num[16];
1371 	int	 val;
1372 
1373 	val = 0;
1374 	if ((cp = netpgp_getvar(netpgp, name)) != NULL) {
1375 		val = atoi(cp);
1376 	}
1377 	(void) snprintf(num, sizeof(num), "%d", val + delta);
1378 	netpgp_setvar(netpgp, name, num);
1379 	return 1;
1380 }
1381 
1382 /* set the home directory value to "home/subdir" */
1383 int
1384 netpgp_set_homedir(netpgp_t *netpgp, char *home, const char *subdir, const int quiet)
1385 {
1386 	struct stat	st;
1387 	char		d[MAXPATHLEN];
1388 
1389 	if (home == NULL) {
1390 		if (!quiet) {
1391 			(void) fprintf(stderr, "NULL HOME directory\n");
1392 		}
1393 		return 0;
1394 	}
1395 	(void) snprintf(d, sizeof(d), "%s%s", home, (subdir) ? subdir : "");
1396 	if (stat(d, &st) == 0) {
1397 		if ((st.st_mode & S_IFMT) == S_IFDIR) {
1398 			netpgp_setvar(netpgp, "homedir", d);
1399 			return 1;
1400 		}
1401 		(void) fprintf(stderr, "netpgp: homedir \"%s\" is not a dir\n",
1402 					d);
1403 		return 0;
1404 	}
1405 	if (!quiet) {
1406 		(void) fprintf(stderr,
1407 			"netpgp: warning homedir \"%s\" not found\n", d);
1408 	}
1409 	netpgp_setvar(netpgp, "homedir", d);
1410 	return 1;
1411 }
1412 
1413 /* validate all sigs in the pub keyring */
1414 int
1415 netpgp_validate_sigs(netpgp_t *netpgp)
1416 {
1417 	__ops_validation_t	result;
1418 
1419 	return (int)__ops_validate_all_sigs(&result, netpgp->pubring, NULL);
1420 }
1421 
1422 #if 0
1423 #include "sshkey.h"
1424 
1425 int
1426 netpgp_pgpkey_to_sshkey(netpgp_t *netpgp, char *name, SSHKey *sshkey)
1427 {
1428 	const __ops_key_t	*pgpkey;
1429 	unsigned		 k;
1430 
1431 	k = 0;
1432 	pgpkey = __ops_getnextkeybyname(netpgp->io, netpgp->pubring, name, &k);
1433 	if (pgpkey == NULL) {
1434 		pgpkey = __ops_getkeybyname(io, netpgp->pubring, userid);
1435 	}
1436 	if (pgpkey == NULL) {
1437 		(void) fprintf(stderr, "No key matching '%s'\n", name);
1438 		return 0;
1439 	}
1440 	switch(pgpkey->key.pubkey.alg) {
1441 	case OPS_PKA_RSA:
1442 		sshkey->type = KEY_RSA;
1443 		sshkey->rsa = calloc(1, sizeof(*sshkey->rsa);
1444 		if (sshkey->rsa == NULL) {
1445 			(void) fprintf(stderr, "RSA memory problems\n");
1446 			return 0;
1447 		}
1448 		sshkey->rsa->n = pgpkey->key.pubkey.key.rsa.n;
1449 		sshkey->rsa->e = pgpkey->key.pubkey.key.rsa.e;
1450 		sshkey->rsa->d = pgpkey->key.seckey.key.rsa.d;
1451 		sshkey->rsa->p = pgpkey->key.seckey.key.rsa.p;
1452 		sshkey->rsa->q = pgpkey->key.seckey.key.rsa.q;
1453 		sshkey->rsa->iqmp = pgpkey->key.seckey.key.rsa.u;
1454 		break;
1455 	case OPS_PKA_DSA:
1456 		sshkey->type = KEY_DSA;
1457 		sshkey->dsa = calloc(1, sizeof(*sshkey->dsa);
1458 		if (sshkey->dsa == NULL) {
1459 			(void) fprintf(stderr, "DSA memory problems\n");
1460 			return 0;
1461 		}
1462 		sshkey->rsa->n = pgpkey->key.pubkey.key.rsa.n;
1463 		key->dsa->p = pgpkey->key.pubkey.key.dsa.p;
1464 		key->dsa->q = pgpkey->key.pubkey.key.dsa.q;
1465 		key->dsa->g = pgpkey->key.pubkey.key.dsa.g;
1466 		key->dsa->pub_key = pgpkey->key.pubkey.key.dsa.y;
1467 		key->dsa->priv_key = pgpkey->key.seckey.key.dsa.x;
1468 		break;
1469 	default:
1470 		(void) fprintf(stderr, "weird type\n");
1471 		return 0;
1472 	}
1473 	return 1;
1474 }
1475 #endif
1476