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