2 * Copyright (C) 2004, 2005, 2007, 2008, 2011, 2012 Internet Systems Consortium, Inc. ("ISC")
3 * Copyright (C) 2001, 2003 Internet Software Consortium.
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.
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.
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.
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>
42 #include <isc/keyboard.h>
45 #include <isc/print.h>
46 #include <isc/result.h>
47 #include <isc/string.h>
51 #include <dns/keyvalues.h>
59 #define DEFAULT_KEYLENGTH 128 /*% Bits. */
60 #define DEFAULT_KEYNAME "rndc-key"
61 #define DEFAULT_SERVER "127.0.0.1"
62 #define DEFAULT_PORT 953
64 static char program[256];
67 isc_boolean_t verbose = ISC_FALSE;
69 const char *keyfile, *keydef;
71 ISC_PLATFORM_NORETURN_PRE static void
72 usage(int status) ISC_PLATFORM_NORETURN_POST;
79 %s [-a] [-b bits] [-c keyfile] [-k keyname] [-p port] [-r randomfile] \
80 [-s addr] [-t chrootdir] [-u user]\n\
81 -a: generate just the key clause and write it to keyfile (%s)\n\
82 -b bits: from 1 through 512, default %d; total length of the secret\n\
83 -c keyfile: specify an alternate key file (requires -a)\n\
84 -k keyname: the name as it will be used in named.conf and rndc.conf\n\
85 -p port: the port named will listen on and rndc will connect to\n\
86 -r randomfile: a file containing random data\n\
87 -s addr: the address to which rndc should connect\n\
88 -t chrootdir: write a keyfile in chrootdir as well (requires -a)\n\
89 -u user: set the keyfile owner to \"user\" (requires -a)\n",
90 progname, keydef, DEFAULT_KEYLENGTH);
96 * Write an rndc.key file to 'keyfile'. If 'user' is non-NULL,
97 * make that user the owner of the file. The key will have
98 * the name 'keyname' and the secret in the buffer 'secret'.
101 write_key_file(const char *keyfile, const char *user,
102 const char *keyname, isc_buffer_t *secret )
106 fd = safe_create(keyfile);
108 fatal( "unable to create \"%s\"\n", keyfile);
110 if (set_user(fd, user) == -1)
111 fatal("unable to set file owner\n");
113 fprintf(fd, "key \"%s\" {\n\talgorithm hmac-md5;\n"
114 "\tsecret \"%.*s\";\n};\n", keyname,
115 (int)isc_buffer_usedlength(secret),
116 (char *)isc_buffer_base(secret));
119 fatal("write to %s failed\n", keyfile);
121 fatal("fclose(%s) failed\n", keyfile);
122 fprintf(stderr, "wrote key file \"%s\"\n", keyfile);
126 main(int argc, char **argv) {
127 isc_boolean_t show_final_mem = ISC_FALSE;
128 isc_buffer_t key_rawbuffer;
129 isc_buffer_t key_txtbuffer;
130 isc_region_t key_rawregion;
131 isc_mem_t *mctx = NULL;
132 isc_entropy_t *ectx = NULL;
133 isc_entropysource_t *entropy_source = NULL;
134 isc_result_t result = ISC_R_SUCCESS;
135 dst_key_t *key = NULL;
136 const char *keyname = NULL;
137 const char *randomfile = NULL;
138 const char *serveraddr = NULL;
139 char key_rawsecret[64];
140 char key_txtsecret[256];
145 int entropy_flags = 0;
146 int open_keyboard = ISC_ENTROPY_KEYBOARDMAYBE;
147 struct in_addr addr4_dummy;
148 struct in6_addr addr6_dummy;
149 char *chrootdir = NULL;
151 isc_boolean_t keyonly = ISC_FALSE;
154 keydef = keyfile = RNDC_KEYFILE;
156 result = isc_file_progname(*argv, program, sizeof(program));
157 if (result != ISC_R_SUCCESS)
158 memcpy(program, "rndc-confgen", 13);
161 keyname = DEFAULT_KEYNAME;
162 keysize = DEFAULT_KEYLENGTH;
163 serveraddr = DEFAULT_SERVER;
166 isc_commandline_errprint = ISC_FALSE;
168 while ((ch = isc_commandline_parse(argc, argv,
169 "ab:c:hk:Mmp:r:s:t:u:Vy")) != -1) {
175 keysize = strtol(isc_commandline_argument, &p, 10);
176 if (*p != '\0' || keysize < 0)
177 fatal("-b requires a non-negative number");
178 if (keysize < 1 || keysize > 512)
179 fatal("-b must be in the range 1 through 512");
182 keyfile = isc_commandline_argument;
187 case 'y': /* Compatible with rndc -y. */
188 keyname = isc_commandline_argument;
191 isc_mem_debugging = ISC_MEM_DEBUGTRACE;
195 show_final_mem = ISC_TRUE;
198 port = strtol(isc_commandline_argument, &p, 10);
199 if (*p != '\0' || port < 0 || port > 65535)
200 fatal("port '%s' out of range",
201 isc_commandline_argument);
204 randomfile = isc_commandline_argument;
207 serveraddr = isc_commandline_argument;
208 if (inet_pton(AF_INET, serveraddr, &addr4_dummy) != 1 &&
209 inet_pton(AF_INET6, serveraddr, &addr6_dummy) != 1)
210 fatal("-s should be an IPv4 or IPv6 address");
213 chrootdir = isc_commandline_argument;
216 user = isc_commandline_argument;
222 if (isc_commandline_option != '?') {
223 fprintf(stderr, "%s: invalid argument -%c\n",
224 program, isc_commandline_option);
230 fprintf(stderr, "%s: unhandled option -%c\n",
231 program, isc_commandline_option);
236 argc -= isc_commandline_index;
237 argv += isc_commandline_index;
243 DO("create memory context", isc_mem_create(0, 0, &mctx));
245 DO("create entropy context", isc_entropy_create(mctx, &ectx));
247 if (randomfile != NULL && strcmp(randomfile, "keyboard") == 0) {
249 open_keyboard = ISC_ENTROPY_KEYBOARDYES;
251 DO("start entropy source", isc_entropy_usebestsource(ectx,
256 entropy_flags = ISC_ENTROPY_BLOCKING | ISC_ENTROPY_GOODONLY;
258 DO("initialize dst library", dst_lib_init(mctx, ectx, entropy_flags));
260 DO("generate key", dst_key_generate(dns_rootname, DST_ALG_HMACMD5,
263 dns_rdataclass_in, mctx, &key));
265 isc_buffer_init(&key_rawbuffer, &key_rawsecret, sizeof(key_rawsecret));
267 DO("dump key to buffer", dst_key_tobuffer(key, &key_rawbuffer));
269 isc_buffer_init(&key_txtbuffer, &key_txtsecret, sizeof(key_txtsecret));
270 isc_buffer_usedregion(&key_rawbuffer, &key_rawregion);
272 DO("bsse64 encode secret", isc_base64_totext(&key_rawregion, -1, "",
276 * Shut down the entropy source now so the "stop typing" message
277 * does not muck with the output.
279 if (entropy_source != NULL)
280 isc_entropy_destroysource(&entropy_source);
285 isc_entropy_detach(&ectx);
289 write_key_file(keyfile, chrootdir == NULL ? user : NULL,
290 keyname, &key_txtbuffer);
292 if (chrootdir != NULL) {
294 len = strlen(chrootdir) + strlen(keyfile) + 2;
295 buf = isc_mem_get(mctx, len);
297 fatal("isc_mem_get(%d) failed\n", len);
298 snprintf(buf, len, "%s%s%s", chrootdir,
299 (*keyfile != '/') ? "/" : "", keyfile);
301 write_key_file(buf, user, keyname, &key_txtbuffer);
302 isc_mem_put(mctx, buf, len);
306 # Start of rndc.conf\n\
308 algorithm hmac-md5;\n\
313 default-key \"%s\";\n\
314 default-server %s;\n\
317 # End of rndc.conf\n\
319 # Use with the following in named.conf, adjusting the allow list as needed:\n\
321 # algorithm hmac-md5;\n\
322 # secret \"%.*s\";\n\
327 # allow { %s; } keys { \"%s\"; };\n\
329 # End of named.conf\n",
331 (int)isc_buffer_usedlength(&key_txtbuffer),
332 (char *)isc_buffer_base(&key_txtbuffer),
333 keyname, serveraddr, port,
335 (int)isc_buffer_usedlength(&key_txtbuffer),
336 (char *)isc_buffer_base(&key_txtbuffer),
337 serveraddr, port, serveraddr, keyname);
341 isc_mem_stats(mctx, stderr);
343 isc_mem_destroy(&mctx);