]> CyberLeo.Net >> Repos - FreeBSD/releng/9.2.git/blob - contrib/bind9/lib/dns/ssu_external.c
- Copy stable/9 to releng/9.2 as part of the 9.2-RELEASE cycle.
[FreeBSD/releng/9.2.git] / contrib / bind9 / lib / dns / ssu_external.c
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
51 static void
52 ssu_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  */
65 static int
66 ux_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  */
119 isc_boolean_t
120 dns_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 }