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