xref: /netbsd-src/crypto/external/bsd/netpgp/dist/src/lib/netpgp.c (revision 6deb2c22d20de1d75d538e8a5c57b573926fd157)
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.29 2009/10/07 04:18:47 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 <regex.h>
54 #include <stdarg.h>
55 #include <stdlib.h>
56 #include <string.h>
57 #include <time.h>
58 
59 #ifdef HAVE_UNISTD_H
60 #include <unistd.h>
61 #endif
62 
63 #include <errno.h>
64 
65 #ifdef HAVE_LIMITS_H
66 #include <limits.h>
67 #endif
68 
69 #include <netpgp.h>
70 
71 #include "packet.h"
72 #include "packet-parse.h"
73 #include "keyring.h"
74 #include "errors.h"
75 #include "packet-show.h"
76 #include "create.h"
77 #include "netpgpsdk.h"
78 #include "memory.h"
79 #include "validate.h"
80 #include "readerwriter.h"
81 #include "netpgpdefs.h"
82 #include "crypto.h"
83 
84 /* read any gpg config file */
85 static int
86 conffile(netpgp_t *netpgp, char *homedir, char *userid, size_t length)
87 {
88 	regmatch_t	 matchv[10];
89 	regex_t		 keyre;
90 	char		 buf[BUFSIZ];
91 	FILE		*fp;
92 
93 	__OPS_USED(netpgp);
94 	(void) snprintf(buf, sizeof(buf), "%s/gpg.conf", homedir);
95 	if ((fp = fopen(buf, "r")) == NULL) {
96 		return 0;
97 	}
98 	(void) memset(&keyre, 0x0, sizeof(keyre));
99 	(void) regcomp(&keyre, "^[ \t]*default-key[ \t]+([0-9a-zA-F]+)",
100 		REG_EXTENDED);
101 	while (fgets(buf, sizeof(buf), fp) != NULL) {
102 		if (regexec(&keyre, buf, 10, matchv, 0) == 0) {
103 			(void) memcpy(userid, &buf[(int)matchv[1].rm_so],
104 				MIN((unsigned)(matchv[1].rm_eo -
105 						matchv[1].rm_so), length));
106 			(void) fprintf(stderr,
107 				"netpgp: default key set to \"%.*s\"\n",
108 				(int)(matchv[1].rm_eo - matchv[1].rm_so),
109 				&buf[(int)matchv[1].rm_so]);
110 		}
111 	}
112 	(void) fclose(fp);
113 	return 1;
114 }
115 
116 /* small function to pretty print an 8-character raw userid */
117 static char    *
118 userid_to_id(const unsigned char *userid, char *id)
119 {
120 	static const char *hexes = "0123456789abcdef";
121 	int		   i;
122 
123 	for (i = 0; i < 8 ; i++) {
124 		id[i * 2] = hexes[(unsigned)(userid[i] & 0xf0) >> 4];
125 		id[(i * 2) + 1] = hexes[userid[i] & 0xf];
126 	}
127 	id[8 * 2] = 0x0;
128 	return id;
129 }
130 
131 /* print out the successful signature information */
132 static void
133 resultp(__ops_io_t *io,
134 	const char *f,
135 	__ops_validation_t *res,
136 	__ops_keyring_t *ring)
137 {
138 	const __ops_key_t	*pubkey;
139 	unsigned		 i;
140 	char			 id[MAX_ID_LENGTH + 1];
141 
142 	for (i = 0; i < res->validc; i++) {
143 		(void) fprintf(io->res,
144 			"Good signature for %s made %susing %s key %s\n",
145 			f,
146 			ctime(&res->valid_sigs[i].birthtime),
147 			__ops_show_pka(res->valid_sigs[i].key_alg),
148 			userid_to_id(res->valid_sigs[i].signer_id, id));
149 		pubkey = __ops_getkeybyid(io, ring,
150 			(const unsigned char *) res->valid_sigs[i].signer_id);
151 		__ops_print_pubkeydata(io, pubkey);
152 	}
153 }
154 
155 /* check there's enough space in the arrays */
156 static int
157 size_arrays(netpgp_t *netpgp, unsigned needed)
158 {
159 	char	**temp;
160 
161 	if (netpgp->size == 0) {
162 		/* only get here first time around */
163 		netpgp->size = needed;
164 		if ((netpgp->name = calloc(sizeof(char *), needed)) == NULL) {
165 			(void) fprintf(stderr, "size_arrays: bad alloc\n");
166 			return 0;
167 		}
168 		if ((netpgp->value = calloc(sizeof(char *), needed)) == NULL) {
169 			free(netpgp->name);
170 			(void) fprintf(stderr, "size_arrays: bad alloc\n");
171 			return 0;
172 		}
173 	} else if (netpgp->c == netpgp->size) {
174 		/* only uses 'needed' when filled array */
175 		netpgp->size += needed;
176 		temp = realloc(netpgp->name, sizeof(char *) * needed);
177 		if (temp == NULL) {
178 			(void) fprintf(stderr, "size_arrays: bad alloc\n");
179 			return 0;
180 		}
181 		netpgp->name = temp;
182 		temp = realloc(netpgp->value, sizeof(char *) * needed);
183 		if (temp == NULL) {
184 			(void) fprintf(stderr, "size_arrays: bad alloc\n");
185 			return 0;
186 		}
187 		netpgp->value = temp;
188 	}
189 	return 1;
190 }
191 
192 /* find the name in the array */
193 static int
194 findvar(netpgp_t *netpgp, const char *name)
195 {
196 	unsigned	i;
197 
198 	for (i = 0 ; i < netpgp->c && strcmp(netpgp->name[i], name) != 0; i++) {
199 	}
200 	return (i == netpgp->c) ? -1 : (int)i;
201 }
202 
203 /* read a keyring and return it */
204 static void *
205 readkeyring(netpgp_t *netpgp, const char *name)
206 {
207 	__ops_keyring_t	*keyring;
208 	const unsigned	 noarmor = 0;
209 	char		 f[MAXPATHLEN];
210 	char		*filename;
211 	char		*homedir;
212 
213 	homedir = netpgp_getvar(netpgp, "homedir");
214 	if ((filename = netpgp_getvar(netpgp, name)) == NULL) {
215 		(void) snprintf(f, sizeof(f), "%s/%s.gpg", homedir, name);
216 		filename = f;
217 	}
218 	if ((keyring = calloc(1, sizeof(*keyring))) == NULL) {
219 		(void) fprintf(stderr, "readkeyring: bad alloc\n");
220 		return NULL;
221 	}
222 	if (!__ops_keyring_fileread(keyring, noarmor, filename)) {
223 		free(keyring);
224 		(void) fprintf(stderr, "Can't read %s %s\n", name, filename);
225 		return NULL;
226 	}
227 	netpgp_setvar(netpgp, name, filename);
228 	return keyring;
229 }
230 
231 /***************************************************************************/
232 /* exported functions start here */
233 /***************************************************************************/
234 
235 /* initialise a netpgp_t structure */
236 int
237 netpgp_init(netpgp_t *netpgp)
238 {
239 	__ops_io_t	*io;
240 	char		 id[MAX_ID_LENGTH];
241 	char		*homedir;
242 	char		*userid;
243 	char		*stream;
244 	char		*passfd;
245 	char		*results;
246 	int		 coredumps;
247 
248 #ifdef HAVE_SYS_RESOURCE_H
249 	struct rlimit	limit;
250 
251 	coredumps = netpgp_getvar(netpgp, "coredumps") != NULL;
252 	if (!coredumps) {
253 		(void) memset(&limit, 0x0, sizeof(limit));
254 		if (setrlimit(RLIMIT_CORE, &limit) != 0) {
255 			(void) fprintf(stderr,
256 			"netpgp_init: warning - can't turn off core dumps\n");
257 			coredumps = 1;
258 		}
259 	}
260 #else
261 	coredumps = 1;
262 #endif
263 	if ((io = calloc(1, sizeof(*io))) == NULL) {
264 		(void) fprintf(stderr, "netpgp_init: bad alloc\n");
265 		return 0;
266 	}
267 	io->outs = stdout;
268 	if ((stream = netpgp_getvar(netpgp, "stdout")) != NULL &&
269 	    strcmp(stream, "stderr") == 0) {
270 		io->outs = stderr;
271 	}
272 	io->errs = stderr;
273 	if ((stream = netpgp_getvar(netpgp, "stderr")) != NULL &&
274 	    strcmp(stream, "stdout") == 0) {
275 		io->errs = stdout;
276 	}
277 	io->errs = stderr;
278 	netpgp->io = io;
279 	if (coredumps) {
280 		(void) fprintf(io->errs,
281 			"netpgp: warning: core dumps enabled\n");
282 	}
283 	if ((homedir = netpgp_getvar(netpgp, "homedir")) == NULL) {
284 		(void) fprintf(io->errs, "netpgp: bad homedir\n");
285 		return 0;
286 	}
287 	if ((userid = netpgp_getvar(netpgp, "userid")) == NULL) {
288 		(void) memset(id, 0x0, sizeof(id));
289 		(void) conffile(netpgp, homedir, id, sizeof(id));
290 		if (id[0] != 0x0) {
291 			netpgp_setvar(netpgp, "userid", userid = id);
292 		}
293 	}
294 	if (userid == NULL) {
295 		if (netpgp_getvar(netpgp, "need userid") != NULL) {
296 			(void) fprintf(io->errs, "Cannot find user id\n");
297 			return 0;
298 		}
299 	} else {
300 		(void) netpgp_setvar(netpgp, "userid", userid);
301 	}
302 	if ((netpgp->pubring = readkeyring(netpgp, "pubring")) == NULL) {
303 		(void) fprintf(io->errs, "Can't read pub keyring\n");
304 		return 0;
305 	}
306 	if ((netpgp->secring = readkeyring(netpgp, "secring")) == NULL) {
307 		(void) fprintf(io->errs, "Can't read sec keyring\n");
308 		return 0;
309 	}
310 	if ((passfd = netpgp_getvar(netpgp, "pass-fd")) != NULL &&
311 	    (netpgp->passfp = fdopen(atoi(passfd), "r")) == NULL) {
312 		(void) fprintf(io->errs, "Can't open fd %s for reading\n",
313 			passfd);
314 		return 0;
315 	}
316 	if ((results = netpgp_getvar(netpgp, "results")) == NULL) {
317 		io->res = io->errs;
318 	} else if ((io->res = fopen(results, "w")) == NULL) {
319 		(void) fprintf(io->errs, "Can't open results %s for writing\n",
320 			results);
321 		return 0;
322 	}
323 	return 1;
324 }
325 
326 /* finish off with the netpgp_t struct */
327 int
328 netpgp_end(netpgp_t *netpgp)
329 {
330 	unsigned	i;
331 
332 	for (i = 0 ; i < netpgp->c ; i++) {
333 		if (netpgp->name[i] != NULL) {
334 			free(netpgp->name[i]);
335 		}
336 		if (netpgp->value[i] != NULL) {
337 			free(netpgp->value[i]);
338 		}
339 	}
340 	if (netpgp->name != NULL) {
341 		free(netpgp->name);
342 	}
343 	if (netpgp->value != NULL) {
344 		free(netpgp->value);
345 	}
346 	if (netpgp->pubring != NULL) {
347 		__ops_keyring_free(netpgp->pubring);
348 	}
349 	if (netpgp->secring != NULL) {
350 		__ops_keyring_free(netpgp->secring);
351 	}
352 	free(netpgp->io);
353 	return 1;
354 }
355 
356 /* list the keys in a keyring */
357 int
358 netpgp_list_keys(netpgp_t *netpgp)
359 {
360 	return __ops_keyring_list(netpgp->io, netpgp->pubring);
361 }
362 
363 /* find a key in a keyring */
364 int
365 netpgp_find_key(netpgp_t *netpgp, char *id)
366 {
367 	__ops_io_t	*io;
368 
369 	io = netpgp->io;
370 	if (id == NULL) {
371 		(void) fprintf(io->errs, "NULL id to search for\n");
372 		return 0;
373 	}
374 	return __ops_getkeybyname(netpgp->io, netpgp->pubring, id) != NULL;
375 }
376 
377 /* export a given key */
378 int
379 netpgp_export_key(netpgp_t *netpgp, char *userid)
380 {
381 	const __ops_key_t	*keypair;
382 	__ops_io_t		*io;
383 
384 	io = netpgp->io;
385 	if (userid == NULL) {
386 		userid = netpgp_getvar(netpgp, "userid");
387 	}
388 	keypair = __ops_getkeybyname(io, netpgp->pubring, userid);
389 	if (keypair == NULL) {
390 		(void) fprintf(io->errs,
391 			"Cannot find own key \"%s\" in keyring\n", userid);
392 		return 0;
393 	}
394 	return __ops_export_key(keypair, NULL);
395 }
396 
397 /* import a key into our keyring */
398 int
399 netpgp_import_key(netpgp_t *netpgp, char *f)
400 {
401 	const unsigned	noarmor = 0;
402 	const unsigned	armor = 1;
403 	__ops_io_t	*io;
404 	int		done;
405 
406 	io = netpgp->io;
407 	if ((done = __ops_keyring_fileread(netpgp->pubring, noarmor, f)) == 0) {
408 		done = __ops_keyring_fileread(netpgp->pubring, armor, f);
409 	}
410 	if (!done) {
411 		(void) fprintf(io->errs, "Cannot import key from file %s\n",
412 				f);
413 		return 0;
414 	}
415 	return __ops_keyring_list(io, netpgp->pubring);
416 }
417 
418 /* generate a new key */
419 int
420 netpgp_generate_key(netpgp_t *netpgp, char *id, int numbits)
421 {
422 	__ops_key_t		*keypair;
423 	__ops_userid_t		 uid;
424 	__ops_output_t		*create;
425 	const unsigned		 noarmor = 0;
426 	__ops_io_t		*io;
427 	char			*ringfile;
428 	int             	 fd;
429 
430 	(void) memset(&uid, 0x0, sizeof(uid));
431 	io = netpgp->io;
432 	/* generate a new key for 'id' */
433 	uid.userid = (unsigned char *) id;
434 	keypair = __ops_rsa_new_selfsign_key(numbits, 65537UL, &uid);
435 	if (keypair == NULL) {
436 		(void) fprintf(io->errs, "Cannot generate key\n");
437 		return 0;
438 	}
439 	/* write public key, and try to re-read it */
440 	ringfile = netpgp_getvar(netpgp, "pubring");
441 	fd = __ops_setup_file_append(&create, ringfile);
442 	if (!__ops_write_xfer_pubkey(create, keypair, noarmor)) {
443 		(void) fprintf(io->errs, "Cannot write pubkey\n");
444 		return 0;
445 	}
446 	__ops_teardown_file_write(create, fd);
447 	__ops_keyring_free(netpgp->pubring);
448 	if (!__ops_keyring_fileread(netpgp->pubring, noarmor, ringfile)) {
449 		(void) fprintf(io->errs, "Cannot read pubring %s\n", ringfile);
450 		return 0;
451 	}
452 	/* write secret key, and try to re-read it */
453 	ringfile = netpgp_getvar(netpgp, "sec ring file");
454 	fd = __ops_setup_file_append(&create, ringfile);
455 	if (!__ops_write_xfer_seckey(create, keypair, NULL, 0, noarmor)) {
456 		(void) fprintf(io->errs, "Cannot write seckey\n");
457 		return 0;
458 	}
459 	__ops_teardown_file_write(create, fd);
460 	__ops_keyring_free(netpgp->secring);
461 	if (!__ops_keyring_fileread(netpgp->secring, noarmor, ringfile)) {
462 		(void) fprintf(io->errs, "Can't read secring %s\n", ringfile);
463 		return 0;
464 	}
465 	__ops_keydata_free(keypair);
466 	return 1;
467 }
468 
469 /* encrypt a file */
470 int
471 netpgp_encrypt_file(netpgp_t *netpgp,
472 			const char *userid,
473 			const char *f,
474 			char *out,
475 			int armored)
476 {
477 	const __ops_key_t	*keypair;
478 	const unsigned		 overwrite = 1;
479 	const char		*suffix;
480 	__ops_io_t		*io;
481 	char			 outname[MAXPATHLEN];
482 
483 	io = netpgp->io;
484 	if (f == NULL) {
485 		(void) fprintf(io->errs,
486 			"netpgp_encrypt_file: no filename specified\n");
487 		return 0;
488 	}
489 	if (userid == NULL) {
490 		userid = netpgp_getvar(netpgp, "userid");
491 	}
492 	suffix = (armored) ? ".asc" : ".gpg";
493 	keypair = __ops_getkeybyname(io, netpgp->pubring, userid);
494 	if (keypair == NULL) {
495 		(void) fprintf(io->errs, "Userid '%s' not found in keyring\n",
496 					userid);
497 		return 0;
498 	}
499 	if (out == NULL) {
500 		(void) snprintf(outname, sizeof(outname), "%s%s", f, suffix);
501 		out = outname;
502 	}
503 	return (int)__ops_encrypt_file(io, f, out, keypair, (unsigned)armored,
504 					overwrite);
505 }
506 
507 /* decrypt a file */
508 int
509 netpgp_decrypt_file(netpgp_t *netpgp, const char *f, char *out, int armored)
510 {
511 	const unsigned	overwrite = 1;
512 	__ops_io_t		*io;
513 
514 	io = netpgp->io;
515 	if (f == NULL) {
516 		(void) fprintf(io->errs,
517 			"netpgp_decrypt_file: no filename specified\n");
518 		return 0;
519 	}
520 	return __ops_decrypt_file(netpgp->io, f, out, netpgp->secring,
521 				(unsigned)armored, overwrite, netpgp->passfp,
522 				get_passphrase_cb);
523 }
524 
525 /* sign a file */
526 int
527 netpgp_sign_file(netpgp_t *netpgp,
528 		const char *userid,
529 		const char *f,
530 		char *out,
531 		int armored,
532 		int cleartext,
533 		int detached)
534 {
535 	const __ops_key_t	*keypair;
536 	__ops_seckey_t		*seckey;
537 	const unsigned		 overwrite = 1;
538 	__ops_io_t		*io;
539 	char			*hashalg;
540 	int			 ret;
541 
542 	io = netpgp->io;
543 	if (f == NULL) {
544 		(void) fprintf(io->errs,
545 			"netpgp_sign_file: no filename specified\n");
546 		return 0;
547 	}
548 	if (userid == NULL) {
549 		userid = netpgp_getvar(netpgp, "userid");
550 	}
551 	/* get key with which to sign */
552 	keypair = __ops_getkeybyname(io, netpgp->secring, userid);
553 	if (keypair == NULL) {
554 		(void) fprintf(io->errs, "Userid '%s' not found in keyring\n",
555 				userid);
556 		return 0;
557 	}
558 	ret = 1;
559 	do {
560 		/* print out the user id */
561 		__ops_print_pubkeydata(io, keypair);
562 		/* now decrypt key */
563 		seckey = __ops_decrypt_seckey(keypair);
564 		if (seckey == NULL) {
565 			(void) fprintf(io->errs, "Bad passphrase\n");
566 		}
567 	} while (seckey == NULL);
568 	/* sign file */
569 	hashalg = netpgp_getvar(netpgp, "hash");
570 	if (cleartext) {
571 		ret = __ops_sign_file_as_cleartext(io, f, out, seckey,
572 						hashalg, overwrite);
573 	} else if (detached) {
574 		ret = __ops_sign_detached(io, f, out, seckey, hashalg);
575 	} else {
576 		ret = __ops_sign_file(io, f, out, seckey, hashalg,
577 					(unsigned)armored, overwrite);
578 	}
579 	__ops_forget(seckey, sizeof(*seckey));
580 	return ret;
581 }
582 
583 /* verify a file */
584 int
585 netpgp_verify_file(netpgp_t *netpgp, const char *in, const char *out, int armored)
586 {
587 	__ops_validation_t	 result;
588 	__ops_io_t		*io;
589 
590 	(void) memset(&result, 0x0, sizeof(result));
591 	io = netpgp->io;
592 	if (in == NULL) {
593 		(void) fprintf(io->errs,
594 			"netpgp_verify_file: no filename specified\n");
595 		return 0;
596 	}
597 	if (__ops_validate_file(io, &result, in, out, armored,
598 						netpgp->pubring)) {
599 		resultp(io, in, &result, netpgp->pubring);
600 		return 1;
601 	}
602 	if (result.validc + result.invalidc + result.unknownc == 0) {
603 		(void) fprintf(io->errs,
604 		"\"%s\": No signatures found - is this a signed file?\n",
605 			in);
606 	} else {
607 		(void) fprintf(io->errs,
608 "\"%s\": verification failure: %u invalid signatures, %u unknown signatures\n",
609 			in, result.invalidc, result.unknownc);
610 	}
611 	return 0;
612 }
613 
614 /* wrappers for the ops_debug_level functions we added to openpgpsdk */
615 
616 /* set the debugging level per filename */
617 int
618 netpgp_set_debug(const char *f)
619 {
620 	return __ops_set_debug_level(f);
621 }
622 
623 /* get the debugging level per filename */
624 int
625 netpgp_get_debug(const char *f)
626 {
627 	return __ops_get_debug_level(f);
628 }
629 
630 /* return the version for the library */
631 const char *
632 netpgp_get_info(const char *type)
633 {
634 	return __ops_get_info(type);
635 }
636 
637 /* list all the packets in a file */
638 int
639 netpgp_list_packets(netpgp_t *netpgp, char *f, int armour, char *pubringname)
640 {
641 	__ops_keyring_t	*keyring;
642 	const unsigned	 noarmor = 0;
643 	__ops_io_t	*io;
644 	char		 ringname[MAXPATHLEN];
645 	char		*homedir;
646 	int		 ret;
647 
648 	io = netpgp->io;
649 	if (f == NULL) {
650 		(void) fprintf(io->errs, "No file containing packets\n");
651 		return 0;
652 	}
653 	homedir = netpgp_getvar(netpgp, "homedir");
654 	if (pubringname == NULL) {
655 		(void) snprintf(ringname, sizeof(ringname),
656 				"%s/pubring.gpg", homedir);
657 		pubringname = ringname;
658 	}
659 	if ((keyring = calloc(1, sizeof(*keyring))) == NULL) {
660 		(void) fprintf(io->errs, "netpgp_list_packets: bad alloc\n");
661 		return 0;
662 	}
663 	if (!__ops_keyring_fileread(keyring, noarmor, pubringname)) {
664 		free(keyring);
665 		(void) fprintf(io->errs, "Cannot read pub keyring %s\n",
666 			pubringname);
667 		return 0;
668 	}
669 	netpgp->pubring = keyring;
670 	netpgp_setvar(netpgp, "pubring", pubringname);
671 	ret = __ops_list_packets(io, f, (unsigned)armour, keyring,
672 					netpgp->passfp,
673 					get_passphrase_cb);
674 	free(keyring);
675 	return ret;
676 }
677 
678 /* set a variable */
679 int
680 netpgp_setvar(netpgp_t *netpgp, const char *name, const char *value)
681 {
682 	int	i;
683 
684 	if ((i = findvar(netpgp, name)) < 0) {
685 		/* add the element to the array */
686 		if (size_arrays(netpgp, netpgp->size + 15)) {
687 			netpgp->name[i = netpgp->c++] = strdup(name);
688 		}
689 	} else {
690 		/* replace the element in the array */
691 		if (netpgp->value[i]) {
692 			free(netpgp->value[i]);
693 			netpgp->value[i] = NULL;
694 		}
695 	}
696 	/* sanity checks for range of values */
697 	if (strcmp(name, "hash") == 0 || strcmp(name, "algorithm") == 0) {
698 		if (__ops_str_to_hash_alg(value) == OPS_HASH_UNKNOWN) {
699 			return 0;
700 		}
701 	}
702 	netpgp->value[i] = strdup(value);
703 	return 1;
704 }
705 
706 /* get a variable's value (NULL if not set) */
707 char *
708 netpgp_getvar(netpgp_t *netpgp, const char *name)
709 {
710 	int	i;
711 
712 	return ((i = findvar(netpgp, name)) < 0) ? NULL : netpgp->value[i];
713 }
714