"Fossies" - the Fresh Open Source Software Archive

Member "bind-9.11.23/bin/named/controlconf.c" (7 Sep 2020, 41570 Bytes) of package /linux/misc/dns/bind9/9.11.23/bind-9.11.23.tar.gz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "controlconf.c" see the Fossies "Dox" file reference documentation and the last Fossies "Diffs" side-by-side code changes report: 9.17.3_vs_9.17.4.

    1 /*
    2  * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
    3  *
    4  * This Source Code Form is subject to the terms of the Mozilla Public
    5  * License, v. 2.0. If a copy of the MPL was not distributed with this
    6  * file, You can obtain one at http://mozilla.org/MPL/2.0/.
    7  *
    8  * See the COPYRIGHT file distributed with this work for additional
    9  * information regarding copyright ownership.
   10  */
   11 
   12 /*! \file */
   13 
   14 #include <config.h>
   15 
   16 #include <inttypes.h>
   17 #include <stdbool.h>
   18 
   19 #include <isc/base64.h>
   20 #include <isc/buffer.h>
   21 #include <isc/event.h>
   22 #include <isc/file.h>
   23 #include <isc/mem.h>
   24 #include <isc/net.h>
   25 #include <isc/netaddr.h>
   26 #include <isc/random.h>
   27 #include <isc/result.h>
   28 #include <isc/stdtime.h>
   29 #include <isc/string.h>
   30 #include <isc/timer.h>
   31 #include <isc/util.h>
   32 
   33 #include <isccfg/namedconf.h>
   34 
   35 #include <bind9/check.h>
   36 
   37 #include <isccc/alist.h>
   38 #include <isccc/cc.h>
   39 #include <isccc/ccmsg.h>
   40 #include <isccc/events.h>
   41 #include <isccc/result.h>
   42 #include <isccc/sexpr.h>
   43 #include <isccc/symtab.h>
   44 #include <isccc/util.h>
   45 
   46 #include <dns/result.h>
   47 
   48 #include <named/config.h>
   49 #include <named/control.h>
   50 #include <named/log.h>
   51 #include <named/server.h>
   52 
   53 /*
   54  * Note: Listeners and connections are not locked.  All event handlers are
   55  * executed by the server task, and all callers of exported routines must
   56  * be running under the server task.
   57  */
   58 
   59 typedef struct controlkey controlkey_t;
   60 typedef ISC_LIST(controlkey_t) controlkeylist_t;
   61 
   62 typedef struct controlconnection controlconnection_t;
   63 typedef ISC_LIST(controlconnection_t) controlconnectionlist_t;
   64 
   65 typedef struct controllistener controllistener_t;
   66 typedef ISC_LIST(controllistener_t) controllistenerlist_t;
   67 
   68 struct controlkey {
   69     char *              keyname;
   70     uint32_t            algorithm;
   71     isc_region_t            secret;
   72     ISC_LINK(controlkey_t)      link;
   73 };
   74 
   75 struct controlconnection {
   76     isc_socket_t *          sock;
   77     isccc_ccmsg_t           ccmsg;
   78     bool            ccmsg_valid;
   79     bool            sending;
   80     isc_timer_t *           timer;
   81     isc_buffer_t *          buffer;
   82     controllistener_t *     listener;
   83     uint32_t            nonce;
   84     ISC_LINK(controlconnection_t)   link;
   85 };
   86 
   87 struct controllistener {
   88     ns_controls_t *         controls;
   89     isc_mem_t *         mctx;
   90     isc_task_t *            task;
   91     isc_sockaddr_t          address;
   92     isc_socket_t *          sock;
   93     dns_acl_t *         acl;
   94     bool            listening;
   95     bool            exiting;
   96     controlkeylist_t        keys;
   97     controlconnectionlist_t     connections;
   98     isc_sockettype_t        type;
   99     uint32_t            perm;
  100     uint32_t            owner;
  101     uint32_t            group;
  102     bool            readonly;
  103     ISC_LINK(controllistener_t) link;
  104 };
  105 
  106 struct ns_controls {
  107     ns_server_t         *server;
  108     controllistenerlist_t       listeners;
  109     bool            shuttingdown;
  110     isccc_symtab_t          *symtab;
  111 };
  112 
  113 static void control_newconn(isc_task_t *task, isc_event_t *event);
  114 static void control_recvmessage(isc_task_t *task, isc_event_t *event);
  115 
  116 #define CLOCKSKEW 300
  117 
  118 static void
  119 free_controlkey(controlkey_t *key, isc_mem_t *mctx) {
  120     if (key->keyname != NULL)
  121         isc_mem_free(mctx, key->keyname);
  122     if (key->secret.base != NULL)
  123         isc_mem_put(mctx, key->secret.base, key->secret.length);
  124     isc_mem_put(mctx, key, sizeof(*key));
  125 }
  126 
  127 static void
  128 free_controlkeylist(controlkeylist_t *keylist, isc_mem_t *mctx) {
  129     while (!ISC_LIST_EMPTY(*keylist)) {
  130         controlkey_t *key = ISC_LIST_HEAD(*keylist);
  131         ISC_LIST_UNLINK(*keylist, key, link);
  132         free_controlkey(key, mctx);
  133     }
  134 }
  135 
  136 static void
  137 free_listener(controllistener_t *listener) {
  138     INSIST(listener->exiting);
  139     INSIST(!listener->listening);
  140     INSIST(ISC_LIST_EMPTY(listener->connections));
  141 
  142     if (listener->sock != NULL)
  143         isc_socket_detach(&listener->sock);
  144 
  145     free_controlkeylist(&listener->keys, listener->mctx);
  146 
  147     if (listener->acl != NULL)
  148         dns_acl_detach(&listener->acl);
  149 
  150     isc_mem_putanddetach(&listener->mctx, listener, sizeof(*listener));
  151 }
  152 
  153 static void
  154 maybe_free_listener(controllistener_t *listener) {
  155     if (listener->exiting &&
  156         !listener->listening &&
  157         ISC_LIST_EMPTY(listener->connections))
  158         free_listener(listener);
  159 }
  160 
  161 static void
  162 maybe_free_connection(controlconnection_t *conn) {
  163     controllistener_t *listener = conn->listener;
  164 
  165     if (conn->buffer != NULL)
  166         isc_buffer_free(&conn->buffer);
  167 
  168     if (conn->timer != NULL)
  169         isc_timer_detach(&conn->timer);
  170 
  171     if (conn->ccmsg_valid) {
  172         isccc_ccmsg_cancelread(&conn->ccmsg);
  173         return;
  174     }
  175 
  176     if (conn->sending) {
  177         isc_socket_cancel(conn->sock, listener->task,
  178                   ISC_SOCKCANCEL_SEND);
  179         return;
  180     }
  181 
  182     ISC_LIST_UNLINK(listener->connections, conn, link);
  183 #ifdef ENABLE_AFL
  184     if (ns_g_fuzz_type == ns_fuzz_rndc) {
  185         named_fuzz_notify();
  186     }
  187 #endif
  188     isc_mem_put(listener->mctx, conn, sizeof(*conn));
  189 }
  190 
  191 static void
  192 shutdown_listener(controllistener_t *listener) {
  193     controlconnection_t *conn;
  194     controlconnection_t *next;
  195 
  196     if (!listener->exiting) {
  197         char socktext[ISC_SOCKADDR_FORMATSIZE];
  198 
  199         ISC_LIST_UNLINK(listener->controls->listeners, listener, link);
  200 
  201         isc_sockaddr_format(&listener->address, socktext,
  202                     sizeof(socktext));
  203         isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
  204                   NS_LOGMODULE_CONTROL, ISC_LOG_NOTICE,
  205                   "stopping command channel on %s", socktext);
  206         if (listener->type == isc_sockettype_unix)
  207             isc_socket_cleanunix(&listener->address, true);
  208         listener->exiting = true;
  209     }
  210 
  211     for (conn = ISC_LIST_HEAD(listener->connections);
  212          conn != NULL;
  213          conn = next)
  214     {
  215         next = ISC_LIST_NEXT(conn, link);
  216         maybe_free_connection(conn);
  217     }
  218 
  219     if (listener->listening)
  220         isc_socket_cancel(listener->sock, listener->task,
  221                   ISC_SOCKCANCEL_ACCEPT);
  222 
  223     maybe_free_listener(listener);
  224 }
  225 
  226 static bool
  227 address_ok(isc_sockaddr_t *sockaddr, dns_acl_t *acl) {
  228     isc_netaddr_t netaddr;
  229     isc_result_t result;
  230     int match;
  231 
  232     isc_netaddr_fromsockaddr(&netaddr, sockaddr);
  233 
  234     result = dns_acl_match(&netaddr, NULL, acl,
  235                    &ns_g_server->aclenv, &match, NULL);
  236 
  237     if (result != ISC_R_SUCCESS || match <= 0)
  238         return (false);
  239     else
  240         return (true);
  241 }
  242 
  243 static isc_result_t
  244 control_accept(controllistener_t *listener) {
  245     isc_result_t result;
  246     result = isc_socket_accept(listener->sock,
  247                    listener->task,
  248                    control_newconn, listener);
  249     if (result != ISC_R_SUCCESS)
  250         UNEXPECTED_ERROR(__FILE__, __LINE__,
  251                  "isc_socket_accept() failed: %s",
  252                  isc_result_totext(result));
  253     else
  254         listener->listening = true;
  255     return (result);
  256 }
  257 
  258 static isc_result_t
  259 control_listen(controllistener_t *listener) {
  260     isc_result_t result;
  261 
  262     result = isc_socket_listen(listener->sock, 0);
  263     if (result != ISC_R_SUCCESS)
  264         UNEXPECTED_ERROR(__FILE__, __LINE__,
  265                  "isc_socket_listen() failed: %s",
  266                  isc_result_totext(result));
  267     return (result);
  268 }
  269 
  270 static void
  271 control_next(controllistener_t *listener) {
  272     (void)control_accept(listener);
  273 }
  274 
  275 static void
  276 control_senddone(isc_task_t *task, isc_event_t *event) {
  277     isc_socketevent_t *sevent = (isc_socketevent_t *) event;
  278     controlconnection_t *conn = event->ev_arg;
  279     controllistener_t *listener = conn->listener;
  280     isc_socket_t *sock = (isc_socket_t *)sevent->ev_sender;
  281     isc_result_t result;
  282 
  283     REQUIRE(conn->sending);
  284 
  285     UNUSED(task);
  286 
  287     conn->sending = false;
  288 
  289     if (sevent->result != ISC_R_SUCCESS &&
  290         sevent->result != ISC_R_CANCELED)
  291     {
  292         char socktext[ISC_SOCKADDR_FORMATSIZE];
  293         isc_sockaddr_t peeraddr;
  294 
  295         (void)isc_socket_getpeername(sock, &peeraddr);
  296         isc_sockaddr_format(&peeraddr, socktext, sizeof(socktext));
  297         isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
  298                   NS_LOGMODULE_CONTROL, ISC_LOG_WARNING,
  299                   "error sending command response to %s: %s",
  300                   socktext, isc_result_totext(sevent->result));
  301     }
  302     isc_event_free(&event);
  303 
  304     result = isccc_ccmsg_readmessage(&conn->ccmsg, listener->task,
  305                      control_recvmessage, conn);
  306     if (result != ISC_R_SUCCESS) {
  307         isc_socket_detach(&conn->sock);
  308         maybe_free_connection(conn);
  309         maybe_free_listener(listener);
  310     }
  311 }
  312 
  313 static inline void
  314 log_invalid(isccc_ccmsg_t *ccmsg, isc_result_t result) {
  315     char socktext[ISC_SOCKADDR_FORMATSIZE];
  316     isc_sockaddr_t peeraddr;
  317 
  318     (void)isc_socket_getpeername(ccmsg->sock, &peeraddr);
  319     isc_sockaddr_format(&peeraddr, socktext, sizeof(socktext));
  320     isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
  321               NS_LOGMODULE_CONTROL, ISC_LOG_ERROR,
  322               "invalid command from %s: %s",
  323               socktext, isc_result_totext(result));
  324 }
  325 
  326 static void
  327 control_recvmessage(isc_task_t *task, isc_event_t *event) {
  328     controlconnection_t *conn;
  329     controllistener_t *listener;
  330     controlkey_t *key;
  331     isccc_sexpr_t *request = NULL;
  332     isccc_sexpr_t *response = NULL;
  333     uint32_t algorithm;
  334     isccc_region_t secret;
  335     isc_stdtime_t now;
  336     isc_buffer_t b;
  337     isc_region_t r;
  338     isc_buffer_t *text;
  339     isc_result_t result;
  340     isc_result_t eresult;
  341     isccc_sexpr_t *_ctrl;
  342     isccc_time_t sent;
  343     isccc_time_t exp;
  344     uint32_t nonce;
  345     isccc_sexpr_t *data;
  346 
  347     REQUIRE(event->ev_type == ISCCC_EVENT_CCMSG);
  348 
  349     conn = event->ev_arg;
  350     listener = conn->listener;
  351     algorithm = DST_ALG_UNKNOWN;
  352     secret.rstart = NULL;
  353     text = NULL;
  354 
  355     /* Is the server shutting down? */
  356     if (listener->controls->shuttingdown)
  357         goto cleanup;
  358 
  359     if (conn->ccmsg.result != ISC_R_SUCCESS) {
  360         if (conn->ccmsg.result != ISC_R_CANCELED &&
  361             conn->ccmsg.result != ISC_R_EOF)
  362             log_invalid(&conn->ccmsg, conn->ccmsg.result);
  363         goto cleanup;
  364     }
  365 
  366     request = NULL;
  367 
  368     for (key = ISC_LIST_HEAD(listener->keys);
  369          key != NULL;
  370          key = ISC_LIST_NEXT(key, link))
  371     {
  372         isccc_region_t ccregion;
  373 
  374         ccregion.rstart = isc_buffer_base(&conn->ccmsg.buffer);
  375         ccregion.rend = isc_buffer_used(&conn->ccmsg.buffer);
  376         secret.rstart = isc_mem_get(listener->mctx, key->secret.length);
  377         if (secret.rstart == NULL)
  378             goto cleanup;
  379         memmove(secret.rstart, key->secret.base, key->secret.length);
  380         secret.rend = secret.rstart + key->secret.length;
  381         algorithm = key->algorithm;
  382         result = isccc_cc_fromwire(&ccregion, &request,
  383                        algorithm, &secret);
  384         if (result == ISC_R_SUCCESS)
  385             break;
  386         isc_mem_put(listener->mctx, secret.rstart, REGION_SIZE(secret));
  387         if (result != ISCCC_R_BADAUTH) {
  388             log_invalid(&conn->ccmsg, result);
  389             goto cleanup;
  390         }
  391     }
  392 
  393     if (key == NULL) {
  394         log_invalid(&conn->ccmsg, ISCCC_R_BADAUTH);
  395         goto cleanup;
  396     }
  397 
  398     /* We shouldn't be getting a reply. */
  399     if (isccc_cc_isreply(request)) {
  400         log_invalid(&conn->ccmsg, ISC_R_FAILURE);
  401         goto cleanup_request;
  402     }
  403 
  404     isc_stdtime_get(&now);
  405 
  406     /*
  407      * Limit exposure to replay attacks.
  408      */
  409     _ctrl = isccc_alist_lookup(request, "_ctrl");
  410     if (!isccc_alist_alistp(_ctrl)) {
  411         log_invalid(&conn->ccmsg, ISC_R_FAILURE);
  412         goto cleanup_request;
  413     }
  414 
  415     if (isccc_cc_lookupuint32(_ctrl, "_tim", &sent) == ISC_R_SUCCESS) {
  416         if ((sent + CLOCKSKEW) < now || (sent - CLOCKSKEW) > now) {
  417             log_invalid(&conn->ccmsg, ISCCC_R_CLOCKSKEW);
  418             goto cleanup_request;
  419         }
  420     } else {
  421         log_invalid(&conn->ccmsg, ISC_R_FAILURE);
  422         goto cleanup_request;
  423     }
  424 
  425     /*
  426      * Expire messages that are too old.
  427      */
  428     if (isccc_cc_lookupuint32(_ctrl, "_exp", &exp) == ISC_R_SUCCESS &&
  429         now > exp) {
  430         log_invalid(&conn->ccmsg, ISCCC_R_EXPIRED);
  431         goto cleanup_request;
  432     }
  433 
  434     /*
  435      * Duplicate suppression (required for UDP).
  436      */
  437     isccc_cc_cleansymtab(listener->controls->symtab, now);
  438     result = isccc_cc_checkdup(listener->controls->symtab, request, now);
  439     if (result != ISC_R_SUCCESS) {
  440         if (result == ISC_R_EXISTS)
  441             result = ISCCC_R_DUPLICATE;
  442         log_invalid(&conn->ccmsg, result);
  443         goto cleanup_request;
  444     }
  445 
  446     if (conn->nonce != 0 &&
  447         (isccc_cc_lookupuint32(_ctrl, "_nonce", &nonce) != ISC_R_SUCCESS ||
  448          conn->nonce != nonce)) {
  449         log_invalid(&conn->ccmsg, ISCCC_R_BADAUTH);
  450         goto cleanup_request;
  451     }
  452 
  453     result = isc_buffer_allocate(listener->mctx, &text, 2 * 2048);
  454     if (result != ISC_R_SUCCESS)
  455         goto cleanup_request;
  456 
  457     /*
  458      * Establish nonce.
  459      */
  460     if (conn->nonce == 0) {
  461         while (conn->nonce == 0)
  462             isc_random_get(&conn->nonce);
  463         eresult = ISC_R_SUCCESS;
  464     } else
  465         eresult = ns_control_docommand(request, listener->readonly, &text);
  466 
  467     result = isccc_cc_createresponse(request, now, now + 60, &response);
  468     if (result != ISC_R_SUCCESS)
  469         goto cleanup_request;
  470 
  471     data = isccc_alist_lookup(response, "_data");
  472     if (data != NULL) {
  473         if (isccc_cc_defineuint32(data, "result", eresult) == NULL)
  474             goto cleanup_response;
  475     }
  476 
  477     if (eresult != ISC_R_SUCCESS) {
  478         if (data != NULL) {
  479             const char *estr = isc_result_totext(eresult);
  480             if (isccc_cc_definestring(data, "err", estr) == NULL)
  481                 goto cleanup_response;
  482         }
  483     }
  484 
  485     if (isc_buffer_usedlength(text) > 0) {
  486         if (data != NULL) {
  487             char *str = (char *)isc_buffer_base(text);
  488             if (isccc_cc_definestring(data, "text", str) == NULL)
  489                 goto cleanup_response;
  490         }
  491     }
  492 
  493     _ctrl = isccc_alist_lookup(response, "_ctrl");
  494     if (_ctrl == NULL ||
  495         isccc_cc_defineuint32(_ctrl, "_nonce", conn->nonce) == NULL)
  496         goto cleanup_response;
  497 
  498     if (conn->buffer == NULL) {
  499         result = isc_buffer_allocate(listener->mctx,
  500                          &conn->buffer, 2 * 2048);
  501         if (result != ISC_R_SUCCESS)
  502             goto cleanup_response;
  503     }
  504 
  505     isc_buffer_clear(conn->buffer);
  506     /* Skip the length field (4 bytes) */
  507     isc_buffer_add(conn->buffer, 4);
  508 
  509     result = isccc_cc_towire(response, &conn->buffer, algorithm, &secret);
  510     if (result != ISC_R_SUCCESS)
  511         goto cleanup_response;
  512 
  513     isc_buffer_init(&b, conn->buffer->base, 4);
  514     isc_buffer_putuint32(&b, conn->buffer->used - 4);
  515 
  516     r.base = conn->buffer->base;
  517     r.length = conn->buffer->used;
  518 
  519     result = isc_socket_send(conn->sock, &r, task, control_senddone, conn);
  520     if (result != ISC_R_SUCCESS)
  521         goto cleanup_response;
  522     conn->sending = true;
  523 
  524     isc_mem_put(listener->mctx, secret.rstart, REGION_SIZE(secret));
  525     isccc_sexpr_free(&request);
  526     isccc_sexpr_free(&response);
  527     isc_buffer_free(&text);
  528     return;
  529 
  530  cleanup_response:
  531     isccc_sexpr_free(&response);
  532 
  533  cleanup_request:
  534     isccc_sexpr_free(&request);
  535     isc_mem_put(listener->mctx, secret.rstart, REGION_SIZE(secret));
  536     if (text != NULL)
  537         isc_buffer_free(&text);
  538 
  539  cleanup:
  540     isc_socket_detach(&conn->sock);
  541     isccc_ccmsg_invalidate(&conn->ccmsg);
  542     conn->ccmsg_valid = false;
  543     maybe_free_connection(conn);
  544     maybe_free_listener(listener);
  545 }
  546 
  547 static void
  548 control_timeout(isc_task_t *task, isc_event_t *event) {
  549     controlconnection_t *conn = event->ev_arg;
  550 
  551     UNUSED(task);
  552 
  553     isc_timer_detach(&conn->timer);
  554     maybe_free_connection(conn);
  555 
  556     isc_event_free(&event);
  557 }
  558 
  559 static isc_result_t
  560 newconnection(controllistener_t *listener, isc_socket_t *sock) {
  561     controlconnection_t *conn;
  562     isc_interval_t interval;
  563     isc_result_t result;
  564 
  565     conn = isc_mem_get(listener->mctx, sizeof(*conn));
  566     if (conn == NULL)
  567         return (ISC_R_NOMEMORY);
  568 
  569     conn->sock = sock;
  570     isccc_ccmsg_init(listener->mctx, sock, &conn->ccmsg);
  571 
  572     /* Set a 32 KiB upper limit on incoming message. */
  573     isccc_ccmsg_setmaxsize(&conn->ccmsg, 32768);
  574 
  575     conn->ccmsg_valid = true;
  576     conn->sending = false;
  577     conn->buffer = NULL;
  578     conn->timer = NULL;
  579     isc_interval_set(&interval, 60, 0);
  580     result = isc_timer_create(ns_g_timermgr, isc_timertype_once,
  581                   NULL, &interval, listener->task,
  582                   control_timeout, conn, &conn->timer);
  583     if (result != ISC_R_SUCCESS)
  584         goto cleanup;
  585 
  586     conn->listener = listener;
  587     conn->nonce = 0;
  588     ISC_LINK_INIT(conn, link);
  589 
  590     result = isccc_ccmsg_readmessage(&conn->ccmsg, listener->task,
  591                      control_recvmessage, conn);
  592     if (result != ISC_R_SUCCESS)
  593         goto cleanup;
  594 
  595     ISC_LIST_APPEND(listener->connections, conn, link);
  596     return (ISC_R_SUCCESS);
  597 
  598  cleanup:
  599     if (conn->buffer != NULL)
  600         isc_buffer_free(&conn->buffer);
  601     isccc_ccmsg_invalidate(&conn->ccmsg);
  602     if (conn->timer != NULL)
  603         isc_timer_detach(&conn->timer);
  604     isc_mem_put(listener->mctx, conn, sizeof(*conn));
  605 #ifdef ENABLE_AFL
  606     if (ns_g_fuzz_type == ns_fuzz_rndc) {
  607         named_fuzz_notify();
  608     }
  609 #endif
  610     return (result);
  611 }
  612 
  613 static void
  614 control_newconn(isc_task_t *task, isc_event_t *event) {
  615     isc_socket_newconnev_t *nevent = (isc_socket_newconnev_t *)event;
  616     controllistener_t *listener = event->ev_arg;
  617     isc_socket_t *sock;
  618     isc_sockaddr_t peeraddr;
  619     isc_result_t result;
  620 
  621     UNUSED(task);
  622 
  623     listener->listening = false;
  624 
  625     if (nevent->result != ISC_R_SUCCESS) {
  626         if (nevent->result == ISC_R_CANCELED) {
  627             shutdown_listener(listener);
  628             goto cleanup;
  629         }
  630         goto restart;
  631     }
  632 
  633     sock = nevent->newsocket;
  634     isc_socket_setname(sock, "control", NULL);
  635     (void)isc_socket_getpeername(sock, &peeraddr);
  636     if (listener->type == isc_sockettype_tcp &&
  637         !address_ok(&peeraddr, listener->acl)) {
  638         char socktext[ISC_SOCKADDR_FORMATSIZE];
  639         isc_sockaddr_format(&peeraddr, socktext, sizeof(socktext));
  640         isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
  641                   NS_LOGMODULE_CONTROL, ISC_LOG_WARNING,
  642                   "rejected command channel message from %s",
  643                   socktext);
  644         isc_socket_detach(&sock);
  645         goto restart;
  646     }
  647 
  648     result = newconnection(listener, sock);
  649     if (result != ISC_R_SUCCESS) {
  650         char socktext[ISC_SOCKADDR_FORMATSIZE];
  651         isc_sockaddr_format(&peeraddr, socktext, sizeof(socktext));
  652         isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
  653                   NS_LOGMODULE_CONTROL, ISC_LOG_WARNING,
  654                   "dropped command channel from %s: %s",
  655                   socktext, isc_result_totext(result));
  656         isc_socket_detach(&sock);
  657         goto restart;
  658     }
  659 
  660  restart:
  661     control_next(listener);
  662  cleanup:
  663     isc_event_free(&event);
  664 }
  665 
  666 static void
  667 controls_shutdown(ns_controls_t *controls) {
  668     controllistener_t *listener;
  669     controllistener_t *next;
  670 
  671     for (listener = ISC_LIST_HEAD(controls->listeners);
  672          listener != NULL;
  673          listener = next)
  674     {
  675         /*
  676          * This is asynchronous.  As listeners shut down, they will
  677          * call their callbacks.
  678          */
  679         next = ISC_LIST_NEXT(listener, link);
  680         shutdown_listener(listener);
  681     }
  682 }
  683 
  684 void
  685 ns_controls_shutdown(ns_controls_t *controls) {
  686     controls_shutdown(controls);
  687     controls->shuttingdown = true;
  688 }
  689 
  690 static isc_result_t
  691 cfgkeylist_find(const cfg_obj_t *keylist, const char *keyname,
  692         const cfg_obj_t **objp)
  693 {
  694     const cfg_listelt_t *element;
  695     const char *str;
  696     const cfg_obj_t *obj;
  697 
  698     for (element = cfg_list_first(keylist);
  699          element != NULL;
  700          element = cfg_list_next(element))
  701     {
  702         obj = cfg_listelt_value(element);
  703         str = cfg_obj_asstring(cfg_map_getname(obj));
  704         if (strcasecmp(str, keyname) == 0)
  705             break;
  706     }
  707     if (element == NULL)
  708         return (ISC_R_NOTFOUND);
  709     obj = cfg_listelt_value(element);
  710     *objp = obj;
  711     return (ISC_R_SUCCESS);
  712 }
  713 
  714 static isc_result_t
  715 controlkeylist_fromcfg(const cfg_obj_t *keylist, isc_mem_t *mctx,
  716                controlkeylist_t *keyids)
  717 {
  718     const cfg_listelt_t *element;
  719     char *newstr = NULL;
  720     const char *str;
  721     const cfg_obj_t *obj;
  722     controlkey_t *key;
  723 
  724     for (element = cfg_list_first(keylist);
  725          element != NULL;
  726          element = cfg_list_next(element))
  727     {
  728         obj = cfg_listelt_value(element);
  729         str = cfg_obj_asstring(obj);
  730         newstr = isc_mem_strdup(mctx, str);
  731         if (newstr == NULL)
  732             goto cleanup;
  733         key = isc_mem_get(mctx, sizeof(*key));
  734         if (key == NULL)
  735             goto cleanup;
  736         key->keyname = newstr;
  737         key->algorithm = DST_ALG_UNKNOWN;
  738         key->secret.base = NULL;
  739         key->secret.length = 0;
  740         ISC_LINK_INIT(key, link);
  741         ISC_LIST_APPEND(*keyids, key, link);
  742         newstr = NULL;
  743     }
  744     return (ISC_R_SUCCESS);
  745 
  746  cleanup:
  747     if (newstr != NULL)
  748         isc_mem_free(mctx, newstr);
  749     free_controlkeylist(keyids, mctx);
  750     return (ISC_R_NOMEMORY);
  751 }
  752 
  753 static void
  754 register_keys(const cfg_obj_t *control, const cfg_obj_t *keylist,
  755           controlkeylist_t *keyids, isc_mem_t *mctx, const char *socktext)
  756 {
  757     controlkey_t *keyid, *next;
  758     const cfg_obj_t *keydef;
  759     char secret[1024];
  760     isc_buffer_t b;
  761     isc_result_t result;
  762 
  763     /*
  764      * Find the keys corresponding to the keyids used by this listener.
  765      */
  766     for (keyid = ISC_LIST_HEAD(*keyids); keyid != NULL; keyid = next) {
  767         next = ISC_LIST_NEXT(keyid, link);
  768 
  769         result = cfgkeylist_find(keylist, keyid->keyname, &keydef);
  770         if (result != ISC_R_SUCCESS) {
  771             cfg_obj_log(control, ns_g_lctx, ISC_LOG_WARNING,
  772                     "couldn't find key '%s' for use with "
  773                     "command channel %s",
  774                     keyid->keyname, socktext);
  775             ISC_LIST_UNLINK(*keyids, keyid, link);
  776             free_controlkey(keyid, mctx);
  777         } else {
  778             const cfg_obj_t *algobj = NULL;
  779             const cfg_obj_t *secretobj = NULL;
  780             const char *algstr = NULL;
  781             const char *secretstr = NULL;
  782             unsigned int algtype;
  783 
  784             (void)cfg_map_get(keydef, "algorithm", &algobj);
  785             (void)cfg_map_get(keydef, "secret", &secretobj);
  786             INSIST(algobj != NULL && secretobj != NULL);
  787 
  788             algstr = cfg_obj_asstring(algobj);
  789             secretstr = cfg_obj_asstring(secretobj);
  790 
  791             if (ns_config_getkeyalgorithm2(algstr, NULL,
  792                     &algtype, NULL) != ISC_R_SUCCESS)
  793             {
  794                 cfg_obj_log(control, ns_g_lctx,
  795                         ISC_LOG_WARNING,
  796                         "unsupported algorithm '%s' in "
  797                         "key '%s' for use with command "
  798                         "channel %s",
  799                         algstr, keyid->keyname, socktext);
  800                 ISC_LIST_UNLINK(*keyids, keyid, link);
  801                 free_controlkey(keyid, mctx);
  802                 continue;
  803             }
  804 
  805             keyid->algorithm = algtype;
  806             isc_buffer_init(&b, secret, sizeof(secret));
  807             result = isc_base64_decodestring(secretstr, &b);
  808 
  809             if (result != ISC_R_SUCCESS) {
  810                 cfg_obj_log(keydef, ns_g_lctx, ISC_LOG_WARNING,
  811                         "secret for key '%s' on "
  812                         "command channel %s: %s",
  813                         keyid->keyname, socktext,
  814                         isc_result_totext(result));
  815                 ISC_LIST_UNLINK(*keyids, keyid, link);
  816                 free_controlkey(keyid, mctx);
  817                 continue;
  818             }
  819 
  820             keyid->secret.length = isc_buffer_usedlength(&b);
  821             keyid->secret.base = isc_mem_get(mctx,
  822                              keyid->secret.length);
  823             if (keyid->secret.base == NULL) {
  824                 cfg_obj_log(keydef, ns_g_lctx, ISC_LOG_WARNING,
  825                        "couldn't register key '%s': "
  826                        "out of memory", keyid->keyname);
  827                 ISC_LIST_UNLINK(*keyids, keyid, link);
  828                 free_controlkey(keyid, mctx);
  829                 break;
  830             }
  831             memmove(keyid->secret.base, isc_buffer_base(&b),
  832                 keyid->secret.length);
  833         }
  834     }
  835 }
  836 
  837 #define CHECK(x) \
  838     do { \
  839          result = (x); \
  840          if (result != ISC_R_SUCCESS) \
  841             goto cleanup; \
  842     } while (0)
  843 
  844 static isc_result_t
  845 get_rndckey(isc_mem_t *mctx, controlkeylist_t *keyids) {
  846     isc_result_t result;
  847     cfg_parser_t *pctx = NULL;
  848     cfg_obj_t *config = NULL;
  849     const cfg_obj_t *key = NULL;
  850     const cfg_obj_t *algobj = NULL;
  851     const cfg_obj_t *secretobj = NULL;
  852     const char *algstr = NULL;
  853     const char *secretstr = NULL;
  854     controlkey_t *keyid = NULL;
  855     char secret[1024];
  856     unsigned int algtype;
  857     isc_buffer_t b;
  858 
  859     isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
  860               NS_LOGMODULE_CONTROL, ISC_LOG_INFO,
  861               "configuring command channel from '%s'",
  862               ns_g_keyfile);
  863     if (! isc_file_exists(ns_g_keyfile))
  864         return (ISC_R_FILENOTFOUND);
  865 
  866     CHECK(cfg_parser_create(mctx, ns_g_lctx, &pctx));
  867     CHECK(cfg_parse_file(pctx, ns_g_keyfile, &cfg_type_rndckey, &config));
  868     CHECK(cfg_map_get(config, "key", &key));
  869 
  870     keyid = isc_mem_get(mctx, sizeof(*keyid));
  871     if (keyid == NULL)
  872         CHECK(ISC_R_NOMEMORY);
  873     keyid->keyname = isc_mem_strdup(mctx,
  874                     cfg_obj_asstring(cfg_map_getname(key)));
  875     keyid->secret.base = NULL;
  876     keyid->secret.length = 0;
  877     keyid->algorithm = DST_ALG_UNKNOWN;
  878     ISC_LINK_INIT(keyid, link);
  879     if (keyid->keyname == NULL)
  880         CHECK(ISC_R_NOMEMORY);
  881 
  882     CHECK(bind9_check_key(key, ns_g_lctx));
  883 
  884     (void)cfg_map_get(key, "algorithm", &algobj);
  885     (void)cfg_map_get(key, "secret", &secretobj);
  886     INSIST(algobj != NULL && secretobj != NULL);
  887 
  888     algstr = cfg_obj_asstring(algobj);
  889     secretstr = cfg_obj_asstring(secretobj);
  890 
  891     if (ns_config_getkeyalgorithm2(algstr, NULL,
  892                        &algtype, NULL) != ISC_R_SUCCESS) {
  893         cfg_obj_log(key, ns_g_lctx,
  894                 ISC_LOG_WARNING,
  895                 "unsupported algorithm '%s' in "
  896                 "key '%s' for use with command "
  897                 "channel",
  898                 algstr, keyid->keyname);
  899         goto cleanup;
  900     }
  901 
  902     keyid->algorithm = algtype;
  903     isc_buffer_init(&b, secret, sizeof(secret));
  904     result = isc_base64_decodestring(secretstr, &b);
  905 
  906     if (result != ISC_R_SUCCESS) {
  907         cfg_obj_log(key, ns_g_lctx, ISC_LOG_WARNING,
  908                 "secret for key '%s' on command channel: %s",
  909                 keyid->keyname, isc_result_totext(result));
  910         goto cleanup;
  911     }
  912 
  913     keyid->secret.length = isc_buffer_usedlength(&b);
  914     keyid->secret.base = isc_mem_get(mctx,
  915                      keyid->secret.length);
  916     if (keyid->secret.base == NULL) {
  917         cfg_obj_log(key, ns_g_lctx, ISC_LOG_WARNING,
  918                "couldn't register key '%s': "
  919                "out of memory", keyid->keyname);
  920         CHECK(ISC_R_NOMEMORY);
  921     }
  922     memmove(keyid->secret.base, isc_buffer_base(&b),
  923         keyid->secret.length);
  924     ISC_LIST_APPEND(*keyids, keyid, link);
  925     keyid = NULL;
  926     result = ISC_R_SUCCESS;
  927 
  928   cleanup:
  929     if (keyid != NULL)
  930         free_controlkey(keyid, mctx);
  931     if (config != NULL)
  932         cfg_obj_destroy(pctx, &config);
  933     if (pctx != NULL)
  934         cfg_parser_destroy(&pctx);
  935     return (result);
  936 }
  937 
  938 /*
  939  * Ensures that both '*global_keylistp' and '*control_keylistp' are
  940  * valid or both are NULL.
  941  */
  942 static void
  943 get_key_info(const cfg_obj_t *config, const cfg_obj_t *control,
  944          const cfg_obj_t **global_keylistp,
  945          const cfg_obj_t **control_keylistp)
  946 {
  947     isc_result_t result;
  948     const cfg_obj_t *control_keylist = NULL;
  949     const cfg_obj_t *global_keylist = NULL;
  950 
  951     REQUIRE(global_keylistp != NULL && *global_keylistp == NULL);
  952     REQUIRE(control_keylistp != NULL && *control_keylistp == NULL);
  953 
  954     control_keylist = cfg_tuple_get(control, "keys");
  955 
  956     if (!cfg_obj_isvoid(control_keylist) &&
  957         cfg_list_first(control_keylist) != NULL) {
  958         result = cfg_map_get(config, "key", &global_keylist);
  959 
  960         if (result == ISC_R_SUCCESS) {
  961             *global_keylistp = global_keylist;
  962             *control_keylistp = control_keylist;
  963         }
  964     }
  965 }
  966 
  967 static void
  968 update_listener(ns_controls_t *cp, controllistener_t **listenerp,
  969         const cfg_obj_t *control, const cfg_obj_t *config,
  970         isc_sockaddr_t *addr, cfg_aclconfctx_t *aclconfctx,
  971         const char *socktext, isc_sockettype_t type)
  972 {
  973     controllistener_t *listener;
  974     const cfg_obj_t *allow;
  975     const cfg_obj_t *global_keylist = NULL;
  976     const cfg_obj_t *control_keylist = NULL;
  977     dns_acl_t *new_acl = NULL;
  978     controlkeylist_t keys;
  979     isc_result_t result = ISC_R_SUCCESS;
  980 
  981     for (listener = ISC_LIST_HEAD(cp->listeners);
  982          listener != NULL;
  983          listener = ISC_LIST_NEXT(listener, link))
  984         if (isc_sockaddr_equal(addr, &listener->address))
  985             break;
  986 
  987     if (listener == NULL) {
  988         *listenerp = NULL;
  989         return;
  990     }
  991 
  992     /*
  993      * There is already a listener for this sockaddr.
  994      * Update the access list and key information.
  995      *
  996      * First try to deal with the key situation.  There are a few
  997      * possibilities:
  998      *  (a) It had an explicit keylist and still has an explicit keylist.
  999      *  (b) It had an automagic key and now has an explicit keylist.
 1000      *  (c) It had an explicit keylist and now needs an automagic key.
 1001      *  (d) It has an automagic key and still needs the automagic key.
 1002      *
 1003      * (c) and (d) are the annoying ones.  The caller needs to know
 1004      * that it should use the automagic configuration for key information
 1005      * in place of the named.conf configuration.
 1006      *
 1007      * XXXDCL There is one other hazard that has not been dealt with,
 1008      * the problem that if a key change is being caused by a control
 1009      * channel reload, then the response will be with the new key
 1010      * and not able to be decrypted by the client.
 1011      */
 1012     if (control != NULL)
 1013         get_key_info(config, control, &global_keylist,
 1014                  &control_keylist);
 1015 
 1016     if (control_keylist != NULL) {
 1017         INSIST(global_keylist != NULL);
 1018 
 1019         ISC_LIST_INIT(keys);
 1020         result = controlkeylist_fromcfg(control_keylist,
 1021                         listener->mctx, &keys);
 1022         if (result == ISC_R_SUCCESS) {
 1023             free_controlkeylist(&listener->keys, listener->mctx);
 1024             listener->keys = keys;
 1025             register_keys(control, global_keylist, &listener->keys,
 1026                       listener->mctx, socktext);
 1027         }
 1028     } else {
 1029         free_controlkeylist(&listener->keys, listener->mctx);
 1030         result = get_rndckey(listener->mctx, &listener->keys);
 1031     }
 1032 
 1033     if (result != ISC_R_SUCCESS && global_keylist != NULL) {
 1034         /*
 1035          * This message might be a little misleading since the
 1036          * "new keys" might in fact be identical to the old ones,
 1037          * but tracking whether they are identical just for the
 1038          * sake of avoiding this message would be too much trouble.
 1039          */
 1040         if (control != NULL)
 1041             cfg_obj_log(control, ns_g_lctx, ISC_LOG_WARNING,
 1042                     "couldn't install new keys for "
 1043                     "command channel %s: %s",
 1044                     socktext, isc_result_totext(result));
 1045         else
 1046             isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
 1047                       NS_LOGMODULE_CONTROL, ISC_LOG_WARNING,
 1048                       "couldn't install new keys for "
 1049                       "command channel %s: %s",
 1050                       socktext, isc_result_totext(result));
 1051     }
 1052 
 1053     /*
 1054      * Now, keep the old access list unless a new one can be made.
 1055      */
 1056     if (control != NULL && type == isc_sockettype_tcp) {
 1057         allow = cfg_tuple_get(control, "allow");
 1058         result = cfg_acl_fromconfig(allow, config, ns_g_lctx,
 1059                         aclconfctx, listener->mctx, 0,
 1060                         &new_acl);
 1061     } else {
 1062         result = dns_acl_any(listener->mctx, &new_acl);
 1063     }
 1064 
 1065     if (control != NULL) {
 1066         const cfg_obj_t *readonly;
 1067 
 1068         readonly = cfg_tuple_get(control, "read-only");
 1069         if (!cfg_obj_isvoid(readonly))
 1070             listener->readonly = cfg_obj_asboolean(readonly);
 1071     }
 1072 
 1073     if (result == ISC_R_SUCCESS) {
 1074         dns_acl_detach(&listener->acl);
 1075         dns_acl_attach(new_acl, &listener->acl);
 1076         dns_acl_detach(&new_acl);
 1077         /* XXXDCL say the old acl is still used? */
 1078     } else if (control != NULL)
 1079         cfg_obj_log(control, ns_g_lctx, ISC_LOG_WARNING,
 1080                 "couldn't install new acl for "
 1081                 "command channel %s: %s",
 1082                 socktext, isc_result_totext(result));
 1083     else
 1084         isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
 1085                   NS_LOGMODULE_CONTROL, ISC_LOG_WARNING,
 1086                   "couldn't install new acl for "
 1087                   "command channel %s: %s",
 1088                   socktext, isc_result_totext(result));
 1089 
 1090     if (result == ISC_R_SUCCESS && type == isc_sockettype_unix) {
 1091         uint32_t perm, owner, group;
 1092         perm  = cfg_obj_asuint32(cfg_tuple_get(control, "perm"));
 1093         owner = cfg_obj_asuint32(cfg_tuple_get(control, "owner"));
 1094         group = cfg_obj_asuint32(cfg_tuple_get(control, "group"));
 1095         result = ISC_R_SUCCESS;
 1096         if (listener->perm != perm || listener->owner != owner ||
 1097             listener->group != group)
 1098             result = isc_socket_permunix(&listener->address, perm,
 1099                              owner, group);
 1100         if (result == ISC_R_SUCCESS) {
 1101             listener->perm = perm;
 1102             listener->owner = owner;
 1103             listener->group = group;
 1104         } else if (control != NULL)
 1105             cfg_obj_log(control, ns_g_lctx, ISC_LOG_WARNING,
 1106                     "couldn't update ownership/permission for "
 1107                     "command channel %s", socktext);
 1108     }
 1109 
 1110     *listenerp = listener;
 1111 }
 1112 
 1113 static void
 1114 add_listener(ns_controls_t *cp, controllistener_t **listenerp,
 1115          const cfg_obj_t *control, const cfg_obj_t *config,
 1116          isc_sockaddr_t *addr, cfg_aclconfctx_t *aclconfctx,
 1117          const char *socktext, isc_sockettype_t type)
 1118 {
 1119     isc_mem_t *mctx = cp->server->mctx;
 1120     controllistener_t *listener;
 1121     const cfg_obj_t *allow;
 1122     const cfg_obj_t *global_keylist = NULL;
 1123     const cfg_obj_t *control_keylist = NULL;
 1124     dns_acl_t *new_acl = NULL;
 1125     isc_result_t result = ISC_R_SUCCESS;
 1126 
 1127     listener = isc_mem_get(mctx, sizeof(*listener));
 1128     if (listener == NULL)
 1129         result = ISC_R_NOMEMORY;
 1130 
 1131     if (result == ISC_R_SUCCESS) {
 1132         listener->mctx = NULL;
 1133         isc_mem_attach(mctx, &listener->mctx);
 1134         listener->controls = cp;
 1135         listener->task = cp->server->task;
 1136         listener->address = *addr;
 1137         listener->sock = NULL;
 1138         listener->listening = false;
 1139         listener->exiting = false;
 1140         listener->acl = NULL;
 1141         listener->type = type;
 1142         listener->perm = 0;
 1143         listener->owner = 0;
 1144         listener->group = 0;
 1145         listener->readonly = false;
 1146         ISC_LINK_INIT(listener, link);
 1147         ISC_LIST_INIT(listener->keys);
 1148         ISC_LIST_INIT(listener->connections);
 1149 
 1150         /*
 1151          * Make the acl.
 1152          */
 1153         if (control != NULL && type == isc_sockettype_tcp) {
 1154             allow = cfg_tuple_get(control, "allow");
 1155             result = cfg_acl_fromconfig(allow, config, ns_g_lctx,
 1156                             aclconfctx, mctx, 0,
 1157                             &new_acl);
 1158         } else {
 1159             result = dns_acl_any(mctx, &new_acl);
 1160         }
 1161     }
 1162 
 1163     if ((result == ISC_R_SUCCESS) && (control != NULL)) {
 1164         const cfg_obj_t *readonly;
 1165 
 1166         readonly = cfg_tuple_get(control, "read-only");
 1167         if (!cfg_obj_isvoid(readonly))
 1168             listener->readonly = cfg_obj_asboolean(readonly);
 1169     }
 1170 
 1171     if (result == ISC_R_SUCCESS) {
 1172         dns_acl_attach(new_acl, &listener->acl);
 1173         dns_acl_detach(&new_acl);
 1174 
 1175         if (config != NULL)
 1176             get_key_info(config, control, &global_keylist,
 1177                      &control_keylist);
 1178 
 1179         if (control_keylist != NULL) {
 1180             result = controlkeylist_fromcfg(control_keylist,
 1181                             listener->mctx,
 1182                             &listener->keys);
 1183             if (result == ISC_R_SUCCESS)
 1184                 register_keys(control, global_keylist,
 1185                           &listener->keys,
 1186                           listener->mctx, socktext);
 1187         } else
 1188             result = get_rndckey(mctx, &listener->keys);
 1189 
 1190         if (result != ISC_R_SUCCESS && control != NULL)
 1191             cfg_obj_log(control, ns_g_lctx, ISC_LOG_WARNING,
 1192                     "couldn't install keys for "
 1193                     "command channel %s: %s",
 1194                     socktext, isc_result_totext(result));
 1195     }
 1196 
 1197     if (result == ISC_R_SUCCESS) {
 1198         int pf = isc_sockaddr_pf(&listener->address);
 1199         if ((pf == AF_INET && isc_net_probeipv4() != ISC_R_SUCCESS) ||
 1200 #ifdef ISC_PLATFORM_HAVESYSUNH
 1201             (pf == AF_UNIX && isc_net_probeunix() != ISC_R_SUCCESS) ||
 1202 #endif
 1203             (pf == AF_INET6 && isc_net_probeipv6() != ISC_R_SUCCESS))
 1204             result = ISC_R_FAMILYNOSUPPORT;
 1205     }
 1206 
 1207     if (result == ISC_R_SUCCESS && type == isc_sockettype_unix)
 1208         isc_socket_cleanunix(&listener->address, false);
 1209 
 1210     if (result == ISC_R_SUCCESS)
 1211         result = isc_socket_create(ns_g_socketmgr,
 1212                        isc_sockaddr_pf(&listener->address),
 1213                        type, &listener->sock);
 1214     if (result == ISC_R_SUCCESS)
 1215         isc_socket_setname(listener->sock, "control", NULL);
 1216 
 1217 #ifndef ISC_ALLOW_MAPPED
 1218     if (result == ISC_R_SUCCESS)
 1219         isc_socket_ipv6only(listener->sock, true);
 1220 #endif
 1221 
 1222     if (result == ISC_R_SUCCESS)
 1223         result = isc_socket_bind(listener->sock, &listener->address,
 1224                      ISC_SOCKET_REUSEADDRESS);
 1225 
 1226     if (result == ISC_R_SUCCESS && type == isc_sockettype_unix) {
 1227         listener->perm = cfg_obj_asuint32(cfg_tuple_get(control,
 1228                                 "perm"));
 1229         listener->owner = cfg_obj_asuint32(cfg_tuple_get(control,
 1230                                  "owner"));
 1231         listener->group = cfg_obj_asuint32(cfg_tuple_get(control,
 1232                                  "group"));
 1233         result = isc_socket_permunix(&listener->address, listener->perm,
 1234                          listener->owner, listener->group);
 1235     }
 1236     if (result == ISC_R_SUCCESS)
 1237         result = control_listen(listener);
 1238 
 1239     if (result == ISC_R_SUCCESS)
 1240         result = control_accept(listener);
 1241 
 1242     if (result == ISC_R_SUCCESS) {
 1243         isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
 1244                   NS_LOGMODULE_CONTROL, ISC_LOG_NOTICE,
 1245                   "command channel listening on %s", socktext);
 1246         *listenerp = listener;
 1247 
 1248     } else {
 1249         if (listener != NULL) {
 1250             listener->exiting = true;
 1251             free_listener(listener);
 1252         }
 1253 
 1254         if (control != NULL)
 1255             cfg_obj_log(control, ns_g_lctx, ISC_LOG_WARNING,
 1256                     "couldn't add command channel %s: %s",
 1257                     socktext, isc_result_totext(result));
 1258         else
 1259             isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
 1260                       NS_LOGMODULE_CONTROL, ISC_LOG_NOTICE,
 1261                       "couldn't add command channel %s: %s",
 1262                       socktext, isc_result_totext(result));
 1263 
 1264         *listenerp = NULL;
 1265     }
 1266 
 1267     /* XXXDCL return error results? fail hard? */
 1268 }
 1269 
 1270 isc_result_t
 1271 ns_controls_configure(ns_controls_t *cp, const cfg_obj_t *config,
 1272               cfg_aclconfctx_t *aclconfctx)
 1273 {
 1274     controllistener_t *listener;
 1275     controllistenerlist_t new_listeners;
 1276     const cfg_obj_t *controlslist = NULL;
 1277     const cfg_listelt_t *element, *element2;
 1278     char socktext[ISC_SOCKADDR_FORMATSIZE];
 1279 
 1280     ISC_LIST_INIT(new_listeners);
 1281 
 1282     /*
 1283      * Get the list of named.conf 'controls' statements.
 1284      */
 1285     (void)cfg_map_get(config, "controls", &controlslist);
 1286 
 1287     /*
 1288      * Run through the new control channel list, noting sockets that
 1289      * are already being listened on and moving them to the new list.
 1290      *
 1291      * Identifying duplicate addr/port combinations is left to either
 1292      * the underlying config code, or to the bind attempt getting an
 1293      * address-in-use error.
 1294      */
 1295     if (controlslist != NULL) {
 1296         for (element = cfg_list_first(controlslist);
 1297              element != NULL;
 1298              element = cfg_list_next(element)) {
 1299             const cfg_obj_t *controls;
 1300             const cfg_obj_t *inetcontrols = NULL;
 1301 
 1302             controls = cfg_listelt_value(element);
 1303             (void)cfg_map_get(controls, "inet", &inetcontrols);
 1304             if (inetcontrols == NULL)
 1305                 continue;
 1306 
 1307             for (element2 = cfg_list_first(inetcontrols);
 1308                  element2 != NULL;
 1309                  element2 = cfg_list_next(element2)) {
 1310                 const cfg_obj_t *control;
 1311                 const cfg_obj_t *obj;
 1312                 isc_sockaddr_t addr;
 1313 
 1314                 /*
 1315                  * The parser handles BIND 8 configuration file
 1316                  * syntax, so it allows unix phrases as well
 1317                  * inet phrases with no keys{} clause.
 1318                  */
 1319                 control = cfg_listelt_value(element2);
 1320 
 1321                 obj = cfg_tuple_get(control, "address");
 1322                 addr = *cfg_obj_assockaddr(obj);
 1323                 if (isc_sockaddr_getport(&addr) == 0)
 1324                     isc_sockaddr_setport(&addr,
 1325                                  NS_CONTROL_PORT);
 1326 
 1327                 isc_sockaddr_format(&addr, socktext,
 1328                             sizeof(socktext));
 1329 
 1330                 isc_log_write(ns_g_lctx,
 1331                           NS_LOGCATEGORY_GENERAL,
 1332                           NS_LOGMODULE_CONTROL,
 1333                           ISC_LOG_DEBUG(9),
 1334                           "processing control channel %s",
 1335                           socktext);
 1336 
 1337                 update_listener(cp, &listener, control, config,
 1338                         &addr, aclconfctx, socktext,
 1339                         isc_sockettype_tcp);
 1340 
 1341                 if (listener != NULL)
 1342                     /*
 1343                      * Remove the listener from the old
 1344                      * list, so it won't be shut down.
 1345                      */
 1346                     ISC_LIST_UNLINK(cp->listeners,
 1347                             listener, link);
 1348                 else
 1349                     /*
 1350                      * This is a new listener.
 1351                      */
 1352                     add_listener(cp, &listener, control,
 1353                              config, &addr, aclconfctx,
 1354                              socktext,
 1355                              isc_sockettype_tcp);
 1356 
 1357                 if (listener != NULL)
 1358                     ISC_LIST_APPEND(new_listeners,
 1359                             listener, link);
 1360             }
 1361         }
 1362         for (element = cfg_list_first(controlslist);
 1363              element != NULL;
 1364              element = cfg_list_next(element)) {
 1365             const cfg_obj_t *controls;
 1366             const cfg_obj_t *unixcontrols = NULL;
 1367 
 1368             controls = cfg_listelt_value(element);
 1369             (void)cfg_map_get(controls, "unix", &unixcontrols);
 1370             if (unixcontrols == NULL)
 1371                 continue;
 1372 
 1373             for (element2 = cfg_list_first(unixcontrols);
 1374                  element2 != NULL;
 1375                  element2 = cfg_list_next(element2)) {
 1376                 const cfg_obj_t *control;
 1377                 const cfg_obj_t *path;
 1378                 isc_sockaddr_t addr;
 1379                 isc_result_t result;
 1380 
 1381                 /*
 1382                  * The parser handles BIND 8 configuration file
 1383                  * syntax, so it allows unix phrases as well
 1384                  * inet phrases with no keys{} clause.
 1385                  */
 1386                 control = cfg_listelt_value(element2);
 1387 
 1388                 path = cfg_tuple_get(control, "path");
 1389                 result = isc_sockaddr_frompath(&addr,
 1390                               cfg_obj_asstring(path));
 1391                 if (result != ISC_R_SUCCESS) {
 1392                     isc_log_write(ns_g_lctx,
 1393                           NS_LOGCATEGORY_GENERAL,
 1394                           NS_LOGMODULE_CONTROL,
 1395                           ISC_LOG_DEBUG(9),
 1396                           "control channel '%s': %s",
 1397                           cfg_obj_asstring(path),
 1398                           isc_result_totext(result));
 1399                     continue;
 1400                 }
 1401 
 1402                 isc_log_write(ns_g_lctx,
 1403                           NS_LOGCATEGORY_GENERAL,
 1404                           NS_LOGMODULE_CONTROL,
 1405                           ISC_LOG_DEBUG(9),
 1406                           "processing control channel '%s'",
 1407                           cfg_obj_asstring(path));
 1408 
 1409                 update_listener(cp, &listener, control, config,
 1410                         &addr, aclconfctx,
 1411                         cfg_obj_asstring(path),
 1412                         isc_sockettype_unix);
 1413 
 1414                 if (listener != NULL)
 1415                     /*
 1416                      * Remove the listener from the old
 1417                      * list, so it won't be shut down.
 1418                      */
 1419                     ISC_LIST_UNLINK(cp->listeners,
 1420                             listener, link);
 1421                 else
 1422                     /*
 1423                      * This is a new listener.
 1424                      */
 1425                     add_listener(cp, &listener, control,
 1426                              config, &addr, aclconfctx,
 1427                              cfg_obj_asstring(path),
 1428                              isc_sockettype_unix);
 1429 
 1430                 if (listener != NULL)
 1431                     ISC_LIST_APPEND(new_listeners,
 1432                             listener, link);
 1433             }
 1434         }
 1435     } else {
 1436         int i;
 1437 
 1438         for (i = 0; i < 2; i++) {
 1439             isc_sockaddr_t addr;
 1440 
 1441             if (i == 0) {
 1442                 struct in_addr localhost;
 1443 
 1444                 if (isc_net_probeipv4() != ISC_R_SUCCESS)
 1445                     continue;
 1446                 localhost.s_addr = htonl(INADDR_LOOPBACK);
 1447                 isc_sockaddr_fromin(&addr, &localhost, 0);
 1448             } else {
 1449                 if (isc_net_probeipv6() != ISC_R_SUCCESS)
 1450                     continue;
 1451                 isc_sockaddr_fromin6(&addr,
 1452                              &in6addr_loopback, 0);
 1453             }
 1454             isc_sockaddr_setport(&addr, NS_CONTROL_PORT);
 1455 
 1456             isc_sockaddr_format(&addr, socktext, sizeof(socktext));
 1457 
 1458             update_listener(cp, &listener, NULL, NULL,
 1459                     &addr, NULL, socktext,
 1460                     isc_sockettype_tcp);
 1461 
 1462             if (listener != NULL)
 1463                 /*
 1464                  * Remove the listener from the old
 1465                  * list, so it won't be shut down.
 1466                  */
 1467                 ISC_LIST_UNLINK(cp->listeners,
 1468                         listener, link);
 1469             else
 1470                 /*
 1471                  * This is a new listener.
 1472                  */
 1473                 add_listener(cp, &listener, NULL, NULL,
 1474                          &addr, NULL, socktext,
 1475                          isc_sockettype_tcp);
 1476 
 1477             if (listener != NULL)
 1478                 ISC_LIST_APPEND(new_listeners,
 1479                         listener, link);
 1480         }
 1481     }
 1482 
 1483     /*
 1484      * ns_control_shutdown() will stop whatever is on the global
 1485      * listeners list, which currently only has whatever sockaddrs
 1486      * were in the previous configuration (if any) that do not
 1487      * remain in the current configuration.
 1488      */
 1489     controls_shutdown(cp);
 1490 
 1491     /*
 1492      * Put all of the valid listeners on the listeners list.
 1493      * Anything already on listeners in the process of shutting
 1494      * down will be taken care of by listen_done().
 1495      */
 1496     ISC_LIST_APPENDLIST(cp->listeners, new_listeners, link);
 1497     return (ISC_R_SUCCESS);
 1498 }
 1499 
 1500 isc_result_t
 1501 ns_controls_create(ns_server_t *server, ns_controls_t **ctrlsp) {
 1502     isc_mem_t *mctx = server->mctx;
 1503     isc_result_t result;
 1504     ns_controls_t *controls = isc_mem_get(mctx, sizeof(*controls));
 1505 
 1506     if (controls == NULL)
 1507         return (ISC_R_NOMEMORY);
 1508     controls->server = server;
 1509     ISC_LIST_INIT(controls->listeners);
 1510     controls->shuttingdown = false;
 1511     controls->symtab = NULL;
 1512     result = isccc_cc_createsymtab(&controls->symtab);
 1513     if (result != ISC_R_SUCCESS) {
 1514         isc_mem_put(server->mctx, controls, sizeof(*controls));
 1515         return (result);
 1516     }
 1517     *ctrlsp = controls;
 1518     return (ISC_R_SUCCESS);
 1519 }
 1520 
 1521 void
 1522 ns_controls_destroy(ns_controls_t **ctrlsp) {
 1523     ns_controls_t *controls = *ctrlsp;
 1524 
 1525     REQUIRE(ISC_LIST_EMPTY(controls->listeners));
 1526 
 1527     isccc_symtab_destroy(&controls->symtab);
 1528     isc_mem_put(controls->server->mctx, controls, sizeof(*controls));
 1529     *ctrlsp = NULL;
 1530 }