xref: /minix3/external/bsd/bind/dist/lib/dns/ssu_external.c (revision 00b67f09dd46474d133c95011a48590a8e8f94c7)
1*00b67f09SDavid van Moolenbroek /*	$NetBSD: ssu_external.c,v 1.7 2014/12/10 04:37:58 christos Exp $	*/
2*00b67f09SDavid van Moolenbroek 
3*00b67f09SDavid van Moolenbroek /*
4*00b67f09SDavid van Moolenbroek  * Copyright (C) 2011-2013  Internet Systems Consortium, Inc. ("ISC")
5*00b67f09SDavid van Moolenbroek  *
6*00b67f09SDavid van Moolenbroek  * Permission to use, copy, modify, and/or distribute this software for any
7*00b67f09SDavid van Moolenbroek  * purpose with or without fee is hereby granted, provided that the above
8*00b67f09SDavid van Moolenbroek  * copyright notice and this permission notice appear in all copies.
9*00b67f09SDavid van Moolenbroek  *
10*00b67f09SDavid van Moolenbroek  * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
11*00b67f09SDavid van Moolenbroek  * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
12*00b67f09SDavid van Moolenbroek  * AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
13*00b67f09SDavid van Moolenbroek  * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
14*00b67f09SDavid van Moolenbroek  * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
15*00b67f09SDavid van Moolenbroek  * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
16*00b67f09SDavid van Moolenbroek  * PERFORMANCE OF THIS SOFTWARE.
17*00b67f09SDavid van Moolenbroek  */
18*00b67f09SDavid van Moolenbroek 
19*00b67f09SDavid van Moolenbroek /* Id */
20*00b67f09SDavid van Moolenbroek 
21*00b67f09SDavid van Moolenbroek /*
22*00b67f09SDavid van Moolenbroek  * This implements external update-policy rules.  This allows permission
23*00b67f09SDavid van Moolenbroek  * to update a zone to be checked by consulting an external daemon (e.g.,
24*00b67f09SDavid van Moolenbroek  * kerberos).
25*00b67f09SDavid van Moolenbroek  */
26*00b67f09SDavid van Moolenbroek 
27*00b67f09SDavid van Moolenbroek #include <config.h>
28*00b67f09SDavid van Moolenbroek #include <errno.h>
29*00b67f09SDavid van Moolenbroek #include <unistd.h>
30*00b67f09SDavid van Moolenbroek 
31*00b67f09SDavid van Moolenbroek #ifdef ISC_PLATFORM_HAVESYSUNH
32*00b67f09SDavid van Moolenbroek #include <sys/socket.h>
33*00b67f09SDavid van Moolenbroek #include <sys/un.h>
34*00b67f09SDavid van Moolenbroek #endif
35*00b67f09SDavid van Moolenbroek 
36*00b67f09SDavid van Moolenbroek #include <isc/magic.h>
37*00b67f09SDavid van Moolenbroek #include <isc/mem.h>
38*00b67f09SDavid van Moolenbroek #include <isc/netaddr.h>
39*00b67f09SDavid van Moolenbroek #include <isc/result.h>
40*00b67f09SDavid van Moolenbroek #include <isc/string.h>
41*00b67f09SDavid van Moolenbroek #include <isc/util.h>
42*00b67f09SDavid van Moolenbroek #include <isc/strerror.h>
43*00b67f09SDavid van Moolenbroek 
44*00b67f09SDavid van Moolenbroek #include <dns/fixedname.h>
45*00b67f09SDavid van Moolenbroek #include <dns/name.h>
46*00b67f09SDavid van Moolenbroek #include <dns/ssu.h>
47*00b67f09SDavid van Moolenbroek #include <dns/log.h>
48*00b67f09SDavid van Moolenbroek #include <dns/rdatatype.h>
49*00b67f09SDavid van Moolenbroek 
50*00b67f09SDavid van Moolenbroek #include <dst/dst.h>
51*00b67f09SDavid van Moolenbroek 
52*00b67f09SDavid van Moolenbroek 
53*00b67f09SDavid van Moolenbroek static void
ssu_e_log(int level,const char * fmt,...)54*00b67f09SDavid van Moolenbroek ssu_e_log(int level, const char *fmt, ...) {
55*00b67f09SDavid van Moolenbroek 	va_list ap;
56*00b67f09SDavid van Moolenbroek 
57*00b67f09SDavid van Moolenbroek 	va_start(ap, fmt);
58*00b67f09SDavid van Moolenbroek 	isc_log_vwrite(dns_lctx, DNS_LOGCATEGORY_SECURITY,
59*00b67f09SDavid van Moolenbroek 		       DNS_LOGMODULE_ZONE, ISC_LOG_DEBUG(level), fmt, ap);
60*00b67f09SDavid van Moolenbroek 	va_end(ap);
61*00b67f09SDavid van Moolenbroek }
62*00b67f09SDavid van Moolenbroek 
63*00b67f09SDavid van Moolenbroek 
64*00b67f09SDavid van Moolenbroek /*
65*00b67f09SDavid van Moolenbroek  * Connect to a UNIX domain socket.
66*00b67f09SDavid van Moolenbroek  */
67*00b67f09SDavid van Moolenbroek static int
ux_socket_connect(const char * path)68*00b67f09SDavid van Moolenbroek ux_socket_connect(const char *path) {
69*00b67f09SDavid van Moolenbroek 	int fd = -1;
70*00b67f09SDavid van Moolenbroek #ifdef ISC_PLATFORM_HAVESYSUNH
71*00b67f09SDavid van Moolenbroek 	struct sockaddr_un addr;
72*00b67f09SDavid van Moolenbroek 
73*00b67f09SDavid van Moolenbroek 	REQUIRE(path != NULL);
74*00b67f09SDavid van Moolenbroek 
75*00b67f09SDavid van Moolenbroek 	if (strlen(path) > sizeof(addr.sun_path)) {
76*00b67f09SDavid van Moolenbroek 		ssu_e_log(3, "ssu_external: socket path '%s' "
77*00b67f09SDavid van Moolenbroek 			     "longer than system maximum %u",
78*00b67f09SDavid van Moolenbroek 			  path, sizeof(addr.sun_path));
79*00b67f09SDavid van Moolenbroek 		return (-1);
80*00b67f09SDavid van Moolenbroek 	}
81*00b67f09SDavid van Moolenbroek 
82*00b67f09SDavid van Moolenbroek 	memset(&addr, 0, sizeof(addr));
83*00b67f09SDavid van Moolenbroek 	addr.sun_family = AF_UNIX;
84*00b67f09SDavid van Moolenbroek 	strlcpy(addr.sun_path, path, sizeof(addr.sun_path));
85*00b67f09SDavid van Moolenbroek 
86*00b67f09SDavid van Moolenbroek 	fd = socket(AF_UNIX, SOCK_STREAM, 0);
87*00b67f09SDavid van Moolenbroek 	if (fd == -1) {
88*00b67f09SDavid van Moolenbroek 		char strbuf[ISC_STRERRORSIZE];
89*00b67f09SDavid van Moolenbroek 		isc__strerror(errno, strbuf, sizeof(strbuf));
90*00b67f09SDavid van Moolenbroek 		ssu_e_log(3, "ssu_external: unable to create socket - %s",
91*00b67f09SDavid van Moolenbroek 			  strbuf);
92*00b67f09SDavid van Moolenbroek 		return (-1);
93*00b67f09SDavid van Moolenbroek 	}
94*00b67f09SDavid van Moolenbroek 
95*00b67f09SDavid van Moolenbroek 	if (connect(fd, (struct sockaddr *)&addr, sizeof(addr)) == -1) {
96*00b67f09SDavid van Moolenbroek 		char strbuf[ISC_STRERRORSIZE];
97*00b67f09SDavid van Moolenbroek 		isc__strerror(errno, strbuf, sizeof(strbuf));
98*00b67f09SDavid van Moolenbroek 		ssu_e_log(3, "ssu_external: unable to connect to "
99*00b67f09SDavid van Moolenbroek 			     "socket '%s' - %s",
100*00b67f09SDavid van Moolenbroek 			  path, strbuf);
101*00b67f09SDavid van Moolenbroek 		close(fd);
102*00b67f09SDavid van Moolenbroek 		return (-1);
103*00b67f09SDavid van Moolenbroek 	}
104*00b67f09SDavid van Moolenbroek #endif
105*00b67f09SDavid van Moolenbroek 	return (fd);
106*00b67f09SDavid van Moolenbroek }
107*00b67f09SDavid van Moolenbroek 
108*00b67f09SDavid van Moolenbroek /* Change this version if you update the format of the request */
109*00b67f09SDavid van Moolenbroek #define SSU_EXTERNAL_VERSION 1
110*00b67f09SDavid van Moolenbroek 
111*00b67f09SDavid van Moolenbroek /*
112*00b67f09SDavid van Moolenbroek  * Perform an update-policy rule check against an external application
113*00b67f09SDavid van Moolenbroek  * over a socket.
114*00b67f09SDavid van Moolenbroek  *
115*00b67f09SDavid van Moolenbroek  * This currently only supports local: for unix domain datagram sockets.
116*00b67f09SDavid van Moolenbroek  *
117*00b67f09SDavid van Moolenbroek  * Note that by using a datagram socket and creating a new socket each
118*00b67f09SDavid van Moolenbroek  * time we avoid the need for locking and allow for parallel access to
119*00b67f09SDavid van Moolenbroek  * the authorization server.
120*00b67f09SDavid van Moolenbroek  */
121*00b67f09SDavid van Moolenbroek isc_boolean_t
dns_ssu_external_match(dns_name_t * identity,dns_name_t * signer,dns_name_t * name,isc_netaddr_t * tcpaddr,dns_rdatatype_t type,const dst_key_t * key,isc_mem_t * mctx)122*00b67f09SDavid van Moolenbroek dns_ssu_external_match(dns_name_t *identity,
123*00b67f09SDavid van Moolenbroek 		       dns_name_t *signer, dns_name_t *name,
124*00b67f09SDavid van Moolenbroek 		       isc_netaddr_t *tcpaddr, dns_rdatatype_t type,
125*00b67f09SDavid van Moolenbroek 		       const dst_key_t *key, isc_mem_t *mctx)
126*00b67f09SDavid van Moolenbroek {
127*00b67f09SDavid van Moolenbroek 	char b_identity[DNS_NAME_FORMATSIZE];
128*00b67f09SDavid van Moolenbroek 	char b_signer[DNS_NAME_FORMATSIZE];
129*00b67f09SDavid van Moolenbroek 	char b_name[DNS_NAME_FORMATSIZE];
130*00b67f09SDavid van Moolenbroek 	char b_addr[ISC_NETADDR_FORMATSIZE];
131*00b67f09SDavid van Moolenbroek 	char b_type[DNS_RDATATYPE_FORMATSIZE];
132*00b67f09SDavid van Moolenbroek 	char b_key[DST_KEY_FORMATSIZE];
133*00b67f09SDavid van Moolenbroek 	isc_buffer_t *tkey_token = NULL;
134*00b67f09SDavid van Moolenbroek 	int fd;
135*00b67f09SDavid van Moolenbroek 	const char *sock_path;
136*00b67f09SDavid van Moolenbroek 	unsigned int req_len;
137*00b67f09SDavid van Moolenbroek 	isc_region_t token_region;
138*00b67f09SDavid van Moolenbroek 	unsigned char *data;
139*00b67f09SDavid van Moolenbroek 	isc_buffer_t buf;
140*00b67f09SDavid van Moolenbroek 	isc_uint32_t token_len = 0;
141*00b67f09SDavid van Moolenbroek 	isc_uint32_t reply;
142*00b67f09SDavid van Moolenbroek 	ssize_t ret;
143*00b67f09SDavid van Moolenbroek 
144*00b67f09SDavid van Moolenbroek 	/* The identity contains local:/path/to/socket */
145*00b67f09SDavid van Moolenbroek 	dns_name_format(identity, b_identity, sizeof(b_identity));
146*00b67f09SDavid van Moolenbroek 
147*00b67f09SDavid van Moolenbroek 	/* For now only local: is supported */
148*00b67f09SDavid van Moolenbroek 	if (strncmp(b_identity, "local:", 6) != 0) {
149*00b67f09SDavid van Moolenbroek 		ssu_e_log(3, "ssu_external: invalid socket path '%s'",
150*00b67f09SDavid van Moolenbroek 			  b_identity);
151*00b67f09SDavid van Moolenbroek 		return (ISC_FALSE);
152*00b67f09SDavid van Moolenbroek 	}
153*00b67f09SDavid van Moolenbroek 	sock_path = &b_identity[6];
154*00b67f09SDavid van Moolenbroek 
155*00b67f09SDavid van Moolenbroek 	fd = ux_socket_connect(sock_path);
156*00b67f09SDavid van Moolenbroek 	if (fd == -1)
157*00b67f09SDavid van Moolenbroek 		return (ISC_FALSE);
158*00b67f09SDavid van Moolenbroek 
159*00b67f09SDavid van Moolenbroek 	if (key != NULL) {
160*00b67f09SDavid van Moolenbroek 		dst_key_format(key, b_key, sizeof(b_key));
161*00b67f09SDavid van Moolenbroek 		tkey_token = dst_key_tkeytoken(key);
162*00b67f09SDavid van Moolenbroek 	} else
163*00b67f09SDavid van Moolenbroek 		b_key[0] = 0;
164*00b67f09SDavid van Moolenbroek 
165*00b67f09SDavid van Moolenbroek 	if (tkey_token != NULL) {
166*00b67f09SDavid van Moolenbroek 		isc_buffer_region(tkey_token, &token_region);
167*00b67f09SDavid van Moolenbroek 		token_len = token_region.length;
168*00b67f09SDavid van Moolenbroek 	}
169*00b67f09SDavid van Moolenbroek 
170*00b67f09SDavid van Moolenbroek 	/* Format the request elements */
171*00b67f09SDavid van Moolenbroek 	if (signer != NULL)
172*00b67f09SDavid van Moolenbroek 		dns_name_format(signer, b_signer, sizeof(b_signer));
173*00b67f09SDavid van Moolenbroek 	else
174*00b67f09SDavid van Moolenbroek 		b_signer[0] = 0;
175*00b67f09SDavid van Moolenbroek 
176*00b67f09SDavid van Moolenbroek 	dns_name_format(name, b_name, sizeof(b_name));
177*00b67f09SDavid van Moolenbroek 
178*00b67f09SDavid van Moolenbroek 	if (tcpaddr != NULL)
179*00b67f09SDavid van Moolenbroek 		isc_netaddr_format(tcpaddr, b_addr, sizeof(b_addr));
180*00b67f09SDavid van Moolenbroek 	else
181*00b67f09SDavid van Moolenbroek 		b_addr[0] = 0;
182*00b67f09SDavid van Moolenbroek 
183*00b67f09SDavid van Moolenbroek 	dns_rdatatype_format(type, b_type, sizeof(b_type));
184*00b67f09SDavid van Moolenbroek 
185*00b67f09SDavid van Moolenbroek 	/* Work out how big the request will be */
186*00b67f09SDavid van Moolenbroek 	req_len = sizeof(isc_uint32_t)     + /* Format version */
187*00b67f09SDavid van Moolenbroek 		  sizeof(isc_uint32_t)     + /* Length */
188*00b67f09SDavid van Moolenbroek 		  strlen(b_signer) + 1 + /* Signer */
189*00b67f09SDavid van Moolenbroek 		  strlen(b_name) + 1   + /* Name */
190*00b67f09SDavid van Moolenbroek 		  strlen(b_addr) + 1   + /* Address */
191*00b67f09SDavid van Moolenbroek 		  strlen(b_type) + 1   + /* Type */
192*00b67f09SDavid van Moolenbroek 		  strlen(b_key) + 1    + /* Key */
193*00b67f09SDavid van Moolenbroek 		  sizeof(isc_uint32_t)     + /* tkey_token length */
194*00b67f09SDavid van Moolenbroek 		  token_len;             /* tkey_token */
195*00b67f09SDavid van Moolenbroek 
196*00b67f09SDavid van Moolenbroek 
197*00b67f09SDavid van Moolenbroek 	/* format the buffer */
198*00b67f09SDavid van Moolenbroek 	data = isc_mem_allocate(mctx, req_len);
199*00b67f09SDavid van Moolenbroek 	if (data == NULL) {
200*00b67f09SDavid van Moolenbroek 		close(fd);
201*00b67f09SDavid van Moolenbroek 		return (ISC_FALSE);
202*00b67f09SDavid van Moolenbroek 	}
203*00b67f09SDavid van Moolenbroek 
204*00b67f09SDavid van Moolenbroek 	isc_buffer_init(&buf, data, req_len);
205*00b67f09SDavid van Moolenbroek 	isc_buffer_putuint32(&buf, SSU_EXTERNAL_VERSION);
206*00b67f09SDavid van Moolenbroek 	isc_buffer_putuint32(&buf, req_len);
207*00b67f09SDavid van Moolenbroek 
208*00b67f09SDavid van Moolenbroek 	/* Strings must be null-terminated */
209*00b67f09SDavid van Moolenbroek 	isc_buffer_putstr(&buf, b_signer);
210*00b67f09SDavid van Moolenbroek 	isc_buffer_putuint8(&buf, 0);
211*00b67f09SDavid van Moolenbroek 	isc_buffer_putstr(&buf, b_name);
212*00b67f09SDavid van Moolenbroek 	isc_buffer_putuint8(&buf, 0);
213*00b67f09SDavid van Moolenbroek 	isc_buffer_putstr(&buf, b_addr);
214*00b67f09SDavid van Moolenbroek 	isc_buffer_putuint8(&buf, 0);
215*00b67f09SDavid van Moolenbroek 	isc_buffer_putstr(&buf, b_type);
216*00b67f09SDavid van Moolenbroek 	isc_buffer_putuint8(&buf, 0);
217*00b67f09SDavid van Moolenbroek 	isc_buffer_putstr(&buf, b_key);
218*00b67f09SDavid van Moolenbroek 	isc_buffer_putuint8(&buf, 0);
219*00b67f09SDavid van Moolenbroek 
220*00b67f09SDavid van Moolenbroek 	isc_buffer_putuint32(&buf, token_len);
221*00b67f09SDavid van Moolenbroek 	if (tkey_token && token_len != 0)
222*00b67f09SDavid van Moolenbroek 		isc_buffer_putmem(&buf, token_region.base, token_len);
223*00b67f09SDavid van Moolenbroek 
224*00b67f09SDavid van Moolenbroek 	ENSURE(isc_buffer_availablelength(&buf) == 0);
225*00b67f09SDavid van Moolenbroek 
226*00b67f09SDavid van Moolenbroek 	/* Send the request */
227*00b67f09SDavid van Moolenbroek 	ret = write(fd, data, req_len);
228*00b67f09SDavid van Moolenbroek 	isc_mem_free(mctx, data);
229*00b67f09SDavid van Moolenbroek 	if (ret != (ssize_t) req_len) {
230*00b67f09SDavid van Moolenbroek 		char strbuf[ISC_STRERRORSIZE];
231*00b67f09SDavid van Moolenbroek 		isc__strerror(errno, strbuf, sizeof(strbuf));
232*00b67f09SDavid van Moolenbroek 		ssu_e_log(3, "ssu_external: unable to send request - %s",
233*00b67f09SDavid van Moolenbroek 			  strbuf);
234*00b67f09SDavid van Moolenbroek 		close(fd);
235*00b67f09SDavid van Moolenbroek 		return (ISC_FALSE);
236*00b67f09SDavid van Moolenbroek 	}
237*00b67f09SDavid van Moolenbroek 
238*00b67f09SDavid van Moolenbroek 	/* Receive the reply */
239*00b67f09SDavid van Moolenbroek 	ret = read(fd, &reply, sizeof(isc_uint32_t));
240*00b67f09SDavid van Moolenbroek 	if (ret != (ssize_t) sizeof(isc_uint32_t)) {
241*00b67f09SDavid van Moolenbroek 		char strbuf[ISC_STRERRORSIZE];
242*00b67f09SDavid van Moolenbroek 		isc__strerror(errno, strbuf, sizeof(strbuf));
243*00b67f09SDavid van Moolenbroek 		ssu_e_log(3, "ssu_external: unable to receive reply - %s",
244*00b67f09SDavid van Moolenbroek 			  strbuf);
245*00b67f09SDavid van Moolenbroek 		close(fd);
246*00b67f09SDavid van Moolenbroek 		return (ISC_FALSE);
247*00b67f09SDavid van Moolenbroek 	}
248*00b67f09SDavid van Moolenbroek 
249*00b67f09SDavid van Moolenbroek 	close(fd);
250*00b67f09SDavid van Moolenbroek 
251*00b67f09SDavid van Moolenbroek 	reply = ntohl(reply);
252*00b67f09SDavid van Moolenbroek 
253*00b67f09SDavid van Moolenbroek 	if (reply == 0) {
254*00b67f09SDavid van Moolenbroek 		ssu_e_log(3, "ssu_external: denied external auth for '%s'",
255*00b67f09SDavid van Moolenbroek 			  b_name);
256*00b67f09SDavid van Moolenbroek 		return (ISC_FALSE);
257*00b67f09SDavid van Moolenbroek 	} else if (reply == 1) {
258*00b67f09SDavid van Moolenbroek 		ssu_e_log(3, "ssu_external: allowed external auth for '%s'",
259*00b67f09SDavid van Moolenbroek 			  b_name);
260*00b67f09SDavid van Moolenbroek 		return (ISC_TRUE);
261*00b67f09SDavid van Moolenbroek 	}
262*00b67f09SDavid van Moolenbroek 
263*00b67f09SDavid van Moolenbroek 	ssu_e_log(3, "ssu_external: invalid reply 0x%08x", reply);
264*00b67f09SDavid van Moolenbroek 
265*00b67f09SDavid van Moolenbroek 	return (ISC_FALSE);
266*00b67f09SDavid van Moolenbroek }
267