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