ddns-confgen.c 7.44 KB
Newer Older
1
/*
2
 * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
3
 *
4
5
6
 * This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
7
8
9
 *
 * See the COPYRIGHT file distributed with this work for additional
 * information regarding copyright ownership.
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
 */

/*! \file */

/**
 * ddns-confgen generates configuration files for dynamic DNS. It can
 * be used as a convenient alternative to writing the ddns.key file
 * and the corresponding key and update-policy statements in named.conf.
 */

#include <config.h>

#include <stdlib.h>
#include <stdarg.h>

#include <isc/assertions.h>
#include <isc/base64.h>
#include <isc/buffer.h>
#include <isc/commandline.h>
#include <isc/entropy.h>
#include <isc/file.h>
#include <isc/keyboard.h>
#include <isc/mem.h>
#include <isc/net.h>
#include <isc/print.h>
#include <isc/result.h>
#include <isc/string.h>
#include <isc/time.h>
#include <isc/util.h>

Mark Andrews's avatar
Mark Andrews committed
40
41
42
43
#ifdef PKCS11CRYPTO
#include <pk11/result.h>
#endif

44
45
#include <dns/keyvalues.h>
#include <dns/name.h>
Mark Andrews's avatar
Mark Andrews committed
46
#include <dns/result.h>
47
48
49
50
51
52
53

#include <dst/dst.h>
#include <confgen/os.h>

#include "util.h"
#include "keygen.h"

Evan Hunt's avatar
Evan Hunt committed
54
55
#define KEYGEN_DEFAULT		"tsig-key"
#define CONFGEN_DEFAULT		"ddns-key"
56
57
58

static char program[256];
const char *progname;
Evan Hunt's avatar
Evan Hunt committed
59
60
static enum { progmode_keygen, progmode_confgen} progmode;
isc_boolean_t verbose = ISC_FALSE; /* needed by util.c but not used here */
61

Francis Dupont's avatar
Francis Dupont committed
62
63
64
ISC_PLATFORM_NORETURN_PRE static void
usage(int status) ISC_PLATFORM_NORETURN_POST;

65
66
static void
usage(int status) {
Evan Hunt's avatar
Evan Hunt committed
67
68
	if (progmode == progmode_confgen) {
		fprintf(stderr, "\
69
Usage:\n\
70
 %s [-a alg] [-k keyname] [-r randomfile] [-q] [-s name | -z zone]\n\
71
  -a alg:        algorithm (default hmac-sha256)\n\
72
  -k keyname:    name of the key as it will be used in named.conf\n\
73
  -r randomfile: source of random data (use \"keyboard\" for key timing)\n\
74
  -s name:       domain name to be updated using the created key\n\
75
76
  -z zone:       name of the zone as it will be used in named.conf\n\
  -q:            quiet mode: print the key, with no explanatory text\n",
Evan Hunt's avatar
Evan Hunt committed
77
78
79
80
81
82
83
84
85
			 progname);
	} else {
		fprintf(stderr, "\
Usage:\n\
 %s [-a alg] [-r randomfile] [keyname]\n\
  -a alg:        algorithm (default hmac-sha256)\n\
  -r randomfile: source of random data (use \"keyboard\" for key timing)\n",
			 progname);
	}
86
87
88
89
90
91

	exit (status);
}

int
main(int argc, char **argv) {
Evan Hunt's avatar
Evan Hunt committed
92
	isc_result_t result = ISC_R_SUCCESS;
93
94
95
96
97
98
99
100
	isc_boolean_t show_final_mem = ISC_FALSE;
	isc_boolean_t quiet = ISC_FALSE;
	isc_buffer_t key_txtbuffer;
	char key_txtsecret[256];
	isc_mem_t *mctx = NULL;
	const char *randomfile = NULL;
	const char *keyname = NULL;
	const char *zone = NULL;
101
	const char *self_domain = NULL;
102
103
	char *keybuf = NULL;
	dns_secalg_t alg = DST_ALG_HMACSHA256;
Evan Hunt's avatar
Evan Hunt committed
104
	const char *algname;
105
106
107
108
	int keysize = 256;
	int len = 0;
	int ch;

109
110
111
112
113
#ifdef PKCS11CRYPTO
	pk11_result_register();
#endif
	dns_result_register();

114
115
	result = isc_file_progname(*argv, program, sizeof(program));
	if (result != ISC_R_SUCCESS)
Evan Hunt's avatar
Evan Hunt committed
116
		memmove(program, "tsig-keygen", 11);
117
118
	progname = program;

Evan Hunt's avatar
Evan Hunt committed
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
	/*
	 * Libtool doesn't preserve the program name prior to final
	 * installation.  Remove the libtool prefix ("lt-").
	 */
	if (strncmp(progname, "lt-", 3) == 0)
		progname += 3;

#define PROGCMP(X) \
	(strcasecmp(progname, X) == 0 || strcasecmp(progname, X ".exe") == 0)

	if (PROGCMP("tsig-keygen")) {
		progmode = progmode_keygen;
		quiet = ISC_TRUE;
	} else if (PROGCMP("ddns-confgen"))
		progmode = progmode_confgen;
	else
		INSIST(0);

137
138
139
	isc_commandline_errprint = ISC_FALSE;

	while ((ch = isc_commandline_parse(argc, argv,
Evan Hunt's avatar
Evan Hunt committed
140
					   "a:hk:Mmr:qs:y:z:")) != -1) {
141
142
143
		switch (ch) {
		case 'a':
			algname = isc_commandline_argument;
Automatic Updater's avatar
Automatic Updater committed
144
145
			alg = alg_fromtext(algname);
			if (alg == DST_ALG_UNKNOWN)
146
				fatal("Unsupported algorithm '%s'", algname);
Automatic Updater's avatar
Automatic Updater committed
147
			keysize = alg_bits(alg);
148
149
150
151
152
			break;
		case 'h':
			usage(0);
		case 'k':
		case 'y':
Evan Hunt's avatar
Evan Hunt committed
153
154
155
156
			if (progmode == progmode_confgen)
				keyname = isc_commandline_argument;
			else
				usage(1);
157
158
159
160
161
162
163
164
			break;
		case 'M':
			isc_mem_debugging = ISC_MEM_DEBUGTRACE;
			break;
		case 'm':
			show_final_mem = ISC_TRUE;
			break;
		case 'q':
Evan Hunt's avatar
Evan Hunt committed
165
166
167
168
			if (progmode == progmode_confgen)
				quiet = ISC_TRUE;
			else
				usage(1);
169
170
171
172
173
			break;
		case 'r':
			randomfile = isc_commandline_argument;
			break;
		case 's':
Evan Hunt's avatar
Evan Hunt committed
174
175
176
177
			if (progmode == progmode_confgen)
				self_domain = isc_commandline_argument;
			else
				usage(1);
178
			break;
179
		case 'z':
Evan Hunt's avatar
Evan Hunt committed
180
181
182
183
			if (progmode == progmode_confgen)
				zone = isc_commandline_argument;
			else
				usage(1);
184
			break;
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
		case '?':
			if (isc_commandline_option != '?') {
				fprintf(stderr, "%s: invalid argument -%c\n",
					program, isc_commandline_option);
				usage(1);
			} else
				usage(0);
			break;
		default:
			fprintf(stderr, "%s: unhandled option -%c\n",
				program, isc_commandline_option);
			exit(1);
		}
	}

Evan Hunt's avatar
Evan Hunt committed
200
201
202
	if (progmode == progmode_keygen)
		keyname = argv[isc_commandline_index++];

203
	POST(argv);
204

205
206
	if (self_domain != NULL && zone != NULL)
		usage(1);	/* -s and -z cannot coexist */
Tinderbox User's avatar
Tinderbox User committed
207

Evan Hunt's avatar
Evan Hunt committed
208
	if (argc > isc_commandline_index)
209
210
		usage(1);

Evan Hunt's avatar
Evan Hunt committed
211
212
213
	/* Use canonical algorithm name */
	algname = alg_totext(alg);

214
215
	DO("create memory context", isc_mem_create(0, 0, &mctx));

216
217
	if (keyname == NULL) {
		const char *suffix = NULL;
Automatic Updater's avatar
Automatic Updater committed
218

Evan Hunt's avatar
Evan Hunt committed
219
220
221
		keyname = ((progmode == progmode_keygen)
			?  KEYGEN_DEFAULT
			: CONFGEN_DEFAULT);
222
223
224
225
226
227
		if (self_domain != NULL)
			suffix = self_domain;
		else if (zone != NULL)
			suffix = zone;
		if (suffix != NULL) {
			len = strlen(keyname) + strlen(suffix) + 2;
Automatic Updater's avatar
Automatic Updater committed
228
			keybuf = isc_mem_get(mctx, len);
229
230
231
			if (keybuf == NULL)
				fatal("failed to allocate memory for keyname");
			snprintf(keybuf, len, "%s.%s", keyname, suffix);
Automatic Updater's avatar
Automatic Updater committed
232
233
234
			keyname = (const char *) keybuf;
		}
	}
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256

	isc_buffer_init(&key_txtbuffer, &key_txtsecret, sizeof(key_txtsecret));

	generate_key(mctx, randomfile, alg, keysize, &key_txtbuffer);


	if (!quiet)
		printf("\
# To activate this key, place the following in named.conf, and\n\
# in a separate keyfile on the system or systems from which nsupdate\n\
# will be run:\n");

	printf("\
key \"%s\" {\n\
	algorithm %s;\n\
	secret \"%.*s\";\n\
};\n",
	       keyname, algname,
	       (int)isc_buffer_usedlength(&key_txtbuffer),
	       (char *)isc_buffer_base(&key_txtbuffer));

	if (!quiet) {
257
		if (self_domain != NULL) {
258
			printf("\n\
259
# Then, in the \"zone\" statement for the zone containing the\n\
260
261
262
# name \"%s\", place an \"update-policy\" statement\n\
# like this one, adjusted as needed for your preferred permissions:\n\
update-policy {\n\
263
	  grant %s name %s ANY;\n\
264
};\n",
265
			       self_domain, keyname, self_domain);
266
		} else if (zone != NULL) {
267
			printf("\n\
268
# Then, in the \"zone\" definition statement for \"%s\",\n\
269
270
271
# place an \"update-policy\" statement like this one, adjusted as \n\
# needed for your preferred permissions:\n\
update-policy {\n\
272
	  grant %s zonesub ANY;\n\
273
};\n",
274
275
276
277
278
279
280
281
282
283
284
			       zone, keyname);
		} else {
			printf("\n\
# Then, in the \"zone\" statement for each zone you wish to dynamically\n\
# update, place an \"update-policy\" statement granting update permission\n\
# to this key.  For example, the following statement grants this key\n\
# permission to update any name within the zone:\n\
update-policy {\n\
	grant %s zonesub ANY;\n\
};\n",
			       keyname);
285
286
		}

287
		printf("\n\
288
# After the keyfile has been placed, the following command will\n\
289
290
291
# execute nsupdate using this key:\n\
nsupdate -k <keyfile>\n");

292
293
	}

294
	if (keybuf != NULL)
295
296
297
298
299
300
301
302
303
		isc_mem_put(mctx, keybuf, len);

	if (show_final_mem)
		isc_mem_stats(mctx, stderr);

	isc_mem_destroy(&mctx);

	return (0);
}