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