controlconf.c revision 245163
1163953Srrs/* 2169382Srrs * Copyright (C) 2004-2008, 2011, 2012 Internet Systems Consortium, Inc. ("ISC") 3163953Srrs * Copyright (C) 2001-2003 Internet Software Consortium. 4163953Srrs * 5163953Srrs * Permission to use, copy, modify, and/or distribute this software for any 6163953Srrs * purpose with or without fee is hereby granted, provided that the above 7163953Srrs * copyright notice and this permission notice appear in all copies. 8163953Srrs * 9163953Srrs * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH 10163953Srrs * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY 11163953Srrs * AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT, 12163953Srrs * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM 13163953Srrs * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE 14163953Srrs * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR 15163953Srrs * PERFORMANCE OF THIS SOFTWARE. 16163953Srrs */ 17163953Srrs 18163953Srrs/* $Id: controlconf.c,v 1.60.544.3 2011/12/22 08:10:09 marka Exp $ */ 19163953Srrs 20163953Srrs/*! \file */ 21163953Srrs 22163953Srrs#include <config.h> 23163953Srrs 24163953Srrs#include <isc/base64.h> 25163953Srrs#include <isc/buffer.h> 26163953Srrs#include <isc/event.h> 27163953Srrs#include <isc/mem.h> 28163953Srrs#include <isc/net.h> 29163953Srrs#include <isc/netaddr.h> 30163953Srrs#include <isc/random.h> 31174510Sobrien#include <isc/result.h> 32163954Srrs#include <isc/stdtime.h> 33163953Srrs#include <isc/string.h> 34163953Srrs#include <isc/timer.h> 35166086Srrs#include <isc/util.h> 36163953Srrs 37163953Srrs#include <isccfg/namedconf.h> 38163953Srrs 39163953Srrs#include <bind9/check.h> 40168709Srrs 41168709Srrs#include <isccc/alist.h> 42168709Srrs#include <isccc/cc.h> 43167598Srrs#include <isccc/ccmsg.h> 44163953Srrs#include <isccc/events.h> 45166086Srrs#include <isccc/result.h> 46163953Srrs#include <isccc/sexpr.h> 47166086Srrs#include <isccc/symtab.h> 48166086Srrs#include <isccc/util.h> 49166086Srrs 50166086Srrs#include <dns/result.h> 51168709Srrs 52168709Srrs#include <named/config.h> 53170091Srrs#include <named/control.h> 54179783Srrs#include <named/log.h> 55163953Srrs#include <named/server.h> 56171167Sgnn 57171133Sgnn/* 58171133Sgnn * Note: Listeners and connections are not locked. All event handlers are 59171133Sgnn * executed by the server task, and all callers of exported routines must 60171440Srrs * be running under the server task. 61171440Srrs */ 62163953Srrs 63163953Srrstypedef struct controlkey controlkey_t; 64163953Srrstypedef ISC_LIST(controlkey_t) controlkeylist_t; 65163953Srrs 66171259Sdelphijtypedef struct controlconnection controlconnection_t; 67163953Srrstypedef ISC_LIST(controlconnection_t) controlconnectionlist_t; 68165647Srrs 69163953Srrstypedef struct controllistener controllistener_t; 70163953Srrstypedef ISC_LIST(controllistener_t) controllistenerlist_t; 71163953Srrs 72163953Srrsstruct controlkey { 73163953Srrs char * keyname; 74169352Srrs isc_region_t secret; 75170181Srrs ISC_LINK(controlkey_t) link; 76163953Srrs}; 77163953Srrs 78163953Srrsstruct controlconnection { 79168299Srrs isc_socket_t * sock; 80163953Srrs isccc_ccmsg_t ccmsg; 81170056Srrs isc_boolean_t ccmsg_valid; 82163953Srrs isc_boolean_t sending; 83179783Srrs isc_timer_t * timer; 84163953Srrs unsigned char buffer[2048]; 85169352Srrs controllistener_t * listener; 86169352Srrs isc_uint32_t nonce; 87169352Srrs ISC_LINK(controlconnection_t) link; 88169352Srrs}; 89169352Srrs 90168709Srrsstruct controllistener { 91170056Srrs ns_controls_t * controls; 92165647Srrs isc_mem_t * mctx; 93170091Srrs isc_task_t * task; 94170091Srrs isc_sockaddr_t address; 95170091Srrs isc_socket_t * sock; 96163953Srrs dns_acl_t * acl; 97163953Srrs isc_boolean_t listening; 98170056Srrs isc_boolean_t exiting; 99170056Srrs controlkeylist_t keys; 100163953Srrs controlconnectionlist_t connections; 101163953Srrs isc_sockettype_t type; 102163953Srrs isc_uint32_t perm; 103163953Srrs isc_uint32_t owner; 104163953Srrs isc_uint32_t group; 105163953Srrs ISC_LINK(controllistener_t) link; 106163953Srrs}; 107170859Srrs 108170859Srrsstruct ns_controls { 109163953Srrs ns_server_t *server; 110170859Srrs controllistenerlist_t listeners; 111163953Srrs isc_boolean_t shuttingdown; 112163953Srrs isccc_symtab_t *symtab; 113163953Srrs}; 114163953Srrs 115163953Srrsstatic void control_newconn(isc_task_t *task, isc_event_t *event); 116163953Srrsstatic void control_recvmessage(isc_task_t *task, isc_event_t *event); 117163953Srrs 118163953Srrs#define CLOCKSKEW 300 119163953Srrs 120169420Srrsstatic void 121170056Srrsfree_controlkey(controlkey_t *key, isc_mem_t *mctx) { 122163953Srrs if (key->keyname != NULL) 123163953Srrs isc_mem_free(mctx, key->keyname); 124163953Srrs if (key->secret.base != NULL) 125163953Srrs isc_mem_put(mctx, key->secret.base, key->secret.length); 126163953Srrs isc_mem_put(mctx, key, sizeof(*key)); 127163953Srrs} 128163953Srrs 129171990Srrsstatic void 130179783Srrsfree_controlkeylist(controlkeylist_t *keylist, isc_mem_t *mctx) { 131171990Srrs while (!ISC_LIST_EMPTY(*keylist)) { 132171990Srrs controlkey_t *key = ISC_LIST_HEAD(*keylist); 133171990Srrs ISC_LIST_UNLINK(*keylist, key, link); 134171990Srrs free_controlkey(key, mctx); 135171990Srrs } 136171990Srrs} 137171990Srrs 138171990Srrsstatic void 139171990Srrsfree_listener(controllistener_t *listener) { 140171990Srrs INSIST(listener->exiting); 141179783Srrs INSIST(!listener->listening); 142179783Srrs INSIST(ISC_LIST_EMPTY(listener->connections)); 143179783Srrs 144179783Srrs if (listener->sock != NULL) 145179783Srrs isc_socket_detach(&listener->sock); 146179783Srrs 147171990Srrs free_controlkeylist(&listener->keys, listener->mctx); 148171990Srrs 149171990Srrs if (listener->acl != NULL) 150172090Srrs dns_acl_detach(&listener->acl); 151171990Srrs 152171990Srrs isc_mem_put(listener->mctx, listener, sizeof(*listener)); 153163953Srrs} 154171990Srrs 155171990Srrsstatic void 156171990Srrsmaybe_free_listener(controllistener_t *listener) { 157165647Srrs if (listener->exiting && 158171990Srrs !listener->listening && 159171990Srrs ISC_LIST_EMPTY(listener->connections)) 160163953Srrs free_listener(listener); 161163953Srrs} 162163953Srrs 163163953Srrsstatic void 164163953Srrsmaybe_free_connection(controlconnection_t *conn) { 165163953Srrs controllistener_t *listener = conn->listener; 166163953Srrs 167168299Srrs if (conn->timer != NULL) 168179783Srrs isc_timer_detach(&conn->timer); 169179783Srrs 170179783Srrs if (conn->ccmsg_valid) { 171179783Srrs isccc_ccmsg_cancelread(&conn->ccmsg); 172179783Srrs return; 173179783Srrs } 174163953Srrs 175163953Srrs if (conn->sending) { 176163953Srrs isc_socket_cancel(conn->sock, listener->task, 177163953Srrs ISC_SOCKCANCEL_SEND); 178163953Srrs return; 179163953Srrs } 180163953Srrs 181163953Srrs ISC_LIST_UNLINK(listener->connections, conn, link); 182163953Srrs isc_mem_put(listener->mctx, conn, sizeof(*conn)); 183163953Srrs} 184163953Srrs 185163953Srrsstatic void 186163953Srrsshutdown_listener(controllistener_t *listener) { 187168299Srrs controlconnection_t *conn; 188169420Srrs controlconnection_t *next; 189169420Srrs 190169420Srrs if (!listener->exiting) { 191169420Srrs char socktext[ISC_SOCKADDR_FORMATSIZE]; 192163953Srrs 193165220Srrs ISC_LIST_UNLINK(listener->controls->listeners, listener, link); 194179783Srrs 195165220Srrs isc_sockaddr_format(&listener->address, socktext, 196165220Srrs sizeof(socktext)); 197165220Srrs isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, 198165220Srrs NS_LOGMODULE_CONTROL, ISC_LOG_NOTICE, 199165220Srrs "stopping command channel on %s", socktext); 200165220Srrs if (listener->type == isc_sockettype_unix) 201179783Srrs isc_socket_cleanunix(&listener->address, ISC_TRUE); 202163953Srrs listener->exiting = ISC_TRUE; 203163953Srrs } 204163953Srrs 205163953Srrs for (conn = ISC_LIST_HEAD(listener->connections); 206163953Srrs conn != NULL; 207171167Sgnn conn = next) 208163953Srrs { 209163953Srrs next = ISC_LIST_NEXT(conn, link); 210163953Srrs maybe_free_connection(conn); 211163996Srrs } 212163953Srrs 213163953Srrs if (listener->listening) 214163953Srrs isc_socket_cancel(listener->sock, listener->task, 215163996Srrs ISC_SOCKCANCEL_ACCEPT); 216171440Srrs 217163953Srrs maybe_free_listener(listener); 218163953Srrs} 219163953Srrs 220163953Srrsstatic isc_boolean_t 221163953Srrsaddress_ok(isc_sockaddr_t *sockaddr, dns_acl_t *acl) { 222163953Srrs isc_netaddr_t netaddr; 223165647Srrs isc_result_t result; 224165647Srrs int match; 225165647Srrs 226165647Srrs isc_netaddr_fromsockaddr(&netaddr, sockaddr); 227169655Srrs 228169378Srrs result = dns_acl_match(&netaddr, NULL, acl, 229179783Srrs &ns_g_server->aclenv, &match, NULL); 230163953Srrs 231163953Srrs if (result != ISC_R_SUCCESS || match <= 0) 232163953Srrs return (ISC_FALSE); 233169352Srrs else 234163953Srrs return (ISC_TRUE); 235163953Srrs} 236163953Srrs 237163953Srrsstatic isc_result_t 238163953Srrscontrol_accept(controllistener_t *listener) { 239163953Srrs isc_result_t result; 240163953Srrs result = isc_socket_accept(listener->sock, 241163953Srrs listener->task, 242163953Srrs control_newconn, listener); 243169420Srrs if (result != ISC_R_SUCCESS) 244163953Srrs UNEXPECTED_ERROR(__FILE__, __LINE__, 245169420Srrs "isc_socket_accept() failed: %s", 246163953Srrs isc_result_totext(result)); 247163953Srrs else 248163953Srrs listener->listening = ISC_TRUE; 249163953Srrs return (result); 250163953Srrs} 251163953Srrs 252163953Srrsstatic isc_result_t 253169352Srrscontrol_listen(controllistener_t *listener) { 254163953Srrs isc_result_t result; 255163953Srrs 256163953Srrs result = isc_socket_listen(listener->sock, 0); 257163953Srrs if (result != ISC_R_SUCCESS) 258163953Srrs UNEXPECTED_ERROR(__FILE__, __LINE__, 259171259Sdelphij "isc_socket_listen() failed: %s", 260171259Sdelphij isc_result_totext(result)); 261163953Srrs return (result); 262168299Srrs} 263163953Srrs 264163953Srrsstatic void 265163953Srrscontrol_next(controllistener_t *listener) { 266163953Srrs (void)control_accept(listener); 267163953Srrs} 268163953Srrs 269163953Srrsstatic void 270163953Srrscontrol_senddone(isc_task_t *task, isc_event_t *event) { 271163953Srrs isc_socketevent_t *sevent = (isc_socketevent_t *) event; 272163953Srrs controlconnection_t *conn = event->ev_arg; 273163953Srrs controllistener_t *listener = conn->listener; 274163953Srrs isc_socket_t *sock = (isc_socket_t *)sevent->ev_sender; 275163953Srrs isc_result_t result; 276163953Srrs 277163953Srrs REQUIRE(conn->sending); 278163953Srrs 279163953Srrs UNUSED(task); 280163953Srrs 281163953Srrs conn->sending = ISC_FALSE; 282163953Srrs 283163953Srrs if (sevent->result != ISC_R_SUCCESS && 284165220Srrs sevent->result != ISC_R_CANCELED) 285163953Srrs { 286163953Srrs char socktext[ISC_SOCKADDR_FORMATSIZE]; 287163953Srrs isc_sockaddr_t peeraddr; 288163953Srrs 289163953Srrs (void)isc_socket_getpeername(sock, &peeraddr); 290163953Srrs isc_sockaddr_format(&peeraddr, socktext, sizeof(socktext)); 291163953Srrs isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, 292163953Srrs NS_LOGMODULE_CONTROL, ISC_LOG_WARNING, 293163953Srrs "error sending command response to %s: %s", 294163953Srrs socktext, isc_result_totext(sevent->result)); 295163953Srrs } 296163953Srrs isc_event_free(&event); 297163953Srrs 298163953Srrs result = isccc_ccmsg_readmessage(&conn->ccmsg, listener->task, 299168299Srrs control_recvmessage, conn); 300163953Srrs if (result != ISC_R_SUCCESS) { 301163953Srrs isc_socket_detach(&conn->sock); 302163953Srrs maybe_free_connection(conn); 303163953Srrs maybe_free_listener(listener); 304168299Srrs } 305163953Srrs} 306163953Srrs 307163953Srrsstatic inline void 308163953Srrslog_invalid(isccc_ccmsg_t *ccmsg, isc_result_t result) { 309163953Srrs char socktext[ISC_SOCKADDR_FORMATSIZE]; 310163953Srrs isc_sockaddr_t peeraddr; 311163953Srrs 312163953Srrs (void)isc_socket_getpeername(ccmsg->sock, &peeraddr); 313163953Srrs isc_sockaddr_format(&peeraddr, socktext, sizeof(socktext)); 314163953Srrs isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, 315163953Srrs NS_LOGMODULE_CONTROL, ISC_LOG_ERROR, 316163953Srrs "invalid command from %s: %s", 317163953Srrs socktext, isc_result_totext(result)); 318163953Srrs} 319163953Srrs 320163953Srrsstatic void 321163953Srrscontrol_recvmessage(isc_task_t *task, isc_event_t *event) { 322163953Srrs controlconnection_t *conn; 323163953Srrs controllistener_t *listener; 324163953Srrs controlkey_t *key; 325163953Srrs isccc_sexpr_t *request = NULL; 326169420Srrs isccc_sexpr_t *response = NULL; 327163953Srrs isccc_region_t ccregion; 328169420Srrs isccc_region_t secret; 329163953Srrs isc_stdtime_t now; 330163953Srrs isc_buffer_t b; 331163953Srrs isc_region_t r; 332172156Srrs isc_uint32_t len; 333172091Srrs isc_buffer_t text; 334172091Srrs char textarray[1024]; 335172091Srrs isc_result_t result; 336172091Srrs isc_result_t eresult; 337172091Srrs isccc_sexpr_t *_ctrl; 338172091Srrs isccc_time_t sent; 339172091Srrs isccc_time_t exp; 340172091Srrs isc_uint32_t nonce; 341172091Srrs 342172091Srrs REQUIRE(event->ev_type == ISCCC_EVENT_CCMSG); 343172091Srrs 344172091Srrs conn = event->ev_arg; 345172091Srrs listener = conn->listener; 346172091Srrs secret.rstart = NULL; 347172091Srrs 348172091Srrs /* Is the server shutting down? */ 349172091Srrs if (listener->controls->shuttingdown) 350172091Srrs goto cleanup; 351172091Srrs 352172091Srrs if (conn->ccmsg.result != ISC_R_SUCCESS) { 353172091Srrs if (conn->ccmsg.result != ISC_R_CANCELED && 354172091Srrs conn->ccmsg.result != ISC_R_EOF) 355172091Srrs log_invalid(&conn->ccmsg, conn->ccmsg.result); 356172091Srrs goto cleanup; 357172091Srrs } 358172091Srrs 359172091Srrs request = NULL; 360172091Srrs 361172091Srrs for (key = ISC_LIST_HEAD(listener->keys); 362172091Srrs key != NULL; 363172091Srrs key = ISC_LIST_NEXT(key, link)) 364172091Srrs { 365172091Srrs ccregion.rstart = isc_buffer_base(&conn->ccmsg.buffer); 366172091Srrs ccregion.rend = isc_buffer_used(&conn->ccmsg.buffer); 367172091Srrs secret.rstart = isc_mem_get(listener->mctx, key->secret.length); 368172091Srrs if (secret.rstart == NULL) 369172091Srrs goto cleanup; 370172091Srrs memcpy(secret.rstart, key->secret.base, key->secret.length); 371172091Srrs secret.rend = secret.rstart + key->secret.length; 372172091Srrs result = isccc_cc_fromwire(&ccregion, &request, &secret); 373172091Srrs if (result == ISC_R_SUCCESS) 374172091Srrs break; 375172091Srrs isc_mem_put(listener->mctx, secret.rstart, REGION_SIZE(secret)); 376172091Srrs if (result != ISCCC_R_BADAUTH) { 377172091Srrs log_invalid(&conn->ccmsg, result); 378172091Srrs goto cleanup; 379172091Srrs } 380172091Srrs } 381172091Srrs 382172091Srrs if (key == NULL) { 383172091Srrs log_invalid(&conn->ccmsg, ISCCC_R_BADAUTH); 384172091Srrs goto cleanup; 385172091Srrs } 386172091Srrs 387172091Srrs /* We shouldn't be getting a reply. */ 388172091Srrs if (isccc_cc_isreply(request)) { 389172091Srrs log_invalid(&conn->ccmsg, ISC_R_FAILURE); 390172091Srrs goto cleanup_request; 391172091Srrs } 392172091Srrs 393172091Srrs isc_stdtime_get(&now); 394172091Srrs 395172091Srrs /* 396172091Srrs * Limit exposure to replay attacks. 397172091Srrs */ 398172091Srrs _ctrl = isccc_alist_lookup(request, "_ctrl"); 399172091Srrs if (_ctrl == NULL) { 400172091Srrs log_invalid(&conn->ccmsg, ISC_R_FAILURE); 401179783Srrs goto cleanup_request; 402172091Srrs } 403172091Srrs 404172091Srrs if (isccc_cc_lookupuint32(_ctrl, "_tim", &sent) == ISC_R_SUCCESS) { 405172091Srrs if ((sent + CLOCKSKEW) < now || (sent - CLOCKSKEW) > now) { 406172091Srrs log_invalid(&conn->ccmsg, ISCCC_R_CLOCKSKEW); 407172091Srrs goto cleanup_request; 408172091Srrs } 409172091Srrs } else { 410172091Srrs log_invalid(&conn->ccmsg, ISC_R_FAILURE); 411172091Srrs goto cleanup_request; 412172091Srrs } 413172091Srrs 414172091Srrs /* 415172091Srrs * Expire messages that are too old. 416172091Srrs */ 417172091Srrs if (isccc_cc_lookupuint32(_ctrl, "_exp", &exp) == ISC_R_SUCCESS && 418172091Srrs now > exp) { 419172091Srrs log_invalid(&conn->ccmsg, ISCCC_R_EXPIRED); 420172091Srrs goto cleanup_request; 421172091Srrs } 422172091Srrs 423172091Srrs /* 424172091Srrs * Duplicate suppression (required for UDP). 425172091Srrs */ 426172091Srrs isccc_cc_cleansymtab(listener->controls->symtab, now); 427172091Srrs result = isccc_cc_checkdup(listener->controls->symtab, request, now); 428172091Srrs if (result != ISC_R_SUCCESS) { 429172091Srrs if (result == ISC_R_EXISTS) 430172091Srrs result = ISCCC_R_DUPLICATE; 431172091Srrs log_invalid(&conn->ccmsg, result); 432172091Srrs goto cleanup_request; 433172091Srrs } 434172091Srrs 435172091Srrs if (conn->nonce != 0 && 436172091Srrs (isccc_cc_lookupuint32(_ctrl, "_nonce", &nonce) != ISC_R_SUCCESS || 437172091Srrs conn->nonce != nonce)) { 438172091Srrs log_invalid(&conn->ccmsg, ISCCC_R_BADAUTH); 439172091Srrs goto cleanup_request; 440172091Srrs } 441172091Srrs 442172091Srrs /* 443172091Srrs * Establish nonce. 444163953Srrs */ 445171259Sdelphij while (conn->nonce == 0) 446163953Srrs isc_random_get(&conn->nonce); 447163953Srrs 448163953Srrs isc_buffer_init(&text, textarray, sizeof(textarray)); 449167598Srrs eresult = ns_control_docommand(request, &text); 450163953Srrs 451167598Srrs result = isccc_cc_createresponse(request, now, now + 60, &response); 452167598Srrs if (result != ISC_R_SUCCESS) 453163953Srrs goto cleanup_request; 454163953Srrs if (eresult != ISC_R_SUCCESS) { 455163953Srrs isccc_sexpr_t *data; 456163953Srrs 457163953Srrs data = isccc_alist_lookup(response, "_data"); 458163953Srrs if (data != NULL) { 459163953Srrs const char *estr = isc_result_totext(eresult); 460163953Srrs if (isccc_cc_definestring(data, "err", estr) == NULL) 461163953Srrs goto cleanup_response; 462163953Srrs } 463163953Srrs } 464163953Srrs 465163953Srrs if (isc_buffer_usedlength(&text) > 0) { 466163953Srrs isccc_sexpr_t *data; 467163953Srrs 468163953Srrs data = isccc_alist_lookup(response, "_data"); 469163953Srrs if (data != NULL) { 470163953Srrs char *str = (char *)isc_buffer_base(&text); 471163953Srrs if (isccc_cc_definestring(data, "text", str) == NULL) 472163953Srrs goto cleanup_response; 473163953Srrs } 474163953Srrs } 475163953Srrs 476163953Srrs _ctrl = isccc_alist_lookup(response, "_ctrl"); 477163953Srrs if (_ctrl == NULL || 478163953Srrs isccc_cc_defineuint32(_ctrl, "_nonce", conn->nonce) == NULL) 479163953Srrs goto cleanup_response; 480163953Srrs 481163953Srrs ccregion.rstart = conn->buffer + 4; 482165647Srrs ccregion.rend = conn->buffer + sizeof(conn->buffer); 483163953Srrs result = isccc_cc_towire(response, &ccregion, &secret); 484163953Srrs if (result != ISC_R_SUCCESS) 485163953Srrs goto cleanup_response; 486163953Srrs isc_buffer_init(&b, conn->buffer, 4); 487163953Srrs len = sizeof(conn->buffer) - REGION_SIZE(ccregion); 488163953Srrs isc_buffer_putuint32(&b, len - 4); 489163953Srrs r.base = conn->buffer; 490163953Srrs r.length = len; 491163953Srrs 492163953Srrs result = isc_socket_send(conn->sock, &r, task, control_senddone, conn); 493163953Srrs if (result != ISC_R_SUCCESS) 494163953Srrs goto cleanup_response; 495163953Srrs conn->sending = ISC_TRUE; 496163953Srrs 497163953Srrs isc_mem_put(listener->mctx, secret.rstart, REGION_SIZE(secret)); 498167598Srrs isccc_sexpr_free(&request); 499163953Srrs isccc_sexpr_free(&response); 500163953Srrs return; 501163953Srrs 502163953Srrs cleanup_response: 503163953Srrs isccc_sexpr_free(&response); 504163953Srrs 505163953Srrs cleanup_request: 506163953Srrs isccc_sexpr_free(&request); 507163953Srrs isc_mem_put(listener->mctx, secret.rstart, REGION_SIZE(secret)); 508163953Srrs 509172091Srrs cleanup: 510163953Srrs isc_socket_detach(&conn->sock); 511163953Srrs isccc_ccmsg_invalidate(&conn->ccmsg); 512163953Srrs conn->ccmsg_valid = ISC_FALSE; 513163953Srrs maybe_free_connection(conn); 514163953Srrs maybe_free_listener(listener); 515163953Srrs} 516163953Srrs 517163953Srrsstatic void 518163953Srrscontrol_timeout(isc_task_t *task, isc_event_t *event) { 519163953Srrs controlconnection_t *conn = event->ev_arg; 520163953Srrs 521163953Srrs UNUSED(task); 522163953Srrs 523163953Srrs isc_timer_detach(&conn->timer); 524163953Srrs maybe_free_connection(conn); 525163953Srrs 526163953Srrs isc_event_free(&event); 527163953Srrs} 528163953Srrs 529163953Srrsstatic isc_result_t 530163953Srrsnewconnection(controllistener_t *listener, isc_socket_t *sock) { 531163953Srrs controlconnection_t *conn; 532163953Srrs isc_interval_t interval; 533163953Srrs isc_result_t result; 534163953Srrs 535163953Srrs conn = isc_mem_get(listener->mctx, sizeof(*conn)); 536163953Srrs if (conn == NULL) 537163953Srrs return (ISC_R_NOMEMORY); 538164085Srrs 539163953Srrs conn->sock = sock; 540163953Srrs isccc_ccmsg_init(listener->mctx, sock, &conn->ccmsg); 541163953Srrs conn->ccmsg_valid = ISC_TRUE; 542163953Srrs conn->sending = ISC_FALSE; 543164085Srrs conn->timer = NULL; 544167598Srrs isc_interval_set(&interval, 60, 0); 545163953Srrs result = isc_timer_create(ns_g_timermgr, isc_timertype_once, 546167598Srrs NULL, &interval, listener->task, 547167598Srrs control_timeout, conn, &conn->timer); 548170587Srwatson if (result != ISC_R_SUCCESS) 549163953Srrs goto cleanup; 550163953Srrs 551163953Srrs conn->listener = listener; 552171943Srrs conn->nonce = 0; 553171943Srrs ISC_LINK_INIT(conn, link); 554163953Srrs 555171943Srrs result = isccc_ccmsg_readmessage(&conn->ccmsg, listener->task, 556171943Srrs control_recvmessage, conn); 557171943Srrs if (result != ISC_R_SUCCESS) 558163953Srrs goto cleanup; 559171943Srrs isccc_ccmsg_setmaxsize(&conn->ccmsg, 2048); 560163953Srrs 561163953Srrs ISC_LIST_APPEND(listener->connections, conn, link); 562163953Srrs return (ISC_R_SUCCESS); 563163953Srrs 564163953Srrs cleanup: 565163953Srrs isccc_ccmsg_invalidate(&conn->ccmsg); 566167598Srrs if (conn->timer != NULL) 567163953Srrs isc_timer_detach(&conn->timer); 568164085Srrs isc_mem_put(listener->mctx, conn, sizeof(*conn)); 569164085Srrs return (result); 570163953Srrs} 571163953Srrs 572164085Srrsstatic void 573163953Srrscontrol_newconn(isc_task_t *task, isc_event_t *event) { 574171943Srrs isc_socket_newconnev_t *nevent = (isc_socket_newconnev_t *)event; 575164085Srrs controllistener_t *listener = event->ev_arg; 576163953Srrs isc_socket_t *sock; 577163953Srrs isc_sockaddr_t peeraddr; 578163953Srrs isc_result_t result; 579164085Srrs 580164085Srrs UNUSED(task); 581164085Srrs 582164085Srrs listener->listening = ISC_FALSE; 583164085Srrs 584164085Srrs if (nevent->result != ISC_R_SUCCESS) { 585164085Srrs if (nevent->result == ISC_R_CANCELED) { 586164085Srrs shutdown_listener(listener); 587164085Srrs goto cleanup; 588164085Srrs } 589164085Srrs goto restart; 590164085Srrs } 591164085Srrs 592164085Srrs sock = nevent->newsocket; 593164085Srrs isc_socket_setname(sock, "control", NULL); 594164085Srrs (void)isc_socket_getpeername(sock, &peeraddr); 595163953Srrs if (listener->type == isc_sockettype_tcp && 596163953Srrs !address_ok(&peeraddr, listener->acl)) { 597163953Srrs char socktext[ISC_SOCKADDR_FORMATSIZE]; 598163953Srrs isc_sockaddr_format(&peeraddr, socktext, sizeof(socktext)); 599163953Srrs isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, 600163953Srrs NS_LOGMODULE_CONTROL, ISC_LOG_WARNING, 601163953Srrs "rejected command channel message from %s", 602163953Srrs socktext); 603163953Srrs isc_socket_detach(&sock); 604163953Srrs goto restart; 605163953Srrs } 606163953Srrs 607163953Srrs result = newconnection(listener, sock); 608163953Srrs if (result != ISC_R_SUCCESS) { 609163953Srrs char socktext[ISC_SOCKADDR_FORMATSIZE]; 610163953Srrs isc_sockaddr_format(&peeraddr, socktext, sizeof(socktext)); 611163953Srrs isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, 612172091Srrs NS_LOGMODULE_CONTROL, ISC_LOG_WARNING, 613172091Srrs "dropped command channel from %s: %s", 614163953Srrs socktext, isc_result_totext(result)); 615172091Srrs isc_socket_detach(&sock); 616163953Srrs goto restart; 617163953Srrs } 618163953Srrs 619163953Srrs restart: 620163953Srrs control_next(listener); 621163953Srrs cleanup: 622163953Srrs isc_event_free(&event); 623163953Srrs} 624163953Srrs 625163953Srrsstatic void 626169380Srrscontrols_shutdown(ns_controls_t *controls) { 627169380Srrs controllistener_t *listener; 628163953Srrs controllistener_t *next; 629167695Srrs 630163953Srrs for (listener = ISC_LIST_HEAD(controls->listeners); 631163953Srrs listener != NULL; 632163953Srrs listener = next) 633163953Srrs { 634167695Srrs /* 635167695Srrs * This is asynchronous. As listeners shut down, they will 636163953Srrs * call their callbacks. 637163953Srrs */ 638163953Srrs next = ISC_LIST_NEXT(listener, link); 639163953Srrs shutdown_listener(listener); 640163953Srrs } 641163953Srrs} 642163953Srrs 643163953Srrsvoid 644163953Srrsns_controls_shutdown(ns_controls_t *controls) { 645163953Srrs controls_shutdown(controls); 646163953Srrs controls->shuttingdown = ISC_TRUE; 647163953Srrs} 648163953Srrs 649163953Srrsstatic isc_result_t 650163953Srrscfgkeylist_find(const cfg_obj_t *keylist, const char *keyname, 651166086Srrs const cfg_obj_t **objp) 652163953Srrs{ 653170205Srrs const cfg_listelt_t *element; 654163953Srrs const char *str; 655163953Srrs const cfg_obj_t *obj; 656171943Srrs 657171943Srrs for (element = cfg_list_first(keylist); 658163953Srrs element != NULL; 659171943Srrs element = cfg_list_next(element)) 660163953Srrs { 661179783Srrs obj = cfg_listelt_value(element); 662163953Srrs str = cfg_obj_asstring(cfg_map_getname(obj)); 663163953Srrs if (strcasecmp(str, keyname) == 0) 664163953Srrs break; 665170205Srrs } 666163953Srrs if (element == NULL) 667163953Srrs return (ISC_R_NOTFOUND); 668163953Srrs obj = cfg_listelt_value(element); 669170205Srrs *objp = obj; 670163953Srrs return (ISC_R_SUCCESS); 671163953Srrs} 672163953Srrs 673163953Srrsstatic isc_result_t 674163953Srrscontrolkeylist_fromcfg(const cfg_obj_t *keylist, isc_mem_t *mctx, 675163953Srrs controlkeylist_t *keyids) 676163953Srrs{ 677163953Srrs const cfg_listelt_t *element; 678163953Srrs char *newstr = NULL; 679163953Srrs const char *str; 680163953Srrs const cfg_obj_t *obj; 681163953Srrs controlkey_t *key; 682163953Srrs 683163953Srrs for (element = cfg_list_first(keylist); 684163953Srrs element != NULL; 685163953Srrs element = cfg_list_next(element)) 686163953Srrs { 687163953Srrs obj = cfg_listelt_value(element); 688170205Srrs str = cfg_obj_asstring(obj); 689163953Srrs newstr = isc_mem_strdup(mctx, str); 690163953Srrs if (newstr == NULL) 691163953Srrs goto cleanup; 692163953Srrs key = isc_mem_get(mctx, sizeof(*key)); 693163953Srrs if (key == NULL) 694163953Srrs goto cleanup; 695163953Srrs key->keyname = newstr; 696163953Srrs key->secret.base = NULL; 697166086Srrs key->secret.length = 0; 698163953Srrs ISC_LINK_INIT(key, link); 699163953Srrs ISC_LIST_APPEND(*keyids, key, link); 700171943Srrs newstr = NULL; 701171943Srrs } 702163953Srrs return (ISC_R_SUCCESS); 703171943Srrs 704170056Srrs cleanup: 705170056Srrs if (newstr != NULL) 706170056Srrs isc_mem_free(mctx, newstr); 707171943Srrs free_controlkeylist(keyids, mctx); 708170056Srrs return (ISC_R_NOMEMORY); 709170056Srrs} 710170056Srrs 711170056Srrsstatic void 712171943Srrsregister_keys(const cfg_obj_t *control, const cfg_obj_t *keylist, 713170056Srrs controlkeylist_t *keyids, isc_mem_t *mctx, const char *socktext) 714170056Srrs{ 715170056Srrs controlkey_t *keyid, *next; 716163953Srrs const cfg_obj_t *keydef; 717163953Srrs char secret[1024]; 718163953Srrs isc_buffer_t b; 719166023Srrs isc_result_t result; 720163953Srrs 721163953Srrs /* 722163953Srrs * Find the keys corresponding to the keyids used by this listener. 723163953Srrs */ 724163953Srrs for (keyid = ISC_LIST_HEAD(*keyids); keyid != NULL; keyid = next) { 725163953Srrs next = ISC_LIST_NEXT(keyid, link); 726163953Srrs 727163953Srrs result = cfgkeylist_find(keylist, keyid->keyname, &keydef); 728163953Srrs if (result != ISC_R_SUCCESS) { 729163953Srrs cfg_obj_log(control, ns_g_lctx, ISC_LOG_WARNING, 730163953Srrs "couldn't find key '%s' for use with " 731163953Srrs "command channel %s", 732163953Srrs keyid->keyname, socktext); 733163953Srrs ISC_LIST_UNLINK(*keyids, keyid, link); 734163953Srrs free_controlkey(keyid, mctx); 735163953Srrs } else { 736163953Srrs const cfg_obj_t *algobj = NULL; 737171572Srrs const cfg_obj_t *secretobj = NULL; 738163953Srrs const char *algstr = NULL; 739163953Srrs const char *secretstr = NULL; 740163953Srrs 741163953Srrs (void)cfg_map_get(keydef, "algorithm", &algobj); 742163953Srrs (void)cfg_map_get(keydef, "secret", &secretobj); 743163953Srrs INSIST(algobj != NULL && secretobj != NULL); 744163953Srrs 745171943Srrs algstr = cfg_obj_asstring(algobj); 746163953Srrs secretstr = cfg_obj_asstring(secretobj); 747163953Srrs 748163953Srrs if (ns_config_getkeyalgorithm(algstr, NULL, NULL) != 749163953Srrs ISC_R_SUCCESS) 750163953Srrs { 751163953Srrs cfg_obj_log(control, ns_g_lctx, 752172091Srrs ISC_LOG_WARNING, 753163953Srrs "unsupported algorithm '%s' in " 754163953Srrs "key '%s' for use with command " 755171943Srrs "channel %s", 756172091Srrs algstr, keyid->keyname, socktext); 757172091Srrs ISC_LIST_UNLINK(*keyids, keyid, link); 758163953Srrs free_controlkey(keyid, mctx); 759163953Srrs continue; 760171572Srrs } 761163953Srrs 762163953Srrs isc_buffer_init(&b, secret, sizeof(secret)); 763163953Srrs result = isc_base64_decodestring(secretstr, &b); 764163953Srrs 765163953Srrs if (result != ISC_R_SUCCESS) { 766163953Srrs cfg_obj_log(keydef, ns_g_lctx, ISC_LOG_WARNING, 767163953Srrs "secret for key '%s' on " 768171990Srrs "command channel %s: %s", 769163953Srrs keyid->keyname, socktext, 770163953Srrs isc_result_totext(result)); 771167598Srrs ISC_LIST_UNLINK(*keyids, keyid, link); 772163953Srrs free_controlkey(keyid, mctx); 773168709Srrs continue; 774168709Srrs } 775163953Srrs 776163953Srrs keyid->secret.length = isc_buffer_usedlength(&b); 777171990Srrs keyid->secret.base = isc_mem_get(mctx, 778163953Srrs keyid->secret.length); 779163953Srrs if (keyid->secret.base == NULL) { 780168709Srrs cfg_obj_log(keydef, ns_g_lctx, ISC_LOG_WARNING, 781163953Srrs "couldn't register key '%s': " 782163953Srrs "out of memory", keyid->keyname); 783163953Srrs ISC_LIST_UNLINK(*keyids, keyid, link); 784163953Srrs free_controlkey(keyid, mctx); 785163953Srrs break; 786163953Srrs } 787163953Srrs memcpy(keyid->secret.base, isc_buffer_base(&b), 788163953Srrs keyid->secret.length); 789163953Srrs } 790163953Srrs } 791163953Srrs} 792163953Srrs 793163953Srrs#define CHECK(x) \ 794163953Srrs do { \ 795163953Srrs result = (x); \ 796163953Srrs if (result != ISC_R_SUCCESS) \ 797163953Srrs goto cleanup; \ 798163953Srrs } while (0) 799163953Srrs 800163953Srrsstatic isc_result_t 801163953Srrsget_rndckey(isc_mem_t *mctx, controlkeylist_t *keyids) { 802163953Srrs isc_result_t result; 803169352Srrs cfg_parser_t *pctx = NULL; 804163953Srrs cfg_obj_t *config = NULL; 805163953Srrs const cfg_obj_t *key = NULL; 806169352Srrs const cfg_obj_t *algobj = NULL; 807171943Srrs const cfg_obj_t *secretobj = NULL; 808163953Srrs const char *algstr = NULL; 809163953Srrs const char *secretstr = NULL; 810163953Srrs controlkey_t *keyid = NULL; 811163953Srrs char secret[1024]; 812163953Srrs isc_buffer_t b; 813163953Srrs 814163953Srrs CHECK(cfg_parser_create(mctx, ns_g_lctx, &pctx)); 815163953Srrs CHECK(cfg_parse_file(pctx, ns_g_keyfile, &cfg_type_rndckey, &config)); 816163953Srrs CHECK(cfg_map_get(config, "key", &key)); 817163953Srrs 818163953Srrs keyid = isc_mem_get(mctx, sizeof(*keyid)); 819163953Srrs if (keyid == NULL) 820163953Srrs CHECK(ISC_R_NOMEMORY); 821169352Srrs keyid->keyname = isc_mem_strdup(mctx, 822163953Srrs cfg_obj_asstring(cfg_map_getname(key))); 823169352Srrs keyid->secret.base = NULL; 824163953Srrs keyid->secret.length = 0; 825163953Srrs ISC_LINK_INIT(keyid, link); 826171943Srrs if (keyid->keyname == NULL) 827163953Srrs CHECK(ISC_R_NOMEMORY); 828163953Srrs 829163953Srrs CHECK(bind9_check_key(key, ns_g_lctx)); 830163953Srrs 831166023Srrs (void)cfg_map_get(key, "algorithm", &algobj); 832163953Srrs (void)cfg_map_get(key, "secret", &secretobj); 833163953Srrs INSIST(algobj != NULL && secretobj != NULL); 834163953Srrs 835163953Srrs algstr = cfg_obj_asstring(algobj); 836163953Srrs secretstr = cfg_obj_asstring(secretobj); 837171943Srrs 838163953Srrs if (ns_config_getkeyalgorithm(algstr, NULL, NULL) != ISC_R_SUCCESS) { 839163953Srrs cfg_obj_log(key, ns_g_lctx, 840163953Srrs ISC_LOG_WARNING, 841171943Srrs "unsupported algorithm '%s' in " 842163953Srrs "key '%s' for use with command " 843163953Srrs "channel", 844163953Srrs algstr, keyid->keyname); 845163953Srrs goto cleanup; 846163953Srrs } 847163953Srrs 848163953Srrs isc_buffer_init(&b, secret, sizeof(secret)); 849163953Srrs result = isc_base64_decodestring(secretstr, &b); 850163953Srrs 851163953Srrs if (result != ISC_R_SUCCESS) { 852163953Srrs cfg_obj_log(key, ns_g_lctx, ISC_LOG_WARNING, 853163953Srrs "secret for key '%s' on command channel: %s", 854163953Srrs keyid->keyname, isc_result_totext(result)); 855171943Srrs goto cleanup; 856163953Srrs } 857163953Srrs 858163953Srrs keyid->secret.length = isc_buffer_usedlength(&b); 859163953Srrs keyid->secret.base = isc_mem_get(mctx, 860163953Srrs keyid->secret.length); 861163953Srrs if (keyid->secret.base == NULL) { 862163953Srrs cfg_obj_log(key, ns_g_lctx, ISC_LOG_WARNING, 863163953Srrs "couldn't register key '%s': " 864169420Srrs "out of memory", keyid->keyname); 865169352Srrs CHECK(ISC_R_NOMEMORY); 866163953Srrs } 867163953Srrs memcpy(keyid->secret.base, isc_buffer_base(&b), 868163953Srrs keyid->secret.length); 869163953Srrs ISC_LIST_APPEND(*keyids, keyid, link); 870163953Srrs keyid = NULL; 871163953Srrs result = ISC_R_SUCCESS; 872165647Srrs 873163953Srrs cleanup: 874163953Srrs if (keyid != NULL) 875163953Srrs free_controlkey(keyid, mctx); 876163953Srrs if (config != NULL) 877163953Srrs cfg_obj_destroy(pctx, &config); 878163953Srrs if (pctx != NULL) 879163953Srrs cfg_parser_destroy(&pctx); 880163953Srrs return (result); 881163953Srrs} 882163953Srrs 883163953Srrs/* 884163953Srrs * Ensures that both '*global_keylistp' and '*control_keylistp' are 885163953Srrs * valid or both are NULL. 886163953Srrs */ 887163953Srrsstatic void 888163953Srrsget_key_info(const cfg_obj_t *config, const cfg_obj_t *control, 889163953Srrs const cfg_obj_t **global_keylistp, 890163953Srrs const cfg_obj_t **control_keylistp) 891163953Srrs{ 892163953Srrs isc_result_t result; 893163953Srrs const cfg_obj_t *control_keylist = NULL; 894163953Srrs const cfg_obj_t *global_keylist = NULL; 895163953Srrs 896163953Srrs REQUIRE(global_keylistp != NULL && *global_keylistp == NULL); 897163953Srrs REQUIRE(control_keylistp != NULL && *control_keylistp == NULL); 898163953Srrs 899163953Srrs control_keylist = cfg_tuple_get(control, "keys"); 900163953Srrs 901163953Srrs if (!cfg_obj_isvoid(control_keylist) && 902167598Srrs cfg_list_first(control_keylist) != NULL) { 903163953Srrs result = cfg_map_get(config, "key", &global_keylist); 904163953Srrs 905163953Srrs if (result == ISC_R_SUCCESS) { 906163953Srrs *global_keylistp = global_keylist; 907163953Srrs *control_keylistp = control_keylist; 908163953Srrs } 909163953Srrs } 910163953Srrs} 911163953Srrs 912163953Srrsstatic void 913163953Srrsupdate_listener(ns_controls_t *cp, controllistener_t **listenerp, 914163953Srrs const cfg_obj_t *control, const cfg_obj_t *config, 915163953Srrs isc_sockaddr_t *addr, cfg_aclconfctx_t *aclconfctx, 916163953Srrs const char *socktext, isc_sockettype_t type) 917171943Srrs{ 918163953Srrs controllistener_t *listener; 919163953Srrs const cfg_obj_t *allow; 920163953Srrs const cfg_obj_t *global_keylist = NULL; 921170056Srrs const cfg_obj_t *control_keylist = NULL; 922171943Srrs dns_acl_t *new_acl = NULL; 923170056Srrs controlkeylist_t keys; 924170056Srrs isc_result_t result = ISC_R_SUCCESS; 925170056Srrs 926171943Srrs for (listener = ISC_LIST_HEAD(cp->listeners); 927170056Srrs listener != NULL; 928170056Srrs listener = ISC_LIST_NEXT(listener, link)) 929170056Srrs if (isc_sockaddr_equal(addr, &listener->address)) 930171943Srrs break; 931170056Srrs 932170056Srrs if (listener == NULL) { 933168299Srrs *listenerp = NULL; 934163953Srrs return; 935163953Srrs } 936163953Srrs 937163953Srrs /* 938163953Srrs * There is already a listener for this sockaddr. 939163953Srrs * Update the access list and key information. 940163953Srrs * 941163953Srrs * First try to deal with the key situation. There are a few 942163953Srrs * possibilities: 943163953Srrs * (a) It had an explicit keylist and still has an explicit keylist. 944163953Srrs * (b) It had an automagic key and now has an explicit keylist. 945163953Srrs * (c) It had an explicit keylist and now needs an automagic key. 946163953Srrs * (d) It has an automagic key and still needs the automagic key. 947163953Srrs * 948163953Srrs * (c) and (d) are the annoying ones. The caller needs to know 949163953Srrs * that it should use the automagic configuration for key information 950163953Srrs * in place of the named.conf configuration. 951163953Srrs * 952163953Srrs * XXXDCL There is one other hazard that has not been dealt with, 953171943Srrs * the problem that if a key change is being caused by a control 954163953Srrs * channel reload, then the response will be with the new key 955163953Srrs * and not able to be decrypted by the client. 956163953Srrs */ 957163953Srrs if (control != NULL) 958166023Srrs get_key_info(config, control, &global_keylist, 959163953Srrs &control_keylist); 960163953Srrs 961163953Srrs if (control_keylist != NULL) { 962163953Srrs INSIST(global_keylist != NULL); 963163953Srrs 964163953Srrs ISC_LIST_INIT(keys); 965163953Srrs result = controlkeylist_fromcfg(control_keylist, 966171943Srrs listener->mctx, &keys); 967163953Srrs if (result == ISC_R_SUCCESS) { 968163953Srrs free_controlkeylist(&listener->keys, listener->mctx); 969163953Srrs listener->keys = keys; 970163953Srrs register_keys(control, global_keylist, &listener->keys, 971163953Srrs listener->mctx, socktext); 972171943Srrs } 973163953Srrs } else { 974163953Srrs free_controlkeylist(&listener->keys, listener->mctx); 975163953Srrs result = get_rndckey(listener->mctx, &listener->keys); 976163953Srrs } 977163953Srrs 978163953Srrs if (result != ISC_R_SUCCESS && global_keylist != NULL) { 979163953Srrs /* 980163953Srrs * This message might be a little misleading since the 981163953Srrs * "new keys" might in fact be identical to the old ones, 982163953Srrs * but tracking whether they are identical just for the 983163953Srrs * sake of avoiding this message would be too much trouble. 984163953Srrs */ 985171943Srrs if (control != NULL) 986163953Srrs cfg_obj_log(control, ns_g_lctx, ISC_LOG_WARNING, 987163953Srrs "couldn't install new keys for " 988163953Srrs "command channel %s: %s", 989163953Srrs socktext, isc_result_totext(result)); 990163953Srrs else 991163953Srrs isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, 992163953Srrs NS_LOGMODULE_CONTROL, ISC_LOG_WARNING, 993163953Srrs "couldn't install new keys for " 994163953Srrs "command channel %s: %s", 995169420Srrs socktext, isc_result_totext(result)); 996163953Srrs } 997169420Srrs 998163953Srrs /* 999163953Srrs * Now, keep the old access list unless a new one can be made. 1000163953Srrs */ 1001163953Srrs if (control != NULL && type == isc_sockettype_tcp) { 1002163953Srrs allow = cfg_tuple_get(control, "allow"); 1003163953Srrs result = cfg_acl_fromconfig(allow, config, ns_g_lctx, 1004163953Srrs aclconfctx, listener->mctx, 0, 1005163953Srrs &new_acl); 1006163953Srrs } else { 1007163953Srrs result = dns_acl_any(listener->mctx, &new_acl); 1008163953Srrs } 1009163953Srrs 1010163953Srrs if (result == ISC_R_SUCCESS) { 1011163953Srrs dns_acl_detach(&listener->acl); 1012163953Srrs dns_acl_attach(new_acl, &listener->acl); 1013163953Srrs dns_acl_detach(&new_acl); 1014163953Srrs /* XXXDCL say the old acl is still used? */ 1015163953Srrs } else if (control != NULL) 1016171943Srrs cfg_obj_log(control, ns_g_lctx, ISC_LOG_WARNING, 1017163953Srrs "couldn't install new acl for " 1018163953Srrs "command channel %s: %s", 1019163953Srrs socktext, isc_result_totext(result)); 1020171531Srrs else 1021163953Srrs isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, 1022163953Srrs NS_LOGMODULE_CONTROL, ISC_LOG_WARNING, 1023163953Srrs "couldn't install new acl for " 1024163953Srrs "command channel %s: %s", 1025163953Srrs socktext, isc_result_totext(result)); 1026163953Srrs 1027163953Srrs if (result == ISC_R_SUCCESS && type == isc_sockettype_unix) { 1028163953Srrs isc_uint32_t perm, owner, group; 1029163953Srrs perm = cfg_obj_asuint32(cfg_tuple_get(control, "perm")); 1030163953Srrs owner = cfg_obj_asuint32(cfg_tuple_get(control, "owner")); 1031163953Srrs group = cfg_obj_asuint32(cfg_tuple_get(control, "group")); 1032169420Srrs result = ISC_R_SUCCESS; 1033163953Srrs if (listener->perm != perm || listener->owner != owner || 1034163953Srrs listener->group != group) 1035163953Srrs result = isc_socket_permunix(&listener->address, perm, 1036163953Srrs owner, group); 1037172090Srrs if (result == ISC_R_SUCCESS) { 1038163953Srrs listener->perm = perm; 1039163953Srrs listener->owner = owner; 1040163953Srrs listener->group = group; 1041163953Srrs } else if (control != NULL) 1042163953Srrs cfg_obj_log(control, ns_g_lctx, ISC_LOG_WARNING, 1043163953Srrs "couldn't update ownership/permission for " 1044163953Srrs "command channel %s", socktext); 1045163953Srrs } 1046163953Srrs 1047167598Srrs *listenerp = listener; 1048167598Srrs} 1049163953Srrs 1050163953Srrsstatic void 1051163953Srrsadd_listener(ns_controls_t *cp, controllistener_t **listenerp, 1052163953Srrs const cfg_obj_t *control, const cfg_obj_t *config, 1053163953Srrs isc_sockaddr_t *addr, cfg_aclconfctx_t *aclconfctx, 1054163953Srrs const char *socktext, isc_sockettype_t type) 1055163953Srrs{ 1056163953Srrs isc_mem_t *mctx = cp->server->mctx; 1057163953Srrs controllistener_t *listener; 1058163953Srrs const cfg_obj_t *allow; 1059163953Srrs const cfg_obj_t *global_keylist = NULL; 1060163953Srrs const cfg_obj_t *control_keylist = NULL; 1061163953Srrs dns_acl_t *new_acl = NULL; 1062171943Srrs isc_result_t result = ISC_R_SUCCESS; 1063163953Srrs 1064163953Srrs listener = isc_mem_get(mctx, sizeof(*listener)); 1065163953Srrs if (listener == NULL) 1066163953Srrs result = ISC_R_NOMEMORY; 1067163953Srrs 1068163953Srrs if (result == ISC_R_SUCCESS) { 1069163953Srrs listener->controls = cp; 1070163953Srrs listener->mctx = mctx; 1071163953Srrs listener->task = cp->server->task; 1072163953Srrs listener->address = *addr; 1073163953Srrs listener->sock = NULL; 1074163953Srrs listener->listening = ISC_FALSE; 1075163953Srrs listener->exiting = ISC_FALSE; 1076163953Srrs listener->acl = NULL; 1077163953Srrs listener->type = type; 1078163953Srrs listener->perm = 0; 1079163953Srrs listener->owner = 0; 1080163953Srrs listener->group = 0; 1081163953Srrs ISC_LINK_INIT(listener, link); 1082163953Srrs ISC_LIST_INIT(listener->keys); 1083164085Srrs ISC_LIST_INIT(listener->connections); 1084164085Srrs 1085164085Srrs /* 1086164085Srrs * Make the acl. 1087163953Srrs */ 1088163953Srrs if (control != NULL && type == isc_sockettype_tcp) { 1089163953Srrs allow = cfg_tuple_get(control, "allow"); 1090163953Srrs result = cfg_acl_fromconfig(allow, config, ns_g_lctx, 1091163953Srrs aclconfctx, mctx, 0, 1092163953Srrs &new_acl); 1093163953Srrs } else { 1094163953Srrs result = dns_acl_any(mctx, &new_acl); 1095163953Srrs } 1096168299Srrs } 1097168299Srrs 1098167598Srrs if (result == ISC_R_SUCCESS) { 1099167598Srrs dns_acl_attach(new_acl, &listener->acl); 1100167598Srrs dns_acl_detach(&new_acl); 1101163953Srrs 1102163953Srrs if (config != NULL) 1103163953Srrs get_key_info(config, control, &global_keylist, 1104163953Srrs &control_keylist); 1105163953Srrs 1106163953Srrs if (control_keylist != NULL) { 1107163953Srrs result = controlkeylist_fromcfg(control_keylist, 1108163953Srrs listener->mctx, 1109163953Srrs &listener->keys); 1110163953Srrs if (result == ISC_R_SUCCESS) 1111163953Srrs register_keys(control, global_keylist, 1112167598Srrs &listener->keys, 1113163953Srrs listener->mctx, socktext); 1114163953Srrs } else 1115167598Srrs result = get_rndckey(mctx, &listener->keys); 1116163953Srrs 1117163953Srrs if (result != ISC_R_SUCCESS && control != NULL) 1118163953Srrs cfg_obj_log(control, ns_g_lctx, ISC_LOG_WARNING, 1119163953Srrs "couldn't install keys for " 1120163953Srrs "command channel %s: %s", 1121163953Srrs socktext, isc_result_totext(result)); 1122163953Srrs } 1123163953Srrs 1124171943Srrs if (result == ISC_R_SUCCESS) { 1125163953Srrs int pf = isc_sockaddr_pf(&listener->address); 1126163953Srrs if ((pf == AF_INET && isc_net_probeipv4() != ISC_R_SUCCESS) || 1127163953Srrs#ifdef ISC_PLATFORM_HAVESYSUNH 1128163953Srrs (pf == AF_UNIX && isc_net_probeunix() != ISC_R_SUCCESS) || 1129163953Srrs#endif 1130164085Srrs (pf == AF_INET6 && isc_net_probeipv6() != ISC_R_SUCCESS)) 1131164085Srrs result = ISC_R_FAMILYNOSUPPORT; 1132163953Srrs } 1133164085Srrs 1134163953Srrs if (result == ISC_R_SUCCESS && type == isc_sockettype_unix) 1135163953Srrs isc_socket_cleanunix(&listener->address, ISC_FALSE); 1136163953Srrs 1137163953Srrs if (result == ISC_R_SUCCESS) 1138163953Srrs result = isc_socket_create(ns_g_socketmgr, 1139163953Srrs isc_sockaddr_pf(&listener->address), 1140163953Srrs type, &listener->sock); 1141163953Srrs if (result == ISC_R_SUCCESS) 1142163953Srrs isc_socket_setname(listener->sock, "control", NULL); 1143163953Srrs 1144163953Srrs#ifndef ISC_ALLOW_MAPPED 1145163953Srrs if (result == ISC_R_SUCCESS) 1146163953Srrs isc_socket_ipv6only(listener->sock, ISC_TRUE); 1147163953Srrs#endif 1148163953Srrs 1149163953Srrs if (result == ISC_R_SUCCESS) 1150163953Srrs result = isc_socket_bind(listener->sock, &listener->address, 1151163953Srrs ISC_SOCKET_REUSEADDRESS); 1152163953Srrs 1153163953Srrs if (result == ISC_R_SUCCESS && type == isc_sockettype_unix) { 1154163953Srrs listener->perm = cfg_obj_asuint32(cfg_tuple_get(control, 1155163953Srrs "perm")); 1156171943Srrs listener->owner = cfg_obj_asuint32(cfg_tuple_get(control, 1157163953Srrs "owner")); 1158163953Srrs listener->group = cfg_obj_asuint32(cfg_tuple_get(control, 1159163953Srrs "group")); 1160163953Srrs result = isc_socket_permunix(&listener->address, listener->perm, 1161163953Srrs listener->owner, listener->group); 1162163953Srrs } 1163163953Srrs if (result == ISC_R_SUCCESS) 1164163953Srrs result = control_listen(listener); 1165163953Srrs 1166163953Srrs if (result == ISC_R_SUCCESS) 1167171943Srrs result = control_accept(listener); 1168163953Srrs 1169163953Srrs if (result == ISC_R_SUCCESS) { 1170163953Srrs isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, 1171163953Srrs NS_LOGMODULE_CONTROL, ISC_LOG_NOTICE, 1172169420Srrs "command channel listening on %s", socktext); 1173163953Srrs *listenerp = listener; 1174169420Srrs 1175163953Srrs } else { 1176163953Srrs if (listener != NULL) { 1177163953Srrs listener->exiting = ISC_TRUE; 1178171943Srrs free_listener(listener); 1179163953Srrs } 1180163953Srrs 1181163953Srrs if (control != NULL) 1182163953Srrs cfg_obj_log(control, ns_g_lctx, ISC_LOG_WARNING, 1183163953Srrs "couldn't add command channel %s: %s", 1184163953Srrs socktext, isc_result_totext(result)); 1185163953Srrs else 1186163953Srrs isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, 1187163953Srrs NS_LOGMODULE_CONTROL, ISC_LOG_NOTICE, 1188163953Srrs "couldn't add command channel %s: %s", 1189163953Srrs socktext, isc_result_totext(result)); 1190163953Srrs 1191163953Srrs *listenerp = NULL; 1192163953Srrs } 1193163953Srrs 1194163953Srrs /* XXXDCL return error results? fail hard? */ 1195171943Srrs} 1196163953Srrs 1197163953Srrsisc_result_t 1198163953Srrsns_controls_configure(ns_controls_t *cp, const cfg_obj_t *config, 1199163953Srrs cfg_aclconfctx_t *aclconfctx) 1200163953Srrs{ 1201163953Srrs controllistener_t *listener; 1202163953Srrs controllistenerlist_t new_listeners; 1203163953Srrs const cfg_obj_t *controlslist = NULL; 1204163953Srrs const cfg_listelt_t *element, *element2; 1205163953Srrs char socktext[ISC_SOCKADDR_FORMATSIZE]; 1206163953Srrs 1207163953Srrs ISC_LIST_INIT(new_listeners); 1208163953Srrs 1209166086Srrs /* 1210163953Srrs * Get the list of named.conf 'controls' statements. 1211171943Srrs */ 1212171943Srrs (void)cfg_map_get(config, "controls", &controlslist); 1213163953Srrs 1214171943Srrs /* 1215163953Srrs * Run through the new control channel list, noting sockets that 1216163953Srrs * are already being listened on and moving them to the new list. 1217163953Srrs * 1218163953Srrs * Identifying duplicate addr/port combinations is left to either 1219163953Srrs * the underlying config code, or to the bind attempt getting an 1220163953Srrs * address-in-use error. 1221163953Srrs */ 1222163953Srrs if (controlslist != NULL) { 1223163953Srrs for (element = cfg_list_first(controlslist); 1224163953Srrs element != NULL; 1225166023Srrs element = cfg_list_next(element)) { 1226163953Srrs const cfg_obj_t *controls; 1227163953Srrs const cfg_obj_t *inetcontrols = NULL; 1228163953Srrs 1229163953Srrs controls = cfg_listelt_value(element); 1230168709Srrs (void)cfg_map_get(controls, "inet", &inetcontrols); 1231163953Srrs if (inetcontrols == NULL) 1232163953Srrs continue; 1233163953Srrs 1234163953Srrs for (element2 = cfg_list_first(inetcontrols); 1235163953Srrs element2 != NULL; 1236163953Srrs element2 = cfg_list_next(element2)) { 1237163953Srrs const cfg_obj_t *control; 1238163953Srrs const cfg_obj_t *obj; 1239163953Srrs isc_sockaddr_t addr; 1240163953Srrs 1241163953Srrs /* 1242166086Srrs * The parser handles BIND 8 configuration file 1243163953Srrs * syntax, so it allows unix phrases as well 1244171943Srrs * inet phrases with no keys{} clause. 1245171943Srrs */ 1246163953Srrs control = cfg_listelt_value(element2); 1247171943Srrs 1248163953Srrs obj = cfg_tuple_get(control, "address"); 1249163953Srrs addr = *cfg_obj_assockaddr(obj); 1250163953Srrs if (isc_sockaddr_getport(&addr) == 0) 1251163953Srrs isc_sockaddr_setport(&addr, 1252163953Srrs NS_CONTROL_PORT); 1253163953Srrs 1254163953Srrs isc_sockaddr_format(&addr, socktext, 1255163953Srrs sizeof(socktext)); 1256163953Srrs 1257166023Srrs isc_log_write(ns_g_lctx, 1258163953Srrs NS_LOGCATEGORY_GENERAL, 1259163953Srrs NS_LOGMODULE_CONTROL, 1260163953Srrs ISC_LOG_DEBUG(9), 1261163953Srrs "processing control channel %s", 1262163953Srrs socktext); 1263163953Srrs 1264163953Srrs update_listener(cp, &listener, control, config, 1265163953Srrs &addr, aclconfctx, socktext, 1266163953Srrs isc_sockettype_tcp); 1267163953Srrs 1268163953Srrs if (listener != NULL) 1269163953Srrs /* 1270163953Srrs * Remove the listener from the old 1271163953Srrs * list, so it won't be shut down. 1272163953Srrs */ 1273163953Srrs ISC_LIST_UNLINK(cp->listeners, 1274163953Srrs listener, link); 1275163953Srrs else 1276163953Srrs /* 1277178201Srrs * This is a new listener. 1278163953Srrs */ 1279163953Srrs add_listener(cp, &listener, control, 1280163953Srrs config, &addr, aclconfctx, 1281163953Srrs socktext, 1282163953Srrs isc_sockettype_tcp); 1283163953Srrs 1284163953Srrs if (listener != NULL) 1285163953Srrs ISC_LIST_APPEND(new_listeners, 1286163953Srrs listener, link); 1287 } 1288 } 1289 for (element = cfg_list_first(controlslist); 1290 element != NULL; 1291 element = cfg_list_next(element)) { 1292 const cfg_obj_t *controls; 1293 const cfg_obj_t *unixcontrols = NULL; 1294 1295 controls = cfg_listelt_value(element); 1296 (void)cfg_map_get(controls, "unix", &unixcontrols); 1297 if (unixcontrols == NULL) 1298 continue; 1299 1300 for (element2 = cfg_list_first(unixcontrols); 1301 element2 != NULL; 1302 element2 = cfg_list_next(element2)) { 1303 const cfg_obj_t *control; 1304 const cfg_obj_t *path; 1305 isc_sockaddr_t addr; 1306 isc_result_t result; 1307 1308 /* 1309 * The parser handles BIND 8 configuration file 1310 * syntax, so it allows unix phrases as well 1311 * inet phrases with no keys{} clause. 1312 */ 1313 control = cfg_listelt_value(element2); 1314 1315 path = cfg_tuple_get(control, "path"); 1316 result = isc_sockaddr_frompath(&addr, 1317 cfg_obj_asstring(path)); 1318 if (result != ISC_R_SUCCESS) { 1319 isc_log_write(ns_g_lctx, 1320 NS_LOGCATEGORY_GENERAL, 1321 NS_LOGMODULE_CONTROL, 1322 ISC_LOG_DEBUG(9), 1323 "control channel '%s': %s", 1324 cfg_obj_asstring(path), 1325 isc_result_totext(result)); 1326 continue; 1327 } 1328 1329 isc_log_write(ns_g_lctx, 1330 NS_LOGCATEGORY_GENERAL, 1331 NS_LOGMODULE_CONTROL, 1332 ISC_LOG_DEBUG(9), 1333 "processing control channel '%s'", 1334 cfg_obj_asstring(path)); 1335 1336 update_listener(cp, &listener, control, config, 1337 &addr, aclconfctx, 1338 cfg_obj_asstring(path), 1339 isc_sockettype_unix); 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 cfg_obj_asstring(path), 1355 isc_sockettype_unix); 1356 1357 if (listener != NULL) 1358 ISC_LIST_APPEND(new_listeners, 1359 listener, link); 1360 } 1361 } 1362 } else { 1363 int i; 1364 1365 for (i = 0; i < 2; i++) { 1366 isc_sockaddr_t addr; 1367 1368 if (i == 0) { 1369 struct in_addr localhost; 1370 1371 if (isc_net_probeipv4() != ISC_R_SUCCESS) 1372 continue; 1373 localhost.s_addr = htonl(INADDR_LOOPBACK); 1374 isc_sockaddr_fromin(&addr, &localhost, 0); 1375 } else { 1376 if (isc_net_probeipv6() != ISC_R_SUCCESS) 1377 continue; 1378 isc_sockaddr_fromin6(&addr, 1379 &in6addr_loopback, 0); 1380 } 1381 isc_sockaddr_setport(&addr, NS_CONTROL_PORT); 1382 1383 isc_sockaddr_format(&addr, socktext, sizeof(socktext)); 1384 1385 update_listener(cp, &listener, NULL, NULL, 1386 &addr, NULL, socktext, 1387 isc_sockettype_tcp); 1388 1389 if (listener != NULL) 1390 /* 1391 * Remove the listener from the old 1392 * list, so it won't be shut down. 1393 */ 1394 ISC_LIST_UNLINK(cp->listeners, 1395 listener, link); 1396 else 1397 /* 1398 * This is a new listener. 1399 */ 1400 add_listener(cp, &listener, NULL, NULL, 1401 &addr, NULL, socktext, 1402 isc_sockettype_tcp); 1403 1404 if (listener != NULL) 1405 ISC_LIST_APPEND(new_listeners, 1406 listener, link); 1407 } 1408 } 1409 1410 /* 1411 * ns_control_shutdown() will stop whatever is on the global 1412 * listeners list, which currently only has whatever sockaddrs 1413 * were in the previous configuration (if any) that do not 1414 * remain in the current configuration. 1415 */ 1416 controls_shutdown(cp); 1417 1418 /* 1419 * Put all of the valid listeners on the listeners list. 1420 * Anything already on listeners in the process of shutting 1421 * down will be taken care of by listen_done(). 1422 */ 1423 ISC_LIST_APPENDLIST(cp->listeners, new_listeners, link); 1424 return (ISC_R_SUCCESS); 1425} 1426 1427isc_result_t 1428ns_controls_create(ns_server_t *server, ns_controls_t **ctrlsp) { 1429 isc_mem_t *mctx = server->mctx; 1430 isc_result_t result; 1431 ns_controls_t *controls = isc_mem_get(mctx, sizeof(*controls)); 1432 1433 if (controls == NULL) 1434 return (ISC_R_NOMEMORY); 1435 controls->server = server; 1436 ISC_LIST_INIT(controls->listeners); 1437 controls->shuttingdown = ISC_FALSE; 1438 controls->symtab = NULL; 1439 result = isccc_cc_createsymtab(&controls->symtab); 1440 if (result != ISC_R_SUCCESS) { 1441 isc_mem_put(server->mctx, controls, sizeof(*controls)); 1442 return (result); 1443 } 1444 *ctrlsp = controls; 1445 return (ISC_R_SUCCESS); 1446} 1447 1448void 1449ns_controls_destroy(ns_controls_t **ctrlsp) { 1450 ns_controls_t *controls = *ctrlsp; 1451 1452 REQUIRE(ISC_LIST_EMPTY(controls->listeners)); 1453 1454 isccc_symtab_destroy(&controls->symtab); 1455 isc_mem_put(controls->server->mctx, controls, sizeof(*controls)); 1456 *ctrlsp = NULL; 1457} 1458