nsupdate.c 83.9 KB
Newer Older
Michael Sawyer's avatar
Michael Sawyer committed
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.
Michael Sawyer's avatar
Michael Sawyer committed
10 11
 */

12
/*! \file */
Michael Sawyer's avatar
Michael Sawyer committed
13

14 15
#include <ctype.h>
#include <errno.h>
16
#include <inttypes.h>
17
#include <limits.h>
18
#include <stdbool.h>
19 20 21
#include <stdlib.h>
#include <unistd.h>

22
#include <isc/app.h>
Michael Sawyer's avatar
Michael Sawyer committed
23
#include <isc/base64.h>
Michael Sawyer's avatar
Michael Sawyer committed
24
#include <isc/buffer.h>
Brian Wellington's avatar
Brian Wellington committed
25
#include <isc/commandline.h>
26
#include <isc/event.h>
27
#include <isc/file.h>
28
#include <isc/hash.h>
Michael Sawyer's avatar
Michael Sawyer committed
29
#include <isc/lex.h>
30
#include <isc/log.h>
Michael Sawyer's avatar
Michael Sawyer committed
31
#include <isc/mem.h>
32
#include <isc/nonce.h>
33
#include <isc/parseint.h>
34
#include <isc/platform.h>
35
#include <isc/portset.h>
Evan Hunt's avatar
Evan Hunt committed
36
#include <isc/print.h>
37
#include <isc/random.h>
Michael Sawyer's avatar
Michael Sawyer committed
38
#include <isc/region.h>
Michael Sawyer's avatar
Michael Sawyer committed
39 40
#include <isc/sockaddr.h>
#include <isc/socket.h>
41
#include <isc/stdio.h>
Michael Sawyer's avatar
Michael Sawyer committed
42
#include <isc/string.h>
Michael Sawyer's avatar
Michael Sawyer committed
43
#include <isc/task.h>
Michael Sawyer's avatar
Michael Sawyer committed
44
#include <isc/timer.h>
Michael Sawyer's avatar
Michael Sawyer committed
45
#include <isc/types.h>
Michael Sawyer's avatar
Michael Sawyer committed
46
#include <isc/util.h>
Michael Sawyer's avatar
Michael Sawyer committed
47

Brian Wellington's avatar
Brian Wellington committed
48 49
#include <dns/callbacks.h>
#include <dns/dispatch.h>
50
#include <dns/dnssec.h>
Brian Wellington's avatar
Brian Wellington committed
51
#include <dns/events.h>
52
#include <dns/fixedname.h>
53
#include <dns/log.h>
54
#include <dns/masterdump.h>
Brian Wellington's avatar
Brian Wellington committed
55 56
#include <dns/message.h>
#include <dns/name.h>
57
#include <dns/rcode.h>
Brian Wellington's avatar
Brian Wellington committed
58 59 60 61 62 63 64 65
#include <dns/rdata.h>
#include <dns/rdataclass.h>
#include <dns/rdatalist.h>
#include <dns/rdataset.h>
#include <dns/rdatastruct.h>
#include <dns/rdatatype.h>
#include <dns/request.h>
#include <dns/result.h>
66
#include <dns/tkey.h>
Brian Wellington's avatar
Brian Wellington committed
67
#include <dns/tsig.h>
68

69
#include <isccfg/namedconf.h>
Brian Wellington's avatar
Brian Wellington committed
70

71
#include <dst/dst.h>
72
#include <irs/resconf.h>
73
#include <pk11/site.h>
74

75 76
#ifdef GSSAPI
#include <dst/gssapi.h>
77 78
#ifdef WIN32
#include <krb5/krb5.h>
79
#else /* ifdef WIN32 */
80
#include ISC_PLATFORM_KRB5HEADER
81 82
#endif /* ifdef WIN32 */
#endif /* ifdef GSSAPI */
83 84
#include <bind9/getaddresses.h>

85
#if defined(HAVE_READLINE)
86 87 88 89
#if defined(HAVE_EDIT_READLINE_READLINE_H)
#include <edit/readline/readline.h>
#if defined(HAVE_EDIT_READLINE_HISTORY_H)
#include <edit/readline/history.h>
90
#endif /* if defined(HAVE_EDIT_READLINE_HISTORY_H) */
91
#elif defined(HAVE_EDITLINE_READLINE_H)
92
#include <editline/readline.h>
93
#else /* if defined(HAVE_EDIT_READLINE_READLINE_H) */
94
#include <readline/history.h>
95
#include <readline/readline.h>
96 97
#endif /* if defined(HAVE_EDIT_READLINE_READLINE_H) */
#endif /* if defined(HAVE_READLINE) */
98

Evan Hunt's avatar
Evan Hunt committed
99 100 101 102 103
#define MAXCMD	     (128 * 1024)
#define MAXWIRE	     (64 * 1024)
#define PACKETSIZE   ((64 * 1024) - 1)
#define INITTEXT     (2 * 1024)
#define MAXTEXT	     (128 * 1024)
Michael Sawyer's avatar
Michael Sawyer committed
104
#define FIND_TIMEOUT 5
Evan Hunt's avatar
Evan Hunt committed
105
#define TTL_MAX	     2147483647U /* Maximum signed 32 bit integer. */
Michael Sawyer's avatar
Michael Sawyer committed
106

107 108
#define DNSDEFAULTPORT 53

109 110 111
/* Number of addresses to request from bind9_getaddresses() */
#define MAX_SERVERADDRS 4

112
static uint16_t dnsport = DNSDEFAULTPORT;
113

114
#ifndef RESOLV_CONF
Michael Sawyer's avatar
Michael Sawyer committed
115
#define RESOLV_CONF "/etc/resolv.conf"
116
#endif /* ifndef RESOLV_CONF */
Michael Sawyer's avatar
Michael Sawyer committed
117

Evan Hunt's avatar
Evan Hunt committed
118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165
static bool debugging = false, ddebugging = false;
static bool memdebugging = false;
static bool have_ipv4 = false;
static bool have_ipv6 = false;
static bool is_dst_up = false;
static bool usevc = false;
static bool usegsstsig = false;
static bool use_win2k_gsstsig = false;
static bool tried_other_gsstsig = false;
static bool local_only = false;
static isc_taskmgr_t *taskmgr = NULL;
static isc_task_t *global_task = NULL;
static isc_event_t *global_event = NULL;
static isc_log_t *glctx = NULL;
static isc_mem_t *gmctx = NULL;
static dns_dispatchmgr_t *dispatchmgr = NULL;
static dns_requestmgr_t *requestmgr = NULL;
static isc_socketmgr_t *socketmgr = NULL;
static isc_timermgr_t *timermgr = NULL;
static dns_dispatch_t *dispatchv4 = NULL;
static dns_dispatch_t *dispatchv6 = NULL;
static dns_message_t *updatemsg = NULL;
static dns_fixedname_t fuserzone;
static dns_fixedname_t fzname;
static dns_name_t *userzone = NULL;
static dns_name_t *zname = NULL;
static dns_name_t tmpzonename = DNS_NAME_INITEMPTY;
static dns_name_t restart_master = DNS_NAME_INITEMPTY;
static dns_tsig_keyring_t *gssring = NULL;
static dns_tsigkey_t *tsigkey = NULL;
static dst_key_t *sig0key = NULL;
static isc_sockaddr_t *servers = NULL;
static isc_sockaddr_t *master_servers = NULL;
static bool default_servers = true;
static int ns_inuse = 0;
static int master_inuse = 0;
static int ns_total = 0;
static int ns_alloc = 0;
static int master_total = 0;
static int master_alloc = 0;
static isc_sockaddr_t *localaddr4 = NULL;
static isc_sockaddr_t *localaddr6 = NULL;
static const char *keyfile = NULL;
static char *keystr = NULL;
static bool shuttingdown = false;
static FILE *input;
static bool interactive = true;
static bool seenerror = false;
Danny Mayer's avatar
Danny Mayer committed
166
static const dns_master_style_t *style;
Evan Hunt's avatar
Evan Hunt committed
167 168 169 170 171 172 173 174 175 176 177
static int requests = 0;
static unsigned int logdebuglevel = 0;
static unsigned int timeout = 300;
static unsigned int udp_timeout = 3;
static unsigned int udp_retries = 3;
static dns_rdataclass_t defaultclass = dns_rdataclass_in;
static dns_rdataclass_t zoneclass = dns_rdataclass_none;
static dns_message_t *answer = NULL;
static uint32_t default_ttl = 0;
static bool default_ttl_set = false;
static bool checknames = true;
Brian Wellington's avatar
Brian Wellington committed
178

179
typedef struct nsu_requestinfo {
Evan Hunt's avatar
Evan Hunt committed
180
	dns_message_t *msg;
181 182 183
	isc_sockaddr_t *addr;
} nsu_requestinfo_t;

Ondřej Surý's avatar
Ondřej Surý committed
184 185 186 187 188
static void
sendrequest(isc_sockaddr_t *destaddr, dns_message_t *msg,
	    dns_request_t **request);
static void
send_update(dns_name_t *zonename, isc_sockaddr_t *master);
Francis Dupont's avatar
Francis Dupont committed
189

Ondřej Surý's avatar
Ondřej Surý committed
190 191
ISC_PLATFORM_NORETURN_PRE static void
fatal(const char *format, ...)
192
	ISC_FORMAT_PRINTF(1, 2) ISC_PLATFORM_NORETURN_POST;
193

Ondřej Surý's avatar
Ondřej Surý committed
194 195
static void
debug(const char *format, ...) ISC_FORMAT_PRINTF(1, 2);
196

Ondřej Surý's avatar
Ondřej Surý committed
197 198
static void
ddebug(const char *format, ...) ISC_FORMAT_PRINTF(1, 2);
Michael Sawyer's avatar
Michael Sawyer committed
199

200 201 202
#ifdef GSSAPI
static dns_fixedname_t fkname;
static isc_sockaddr_t *kserver = NULL;
Evan Hunt's avatar
Evan Hunt committed
203 204 205
static char *realm = NULL;
static char servicename[DNS_NAME_FORMATSIZE];
static dns_name_t *keyname;
206
typedef struct nsu_gssinfo {
Evan Hunt's avatar
Evan Hunt committed
207
	dns_message_t *msg;
208
	isc_sockaddr_t *addr;
Evan Hunt's avatar
Evan Hunt committed
209
	gss_ctx_id_t context;
210 211
} nsu_gssinfo_t;

Ondřej Surý's avatar
Ondřej Surý committed
212 213 214 215 216 217 218 219 220
static void
failed_gssrequest();
static void
start_gssrequest(dns_name_t *master);
static void
send_gssrequest(isc_sockaddr_t *destaddr, dns_message_t *msg,
		dns_request_t **request, gss_ctx_id_t context);
static void
recvgss(isc_task_t *task, isc_event_t *event);
221 222
#endif /* GSSAPI */

Ondřej Surý's avatar
Ondřej Surý committed
223 224
static void
error(const char *format, ...) ISC_FORMAT_PRINTF(1, 2);
225

Evan Hunt's avatar
Evan Hunt committed
226 227 228
#define STATUS_MORE   (uint16_t)0
#define STATUS_SEND   (uint16_t)1
#define STATUS_QUIT   (uint16_t)2
229
#define STATUS_SYNTAX (uint16_t)3
Michael Sawyer's avatar
Michael Sawyer committed
230

231
static void
Evan Hunt's avatar
Evan Hunt committed
232
master_from_servers(void) {
233
	if (master_servers != NULL && master_servers != servers) {
234
		isc_mem_put(gmctx, master_servers,
235
			    master_alloc * sizeof(isc_sockaddr_t));
236
	}
237 238
	master_servers = servers;
	master_total = ns_total;
239
	master_alloc = ns_alloc;
240 241
	master_inuse = ns_inuse;
}
242

243
static dns_rdataclass_t
Evan Hunt's avatar
Evan Hunt committed
244
getzoneclass(void) {
245
	if (zoneclass == dns_rdataclass_none) {
246
		zoneclass = defaultclass;
247
	}
248 249 250
	return (zoneclass);
}

251
static bool
Evan Hunt's avatar
Evan Hunt committed
252 253 254
setzoneclass(dns_rdataclass_t rdclass) {
	if (zoneclass == dns_rdataclass_none || rdclass == dns_rdataclass_none)
	{
255
		zoneclass = rdclass;
256 257
	}
	if (zoneclass != rdclass) {
258
		return (false);
259
	}
260
	return (true);
261 262
}

Michael Sawyer's avatar
Michael Sawyer committed
263
static void
Evan Hunt's avatar
Evan Hunt committed
264
fatal(const char *format, ...) {
Michael Sawyer's avatar
Michael Sawyer committed
265 266
	va_list args;

267
	va_start(args, format);
Michael Sawyer's avatar
Michael Sawyer committed
268 269 270
	vfprintf(stderr, format, args);
	va_end(args);
	fprintf(stderr, "\n");
Brian Wellington's avatar
Brian Wellington committed
271
	exit(1);
Michael Sawyer's avatar
Michael Sawyer committed
272 273
}

274
static void
Evan Hunt's avatar
Evan Hunt committed
275
error(const char *format, ...) {
276 277 278 279 280 281 282 283
	va_list args;

	va_start(args, format);
	vfprintf(stderr, format, args);
	va_end(args);
	fprintf(stderr, "\n");
}

Michael Sawyer's avatar
Michael Sawyer committed
284
static void
Evan Hunt's avatar
Evan Hunt committed
285
debug(const char *format, ...) {
Michael Sawyer's avatar
Michael Sawyer committed
286 287 288
	va_list args;

	if (debugging) {
289
		va_start(args, format);
Michael Sawyer's avatar
Michael Sawyer committed
290 291 292 293 294 295
		vfprintf(stderr, format, args);
		va_end(args);
		fprintf(stderr, "\n");
	}
}

296
static void
Evan Hunt's avatar
Evan Hunt committed
297
ddebug(const char *format, ...) {
298 299 300
	va_list args;

	if (ddebugging) {
301
		va_start(args, format);
302 303 304 305 306 307
		vfprintf(stderr, format, args);
		va_end(args);
		fprintf(stderr, "\n");
	}
}

308
static inline void
Evan Hunt's avatar
Evan Hunt committed
309
check_result(isc_result_t result, const char *msg) {
310
	if (result != ISC_R_SUCCESS) {
Michael Sawyer's avatar
Michael Sawyer committed
311
		fatal("%s: %s", msg, isc_result_totext(result));
312
	}
Michael Sawyer's avatar
Michael Sawyer committed
313 314
}

315
static char *
Evan Hunt's avatar
Evan Hunt committed
316
nsu_strsep(char **stringp, const char *delim) {
317
	char *string = *stringp;
318
	*stringp = NULL;
Evan Hunt's avatar
Evan Hunt committed
319
	char *s;
320
	const char *d;
Evan Hunt's avatar
Evan Hunt committed
321
	char sc, dc;
322

323
	if (string == NULL) {
324
		return (NULL);
325
	}
326

327 328 329
	for (; *string != '\0'; string++) {
		sc = *string;
		for (d = delim; (dc = *d) != '\0'; d++) {
330
			if (sc == dc) {
331
				break;
332
			}
333
		}
334
		if (dc == 0) {
335
			break;
336
		}
337 338
	}

339 340
	for (s = string; *s != '\0'; s++) {
		sc = *s;
341
		for (d = delim; (dc = *d) != '\0'; d++) {
342 343 344 345 346
			if (sc == dc) {
				*s++ = '\0';
				*stringp = s;
				return (string);
			}
347
		}
348 349 350 351
	}
	return (string);
}

Michael Sawyer's avatar
Michael Sawyer committed
352
static void
Evan Hunt's avatar
Evan Hunt committed
353
reset_system(void) {
Michael Sawyer's avatar
Michael Sawyer committed
354 355
	isc_result_t result;

356
	ddebug("reset_system()");
Michael Sawyer's avatar
Michael Sawyer committed
357
	/* If the update message is still around, destroy it */
358
	if (updatemsg != NULL) {
Brian Wellington's avatar
Brian Wellington committed
359
		dns_message_reset(updatemsg, DNS_MESSAGE_INTENTRENDER);
360
	} else {
361
		result = dns_message_create(gmctx, DNS_MESSAGE_INTENTRENDER,
Brian Wellington's avatar
Brian Wellington committed
362
					    &updatemsg);
363
		check_result(result, "dns_message_create");
Brian Wellington's avatar
Brian Wellington committed
364
	}
Michael Sawyer's avatar
Michael Sawyer committed
365
	updatemsg->opcode = dns_opcode_update;
366
	if (usegsstsig) {
367
		if (tsigkey != NULL) {
368
			dns_tsigkey_detach(&tsigkey);
369 370
		}
		if (gssring != NULL) {
371
			dns_tsigkeyring_detach(&gssring);
372
		}
373
		tried_other_gsstsig = false;
374
	}
Michael Sawyer's avatar
Michael Sawyer committed
375 376
}

377
static bool
378
parse_hmac(const dns_name_t **hmac, const char *hmacstr, size_t len,
Evan Hunt's avatar
Evan Hunt committed
379 380
	   uint16_t *digestbitsp) {
	uint16_t digestbits = 0;
381
	isc_result_t result;
Evan Hunt's avatar
Evan Hunt committed
382
	char buf[20];
383 384 385 386

	REQUIRE(hmac != NULL && *hmac == NULL);
	REQUIRE(hmacstr != NULL);

387 388
	if (len >= sizeof(buf)) {
		error("unknown key type '%.*s'", (int)(len), hmacstr);
389
		return (false);
390
	}
391

392 393
	/* Copy len bytes and NUL terminate. */
	strlcpy(buf, hmacstr, ISC_MIN(len + 1, sizeof(buf)));
Automatic Updater's avatar
Automatic Updater committed
394

395 396 397 398 399
	if (strcasecmp(buf, "hmac-md5") == 0) {
		*hmac = DNS_TSIG_HMACMD5_NAME;
	} else if (strncasecmp(buf, "hmac-md5-", 9) == 0) {
		*hmac = DNS_TSIG_HMACMD5_NAME;
		result = isc_parse_uint16(&digestbits, &buf[9], 10);
400 401
		if (result != ISC_R_SUCCESS || digestbits > 128) {
			error("digest-bits out of range [0..128]");
402
			return (false);
403 404
		}
		*digestbitsp = (digestbits + 7) & ~0x7U;
Ondřej Surý's avatar
Ondřej Surý committed
405
	} else if (strcasecmp(buf, "hmac-sha1") == 0) {
406 407 408 409
		*hmac = DNS_TSIG_HMACSHA1_NAME;
	} else if (strncasecmp(buf, "hmac-sha1-", 10) == 0) {
		*hmac = DNS_TSIG_HMACSHA1_NAME;
		result = isc_parse_uint16(&digestbits, &buf[10], 10);
410 411
		if (result != ISC_R_SUCCESS || digestbits > 160) {
			error("digest-bits out of range [0..160]");
412
			return (false);
413 414
		}
		*digestbitsp = (digestbits + 7) & ~0x7U;
415 416 417 418 419
	} else if (strcasecmp(buf, "hmac-sha224") == 0) {
		*hmac = DNS_TSIG_HMACSHA224_NAME;
	} else if (strncasecmp(buf, "hmac-sha224-", 12) == 0) {
		*hmac = DNS_TSIG_HMACSHA224_NAME;
		result = isc_parse_uint16(&digestbits, &buf[12], 10);
420 421
		if (result != ISC_R_SUCCESS || digestbits > 224) {
			error("digest-bits out of range [0..224]");
422
			return (false);
423 424
		}
		*digestbitsp = (digestbits + 7) & ~0x7U;
425 426 427 428 429
	} else if (strcasecmp(buf, "hmac-sha256") == 0) {
		*hmac = DNS_TSIG_HMACSHA256_NAME;
	} else if (strncasecmp(buf, "hmac-sha256-", 12) == 0) {
		*hmac = DNS_TSIG_HMACSHA256_NAME;
		result = isc_parse_uint16(&digestbits, &buf[12], 10);
430 431
		if (result != ISC_R_SUCCESS || digestbits > 256) {
			error("digest-bits out of range [0..256]");
432
			return (false);
433 434
		}
		*digestbitsp = (digestbits + 7) & ~0x7U;
435 436 437 438 439
	} else if (strcasecmp(buf, "hmac-sha384") == 0) {
		*hmac = DNS_TSIG_HMACSHA384_NAME;
	} else if (strncasecmp(buf, "hmac-sha384-", 12) == 0) {
		*hmac = DNS_TSIG_HMACSHA384_NAME;
		result = isc_parse_uint16(&digestbits, &buf[12], 10);
440 441
		if (result != ISC_R_SUCCESS || digestbits > 384) {
			error("digest-bits out of range [0..384]");
442
			return (false);
443 444
		}
		*digestbitsp = (digestbits + 7) & ~0x7U;
445 446 447 448 449
	} else if (strcasecmp(buf, "hmac-sha512") == 0) {
		*hmac = DNS_TSIG_HMACSHA512_NAME;
	} else if (strncasecmp(buf, "hmac-sha512-", 12) == 0) {
		*hmac = DNS_TSIG_HMACSHA512_NAME;
		result = isc_parse_uint16(&digestbits, &buf[12], 10);
450 451
		if (result != ISC_R_SUCCESS || digestbits > 512) {
			error("digest-bits out of range [0..512]");
452
			return (false);
453 454 455 456
		}
		*digestbitsp = (digestbits + 7) & ~0x7U;
	} else {
		error("unknown key type '%s'", buf);
457
		return (false);
458
	}
459
	return (true);
460 461
}

462
static int
Evan Hunt's avatar
Evan Hunt committed
463
basenamelen(const char *file) {
Automatic Updater's avatar
Automatic Updater committed
464 465
	int len = strlen(file);

466
	if (len > 1 && file[len - 1] == '.') {
Automatic Updater's avatar
Automatic Updater committed
467
		len -= 1;
468
	} else if (len > 8 && strcmp(file + len - 8, ".private") == 0) {
Automatic Updater's avatar
Automatic Updater committed
469
		len -= 8;
470
	} else if (len > 4 && strcmp(file + len - 4, ".key") == 0) {
Automatic Updater's avatar
Automatic Updater committed
471
		len -= 4;
472
	}
473 474 475
	return (len);
}

476
static void
Evan Hunt's avatar
Evan Hunt committed
477 478 479 480 481 482 483 484 485 486 487
setup_keystr(void) {
	unsigned char *secret = NULL;
	int secretlen;
	isc_buffer_t secretbuf;
	isc_result_t result;
	isc_buffer_t keynamesrc;
	char *secretstr;
	char *s, *n;
	dns_fixedname_t fkeyname;
	dns_name_t *mykeyname;
	char *name;
488
	const dns_name_t *hmacname = NULL;
Evan Hunt's avatar
Evan Hunt committed
489
	uint16_t digestbits = 0;
490

491
	mykeyname = dns_fixedname_initname(&fkeyname);
492

493
	debug("Creating key...");
494

495
	s = strchr(keystr, ':');
496
	if (s == NULL || s == keystr || s[1] == 0) {
497
		fatal("key option must specify [hmac:]keyname:secret");
498
	}
499
	secretstr = s + 1;
500 501
	n = strchr(secretstr, ':');
	if (n != NULL) {
502
		if (n == secretstr || n[1] == 0) {
503
			fatal("key option must specify [hmac:]keyname:secret");
504
		}
505 506
		name = secretstr;
		secretstr = n + 1;
507 508 509
		if (!parse_hmac(&hmacname, keystr, s - keystr, &digestbits)) {
			exit(1);
		}
510 511 512 513 514
	} else {
		hmacname = DNS_TSIG_HMACMD5_NAME;
		name = keystr;
		n = s;
	}
515

516 517
	isc_buffer_init(&keynamesrc, name, (unsigned int)(n - name));
	isc_buffer_add(&keynamesrc, (unsigned int)(n - name));
518

519
	debug("namefromtext");
520 521
	result = dns_name_fromtext(mykeyname, &keynamesrc, dns_rootname, 0,
				   NULL);
522
	check_result(result, "dns_name_fromtext");
523

524
	secretlen = strlen(secretstr) * 3 / 4;
525
	secret = isc_mem_allocate(gmctx, secretlen);
526

527 528 529
	isc_buffer_init(&secretbuf, secret, secretlen);
	result = isc_base64_decodestring(secretstr, &secretbuf);
	if (result != ISC_R_SUCCESS) {
530 531
		fprintf(stderr, "could not create key from %s: %s\n", keystr,
			isc_result_totext(result));
532
		goto failure;
533
	}
534

535 536
	secretlen = isc_buffer_usedlength(&secretbuf);

537
	debug("keycreate");
538
	result = dns_tsigkey_create(mykeyname, hmacname, secret, secretlen,
539
				    false, NULL, 0, 0, gmctx, NULL, &tsigkey);
540
	if (result != ISC_R_SUCCESS) {
541 542
		fprintf(stderr, "could not create key from %s: %s\n", keystr,
			dns_result_totext(result));
543
	} else {
544
		dst_key_setbits(tsigkey->key, digestbits);
545
	}
546
failure:
547
	if (secret != NULL) {
548
		isc_mem_free(gmctx, secret);
549
	}
550 551
}

552 553 554 555
/*
 * Get a key from a named.conf format keyfile
 */
static isc_result_t
Evan Hunt's avatar
Evan Hunt committed
556 557 558
read_sessionkey(isc_mem_t *mctx, isc_log_t *lctx) {
	cfg_parser_t *pctx = NULL;
	cfg_obj_t *sessionkey = NULL;
559 560 561
	const cfg_obj_t *key = NULL;
	const cfg_obj_t *secretobj = NULL;
	const cfg_obj_t *algorithmobj = NULL;
Evan Hunt's avatar
Evan Hunt committed
562 563 564 565 566
	const char *mykeyname;
	const char *secretstr;
	const char *algorithm;
	isc_result_t result;
	int len;
567

568
	if (!isc_file_exists(keyfile)) {
569
		return (ISC_R_FILENOTFOUND);
570
	}
571 572

	result = cfg_parser_create(mctx, lctx, &pctx);
573
	if (result != ISC_R_SUCCESS) {
574
		goto cleanup;
575
	}
576

577
	result = cfg_parse_file(pctx, keyfile, &cfg_type_sessionkey,
Automatic Updater's avatar
Automatic Updater committed
578
				&sessionkey);
579
	if (result != ISC_R_SUCCESS) {
580
		goto cleanup;
581
	}
582

583
	result = cfg_map_get(sessionkey, "key", &key);
584
	if (result != ISC_R_SUCCESS) {
585
		goto cleanup;
586
	}
587

588 589
	(void)cfg_map_get(key, "secret", &secretobj);
	(void)cfg_map_get(key, "algorithm", &algorithmobj);
590
	if (secretobj == NULL || algorithmobj == NULL) {
591
		fatal("key must have algorithm and secret");
592
	}
593

594
	mykeyname = cfg_obj_asstring(cfg_map_getname(key));
595 596 597
	secretstr = cfg_obj_asstring(secretobj);
	algorithm = cfg_obj_asstring(algorithmobj);

598
	len = strlen(algorithm) + strlen(mykeyname) + strlen(secretstr) + 3;
599
	keystr = isc_mem_allocate(mctx, len);
600
	snprintf(keystr, len, "%s:%s:%s", algorithm, mykeyname, secretstr);
601 602
	setup_keystr();

603
cleanup:
604
	if (pctx != NULL) {
605
		if (sessionkey != NULL) {
606
			cfg_obj_destroy(pctx, &sessionkey);
607
		}
608 609 610
		cfg_parser_destroy(&pctx);
	}

611
	if (keystr != NULL) {
612
		isc_mem_free(mctx, keystr);
613
	}
614 615 616 617

	return (result);
}

618
static void
Evan Hunt's avatar
Evan Hunt committed
619 620 621
setup_keyfile(isc_mem_t *mctx, isc_log_t *lctx) {
	dst_key_t *dstkey = NULL;
	isc_result_t result;
622
	const dns_name_t *hmacname = NULL;
623 624 625

	debug("Creating key...");

626
	if (sig0key != NULL) {
627
		dst_key_free(&sig0key);
628
	}
629

630
	/* Try reading the key from a K* pair */
631 632
	result = dst_key_fromnamedfile(
		keyfile, NULL, DST_TYPE_PRIVATE | DST_TYPE_KEY, mctx, &dstkey);
633

634
	/* If that didn't work, try reading it as a session.key keyfile */
635
	if (result != ISC_R_SUCCESS) {
636
		result = read_sessionkey(mctx, lctx);
637
		if (result == ISC_R_SUCCESS) {
638
			return;
639
		}
640 641
	}

642
	if (result != ISC_R_SUCCESS) {
643 644 645 646 647
		fprintf(stderr,
			"could not read key from %.*s.{private,key}: "
			"%s\n",
			basenamelen(keyfile), keyfile,
			isc_result_totext(result));
648 649
		return;
	}
650

651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671
	switch (dst_key_alg(dstkey)) {
	case DST_ALG_HMACMD5:
		hmacname = DNS_TSIG_HMACMD5_NAME;
		break;
	case DST_ALG_HMACSHA1:
		hmacname = DNS_TSIG_HMACSHA1_NAME;
		break;
	case DST_ALG_HMACSHA224:
		hmacname = DNS_TSIG_HMACSHA224_NAME;
		break;
	case DST_ALG_HMACSHA256:
		hmacname = DNS_TSIG_HMACSHA256_NAME;
		break;
	case DST_ALG_HMACSHA384:
		hmacname = DNS_TSIG_HMACSHA384_NAME;
		break;
	case DST_ALG_HMACSHA512:
		hmacname = DNS_TSIG_HMACSHA512_NAME;
		break;
	}
	if (hmacname != NULL) {
672 673 674
		result = dns_tsigkey_createfromkey(
			dst_key_name(dstkey), hmacname, dstkey, false, NULL, 0,
			0, mctx, NULL, &tsigkey);
675
		dst_key_free(&dstkey);
676 677 678 679 680
		if (result != ISC_R_SUCCESS) {
			fprintf(stderr, "could not create key from %s: %s\n",
				keyfile, isc_result_totext(result));
			return;
		}
681
	} else {
682
		dst_key_attach(dstkey, &sig0key);
683 684
		dst_key_free(&dstkey);
	}
685 686
}

687
static void
Evan Hunt's avatar
Evan Hunt committed
688
doshutdown(void) {
689
	isc_task_detach(&global_task);
690

691 692
	/*
	 * The isc_mem_put of master_servers must be before the
Mark Andrews's avatar
Mark Andrews committed
693 694
	 * isc_mem_put of servers as it sets the servers pointer
	 * to NULL.
695
	 */
696
	if (master_servers != NULL && master_servers != servers) {
697
		isc_mem_put(gmctx, master_servers,
698
			    master_alloc * sizeof(isc_sockaddr_t));
699
	}
700

701
	if (servers != NULL) {
702
		isc_mem_put(gmctx, servers, ns_alloc * sizeof(isc_sockaddr_t));
703
	}
704

705
	if (localaddr4 != NULL) {
706
		isc_mem_put(gmctx, localaddr4, sizeof(isc_sockaddr_t));
707
	}
708

709
	if (localaddr6 != NULL) {
710
		isc_mem_put(gmctx, localaddr6, sizeof(isc_sockaddr_t));
711
	}
712

713 714 715 716 717 718 719 720
	if (tsigkey != NULL) {
		ddebug("Freeing TSIG key");
		dns_tsigkey_detach(&tsigkey);
	}

	if (sig0key != NULL) {
		ddebug("Freeing SIG(0) key");
		dst_key_free(&sig0key);
721 722
	}

723
	if (updatemsg != NULL) {
724
		dns_message_destroy(&updatemsg);
725
	}
726 727

	if (is_dst_up) {
728
		ddebug("Destroy DST lib");
729
		dst_lib_destroy();
730
		is_dst_up = false;
731 732
	}

733
	ddebug("Destroying request manager");
734 735 736
	dns_requestmgr_detach(&requestmgr);

	ddebug("Freeing the dispatchers");
737
	if (have_ipv4) {
738
		dns_dispatch_detach(&dispatchv4);
739 740
	}
	if (have_ipv6) {
741
		dns_dispatch_detach(&dispatchv6);
742
	}
743 744 745

	ddebug("Shutting down dispatch manager");
	dns_dispatchmgr_destroy(&dispatchmgr);
746 747
}

748
static void
Evan Hunt's avatar
Evan Hunt committed
749
maybeshutdown(void) {
750 751 752
	ddebug("Shutting down request manager");
	dns_requestmgr_shutdown(requestmgr);

753
	if (requests != 0) {
754
		return;
755
	}
756 757 758 759 760

	doshutdown();
}

static void
Evan Hunt's avatar
Evan Hunt committed
761
shutdown_program(isc_task_t *task, isc_event_t *event) {
762 763 764 765 766 767
	REQUIRE(task == global_task);
	UNUSED(task);

	ddebug("shutdown_program()");
	isc_event_free(&event);

768
	shuttingdown = true;