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