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