controlconf.c

Go to the documentation of this file.
00001 /*
00002  * Copyright (C) 2004-2008, 2011-2014  Internet Systems Consortium, Inc. ("ISC")
00003  * Copyright (C) 2001-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 /* $Id: controlconf.c,v 1.63 2011/12/22 08:07:48 marka Exp $ */
00019 
00020 /*! \file */
00021 
00022 #include <config.h>
00023 
00024 #include <isc/base64.h>
00025 #include <isc/buffer.h>
00026 #include <isc/event.h>
00027 #include <isc/file.h>
00028 #include <isc/mem.h>
00029 #include <isc/net.h>
00030 #include <isc/netaddr.h>
00031 #include <isc/random.h>
00032 #include <isc/result.h>
00033 #include <isc/stdtime.h>
00034 #include <isc/string.h>
00035 #include <isc/timer.h>
00036 #include <isc/util.h>
00037 
00038 #include <isccfg/namedconf.h>
00039 
00040 #include <bind9/check.h>
00041 
00042 #include <isccc/alist.h>
00043 #include <isccc/cc.h>
00044 #include <isccc/ccmsg.h>
00045 #include <isccc/events.h>
00046 #include <isccc/result.h>
00047 #include <isccc/sexpr.h>
00048 #include <isccc/symtab.h>
00049 #include <isccc/util.h>
00050 
00051 #include <dns/result.h>
00052 
00053 #include <named/config.h>
00054 #include <named/control.h>
00055 #include <named/log.h>
00056 #include <named/server.h>
00057 
00058 /*
00059  * Note: Listeners and connections are not locked.  All event handlers are
00060  * executed by the server task, and all callers of exported routines must
00061  * be running under the server task.
00062  */
00063 
00064 typedef struct controlkey controlkey_t;
00065 typedef ISC_LIST(controlkey_t) controlkeylist_t;
00066 
00067 typedef struct controlconnection controlconnection_t;
00068 typedef ISC_LIST(controlconnection_t) controlconnectionlist_t;
00069 
00070 typedef struct controllistener controllistener_t;
00071 typedef ISC_LIST(controllistener_t) controllistenerlist_t;
00072 
00073 struct controlkey {
00074         char *                          keyname;
00075         isc_uint32_t                    algorithm;
00076         isc_region_t                    secret;
00077         ISC_LINK(controlkey_t)          link;
00078 };
00079 
00080 struct controlconnection {
00081         isc_socket_t *                  sock;
00082         isccc_ccmsg_t                   ccmsg;
00083         isc_boolean_t                   ccmsg_valid;
00084         isc_boolean_t                   sending;
00085         isc_timer_t *                   timer;
00086         isc_buffer_t *                  buffer;
00087         controllistener_t *             listener;
00088         isc_uint32_t                    nonce;
00089         ISC_LINK(controlconnection_t)   link;
00090 };
00091 
00092 struct controllistener {
00093         ns_controls_t *                 controls;
00094         isc_mem_t *                     mctx;
00095         isc_task_t *                    task;
00096         isc_sockaddr_t                  address;
00097         isc_socket_t *                  sock;
00098         dns_acl_t *                     acl;
00099         isc_boolean_t                   listening;
00100         isc_boolean_t                   exiting;
00101         controlkeylist_t                keys;
00102         controlconnectionlist_t         connections;
00103         isc_sockettype_t                type;
00104         isc_uint32_t                    perm;
00105         isc_uint32_t                    owner;
00106         isc_uint32_t                    group;
00107         ISC_LINK(controllistener_t)     link;
00108 };
00109 
00110 struct ns_controls {
00111         ns_server_t                     *server;
00112         controllistenerlist_t           listeners;
00113         isc_boolean_t                   shuttingdown;
00114         isccc_symtab_t                  *symtab;
00115 };
00116 
00117 static void control_newconn(isc_task_t *task, isc_event_t *event);
00118 static void control_recvmessage(isc_task_t *task, isc_event_t *event);
00119 
00120 #define CLOCKSKEW 300
00121 
00122 static void
00123 free_controlkey(controlkey_t *key, isc_mem_t *mctx) {
00124         if (key->keyname != NULL)
00125                 isc_mem_free(mctx, key->keyname);
00126         if (key->secret.base != NULL)
00127                 isc_mem_put(mctx, key->secret.base, key->secret.length);
00128         isc_mem_put(mctx, key, sizeof(*key));
00129 }
00130 
00131 static void
00132 free_controlkeylist(controlkeylist_t *keylist, isc_mem_t *mctx) {
00133         while (!ISC_LIST_EMPTY(*keylist)) {
00134                 controlkey_t *key = ISC_LIST_HEAD(*keylist);
00135                 ISC_LIST_UNLINK(*keylist, key, link);
00136                 free_controlkey(key, mctx);
00137         }
00138 }
00139 
00140 static void
00141 free_listener(controllistener_t *listener) {
00142         INSIST(listener->exiting);
00143         INSIST(!listener->listening);
00144         INSIST(ISC_LIST_EMPTY(listener->connections));
00145 
00146         if (listener->sock != NULL)
00147                 isc_socket_detach(&listener->sock);
00148 
00149         free_controlkeylist(&listener->keys, listener->mctx);
00150 
00151         if (listener->acl != NULL)
00152                 dns_acl_detach(&listener->acl);
00153 
00154         isc_mem_putanddetach(&listener->mctx, listener, sizeof(*listener));
00155 }
00156 
00157 static void
00158 maybe_free_listener(controllistener_t *listener) {
00159         if (listener->exiting &&
00160             !listener->listening &&
00161             ISC_LIST_EMPTY(listener->connections))
00162                 free_listener(listener);
00163 }
00164 
00165 static void
00166 maybe_free_connection(controlconnection_t *conn) {
00167         controllistener_t *listener = conn->listener;
00168 
00169         if (conn->buffer != NULL)
00170                 isc_buffer_free(&conn->buffer);
00171 
00172         if (conn->timer != NULL)
00173                 isc_timer_detach(&conn->timer);
00174 
00175         if (conn->ccmsg_valid) {
00176                 isccc_ccmsg_cancelread(&conn->ccmsg);
00177                 return;
00178         }
00179 
00180         if (conn->sending) {
00181                 isc_socket_cancel(conn->sock, listener->task,
00182                                   ISC_SOCKCANCEL_SEND);
00183                 return;
00184         }
00185 
00186         ISC_LIST_UNLINK(listener->connections, conn, link);
00187         isc_mem_put(listener->mctx, conn, sizeof(*conn));
00188 }
00189 
00190 static void
00191 shutdown_listener(controllistener_t *listener) {
00192         controlconnection_t *conn;
00193         controlconnection_t *next;
00194 
00195         if (!listener->exiting) {
00196                 char socktext[ISC_SOCKADDR_FORMATSIZE];
00197 
00198                 ISC_LIST_UNLINK(listener->controls->listeners, listener, link);
00199 
00200                 isc_sockaddr_format(&listener->address, socktext,
00201                                     sizeof(socktext));
00202                 isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
00203                               NS_LOGMODULE_CONTROL, ISC_LOG_NOTICE,
00204                               "stopping command channel on %s", socktext);
00205                 if (listener->type == isc_sockettype_unix)
00206                         isc_socket_cleanunix(&listener->address, ISC_TRUE);
00207                 listener->exiting = ISC_TRUE;
00208         }
00209 
00210         for (conn = ISC_LIST_HEAD(listener->connections);
00211              conn != NULL;
00212              conn = next)
00213         {
00214                 next = ISC_LIST_NEXT(conn, link);
00215                 maybe_free_connection(conn);
00216         }
00217 
00218         if (listener->listening)
00219                 isc_socket_cancel(listener->sock, listener->task,
00220                                   ISC_SOCKCANCEL_ACCEPT);
00221 
00222         maybe_free_listener(listener);
00223 }
00224 
00225 static isc_boolean_t
00226 address_ok(isc_sockaddr_t *sockaddr, dns_acl_t *acl) {
00227         isc_netaddr_t netaddr;
00228         isc_result_t result;
00229         int match;
00230 
00231         isc_netaddr_fromsockaddr(&netaddr, sockaddr);
00232 
00233         result = dns_acl_match(&netaddr, NULL, acl,
00234                                &ns_g_server->aclenv, &match, NULL);
00235 
00236         if (result != ISC_R_SUCCESS || match <= 0)
00237                 return (ISC_FALSE);
00238         else
00239                 return (ISC_TRUE);
00240 }
00241 
00242 static isc_result_t
00243 control_accept(controllistener_t *listener) {
00244         isc_result_t result;
00245         result = isc_socket_accept(listener->sock,
00246                                    listener->task,
00247                                    control_newconn, listener);
00248         if (result != ISC_R_SUCCESS)
00249                 UNEXPECTED_ERROR(__FILE__, __LINE__,
00250                                  "isc_socket_accept() failed: %s",
00251                                  isc_result_totext(result));
00252         else
00253                 listener->listening = ISC_TRUE;
00254         return (result);
00255 }
00256 
00257 static isc_result_t
00258 control_listen(controllistener_t *listener) {
00259         isc_result_t result;
00260 
00261         result = isc_socket_listen(listener->sock, 0);
00262         if (result != ISC_R_SUCCESS)
00263                 UNEXPECTED_ERROR(__FILE__, __LINE__,
00264                                  "isc_socket_listen() failed: %s",
00265                                  isc_result_totext(result));
00266         return (result);
00267 }
00268 
00269 static void
00270 control_next(controllistener_t *listener) {
00271         (void)control_accept(listener);
00272 }
00273 
00274 static void
00275 control_senddone(isc_task_t *task, isc_event_t *event) {
00276         isc_socketevent_t *sevent = (isc_socketevent_t *) event;
00277         controlconnection_t *conn = event->ev_arg;
00278         controllistener_t *listener = conn->listener;
00279         isc_socket_t *sock = (isc_socket_t *)sevent->ev_sender;
00280         isc_result_t result;
00281 
00282         REQUIRE(conn->sending);
00283 
00284         UNUSED(task);
00285 
00286         conn->sending = ISC_FALSE;
00287 
00288         if (sevent->result != ISC_R_SUCCESS &&
00289             sevent->result != ISC_R_CANCELED)
00290         {
00291                 char socktext[ISC_SOCKADDR_FORMATSIZE];
00292                 isc_sockaddr_t peeraddr;
00293 
00294                 (void)isc_socket_getpeername(sock, &peeraddr);
00295                 isc_sockaddr_format(&peeraddr, socktext, sizeof(socktext));
00296                 isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
00297                               NS_LOGMODULE_CONTROL, ISC_LOG_WARNING,
00298                               "error sending command response to %s: %s",
00299                               socktext, isc_result_totext(sevent->result));
00300         }
00301         isc_event_free(&event);
00302 
00303         result = isccc_ccmsg_readmessage(&conn->ccmsg, listener->task,
00304                                          control_recvmessage, conn);
00305         if (result != ISC_R_SUCCESS) {
00306                 isc_socket_detach(&conn->sock);
00307                 maybe_free_connection(conn);
00308                 maybe_free_listener(listener);
00309         }
00310 }
00311 
00312 static inline void
00313 log_invalid(isccc_ccmsg_t *ccmsg, isc_result_t result) {
00314         char socktext[ISC_SOCKADDR_FORMATSIZE];
00315         isc_sockaddr_t peeraddr;
00316 
00317         (void)isc_socket_getpeername(ccmsg->sock, &peeraddr);
00318         isc_sockaddr_format(&peeraddr, socktext, sizeof(socktext));
00319         isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
00320                       NS_LOGMODULE_CONTROL, ISC_LOG_ERROR,
00321                       "invalid command from %s: %s",
00322                       socktext, isc_result_totext(result));
00323 }
00324 
00325 static void
00326 control_recvmessage(isc_task_t *task, isc_event_t *event) {
00327         controlconnection_t *conn;
00328         controllistener_t *listener;
00329         controlkey_t *key;
00330         isccc_sexpr_t *request = NULL;
00331         isccc_sexpr_t *response = NULL;
00332         isc_uint32_t algorithm;
00333         isccc_region_t secret;
00334         isc_stdtime_t now;
00335         isc_buffer_t b;
00336         isc_region_t r;
00337         isc_buffer_t *text;
00338         isc_result_t result;
00339         isc_result_t eresult;
00340         isccc_sexpr_t *_ctrl;
00341         isccc_time_t sent;
00342         isccc_time_t exp;
00343         isc_uint32_t nonce;
00344 
00345         REQUIRE(event->ev_type == ISCCC_EVENT_CCMSG);
00346 
00347         conn = event->ev_arg;
00348         listener = conn->listener;
00349         algorithm = DST_ALG_UNKNOWN;
00350         secret.rstart = NULL;
00351         text = NULL;
00352 
00353         /* Is the server shutting down? */
00354         if (listener->controls->shuttingdown)
00355                 goto cleanup;
00356 
00357         if (conn->ccmsg.result != ISC_R_SUCCESS) {
00358                 if (conn->ccmsg.result != ISC_R_CANCELED &&
00359                     conn->ccmsg.result != ISC_R_EOF)
00360                         log_invalid(&conn->ccmsg, conn->ccmsg.result);
00361                 goto cleanup;
00362         }
00363 
00364         request = NULL;
00365 
00366         for (key = ISC_LIST_HEAD(listener->keys);
00367              key != NULL;
00368              key = ISC_LIST_NEXT(key, link))
00369         {
00370                 isccc_region_t ccregion;
00371 
00372                 ccregion.rstart = isc_buffer_base(&conn->ccmsg.buffer);
00373                 ccregion.rend = isc_buffer_used(&conn->ccmsg.buffer);
00374                 secret.rstart = isc_mem_get(listener->mctx, key->secret.length);
00375                 if (secret.rstart == NULL)
00376                         goto cleanup;
00377                 memmove(secret.rstart, key->secret.base, key->secret.length);
00378                 secret.rend = secret.rstart + key->secret.length;
00379                 algorithm = key->algorithm;
00380                 result = isccc_cc_fromwire(&ccregion, &request,
00381                                            algorithm, &secret);
00382                 if (result == ISC_R_SUCCESS)
00383                         break;
00384                 isc_mem_put(listener->mctx, secret.rstart, REGION_SIZE(secret));
00385                 if (result != ISCCC_R_BADAUTH) {
00386                         log_invalid(&conn->ccmsg, result);
00387                         goto cleanup;
00388                 }
00389         }
00390 
00391         if (key == NULL) {
00392                 log_invalid(&conn->ccmsg, ISCCC_R_BADAUTH);
00393                 goto cleanup;
00394         }
00395 
00396         /* We shouldn't be getting a reply. */
00397         if (isccc_cc_isreply(request)) {
00398                 log_invalid(&conn->ccmsg, ISC_R_FAILURE);
00399                 goto cleanup_request;
00400         }
00401 
00402         isc_stdtime_get(&now);
00403 
00404         /*
00405          * Limit exposure to replay attacks.
00406          */
00407         _ctrl = isccc_alist_lookup(request, "_ctrl");
00408         if (_ctrl == NULL) {
00409                 log_invalid(&conn->ccmsg, ISC_R_FAILURE);
00410                 goto cleanup_request;
00411         }
00412 
00413         if (isccc_cc_lookupuint32(_ctrl, "_tim", &sent) == ISC_R_SUCCESS) {
00414                 if ((sent + CLOCKSKEW) < now || (sent - CLOCKSKEW) > now) {
00415                         log_invalid(&conn->ccmsg, ISCCC_R_CLOCKSKEW);
00416                         goto cleanup_request;
00417                 }
00418         } else {
00419                 log_invalid(&conn->ccmsg, ISC_R_FAILURE);
00420                 goto cleanup_request;
00421         }
00422 
00423         /*
00424          * Expire messages that are too old.
00425          */
00426         if (isccc_cc_lookupuint32(_ctrl, "_exp", &exp) == ISC_R_SUCCESS &&
00427             now > exp) {
00428                 log_invalid(&conn->ccmsg, ISCCC_R_EXPIRED);
00429                 goto cleanup_request;
00430         }
00431 
00432         /*
00433          * Duplicate suppression (required for UDP).
00434          */
00435         isccc_cc_cleansymtab(listener->controls->symtab, now);
00436         result = isccc_cc_checkdup(listener->controls->symtab, request, now);
00437         if (result != ISC_R_SUCCESS) {
00438                 if (result == ISC_R_EXISTS)
00439                         result = ISCCC_R_DUPLICATE;
00440                 log_invalid(&conn->ccmsg, result);
00441                 goto cleanup_request;
00442         }
00443 
00444         if (conn->nonce != 0 &&
00445             (isccc_cc_lookupuint32(_ctrl, "_nonce", &nonce) != ISC_R_SUCCESS ||
00446              conn->nonce != nonce)) {
00447                 log_invalid(&conn->ccmsg, ISCCC_R_BADAUTH);
00448                 goto cleanup_request;
00449         }
00450 
00451         result = isc_buffer_allocate(listener->mctx, &text, 2 * 2048);
00452         if (result != ISC_R_SUCCESS)
00453                 goto cleanup_request;
00454 
00455         /*
00456          * Establish nonce.
00457          */
00458         if (conn->nonce == 0) {
00459                 while (conn->nonce == 0)
00460                         isc_random_get(&conn->nonce);
00461                 eresult = ISC_R_SUCCESS;
00462         } else
00463                 eresult = ns_control_docommand(request, &text);
00464 
00465         result = isccc_cc_createresponse(request, now, now + 60, &response);
00466         if (result != ISC_R_SUCCESS)
00467                 goto cleanup_request;
00468         if (eresult != ISC_R_SUCCESS) {
00469                 isccc_sexpr_t *data;
00470 
00471                 data = isccc_alist_lookup(response, "_data");
00472                 if (data != NULL) {
00473                         const char *estr = isc_result_totext(eresult);
00474                         if (isccc_cc_definestring(data, "err", estr) == NULL)
00475                                 goto cleanup_response;
00476                 }
00477         }
00478 
00479         if (isc_buffer_usedlength(text) > 0) {
00480                 isccc_sexpr_t *data;
00481 
00482                 data = isccc_alist_lookup(response, "_data");
00483                 if (data != NULL) {
00484                         char *str = (char *)isc_buffer_base(text);
00485                         if (isccc_cc_definestring(data, "text", str) == NULL)
00486                                 goto cleanup_response;
00487                 }
00488         }
00489 
00490         _ctrl = isccc_alist_lookup(response, "_ctrl");
00491         if (_ctrl == NULL ||
00492             isccc_cc_defineuint32(_ctrl, "_nonce", conn->nonce) == NULL)
00493                 goto cleanup_response;
00494 
00495         if (conn->buffer == NULL) {
00496                 result = isc_buffer_allocate(listener->mctx,
00497                                              &conn->buffer, 2 * 2048);
00498                 if (result != ISC_R_SUCCESS)
00499                         goto cleanup_response;
00500         }
00501 
00502         isc_buffer_clear(conn->buffer);
00503         /* Skip the length field (4 bytes) */
00504         isc_buffer_add(conn->buffer, 4);
00505 
00506         result = isccc_cc_towire(response, &conn->buffer, algorithm, &secret);
00507         if (result != ISC_R_SUCCESS)
00508                 goto cleanup_response;
00509 
00510         isc_buffer_init(&b, conn->buffer->base, 4);
00511         isc_buffer_putuint32(&b, conn->buffer->used - 4);
00512 
00513         r.base = conn->buffer->base;
00514         r.length = conn->buffer->used;
00515 
00516         result = isc_socket_send(conn->sock, &r, task, control_senddone, conn);
00517         if (result != ISC_R_SUCCESS)
00518                 goto cleanup_response;
00519         conn->sending = ISC_TRUE;
00520 
00521         isc_mem_put(listener->mctx, secret.rstart, REGION_SIZE(secret));
00522         isccc_sexpr_free(&request);
00523         isccc_sexpr_free(&response);
00524         isc_buffer_free(&text);
00525         return;
00526 
00527  cleanup_response:
00528         isccc_sexpr_free(&response);
00529 
00530  cleanup_request:
00531         isccc_sexpr_free(&request);
00532         isc_mem_put(listener->mctx, secret.rstart, REGION_SIZE(secret));
00533         if (text != NULL)
00534                 isc_buffer_free(&text);
00535 
00536  cleanup:
00537         isc_socket_detach(&conn->sock);
00538         isccc_ccmsg_invalidate(&conn->ccmsg);
00539         conn->ccmsg_valid = ISC_FALSE;
00540         maybe_free_connection(conn);
00541         maybe_free_listener(listener);
00542 }
00543 
00544 static void
00545 control_timeout(isc_task_t *task, isc_event_t *event) {
00546         controlconnection_t *conn = event->ev_arg;
00547 
00548         UNUSED(task);
00549 
00550         isc_timer_detach(&conn->timer);
00551         maybe_free_connection(conn);
00552 
00553         isc_event_free(&event);
00554 }
00555 
00556 static isc_result_t
00557 newconnection(controllistener_t *listener, isc_socket_t *sock) {
00558         controlconnection_t *conn;
00559         isc_interval_t interval;
00560         isc_result_t result;
00561 
00562         conn = isc_mem_get(listener->mctx, sizeof(*conn));
00563         if (conn == NULL)
00564                 return (ISC_R_NOMEMORY);
00565 
00566         conn->sock = sock;
00567         isccc_ccmsg_init(listener->mctx, sock, &conn->ccmsg);
00568         conn->ccmsg_valid = ISC_TRUE;
00569         conn->sending = ISC_FALSE;
00570         conn->buffer = NULL;
00571         conn->timer = NULL;
00572         isc_interval_set(&interval, 60, 0);
00573         result = isc_timer_create(ns_g_timermgr, isc_timertype_once,
00574                                   NULL, &interval, listener->task,
00575                                   control_timeout, conn, &conn->timer);
00576         if (result != ISC_R_SUCCESS)
00577                 goto cleanup;
00578 
00579         conn->listener = listener;
00580         conn->nonce = 0;
00581         ISC_LINK_INIT(conn, link);
00582 
00583         result = isccc_ccmsg_readmessage(&conn->ccmsg, listener->task,
00584                                          control_recvmessage, conn);
00585         if (result != ISC_R_SUCCESS)
00586                 goto cleanup;
00587 
00588         ISC_LIST_APPEND(listener->connections, conn, link);
00589         return (ISC_R_SUCCESS);
00590 
00591  cleanup:
00592         if (conn->buffer != NULL)
00593                 isc_buffer_free(&conn->buffer);
00594         isccc_ccmsg_invalidate(&conn->ccmsg);
00595         if (conn->timer != NULL)
00596                 isc_timer_detach(&conn->timer);
00597         isc_mem_put(listener->mctx, conn, sizeof(*conn));
00598         return (result);
00599 }
00600 
00601 static void
00602 control_newconn(isc_task_t *task, isc_event_t *event) {
00603         isc_socket_newconnev_t *nevent = (isc_socket_newconnev_t *)event;
00604         controllistener_t *listener = event->ev_arg;
00605         isc_socket_t *sock;
00606         isc_sockaddr_t peeraddr;
00607         isc_result_t result;
00608 
00609         UNUSED(task);
00610 
00611         listener->listening = ISC_FALSE;
00612 
00613         if (nevent->result != ISC_R_SUCCESS) {
00614                 if (nevent->result == ISC_R_CANCELED) {
00615                         shutdown_listener(listener);
00616                         goto cleanup;
00617                 }
00618                 goto restart;
00619         }
00620 
00621         sock = nevent->newsocket;
00622         isc_socket_setname(sock, "control", NULL);
00623         (void)isc_socket_getpeername(sock, &peeraddr);
00624         if (listener->type == isc_sockettype_tcp &&
00625             !address_ok(&peeraddr, listener->acl)) {
00626                 char socktext[ISC_SOCKADDR_FORMATSIZE];
00627                 isc_sockaddr_format(&peeraddr, socktext, sizeof(socktext));
00628                 isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
00629                               NS_LOGMODULE_CONTROL, ISC_LOG_WARNING,
00630                               "rejected command channel message from %s",
00631                               socktext);
00632                 isc_socket_detach(&sock);
00633                 goto restart;
00634         }
00635 
00636         result = newconnection(listener, sock);
00637         if (result != ISC_R_SUCCESS) {
00638                 char socktext[ISC_SOCKADDR_FORMATSIZE];
00639                 isc_sockaddr_format(&peeraddr, socktext, sizeof(socktext));
00640                 isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
00641                               NS_LOGMODULE_CONTROL, ISC_LOG_WARNING,
00642                               "dropped command channel from %s: %s",
00643                               socktext, isc_result_totext(result));
00644                 isc_socket_detach(&sock);
00645                 goto restart;
00646         }
00647 
00648  restart:
00649         control_next(listener);
00650  cleanup:
00651         isc_event_free(&event);
00652 }
00653 
00654 static void
00655 controls_shutdown(ns_controls_t *controls) {
00656         controllistener_t *listener;
00657         controllistener_t *next;
00658 
00659         for (listener = ISC_LIST_HEAD(controls->listeners);
00660              listener != NULL;
00661              listener = next)
00662         {
00663                 /*
00664                  * This is asynchronous.  As listeners shut down, they will
00665                  * call their callbacks.
00666                  */
00667                 next = ISC_LIST_NEXT(listener, link);
00668                 shutdown_listener(listener);
00669         }
00670 }
00671 
00672 void
00673 ns_controls_shutdown(ns_controls_t *controls) {
00674         controls_shutdown(controls);
00675         controls->shuttingdown = ISC_TRUE;
00676 }
00677 
00678 static isc_result_t
00679 cfgkeylist_find(const cfg_obj_t *keylist, const char *keyname,
00680                 const cfg_obj_t **objp)
00681 {
00682         const cfg_listelt_t *element;
00683         const char *str;
00684         const cfg_obj_t *obj;
00685 
00686         for (element = cfg_list_first(keylist);
00687              element != NULL;
00688              element = cfg_list_next(element))
00689         {
00690                 obj = cfg_listelt_value(element);
00691                 str = cfg_obj_asstring(cfg_map_getname(obj));
00692                 if (strcasecmp(str, keyname) == 0)
00693                         break;
00694         }
00695         if (element == NULL)
00696                 return (ISC_R_NOTFOUND);
00697         obj = cfg_listelt_value(element);
00698         *objp = obj;
00699         return (ISC_R_SUCCESS);
00700 }
00701 
00702 static isc_result_t
00703 controlkeylist_fromcfg(const cfg_obj_t *keylist, isc_mem_t *mctx,
00704                        controlkeylist_t *keyids)
00705 {
00706         const cfg_listelt_t *element;
00707         char *newstr = NULL;
00708         const char *str;
00709         const cfg_obj_t *obj;
00710         controlkey_t *key;
00711 
00712         for (element = cfg_list_first(keylist);
00713              element != NULL;
00714              element = cfg_list_next(element))
00715         {
00716                 obj = cfg_listelt_value(element);
00717                 str = cfg_obj_asstring(obj);
00718                 newstr = isc_mem_strdup(mctx, str);
00719                 if (newstr == NULL)
00720                         goto cleanup;
00721                 key = isc_mem_get(mctx, sizeof(*key));
00722                 if (key == NULL)
00723                         goto cleanup;
00724                 key->keyname = newstr;
00725                 key->algorithm = DST_ALG_UNKNOWN;
00726                 key->secret.base = NULL;
00727                 key->secret.length = 0;
00728                 ISC_LINK_INIT(key, link);
00729                 ISC_LIST_APPEND(*keyids, key, link);
00730                 newstr = NULL;
00731         }
00732         return (ISC_R_SUCCESS);
00733 
00734  cleanup:
00735         if (newstr != NULL)
00736                 isc_mem_free(mctx, newstr);
00737         free_controlkeylist(keyids, mctx);
00738         return (ISC_R_NOMEMORY);
00739 }
00740 
00741 static void
00742 register_keys(const cfg_obj_t *control, const cfg_obj_t *keylist,
00743               controlkeylist_t *keyids, isc_mem_t *mctx, const char *socktext)
00744 {
00745         controlkey_t *keyid, *next;
00746         const cfg_obj_t *keydef;
00747         char secret[1024];
00748         isc_buffer_t b;
00749         isc_result_t result;
00750 
00751         /*
00752          * Find the keys corresponding to the keyids used by this listener.
00753          */
00754         for (keyid = ISC_LIST_HEAD(*keyids); keyid != NULL; keyid = next) {
00755                 next = ISC_LIST_NEXT(keyid, link);
00756 
00757                 result = cfgkeylist_find(keylist, keyid->keyname, &keydef);
00758                 if (result != ISC_R_SUCCESS) {
00759                         cfg_obj_log(control, ns_g_lctx, ISC_LOG_WARNING,
00760                                     "couldn't find key '%s' for use with "
00761                                     "command channel %s",
00762                                     keyid->keyname, socktext);
00763                         ISC_LIST_UNLINK(*keyids, keyid, link);
00764                         free_controlkey(keyid, mctx);
00765                 } else {
00766                         const cfg_obj_t *algobj = NULL;
00767                         const cfg_obj_t *secretobj = NULL;
00768                         const char *algstr = NULL;
00769                         const char *secretstr = NULL;
00770                         unsigned int algtype;
00771 
00772                         (void)cfg_map_get(keydef, "algorithm", &algobj);
00773                         (void)cfg_map_get(keydef, "secret", &secretobj);
00774                         INSIST(algobj != NULL && secretobj != NULL);
00775 
00776                         algstr = cfg_obj_asstring(algobj);
00777                         secretstr = cfg_obj_asstring(secretobj);
00778 
00779                         if (ns_config_getkeyalgorithm2(algstr, NULL,
00780                                         &algtype, NULL) != ISC_R_SUCCESS)
00781                         {
00782                                 cfg_obj_log(control, ns_g_lctx,
00783                                             ISC_LOG_WARNING,
00784                                             "unsupported algorithm '%s' in "
00785                                             "key '%s' for use with command "
00786                                             "channel %s",
00787                                             algstr, keyid->keyname, socktext);
00788                                 ISC_LIST_UNLINK(*keyids, keyid, link);
00789                                 free_controlkey(keyid, mctx);
00790                                 continue;
00791                         }
00792 
00793                         keyid->algorithm = algtype;
00794                         isc_buffer_init(&b, secret, sizeof(secret));
00795                         result = isc_base64_decodestring(secretstr, &b);
00796 
00797                         if (result != ISC_R_SUCCESS) {
00798                                 cfg_obj_log(keydef, ns_g_lctx, ISC_LOG_WARNING,
00799                                             "secret for key '%s' on "
00800                                             "command channel %s: %s",
00801                                             keyid->keyname, socktext,
00802                                             isc_result_totext(result));
00803                                 ISC_LIST_UNLINK(*keyids, keyid, link);
00804                                 free_controlkey(keyid, mctx);
00805                                 continue;
00806                         }
00807 
00808                         keyid->secret.length = isc_buffer_usedlength(&b);
00809                         keyid->secret.base = isc_mem_get(mctx,
00810                                                          keyid->secret.length);
00811                         if (keyid->secret.base == NULL) {
00812                                 cfg_obj_log(keydef, ns_g_lctx, ISC_LOG_WARNING,
00813                                            "couldn't register key '%s': "
00814                                            "out of memory", keyid->keyname);
00815                                 ISC_LIST_UNLINK(*keyids, keyid, link);
00816                                 free_controlkey(keyid, mctx);
00817                                 break;
00818                         }
00819                         memmove(keyid->secret.base, isc_buffer_base(&b),
00820                                 keyid->secret.length);
00821                 }
00822         }
00823 }
00824 
00825 #define CHECK(x) \
00826         do { \
00827                  result = (x); \
00828                  if (result != ISC_R_SUCCESS) \
00829                         goto cleanup; \
00830         } while (0)
00831 
00832 static isc_result_t
00833 get_rndckey(isc_mem_t *mctx, controlkeylist_t *keyids) {
00834         isc_result_t result;
00835         cfg_parser_t *pctx = NULL;
00836         cfg_obj_t *config = NULL;
00837         const cfg_obj_t *key = NULL;
00838         const cfg_obj_t *algobj = NULL;
00839         const cfg_obj_t *secretobj = NULL;
00840         const char *algstr = NULL;
00841         const char *secretstr = NULL;
00842         controlkey_t *keyid = NULL;
00843         char secret[1024];
00844         unsigned int algtype;
00845         isc_buffer_t b;
00846 
00847         isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
00848                       NS_LOGMODULE_CONTROL, ISC_LOG_INFO,
00849                       "configuring command channel from '%s'",
00850                       ns_g_keyfile);
00851         if (! isc_file_exists(ns_g_keyfile))
00852                 return (ISC_R_FILENOTFOUND);
00853 
00854         CHECK(cfg_parser_create(mctx, ns_g_lctx, &pctx));
00855         CHECK(cfg_parse_file(pctx, ns_g_keyfile, &cfg_type_rndckey, &config));
00856         CHECK(cfg_map_get(config, "key", &key));
00857 
00858         keyid = isc_mem_get(mctx, sizeof(*keyid));
00859         if (keyid == NULL)
00860                 CHECK(ISC_R_NOMEMORY);
00861         keyid->keyname = isc_mem_strdup(mctx,
00862                                         cfg_obj_asstring(cfg_map_getname(key)));
00863         keyid->secret.base = NULL;
00864         keyid->secret.length = 0;
00865         keyid->algorithm = DST_ALG_UNKNOWN;
00866         ISC_LINK_INIT(keyid, link);
00867         if (keyid->keyname == NULL)
00868                 CHECK(ISC_R_NOMEMORY);
00869 
00870         CHECK(bind9_check_key(key, ns_g_lctx));
00871 
00872         (void)cfg_map_get(key, "algorithm", &algobj);
00873         (void)cfg_map_get(key, "secret", &secretobj);
00874         INSIST(algobj != NULL && secretobj != NULL);
00875 
00876         algstr = cfg_obj_asstring(algobj);
00877         secretstr = cfg_obj_asstring(secretobj);
00878 
00879         if (ns_config_getkeyalgorithm2(algstr, NULL,
00880                                        &algtype, NULL) != ISC_R_SUCCESS) {
00881                 cfg_obj_log(key, ns_g_lctx,
00882                             ISC_LOG_WARNING,
00883                             "unsupported algorithm '%s' in "
00884                             "key '%s' for use with command "
00885                             "channel",
00886                             algstr, keyid->keyname);
00887                 goto cleanup;
00888         }
00889 
00890         keyid->algorithm = algtype;
00891         isc_buffer_init(&b, secret, sizeof(secret));
00892         result = isc_base64_decodestring(secretstr, &b);
00893 
00894         if (result != ISC_R_SUCCESS) {
00895                 cfg_obj_log(key, ns_g_lctx, ISC_LOG_WARNING,
00896                             "secret for key '%s' on command channel: %s",
00897                             keyid->keyname, isc_result_totext(result));
00898                 goto cleanup;
00899         }
00900 
00901         keyid->secret.length = isc_buffer_usedlength(&b);
00902         keyid->secret.base = isc_mem_get(mctx,
00903                                          keyid->secret.length);
00904         if (keyid->secret.base == NULL) {
00905                 cfg_obj_log(key, ns_g_lctx, ISC_LOG_WARNING,
00906                            "couldn't register key '%s': "
00907                            "out of memory", keyid->keyname);
00908                 CHECK(ISC_R_NOMEMORY);
00909         }
00910         memmove(keyid->secret.base, isc_buffer_base(&b),
00911                 keyid->secret.length);
00912         ISC_LIST_APPEND(*keyids, keyid, link);
00913         keyid = NULL;
00914         result = ISC_R_SUCCESS;
00915 
00916   cleanup:
00917         if (keyid != NULL)
00918                 free_controlkey(keyid, mctx);
00919         if (config != NULL)
00920                 cfg_obj_destroy(pctx, &config);
00921         if (pctx != NULL)
00922                 cfg_parser_destroy(&pctx);
00923         return (result);
00924 }
00925 
00926 /*
00927  * Ensures that both '*global_keylistp' and '*control_keylistp' are
00928  * valid or both are NULL.
00929  */
00930 static void
00931 get_key_info(const cfg_obj_t *config, const cfg_obj_t *control,
00932              const cfg_obj_t **global_keylistp,
00933              const cfg_obj_t **control_keylistp)
00934 {
00935         isc_result_t result;
00936         const cfg_obj_t *control_keylist = NULL;
00937         const cfg_obj_t *global_keylist = NULL;
00938 
00939         REQUIRE(global_keylistp != NULL && *global_keylistp == NULL);
00940         REQUIRE(control_keylistp != NULL && *control_keylistp == NULL);
00941 
00942         control_keylist = cfg_tuple_get(control, "keys");
00943 
00944         if (!cfg_obj_isvoid(control_keylist) &&
00945             cfg_list_first(control_keylist) != NULL) {
00946                 result = cfg_map_get(config, "key", &global_keylist);
00947 
00948                 if (result == ISC_R_SUCCESS) {
00949                         *global_keylistp = global_keylist;
00950                         *control_keylistp = control_keylist;
00951                 }
00952         }
00953 }
00954 
00955 static void
00956 update_listener(ns_controls_t *cp, controllistener_t **listenerp,
00957                 const cfg_obj_t *control, const cfg_obj_t *config,
00958                 isc_sockaddr_t *addr, cfg_aclconfctx_t *aclconfctx,
00959                 const char *socktext, isc_sockettype_t type)
00960 {
00961         controllistener_t *listener;
00962         const cfg_obj_t *allow;
00963         const cfg_obj_t *global_keylist = NULL;
00964         const cfg_obj_t *control_keylist = NULL;
00965         dns_acl_t *new_acl = NULL;
00966         controlkeylist_t keys;
00967         isc_result_t result = ISC_R_SUCCESS;
00968 
00969         for (listener = ISC_LIST_HEAD(cp->listeners);
00970              listener != NULL;
00971              listener = ISC_LIST_NEXT(listener, link))
00972                 if (isc_sockaddr_equal(addr, &listener->address))
00973                         break;
00974 
00975         if (listener == NULL) {
00976                 *listenerp = NULL;
00977                 return;
00978         }
00979 
00980         /*
00981          * There is already a listener for this sockaddr.
00982          * Update the access list and key information.
00983          *
00984          * First try to deal with the key situation.  There are a few
00985          * possibilities:
00986          *  (a) It had an explicit keylist and still has an explicit keylist.
00987          *  (b) It had an automagic key and now has an explicit keylist.
00988          *  (c) It had an explicit keylist and now needs an automagic key.
00989          *  (d) It has an automagic key and still needs the automagic key.
00990          *
00991          * (c) and (d) are the annoying ones.  The caller needs to know
00992          * that it should use the automagic configuration for key information
00993          * in place of the named.conf configuration.
00994          *
00995          * XXXDCL There is one other hazard that has not been dealt with,
00996          * the problem that if a key change is being caused by a control
00997          * channel reload, then the response will be with the new key
00998          * and not able to be decrypted by the client.
00999          */
01000         if (control != NULL)
01001                 get_key_info(config, control, &global_keylist,
01002                              &control_keylist);
01003 
01004         if (control_keylist != NULL) {
01005                 INSIST(global_keylist != NULL);
01006 
01007                 ISC_LIST_INIT(keys);
01008                 result = controlkeylist_fromcfg(control_keylist,
01009                                                 listener->mctx, &keys);
01010                 if (result == ISC_R_SUCCESS) {
01011                         free_controlkeylist(&listener->keys, listener->mctx);
01012                         listener->keys = keys;
01013                         register_keys(control, global_keylist, &listener->keys,
01014                                       listener->mctx, socktext);
01015                 }
01016         } else {
01017                 free_controlkeylist(&listener->keys, listener->mctx);
01018                 result = get_rndckey(listener->mctx, &listener->keys);
01019         }
01020 
01021         if (result != ISC_R_SUCCESS && global_keylist != NULL) {
01022                 /*
01023                  * This message might be a little misleading since the
01024                  * "new keys" might in fact be identical to the old ones,
01025                  * but tracking whether they are identical just for the
01026                  * sake of avoiding this message would be too much trouble.
01027                  */
01028                 if (control != NULL)
01029                         cfg_obj_log(control, ns_g_lctx, ISC_LOG_WARNING,
01030                                     "couldn't install new keys for "
01031                                     "command channel %s: %s",
01032                                     socktext, isc_result_totext(result));
01033                 else
01034                         isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
01035                                       NS_LOGMODULE_CONTROL, ISC_LOG_WARNING,
01036                                       "couldn't install new keys for "
01037                                       "command channel %s: %s",
01038                                       socktext, isc_result_totext(result));
01039         }
01040 
01041         /*
01042          * Now, keep the old access list unless a new one can be made.
01043          */
01044         if (control != NULL && type == isc_sockettype_tcp) {
01045                 allow = cfg_tuple_get(control, "allow");
01046                 result = cfg_acl_fromconfig(allow, config, ns_g_lctx,
01047                                             aclconfctx, listener->mctx, 0,
01048                                             &new_acl);
01049         } else {
01050                 result = dns_acl_any(listener->mctx, &new_acl);
01051         }
01052 
01053         if (result == ISC_R_SUCCESS) {
01054                 dns_acl_detach(&listener->acl);
01055                 dns_acl_attach(new_acl, &listener->acl);
01056                 dns_acl_detach(&new_acl);
01057                 /* XXXDCL say the old acl is still used? */
01058         } else if (control != NULL)
01059                 cfg_obj_log(control, ns_g_lctx, ISC_LOG_WARNING,
01060                             "couldn't install new acl for "
01061                             "command channel %s: %s",
01062                             socktext, isc_result_totext(result));
01063         else
01064                 isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
01065                               NS_LOGMODULE_CONTROL, ISC_LOG_WARNING,
01066                               "couldn't install new acl for "
01067                               "command channel %s: %s",
01068                               socktext, isc_result_totext(result));
01069 
01070         if (result == ISC_R_SUCCESS && type == isc_sockettype_unix) {
01071                 isc_uint32_t perm, owner, group;
01072                 perm  = cfg_obj_asuint32(cfg_tuple_get(control, "perm"));
01073                 owner = cfg_obj_asuint32(cfg_tuple_get(control, "owner"));
01074                 group = cfg_obj_asuint32(cfg_tuple_get(control, "group"));
01075                 result = ISC_R_SUCCESS;
01076                 if (listener->perm != perm || listener->owner != owner ||
01077                     listener->group != group)
01078                         result = isc_socket_permunix(&listener->address, perm,
01079                                                      owner, group);
01080                 if (result == ISC_R_SUCCESS) {
01081                         listener->perm = perm;
01082                         listener->owner = owner;
01083                         listener->group = group;
01084                 } else if (control != NULL)
01085                         cfg_obj_log(control, ns_g_lctx, ISC_LOG_WARNING,
01086                                     "couldn't update ownership/permission for "
01087                                     "command channel %s", socktext);
01088         }
01089 
01090         *listenerp = listener;
01091 }
01092 
01093 static void
01094 add_listener(ns_controls_t *cp, controllistener_t **listenerp,
01095              const cfg_obj_t *control, const cfg_obj_t *config,
01096              isc_sockaddr_t *addr, cfg_aclconfctx_t *aclconfctx,
01097              const char *socktext, isc_sockettype_t type)
01098 {
01099         isc_mem_t *mctx = cp->server->mctx;
01100         controllistener_t *listener;
01101         const cfg_obj_t *allow;
01102         const cfg_obj_t *global_keylist = NULL;
01103         const cfg_obj_t *control_keylist = NULL;
01104         dns_acl_t *new_acl = NULL;
01105         isc_result_t result = ISC_R_SUCCESS;
01106 
01107         listener = isc_mem_get(mctx, sizeof(*listener));
01108         if (listener == NULL)
01109                 result = ISC_R_NOMEMORY;
01110 
01111         if (result == ISC_R_SUCCESS) {
01112                 listener->mctx = NULL;
01113                 isc_mem_attach(mctx, &listener->mctx);
01114                 listener->controls = cp;
01115                 listener->task = cp->server->task;
01116                 listener->address = *addr;
01117                 listener->sock = NULL;
01118                 listener->listening = ISC_FALSE;
01119                 listener->exiting = ISC_FALSE;
01120                 listener->acl = NULL;
01121                 listener->type = type;
01122                 listener->perm = 0;
01123                 listener->owner = 0;
01124                 listener->group = 0;
01125                 ISC_LINK_INIT(listener, link);
01126                 ISC_LIST_INIT(listener->keys);
01127                 ISC_LIST_INIT(listener->connections);
01128 
01129                 /*
01130                  * Make the acl.
01131                  */
01132                 if (control != NULL && type == isc_sockettype_tcp) {
01133                         allow = cfg_tuple_get(control, "allow");
01134                         result = cfg_acl_fromconfig(allow, config, ns_g_lctx,
01135                                                     aclconfctx, mctx, 0,
01136                                                     &new_acl);
01137                 } else {
01138                         result = dns_acl_any(mctx, &new_acl);
01139                 }
01140         }
01141 
01142         if (result == ISC_R_SUCCESS) {
01143                 dns_acl_attach(new_acl, &listener->acl);
01144                 dns_acl_detach(&new_acl);
01145 
01146                 if (config != NULL)
01147                         get_key_info(config, control, &global_keylist,
01148                                      &control_keylist);
01149 
01150                 if (control_keylist != NULL) {
01151                         result = controlkeylist_fromcfg(control_keylist,
01152                                                         listener->mctx,
01153                                                         &listener->keys);
01154                         if (result == ISC_R_SUCCESS)
01155                                 register_keys(control, global_keylist,
01156                                               &listener->keys,
01157                                               listener->mctx, socktext);
01158                 } else
01159                         result = get_rndckey(mctx, &listener->keys);
01160 
01161                 if (result != ISC_R_SUCCESS && control != NULL)
01162                         cfg_obj_log(control, ns_g_lctx, ISC_LOG_WARNING,
01163                                     "couldn't install keys for "
01164                                     "command channel %s: %s",
01165                                     socktext, isc_result_totext(result));
01166         }
01167 
01168         if (result == ISC_R_SUCCESS) {
01169                 int pf = isc_sockaddr_pf(&listener->address);
01170                 if ((pf == AF_INET && isc_net_probeipv4() != ISC_R_SUCCESS) ||
01171 #ifdef ISC_PLATFORM_HAVESYSUNH
01172                     (pf == AF_UNIX && isc_net_probeunix() != ISC_R_SUCCESS) ||
01173 #endif
01174                     (pf == AF_INET6 && isc_net_probeipv6() != ISC_R_SUCCESS))
01175                         result = ISC_R_FAMILYNOSUPPORT;
01176         }
01177 
01178         if (result == ISC_R_SUCCESS && type == isc_sockettype_unix)
01179                 isc_socket_cleanunix(&listener->address, ISC_FALSE);
01180 
01181         if (result == ISC_R_SUCCESS)
01182                 result = isc_socket_create(ns_g_socketmgr,
01183                                            isc_sockaddr_pf(&listener->address),
01184                                            type, &listener->sock);
01185         if (result == ISC_R_SUCCESS)
01186                 isc_socket_setname(listener->sock, "control", NULL);
01187 
01188 #ifndef ISC_ALLOW_MAPPED
01189         if (result == ISC_R_SUCCESS)
01190                 isc_socket_ipv6only(listener->sock, ISC_TRUE);
01191 #endif
01192 
01193         if (result == ISC_R_SUCCESS)
01194                 result = isc_socket_bind(listener->sock, &listener->address,
01195                                          ISC_SOCKET_REUSEADDRESS);
01196 
01197         if (result == ISC_R_SUCCESS && type == isc_sockettype_unix) {
01198                 listener->perm = cfg_obj_asuint32(cfg_tuple_get(control,
01199                                                                 "perm"));
01200                 listener->owner = cfg_obj_asuint32(cfg_tuple_get(control,
01201                                                                  "owner"));
01202                 listener->group = cfg_obj_asuint32(cfg_tuple_get(control,
01203                                                                  "group"));
01204                 result = isc_socket_permunix(&listener->address, listener->perm,
01205                                              listener->owner, listener->group);
01206         }
01207         if (result == ISC_R_SUCCESS)
01208                 result = control_listen(listener);
01209 
01210         if (result == ISC_R_SUCCESS)
01211                 result = control_accept(listener);
01212 
01213         if (result == ISC_R_SUCCESS) {
01214                 isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
01215                               NS_LOGMODULE_CONTROL, ISC_LOG_NOTICE,
01216                               "command channel listening on %s", socktext);
01217                 *listenerp = listener;
01218 
01219         } else {
01220                 if (listener != NULL) {
01221                         listener->exiting = ISC_TRUE;
01222                         free_listener(listener);
01223                 }
01224 
01225                 if (control != NULL)
01226                         cfg_obj_log(control, ns_g_lctx, ISC_LOG_WARNING,
01227                                     "couldn't add command channel %s: %s",
01228                                     socktext, isc_result_totext(result));
01229                 else
01230                         isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
01231                                       NS_LOGMODULE_CONTROL, ISC_LOG_NOTICE,
01232                                       "couldn't add command channel %s: %s",
01233                                       socktext, isc_result_totext(result));
01234 
01235                 *listenerp = NULL;
01236         }
01237 
01238         /* XXXDCL return error results? fail hard? */
01239 }
01240 
01241 isc_result_t
01242 ns_controls_configure(ns_controls_t *cp, const cfg_obj_t *config,
01243                       cfg_aclconfctx_t *aclconfctx)
01244 {
01245         controllistener_t *listener;
01246         controllistenerlist_t new_listeners;
01247         const cfg_obj_t *controlslist = NULL;
01248         const cfg_listelt_t *element, *element2;
01249         char socktext[ISC_SOCKADDR_FORMATSIZE];
01250 
01251         ISC_LIST_INIT(new_listeners);
01252 
01253         /*
01254          * Get the list of named.conf 'controls' statements.
01255          */
01256         (void)cfg_map_get(config, "controls", &controlslist);
01257 
01258         /*
01259          * Run through the new control channel list, noting sockets that
01260          * are already being listened on and moving them to the new list.
01261          *
01262          * Identifying duplicate addr/port combinations is left to either
01263          * the underlying config code, or to the bind attempt getting an
01264          * address-in-use error.
01265          */
01266         if (controlslist != NULL) {
01267                 for (element = cfg_list_first(controlslist);
01268                      element != NULL;
01269                      element = cfg_list_next(element)) {
01270                         const cfg_obj_t *controls;
01271                         const cfg_obj_t *inetcontrols = NULL;
01272 
01273                         controls = cfg_listelt_value(element);
01274                         (void)cfg_map_get(controls, "inet", &inetcontrols);
01275                         if (inetcontrols == NULL)
01276                                 continue;
01277 
01278                         for (element2 = cfg_list_first(inetcontrols);
01279                              element2 != NULL;
01280                              element2 = cfg_list_next(element2)) {
01281                                 const cfg_obj_t *control;
01282                                 const cfg_obj_t *obj;
01283                                 isc_sockaddr_t addr;
01284 
01285                                 /*
01286                                  * The parser handles BIND 8 configuration file
01287                                  * syntax, so it allows unix phrases as well
01288                                  * inet phrases with no keys{} clause.
01289                                  */
01290                                 control = cfg_listelt_value(element2);
01291 
01292                                 obj = cfg_tuple_get(control, "address");
01293                                 addr = *cfg_obj_assockaddr(obj);
01294                                 if (isc_sockaddr_getport(&addr) == 0)
01295                                         isc_sockaddr_setport(&addr,
01296                                                              NS_CONTROL_PORT);
01297 
01298                                 isc_sockaddr_format(&addr, socktext,
01299                                                     sizeof(socktext));
01300 
01301                                 isc_log_write(ns_g_lctx,
01302                                               NS_LOGCATEGORY_GENERAL,
01303                                               NS_LOGMODULE_CONTROL,
01304                                               ISC_LOG_DEBUG(9),
01305                                               "processing control channel %s",
01306                                               socktext);
01307 
01308                                 update_listener(cp, &listener, control, config,
01309                                                 &addr, aclconfctx, socktext,
01310                                                 isc_sockettype_tcp);
01311 
01312                                 if (listener != NULL)
01313                                         /*
01314                                          * Remove the listener from the old
01315                                          * list, so it won't be shut down.
01316                                          */
01317                                         ISC_LIST_UNLINK(cp->listeners,
01318                                                         listener, link);
01319                                 else
01320                                         /*
01321                                          * This is a new listener.
01322                                          */
01323                                         add_listener(cp, &listener, control,
01324                                                      config, &addr, aclconfctx,
01325                                                      socktext,
01326                                                      isc_sockettype_tcp);
01327 
01328                                 if (listener != NULL)
01329                                         ISC_LIST_APPEND(new_listeners,
01330                                                         listener, link);
01331                         }
01332                 }
01333                 for (element = cfg_list_first(controlslist);
01334                      element != NULL;
01335                      element = cfg_list_next(element)) {
01336                         const cfg_obj_t *controls;
01337                         const cfg_obj_t *unixcontrols = NULL;
01338 
01339                         controls = cfg_listelt_value(element);
01340                         (void)cfg_map_get(controls, "unix", &unixcontrols);
01341                         if (unixcontrols == NULL)
01342                                 continue;
01343 
01344                         for (element2 = cfg_list_first(unixcontrols);
01345                              element2 != NULL;
01346                              element2 = cfg_list_next(element2)) {
01347                                 const cfg_obj_t *control;
01348                                 const cfg_obj_t *path;
01349                                 isc_sockaddr_t addr;
01350                                 isc_result_t result;
01351 
01352                                 /*
01353                                  * The parser handles BIND 8 configuration file
01354                                  * syntax, so it allows unix phrases as well
01355                                  * inet phrases with no keys{} clause.
01356                                  */
01357                                 control = cfg_listelt_value(element2);
01358 
01359                                 path = cfg_tuple_get(control, "path");
01360                                 result = isc_sockaddr_frompath(&addr,
01361                                                       cfg_obj_asstring(path));
01362                                 if (result != ISC_R_SUCCESS) {
01363                                         isc_log_write(ns_g_lctx,
01364                                               NS_LOGCATEGORY_GENERAL,
01365                                               NS_LOGMODULE_CONTROL,
01366                                               ISC_LOG_DEBUG(9),
01367                                               "control channel '%s': %s",
01368                                               cfg_obj_asstring(path),
01369                                               isc_result_totext(result));
01370                                         continue;
01371                                 }
01372 
01373                                 isc_log_write(ns_g_lctx,
01374                                               NS_LOGCATEGORY_GENERAL,
01375                                               NS_LOGMODULE_CONTROL,
01376                                               ISC_LOG_DEBUG(9),
01377                                               "processing control channel '%s'",
01378                                               cfg_obj_asstring(path));
01379 
01380                                 update_listener(cp, &listener, control, config,
01381                                                 &addr, aclconfctx,
01382                                                 cfg_obj_asstring(path),
01383                                                 isc_sockettype_unix);
01384 
01385                                 if (listener != NULL)
01386                                         /*
01387                                          * Remove the listener from the old
01388                                          * list, so it won't be shut down.
01389                                          */
01390                                         ISC_LIST_UNLINK(cp->listeners,
01391                                                         listener, link);
01392                                 else
01393                                         /*
01394                                          * This is a new listener.
01395                                          */
01396                                         add_listener(cp, &listener, control,
01397                                                      config, &addr, aclconfctx,
01398                                                      cfg_obj_asstring(path),
01399                                                      isc_sockettype_unix);
01400 
01401                                 if (listener != NULL)
01402                                         ISC_LIST_APPEND(new_listeners,
01403                                                         listener, link);
01404                         }
01405                 }
01406         } else {
01407                 int i;
01408 
01409                 for (i = 0; i < 2; i++) {
01410                         isc_sockaddr_t addr;
01411 
01412                         if (i == 0) {
01413                                 struct in_addr localhost;
01414 
01415                                 if (isc_net_probeipv4() != ISC_R_SUCCESS)
01416                                         continue;
01417                                 localhost.s_addr = htonl(INADDR_LOOPBACK);
01418                                 isc_sockaddr_fromin(&addr, &localhost, 0);
01419                         } else {
01420                                 if (isc_net_probeipv6() != ISC_R_SUCCESS)
01421                                         continue;
01422                                 isc_sockaddr_fromin6(&addr,
01423                                                      &in6addr_loopback, 0);
01424                         }
01425                         isc_sockaddr_setport(&addr, NS_CONTROL_PORT);
01426 
01427                         isc_sockaddr_format(&addr, socktext, sizeof(socktext));
01428 
01429                         update_listener(cp, &listener, NULL, NULL,
01430                                         &addr, NULL, socktext,
01431                                         isc_sockettype_tcp);
01432 
01433                         if (listener != NULL)
01434                                 /*
01435                                  * Remove the listener from the old
01436                                  * list, so it won't be shut down.
01437                                  */
01438                                 ISC_LIST_UNLINK(cp->listeners,
01439                                                 listener, link);
01440                         else
01441                                 /*
01442                                  * This is a new listener.
01443                                  */
01444                                 add_listener(cp, &listener, NULL, NULL,
01445                                              &addr, NULL, socktext,
01446                                              isc_sockettype_tcp);
01447 
01448                         if (listener != NULL)
01449                                 ISC_LIST_APPEND(new_listeners,
01450                                                 listener, link);
01451                 }
01452         }
01453 
01454         /*
01455          * ns_control_shutdown() will stop whatever is on the global
01456          * listeners list, which currently only has whatever sockaddrs
01457          * were in the previous configuration (if any) that do not
01458          * remain in the current configuration.
01459          */
01460         controls_shutdown(cp);
01461 
01462         /*
01463          * Put all of the valid listeners on the listeners list.
01464          * Anything already on listeners in the process of shutting
01465          * down will be taken care of by listen_done().
01466          */
01467         ISC_LIST_APPENDLIST(cp->listeners, new_listeners, link);
01468         return (ISC_R_SUCCESS);
01469 }
01470 
01471 isc_result_t
01472 ns_controls_create(ns_server_t *server, ns_controls_t **ctrlsp) {
01473         isc_mem_t *mctx = server->mctx;
01474         isc_result_t result;
01475         ns_controls_t *controls = isc_mem_get(mctx, sizeof(*controls));
01476 
01477         if (controls == NULL)
01478                 return (ISC_R_NOMEMORY);
01479         controls->server = server;
01480         ISC_LIST_INIT(controls->listeners);
01481         controls->shuttingdown = ISC_FALSE;
01482         controls->symtab = NULL;
01483         result = isccc_cc_createsymtab(&controls->symtab);
01484         if (result != ISC_R_SUCCESS) {
01485                 isc_mem_put(server->mctx, controls, sizeof(*controls));
01486                 return (result);
01487         }
01488         *ctrlsp = controls;
01489         return (ISC_R_SUCCESS);
01490 }
01491 
01492 void
01493 ns_controls_destroy(ns_controls_t **ctrlsp) {
01494         ns_controls_t *controls = *ctrlsp;
01495 
01496         REQUIRE(ISC_LIST_EMPTY(controls->listeners));
01497 
01498         isccc_symtab_destroy(&controls->symtab);
01499         isc_mem_put(controls->server->mctx, controls, sizeof(*controls));
01500         *ctrlsp = NULL;
01501 }

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