nsupdate.c

Go to the documentation of this file.
00001 /*
00002  * Copyright (C) 2004-2015  Internet Systems Consortium, Inc. ("ISC")
00003  * Copyright (C) 2000-2003  Internet Software Consortium.
00004  *
00005  * Permission to use, copy, modify, and/or distribute this software for any
00006  * purpose with or without fee is hereby granted, provided that the above
00007  * copyright notice and this permission notice appear in all copies.
00008  *
00009  * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
00010  * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
00011  * AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
00012  * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
00013  * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
00014  * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
00015  * PERFORMANCE OF THIS SOFTWARE.
00016  */
00017 
00018 /*! \file */
00019 
00020 #include <config.h>
00021 
00022 #include <ctype.h>
00023 #include <errno.h>
00024 #include <limits.h>
00025 #include <stdlib.h>
00026 #include <unistd.h>
00027 
00028 #include <isc/app.h>
00029 #include <isc/base64.h>
00030 #include <isc/buffer.h>
00031 #include <isc/commandline.h>
00032 #include <isc/entropy.h>
00033 #include <isc/event.h>
00034 #include <isc/file.h>
00035 #include <isc/hash.h>
00036 #include <isc/lex.h>
00037 #include <isc/log.h>
00038 #include <isc/mem.h>
00039 #include <isc/parseint.h>
00040 #include <isc/print.h>
00041 #include <isc/random.h>
00042 #include <isc/region.h>
00043 #include <isc/sockaddr.h>
00044 #include <isc/socket.h>
00045 #include <isc/stdio.h>
00046 #include <isc/string.h>
00047 #include <isc/task.h>
00048 #include <isc/timer.h>
00049 #include <isc/types.h>
00050 #include <isc/util.h>
00051 
00052 #include <isccfg/namedconf.h>
00053 
00054 #include <dns/callbacks.h>
00055 #include <dns/dispatch.h>
00056 #include <dns/dnssec.h>
00057 #include <dns/events.h>
00058 #include <dns/fixedname.h>
00059 #include <dns/log.h>
00060 #include <dns/masterdump.h>
00061 #include <dns/message.h>
00062 #include <dns/name.h>
00063 #include <dns/rcode.h>
00064 #include <dns/rdata.h>
00065 #include <dns/rdataclass.h>
00066 #include <dns/rdatalist.h>
00067 #include <dns/rdataset.h>
00068 #include <dns/rdatastruct.h>
00069 #include <dns/rdatatype.h>
00070 #include <dns/request.h>
00071 #include <dns/result.h>
00072 #include <dns/tkey.h>
00073 #include <dns/tsig.h>
00074 
00075 #include <dst/dst.h>
00076 
00077 #include <lwres/lwres.h>
00078 #include <lwres/net.h>
00079 
00080 #ifdef GSSAPI
00081 #include <dst/gssapi.h>
00082 #ifdef WIN32
00083 #include <krb5/krb5.h>
00084 #else
00085 #include ISC_PLATFORM_KRB5HEADER
00086 #endif
00087 #endif
00088 #include <bind9/getaddresses.h>
00089 
00090 #if defined(HAVE_READLINE)
00091 #include <readline/readline.h>
00092 #include <readline/history.h>
00093 #endif
00094 
00095 #ifdef HAVE_ADDRINFO
00096 #ifdef HAVE_GETADDRINFO
00097 #ifdef HAVE_GAISTRERROR
00098 #define USE_GETADDRINFO
00099 #endif
00100 #endif
00101 #endif
00102 
00103 #ifndef USE_GETADDRINFO
00104 #ifndef ISC_PLATFORM_NONSTDHERRNO
00105 extern int h_errno;
00106 #endif
00107 #endif
00108 
00109 #define MAXCMD (128 * 1024)
00110 #define MAXWIRE (64 * 1024)
00111 #define PACKETSIZE ((64 * 1024) - 1)
00112 #define INITTEXT (2 * 1024)
00113 #define MAXTEXT (128 * 1024)
00114 #define FIND_TIMEOUT 5
00115 #define TTL_MAX 2147483647U     /* Maximum signed 32 bit integer. */
00116 
00117 #define DNSDEFAULTPORT 53
00118 
00119 /* Number of addresses to request from bind9_getaddresses() */
00120 #define MAX_SERVERADDRS 4
00121 
00122 static isc_uint16_t dnsport = DNSDEFAULTPORT;
00123 
00124 #ifndef RESOLV_CONF
00125 #define RESOLV_CONF "/etc/resolv.conf"
00126 #endif
00127 
00128 static isc_boolean_t debugging = ISC_FALSE, ddebugging = ISC_FALSE;
00129 static isc_boolean_t memdebugging = ISC_FALSE;
00130 static isc_boolean_t have_ipv4 = ISC_FALSE;
00131 static isc_boolean_t have_ipv6 = ISC_FALSE;
00132 static isc_boolean_t is_dst_up = ISC_FALSE;
00133 static isc_boolean_t usevc = ISC_FALSE;
00134 static isc_boolean_t usegsstsig = ISC_FALSE;
00135 static isc_boolean_t use_win2k_gsstsig = ISC_FALSE;
00136 static isc_boolean_t tried_other_gsstsig = ISC_FALSE;
00137 static isc_boolean_t local_only = ISC_FALSE;
00138 static isc_taskmgr_t *taskmgr = NULL;
00139 static isc_task_t *global_task = NULL;
00140 static isc_event_t *global_event = NULL;
00141 static isc_log_t *glctx = NULL;
00142 static isc_mem_t *gmctx = NULL;
00143 static dns_dispatchmgr_t *dispatchmgr = NULL;
00144 static dns_requestmgr_t *requestmgr = NULL;
00145 static isc_socketmgr_t *socketmgr = NULL;
00146 static isc_timermgr_t *timermgr = NULL;
00147 static dns_dispatch_t *dispatchv4 = NULL;
00148 static dns_dispatch_t *dispatchv6 = NULL;
00149 static dns_message_t *updatemsg = NULL;
00150 static dns_fixedname_t fuserzone;
00151 static dns_name_t *userzone = NULL;
00152 static dns_name_t *zname = NULL;
00153 static dns_name_t tmpzonename;
00154 static dns_name_t restart_master;
00155 static dns_tsig_keyring_t *gssring = NULL;
00156 static dns_tsigkey_t *tsigkey = NULL;
00157 static dst_key_t *sig0key = NULL;
00158 static lwres_context_t *lwctx = NULL;
00159 static lwres_conf_t *lwconf;
00160 static isc_sockaddr_t *servers = NULL;
00161 static isc_sockaddr_t *master_servers = NULL;
00162 static isc_boolean_t default_servers = ISC_TRUE;
00163 static int ns_inuse = 0;
00164 static int master_inuse = 0;
00165 static int ns_total = 0;
00166 static int master_total = 0;
00167 static isc_sockaddr_t *localaddr4 = NULL;
00168 static isc_sockaddr_t *localaddr6 = NULL;
00169 static const char *keyfile = NULL;
00170 static char *keystr = NULL;
00171 static isc_entropy_t *entropy = NULL;
00172 static isc_boolean_t shuttingdown = ISC_FALSE;
00173 static FILE *input;
00174 static isc_boolean_t interactive = ISC_TRUE;
00175 static isc_boolean_t seenerror = ISC_FALSE;
00176 static const dns_master_style_t *style;
00177 static int requests = 0;
00178 static unsigned int logdebuglevel = 0;
00179 static unsigned int timeout = 300;
00180 static unsigned int udp_timeout = 3;
00181 static unsigned int udp_retries = 3;
00182 static dns_rdataclass_t defaultclass = dns_rdataclass_in;
00183 static dns_rdataclass_t zoneclass = dns_rdataclass_none;
00184 static dns_message_t *answer = NULL;
00185 static isc_uint32_t default_ttl = 0;
00186 static isc_boolean_t default_ttl_set = ISC_FALSE;
00187 static isc_boolean_t checknames = ISC_TRUE;
00188 
00189 typedef struct nsu_requestinfo {
00190         dns_message_t *msg;
00191         isc_sockaddr_t *addr;
00192 } nsu_requestinfo_t;
00193 
00194 static void
00195 sendrequest(isc_sockaddr_t *destaddr, dns_message_t *msg,
00196             dns_request_t **request);
00197 static void
00198 send_update(dns_name_t *zonename, isc_sockaddr_t *master);
00199 
00200 ISC_PLATFORM_NORETURN_PRE static void
00201 fatal(const char *format, ...)
00202 ISC_FORMAT_PRINTF(1, 2) ISC_PLATFORM_NORETURN_POST;
00203 
00204 static void
00205 debug(const char *format, ...) ISC_FORMAT_PRINTF(1, 2);
00206 
00207 static void
00208 ddebug(const char *format, ...) ISC_FORMAT_PRINTF(1, 2);
00209 
00210 #ifdef GSSAPI
00211 static dns_fixedname_t fkname;
00212 static isc_sockaddr_t *kserver = NULL;
00213 static char *realm = NULL;
00214 static char servicename[DNS_NAME_FORMATSIZE];
00215 static dns_name_t *keyname;
00216 typedef struct nsu_gssinfo {
00217         dns_message_t *msg;
00218         isc_sockaddr_t *addr;
00219         gss_ctx_id_t context;
00220 } nsu_gssinfo_t;
00221 
00222 static void
00223 start_gssrequest(dns_name_t *master);
00224 static void
00225 send_gssrequest(isc_sockaddr_t *destaddr, dns_message_t *msg,
00226                 dns_request_t **request, gss_ctx_id_t context);
00227 static void
00228 recvgss(isc_task_t *task, isc_event_t *event);
00229 #endif /* GSSAPI */
00230 
00231 static void
00232 error(const char *format, ...) ISC_FORMAT_PRINTF(1, 2);
00233 
00234 #define STATUS_MORE     (isc_uint16_t)0
00235 #define STATUS_SEND     (isc_uint16_t)1
00236 #define STATUS_QUIT     (isc_uint16_t)2
00237 #define STATUS_SYNTAX   (isc_uint16_t)3
00238 
00239 typedef struct entropysource entropysource_t;
00240 
00241 struct entropysource {
00242         isc_entropysource_t *source;
00243         isc_mem_t *mctx;
00244         ISC_LINK(entropysource_t) link;
00245 };
00246 
00247 static ISC_LIST(entropysource_t) sources;
00248 
00249 static void
00250 setup_entropy(isc_mem_t *mctx, const char *randomfile, isc_entropy_t **ectx) {
00251         isc_result_t result;
00252         isc_entropysource_t *source = NULL;
00253         entropysource_t *elt;
00254         int usekeyboard = ISC_ENTROPY_KEYBOARDMAYBE;
00255 
00256         REQUIRE(ectx != NULL);
00257 
00258         if (*ectx == NULL) {
00259                 result = isc_entropy_create(mctx, ectx);
00260                 if (result != ISC_R_SUCCESS)
00261                         fatal("could not create entropy object");
00262                 ISC_LIST_INIT(sources);
00263         }
00264 
00265         if (randomfile != NULL && strcmp(randomfile, "keyboard") == 0) {
00266                 usekeyboard = ISC_ENTROPY_KEYBOARDYES;
00267                 randomfile = NULL;
00268         }
00269 
00270         result = isc_entropy_usebestsource(*ectx, &source, randomfile,
00271                                            usekeyboard);
00272 
00273         if (result != ISC_R_SUCCESS)
00274                 fatal("could not initialize entropy source: %s",
00275                       isc_result_totext(result));
00276 
00277         if (source != NULL) {
00278                 elt = isc_mem_get(mctx, sizeof(*elt));
00279                 if (elt == NULL)
00280                         fatal("out of memory");
00281                 elt->source = source;
00282                 elt->mctx = mctx;
00283                 ISC_LINK_INIT(elt, link);
00284                 ISC_LIST_APPEND(sources, elt, link);
00285         }
00286 }
00287 
00288 static void
00289 cleanup_entropy(isc_entropy_t **ectx) {
00290         entropysource_t *source;
00291         while (!ISC_LIST_EMPTY(sources)) {
00292                 source = ISC_LIST_HEAD(sources);
00293                 ISC_LIST_UNLINK(sources, source, link);
00294                 isc_entropy_destroysource(&source->source);
00295                 isc_mem_put(source->mctx, source, sizeof(*source));
00296         }
00297         isc_entropy_detach(ectx);
00298 }
00299 
00300 static void
00301 master_from_servers(void) {
00302 
00303         if (master_servers != NULL && master_servers != servers)
00304                 isc_mem_put(gmctx, master_servers,
00305                             master_total * sizeof(isc_sockaddr_t));
00306         master_servers = servers;
00307         master_total = ns_total;
00308         master_inuse = ns_inuse;
00309 }
00310 
00311 static dns_rdataclass_t
00312 getzoneclass(void) {
00313         if (zoneclass == dns_rdataclass_none)
00314                 zoneclass = defaultclass;
00315         return (zoneclass);
00316 }
00317 
00318 static isc_boolean_t
00319 setzoneclass(dns_rdataclass_t rdclass) {
00320         if (zoneclass == dns_rdataclass_none ||
00321             rdclass == dns_rdataclass_none)
00322                 zoneclass = rdclass;
00323         if (zoneclass != rdclass)
00324                 return (ISC_FALSE);
00325         return (ISC_TRUE);
00326 }
00327 
00328 static void
00329 fatal(const char *format, ...) {
00330         va_list args;
00331 
00332         va_start(args, format);
00333         vfprintf(stderr, format, args);
00334         va_end(args);
00335         fprintf(stderr, "\n");
00336         exit(1);
00337 }
00338 
00339 static void
00340 error(const char *format, ...) {
00341         va_list args;
00342 
00343         va_start(args, format);
00344         vfprintf(stderr, format, args);
00345         va_end(args);
00346         fprintf(stderr, "\n");
00347 }
00348 
00349 static void
00350 debug(const char *format, ...) {
00351         va_list args;
00352 
00353         if (debugging) {
00354                 va_start(args, format);
00355                 vfprintf(stderr, format, args);
00356                 va_end(args);
00357                 fprintf(stderr, "\n");
00358         }
00359 }
00360 
00361 static void
00362 ddebug(const char *format, ...) {
00363         va_list args;
00364 
00365         if (ddebugging) {
00366                 va_start(args, format);
00367                 vfprintf(stderr, format, args);
00368                 va_end(args);
00369                 fprintf(stderr, "\n");
00370         }
00371 }
00372 
00373 static inline void
00374 check_result(isc_result_t result, const char *msg) {
00375         if (result != ISC_R_SUCCESS)
00376                 fatal("%s: %s", msg, isc_result_totext(result));
00377 }
00378 
00379 static void *
00380 mem_alloc(void *arg, size_t size) {
00381         return (isc_mem_get(arg, size));
00382 }
00383 
00384 static void
00385 mem_free(void *arg, void *mem, size_t size) {
00386         isc_mem_put(arg, mem, size);
00387 }
00388 
00389 static char *
00390 nsu_strsep(char **stringp, const char *delim) {
00391         char *string = *stringp;
00392         char *s;
00393         const char *d;
00394         char sc, dc;
00395 
00396         if (string == NULL)
00397                 return (NULL);
00398 
00399         for (; *string != '\0'; string++) {
00400                 sc = *string;
00401                 for (d = delim; (dc = *d) != '\0'; d++) {
00402                         if (sc == dc)
00403                                 break;
00404                 }
00405                 if (dc == 0)
00406                         break;
00407         }
00408 
00409         for (s = string; *s != '\0'; s++) {
00410                 sc = *s;
00411                 for (d = delim; (dc = *d) != '\0'; d++) {
00412                         if (sc == dc) {
00413                                 *s++ = '\0';
00414                                 *stringp = s;
00415                                 return (string);
00416                         }
00417                 }
00418         }
00419         *stringp = NULL;
00420         return (string);
00421 }
00422 
00423 static void
00424 reset_system(void) {
00425         isc_result_t result;
00426 
00427         ddebug("reset_system()");
00428         /* If the update message is still around, destroy it */
00429         if (updatemsg != NULL)
00430                 dns_message_reset(updatemsg, DNS_MESSAGE_INTENTRENDER);
00431         else {
00432                 result = dns_message_create(gmctx, DNS_MESSAGE_INTENTRENDER,
00433                                             &updatemsg);
00434                 check_result(result, "dns_message_create");
00435         }
00436         updatemsg->opcode = dns_opcode_update;
00437         if (usegsstsig) {
00438                 if (tsigkey != NULL)
00439                         dns_tsigkey_detach(&tsigkey);
00440                 if (gssring != NULL)
00441                         dns_tsigkeyring_detach(&gssring);
00442                 tried_other_gsstsig = ISC_FALSE;
00443         }
00444 }
00445 
00446 static isc_uint16_t
00447 parse_hmac(dns_name_t **hmac, const char *hmacstr, size_t len) {
00448         isc_uint16_t digestbits = 0;
00449         isc_result_t result;
00450         char buf[20];
00451 
00452         REQUIRE(hmac != NULL && *hmac == NULL);
00453         REQUIRE(hmacstr != NULL);
00454 
00455         if (len >= sizeof(buf))
00456                 fatal("unknown key type '%.*s'", (int)(len), hmacstr);
00457 
00458         strncpy(buf, hmacstr, len);
00459         buf[len] = 0;
00460 
00461         if (strcasecmp(buf, "hmac-md5") == 0) {
00462                 *hmac = DNS_TSIG_HMACMD5_NAME;
00463         } else if (strncasecmp(buf, "hmac-md5-", 9) == 0) {
00464                 *hmac = DNS_TSIG_HMACMD5_NAME;
00465                 result = isc_parse_uint16(&digestbits, &buf[9], 10);
00466                 if (result != ISC_R_SUCCESS || digestbits > 128)
00467                         fatal("digest-bits out of range [0..128]");
00468                 digestbits = (digestbits +7) & ~0x7U;
00469         } else if (strcasecmp(buf, "hmac-sha1") == 0) {
00470                 *hmac = DNS_TSIG_HMACSHA1_NAME;
00471         } else if (strncasecmp(buf, "hmac-sha1-", 10) == 0) {
00472                 *hmac = DNS_TSIG_HMACSHA1_NAME;
00473                 result = isc_parse_uint16(&digestbits, &buf[10], 10);
00474                 if (result != ISC_R_SUCCESS || digestbits > 160)
00475                         fatal("digest-bits out of range [0..160]");
00476                 digestbits = (digestbits +7) & ~0x7U;
00477         } else if (strcasecmp(buf, "hmac-sha224") == 0) {
00478                 *hmac = DNS_TSIG_HMACSHA224_NAME;
00479         } else if (strncasecmp(buf, "hmac-sha224-", 12) == 0) {
00480                 *hmac = DNS_TSIG_HMACSHA224_NAME;
00481                 result = isc_parse_uint16(&digestbits, &buf[12], 10);
00482                 if (result != ISC_R_SUCCESS || digestbits > 224)
00483                         fatal("digest-bits out of range [0..224]");
00484                 digestbits = (digestbits +7) & ~0x7U;
00485         } else if (strcasecmp(buf, "hmac-sha256") == 0) {
00486                 *hmac = DNS_TSIG_HMACSHA256_NAME;
00487         } else if (strncasecmp(buf, "hmac-sha256-", 12) == 0) {
00488                 *hmac = DNS_TSIG_HMACSHA256_NAME;
00489                 result = isc_parse_uint16(&digestbits, &buf[12], 10);
00490                 if (result != ISC_R_SUCCESS || digestbits > 256)
00491                         fatal("digest-bits out of range [0..256]");
00492                 digestbits = (digestbits +7) & ~0x7U;
00493         } else if (strcasecmp(buf, "hmac-sha384") == 0) {
00494                 *hmac = DNS_TSIG_HMACSHA384_NAME;
00495         } else if (strncasecmp(buf, "hmac-sha384-", 12) == 0) {
00496                 *hmac = DNS_TSIG_HMACSHA384_NAME;
00497                 result = isc_parse_uint16(&digestbits, &buf[12], 10);
00498                 if (result != ISC_R_SUCCESS || digestbits > 384)
00499                         fatal("digest-bits out of range [0..384]");
00500                 digestbits = (digestbits +7) & ~0x7U;
00501         } else if (strcasecmp(buf, "hmac-sha512") == 0) {
00502                 *hmac = DNS_TSIG_HMACSHA512_NAME;
00503         } else if (strncasecmp(buf, "hmac-sha512-", 12) == 0) {
00504                 *hmac = DNS_TSIG_HMACSHA512_NAME;
00505                 result = isc_parse_uint16(&digestbits, &buf[12], 10);
00506                 if (result != ISC_R_SUCCESS || digestbits > 512)
00507                         fatal("digest-bits out of range [0..512]");
00508                 digestbits = (digestbits +7) & ~0x7U;
00509         } else
00510                 fatal("unknown key type '%s'", buf);
00511         return (digestbits);
00512 }
00513 
00514 static int
00515 basenamelen(const char *file) {
00516         int len = strlen(file);
00517 
00518         if (len > 1 && file[len - 1] == '.')
00519                 len -= 1;
00520         else if (len > 8 && strcmp(file + len - 8, ".private") == 0)
00521                 len -= 8;
00522         else if (len > 4 && strcmp(file + len - 4, ".key") == 0)
00523                 len -= 4;
00524         return (len);
00525 }
00526 
00527 static void
00528 setup_keystr(void) {
00529         unsigned char *secret = NULL;
00530         int secretlen;
00531         isc_buffer_t secretbuf;
00532         isc_result_t result;
00533         isc_buffer_t keynamesrc;
00534         char *secretstr;
00535         char *s, *n;
00536         dns_fixedname_t fkeyname;
00537         dns_name_t *mykeyname;
00538         char *name;
00539         dns_name_t *hmacname = NULL;
00540         isc_uint16_t digestbits = 0;
00541 
00542         dns_fixedname_init(&fkeyname);
00543         mykeyname = dns_fixedname_name(&fkeyname);
00544 
00545         debug("Creating key...");
00546 
00547         s = strchr(keystr, ':');
00548         if (s == NULL || s == keystr || s[1] == 0)
00549                 fatal("key option must specify [hmac:]keyname:secret");
00550         secretstr = s + 1;
00551         n = strchr(secretstr, ':');
00552         if (n != NULL) {
00553                 if (n == secretstr || n[1] == 0)
00554                         fatal("key option must specify [hmac:]keyname:secret");
00555                 name = secretstr;
00556                 secretstr = n + 1;
00557                 digestbits = parse_hmac(&hmacname, keystr, s - keystr);
00558         } else {
00559                 hmacname = DNS_TSIG_HMACMD5_NAME;
00560                 name = keystr;
00561                 n = s;
00562         }
00563 
00564         isc_buffer_init(&keynamesrc, name, (unsigned int)(n - name));
00565         isc_buffer_add(&keynamesrc, (unsigned int)(n - name));
00566 
00567         debug("namefromtext");
00568         result = dns_name_fromtext(mykeyname, &keynamesrc, dns_rootname, 0,
00569                                    NULL);
00570         check_result(result, "dns_name_fromtext");
00571 
00572         secretlen = strlen(secretstr) * 3 / 4;
00573         secret = isc_mem_allocate(gmctx, secretlen);
00574         if (secret == NULL)
00575                 fatal("out of memory");
00576 
00577         isc_buffer_init(&secretbuf, secret, secretlen);
00578         result = isc_base64_decodestring(secretstr, &secretbuf);
00579         if (result != ISC_R_SUCCESS) {
00580                 fprintf(stderr, "could not create key from %s: %s\n",
00581                         keystr, isc_result_totext(result));
00582                 goto failure;
00583         }
00584 
00585         secretlen = isc_buffer_usedlength(&secretbuf);
00586 
00587         debug("keycreate");
00588         result = dns_tsigkey_create(mykeyname, hmacname, secret, secretlen,
00589                                     ISC_FALSE, NULL, 0, 0, gmctx, NULL,
00590                                     &tsigkey);
00591         if (result != ISC_R_SUCCESS)
00592                 fprintf(stderr, "could not create key from %s: %s\n",
00593                         keystr, dns_result_totext(result));
00594         else
00595                 dst_key_setbits(tsigkey->key, digestbits);
00596  failure:
00597         if (secret != NULL)
00598                 isc_mem_free(gmctx, secret);
00599 }
00600 
00601 /*
00602  * Get a key from a named.conf format keyfile
00603  */
00604 static isc_result_t
00605 read_sessionkey(isc_mem_t *mctx, isc_log_t *lctx) {
00606         cfg_parser_t *pctx = NULL;
00607         cfg_obj_t *sessionkey = NULL;
00608         const cfg_obj_t *key = NULL;
00609         const cfg_obj_t *secretobj = NULL;
00610         const cfg_obj_t *algorithmobj = NULL;
00611         const char *mykeyname;
00612         const char *secretstr;
00613         const char *algorithm;
00614         isc_result_t result;
00615         int len;
00616 
00617         if (! isc_file_exists(keyfile))
00618                 return (ISC_R_FILENOTFOUND);
00619 
00620         result = cfg_parser_create(mctx, lctx, &pctx);
00621         if (result != ISC_R_SUCCESS)
00622                 goto cleanup;
00623 
00624         result = cfg_parse_file(pctx, keyfile, &cfg_type_sessionkey,
00625                                 &sessionkey);
00626         if (result != ISC_R_SUCCESS)
00627                 goto cleanup;
00628 
00629         result = cfg_map_get(sessionkey, "key", &key);
00630         if (result != ISC_R_SUCCESS)
00631                 goto cleanup;
00632 
00633         (void) cfg_map_get(key, "secret", &secretobj);
00634         (void) cfg_map_get(key, "algorithm", &algorithmobj);
00635         if (secretobj == NULL || algorithmobj == NULL)
00636                 fatal("key must have algorithm and secret");
00637 
00638         mykeyname = cfg_obj_asstring(cfg_map_getname(key));
00639         secretstr = cfg_obj_asstring(secretobj);
00640         algorithm = cfg_obj_asstring(algorithmobj);
00641 
00642         len = strlen(algorithm) + strlen(mykeyname) + strlen(secretstr) + 3;
00643         keystr = isc_mem_allocate(mctx, len);
00644         snprintf(keystr, len, "%s:%s:%s", algorithm, mykeyname, secretstr);
00645         setup_keystr();
00646 
00647  cleanup:
00648         if (pctx != NULL) {
00649                 if (sessionkey != NULL)
00650                         cfg_obj_destroy(pctx, &sessionkey);
00651                 cfg_parser_destroy(&pctx);
00652         }
00653 
00654         if (keystr != NULL)
00655                 isc_mem_free(mctx, keystr);
00656 
00657         return (result);
00658 }
00659 
00660 static void
00661 setup_keyfile(isc_mem_t *mctx, isc_log_t *lctx) {
00662         dst_key_t *dstkey = NULL;
00663         isc_result_t result;
00664         dns_name_t *hmacname = NULL;
00665 
00666         debug("Creating key...");
00667 
00668         if (sig0key != NULL)
00669                 dst_key_free(&sig0key);
00670 
00671         /* Try reading the key from a K* pair */
00672         result = dst_key_fromnamedfile(keyfile, NULL,
00673                                        DST_TYPE_PRIVATE | DST_TYPE_KEY, mctx,
00674                                        &dstkey);
00675 
00676         /* If that didn't work, try reading it as a session.key keyfile */
00677         if (result != ISC_R_SUCCESS) {
00678                 result = read_sessionkey(mctx, lctx);
00679                 if (result == ISC_R_SUCCESS)
00680                         return;
00681         }
00682 
00683         if (result != ISC_R_SUCCESS) {
00684                 fprintf(stderr, "could not read key from %.*s.{private,key}: "
00685                                 "%s\n", basenamelen(keyfile), keyfile,
00686                                 isc_result_totext(result));
00687                 return;
00688         }
00689 
00690         switch (dst_key_alg(dstkey)) {
00691         case DST_ALG_HMACMD5:
00692                 hmacname = DNS_TSIG_HMACMD5_NAME;
00693                 break;
00694         case DST_ALG_HMACSHA1:
00695                 hmacname = DNS_TSIG_HMACSHA1_NAME;
00696                 break;
00697         case DST_ALG_HMACSHA224:
00698                 hmacname = DNS_TSIG_HMACSHA224_NAME;
00699                 break;
00700         case DST_ALG_HMACSHA256:
00701                 hmacname = DNS_TSIG_HMACSHA256_NAME;
00702                 break;
00703         case DST_ALG_HMACSHA384:
00704                 hmacname = DNS_TSIG_HMACSHA384_NAME;
00705                 break;
00706         case DST_ALG_HMACSHA512:
00707                 hmacname = DNS_TSIG_HMACSHA512_NAME;
00708                 break;
00709         }
00710         if (hmacname != NULL) {
00711                 result = dns_tsigkey_createfromkey(dst_key_name(dstkey),
00712                                                    hmacname, dstkey, ISC_FALSE,
00713                                                    NULL, 0, 0, mctx, NULL,
00714                                                    &tsigkey);
00715                 dst_key_free(&dstkey);
00716                 if (result != ISC_R_SUCCESS) {
00717                         fprintf(stderr, "could not create key from %s: %s\n",
00718                                 keyfile, isc_result_totext(result));
00719                         return;
00720                 }
00721         } else {
00722                 dst_key_attach(dstkey, &sig0key);
00723                 dst_key_free(&dstkey);
00724         }
00725 }
00726 
00727 static void
00728 doshutdown(void) {
00729         isc_task_detach(&global_task);
00730 
00731         /*
00732          * The isc_mem_put of master_servers must be before the
00733          * isc_mem_put of servers as it sets the servers pointer
00734          * to NULL.
00735          */
00736         if (master_servers != NULL && master_servers != servers)
00737                 isc_mem_put(gmctx, master_servers,
00738                             master_total * sizeof(isc_sockaddr_t));
00739 
00740         if (servers != NULL)
00741                 isc_mem_put(gmctx, servers, ns_total * sizeof(isc_sockaddr_t));
00742 
00743         if (localaddr4 != NULL)
00744                 isc_mem_put(gmctx, localaddr4, sizeof(isc_sockaddr_t));
00745 
00746         if (localaddr6 != NULL)
00747                 isc_mem_put(gmctx, localaddr6, sizeof(isc_sockaddr_t));
00748 
00749         if (tsigkey != NULL) {
00750                 ddebug("Freeing TSIG key");
00751                 dns_tsigkey_detach(&tsigkey);
00752         }
00753 
00754         if (sig0key != NULL) {
00755                 ddebug("Freeing SIG(0) key");
00756                 dst_key_free(&sig0key);
00757         }
00758 
00759         if (updatemsg != NULL)
00760                 dns_message_destroy(&updatemsg);
00761 
00762         if (is_dst_up) {
00763                 ddebug("Destroy DST lib");
00764                 dst_lib_destroy();
00765                 is_dst_up = ISC_FALSE;
00766         }
00767 
00768         cleanup_entropy(&entropy);
00769 
00770         lwres_conf_clear(lwctx);
00771         lwres_context_destroy(&lwctx);
00772 
00773         ddebug("Destroying request manager");
00774         dns_requestmgr_detach(&requestmgr);
00775 
00776         ddebug("Freeing the dispatchers");
00777         if (have_ipv4)
00778                 dns_dispatch_detach(&dispatchv4);
00779         if (have_ipv6)
00780                 dns_dispatch_detach(&dispatchv6);
00781 
00782         ddebug("Shutting down dispatch manager");
00783         dns_dispatchmgr_destroy(&dispatchmgr);
00784 
00785 }
00786 
00787 static void
00788 maybeshutdown(void) {
00789         ddebug("Shutting down request manager");
00790         dns_requestmgr_shutdown(requestmgr);
00791 
00792         if (requests != 0)
00793                 return;
00794 
00795         doshutdown();
00796 }
00797 
00798 static void
00799 shutdown_program(isc_task_t *task, isc_event_t *event) {
00800         REQUIRE(task == global_task);
00801         UNUSED(task);
00802 
00803         ddebug("shutdown_program()");
00804         isc_event_free(&event);
00805 
00806         shuttingdown = ISC_TRUE;
00807         maybeshutdown();
00808 }
00809 
00810 static void
00811 setup_system(void) {
00812         isc_result_t result;
00813         isc_sockaddr_t bind_any, bind_any6;
00814         lwres_result_t lwresult;
00815         unsigned int attrs, attrmask;
00816         int i;
00817         isc_logconfig_t *logconfig = NULL;
00818 
00819         ddebug("setup_system()");
00820 
00821         dns_result_register();
00822 
00823         result = isc_net_probeipv4();
00824         if (result == ISC_R_SUCCESS)
00825                 have_ipv4 = ISC_TRUE;
00826 
00827         result = isc_net_probeipv6();
00828         if (result == ISC_R_SUCCESS)
00829                 have_ipv6 = ISC_TRUE;
00830 
00831         if (!have_ipv4 && !have_ipv6)
00832                 fatal("could not find either IPv4 or IPv6");
00833 
00834         result = isc_log_create(gmctx, &glctx, &logconfig);
00835         check_result(result, "isc_log_create");
00836 
00837         isc_log_setcontext(glctx);
00838         dns_log_init(glctx);
00839         dns_log_setcontext(glctx);
00840 
00841         result = isc_log_usechannel(logconfig, "default_debug", NULL, NULL);
00842         check_result(result, "isc_log_usechannel");
00843 
00844         isc_log_setdebuglevel(glctx, logdebuglevel);
00845 
00846         lwresult = lwres_context_create(&lwctx, gmctx, mem_alloc, mem_free, 1);
00847         if (lwresult != LWRES_R_SUCCESS)
00848                 fatal("lwres_context_create failed");
00849 
00850         (void)lwres_conf_parse(lwctx, RESOLV_CONF);
00851         lwconf = lwres_conf_get(lwctx);
00852 
00853         if (servers != NULL) {
00854                 if (master_servers == servers)
00855                         master_servers = NULL;
00856                 isc_mem_put(gmctx, servers, ns_total * sizeof(isc_sockaddr_t));
00857         }
00858 
00859         ns_inuse = 0;
00860         if (local_only || lwconf->nsnext <= 0) {
00861                 struct in_addr in;
00862                 struct in6_addr in6;
00863 
00864                 if (local_only && keyfile == NULL)
00865                         keyfile = SESSION_KEYFILE;
00866 
00867                 default_servers = !local_only;
00868 
00869                 ns_total = (have_ipv4 ? 1 : 0) + (have_ipv6 ? 1 : 0);
00870                 servers = isc_mem_get(gmctx, ns_total * sizeof(isc_sockaddr_t));
00871                 if (servers == NULL)
00872                         fatal("out of memory");
00873 
00874                 if (have_ipv4) {
00875                         in.s_addr = htonl(INADDR_LOOPBACK);
00876                         isc_sockaddr_fromin(&servers[0], &in, dnsport);
00877                 }
00878                 if (have_ipv6) {
00879                         memset(&in6, 0, sizeof(in6));
00880                         in6.s6_addr[15] = 1;
00881                         isc_sockaddr_fromin6(&servers[(have_ipv4 ? 1 : 0)],
00882                                              &in6, dnsport);
00883                 }
00884         } else {
00885                 ns_total = lwconf->nsnext;
00886                 servers = isc_mem_get(gmctx, ns_total * sizeof(isc_sockaddr_t));
00887                 if (servers == NULL)
00888                         fatal("out of memory");
00889                 for (i = 0; i < ns_total; i++) {
00890                         if (lwconf->nameservers[i].family == LWRES_ADDRTYPE_V4)
00891                         {
00892                                 struct in_addr in4;
00893                                 memmove(&in4,
00894                                         lwconf->nameservers[i].address, 4);
00895                                 isc_sockaddr_fromin(&servers[i],
00896                                                     &in4, dnsport);
00897                         } else {
00898                                 struct in6_addr in6;
00899                                 memmove(&in6,
00900                                         lwconf->nameservers[i].address, 16);
00901                                 isc_sockaddr_fromin6(&servers[i],
00902                                                      &in6, dnsport);
00903                         }
00904                 }
00905         }
00906 
00907         setup_entropy(gmctx, NULL, &entropy);
00908 
00909         result = isc_hash_create(gmctx, entropy, DNS_NAME_MAXWIRE);
00910         check_result(result, "isc_hash_create");
00911         isc_hash_init();
00912 
00913         result = dns_dispatchmgr_create(gmctx, entropy, &dispatchmgr);
00914         check_result(result, "dns_dispatchmgr_create");
00915 
00916         result = isc_socketmgr_create(gmctx, &socketmgr);
00917         check_result(result, "dns_socketmgr_create");
00918 
00919         result = isc_timermgr_create(gmctx, &timermgr);
00920         check_result(result, "dns_timermgr_create");
00921 
00922         result = isc_taskmgr_create(gmctx, 1, 0, &taskmgr);
00923         check_result(result, "isc_taskmgr_create");
00924 
00925         result = isc_task_create(taskmgr, 0, &global_task);
00926         check_result(result, "isc_task_create");
00927 
00928         result = isc_task_onshutdown(global_task, shutdown_program, NULL);
00929         check_result(result, "isc_task_onshutdown");
00930 
00931         result = dst_lib_init(gmctx, entropy, 0);
00932         check_result(result, "dst_lib_init");
00933         is_dst_up = ISC_TRUE;
00934 
00935         attrmask = DNS_DISPATCHATTR_UDP | DNS_DISPATCHATTR_TCP;
00936         attrmask |= DNS_DISPATCHATTR_IPV4 | DNS_DISPATCHATTR_IPV6;
00937 
00938         if (have_ipv6) {
00939                 attrs = DNS_DISPATCHATTR_UDP;
00940                 attrs |= DNS_DISPATCHATTR_MAKEQUERY;
00941                 attrs |= DNS_DISPATCHATTR_IPV6;
00942                 isc_sockaddr_any6(&bind_any6);
00943                 result = dns_dispatch_getudp(dispatchmgr, socketmgr, taskmgr,
00944                                              &bind_any6, PACKETSIZE,
00945                                              4, 2, 3, 5,
00946                                              attrs, attrmask, &dispatchv6);
00947                 check_result(result, "dns_dispatch_getudp (v6)");
00948         }
00949 
00950         if (have_ipv4) {
00951                 attrs = DNS_DISPATCHATTR_UDP;
00952                 attrs |= DNS_DISPATCHATTR_MAKEQUERY;
00953                 attrs |= DNS_DISPATCHATTR_IPV4;
00954                 isc_sockaddr_any(&bind_any);
00955                 result = dns_dispatch_getudp(dispatchmgr, socketmgr, taskmgr,
00956                                              &bind_any, PACKETSIZE,
00957                                              4, 2, 3, 5,
00958                                              attrs, attrmask, &dispatchv4);
00959                 check_result(result, "dns_dispatch_getudp (v4)");
00960         }
00961 
00962         result = dns_requestmgr_create(gmctx, timermgr,
00963                                        socketmgr, taskmgr, dispatchmgr,
00964                                        dispatchv4, dispatchv6, &requestmgr);
00965         check_result(result, "dns_requestmgr_create");
00966 
00967         if (keystr != NULL)
00968                 setup_keystr();
00969         else if (local_only) {
00970                 result = read_sessionkey(gmctx, glctx);
00971                 if (result != ISC_R_SUCCESS)
00972                         fatal("can't read key from %s: %s\n",
00973                               keyfile, isc_result_totext(result));
00974         } else if (keyfile != NULL)
00975                 setup_keyfile(gmctx, glctx);
00976 }
00977 
00978 static void
00979 get_addresses(char *host, in_port_t port,
00980               isc_sockaddr_t *sockaddr, int naddrs)
00981 {
00982         int count;
00983         isc_result_t result;
00984 
00985         isc_app_block();
00986         result = bind9_getaddresses(host, port, sockaddr, naddrs, &count);
00987         isc_app_unblock();
00988         if (result != ISC_R_SUCCESS)
00989                 fatal("couldn't get address for '%s': %s",
00990                       host, isc_result_totext(result));
00991 }
00992 
00993 static void
00994 version(void) {
00995         fputs("nsupdate " VERSION "\n", stderr);
00996 }
00997 
00998 #define PARSE_ARGS_FMT "dDML:y:ghlovk:p:Pr:R::t:Tu:V"
00999 
01000 static void
01001 pre_parse_args(int argc, char **argv) {
01002         dns_rdatatype_t t;
01003         int ch;
01004         char buf[100];
01005         isc_boolean_t doexit = ISC_FALSE;
01006 
01007         while ((ch = isc_commandline_parse(argc, argv, PARSE_ARGS_FMT)) != -1) {
01008                 switch (ch) {
01009                 case 'M': /* was -dm */
01010                         debugging = ISC_TRUE;
01011                         ddebugging = ISC_TRUE;
01012                         memdebugging = ISC_TRUE;
01013                         isc_mem_debugging = ISC_MEM_DEBUGTRACE |
01014                                             ISC_MEM_DEBUGRECORD;
01015                         break;
01016 
01017                 case '?':
01018                 case 'h':
01019                         if (isc_commandline_option != '?')
01020                                 fprintf(stderr, "%s: invalid argument -%c\n",
01021                                         argv[0], isc_commandline_option);
01022                         fprintf(stderr, "usage: nsupdate [-dD] [-L level] [-l]"
01023                                 "[-g | -o | -y keyname:secret | -k keyfile] "
01024                                 "[-v] [-V] [filename]\n");
01025                         exit(1);
01026 
01027                 case 'P':
01028                         for (t = 0xff00; t <= 0xfffe; t++) {
01029                                 if (dns_rdatatype_ismeta(t))
01030                                         continue;
01031                                 dns_rdatatype_format(t, buf, sizeof(buf));
01032                                 if (strncmp(buf, "TYPE", 4) != 0)
01033                                         fprintf(stdout, "%s\n", buf);
01034                         }
01035                         doexit = ISC_TRUE;
01036                         break;
01037 
01038                 case 'T':
01039                         for (t = 1; t <= 0xfeff; t++) {
01040                                 if (dns_rdatatype_ismeta(t))
01041                                         continue;
01042                                 dns_rdatatype_format(t, buf, sizeof(buf));
01043                                 if (strncmp(buf, "TYPE", 4) != 0)
01044                                         fprintf(stdout, "%s\n", buf);
01045                         }
01046                         doexit = ISC_TRUE;
01047                         break;
01048 
01049                 case 'V':
01050                         version();
01051                         doexit = ISC_TRUE;
01052                         break;
01053 
01054                 default:
01055                         break;
01056                 }
01057         }
01058         if (doexit)
01059                 exit(0);
01060         isc_commandline_reset = ISC_TRUE;
01061         isc_commandline_index = 1;
01062 }
01063 
01064 static void
01065 parse_args(int argc, char **argv, isc_mem_t *mctx, isc_entropy_t **ectx) {
01066         int ch;
01067         isc_uint32_t i;
01068         isc_result_t result;
01069 
01070         debug("parse_args");
01071         while ((ch = isc_commandline_parse(argc, argv, PARSE_ARGS_FMT)) != -1) {
01072                 switch (ch) {
01073                 case 'd':
01074                         debugging = ISC_TRUE;
01075                         break;
01076                 case 'D': /* was -dd */
01077                         debugging = ISC_TRUE;
01078                         ddebugging = ISC_TRUE;
01079                         break;
01080                 case 'M':
01081                         break;
01082                 case 'l':
01083                         local_only = ISC_TRUE;
01084                         break;
01085                 case 'L':
01086                         result = isc_parse_uint32(&i, isc_commandline_argument,
01087                                                   10);
01088                         if (result != ISC_R_SUCCESS) {
01089                                 fprintf(stderr, "bad library debug value "
01090                                         "'%s'\n", isc_commandline_argument);
01091                                 exit(1);
01092                         }
01093                         logdebuglevel = i;
01094                         break;
01095                 case 'y':
01096                         keystr = isc_commandline_argument;
01097                         break;
01098                 case 'v':
01099                         usevc = ISC_TRUE;
01100                         break;
01101                 case 'k':
01102                         keyfile = isc_commandline_argument;
01103                         break;
01104                 case 'g':
01105                         usegsstsig = ISC_TRUE;
01106                         use_win2k_gsstsig = ISC_FALSE;
01107                         break;
01108                 case 'o':
01109                         usegsstsig = ISC_TRUE;
01110                         use_win2k_gsstsig = ISC_TRUE;
01111                         break;
01112                 case 'p':
01113                         result = isc_parse_uint16(&dnsport,
01114                                                   isc_commandline_argument, 10);
01115                         if (result != ISC_R_SUCCESS) {
01116                                 fprintf(stderr, "bad port number "
01117                                         "'%s'\n", isc_commandline_argument);
01118                                 exit(1);
01119                         }
01120                         break;
01121                 case 't':
01122                         result = isc_parse_uint32(&timeout,
01123                                                   isc_commandline_argument, 10);
01124                         if (result != ISC_R_SUCCESS) {
01125                                 fprintf(stderr, "bad timeout '%s'\n",                                           isc_commandline_argument);
01126                                 exit(1);
01127                         }
01128                         if (timeout == 0)
01129                                 timeout = UINT_MAX;
01130                         break;
01131                 case 'u':
01132                         result = isc_parse_uint32(&udp_timeout,
01133                                                   isc_commandline_argument, 10);
01134                         if (result != ISC_R_SUCCESS) {
01135                                 fprintf(stderr, "bad udp timeout '%s'\n",                                               isc_commandline_argument);
01136                                 exit(1);
01137                         }
01138                         if (udp_timeout == 0)
01139                                 udp_timeout = UINT_MAX;
01140                         break;
01141                 case 'r':
01142                         result = isc_parse_uint32(&udp_retries,
01143                                                   isc_commandline_argument, 10);
01144                         if (result != ISC_R_SUCCESS) {
01145                                 fprintf(stderr, "bad udp retries '%s'\n",                                               isc_commandline_argument);
01146                                 exit(1);
01147                         }
01148                         break;
01149 
01150                 case 'R':
01151                         setup_entropy(mctx, isc_commandline_argument, ectx);
01152                         break;
01153 
01154                 default:
01155                         fprintf(stderr, "%s: unhandled option: %c\n",
01156                                 argv[0], isc_commandline_option);
01157                         exit(1);
01158                 }
01159         }
01160         if (keyfile != NULL && keystr != NULL) {
01161                 fprintf(stderr, "%s: cannot specify both -k and -y\n",
01162                         argv[0]);
01163                 exit(1);
01164         }
01165 
01166 #ifdef GSSAPI
01167         if (usegsstsig && (keyfile != NULL || keystr != NULL)) {
01168                 fprintf(stderr, "%s: cannot specify -g with -k or -y\n",
01169                         argv[0]);
01170                 exit(1);
01171         }
01172 #else
01173         if (usegsstsig) {
01174                 fprintf(stderr, "%s: cannot specify -g  or -o, " \
01175                         "program not linked with GSS API Library\n",
01176                         argv[0]);
01177                 exit(1);
01178         }
01179 #endif
01180 
01181         if (argv[isc_commandline_index] != NULL) {
01182                 if (strcmp(argv[isc_commandline_index], "-") == 0) {
01183                         input = stdin;
01184                 } else {
01185                         result = isc_stdio_open(argv[isc_commandline_index],
01186                                                 "r", &input);
01187                         if (result != ISC_R_SUCCESS) {
01188                                 fprintf(stderr, "could not open '%s': %s\n",
01189                                         argv[isc_commandline_index],
01190                                         isc_result_totext(result));
01191                                 exit(1);
01192                         }
01193                 }
01194                 interactive = ISC_FALSE;
01195         }
01196 }
01197 
01198 static isc_uint16_t
01199 parse_name(char **cmdlinep, dns_message_t *msg, dns_name_t **namep) {
01200         isc_result_t result;
01201         char *word;
01202         isc_buffer_t *namebuf = NULL;
01203         isc_buffer_t source;
01204 
01205         word = nsu_strsep(cmdlinep, " \t\r\n");
01206         if (word == NULL || *word == 0) {
01207                 fprintf(stderr, "could not read owner name\n");
01208                 return (STATUS_SYNTAX);
01209         }
01210 
01211         result = dns_message_gettempname(msg, namep);
01212         check_result(result, "dns_message_gettempname");
01213         result = isc_buffer_allocate(gmctx, &namebuf, DNS_NAME_MAXWIRE);
01214         check_result(result, "isc_buffer_allocate");
01215         dns_name_init(*namep, NULL);
01216         dns_name_setbuffer(*namep, namebuf);
01217         dns_message_takebuffer(msg, &namebuf);
01218         isc_buffer_init(&source, word, strlen(word));
01219         isc_buffer_add(&source, strlen(word));
01220         result = dns_name_fromtext(*namep, &source, dns_rootname, 0, NULL);
01221         check_result(result, "dns_name_fromtext");
01222         isc_buffer_invalidate(&source);
01223         return (STATUS_MORE);
01224 }
01225 
01226 static isc_uint16_t
01227 parse_rdata(char **cmdlinep, dns_rdataclass_t rdataclass,
01228             dns_rdatatype_t rdatatype, dns_message_t *msg,
01229             dns_rdata_t *rdata)
01230 {
01231         char *cmdline = *cmdlinep;
01232         isc_buffer_t source, *buf = NULL, *newbuf = NULL;
01233         isc_region_t r;
01234         isc_lex_t *lex = NULL;
01235         dns_rdatacallbacks_t callbacks;
01236         isc_result_t result;
01237 
01238         if (cmdline == NULL) {
01239                 rdata->flags = DNS_RDATA_UPDATE;
01240                 return (STATUS_MORE);
01241         }
01242 
01243         while (*cmdline != 0 && isspace((unsigned char)*cmdline))
01244                 cmdline++;
01245 
01246         if (*cmdline != 0) {
01247                 dns_rdatacallbacks_init(&callbacks);
01248                 result = isc_lex_create(gmctx, strlen(cmdline), &lex);
01249                 check_result(result, "isc_lex_create");
01250                 isc_buffer_init(&source, cmdline, strlen(cmdline));
01251                 isc_buffer_add(&source, strlen(cmdline));
01252                 result = isc_lex_openbuffer(lex, &source);
01253                 check_result(result, "isc_lex_openbuffer");
01254                 result = isc_buffer_allocate(gmctx, &buf, MAXWIRE);
01255                 check_result(result, "isc_buffer_allocate");
01256                 result = dns_rdata_fromtext(NULL, rdataclass, rdatatype, lex,
01257                                             dns_rootname, 0, gmctx, buf,
01258                                             &callbacks);
01259                 isc_lex_destroy(&lex);
01260                 if (result == ISC_R_SUCCESS) {
01261                         isc_buffer_usedregion(buf, &r);
01262                         result = isc_buffer_allocate(gmctx, &newbuf, r.length);
01263                         check_result(result, "isc_buffer_allocate");
01264                         isc_buffer_putmem(newbuf, r.base, r.length);
01265                         isc_buffer_usedregion(newbuf, &r);
01266                         dns_rdata_fromregion(rdata, rdataclass, rdatatype, &r);
01267                         isc_buffer_free(&buf);
01268                         dns_message_takebuffer(msg, &newbuf);
01269                 } else {
01270                         fprintf(stderr, "invalid rdata format: %s\n",
01271                                 isc_result_totext(result));
01272                         isc_buffer_free(&buf);
01273                         return (STATUS_SYNTAX);
01274                 }
01275         } else {
01276                 rdata->flags = DNS_RDATA_UPDATE;
01277         }
01278         *cmdlinep = cmdline;
01279         return (STATUS_MORE);
01280 }
01281 
01282 static isc_uint16_t
01283 make_prereq(char *cmdline, isc_boolean_t ispositive, isc_boolean_t isrrset) {
01284         isc_result_t result;
01285         char *word;
01286         dns_name_t *name = NULL;
01287         isc_textregion_t region;
01288         dns_rdataset_t *rdataset = NULL;
01289         dns_rdatalist_t *rdatalist = NULL;
01290         dns_rdataclass_t rdataclass;
01291         dns_rdatatype_t rdatatype;
01292         dns_rdata_t *rdata = NULL;
01293         isc_uint16_t retval;
01294 
01295         ddebug("make_prereq()");
01296 
01297         /*
01298          * Read the owner name
01299          */
01300         retval = parse_name(&cmdline, updatemsg, &name);
01301         if (retval != STATUS_MORE)
01302                 return (retval);
01303 
01304         /*
01305          * If this is an rrset prereq, read the class or type.
01306          */
01307         if (isrrset) {
01308                 word = nsu_strsep(&cmdline, " \t\r\n");
01309                 if (word == NULL || *word == 0) {
01310                         fprintf(stderr, "could not read class or type\n");
01311                         goto failure;
01312                 }
01313                 region.base = word;
01314                 region.length = strlen(word);
01315                 result = dns_rdataclass_fromtext(&rdataclass, &region);
01316                 if (result == ISC_R_SUCCESS) {
01317                         if (!setzoneclass(rdataclass)) {
01318                                 fprintf(stderr, "class mismatch: %s\n", word);
01319                                 goto failure;
01320                         }
01321                         /*
01322                          * Now read the type.
01323                          */
01324                         word = nsu_strsep(&cmdline, " \t\r\n");
01325                         if (word == NULL || *word == 0) {
01326                                 fprintf(stderr, "could not read type\n");
01327                                 goto failure;
01328                         }
01329                         region.base = word;
01330                         region.length = strlen(word);
01331                         result = dns_rdatatype_fromtext(&rdatatype, &region);
01332                         if (result != ISC_R_SUCCESS) {
01333                                 fprintf(stderr, "invalid type: %s\n", word);
01334                                 goto failure;
01335                         }
01336                 } else {
01337                         rdataclass = getzoneclass();
01338                         result = dns_rdatatype_fromtext(&rdatatype, &region);
01339                         if (result != ISC_R_SUCCESS) {
01340                                 fprintf(stderr, "invalid type: %s\n", word);
01341                                 goto failure;
01342                         }
01343                 }
01344         } else
01345                 rdatatype = dns_rdatatype_any;
01346 
01347         result = dns_message_gettemprdata(updatemsg, &rdata);
01348         check_result(result, "dns_message_gettemprdata");
01349 
01350         dns_rdata_init(rdata);
01351 
01352         if (isrrset && ispositive) {
01353                 retval = parse_rdata(&cmdline, rdataclass, rdatatype,
01354                                      updatemsg, rdata);
01355                 if (retval != STATUS_MORE)
01356                         goto failure;
01357         } else
01358                 rdata->flags = DNS_RDATA_UPDATE;
01359 
01360         result = dns_message_gettemprdatalist(updatemsg, &rdatalist);
01361         check_result(result, "dns_message_gettemprdatalist");
01362         result = dns_message_gettemprdataset(updatemsg, &rdataset);
01363         check_result(result, "dns_message_gettemprdataset");
01364         rdatalist->type = rdatatype;
01365         if (ispositive) {
01366                 if (isrrset && rdata->data != NULL)
01367                         rdatalist->rdclass = rdataclass;
01368                 else
01369                         rdatalist->rdclass = dns_rdataclass_any;
01370         } else
01371                 rdatalist->rdclass = dns_rdataclass_none;
01372         rdata->rdclass = rdatalist->rdclass;
01373         rdata->type = rdatatype;
01374         ISC_LIST_APPEND(rdatalist->rdata, rdata, link);
01375         dns_rdataset_init(rdataset);
01376         dns_rdatalist_tordataset(rdatalist, rdataset);
01377         ISC_LIST_INIT(name->list);
01378         ISC_LIST_APPEND(name->list, rdataset, link);
01379         dns_message_addname(updatemsg, name, DNS_SECTION_PREREQUISITE);
01380         return (STATUS_MORE);
01381 
01382  failure:
01383         if (name != NULL)
01384                 dns_message_puttempname(updatemsg, &name);
01385         return (STATUS_SYNTAX);
01386 }
01387 
01388 static isc_uint16_t
01389 evaluate_prereq(char *cmdline) {
01390         char *word;
01391         isc_boolean_t ispositive, isrrset;
01392 
01393         ddebug("evaluate_prereq()");
01394         word = nsu_strsep(&cmdline, " \t\r\n");
01395         if (word == NULL || *word == 0) {
01396                 fprintf(stderr, "could not read operation code\n");
01397                 return (STATUS_SYNTAX);
01398         }
01399         if (strcasecmp(word, "nxdomain") == 0) {
01400                 ispositive = ISC_FALSE;
01401                 isrrset = ISC_FALSE;
01402         } else if (strcasecmp(word, "yxdomain") == 0) {
01403                 ispositive = ISC_TRUE;
01404                 isrrset = ISC_FALSE;
01405         } else if (strcasecmp(word, "nxrrset") == 0) {
01406                 ispositive = ISC_FALSE;
01407                 isrrset = ISC_TRUE;
01408         } else if (strcasecmp(word, "yxrrset") == 0) {
01409                 ispositive = ISC_TRUE;
01410                 isrrset = ISC_TRUE;
01411         } else {
01412                 fprintf(stderr, "incorrect operation code: %s\n", word);
01413                 return (STATUS_SYNTAX);
01414         }
01415         return (make_prereq(cmdline, ispositive, isrrset));
01416 }
01417 
01418 static isc_uint16_t
01419 evaluate_server(char *cmdline) {
01420         char *word, *server;
01421         long port;
01422 
01423         if (local_only) {
01424                 fprintf(stderr, "cannot reset server in localhost-only mode\n");
01425                 return (STATUS_SYNTAX);
01426         }
01427 
01428         word = nsu_strsep(&cmdline, " \t\r\n");
01429         if (word == NULL || *word == 0) {
01430                 fprintf(stderr, "could not read server name\n");
01431                 return (STATUS_SYNTAX);
01432         }
01433         server = word;
01434 
01435         word = nsu_strsep(&cmdline, " \t\r\n");
01436         if (word == NULL || *word == 0)
01437                 port = dnsport;
01438         else {
01439                 char *endp;
01440                 port = strtol(word, &endp, 10);
01441                 if (*endp != 0) {
01442                         fprintf(stderr, "port '%s' is not numeric\n", word);
01443                         return (STATUS_SYNTAX);
01444                 } else if (port < 1 || port > 65535) {
01445                         fprintf(stderr, "port '%s' is out of range "
01446                                 "(1 to 65535)\n", word);
01447                         return (STATUS_SYNTAX);
01448                 }
01449         }
01450 
01451         if (servers != NULL) {
01452                 if (master_servers == servers)
01453                         master_servers = NULL;
01454                 isc_mem_put(gmctx, servers, ns_total * sizeof(isc_sockaddr_t));
01455         }
01456 
01457         default_servers = ISC_FALSE;
01458 
01459         ns_total = MAX_SERVERADDRS;
01460         ns_inuse = 0;
01461         servers = isc_mem_get(gmctx, ns_total * sizeof(isc_sockaddr_t));
01462         if (servers == NULL)
01463                 fatal("out of memory");
01464 
01465         memset(servers, 0, ns_total * sizeof(isc_sockaddr_t));
01466         get_addresses(server, (in_port_t)port, servers, ns_total);
01467 
01468         return (STATUS_MORE);
01469 }
01470 
01471 static isc_uint16_t
01472 evaluate_local(char *cmdline) {
01473         char *word, *local;
01474         long port;
01475         struct in_addr in4;
01476         struct in6_addr in6;
01477 
01478         word = nsu_strsep(&cmdline, " \t\r\n");
01479         if (word == NULL || *word == 0) {
01480                 fprintf(stderr, "could not read server name\n");
01481                 return (STATUS_SYNTAX);
01482         }
01483         local = word;
01484 
01485         word = nsu_strsep(&cmdline, " \t\r\n");
01486         if (word == NULL || *word == 0)
01487                 port = 0;
01488         else {
01489                 char *endp;
01490                 port = strtol(word, &endp, 10);
01491                 if (*endp != 0) {
01492                         fprintf(stderr, "port '%s' is not numeric\n", word);
01493                         return (STATUS_SYNTAX);
01494                 } else if (port < 1 || port > 65535) {
01495                         fprintf(stderr, "port '%s' is out of range "
01496                                 "(1 to 65535)\n", word);
01497                         return (STATUS_SYNTAX);
01498                 }
01499         }
01500 
01501         if (have_ipv6 && inet_pton(AF_INET6, local, &in6) == 1) {
01502                 if (localaddr6 == NULL)
01503                         localaddr6 = isc_mem_get(gmctx, sizeof(isc_sockaddr_t));
01504                 if (localaddr6 == NULL)
01505                         fatal("out of memory");
01506                 isc_sockaddr_fromin6(localaddr6, &in6, (in_port_t)port);
01507         } else if (have_ipv4 && inet_pton(AF_INET, local, &in4) == 1) {
01508                 if (localaddr4 == NULL)
01509                         localaddr4 = isc_mem_get(gmctx, sizeof(isc_sockaddr_t));
01510                 if (localaddr4 == NULL)
01511                         fatal("out of memory");
01512                 isc_sockaddr_fromin(localaddr4, &in4, (in_port_t)port);
01513         } else {
01514                 fprintf(stderr, "invalid address %s", local);
01515                 return (STATUS_SYNTAX);
01516         }
01517 
01518         return (STATUS_MORE);
01519 }
01520 
01521 static isc_uint16_t
01522 evaluate_key(char *cmdline) {
01523         char *namestr;
01524         char *secretstr;
01525         isc_buffer_t b;
01526         isc_result_t result;
01527         dns_fixedname_t fkeyname;
01528         dns_name_t *mykeyname;
01529         int secretlen;
01530         unsigned char *secret = NULL;
01531         isc_buffer_t secretbuf;
01532         dns_name_t *hmacname = NULL;
01533         isc_uint16_t digestbits = 0;
01534         char *n;
01535 
01536         namestr = nsu_strsep(&cmdline, " \t\r\n");
01537         if (namestr == NULL || *namestr == 0) {
01538                 fprintf(stderr, "could not read key name\n");
01539                 return (STATUS_SYNTAX);
01540         }
01541 
01542         dns_fixedname_init(&fkeyname);
01543         mykeyname = dns_fixedname_name(&fkeyname);
01544 
01545         n = strchr(namestr, ':');
01546         if (n != NULL) {
01547                 digestbits = parse_hmac(&hmacname, namestr, n - namestr);
01548                 namestr = n + 1;
01549         } else
01550                 hmacname = DNS_TSIG_HMACMD5_NAME;
01551 
01552         isc_buffer_init(&b, namestr, strlen(namestr));
01553         isc_buffer_add(&b, strlen(namestr));
01554         result = dns_name_fromtext(mykeyname, &b, dns_rootname, 0, NULL);
01555         if (result != ISC_R_SUCCESS) {
01556                 fprintf(stderr, "could not parse key name\n");
01557                 return (STATUS_SYNTAX);
01558         }
01559 
01560         secretstr = nsu_strsep(&cmdline, "\r\n");
01561         if (secretstr == NULL || *secretstr == 0) {
01562                 fprintf(stderr, "could not read key secret\n");
01563                 return (STATUS_SYNTAX);
01564         }
01565         secretlen = strlen(secretstr) * 3 / 4;
01566         secret = isc_mem_allocate(gmctx, secretlen);
01567         if (secret == NULL)
01568                 fatal("out of memory");
01569 
01570         isc_buffer_init(&secretbuf, secret, secretlen);
01571         result = isc_base64_decodestring(secretstr, &secretbuf);
01572         if (result != ISC_R_SUCCESS) {
01573                 fprintf(stderr, "could not create key from %s: %s\n",
01574                         secretstr, isc_result_totext(result));
01575                 isc_mem_free(gmctx, secret);
01576                 return (STATUS_SYNTAX);
01577         }
01578         secretlen = isc_buffer_usedlength(&secretbuf);
01579 
01580         if (tsigkey != NULL)
01581                 dns_tsigkey_detach(&tsigkey);
01582         result = dns_tsigkey_create(mykeyname, hmacname, secret, secretlen,
01583                                     ISC_FALSE, NULL, 0, 0, gmctx, NULL,
01584                                     &tsigkey);
01585         isc_mem_free(gmctx, secret);
01586         if (result != ISC_R_SUCCESS) {
01587                 fprintf(stderr, "could not create key from %s %s: %s\n",
01588                         namestr, secretstr, dns_result_totext(result));
01589                 return (STATUS_SYNTAX);
01590         }
01591         dst_key_setbits(tsigkey->key, digestbits);
01592         return (STATUS_MORE);
01593 }
01594 
01595 static isc_uint16_t
01596 evaluate_zone(char *cmdline) {
01597         char *word;
01598         isc_buffer_t b;
01599         isc_result_t result;
01600 
01601         word = nsu_strsep(&cmdline, " \t\r\n");
01602         if (word == NULL || *word == 0) {
01603                 fprintf(stderr, "could not read zone name\n");
01604                 return (STATUS_SYNTAX);
01605         }
01606 
01607         dns_fixedname_init(&fuserzone);
01608         userzone = dns_fixedname_name(&fuserzone);
01609         isc_buffer_init(&b, word, strlen(word));
01610         isc_buffer_add(&b, strlen(word));
01611         result = dns_name_fromtext(userzone, &b, dns_rootname, 0, NULL);
01612         if (result != ISC_R_SUCCESS) {
01613                 userzone = NULL; /* Lest it point to an invalid name */
01614                 fprintf(stderr, "could not parse zone name\n");
01615                 return (STATUS_SYNTAX);
01616         }
01617 
01618         return (STATUS_MORE);
01619 }
01620 
01621 static isc_uint16_t
01622 evaluate_realm(char *cmdline) {
01623 #ifdef GSSAPI
01624         char *word;
01625         char buf[1024];
01626         int n;
01627 
01628         if (realm != NULL) {
01629                 isc_mem_free(gmctx, realm);
01630                 realm = NULL;
01631         }
01632 
01633         word = nsu_strsep(&cmdline, " \t\r\n");
01634         if (word == NULL || *word == 0)
01635                 return (STATUS_MORE);
01636 
01637         n = snprintf(buf, sizeof(buf), "@%s", word);
01638         if (n < 0 || (size_t)n >= sizeof(buf))
01639                 fatal("realm is too long");
01640         realm = isc_mem_strdup(gmctx, buf);
01641         if (realm == NULL)
01642                 fatal("out of memory");
01643         return (STATUS_MORE);
01644 #else
01645         UNUSED(cmdline);
01646         return (STATUS_SYNTAX);
01647 #endif
01648 }
01649 
01650 static isc_uint16_t
01651 evaluate_ttl(char *cmdline) {
01652         char *word;
01653         isc_result_t result;
01654         isc_uint32_t ttl;
01655 
01656         word = nsu_strsep(&cmdline, " \t\r\n");
01657         if (word == NULL || *word == 0) {
01658                 fprintf(stderr, "could not ttl\n");
01659                 return (STATUS_SYNTAX);
01660         }
01661 
01662         if (!strcasecmp(word, "none")) {
01663                 default_ttl = 0;
01664                 default_ttl_set = ISC_FALSE;
01665                 return (STATUS_MORE);
01666         }
01667 
01668         result = isc_parse_uint32(&ttl, word, 10);
01669         if (result != ISC_R_SUCCESS)
01670                 return (STATUS_SYNTAX);
01671 
01672         if (ttl > TTL_MAX) {
01673                 fprintf(stderr, "ttl '%s' is out of range (0 to %u)\n",
01674                         word, TTL_MAX);
01675                 return (STATUS_SYNTAX);
01676         }
01677         default_ttl = ttl;
01678         default_ttl_set = ISC_TRUE;
01679 
01680         return (STATUS_MORE);
01681 }
01682 
01683 static isc_uint16_t
01684 evaluate_class(char *cmdline) {
01685         char *word;
01686         isc_textregion_t r;
01687         isc_result_t result;
01688         dns_rdataclass_t rdclass;
01689 
01690         word = nsu_strsep(&cmdline, " \t\r\n");
01691         if (word == NULL || *word == 0) {
01692                 fprintf(stderr, "could not read class name\n");
01693                 return (STATUS_SYNTAX);
01694         }
01695 
01696         r.base = word;
01697         r.length = strlen(word);
01698         result = dns_rdataclass_fromtext(&rdclass, &r);
01699         if (result != ISC_R_SUCCESS) {
01700                 fprintf(stderr, "could not parse class name: %s\n", word);
01701                 return (STATUS_SYNTAX);
01702         }
01703         switch (rdclass) {
01704         case dns_rdataclass_none:
01705         case dns_rdataclass_any:
01706         case dns_rdataclass_reserved0:
01707                 fprintf(stderr, "bad default class: %s\n", word);
01708                 return (STATUS_SYNTAX);
01709         default:
01710                 defaultclass = rdclass;
01711         }
01712 
01713         return (STATUS_MORE);
01714 }
01715 
01716 static isc_uint16_t
01717 update_addordelete(char *cmdline, isc_boolean_t isdelete) {
01718         isc_result_t result;
01719         dns_name_t *name = NULL;
01720         isc_uint32_t ttl;
01721         char *word;
01722         dns_rdataclass_t rdataclass;
01723         dns_rdatatype_t rdatatype;
01724         dns_rdata_t *rdata = NULL;
01725         dns_rdatalist_t *rdatalist = NULL;
01726         dns_rdataset_t *rdataset = NULL;
01727         isc_textregion_t region;
01728         isc_uint16_t retval;
01729 
01730         ddebug("update_addordelete()");
01731 
01732         /*
01733          * Read the owner name.
01734          */
01735         retval = parse_name(&cmdline, updatemsg, &name);
01736         if (retval != STATUS_MORE)
01737                 return (retval);
01738 
01739         result = dns_message_gettemprdata(updatemsg, &rdata);
01740         check_result(result, "dns_message_gettemprdata");
01741 
01742         dns_rdata_init(rdata);
01743 
01744         /*
01745          * If this is an add, read the TTL and verify that it's in range.
01746          * If it's a delete, ignore a TTL if present (for compatibility).
01747          */
01748         word = nsu_strsep(&cmdline, " \t\r\n");
01749         if (word == NULL || *word == 0) {
01750                 if (!isdelete) {
01751                         fprintf(stderr, "could not read owner ttl\n");
01752                         goto failure;
01753                 }
01754                 else {
01755                         ttl = 0;
01756                         rdataclass = dns_rdataclass_any;
01757                         rdatatype = dns_rdatatype_any;
01758                         rdata->flags = DNS_RDATA_UPDATE;
01759                         goto doneparsing;
01760                 }
01761         }
01762         result = isc_parse_uint32(&ttl, word, 10);
01763         if (result != ISC_R_SUCCESS) {
01764                 if (isdelete) {
01765                         ttl = 0;
01766                         goto parseclass;
01767                 } else if (default_ttl_set) {
01768                         ttl = default_ttl;
01769                         goto parseclass;
01770                 } else {
01771                         fprintf(stderr, "ttl '%s': %s\n", word,
01772                                 isc_result_totext(result));
01773                         goto failure;
01774                 }
01775         }
01776 
01777         if (isdelete)
01778                 ttl = 0;
01779         else if (ttl > TTL_MAX) {
01780                 fprintf(stderr, "ttl '%s' is out of range (0 to %u)\n",
01781                         word, TTL_MAX);
01782                 goto failure;
01783         }
01784 
01785         /*
01786          * Read the class or type.
01787          */
01788         word = nsu_strsep(&cmdline, " \t\r\n");
01789  parseclass:
01790         if (word == NULL || *word == 0) {
01791                 if (isdelete) {
01792                         rdataclass = dns_rdataclass_any;
01793                         rdatatype = dns_rdatatype_any;
01794                         rdata->flags = DNS_RDATA_UPDATE;
01795                         goto doneparsing;
01796                 } else {
01797                         fprintf(stderr, "could not read class or type\n");
01798                         goto failure;
01799                 }
01800         }
01801         region.base = word;
01802         region.length = strlen(word);
01803         rdataclass = dns_rdataclass_any;
01804         result = dns_rdataclass_fromtext(&rdataclass, &region);
01805         if (result == ISC_R_SUCCESS && rdataclass != dns_rdataclass_any) {
01806                 if (!setzoneclass(rdataclass)) {
01807                         fprintf(stderr, "class mismatch: %s\n", word);
01808                         goto failure;
01809                 }
01810                 /*
01811                  * Now read the type.
01812                  */
01813                 word = nsu_strsep(&cmdline, " \t\r\n");
01814                 if (word == NULL || *word == 0) {
01815                         if (isdelete) {
01816                                 rdataclass = dns_rdataclass_any;
01817                                 rdatatype = dns_rdatatype_any;
01818                                 rdata->flags = DNS_RDATA_UPDATE;
01819                                 goto doneparsing;
01820                         } else {
01821                                 fprintf(stderr, "could not read type\n");
01822                                 goto failure;
01823                         }
01824                 }
01825                 region.base = word;
01826                 region.length = strlen(word);
01827                 result = dns_rdatatype_fromtext(&rdatatype, &region);
01828                 if (result != ISC_R_SUCCESS) {
01829                         fprintf(stderr, "'%s' is not a valid type: %s\n",
01830                                 word, isc_result_totext(result));
01831                         goto failure;
01832                 }
01833         } else {
01834                 rdataclass = getzoneclass();
01835                 result = dns_rdatatype_fromtext(&rdatatype, &region);
01836                 if (result != ISC_R_SUCCESS) {
01837                         fprintf(stderr, "'%s' is not a valid class or type: "
01838                                 "%s\n", word, isc_result_totext(result));
01839                         goto failure;
01840                 }
01841         }
01842 
01843         retval = parse_rdata(&cmdline, rdataclass, rdatatype, updatemsg,
01844                              rdata);
01845         if (retval != STATUS_MORE)
01846                 goto failure;
01847 
01848         if (isdelete) {
01849                 if ((rdata->flags & DNS_RDATA_UPDATE) != 0)
01850                         rdataclass = dns_rdataclass_any;
01851                 else
01852                         rdataclass = dns_rdataclass_none;
01853         } else {
01854                 if ((rdata->flags & DNS_RDATA_UPDATE) != 0) {
01855                         fprintf(stderr, "could not read rdata\n");
01856                         goto failure;
01857                 }
01858         }
01859 
01860         if (!isdelete && checknames) {
01861                 dns_fixedname_t fixed;
01862                 dns_name_t *bad;
01863 
01864                 if (!dns_rdata_checkowner(name, rdata->rdclass, rdata->type,
01865                                           ISC_TRUE))
01866                 {
01867                         char namebuf[DNS_NAME_FORMATSIZE];
01868 
01869                         dns_name_format(name, namebuf, sizeof(namebuf));
01870                         fprintf(stderr, "check-names failed: bad owner '%s'\n",
01871                                 namebuf);
01872                         goto failure;
01873                 }
01874 
01875                 dns_fixedname_init(&fixed);
01876                 bad = dns_fixedname_name(&fixed);
01877                 if (!dns_rdata_checknames(rdata, name, bad)) {
01878                         char namebuf[DNS_NAME_FORMATSIZE];
01879 
01880                         dns_name_format(bad, namebuf, sizeof(namebuf));
01881                         fprintf(stderr, "check-names failed: bad name '%s'\n",
01882                                 namebuf);
01883                         goto failure;
01884                 }
01885         }
01886 
01887  doneparsing:
01888 
01889         result = dns_message_gettemprdatalist(updatemsg, &rdatalist);
01890         check_result(result, "dns_message_gettemprdatalist");
01891         result = dns_message_gettemprdataset(updatemsg, &rdataset);
01892         check_result(result, "dns_message_gettemprdataset");
01893         rdatalist->type = rdatatype;
01894         rdatalist->rdclass = rdataclass;
01895         rdatalist->covers = rdatatype;
01896         rdatalist->ttl = (dns_ttl_t)ttl;
01897         ISC_LIST_APPEND(rdatalist->rdata, rdata, link);
01898         dns_rdataset_init(rdataset);
01899         dns_rdatalist_tordataset(rdatalist, rdataset);
01900         ISC_LIST_INIT(name->list);
01901         ISC_LIST_APPEND(name->list, rdataset, link);
01902         dns_message_addname(updatemsg, name, DNS_SECTION_UPDATE);
01903         return (STATUS_MORE);
01904 
01905  failure:
01906         if (name != NULL)
01907                 dns_message_puttempname(updatemsg, &name);
01908         dns_message_puttemprdata(updatemsg, &rdata);
01909         return (STATUS_SYNTAX);
01910 }
01911 
01912 static isc_uint16_t
01913 evaluate_update(char *cmdline) {
01914         char *word;
01915         isc_boolean_t isdelete;
01916 
01917         ddebug("evaluate_update()");
01918         word = nsu_strsep(&cmdline, " \t\r\n");
01919         if (word == NULL || *word == 0) {
01920                 fprintf(stderr, "could not read operation code\n");
01921                 return (STATUS_SYNTAX);
01922         }
01923         if (strcasecmp(word, "delete") == 0)
01924                 isdelete = ISC_TRUE;
01925         else if (strcasecmp(word, "del") == 0)
01926                 isdelete = ISC_TRUE;
01927         else if (strcasecmp(word, "add") == 0)
01928                 isdelete = ISC_FALSE;
01929         else {
01930                 fprintf(stderr, "incorrect operation code: %s\n", word);
01931                 return (STATUS_SYNTAX);
01932         }
01933         return (update_addordelete(cmdline, isdelete));
01934 }
01935 
01936 static isc_uint16_t
01937 evaluate_checknames(char *cmdline) {
01938         char *word;
01939 
01940         ddebug("evaluate_checknames()");
01941         word = nsu_strsep(&cmdline, " \t\r\n");
01942         if (word == NULL || *word == 0) {
01943                 fprintf(stderr, "could not read check-names directive\n");
01944                 return (STATUS_SYNTAX);
01945         }
01946         if (strcasecmp(word, "yes") == 0 ||
01947             strcasecmp(word, "true") == 0 ||
01948             strcasecmp(word, "on") == 0) {
01949                 checknames = ISC_TRUE;
01950         } else if (strcasecmp(word, "no") == 0 ||
01951                  strcasecmp(word, "false") == 0 ||
01952                  strcasecmp(word, "off") == 0) {
01953                 checknames = ISC_FALSE;
01954         } else {
01955                 fprintf(stderr, "incorrect check-names directive: %s\n", word);
01956                 return (STATUS_SYNTAX);
01957         }
01958         return (STATUS_MORE);
01959 }
01960 
01961 static void
01962 setzone(dns_name_t *zonename) {
01963         isc_result_t result;
01964         dns_name_t *name = NULL;
01965         dns_rdataset_t *rdataset = NULL;
01966 
01967         result = dns_message_firstname(updatemsg, DNS_SECTION_ZONE);
01968         if (result == ISC_R_SUCCESS) {
01969                 dns_message_currentname(updatemsg, DNS_SECTION_ZONE, &name);
01970                 dns_message_removename(updatemsg, name, DNS_SECTION_ZONE);
01971                 for (rdataset = ISC_LIST_HEAD(name->list);
01972                      rdataset != NULL;
01973                      rdataset = ISC_LIST_HEAD(name->list)) {
01974                         ISC_LIST_UNLINK(name->list, rdataset, link);
01975                         dns_rdataset_disassociate(rdataset);
01976                         dns_message_puttemprdataset(updatemsg, &rdataset);
01977                 }
01978                 dns_message_puttempname(updatemsg, &name);
01979         }
01980 
01981         if (zonename != NULL) {
01982                 result = dns_message_gettempname(updatemsg, &name);
01983                 check_result(result, "dns_message_gettempname");
01984                 dns_name_init(name, NULL);
01985                 dns_name_clone(zonename, name);
01986                 result = dns_message_gettemprdataset(updatemsg, &rdataset);
01987                 check_result(result, "dns_message_gettemprdataset");
01988                 dns_rdataset_makequestion(rdataset, getzoneclass(),
01989                                           dns_rdatatype_soa);
01990                 ISC_LIST_INIT(name->list);
01991                 ISC_LIST_APPEND(name->list, rdataset, link);
01992                 dns_message_addname(updatemsg, name, DNS_SECTION_ZONE);
01993         }
01994 }
01995 
01996 static void
01997 show_message(FILE *stream, dns_message_t *msg, const char *description) {
01998         isc_result_t result;
01999         isc_buffer_t *buf = NULL;
02000         int bufsz;
02001 
02002         ddebug("show_message()");
02003 
02004         setzone(userzone);
02005 
02006         bufsz = INITTEXT;
02007         do {
02008                 if (bufsz > MAXTEXT) {
02009                         fprintf(stderr, "could not allocate large enough "
02010                                 "buffer to display message\n");
02011                         exit(1);
02012                 }
02013                 if (buf != NULL)
02014                         isc_buffer_free(&buf);
02015                 result = isc_buffer_allocate(gmctx, &buf, bufsz);
02016                 check_result(result, "isc_buffer_allocate");
02017                 result = dns_message_totext(msg, style, 0, buf);
02018                 bufsz *= 2;
02019         } while (result == ISC_R_NOSPACE);
02020         if (result != ISC_R_SUCCESS) {
02021                 fprintf(stderr, "could not convert message to text format.\n");
02022                 isc_buffer_free(&buf);
02023                 return;
02024         }
02025         fprintf(stream, "%s\n%.*s", description,
02026                (int)isc_buffer_usedlength(buf), (char*)isc_buffer_base(buf));
02027         isc_buffer_free(&buf);
02028 }
02029 
02030 static isc_uint16_t
02031 do_next_command(char *cmdline) {
02032         char *word;
02033 
02034         ddebug("do_next_command()");
02035         word = nsu_strsep(&cmdline, " \t\r\n");
02036 
02037         if (word == NULL || *word == 0)
02038                 return (STATUS_SEND);
02039         if (word[0] == ';')
02040                 return (STATUS_MORE);
02041         if (strcasecmp(word, "quit") == 0)
02042                 return (STATUS_QUIT);
02043         if (strcasecmp(word, "prereq") == 0)
02044                 return (evaluate_prereq(cmdline));
02045         if (strcasecmp(word, "nxdomain") == 0)
02046                 return (make_prereq(cmdline, ISC_FALSE, ISC_FALSE));
02047         if (strcasecmp(word, "yxdomain") == 0)
02048                 return (make_prereq(cmdline, ISC_TRUE, ISC_FALSE));
02049         if (strcasecmp(word, "nxrrset") == 0)
02050                 return (make_prereq(cmdline, ISC_FALSE, ISC_TRUE));
02051         if (strcasecmp(word, "yxrrset") == 0)
02052                 return (make_prereq(cmdline, ISC_TRUE, ISC_TRUE));
02053         if (strcasecmp(word, "update") == 0)
02054                 return (evaluate_update(cmdline));
02055         if (strcasecmp(word, "delete") == 0)
02056                 return (update_addordelete(cmdline, ISC_TRUE));
02057         if (strcasecmp(word, "del") == 0)
02058                 return (update_addordelete(cmdline, ISC_TRUE));
02059         if (strcasecmp(word, "add") == 0)
02060                 return (update_addordelete(cmdline, ISC_FALSE));
02061         if (strcasecmp(word, "server") == 0)
02062                 return (evaluate_server(cmdline));
02063         if (strcasecmp(word, "local") == 0)
02064                 return (evaluate_local(cmdline));
02065         if (strcasecmp(word, "zone") == 0)
02066                 return (evaluate_zone(cmdline));
02067         if (strcasecmp(word, "class") == 0)
02068                 return (evaluate_class(cmdline));
02069         if (strcasecmp(word, "send") == 0)
02070                 return (STATUS_SEND);
02071         if (strcasecmp(word, "debug") == 0) {
02072                 if (debugging)
02073                         ddebugging = ISC_TRUE;
02074                 else
02075                         debugging = ISC_TRUE;
02076                 return (STATUS_MORE);
02077         }
02078         if (strcasecmp(word, "ttl") == 0)
02079                 return (evaluate_ttl(cmdline));
02080         if (strcasecmp(word, "show") == 0) {
02081                 show_message(stdout, updatemsg, "Outgoing update query:");
02082                 return (STATUS_MORE);
02083         }
02084         if (strcasecmp(word, "answer") == 0) {
02085                 if (answer != NULL)
02086                         show_message(stdout, answer, "Answer:");
02087                 return (STATUS_MORE);
02088         }
02089         if (strcasecmp(word, "key") == 0) {
02090                 usegsstsig = ISC_FALSE;
02091                 return (evaluate_key(cmdline));
02092         }
02093         if (strcasecmp(word, "realm") == 0)
02094                 return (evaluate_realm(cmdline));
02095         if (strcasecmp(word, "check-names") == 0 ||
02096             strcasecmp(word, "checknames") == 0)
02097                 return (evaluate_checknames(cmdline));
02098         if (strcasecmp(word, "gsstsig") == 0) {
02099 #ifdef GSSAPI
02100                 usegsstsig = ISC_TRUE;
02101                 use_win2k_gsstsig = ISC_FALSE;
02102 #else
02103                 fprintf(stderr, "gsstsig not supported\n");
02104 #endif
02105                 return (STATUS_MORE);
02106         }
02107         if (strcasecmp(word, "oldgsstsig") == 0) {
02108 #ifdef GSSAPI
02109                 usegsstsig = ISC_TRUE;
02110                 use_win2k_gsstsig = ISC_TRUE;
02111 #else
02112                 fprintf(stderr, "gsstsig not supported\n");
02113 #endif
02114                 return (STATUS_MORE);
02115         }
02116         if (strcasecmp(word, "help") == 0) {
02117                 fprintf(stdout,
02118 "nsupdate " VERSION ":\n"
02119 "local address [port]      (set local resolver)\n"
02120 "server address [port]     (set master server for zone)\n"
02121 "send                      (send the update request)\n"
02122 "show                      (show the update request)\n"
02123 "answer                    (show the answer to the last request)\n"
02124 "quit                      (quit, any pending update is not sent\n"
02125 "help                      (display this message_\n"
02126 "key [hmac:]keyname secret (use TSIG to sign the request)\n"
02127 "gsstsig                   (use GSS_TSIG to sign the request)\n"
02128 "oldgsstsig                (use Microsoft's GSS_TSIG to sign the request)\n"
02129 "zone name                 (set the zone to be updated)\n"
02130 "class CLASS               (set the zone's DNS class, e.g. IN (default), CH)\n"
02131 "check-names { on | off }  (enable / disable check-names)\n"
02132 "[prereq] nxdomain name    (does this name not exist)\n"
02133 "[prereq] yxdomain name    (does this name exist)\n"
02134 "[prereq] nxrrset ....     (does this RRset exist)\n"
02135 "[prereq] yxrrset ....     (does this RRset not exist)\n"
02136 "[update] add ....         (add the given record to the zone)\n"
02137 "[update] del[ete] ....    (remove the given record(s) from the zone)\n");
02138                 return (STATUS_MORE);
02139         }
02140         if (strcasecmp(word, "version") == 0) {
02141                 fprintf(stdout, "nsupdate " VERSION "\n");
02142                 return (STATUS_MORE);
02143         }
02144         fprintf(stderr, "incorrect section name: %s\n", word);
02145         return (STATUS_SYNTAX);
02146 }
02147 
02148 static isc_uint16_t
02149 get_next_command(void) {
02150         isc_uint16_t result = STATUS_QUIT;
02151         char cmdlinebuf[MAXCMD];
02152         char *cmdline;
02153 
02154         isc_app_block();
02155         if (interactive) {
02156 #ifdef HAVE_READLINE
02157                 cmdline = readline("> ");
02158                 if (cmdline != NULL)
02159                         add_history(cmdline);
02160 #else
02161                 fprintf(stdout, "> ");
02162                 fflush(stdout);
02163                 cmdline = fgets(cmdlinebuf, MAXCMD, input);
02164 #endif
02165         } else
02166                 cmdline = fgets(cmdlinebuf, MAXCMD, input);
02167         isc_app_unblock();
02168 
02169         if (cmdline != NULL) {
02170                 char *tmp = cmdline;
02171 
02172                 /*
02173                  * Normalize input by removing any eol as readline()
02174                  * removes eol but fgets doesn't.
02175                  */
02176                 (void)nsu_strsep(&tmp, "\r\n");
02177                 result = do_next_command(cmdline);
02178         }
02179 #ifdef HAVE_READLINE
02180         if (interactive)
02181                 free(cmdline);
02182 #endif
02183         return (result);
02184 }
02185 
02186 static isc_boolean_t
02187 user_interaction(void) {
02188         isc_uint16_t result = STATUS_MORE;
02189 
02190         ddebug("user_interaction()");
02191         while ((result == STATUS_MORE) || (result == STATUS_SYNTAX)) {
02192                 result = get_next_command();
02193                 if (!interactive && result == STATUS_SYNTAX)
02194                         fatal("syntax error");
02195         }
02196         if (result == STATUS_SEND)
02197                 return (ISC_TRUE);
02198         return (ISC_FALSE);
02199 
02200 }
02201 
02202 static void
02203 done_update(void) {
02204         isc_event_t *event = global_event;
02205         ddebug("done_update()");
02206         isc_task_send(global_task, &event);
02207 }
02208 
02209 static void
02210 check_tsig_error(dns_rdataset_t *rdataset, isc_buffer_t *b) {
02211         isc_result_t result;
02212         dns_rdata_t rdata = DNS_RDATA_INIT;
02213         dns_rdata_any_tsig_t tsig;
02214 
02215         result = dns_rdataset_first(rdataset);
02216         check_result(result, "dns_rdataset_first");
02217         dns_rdataset_current(rdataset, &rdata);
02218         result = dns_rdata_tostruct(&rdata, &tsig, NULL);
02219         check_result(result, "dns_rdata_tostruct");
02220         if (tsig.error != 0) {
02221                 if (isc_buffer_remaininglength(b) < 1)
02222                       check_result(ISC_R_NOSPACE, "isc_buffer_remaininglength");
02223                 isc_buffer_putstr(b, "(" /*)*/);
02224                 result = dns_tsigrcode_totext(tsig.error, b);
02225                 check_result(result, "dns_tsigrcode_totext");
02226                 if (isc_buffer_remaininglength(b) < 1)
02227                       check_result(ISC_R_NOSPACE, "isc_buffer_remaininglength");
02228                 isc_buffer_putstr(b,  /*(*/ ")");
02229         }
02230 }
02231 
02232 static isc_boolean_t
02233 next_master(const char *caller, isc_sockaddr_t *addr, isc_result_t eresult) {
02234         char addrbuf[ISC_SOCKADDR_FORMATSIZE];
02235 
02236         isc_sockaddr_format(addr, addrbuf, sizeof(addrbuf));
02237         fprintf(stderr, "; Communication with %s failed: %s\n",
02238                 addrbuf, isc_result_totext(eresult));
02239         if (++master_inuse >= master_total)
02240                 return (ISC_FALSE);
02241         ddebug("%s: trying next server", caller);
02242         return (ISC_TRUE);
02243 }
02244 
02245 static void
02246 update_completed(isc_task_t *task, isc_event_t *event) {
02247         dns_requestevent_t *reqev = NULL;
02248         isc_result_t result;
02249         dns_request_t *request;
02250 
02251         UNUSED(task);
02252 
02253         ddebug("update_completed()");
02254 
02255         requests--;
02256 
02257         REQUIRE(event->ev_type == DNS_EVENT_REQUESTDONE);
02258         reqev = (dns_requestevent_t *)event;
02259         request = reqev->request;
02260 
02261         if (shuttingdown) {
02262                 dns_request_destroy(&request);
02263                 isc_event_free(&event);
02264                 maybeshutdown();
02265                 return;
02266         }
02267 
02268         if (reqev->result != ISC_R_SUCCESS) {
02269                 if (!next_master("recvsoa", &master_servers[master_inuse],
02270                                  reqev->result)) {
02271                         seenerror = ISC_TRUE;
02272                         goto done;
02273                 }
02274 
02275                 ddebug("Destroying request [%p]", request);
02276                 dns_request_destroy(&request);
02277                 dns_message_renderreset(updatemsg);
02278                 dns_message_settsigkey(updatemsg, NULL);
02279                 /* XXX MPA fix zonename is freed already */
02280                 send_update(zname, &master_servers[master_inuse]);
02281                 isc_event_free(&event);
02282                 return;
02283         }
02284 
02285         result = dns_message_create(gmctx, DNS_MESSAGE_INTENTPARSE, &answer);
02286         check_result(result, "dns_message_create");
02287         result = dns_request_getresponse(request, answer,
02288                                          DNS_MESSAGEPARSE_PRESERVEORDER);
02289         switch (result) {
02290         case ISC_R_SUCCESS:
02291                 if (answer->verify_attempted)
02292                         ddebug("tsig verification successful");
02293                 break;
02294         case DNS_R_CLOCKSKEW:
02295         case DNS_R_EXPECTEDTSIG:
02296         case DNS_R_TSIGERRORSET:
02297         case DNS_R_TSIGVERIFYFAILURE:
02298         case DNS_R_UNEXPECTEDTSIG:
02299         case ISC_R_FAILURE:
02300 #if 0
02301                 if (usegsstsig && answer->rcode == dns_rcode_noerror) {
02302                         /*
02303                          * For MS DNS that violates RFC 2845, section 4.2
02304                          */
02305                         break;
02306                 }
02307 #endif
02308                 fprintf(stderr, "; TSIG error with server: %s\n",
02309                         isc_result_totext(result));
02310                 seenerror = ISC_TRUE;
02311                 break;
02312         default:
02313                 check_result(result, "dns_request_getresponse");
02314         }
02315 
02316         if (answer->rcode != dns_rcode_noerror) {
02317                 seenerror = ISC_TRUE;
02318                 if (!debugging) {
02319                         char buf[64];
02320                         isc_buffer_t b;
02321                         dns_rdataset_t *rds;
02322 
02323                         isc_buffer_init(&b, buf, sizeof(buf) - 1);
02324                         result = dns_rcode_totext(answer->rcode, &b);
02325                         check_result(result, "dns_rcode_totext");
02326                         rds = dns_message_gettsig(answer, NULL);
02327                         if (rds != NULL)
02328                                 check_tsig_error(rds, &b);
02329                         fprintf(stderr, "update failed: %.*s\n",
02330                                 (int)isc_buffer_usedlength(&b), buf);
02331                 }
02332         }
02333         if (debugging)
02334                 show_message(stderr, answer, "\nReply from update query:");
02335 
02336  done:
02337         dns_request_destroy(&request);
02338         if (usegsstsig) {
02339                 dns_name_free(&tmpzonename, gmctx);
02340                 dns_name_free(&restart_master, gmctx);
02341         }
02342         isc_event_free(&event);
02343         done_update();
02344 }
02345 
02346 static void
02347 send_update(dns_name_t *zone, isc_sockaddr_t *master) {
02348         isc_result_t result;
02349         dns_request_t *request = NULL;
02350         unsigned int options = DNS_REQUESTOPT_CASE;
02351         isc_sockaddr_t *srcaddr;
02352 
02353         ddebug("send_update()");
02354 
02355         setzone(zone);
02356 
02357         if (usevc)
02358                 options |= DNS_REQUESTOPT_TCP;
02359         if (tsigkey == NULL && sig0key != NULL) {
02360                 result = dns_message_setsig0key(updatemsg, sig0key);
02361                 check_result(result, "dns_message_setsig0key");
02362         }
02363         if (debugging) {
02364                 char addrbuf[ISC_SOCKADDR_FORMATSIZE];
02365 
02366                 isc_sockaddr_format(master, addrbuf, sizeof(addrbuf));
02367                 fprintf(stderr, "Sending update to %s\n", addrbuf);
02368         }
02369 
02370         if (isc_sockaddr_pf(master) == AF_INET6)
02371                 srcaddr = localaddr6;
02372         else
02373                 srcaddr = localaddr4;
02374 
02375         /* Windows doesn't like the tsig name to be compressed. */
02376         if (updatemsg->tsigname)
02377                 updatemsg->tsigname->attributes |= DNS_NAMEATTR_NOCOMPRESS;
02378 
02379         result = dns_request_createvia3(requestmgr, updatemsg, srcaddr,
02380                                         master, options, tsigkey, timeout,
02381                                         udp_timeout, udp_retries, global_task,
02382                                         update_completed, NULL, &request);
02383         check_result(result, "dns_request_createvia3");
02384 
02385         if (debugging)
02386                 show_message(stdout, updatemsg, "Outgoing update query:");
02387 
02388         requests++;
02389 }
02390 
02391 static void
02392 next_server(const char *caller, isc_sockaddr_t *addr, isc_result_t eresult) {
02393         char addrbuf[ISC_SOCKADDR_FORMATSIZE];
02394 
02395         isc_sockaddr_format(addr, addrbuf, sizeof(addrbuf));
02396         fprintf(stderr, "; Communication with %s failed: %s\n",
02397                 addrbuf, isc_result_totext(eresult));
02398         if (++ns_inuse >= ns_total)
02399                 fatal("could not reach any name server");
02400         else
02401                 ddebug("%s: trying next server", caller);
02402 }
02403 
02404 static void
02405 recvsoa(isc_task_t *task, isc_event_t *event) {
02406         dns_requestevent_t *reqev = NULL;
02407         dns_request_t *request = NULL;
02408         isc_result_t result, eresult;
02409         dns_message_t *rcvmsg = NULL;
02410         dns_section_t section;
02411         dns_name_t *name = NULL;
02412         dns_rdataset_t *soaset = NULL;
02413         dns_rdata_soa_t soa;
02414         dns_rdata_t soarr = DNS_RDATA_INIT;
02415         int pass = 0;
02416         dns_name_t master;
02417         nsu_requestinfo_t *reqinfo;
02418         dns_message_t *soaquery = NULL;
02419         isc_sockaddr_t *addr;
02420         isc_sockaddr_t *srcaddr;
02421         isc_boolean_t seencname = ISC_FALSE;
02422         dns_name_t tname;
02423         unsigned int nlabels;
02424 
02425         UNUSED(task);
02426 
02427         ddebug("recvsoa()");
02428 
02429         requests--;
02430 
02431         REQUIRE(event->ev_type == DNS_EVENT_REQUESTDONE);
02432         reqev = (dns_requestevent_t *)event;
02433         request = reqev->request;
02434         eresult = reqev->result;
02435         reqinfo = reqev->ev_arg;
02436         soaquery = reqinfo->msg;
02437         addr = reqinfo->addr;
02438 
02439         if (shuttingdown) {
02440                 dns_request_destroy(&request);
02441                 dns_message_destroy(&soaquery);
02442                 isc_mem_put(gmctx, reqinfo, sizeof(nsu_requestinfo_t));
02443                 isc_event_free(&event);
02444                 maybeshutdown();
02445                 return;
02446         }
02447 
02448         if (eresult != ISC_R_SUCCESS) {
02449                 next_server("recvsoa", addr, eresult);
02450                 ddebug("Destroying request [%p]", request);
02451                 dns_request_destroy(&request);
02452                 dns_message_renderreset(soaquery);
02453                 dns_message_settsigkey(soaquery, NULL);
02454                 sendrequest(&servers[ns_inuse], soaquery, &request);
02455                 isc_mem_put(gmctx, reqinfo, sizeof(nsu_requestinfo_t));
02456                 isc_event_free(&event);
02457                 setzoneclass(dns_rdataclass_none);
02458                 return;
02459         }
02460 
02461         isc_mem_put(gmctx, reqinfo, sizeof(nsu_requestinfo_t));
02462         reqinfo = NULL;
02463         isc_event_free(&event);
02464         reqev = NULL;
02465 
02466         ddebug("About to create rcvmsg");
02467         result = dns_message_create(gmctx, DNS_MESSAGE_INTENTPARSE, &rcvmsg);
02468         check_result(result, "dns_message_create");
02469         result = dns_request_getresponse(request, rcvmsg,
02470                                          DNS_MESSAGEPARSE_PRESERVEORDER);
02471         if (result == DNS_R_TSIGERRORSET && servers != NULL) {
02472                 dns_message_destroy(&rcvmsg);
02473                 ddebug("Destroying request [%p]", request);
02474                 dns_request_destroy(&request);
02475                 reqinfo = isc_mem_get(gmctx, sizeof(nsu_requestinfo_t));
02476                 if (reqinfo == NULL)
02477                         fatal("out of memory");
02478                 reqinfo->msg = soaquery;
02479                 reqinfo->addr = addr;
02480                 dns_message_renderreset(soaquery);
02481                 ddebug("retrying soa request without TSIG");
02482 
02483                 if (isc_sockaddr_pf(addr) == AF_INET6)
02484                         srcaddr = localaddr6;
02485                 else
02486                         srcaddr = localaddr4;
02487 
02488                 result = dns_request_createvia3(requestmgr, soaquery, srcaddr,
02489                                                 addr, 0, NULL,
02490                                                 FIND_TIMEOUT * 20,
02491                                                 FIND_TIMEOUT, 3,
02492                                                 global_task, recvsoa, reqinfo,
02493                                                 &request);
02494                 check_result(result, "dns_request_createvia");
02495                 requests++;
02496                 return;
02497         }
02498         check_result(result, "dns_request_getresponse");
02499         section = DNS_SECTION_ANSWER;
02500         POST(section);
02501         if (debugging)
02502                 show_message(stderr, rcvmsg, "Reply from SOA query:");
02503 
02504         if (rcvmsg->rcode != dns_rcode_noerror &&
02505             rcvmsg->rcode != dns_rcode_nxdomain)
02506                 fatal("response to SOA query was unsuccessful");
02507 
02508         if (userzone != NULL && rcvmsg->rcode == dns_rcode_nxdomain) {
02509                 char namebuf[DNS_NAME_FORMATSIZE];
02510                 dns_name_format(userzone, namebuf, sizeof(namebuf));
02511                 error("specified zone '%s' does not exist (NXDOMAIN)",
02512                       namebuf);
02513                 dns_message_destroy(&rcvmsg);
02514                 dns_request_destroy(&request);
02515                 dns_message_destroy(&soaquery);
02516                 ddebug("Out of recvsoa");
02517                 done_update();
02518                 seenerror = ISC_TRUE;
02519                 return;
02520         }
02521 
02522  lookforsoa:
02523         if (pass == 0)
02524                 section = DNS_SECTION_ANSWER;
02525         else if (pass == 1)
02526                 section = DNS_SECTION_AUTHORITY;
02527         else
02528                 goto droplabel;
02529 
02530         result = dns_message_firstname(rcvmsg, section);
02531         if (result != ISC_R_SUCCESS) {
02532                 pass++;
02533                 goto lookforsoa;
02534         }
02535         while (result == ISC_R_SUCCESS) {
02536                 name = NULL;
02537                 dns_message_currentname(rcvmsg, section, &name);
02538                 soaset = NULL;
02539                 result = dns_message_findtype(name, dns_rdatatype_soa, 0,
02540                                               &soaset);
02541                 if (result == ISC_R_SUCCESS)
02542                         break;
02543                 if (section == DNS_SECTION_ANSWER) {
02544                         dns_rdataset_t *tset = NULL;
02545                         if (dns_message_findtype(name, dns_rdatatype_cname, 0,
02546                                                  &tset) == ISC_R_SUCCESS ||
02547                             dns_message_findtype(name, dns_rdatatype_dname, 0,
02548                                                  &tset) == ISC_R_SUCCESS ) {
02549                                 seencname = ISC_TRUE;
02550                                 break;
02551                         }
02552                 }
02553 
02554                 result = dns_message_nextname(rcvmsg, section);
02555         }
02556 
02557         if (soaset == NULL && !seencname) {
02558                 pass++;
02559                 goto lookforsoa;
02560         }
02561 
02562         if (seencname)
02563                 goto droplabel;
02564 
02565         if (debugging) {
02566                 char namestr[DNS_NAME_FORMATSIZE];
02567                 dns_name_format(name, namestr, sizeof(namestr));
02568                 fprintf(stderr, "Found zone name: %s\n", namestr);
02569         }
02570 
02571         result = dns_rdataset_first(soaset);
02572         check_result(result, "dns_rdataset_first");
02573 
02574         dns_rdata_init(&soarr);
02575         dns_rdataset_current(soaset, &soarr);
02576         result = dns_rdata_tostruct(&soarr, &soa, NULL);
02577         check_result(result, "dns_rdata_tostruct");
02578 
02579         dns_name_init(&master, NULL);
02580         dns_name_clone(&soa.origin, &master);
02581 
02582         /*
02583          * XXXMPA
02584          */
02585         if (userzone != NULL)
02586                 zname = userzone;
02587         else
02588                 zname = name;
02589 
02590         if (debugging) {
02591                 char namestr[DNS_NAME_FORMATSIZE];
02592                 dns_name_format(&master, namestr, sizeof(namestr));
02593                 fprintf(stderr, "The master is: %s\n", namestr);
02594         }
02595 
02596         if (default_servers) {
02597                 char serverstr[DNS_NAME_MAXTEXT+1];
02598                 isc_buffer_t buf;
02599                 size_t size;
02600 
02601                 isc_buffer_init(&buf, serverstr, sizeof(serverstr));
02602                 result = dns_name_totext(&master, ISC_TRUE, &buf);
02603                 check_result(result, "dns_name_totext");
02604                 serverstr[isc_buffer_usedlength(&buf)] = 0;
02605 
02606                 if (master_servers != NULL && master_servers != servers)
02607                         isc_mem_put(gmctx, master_servers,
02608                                     master_total * sizeof(isc_sockaddr_t));
02609                 master_total = MAX_SERVERADDRS;
02610                 size = master_total * sizeof(isc_sockaddr_t);
02611                 master_servers = isc_mem_get(gmctx, size);
02612                 if (master_servers == NULL)
02613                         fatal("out of memory");
02614 
02615                 memset(master_servers, 0, size);
02616                 get_addresses(serverstr, dnsport, master_servers, master_total);
02617                 master_inuse = 0;
02618         } else
02619                 master_from_servers();
02620         dns_rdata_freestruct(&soa);
02621 
02622 #ifdef GSSAPI
02623         if (usegsstsig) {
02624                 dns_name_init(&tmpzonename, NULL);
02625                 dns_name_dup(zname, gmctx, &tmpzonename);
02626                 dns_name_init(&restart_master, NULL);
02627                 dns_name_dup(&master, gmctx, &restart_master);
02628                 start_gssrequest(&master);
02629         } else {
02630                 send_update(zname, &master_servers[master_inuse]);
02631                 setzoneclass(dns_rdataclass_none);
02632         }
02633 #else
02634         send_update(zname, &master_servers[master_inuse]);
02635         setzoneclass(dns_rdataclass_none);
02636 #endif
02637 
02638         dns_message_destroy(&soaquery);
02639         dns_request_destroy(&request);
02640 
02641  out:
02642         dns_message_destroy(&rcvmsg);
02643         ddebug("Out of recvsoa");
02644         return;
02645 
02646  droplabel:
02647         result = dns_message_firstname(soaquery, DNS_SECTION_QUESTION);
02648         INSIST(result == ISC_R_SUCCESS);
02649         name = NULL;
02650         dns_message_currentname(soaquery, DNS_SECTION_QUESTION, &name);
02651         nlabels = dns_name_countlabels(name);
02652         if (nlabels == 1)
02653                 fatal("could not find enclosing zone");
02654         dns_name_init(&tname, NULL);
02655         dns_name_getlabelsequence(name, 1, nlabels - 1, &tname);
02656         dns_name_clone(&tname, name);
02657         dns_request_destroy(&request);
02658         dns_message_renderreset(soaquery);
02659         dns_message_settsigkey(soaquery, NULL);
02660         sendrequest(&servers[ns_inuse], soaquery, &request);
02661         goto out;
02662 }
02663 
02664 static void
02665 sendrequest(isc_sockaddr_t *destaddr, dns_message_t *msg,
02666             dns_request_t **request)
02667 {
02668         isc_result_t result;
02669         nsu_requestinfo_t *reqinfo;
02670         isc_sockaddr_t *srcaddr;
02671 
02672         reqinfo = isc_mem_get(gmctx, sizeof(nsu_requestinfo_t));
02673         if (reqinfo == NULL)
02674                 fatal("out of memory");
02675         reqinfo->msg = msg;
02676         reqinfo->addr = destaddr;
02677 
02678         if (isc_sockaddr_pf(destaddr) == AF_INET6)
02679                 srcaddr = localaddr6;
02680         else
02681                 srcaddr = localaddr4;
02682 
02683         result = dns_request_createvia3(requestmgr, msg, srcaddr, destaddr, 0,
02684                                         default_servers ? NULL : tsigkey,
02685                                         FIND_TIMEOUT * 20, FIND_TIMEOUT, 3,
02686                                         global_task, recvsoa, reqinfo, request);
02687         check_result(result, "dns_request_createvia");
02688         requests++;
02689 }
02690 
02691 #ifdef GSSAPI
02692 
02693 /*
02694  * Get the realm from the users kerberos ticket if possible
02695  */
02696 static void
02697 get_ticket_realm(isc_mem_t *mctx) {
02698         krb5_context ctx;
02699         krb5_error_code rc;
02700         krb5_ccache ccache;
02701         krb5_principal princ;
02702         char *name, *ticket_realm;
02703 
02704         rc = krb5_init_context(&ctx);
02705         if (rc != 0)
02706                 return;
02707 
02708         rc = krb5_cc_default(ctx, &ccache);
02709         if (rc != 0) {
02710                 krb5_free_context(ctx);
02711                 return;
02712         }
02713 
02714         rc = krb5_cc_get_principal(ctx, ccache, &princ);
02715         if (rc != 0) {
02716                 krb5_cc_close(ctx, ccache);
02717                 krb5_free_context(ctx);
02718                 return;
02719         }
02720 
02721         rc = krb5_unparse_name(ctx, princ, &name);
02722         if (rc != 0) {
02723                 krb5_free_principal(ctx, princ);
02724                 krb5_cc_close(ctx, ccache);
02725                 krb5_free_context(ctx);
02726                 return;
02727         }
02728 
02729         ticket_realm = strrchr(name, '@');
02730         if (ticket_realm != NULL) {
02731                 realm = isc_mem_strdup(mctx, ticket_realm);
02732         }
02733 
02734         free(name);
02735         krb5_free_principal(ctx, princ);
02736         krb5_cc_close(ctx, ccache);
02737         krb5_free_context(ctx);
02738         if (realm != NULL && debugging)
02739                 fprintf(stderr, "Found realm from ticket: %s\n", realm+1);
02740 }
02741 
02742 
02743 static void
02744 start_gssrequest(dns_name_t *master) {
02745         gss_ctx_id_t context;
02746         isc_buffer_t buf;
02747         isc_result_t result;
02748         isc_uint32_t val = 0;
02749         dns_message_t *rmsg;
02750         dns_request_t *request = NULL;
02751         dns_name_t *servname;
02752         dns_fixedname_t fname;
02753         char namestr[DNS_NAME_FORMATSIZE];
02754         char mykeystr[DNS_NAME_FORMATSIZE];
02755         char *err_message = NULL;
02756 
02757         debug("start_gssrequest");
02758         usevc = ISC_TRUE;
02759 
02760         if (gssring != NULL)
02761                 dns_tsigkeyring_detach(&gssring);
02762         gssring = NULL;
02763         result = dns_tsigkeyring_create(gmctx, &gssring);
02764 
02765         if (result != ISC_R_SUCCESS)
02766                 fatal("dns_tsigkeyring_create failed: %s",
02767                       isc_result_totext(result));
02768 
02769         dns_name_format(master, namestr, sizeof(namestr));
02770         if (kserver == NULL) {
02771                 kserver = isc_mem_get(gmctx, sizeof(isc_sockaddr_t));
02772                 if (kserver == NULL)
02773                         fatal("out of memory");
02774         }
02775         if (servers == NULL)
02776                 get_addresses(namestr, dnsport, kserver, 1);
02777         else
02778                 memmove(kserver, &servers[ns_inuse], sizeof(isc_sockaddr_t));
02779 
02780         dns_fixedname_init(&fname);
02781         servname = dns_fixedname_name(&fname);
02782 
02783         if (realm == NULL)
02784                 get_ticket_realm(gmctx);
02785 
02786         result = isc_string_printf(servicename, sizeof(servicename),
02787                                    "DNS/%s%s", namestr, realm ? realm : "");
02788         if (result != ISC_R_SUCCESS)
02789                 fatal("isc_string_printf(servicename) failed: %s",
02790                       isc_result_totext(result));
02791         isc_buffer_init(&buf, servicename, strlen(servicename));
02792         isc_buffer_add(&buf, strlen(servicename));
02793         result = dns_name_fromtext(servname, &buf, dns_rootname, 0, NULL);
02794         if (result != ISC_R_SUCCESS)
02795                 fatal("dns_name_fromtext(servname) failed: %s",
02796                       isc_result_totext(result));
02797 
02798         dns_fixedname_init(&fkname);
02799         keyname = dns_fixedname_name(&fkname);
02800 
02801         isc_random_get(&val);
02802         result = isc_string_printf(mykeystr, sizeof(mykeystr), "%u.sig-%s",
02803                                    val, namestr);
02804         if (result != ISC_R_SUCCESS)
02805                 fatal("isc_string_printf(mykeystr) failed: %s",
02806                       isc_result_totext(result));
02807         isc_buffer_init(&buf, mykeystr, strlen(mykeystr));
02808         isc_buffer_add(&buf, strlen(mykeystr));
02809 
02810         result = dns_name_fromtext(keyname, &buf, dns_rootname, 0, NULL);
02811         if (result != ISC_R_SUCCESS)
02812                 fatal("dns_name_fromtext(keyname) failed: %s",
02813                       isc_result_totext(result));
02814 
02815         /* Windows doesn't recognize name compression in the key name. */
02816         keyname->attributes |= DNS_NAMEATTR_NOCOMPRESS;
02817 
02818         rmsg = NULL;
02819         result = dns_message_create(gmctx, DNS_MESSAGE_INTENTRENDER, &rmsg);
02820         if (result != ISC_R_SUCCESS)
02821                 fatal("dns_message_create failed: %s",
02822                       isc_result_totext(result));
02823 
02824         /* Build first request. */
02825         context = GSS_C_NO_CONTEXT;
02826         result = dns_tkey_buildgssquery(rmsg, keyname, servname, NULL, 0,
02827                                         &context, use_win2k_gsstsig,
02828                                         gmctx, &err_message);
02829         if (result == ISC_R_FAILURE)
02830                 fatal("tkey query failed: %s",
02831                       err_message != NULL ? err_message : "unknown error");
02832         if (result != ISC_R_SUCCESS)
02833                 fatal("dns_tkey_buildgssquery failed: %s",
02834                       isc_result_totext(result));
02835 
02836         send_gssrequest(kserver, rmsg, &request, context);
02837 }
02838 
02839 static void
02840 send_gssrequest(isc_sockaddr_t *destaddr, dns_message_t *msg,
02841                 dns_request_t **request, gss_ctx_id_t context)
02842 {
02843         isc_result_t result;
02844         nsu_gssinfo_t *reqinfo;
02845         unsigned int options = 0;
02846         isc_sockaddr_t *srcaddr;
02847 
02848         debug("send_gssrequest");
02849         reqinfo = isc_mem_get(gmctx, sizeof(nsu_gssinfo_t));
02850         if (reqinfo == NULL)
02851                 fatal("out of memory");
02852         reqinfo->msg = msg;
02853         reqinfo->addr = destaddr;
02854         reqinfo->context = context;
02855 
02856         options |= DNS_REQUESTOPT_TCP;
02857 
02858         if (isc_sockaddr_pf(destaddr) == AF_INET6)
02859                 srcaddr = localaddr6;
02860         else
02861                 srcaddr = localaddr4;
02862 
02863         result = dns_request_createvia3(requestmgr, msg, srcaddr, destaddr,
02864                                         options, tsigkey, FIND_TIMEOUT * 20,
02865                                         FIND_TIMEOUT, 3, global_task, recvgss,
02866                                         reqinfo, request);
02867         check_result(result, "dns_request_createvia3");
02868         if (debugging)
02869                 show_message(stdout, msg, "Outgoing update query:");
02870         requests++;
02871 }
02872 
02873 static void
02874 recvgss(isc_task_t *task, isc_event_t *event) {
02875         dns_requestevent_t *reqev = NULL;
02876         dns_request_t *request = NULL;
02877         isc_result_t result, eresult;
02878         dns_message_t *rcvmsg = NULL;
02879         nsu_gssinfo_t *reqinfo;
02880         dns_message_t *tsigquery = NULL;
02881         isc_sockaddr_t *addr;
02882         gss_ctx_id_t context;
02883         isc_buffer_t buf;
02884         dns_name_t *servname;
02885         dns_fixedname_t fname;
02886         char *err_message = NULL;
02887 
02888         UNUSED(task);
02889 
02890         ddebug("recvgss()");
02891 
02892         requests--;
02893 
02894         REQUIRE(event->ev_type == DNS_EVENT_REQUESTDONE);
02895         reqev = (dns_requestevent_t *)event;
02896         request = reqev->request;
02897         eresult = reqev->result;
02898         reqinfo = reqev->ev_arg;
02899         tsigquery = reqinfo->msg;
02900         context = reqinfo->context;
02901         addr = reqinfo->addr;
02902 
02903         if (shuttingdown) {
02904                 dns_request_destroy(&request);
02905                 dns_message_destroy(&tsigquery);
02906                 isc_mem_put(gmctx, reqinfo, sizeof(nsu_gssinfo_t));
02907                 isc_event_free(&event);
02908                 maybeshutdown();
02909                 return;
02910         }
02911 
02912         if (eresult != ISC_R_SUCCESS) {
02913                 next_server("recvgss", addr, eresult);
02914                 ddebug("Destroying request [%p]", request);
02915                 dns_request_destroy(&request);
02916                 dns_message_renderreset(tsigquery);
02917                 sendrequest(&servers[ns_inuse], tsigquery, &request);
02918                 isc_mem_put(gmctx, reqinfo, sizeof(nsu_gssinfo_t));
02919                 isc_event_free(&event);
02920                 return;
02921         }
02922         isc_mem_put(gmctx, reqinfo, sizeof(nsu_gssinfo_t));
02923 
02924         isc_event_free(&event);
02925         reqev = NULL;
02926 
02927         ddebug("recvgss creating rcvmsg");
02928         result = dns_message_create(gmctx, DNS_MESSAGE_INTENTPARSE, &rcvmsg);
02929         check_result(result, "dns_message_create");
02930 
02931         result = dns_request_getresponse(request, rcvmsg,
02932                                          DNS_MESSAGEPARSE_PRESERVEORDER);
02933         check_result(result, "dns_request_getresponse");
02934 
02935         if (debugging)
02936                 show_message(stderr, rcvmsg,
02937                              "recvmsg reply from GSS-TSIG query");
02938 
02939         if (rcvmsg->rcode == dns_rcode_formerr && !tried_other_gsstsig) {
02940                 ddebug("recvgss trying %s GSS-TSIG",
02941                        use_win2k_gsstsig ? "Standard" : "Win2k");
02942                 if (use_win2k_gsstsig)
02943                         use_win2k_gsstsig = ISC_FALSE;
02944                 else
02945                         use_win2k_gsstsig = ISC_TRUE;
02946                 tried_other_gsstsig = ISC_TRUE;
02947                 start_gssrequest(&restart_master);
02948                 goto done;
02949         }
02950 
02951         if (rcvmsg->rcode != dns_rcode_noerror &&
02952             rcvmsg->rcode != dns_rcode_nxdomain)
02953                 fatal("response to GSS-TSIG query was unsuccessful");
02954 
02955 
02956         dns_fixedname_init(&fname);
02957         servname = dns_fixedname_name(&fname);
02958         isc_buffer_init(&buf, servicename, strlen(servicename));
02959         isc_buffer_add(&buf, strlen(servicename));
02960         result = dns_name_fromtext(servname, &buf, dns_rootname, 0, NULL);
02961         check_result(result, "dns_name_fromtext");
02962 
02963         tsigkey = NULL;
02964         result = dns_tkey_gssnegotiate(tsigquery, rcvmsg, servname,
02965                                        &context, &tsigkey, gssring,
02966                                        use_win2k_gsstsig,
02967                                        &err_message);
02968         switch (result) {
02969 
02970         case DNS_R_CONTINUE:
02971                 send_gssrequest(kserver, tsigquery, &request, context);
02972                 break;
02973 
02974         case ISC_R_SUCCESS:
02975                 /*
02976                  * XXXSRA Waaay too much fun here.  There's no good
02977                  * reason why we need a TSIG here (the people who put
02978                  * it into the spec admitted at the time that it was
02979                  * not a security issue), and Windows clients don't
02980                  * seem to work if named complies with the spec and
02981                  * includes the gratuitous TSIG.  So we're in the
02982                  * bizarre situation of having to choose between
02983                  * complying with a useless requirement in the spec
02984                  * and interoperating.  This is nuts.  If we can
02985                  * confirm this behavior, we should ask the WG to
02986                  * consider removing the requirement for the
02987                  * gratuitous TSIG here.  For the moment, we ignore
02988                  * the TSIG -- this too is a spec violation, but it's
02989                  * the least insane thing to do.
02990                  */
02991 #if 0
02992                 /*
02993                  * Verify the signature.
02994                  */
02995                 rcvmsg->state = DNS_SECTION_ANY;
02996                 dns_message_setquerytsig(rcvmsg, NULL);
02997                 result = dns_message_settsigkey(rcvmsg, tsigkey);
02998                 check_result(result, "dns_message_settsigkey");
02999                 result = dns_message_checksig(rcvmsg, NULL);
03000                 ddebug("tsig verification: %s", dns_result_totext(result));
03001                 check_result(result, "dns_message_checksig");
03002 #endif /* 0 */
03003 
03004                 send_update(&tmpzonename, &master_servers[master_inuse]);
03005                 setzoneclass(dns_rdataclass_none);
03006                 break;
03007 
03008         default:
03009                 fatal("dns_tkey_negotiategss: %s %s",
03010                       isc_result_totext(result),
03011                       err_message != NULL ? err_message : "");
03012         }
03013 
03014  done:
03015         dns_request_destroy(&request);
03016         dns_message_destroy(&tsigquery);
03017 
03018         dns_message_destroy(&rcvmsg);
03019         ddebug("Out of recvgss");
03020 }
03021 #endif
03022 
03023 static void
03024 start_update(void) {
03025         isc_result_t result;
03026         dns_rdataset_t *rdataset = NULL;
03027         dns_name_t *name = NULL;
03028         dns_request_t *request = NULL;
03029         dns_message_t *soaquery = NULL;
03030         dns_name_t *firstname;
03031         dns_section_t section = DNS_SECTION_UPDATE;
03032 
03033         ddebug("start_update()");
03034 
03035         if (answer != NULL)
03036                 dns_message_destroy(&answer);
03037 
03038         /*
03039          * If we have both the zone and the servers we have enough information
03040          * to send the update straight away otherwise we need to discover
03041          * the zone and / or the master server.
03042          */
03043         if (userzone != NULL && !default_servers && !usegsstsig) {
03044                 master_from_servers();
03045                 send_update(userzone, &master_servers[master_inuse]);
03046                 setzoneclass(dns_rdataclass_none);
03047                 return;
03048         }
03049 
03050         result = dns_message_create(gmctx, DNS_MESSAGE_INTENTRENDER,
03051                                     &soaquery);
03052         check_result(result, "dns_message_create");
03053 
03054         if (default_servers)
03055                 soaquery->flags |= DNS_MESSAGEFLAG_RD;
03056 
03057         result = dns_message_gettempname(soaquery, &name);
03058         check_result(result, "dns_message_gettempname");
03059 
03060         result = dns_message_gettemprdataset(soaquery, &rdataset);
03061         check_result(result, "dns_message_gettemprdataset");
03062 
03063         dns_rdataset_makequestion(rdataset, getzoneclass(), dns_rdatatype_soa);
03064 
03065         if (userzone != NULL) {
03066                 dns_name_init(name, NULL);
03067                 dns_name_clone(userzone, name);
03068         } else {
03069                 dns_rdataset_t *tmprdataset;
03070                 result = dns_message_firstname(updatemsg, section);
03071                 if (result == ISC_R_NOMORE) {
03072                         section = DNS_SECTION_PREREQUISITE;
03073                         result = dns_message_firstname(updatemsg, section);
03074                 }
03075                 if (result != ISC_R_SUCCESS) {
03076                         dns_message_puttempname(soaquery, &name);
03077                         dns_rdataset_disassociate(rdataset);
03078                         dns_message_puttemprdataset(soaquery, &rdataset);
03079                         dns_message_destroy(&soaquery);
03080                         done_update();
03081                         return;
03082                 }
03083                 firstname = NULL;
03084                 dns_message_currentname(updatemsg, section, &firstname);
03085                 dns_name_init(name, NULL);
03086                 dns_name_clone(firstname, name);
03087                 /*
03088                  * Looks to see if the first name references a DS record
03089                  * and if that name is not the root remove a label as DS
03090                  * records live in the parent zone so we need to start our
03091                  * search one label up.
03092                  */
03093                 tmprdataset = ISC_LIST_HEAD(firstname->list);
03094                 if (section == DNS_SECTION_UPDATE &&
03095                     !dns_name_equal(firstname, dns_rootname) &&
03096                     tmprdataset->type == dns_rdatatype_ds) {
03097                     unsigned int labels = dns_name_countlabels(name);
03098                     dns_name_getlabelsequence(name, 1, labels - 1, name);
03099                 }
03100         }
03101 
03102         ISC_LIST_INIT(name->list);
03103         ISC_LIST_APPEND(name->list, rdataset, link);
03104         dns_message_addname(soaquery, name, DNS_SECTION_QUESTION);
03105 
03106         ns_inuse = 0;
03107         sendrequest(&servers[ns_inuse], soaquery, &request);
03108 }
03109 
03110 static void
03111 cleanup(void) {
03112         ddebug("cleanup()");
03113 
03114         if (answer != NULL)
03115                 dns_message_destroy(&answer);
03116 
03117 #ifdef GSSAPI
03118         if (tsigkey != NULL) {
03119                 ddebug("detach tsigkey x%p", tsigkey);
03120                 dns_tsigkey_detach(&tsigkey);
03121         }
03122         if (gssring != NULL) {
03123                 ddebug("Detaching GSS-TSIG keyring");
03124                 dns_tsigkeyring_detach(&gssring);
03125         }
03126         if (kserver != NULL) {
03127                 isc_mem_put(gmctx, kserver, sizeof(isc_sockaddr_t));
03128                 kserver = NULL;
03129         }
03130         if (realm != NULL) {
03131                 isc_mem_free(gmctx, realm);
03132                 realm = NULL;
03133         }
03134 #endif
03135 
03136         if (sig0key != NULL)
03137                 dst_key_free(&sig0key);
03138 
03139         ddebug("Shutting down task manager");
03140         isc_taskmgr_destroy(&taskmgr);
03141 
03142         ddebug("Destroying event");
03143         isc_event_free(&global_event);
03144 
03145         ddebug("Shutting down socket manager");
03146         isc_socketmgr_destroy(&socketmgr);
03147 
03148         ddebug("Shutting down timer manager");
03149         isc_timermgr_destroy(&timermgr);
03150 
03151         ddebug("Destroying hash context");
03152         isc_hash_destroy();
03153 
03154         ddebug("Destroying name state");
03155         dns_name_destroy();
03156 
03157         ddebug("Removing log context");
03158         isc_log_destroy(&glctx);
03159 
03160         ddebug("Destroying memory context");
03161         if (memdebugging)
03162                 isc_mem_stats(gmctx, stderr);
03163         isc_mem_destroy(&gmctx);
03164 }
03165 
03166 static void
03167 getinput(isc_task_t *task, isc_event_t *event) {
03168         isc_boolean_t more;
03169 
03170         UNUSED(task);
03171 
03172         if (shuttingdown) {
03173                 maybeshutdown();
03174                 return;
03175         }
03176 
03177         if (global_event == NULL)
03178                 global_event = event;
03179 
03180         reset_system();
03181         more = user_interaction();
03182         if (!more) {
03183                 isc_app_shutdown();
03184                 return;
03185         }
03186         start_update();
03187         return;
03188 }
03189 
03190 int
03191 main(int argc, char **argv) {
03192         isc_result_t result;
03193         style = &dns_master_style_debug;
03194 
03195         input = stdin;
03196 
03197         interactive = ISC_TF(isatty(0));
03198 
03199         isc_app_start();
03200 
03201         pre_parse_args(argc, argv);
03202 
03203         result = isc_mem_create(0, 0, &gmctx);
03204         check_result(result, "isc_mem_create");
03205 
03206         parse_args(argc, argv, gmctx, &entropy);
03207 
03208         setup_system();
03209 
03210         result = isc_app_onrun(gmctx, global_task, getinput, NULL);
03211         check_result(result, "isc_app_onrun");
03212 
03213         (void)isc_app_run();
03214 
03215         cleanup();
03216 
03217         isc_app_finish();
03218 
03219         if (seenerror)
03220                 return (2);
03221         else
03222                 return (0);
03223 }

Generated on Tue Apr 28 17:40:55 2015 by Doxygen 1.5.4 for BIND9 Internals 9.11.0pre-alpha