PageRenderTime 47ms CodeModel.GetById 27ms app.highlight 16ms RepoModel.GetById 1ms app.codeStats 0ms

/contrib/bind9/lib/dns/ssu_external.c

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