1/* 2 * Copyright (C) 2004, 2005, 2007-2009, 2011 Internet Systems Consortium, Inc. ("ISC") 3 * Copyright (C) 2001, 2003 Internet Software Consortium. 4 * 5 * Permission to use, copy, modify, and/or distribute this software for any 6 * purpose with or without fee is hereby granted, provided that the above 7 * copyright notice and this permission notice appear in all copies. 8 * 9 * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH 10 * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY 11 * AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT, 12 * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM 13 * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE 14 * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR 15 * PERFORMANCE OF THIS SOFTWARE. 16 */ 17 18/* $Id: rndc-confgen.c,v 1.5.308.2 2011/03/12 04:59:13 tbox Exp $ */ 19 20/*! \file */ 21 22/** 23 * rndc-confgen generates configuration files for rndc. It can be used 24 * as a convenient alternative to writing the rndc.conf file and the 25 * corresponding controls and key statements in named.conf by hand. 26 * Alternatively, it can be run with the -a option to set up a 27 * rndc.key file and avoid the need for a rndc.conf file and a 28 * controls statement altogether. 29 */ 30 31#include <config.h> 32 33#include <stdlib.h> 34#include <stdarg.h> 35 36#include <isc/assertions.h> 37#include <isc/base64.h> 38#include <isc/buffer.h> 39#include <isc/commandline.h> 40#include <isc/entropy.h> 41#include <isc/file.h> 42#include <isc/keyboard.h> 43#include <isc/mem.h> 44#include <isc/net.h> 45#include <isc/print.h> 46#include <isc/result.h> 47#include <isc/string.h> 48#include <isc/time.h> 49#include <isc/util.h> 50 51#include <dns/keyvalues.h> 52#include <dns/name.h> 53 54#include <dst/dst.h> 55#include <confgen/os.h> 56 57#include "util.h" 58#include "keygen.h" 59 60#define DEFAULT_KEYLENGTH 128 /*% Bits. */ 61#define DEFAULT_KEYNAME "rndc-key" 62#define DEFAULT_SERVER "127.0.0.1" 63#define DEFAULT_PORT 953 64 65static char program[256]; 66const char *progname; 67 68isc_boolean_t verbose = ISC_FALSE; 69 70const char *keyfile, *keydef; 71 72ISC_PLATFORM_NORETURN_PRE static void 73usage(int status) ISC_PLATFORM_NORETURN_POST; 74 75static void 76usage(int status) { 77 78 fprintf(stderr, "\ 79Usage:\n\ 80 %s [-a] [-b bits] [-c keyfile] [-k keyname] [-p port] [-r randomfile] \ 81[-s addr] [-t chrootdir] [-u user]\n\ 82 -a: generate just the key clause and write it to keyfile (%s)\n\ 83 -b bits: from 1 through 512, default %d; total length of the secret\n\ 84 -c keyfile: specify an alternate key file (requires -a)\n\ 85 -k keyname: the name as it will be used in named.conf and rndc.conf\n\ 86 -p port: the port named will listen on and rndc will connect to\n\ 87 -r randomfile: source of random data (use \"keyboard\" for key timing)\n\ 88 -s addr: the address to which rndc should connect\n\ 89 -t chrootdir: write a keyfile in chrootdir as well (requires -a)\n\ 90 -u user: set the keyfile owner to \"user\" (requires -a)\n", 91 progname, keydef, DEFAULT_KEYLENGTH); 92 93 exit (status); 94} 95 96int 97main(int argc, char **argv) { 98 isc_boolean_t show_final_mem = ISC_FALSE; 99 isc_buffer_t key_txtbuffer; 100 char key_txtsecret[256]; 101 isc_mem_t *mctx = NULL; 102 isc_result_t result = ISC_R_SUCCESS; 103 const char *keyname = NULL; 104 const char *randomfile = NULL; 105 const char *serveraddr = NULL; 106 dns_secalg_t alg = DST_ALG_HMACMD5; 107 const char *algname = alg_totext(alg); 108 char *p; 109 int ch; 110 int port; 111 int keysize; 112 struct in_addr addr4_dummy; 113 struct in6_addr addr6_dummy; 114 char *chrootdir = NULL; 115 char *user = NULL; 116 isc_boolean_t keyonly = ISC_FALSE; 117 int len; 118 119 keydef = keyfile = RNDC_KEYFILE; 120 121 result = isc_file_progname(*argv, program, sizeof(program)); 122 if (result != ISC_R_SUCCESS) 123 memcpy(program, "rndc-confgen", 13); 124 progname = program; 125 126 keyname = DEFAULT_KEYNAME; 127 keysize = DEFAULT_KEYLENGTH; 128 serveraddr = DEFAULT_SERVER; 129 port = DEFAULT_PORT; 130 131 isc_commandline_errprint = ISC_FALSE; 132 133 while ((ch = isc_commandline_parse(argc, argv, 134 "ab:c:hk:Mmp:r:s:t:u:Vy")) != -1) { 135 switch (ch) { 136 case 'a': 137 keyonly = ISC_TRUE; 138 break; 139 case 'b': 140 keysize = strtol(isc_commandline_argument, &p, 10); 141 if (*p != '\0' || keysize < 0) 142 fatal("-b requires a non-negative number"); 143 if (keysize < 1 || keysize > 512) 144 fatal("-b must be in the range 1 through 512"); 145 break; 146 case 'c': 147 keyfile = isc_commandline_argument; 148 break; 149 case 'h': 150 usage(0); 151 case 'k': 152 case 'y': /* Compatible with rndc -y. */ 153 keyname = isc_commandline_argument; 154 break; 155 case 'M': 156 isc_mem_debugging = ISC_MEM_DEBUGTRACE; 157 break; 158 159 case 'm': 160 show_final_mem = ISC_TRUE; 161 break; 162 case 'p': 163 port = strtol(isc_commandline_argument, &p, 10); 164 if (*p != '\0' || port < 0 || port > 65535) 165 fatal("port '%s' out of range", 166 isc_commandline_argument); 167 break; 168 case 'r': 169 randomfile = isc_commandline_argument; 170 break; 171 case 's': 172 serveraddr = isc_commandline_argument; 173 if (inet_pton(AF_INET, serveraddr, &addr4_dummy) != 1 && 174 inet_pton(AF_INET6, serveraddr, &addr6_dummy) != 1) 175 fatal("-s should be an IPv4 or IPv6 address"); 176 break; 177 case 't': 178 chrootdir = isc_commandline_argument; 179 break; 180 case 'u': 181 user = isc_commandline_argument; 182 break; 183 case 'V': 184 verbose = ISC_TRUE; 185 break; 186 case '?': 187 if (isc_commandline_option != '?') { 188 fprintf(stderr, "%s: invalid argument -%c\n", 189 program, isc_commandline_option); 190 usage(1); 191 } else 192 usage(0); 193 break; 194 default: 195 fprintf(stderr, "%s: unhandled option -%c\n", 196 program, isc_commandline_option); 197 exit(1); 198 } 199 } 200 201 argc -= isc_commandline_index; 202 argv += isc_commandline_index; 203 POST(argv); 204 205 if (argc > 0) 206 usage(1); 207 208 DO("create memory context", isc_mem_create(0, 0, &mctx)); 209 isc_buffer_init(&key_txtbuffer, &key_txtsecret, sizeof(key_txtsecret)); 210 211 generate_key(mctx, randomfile, alg, keysize, &key_txtbuffer); 212 213 if (keyonly) { 214 write_key_file(keyfile, chrootdir == NULL ? user : NULL, 215 keyname, &key_txtbuffer, alg); 216 217 if (chrootdir != NULL) { 218 char *buf; 219 len = strlen(chrootdir) + strlen(keyfile) + 2; 220 buf = isc_mem_get(mctx, len); 221 if (buf == NULL) 222 fatal("isc_mem_get(%d) failed\n", len); 223 snprintf(buf, len, "%s%s%s", chrootdir, 224 (*keyfile != '/') ? "/" : "", keyfile); 225 226 write_key_file(buf, user, keyname, &key_txtbuffer, alg); 227 isc_mem_put(mctx, buf, len); 228 } 229 } else { 230 printf("\ 231# Start of rndc.conf\n\ 232key \"%s\" {\n\ 233 algorithm %s;\n\ 234 secret \"%.*s\";\n\ 235};\n\ 236\n\ 237options {\n\ 238 default-key \"%s\";\n\ 239 default-server %s;\n\ 240 default-port %d;\n\ 241};\n\ 242# End of rndc.conf\n\ 243\n\ 244# Use with the following in named.conf, adjusting the allow list as needed:\n\ 245# key \"%s\" {\n\ 246# algorithm %s;\n\ 247# secret \"%.*s\";\n\ 248# };\n\ 249# \n\ 250# controls {\n\ 251# inet %s port %d\n\ 252# allow { %s; } keys { \"%s\"; };\n\ 253# };\n\ 254# End of named.conf\n", 255 keyname, algname, 256 (int)isc_buffer_usedlength(&key_txtbuffer), 257 (char *)isc_buffer_base(&key_txtbuffer), 258 keyname, serveraddr, port, 259 keyname, algname, 260 (int)isc_buffer_usedlength(&key_txtbuffer), 261 (char *)isc_buffer_base(&key_txtbuffer), 262 serveraddr, port, serveraddr, keyname); 263 } 264 265 if (show_final_mem) 266 isc_mem_stats(mctx, stderr); 267 268 isc_mem_destroy(&mctx); 269 270 return (0); 271} 272