1 /* $NetBSD: rndc-confgen.c,v 1.6 2022/09/23 12:15:20 christos Exp $ */ 2 3 /* 4 * Copyright (C) Internet Systems Consortium, Inc. ("ISC") 5 * 6 * SPDX-License-Identifier: MPL-2.0 7 * 8 * This Source Code Form is subject to the terms of the Mozilla Public 9 * License, v. 2.0. If a copy of the MPL was not distributed with this 10 * file, you can obtain one at https://mozilla.org/MPL/2.0/. 11 * 12 * See the COPYRIGHT file distributed with this work for additional 13 * information regarding copyright ownership. 14 */ 15 16 /*! \file */ 17 18 /** 19 * rndc-confgen generates configuration files for rndc. It can be used 20 * as a convenient alternative to writing the rndc.conf file and the 21 * corresponding controls and key statements in named.conf by hand. 22 * Alternatively, it can be run with the -a option to set up a 23 * rndc.key file and avoid the need for a rndc.conf file and a 24 * controls statement altogether. 25 */ 26 27 #include <stdarg.h> 28 #include <stdbool.h> 29 #include <stdlib.h> 30 31 #include <isc/assertions.h> 32 #include <isc/base64.h> 33 #include <isc/buffer.h> 34 #include <isc/commandline.h> 35 #include <isc/file.h> 36 #include <isc/mem.h> 37 #include <isc/net.h> 38 #include <isc/print.h> 39 #include <isc/result.h> 40 #include <isc/string.h> 41 #include <isc/time.h> 42 #include <isc/util.h> 43 44 #include <pk11/site.h> 45 46 #include <dns/keyvalues.h> 47 #include <dns/name.h> 48 49 #include <dst/dst.h> 50 51 #include <confgen/os.h> 52 53 #include "keygen.h" 54 #include "util.h" 55 56 #define DEFAULT_KEYNAME "rndc-key" 57 #define DEFAULT_SERVER "127.0.0.1" 58 #define DEFAULT_PORT 953 59 60 static char program[256]; 61 const char *progname; 62 63 bool verbose = false; 64 65 const char *keyfile, *keydef; 66 67 ISC_PLATFORM_NORETURN_PRE static void 68 usage(int status) ISC_PLATFORM_NORETURN_POST; 69 70 static void 71 usage(int status) { 72 fprintf(stderr, "\ 73 Usage:\n\ 74 %s [-a] [-b bits] [-c keyfile] [-k keyname] [-p port] \ 75 [-s addr] [-t chrootdir] [-u user]\n\ 76 -a: generate just the key clause and write it to keyfile (%s)\n\ 77 -A alg: algorithm (default hmac-sha256)\n\ 78 -b bits: from 1 through 512, default 256; total length of the secret\n\ 79 -c keyfile: specify an alternate key file (requires -a)\n\ 80 -k keyname: the name as it will be used in named.conf and rndc.conf\n\ 81 -p port: the port named will listen on and rndc will connect to\n\ 82 -s addr: the address to which rndc should connect\n\ 83 -t chrootdir: write a keyfile in chrootdir as well (requires -a)\n\ 84 -u user: set the keyfile owner to \"user\" (requires -a)\n", 85 progname, keydef); 86 87 exit(status); 88 } 89 90 int 91 main(int argc, char **argv) { 92 bool show_final_mem = false; 93 isc_buffer_t key_txtbuffer; 94 char key_txtsecret[256]; 95 isc_mem_t *mctx = NULL; 96 isc_result_t result = ISC_R_SUCCESS; 97 const char *keyname = NULL; 98 const char *serveraddr = NULL; 99 dns_secalg_t alg; 100 const char *algname; 101 char *p; 102 int ch; 103 int port; 104 int keysize = -1; 105 struct in_addr addr4_dummy; 106 struct in6_addr addr6_dummy; 107 char *chrootdir = NULL; 108 char *user = NULL; 109 bool keyonly = false; 110 int len; 111 112 keydef = keyfile = RNDC_KEYFILE; 113 114 result = isc_file_progname(*argv, program, sizeof(program)); 115 if (result != ISC_R_SUCCESS) { 116 memmove(program, "rndc-confgen", 13); 117 } 118 progname = program; 119 120 keyname = DEFAULT_KEYNAME; 121 alg = DST_ALG_HMACSHA256; 122 serveraddr = DEFAULT_SERVER; 123 port = DEFAULT_PORT; 124 125 isc_commandline_errprint = false; 126 127 while ((ch = isc_commandline_parse(argc, argv, 128 "aA:b:c:hk:Mmp:r:s:t:u:Vy")) != -1) 129 { 130 switch (ch) { 131 case 'a': 132 keyonly = true; 133 break; 134 case 'A': 135 algname = isc_commandline_argument; 136 alg = alg_fromtext(algname); 137 if (alg == DST_ALG_UNKNOWN) { 138 fatal("Unsupported algorithm '%s'", algname); 139 } 140 break; 141 case 'b': 142 keysize = strtol(isc_commandline_argument, &p, 10); 143 if (*p != '\0' || keysize < 0) { 144 fatal("-b requires a non-negative number"); 145 } 146 break; 147 case 'c': 148 keyfile = isc_commandline_argument; 149 break; 150 case 'h': 151 usage(0); 152 case 'k': 153 case 'y': /* Compatible with rndc -y. */ 154 keyname = isc_commandline_argument; 155 break; 156 case 'M': 157 isc_mem_debugging = ISC_MEM_DEBUGTRACE; 158 break; 159 160 case 'm': 161 show_final_mem = true; 162 break; 163 case 'p': 164 port = strtol(isc_commandline_argument, &p, 10); 165 if (*p != '\0' || port < 0 || port > 65535) { 166 fatal("port '%s' out of range", 167 isc_commandline_argument); 168 } 169 break; 170 case 'r': 171 fatal("The -r option has been deprecated."); 172 break; 173 case 's': 174 serveraddr = isc_commandline_argument; 175 if (inet_pton(AF_INET, serveraddr, &addr4_dummy) != 1 && 176 inet_pton(AF_INET6, serveraddr, &addr6_dummy) != 1) 177 { 178 fatal("-s should be an IPv4 or IPv6 address"); 179 } 180 break; 181 case 't': 182 chrootdir = isc_commandline_argument; 183 break; 184 case 'u': 185 user = isc_commandline_argument; 186 break; 187 case 'V': 188 verbose = true; 189 break; 190 case '?': 191 if (isc_commandline_option != '?') { 192 fprintf(stderr, "%s: invalid argument -%c\n", 193 program, isc_commandline_option); 194 usage(1); 195 } else { 196 usage(0); 197 } 198 break; 199 default: 200 fprintf(stderr, "%s: unhandled option -%c\n", program, 201 isc_commandline_option); 202 exit(1); 203 } 204 } 205 206 argc -= isc_commandline_index; 207 argv += isc_commandline_index; 208 POST(argv); 209 210 if (argc > 0) { 211 usage(1); 212 } 213 214 if (alg == DST_ALG_HMACMD5) { 215 fprintf(stderr, "warning: use of hmac-md5 for RNDC keys " 216 "is deprecated; hmac-sha256 is now " 217 "recommended.\n"); 218 } 219 220 if (keysize < 0) { 221 keysize = alg_bits(alg); 222 } 223 algname = alg_totext(alg); 224 225 isc_mem_create(&mctx); 226 isc_buffer_init(&key_txtbuffer, &key_txtsecret, sizeof(key_txtsecret)); 227 228 generate_key(mctx, alg, keysize, &key_txtbuffer); 229 230 if (keyonly) { 231 write_key_file(keyfile, chrootdir == NULL ? user : NULL, 232 keyname, &key_txtbuffer, alg); 233 234 if (chrootdir != NULL) { 235 char *buf; 236 len = strlen(chrootdir) + strlen(keyfile) + 2; 237 buf = isc_mem_get(mctx, len); 238 snprintf(buf, len, "%s%s%s", chrootdir, 239 (*keyfile != '/') ? "/" : "", keyfile); 240 241 write_key_file(buf, user, keyname, &key_txtbuffer, alg); 242 isc_mem_put(mctx, buf, len); 243 } 244 } else { 245 printf("\ 246 # Start of rndc.conf\n\ 247 key \"%s\" {\n\ 248 algorithm %s;\n\ 249 secret \"%.*s\";\n\ 250 };\n\ 251 \n\ 252 options {\n\ 253 default-key \"%s\";\n\ 254 default-server %s;\n\ 255 default-port %d;\n\ 256 };\n\ 257 # End of rndc.conf\n\ 258 \n\ 259 # Use with the following in named.conf, adjusting the allow list as needed:\n\ 260 # key \"%s\" {\n\ 261 # algorithm %s;\n\ 262 # secret \"%.*s\";\n\ 263 # };\n\ 264 # \n\ 265 # controls {\n\ 266 # inet %s port %d\n\ 267 # allow { %s; } keys { \"%s\"; };\n\ 268 # };\n\ 269 # End of named.conf\n", 270 keyname, algname, 271 (int)isc_buffer_usedlength(&key_txtbuffer), 272 (char *)isc_buffer_base(&key_txtbuffer), keyname, 273 serveraddr, port, keyname, algname, 274 (int)isc_buffer_usedlength(&key_txtbuffer), 275 (char *)isc_buffer_base(&key_txtbuffer), serveraddr, 276 port, serveraddr, keyname); 277 } 278 279 if (show_final_mem) { 280 isc_mem_stats(mctx, stderr); 281 } 282 283 isc_mem_destroy(&mctx); 284 285 return (0); 286 } 287