xref: /netbsd-src/crypto/external/bsd/netpgp/dist/src/netpgpkeys/netpgpkeys.c (revision 5aae2c74b0a496add3697f16c824210c042d9148)
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 
30 /* Command line program to perform netpgp operations */
31 #include <sys/types.h>
32 #include <sys/param.h>
33 #include <sys/stat.h>
34 
35 #include <getopt.h>
36 #include <stdio.h>
37 #include <stdlib.h>
38 #include <string.h>
39 #include <unistd.h>
40 
41 #include <netpgp.h>
42 
43 /*
44  * 2048 is the absolute minimum, really - we should really look at
45  * bumping this to 4096 or even higher - agc, 20090522
46  */
47 #define DEFAULT_NUMBITS 2048
48 
49 static const char *usage =
50 	" --help OR\n"
51 	"\t--export-keys [options] OR\n"
52 	"\t--find-key [options] OR\n"
53 	"\t--generate-key [options] OR\n"
54 	"\t--import-key [options] OR\n"
55 	"\t--list-keys [options] OR\n"
56 	"\t--list-sigs [options] OR\n"
57 	"\t--get-key keyid [options] OR\n"
58 	"\t--version\n"
59 	"where options are:\n"
60 	"\t[--coredumps] AND/OR\n"
61 	"\t[--homedir=<homedir>] AND/OR\n"
62 	"\t[--keyring=<keyring>] AND/OR\n"
63 	"\t[--userid=<userid>] AND/OR\n"
64 	"\t[--verbose]\n";
65 
66 enum optdefs {
67 	/* commands */
68 	LIST_KEYS = 1,
69 	LIST_SIGS,
70 	FIND_KEY,
71 	EXPORT_KEY,
72 	IMPORT_KEY,
73 	GENERATE_KEY,
74 	VERSION_CMD,
75 	HELP_CMD,
76 	GET_KEY,
77 
78 	/* options */
79 	SSHKEYS,
80 	KEYRING,
81 	USERID,
82 	HOMEDIR,
83 	NUMBITS,
84 	VERBOSE,
85 	COREDUMPS,
86 	PASSWDFD,
87 	RESULTS,
88 	SSHKEYFILE,
89 
90 	/* debug */
91 	OPS_DEBUG
92 
93 };
94 
95 #define EXIT_ERROR	2
96 
97 static struct option options[] = {
98 	/* key-management commands */
99 	{"list-keys",	no_argument,		NULL,	LIST_KEYS},
100 	{"list-sigs",	no_argument,		NULL,	LIST_SIGS},
101 	{"find-key",	no_argument,		NULL,	FIND_KEY},
102 	{"export-key",	no_argument,		NULL,	EXPORT_KEY},
103 	{"import-key",	no_argument,		NULL,	IMPORT_KEY},
104 	{"generate-key", no_argument,		NULL,	GENERATE_KEY},
105 	{"get-key", 	no_argument,		NULL,	GET_KEY},
106 	/* debugging commands */
107 	{"help",	no_argument,		NULL,	HELP_CMD},
108 	{"version",	no_argument,		NULL,	VERSION_CMD},
109 	{"debug",	required_argument, 	NULL,	OPS_DEBUG},
110 	/* options */
111 	{"coredumps",	no_argument, 		NULL,	COREDUMPS},
112 	{"keyring",	required_argument, 	NULL,	KEYRING},
113 	{"userid",	required_argument, 	NULL,	USERID},
114 	{"home",	required_argument, 	NULL,	HOMEDIR},
115 	{"homedir",	required_argument, 	NULL,	HOMEDIR},
116 	{"numbits",	required_argument, 	NULL,	NUMBITS},
117 	{"ssh-keys",	no_argument, 		NULL,	SSHKEYS},
118 	{"sshkeyfile",	required_argument, 	NULL,	SSHKEYFILE},
119 	{"verbose",	no_argument, 		NULL,	VERBOSE},
120 	{"pass-fd",	required_argument, 	NULL,	PASSWDFD},
121 	{"results",	required_argument, 	NULL,	RESULTS},
122 	{ NULL,		0,			NULL,	0},
123 };
124 
125 /* gather up program variables into one struct */
126 typedef struct prog_t {
127 	char	 keyring[MAXPATHLEN + 1];	/* name of keyring */
128 	char	*progname;			/* program name */
129 	int	 numbits;			/* # of bits */
130 	int	 cmd;				/* netpgpkeys command */
131 } prog_t;
132 
133 
134 /* print a usage message */
135 static void
136 print_usage(const char *usagemsg, char *progname)
137 {
138 	(void) fprintf(stderr,
139 	"%s\nAll bug reports, praise and chocolate, please, to:\n%s\n",
140 				netpgp_get_info("version"),
141 				netpgp_get_info("maintainer"));
142 	(void) fprintf(stderr, "Usage: %s COMMAND OPTIONS:\n%s %s",
143 		progname, progname, usagemsg);
144 }
145 
146 /* do a command once for a specified file 'f' */
147 static int
148 netpgp_cmd(netpgp_t *netpgp, prog_t *p, char *f)
149 {
150 	char	*key;
151 
152 	switch (p->cmd) {
153 	case LIST_KEYS:
154 		return (f == NULL) ? netpgp_list_keys(netpgp, 0) : netpgp_match_keys(netpgp, f, "human", stdout, 0);
155 	case LIST_SIGS:
156 		return (f == NULL) ? netpgp_list_keys(netpgp, 1) : netpgp_match_keys(netpgp, f, "human", stdout, 1);
157 	case FIND_KEY:
158 		return netpgp_find_key(netpgp, netpgp_getvar(netpgp, "userid"));
159 	case EXPORT_KEY:
160 		key = netpgp_export_key(netpgp,
161 				netpgp_getvar(netpgp, "userid"));
162 		if (key) {
163 			printf("%s", key);
164 			return 1;
165 		}
166 		(void) fprintf(stderr, "key '%s' not found\n", f);
167 		return 0;
168 	case IMPORT_KEY:
169 		return netpgp_import_key(netpgp, f);
170 	case GENERATE_KEY:
171 		return netpgp_generate_key(netpgp,
172 				netpgp_getvar(netpgp, "userid"), p->numbits);
173 	case GET_KEY:
174 		key = netpgp_get_key(netpgp, f, "human");
175 		if (key) {
176 			printf("%s", key);
177 			return 1;
178 		}
179 		(void) fprintf(stderr, "key '%s' not found\n", f);
180 		return 0;
181 	case HELP_CMD:
182 	default:
183 		print_usage(usage, p->progname);
184 		exit(EXIT_SUCCESS);
185 	}
186 }
187 
188 int
189 main(int argc, char **argv)
190 {
191 	struct stat	st;
192 	netpgp_t	netpgp;
193 	prog_t          p;
194 	int             optindex;
195 	int             ret;
196 	int             ch;
197 	int             i;
198 
199 	(void) memset(&p, 0x0, sizeof(p));
200 	(void) memset(&netpgp, 0x0, sizeof(netpgp));
201 	p.progname = argv[0];
202 	p.numbits = DEFAULT_NUMBITS;
203 	if (argc < 2) {
204 		print_usage(usage, p.progname);
205 		exit(EXIT_ERROR);
206 	}
207 	/* set some defaults */
208 	netpgp_set_homedir(&netpgp, getenv("HOME"), "/.gnupg", 1);
209 	netpgp_setvar(&netpgp, "sshkeydir", "/etc/ssh");
210 	optindex = 0;
211 	while ((ch = getopt_long(argc, argv, "", options, &optindex)) != -1) {
212 		switch (options[optindex].val) {
213 		case COREDUMPS:
214 			netpgp_setvar(&netpgp, "coredumps", "allowed");
215 			p.cmd = options[optindex].val;
216 			break;
217 		case GENERATE_KEY:
218 			netpgp_setvar(&netpgp, "userid checks", "skip");
219 			p.cmd = options[optindex].val;
220 			break;
221 		case LIST_KEYS:
222 		case LIST_SIGS:
223 		case FIND_KEY:
224 		case EXPORT_KEY:
225 		case IMPORT_KEY:
226 		case GET_KEY:
227 		case HELP_CMD:
228 			p.cmd = options[optindex].val;
229 			break;
230 		case VERSION_CMD:
231 			printf(
232 "%s\nAll bug reports, praise and chocolate, please, to:\n%s\n",
233 				netpgp_get_info("version"),
234 				netpgp_get_info("maintainer"));
235 			exit(EXIT_SUCCESS);
236 			/* options */
237 		case SSHKEYS:
238 			netpgp_setvar(&netpgp, "ssh keys", "1");
239 			break;
240 		case KEYRING:
241 			if (optarg == NULL) {
242 				(void) fprintf(stderr,
243 					"%s: No keyring argument provided\n",
244 					*argv);
245 				exit(EXIT_ERROR);
246 			}
247 			snprintf(p.keyring, sizeof(p.keyring), "%s", optarg);
248 			break;
249 		case USERID:
250 			if (optarg == NULL) {
251 				(void) fprintf(stderr,
252 					"%s: no userid argument provided\n",
253 					*argv);
254 				exit(EXIT_ERROR);
255 			}
256 			netpgp_setvar(&netpgp, "userid", optarg);
257 			break;
258 		case VERBOSE:
259 			netpgp_incvar(&netpgp, "verbose", 1);
260 			break;
261 		case HOMEDIR:
262 			if (optarg == NULL) {
263 				(void) fprintf(stderr,
264 				"%s: no home directory argument provided\n",
265 				*argv);
266 				exit(EXIT_ERROR);
267 			}
268 			netpgp_set_homedir(&netpgp, optarg, NULL, 0);
269 			break;
270 		case NUMBITS:
271 			if (optarg == NULL) {
272 				(void) fprintf(stderr,
273 				"%s: no number of bits argument provided\n",
274 				*argv);
275 				exit(EXIT_ERROR);
276 			}
277 			p.numbits = atoi(optarg);
278 			break;
279 		case PASSWDFD:
280 			if (optarg == NULL) {
281 				(void) fprintf(stderr,
282 				"%s: no pass-fd argument provided\n", *argv);
283 				exit(EXIT_ERROR);
284 			}
285 			netpgp_setvar(&netpgp, "pass-fd", optarg);
286 			break;
287 		case RESULTS:
288 			if (optarg == NULL) {
289 				(void) fprintf(stderr,
290 				"No output filename argument provided\n");
291 				exit(EXIT_ERROR);
292 			}
293 			netpgp_setvar(&netpgp, "results", optarg);
294 			break;
295 		case SSHKEYFILE:
296 			netpgp_setvar(&netpgp, "sshkeyfile", optarg);
297 			break;
298 		case OPS_DEBUG:
299 			netpgp_set_debug(optarg);
300 			break;
301 		default:
302 			p.cmd = HELP_CMD;
303 			break;
304 		}
305 	}
306 	/* initialise, and read keys from file */
307 	if (!netpgp_init(&netpgp)) {
308 		if (stat(netpgp_getvar(&netpgp, "homedir"), &st) < 0 &&
309 		    mkdir("homedir", 0700) < 0) {
310 			(void) fprintf(stderr, "can't create home directory '%s'\n",
311 				netpgp_getvar(&netpgp, "homedir"));
312 			exit(EXIT_ERROR);
313 		}
314 	}
315 	/* now do the required action for each of the command line args */
316 	ret = EXIT_SUCCESS;
317 	if (optind == argc) {
318 		if (!netpgp_cmd(&netpgp, &p, NULL)) {
319 			ret = EXIT_FAILURE;
320 		}
321 	} else {
322 		for (i = optind; i < argc; i++) {
323 			if (!netpgp_cmd(&netpgp, &p, argv[i])) {
324 				ret = EXIT_FAILURE;
325 			}
326 		}
327 	}
328 	netpgp_end(&netpgp);
329 	exit(ret);
330 }
331