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