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