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