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