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