]> CyberLeo.Net >> Repos - FreeBSD/stable/9.git/blob - contrib/bind9/bin/named/controlconf.c
MFC r363988:
[FreeBSD/stable/9.git] / contrib / bind9 / bin / named / controlconf.c
1 /*
2  * Copyright (C) 2004-2008, 2011-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
543         /* Set a 32 KiB upper limit on incoming message. */
544         isccc_ccmsg_setmaxsize(&conn->ccmsg, 32768);
545
546         conn->ccmsg_valid = ISC_TRUE;
547         conn->sending = ISC_FALSE;
548         conn->timer = NULL;
549         isc_interval_set(&interval, 60, 0);
550         result = isc_timer_create(ns_g_timermgr, isc_timertype_once,
551                                   NULL, &interval, listener->task,
552                                   control_timeout, conn, &conn->timer);
553         if (result != ISC_R_SUCCESS)
554                 goto cleanup;
555
556         conn->listener = listener;
557         conn->nonce = 0;
558         ISC_LINK_INIT(conn, link);
559
560         result = isccc_ccmsg_readmessage(&conn->ccmsg, listener->task,
561                                          control_recvmessage, conn);
562         if (result != ISC_R_SUCCESS)
563                 goto cleanup;
564         isccc_ccmsg_setmaxsize(&conn->ccmsg, 2048);
565
566         ISC_LIST_APPEND(listener->connections, conn, link);
567         return (ISC_R_SUCCESS);
568
569  cleanup:
570         isccc_ccmsg_invalidate(&conn->ccmsg);
571         if (conn->timer != NULL)
572                 isc_timer_detach(&conn->timer);
573         isc_mem_put(listener->mctx, conn, sizeof(*conn));
574         return (result);
575 }
576
577 static void
578 control_newconn(isc_task_t *task, isc_event_t *event) {
579         isc_socket_newconnev_t *nevent = (isc_socket_newconnev_t *)event;
580         controllistener_t *listener = event->ev_arg;
581         isc_socket_t *sock;
582         isc_sockaddr_t peeraddr;
583         isc_result_t result;
584
585         UNUSED(task);
586
587         listener->listening = ISC_FALSE;
588
589         if (nevent->result != ISC_R_SUCCESS) {
590                 if (nevent->result == ISC_R_CANCELED) {
591                         shutdown_listener(listener);
592                         goto cleanup;
593                 }
594                 goto restart;
595         }
596
597         sock = nevent->newsocket;
598         isc_socket_setname(sock, "control", NULL);
599         (void)isc_socket_getpeername(sock, &peeraddr);
600         if (listener->type == isc_sockettype_tcp &&
601             !address_ok(&peeraddr, listener->acl)) {
602                 char socktext[ISC_SOCKADDR_FORMATSIZE];
603                 isc_sockaddr_format(&peeraddr, socktext, sizeof(socktext));
604                 isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
605                               NS_LOGMODULE_CONTROL, ISC_LOG_WARNING,
606                               "rejected command channel message from %s",
607                               socktext);
608                 isc_socket_detach(&sock);
609                 goto restart;
610         }
611
612         result = newconnection(listener, sock);
613         if (result != ISC_R_SUCCESS) {
614                 char socktext[ISC_SOCKADDR_FORMATSIZE];
615                 isc_sockaddr_format(&peeraddr, socktext, sizeof(socktext));
616                 isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
617                               NS_LOGMODULE_CONTROL, ISC_LOG_WARNING,
618                               "dropped command channel from %s: %s",
619                               socktext, isc_result_totext(result));
620                 isc_socket_detach(&sock);
621                 goto restart;
622         }
623
624  restart:
625         control_next(listener);
626  cleanup:
627         isc_event_free(&event);
628 }
629
630 static void
631 controls_shutdown(ns_controls_t *controls) {
632         controllistener_t *listener;
633         controllistener_t *next;
634
635         for (listener = ISC_LIST_HEAD(controls->listeners);
636              listener != NULL;
637              listener = next)
638         {
639                 /*
640                  * This is asynchronous.  As listeners shut down, they will
641                  * call their callbacks.
642                  */
643                 next = ISC_LIST_NEXT(listener, link);
644                 shutdown_listener(listener);
645         }
646 }
647
648 void
649 ns_controls_shutdown(ns_controls_t *controls) {
650         controls_shutdown(controls);
651         controls->shuttingdown = ISC_TRUE;
652 }
653
654 static isc_result_t
655 cfgkeylist_find(const cfg_obj_t *keylist, const char *keyname,
656                 const cfg_obj_t **objp)
657 {
658         const cfg_listelt_t *element;
659         const char *str;
660         const cfg_obj_t *obj;
661
662         for (element = cfg_list_first(keylist);
663              element != NULL;
664              element = cfg_list_next(element))
665         {
666                 obj = cfg_listelt_value(element);
667                 str = cfg_obj_asstring(cfg_map_getname(obj));
668                 if (strcasecmp(str, keyname) == 0)
669                         break;
670         }
671         if (element == NULL)
672                 return (ISC_R_NOTFOUND);
673         obj = cfg_listelt_value(element);
674         *objp = obj;
675         return (ISC_R_SUCCESS);
676 }
677
678 static isc_result_t
679 controlkeylist_fromcfg(const cfg_obj_t *keylist, isc_mem_t *mctx,
680                        controlkeylist_t *keyids)
681 {
682         const cfg_listelt_t *element;
683         char *newstr = NULL;
684         const char *str;
685         const cfg_obj_t *obj;
686         controlkey_t *key;
687
688         for (element = cfg_list_first(keylist);
689              element != NULL;
690              element = cfg_list_next(element))
691         {
692                 obj = cfg_listelt_value(element);
693                 str = cfg_obj_asstring(obj);
694                 newstr = isc_mem_strdup(mctx, str);
695                 if (newstr == NULL)
696                         goto cleanup;
697                 key = isc_mem_get(mctx, sizeof(*key));
698                 if (key == NULL)
699                         goto cleanup;
700                 key->keyname = newstr;
701                 key->secret.base = NULL;
702                 key->secret.length = 0;
703                 ISC_LINK_INIT(key, link);
704                 ISC_LIST_APPEND(*keyids, key, link);
705                 newstr = NULL;
706         }
707         return (ISC_R_SUCCESS);
708
709  cleanup:
710         if (newstr != NULL)
711                 isc_mem_free(mctx, newstr);
712         free_controlkeylist(keyids, mctx);
713         return (ISC_R_NOMEMORY);
714 }
715
716 static void
717 register_keys(const cfg_obj_t *control, const cfg_obj_t *keylist,
718               controlkeylist_t *keyids, isc_mem_t *mctx, const char *socktext)
719 {
720         controlkey_t *keyid, *next;
721         const cfg_obj_t *keydef;
722         char secret[1024];
723         isc_buffer_t b;
724         isc_result_t result;
725
726         /*
727          * Find the keys corresponding to the keyids used by this listener.
728          */
729         for (keyid = ISC_LIST_HEAD(*keyids); keyid != NULL; keyid = next) {
730                 next = ISC_LIST_NEXT(keyid, link);
731
732                 result = cfgkeylist_find(keylist, keyid->keyname, &keydef);
733                 if (result != ISC_R_SUCCESS) {
734                         cfg_obj_log(control, ns_g_lctx, ISC_LOG_WARNING,
735                                     "couldn't find key '%s' for use with "
736                                     "command channel %s",
737                                     keyid->keyname, socktext);
738                         ISC_LIST_UNLINK(*keyids, keyid, link);
739                         free_controlkey(keyid, mctx);
740                 } else {
741                         const cfg_obj_t *algobj = NULL;
742                         const cfg_obj_t *secretobj = NULL;
743                         const char *algstr = NULL;
744                         const char *secretstr = NULL;
745
746                         (void)cfg_map_get(keydef, "algorithm", &algobj);
747                         (void)cfg_map_get(keydef, "secret", &secretobj);
748                         INSIST(algobj != NULL && secretobj != NULL);
749
750                         algstr = cfg_obj_asstring(algobj);
751                         secretstr = cfg_obj_asstring(secretobj);
752
753                         if (ns_config_getkeyalgorithm(algstr, NULL, NULL) !=
754                             ISC_R_SUCCESS)
755                         {
756                                 cfg_obj_log(control, ns_g_lctx,
757                                             ISC_LOG_WARNING,
758                                             "unsupported algorithm '%s' in "
759                                             "key '%s' for use with command "
760                                             "channel %s",
761                                             algstr, keyid->keyname, socktext);
762                                 ISC_LIST_UNLINK(*keyids, keyid, link);
763                                 free_controlkey(keyid, mctx);
764                                 continue;
765                         }
766
767                         isc_buffer_init(&b, secret, sizeof(secret));
768                         result = isc_base64_decodestring(secretstr, &b);
769
770                         if (result != ISC_R_SUCCESS) {
771                                 cfg_obj_log(keydef, ns_g_lctx, ISC_LOG_WARNING,
772                                             "secret for key '%s' on "
773                                             "command channel %s: %s",
774                                             keyid->keyname, socktext,
775                                             isc_result_totext(result));
776                                 ISC_LIST_UNLINK(*keyids, keyid, link);
777                                 free_controlkey(keyid, mctx);
778                                 continue;
779                         }
780
781                         keyid->secret.length = isc_buffer_usedlength(&b);
782                         keyid->secret.base = isc_mem_get(mctx,
783                                                          keyid->secret.length);
784                         if (keyid->secret.base == NULL) {
785                                 cfg_obj_log(keydef, ns_g_lctx, ISC_LOG_WARNING,
786                                            "couldn't register key '%s': "
787                                            "out of memory", keyid->keyname);
788                                 ISC_LIST_UNLINK(*keyids, keyid, link);
789                                 free_controlkey(keyid, mctx);
790                                 break;
791                         }
792                         memmove(keyid->secret.base, isc_buffer_base(&b),
793                                 keyid->secret.length);
794                 }
795         }
796 }
797
798 #define CHECK(x) \
799         do { \
800                  result = (x); \
801                  if (result != ISC_R_SUCCESS) \
802                         goto cleanup; \
803         } while (0)
804
805 static isc_result_t
806 get_rndckey(isc_mem_t *mctx, controlkeylist_t *keyids) {
807         isc_result_t result;
808         cfg_parser_t *pctx = NULL;
809         cfg_obj_t *config = NULL;
810         const cfg_obj_t *key = NULL;
811         const cfg_obj_t *algobj = NULL;
812         const cfg_obj_t *secretobj = NULL;
813         const char *algstr = NULL;
814         const char *secretstr = NULL;
815         controlkey_t *keyid = NULL;
816         char secret[1024];
817         isc_buffer_t b;
818
819         isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
820                       NS_LOGMODULE_CONTROL, ISC_LOG_INFO,
821                       "configuring command channel from '%s'",
822                       ns_g_keyfile);
823         if (! isc_file_exists(ns_g_keyfile))
824                 return (ISC_R_FILENOTFOUND);
825
826         CHECK(cfg_parser_create(mctx, ns_g_lctx, &pctx));
827         CHECK(cfg_parse_file(pctx, ns_g_keyfile, &cfg_type_rndckey, &config));
828         CHECK(cfg_map_get(config, "key", &key));
829
830         keyid = isc_mem_get(mctx, sizeof(*keyid));
831         if (keyid == NULL)
832                 CHECK(ISC_R_NOMEMORY);
833         keyid->keyname = isc_mem_strdup(mctx,
834                                         cfg_obj_asstring(cfg_map_getname(key)));
835         keyid->secret.base = NULL;
836         keyid->secret.length = 0;
837         ISC_LINK_INIT(keyid, link);
838         if (keyid->keyname == NULL)
839                 CHECK(ISC_R_NOMEMORY);
840
841         CHECK(bind9_check_key(key, ns_g_lctx));
842
843         (void)cfg_map_get(key, "algorithm", &algobj);
844         (void)cfg_map_get(key, "secret", &secretobj);
845         INSIST(algobj != NULL && secretobj != NULL);
846
847         algstr = cfg_obj_asstring(algobj);
848         secretstr = cfg_obj_asstring(secretobj);
849
850         if (ns_config_getkeyalgorithm(algstr, NULL, NULL) != ISC_R_SUCCESS) {
851                 cfg_obj_log(key, ns_g_lctx,
852                             ISC_LOG_WARNING,
853                             "unsupported algorithm '%s' in "
854                             "key '%s' for use with command "
855                             "channel",
856                             algstr, keyid->keyname);
857                 goto cleanup;
858         }
859
860         isc_buffer_init(&b, secret, sizeof(secret));
861         result = isc_base64_decodestring(secretstr, &b);
862
863         if (result != ISC_R_SUCCESS) {
864                 cfg_obj_log(key, ns_g_lctx, ISC_LOG_WARNING,
865                             "secret for key '%s' on command channel: %s",
866                             keyid->keyname, isc_result_totext(result));
867                 goto cleanup;
868         }
869
870         keyid->secret.length = isc_buffer_usedlength(&b);
871         keyid->secret.base = isc_mem_get(mctx,
872                                          keyid->secret.length);
873         if (keyid->secret.base == NULL) {
874                 cfg_obj_log(key, ns_g_lctx, ISC_LOG_WARNING,
875                            "couldn't register key '%s': "
876                            "out of memory", keyid->keyname);
877                 CHECK(ISC_R_NOMEMORY);
878         }
879         memmove(keyid->secret.base, isc_buffer_base(&b),
880                 keyid->secret.length);
881         ISC_LIST_APPEND(*keyids, keyid, link);
882         keyid = NULL;
883         result = ISC_R_SUCCESS;
884
885   cleanup:
886         if (keyid != NULL)
887                 free_controlkey(keyid, mctx);
888         if (config != NULL)
889                 cfg_obj_destroy(pctx, &config);
890         if (pctx != NULL)
891                 cfg_parser_destroy(&pctx);
892         return (result);
893 }
894
895 /*
896  * Ensures that both '*global_keylistp' and '*control_keylistp' are
897  * valid or both are NULL.
898  */
899 static void
900 get_key_info(const cfg_obj_t *config, const cfg_obj_t *control,
901              const cfg_obj_t **global_keylistp,
902              const cfg_obj_t **control_keylistp)
903 {
904         isc_result_t result;
905         const cfg_obj_t *control_keylist = NULL;
906         const cfg_obj_t *global_keylist = NULL;
907
908         REQUIRE(global_keylistp != NULL && *global_keylistp == NULL);
909         REQUIRE(control_keylistp != NULL && *control_keylistp == NULL);
910
911         control_keylist = cfg_tuple_get(control, "keys");
912
913         if (!cfg_obj_isvoid(control_keylist) &&
914             cfg_list_first(control_keylist) != NULL) {
915                 result = cfg_map_get(config, "key", &global_keylist);
916
917                 if (result == ISC_R_SUCCESS) {
918                         *global_keylistp = global_keylist;
919                         *control_keylistp = control_keylist;
920                 }
921         }
922 }
923
924 static void
925 update_listener(ns_controls_t *cp, controllistener_t **listenerp,
926                 const cfg_obj_t *control, const cfg_obj_t *config,
927                 isc_sockaddr_t *addr, cfg_aclconfctx_t *aclconfctx,
928                 const char *socktext, isc_sockettype_t type)
929 {
930         controllistener_t *listener;
931         const cfg_obj_t *allow;
932         const cfg_obj_t *global_keylist = NULL;
933         const cfg_obj_t *control_keylist = NULL;
934         dns_acl_t *new_acl = NULL;
935         controlkeylist_t keys;
936         isc_result_t result = ISC_R_SUCCESS;
937
938         for (listener = ISC_LIST_HEAD(cp->listeners);
939              listener != NULL;
940              listener = ISC_LIST_NEXT(listener, link))
941                 if (isc_sockaddr_equal(addr, &listener->address))
942                         break;
943
944         if (listener == NULL) {
945                 *listenerp = NULL;
946                 return;
947         }
948
949         /*
950          * There is already a listener for this sockaddr.
951          * Update the access list and key information.
952          *
953          * First try to deal with the key situation.  There are a few
954          * possibilities:
955          *  (a) It had an explicit keylist and still has an explicit keylist.
956          *  (b) It had an automagic key and now has an explicit keylist.
957          *  (c) It had an explicit keylist and now needs an automagic key.
958          *  (d) It has an automagic key and still needs the automagic key.
959          *
960          * (c) and (d) are the annoying ones.  The caller needs to know
961          * that it should use the automagic configuration for key information
962          * in place of the named.conf configuration.
963          *
964          * XXXDCL There is one other hazard that has not been dealt with,
965          * the problem that if a key change is being caused by a control
966          * channel reload, then the response will be with the new key
967          * and not able to be decrypted by the client.
968          */
969         if (control != NULL)
970                 get_key_info(config, control, &global_keylist,
971                              &control_keylist);
972
973         if (control_keylist != NULL) {
974                 INSIST(global_keylist != NULL);
975
976                 ISC_LIST_INIT(keys);
977                 result = controlkeylist_fromcfg(control_keylist,
978                                                 listener->mctx, &keys);
979                 if (result == ISC_R_SUCCESS) {
980                         free_controlkeylist(&listener->keys, listener->mctx);
981                         listener->keys = keys;
982                         register_keys(control, global_keylist, &listener->keys,
983                                       listener->mctx, socktext);
984                 }
985         } else {
986                 free_controlkeylist(&listener->keys, listener->mctx);
987                 result = get_rndckey(listener->mctx, &listener->keys);
988         }
989
990         if (result != ISC_R_SUCCESS && global_keylist != NULL) {
991                 /*
992                  * This message might be a little misleading since the
993                  * "new keys" might in fact be identical to the old ones,
994                  * but tracking whether they are identical just for the
995                  * sake of avoiding this message would be too much trouble.
996                  */
997                 if (control != NULL)
998                         cfg_obj_log(control, ns_g_lctx, ISC_LOG_WARNING,
999                                     "couldn't install new keys for "
1000                                     "command channel %s: %s",
1001                                     socktext, isc_result_totext(result));
1002                 else
1003                         isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
1004                                       NS_LOGMODULE_CONTROL, ISC_LOG_WARNING,
1005                                       "couldn't install new keys for "
1006                                       "command channel %s: %s",
1007                                       socktext, isc_result_totext(result));
1008         }
1009
1010         /*
1011          * Now, keep the old access list unless a new one can be made.
1012          */
1013         if (control != NULL && type == isc_sockettype_tcp) {
1014                 allow = cfg_tuple_get(control, "allow");
1015                 result = cfg_acl_fromconfig(allow, config, ns_g_lctx,
1016                                             aclconfctx, listener->mctx, 0,
1017                                             &new_acl);
1018         } else {
1019                 result = dns_acl_any(listener->mctx, &new_acl);
1020         }
1021
1022         if (result == ISC_R_SUCCESS) {
1023                 dns_acl_detach(&listener->acl);
1024                 dns_acl_attach(new_acl, &listener->acl);
1025                 dns_acl_detach(&new_acl);
1026                 /* XXXDCL say the old acl is still used? */
1027         } else if (control != NULL)
1028                 cfg_obj_log(control, ns_g_lctx, ISC_LOG_WARNING,
1029                             "couldn't install new acl for "
1030                             "command channel %s: %s",
1031                             socktext, isc_result_totext(result));
1032         else
1033                 isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
1034                               NS_LOGMODULE_CONTROL, ISC_LOG_WARNING,
1035                               "couldn't install new acl for "
1036                               "command channel %s: %s",
1037                               socktext, isc_result_totext(result));
1038
1039         if (result == ISC_R_SUCCESS && type == isc_sockettype_unix) {
1040                 isc_uint32_t perm, owner, group;
1041                 perm  = cfg_obj_asuint32(cfg_tuple_get(control, "perm"));
1042                 owner = cfg_obj_asuint32(cfg_tuple_get(control, "owner"));
1043                 group = cfg_obj_asuint32(cfg_tuple_get(control, "group"));
1044                 result = ISC_R_SUCCESS;
1045                 if (listener->perm != perm || listener->owner != owner ||
1046                     listener->group != group)
1047                         result = isc_socket_permunix(&listener->address, perm,
1048                                                      owner, group);
1049                 if (result == ISC_R_SUCCESS) {
1050                         listener->perm = perm;
1051                         listener->owner = owner;
1052                         listener->group = group;
1053                 } else if (control != NULL)
1054                         cfg_obj_log(control, ns_g_lctx, ISC_LOG_WARNING,
1055                                     "couldn't update ownership/permission for "
1056                                     "command channel %s", socktext);
1057         }
1058
1059         *listenerp = listener;
1060 }
1061
1062 static void
1063 add_listener(ns_controls_t *cp, controllistener_t **listenerp,
1064              const cfg_obj_t *control, const cfg_obj_t *config,
1065              isc_sockaddr_t *addr, cfg_aclconfctx_t *aclconfctx,
1066              const char *socktext, isc_sockettype_t type)
1067 {
1068         isc_mem_t *mctx = cp->server->mctx;
1069         controllistener_t *listener;
1070         const cfg_obj_t *allow;
1071         const cfg_obj_t *global_keylist = NULL;
1072         const cfg_obj_t *control_keylist = NULL;
1073         dns_acl_t *new_acl = NULL;
1074         isc_result_t result = ISC_R_SUCCESS;
1075
1076         listener = isc_mem_get(mctx, sizeof(*listener));
1077         if (listener == NULL)
1078                 result = ISC_R_NOMEMORY;
1079
1080         if (result == ISC_R_SUCCESS) {
1081                 listener->mctx = NULL;
1082                 isc_mem_attach(mctx, &listener->mctx);
1083                 listener->controls = cp;
1084                 listener->task = cp->server->task;
1085                 listener->address = *addr;
1086                 listener->sock = NULL;
1087                 listener->listening = ISC_FALSE;
1088                 listener->exiting = ISC_FALSE;
1089                 listener->acl = NULL;
1090                 listener->type = type;
1091                 listener->perm = 0;
1092                 listener->owner = 0;
1093                 listener->group = 0;
1094                 ISC_LINK_INIT(listener, link);
1095                 ISC_LIST_INIT(listener->keys);
1096                 ISC_LIST_INIT(listener->connections);
1097
1098                 /*
1099                  * Make the acl.
1100                  */
1101                 if (control != NULL && type == isc_sockettype_tcp) {
1102                         allow = cfg_tuple_get(control, "allow");
1103                         result = cfg_acl_fromconfig(allow, config, ns_g_lctx,
1104                                                     aclconfctx, mctx, 0,
1105                                                     &new_acl);
1106                 } else {
1107                         result = dns_acl_any(mctx, &new_acl);
1108                 }
1109         }
1110
1111         if (result == ISC_R_SUCCESS) {
1112                 dns_acl_attach(new_acl, &listener->acl);
1113                 dns_acl_detach(&new_acl);
1114
1115                 if (config != NULL)
1116                         get_key_info(config, control, &global_keylist,
1117                                      &control_keylist);
1118
1119                 if (control_keylist != NULL) {
1120                         result = controlkeylist_fromcfg(control_keylist,
1121                                                         listener->mctx,
1122                                                         &listener->keys);
1123                         if (result == ISC_R_SUCCESS)
1124                                 register_keys(control, global_keylist,
1125                                               &listener->keys,
1126                                               listener->mctx, socktext);
1127                 } else
1128                         result = get_rndckey(mctx, &listener->keys);
1129
1130                 if (result != ISC_R_SUCCESS && control != NULL)
1131                         cfg_obj_log(control, ns_g_lctx, ISC_LOG_WARNING,
1132                                     "couldn't install keys for "
1133                                     "command channel %s: %s",
1134                                     socktext, isc_result_totext(result));
1135         }
1136
1137         if (result == ISC_R_SUCCESS) {
1138                 int pf = isc_sockaddr_pf(&listener->address);
1139                 if ((pf == AF_INET && isc_net_probeipv4() != ISC_R_SUCCESS) ||
1140 #ifdef ISC_PLATFORM_HAVESYSUNH
1141                     (pf == AF_UNIX && isc_net_probeunix() != ISC_R_SUCCESS) ||
1142 #endif
1143                     (pf == AF_INET6 && isc_net_probeipv6() != ISC_R_SUCCESS))
1144                         result = ISC_R_FAMILYNOSUPPORT;
1145         }
1146
1147         if (result == ISC_R_SUCCESS && type == isc_sockettype_unix)
1148                 isc_socket_cleanunix(&listener->address, ISC_FALSE);
1149
1150         if (result == ISC_R_SUCCESS)
1151                 result = isc_socket_create(ns_g_socketmgr,
1152                                            isc_sockaddr_pf(&listener->address),
1153                                            type, &listener->sock);
1154         if (result == ISC_R_SUCCESS)
1155                 isc_socket_setname(listener->sock, "control", NULL);
1156
1157 #ifndef ISC_ALLOW_MAPPED
1158         if (result == ISC_R_SUCCESS)
1159                 isc_socket_ipv6only(listener->sock, ISC_TRUE);
1160 #endif
1161
1162         if (result == ISC_R_SUCCESS)
1163                 result = isc_socket_bind(listener->sock, &listener->address,
1164                                          ISC_SOCKET_REUSEADDRESS);
1165
1166         if (result == ISC_R_SUCCESS && type == isc_sockettype_unix) {
1167                 listener->perm = cfg_obj_asuint32(cfg_tuple_get(control,
1168                                                                 "perm"));
1169                 listener->owner = cfg_obj_asuint32(cfg_tuple_get(control,
1170                                                                  "owner"));
1171                 listener->group = cfg_obj_asuint32(cfg_tuple_get(control,
1172                                                                  "group"));
1173                 result = isc_socket_permunix(&listener->address, listener->perm,
1174                                              listener->owner, listener->group);
1175         }
1176         if (result == ISC_R_SUCCESS)
1177                 result = control_listen(listener);
1178
1179         if (result == ISC_R_SUCCESS)
1180                 result = control_accept(listener);
1181
1182         if (result == ISC_R_SUCCESS) {
1183                 isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
1184                               NS_LOGMODULE_CONTROL, ISC_LOG_NOTICE,
1185                               "command channel listening on %s", socktext);
1186                 *listenerp = listener;
1187
1188         } else {
1189                 if (listener != NULL) {
1190                         listener->exiting = ISC_TRUE;
1191                         free_listener(listener);
1192                 }
1193
1194                 if (control != NULL)
1195                         cfg_obj_log(control, ns_g_lctx, ISC_LOG_WARNING,
1196                                     "couldn't add command channel %s: %s",
1197                                     socktext, isc_result_totext(result));
1198                 else
1199                         isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
1200                                       NS_LOGMODULE_CONTROL, ISC_LOG_NOTICE,
1201                                       "couldn't add command channel %s: %s",
1202                                       socktext, isc_result_totext(result));
1203
1204                 *listenerp = NULL;
1205         }
1206
1207         /* XXXDCL return error results? fail hard? */
1208 }
1209
1210 isc_result_t
1211 ns_controls_configure(ns_controls_t *cp, const cfg_obj_t *config,
1212                       cfg_aclconfctx_t *aclconfctx)
1213 {
1214         controllistener_t *listener;
1215         controllistenerlist_t new_listeners;
1216         const cfg_obj_t *controlslist = NULL;
1217         const cfg_listelt_t *element, *element2;
1218         char socktext[ISC_SOCKADDR_FORMATSIZE];
1219
1220         ISC_LIST_INIT(new_listeners);
1221
1222         /*
1223          * Get the list of named.conf 'controls' statements.
1224          */
1225         (void)cfg_map_get(config, "controls", &controlslist);
1226
1227         /*
1228          * Run through the new control channel list, noting sockets that
1229          * are already being listened on and moving them to the new list.
1230          *
1231          * Identifying duplicate addr/port combinations is left to either
1232          * the underlying config code, or to the bind attempt getting an
1233          * address-in-use error.
1234          */
1235         if (controlslist != NULL) {
1236                 for (element = cfg_list_first(controlslist);
1237                      element != NULL;
1238                      element = cfg_list_next(element)) {
1239                         const cfg_obj_t *controls;
1240                         const cfg_obj_t *inetcontrols = NULL;
1241
1242                         controls = cfg_listelt_value(element);
1243                         (void)cfg_map_get(controls, "inet", &inetcontrols);
1244                         if (inetcontrols == NULL)
1245                                 continue;
1246
1247                         for (element2 = cfg_list_first(inetcontrols);
1248                              element2 != NULL;
1249                              element2 = cfg_list_next(element2)) {
1250                                 const cfg_obj_t *control;
1251                                 const cfg_obj_t *obj;
1252                                 isc_sockaddr_t addr;
1253
1254                                 /*
1255                                  * The parser handles BIND 8 configuration file
1256                                  * syntax, so it allows unix phrases as well
1257                                  * inet phrases with no keys{} clause.
1258                                  */
1259                                 control = cfg_listelt_value(element2);
1260
1261                                 obj = cfg_tuple_get(control, "address");
1262                                 addr = *cfg_obj_assockaddr(obj);
1263                                 if (isc_sockaddr_getport(&addr) == 0)
1264                                         isc_sockaddr_setport(&addr,
1265                                                              NS_CONTROL_PORT);
1266
1267                                 isc_sockaddr_format(&addr, socktext,
1268                                                     sizeof(socktext));
1269
1270                                 isc_log_write(ns_g_lctx,
1271                                               NS_LOGCATEGORY_GENERAL,
1272                                               NS_LOGMODULE_CONTROL,
1273                                               ISC_LOG_DEBUG(9),
1274                                               "processing control channel %s",
1275                                               socktext);
1276
1277                                 update_listener(cp, &listener, control, config,
1278                                                 &addr, aclconfctx, socktext,
1279                                                 isc_sockettype_tcp);
1280
1281                                 if (listener != NULL)
1282                                         /*
1283                                          * Remove the listener from the old
1284                                          * list, so it won't be shut down.
1285                                          */
1286                                         ISC_LIST_UNLINK(cp->listeners,
1287                                                         listener, link);
1288                                 else
1289                                         /*
1290                                          * This is a new listener.
1291                                          */
1292                                         add_listener(cp, &listener, control,
1293                                                      config, &addr, aclconfctx,
1294                                                      socktext,
1295                                                      isc_sockettype_tcp);
1296
1297                                 if (listener != NULL)
1298                                         ISC_LIST_APPEND(new_listeners,
1299                                                         listener, link);
1300                         }
1301                 }
1302                 for (element = cfg_list_first(controlslist);
1303                      element != NULL;
1304                      element = cfg_list_next(element)) {
1305                         const cfg_obj_t *controls;
1306                         const cfg_obj_t *unixcontrols = NULL;
1307
1308                         controls = cfg_listelt_value(element);
1309                         (void)cfg_map_get(controls, "unix", &unixcontrols);
1310                         if (unixcontrols == NULL)
1311                                 continue;
1312
1313                         for (element2 = cfg_list_first(unixcontrols);
1314                              element2 != NULL;
1315                              element2 = cfg_list_next(element2)) {
1316                                 const cfg_obj_t *control;
1317                                 const cfg_obj_t *path;
1318                                 isc_sockaddr_t addr;
1319                                 isc_result_t result;
1320
1321                                 /*
1322                                  * The parser handles BIND 8 configuration file
1323                                  * syntax, so it allows unix phrases as well
1324                                  * inet phrases with no keys{} clause.
1325                                  */
1326                                 control = cfg_listelt_value(element2);
1327
1328                                 path = cfg_tuple_get(control, "path");
1329                                 result = isc_sockaddr_frompath(&addr,
1330                                                       cfg_obj_asstring(path));
1331                                 if (result != ISC_R_SUCCESS) {
1332                                         isc_log_write(ns_g_lctx,
1333                                               NS_LOGCATEGORY_GENERAL,
1334                                               NS_LOGMODULE_CONTROL,
1335                                               ISC_LOG_DEBUG(9),
1336                                               "control channel '%s': %s",
1337                                               cfg_obj_asstring(path),
1338                                               isc_result_totext(result));
1339                                         continue;
1340                                 }
1341
1342                                 isc_log_write(ns_g_lctx,
1343                                               NS_LOGCATEGORY_GENERAL,
1344                                               NS_LOGMODULE_CONTROL,
1345                                               ISC_LOG_DEBUG(9),
1346                                               "processing control channel '%s'",
1347                                               cfg_obj_asstring(path));
1348
1349                                 update_listener(cp, &listener, control, config,
1350                                                 &addr, aclconfctx,
1351                                                 cfg_obj_asstring(path),
1352                                                 isc_sockettype_unix);
1353
1354                                 if (listener != NULL)
1355                                         /*
1356                                          * Remove the listener from the old
1357                                          * list, so it won't be shut down.
1358                                          */
1359                                         ISC_LIST_UNLINK(cp->listeners,
1360                                                         listener, link);
1361                                 else
1362                                         /*
1363                                          * This is a new listener.
1364                                          */
1365                                         add_listener(cp, &listener, control,
1366                                                      config, &addr, aclconfctx,
1367                                                      cfg_obj_asstring(path),
1368                                                      isc_sockettype_unix);
1369
1370                                 if (listener != NULL)
1371                                         ISC_LIST_APPEND(new_listeners,
1372                                                         listener, link);
1373                         }
1374                 }
1375         } else {
1376                 int i;
1377
1378                 for (i = 0; i < 2; i++) {
1379                         isc_sockaddr_t addr;
1380
1381                         if (i == 0) {
1382                                 struct in_addr localhost;
1383
1384                                 if (isc_net_probeipv4() != ISC_R_SUCCESS)
1385                                         continue;
1386                                 localhost.s_addr = htonl(INADDR_LOOPBACK);
1387                                 isc_sockaddr_fromin(&addr, &localhost, 0);
1388                         } else {
1389                                 if (isc_net_probeipv6() != ISC_R_SUCCESS)
1390                                         continue;
1391                                 isc_sockaddr_fromin6(&addr,
1392                                                      &in6addr_loopback, 0);
1393                         }
1394                         isc_sockaddr_setport(&addr, NS_CONTROL_PORT);
1395
1396                         isc_sockaddr_format(&addr, socktext, sizeof(socktext));
1397
1398                         update_listener(cp, &listener, NULL, NULL,
1399                                         &addr, NULL, socktext,
1400                                         isc_sockettype_tcp);
1401
1402                         if (listener != NULL)
1403                                 /*
1404                                  * Remove the listener from the old
1405                                  * list, so it won't be shut down.
1406                                  */
1407                                 ISC_LIST_UNLINK(cp->listeners,
1408                                                 listener, link);
1409                         else
1410                                 /*
1411                                  * This is a new listener.
1412                                  */
1413                                 add_listener(cp, &listener, NULL, NULL,
1414                                              &addr, NULL, socktext,
1415                                              isc_sockettype_tcp);
1416
1417                         if (listener != NULL)
1418                                 ISC_LIST_APPEND(new_listeners,
1419                                                 listener, link);
1420                 }
1421         }
1422
1423         /*
1424          * ns_control_shutdown() will stop whatever is on the global
1425          * listeners list, which currently only has whatever sockaddrs
1426          * were in the previous configuration (if any) that do not
1427          * remain in the current configuration.
1428          */
1429         controls_shutdown(cp);
1430
1431         /*
1432          * Put all of the valid listeners on the listeners list.
1433          * Anything already on listeners in the process of shutting
1434          * down will be taken care of by listen_done().
1435          */
1436         ISC_LIST_APPENDLIST(cp->listeners, new_listeners, link);
1437         return (ISC_R_SUCCESS);
1438 }
1439
1440 isc_result_t
1441 ns_controls_create(ns_server_t *server, ns_controls_t **ctrlsp) {
1442         isc_mem_t *mctx = server->mctx;
1443         isc_result_t result;
1444         ns_controls_t *controls = isc_mem_get(mctx, sizeof(*controls));
1445
1446         if (controls == NULL)
1447                 return (ISC_R_NOMEMORY);
1448         controls->server = server;
1449         ISC_LIST_INIT(controls->listeners);
1450         controls->shuttingdown = ISC_FALSE;
1451         controls->symtab = NULL;
1452         result = isccc_cc_createsymtab(&controls->symtab);
1453         if (result != ISC_R_SUCCESS) {
1454                 isc_mem_put(server->mctx, controls, sizeof(*controls));
1455                 return (result);
1456         }
1457         *ctrlsp = controls;
1458         return (ISC_R_SUCCESS);
1459 }
1460
1461 void
1462 ns_controls_destroy(ns_controls_t **ctrlsp) {
1463         ns_controls_t *controls = *ctrlsp;
1464
1465         REQUIRE(ISC_LIST_EMPTY(controls->listeners));
1466
1467         isccc_symtab_destroy(&controls->symtab);
1468         isc_mem_put(controls->server->mctx, controls, sizeof(*controls));
1469         *ctrlsp = NULL;
1470 }