1 /* $NetBSD: ddns-confgen.c,v 1.8 2014/12/10 04:37:51 christos Exp $ */ 2 3 /* 4 * Copyright (C) 2009, 2011, 2014 Internet Systems Consortium, Inc. ("ISC") 5 * 6 * Permission to use, copy, modify, and/or distribute this software for any 7 * purpose with or without fee is hereby granted, provided that the above 8 * copyright notice and this permission notice appear in all copies. 9 * 10 * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH 11 * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY 12 * AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT, 13 * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM 14 * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE 15 * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR 16 * PERFORMANCE OF THIS SOFTWARE. 17 */ 18 19 /*! \file */ 20 21 /** 22 * ddns-confgen generates configuration files for dynamic DNS. It can 23 * be used as a convenient alternative to writing the ddns.key file 24 * and the corresponding key and update-policy statements in named.conf. 25 */ 26 27 #include <config.h> 28 29 #include <stdlib.h> 30 #include <stdarg.h> 31 32 #include <isc/assertions.h> 33 #include <isc/base64.h> 34 #include <isc/buffer.h> 35 #include <isc/commandline.h> 36 #include <isc/entropy.h> 37 #include <isc/file.h> 38 #include <isc/keyboard.h> 39 #include <isc/mem.h> 40 #include <isc/net.h> 41 #include <isc/print.h> 42 #include <isc/result.h> 43 #include <isc/string.h> 44 #include <isc/time.h> 45 #include <isc/util.h> 46 47 #ifdef PKCS11CRYPTO 48 #include <pk11/result.h> 49 #endif 50 51 #include <dns/keyvalues.h> 52 #include <dns/name.h> 53 #include <dns/result.h> 54 55 #include <dst/dst.h> 56 #include <confgen/os.h> 57 58 #include "util.h" 59 #include "keygen.h" 60 61 #define KEYGEN_DEFAULT "tsig-key" 62 #define CONFGEN_DEFAULT "ddns-key" 63 64 static char program[256]; 65 const char *progname; 66 static enum { progmode_keygen, progmode_confgen} progmode; 67 isc_boolean_t verbose = ISC_FALSE; /* needed by util.c but not used here */ 68 69 ISC_PLATFORM_NORETURN_PRE static void 70 usage(int status) ISC_PLATFORM_NORETURN_POST; 71 72 static void 73 usage(int status) { 74 if (progmode == progmode_confgen) { 75 fprintf(stderr, "\ 76 Usage:\n\ 77 %s [-a alg] [-k keyname] [-r randomfile] [-q] [-s name | -z zone]\n\ 78 -a alg: algorithm (default hmac-sha256)\n\ 79 -k keyname: name of the key as it will be used in named.conf\n\ 80 -r randomfile: source of random data (use \"keyboard\" for key timing)\n\ 81 -s name: domain name to be updated using the created key\n\ 82 -z zone: name of the zone as it will be used in named.conf\n\ 83 -q: quiet mode: print the key, with no explanatory text\n", 84 progname); 85 } else { 86 fprintf(stderr, "\ 87 Usage:\n\ 88 %s [-a alg] [-r randomfile] [keyname]\n\ 89 -a alg: algorithm (default hmac-sha256)\n\ 90 -r randomfile: source of random data (use \"keyboard\" for key timing)\n", 91 progname); 92 } 93 94 exit (status); 95 } 96 97 int 98 main(int argc, char **argv) { 99 isc_result_t result = ISC_R_SUCCESS; 100 isc_boolean_t show_final_mem = ISC_FALSE; 101 isc_boolean_t quiet = ISC_FALSE; 102 isc_buffer_t key_txtbuffer; 103 char key_txtsecret[256]; 104 isc_mem_t *mctx = NULL; 105 const char *randomfile = NULL; 106 const char *keyname = NULL; 107 const char *zone = NULL; 108 const char *self_domain = NULL; 109 char *keybuf = NULL; 110 dns_secalg_t alg = DST_ALG_HMACSHA256; 111 const char *algname; 112 int keysize = 256; 113 int len = 0; 114 int ch; 115 116 #ifdef PKCS11CRYPTO 117 pk11_result_register(); 118 #endif 119 dns_result_register(); 120 121 result = isc_file_progname(*argv, program, sizeof(program)); 122 if (result != ISC_R_SUCCESS) 123 memmove(program, "tsig-keygen", 11); 124 progname = program; 125 126 /* 127 * Libtool doesn't preserve the program name prior to final 128 * installation. Remove the libtool prefix ("lt-"). 129 */ 130 if (strncmp(progname, "lt-", 3) == 0) 131 progname += 3; 132 133 #define PROGCMP(X) \ 134 (strcasecmp(progname, X) == 0 || strcasecmp(progname, X ".exe") == 0) 135 136 if (PROGCMP("tsig-keygen")) { 137 progmode = progmode_keygen; 138 quiet = ISC_TRUE; 139 } else if (PROGCMP("ddns-confgen")) 140 progmode = progmode_confgen; 141 else 142 INSIST(0); 143 144 isc_commandline_errprint = ISC_FALSE; 145 146 while ((ch = isc_commandline_parse(argc, argv, 147 "a:hk:Mmr:qs:y:z:")) != -1) { 148 switch (ch) { 149 case 'a': 150 algname = isc_commandline_argument; 151 alg = alg_fromtext(algname); 152 if (alg == DST_ALG_UNKNOWN) 153 fatal("Unsupported algorithm '%s'", algname); 154 keysize = alg_bits(alg); 155 break; 156 case 'h': 157 usage(0); 158 case 'k': 159 case 'y': 160 if (progmode == progmode_confgen) 161 keyname = isc_commandline_argument; 162 else 163 usage(1); 164 break; 165 case 'M': 166 isc_mem_debugging = ISC_MEM_DEBUGTRACE; 167 break; 168 case 'm': 169 show_final_mem = ISC_TRUE; 170 break; 171 case 'q': 172 if (progmode == progmode_confgen) 173 quiet = ISC_TRUE; 174 else 175 usage(1); 176 break; 177 case 'r': 178 randomfile = isc_commandline_argument; 179 break; 180 case 's': 181 if (progmode == progmode_confgen) 182 self_domain = isc_commandline_argument; 183 else 184 usage(1); 185 break; 186 case 'z': 187 if (progmode == progmode_confgen) 188 zone = isc_commandline_argument; 189 else 190 usage(1); 191 break; 192 case '?': 193 if (isc_commandline_option != '?') { 194 fprintf(stderr, "%s: invalid argument -%c\n", 195 program, isc_commandline_option); 196 usage(1); 197 } else 198 usage(0); 199 break; 200 default: 201 fprintf(stderr, "%s: unhandled option -%c\n", 202 program, isc_commandline_option); 203 exit(1); 204 } 205 } 206 207 if (progmode == progmode_keygen) 208 keyname = argv[isc_commandline_index++]; 209 210 POST(argv); 211 212 if (self_domain != NULL && zone != NULL) 213 usage(1); /* -s and -z cannot coexist */ 214 215 if (argc > isc_commandline_index) 216 usage(1); 217 218 /* Use canonical algorithm name */ 219 algname = alg_totext(alg); 220 221 DO("create memory context", isc_mem_create(0, 0, &mctx)); 222 223 if (keyname == NULL) { 224 const char *suffix = NULL; 225 226 keyname = ((progmode == progmode_keygen) 227 ? KEYGEN_DEFAULT 228 : CONFGEN_DEFAULT); 229 if (self_domain != NULL) 230 suffix = self_domain; 231 else if (zone != NULL) 232 suffix = zone; 233 if (suffix != NULL) { 234 len = strlen(keyname) + strlen(suffix) + 2; 235 keybuf = isc_mem_get(mctx, len); 236 if (keybuf == NULL) 237 fatal("failed to allocate memory for keyname"); 238 snprintf(keybuf, len, "%s.%s", keyname, suffix); 239 keyname = (const char *) keybuf; 240 } 241 } 242 243 isc_buffer_init(&key_txtbuffer, &key_txtsecret, sizeof(key_txtsecret)); 244 245 generate_key(mctx, randomfile, alg, keysize, &key_txtbuffer); 246 247 248 if (!quiet) 249 printf("\ 250 # To activate this key, place the following in named.conf, and\n\ 251 # in a separate keyfile on the system or systems from which nsupdate\n\ 252 # will be run:\n"); 253 254 printf("\ 255 key \"%s\" {\n\ 256 algorithm %s;\n\ 257 secret \"%.*s\";\n\ 258 };\n", 259 keyname, algname, 260 (int)isc_buffer_usedlength(&key_txtbuffer), 261 (char *)isc_buffer_base(&key_txtbuffer)); 262 263 if (!quiet) { 264 if (self_domain != NULL) { 265 printf("\n\ 266 # Then, in the \"zone\" statement for the zone containing the\n\ 267 # name \"%s\", place an \"update-policy\" statement\n\ 268 # like this one, adjusted as needed for your preferred permissions:\n\ 269 update-policy {\n\ 270 grant %s name %s ANY;\n\ 271 };\n", 272 self_domain, keyname, self_domain); 273 } else if (zone != NULL) { 274 printf("\n\ 275 # Then, in the \"zone\" definition statement for \"%s\",\n\ 276 # place an \"update-policy\" statement like this one, adjusted as \n\ 277 # needed for your preferred permissions:\n\ 278 update-policy {\n\ 279 grant %s zonesub ANY;\n\ 280 };\n", 281 zone, keyname); 282 } else { 283 printf("\n\ 284 # Then, in the \"zone\" statement for each zone you wish to dynamically\n\ 285 # update, place an \"update-policy\" statement granting update permission\n\ 286 # to this key. For example, the following statement grants this key\n\ 287 # permission to update any name within the zone:\n\ 288 update-policy {\n\ 289 grant %s zonesub ANY;\n\ 290 };\n", 291 keyname); 292 } 293 294 printf("\n\ 295 # After the keyfile has been placed, the following command will\n\ 296 # execute nsupdate using this key:\n\ 297 nsupdate -k <keyfile>\n"); 298 299 } 300 301 if (keybuf != NULL) 302 isc_mem_put(mctx, keybuf, len); 303 304 if (show_final_mem) 305 isc_mem_stats(mctx, stderr); 306 307 isc_mem_destroy(&mctx); 308 309 return (0); 310 } 311