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