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