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