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