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