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