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