1/* 2 * Copyright (C) 2009, 2011 Internet Systems Consortium, Inc. ("ISC") 3 * 4 * Permission to use, copy, modify, and/or distribute this software for any 5 * purpose with or without fee is hereby granted, provided that the above 6 * copyright notice and this permission notice appear in all copies. 7 * 8 * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH 9 * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY 10 * AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT, 11 * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM 12 * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE 13 * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR 14 * PERFORMANCE OF THIS SOFTWARE. 15 */ 16 17/* $Id: ddns-confgen.c,v 1.9.308.2 2011/03/12 04:59:13 tbox Exp $ */ 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#include <dns/keyvalues.h> 48#include <dns/name.h> 49 50#include <dst/dst.h> 51#include <confgen/os.h> 52 53#include "util.h" 54#include "keygen.h" 55 56#define DEFAULT_KEYNAME "ddns-key" 57 58static char program[256]; 59const char *progname; 60 61isc_boolean_t verbose = ISC_FALSE; 62 63ISC_PLATFORM_NORETURN_PRE static void 64usage(int status) ISC_PLATFORM_NORETURN_POST; 65 66static void 67usage(int status) { 68 69 fprintf(stderr, "\ 70Usage:\n\ 71 %s [-a alg] [-k keyname] [-r randomfile] [-q] [-s name | -z zone]\n\ 72 -a alg: algorithm (default hmac-sha256)\n\ 73 -k keyname: name of the key as it will be used in named.conf\n\ 74 -r randomfile: source of random data (use \"keyboard\" for key timing)\n\ 75 -s name: domain name to be updated using the created key\n\ 76 -z zone: name of the zone as it will be used in named.conf\n\ 77 -q: quiet mode: print the key, with no explanatory text\n", 78 progname); 79 80 exit (status); 81} 82 83int 84main(int argc, char **argv) { 85 isc_boolean_t show_final_mem = ISC_FALSE; 86 isc_boolean_t quiet = ISC_FALSE; 87 isc_buffer_t key_txtbuffer; 88 char key_txtsecret[256]; 89 isc_mem_t *mctx = NULL; 90 isc_result_t result = ISC_R_SUCCESS; 91 const char *randomfile = NULL; 92 const char *keyname = NULL; 93 const char *zone = NULL; 94 const char *self_domain = NULL; 95 char *keybuf = NULL; 96 dns_secalg_t alg = DST_ALG_HMACSHA256; 97 const char *algname = alg_totext(alg); 98 int keysize = 256; 99 int len = 0; 100 int ch; 101 102 result = isc_file_progname(*argv, program, sizeof(program)); 103 if (result != ISC_R_SUCCESS) 104 memcpy(program, "ddns-confgen", 13); 105 progname = program; 106 107 isc_commandline_errprint = ISC_FALSE; 108 109 while ((ch = isc_commandline_parse(argc, argv, 110 "a:hk:Mmr:qs:Vy:z:")) != -1) { 111 switch (ch) { 112 case 'a': 113 algname = isc_commandline_argument; 114 alg = alg_fromtext(algname); 115 if (alg == DST_ALG_UNKNOWN) 116 fatal("Unsupported algorithm '%s'", algname); 117 keysize = alg_bits(alg); 118 break; 119 case 'h': 120 usage(0); 121 case 'k': 122 case 'y': 123 keyname = isc_commandline_argument; 124 break; 125 case 'M': 126 isc_mem_debugging = ISC_MEM_DEBUGTRACE; 127 break; 128 case 'm': 129 show_final_mem = ISC_TRUE; 130 break; 131 case 'q': 132 quiet = ISC_TRUE; 133 break; 134 case 'r': 135 randomfile = isc_commandline_argument; 136 break; 137 case 's': 138 self_domain = isc_commandline_argument; 139 break; 140 case 'V': 141 verbose = ISC_TRUE; 142 break; 143 case 'z': 144 zone = isc_commandline_argument; 145 break; 146 case '?': 147 if (isc_commandline_option != '?') { 148 fprintf(stderr, "%s: invalid argument -%c\n", 149 program, isc_commandline_option); 150 usage(1); 151 } else 152 usage(0); 153 break; 154 default: 155 fprintf(stderr, "%s: unhandled option -%c\n", 156 program, isc_commandline_option); 157 exit(1); 158 } 159 } 160 161 argc -= isc_commandline_index; 162 argv += isc_commandline_index; 163 POST(argv); 164 165 if (self_domain != NULL && zone != NULL) 166 usage(1); /* -s and -z cannot coexist */ 167 168 if (argc > 0) 169 usage(1); 170 171 DO("create memory context", isc_mem_create(0, 0, &mctx)); 172 173 if (keyname == NULL) { 174 const char *suffix = NULL; 175 176 keyname = DEFAULT_KEYNAME; 177 if (self_domain != NULL) 178 suffix = self_domain; 179 else if (zone != NULL) 180 suffix = zone; 181 if (suffix != NULL) { 182 len = strlen(keyname) + strlen(suffix) + 2; 183 keybuf = isc_mem_get(mctx, len); 184 if (keybuf == NULL) 185 fatal("failed to allocate memory for keyname"); 186 snprintf(keybuf, len, "%s.%s", keyname, suffix); 187 keyname = (const char *) keybuf; 188 } 189 } 190 191 isc_buffer_init(&key_txtbuffer, &key_txtsecret, sizeof(key_txtsecret)); 192 193 generate_key(mctx, randomfile, alg, keysize, &key_txtbuffer); 194 195 196 if (!quiet) 197 printf("\ 198# To activate this key, place the following in named.conf, and\n\ 199# in a separate keyfile on the system or systems from which nsupdate\n\ 200# will be run:\n"); 201 202 printf("\ 203key \"%s\" {\n\ 204 algorithm %s;\n\ 205 secret \"%.*s\";\n\ 206};\n", 207 keyname, algname, 208 (int)isc_buffer_usedlength(&key_txtbuffer), 209 (char *)isc_buffer_base(&key_txtbuffer)); 210 211 if (!quiet) { 212 if (self_domain != NULL) { 213 printf("\n\ 214# Then, in the \"zone\" statement for the zone containing the\n\ 215# name \"%s\", place an \"update-policy\" statement\n\ 216# like this one, adjusted as needed for your preferred permissions:\n\ 217update-policy {\n\ 218 grant %s name %s ANY;\n\ 219};\n", 220 self_domain, keyname, self_domain); 221 } else if (zone != NULL) { 222 printf("\n\ 223# Then, in the \"zone\" definition statement for \"%s\",\n\ 224# place an \"update-policy\" statement like this one, adjusted as \n\ 225# needed for your preferred permissions:\n\ 226update-policy {\n\ 227 grant %s zonesub ANY;\n\ 228};\n", 229 zone, keyname); 230 } else { 231 printf("\n\ 232# Then, in the \"zone\" statement for each zone you wish to dynamically\n\ 233# update, place an \"update-policy\" statement granting update permission\n\ 234# to this key. For example, the following statement grants this key\n\ 235# permission to update any name within the zone:\n\ 236update-policy {\n\ 237 grant %s zonesub ANY;\n\ 238};\n", 239 keyname); 240 } 241 242 printf("\n\ 243# After the keyfile has been placed, the following command will\n\ 244# execute nsupdate using this key:\n\ 245nsupdate -k <keyfile>\n"); 246 247 } 248 249 if (keybuf != NULL) 250 isc_mem_put(mctx, keybuf, len); 251 252 if (show_final_mem) 253 isc_mem_stats(mctx, stderr); 254 255 isc_mem_destroy(&mctx); 256 257 return (0); 258} 259