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