ddns-confgen.c 7.2 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
 */

/*! \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/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>

Ondřej Surý's avatar
Ondřej Surý committed
39
#if HAVE_PKCS11
Mark Andrews's avatar
Mark Andrews committed
40
41
42
#include <pk11/result.h>
#endif

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

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

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

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

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

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

64
65
static void
usage(int status) {
Evan Hunt's avatar
Evan Hunt committed
66
67
	if (progmode == progmode_confgen) {
		fprintf(stderr, "\
68
Usage:\n\
69
 %s [-a alg] [-k keyname] [-q] [-s name | -z zone]\n\
70
  -a alg:        algorithm (default hmac-sha256)\n\
71
  -k keyname:    name of the key as it will be used in named.conf\n\
72
  -s name:       domain name to be updated using the created key\n\
73
74
  -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
75
76
77
78
			 progname);
	} else {
		fprintf(stderr, "\
Usage:\n\
79
80
 %s [-a alg] [keyname]\n\
  -a alg:        algorithm (default hmac-sha256)\n\n",
Evan Hunt's avatar
Evan Hunt committed
81
82
			 progname);
	}
83
84
85
86
87
88

	exit (status);
}

int
main(int argc, char **argv) {
Evan Hunt's avatar
Evan Hunt committed
89
	isc_result_t result = ISC_R_SUCCESS;
90
91
92
93
94
95
96
	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 *keyname = NULL;
	const char *zone = NULL;
97
	const char *self_domain = NULL;
98
99
	char *keybuf = NULL;
	dns_secalg_t alg = DST_ALG_HMACSHA256;
Evan Hunt's avatar
Evan Hunt committed
100
	const char *algname;
101
102
103
104
	int keysize = 256;
	int len = 0;
	int ch;

Ondřej Surý's avatar
Ondřej Surý committed
105
#if HAVE_PKCS11
106
107
108
109
	pk11_result_register();
#endif
	dns_result_register();

110
111
	result = isc_file_progname(*argv, program, sizeof(program));
	if (result != ISC_R_SUCCESS)
Evan Hunt's avatar
Evan Hunt committed
112
		memmove(program, "tsig-keygen", 11);
113
114
	progname = program;

Evan Hunt's avatar
Evan Hunt committed
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
	/*
	 * 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);

133
134
135
	isc_commandline_errprint = ISC_FALSE;

	while ((ch = isc_commandline_parse(argc, argv,
Evan Hunt's avatar
Evan Hunt committed
136
					   "a:hk:Mmr:qs:y:z:")) != -1) {
137
138
139
		switch (ch) {
		case 'a':
			algname = isc_commandline_argument;
Automatic Updater's avatar
Automatic Updater committed
140
141
			alg = alg_fromtext(algname);
			if (alg == DST_ALG_UNKNOWN)
142
				fatal("Unsupported algorithm '%s'", algname);
Automatic Updater's avatar
Automatic Updater committed
143
			keysize = alg_bits(alg);
144
145
146
147
148
			break;
		case 'h':
			usage(0);
		case 'k':
		case 'y':
Evan Hunt's avatar
Evan Hunt committed
149
150
151
152
			if (progmode == progmode_confgen)
				keyname = isc_commandline_argument;
			else
				usage(1);
153
154
155
156
157
158
159
160
			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
161
162
163
164
			if (progmode == progmode_confgen)
				quiet = ISC_TRUE;
			else
				usage(1);
165
166
			break;
		case 'r':
167
			fatal("The -r option has been deprecated.");
168
169
			break;
		case 's':
Evan Hunt's avatar
Evan Hunt committed
170
171
172
173
			if (progmode == progmode_confgen)
				self_domain = isc_commandline_argument;
			else
				usage(1);
174
			break;
175
		case 'z':
Evan Hunt's avatar
Evan Hunt committed
176
177
178
179
			if (progmode == progmode_confgen)
				zone = isc_commandline_argument;
			else
				usage(1);
180
			break;
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
		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
196
197
198
	if (progmode == progmode_keygen)
		keyname = argv[isc_commandline_index++];

199
	POST(argv);
200

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

Evan Hunt's avatar
Evan Hunt committed
204
	if (argc > isc_commandline_index)
205
206
		usage(1);

Evan Hunt's avatar
Evan Hunt committed
207
208
209
	/* Use canonical algorithm name */
	algname = alg_totext(alg);

210
211
	DO("create memory context", isc_mem_create(0, 0, &mctx));

212
213
	if (keyname == NULL) {
		const char *suffix = NULL;
Automatic Updater's avatar
Automatic Updater committed
214

Evan Hunt's avatar
Evan Hunt committed
215
216
217
		keyname = ((progmode == progmode_keygen)
			?  KEYGEN_DEFAULT
			: CONFGEN_DEFAULT);
218
219
220
221
222
223
		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
224
			keybuf = isc_mem_get(mctx, len);
225
226
227
			if (keybuf == NULL)
				fatal("failed to allocate memory for keyname");
			snprintf(keybuf, len, "%s.%s", keyname, suffix);
Automatic Updater's avatar
Automatic Updater committed
228
229
230
			keyname = (const char *) keybuf;
		}
	}
231
232
233

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

234
	generate_key(mctx, alg, keysize, &key_txtbuffer);
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252


	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) {
253
		if (self_domain != NULL) {
254
			printf("\n\
255
# Then, in the \"zone\" statement for the zone containing the\n\
256
257
258
# name \"%s\", place an \"update-policy\" statement\n\
# like this one, adjusted as needed for your preferred permissions:\n\
update-policy {\n\
259
	  grant %s name %s ANY;\n\
260
};\n",
261
			       self_domain, keyname, self_domain);
262
		} else if (zone != NULL) {
263
			printf("\n\
264
# Then, in the \"zone\" definition statement for \"%s\",\n\
265
266
267
# place an \"update-policy\" statement like this one, adjusted as \n\
# needed for your preferred permissions:\n\
update-policy {\n\
268
	  grant %s zonesub ANY;\n\
269
};\n",
270
271
272
273
274
275
276
277
278
279
280
			       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);
281
282
		}

283
		printf("\n\
284
# After the keyfile has been placed, the following command will\n\
285
286
287
# execute nsupdate using this key:\n\
nsupdate -k <keyfile>\n");

288
289
	}

290
	if (keybuf != NULL)
291
292
293
294
295
296
297
298
299
		isc_mem_put(mctx, keybuf, len);

	if (show_final_mem)
		isc_mem_stats(mctx, stderr);

	isc_mem_destroy(&mctx);

	return (0);
}