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