Home | History | Annotate | Line # | Download | only in lib
      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 (at) 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.106 2022/08/27 08:58:32 rillig 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 "ssh2pgp.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 	__PGP_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, (int)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(pgp_io_t *io,
    140 	const char *f,
    141 	pgp_validation_t *res,
    142 	pgp_keyring_t *ring)
    143 {
    144 	const pgp_key_t	*key;
    145 	pgp_pubkey_t		*sigkey;
    146 	unsigned		 from;
    147 	unsigned		 i;
    148 	time_t			 t;
    149 	char			 id[MAX_ID_LENGTH + 1];
    150 
    151 	for (i = 0; i < res->validc; i++) {
    152 		(void) fprintf(io->res,
    153 			"Good signature for %s made %s",
    154 			(f) ? f : "<stdin>",
    155 			ctime(&res->valid_sigs[i].birthtime));
    156 		if (res->duration > 0) {
    157 			t = res->birthtime + res->duration;
    158 			(void) fprintf(io->res, "Valid until %s", ctime(&t));
    159 		}
    160 		(void) fprintf(io->res,
    161 			"using %s key %s\n",
    162 			pgp_show_pka(res->valid_sigs[i].key_alg),
    163 			userid_to_id(res->valid_sigs[i].signer_id, id));
    164 		from = 0;
    165 		key = pgp_getkeybyid(io, ring,
    166 			(const uint8_t *) res->valid_sigs[i].signer_id,
    167 			&from, &sigkey);
    168 		if (sigkey == &key->enckey) {
    169 			(void) fprintf(io->res,
    170 				"WARNING: signature for %s made with encryption key\n",
    171 				(f) ? f : "<stdin>");
    172 		}
    173 		pgp_print_keydata(io, ring, key, "signature ", &key->key.pubkey, 0);
    174 	}
    175 }
    176 
    177 /* check there's enough space in the arrays */
    178 static int
    179 size_arrays(netpgp_t *netpgp, unsigned needed)
    180 {
    181 	char	**temp;
    182 
    183 	if (netpgp->size == 0) {
    184 		/* only get here first time around */
    185 		netpgp->size = needed;
    186 		if ((netpgp->name = calloc(sizeof(char *), needed)) == NULL) {
    187 			(void) fprintf(stderr, "size_arrays: bad alloc\n");
    188 			return 0;
    189 		}
    190 		if ((netpgp->value = calloc(sizeof(char *), needed)) == NULL) {
    191 			free(netpgp->name);
    192 			(void) fprintf(stderr, "size_arrays: bad alloc\n");
    193 			return 0;
    194 		}
    195 	} else if (netpgp->c == netpgp->size) {
    196 		/* only uses 'needed' when filled array */
    197 		netpgp->size += needed;
    198 		temp = realloc(netpgp->name, sizeof(char *) * needed);
    199 		if (temp == NULL) {
    200 			(void) fprintf(stderr, "size_arrays: bad alloc\n");
    201 			return 0;
    202 		}
    203 		netpgp->name = temp;
    204 		temp = realloc(netpgp->value, sizeof(char *) * needed);
    205 		if (temp == NULL) {
    206 			(void) fprintf(stderr, "size_arrays: bad alloc\n");
    207 			return 0;
    208 		}
    209 		netpgp->value = temp;
    210 	}
    211 	return 1;
    212 }
    213 
    214 /* find the name in the array */
    215 static int
    216 findvar(netpgp_t *netpgp, const char *name)
    217 {
    218 	unsigned	i;
    219 
    220 	for (i = 0 ; i < netpgp->c && strcmp(netpgp->name[i], name) != 0; i++) {
    221 	}
    222 	return (i == netpgp->c) ? -1 : (int)i;
    223 }
    224 
    225 /* append a key to a keyring */
    226 static int
    227 appendkey(pgp_io_t *io, pgp_key_t *key, char *ringfile)
    228 {
    229 	pgp_output_t	*create;
    230 	const unsigned	 noarmor = 0;
    231 	int		 fd;
    232 
    233 	if ((fd = pgp_setup_file_append(&create, ringfile)) < 0) {
    234 		fd = pgp_setup_file_write(&create, ringfile, 0);
    235 	}
    236 	if (fd < 0) {
    237 		(void) fprintf(io->errs, "can't open pubring '%s'\n", ringfile);
    238 		return 0;
    239 	}
    240 	if (!pgp_write_xfer_pubkey(create, key, noarmor)) {
    241 		(void) fprintf(io->errs, "Cannot write pubkey\n");
    242 		return 0;
    243 	}
    244 	pgp_teardown_file_write(create, fd);
    245 	return 1;
    246 }
    247 
    248 /* return filename of a keyring */
    249 static char *
    250 keyringfile(netpgp_t *netpgp, const char *name)
    251 {
    252 	char		 f[MAXPATHLEN];
    253 	char		*homedir;
    254 	char		*filename;
    255 
    256 	homedir = netpgp_getvar(netpgp, "homedir");
    257 	filename = netpgp_getvar(netpgp, name);
    258 	if (filename == NULL || filename[0] == '\0') {
    259 		(void) snprintf(f, sizeof(f), "%s/%s.gpg", homedir, name);
    260 		filename = f;
    261 	}
    262 
    263 	return netpgp_strdup(filename);
    264 }
    265 
    266 /* return an empty keyring */
    267 static void *
    268 newkeyring(netpgp_t *netpgp, const char *name)
    269 {
    270 	pgp_keyring_t	*keyring;
    271 	char		*filename;
    272 
    273 	if ((keyring = calloc(1, sizeof(*keyring))) == NULL) {
    274 		(void) fprintf(stderr, "newkeyring: bad alloc\n");
    275 		return NULL;
    276 	}
    277 
    278 	filename = keyringfile(netpgp, name);
    279 	netpgp_setvar(netpgp, name, filename);
    280 	free(filename);
    281 
    282 	return keyring;
    283 }
    284 
    285 /* read a keyring and return it */
    286 static void *
    287 readkeyring(netpgp_t *netpgp, const char *name)
    288 {
    289 	pgp_keyring_t	*keyring;
    290 	const unsigned	 noarmor = 0;
    291 	char		*filename;
    292 
    293 	if ((keyring = calloc(1, sizeof(*keyring))) == NULL) {
    294 		(void) fprintf(stderr, "readkeyring: bad alloc\n");
    295 		return NULL;
    296 	}
    297 
    298 	filename = keyringfile(netpgp, name);
    299 	if (!pgp_keyring_fileread(keyring, noarmor, filename)) {
    300 		(void) fprintf(stderr, "Can't read %s %s\n", name, filename);
    301 		free(filename);
    302 		free(keyring);
    303 		return NULL;
    304 	}
    305 	netpgp_setvar(netpgp, name, filename);
    306 	free(filename);
    307 
    308 	return keyring;
    309 }
    310 
    311 /* write a keyring */
    312 static int
    313 writekeyring(netpgp_t *netpgp, const char *name, pgp_keyring_t *keyring, uint8_t *passphrase)
    314 {
    315 	const unsigned	 noarmor = 0;
    316 	char		*filename;
    317 
    318 	filename = keyringfile(netpgp, name);
    319 	if (!pgp_keyring_filewrite(keyring, noarmor, filename, passphrase)) {
    320 		(void) fprintf(stderr, "Can't write %s %s\n", name, filename);
    321 		free(filename);
    322 		return 0;
    323 	}
    324 	netpgp_setvar(netpgp, name, filename);
    325 	free(filename);
    326 
    327 	return 1;
    328 }
    329 
    330 /* append key to a keyring */
    331 static int
    332 appendtokeyring(netpgp_t *netpgp, const char *name, pgp_key_t *key)
    333 {
    334 	char	*filename;
    335 	int	ret;
    336 
    337 	filename = keyringfile(netpgp, name);
    338 	ret = appendkey(netpgp->io, key, filename);
    339 	free(filename);
    340 
    341 	return ret;
    342 }
    343 
    344 /* read keys from ssh key files */
    345 static int
    346 readsshkeys(netpgp_t *netpgp, char *homedir, const char *needseckey)
    347 {
    348 	pgp_keyring_t	*pubring;
    349 	pgp_keyring_t	*secring;
    350 	struct stat	 st;
    351 	unsigned	 hashtype;
    352 	char		*hash;
    353 	char		 f[MAXPATHLEN];
    354 	char		*filename;
    355 
    356 	if ((filename = netpgp_getvar(netpgp, "sshkeyfile")) == NULL) {
    357 		/* set reasonable default for RSA key */
    358 		(void) snprintf(f, sizeof(f), "%s/id_rsa.pub", homedir);
    359 		filename = f;
    360 	} else if (strcmp(&filename[strlen(filename) - 4], ".pub") != 0) {
    361 		/* got ssh keys, check for pub file name */
    362 		(void) snprintf(f, sizeof(f), "%s.pub", filename);
    363 		filename = f;
    364 	}
    365 	/* check the pub file exists */
    366 	if (stat(filename, &st) != 0) {
    367 		(void) fprintf(stderr, "readsshkeys: bad pubkey filename '%s'\n", filename);
    368 		return 0;
    369 	}
    370 	if ((pubring = calloc(1, sizeof(*pubring))) == NULL) {
    371 		(void) fprintf(stderr, "readsshkeys: bad alloc\n");
    372 		return 0;
    373 	}
    374 	/* openssh2 keys use md5 by default */
    375 	hashtype = PGP_HASH_MD5;
    376 	if ((hash = netpgp_getvar(netpgp, "hash")) != NULL) {
    377 		/* openssh 2 hasn't really caught up to anything else yet */
    378 		if (netpgp_strcasecmp(hash, "md5") == 0) {
    379 			hashtype = PGP_HASH_MD5;
    380 		} else if (netpgp_strcasecmp(hash, "sha1") == 0) {
    381 			hashtype = PGP_HASH_SHA1;
    382 		} else if (netpgp_strcasecmp(hash, "sha256") == 0) {
    383 			hashtype = PGP_HASH_SHA256;
    384 		}
    385 	}
    386 	if (!pgp_ssh2_readkeys(netpgp->io, pubring, NULL, filename, NULL, hashtype)) {
    387 		free(pubring);
    388 		(void) fprintf(stderr, "readsshkeys: can't read %s\n",
    389 				filename);
    390 		return 0;
    391 	}
    392 	if (netpgp->pubring == NULL) {
    393 		netpgp->pubring = pubring;
    394 	} else {
    395 		pgp_append_keyring(netpgp->pubring, pubring);
    396 	}
    397 	if (needseckey) {
    398 		netpgp_setvar(netpgp, "sshpubfile", filename);
    399 		/* try to take the ".pub" off the end */
    400 		if (filename == f) {
    401 			f[strlen(f) - 4] = 0x0;
    402 		} else {
    403 			(void) snprintf(f, sizeof(f), "%.*s",
    404 					(int)strlen(filename) - 4, filename);
    405 			filename = f;
    406 		}
    407 		if ((secring = calloc(1, sizeof(*secring))) == NULL) {
    408 			free(pubring);
    409 			(void) fprintf(stderr, "readsshkeys: bad alloc\n");
    410 			return 0;
    411 		}
    412 		if (!pgp_ssh2_readkeys(netpgp->io, pubring, secring, NULL, filename, hashtype)) {
    413 			free(pubring);
    414 			free(secring);
    415 			(void) fprintf(stderr, "readsshkeys: can't read sec %s\n", filename);
    416 			return 0;
    417 		}
    418 		netpgp->secring = secring;
    419 		netpgp_setvar(netpgp, "sshsecfile", filename);
    420 	}
    421 	return 1;
    422 }
    423 
    424 /* get the uid of the first key in the keyring */
    425 static int
    426 get_first_ring(pgp_keyring_t *ring, char *id, size_t len, int last)
    427 {
    428 	uint8_t	*src;
    429 	int	 i;
    430 	int	 n;
    431 
    432 	if (ring == NULL || ring->keyc == 0) {
    433 		return 0;
    434 	}
    435 	(void) memset(id, 0x0, len);
    436 	src = ring->keys[(last) ? ring->keyc - 1 : 0].sigid;
    437 	for (i = 0, n = 0 ; i < PGP_KEY_ID_SIZE ; i += 2) {
    438 		n += snprintf(&id[n], len - n, "%02x%02x", src[i], src[i + 1]);
    439 	}
    440 	id[n] = 0x0;
    441 	return 1;
    442 }
    443 
    444 /* find the time - in a specific %Y-%m-%d format - using a regexp */
    445 static int
    446 grabdate(char *s, int64_t *t)
    447 {
    448 	static regex_t	r;
    449 	static int	compiled;
    450 	regmatch_t	matches[10];
    451 	struct tm	tm;
    452 
    453 	if (!compiled) {
    454 		compiled = 1;
    455 		(void) regcomp(&r, "([0-9][0-9][0-9][0-9])[-/]([0-9][0-9])[-/]([0-9][0-9])", REG_EXTENDED);
    456 	}
    457 	if (regexec(&r, s, 10, matches, 0) == 0) {
    458 		(void) memset(&tm, 0x0, sizeof(tm));
    459 		tm.tm_year = (int)strtol(&s[(int)matches[1].rm_so], NULL, 10);
    460 		tm.tm_mon = (int)strtol(&s[(int)matches[2].rm_so], NULL, 10) - 1;
    461 		tm.tm_mday = (int)strtol(&s[(int)matches[3].rm_so], NULL, 10);
    462 		*t = mktime(&tm);
    463 		return 1;
    464 	}
    465 	return 0;
    466 }
    467 
    468 /* get expiration in seconds */
    469 static uint64_t
    470 get_duration(char *s)
    471 {
    472 	uint64_t	 now;
    473 	int64_t	 	 t;
    474 	const char	*mult;
    475 
    476 	if (s == NULL) {
    477 		return 0;
    478 	}
    479 	now = (uint64_t)strtoull(s, NULL, 10);
    480 	if ((mult = strchr("hdwmy", s[strlen(s) - 1])) != NULL) {
    481 		switch(*mult) {
    482 		case 'h':
    483 			return now * 60 * 60;
    484 		case 'd':
    485 			return now * 60 * 60 * 24;
    486 		case 'w':
    487 			return now * 60 * 60 * 24 * 7;
    488 		case 'm':
    489 			return now * 60 * 60 * 24 * 31;
    490 		case 'y':
    491 			return now * 60 * 60 * 24 * 365;
    492 		}
    493 	}
    494 	if (grabdate(s, &t)) {
    495 		return t;
    496 	}
    497 	return (uint64_t)strtoll(s, NULL, 10);
    498 }
    499 
    500 /* get birthtime in seconds */
    501 static int64_t
    502 get_birthtime(char *s)
    503 {
    504 	int64_t	t;
    505 
    506 	if (s == NULL) {
    507 		return time(NULL);
    508 	}
    509 	if (grabdate(s, &t)) {
    510 		return t;
    511 	}
    512 	return (uint64_t)strtoll(s, NULL, 10);
    513 }
    514 
    515 /* resolve the userid */
    516 static const pgp_key_t *
    517 resolve_userid(netpgp_t *netpgp, const pgp_keyring_t *keyring, const char *userid)
    518 {
    519 	const pgp_key_t	*key;
    520 	pgp_io_t		*io;
    521 
    522 	if (userid == NULL) {
    523 		userid = netpgp_getvar(netpgp, "userid");
    524 		if (userid == NULL)
    525 			return NULL;
    526 	} else if (userid[0] == '0' && userid[1] == 'x') {
    527 		userid += 2;
    528 	}
    529 	io = netpgp->io;
    530 	if ((key = pgp_getkeybyname(io, keyring, userid)) == NULL) {
    531 		(void) fprintf(io->errs, "Can't find key '%s'\n", userid);
    532 	}
    533 	return key;
    534 }
    535 
    536 /* return 1 if the file contains ascii-armoured text */
    537 static unsigned
    538 isarmoured(pgp_io_t *io, const char *f, const void *memory, const char *text)
    539 {
    540 	regmatch_t	 matches[10];
    541 	unsigned	 armoured;
    542 	regex_t		 r;
    543 	FILE		*fp;
    544 	char	 	 buf[BUFSIZ];
    545 
    546 	armoured = 0;
    547 	(void) regcomp(&r, text, REG_EXTENDED);
    548 	if (f) {
    549 		if ((fp = fopen(f, "r")) == NULL) {
    550 			(void) fprintf(io->errs, "isarmoured: can't open '%s'\n", f);
    551 			regfree(&r);
    552 			return 0;
    553 		}
    554 		if (fgets(buf, (int)sizeof(buf), fp) != NULL) {
    555 			if (regexec(&r, buf, 10, matches, 0) == 0) {
    556 				armoured = 1;
    557 			}
    558 		}
    559 		(void) fclose(fp);
    560 	} else {
    561 		if (regexec(&r, memory, 10, matches, 0) == 0) {
    562 			armoured = 1;
    563 		}
    564 	}
    565 	regfree(&r);
    566 	return armoured;
    567 }
    568 
    569 /* vararg print function */
    570 static void
    571 p(FILE *fp, const char *s, ...)
    572 {
    573 	va_list	args;
    574 
    575 	va_start(args, s);
    576 	while (s != NULL) {
    577 		(void) fprintf(fp, "%s", s);
    578 		s = va_arg(args, char *);
    579 	}
    580 	va_end(args);
    581 }
    582 
    583 /* print a JSON object to the FILE stream */
    584 static void
    585 pobj(FILE *fp, mj_t *obj, int depth)
    586 {
    587 
    588 	if (obj == NULL) {
    589 		(void) fprintf(stderr, "No object found\n");
    590 		return;
    591 	}
    592 
    593 	mj_pretty(obj, fp, depth, "");
    594 }
    595 
    596 /* return the time as a string */
    597 static char *
    598 ptimestr(char *dest, size_t size, time_t t)
    599 {
    600 	struct tm      *tm;
    601 
    602 	tm = gmtime(&t);
    603 	(void) snprintf(dest, size, "%04d-%02d-%02d",
    604 		tm->tm_year + 1900,
    605 		tm->tm_mon + 1,
    606 		tm->tm_mday);
    607 	return dest;
    608 }
    609 
    610 /* format a JSON object */
    611 static void
    612 format_json_key(FILE *fp, mj_t *obj, const int psigs)
    613 {
    614 	int64_t	 birthtime;
    615 	int64_t	 duration;
    616 	time_t	 now;
    617 	char	 tbuf[32];
    618 	char	*s;
    619 	mj_t	*sub;
    620 	int	 i;
    621 
    622 	if (pgp_get_debug_level(__FILE__)) {
    623 		mj_asprint(&s, obj, MJ_HUMAN);
    624 		(void) fprintf(stderr, "formatobj: json is '%s'\n", s);
    625 		free(s);
    626 	}
    627 	if (obj->c == 2 && obj->value.v[1].type == MJ_STRING &&
    628 	    strcmp(obj->value.v[1].value.s, "[REVOKED]") == 0) {
    629 		/* whole key has been rovoked - just return */
    630 		return;
    631 	}
    632 	pobj(fp, &obj->value.v[mj_object_find(obj, "header", 0, 2) + 1], 0);
    633 	p(fp, " ", NULL);
    634 	pobj(fp, &obj->value.v[mj_object_find(obj, "key bits", 0, 2) + 1], 0);
    635 	p(fp, "/", NULL);
    636 	pobj(fp, &obj->value.v[mj_object_find(obj, "pka", 0, 2) + 1], 0);
    637 	p(fp, " ", NULL);
    638 	pobj(fp, &obj->value.v[mj_object_find(obj, "key id", 0, 2) + 1], 0);
    639 	birthtime = (int64_t)strtoll(obj->value.v[mj_object_find(obj, "birthtime", 0, 2) + 1].value.s, NULL, 10);
    640 	p(fp, " ", ptimestr(tbuf, sizeof(tbuf), birthtime), NULL);
    641 	duration = (int64_t)strtoll(obj->value.v[mj_object_find(obj, "duration", 0, 2) + 1].value.s, NULL, 10);
    642 	if (duration > 0) {
    643 		now = time(NULL);
    644 		p(fp, " ", (birthtime + duration < now) ? "[EXPIRED " : "[EXPIRES ",
    645 			ptimestr(tbuf, sizeof(tbuf), birthtime + duration), "]", NULL);
    646 	}
    647 	p(fp, "\n", "Key fingerprint: ", NULL);
    648 	pobj(fp, &obj->value.v[mj_object_find(obj, "fingerprint", 0, 2) + 1], 0);
    649 	p(fp, "\n", NULL);
    650 	/* go to field after \"duration\" */
    651 	for (i = mj_object_find(obj, "duration", 0, 2) + 2; i < mj_arraycount(obj) ; i += 2) {
    652 		if (strcmp(obj->value.v[i].value.s, "uid") == 0) {
    653 			sub = &obj->value.v[i + 1];
    654 			p(fp, "uid", NULL);
    655 			pobj(fp, &sub->value.v[0], (psigs) ? 4 : 14); /* human name */
    656 			pobj(fp, &sub->value.v[1], 1); /* any revocation */
    657 			p(fp, "\n", NULL);
    658 		} else if (strcmp(obj->value.v[i].value.s, "encryption") == 0) {
    659 			sub = &obj->value.v[i + 1];
    660 			p(fp, "encryption", NULL);
    661 			pobj(fp, &sub->value.v[0], 1);	/* size */
    662 			p(fp, "/", NULL);
    663 			pobj(fp, &sub->value.v[1], 0); /* alg */
    664 			p(fp, " ", NULL);
    665 			pobj(fp, &sub->value.v[2], 0); /* id */
    666 			p(fp, " ", ptimestr(tbuf, sizeof(tbuf),
    667 					(time_t)strtoll(sub->value.v[3].value.s, NULL, 10)),
    668 				"\n", NULL);
    669 		} else if (strcmp(obj->value.v[i].value.s, "sig") == 0) {
    670 			sub = &obj->value.v[i + 1];
    671 			p(fp, "sig", NULL);
    672 			pobj(fp, &sub->value.v[0], 8);	/* size */
    673 			p(fp, "  ", ptimestr(tbuf, sizeof(tbuf),
    674 					(time_t)strtoll(sub->value.v[1].value.s, NULL, 10)),
    675 				" ", NULL); /* time */
    676 			pobj(fp, &sub->value.v[2], 0); /* human name */
    677 			p(fp, "\n", NULL);
    678 		} else {
    679 			fprintf(stderr, "weird '%s'\n", obj->value.v[i].value.s);
    680 			pobj(fp, &obj->value.v[i], 0); /* human name */
    681 		}
    682 	}
    683 	p(fp, "\n", NULL);
    684 }
    685 
    686 /* save a pgp pubkey to a temp file */
    687 static int
    688 savepubkey(char *res, char *f, size_t size)
    689 {
    690 	size_t	len;
    691 	int	cc;
    692 	int	wc;
    693 	int	fd;
    694 
    695 	(void) snprintf(f, size, "/tmp/pgp2ssh.XXXXXXX");
    696 	if ((fd = mkstemp(f)) < 0) {
    697 		(void) fprintf(stderr, "can't create temp file '%s'\n", f);
    698 		return 0;
    699 	}
    700 	len = strlen(res);
    701 	for (cc = 0 ; (wc = (int)write(fd, &res[cc], len - (size_t)cc)) > 0 ; cc += wc) {
    702 	}
    703 	(void) close(fd);
    704 	return 1;
    705 }
    706 
    707 /* format a uint32_t */
    708 static int
    709 formatu32(uint8_t *buffer, uint32_t value)
    710 {
    711 	buffer[0] = (uint8_t)(value >> 24) & 0xff;
    712 	buffer[1] = (uint8_t)(value >> 16) & 0xff;
    713 	buffer[2] = (uint8_t)(value >> 8) & 0xff;
    714 	buffer[3] = (uint8_t)value & 0xff;
    715 	return sizeof(uint32_t);
    716 }
    717 
    718 /* format a string as (len, string) */
    719 static int
    720 formatstring(char *buffer, const uint8_t *s, size_t len)
    721 {
    722 	int	cc;
    723 
    724 	cc = formatu32((uint8_t *)buffer, (uint32_t)len);
    725 	(void) memcpy(&buffer[cc], s, len);
    726 	return cc + (int)len;
    727 }
    728 
    729 /* format a bignum, checking for "interesting" high bit values */
    730 static int
    731 formatbignum(char *buffer, BIGNUM *bn)
    732 {
    733 	size_t	 len;
    734 	uint8_t	*cp;
    735 	int	 cc;
    736 
    737 	len = (size_t) BN_num_bytes(bn);
    738 	if ((cp = calloc(1, len + 1)) == NULL) {
    739 		(void) fprintf(stderr, "calloc failure in formatbignum\n");
    740 		return 0;
    741 	}
    742 	(void) BN_bn2bin(bn, cp + 1);
    743 	cp[0] = 0x0;
    744 	cc = (cp[1] & 0x80) ? formatstring(buffer, cp, len + 1) : formatstring(buffer, &cp[1], len);
    745 	free(cp);
    746 	return cc;
    747 }
    748 
    749 #define MAX_PASSPHRASE_ATTEMPTS	3
    750 #define INFINITE_ATTEMPTS	-1
    751 
    752 /* get the passphrase from the user */
    753 static int
    754 find_passphrase(FILE *passfp, const char *id, char *passphrase, size_t size, int attempts)
    755 {
    756 	char	 prompt[BUFSIZ];
    757 	char	 buf[128];
    758 	char	*cp;
    759 	int	 cc;
    760 	int	 i;
    761 
    762 	if (passfp) {
    763 		if (fgets(passphrase, (int)size, passfp) == NULL) {
    764 			return 0;
    765 		}
    766 		return (int)strlen(passphrase);
    767 	}
    768 	for (i = 0 ; i < attempts ; i++) {
    769 		(void) snprintf(prompt, sizeof(prompt), "Enter passphrase for %.16s: ", id);
    770 		if ((cp = getpass(prompt)) == NULL) {
    771 			break;
    772 		}
    773 		cc = snprintf(buf, sizeof(buf), "%s", cp);
    774 		(void) snprintf(prompt, sizeof(prompt), "Repeat passphrase for %.16s: ", id);
    775 		if ((cp = getpass(prompt)) == NULL) {
    776 			break;
    777 		}
    778 		cc = snprintf(passphrase, size, "%s", cp);
    779 		if (strcmp(buf, passphrase) == 0) {
    780 			(void) memset(buf, 0x0, sizeof(buf));
    781 			return cc;
    782 		}
    783 	}
    784 	(void) memset(buf, 0x0, sizeof(buf));
    785 	(void) memset(passphrase, 0x0, size);
    786 	return 0;
    787 }
    788 
    789 /***************************************************************************/
    790 /* exported functions start here */
    791 /***************************************************************************/
    792 
    793 /* initialise a netpgp_t structure */
    794 int
    795 netpgp_init(netpgp_t *netpgp)
    796 {
    797 	pgp_io_t	*io;
    798 	time_t		 t;
    799 	char		 id[MAX_ID_LENGTH];
    800 	char		*homedir;
    801 	char		*userid;
    802 	char		*stream;
    803 	char		*passfd;
    804 	char		*results;
    805 	int		 coredumps;
    806 	int		 last;
    807 
    808 #ifdef HAVE_SYS_RESOURCE_H
    809 	struct rlimit	limit;
    810 
    811 	coredumps = netpgp_getvar(netpgp, "coredumps") != NULL;
    812 	if (!coredumps) {
    813 		(void) memset(&limit, 0x0, sizeof(limit));
    814 		if (setrlimit(RLIMIT_CORE, &limit) != 0) {
    815 			(void) fprintf(stderr,
    816 			"netpgp: warning - can't turn off core dumps\n");
    817 			coredumps = 1;
    818 		}
    819 	}
    820 #else
    821 	coredumps = 1;
    822 #endif
    823 	if ((io = calloc(1, sizeof(*io))) == NULL) {
    824 		(void) fprintf(stderr, "netpgp_init: bad alloc\n");
    825 		return 0;
    826 	}
    827 	io->outs = stdout;
    828 	if ((stream = netpgp_getvar(netpgp, "outs")) != NULL &&
    829 	    strcmp(stream, "<stderr>") == 0) {
    830 		io->outs = stderr;
    831 	}
    832 	io->errs = stderr;
    833 	if ((stream = netpgp_getvar(netpgp, "errs")) != NULL &&
    834 	    strcmp(stream, "<stdout>") == 0) {
    835 		io->errs = stdout;
    836 	}
    837 	if ((results = netpgp_getvar(netpgp, "res")) == NULL) {
    838 		io->res = io->errs;
    839 	} else if (strcmp(results, "<stdout>") == 0) {
    840 		io->res = stdout;
    841 	} else if (strcmp(results, "<stderr>") == 0) {
    842 		io->res = stderr;
    843 	} else {
    844 		if ((io->res = fopen(results, "w")) == NULL) {
    845 			(void) fprintf(io->errs, "Can't open results %s for writing\n",
    846 				results);
    847 			free(io);
    848 			return 0;
    849 		}
    850 	}
    851 	netpgp->io = io;
    852 	/* get passphrase from an fd */
    853 	if ((passfd = netpgp_getvar(netpgp, "pass-fd")) != NULL &&
    854 	    (netpgp->passfp = fdopen(atoi(passfd), "r")) == NULL) {
    855 		(void) fprintf(io->errs, "Can't open fd %s for reading\n",
    856 			passfd);
    857 		return 0;
    858 	}
    859 	/* warn if core dumps are enabled */
    860 	if (coredumps) {
    861 		(void) fprintf(io->errs,
    862 			"netpgp: warning: core dumps enabled\n");
    863 	}
    864 	/* get home directory - where keyrings are in a subdir */
    865 	if ((homedir = netpgp_getvar(netpgp, "homedir")) == NULL) {
    866 		(void) fprintf(io->errs, "netpgp: bad homedir\n");
    867 		return 0;
    868 	}
    869 	if (netpgp_getvar(netpgp, "ssh keys") == NULL) {
    870 		/* read from ordinary pgp keyrings */
    871 		netpgp->pubring = readkeyring(netpgp, "pubring");
    872 		if (netpgp->pubring == NULL) {
    873 			return 0;
    874 		}
    875 		/* if a userid has been given, we'll use it */
    876 		if ((userid = netpgp_getvar(netpgp, "userid")) == NULL) {
    877 			/* also search in config file for default id */
    878 			(void) memset(id, 0x0, sizeof(id));
    879 			(void) conffile(netpgp, homedir, id, sizeof(id));
    880 			if (id[0] != 0x0) {
    881 				netpgp_setvar(netpgp, "userid", userid = id);
    882 			}
    883 		}
    884 		/* only read secret keys if we need to */
    885 		if (netpgp_getvar(netpgp, "need seckey")) {
    886 			/* read the secret ring */
    887 			netpgp->secring = readkeyring(netpgp, "secring");
    888 			if (netpgp->secring == NULL) {
    889 				return 0;
    890 			}
    891 			/* now, if we don't have a valid user, use the first in secring */
    892 			if (!userid && netpgp_getvar(netpgp, "need userid") != NULL) {
    893 				/* signing - need userid and sec key */
    894 				(void) memset(id, 0x0, sizeof(id));
    895 				if (get_first_ring(netpgp->secring, id, sizeof(id), 0)) {
    896 					netpgp_setvar(netpgp, "userid", userid = id);
    897 				}
    898 			}
    899 		} else if (netpgp_getvar(netpgp, "need userid") != NULL) {
    900 			/* encrypting - get first in pubring */
    901 			if (!userid && get_first_ring(netpgp->pubring, id, sizeof(id), 0)) {
    902 				(void) netpgp_setvar(netpgp, "userid", userid = id);
    903 			}
    904 		}
    905 		if (!userid && netpgp_getvar(netpgp, "need userid")) {
    906 			/* if we don't have a user id, and we need one, fail */
    907 			(void) fprintf(io->errs, "Cannot find user id\n");
    908 			return 0;
    909 		}
    910 	} else {
    911 		/* read from ssh keys */
    912 		last = (netpgp->pubring != NULL);
    913 		if (!readsshkeys(netpgp, homedir, netpgp_getvar(netpgp, "need seckey"))) {
    914 			return 0;
    915 		}
    916 		if ((userid = netpgp_getvar(netpgp, "userid")) == NULL) {
    917 			get_first_ring(netpgp->pubring, id, sizeof(id), last);
    918 			netpgp_setvar(netpgp, "userid", userid = id);
    919 		}
    920 		if (userid == NULL) {
    921 			if (netpgp_getvar(netpgp, "need userid") != NULL) {
    922 				(void) fprintf(io->errs,
    923 						"Cannot find user id\n");
    924 				return 0;
    925 			}
    926 		} else {
    927 			(void) netpgp_setvar(netpgp, "userid", userid);
    928 		}
    929 	}
    930 	t = time(NULL);
    931 	netpgp_setvar(netpgp, "initialised", ctime(&t));
    932 	return 1;
    933 }
    934 
    935 /* finish off with the netpgp_t struct */
    936 int
    937 netpgp_end(netpgp_t *netpgp)
    938 {
    939 	unsigned	i;
    940 
    941 	for (i = 0 ; i < netpgp->c ; i++) {
    942 		if (netpgp->name[i] != NULL) {
    943 			free(netpgp->name[i]);
    944 		}
    945 		if (netpgp->value[i] != NULL) {
    946 			free(netpgp->value[i]);
    947 		}
    948 	}
    949 	if (netpgp->name != NULL) {
    950 		free(netpgp->name);
    951 	}
    952 	if (netpgp->value != NULL) {
    953 		free(netpgp->value);
    954 	}
    955 	if (netpgp->pubring != NULL) {
    956 		pgp_keyring_free(netpgp->pubring);
    957 	}
    958 	if (netpgp->secring != NULL) {
    959 		pgp_keyring_free(netpgp->secring);
    960 	}
    961 	free(netpgp->io);
    962 	return 1;
    963 }
    964 
    965 /* list the keys in a keyring */
    966 int
    967 netpgp_list_keys(netpgp_t *netpgp, const int psigs)
    968 {
    969 	if (netpgp->pubring == NULL) {
    970 		(void) fprintf(stderr, "No keyring\n");
    971 		return 0;
    972 	}
    973 	return pgp_keyring_list(netpgp->io, netpgp->pubring, psigs);
    974 }
    975 
    976 /* list the keys in a keyring, returning a JSON encoded string */
    977 int
    978 netpgp_list_keys_json(netpgp_t *netpgp, char **json, const int psigs)
    979 {
    980 	mj_t	obj;
    981 	int	ret;
    982 
    983 	if (netpgp->pubring == NULL) {
    984 		(void) fprintf(stderr, "No keyring\n");
    985 		return 0;
    986 	}
    987 	(void) memset(&obj, 0x0, sizeof(obj));
    988 	if (!pgp_keyring_json(netpgp->io, netpgp->pubring, &obj, psigs)) {
    989 		(void) fprintf(stderr, "No keys in keyring\n");
    990 		return 0;
    991 	}
    992 	ret = mj_asprint(json, &obj, MJ_JSON_ENCODE);
    993 	mj_delete(&obj);
    994 	return ret;
    995 }
    996 
    997 DEFINE_ARRAY(strings_t, char *);
    998 
    999 #ifndef HKP_VERSION
   1000 #define HKP_VERSION	1
   1001 #endif
   1002 
   1003 /* find and list some keys in a keyring */
   1004 int
   1005 netpgp_match_keys(netpgp_t *netpgp, char *name, const char *fmt, void *vp, const int psigs)
   1006 {
   1007 	const pgp_key_t	*key;
   1008 	unsigned		 k;
   1009 	strings_t		 pubs;
   1010 	FILE			*fp = (FILE *)vp;
   1011 
   1012 	if (name[0] == '0' && name[1] == 'x') {
   1013 		name += 2;
   1014 	}
   1015 	(void) memset(&pubs, 0x0, sizeof(pubs));
   1016 	k = 0;
   1017 	do {
   1018 		key = pgp_getnextkeybyname(netpgp->io, netpgp->pubring,
   1019 						name, &k);
   1020 		if (key != NULL) {
   1021 			ALLOC(char *, pubs.v, pubs.size, pubs.c, 10, 10,
   1022 					"netpgp_match_keys", return 0);
   1023 			if (strcmp(fmt, "mr") == 0) {
   1024 				pgp_hkp_sprint_keydata(netpgp->io, netpgp->pubring,
   1025 						key, &pubs.v[pubs.c],
   1026 						&key->key.pubkey, psigs);
   1027 			} else {
   1028 				pgp_sprint_keydata(netpgp->io, netpgp->pubring,
   1029 						key, &pubs.v[pubs.c],
   1030 						"signature ",
   1031 						&key->key.pubkey, psigs);
   1032 			}
   1033 			if (pubs.v[pubs.c] != NULL) {
   1034 				pubs.c += 1;
   1035 			}
   1036 			k += 1;
   1037 		}
   1038 	} while (key != NULL);
   1039 	if (strcmp(fmt, "mr") == 0) {
   1040 		(void) fprintf(fp, "info:%d:%d\n", HKP_VERSION, pubs.c);
   1041 	} else {
   1042 		(void) fprintf(fp, "%d key%s found\n", pubs.c,
   1043 			(pubs.c == 1) ? "" : "s");
   1044 	}
   1045 	for (k = 0 ; k < pubs.c ; k++) {
   1046 		(void) fprintf(fp, "%s%s", pubs.v[k], (k < pubs.c - 1) ? "\n" : "");
   1047 		free(pubs.v[k]);
   1048 	}
   1049 	free(pubs.v);
   1050 	return pubs.c;
   1051 }
   1052 
   1053 /* find and list some keys in a keyring - return JSON string */
   1054 int
   1055 netpgp_match_keys_json(netpgp_t *netpgp, char **json, char *name, const char *fmt, const int psigs)
   1056 {
   1057 	const pgp_key_t	*key;
   1058 	unsigned	 k;
   1059 	mj_t		 id_array;
   1060 	char		*newkey;
   1061 	int		 ret;
   1062 
   1063 	if (name[0] == '0' && name[1] == 'x') {
   1064 		name += 2;
   1065 	}
   1066 	(void) memset(&id_array, 0x0, sizeof(id_array));
   1067 	k = 0;
   1068 	*json = NULL;
   1069 	mj_create(&id_array, "array");
   1070 	do {
   1071 		key = pgp_getnextkeybyname(netpgp->io, netpgp->pubring,
   1072 						name, &k);
   1073 		if (key != NULL) {
   1074 			if (strcmp(fmt, "mr") == 0) {
   1075 				pgp_hkp_sprint_keydata(netpgp->io, netpgp->pubring,
   1076 						key, &newkey,
   1077 						&key->key.pubkey, 0);
   1078 				if (newkey) {
   1079 					printf("%s\n", newkey);
   1080 					free(newkey);
   1081 				}
   1082 			} else {
   1083 				ALLOC(mj_t, id_array.value.v, id_array.size,
   1084 					id_array.c, 10, 10, "netpgp_match_keys_json", return 0);
   1085 				pgp_sprint_mj(netpgp->io, netpgp->pubring,
   1086 						key, &id_array.value.v[id_array.c++],
   1087 						"signature",
   1088 						&key->key.pubkey, psigs);
   1089 			}
   1090 			k += 1;
   1091 		}
   1092 	} while (key != NULL);
   1093 	ret = mj_asprint(json, &id_array, MJ_JSON_ENCODE);
   1094 	mj_delete(&id_array);
   1095 	return ret;
   1096 }
   1097 
   1098 /* find and list some public keys in a keyring */
   1099 int
   1100 netpgp_match_pubkeys(netpgp_t *netpgp, char *name, void *vp)
   1101 {
   1102 	const pgp_key_t	*key;
   1103 	unsigned	 k;
   1104 	ssize_t		 cc;
   1105 	char		 out[1024 * 64];
   1106 	FILE		*fp = (FILE *)vp;
   1107 
   1108 	k = 0;
   1109 	do {
   1110 		key = pgp_getnextkeybyname(netpgp->io, netpgp->pubring,
   1111 						name, &k);
   1112 		if (key != NULL) {
   1113 			cc = pgp_sprint_pubkey(key, out, sizeof(out));
   1114 			(void) fprintf(fp, "%.*s", (int)cc, out);
   1115 			k += 1;
   1116 		}
   1117 	} while (key != NULL);
   1118 	return k;
   1119 }
   1120 
   1121 /* find a key in a keyring */
   1122 int
   1123 netpgp_find_key(netpgp_t *netpgp, char *id)
   1124 {
   1125 	pgp_io_t	*io;
   1126 
   1127 	io = netpgp->io;
   1128 	if (id == NULL) {
   1129 		(void) fprintf(io->errs, "NULL id to search for\n");
   1130 		return 0;
   1131 	}
   1132 	return pgp_getkeybyname(netpgp->io, netpgp->pubring, id) != NULL;
   1133 }
   1134 
   1135 /* get a key in a keyring */
   1136 char *
   1137 netpgp_get_key(netpgp_t *netpgp, const char *name, const char *fmt)
   1138 {
   1139 	const pgp_key_t	*key;
   1140 	char		*newkey;
   1141 
   1142 	if ((key = resolve_userid(netpgp, netpgp->pubring, name)) == NULL) {
   1143 		return NULL;
   1144 	}
   1145 	if (strcmp(fmt, "mr") == 0) {
   1146 		return (pgp_hkp_sprint_keydata(netpgp->io, netpgp->pubring,
   1147 				key, &newkey,
   1148 				&key->key.pubkey,
   1149 				netpgp_getvar(netpgp, "subkey sigs") != NULL) > 0) ? newkey : NULL;
   1150 	}
   1151 	return (pgp_sprint_keydata(netpgp->io, netpgp->pubring,
   1152 				key, &newkey, "signature",
   1153 				&key->key.pubkey,
   1154 				netpgp_getvar(netpgp, "subkey sigs") != NULL) > 0) ? newkey : NULL;
   1155 }
   1156 
   1157 /* export a given key */
   1158 char *
   1159 netpgp_export_key(netpgp_t *netpgp, char *name)
   1160 {
   1161 	const pgp_key_t	*key;
   1162 	pgp_io_t		*io;
   1163 
   1164 	io = netpgp->io;
   1165 	if ((key = resolve_userid(netpgp, netpgp->pubring, name)) == NULL) {
   1166 		return NULL;
   1167 	}
   1168 	return pgp_export_key(io, key, NULL);
   1169 }
   1170 
   1171 #define IMPORT_ARMOR_HEAD	"-----BEGIN PGP PUBLIC KEY BLOCK-----"
   1172 
   1173 /* import a key into our keyring */
   1174 int
   1175 netpgp_import_key(netpgp_t *netpgp, char *f)
   1176 {
   1177 	pgp_io_t	*io;
   1178 	unsigned	 realarmor;
   1179 	int		 done;
   1180 	pgp_keyring_t	*keyring;
   1181 	pgp_key_t	*key;
   1182 	const char	*ringname;
   1183 	int		 rv;
   1184 
   1185 	io = netpgp->io;
   1186 
   1187 	if (f == NULL) {
   1188 		(void) fprintf(io->errs, "No input file given\n");
   1189 		return 0;
   1190 	}
   1191 
   1192 	if ((keyring = calloc(1, sizeof(*keyring))) == NULL) {
   1193 		(void) fprintf(io->errs, "netpgp_import_key: bad alloc\n");
   1194 		return 0;
   1195 	}
   1196 
   1197 	realarmor = isarmoured(io, f, NULL, IMPORT_ARMOR_HEAD);
   1198 	done = pgp_keyring_fileread(keyring, realarmor, f);
   1199 	if (!done || keyring->keyc == 0) {
   1200 		(void) fprintf(io->errs, "Cannot import key from file %s\n", f);
   1201 		pgp_keyring_free(keyring);
   1202 		return 0;
   1203 	}
   1204 	done = pgp_keyring_list(io, keyring, 0);
   1205 	if (!done)
   1206 		return 0;
   1207 
   1208 	key = keyring->keys;
   1209 
   1210 	if (key->type == PGP_PTAG_CT_PUBLIC_KEY) {
   1211 		ringname = "pubring";
   1212 	} else {
   1213 		ringname = "secring";
   1214 	}
   1215 
   1216 	if (!done) {
   1217 		pgp_keyring_free(keyring);
   1218 		(void) fprintf(io->errs, "Bad append\n");
   1219 		return 0;
   1220 	}
   1221 
   1222 	rv = appendtokeyring(netpgp, ringname, key);
   1223 	pgp_keyring_free(keyring);
   1224 
   1225 	return rv;
   1226 }
   1227 
   1228 #define ID_OFFSET	38
   1229 
   1230 /* generate a new key */
   1231 int
   1232 netpgp_generate_key(netpgp_t *netpgp, char *id, int numbits)
   1233 {
   1234 	pgp_output_t		*create;
   1235 	const unsigned		 noarmor = 0;
   1236 	pgp_key_t		*key;
   1237 	pgp_io_t		*io;
   1238 	uint8_t			*uid;
   1239 	char			 passphrase[128];
   1240 	char			 newid[1024];
   1241 	char			 filename[MAXPATHLEN];
   1242 	char			 dir[MAXPATHLEN];
   1243 	char			*cp;
   1244 	char			*ringfile;
   1245 	char			*numtries;
   1246 	int             	 attempts;
   1247 	int             	 passc;
   1248 	int             	 fd;
   1249 	int             	 cc;
   1250 	int			 rv = 0;
   1251 
   1252 	uid = NULL;
   1253 	io = netpgp->io;
   1254 	/* generate a new key */
   1255 	if (id) {
   1256 		(void) snprintf(newid, sizeof(newid), "%s", id);
   1257 	} else {
   1258 		(void) snprintf(newid, sizeof(newid),
   1259 			"RSA %d-bit key <%s@localhost>", numbits, getenv("LOGNAME"));
   1260 	}
   1261 	uid = (uint8_t *)newid;
   1262 	key = pgp_rsa_new_selfsign_key(numbits, 65537UL, uid,
   1263 			netpgp_getvar(netpgp, "hash"),
   1264 			netpgp_getvar(netpgp, "cipher"));
   1265 	if (key == NULL) {
   1266 		(void) fprintf(io->errs, "Cannot generate key\n");
   1267 		return 0;
   1268 	}
   1269 	cp = NULL;
   1270 	pgp_sprint_keydata(netpgp->io, NULL, key, &cp, "signature ", &key->key.seckey.pubkey, 0);
   1271 	(void) fprintf(stdout, "%s", cp);
   1272 	/* write public key */
   1273 	cc = snprintf(dir, sizeof(dir), "%s/%.16s", netpgp_getvar(netpgp, "homedir"), &cp[ID_OFFSET]);
   1274 	netpgp_setvar(netpgp, "generated userid", &dir[cc - 16]);
   1275 	if (mkdir(dir, 0700) < 0) {
   1276 		(void) fprintf(io->errs, "can't mkdir '%s'\n", dir);
   1277 		goto out;
   1278 	}
   1279 	(void) fprintf(io->errs, "netpgp: generated keys in directory %s\n", dir);
   1280 	(void) snprintf(ringfile = filename, sizeof(filename), "%s/pubring.gpg", dir);
   1281 	if (!appendkey(io, key, ringfile)) {
   1282 		(void) fprintf(io->errs, "Cannot write pubkey to '%s'\n", ringfile);
   1283 		goto out;
   1284 	}
   1285 	if (netpgp->pubring != NULL) {
   1286 		pgp_keyring_free(netpgp->pubring);
   1287 	}
   1288 	/* write secret key */
   1289 	(void) snprintf(ringfile = filename, sizeof(filename), "%s/secring.gpg", dir);
   1290 	if ((fd = pgp_setup_file_append(&create, ringfile)) < 0) {
   1291 		fd = pgp_setup_file_write(&create, ringfile, 0);
   1292 	}
   1293 	if (fd < 0) {
   1294 		(void) fprintf(io->errs, "can't append secring '%s'\n", ringfile);
   1295 		goto out;
   1296 	}
   1297 	/* get the passphrase */
   1298 	if ((numtries = netpgp_getvar(netpgp, "numtries")) == NULL ||
   1299 	    (attempts = atoi(numtries)) <= 0) {
   1300 		attempts = MAX_PASSPHRASE_ATTEMPTS;
   1301 	} else if (strcmp(numtries, "unlimited") == 0) {
   1302 		attempts = INFINITE_ATTEMPTS;
   1303 	}
   1304 	passc = find_passphrase(netpgp->passfp, &cp[ID_OFFSET], passphrase, sizeof(passphrase), attempts);
   1305 	if (!pgp_write_xfer_seckey(create, key, (uint8_t *)passphrase, (const unsigned)passc, noarmor)) {
   1306 		(void) fprintf(io->errs, "Cannot write seckey\n");
   1307 		goto out1;
   1308 	}
   1309 	rv = 1;
   1310 out1:
   1311 	pgp_teardown_file_write(create, fd);
   1312 	if (netpgp->secring != NULL) {
   1313 		pgp_keyring_free(netpgp->secring);
   1314 	}
   1315 out:
   1316 	pgp_keydata_free(key);
   1317 	free(cp);
   1318 	return rv;
   1319 }
   1320 
   1321 /* encrypt a file */
   1322 int
   1323 netpgp_encrypt_file(netpgp_t *netpgp,
   1324 			const char *userid,
   1325 			const char *f,
   1326 			char *out,
   1327 			int armored)
   1328 {
   1329 	const pgp_key_t	*key;
   1330 	const unsigned		 overwrite = 1;
   1331 	const char		*suffix;
   1332 	pgp_io_t		*io;
   1333 	char			 outname[MAXPATHLEN];
   1334 
   1335 	io = netpgp->io;
   1336 	if (f == NULL) {
   1337 		(void) fprintf(io->errs,
   1338 			"netpgp_encrypt_file: no filename specified\n");
   1339 		return 0;
   1340 	}
   1341 	suffix = (armored) ? ".asc" : ".gpg";
   1342 	/* get key with which to sign */
   1343 	if ((key = resolve_userid(netpgp, netpgp->pubring, userid)) == NULL) {
   1344 		return 0;
   1345 	}
   1346 	if (out == NULL) {
   1347 		(void) snprintf(outname, sizeof(outname), "%s%s", f, suffix);
   1348 		out = outname;
   1349 	}
   1350 	return (int)pgp_encrypt_file(io, f, out, key, (unsigned)armored,
   1351 				overwrite, netpgp_getvar(netpgp, "cipher"));
   1352 }
   1353 
   1354 #define ARMOR_HEAD	"-----BEGIN PGP MESSAGE-----"
   1355 
   1356 /* decrypt a file */
   1357 int
   1358 netpgp_decrypt_file(netpgp_t *netpgp, const char *f, char *out, int armored)
   1359 {
   1360 	const unsigned	 overwrite = 1;
   1361 	pgp_io_t	*io;
   1362 	unsigned	 realarmor;
   1363 	unsigned	 sshkeys;
   1364 	char		*numtries;
   1365 	int            	 attempts;
   1366 
   1367 	__PGP_USED(armored);
   1368 	io = netpgp->io;
   1369 	if (f == NULL) {
   1370 		(void) fprintf(io->errs,
   1371 			"netpgp_decrypt_file: no filename specified\n");
   1372 		return 0;
   1373 	}
   1374 	realarmor = isarmoured(io, f, NULL, ARMOR_HEAD);
   1375 	sshkeys = (unsigned)(netpgp_getvar(netpgp, "ssh keys") != NULL);
   1376 	if ((numtries = netpgp_getvar(netpgp, "numtries")) == NULL ||
   1377 	    (attempts = atoi(numtries)) <= 0) {
   1378 		attempts = MAX_PASSPHRASE_ATTEMPTS;
   1379 	} else if (strcmp(numtries, "unlimited") == 0) {
   1380 		attempts = INFINITE_ATTEMPTS;
   1381 	}
   1382 	return pgp_decrypt_file(netpgp->io, f, out, netpgp->secring,
   1383 				netpgp->pubring,
   1384 				realarmor, overwrite, sshkeys,
   1385 				netpgp->passfp, attempts, get_passphrase_cb);
   1386 }
   1387 
   1388 /* sign a file */
   1389 int
   1390 netpgp_sign_file(netpgp_t *netpgp,
   1391 		const char *userid,
   1392 		const char *f,
   1393 		char *out,
   1394 		int armored,
   1395 		int cleartext,
   1396 		int detached)
   1397 {
   1398 	const pgp_key_t		*keypair;
   1399 	const pgp_key_t		*pubkey;
   1400 	const unsigned		 overwrite = 1;
   1401 	pgp_seckey_t		*seckey;
   1402 	const char		*hashalg;
   1403 	pgp_io_t		*io;
   1404 	char			*numtries;
   1405 	int			 attempts;
   1406 	int			 ret;
   1407 	int			 i;
   1408 
   1409 	io = netpgp->io;
   1410 	if (f == NULL) {
   1411 		(void) fprintf(io->errs,
   1412 			"netpgp_sign_file: no filename specified\n");
   1413 		return 0;
   1414 	}
   1415 	/* get key with which to sign */
   1416 	if ((keypair = resolve_userid(netpgp, netpgp->secring, userid)) == NULL) {
   1417 		return 0;
   1418 	}
   1419 	ret = 1;
   1420 	if ((numtries = netpgp_getvar(netpgp, "numtries")) == NULL ||
   1421 	    (attempts = atoi(numtries)) <= 0) {
   1422 		attempts = MAX_PASSPHRASE_ATTEMPTS;
   1423 	} else if (strcmp(numtries, "unlimited") == 0) {
   1424 		attempts = INFINITE_ATTEMPTS;
   1425 	}
   1426 	for (i = 0, seckey = NULL ; !seckey && (i < attempts || attempts == INFINITE_ATTEMPTS) ; i++) {
   1427 		if (netpgp->passfp == NULL) {
   1428 			/* print out the user id */
   1429 			pubkey = pgp_getkeybyname(io, netpgp->pubring, userid);
   1430 			if (pubkey == NULL) {
   1431 				(void) fprintf(io->errs,
   1432 					"netpgp: warning - using pubkey from secring\n");
   1433 				pgp_print_keydata(io, netpgp->pubring, keypair, "signature ",
   1434 					&keypair->key.seckey.pubkey, 0);
   1435 			} else {
   1436 				pgp_print_keydata(io, netpgp->pubring, pubkey, "signature ",
   1437 					&pubkey->key.pubkey, 0);
   1438 			}
   1439 		}
   1440 		if (netpgp_getvar(netpgp, "ssh keys") == NULL) {
   1441 			/* now decrypt key */
   1442 			seckey = pgp_decrypt_seckey(keypair, netpgp->passfp);
   1443 			if (seckey == NULL) {
   1444 				(void) fprintf(io->errs, "Bad passphrase\n");
   1445 			}
   1446 		} else {
   1447 			pgp_keyring_t	*secring;
   1448 
   1449 			secring = netpgp->secring;
   1450 			seckey = &secring->keys[0].key.seckey;
   1451 		}
   1452 	}
   1453 	if (seckey == NULL) {
   1454 		(void) fprintf(io->errs, "Bad passphrase\n");
   1455 		return 0;
   1456 	}
   1457 	/* sign file */
   1458 	hashalg = netpgp_getvar(netpgp, "hash");
   1459 	if (seckey->pubkey.alg == PGP_PKA_DSA) {
   1460 		hashalg = "sha1";
   1461 	}
   1462 	if (detached) {
   1463 		ret = pgp_sign_detached(io, f, out, seckey, hashalg,
   1464 				get_birthtime(netpgp_getvar(netpgp, "birthtime")),
   1465 				get_duration(netpgp_getvar(netpgp, "duration")),
   1466 				(unsigned)armored,
   1467 				overwrite);
   1468 	} else {
   1469 		ret = pgp_sign_file(io, f, out, seckey, hashalg,
   1470 				get_birthtime(netpgp_getvar(netpgp, "birthtime")),
   1471 				get_duration(netpgp_getvar(netpgp, "duration")),
   1472 				(unsigned)armored, (unsigned)cleartext,
   1473 				overwrite);
   1474 	}
   1475 	pgp_forget(seckey, sizeof(*seckey));
   1476 	return ret;
   1477 }
   1478 
   1479 #define ARMOR_SIG_HEAD	"-----BEGIN PGP (SIGNATURE|SIGNED MESSAGE)-----"
   1480 
   1481 /* verify a file */
   1482 int
   1483 netpgp_verify_file(netpgp_t *netpgp, const char *in, const char *out, int armored)
   1484 {
   1485 	pgp_validation_t	 result;
   1486 	pgp_io_t		*io;
   1487 	unsigned		 realarmor;
   1488 
   1489 	__PGP_USED(armored);
   1490 	(void) memset(&result, 0x0, sizeof(result));
   1491 	io = netpgp->io;
   1492 	if (in == NULL) {
   1493 		(void) fprintf(io->errs,
   1494 			"netpgp_verify_file: no filename specified\n");
   1495 		return 0;
   1496 	}
   1497 	realarmor = isarmoured(io, in, NULL, ARMOR_SIG_HEAD);
   1498 	if (pgp_validate_file(io, &result, in, out, (const int)realarmor, netpgp->pubring)) {
   1499 		resultp(io, in, &result, netpgp->pubring);
   1500 		return 1;
   1501 	}
   1502 	if (result.validc + result.invalidc + result.unknownc == 0) {
   1503 		(void) fprintf(io->errs,
   1504 		"\"%s\": No signatures found - is this a signed file?\n",
   1505 			in);
   1506 	} else if (result.invalidc == 0 && result.unknownc == 0) {
   1507 		(void) fprintf(io->errs,
   1508 			"\"%s\": file verification failure: invalid signature time\n", in);
   1509 	} else {
   1510 		(void) fprintf(io->errs,
   1511 "\"%s\": verification failure: %u invalid signatures, %u unknown signatures\n",
   1512 			in, result.invalidc, result.unknownc);
   1513 	}
   1514 	return 0;
   1515 }
   1516 
   1517 /* sign some memory */
   1518 int
   1519 netpgp_sign_memory(netpgp_t *netpgp,
   1520 		const char *userid,
   1521 		char *mem,
   1522 		size_t size,
   1523 		char *out,
   1524 		size_t outsize,
   1525 		const unsigned armored,
   1526 		const unsigned cleartext)
   1527 {
   1528 	const pgp_key_t		*keypair;
   1529 	const pgp_key_t		*pubkey;
   1530 	pgp_seckey_t		*seckey;
   1531 	pgp_memory_t		*signedmem;
   1532 	const char		*hashalg;
   1533 	pgp_io_t		*io;
   1534 	char 			*numtries;
   1535 	int			 attempts;
   1536 	int			 ret;
   1537 	int			 i;
   1538 
   1539 	io = netpgp->io;
   1540 	if (mem == NULL) {
   1541 		(void) fprintf(io->errs,
   1542 			"netpgp_sign_memory: no memory to sign\n");
   1543 		return 0;
   1544 	}
   1545 	if ((keypair = resolve_userid(netpgp, netpgp->secring, userid)) == NULL) {
   1546 		return 0;
   1547 	}
   1548 	ret = 1;
   1549 	if ((numtries = netpgp_getvar(netpgp, "numtries")) == NULL ||
   1550 	    (attempts = atoi(numtries)) <= 0) {
   1551 		attempts = MAX_PASSPHRASE_ATTEMPTS;
   1552 	} else if (strcmp(numtries, "unlimited") == 0) {
   1553 		attempts = INFINITE_ATTEMPTS;
   1554 	}
   1555 	for (i = 0, seckey = NULL ; !seckey && (i < attempts || attempts == INFINITE_ATTEMPTS) ; i++) {
   1556 		if (netpgp->passfp == NULL) {
   1557 			/* print out the user id */
   1558 			pubkey = pgp_getkeybyname(io, netpgp->pubring, userid);
   1559 			if (pubkey == NULL) {
   1560 				(void) fprintf(io->errs,
   1561 					"netpgp: warning - using pubkey from secring\n");
   1562 				pgp_print_keydata(io, netpgp->pubring, keypair, "signature ",
   1563 					&keypair->key.seckey.pubkey, 0);
   1564 			} else {
   1565 				pgp_print_keydata(io, netpgp->pubring, pubkey, "signature ",
   1566 					&pubkey->key.pubkey, 0);
   1567 			}
   1568 		}
   1569 		if (netpgp_getvar(netpgp, "ssh keys") == NULL) {
   1570 			/* now decrypt key */
   1571 			seckey = pgp_decrypt_seckey(keypair, netpgp->passfp);
   1572 			if (seckey == NULL) {
   1573 				(void) fprintf(io->errs, "Bad passphrase\n");
   1574 			}
   1575 		} else {
   1576 			pgp_keyring_t	*secring;
   1577 
   1578 			secring = netpgp->secring;
   1579 			seckey = &secring->keys[0].key.seckey;
   1580 		}
   1581 	}
   1582 	if (seckey == NULL) {
   1583 		(void) fprintf(io->errs, "Bad passphrase\n");
   1584 		return 0;
   1585 	}
   1586 	/* sign file */
   1587 	(void) memset(out, 0x0, outsize);
   1588 	hashalg = netpgp_getvar(netpgp, "hash");
   1589 	if (seckey->pubkey.alg == PGP_PKA_DSA) {
   1590 		hashalg = "sha1";
   1591 	}
   1592 	signedmem = pgp_sign_buf(io, mem, size, seckey,
   1593 				get_birthtime(netpgp_getvar(netpgp, "birthtime")),
   1594 				get_duration(netpgp_getvar(netpgp, "duration")),
   1595 				hashalg, armored, cleartext);
   1596 	if (signedmem) {
   1597 		size_t	m;
   1598 
   1599 		m = MIN(pgp_mem_len(signedmem), outsize);
   1600 		(void) memcpy(out, pgp_mem_data(signedmem), m);
   1601 		pgp_memory_free(signedmem);
   1602 		ret = (int)m;
   1603 	} else {
   1604 		ret = 0;
   1605 	}
   1606 	pgp_forget(seckey, sizeof(*seckey));
   1607 	return ret;
   1608 }
   1609 
   1610 /* verify memory */
   1611 int
   1612 netpgp_verify_memory(netpgp_t *netpgp, const void *in, const size_t size,
   1613 			void *out, size_t outsize, const int armored)
   1614 {
   1615 	pgp_validation_t	 result;
   1616 	pgp_memory_t		*signedmem;
   1617 	pgp_memory_t		*cat;
   1618 	pgp_io_t		*io;
   1619 	size_t			 m;
   1620 	int			 ret;
   1621 
   1622 	(void) memset(&result, 0x0, sizeof(result));
   1623 	io = netpgp->io;
   1624 	if (in == NULL) {
   1625 		(void) fprintf(io->errs,
   1626 			"netpgp_verify_memory: no memory to verify\n");
   1627 		return 0;
   1628 	}
   1629 	signedmem = pgp_memory_new();
   1630 	pgp_memory_add(signedmem, in, size);
   1631 	if (out) {
   1632 		cat = pgp_memory_new();
   1633 	}
   1634 	ret = pgp_validate_mem(io, &result, signedmem,
   1635 				(out) ? &cat : NULL,
   1636 				armored, netpgp->pubring);
   1637 	/* signedmem is freed from pgp_validate_mem */
   1638 	if (ret) {
   1639 		resultp(io, "<stdin>", &result, netpgp->pubring);
   1640 		if (out) {
   1641 			m = MIN(pgp_mem_len(cat), outsize);
   1642 			(void) memcpy(out, pgp_mem_data(cat), m);
   1643 			pgp_memory_free(cat);
   1644 		} else {
   1645 			m = 1;
   1646 		}
   1647 		return (int)m;
   1648 	}
   1649 	if (result.validc + result.invalidc + result.unknownc == 0) {
   1650 		(void) fprintf(io->errs,
   1651 		"No signatures found - is this memory signed?\n");
   1652 	} else if (result.invalidc == 0 && result.unknownc == 0) {
   1653 		(void) fprintf(io->errs,
   1654 			"memory verification failure: invalid signature time\n");
   1655 	} else {
   1656 		(void) fprintf(io->errs,
   1657 "memory verification failure: %u invalid signatures, %u unknown signatures\n",
   1658 			result.invalidc, result.unknownc);
   1659 	}
   1660 	return 0;
   1661 }
   1662 
   1663 /* encrypt some memory */
   1664 int
   1665 netpgp_encrypt_memory(netpgp_t *netpgp,
   1666 			const char *userid,
   1667 			void *in,
   1668 			const size_t insize,
   1669 			char *out,
   1670 			size_t outsize,
   1671 			int armored)
   1672 {
   1673 	const pgp_key_t	*keypair;
   1674 	pgp_memory_t	*enc;
   1675 	pgp_io_t	*io;
   1676 	size_t		 m;
   1677 
   1678 	io = netpgp->io;
   1679 	if (in == NULL) {
   1680 		(void) fprintf(io->errs,
   1681 			"netpgp_encrypt_buf: no memory to encrypt\n");
   1682 		return 0;
   1683 	}
   1684 	if ((keypair = resolve_userid(netpgp, netpgp->pubring, userid)) == NULL) {
   1685 		return 0;
   1686 	}
   1687 	if (in == out) {
   1688 		(void) fprintf(io->errs,
   1689 			"netpgp_encrypt_buf: input and output bufs need to be different\n");
   1690 		return 0;
   1691 	}
   1692 	if (outsize < insize) {
   1693 		(void) fprintf(io->errs,
   1694 			"netpgp_encrypt_buf: input size is larger than output size\n");
   1695 		return 0;
   1696 	}
   1697 	enc = pgp_encrypt_buf(io, in, insize, keypair, (unsigned)armored,
   1698 				netpgp_getvar(netpgp, "cipher"));
   1699 	m = MIN(pgp_mem_len(enc), outsize);
   1700 	(void) memcpy(out, pgp_mem_data(enc), m);
   1701 	pgp_memory_free(enc);
   1702 	return (int)m;
   1703 }
   1704 
   1705 /* decrypt a chunk of memory */
   1706 int
   1707 netpgp_decrypt_memory(netpgp_t *netpgp, const void *input, const size_t insize,
   1708 			char *out, size_t outsize, const int armored)
   1709 {
   1710 	pgp_memory_t	*mem;
   1711 	pgp_io_t	*io;
   1712 	unsigned	 realarmour;
   1713 	unsigned	 sshkeys;
   1714 	size_t		 m;
   1715 	char		*numtries;
   1716 	int            	 attempts;
   1717 
   1718 	__PGP_USED(armored);
   1719 	io = netpgp->io;
   1720 	if (input == NULL) {
   1721 		(void) fprintf(io->errs,
   1722 			"netpgp_decrypt_memory: no memory\n");
   1723 		return 0;
   1724 	}
   1725 	realarmour = isarmoured(io, NULL, input, ARMOR_HEAD);
   1726 	sshkeys = (unsigned)(netpgp_getvar(netpgp, "ssh keys") != NULL);
   1727 	if ((numtries = netpgp_getvar(netpgp, "numtries")) == NULL ||
   1728 	    (attempts = atoi(numtries)) <= 0) {
   1729 		attempts = MAX_PASSPHRASE_ATTEMPTS;
   1730 	} else if (strcmp(numtries, "unlimited") == 0) {
   1731 		attempts = INFINITE_ATTEMPTS;
   1732 	}
   1733 	mem = pgp_decrypt_buf(netpgp->io, input, insize, netpgp->secring,
   1734 				netpgp->pubring,
   1735 				realarmour, sshkeys,
   1736 				netpgp->passfp,
   1737 				attempts,
   1738 				get_passphrase_cb);
   1739 	if (mem == NULL) {
   1740 		return -1;
   1741 	}
   1742 	m = MIN(pgp_mem_len(mem), outsize);
   1743 	(void) memcpy(out, pgp_mem_data(mem), m);
   1744 	pgp_memory_free(mem);
   1745 	return (int)m;
   1746 }
   1747 
   1748 /* wrappers for the ops_debug_level functions we added to openpgpsdk */
   1749 
   1750 /* set the debugging level per filename */
   1751 int
   1752 netpgp_set_debug(const char *f)
   1753 {
   1754 	return pgp_set_debug_level(f);
   1755 }
   1756 
   1757 /* get the debugging level per filename */
   1758 int
   1759 netpgp_get_debug(const char *f)
   1760 {
   1761 	return pgp_get_debug_level(f);
   1762 }
   1763 
   1764 /* return the version for the library */
   1765 const char *
   1766 netpgp_get_info(const char *type)
   1767 {
   1768 	return pgp_get_info(type);
   1769 }
   1770 
   1771 /* list all the packets in a file */
   1772 int
   1773 netpgp_list_packets(netpgp_t *netpgp, char *f, int armor, char *pubringname)
   1774 {
   1775 	pgp_keyring_t	*keyring;
   1776 	const unsigned	 noarmor = 0;
   1777 	struct stat	 st;
   1778 	pgp_io_t	*io;
   1779 	char		 ringname[MAXPATHLEN];
   1780 	char		*homedir;
   1781 	int		 ret;
   1782 
   1783 	io = netpgp->io;
   1784 	if (f == NULL) {
   1785 		(void) fprintf(io->errs, "No file containing packets\n");
   1786 		return 0;
   1787 	}
   1788 	if (stat(f, &st) < 0) {
   1789 		(void) fprintf(io->errs, "No such file '%s'\n", f);
   1790 		return 0;
   1791 	}
   1792 	homedir = netpgp_getvar(netpgp, "homedir");
   1793 	if (pubringname == NULL) {
   1794 		(void) snprintf(ringname, sizeof(ringname),
   1795 				"%s/pubring.gpg", homedir);
   1796 		pubringname = ringname;
   1797 	}
   1798 	if ((keyring = calloc(1, sizeof(*keyring))) == NULL) {
   1799 		(void) fprintf(io->errs, "netpgp_list_packets: bad alloc\n");
   1800 		return 0;
   1801 	}
   1802 	if (!pgp_keyring_fileread(keyring, noarmor, pubringname)) {
   1803 		free(keyring);
   1804 		(void) fprintf(io->errs, "Cannot read pub keyring %s\n",
   1805 			pubringname);
   1806 		return 0;
   1807 	}
   1808 	netpgp->pubring = keyring;
   1809 	netpgp_setvar(netpgp, "pubring", pubringname);
   1810 	ret = pgp_list_packets(io, f, (unsigned)armor,
   1811 					netpgp->secring,
   1812 					netpgp->pubring,
   1813 					netpgp->passfp,
   1814 					get_passphrase_cb);
   1815 	free(keyring);
   1816 	return ret;
   1817 }
   1818 
   1819 /* set a variable */
   1820 int
   1821 netpgp_setvar(netpgp_t *netpgp, const char *name, const char *value)
   1822 {
   1823 	char	*newval;
   1824 	int	 i;
   1825 
   1826 	/* protect against the case where 'value' is netpgp->value[i] */
   1827 	newval = netpgp_strdup(value);
   1828 	if ((i = findvar(netpgp, name)) < 0) {
   1829 		/* add the element to the array */
   1830 		if (size_arrays(netpgp, netpgp->size + 15)) {
   1831 			netpgp->name[i = netpgp->c++] = netpgp_strdup(name);
   1832 		}
   1833 	} else {
   1834 		/* replace the element in the array */
   1835 		if (netpgp->value[i]) {
   1836 			free(netpgp->value[i]);
   1837 			netpgp->value[i] = NULL;
   1838 		}
   1839 	}
   1840 	/* sanity checks for range of values */
   1841 	if (strcmp(name, "hash") == 0 || strcmp(name, "algorithm") == 0) {
   1842 		if (pgp_str_to_hash_alg(newval) == PGP_HASH_UNKNOWN) {
   1843 			free(newval);
   1844 			return 0;
   1845 		}
   1846 	}
   1847 	netpgp->value[i] = newval;
   1848 	return 1;
   1849 }
   1850 
   1851 /* unset a variable */
   1852 int
   1853 netpgp_unsetvar(netpgp_t *netpgp, const char *name)
   1854 {
   1855 	int	i;
   1856 
   1857 	if ((i = findvar(netpgp, name)) >= 0) {
   1858 		if (netpgp->value[i]) {
   1859 			free(netpgp->value[i]);
   1860 			netpgp->value[i] = NULL;
   1861 		}
   1862 		netpgp->value[i] = NULL;
   1863 		return 1;
   1864 	}
   1865 	return 0;
   1866 }
   1867 
   1868 /* get a variable's value (NULL if not set) */
   1869 char *
   1870 netpgp_getvar(netpgp_t *netpgp, const char *name)
   1871 {
   1872 	int	i;
   1873 
   1874 	return ((i = findvar(netpgp, name)) < 0) ? NULL : netpgp->value[i];
   1875 }
   1876 
   1877 /* increment a value */
   1878 int
   1879 netpgp_incvar(netpgp_t *netpgp, const char *name, const int delta)
   1880 {
   1881 	char	*cp;
   1882 	char	 num[16];
   1883 	int	 val;
   1884 
   1885 	val = 0;
   1886 	if ((cp = netpgp_getvar(netpgp, name)) != NULL) {
   1887 		val = atoi(cp);
   1888 	}
   1889 	(void) snprintf(num, sizeof(num), "%d", val + delta);
   1890 	netpgp_setvar(netpgp, name, num);
   1891 	return 1;
   1892 }
   1893 
   1894 /* set the home directory value to "home/subdir" */
   1895 int
   1896 netpgp_set_homedir(netpgp_t *netpgp, char *home, const char *subdir, const int quiet)
   1897 {
   1898 	struct stat	st;
   1899 	char		d[MAXPATHLEN];
   1900 
   1901 	if (home == NULL) {
   1902 		if (!quiet) {
   1903 			(void) fprintf(stderr, "NULL HOME directory\n");
   1904 		}
   1905 		return 0;
   1906 	}
   1907 	(void) snprintf(d, sizeof(d), "%s%s", home, (subdir) ? subdir : "");
   1908 	if (stat(d, &st) == 0) {
   1909 		if ((st.st_mode & S_IFMT) == S_IFDIR) {
   1910 			netpgp_setvar(netpgp, "homedir", d);
   1911 			return 1;
   1912 		}
   1913 		(void) fprintf(stderr, "netpgp: homedir \"%s\" is not a dir\n",
   1914 					d);
   1915 		return 0;
   1916 	}
   1917 	if (!quiet) {
   1918 		(void) fprintf(stderr,
   1919 			"netpgp: warning homedir \"%s\" not found\n", d);
   1920 	}
   1921 	netpgp_setvar(netpgp, "homedir", d);
   1922 	return 1;
   1923 }
   1924 
   1925 /* validate all sigs in the pub keyring */
   1926 int
   1927 netpgp_validate_sigs(netpgp_t *netpgp)
   1928 {
   1929 	pgp_validation_t	result;
   1930 
   1931 	return (int)pgp_validate_all_sigs(&result, netpgp->pubring, NULL);
   1932 }
   1933 
   1934 /* print the json out on 'fp' */
   1935 int
   1936 netpgp_format_json(void *vp, const char *json, const int psigs)
   1937 {
   1938 	mj_t	 ids;
   1939 	FILE	*fp;
   1940 	int	 from;
   1941 	int	 idc;
   1942 	int	 tok;
   1943 	int	 to;
   1944 	int	 i;
   1945 
   1946 	if ((fp = (FILE *)vp) == NULL || json == NULL) {
   1947 		return 0;
   1948 	}
   1949 	/* ids is an array of strings, each containing 1 entry */
   1950 	(void) memset(&ids, 0x0, sizeof(ids));
   1951 	from = to = tok = 0;
   1952 	/* convert from string into an mj structure */
   1953 	(void) mj_parse(&ids, json, &from, &to, &tok);
   1954 	if ((idc = mj_arraycount(&ids)) == 1 && strchr(json, '{') == NULL) {
   1955 		idc = 0;
   1956 	}
   1957 	(void) fprintf(fp, "%d key%s found\n", idc, (idc == 1) ? "" : "s");
   1958 	for (i = 0 ; i < idc ; i++) {
   1959 		format_json_key(fp, &ids.value.v[i], psigs);
   1960 	}
   1961 	/* clean up */
   1962 	mj_delete(&ids);
   1963 	return idc;
   1964 }
   1965 
   1966 /* find a key in keyring, and write it in ssh format */
   1967 int
   1968 netpgp_write_sshkey(netpgp_t *netpgp, char *s, const char *userid, char *out, size_t size)
   1969 {
   1970 	const pgp_key_t	*key;
   1971 	pgp_keyring_t	*keyring;
   1972 	pgp_io_t	*io;
   1973 	unsigned	 k;
   1974 	size_t		 cc;
   1975 	char		 f[MAXPATHLEN];
   1976 
   1977 	keyring = NULL;
   1978 	io = NULL;
   1979 	cc = 0;
   1980 	if ((io = calloc(1, sizeof(pgp_io_t))) == NULL) {
   1981 		(void) fprintf(stderr, "netpgp_save_sshpub: bad alloc 1\n");
   1982 		goto done;
   1983 	}
   1984 	io->outs = stdout;
   1985 	io->errs = stderr;
   1986 	io->res = stderr;
   1987 	netpgp->io = io;
   1988 	/* write new to temp file */
   1989 	savepubkey(s, f, sizeof(f));
   1990 	if ((keyring = calloc(1, sizeof(*keyring))) == NULL) {
   1991 		(void) fprintf(stderr, "netpgp_save_sshpub: bad alloc 2\n");
   1992 		goto done;
   1993 	}
   1994 	if (!pgp_keyring_fileread(netpgp->pubring = keyring, 1, f)) {
   1995 		(void) fprintf(stderr, "can't import key\n");
   1996 		goto done;
   1997 	}
   1998 	/* get rsa key */
   1999 	k = 0;
   2000 	key = pgp_getnextkeybyname(netpgp->io, netpgp->pubring, userid, &k);
   2001 	if (key == NULL) {
   2002 		(void) fprintf(stderr, "no key found for '%s'\n", userid);
   2003 		goto done;
   2004 	}
   2005 	if (key->key.pubkey.alg != PGP_PKA_RSA) {
   2006 		/* we're not interested in supporting DSA either :-) */
   2007 		(void) fprintf(stderr, "key not RSA '%s'\n", userid);
   2008 		goto done;
   2009 	}
   2010 	/* XXX - check trust sigs */
   2011 	/* XXX - check expiry */
   2012 	/* XXX - check start */
   2013 	/* XXX - check not weak key */
   2014 	/* get rsa e and n */
   2015 	(void) memset(out, 0x0, size);
   2016 	cc = formatstring((char *)out, (const uint8_t *)"ssh-rsa", 7);
   2017 	cc += formatbignum((char *)&out[cc], key->key.pubkey.key.rsa.e);
   2018 	cc += formatbignum((char *)&out[cc], key->key.pubkey.key.rsa.n);
   2019 done:
   2020 	if (io) {
   2021 		free(io);
   2022 	}
   2023 	if (keyring) {
   2024 		free(keyring);
   2025 	}
   2026 	return (int)cc;
   2027 }
   2028