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