]> CyberLeo.Net >> Repos - FreeBSD/stable/8.git/blob - contrib/bind9/bin/nsupdate/nsupdate.c
Update to version 9.6-ESV-R5 which contains various bug fixes
[FreeBSD/stable/8.git] / contrib / bind9 / bin / nsupdate / nsupdate.c
1 /*
2  * Copyright (C) 2004-2011  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.18 2011-05-23 22:24:12 each 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         POST(section);
2151         if (debugging)
2152                 show_message(stderr, rcvmsg, "Reply from SOA query:");
2153
2154         if (rcvmsg->rcode != dns_rcode_noerror &&
2155             rcvmsg->rcode != dns_rcode_nxdomain)
2156                 fatal("response to SOA query was unsuccessful");
2157
2158         if (userzone != NULL && rcvmsg->rcode == dns_rcode_nxdomain) {
2159                 char namebuf[DNS_NAME_FORMATSIZE];
2160                 dns_name_format(userzone, namebuf, sizeof(namebuf));
2161                 error("specified zone '%s' does not exist (NXDOMAIN)",
2162                       namebuf);
2163                 dns_message_destroy(&rcvmsg);
2164                 dns_request_destroy(&request);
2165                 dns_message_destroy(&soaquery);
2166                 ddebug("Out of recvsoa");
2167                 done_update();
2168                 return;
2169         }
2170
2171  lookforsoa:
2172         if (pass == 0)
2173                 section = DNS_SECTION_ANSWER;
2174         else if (pass == 1)
2175                 section = DNS_SECTION_AUTHORITY;
2176         else
2177                 goto droplabel;
2178
2179         result = dns_message_firstname(rcvmsg, section);
2180         if (result != ISC_R_SUCCESS) {
2181                 pass++;
2182                 goto lookforsoa;
2183         }
2184         while (result == ISC_R_SUCCESS) {
2185                 name = NULL;
2186                 dns_message_currentname(rcvmsg, section, &name);
2187                 soaset = NULL;
2188                 result = dns_message_findtype(name, dns_rdatatype_soa, 0,
2189                                               &soaset);
2190                 if (result == ISC_R_SUCCESS)
2191                         break;
2192                 if (section == DNS_SECTION_ANSWER) {
2193                         dns_rdataset_t *tset = NULL;
2194                         if (dns_message_findtype(name, dns_rdatatype_cname, 0,
2195                                                  &tset) == ISC_R_SUCCESS ||
2196                             dns_message_findtype(name, dns_rdatatype_dname, 0,
2197                                                  &tset) == ISC_R_SUCCESS ) {
2198                                 seencname = ISC_TRUE;
2199                                 break;
2200                         }
2201                 }
2202
2203                 result = dns_message_nextname(rcvmsg, section);
2204         }
2205
2206         if (soaset == NULL && !seencname) {
2207                 pass++;
2208                 goto lookforsoa;
2209         }
2210
2211         if (seencname)
2212                 goto droplabel;
2213
2214         if (debugging) {
2215                 char namestr[DNS_NAME_FORMATSIZE];
2216                 dns_name_format(name, namestr, sizeof(namestr));
2217                 fprintf(stderr, "Found zone name: %s\n", namestr);
2218         }
2219
2220         result = dns_rdataset_first(soaset);
2221         check_result(result, "dns_rdataset_first");
2222
2223         dns_rdata_init(&soarr);
2224         dns_rdataset_current(soaset, &soarr);
2225         result = dns_rdata_tostruct(&soarr, &soa, NULL);
2226         check_result(result, "dns_rdata_tostruct");
2227
2228         dns_name_init(&master, NULL);
2229         dns_name_clone(&soa.origin, &master);
2230
2231         if (userzone != NULL)
2232                 zonename = userzone;
2233         else
2234                 zonename = name;
2235
2236         if (debugging) {
2237                 char namestr[DNS_NAME_FORMATSIZE];
2238                 dns_name_format(&master, namestr, sizeof(namestr));
2239                 fprintf(stderr, "The master is: %s\n", namestr);
2240         }
2241
2242         if (userserver != NULL)
2243                 serveraddr = userserver;
2244         else {
2245                 char serverstr[DNS_NAME_MAXTEXT+1];
2246                 isc_buffer_t buf;
2247
2248                 isc_buffer_init(&buf, serverstr, sizeof(serverstr));
2249                 result = dns_name_totext(&master, ISC_TRUE, &buf);
2250                 check_result(result, "dns_name_totext");
2251                 serverstr[isc_buffer_usedlength(&buf)] = 0;
2252                 get_address(serverstr, DNSDEFAULTPORT, &tempaddr);
2253                 serveraddr = &tempaddr;
2254         }
2255         dns_rdata_freestruct(&soa);
2256
2257 #ifdef GSSAPI
2258         if (usegsstsig) {
2259                 dns_name_init(&tmpzonename, NULL);
2260                 dns_name_dup(zonename, mctx, &tmpzonename);
2261                 dns_name_init(&restart_master, NULL);
2262                 dns_name_dup(&master, mctx, &restart_master);
2263                 start_gssrequest(&master);
2264         } else {
2265                 send_update(zonename, serveraddr, localaddr);
2266                 setzoneclass(dns_rdataclass_none);
2267         }
2268 #else
2269         send_update(zonename, serveraddr, localaddr);
2270         setzoneclass(dns_rdataclass_none);
2271 #endif
2272
2273         dns_message_destroy(&soaquery);
2274         dns_request_destroy(&request);
2275
2276  out:
2277         dns_message_destroy(&rcvmsg);
2278         ddebug("Out of recvsoa");
2279         return;
2280
2281  droplabel:
2282         result = dns_message_firstname(soaquery, DNS_SECTION_QUESTION);
2283         INSIST(result == ISC_R_SUCCESS);
2284         name = NULL;
2285         dns_message_currentname(soaquery, DNS_SECTION_QUESTION, &name);
2286         nlabels = dns_name_countlabels(name);
2287         if (nlabels == 1)
2288                 fatal("could not find enclosing zone");
2289         dns_name_init(&tname, NULL);
2290         dns_name_getlabelsequence(name, 1, nlabels - 1, &tname);
2291         dns_name_clone(&tname, name);
2292         dns_request_destroy(&request);
2293         dns_message_renderreset(soaquery);
2294         dns_message_settsigkey(soaquery, NULL);
2295         if (userserver != NULL)
2296                 sendrequest(localaddr, userserver, soaquery, &request);
2297         else
2298                 sendrequest(localaddr, &servers[ns_inuse], soaquery, &request);
2299         goto out;
2300 }
2301
2302 static void
2303 sendrequest(isc_sockaddr_t *srcaddr, isc_sockaddr_t *destaddr,
2304             dns_message_t *msg, dns_request_t **request)
2305 {
2306         isc_result_t result;
2307         nsu_requestinfo_t *reqinfo;
2308
2309         reqinfo = isc_mem_get(mctx, sizeof(nsu_requestinfo_t));
2310         if (reqinfo == NULL)
2311                 fatal("out of memory");
2312         reqinfo->msg = msg;
2313         reqinfo->addr = destaddr;
2314         result = dns_request_createvia3(requestmgr, msg, srcaddr, destaddr, 0,
2315                                         (userserver != NULL) ? tsigkey : NULL,
2316                                         FIND_TIMEOUT * 20, FIND_TIMEOUT, 3,
2317                                         global_task, recvsoa, reqinfo, request);
2318         check_result(result, "dns_request_createvia");
2319         requests++;
2320 }
2321
2322 #ifdef GSSAPI
2323 static void
2324 start_gssrequest(dns_name_t *master)
2325 {
2326         gss_ctx_id_t context;
2327         isc_buffer_t buf;
2328         isc_result_t result;
2329         isc_uint32_t val = 0;
2330         dns_message_t *rmsg;
2331         dns_request_t *request = NULL;
2332         dns_name_t *servname;
2333         dns_fixedname_t fname;
2334         char namestr[DNS_NAME_FORMATSIZE];
2335         char keystr[DNS_NAME_FORMATSIZE];
2336
2337         debug("start_gssrequest");
2338         usevc = ISC_TRUE;
2339
2340         if (gssring != NULL)
2341                 dns_tsigkeyring_destroy(&gssring);
2342         gssring = NULL;
2343         result = dns_tsigkeyring_create(mctx, &gssring);
2344
2345         if (result != ISC_R_SUCCESS)
2346                 fatal("dns_tsigkeyring_create failed: %s",
2347                       isc_result_totext(result));
2348
2349         dns_name_format(master, namestr, sizeof(namestr));
2350         if (kserver == NULL) {
2351                 kserver = isc_mem_get(mctx, sizeof(isc_sockaddr_t));
2352                 if (kserver == NULL)
2353                         fatal("out of memory");
2354         }
2355         if (userserver == NULL)
2356                 get_address(namestr, DNSDEFAULTPORT, kserver);
2357         else
2358                 (void)memcpy(kserver, userserver, sizeof(isc_sockaddr_t));
2359
2360         dns_fixedname_init(&fname);
2361         servname = dns_fixedname_name(&fname);
2362
2363         result = isc_string_printf(servicename, sizeof(servicename),
2364                                    "DNS/%s%s", namestr, realm ? realm : "");
2365         if (result != ISC_R_SUCCESS)
2366                 fatal("isc_string_printf(servicename) failed: %s",
2367                       isc_result_totext(result));
2368         isc_buffer_init(&buf, servicename, strlen(servicename));
2369         isc_buffer_add(&buf, strlen(servicename));
2370         result = dns_name_fromtext(servname, &buf, dns_rootname,
2371                                    ISC_FALSE, NULL);
2372         if (result != ISC_R_SUCCESS)
2373                 fatal("dns_name_fromtext(servname) failed: %s",
2374                       isc_result_totext(result));
2375
2376         dns_fixedname_init(&fkname);
2377         keyname = dns_fixedname_name(&fkname);
2378
2379         isc_random_get(&val);
2380         result = isc_string_printf(keystr, sizeof(keystr), "%u.sig-%s",
2381                                    val, namestr);
2382         if (result != ISC_R_SUCCESS)
2383                 fatal("isc_string_printf(keystr) failed: %s",
2384                       isc_result_totext(result));
2385         isc_buffer_init(&buf, keystr, strlen(keystr));
2386         isc_buffer_add(&buf, strlen(keystr));
2387
2388         result = dns_name_fromtext(keyname, &buf, dns_rootname,
2389                                    ISC_FALSE, NULL);
2390         if (result != ISC_R_SUCCESS)
2391                 fatal("dns_name_fromtext(keyname) failed: %s",
2392                       isc_result_totext(result));
2393
2394         /* Windows doesn't recognize name compression in the key name. */
2395         keyname->attributes |= DNS_NAMEATTR_NOCOMPRESS;
2396
2397         rmsg = NULL;
2398         result = dns_message_create(mctx, DNS_MESSAGE_INTENTRENDER, &rmsg);
2399         if (result != ISC_R_SUCCESS)
2400                 fatal("dns_message_create failed: %s",
2401                       isc_result_totext(result));
2402
2403         /* Build first request. */
2404         context = GSS_C_NO_CONTEXT;
2405         result = dns_tkey_buildgssquery(rmsg, keyname, servname, NULL, 0,
2406                                         &context, use_win2k_gsstsig);
2407         if (result == ISC_R_FAILURE)
2408                 fatal("Check your Kerberos ticket, it may have expired.");
2409         if (result != ISC_R_SUCCESS)
2410                 fatal("dns_tkey_buildgssquery failed: %s",
2411                       isc_result_totext(result));
2412
2413         send_gssrequest(localaddr, kserver, rmsg, &request, context);
2414 }
2415
2416 static void
2417 send_gssrequest(isc_sockaddr_t *srcaddr, isc_sockaddr_t *destaddr,
2418                 dns_message_t *msg, dns_request_t **request,
2419                 gss_ctx_id_t context)
2420 {
2421         isc_result_t result;
2422         nsu_gssinfo_t *reqinfo;
2423         unsigned int options = 0;
2424
2425         debug("send_gssrequest");
2426         reqinfo = isc_mem_get(mctx, sizeof(nsu_gssinfo_t));
2427         if (reqinfo == NULL)
2428                 fatal("out of memory");
2429         reqinfo->msg = msg;
2430         reqinfo->addr = destaddr;
2431         reqinfo->context = context;
2432
2433         options |= DNS_REQUESTOPT_TCP;
2434         result = dns_request_createvia3(requestmgr, msg, srcaddr, destaddr,
2435                                         options, tsigkey, FIND_TIMEOUT * 20,
2436                                         FIND_TIMEOUT, 3, global_task, recvgss,
2437                                         reqinfo, request);
2438         check_result(result, "dns_request_createvia3");
2439         if (debugging)
2440                 show_message(stdout, msg, "Outgoing update query:");
2441         requests++;
2442 }
2443
2444 static void
2445 recvgss(isc_task_t *task, isc_event_t *event) {
2446         dns_requestevent_t *reqev = NULL;
2447         dns_request_t *request = NULL;
2448         isc_result_t result, eresult;
2449         dns_message_t *rcvmsg = NULL;
2450         nsu_gssinfo_t *reqinfo;
2451         dns_message_t *tsigquery = NULL;
2452         isc_sockaddr_t *addr;
2453         gss_ctx_id_t context;
2454         isc_buffer_t buf;
2455         dns_name_t *servname;
2456         dns_fixedname_t fname;
2457
2458         UNUSED(task);
2459
2460         ddebug("recvgss()");
2461
2462         requests--;
2463
2464         REQUIRE(event->ev_type == DNS_EVENT_REQUESTDONE);
2465         reqev = (dns_requestevent_t *)event;
2466         request = reqev->request;
2467         eresult = reqev->result;
2468         reqinfo = reqev->ev_arg;
2469         tsigquery = reqinfo->msg;
2470         context = reqinfo->context;
2471         addr = reqinfo->addr;
2472
2473         if (shuttingdown) {
2474                 dns_request_destroy(&request);
2475                 dns_message_destroy(&tsigquery);
2476                 isc_mem_put(mctx, reqinfo, sizeof(nsu_gssinfo_t));
2477                 isc_event_free(&event);
2478                 maybeshutdown();
2479                 return;
2480         }
2481
2482         if (eresult != ISC_R_SUCCESS) {
2483                 char addrbuf[ISC_SOCKADDR_FORMATSIZE];
2484
2485                 isc_sockaddr_format(addr, addrbuf, sizeof(addrbuf));
2486                 fprintf(stderr, "; Communication with %s failed: %s\n",
2487                         addrbuf, isc_result_totext(eresult));
2488                 if (userserver != NULL)
2489                         fatal("could not talk to specified name server");
2490                 else if (++ns_inuse >= lwconf->nsnext)
2491                         fatal("could not talk to any default name server");
2492                 ddebug("Destroying request [%p]", request);
2493                 dns_request_destroy(&request);
2494                 dns_message_renderreset(tsigquery);
2495                 sendrequest(localaddr, &servers[ns_inuse], tsigquery,
2496                             &request);
2497                 isc_mem_put(mctx, reqinfo, sizeof(nsu_gssinfo_t));
2498                 isc_event_free(&event);
2499                 return;
2500         }
2501         isc_mem_put(mctx, reqinfo, sizeof(nsu_gssinfo_t));
2502
2503         isc_event_free(&event);
2504         reqev = NULL;
2505
2506         ddebug("recvgss creating rcvmsg");
2507         result = dns_message_create(mctx, DNS_MESSAGE_INTENTPARSE, &rcvmsg);
2508         check_result(result, "dns_message_create");
2509
2510         result = dns_request_getresponse(request, rcvmsg,
2511                                          DNS_MESSAGEPARSE_PRESERVEORDER);
2512         check_result(result, "dns_request_getresponse");
2513
2514         if (debugging)
2515                 show_message(stderr, rcvmsg,
2516                              "recvmsg reply from GSS-TSIG query");
2517
2518         if (rcvmsg->rcode == dns_rcode_formerr && !tried_other_gsstsig) {
2519                 ddebug("recvgss trying %s GSS-TSIG",
2520                        use_win2k_gsstsig ? "Standard" : "Win2k");
2521                 if (use_win2k_gsstsig)
2522                         use_win2k_gsstsig = ISC_FALSE;
2523                 else
2524                         use_win2k_gsstsig = ISC_TRUE;
2525                 tried_other_gsstsig = ISC_TRUE;
2526                 start_gssrequest(&restart_master);
2527                 goto done;
2528         }
2529
2530         if (rcvmsg->rcode != dns_rcode_noerror &&
2531             rcvmsg->rcode != dns_rcode_nxdomain)
2532                 fatal("response to GSS-TSIG query was unsuccessful");
2533
2534
2535         dns_fixedname_init(&fname);
2536         servname = dns_fixedname_name(&fname);
2537         isc_buffer_init(&buf, servicename, strlen(servicename));
2538         isc_buffer_add(&buf, strlen(servicename));
2539         result = dns_name_fromtext(servname, &buf, dns_rootname,
2540                                    ISC_FALSE, NULL);
2541         check_result(result, "dns_name_fromtext");
2542
2543         tsigkey = NULL;
2544         result = dns_tkey_gssnegotiate(tsigquery, rcvmsg, servname,
2545                                        &context, &tsigkey, gssring,
2546                                        use_win2k_gsstsig);
2547         switch (result) {
2548
2549         case DNS_R_CONTINUE:
2550                 send_gssrequest(localaddr, kserver, tsigquery, &request,
2551                                 context);
2552                 break;
2553
2554         case ISC_R_SUCCESS:
2555                 /*
2556                  * XXXSRA Waaay too much fun here.  There's no good
2557                  * reason why we need a TSIG here (the people who put
2558                  * it into the spec admitted at the time that it was
2559                  * not a security issue), and Windows clients don't
2560                  * seem to work if named complies with the spec and
2561                  * includes the gratuitous TSIG.  So we're in the
2562                  * bizarre situation of having to choose between
2563                  * complying with a useless requirement in the spec
2564                  * and interoperating.  This is nuts.  If we can
2565                  * confirm this behavior, we should ask the WG to
2566                  * consider removing the requirement for the
2567                  * gratuitous TSIG here.  For the moment, we ignore
2568                  * the TSIG -- this too is a spec violation, but it's
2569                  * the least insane thing to do.
2570                  */
2571 #if 0
2572                 /*
2573                  * Verify the signature.
2574                  */
2575                 rcvmsg->state = DNS_SECTION_ANY;
2576                 dns_message_setquerytsig(rcvmsg, NULL);
2577                 result = dns_message_settsigkey(rcvmsg, tsigkey);
2578                 check_result(result, "dns_message_settsigkey");
2579                 result = dns_message_checksig(rcvmsg, NULL);
2580                 ddebug("tsig verification: %s", dns_result_totext(result));
2581                 check_result(result, "dns_message_checksig");
2582 #endif /* 0 */
2583
2584                 send_update(&tmpzonename, serveraddr, localaddr);
2585                 setzoneclass(dns_rdataclass_none);
2586                 break;
2587
2588         default:
2589                 fatal("dns_tkey_negotiategss: %s", isc_result_totext(result));
2590         }
2591
2592  done:
2593         dns_request_destroy(&request);
2594         dns_message_destroy(&tsigquery);
2595
2596         dns_message_destroy(&rcvmsg);
2597         ddebug("Out of recvgss");
2598 }
2599 #endif
2600
2601 static void
2602 start_update(void) {
2603         isc_result_t result;
2604         dns_rdataset_t *rdataset = NULL;
2605         dns_name_t *name = NULL;
2606         dns_request_t *request = NULL;
2607         dns_message_t *soaquery = NULL;
2608         dns_name_t *firstname;
2609         dns_section_t section = DNS_SECTION_UPDATE;
2610
2611         ddebug("start_update()");
2612
2613         if (answer != NULL)
2614                 dns_message_destroy(&answer);
2615
2616         if (userzone != NULL && userserver != NULL && ! usegsstsig) {
2617                 send_update(userzone, userserver, localaddr);
2618                 setzoneclass(dns_rdataclass_none);
2619                 return;
2620         }
2621
2622         result = dns_message_create(mctx, DNS_MESSAGE_INTENTRENDER,
2623                                     &soaquery);
2624         check_result(result, "dns_message_create");
2625
2626         if (userserver == NULL)
2627                 soaquery->flags |= DNS_MESSAGEFLAG_RD;
2628
2629         result = dns_message_gettempname(soaquery, &name);
2630         check_result(result, "dns_message_gettempname");
2631
2632         result = dns_message_gettemprdataset(soaquery, &rdataset);
2633         check_result(result, "dns_message_gettemprdataset");
2634
2635         dns_rdataset_makequestion(rdataset, getzoneclass(), dns_rdatatype_soa);
2636
2637         if (userzone != NULL) {
2638                 dns_name_init(name, NULL);
2639                 dns_name_clone(userzone, name);
2640         } else {
2641                 dns_rdataset_t *tmprdataset;
2642                 result = dns_message_firstname(updatemsg, section);
2643                 if (result == ISC_R_NOMORE) {
2644                         section = DNS_SECTION_PREREQUISITE;
2645                         result = dns_message_firstname(updatemsg, section);
2646                 }
2647                 if (result != ISC_R_SUCCESS) {
2648                         dns_message_puttempname(soaquery, &name);
2649                         dns_rdataset_disassociate(rdataset);
2650                         dns_message_puttemprdataset(soaquery, &rdataset);
2651                         dns_message_destroy(&soaquery);
2652                         done_update();
2653                         return;
2654                 }
2655                 firstname = NULL;
2656                 dns_message_currentname(updatemsg, section, &firstname);
2657                 dns_name_init(name, NULL);
2658                 dns_name_clone(firstname, name);
2659                 /*
2660                  * Looks to see if the first name references a DS record
2661                  * and if that name is not the root remove a label as DS
2662                  * records live in the parent zone so we need to start our
2663                  * search one label up.
2664                  */
2665                 tmprdataset = ISC_LIST_HEAD(firstname->list);
2666                 if (section == DNS_SECTION_UPDATE &&
2667                     !dns_name_equal(firstname, dns_rootname) &&
2668                     tmprdataset->type == dns_rdatatype_ds) {
2669                     unsigned int labels = dns_name_countlabels(name);
2670                     dns_name_getlabelsequence(name, 1, labels - 1, name);
2671                 }
2672         }
2673
2674         ISC_LIST_INIT(name->list);
2675         ISC_LIST_APPEND(name->list, rdataset, link);
2676         dns_message_addname(soaquery, name, DNS_SECTION_QUESTION);
2677
2678         if (userserver != NULL)
2679                 sendrequest(localaddr, userserver, soaquery, &request);
2680         else {
2681                 ns_inuse = 0;
2682                 sendrequest(localaddr, &servers[ns_inuse], soaquery, &request);
2683         }
2684 }
2685
2686 static void
2687 cleanup(void) {
2688         ddebug("cleanup()");
2689
2690         if (answer != NULL)
2691                 dns_message_destroy(&answer);
2692
2693 #ifdef GSSAPI
2694         if (tsigkey != NULL) {
2695                 ddebug("detach tsigkey x%p", tsigkey);
2696                 dns_tsigkey_detach(&tsigkey);
2697         }
2698         if (gssring != NULL) {
2699                 ddebug("Destroying GSS-TSIG keyring");
2700                 dns_tsigkeyring_destroy(&gssring);
2701         }
2702         if (kserver != NULL) {
2703                 isc_mem_put(mctx, kserver, sizeof(isc_sockaddr_t));
2704                 kserver = NULL;
2705         }
2706         if (realm != NULL) {
2707                 isc_mem_free(mctx, realm);
2708                 realm = NULL;
2709         }
2710 #endif
2711
2712         if (sig0key != NULL)
2713                 dst_key_free(&sig0key);
2714
2715         ddebug("Shutting down task manager");
2716         isc_taskmgr_destroy(&taskmgr);
2717
2718         ddebug("Destroying event");
2719         isc_event_free(&global_event);
2720
2721         ddebug("Shutting down socket manager");
2722         isc_socketmgr_destroy(&socketmgr);
2723
2724         ddebug("Shutting down timer manager");
2725         isc_timermgr_destroy(&timermgr);
2726
2727         ddebug("Destroying hash context");
2728         isc_hash_destroy();
2729
2730         ddebug("Destroying name state");
2731         dns_name_destroy();
2732
2733         ddebug("Removing log context");
2734         isc_log_destroy(&lctx);
2735
2736         ddebug("Destroying memory context");
2737         if (memdebugging)
2738                 isc_mem_stats(mctx, stderr);
2739         isc_mem_destroy(&mctx);
2740 }
2741
2742 static void
2743 getinput(isc_task_t *task, isc_event_t *event) {
2744         isc_boolean_t more;
2745
2746         UNUSED(task);
2747
2748         if (shuttingdown) {
2749                 maybeshutdown();
2750                 return;
2751         }
2752
2753         if (global_event == NULL)
2754                 global_event = event;
2755
2756         reset_system();
2757         more = user_interaction();
2758         if (!more) {
2759                 isc_app_shutdown();
2760                 return;
2761         }
2762         start_update();
2763         return;
2764 }
2765
2766 int
2767 main(int argc, char **argv) {
2768         isc_result_t result;
2769         style = &dns_master_style_debug;
2770
2771         input = stdin;
2772
2773         interactive = ISC_TF(isatty(0));
2774
2775         isc_app_start();
2776
2777         pre_parse_args(argc, argv);
2778
2779         result = isc_mem_create(0, 0, &mctx);
2780         check_result(result, "isc_mem_create");
2781
2782         parse_args(argc, argv, mctx, &entropy);
2783
2784         setup_system();
2785
2786         result = isc_app_onrun(mctx, global_task, getinput, NULL);
2787         check_result(result, "isc_app_onrun");
2788
2789         (void)isc_app_run();
2790
2791         cleanup();
2792
2793         isc_app_finish();
2794
2795         if (seenerror)
2796                 return (2);
2797         else
2798                 return (0);
2799 }