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