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} 265