nsupdate.c revision 222395
1351278Sdim/*
2351278Sdim * Copyright (C) 2004-2010  Internet Systems Consortium, Inc. ("ISC")
3351278Sdim * Copyright (C) 2000-2003  Internet Software Consortium.
4351278Sdim *
5351278Sdim * Permission to use, copy, modify, and/or distribute this software for any
6351278Sdim * purpose with or without fee is hereby granted, provided that the above
7351278Sdim * copyright notice and this permission notice appear in all copies.
8351278Sdim *
9351278Sdim * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
10351278Sdim * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
11351278Sdim * AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
12351278Sdim * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
13351278Sdim * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
14351278Sdim * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
15351278Sdim * PERFORMANCE OF THIS SOFTWARE.
16351278Sdim */
17360784Sdim
18351278Sdim/* $Id: nsupdate.c,v 1.163.48.15 2010-12-09 04:30:57 tbox Exp $ */
19351278Sdim
20351278Sdim/*! \file */
21351278Sdim
22351278Sdim#include <config.h>
23351278Sdim
24351278Sdim#include <ctype.h>
25351278Sdim#include <errno.h>
26351278Sdim#include <limits.h>
27351278Sdim#include <stdlib.h>
28351278Sdim#include <unistd.h>
29351278Sdim
30351278Sdim#include <isc/app.h>
31351278Sdim#include <isc/base64.h>
32351278Sdim#include <isc/buffer.h>
33351278Sdim#include <isc/commandline.h>
34351278Sdim#include <isc/entropy.h>
35351278Sdim#include <isc/event.h>
36351278Sdim#include <isc/hash.h>
37351278Sdim#include <isc/lex.h>
38351278Sdim#include <isc/log.h>
39351278Sdim#include <isc/mem.h>
40351278Sdim#include <isc/parseint.h>
41351278Sdim#include <isc/print.h>
42351278Sdim#include <isc/random.h>
43351278Sdim#include <isc/region.h>
44351278Sdim#include <isc/sockaddr.h>
45351278Sdim#include <isc/socket.h>
46351278Sdim#include <isc/stdio.h>
47351278Sdim#include <isc/string.h>
48351278Sdim#include <isc/task.h>
49351278Sdim#include <isc/timer.h>
50351278Sdim#include <isc/types.h>
51351278Sdim#include <isc/util.h>
52351278Sdim
53351278Sdim#include <dns/callbacks.h>
54351278Sdim#include <dns/dispatch.h>
55351278Sdim#include <dns/dnssec.h>
56351278Sdim#include <dns/events.h>
57351278Sdim#include <dns/fixedname.h>
58351278Sdim#include <dns/log.h>
59351278Sdim#include <dns/masterdump.h>
60351278Sdim#include <dns/message.h>
61351278Sdim#include <dns/name.h>
62351278Sdim#include <dns/rcode.h>
63351278Sdim#include <dns/rdata.h>
64351278Sdim#include <dns/rdataclass.h>
65351278Sdim#include <dns/rdatalist.h>
66351278Sdim#include <dns/rdataset.h>
67351278Sdim#include <dns/rdatastruct.h>
68360784Sdim#include <dns/rdatatype.h>
69360784Sdim#include <dns/request.h>
70351278Sdim#include <dns/result.h>
71351278Sdim#include <dns/tkey.h>
72351278Sdim#include <dns/tsig.h>
73351278Sdim
74351278Sdim#include <dst/dst.h>
75351278Sdim
76351278Sdim#include <lwres/lwres.h>
77351278Sdim#include <lwres/net.h>
78351278Sdim
79351278Sdim#ifdef GSSAPI
80351278Sdim#include <dst/gssapi.h>
81351278Sdim#endif
82#include <bind9/getaddresses.h>
83
84
85#ifdef HAVE_ADDRINFO
86#ifdef HAVE_GETADDRINFO
87#ifdef HAVE_GAISTRERROR
88#define USE_GETADDRINFO
89#endif
90#endif
91#endif
92
93#ifndef USE_GETADDRINFO
94#ifndef ISC_PLATFORM_NONSTDHERRNO
95extern int h_errno;
96#endif
97#endif
98
99#define MAXCMD (4 * 1024)
100#define MAXWIRE (64 * 1024)
101#define PACKETSIZE ((64 * 1024) - 1)
102#define INITTEXT (2 * 1024)
103#define MAXTEXT (128 * 1024)
104#define FIND_TIMEOUT 5
105#define TTL_MAX 2147483647U	/* Maximum signed 32 bit integer. */
106
107#define DNSDEFAULTPORT 53
108
109#ifndef RESOLV_CONF
110#define RESOLV_CONF "/etc/resolv.conf"
111#endif
112
113static isc_boolean_t debugging = ISC_FALSE, ddebugging = ISC_FALSE;
114static isc_boolean_t memdebugging = ISC_FALSE;
115static isc_boolean_t have_ipv4 = ISC_FALSE;
116static isc_boolean_t have_ipv6 = ISC_FALSE;
117static isc_boolean_t is_dst_up = ISC_FALSE;
118static isc_boolean_t usevc = ISC_FALSE;
119static isc_boolean_t usegsstsig = ISC_FALSE;
120static isc_boolean_t use_win2k_gsstsig = ISC_FALSE;
121static isc_boolean_t tried_other_gsstsig = ISC_FALSE;
122static isc_taskmgr_t *taskmgr = NULL;
123static isc_task_t *global_task = NULL;
124static isc_event_t *global_event = NULL;
125static isc_log_t *lctx = NULL;
126static isc_mem_t *mctx = NULL;
127static dns_dispatchmgr_t *dispatchmgr = NULL;
128static dns_requestmgr_t *requestmgr = NULL;
129static isc_socketmgr_t *socketmgr = NULL;
130static isc_timermgr_t *timermgr = NULL;
131static dns_dispatch_t *dispatchv4 = NULL;
132static dns_dispatch_t *dispatchv6 = NULL;
133static dns_message_t *updatemsg = NULL;
134static dns_fixedname_t fuserzone;
135static dns_name_t *userzone = NULL;
136static dns_name_t *zonename = NULL;
137static dns_name_t tmpzonename;
138static dns_name_t restart_master;
139static dns_tsig_keyring_t *gssring = NULL;
140static dns_tsigkey_t *tsigkey = NULL;
141static dst_key_t *sig0key;
142static lwres_context_t *lwctx = NULL;
143static lwres_conf_t *lwconf;
144static isc_sockaddr_t *servers;
145static int ns_inuse = 0;
146static int ns_total = 0;
147static isc_sockaddr_t *userserver = NULL;
148static isc_sockaddr_t *localaddr = NULL;
149static isc_sockaddr_t *serveraddr = NULL;
150static isc_sockaddr_t tempaddr;
151static char *keystr = NULL, *keyfile = NULL;
152static isc_entropy_t *entropy = NULL;
153static isc_boolean_t shuttingdown = ISC_FALSE;
154static FILE *input;
155static isc_boolean_t interactive = ISC_TRUE;
156static isc_boolean_t seenerror = ISC_FALSE;
157static const dns_master_style_t *style;
158static int requests = 0;
159static unsigned int logdebuglevel = 0;
160static unsigned int timeout = 300;
161static unsigned int udp_timeout = 3;
162static unsigned int udp_retries = 3;
163static dns_rdataclass_t defaultclass = dns_rdataclass_in;
164static dns_rdataclass_t zoneclass = dns_rdataclass_none;
165static dns_message_t *answer = NULL;
166static isc_uint32_t default_ttl = 0;
167static isc_boolean_t default_ttl_set = ISC_FALSE;
168
169typedef struct nsu_requestinfo {
170	dns_message_t *msg;
171	isc_sockaddr_t *addr;
172} nsu_requestinfo_t;
173
174static void
175sendrequest(isc_sockaddr_t *srcaddr, isc_sockaddr_t *destaddr,
176	    dns_message_t *msg, dns_request_t **request);
177static void
178fatal(const char *format, ...) ISC_FORMAT_PRINTF(1, 2);
179
180static void
181debug(const char *format, ...) ISC_FORMAT_PRINTF(1, 2);
182
183static void
184ddebug(const char *format, ...) ISC_FORMAT_PRINTF(1, 2);
185
186#ifdef GSSAPI
187static dns_fixedname_t fkname;
188static isc_sockaddr_t *kserver = NULL;
189static char *realm = NULL;
190static char servicename[DNS_NAME_FORMATSIZE];
191static dns_name_t *keyname;
192typedef struct nsu_gssinfo {
193	dns_message_t *msg;
194	isc_sockaddr_t *addr;
195	gss_ctx_id_t context;
196} nsu_gssinfo_t;
197
198static void
199start_gssrequest(dns_name_t *master);
200static void
201send_gssrequest(isc_sockaddr_t *srcaddr, isc_sockaddr_t *destaddr,
202		dns_message_t *msg, dns_request_t **request,
203		gss_ctx_id_t context);
204static void
205recvgss(isc_task_t *task, isc_event_t *event);
206#endif /* GSSAPI */
207
208static void
209error(const char *format, ...) ISC_FORMAT_PRINTF(1, 2);
210
211#define STATUS_MORE	(isc_uint16_t)0
212#define STATUS_SEND	(isc_uint16_t)1
213#define STATUS_QUIT	(isc_uint16_t)2
214#define STATUS_SYNTAX	(isc_uint16_t)3
215
216typedef struct entropysource entropysource_t;
217
218struct entropysource {
219	isc_entropysource_t *source;
220	isc_mem_t *mctx;
221	ISC_LINK(entropysource_t) link;
222};
223
224static ISC_LIST(entropysource_t) sources;
225
226static void
227setup_entropy(isc_mem_t *mctx, const char *randomfile, isc_entropy_t **ectx)
228{
229	isc_result_t result;
230	isc_entropysource_t *source = NULL;
231	entropysource_t *elt;
232	int usekeyboard = ISC_ENTROPY_KEYBOARDMAYBE;
233
234	REQUIRE(ectx != NULL);
235
236	if (*ectx == NULL) {
237		result = isc_entropy_create(mctx, ectx);
238		if (result != ISC_R_SUCCESS)
239			fatal("could not create entropy object");
240		ISC_LIST_INIT(sources);
241	}
242
243	if (randomfile != NULL && strcmp(randomfile, "keyboard") == 0) {
244		usekeyboard = ISC_ENTROPY_KEYBOARDYES;
245		randomfile = NULL;
246	}
247
248	result = isc_entropy_usebestsource(*ectx, &source, randomfile,
249					   usekeyboard);
250
251	if (result != ISC_R_SUCCESS)
252		fatal("could not initialize entropy source: %s",
253		      isc_result_totext(result));
254
255	if (source != NULL) {
256		elt = isc_mem_get(mctx, sizeof(*elt));
257		if (elt == NULL)
258			fatal("out of memory");
259		elt->source = source;
260		elt->mctx = mctx;
261		ISC_LINK_INIT(elt, link);
262		ISC_LIST_APPEND(sources, elt, link);
263	}
264}
265
266static void
267cleanup_entropy(isc_entropy_t **ectx) {
268	entropysource_t *source;
269	while (!ISC_LIST_EMPTY(sources)) {
270		source = ISC_LIST_HEAD(sources);
271		ISC_LIST_UNLINK(sources, source, link);
272		isc_entropy_destroysource(&source->source);
273		isc_mem_put(source->mctx, source, sizeof(*source));
274	}
275	isc_entropy_detach(ectx);
276}
277
278
279static dns_rdataclass_t
280getzoneclass(void) {
281	if (zoneclass == dns_rdataclass_none)
282		zoneclass = defaultclass;
283	return (zoneclass);
284}
285
286static isc_boolean_t
287setzoneclass(dns_rdataclass_t rdclass) {
288	if (zoneclass == dns_rdataclass_none ||
289	    rdclass == dns_rdataclass_none)
290		zoneclass = rdclass;
291	if (zoneclass != rdclass)
292		return (ISC_FALSE);
293	return (ISC_TRUE);
294}
295
296static void
297fatal(const char *format, ...) {
298	va_list args;
299
300	va_start(args, format);
301	vfprintf(stderr, format, args);
302	va_end(args);
303	fprintf(stderr, "\n");
304	exit(1);
305}
306
307static void
308error(const char *format, ...) {
309	va_list args;
310
311	va_start(args, format);
312	vfprintf(stderr, format, args);
313	va_end(args);
314	fprintf(stderr, "\n");
315}
316
317static void
318debug(const char *format, ...) {
319	va_list args;
320
321	if (debugging) {
322		va_start(args, format);
323		vfprintf(stderr, format, args);
324		va_end(args);
325		fprintf(stderr, "\n");
326	}
327}
328
329static void
330ddebug(const char *format, ...) {
331	va_list args;
332
333	if (ddebugging) {
334		va_start(args, format);
335		vfprintf(stderr, format, args);
336		va_end(args);
337		fprintf(stderr, "\n");
338	}
339}
340
341static inline void
342check_result(isc_result_t result, const char *msg) {
343	if (result != ISC_R_SUCCESS)
344		fatal("%s: %s", msg, isc_result_totext(result));
345}
346
347static void *
348mem_alloc(void *arg, size_t size) {
349	return (isc_mem_get(arg, size));
350}
351
352static void
353mem_free(void *arg, void *mem, size_t size) {
354	isc_mem_put(arg, mem, size);
355}
356
357static char *
358nsu_strsep(char **stringp, const char *delim) {
359	char *string = *stringp;
360	char *s;
361	const char *d;
362	char sc, dc;
363
364	if (string == NULL)
365		return (NULL);
366
367	for (; *string != '\0'; string++) {
368		sc = *string;
369		for (d = delim; (dc = *d) != '\0'; d++) {
370			if (sc == dc)
371				break;
372		}
373		if (dc == 0)
374			break;
375	}
376
377	for (s = string; *s != '\0'; s++) {
378		sc = *s;
379		for (d = delim; (dc = *d) != '\0'; d++) {
380			if (sc == dc) {
381				*s++ = '\0';
382				*stringp = s;
383				return (string);
384			}
385		}
386	}
387	*stringp = NULL;
388	return (string);
389}
390
391static void
392reset_system(void) {
393	isc_result_t result;
394
395	ddebug("reset_system()");
396	/* If the update message is still around, destroy it */
397	if (updatemsg != NULL)
398		dns_message_reset(updatemsg, DNS_MESSAGE_INTENTRENDER);
399	else {
400		result = dns_message_create(mctx, DNS_MESSAGE_INTENTRENDER,
401					    &updatemsg);
402		check_result(result, "dns_message_create");
403	}
404	updatemsg->opcode = dns_opcode_update;
405	if (usegsstsig) {
406		if (tsigkey != NULL)
407			dns_tsigkey_detach(&tsigkey);
408		if (gssring != NULL)
409			dns_tsigkeyring_destroy(&gssring);
410		tried_other_gsstsig = ISC_FALSE;
411	}
412}
413
414static isc_uint16_t
415parse_hmac(dns_name_t **hmac, const char *hmacstr, size_t len) {
416	isc_uint16_t digestbits = 0;
417	isc_result_t result;
418	char buf[20];
419
420	REQUIRE(hmac != NULL && *hmac == NULL);
421	REQUIRE(hmacstr != NULL);
422
423	if (len >= sizeof(buf))
424		fatal("unknown key type '%.*s'", (int)(len), hmacstr);
425
426	strncpy(buf, hmacstr, len);
427	buf[len] = 0;
428
429	if (strcasecmp(buf, "hmac-md5") == 0) {
430		*hmac = DNS_TSIG_HMACMD5_NAME;
431	} else if (strncasecmp(buf, "hmac-md5-", 9) == 0) {
432		*hmac = DNS_TSIG_HMACMD5_NAME;
433		result = isc_parse_uint16(&digestbits, &buf[9], 10);
434		if (result != ISC_R_SUCCESS || digestbits > 128)
435			fatal("digest-bits out of range [0..128]");
436		digestbits = (digestbits +7) & ~0x7U;
437	} else if (strcasecmp(buf, "hmac-sha1") == 0) {
438		*hmac = DNS_TSIG_HMACSHA1_NAME;
439	} else if (strncasecmp(buf, "hmac-sha1-", 10) == 0) {
440		*hmac = DNS_TSIG_HMACSHA1_NAME;
441		result = isc_parse_uint16(&digestbits, &buf[10], 10);
442		if (result != ISC_R_SUCCESS || digestbits > 160)
443			fatal("digest-bits out of range [0..160]");
444		digestbits = (digestbits +7) & ~0x7U;
445	} else if (strcasecmp(buf, "hmac-sha224") == 0) {
446		*hmac = DNS_TSIG_HMACSHA224_NAME;
447	} else if (strncasecmp(buf, "hmac-sha224-", 12) == 0) {
448		*hmac = DNS_TSIG_HMACSHA224_NAME;
449		result = isc_parse_uint16(&digestbits, &buf[12], 10);
450		if (result != ISC_R_SUCCESS || digestbits > 224)
451			fatal("digest-bits out of range [0..224]");
452		digestbits = (digestbits +7) & ~0x7U;
453	} else if (strcasecmp(buf, "hmac-sha256") == 0) {
454		*hmac = DNS_TSIG_HMACSHA256_NAME;
455	} else if (strncasecmp(buf, "hmac-sha256-", 12) == 0) {
456		*hmac = DNS_TSIG_HMACSHA256_NAME;
457		result = isc_parse_uint16(&digestbits, &buf[12], 10);
458		if (result != ISC_R_SUCCESS || digestbits > 256)
459			fatal("digest-bits out of range [0..256]");
460		digestbits = (digestbits +7) & ~0x7U;
461	} else if (strcasecmp(buf, "hmac-sha384") == 0) {
462		*hmac = DNS_TSIG_HMACSHA384_NAME;
463	} else if (strncasecmp(buf, "hmac-sha384-", 12) == 0) {
464		*hmac = DNS_TSIG_HMACSHA384_NAME;
465		result = isc_parse_uint16(&digestbits, &buf[12], 10);
466		if (result != ISC_R_SUCCESS || digestbits > 384)
467			fatal("digest-bits out of range [0..384]");
468		digestbits = (digestbits +7) & ~0x7U;
469	} else if (strcasecmp(buf, "hmac-sha512") == 0) {
470		*hmac = DNS_TSIG_HMACSHA512_NAME;
471	} else if (strncasecmp(buf, "hmac-sha512-", 12) == 0) {
472		*hmac = DNS_TSIG_HMACSHA512_NAME;
473		result = isc_parse_uint16(&digestbits, &buf[12], 10);
474		if (result != ISC_R_SUCCESS || digestbits > 512)
475			fatal("digest-bits out of range [0..512]");
476		digestbits = (digestbits +7) & ~0x7U;
477	} else
478		fatal("unknown key type '%s'", buf);
479	return (digestbits);
480}
481
482static void
483setup_keystr(void) {
484	unsigned char *secret = NULL;
485	int secretlen;
486	isc_buffer_t secretbuf;
487	isc_result_t result;
488	isc_buffer_t keynamesrc;
489	char *secretstr;
490	char *s, *n;
491	dns_fixedname_t fkeyname;
492	dns_name_t *keyname;
493	char *name;
494	dns_name_t *hmacname = NULL;
495	isc_uint16_t digestbits = 0;
496
497	dns_fixedname_init(&fkeyname);
498	keyname = dns_fixedname_name(&fkeyname);
499
500	debug("Creating key...");
501
502	s = strchr(keystr, ':');
503	if (s == NULL || s == keystr || s[1] == 0)
504		fatal("key option must specify [hmac:]keyname:secret");
505	secretstr = s + 1;
506	n = strchr(secretstr, ':');
507	if (n != NULL) {
508		if (n == secretstr || n[1] == 0)
509			fatal("key option must specify [hmac:]keyname:secret");
510		name = secretstr;
511		secretstr = n + 1;
512		digestbits = parse_hmac(&hmacname, keystr, s - keystr);
513	} else {
514		hmacname = DNS_TSIG_HMACMD5_NAME;
515		name = keystr;
516		n = s;
517	}
518
519	isc_buffer_init(&keynamesrc, name, n - name);
520	isc_buffer_add(&keynamesrc, n - name);
521
522	debug("namefromtext");
523	result = dns_name_fromtext(keyname, &keynamesrc, dns_rootname,
524				   ISC_FALSE, NULL);
525	check_result(result, "dns_name_fromtext");
526
527	secretlen = strlen(secretstr) * 3 / 4;
528	secret = isc_mem_allocate(mctx, secretlen);
529	if (secret == NULL)
530		fatal("out of memory");
531
532	isc_buffer_init(&secretbuf, secret, secretlen);
533	result = isc_base64_decodestring(secretstr, &secretbuf);
534	if (result != ISC_R_SUCCESS) {
535		fprintf(stderr, "could not create key from %s: %s\n",
536			keystr, isc_result_totext(result));
537		goto failure;
538	}
539
540	secretlen = isc_buffer_usedlength(&secretbuf);
541
542	debug("keycreate");
543	result = dns_tsigkey_create(keyname, hmacname, secret, secretlen,
544				    ISC_FALSE, NULL, 0, 0, mctx, NULL,
545				    &tsigkey);
546	if (result != ISC_R_SUCCESS)
547		fprintf(stderr, "could not create key from %s: %s\n",
548			keystr, dns_result_totext(result));
549	else
550		dst_key_setbits(tsigkey->key, digestbits);
551 failure:
552	if (secret != NULL)
553		isc_mem_free(mctx, secret);
554}
555
556static int
557basenamelen(const char *file) {
558	int len = strlen(file);
559
560	if (len > 1 && file[len - 1] == '.')
561		len -= 1;
562	else if (len > 8 && strcmp(file + len - 8, ".private") == 0)
563		len -= 8;
564	else if (len > 4 && strcmp(file + len - 4, ".key") == 0)
565		len -= 4;
566	return (len);
567}
568
569static void
570setup_keyfile(void) {
571	dst_key_t *dstkey = NULL;
572	isc_result_t result;
573	dns_name_t *hmacname = NULL;
574
575	debug("Creating key...");
576
577	if (sig0key != NULL)
578		dst_key_free(&sig0key);
579
580	result = dst_key_fromnamedfile(keyfile,
581				       DST_TYPE_PRIVATE | DST_TYPE_KEY, mctx,
582				       &dstkey);
583	if (result != ISC_R_SUCCESS) {
584		fprintf(stderr, "could not read key from %.*s.{private,key}: "
585				"%s\n", basenamelen(keyfile), keyfile,
586				isc_result_totext(result));
587		return;
588	}
589	switch (dst_key_alg(dstkey)) {
590	case DST_ALG_HMACMD5:
591		hmacname = DNS_TSIG_HMACMD5_NAME;
592		break;
593	case DST_ALG_HMACSHA1:
594		hmacname = DNS_TSIG_HMACSHA1_NAME;
595		break;
596	case DST_ALG_HMACSHA224:
597		hmacname = DNS_TSIG_HMACSHA224_NAME;
598		break;
599	case DST_ALG_HMACSHA256:
600		hmacname = DNS_TSIG_HMACSHA256_NAME;
601		break;
602	case DST_ALG_HMACSHA384:
603		hmacname = DNS_TSIG_HMACSHA384_NAME;
604		break;
605	case DST_ALG_HMACSHA512:
606		hmacname = DNS_TSIG_HMACSHA512_NAME;
607		break;
608	}
609	if (hmacname != NULL) {
610		result = dns_tsigkey_createfromkey(dst_key_name(dstkey),
611						   hmacname, dstkey, ISC_FALSE,
612						   NULL, 0, 0, mctx, NULL,
613						   &tsigkey);
614		dst_key_free(&dstkey);
615		if (result != ISC_R_SUCCESS) {
616			fprintf(stderr, "could not create key from %s: %s\n",
617				keyfile, isc_result_totext(result));
618			return;
619		}
620	} else {
621		dst_key_attach(dstkey, &sig0key);
622		dst_key_free(&dstkey);
623	}
624}
625
626static void
627doshutdown(void) {
628	isc_task_detach(&global_task);
629
630	if (userserver != NULL)
631		isc_mem_put(mctx, userserver, sizeof(isc_sockaddr_t));
632
633	if (localaddr != NULL)
634		isc_mem_put(mctx, localaddr, sizeof(isc_sockaddr_t));
635
636	if (tsigkey != NULL) {
637		ddebug("Freeing TSIG key");
638		dns_tsigkey_detach(&tsigkey);
639	}
640
641	if (sig0key != NULL) {
642		ddebug("Freeing SIG(0) key");
643		dst_key_free(&sig0key);
644	}
645
646	if (updatemsg != NULL)
647		dns_message_destroy(&updatemsg);
648
649	if (is_dst_up) {
650		ddebug("Destroy DST lib");
651		dst_lib_destroy();
652		is_dst_up = ISC_FALSE;
653	}
654
655	cleanup_entropy(&entropy);
656
657	lwres_conf_clear(lwctx);
658	lwres_context_destroy(&lwctx);
659
660	isc_mem_put(mctx, servers, ns_total * sizeof(isc_sockaddr_t));
661
662	ddebug("Destroying request manager");
663	dns_requestmgr_detach(&requestmgr);
664
665	ddebug("Freeing the dispatchers");
666	if (have_ipv4)
667		dns_dispatch_detach(&dispatchv4);
668	if (have_ipv6)
669		dns_dispatch_detach(&dispatchv6);
670
671	ddebug("Shutting down dispatch manager");
672	dns_dispatchmgr_destroy(&dispatchmgr);
673
674}
675
676static void
677maybeshutdown(void) {
678	ddebug("Shutting down request manager");
679	dns_requestmgr_shutdown(requestmgr);
680
681	if (requests != 0)
682		return;
683
684	doshutdown();
685}
686
687static void
688shutdown_program(isc_task_t *task, isc_event_t *event) {
689	REQUIRE(task == global_task);
690	UNUSED(task);
691
692	ddebug("shutdown_program()");
693	isc_event_free(&event);
694
695	shuttingdown = ISC_TRUE;
696	maybeshutdown();
697}
698
699static void
700setup_system(void) {
701	isc_result_t result;
702	isc_sockaddr_t bind_any, bind_any6;
703	lwres_result_t lwresult;
704	unsigned int attrs, attrmask;
705	int i;
706	isc_logconfig_t *logconfig = NULL;
707
708	ddebug("setup_system()");
709
710	dns_result_register();
711
712	result = isc_net_probeipv4();
713	if (result == ISC_R_SUCCESS)
714		have_ipv4 = ISC_TRUE;
715
716	result = isc_net_probeipv6();
717	if (result == ISC_R_SUCCESS)
718		have_ipv6 = ISC_TRUE;
719
720	if (!have_ipv4 && !have_ipv6)
721		fatal("could not find either IPv4 or IPv6");
722
723	result = isc_log_create(mctx, &lctx, &logconfig);
724	check_result(result, "isc_log_create");
725
726	isc_log_setcontext(lctx);
727	dns_log_init(lctx);
728	dns_log_setcontext(lctx);
729
730	result = isc_log_usechannel(logconfig, "default_debug", NULL, NULL);
731	check_result(result, "isc_log_usechannel");
732
733	isc_log_setdebuglevel(lctx, logdebuglevel);
734
735	lwresult = lwres_context_create(&lwctx, mctx, mem_alloc, mem_free, 1);
736	if (lwresult != LWRES_R_SUCCESS)
737		fatal("lwres_context_create failed");
738
739	(void)lwres_conf_parse(lwctx, RESOLV_CONF);
740	lwconf = lwres_conf_get(lwctx);
741
742	ns_total = lwconf->nsnext;
743	if (ns_total <= 0) {
744		/* No name servers in resolv.conf; default to loopback. */
745		struct in_addr localhost;
746		ns_total = 1;
747		servers = isc_mem_get(mctx, ns_total * sizeof(isc_sockaddr_t));
748		if (servers == NULL)
749			fatal("out of memory");
750		localhost.s_addr = htonl(INADDR_LOOPBACK);
751		isc_sockaddr_fromin(&servers[0], &localhost, DNSDEFAULTPORT);
752	} else {
753		servers = isc_mem_get(mctx, ns_total * sizeof(isc_sockaddr_t));
754		if (servers == NULL)
755			fatal("out of memory");
756		for (i = 0; i < ns_total; i++) {
757			if (lwconf->nameservers[i].family == LWRES_ADDRTYPE_V4) {
758				struct in_addr in4;
759				memcpy(&in4, lwconf->nameservers[i].address, 4);
760				isc_sockaddr_fromin(&servers[i], &in4, DNSDEFAULTPORT);
761			} else {
762				struct in6_addr in6;
763				memcpy(&in6, lwconf->nameservers[i].address, 16);
764				isc_sockaddr_fromin6(&servers[i], &in6,
765						     DNSDEFAULTPORT);
766			}
767		}
768	}
769
770	setup_entropy(mctx, NULL, &entropy);
771
772	result = isc_hash_create(mctx, entropy, DNS_NAME_MAXWIRE);
773	check_result(result, "isc_hash_create");
774	isc_hash_init();
775
776	result = dns_dispatchmgr_create(mctx, entropy, &dispatchmgr);
777	check_result(result, "dns_dispatchmgr_create");
778
779	result = isc_socketmgr_create(mctx, &socketmgr);
780	check_result(result, "dns_socketmgr_create");
781
782	result = isc_timermgr_create(mctx, &timermgr);
783	check_result(result, "dns_timermgr_create");
784
785	result = isc_taskmgr_create(mctx, 1, 0, &taskmgr);
786	check_result(result, "isc_taskmgr_create");
787
788	result = isc_task_create(taskmgr, 0, &global_task);
789	check_result(result, "isc_task_create");
790
791	result = isc_task_onshutdown(global_task, shutdown_program, NULL);
792	check_result(result, "isc_task_onshutdown");
793
794	result = dst_lib_init(mctx, entropy, 0);
795	check_result(result, "dst_lib_init");
796	is_dst_up = ISC_TRUE;
797
798	attrmask = DNS_DISPATCHATTR_UDP | DNS_DISPATCHATTR_TCP;
799	attrmask |= DNS_DISPATCHATTR_IPV4 | DNS_DISPATCHATTR_IPV6;
800
801	if (have_ipv6) {
802		attrs = DNS_DISPATCHATTR_UDP;
803		attrs |= DNS_DISPATCHATTR_MAKEQUERY;
804		attrs |= DNS_DISPATCHATTR_IPV6;
805		isc_sockaddr_any6(&bind_any6);
806		result = dns_dispatch_getudp(dispatchmgr, socketmgr, taskmgr,
807					     &bind_any6, PACKETSIZE,
808					     4, 2, 3, 5,
809					     attrs, attrmask, &dispatchv6);
810		check_result(result, "dns_dispatch_getudp (v6)");
811	}
812
813	if (have_ipv4) {
814		attrs = DNS_DISPATCHATTR_UDP;
815		attrs |= DNS_DISPATCHATTR_MAKEQUERY;
816		attrs |= DNS_DISPATCHATTR_IPV4;
817		isc_sockaddr_any(&bind_any);
818		result = dns_dispatch_getudp(dispatchmgr, socketmgr, taskmgr,
819					     &bind_any, PACKETSIZE,
820					     4, 2, 3, 5,
821					     attrs, attrmask, &dispatchv4);
822		check_result(result, "dns_dispatch_getudp (v4)");
823	}
824
825	result = dns_requestmgr_create(mctx, timermgr,
826				       socketmgr, taskmgr, dispatchmgr,
827				       dispatchv4, dispatchv6, &requestmgr);
828	check_result(result, "dns_requestmgr_create");
829
830	if (keystr != NULL)
831		setup_keystr();
832	else if (keyfile != NULL)
833		setup_keyfile();
834}
835
836static void
837get_address(char *host, in_port_t port, isc_sockaddr_t *sockaddr) {
838	int count;
839	isc_result_t result;
840
841	isc_app_block();
842	result = bind9_getaddresses(host, port, sockaddr, 1, &count);
843	isc_app_unblock();
844	if (result != ISC_R_SUCCESS)
845		fatal("couldn't get address for '%s': %s",
846		      host, isc_result_totext(result));
847	INSIST(count == 1);
848}
849
850#define PARSE_ARGS_FMT "dDMl:y:govk:rR::t:u:"
851
852static void
853pre_parse_args(int argc, char **argv) {
854	int ch;
855
856	while ((ch = isc_commandline_parse(argc, argv, PARSE_ARGS_FMT)) != -1) {
857		switch (ch) {
858		case 'M': /* was -dm */
859			debugging = ISC_TRUE;
860			ddebugging = ISC_TRUE;
861			memdebugging = ISC_TRUE;
862			isc_mem_debugging = ISC_MEM_DEBUGTRACE |
863					    ISC_MEM_DEBUGRECORD;
864			break;
865
866		case '?':
867			if (isc_commandline_option != '?')
868				fprintf(stderr, "%s: invalid argument -%c\n",
869					argv[0], isc_commandline_option);
870			fprintf(stderr, "usage: nsupdate [-d] "
871				"[-g | -o | -y keyname:secret | -k keyfile] "
872				"[-v] [filename]\n");
873			exit(1);
874
875		default:
876			break;
877		}
878	}
879	isc_commandline_reset = ISC_TRUE;
880	isc_commandline_index = 1;
881}
882
883static void
884parse_args(int argc, char **argv, isc_mem_t *mctx, isc_entropy_t **ectx) {
885	int ch;
886	isc_uint32_t i;
887	isc_result_t result;
888
889	debug("parse_args");
890	while ((ch = isc_commandline_parse(argc, argv, PARSE_ARGS_FMT)) != -1) {
891		switch (ch) {
892		case 'd':
893			debugging = ISC_TRUE;
894			break;
895		case 'D': /* was -dd */
896			debugging = ISC_TRUE;
897			ddebugging = ISC_TRUE;
898			break;
899		case 'M':
900			break;
901		case 'l':
902			result = isc_parse_uint32(&i, isc_commandline_argument,
903						  10);
904			if (result != ISC_R_SUCCESS) {
905				fprintf(stderr, "bad library debug value "
906					"'%s'\n", isc_commandline_argument);
907				exit(1);
908			}
909			logdebuglevel = i;
910			break;
911		case 'y':
912			keystr = isc_commandline_argument;
913			break;
914		case 'v':
915			usevc = ISC_TRUE;
916			break;
917		case 'k':
918			keyfile = isc_commandline_argument;
919			break;
920		case 'g':
921			usegsstsig = ISC_TRUE;
922			use_win2k_gsstsig = ISC_FALSE;
923			break;
924		case 'o':
925			usegsstsig = ISC_TRUE;
926			use_win2k_gsstsig = ISC_TRUE;
927			break;
928		case 't':
929			result = isc_parse_uint32(&timeout,
930						  isc_commandline_argument, 10);
931			if (result != ISC_R_SUCCESS) {
932				fprintf(stderr, "bad timeout '%s'\n",						isc_commandline_argument);
933				exit(1);
934			}
935			if (timeout == 0)
936				timeout = UINT_MAX;
937			break;
938		case 'u':
939			result = isc_parse_uint32(&udp_timeout,
940						  isc_commandline_argument, 10);
941			if (result != ISC_R_SUCCESS) {
942				fprintf(stderr, "bad udp timeout '%s'\n",						isc_commandline_argument);
943				exit(1);
944			}
945			if (udp_timeout == 0)
946				udp_timeout = UINT_MAX;
947			break;
948		case 'r':
949			result = isc_parse_uint32(&udp_retries,
950						  isc_commandline_argument, 10);
951			if (result != ISC_R_SUCCESS) {
952				fprintf(stderr, "bad udp retries '%s'\n",						isc_commandline_argument);
953				exit(1);
954			}
955			break;
956
957		case 'R':
958			setup_entropy(mctx, isc_commandline_argument, ectx);
959			break;
960
961		default:
962			fprintf(stderr, "%s: unhandled option: %c\n",
963				argv[0], isc_commandline_option);
964			exit(1);
965		}
966	}
967	if (keyfile != NULL && keystr != NULL) {
968		fprintf(stderr, "%s: cannot specify both -k and -y\n",
969			argv[0]);
970		exit(1);
971	}
972
973#ifdef GSSAPI
974	if (usegsstsig && (keyfile != NULL || keystr != NULL)) {
975		fprintf(stderr, "%s: cannot specify -g with -k or -y\n",
976			argv[0]);
977		exit(1);
978	}
979#else
980	if (usegsstsig) {
981		fprintf(stderr, "%s: cannot specify -g  or -o, " \
982			"program not linked with GSS API Library\n",
983			argv[0]);
984		exit(1);
985	}
986#endif
987
988	if (argv[isc_commandline_index] != NULL) {
989		if (strcmp(argv[isc_commandline_index], "-") == 0) {
990			input = stdin;
991		} else {
992			result = isc_stdio_open(argv[isc_commandline_index],
993						"r", &input);
994			if (result != ISC_R_SUCCESS) {
995				fprintf(stderr, "could not open '%s': %s\n",
996					argv[isc_commandline_index],
997					isc_result_totext(result));
998				exit(1);
999			}
1000		}
1001		interactive = ISC_FALSE;
1002	}
1003}
1004
1005static isc_uint16_t
1006parse_name(char **cmdlinep, dns_message_t *msg, dns_name_t **namep) {
1007	isc_result_t result;
1008	char *word;
1009	isc_buffer_t *namebuf = NULL;
1010	isc_buffer_t source;
1011
1012	word = nsu_strsep(cmdlinep, " \t\r\n");
1013	if (*word == 0) {
1014		fprintf(stderr, "could not read owner name\n");
1015		return (STATUS_SYNTAX);
1016	}
1017
1018	result = dns_message_gettempname(msg, namep);
1019	check_result(result, "dns_message_gettempname");
1020	result = isc_buffer_allocate(mctx, &namebuf, DNS_NAME_MAXWIRE);
1021	check_result(result, "isc_buffer_allocate");
1022	dns_name_init(*namep, NULL);
1023	dns_name_setbuffer(*namep, namebuf);
1024	dns_message_takebuffer(msg, &namebuf);
1025	isc_buffer_init(&source, word, strlen(word));
1026	isc_buffer_add(&source, strlen(word));
1027	result = dns_name_fromtext(*namep, &source, dns_rootname,
1028				   ISC_FALSE, NULL);
1029	check_result(result, "dns_name_fromtext");
1030	isc_buffer_invalidate(&source);
1031	return (STATUS_MORE);
1032}
1033
1034static isc_uint16_t
1035parse_rdata(char **cmdlinep, dns_rdataclass_t rdataclass,
1036	    dns_rdatatype_t rdatatype, dns_message_t *msg,
1037	    dns_rdata_t *rdata)
1038{
1039	char *cmdline = *cmdlinep;
1040	isc_buffer_t source, *buf = NULL, *newbuf = NULL;
1041	isc_region_t r;
1042	isc_lex_t *lex = NULL;
1043	dns_rdatacallbacks_t callbacks;
1044	isc_result_t result;
1045
1046	while (*cmdline != 0 && isspace((unsigned char)*cmdline))
1047		cmdline++;
1048
1049	if (*cmdline != 0) {
1050		dns_rdatacallbacks_init(&callbacks);
1051		result = isc_lex_create(mctx, strlen(cmdline), &lex);
1052		check_result(result, "isc_lex_create");
1053		isc_buffer_init(&source, cmdline, strlen(cmdline));
1054		isc_buffer_add(&source, strlen(cmdline));
1055		result = isc_lex_openbuffer(lex, &source);
1056		check_result(result, "isc_lex_openbuffer");
1057		result = isc_buffer_allocate(mctx, &buf, MAXWIRE);
1058		check_result(result, "isc_buffer_allocate");
1059		result = dns_rdata_fromtext(NULL, rdataclass, rdatatype, lex,
1060					    dns_rootname, 0, mctx, buf,
1061					    &callbacks);
1062		isc_lex_destroy(&lex);
1063		if (result == ISC_R_SUCCESS) {
1064			isc_buffer_usedregion(buf, &r);
1065			result = isc_buffer_allocate(mctx, &newbuf, r.length);
1066			check_result(result, "isc_buffer_allocate");
1067			isc_buffer_putmem(newbuf, r.base, r.length);
1068			isc_buffer_usedregion(newbuf, &r);
1069			dns_rdata_fromregion(rdata, rdataclass, rdatatype, &r);
1070			isc_buffer_free(&buf);
1071			dns_message_takebuffer(msg, &newbuf);
1072		} else {
1073			fprintf(stderr, "invalid rdata format: %s\n",
1074				isc_result_totext(result));
1075			isc_buffer_free(&buf);
1076			return (STATUS_SYNTAX);
1077		}
1078	} else {
1079		rdata->flags = DNS_RDATA_UPDATE;
1080	}
1081	*cmdlinep = cmdline;
1082	return (STATUS_MORE);
1083}
1084
1085static isc_uint16_t
1086make_prereq(char *cmdline, isc_boolean_t ispositive, isc_boolean_t isrrset) {
1087	isc_result_t result;
1088	char *word;
1089	dns_name_t *name = NULL;
1090	isc_textregion_t region;
1091	dns_rdataset_t *rdataset = NULL;
1092	dns_rdatalist_t *rdatalist = NULL;
1093	dns_rdataclass_t rdataclass;
1094	dns_rdatatype_t rdatatype;
1095	dns_rdata_t *rdata = NULL;
1096	isc_uint16_t retval;
1097
1098	ddebug("make_prereq()");
1099
1100	/*
1101	 * Read the owner name
1102	 */
1103	retval = parse_name(&cmdline, updatemsg, &name);
1104	if (retval != STATUS_MORE)
1105		return (retval);
1106
1107	/*
1108	 * If this is an rrset prereq, read the class or type.
1109	 */
1110	if (isrrset) {
1111		word = nsu_strsep(&cmdline, " \t\r\n");
1112		if (*word == 0) {
1113			fprintf(stderr, "could not read class or type\n");
1114			goto failure;
1115		}
1116		region.base = word;
1117		region.length = strlen(word);
1118		result = dns_rdataclass_fromtext(&rdataclass, &region);
1119		if (result == ISC_R_SUCCESS) {
1120			if (!setzoneclass(rdataclass)) {
1121				fprintf(stderr, "class mismatch: %s\n", word);
1122				goto failure;
1123			}
1124			/*
1125			 * Now read the type.
1126			 */
1127			word = nsu_strsep(&cmdline, " \t\r\n");
1128			if (*word == 0) {
1129				fprintf(stderr, "could not read type\n");
1130				goto failure;
1131			}
1132			region.base = word;
1133			region.length = strlen(word);
1134			result = dns_rdatatype_fromtext(&rdatatype, &region);
1135			if (result != ISC_R_SUCCESS) {
1136				fprintf(stderr, "invalid type: %s\n", word);
1137				goto failure;
1138			}
1139		} else {
1140			rdataclass = getzoneclass();
1141			result = dns_rdatatype_fromtext(&rdatatype, &region);
1142			if (result != ISC_R_SUCCESS) {
1143				fprintf(stderr, "invalid type: %s\n", word);
1144				goto failure;
1145			}
1146		}
1147	} else
1148		rdatatype = dns_rdatatype_any;
1149
1150	result = dns_message_gettemprdata(updatemsg, &rdata);
1151	check_result(result, "dns_message_gettemprdata");
1152
1153	dns_rdata_init(rdata);
1154
1155	if (isrrset && ispositive) {
1156		retval = parse_rdata(&cmdline, rdataclass, rdatatype,
1157				     updatemsg, rdata);
1158		if (retval != STATUS_MORE)
1159			goto failure;
1160	} else
1161		rdata->flags = DNS_RDATA_UPDATE;
1162
1163	result = dns_message_gettemprdatalist(updatemsg, &rdatalist);
1164	check_result(result, "dns_message_gettemprdatalist");
1165	result = dns_message_gettemprdataset(updatemsg, &rdataset);
1166	check_result(result, "dns_message_gettemprdataset");
1167	dns_rdatalist_init(rdatalist);
1168	rdatalist->type = rdatatype;
1169	if (ispositive) {
1170		if (isrrset && rdata->data != NULL)
1171			rdatalist->rdclass = rdataclass;
1172		else
1173			rdatalist->rdclass = dns_rdataclass_any;
1174	} else
1175		rdatalist->rdclass = dns_rdataclass_none;
1176	rdatalist->covers = 0;
1177	rdatalist->ttl = 0;
1178	rdata->rdclass = rdatalist->rdclass;
1179	rdata->type = rdatatype;
1180	ISC_LIST_INIT(rdatalist->rdata);
1181	ISC_LIST_APPEND(rdatalist->rdata, rdata, link);
1182	dns_rdataset_init(rdataset);
1183	dns_rdatalist_tordataset(rdatalist, rdataset);
1184	ISC_LIST_INIT(name->list);
1185	ISC_LIST_APPEND(name->list, rdataset, link);
1186	dns_message_addname(updatemsg, name, DNS_SECTION_PREREQUISITE);
1187	return (STATUS_MORE);
1188
1189 failure:
1190	if (name != NULL)
1191		dns_message_puttempname(updatemsg, &name);
1192	return (STATUS_SYNTAX);
1193}
1194
1195static isc_uint16_t
1196evaluate_prereq(char *cmdline) {
1197	char *word;
1198	isc_boolean_t ispositive, isrrset;
1199
1200	ddebug("evaluate_prereq()");
1201	word = nsu_strsep(&cmdline, " \t\r\n");
1202	if (*word == 0) {
1203		fprintf(stderr, "could not read operation code\n");
1204		return (STATUS_SYNTAX);
1205	}
1206	if (strcasecmp(word, "nxdomain") == 0) {
1207		ispositive = ISC_FALSE;
1208		isrrset = ISC_FALSE;
1209	} else if (strcasecmp(word, "yxdomain") == 0) {
1210		ispositive = ISC_TRUE;
1211		isrrset = ISC_FALSE;
1212	} else if (strcasecmp(word, "nxrrset") == 0) {
1213		ispositive = ISC_FALSE;
1214		isrrset = ISC_TRUE;
1215	} else if (strcasecmp(word, "yxrrset") == 0) {
1216		ispositive = ISC_TRUE;
1217		isrrset = ISC_TRUE;
1218	} else {
1219		fprintf(stderr, "incorrect operation code: %s\n", word);
1220		return (STATUS_SYNTAX);
1221	}
1222	return (make_prereq(cmdline, ispositive, isrrset));
1223}
1224
1225static isc_uint16_t
1226evaluate_server(char *cmdline) {
1227	char *word, *server;
1228	long port;
1229
1230	word = nsu_strsep(&cmdline, " \t\r\n");
1231	if (*word == 0) {
1232		fprintf(stderr, "could not read server name\n");
1233		return (STATUS_SYNTAX);
1234	}
1235	server = word;
1236
1237	word = nsu_strsep(&cmdline, " \t\r\n");
1238	if (*word == 0)
1239		port = DNSDEFAULTPORT;
1240	else {
1241		char *endp;
1242		port = strtol(word, &endp, 10);
1243		if (*endp != 0) {
1244			fprintf(stderr, "port '%s' is not numeric\n", word);
1245			return (STATUS_SYNTAX);
1246		} else if (port < 1 || port > 65535) {
1247			fprintf(stderr, "port '%s' is out of range "
1248				"(1 to 65535)\n", word);
1249			return (STATUS_SYNTAX);
1250		}
1251	}
1252
1253	if (userserver == NULL) {
1254		userserver = isc_mem_get(mctx, sizeof(isc_sockaddr_t));
1255		if (userserver == NULL)
1256			fatal("out of memory");
1257	}
1258
1259	get_address(server, (in_port_t)port, userserver);
1260
1261	return (STATUS_MORE);
1262}
1263
1264static isc_uint16_t
1265evaluate_local(char *cmdline) {
1266	char *word, *local;
1267	long port;
1268	struct in_addr in4;
1269	struct in6_addr in6;
1270
1271	word = nsu_strsep(&cmdline, " \t\r\n");
1272	if (*word == 0) {
1273		fprintf(stderr, "could not read server name\n");
1274		return (STATUS_SYNTAX);
1275	}
1276	local = word;
1277
1278	word = nsu_strsep(&cmdline, " \t\r\n");
1279	if (*word == 0)
1280		port = 0;
1281	else {
1282		char *endp;
1283		port = strtol(word, &endp, 10);
1284		if (*endp != 0) {
1285			fprintf(stderr, "port '%s' is not numeric\n", word);
1286			return (STATUS_SYNTAX);
1287		} else if (port < 1 || port > 65535) {
1288			fprintf(stderr, "port '%s' is out of range "
1289				"(1 to 65535)\n", word);
1290			return (STATUS_SYNTAX);
1291		}
1292	}
1293
1294	if (localaddr == NULL) {
1295		localaddr = isc_mem_get(mctx, sizeof(isc_sockaddr_t));
1296		if (localaddr == NULL)
1297			fatal("out of memory");
1298	}
1299
1300	if (have_ipv6 && inet_pton(AF_INET6, local, &in6) == 1)
1301		isc_sockaddr_fromin6(localaddr, &in6, (in_port_t)port);
1302	else if (have_ipv4 && inet_pton(AF_INET, local, &in4) == 1)
1303		isc_sockaddr_fromin(localaddr, &in4, (in_port_t)port);
1304	else {
1305		fprintf(stderr, "invalid address %s", local);
1306		return (STATUS_SYNTAX);
1307	}
1308
1309	return (STATUS_MORE);
1310}
1311
1312static isc_uint16_t
1313evaluate_key(char *cmdline) {
1314	char *namestr;
1315	char *secretstr;
1316	isc_buffer_t b;
1317	isc_result_t result;
1318	dns_fixedname_t fkeyname;
1319	dns_name_t *keyname;
1320	int secretlen;
1321	unsigned char *secret = NULL;
1322	isc_buffer_t secretbuf;
1323	dns_name_t *hmacname = NULL;
1324	isc_uint16_t digestbits = 0;
1325	char *n;
1326
1327	namestr = nsu_strsep(&cmdline, " \t\r\n");
1328	if (*namestr == 0) {
1329		fprintf(stderr, "could not read key name\n");
1330		return (STATUS_SYNTAX);
1331	}
1332
1333	dns_fixedname_init(&fkeyname);
1334	keyname = dns_fixedname_name(&fkeyname);
1335
1336	n = strchr(namestr, ':');
1337	if (n != NULL) {
1338		digestbits = parse_hmac(&hmacname, namestr, n - namestr);
1339		namestr = n + 1;
1340	} else
1341		hmacname = DNS_TSIG_HMACMD5_NAME;
1342
1343	isc_buffer_init(&b, namestr, strlen(namestr));
1344	isc_buffer_add(&b, strlen(namestr));
1345	result = dns_name_fromtext(keyname, &b, dns_rootname, ISC_FALSE, NULL);
1346	if (result != ISC_R_SUCCESS) {
1347		fprintf(stderr, "could not parse key name\n");
1348		return (STATUS_SYNTAX);
1349	}
1350
1351	secretstr = nsu_strsep(&cmdline, "\r\n");
1352	if (*secretstr == 0) {
1353		fprintf(stderr, "could not read key secret\n");
1354		return (STATUS_SYNTAX);
1355	}
1356	secretlen = strlen(secretstr) * 3 / 4;
1357	secret = isc_mem_allocate(mctx, secretlen);
1358	if (secret == NULL)
1359		fatal("out of memory");
1360
1361	isc_buffer_init(&secretbuf, secret, secretlen);
1362	result = isc_base64_decodestring(secretstr, &secretbuf);
1363	if (result != ISC_R_SUCCESS) {
1364		fprintf(stderr, "could not create key from %s: %s\n",
1365			secretstr, isc_result_totext(result));
1366		isc_mem_free(mctx, secret);
1367		return (STATUS_SYNTAX);
1368	}
1369	secretlen = isc_buffer_usedlength(&secretbuf);
1370
1371	if (tsigkey != NULL)
1372		dns_tsigkey_detach(&tsigkey);
1373	result = dns_tsigkey_create(keyname, hmacname, secret, secretlen,
1374				    ISC_FALSE, NULL, 0, 0, mctx, NULL,
1375				    &tsigkey);
1376	isc_mem_free(mctx, secret);
1377	if (result != ISC_R_SUCCESS) {
1378		fprintf(stderr, "could not create key from %s %s: %s\n",
1379			namestr, secretstr, dns_result_totext(result));
1380		return (STATUS_SYNTAX);
1381	}
1382	dst_key_setbits(tsigkey->key, digestbits);
1383	return (STATUS_MORE);
1384}
1385
1386static isc_uint16_t
1387evaluate_zone(char *cmdline) {
1388	char *word;
1389	isc_buffer_t b;
1390	isc_result_t result;
1391
1392	word = nsu_strsep(&cmdline, " \t\r\n");
1393	if (*word == 0) {
1394		fprintf(stderr, "could not read zone name\n");
1395		return (STATUS_SYNTAX);
1396	}
1397
1398	dns_fixedname_init(&fuserzone);
1399	userzone = dns_fixedname_name(&fuserzone);
1400	isc_buffer_init(&b, word, strlen(word));
1401	isc_buffer_add(&b, strlen(word));
1402	result = dns_name_fromtext(userzone, &b, dns_rootname, ISC_FALSE,
1403				   NULL);
1404	if (result != ISC_R_SUCCESS) {
1405		userzone = NULL; /* Lest it point to an invalid name */
1406		fprintf(stderr, "could not parse zone name\n");
1407		return (STATUS_SYNTAX);
1408	}
1409
1410	return (STATUS_MORE);
1411}
1412
1413static isc_uint16_t
1414evaluate_realm(char *cmdline) {
1415#ifdef GSSAPI
1416	char *word;
1417	char buf[1024];
1418
1419	word = nsu_strsep(&cmdline, " \t\r\n");
1420	if (*word == 0) {
1421		if (realm != NULL)
1422			isc_mem_free(mctx, realm);
1423		realm = NULL;
1424		return (STATUS_MORE);
1425	}
1426
1427	snprintf(buf, sizeof(buf), "@%s", word);
1428	realm = isc_mem_strdup(mctx, buf);
1429	if (realm == NULL)
1430		fatal("out of memory");
1431	return (STATUS_MORE);
1432#else
1433	UNUSED(cmdline);
1434	return (STATUS_SYNTAX);
1435#endif
1436}
1437
1438static isc_uint16_t
1439evaluate_ttl(char *cmdline) {
1440	char *word;
1441	isc_result_t result;
1442	isc_uint32_t ttl;
1443
1444	word = nsu_strsep(&cmdline, " \t\r\n");
1445	if (*word == 0) {
1446		fprintf(stderr, "could not ttl\n");
1447		return (STATUS_SYNTAX);
1448	}
1449
1450	if (!strcasecmp(word, "none")) {
1451		default_ttl = 0;
1452		default_ttl_set = ISC_FALSE;
1453		return (STATUS_MORE);
1454	}
1455
1456	result = isc_parse_uint32(&ttl, word, 10);
1457	if (result != ISC_R_SUCCESS)
1458		return (STATUS_SYNTAX);
1459
1460	if (ttl > TTL_MAX) {
1461		fprintf(stderr, "ttl '%s' is out of range (0 to %u)\n",
1462			word, TTL_MAX);
1463		return (STATUS_SYNTAX);
1464	}
1465	default_ttl = ttl;
1466	default_ttl_set = ISC_TRUE;
1467
1468	return (STATUS_MORE);
1469}
1470
1471static isc_uint16_t
1472evaluate_class(char *cmdline) {
1473	char *word;
1474	isc_textregion_t r;
1475	isc_result_t result;
1476	dns_rdataclass_t rdclass;
1477
1478	word = nsu_strsep(&cmdline, " \t\r\n");
1479	if (*word == 0) {
1480		fprintf(stderr, "could not read class name\n");
1481		return (STATUS_SYNTAX);
1482	}
1483
1484	r.base = word;
1485	r.length = strlen(word);
1486	result = dns_rdataclass_fromtext(&rdclass, &r);
1487	if (result != ISC_R_SUCCESS) {
1488		fprintf(stderr, "could not parse class name: %s\n", word);
1489		return (STATUS_SYNTAX);
1490	}
1491	switch (rdclass) {
1492	case dns_rdataclass_none:
1493	case dns_rdataclass_any:
1494	case dns_rdataclass_reserved0:
1495		fprintf(stderr, "bad default class: %s\n", word);
1496		return (STATUS_SYNTAX);
1497	default:
1498		defaultclass = rdclass;
1499	}
1500
1501	return (STATUS_MORE);
1502}
1503
1504static isc_uint16_t
1505update_addordelete(char *cmdline, isc_boolean_t isdelete) {
1506	isc_result_t result;
1507	dns_name_t *name = NULL;
1508	isc_uint32_t ttl;
1509	char *word;
1510	dns_rdataclass_t rdataclass;
1511	dns_rdatatype_t rdatatype;
1512	dns_rdata_t *rdata = NULL;
1513	dns_rdatalist_t *rdatalist = NULL;
1514	dns_rdataset_t *rdataset = NULL;
1515	isc_textregion_t region;
1516	isc_uint16_t retval;
1517
1518	ddebug("update_addordelete()");
1519
1520	/*
1521	 * Read the owner name.
1522	 */
1523	retval = parse_name(&cmdline, updatemsg, &name);
1524	if (retval != STATUS_MORE)
1525		return (retval);
1526
1527	result = dns_message_gettemprdata(updatemsg, &rdata);
1528	check_result(result, "dns_message_gettemprdata");
1529
1530	dns_rdata_init(rdata);
1531
1532	/*
1533	 * If this is an add, read the TTL and verify that it's in range.
1534	 * If it's a delete, ignore a TTL if present (for compatibility).
1535	 */
1536	word = nsu_strsep(&cmdline, " \t\r\n");
1537	if (*word == 0) {
1538		if (!isdelete) {
1539			fprintf(stderr, "could not read owner ttl\n");
1540			goto failure;
1541		}
1542		else {
1543			ttl = 0;
1544			rdataclass = dns_rdataclass_any;
1545			rdatatype = dns_rdatatype_any;
1546			rdata->flags = DNS_RDATA_UPDATE;
1547			goto doneparsing;
1548		}
1549	}
1550	result = isc_parse_uint32(&ttl, word, 10);
1551	if (result != ISC_R_SUCCESS) {
1552		if (isdelete) {
1553			ttl = 0;
1554			goto parseclass;
1555		} else if (default_ttl_set) {
1556			ttl = default_ttl;
1557			goto parseclass;
1558		} else {
1559			fprintf(stderr, "ttl '%s': %s\n", word,
1560				isc_result_totext(result));
1561			goto failure;
1562		}
1563	}
1564
1565	if (isdelete)
1566		ttl = 0;
1567	else if (ttl > TTL_MAX) {
1568		fprintf(stderr, "ttl '%s' is out of range (0 to %u)\n",
1569			word, TTL_MAX);
1570		goto failure;
1571	}
1572
1573	/*
1574	 * Read the class or type.
1575	 */
1576	word = nsu_strsep(&cmdline, " \t\r\n");
1577 parseclass:
1578	if (*word == 0) {
1579		if (isdelete) {
1580			rdataclass = dns_rdataclass_any;
1581			rdatatype = dns_rdatatype_any;
1582			rdata->flags = DNS_RDATA_UPDATE;
1583			goto doneparsing;
1584		} else {
1585			fprintf(stderr, "could not read class or type\n");
1586			goto failure;
1587		}
1588	}
1589	region.base = word;
1590	region.length = strlen(word);
1591	rdataclass = dns_rdataclass_any;
1592	result = dns_rdataclass_fromtext(&rdataclass, &region);
1593	if (result == ISC_R_SUCCESS && rdataclass != dns_rdataclass_any) {
1594		if (!setzoneclass(rdataclass)) {
1595			fprintf(stderr, "class mismatch: %s\n", word);
1596			goto failure;
1597		}
1598		/*
1599		 * Now read the type.
1600		 */
1601		word = nsu_strsep(&cmdline, " \t\r\n");
1602		if (*word == 0) {
1603			if (isdelete) {
1604				rdataclass = dns_rdataclass_any;
1605				rdatatype = dns_rdatatype_any;
1606				rdata->flags = DNS_RDATA_UPDATE;
1607				goto doneparsing;
1608			} else {
1609				fprintf(stderr, "could not read type\n");
1610				goto failure;
1611			}
1612		}
1613		region.base = word;
1614		region.length = strlen(word);
1615		result = dns_rdatatype_fromtext(&rdatatype, &region);
1616		if (result != ISC_R_SUCCESS) {
1617			fprintf(stderr, "'%s' is not a valid type: %s\n",
1618				word, isc_result_totext(result));
1619			goto failure;
1620		}
1621	} else {
1622		rdataclass = getzoneclass();
1623		result = dns_rdatatype_fromtext(&rdatatype, &region);
1624		if (result != ISC_R_SUCCESS) {
1625			fprintf(stderr, "'%s' is not a valid class or type: "
1626				"%s\n", word, isc_result_totext(result));
1627			goto failure;
1628		}
1629	}
1630
1631	retval = parse_rdata(&cmdline, rdataclass, rdatatype, updatemsg,
1632			     rdata);
1633	if (retval != STATUS_MORE)
1634		goto failure;
1635
1636	if (isdelete) {
1637		if ((rdata->flags & DNS_RDATA_UPDATE) != 0)
1638			rdataclass = dns_rdataclass_any;
1639		else
1640			rdataclass = dns_rdataclass_none;
1641	} else {
1642		if ((rdata->flags & DNS_RDATA_UPDATE) != 0) {
1643			fprintf(stderr, "could not read rdata\n");
1644			goto failure;
1645		}
1646	}
1647
1648 doneparsing:
1649
1650	result = dns_message_gettemprdatalist(updatemsg, &rdatalist);
1651	check_result(result, "dns_message_gettemprdatalist");
1652	result = dns_message_gettemprdataset(updatemsg, &rdataset);
1653	check_result(result, "dns_message_gettemprdataset");
1654	dns_rdatalist_init(rdatalist);
1655	rdatalist->type = rdatatype;
1656	rdatalist->rdclass = rdataclass;
1657	rdatalist->covers = rdatatype;
1658	rdatalist->ttl = (dns_ttl_t)ttl;
1659	ISC_LIST_INIT(rdatalist->rdata);
1660	ISC_LIST_APPEND(rdatalist->rdata, rdata, link);
1661	dns_rdataset_init(rdataset);
1662	dns_rdatalist_tordataset(rdatalist, rdataset);
1663	ISC_LIST_INIT(name->list);
1664	ISC_LIST_APPEND(name->list, rdataset, link);
1665	dns_message_addname(updatemsg, name, DNS_SECTION_UPDATE);
1666	return (STATUS_MORE);
1667
1668 failure:
1669	if (name != NULL)
1670		dns_message_puttempname(updatemsg, &name);
1671	dns_message_puttemprdata(updatemsg, &rdata);
1672	return (STATUS_SYNTAX);
1673}
1674
1675static isc_uint16_t
1676evaluate_update(char *cmdline) {
1677	char *word;
1678	isc_boolean_t isdelete;
1679
1680	ddebug("evaluate_update()");
1681	word = nsu_strsep(&cmdline, " \t\r\n");
1682	if (*word == 0) {
1683		fprintf(stderr, "could not read operation code\n");
1684		return (STATUS_SYNTAX);
1685	}
1686	if (strcasecmp(word, "delete") == 0)
1687		isdelete = ISC_TRUE;
1688	else if (strcasecmp(word, "add") == 0)
1689		isdelete = ISC_FALSE;
1690	else {
1691		fprintf(stderr, "incorrect operation code: %s\n", word);
1692		return (STATUS_SYNTAX);
1693	}
1694	return (update_addordelete(cmdline, isdelete));
1695}
1696
1697static void
1698setzone(dns_name_t *zonename) {
1699	isc_result_t result;
1700	dns_name_t *name = NULL;
1701	dns_rdataset_t *rdataset = NULL;
1702
1703	result = dns_message_firstname(updatemsg, DNS_SECTION_ZONE);
1704	if (result == ISC_R_SUCCESS) {
1705		dns_message_currentname(updatemsg, DNS_SECTION_ZONE, &name);
1706		dns_message_removename(updatemsg, name, DNS_SECTION_ZONE);
1707		for (rdataset = ISC_LIST_HEAD(name->list);
1708		     rdataset != NULL;
1709		     rdataset = ISC_LIST_HEAD(name->list)) {
1710			ISC_LIST_UNLINK(name->list, rdataset, link);
1711			dns_rdataset_disassociate(rdataset);
1712			dns_message_puttemprdataset(updatemsg, &rdataset);
1713		}
1714		dns_message_puttempname(updatemsg, &name);
1715	}
1716
1717	if (zonename != NULL) {
1718		result = dns_message_gettempname(updatemsg, &name);
1719		check_result(result, "dns_message_gettempname");
1720		dns_name_init(name, NULL);
1721		dns_name_clone(zonename, name);
1722		result = dns_message_gettemprdataset(updatemsg, &rdataset);
1723		check_result(result, "dns_message_gettemprdataset");
1724		dns_rdataset_makequestion(rdataset, getzoneclass(),
1725					  dns_rdatatype_soa);
1726		ISC_LIST_INIT(name->list);
1727		ISC_LIST_APPEND(name->list, rdataset, link);
1728		dns_message_addname(updatemsg, name, DNS_SECTION_ZONE);
1729	}
1730}
1731
1732static void
1733show_message(FILE *stream, dns_message_t *msg, const char *description) {
1734	isc_result_t result;
1735	isc_buffer_t *buf = NULL;
1736	int bufsz;
1737
1738	ddebug("show_message()");
1739
1740	setzone(userzone);
1741
1742	bufsz = INITTEXT;
1743	do {
1744		if (bufsz > MAXTEXT) {
1745			fprintf(stderr, "could not allocate large enough "
1746				"buffer to display message\n");
1747			exit(1);
1748		}
1749		if (buf != NULL)
1750			isc_buffer_free(&buf);
1751		result = isc_buffer_allocate(mctx, &buf, bufsz);
1752		check_result(result, "isc_buffer_allocate");
1753		result = dns_message_totext(msg, style, 0, buf);
1754		bufsz *= 2;
1755	} while (result == ISC_R_NOSPACE);
1756	if (result != ISC_R_SUCCESS) {
1757		fprintf(stderr, "could not convert message to text format.\n");
1758		isc_buffer_free(&buf);
1759		return;
1760	}
1761	fprintf(stream, "%s\n%.*s", description,
1762	       (int)isc_buffer_usedlength(buf), (char*)isc_buffer_base(buf));
1763	isc_buffer_free(&buf);
1764}
1765
1766
1767static isc_uint16_t
1768get_next_command(void) {
1769	char cmdlinebuf[MAXCMD];
1770	char *cmdline;
1771	char *word;
1772
1773	ddebug("get_next_command()");
1774	if (interactive) {
1775		fprintf(stdout, "> ");
1776		fflush(stdout);
1777	}
1778	isc_app_block();
1779	cmdline = fgets(cmdlinebuf, MAXCMD, input);
1780	isc_app_unblock();
1781	if (cmdline == NULL)
1782		return (STATUS_QUIT);
1783	word = nsu_strsep(&cmdline, " \t\r\n");
1784
1785	if (feof(input))
1786		return (STATUS_QUIT);
1787	if (*word == 0)
1788		return (STATUS_SEND);
1789	if (word[0] == ';')
1790		return (STATUS_MORE);
1791	if (strcasecmp(word, "quit") == 0)
1792		return (STATUS_QUIT);
1793	if (strcasecmp(word, "prereq") == 0)
1794		return (evaluate_prereq(cmdline));
1795	if (strcasecmp(word, "update") == 0)
1796		return (evaluate_update(cmdline));
1797	if (strcasecmp(word, "server") == 0)
1798		return (evaluate_server(cmdline));
1799	if (strcasecmp(word, "local") == 0)
1800		return (evaluate_local(cmdline));
1801	if (strcasecmp(word, "zone") == 0)
1802		return (evaluate_zone(cmdline));
1803	if (strcasecmp(word, "class") == 0)
1804		return (evaluate_class(cmdline));
1805	if (strcasecmp(word, "send") == 0)
1806		return (STATUS_SEND);
1807	if (strcasecmp(word, "debug") == 0) {
1808		if (debugging)
1809			ddebugging = ISC_TRUE;
1810		else
1811			debugging = ISC_TRUE;
1812		return (STATUS_MORE);
1813	}
1814	if (strcasecmp(word, "ttl") == 0)
1815		return (evaluate_ttl(cmdline));
1816	if (strcasecmp(word, "show") == 0) {
1817		show_message(stdout, updatemsg, "Outgoing update query:");
1818		return (STATUS_MORE);
1819	}
1820	if (strcasecmp(word, "answer") == 0) {
1821		if (answer != NULL)
1822			show_message(stdout, answer, "Answer:");
1823		return (STATUS_MORE);
1824	}
1825	if (strcasecmp(word, "key") == 0) {
1826		usegsstsig = ISC_FALSE;
1827		return (evaluate_key(cmdline));
1828	}
1829	if (strcasecmp(word, "realm") == 0)
1830		return (evaluate_realm(cmdline));
1831	if (strcasecmp(word, "gsstsig") == 0) {
1832#ifdef GSSAPI
1833		usegsstsig = ISC_TRUE;
1834		use_win2k_gsstsig = ISC_FALSE;
1835#else
1836		fprintf(stderr, "gsstsig not supported\n");
1837#endif
1838		return (STATUS_MORE);
1839	}
1840	if (strcasecmp(word, "oldgsstsig") == 0) {
1841#ifdef GSSAPI
1842		usegsstsig = ISC_TRUE;
1843		use_win2k_gsstsig = ISC_TRUE;
1844#else
1845		fprintf(stderr, "gsstsig not supported\n");
1846#endif
1847		return (STATUS_MORE);
1848	}
1849	if (strcasecmp(word, "help") == 0) {
1850		fprintf(stdout,
1851"local address [port]      (set local resolver)\n"
1852"server address [port]     (set master server for zone)\n"
1853"send                      (send the update request)\n"
1854"show                      (show the update request)\n"
1855"answer	                   (show the answer to the last request)\n"
1856"quit                      (quit, any pending update is not sent\n"
1857"help			   (display this message_\n"
1858"key [hmac:]keyname secret (use TSIG to sign the request)\n"
1859"gsstsig                   (use GSS_TSIG to sign the request)\n"
1860"oldgsstsig                (use Microsoft's GSS_TSIG to sign the request)\n"
1861"zone name                 (set the zone to be updated)\n"
1862"class CLASS               (set the zone's DNS class, e.g. IN (default), CH)\n"
1863"prereq nxdomain name      (does this name not exist)\n"
1864"prereq yxdomain name      (does this name exist)\n"
1865"prereq nxrrset ....       (does this RRset exist)\n"
1866"prereq yxrrset ....       (does this RRset not exist)\n"
1867"update add ....           (add the given record to the zone)\n"
1868"update delete ....        (remove the given record(s) from the zone)\n");
1869		return (STATUS_MORE);
1870	}
1871	fprintf(stderr, "incorrect section name: %s\n", word);
1872	return (STATUS_SYNTAX);
1873}
1874
1875static isc_boolean_t
1876user_interaction(void) {
1877	isc_uint16_t result = STATUS_MORE;
1878
1879	ddebug("user_interaction()");
1880	while ((result == STATUS_MORE) || (result == STATUS_SYNTAX)) {
1881		result = get_next_command();
1882		if (!interactive && result == STATUS_SYNTAX)
1883			fatal("syntax error");
1884	}
1885	if (result == STATUS_SEND)
1886		return (ISC_TRUE);
1887	return (ISC_FALSE);
1888
1889}
1890
1891static void
1892done_update(void) {
1893	isc_event_t *event = global_event;
1894	ddebug("done_update()");
1895	isc_task_send(global_task, &event);
1896}
1897
1898static void
1899check_tsig_error(dns_rdataset_t *rdataset, isc_buffer_t *b) {
1900	isc_result_t result;
1901	dns_rdata_t rdata = DNS_RDATA_INIT;
1902	dns_rdata_any_tsig_t tsig;
1903
1904	result = dns_rdataset_first(rdataset);
1905	check_result(result, "dns_rdataset_first");
1906	dns_rdataset_current(rdataset, &rdata);
1907	result = dns_rdata_tostruct(&rdata, &tsig, NULL);
1908	check_result(result, "dns_rdata_tostruct");
1909	if (tsig.error != 0) {
1910		if (isc_buffer_remaininglength(b) < 1)
1911		      check_result(ISC_R_NOSPACE, "isc_buffer_remaininglength");
1912		isc__buffer_putstr(b, "(" /*)*/);
1913		result = dns_tsigrcode_totext(tsig.error, b);
1914		check_result(result, "dns_tsigrcode_totext");
1915		if (isc_buffer_remaininglength(b) < 1)
1916		      check_result(ISC_R_NOSPACE, "isc_buffer_remaininglength");
1917		isc__buffer_putstr(b,  /*(*/ ")");
1918	}
1919}
1920
1921static void
1922update_completed(isc_task_t *task, isc_event_t *event) {
1923	dns_requestevent_t *reqev = NULL;
1924	isc_result_t result;
1925	dns_request_t *request;
1926
1927	UNUSED(task);
1928
1929	ddebug("update_completed()");
1930
1931	requests--;
1932
1933	REQUIRE(event->ev_type == DNS_EVENT_REQUESTDONE);
1934	reqev = (dns_requestevent_t *)event;
1935	request = reqev->request;
1936
1937	if (shuttingdown) {
1938		dns_request_destroy(&request);
1939		isc_event_free(&event);
1940		maybeshutdown();
1941		return;
1942	}
1943
1944	if (reqev->result != ISC_R_SUCCESS) {
1945		fprintf(stderr, "; Communication with server failed: %s\n",
1946			isc_result_totext(reqev->result));
1947		seenerror = ISC_TRUE;
1948		goto done;
1949	}
1950
1951	result = dns_message_create(mctx, DNS_MESSAGE_INTENTPARSE, &answer);
1952	check_result(result, "dns_message_create");
1953	result = dns_request_getresponse(request, answer,
1954					 DNS_MESSAGEPARSE_PRESERVEORDER);
1955	switch (result) {
1956	case ISC_R_SUCCESS:
1957		if (answer->verify_attempted)
1958			ddebug("tsig verification successful");
1959		break;
1960	case DNS_R_CLOCKSKEW:
1961	case DNS_R_EXPECTEDTSIG:
1962	case DNS_R_TSIGERRORSET:
1963	case DNS_R_TSIGVERIFYFAILURE:
1964	case DNS_R_UNEXPECTEDTSIG:
1965	case ISC_R_FAILURE:
1966#if 0
1967		if (usegsstsig && answer->rcode == dns_rcode_noerror) {
1968			/*
1969			 * For MS DNS that violates RFC 2845, section 4.2
1970			 */
1971			break;
1972		}
1973#endif
1974		fprintf(stderr, "; TSIG error with server: %s\n",
1975			isc_result_totext(result));
1976		seenerror = ISC_TRUE;
1977		break;
1978	default:
1979		check_result(result, "dns_request_getresponse");
1980	}
1981
1982	if (answer->rcode != dns_rcode_noerror) {
1983		seenerror = ISC_TRUE;
1984		if (!debugging) {
1985			char buf[64];
1986			isc_buffer_t b;
1987			dns_rdataset_t *rds;
1988
1989			isc_buffer_init(&b, buf, sizeof(buf) - 1);
1990			result = dns_rcode_totext(answer->rcode, &b);
1991			check_result(result, "dns_rcode_totext");
1992			rds = dns_message_gettsig(answer, NULL);
1993			if (rds != NULL)
1994				check_tsig_error(rds, &b);
1995			fprintf(stderr, "update failed: %.*s\n",
1996				(int)isc_buffer_usedlength(&b), buf);
1997		}
1998	}
1999	if (debugging)
2000		show_message(stderr, answer, "\nReply from update query:");
2001
2002 done:
2003	dns_request_destroy(&request);
2004	if (usegsstsig) {
2005		dns_name_free(&tmpzonename, mctx);
2006		dns_name_free(&restart_master, mctx);
2007	}
2008	isc_event_free(&event);
2009	done_update();
2010}
2011
2012static void
2013send_update(dns_name_t *zonename, isc_sockaddr_t *master,
2014	    isc_sockaddr_t *srcaddr)
2015{
2016	isc_result_t result;
2017	dns_request_t *request = NULL;
2018	unsigned int options = 0;
2019
2020	ddebug("send_update()");
2021
2022	setzone(zonename);
2023
2024	if (usevc)
2025		options |= DNS_REQUESTOPT_TCP;
2026	if (tsigkey == NULL && sig0key != NULL) {
2027		result = dns_message_setsig0key(updatemsg, sig0key);
2028		check_result(result, "dns_message_setsig0key");
2029	}
2030	if (debugging) {
2031		char addrbuf[ISC_SOCKADDR_FORMATSIZE];
2032
2033		isc_sockaddr_format(master, addrbuf, sizeof(addrbuf));
2034		fprintf(stderr, "Sending update to %s\n", addrbuf);
2035	}
2036
2037	/* Windows doesn't like the tsig name to be compressed. */
2038	if (updatemsg->tsigname)
2039		updatemsg->tsigname->attributes |= DNS_NAMEATTR_NOCOMPRESS;
2040
2041	result = dns_request_createvia3(requestmgr, updatemsg, srcaddr,
2042					master, options, tsigkey, timeout,
2043					udp_timeout, udp_retries, global_task,
2044					update_completed, NULL, &request);
2045	check_result(result, "dns_request_createvia3");
2046
2047	if (debugging)
2048		show_message(stdout, updatemsg, "Outgoing update query:");
2049
2050	requests++;
2051}
2052
2053static void
2054recvsoa(isc_task_t *task, isc_event_t *event) {
2055	dns_requestevent_t *reqev = NULL;
2056	dns_request_t *request = NULL;
2057	isc_result_t result, eresult;
2058	dns_message_t *rcvmsg = NULL;
2059	dns_section_t section;
2060	dns_name_t *name = NULL;
2061	dns_rdataset_t *soaset = NULL;
2062	dns_rdata_soa_t soa;
2063	dns_rdata_t soarr = DNS_RDATA_INIT;
2064	int pass = 0;
2065	dns_name_t master;
2066	nsu_requestinfo_t *reqinfo;
2067	dns_message_t *soaquery = NULL;
2068	isc_sockaddr_t *addr;
2069	isc_boolean_t seencname = ISC_FALSE;
2070	dns_name_t tname;
2071	unsigned int nlabels;
2072
2073	UNUSED(task);
2074
2075	ddebug("recvsoa()");
2076
2077	requests--;
2078
2079	REQUIRE(event->ev_type == DNS_EVENT_REQUESTDONE);
2080	reqev = (dns_requestevent_t *)event;
2081	request = reqev->request;
2082	eresult = reqev->result;
2083	reqinfo = reqev->ev_arg;
2084	soaquery = reqinfo->msg;
2085	addr = reqinfo->addr;
2086
2087	if (shuttingdown) {
2088		dns_request_destroy(&request);
2089		dns_message_destroy(&soaquery);
2090		isc_mem_put(mctx, reqinfo, sizeof(nsu_requestinfo_t));
2091		isc_event_free(&event);
2092		maybeshutdown();
2093		return;
2094	}
2095
2096	if (eresult != ISC_R_SUCCESS) {
2097		char addrbuf[ISC_SOCKADDR_FORMATSIZE];
2098
2099		isc_sockaddr_format(addr, addrbuf, sizeof(addrbuf));
2100		fprintf(stderr, "; Communication with %s failed: %s\n",
2101			addrbuf, isc_result_totext(eresult));
2102		if (userserver != NULL)
2103			fatal("could not talk to specified name server");
2104		else if (++ns_inuse >= lwconf->nsnext)
2105			fatal("could not talk to any default name server");
2106		ddebug("Destroying request [%p]", request);
2107		dns_request_destroy(&request);
2108		dns_message_renderreset(soaquery);
2109		dns_message_settsigkey(soaquery, NULL);
2110		sendrequest(localaddr, &servers[ns_inuse], soaquery, &request);
2111		isc_mem_put(mctx, reqinfo, sizeof(nsu_requestinfo_t));
2112		isc_event_free(&event);
2113		setzoneclass(dns_rdataclass_none);
2114		return;
2115	}
2116
2117	isc_mem_put(mctx, reqinfo, sizeof(nsu_requestinfo_t));
2118	reqinfo = NULL;
2119	isc_event_free(&event);
2120	reqev = NULL;
2121
2122	ddebug("About to create rcvmsg");
2123	result = dns_message_create(mctx, DNS_MESSAGE_INTENTPARSE, &rcvmsg);
2124	check_result(result, "dns_message_create");
2125	result = dns_request_getresponse(request, rcvmsg,
2126					 DNS_MESSAGEPARSE_PRESERVEORDER);
2127	if (result == DNS_R_TSIGERRORSET && userserver != NULL) {
2128		dns_message_destroy(&rcvmsg);
2129		ddebug("Destroying request [%p]", request);
2130		dns_request_destroy(&request);
2131		reqinfo = isc_mem_get(mctx, sizeof(nsu_requestinfo_t));
2132		if (reqinfo == NULL)
2133			fatal("out of memory");
2134		reqinfo->msg = soaquery;
2135		reqinfo->addr = addr;
2136		dns_message_renderreset(soaquery);
2137		ddebug("retrying soa request without TSIG");
2138		result = dns_request_createvia3(requestmgr, soaquery,
2139						localaddr, addr, 0, NULL,
2140						FIND_TIMEOUT * 20,
2141						FIND_TIMEOUT, 3,
2142						global_task, recvsoa, reqinfo,
2143						&request);
2144		check_result(result, "dns_request_createvia");
2145		requests++;
2146		return;
2147	}
2148	check_result(result, "dns_request_getresponse");
2149	section = DNS_SECTION_ANSWER;
2150	if (debugging)
2151		show_message(stderr, rcvmsg, "Reply from SOA query:");
2152
2153	if (rcvmsg->rcode != dns_rcode_noerror &&
2154	    rcvmsg->rcode != dns_rcode_nxdomain)
2155		fatal("response to SOA query was unsuccessful");
2156
2157	if (userzone != NULL && rcvmsg->rcode == dns_rcode_nxdomain) {
2158		char namebuf[DNS_NAME_FORMATSIZE];
2159		dns_name_format(userzone, namebuf, sizeof(namebuf));
2160		error("specified zone '%s' does not exist (NXDOMAIN)",
2161		      namebuf);
2162		dns_message_destroy(&rcvmsg);
2163		dns_request_destroy(&request);
2164		dns_message_destroy(&soaquery);
2165		ddebug("Out of recvsoa");
2166		done_update();
2167		return;
2168	}
2169
2170 lookforsoa:
2171	if (pass == 0)
2172		section = DNS_SECTION_ANSWER;
2173	else if (pass == 1)
2174		section = DNS_SECTION_AUTHORITY;
2175	else
2176		goto droplabel;
2177
2178	result = dns_message_firstname(rcvmsg, section);
2179	if (result != ISC_R_SUCCESS) {
2180		pass++;
2181		goto lookforsoa;
2182	}
2183	while (result == ISC_R_SUCCESS) {
2184		name = NULL;
2185		dns_message_currentname(rcvmsg, section, &name);
2186		soaset = NULL;
2187		result = dns_message_findtype(name, dns_rdatatype_soa, 0,
2188					      &soaset);
2189		if (result == ISC_R_SUCCESS)
2190			break;
2191		if (section == DNS_SECTION_ANSWER) {
2192			dns_rdataset_t *tset = NULL;
2193			if (dns_message_findtype(name, dns_rdatatype_cname, 0,
2194						 &tset) == ISC_R_SUCCESS ||
2195			    dns_message_findtype(name, dns_rdatatype_dname, 0,
2196						 &tset) == ISC_R_SUCCESS ) {
2197				seencname = ISC_TRUE;
2198				break;
2199			}
2200		}
2201
2202		result = dns_message_nextname(rcvmsg, section);
2203	}
2204
2205	if (soaset == NULL && !seencname) {
2206		pass++;
2207		goto lookforsoa;
2208	}
2209
2210	if (seencname)
2211		goto droplabel;
2212
2213	if (debugging) {
2214		char namestr[DNS_NAME_FORMATSIZE];
2215		dns_name_format(name, namestr, sizeof(namestr));
2216		fprintf(stderr, "Found zone name: %s\n", namestr);
2217	}
2218
2219	result = dns_rdataset_first(soaset);
2220	check_result(result, "dns_rdataset_first");
2221
2222	dns_rdata_init(&soarr);
2223	dns_rdataset_current(soaset, &soarr);
2224	result = dns_rdata_tostruct(&soarr, &soa, NULL);
2225	check_result(result, "dns_rdata_tostruct");
2226
2227	dns_name_init(&master, NULL);
2228	dns_name_clone(&soa.origin, &master);
2229
2230	if (userzone != NULL)
2231		zonename = userzone;
2232	else
2233		zonename = name;
2234
2235	if (debugging) {
2236		char namestr[DNS_NAME_FORMATSIZE];
2237		dns_name_format(&master, namestr, sizeof(namestr));
2238		fprintf(stderr, "The master is: %s\n", namestr);
2239	}
2240
2241	if (userserver != NULL)
2242		serveraddr = userserver;
2243	else {
2244		char serverstr[DNS_NAME_MAXTEXT+1];
2245		isc_buffer_t buf;
2246
2247		isc_buffer_init(&buf, serverstr, sizeof(serverstr));
2248		result = dns_name_totext(&master, ISC_TRUE, &buf);
2249		check_result(result, "dns_name_totext");
2250		serverstr[isc_buffer_usedlength(&buf)] = 0;
2251		get_address(serverstr, DNSDEFAULTPORT, &tempaddr);
2252		serveraddr = &tempaddr;
2253	}
2254	dns_rdata_freestruct(&soa);
2255
2256#ifdef GSSAPI
2257	if (usegsstsig) {
2258		dns_name_init(&tmpzonename, NULL);
2259		dns_name_dup(zonename, mctx, &tmpzonename);
2260		dns_name_init(&restart_master, NULL);
2261		dns_name_dup(&master, mctx, &restart_master);
2262		start_gssrequest(&master);
2263	} else {
2264		send_update(zonename, serveraddr, localaddr);
2265		setzoneclass(dns_rdataclass_none);
2266	}
2267#else
2268	send_update(zonename, serveraddr, localaddr);
2269	setzoneclass(dns_rdataclass_none);
2270#endif
2271
2272	dns_message_destroy(&soaquery);
2273	dns_request_destroy(&request);
2274
2275 out:
2276	dns_message_destroy(&rcvmsg);
2277	ddebug("Out of recvsoa");
2278	return;
2279
2280 droplabel:
2281	result = dns_message_firstname(soaquery, DNS_SECTION_QUESTION);
2282	INSIST(result == ISC_R_SUCCESS);
2283	name = NULL;
2284	dns_message_currentname(soaquery, DNS_SECTION_QUESTION, &name);
2285	nlabels = dns_name_countlabels(name);
2286	if (nlabels == 1)
2287		fatal("could not find enclosing zone");
2288	dns_name_init(&tname, NULL);
2289	dns_name_getlabelsequence(name, 1, nlabels - 1, &tname);
2290	dns_name_clone(&tname, name);
2291	dns_request_destroy(&request);
2292	dns_message_renderreset(soaquery);
2293	dns_message_settsigkey(soaquery, NULL);
2294	if (userserver != NULL)
2295		sendrequest(localaddr, userserver, soaquery, &request);
2296	else
2297		sendrequest(localaddr, &servers[ns_inuse], soaquery, &request);
2298	goto out;
2299}
2300
2301static void
2302sendrequest(isc_sockaddr_t *srcaddr, isc_sockaddr_t *destaddr,
2303	    dns_message_t *msg, dns_request_t **request)
2304{
2305	isc_result_t result;
2306	nsu_requestinfo_t *reqinfo;
2307
2308	reqinfo = isc_mem_get(mctx, sizeof(nsu_requestinfo_t));
2309	if (reqinfo == NULL)
2310		fatal("out of memory");
2311	reqinfo->msg = msg;
2312	reqinfo->addr = destaddr;
2313	result = dns_request_createvia3(requestmgr, msg, srcaddr, destaddr, 0,
2314					(userserver != NULL) ? tsigkey : NULL,
2315					FIND_TIMEOUT * 20, FIND_TIMEOUT, 3,
2316					global_task, recvsoa, reqinfo, request);
2317	check_result(result, "dns_request_createvia");
2318	requests++;
2319}
2320
2321#ifdef GSSAPI
2322static void
2323start_gssrequest(dns_name_t *master)
2324{
2325	gss_ctx_id_t context;
2326	isc_buffer_t buf;
2327	isc_result_t result;
2328	isc_uint32_t val = 0;
2329	dns_message_t *rmsg;
2330	dns_request_t *request = NULL;
2331	dns_name_t *servname;
2332	dns_fixedname_t fname;
2333	char namestr[DNS_NAME_FORMATSIZE];
2334	char keystr[DNS_NAME_FORMATSIZE];
2335
2336	debug("start_gssrequest");
2337	usevc = ISC_TRUE;
2338
2339	if (gssring != NULL)
2340		dns_tsigkeyring_destroy(&gssring);
2341	gssring = NULL;
2342	result = dns_tsigkeyring_create(mctx, &gssring);
2343
2344	if (result != ISC_R_SUCCESS)
2345		fatal("dns_tsigkeyring_create failed: %s",
2346		      isc_result_totext(result));
2347
2348	dns_name_format(master, namestr, sizeof(namestr));
2349	if (kserver == NULL) {
2350		kserver = isc_mem_get(mctx, sizeof(isc_sockaddr_t));
2351		if (kserver == NULL)
2352			fatal("out of memory");
2353	}
2354	if (userserver == NULL)
2355		get_address(namestr, DNSDEFAULTPORT, kserver);
2356	else
2357		(void)memcpy(kserver, userserver, sizeof(isc_sockaddr_t));
2358
2359	dns_fixedname_init(&fname);
2360	servname = dns_fixedname_name(&fname);
2361
2362	result = isc_string_printf(servicename, sizeof(servicename),
2363				   "DNS/%s%s", namestr, realm ? realm : "");
2364	if (result != ISC_R_SUCCESS)
2365		fatal("isc_string_printf(servicename) failed: %s",
2366		      isc_result_totext(result));
2367	isc_buffer_init(&buf, servicename, strlen(servicename));
2368	isc_buffer_add(&buf, strlen(servicename));
2369	result = dns_name_fromtext(servname, &buf, dns_rootname,
2370				   ISC_FALSE, NULL);
2371	if (result != ISC_R_SUCCESS)
2372		fatal("dns_name_fromtext(servname) failed: %s",
2373		      isc_result_totext(result));
2374
2375	dns_fixedname_init(&fkname);
2376	keyname = dns_fixedname_name(&fkname);
2377
2378	isc_random_get(&val);
2379	result = isc_string_printf(keystr, sizeof(keystr), "%u.sig-%s",
2380				   val, namestr);
2381	if (result != ISC_R_SUCCESS)
2382		fatal("isc_string_printf(keystr) failed: %s",
2383		      isc_result_totext(result));
2384	isc_buffer_init(&buf, keystr, strlen(keystr));
2385	isc_buffer_add(&buf, strlen(keystr));
2386
2387	result = dns_name_fromtext(keyname, &buf, dns_rootname,
2388				   ISC_FALSE, NULL);
2389	if (result != ISC_R_SUCCESS)
2390		fatal("dns_name_fromtext(keyname) failed: %s",
2391		      isc_result_totext(result));
2392
2393	/* Windows doesn't recognize name compression in the key name. */
2394	keyname->attributes |= DNS_NAMEATTR_NOCOMPRESS;
2395
2396	rmsg = NULL;
2397	result = dns_message_create(mctx, DNS_MESSAGE_INTENTRENDER, &rmsg);
2398	if (result != ISC_R_SUCCESS)
2399		fatal("dns_message_create failed: %s",
2400		      isc_result_totext(result));
2401
2402	/* Build first request. */
2403	context = GSS_C_NO_CONTEXT;
2404	result = dns_tkey_buildgssquery(rmsg, keyname, servname, NULL, 0,
2405					&context, use_win2k_gsstsig);
2406	if (result == ISC_R_FAILURE)
2407		fatal("Check your Kerberos ticket, it may have expired.");
2408	if (result != ISC_R_SUCCESS)
2409		fatal("dns_tkey_buildgssquery failed: %s",
2410		      isc_result_totext(result));
2411
2412	send_gssrequest(localaddr, kserver, rmsg, &request, context);
2413}
2414
2415static void
2416send_gssrequest(isc_sockaddr_t *srcaddr, isc_sockaddr_t *destaddr,
2417		dns_message_t *msg, dns_request_t **request,
2418		gss_ctx_id_t context)
2419{
2420	isc_result_t result;
2421	nsu_gssinfo_t *reqinfo;
2422	unsigned int options = 0;
2423
2424	debug("send_gssrequest");
2425	reqinfo = isc_mem_get(mctx, sizeof(nsu_gssinfo_t));
2426	if (reqinfo == NULL)
2427		fatal("out of memory");
2428	reqinfo->msg = msg;
2429	reqinfo->addr = destaddr;
2430	reqinfo->context = context;
2431
2432	options |= DNS_REQUESTOPT_TCP;
2433	result = dns_request_createvia3(requestmgr, msg, srcaddr, destaddr,
2434					options, tsigkey, FIND_TIMEOUT * 20,
2435					FIND_TIMEOUT, 3, global_task, recvgss,
2436					reqinfo, request);
2437	check_result(result, "dns_request_createvia3");
2438	if (debugging)
2439		show_message(stdout, msg, "Outgoing update query:");
2440	requests++;
2441}
2442
2443static void
2444recvgss(isc_task_t *task, isc_event_t *event) {
2445	dns_requestevent_t *reqev = NULL;
2446	dns_request_t *request = NULL;
2447	isc_result_t result, eresult;
2448	dns_message_t *rcvmsg = NULL;
2449	nsu_gssinfo_t *reqinfo;
2450	dns_message_t *tsigquery = NULL;
2451	isc_sockaddr_t *addr;
2452	gss_ctx_id_t context;
2453	isc_buffer_t buf;
2454	dns_name_t *servname;
2455	dns_fixedname_t fname;
2456
2457	UNUSED(task);
2458
2459	ddebug("recvgss()");
2460
2461	requests--;
2462
2463	REQUIRE(event->ev_type == DNS_EVENT_REQUESTDONE);
2464	reqev = (dns_requestevent_t *)event;
2465	request = reqev->request;
2466	eresult = reqev->result;
2467	reqinfo = reqev->ev_arg;
2468	tsigquery = reqinfo->msg;
2469	context = reqinfo->context;
2470	addr = reqinfo->addr;
2471
2472	if (shuttingdown) {
2473		dns_request_destroy(&request);
2474		dns_message_destroy(&tsigquery);
2475		isc_mem_put(mctx, reqinfo, sizeof(nsu_gssinfo_t));
2476		isc_event_free(&event);
2477		maybeshutdown();
2478		return;
2479	}
2480
2481	if (eresult != ISC_R_SUCCESS) {
2482		char addrbuf[ISC_SOCKADDR_FORMATSIZE];
2483
2484		isc_sockaddr_format(addr, addrbuf, sizeof(addrbuf));
2485		fprintf(stderr, "; Communication with %s failed: %s\n",
2486			addrbuf, isc_result_totext(eresult));
2487		if (userserver != NULL)
2488			fatal("could not talk to specified name server");
2489		else if (++ns_inuse >= lwconf->nsnext)
2490			fatal("could not talk to any default name server");
2491		ddebug("Destroying request [%p]", request);
2492		dns_request_destroy(&request);
2493		dns_message_renderreset(tsigquery);
2494		sendrequest(localaddr, &servers[ns_inuse], tsigquery,
2495			    &request);
2496		isc_mem_put(mctx, reqinfo, sizeof(nsu_gssinfo_t));
2497		isc_event_free(&event);
2498		return;
2499	}
2500	isc_mem_put(mctx, reqinfo, sizeof(nsu_gssinfo_t));
2501
2502	isc_event_free(&event);
2503	reqev = NULL;
2504
2505	ddebug("recvgss creating rcvmsg");
2506	result = dns_message_create(mctx, DNS_MESSAGE_INTENTPARSE, &rcvmsg);
2507	check_result(result, "dns_message_create");
2508
2509	result = dns_request_getresponse(request, rcvmsg,
2510					 DNS_MESSAGEPARSE_PRESERVEORDER);
2511	check_result(result, "dns_request_getresponse");
2512
2513	if (debugging)
2514		show_message(stderr, rcvmsg,
2515			     "recvmsg reply from GSS-TSIG query");
2516
2517	if (rcvmsg->rcode == dns_rcode_formerr && !tried_other_gsstsig) {
2518		ddebug("recvgss trying %s GSS-TSIG",
2519		       use_win2k_gsstsig ? "Standard" : "Win2k");
2520		if (use_win2k_gsstsig)
2521			use_win2k_gsstsig = ISC_FALSE;
2522		else
2523			use_win2k_gsstsig = ISC_TRUE;
2524		tried_other_gsstsig = ISC_TRUE;
2525		start_gssrequest(&restart_master);
2526		goto done;
2527	}
2528
2529	if (rcvmsg->rcode != dns_rcode_noerror &&
2530	    rcvmsg->rcode != dns_rcode_nxdomain)
2531		fatal("response to GSS-TSIG query was unsuccessful");
2532
2533
2534	dns_fixedname_init(&fname);
2535	servname = dns_fixedname_name(&fname);
2536	isc_buffer_init(&buf, servicename, strlen(servicename));
2537	isc_buffer_add(&buf, strlen(servicename));
2538	result = dns_name_fromtext(servname, &buf, dns_rootname,
2539				   ISC_FALSE, NULL);
2540	check_result(result, "dns_name_fromtext");
2541
2542	tsigkey = NULL;
2543	result = dns_tkey_gssnegotiate(tsigquery, rcvmsg, servname,
2544				       &context, &tsigkey, gssring,
2545				       use_win2k_gsstsig);
2546	switch (result) {
2547
2548	case DNS_R_CONTINUE:
2549		send_gssrequest(localaddr, kserver, tsigquery, &request,
2550				context);
2551		break;
2552
2553	case ISC_R_SUCCESS:
2554		/*
2555		 * XXXSRA Waaay too much fun here.  There's no good
2556		 * reason why we need a TSIG here (the people who put
2557		 * it into the spec admitted at the time that it was
2558		 * not a security issue), and Windows clients don't
2559		 * seem to work if named complies with the spec and
2560		 * includes the gratuitous TSIG.  So we're in the
2561		 * bizarre situation of having to choose between
2562		 * complying with a useless requirement in the spec
2563		 * and interoperating.  This is nuts.  If we can
2564		 * confirm this behavior, we should ask the WG to
2565		 * consider removing the requirement for the
2566		 * gratuitous TSIG here.  For the moment, we ignore
2567		 * the TSIG -- this too is a spec violation, but it's
2568		 * the least insane thing to do.
2569		 */
2570#if 0
2571		/*
2572		 * Verify the signature.
2573		 */
2574		rcvmsg->state = DNS_SECTION_ANY;
2575		dns_message_setquerytsig(rcvmsg, NULL);
2576		result = dns_message_settsigkey(rcvmsg, tsigkey);
2577		check_result(result, "dns_message_settsigkey");
2578		result = dns_message_checksig(rcvmsg, NULL);
2579		ddebug("tsig verification: %s", dns_result_totext(result));
2580		check_result(result, "dns_message_checksig");
2581#endif /* 0 */
2582
2583		send_update(&tmpzonename, serveraddr, localaddr);
2584		setzoneclass(dns_rdataclass_none);
2585		break;
2586
2587	default:
2588		fatal("dns_tkey_negotiategss: %s", isc_result_totext(result));
2589	}
2590
2591 done:
2592	dns_request_destroy(&request);
2593	dns_message_destroy(&tsigquery);
2594
2595	dns_message_destroy(&rcvmsg);
2596	ddebug("Out of recvgss");
2597}
2598#endif
2599
2600static void
2601start_update(void) {
2602	isc_result_t result;
2603	dns_rdataset_t *rdataset = NULL;
2604	dns_name_t *name = NULL;
2605	dns_request_t *request = NULL;
2606	dns_message_t *soaquery = NULL;
2607	dns_name_t *firstname;
2608	dns_section_t section = DNS_SECTION_UPDATE;
2609
2610	ddebug("start_update()");
2611
2612	if (answer != NULL)
2613		dns_message_destroy(&answer);
2614
2615	if (userzone != NULL && userserver != NULL && ! usegsstsig) {
2616		send_update(userzone, userserver, localaddr);
2617		setzoneclass(dns_rdataclass_none);
2618		return;
2619	}
2620
2621	result = dns_message_create(mctx, DNS_MESSAGE_INTENTRENDER,
2622				    &soaquery);
2623	check_result(result, "dns_message_create");
2624
2625	if (userserver == NULL)
2626		soaquery->flags |= DNS_MESSAGEFLAG_RD;
2627
2628	result = dns_message_gettempname(soaquery, &name);
2629	check_result(result, "dns_message_gettempname");
2630
2631	result = dns_message_gettemprdataset(soaquery, &rdataset);
2632	check_result(result, "dns_message_gettemprdataset");
2633
2634	dns_rdataset_makequestion(rdataset, getzoneclass(), dns_rdatatype_soa);
2635
2636	if (userzone != NULL) {
2637		dns_name_init(name, NULL);
2638		dns_name_clone(userzone, name);
2639	} else {
2640		dns_rdataset_t *tmprdataset;
2641		result = dns_message_firstname(updatemsg, section);
2642		if (result == ISC_R_NOMORE) {
2643			section = DNS_SECTION_PREREQUISITE;
2644			result = dns_message_firstname(updatemsg, section);
2645		}
2646		if (result != ISC_R_SUCCESS) {
2647			dns_message_puttempname(soaquery, &name);
2648			dns_rdataset_disassociate(rdataset);
2649			dns_message_puttemprdataset(soaquery, &rdataset);
2650			dns_message_destroy(&soaquery);
2651			done_update();
2652			return;
2653		}
2654		firstname = NULL;
2655		dns_message_currentname(updatemsg, section, &firstname);
2656		dns_name_init(name, NULL);
2657		dns_name_clone(firstname, name);
2658		/*
2659		 * Looks to see if the first name references a DS record
2660		 * and if that name is not the root remove a label as DS
2661		 * records live in the parent zone so we need to start our
2662		 * search one label up.
2663		 */
2664		tmprdataset = ISC_LIST_HEAD(firstname->list);
2665		if (section == DNS_SECTION_UPDATE &&
2666		    !dns_name_equal(firstname, dns_rootname) &&
2667		    tmprdataset->type == dns_rdatatype_ds) {
2668		    unsigned int labels = dns_name_countlabels(name);
2669		    dns_name_getlabelsequence(name, 1, labels - 1, name);
2670		}
2671	}
2672
2673	ISC_LIST_INIT(name->list);
2674	ISC_LIST_APPEND(name->list, rdataset, link);
2675	dns_message_addname(soaquery, name, DNS_SECTION_QUESTION);
2676
2677	if (userserver != NULL)
2678		sendrequest(localaddr, userserver, soaquery, &request);
2679	else {
2680		ns_inuse = 0;
2681		sendrequest(localaddr, &servers[ns_inuse], soaquery, &request);
2682	}
2683}
2684
2685static void
2686cleanup(void) {
2687	ddebug("cleanup()");
2688
2689	if (answer != NULL)
2690		dns_message_destroy(&answer);
2691
2692#ifdef GSSAPI
2693	if (tsigkey != NULL) {
2694		ddebug("detach tsigkey x%p", tsigkey);
2695		dns_tsigkey_detach(&tsigkey);
2696	}
2697	if (gssring != NULL) {
2698		ddebug("Destroying GSS-TSIG keyring");
2699		dns_tsigkeyring_destroy(&gssring);
2700	}
2701	if (kserver != NULL) {
2702		isc_mem_put(mctx, kserver, sizeof(isc_sockaddr_t));
2703		kserver = NULL;
2704	}
2705	if (realm != NULL) {
2706		isc_mem_free(mctx, realm);
2707		realm = NULL;
2708	}
2709#endif
2710
2711	ddebug("Shutting down task manager");
2712	isc_taskmgr_destroy(&taskmgr);
2713
2714	ddebug("Destroying event");
2715	isc_event_free(&global_event);
2716
2717	ddebug("Shutting down socket manager");
2718	isc_socketmgr_destroy(&socketmgr);
2719
2720	ddebug("Shutting down timer manager");
2721	isc_timermgr_destroy(&timermgr);
2722
2723	ddebug("Destroying hash context");
2724	isc_hash_destroy();
2725
2726	ddebug("Destroying name state");
2727	dns_name_destroy();
2728
2729	ddebug("Removing log context");
2730	isc_log_destroy(&lctx);
2731
2732	ddebug("Destroying memory context");
2733	if (memdebugging)
2734		isc_mem_stats(mctx, stderr);
2735	isc_mem_destroy(&mctx);
2736}
2737
2738static void
2739getinput(isc_task_t *task, isc_event_t *event) {
2740	isc_boolean_t more;
2741
2742	UNUSED(task);
2743
2744	if (shuttingdown) {
2745		maybeshutdown();
2746		return;
2747	}
2748
2749	if (global_event == NULL)
2750		global_event = event;
2751
2752	reset_system();
2753	more = user_interaction();
2754	if (!more) {
2755		isc_app_shutdown();
2756		return;
2757	}
2758	start_update();
2759	return;
2760}
2761
2762int
2763main(int argc, char **argv) {
2764	isc_result_t result;
2765	style = &dns_master_style_debug;
2766
2767	input = stdin;
2768
2769	interactive = ISC_TF(isatty(0));
2770
2771	isc_app_start();
2772
2773	pre_parse_args(argc, argv);
2774
2775	result = isc_mem_create(0, 0, &mctx);
2776	check_result(result, "isc_mem_create");
2777
2778	parse_args(argc, argv, mctx, &entropy);
2779
2780	setup_system();
2781
2782	result = isc_app_onrun(mctx, global_task, getinput, NULL);
2783	check_result(result, "isc_app_onrun");
2784
2785	(void)isc_app_run();
2786
2787	cleanup();
2788
2789	isc_app_finish();
2790
2791	if (seenerror)
2792		return (2);
2793	else
2794		return (0);
2795}
2796