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