1/*
2 * Copyright (C) 2004-2011  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 == 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	while (*cmdline != 0 && isspace((unsigned char)*cmdline))
1158		cmdline++;
1159
1160	if (*cmdline != 0) {
1161		dns_rdatacallbacks_init(&callbacks);
1162		result = isc_lex_create(mctx, strlen(cmdline), &lex);
1163		check_result(result, "isc_lex_create");
1164		isc_buffer_init(&source, cmdline, strlen(cmdline));
1165		isc_buffer_add(&source, strlen(cmdline));
1166		result = isc_lex_openbuffer(lex, &source);
1167		check_result(result, "isc_lex_openbuffer");
1168		result = isc_buffer_allocate(mctx, &buf, MAXWIRE);
1169		check_result(result, "isc_buffer_allocate");
1170		result = dns_rdata_fromtext(NULL, rdataclass, rdatatype, lex,
1171					    dns_rootname, 0, mctx, buf,
1172					    &callbacks);
1173		isc_lex_destroy(&lex);
1174		if (result == ISC_R_SUCCESS) {
1175			isc_buffer_usedregion(buf, &r);
1176			result = isc_buffer_allocate(mctx, &newbuf, r.length);
1177			check_result(result, "isc_buffer_allocate");
1178			isc_buffer_putmem(newbuf, r.base, r.length);
1179			isc_buffer_usedregion(newbuf, &r);
1180			dns_rdata_fromregion(rdata, rdataclass, rdatatype, &r);
1181			isc_buffer_free(&buf);
1182			dns_message_takebuffer(msg, &newbuf);
1183		} else {
1184			fprintf(stderr, "invalid rdata format: %s\n",
1185				isc_result_totext(result));
1186			isc_buffer_free(&buf);
1187			return (STATUS_SYNTAX);
1188		}
1189	} else {
1190		rdata->flags = DNS_RDATA_UPDATE;
1191	}
1192	*cmdlinep = cmdline;
1193	return (STATUS_MORE);
1194}
1195
1196static isc_uint16_t
1197make_prereq(char *cmdline, isc_boolean_t ispositive, isc_boolean_t isrrset) {
1198	isc_result_t result;
1199	char *word;
1200	dns_name_t *name = NULL;
1201	isc_textregion_t region;
1202	dns_rdataset_t *rdataset = NULL;
1203	dns_rdatalist_t *rdatalist = NULL;
1204	dns_rdataclass_t rdataclass;
1205	dns_rdatatype_t rdatatype;
1206	dns_rdata_t *rdata = NULL;
1207	isc_uint16_t retval;
1208
1209	ddebug("make_prereq()");
1210
1211	/*
1212	 * Read the owner name
1213	 */
1214	retval = parse_name(&cmdline, updatemsg, &name);
1215	if (retval != STATUS_MORE)
1216		return (retval);
1217
1218	/*
1219	 * If this is an rrset prereq, read the class or type.
1220	 */
1221	if (isrrset) {
1222		word = nsu_strsep(&cmdline, " \t\r\n");
1223		if (*word == 0) {
1224			fprintf(stderr, "could not read class or type\n");
1225			goto failure;
1226		}
1227		region.base = word;
1228		region.length = strlen(word);
1229		result = dns_rdataclass_fromtext(&rdataclass, &region);
1230		if (result == ISC_R_SUCCESS) {
1231			if (!setzoneclass(rdataclass)) {
1232				fprintf(stderr, "class mismatch: %s\n", word);
1233				goto failure;
1234			}
1235			/*
1236			 * Now read the type.
1237			 */
1238			word = nsu_strsep(&cmdline, " \t\r\n");
1239			if (*word == 0) {
1240				fprintf(stderr, "could not read type\n");
1241				goto failure;
1242			}
1243			region.base = word;
1244			region.length = strlen(word);
1245			result = dns_rdatatype_fromtext(&rdatatype, &region);
1246			if (result != ISC_R_SUCCESS) {
1247				fprintf(stderr, "invalid type: %s\n", word);
1248				goto failure;
1249			}
1250		} else {
1251			rdataclass = getzoneclass();
1252			result = dns_rdatatype_fromtext(&rdatatype, &region);
1253			if (result != ISC_R_SUCCESS) {
1254				fprintf(stderr, "invalid type: %s\n", word);
1255				goto failure;
1256			}
1257		}
1258	} else
1259		rdatatype = dns_rdatatype_any;
1260
1261	result = dns_message_gettemprdata(updatemsg, &rdata);
1262	check_result(result, "dns_message_gettemprdata");
1263
1264	dns_rdata_init(rdata);
1265
1266	if (isrrset && ispositive) {
1267		retval = parse_rdata(&cmdline, rdataclass, rdatatype,
1268				     updatemsg, rdata);
1269		if (retval != STATUS_MORE)
1270			goto failure;
1271	} else
1272		rdata->flags = DNS_RDATA_UPDATE;
1273
1274	result = dns_message_gettemprdatalist(updatemsg, &rdatalist);
1275	check_result(result, "dns_message_gettemprdatalist");
1276	result = dns_message_gettemprdataset(updatemsg, &rdataset);
1277	check_result(result, "dns_message_gettemprdataset");
1278	dns_rdatalist_init(rdatalist);
1279	rdatalist->type = rdatatype;
1280	if (ispositive) {
1281		if (isrrset && rdata->data != NULL)
1282			rdatalist->rdclass = rdataclass;
1283		else
1284			rdatalist->rdclass = dns_rdataclass_any;
1285	} else
1286		rdatalist->rdclass = dns_rdataclass_none;
1287	rdatalist->covers = 0;
1288	rdatalist->ttl = 0;
1289	rdata->rdclass = rdatalist->rdclass;
1290	rdata->type = rdatatype;
1291	ISC_LIST_INIT(rdatalist->rdata);
1292	ISC_LIST_APPEND(rdatalist->rdata, rdata, link);
1293	dns_rdataset_init(rdataset);
1294	dns_rdatalist_tordataset(rdatalist, rdataset);
1295	ISC_LIST_INIT(name->list);
1296	ISC_LIST_APPEND(name->list, rdataset, link);
1297	dns_message_addname(updatemsg, name, DNS_SECTION_PREREQUISITE);
1298	return (STATUS_MORE);
1299
1300 failure:
1301	if (name != NULL)
1302		dns_message_puttempname(updatemsg, &name);
1303	return (STATUS_SYNTAX);
1304}
1305
1306static isc_uint16_t
1307evaluate_prereq(char *cmdline) {
1308	char *word;
1309	isc_boolean_t ispositive, isrrset;
1310
1311	ddebug("evaluate_prereq()");
1312	word = nsu_strsep(&cmdline, " \t\r\n");
1313	if (*word == 0) {
1314		fprintf(stderr, "could not read operation code\n");
1315		return (STATUS_SYNTAX);
1316	}
1317	if (strcasecmp(word, "nxdomain") == 0) {
1318		ispositive = ISC_FALSE;
1319		isrrset = ISC_FALSE;
1320	} else if (strcasecmp(word, "yxdomain") == 0) {
1321		ispositive = ISC_TRUE;
1322		isrrset = ISC_FALSE;
1323	} else if (strcasecmp(word, "nxrrset") == 0) {
1324		ispositive = ISC_FALSE;
1325		isrrset = ISC_TRUE;
1326	} else if (strcasecmp(word, "yxrrset") == 0) {
1327		ispositive = ISC_TRUE;
1328		isrrset = ISC_TRUE;
1329	} else {
1330		fprintf(stderr, "incorrect operation code: %s\n", word);
1331		return (STATUS_SYNTAX);
1332	}
1333	return (make_prereq(cmdline, ispositive, isrrset));
1334}
1335
1336static isc_uint16_t
1337evaluate_server(char *cmdline) {
1338	char *word, *server;
1339	long port;
1340
1341	if (local_only) {
1342		fprintf(stderr, "cannot reset server in localhost-only mode\n");
1343		return (STATUS_SYNTAX);
1344	}
1345
1346	word = nsu_strsep(&cmdline, " \t\r\n");
1347	if (*word == 0) {
1348		fprintf(stderr, "could not read server name\n");
1349		return (STATUS_SYNTAX);
1350	}
1351	server = word;
1352
1353	word = nsu_strsep(&cmdline, " \t\r\n");
1354	if (*word == 0)
1355		port = dnsport;
1356	else {
1357		char *endp;
1358		port = strtol(word, &endp, 10);
1359		if (*endp != 0) {
1360			fprintf(stderr, "port '%s' is not numeric\n", word);
1361			return (STATUS_SYNTAX);
1362		} else if (port < 1 || port > 65535) {
1363			fprintf(stderr, "port '%s' is out of range "
1364				"(1 to 65535)\n", word);
1365			return (STATUS_SYNTAX);
1366		}
1367	}
1368
1369	if (userserver == NULL) {
1370		userserver = isc_mem_get(mctx, sizeof(isc_sockaddr_t));
1371		if (userserver == NULL)
1372			fatal("out of memory");
1373	}
1374
1375	get_address(server, (in_port_t)port, userserver);
1376
1377	return (STATUS_MORE);
1378}
1379
1380static isc_uint16_t
1381evaluate_local(char *cmdline) {
1382	char *word, *local;
1383	long port;
1384	struct in_addr in4;
1385	struct in6_addr in6;
1386
1387	word = nsu_strsep(&cmdline, " \t\r\n");
1388	if (*word == 0) {
1389		fprintf(stderr, "could not read server name\n");
1390		return (STATUS_SYNTAX);
1391	}
1392	local = word;
1393
1394	word = nsu_strsep(&cmdline, " \t\r\n");
1395	if (*word == 0)
1396		port = 0;
1397	else {
1398		char *endp;
1399		port = strtol(word, &endp, 10);
1400		if (*endp != 0) {
1401			fprintf(stderr, "port '%s' is not numeric\n", word);
1402			return (STATUS_SYNTAX);
1403		} else if (port < 1 || port > 65535) {
1404			fprintf(stderr, "port '%s' is out of range "
1405				"(1 to 65535)\n", word);
1406			return (STATUS_SYNTAX);
1407		}
1408	}
1409
1410	if (localaddr == NULL) {
1411		localaddr = isc_mem_get(mctx, sizeof(isc_sockaddr_t));
1412		if (localaddr == NULL)
1413			fatal("out of memory");
1414	}
1415
1416	if (have_ipv6 && inet_pton(AF_INET6, local, &in6) == 1)
1417		isc_sockaddr_fromin6(localaddr, &in6, (in_port_t)port);
1418	else if (have_ipv4 && inet_pton(AF_INET, local, &in4) == 1)
1419		isc_sockaddr_fromin(localaddr, &in4, (in_port_t)port);
1420	else {
1421		fprintf(stderr, "invalid address %s", local);
1422		return (STATUS_SYNTAX);
1423	}
1424
1425	return (STATUS_MORE);
1426}
1427
1428static isc_uint16_t
1429evaluate_key(char *cmdline) {
1430	char *namestr;
1431	char *secretstr;
1432	isc_buffer_t b;
1433	isc_result_t result;
1434	dns_fixedname_t fkeyname;
1435	dns_name_t *keyname;
1436	int secretlen;
1437	unsigned char *secret = NULL;
1438	isc_buffer_t secretbuf;
1439	dns_name_t *hmacname = NULL;
1440	isc_uint16_t digestbits = 0;
1441	char *n;
1442
1443	namestr = nsu_strsep(&cmdline, " \t\r\n");
1444	if (*namestr == 0) {
1445		fprintf(stderr, "could not read key name\n");
1446		return (STATUS_SYNTAX);
1447	}
1448
1449	dns_fixedname_init(&fkeyname);
1450	keyname = dns_fixedname_name(&fkeyname);
1451
1452	n = strchr(namestr, ':');
1453	if (n != NULL) {
1454		digestbits = parse_hmac(&hmacname, namestr, n - namestr);
1455		namestr = n + 1;
1456	} else
1457		hmacname = DNS_TSIG_HMACMD5_NAME;
1458
1459	isc_buffer_init(&b, namestr, strlen(namestr));
1460	isc_buffer_add(&b, strlen(namestr));
1461	result = dns_name_fromtext(keyname, &b, dns_rootname, 0, NULL);
1462	if (result != ISC_R_SUCCESS) {
1463		fprintf(stderr, "could not parse key name\n");
1464		return (STATUS_SYNTAX);
1465	}
1466
1467	secretstr = nsu_strsep(&cmdline, "\r\n");
1468	if (*secretstr == 0) {
1469		fprintf(stderr, "could not read key secret\n");
1470		return (STATUS_SYNTAX);
1471	}
1472	secretlen = strlen(secretstr) * 3 / 4;
1473	secret = isc_mem_allocate(mctx, secretlen);
1474	if (secret == NULL)
1475		fatal("out of memory");
1476
1477	isc_buffer_init(&secretbuf, secret, secretlen);
1478	result = isc_base64_decodestring(secretstr, &secretbuf);
1479	if (result != ISC_R_SUCCESS) {
1480		fprintf(stderr, "could not create key from %s: %s\n",
1481			secretstr, isc_result_totext(result));
1482		isc_mem_free(mctx, secret);
1483		return (STATUS_SYNTAX);
1484	}
1485	secretlen = isc_buffer_usedlength(&secretbuf);
1486
1487	if (tsigkey != NULL)
1488		dns_tsigkey_detach(&tsigkey);
1489	result = dns_tsigkey_create(keyname, hmacname, secret, secretlen,
1490				    ISC_FALSE, NULL, 0, 0, mctx, NULL,
1491				    &tsigkey);
1492	isc_mem_free(mctx, secret);
1493	if (result != ISC_R_SUCCESS) {
1494		fprintf(stderr, "could not create key from %s %s: %s\n",
1495			namestr, secretstr, dns_result_totext(result));
1496		return (STATUS_SYNTAX);
1497	}
1498	dst_key_setbits(tsigkey->key, digestbits);
1499	return (STATUS_MORE);
1500}
1501
1502static isc_uint16_t
1503evaluate_zone(char *cmdline) {
1504	char *word;
1505	isc_buffer_t b;
1506	isc_result_t result;
1507
1508	word = nsu_strsep(&cmdline, " \t\r\n");
1509	if (*word == 0) {
1510		fprintf(stderr, "could not read zone name\n");
1511		return (STATUS_SYNTAX);
1512	}
1513
1514	dns_fixedname_init(&fuserzone);
1515	userzone = dns_fixedname_name(&fuserzone);
1516	isc_buffer_init(&b, word, strlen(word));
1517	isc_buffer_add(&b, strlen(word));
1518	result = dns_name_fromtext(userzone, &b, dns_rootname, 0, NULL);
1519	if (result != ISC_R_SUCCESS) {
1520		userzone = NULL; /* Lest it point to an invalid name */
1521		fprintf(stderr, "could not parse zone name\n");
1522		return (STATUS_SYNTAX);
1523	}
1524
1525	return (STATUS_MORE);
1526}
1527
1528static isc_uint16_t
1529evaluate_realm(char *cmdline) {
1530#ifdef GSSAPI
1531	char *word;
1532	char buf[1024];
1533
1534	word = nsu_strsep(&cmdline, " \t\r\n");
1535	if (*word == 0) {
1536		if (realm != NULL)
1537			isc_mem_free(mctx, realm);
1538		realm = NULL;
1539		return (STATUS_MORE);
1540	}
1541
1542	snprintf(buf, sizeof(buf), "@%s", word);
1543	realm = isc_mem_strdup(mctx, buf);
1544	if (realm == NULL)
1545		fatal("out of memory");
1546	return (STATUS_MORE);
1547#else
1548	UNUSED(cmdline);
1549	return (STATUS_SYNTAX);
1550#endif
1551}
1552
1553static isc_uint16_t
1554evaluate_ttl(char *cmdline) {
1555	char *word;
1556	isc_result_t result;
1557	isc_uint32_t ttl;
1558
1559	word = nsu_strsep(&cmdline, " \t\r\n");
1560	if (*word == 0) {
1561		fprintf(stderr, "could not ttl\n");
1562		return (STATUS_SYNTAX);
1563	}
1564
1565	if (!strcasecmp(word, "none")) {
1566		default_ttl = 0;
1567		default_ttl_set = ISC_FALSE;
1568		return (STATUS_MORE);
1569	}
1570
1571	result = isc_parse_uint32(&ttl, word, 10);
1572	if (result != ISC_R_SUCCESS)
1573		return (STATUS_SYNTAX);
1574
1575	if (ttl > TTL_MAX) {
1576		fprintf(stderr, "ttl '%s' is out of range (0 to %u)\n",
1577			word, TTL_MAX);
1578		return (STATUS_SYNTAX);
1579	}
1580	default_ttl = ttl;
1581	default_ttl_set = ISC_TRUE;
1582
1583	return (STATUS_MORE);
1584}
1585
1586static isc_uint16_t
1587evaluate_class(char *cmdline) {
1588	char *word;
1589	isc_textregion_t r;
1590	isc_result_t result;
1591	dns_rdataclass_t rdclass;
1592
1593	word = nsu_strsep(&cmdline, " \t\r\n");
1594	if (*word == 0) {
1595		fprintf(stderr, "could not read class name\n");
1596		return (STATUS_SYNTAX);
1597	}
1598
1599	r.base = word;
1600	r.length = strlen(word);
1601	result = dns_rdataclass_fromtext(&rdclass, &r);
1602	if (result != ISC_R_SUCCESS) {
1603		fprintf(stderr, "could not parse class name: %s\n", word);
1604		return (STATUS_SYNTAX);
1605	}
1606	switch (rdclass) {
1607	case dns_rdataclass_none:
1608	case dns_rdataclass_any:
1609	case dns_rdataclass_reserved0:
1610		fprintf(stderr, "bad default class: %s\n", word);
1611		return (STATUS_SYNTAX);
1612	default:
1613		defaultclass = rdclass;
1614	}
1615
1616	return (STATUS_MORE);
1617}
1618
1619static isc_uint16_t
1620update_addordelete(char *cmdline, isc_boolean_t isdelete) {
1621	isc_result_t result;
1622	dns_name_t *name = NULL;
1623	isc_uint32_t ttl;
1624	char *word;
1625	dns_rdataclass_t rdataclass;
1626	dns_rdatatype_t rdatatype;
1627	dns_rdata_t *rdata = NULL;
1628	dns_rdatalist_t *rdatalist = NULL;
1629	dns_rdataset_t *rdataset = NULL;
1630	isc_textregion_t region;
1631	isc_uint16_t retval;
1632
1633	ddebug("update_addordelete()");
1634
1635	/*
1636	 * Read the owner name.
1637	 */
1638	retval = parse_name(&cmdline, updatemsg, &name);
1639	if (retval != STATUS_MORE)
1640		return (retval);
1641
1642	result = dns_message_gettemprdata(updatemsg, &rdata);
1643	check_result(result, "dns_message_gettemprdata");
1644
1645	dns_rdata_init(rdata);
1646
1647	/*
1648	 * If this is an add, read the TTL and verify that it's in range.
1649	 * If it's a delete, ignore a TTL if present (for compatibility).
1650	 */
1651	word = nsu_strsep(&cmdline, " \t\r\n");
1652	if (*word == 0) {
1653		if (!isdelete) {
1654			fprintf(stderr, "could not read owner ttl\n");
1655			goto failure;
1656		}
1657		else {
1658			ttl = 0;
1659			rdataclass = dns_rdataclass_any;
1660			rdatatype = dns_rdatatype_any;
1661			rdata->flags = DNS_RDATA_UPDATE;
1662			goto doneparsing;
1663		}
1664	}
1665	result = isc_parse_uint32(&ttl, word, 10);
1666	if (result != ISC_R_SUCCESS) {
1667		if (isdelete) {
1668			ttl = 0;
1669			goto parseclass;
1670		} else if (default_ttl_set) {
1671			ttl = default_ttl;
1672			goto parseclass;
1673		} else {
1674			fprintf(stderr, "ttl '%s': %s\n", word,
1675				isc_result_totext(result));
1676			goto failure;
1677		}
1678	}
1679
1680	if (isdelete)
1681		ttl = 0;
1682	else if (ttl > TTL_MAX) {
1683		fprintf(stderr, "ttl '%s' is out of range (0 to %u)\n",
1684			word, TTL_MAX);
1685		goto failure;
1686	}
1687
1688	/*
1689	 * Read the class or type.
1690	 */
1691	word = nsu_strsep(&cmdline, " \t\r\n");
1692 parseclass:
1693	if (*word == 0) {
1694		if (isdelete) {
1695			rdataclass = dns_rdataclass_any;
1696			rdatatype = dns_rdatatype_any;
1697			rdata->flags = DNS_RDATA_UPDATE;
1698			goto doneparsing;
1699		} else {
1700			fprintf(stderr, "could not read class or type\n");
1701			goto failure;
1702		}
1703	}
1704	region.base = word;
1705	region.length = strlen(word);
1706	rdataclass = dns_rdataclass_any;
1707	result = dns_rdataclass_fromtext(&rdataclass, &region);
1708	if (result == ISC_R_SUCCESS && rdataclass != dns_rdataclass_any) {
1709		if (!setzoneclass(rdataclass)) {
1710			fprintf(stderr, "class mismatch: %s\n", word);
1711			goto failure;
1712		}
1713		/*
1714		 * Now read the type.
1715		 */
1716		word = nsu_strsep(&cmdline, " \t\r\n");
1717		if (*word == 0) {
1718			if (isdelete) {
1719				rdataclass = dns_rdataclass_any;
1720				rdatatype = dns_rdatatype_any;
1721				rdata->flags = DNS_RDATA_UPDATE;
1722				goto doneparsing;
1723			} else {
1724				fprintf(stderr, "could not read type\n");
1725				goto failure;
1726			}
1727		}
1728		region.base = word;
1729		region.length = strlen(word);
1730		result = dns_rdatatype_fromtext(&rdatatype, &region);
1731		if (result != ISC_R_SUCCESS) {
1732			fprintf(stderr, "'%s' is not a valid type: %s\n",
1733				word, isc_result_totext(result));
1734			goto failure;
1735		}
1736	} else {
1737		rdataclass = getzoneclass();
1738		result = dns_rdatatype_fromtext(&rdatatype, &region);
1739		if (result != ISC_R_SUCCESS) {
1740			fprintf(stderr, "'%s' is not a valid class or type: "
1741				"%s\n", word, isc_result_totext(result));
1742			goto failure;
1743		}
1744	}
1745
1746	retval = parse_rdata(&cmdline, rdataclass, rdatatype, updatemsg,
1747			     rdata);
1748	if (retval != STATUS_MORE)
1749		goto failure;
1750
1751	if (isdelete) {
1752		if ((rdata->flags & DNS_RDATA_UPDATE) != 0)
1753			rdataclass = dns_rdataclass_any;
1754		else
1755			rdataclass = dns_rdataclass_none;
1756	} else {
1757		if ((rdata->flags & DNS_RDATA_UPDATE) != 0) {
1758			fprintf(stderr, "could not read rdata\n");
1759			goto failure;
1760		}
1761	}
1762
1763 doneparsing:
1764
1765	result = dns_message_gettemprdatalist(updatemsg, &rdatalist);
1766	check_result(result, "dns_message_gettemprdatalist");
1767	result = dns_message_gettemprdataset(updatemsg, &rdataset);
1768	check_result(result, "dns_message_gettemprdataset");
1769	dns_rdatalist_init(rdatalist);
1770	rdatalist->type = rdatatype;
1771	rdatalist->rdclass = rdataclass;
1772	rdatalist->covers = rdatatype;
1773	rdatalist->ttl = (dns_ttl_t)ttl;
1774	ISC_LIST_INIT(rdatalist->rdata);
1775	ISC_LIST_APPEND(rdatalist->rdata, rdata, link);
1776	dns_rdataset_init(rdataset);
1777	dns_rdatalist_tordataset(rdatalist, rdataset);
1778	ISC_LIST_INIT(name->list);
1779	ISC_LIST_APPEND(name->list, rdataset, link);
1780	dns_message_addname(updatemsg, name, DNS_SECTION_UPDATE);
1781	return (STATUS_MORE);
1782
1783 failure:
1784	if (name != NULL)
1785		dns_message_puttempname(updatemsg, &name);
1786	dns_message_puttemprdata(updatemsg, &rdata);
1787	return (STATUS_SYNTAX);
1788}
1789
1790static isc_uint16_t
1791evaluate_update(char *cmdline) {
1792	char *word;
1793	isc_boolean_t isdelete;
1794
1795	ddebug("evaluate_update()");
1796	word = nsu_strsep(&cmdline, " \t\r\n");
1797	if (*word == 0) {
1798		fprintf(stderr, "could not read operation code\n");
1799		return (STATUS_SYNTAX);
1800	}
1801	if (strcasecmp(word, "delete") == 0)
1802		isdelete = ISC_TRUE;
1803	else if (strcasecmp(word, "add") == 0)
1804		isdelete = ISC_FALSE;
1805	else {
1806		fprintf(stderr, "incorrect operation code: %s\n", word);
1807		return (STATUS_SYNTAX);
1808	}
1809	return (update_addordelete(cmdline, isdelete));
1810}
1811
1812static void
1813setzone(dns_name_t *zonename) {
1814	isc_result_t result;
1815	dns_name_t *name = NULL;
1816	dns_rdataset_t *rdataset = NULL;
1817
1818	result = dns_message_firstname(updatemsg, DNS_SECTION_ZONE);
1819	if (result == ISC_R_SUCCESS) {
1820		dns_message_currentname(updatemsg, DNS_SECTION_ZONE, &name);
1821		dns_message_removename(updatemsg, name, DNS_SECTION_ZONE);
1822		for (rdataset = ISC_LIST_HEAD(name->list);
1823		     rdataset != NULL;
1824		     rdataset = ISC_LIST_HEAD(name->list)) {
1825			ISC_LIST_UNLINK(name->list, rdataset, link);
1826			dns_rdataset_disassociate(rdataset);
1827			dns_message_puttemprdataset(updatemsg, &rdataset);
1828		}
1829		dns_message_puttempname(updatemsg, &name);
1830	}
1831
1832	if (zonename != NULL) {
1833		result = dns_message_gettempname(updatemsg, &name);
1834		check_result(result, "dns_message_gettempname");
1835		dns_name_init(name, NULL);
1836		dns_name_clone(zonename, name);
1837		result = dns_message_gettemprdataset(updatemsg, &rdataset);
1838		check_result(result, "dns_message_gettemprdataset");
1839		dns_rdataset_makequestion(rdataset, getzoneclass(),
1840					  dns_rdatatype_soa);
1841		ISC_LIST_INIT(name->list);
1842		ISC_LIST_APPEND(name->list, rdataset, link);
1843		dns_message_addname(updatemsg, name, DNS_SECTION_ZONE);
1844	}
1845}
1846
1847static void
1848show_message(FILE *stream, dns_message_t *msg, const char *description) {
1849	isc_result_t result;
1850	isc_buffer_t *buf = NULL;
1851	int bufsz;
1852
1853	ddebug("show_message()");
1854
1855	setzone(userzone);
1856
1857	bufsz = INITTEXT;
1858	do {
1859		if (bufsz > MAXTEXT) {
1860			fprintf(stderr, "could not allocate large enough "
1861				"buffer to display message\n");
1862			exit(1);
1863		}
1864		if (buf != NULL)
1865			isc_buffer_free(&buf);
1866		result = isc_buffer_allocate(mctx, &buf, bufsz);
1867		check_result(result, "isc_buffer_allocate");
1868		result = dns_message_totext(msg, style, 0, buf);
1869		bufsz *= 2;
1870	} while (result == ISC_R_NOSPACE);
1871	if (result != ISC_R_SUCCESS) {
1872		fprintf(stderr, "could not convert message to text format.\n");
1873		isc_buffer_free(&buf);
1874		return;
1875	}
1876	fprintf(stream, "%s\n%.*s", description,
1877	       (int)isc_buffer_usedlength(buf), (char*)isc_buffer_base(buf));
1878	isc_buffer_free(&buf);
1879}
1880
1881
1882static isc_uint16_t
1883get_next_command(void) {
1884	char cmdlinebuf[MAXCMD];
1885	char *cmdline;
1886	char *word;
1887
1888	ddebug("get_next_command()");
1889	if (interactive) {
1890		fprintf(stdout, "> ");
1891		fflush(stdout);
1892	}
1893	isc_app_block();
1894	cmdline = fgets(cmdlinebuf, MAXCMD, input);
1895	isc_app_unblock();
1896	if (cmdline == NULL)
1897		return (STATUS_QUIT);
1898	word = nsu_strsep(&cmdline, " \t\r\n");
1899
1900	if (feof(input))
1901		return (STATUS_QUIT);
1902	if (*word == 0)
1903		return (STATUS_SEND);
1904	if (word[0] == ';')
1905		return (STATUS_MORE);
1906	if (strcasecmp(word, "quit") == 0)
1907		return (STATUS_QUIT);
1908	if (strcasecmp(word, "prereq") == 0)
1909		return (evaluate_prereq(cmdline));
1910	if (strcasecmp(word, "update") == 0)
1911		return (evaluate_update(cmdline));
1912	if (strcasecmp(word, "server") == 0)
1913		return (evaluate_server(cmdline));
1914	if (strcasecmp(word, "local") == 0)
1915		return (evaluate_local(cmdline));
1916	if (strcasecmp(word, "zone") == 0)
1917		return (evaluate_zone(cmdline));
1918	if (strcasecmp(word, "class") == 0)
1919		return (evaluate_class(cmdline));
1920	if (strcasecmp(word, "send") == 0)
1921		return (STATUS_SEND);
1922	if (strcasecmp(word, "debug") == 0) {
1923		if (debugging)
1924			ddebugging = ISC_TRUE;
1925		else
1926			debugging = ISC_TRUE;
1927		return (STATUS_MORE);
1928	}
1929	if (strcasecmp(word, "ttl") == 0)
1930		return (evaluate_ttl(cmdline));
1931	if (strcasecmp(word, "show") == 0) {
1932		show_message(stdout, updatemsg, "Outgoing update query:");
1933		return (STATUS_MORE);
1934	}
1935	if (strcasecmp(word, "answer") == 0) {
1936		if (answer != NULL)
1937			show_message(stdout, answer, "Answer:");
1938		return (STATUS_MORE);
1939	}
1940	if (strcasecmp(word, "key") == 0) {
1941		usegsstsig = ISC_FALSE;
1942		return (evaluate_key(cmdline));
1943	}
1944	if (strcasecmp(word, "realm") == 0)
1945		return (evaluate_realm(cmdline));
1946	if (strcasecmp(word, "gsstsig") == 0) {
1947#ifdef GSSAPI
1948		usegsstsig = ISC_TRUE;
1949		use_win2k_gsstsig = ISC_FALSE;
1950#else
1951		fprintf(stderr, "gsstsig not supported\n");
1952#endif
1953		return (STATUS_MORE);
1954	}
1955	if (strcasecmp(word, "oldgsstsig") == 0) {
1956#ifdef GSSAPI
1957		usegsstsig = ISC_TRUE;
1958		use_win2k_gsstsig = ISC_TRUE;
1959#else
1960		fprintf(stderr, "gsstsig not supported\n");
1961#endif
1962		return (STATUS_MORE);
1963	}
1964	if (strcasecmp(word, "help") == 0) {
1965		fprintf(stdout,
1966"local address [port]      (set local resolver)\n"
1967"server address [port]     (set master server for zone)\n"
1968"send                      (send the update request)\n"
1969"show                      (show the update request)\n"
1970"answer                    (show the answer to the last request)\n"
1971"quit                      (quit, any pending update is not sent\n"
1972"help                      (display this message_\n"
1973"key [hmac:]keyname secret (use TSIG to sign the request)\n"
1974"gsstsig                   (use GSS_TSIG to sign the request)\n"
1975"oldgsstsig                (use Microsoft's GSS_TSIG to sign the request)\n"
1976"zone name                 (set the zone to be updated)\n"
1977"class CLASS               (set the zone's DNS class, e.g. IN (default), CH)\n"
1978"prereq nxdomain name      (does this name not exist)\n"
1979"prereq yxdomain name      (does this name exist)\n"
1980"prereq nxrrset ....       (does this RRset exist)\n"
1981"prereq yxrrset ....       (does this RRset not exist)\n"
1982"update add ....           (add the given record to the zone)\n"
1983"update delete ....        (remove the given record(s) from the zone)\n");
1984		return (STATUS_MORE);
1985	}
1986	fprintf(stderr, "incorrect section name: %s\n", word);
1987	return (STATUS_SYNTAX);
1988}
1989
1990static isc_boolean_t
1991user_interaction(void) {
1992	isc_uint16_t result = STATUS_MORE;
1993
1994	ddebug("user_interaction()");
1995	while ((result == STATUS_MORE) || (result == STATUS_SYNTAX)) {
1996		result = get_next_command();
1997		if (!interactive && result == STATUS_SYNTAX)
1998			fatal("syntax error");
1999	}
2000	if (result == STATUS_SEND)
2001		return (ISC_TRUE);
2002	return (ISC_FALSE);
2003
2004}
2005
2006static void
2007done_update(void) {
2008	isc_event_t *event = global_event;
2009	ddebug("done_update()");
2010	isc_task_send(global_task, &event);
2011}
2012
2013static void
2014check_tsig_error(dns_rdataset_t *rdataset, isc_buffer_t *b) {
2015	isc_result_t result;
2016	dns_rdata_t rdata = DNS_RDATA_INIT;
2017	dns_rdata_any_tsig_t tsig;
2018
2019	result = dns_rdataset_first(rdataset);
2020	check_result(result, "dns_rdataset_first");
2021	dns_rdataset_current(rdataset, &rdata);
2022	result = dns_rdata_tostruct(&rdata, &tsig, NULL);
2023	check_result(result, "dns_rdata_tostruct");
2024	if (tsig.error != 0) {
2025		if (isc_buffer_remaininglength(b) < 1)
2026		      check_result(ISC_R_NOSPACE, "isc_buffer_remaininglength");
2027		isc__buffer_putstr(b, "(" /*)*/);
2028		result = dns_tsigrcode_totext(tsig.error, b);
2029		check_result(result, "dns_tsigrcode_totext");
2030		if (isc_buffer_remaininglength(b) < 1)
2031		      check_result(ISC_R_NOSPACE, "isc_buffer_remaininglength");
2032		isc__buffer_putstr(b,  /*(*/ ")");
2033	}
2034}
2035
2036static void
2037update_completed(isc_task_t *task, isc_event_t *event) {
2038	dns_requestevent_t *reqev = NULL;
2039	isc_result_t result;
2040	dns_request_t *request;
2041
2042	UNUSED(task);
2043
2044	ddebug("update_completed()");
2045
2046	requests--;
2047
2048	REQUIRE(event->ev_type == DNS_EVENT_REQUESTDONE);
2049	reqev = (dns_requestevent_t *)event;
2050	request = reqev->request;
2051
2052	if (shuttingdown) {
2053		dns_request_destroy(&request);
2054		isc_event_free(&event);
2055		maybeshutdown();
2056		return;
2057	}
2058
2059	if (reqev->result != ISC_R_SUCCESS) {
2060		fprintf(stderr, "; Communication with server failed: %s\n",
2061			isc_result_totext(reqev->result));
2062		seenerror = ISC_TRUE;
2063		goto done;
2064	}
2065
2066	result = dns_message_create(mctx, DNS_MESSAGE_INTENTPARSE, &answer);
2067	check_result(result, "dns_message_create");
2068	result = dns_request_getresponse(request, answer,
2069					 DNS_MESSAGEPARSE_PRESERVEORDER);
2070	switch (result) {
2071	case ISC_R_SUCCESS:
2072		if (answer->verify_attempted)
2073			ddebug("tsig verification successful");
2074		break;
2075	case DNS_R_CLOCKSKEW:
2076	case DNS_R_EXPECTEDTSIG:
2077	case DNS_R_TSIGERRORSET:
2078	case DNS_R_TSIGVERIFYFAILURE:
2079	case DNS_R_UNEXPECTEDTSIG:
2080	case ISC_R_FAILURE:
2081#if 0
2082		if (usegsstsig && answer->rcode == dns_rcode_noerror) {
2083			/*
2084			 * For MS DNS that violates RFC 2845, section 4.2
2085			 */
2086			break;
2087		}
2088#endif
2089		fprintf(stderr, "; TSIG error with server: %s\n",
2090			isc_result_totext(result));
2091		seenerror = ISC_TRUE;
2092		break;
2093	default:
2094		check_result(result, "dns_request_getresponse");
2095	}
2096
2097	if (answer->rcode != dns_rcode_noerror) {
2098		seenerror = ISC_TRUE;
2099		if (!debugging) {
2100			char buf[64];
2101			isc_buffer_t b;
2102			dns_rdataset_t *rds;
2103
2104			isc_buffer_init(&b, buf, sizeof(buf) - 1);
2105			result = dns_rcode_totext(answer->rcode, &b);
2106			check_result(result, "dns_rcode_totext");
2107			rds = dns_message_gettsig(answer, NULL);
2108			if (rds != NULL)
2109				check_tsig_error(rds, &b);
2110			fprintf(stderr, "update failed: %.*s\n",
2111				(int)isc_buffer_usedlength(&b), buf);
2112		}
2113	}
2114	if (debugging)
2115		show_message(stderr, answer, "\nReply from update query:");
2116
2117 done:
2118	dns_request_destroy(&request);
2119	if (usegsstsig) {
2120		dns_name_free(&tmpzonename, mctx);
2121		dns_name_free(&restart_master, mctx);
2122	}
2123	isc_event_free(&event);
2124	done_update();
2125}
2126
2127static void
2128send_update(dns_name_t *zonename, isc_sockaddr_t *master,
2129	    isc_sockaddr_t *srcaddr)
2130{
2131	isc_result_t result;
2132	dns_request_t *request = NULL;
2133	unsigned int options = DNS_REQUESTOPT_CASE;
2134
2135	ddebug("send_update()");
2136
2137	setzone(zonename);
2138
2139	if (usevc)
2140		options |= DNS_REQUESTOPT_TCP;
2141	if (tsigkey == NULL && sig0key != NULL) {
2142		result = dns_message_setsig0key(updatemsg, sig0key);
2143		check_result(result, "dns_message_setsig0key");
2144	}
2145	if (debugging) {
2146		char addrbuf[ISC_SOCKADDR_FORMATSIZE];
2147
2148		isc_sockaddr_format(master, addrbuf, sizeof(addrbuf));
2149		fprintf(stderr, "Sending update to %s\n", addrbuf);
2150	}
2151
2152	/* Windows doesn't like the tsig name to be compressed. */
2153	if (updatemsg->tsigname)
2154		updatemsg->tsigname->attributes |= DNS_NAMEATTR_NOCOMPRESS;
2155
2156	result = dns_request_createvia3(requestmgr, updatemsg, srcaddr,
2157					master, options, tsigkey, timeout,
2158					udp_timeout, udp_retries, global_task,
2159					update_completed, NULL, &request);
2160	check_result(result, "dns_request_createvia3");
2161
2162	if (debugging)
2163		show_message(stdout, updatemsg, "Outgoing update query:");
2164
2165	requests++;
2166}
2167
2168static void
2169recvsoa(isc_task_t *task, isc_event_t *event) {
2170	dns_requestevent_t *reqev = NULL;
2171	dns_request_t *request = NULL;
2172	isc_result_t result, eresult;
2173	dns_message_t *rcvmsg = NULL;
2174	dns_section_t section;
2175	dns_name_t *name = NULL;
2176	dns_rdataset_t *soaset = NULL;
2177	dns_rdata_soa_t soa;
2178	dns_rdata_t soarr = DNS_RDATA_INIT;
2179	int pass = 0;
2180	dns_name_t master;
2181	nsu_requestinfo_t *reqinfo;
2182	dns_message_t *soaquery = NULL;
2183	isc_sockaddr_t *addr;
2184	isc_boolean_t seencname = ISC_FALSE;
2185	dns_name_t tname;
2186	unsigned int nlabels;
2187
2188	UNUSED(task);
2189
2190	ddebug("recvsoa()");
2191
2192	requests--;
2193
2194	REQUIRE(event->ev_type == DNS_EVENT_REQUESTDONE);
2195	reqev = (dns_requestevent_t *)event;
2196	request = reqev->request;
2197	eresult = reqev->result;
2198	reqinfo = reqev->ev_arg;
2199	soaquery = reqinfo->msg;
2200	addr = reqinfo->addr;
2201
2202	if (shuttingdown) {
2203		dns_request_destroy(&request);
2204		dns_message_destroy(&soaquery);
2205		isc_mem_put(mctx, reqinfo, sizeof(nsu_requestinfo_t));
2206		isc_event_free(&event);
2207		maybeshutdown();
2208		return;
2209	}
2210
2211	if (eresult != ISC_R_SUCCESS) {
2212		char addrbuf[ISC_SOCKADDR_FORMATSIZE];
2213
2214		isc_sockaddr_format(addr, addrbuf, sizeof(addrbuf));
2215		fprintf(stderr, "; Communication with %s failed: %s\n",
2216			addrbuf, isc_result_totext(eresult));
2217		if (userserver != NULL)
2218			fatal("could not talk to specified name server");
2219		else if (++ns_inuse >= lwconf->nsnext)
2220			fatal("could not talk to any default name server");
2221		ddebug("Destroying request [%p]", request);
2222		dns_request_destroy(&request);
2223		dns_message_renderreset(soaquery);
2224		dns_message_settsigkey(soaquery, NULL);
2225		sendrequest(localaddr, &servers[ns_inuse], soaquery, &request);
2226		isc_mem_put(mctx, reqinfo, sizeof(nsu_requestinfo_t));
2227		isc_event_free(&event);
2228		setzoneclass(dns_rdataclass_none);
2229		return;
2230	}
2231
2232	isc_mem_put(mctx, reqinfo, sizeof(nsu_requestinfo_t));
2233	reqinfo = NULL;
2234	isc_event_free(&event);
2235	reqev = NULL;
2236
2237	ddebug("About to create rcvmsg");
2238	result = dns_message_create(mctx, DNS_MESSAGE_INTENTPARSE, &rcvmsg);
2239	check_result(result, "dns_message_create");
2240	result = dns_request_getresponse(request, rcvmsg,
2241					 DNS_MESSAGEPARSE_PRESERVEORDER);
2242	if (result == DNS_R_TSIGERRORSET && userserver != NULL) {
2243		dns_message_destroy(&rcvmsg);
2244		ddebug("Destroying request [%p]", request);
2245		dns_request_destroy(&request);
2246		reqinfo = isc_mem_get(mctx, sizeof(nsu_requestinfo_t));
2247		if (reqinfo == NULL)
2248			fatal("out of memory");
2249		reqinfo->msg = soaquery;
2250		reqinfo->addr = addr;
2251		dns_message_renderreset(soaquery);
2252		ddebug("retrying soa request without TSIG");
2253		result = dns_request_createvia3(requestmgr, soaquery,
2254						localaddr, addr, 0, NULL,
2255						FIND_TIMEOUT * 20,
2256						FIND_TIMEOUT, 3,
2257						global_task, recvsoa, reqinfo,
2258						&request);
2259		check_result(result, "dns_request_createvia");
2260		requests++;
2261		return;
2262	}
2263	check_result(result, "dns_request_getresponse");
2264	section = DNS_SECTION_ANSWER;
2265	POST(section);
2266	if (debugging)
2267		show_message(stderr, rcvmsg, "Reply from SOA query:");
2268
2269	if (rcvmsg->rcode != dns_rcode_noerror &&
2270	    rcvmsg->rcode != dns_rcode_nxdomain)
2271		fatal("response to SOA query was unsuccessful");
2272
2273	if (userzone != NULL && rcvmsg->rcode == dns_rcode_nxdomain) {
2274		char namebuf[DNS_NAME_FORMATSIZE];
2275		dns_name_format(userzone, namebuf, sizeof(namebuf));
2276		error("specified zone '%s' does not exist (NXDOMAIN)",
2277		      namebuf);
2278		dns_message_destroy(&rcvmsg);
2279		dns_request_destroy(&request);
2280		dns_message_destroy(&soaquery);
2281		ddebug("Out of recvsoa");
2282		done_update();
2283		seenerror = ISC_TRUE;
2284		return;
2285	}
2286
2287 lookforsoa:
2288	if (pass == 0)
2289		section = DNS_SECTION_ANSWER;
2290	else if (pass == 1)
2291		section = DNS_SECTION_AUTHORITY;
2292	else
2293		goto droplabel;
2294
2295	result = dns_message_firstname(rcvmsg, section);
2296	if (result != ISC_R_SUCCESS) {
2297		pass++;
2298		goto lookforsoa;
2299	}
2300	while (result == ISC_R_SUCCESS) {
2301		name = NULL;
2302		dns_message_currentname(rcvmsg, section, &name);
2303		soaset = NULL;
2304		result = dns_message_findtype(name, dns_rdatatype_soa, 0,
2305					      &soaset);
2306		if (result == ISC_R_SUCCESS)
2307			break;
2308		if (section == DNS_SECTION_ANSWER) {
2309			dns_rdataset_t *tset = NULL;
2310			if (dns_message_findtype(name, dns_rdatatype_cname, 0,
2311						 &tset) == ISC_R_SUCCESS ||
2312			    dns_message_findtype(name, dns_rdatatype_dname, 0,
2313						 &tset) == ISC_R_SUCCESS ) {
2314				seencname = ISC_TRUE;
2315				break;
2316			}
2317		}
2318
2319		result = dns_message_nextname(rcvmsg, section);
2320	}
2321
2322	if (soaset == NULL && !seencname) {
2323		pass++;
2324		goto lookforsoa;
2325	}
2326
2327	if (seencname)
2328		goto droplabel;
2329
2330	if (debugging) {
2331		char namestr[DNS_NAME_FORMATSIZE];
2332		dns_name_format(name, namestr, sizeof(namestr));
2333		fprintf(stderr, "Found zone name: %s\n", namestr);
2334	}
2335
2336	result = dns_rdataset_first(soaset);
2337	check_result(result, "dns_rdataset_first");
2338
2339	dns_rdata_init(&soarr);
2340	dns_rdataset_current(soaset, &soarr);
2341	result = dns_rdata_tostruct(&soarr, &soa, NULL);
2342	check_result(result, "dns_rdata_tostruct");
2343
2344	dns_name_init(&master, NULL);
2345	dns_name_clone(&soa.origin, &master);
2346
2347	if (userzone != NULL)
2348		zonename = userzone;
2349	else
2350		zonename = name;
2351
2352	if (debugging) {
2353		char namestr[DNS_NAME_FORMATSIZE];
2354		dns_name_format(&master, namestr, sizeof(namestr));
2355		fprintf(stderr, "The master is: %s\n", namestr);
2356	}
2357
2358	if (userserver != NULL)
2359		serveraddr = userserver;
2360	else {
2361		char serverstr[DNS_NAME_MAXTEXT+1];
2362		isc_buffer_t buf;
2363
2364		isc_buffer_init(&buf, serverstr, sizeof(serverstr));
2365		result = dns_name_totext(&master, ISC_TRUE, &buf);
2366		check_result(result, "dns_name_totext");
2367		serverstr[isc_buffer_usedlength(&buf)] = 0;
2368		get_address(serverstr, dnsport, &tempaddr);
2369		serveraddr = &tempaddr;
2370	}
2371	dns_rdata_freestruct(&soa);
2372
2373#ifdef GSSAPI
2374	if (usegsstsig) {
2375		dns_name_init(&tmpzonename, NULL);
2376		dns_name_dup(zonename, mctx, &tmpzonename);
2377		dns_name_init(&restart_master, NULL);
2378		dns_name_dup(&master, mctx, &restart_master);
2379		start_gssrequest(&master);
2380	} else {
2381		send_update(zonename, serveraddr, localaddr);
2382		setzoneclass(dns_rdataclass_none);
2383	}
2384#else
2385	send_update(zonename, serveraddr, localaddr);
2386	setzoneclass(dns_rdataclass_none);
2387#endif
2388
2389	dns_message_destroy(&soaquery);
2390	dns_request_destroy(&request);
2391
2392 out:
2393	dns_message_destroy(&rcvmsg);
2394	ddebug("Out of recvsoa");
2395	return;
2396
2397 droplabel:
2398	result = dns_message_firstname(soaquery, DNS_SECTION_QUESTION);
2399	INSIST(result == ISC_R_SUCCESS);
2400	name = NULL;
2401	dns_message_currentname(soaquery, DNS_SECTION_QUESTION, &name);
2402	nlabels = dns_name_countlabels(name);
2403	if (nlabels == 1)
2404		fatal("could not find enclosing zone");
2405	dns_name_init(&tname, NULL);
2406	dns_name_getlabelsequence(name, 1, nlabels - 1, &tname);
2407	dns_name_clone(&tname, name);
2408	dns_request_destroy(&request);
2409	dns_message_renderreset(soaquery);
2410	dns_message_settsigkey(soaquery, NULL);
2411	if (userserver != NULL)
2412		sendrequest(localaddr, userserver, soaquery, &request);
2413	else
2414		sendrequest(localaddr, &servers[ns_inuse], soaquery, &request);
2415	goto out;
2416}
2417
2418static void
2419sendrequest(isc_sockaddr_t *srcaddr, isc_sockaddr_t *destaddr,
2420	    dns_message_t *msg, dns_request_t **request)
2421{
2422	isc_result_t result;
2423	nsu_requestinfo_t *reqinfo;
2424
2425	reqinfo = isc_mem_get(mctx, sizeof(nsu_requestinfo_t));
2426	if (reqinfo == NULL)
2427		fatal("out of memory");
2428	reqinfo->msg = msg;
2429	reqinfo->addr = destaddr;
2430	result = dns_request_createvia3(requestmgr, msg, srcaddr, destaddr, 0,
2431					(userserver != NULL) ? tsigkey : NULL,
2432					FIND_TIMEOUT * 20, FIND_TIMEOUT, 3,
2433					global_task, recvsoa, reqinfo, request);
2434	check_result(result, "dns_request_createvia");
2435	requests++;
2436}
2437
2438#ifdef GSSAPI
2439
2440/*
2441 * Get the realm from the users kerberos ticket if possible
2442 */
2443static void
2444get_ticket_realm(isc_mem_t *mctx)
2445{
2446	krb5_context ctx;
2447	krb5_error_code rc;
2448	krb5_ccache ccache;
2449	krb5_principal princ;
2450	char *name, *ticket_realm;
2451
2452	rc = krb5_init_context(&ctx);
2453	if (rc != 0)
2454		return;
2455
2456	rc = krb5_cc_default(ctx, &ccache);
2457	if (rc != 0) {
2458		krb5_free_context(ctx);
2459		return;
2460	}
2461
2462	rc = krb5_cc_get_principal(ctx, ccache, &princ);
2463	if (rc != 0) {
2464		krb5_cc_close(ctx, ccache);
2465		krb5_free_context(ctx);
2466		return;
2467	}
2468
2469	rc = krb5_unparse_name(ctx, princ, &name);
2470	if (rc != 0) {
2471		krb5_free_principal(ctx, princ);
2472		krb5_cc_close(ctx, ccache);
2473		krb5_free_context(ctx);
2474		return;
2475	}
2476
2477	ticket_realm = strrchr(name, '@');
2478	if (ticket_realm != NULL) {
2479		realm = isc_mem_strdup(mctx, ticket_realm);
2480	}
2481
2482	free(name);
2483	krb5_free_principal(ctx, princ);
2484	krb5_cc_close(ctx, ccache);
2485	krb5_free_context(ctx);
2486	if (realm != NULL && debugging)
2487		fprintf(stderr, "Found realm from ticket: %s\n", realm+1);
2488}
2489
2490
2491static void
2492start_gssrequest(dns_name_t *master) {
2493	gss_ctx_id_t context;
2494	isc_buffer_t buf;
2495	isc_result_t result;
2496	isc_uint32_t val = 0;
2497	dns_message_t *rmsg;
2498	dns_request_t *request = NULL;
2499	dns_name_t *servname;
2500	dns_fixedname_t fname;
2501	char namestr[DNS_NAME_FORMATSIZE];
2502	char keystr[DNS_NAME_FORMATSIZE];
2503	char *err_message = NULL;
2504
2505	debug("start_gssrequest");
2506	usevc = ISC_TRUE;
2507
2508	if (gssring != NULL)
2509		dns_tsigkeyring_detach(&gssring);
2510	gssring = NULL;
2511	result = dns_tsigkeyring_create(mctx, &gssring);
2512
2513	if (result != ISC_R_SUCCESS)
2514		fatal("dns_tsigkeyring_create failed: %s",
2515		      isc_result_totext(result));
2516
2517	dns_name_format(master, namestr, sizeof(namestr));
2518	if (kserver == NULL) {
2519		kserver = isc_mem_get(mctx, sizeof(isc_sockaddr_t));
2520		if (kserver == NULL)
2521			fatal("out of memory");
2522	}
2523	if (userserver == NULL)
2524		get_address(namestr, dnsport, kserver);
2525	else
2526		(void)memcpy(kserver, userserver, sizeof(isc_sockaddr_t));
2527
2528	dns_fixedname_init(&fname);
2529	servname = dns_fixedname_name(&fname);
2530
2531	if (realm == NULL)
2532		get_ticket_realm(mctx);
2533
2534	result = isc_string_printf(servicename, sizeof(servicename),
2535				   "DNS/%s%s", namestr, realm ? realm : "");
2536	if (result != ISC_R_SUCCESS)
2537		fatal("isc_string_printf(servicename) failed: %s",
2538		      isc_result_totext(result));
2539	isc_buffer_init(&buf, servicename, strlen(servicename));
2540	isc_buffer_add(&buf, strlen(servicename));
2541	result = dns_name_fromtext(servname, &buf, dns_rootname, 0, NULL);
2542	if (result != ISC_R_SUCCESS)
2543		fatal("dns_name_fromtext(servname) failed: %s",
2544		      isc_result_totext(result));
2545
2546	dns_fixedname_init(&fkname);
2547	keyname = dns_fixedname_name(&fkname);
2548
2549	isc_random_get(&val);
2550	result = isc_string_printf(keystr, sizeof(keystr), "%u.sig-%s",
2551				   val, namestr);
2552	if (result != ISC_R_SUCCESS)
2553		fatal("isc_string_printf(keystr) failed: %s",
2554		      isc_result_totext(result));
2555	isc_buffer_init(&buf, keystr, strlen(keystr));
2556	isc_buffer_add(&buf, strlen(keystr));
2557
2558	result = dns_name_fromtext(keyname, &buf, dns_rootname, 0, NULL);
2559	if (result != ISC_R_SUCCESS)
2560		fatal("dns_name_fromtext(keyname) failed: %s",
2561		      isc_result_totext(result));
2562
2563	/* Windows doesn't recognize name compression in the key name. */
2564	keyname->attributes |= DNS_NAMEATTR_NOCOMPRESS;
2565
2566	rmsg = NULL;
2567	result = dns_message_create(mctx, DNS_MESSAGE_INTENTRENDER, &rmsg);
2568	if (result != ISC_R_SUCCESS)
2569		fatal("dns_message_create failed: %s",
2570		      isc_result_totext(result));
2571
2572	/* Build first request. */
2573	context = GSS_C_NO_CONTEXT;
2574	result = dns_tkey_buildgssquery(rmsg, keyname, servname, NULL, 0,
2575					&context, use_win2k_gsstsig,
2576					mctx, &err_message);
2577	if (result == ISC_R_FAILURE)
2578		fatal("tkey query failed: %s",
2579		      err_message != NULL ? err_message : "unknown error");
2580	if (result != ISC_R_SUCCESS)
2581		fatal("dns_tkey_buildgssquery failed: %s",
2582		      isc_result_totext(result));
2583
2584	send_gssrequest(localaddr, kserver, rmsg, &request, context);
2585}
2586
2587static void
2588send_gssrequest(isc_sockaddr_t *srcaddr, isc_sockaddr_t *destaddr,
2589		dns_message_t *msg, dns_request_t **request,
2590		gss_ctx_id_t context)
2591{
2592	isc_result_t result;
2593	nsu_gssinfo_t *reqinfo;
2594	unsigned int options = 0;
2595
2596	debug("send_gssrequest");
2597	reqinfo = isc_mem_get(mctx, sizeof(nsu_gssinfo_t));
2598	if (reqinfo == NULL)
2599		fatal("out of memory");
2600	reqinfo->msg = msg;
2601	reqinfo->addr = destaddr;
2602	reqinfo->context = context;
2603
2604	options |= DNS_REQUESTOPT_TCP;
2605	result = dns_request_createvia3(requestmgr, msg, srcaddr, destaddr,
2606					options, tsigkey, FIND_TIMEOUT * 20,
2607					FIND_TIMEOUT, 3, global_task, recvgss,
2608					reqinfo, request);
2609	check_result(result, "dns_request_createvia3");
2610	if (debugging)
2611		show_message(stdout, msg, "Outgoing update query:");
2612	requests++;
2613}
2614
2615static void
2616recvgss(isc_task_t *task, isc_event_t *event) {
2617	dns_requestevent_t *reqev = NULL;
2618	dns_request_t *request = NULL;
2619	isc_result_t result, eresult;
2620	dns_message_t *rcvmsg = NULL;
2621	nsu_gssinfo_t *reqinfo;
2622	dns_message_t *tsigquery = NULL;
2623	isc_sockaddr_t *addr;
2624	gss_ctx_id_t context;
2625	isc_buffer_t buf;
2626	dns_name_t *servname;
2627	dns_fixedname_t fname;
2628	char *err_message = NULL;
2629
2630	UNUSED(task);
2631
2632	ddebug("recvgss()");
2633
2634	requests--;
2635
2636	REQUIRE(event->ev_type == DNS_EVENT_REQUESTDONE);
2637	reqev = (dns_requestevent_t *)event;
2638	request = reqev->request;
2639	eresult = reqev->result;
2640	reqinfo = reqev->ev_arg;
2641	tsigquery = reqinfo->msg;
2642	context = reqinfo->context;
2643	addr = reqinfo->addr;
2644
2645	if (shuttingdown) {
2646		dns_request_destroy(&request);
2647		dns_message_destroy(&tsigquery);
2648		isc_mem_put(mctx, reqinfo, sizeof(nsu_gssinfo_t));
2649		isc_event_free(&event);
2650		maybeshutdown();
2651		return;
2652	}
2653
2654	if (eresult != ISC_R_SUCCESS) {
2655		char addrbuf[ISC_SOCKADDR_FORMATSIZE];
2656
2657		isc_sockaddr_format(addr, addrbuf, sizeof(addrbuf));
2658		fprintf(stderr, "; Communication with %s failed: %s\n",
2659			addrbuf, isc_result_totext(eresult));
2660		if (userserver != NULL)
2661			fatal("could not talk to specified name server");
2662		else if (++ns_inuse >= lwconf->nsnext)
2663			fatal("could not talk to any default name server");
2664		ddebug("Destroying request [%p]", request);
2665		dns_request_destroy(&request);
2666		dns_message_renderreset(tsigquery);
2667		sendrequest(localaddr, &servers[ns_inuse], tsigquery,
2668			    &request);
2669		isc_mem_put(mctx, reqinfo, sizeof(nsu_gssinfo_t));
2670		isc_event_free(&event);
2671		return;
2672	}
2673	isc_mem_put(mctx, reqinfo, sizeof(nsu_gssinfo_t));
2674
2675	isc_event_free(&event);
2676	reqev = NULL;
2677
2678	ddebug("recvgss creating rcvmsg");
2679	result = dns_message_create(mctx, DNS_MESSAGE_INTENTPARSE, &rcvmsg);
2680	check_result(result, "dns_message_create");
2681
2682	result = dns_request_getresponse(request, rcvmsg,
2683					 DNS_MESSAGEPARSE_PRESERVEORDER);
2684	check_result(result, "dns_request_getresponse");
2685
2686	if (debugging)
2687		show_message(stderr, rcvmsg,
2688			     "recvmsg reply from GSS-TSIG query");
2689
2690	if (rcvmsg->rcode == dns_rcode_formerr && !tried_other_gsstsig) {
2691		ddebug("recvgss trying %s GSS-TSIG",
2692		       use_win2k_gsstsig ? "Standard" : "Win2k");
2693		if (use_win2k_gsstsig)
2694			use_win2k_gsstsig = ISC_FALSE;
2695		else
2696			use_win2k_gsstsig = ISC_TRUE;
2697		tried_other_gsstsig = ISC_TRUE;
2698		start_gssrequest(&restart_master);
2699		goto done;
2700	}
2701
2702	if (rcvmsg->rcode != dns_rcode_noerror &&
2703	    rcvmsg->rcode != dns_rcode_nxdomain)
2704		fatal("response to GSS-TSIG query was unsuccessful");
2705
2706
2707	dns_fixedname_init(&fname);
2708	servname = dns_fixedname_name(&fname);
2709	isc_buffer_init(&buf, servicename, strlen(servicename));
2710	isc_buffer_add(&buf, strlen(servicename));
2711	result = dns_name_fromtext(servname, &buf, dns_rootname, 0, NULL);
2712	check_result(result, "dns_name_fromtext");
2713
2714	tsigkey = NULL;
2715	result = dns_tkey_gssnegotiate(tsigquery, rcvmsg, servname,
2716				       &context, &tsigkey, gssring,
2717				       use_win2k_gsstsig,
2718				       &err_message);
2719	switch (result) {
2720
2721	case DNS_R_CONTINUE:
2722		send_gssrequest(localaddr, kserver, tsigquery, &request,
2723				context);
2724		break;
2725
2726	case ISC_R_SUCCESS:
2727		/*
2728		 * XXXSRA Waaay too much fun here.  There's no good
2729		 * reason why we need a TSIG here (the people who put
2730		 * it into the spec admitted at the time that it was
2731		 * not a security issue), and Windows clients don't
2732		 * seem to work if named complies with the spec and
2733		 * includes the gratuitous TSIG.  So we're in the
2734		 * bizarre situation of having to choose between
2735		 * complying with a useless requirement in the spec
2736		 * and interoperating.  This is nuts.  If we can
2737		 * confirm this behavior, we should ask the WG to
2738		 * consider removing the requirement for the
2739		 * gratuitous TSIG here.  For the moment, we ignore
2740		 * the TSIG -- this too is a spec violation, but it's
2741		 * the least insane thing to do.
2742		 */
2743#if 0
2744		/*
2745		 * Verify the signature.
2746		 */
2747		rcvmsg->state = DNS_SECTION_ANY;
2748		dns_message_setquerytsig(rcvmsg, NULL);
2749		result = dns_message_settsigkey(rcvmsg, tsigkey);
2750		check_result(result, "dns_message_settsigkey");
2751		result = dns_message_checksig(rcvmsg, NULL);
2752		ddebug("tsig verification: %s", dns_result_totext(result));
2753		check_result(result, "dns_message_checksig");
2754#endif /* 0 */
2755
2756		send_update(&tmpzonename, serveraddr, localaddr);
2757		setzoneclass(dns_rdataclass_none);
2758		break;
2759
2760	default:
2761		fatal("dns_tkey_negotiategss: %s %s",
2762		      isc_result_totext(result),
2763		      err_message != NULL ? err_message : "");
2764	}
2765
2766 done:
2767	dns_request_destroy(&request);
2768	dns_message_destroy(&tsigquery);
2769
2770	dns_message_destroy(&rcvmsg);
2771	ddebug("Out of recvgss");
2772}
2773#endif
2774
2775static void
2776start_update(void) {
2777	isc_result_t result;
2778	dns_rdataset_t *rdataset = NULL;
2779	dns_name_t *name = NULL;
2780	dns_request_t *request = NULL;
2781	dns_message_t *soaquery = NULL;
2782	dns_name_t *firstname;
2783	dns_section_t section = DNS_SECTION_UPDATE;
2784
2785	ddebug("start_update()");
2786
2787	if (answer != NULL)
2788		dns_message_destroy(&answer);
2789
2790	if (userzone != NULL && userserver != NULL && ! usegsstsig) {
2791		send_update(userzone, userserver, localaddr);
2792		setzoneclass(dns_rdataclass_none);
2793		return;
2794	}
2795
2796	result = dns_message_create(mctx, DNS_MESSAGE_INTENTRENDER,
2797				    &soaquery);
2798	check_result(result, "dns_message_create");
2799
2800	if (userserver == NULL)
2801		soaquery->flags |= DNS_MESSAGEFLAG_RD;
2802
2803	result = dns_message_gettempname(soaquery, &name);
2804	check_result(result, "dns_message_gettempname");
2805
2806	result = dns_message_gettemprdataset(soaquery, &rdataset);
2807	check_result(result, "dns_message_gettemprdataset");
2808
2809	dns_rdataset_makequestion(rdataset, getzoneclass(), dns_rdatatype_soa);
2810
2811	if (userzone != NULL) {
2812		dns_name_init(name, NULL);
2813		dns_name_clone(userzone, name);
2814	} else {
2815		dns_rdataset_t *tmprdataset;
2816		result = dns_message_firstname(updatemsg, section);
2817		if (result == ISC_R_NOMORE) {
2818			section = DNS_SECTION_PREREQUISITE;
2819			result = dns_message_firstname(updatemsg, section);
2820		}
2821		if (result != ISC_R_SUCCESS) {
2822			dns_message_puttempname(soaquery, &name);
2823			dns_rdataset_disassociate(rdataset);
2824			dns_message_puttemprdataset(soaquery, &rdataset);
2825			dns_message_destroy(&soaquery);
2826			done_update();
2827			return;
2828		}
2829		firstname = NULL;
2830		dns_message_currentname(updatemsg, section, &firstname);
2831		dns_name_init(name, NULL);
2832		dns_name_clone(firstname, name);
2833		/*
2834		 * Looks to see if the first name references a DS record
2835		 * and if that name is not the root remove a label as DS
2836		 * records live in the parent zone so we need to start our
2837		 * search one label up.
2838		 */
2839		tmprdataset = ISC_LIST_HEAD(firstname->list);
2840		if (section == DNS_SECTION_UPDATE &&
2841		    !dns_name_equal(firstname, dns_rootname) &&
2842		    tmprdataset->type == dns_rdatatype_ds) {
2843		    unsigned int labels = dns_name_countlabels(name);
2844		    dns_name_getlabelsequence(name, 1, labels - 1, name);
2845		}
2846	}
2847
2848	ISC_LIST_INIT(name->list);
2849	ISC_LIST_APPEND(name->list, rdataset, link);
2850	dns_message_addname(soaquery, name, DNS_SECTION_QUESTION);
2851
2852	if (userserver != NULL)
2853		sendrequest(localaddr, userserver, soaquery, &request);
2854	else {
2855		ns_inuse = 0;
2856		sendrequest(localaddr, &servers[ns_inuse], soaquery, &request);
2857	}
2858}
2859
2860static void
2861cleanup(void) {
2862	ddebug("cleanup()");
2863
2864	if (answer != NULL)
2865		dns_message_destroy(&answer);
2866
2867#ifdef GSSAPI
2868	if (tsigkey != NULL) {
2869		ddebug("detach tsigkey x%p", tsigkey);
2870		dns_tsigkey_detach(&tsigkey);
2871	}
2872	if (gssring != NULL) {
2873		ddebug("Detaching GSS-TSIG keyring");
2874		dns_tsigkeyring_detach(&gssring);
2875	}
2876	if (kserver != NULL) {
2877		isc_mem_put(mctx, kserver, sizeof(isc_sockaddr_t));
2878		kserver = NULL;
2879	}
2880	if (realm != NULL) {
2881		isc_mem_free(mctx, realm);
2882		realm = NULL;
2883	}
2884#endif
2885
2886	if (sig0key != NULL)
2887		dst_key_free(&sig0key);
2888
2889	ddebug("Shutting down task manager");
2890	isc_taskmgr_destroy(&taskmgr);
2891
2892	ddebug("Destroying event");
2893	isc_event_free(&global_event);
2894
2895	ddebug("Shutting down socket manager");
2896	isc_socketmgr_destroy(&socketmgr);
2897
2898	ddebug("Shutting down timer manager");
2899	isc_timermgr_destroy(&timermgr);
2900
2901	ddebug("Destroying hash context");
2902	isc_hash_destroy();
2903
2904	ddebug("Destroying name state");
2905	dns_name_destroy();
2906
2907	ddebug("Removing log context");
2908	isc_log_destroy(&lctx);
2909
2910	ddebug("Destroying memory context");
2911	if (memdebugging)
2912		isc_mem_stats(mctx, stderr);
2913	isc_mem_destroy(&mctx);
2914}
2915
2916static void
2917getinput(isc_task_t *task, isc_event_t *event) {
2918	isc_boolean_t more;
2919
2920	UNUSED(task);
2921
2922	if (shuttingdown) {
2923		maybeshutdown();
2924		return;
2925	}
2926
2927	if (global_event == NULL)
2928		global_event = event;
2929
2930	reset_system();
2931	more = user_interaction();
2932	if (!more) {
2933		isc_app_shutdown();
2934		return;
2935	}
2936	start_update();
2937	return;
2938}
2939
2940int
2941main(int argc, char **argv) {
2942	isc_result_t result;
2943	style = &dns_master_style_debug;
2944
2945	input = stdin;
2946
2947	interactive = ISC_TF(isatty(0));
2948
2949	isc_app_start();
2950
2951	pre_parse_args(argc, argv);
2952
2953	result = isc_mem_create(0, 0, &mctx);
2954	check_result(result, "isc_mem_create");
2955
2956	parse_args(argc, argv, mctx, &entropy);
2957
2958	setup_system();
2959
2960	result = isc_app_onrun(mctx, global_task, getinput, NULL);
2961	check_result(result, "isc_app_onrun");
2962
2963	(void)isc_app_run();
2964
2965	cleanup();
2966
2967	isc_app_finish();
2968
2969	if (seenerror)
2970		return (2);
2971	else
2972		return (0);
2973}
2974