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