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