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