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