1/* $NetBSD: rndc-confgen.c,v 1.7 2024/02/21 22:51:00 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/attributes.h> 33#include <isc/base64.h> 34#include <isc/buffer.h> 35#include <isc/commandline.h> 36#include <isc/file.h> 37#include <isc/mem.h> 38#include <isc/net.h> 39#include <isc/print.h> 40#include <isc/result.h> 41#include <isc/string.h> 42#include <isc/time.h> 43#include <isc/util.h> 44 45#include <dns/keyvalues.h> 46#include <dns/name.h> 47 48#include <dst/dst.h> 49 50#include <confgen/os.h> 51 52#include "keygen.h" 53#include "util.h" 54 55#define DEFAULT_KEYNAME "rndc-key" 56#define DEFAULT_SERVER "127.0.0.1" 57#define DEFAULT_PORT 953 58 59static char program[256]; 60const char *progname; 61 62bool verbose = false; 63 64const char *keyfile, *keydef; 65 66noreturn static void 67usage(int status); 68 69static void 70usage(int status) { 71 fprintf(stderr, "\ 72Usage:\n\ 73 %s [-a] [-b bits] [-c keyfile] [-k keyname] [-p port] \ 74[-s addr] [-t chrootdir] [-u user]\n\ 75 -a: generate just the key clause and write it to keyfile (%s)\n\ 76 -A alg: algorithm (default hmac-sha256)\n\ 77 -b bits: from 1 through 512, default 256; total length of the secret\n\ 78 -c keyfile: specify an alternate key file (requires -a)\n\ 79 -k keyname: the name as it will be used in named.conf and rndc.conf\n\ 80 -p port: the port named will listen on and rndc will connect to\n\ 81 -q: suppress printing written key path\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 90int 91main(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 bool quiet = false; 111 int len; 112 113 keydef = keyfile = RNDC_KEYFILE; 114 115 result = isc_file_progname(*argv, program, sizeof(program)); 116 if (result != ISC_R_SUCCESS) { 117 memmove(program, "rndc-confgen", 13); 118 } 119 progname = program; 120 121 keyname = DEFAULT_KEYNAME; 122 alg = DST_ALG_HMACSHA256; 123 serveraddr = DEFAULT_SERVER; 124 port = DEFAULT_PORT; 125 126 isc_commandline_errprint = false; 127 128 while ((ch = isc_commandline_parse(argc, argv, 129 "aA:b:c:hk:Mmp:r:s:t:u:Vy")) != -1) 130 { 131 switch (ch) { 132 case 'a': 133 keyonly = true; 134 break; 135 case 'A': 136 algname = isc_commandline_argument; 137 alg = alg_fromtext(algname); 138 if (alg == DST_ALG_UNKNOWN) { 139 fatal("Unsupported algorithm '%s'", algname); 140 } 141 break; 142 case 'b': 143 keysize = strtol(isc_commandline_argument, &p, 10); 144 if (*p != '\0' || keysize < 0) { 145 fatal("-b requires a non-negative number"); 146 } 147 break; 148 case 'c': 149 keyfile = isc_commandline_argument; 150 break; 151 case 'h': 152 usage(0); 153 case 'k': 154 case 'y': /* Compatible with rndc -y. */ 155 keyname = isc_commandline_argument; 156 break; 157 case 'M': 158 isc_mem_debugging = ISC_MEM_DEBUGTRACE; 159 break; 160 161 case 'm': 162 show_final_mem = true; 163 break; 164 case 'p': 165 port = strtol(isc_commandline_argument, &p, 10); 166 if (*p != '\0' || port < 0 || port > 65535) { 167 fatal("port '%s' out of range", 168 isc_commandline_argument); 169 } 170 break; 171 case 'q': 172 quiet = true; 173 break; 174 case 'r': 175 fatal("The -r option has been deprecated."); 176 break; 177 case 's': 178 serveraddr = isc_commandline_argument; 179 if (inet_pton(AF_INET, serveraddr, &addr4_dummy) != 1 && 180 inet_pton(AF_INET6, serveraddr, &addr6_dummy) != 1) 181 { 182 fatal("-s should be an IPv4 or IPv6 address"); 183 } 184 break; 185 case 't': 186 chrootdir = isc_commandline_argument; 187 break; 188 case 'u': 189 user = isc_commandline_argument; 190 break; 191 case 'V': 192 verbose = true; 193 break; 194 case '?': 195 if (isc_commandline_option != '?') { 196 fprintf(stderr, "%s: invalid argument -%c\n", 197 program, isc_commandline_option); 198 usage(1); 199 } else { 200 usage(0); 201 } 202 break; 203 default: 204 fprintf(stderr, "%s: unhandled option -%c\n", program, 205 isc_commandline_option); 206 exit(1); 207 } 208 } 209 210 argc -= isc_commandline_index; 211 argv += isc_commandline_index; 212 POST(argv); 213 214 if (argc > 0) { 215 usage(1); 216 } 217 218 if (alg == DST_ALG_HMACMD5) { 219 fprintf(stderr, "warning: use of hmac-md5 for RNDC keys " 220 "is deprecated; hmac-sha256 is now " 221 "recommended.\n"); 222 } 223 224 if (keysize < 0) { 225 keysize = alg_bits(alg); 226 } 227 algname = dst_hmac_algorithm_totext(alg); 228 229 isc_mem_create(&mctx); 230 isc_buffer_init(&key_txtbuffer, &key_txtsecret, sizeof(key_txtsecret)); 231 232 generate_key(mctx, alg, keysize, &key_txtbuffer); 233 234 if (keyonly) { 235 write_key_file(keyfile, chrootdir == NULL ? user : NULL, 236 keyname, &key_txtbuffer, alg); 237 if (!quiet) { 238 printf("wrote key file \"%s\"\n", keyfile); 239 } 240 241 if (chrootdir != NULL) { 242 char *buf; 243 len = strlen(chrootdir) + strlen(keyfile) + 2; 244 buf = isc_mem_get(mctx, len); 245 snprintf(buf, len, "%s%s%s", chrootdir, 246 (*keyfile != '/') ? "/" : "", keyfile); 247 248 write_key_file(buf, user, keyname, &key_txtbuffer, alg); 249 if (!quiet) { 250 printf("wrote key file \"%s\"\n", buf); 251 } 252 isc_mem_put(mctx, buf, len); 253 } 254 } else { 255 printf("\ 256# Start of rndc.conf\n\ 257key \"%s\" {\n\ 258 algorithm %s;\n\ 259 secret \"%.*s\";\n\ 260};\n\ 261\n\ 262options {\n\ 263 default-key \"%s\";\n\ 264 default-server %s;\n\ 265 default-port %d;\n\ 266};\n\ 267# End of rndc.conf\n\ 268\n\ 269# Use with the following in named.conf, adjusting the allow list as needed:\n\ 270# key \"%s\" {\n\ 271# algorithm %s;\n\ 272# secret \"%.*s\";\n\ 273# };\n\ 274# \n\ 275# controls {\n\ 276# inet %s port %d\n\ 277# allow { %s; } keys { \"%s\"; };\n\ 278# };\n\ 279# End of named.conf\n", 280 keyname, algname, 281 (int)isc_buffer_usedlength(&key_txtbuffer), 282 (char *)isc_buffer_base(&key_txtbuffer), keyname, 283 serveraddr, port, keyname, algname, 284 (int)isc_buffer_usedlength(&key_txtbuffer), 285 (char *)isc_buffer_base(&key_txtbuffer), serveraddr, 286 port, serveraddr, keyname); 287 } 288 289 if (show_final_mem) { 290 isc_mem_stats(mctx, stderr); 291 } 292 293 isc_mem_destroy(&mctx); 294 295 return (0); 296} 297