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