/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. /* $Id$ */
  17. /*
  18. * This implements external update-policy rules. This allows permission
  19. * to update a zone to be checked by consulting an external daemon (e.g.,
  20. * kerberos).
  21. */
  22. #include <config.h>
  23. #include <errno.h>
  24. #include <unistd.h>
  25. #ifdef ISC_PLATFORM_HAVESYSUNH
  26. #include <sys/socket.h>
  27. #include <sys/un.h>
  28. #endif
  29. #include <isc/magic.h>
  30. #include <isc/mem.h>
  31. #include <isc/netaddr.h>
  32. #include <isc/result.h>
  33. #include <isc/string.h>
  34. #include <isc/util.h>
  35. #include <isc/strerror.h>
  36. #include <dns/fixedname.h>
  37. #include <dns/name.h>
  38. #include <dns/ssu.h>
  39. #include <dns/log.h>
  40. #include <dns/rdatatype.h>
  41. #include <dst/dst.h>
  42. static void
  43. ssu_e_log(int level, const char *fmt, ...) {
  44. va_list ap;
  45. va_start(ap, fmt);
  46. isc_log_vwrite(dns_lctx, DNS_LOGCATEGORY_SECURITY,
  47. DNS_LOGMODULE_ZONE, ISC_LOG_DEBUG(level), fmt, ap);
  48. va_end(ap);
  49. }
  50. /*
  51. * Connect to a UNIX domain socket.
  52. */
  53. static int
  54. ux_socket_connect(const char *path) {
  55. int fd = -1;
  56. #ifdef ISC_PLATFORM_HAVESYSUNH
  57. struct sockaddr_un addr;
  58. REQUIRE(path != NULL);
  59. if (strlen(path) > sizeof(addr.sun_path)) {
  60. ssu_e_log(3, "ssu_external: socket path '%s' "
  61. "longer than system maximum %u",
  62. path, sizeof(addr.sun_path));
  63. return (-1);
  64. }
  65. memset(&addr, 0, sizeof(addr));
  66. addr.sun_family = AF_UNIX;
  67. strncpy(addr.sun_path, path, sizeof(addr.sun_path));
  68. fd = socket(AF_UNIX, SOCK_STREAM, 0);
  69. if (fd == -1) {
  70. char strbuf[ISC_STRERRORSIZE];
  71. isc__strerror(errno, strbuf, sizeof(strbuf));
  72. ssu_e_log(3, "ssu_external: unable to create socket - %s",
  73. strbuf);
  74. return (-1);
  75. }
  76. if (connect(fd, (struct sockaddr *)&addr, sizeof(addr)) == -1) {
  77. char strbuf[ISC_STRERRORSIZE];
  78. isc__strerror(errno, strbuf, sizeof(strbuf));
  79. ssu_e_log(3, "ssu_external: unable to connect to "
  80. "socket '%s' - %s",
  81. path, strbuf);
  82. close(fd);
  83. return (-1);
  84. }
  85. #endif
  86. return (fd);
  87. }
  88. /* Change this version if you update the format of the request */
  89. #define SSU_EXTERNAL_VERSION 1
  90. /*
  91. * Perform an update-policy rule check against an external application
  92. * over a socket.
  93. *
  94. * This currently only supports local: for unix domain datagram sockets.
  95. *
  96. * Note that by using a datagram socket and creating a new socket each
  97. * time we avoid the need for locking and allow for parallel access to
  98. * the authorization server.
  99. */
  100. isc_boolean_t
  101. dns_ssu_external_match(dns_name_t *identity,
  102. dns_name_t *signer, dns_name_t *name,
  103. isc_netaddr_t *tcpaddr, dns_rdatatype_t type,
  104. const dst_key_t *key, isc_mem_t *mctx)
  105. {
  106. char b_identity[DNS_NAME_FORMATSIZE];
  107. char b_signer[DNS_NAME_FORMATSIZE];
  108. char b_name[DNS_NAME_FORMATSIZE];
  109. char b_addr[ISC_NETADDR_FORMATSIZE];
  110. char b_type[DNS_RDATATYPE_FORMATSIZE];
  111. char b_key[DST_KEY_FORMATSIZE];
  112. isc_buffer_t *tkey_token = NULL;
  113. int fd;
  114. const char *sock_path;
  115. size_t req_len;
  116. isc_region_t token_region;
  117. unsigned char *data;
  118. isc_buffer_t buf;
  119. isc_uint32_t token_len = 0;
  120. isc_uint32_t reply;
  121. ssize_t ret;
  122. /* The identity contains local:/path/to/socket */
  123. dns_name_format(identity, b_identity, sizeof(b_identity));
  124. /* For now only local: is supported */
  125. if (strncmp(b_identity, "local:", 6) != 0) {
  126. ssu_e_log(3, "ssu_external: invalid socket path '%s'",
  127. b_identity);
  128. return (ISC_FALSE);
  129. }
  130. sock_path = &b_identity[6];
  131. fd = ux_socket_connect(sock_path);
  132. if (fd == -1)
  133. return (ISC_FALSE);
  134. if (key != NULL) {
  135. dst_key_format(key, b_key, sizeof(b_key));
  136. tkey_token = dst_key_tkeytoken(key);
  137. } else
  138. b_key[0] = 0;
  139. if (tkey_token != NULL) {
  140. isc_buffer_region(tkey_token, &token_region);
  141. token_len = token_region.length;
  142. }
  143. /* Format the request elements */
  144. if (signer != NULL)
  145. dns_name_format(signer, b_signer, sizeof(b_signer));
  146. else
  147. b_signer[0] = 0;
  148. dns_name_format(name, b_name, sizeof(b_name));
  149. if (tcpaddr != NULL)
  150. isc_netaddr_format(tcpaddr, b_addr, sizeof(b_addr));
  151. else
  152. b_addr[0] = 0;
  153. dns_rdatatype_format(type, b_type, sizeof(b_type));
  154. /* Work out how big the request will be */
  155. req_len = sizeof(isc_uint32_t) + /* Format version */
  156. sizeof(isc_uint32_t) + /* Length */
  157. strlen(b_signer) + 1 + /* Signer */
  158. strlen(b_name) + 1 + /* Name */
  159. strlen(b_addr) + 1 + /* Address */
  160. strlen(b_type) + 1 + /* Type */
  161. strlen(b_key) + 1 + /* Key */
  162. sizeof(isc_uint32_t) + /* tkey_token length */
  163. token_len; /* tkey_token */
  164. /* format the buffer */
  165. data = isc_mem_allocate(mctx, req_len);
  166. if (data == NULL) {
  167. close(fd);
  168. return (ISC_FALSE);
  169. }
  170. isc_buffer_init(&buf, data, req_len);
  171. isc_buffer_putuint32(&buf, SSU_EXTERNAL_VERSION);
  172. isc_buffer_putuint32(&buf, req_len);
  173. /* Strings must be null-terminated */
  174. isc_buffer_putstr(&buf, b_signer);
  175. isc_buffer_putuint8(&buf, 0);
  176. isc_buffer_putstr(&buf, b_name);
  177. isc_buffer_putuint8(&buf, 0);
  178. isc_buffer_putstr(&buf, b_addr);
  179. isc_buffer_putuint8(&buf, 0);
  180. isc_buffer_putstr(&buf, b_type);
  181. isc_buffer_putuint8(&buf, 0);
  182. isc_buffer_putstr(&buf, b_key);
  183. isc_buffer_putuint8(&buf, 0);
  184. isc_buffer_putuint32(&buf, token_len);
  185. if (tkey_token && token_len != 0)
  186. isc_buffer_putmem(&buf, token_region.base, token_len);
  187. ENSURE(isc_buffer_availablelength(&buf) == 0);
  188. /* Send the request */
  189. ret = write(fd, data, req_len);
  190. isc_mem_free(mctx, data);
  191. if (ret != (ssize_t) req_len) {
  192. char strbuf[ISC_STRERRORSIZE];
  193. isc__strerror(errno, strbuf, sizeof(strbuf));
  194. ssu_e_log(3, "ssu_external: unable to send request - %s",
  195. strbuf);
  196. close(fd);
  197. return (ISC_FALSE);
  198. }
  199. /* Receive the reply */
  200. ret = read(fd, &reply, sizeof(isc_uint32_t));
  201. if (ret != (ssize_t) sizeof(isc_uint32_t)) {
  202. char strbuf[ISC_STRERRORSIZE];
  203. isc__strerror(errno, strbuf, sizeof(strbuf));
  204. ssu_e_log(3, "ssu_external: unable to receive reply - %s",
  205. strbuf);
  206. close(fd);
  207. return (ISC_FALSE);
  208. }
  209. close(fd);
  210. reply = ntohl(reply);
  211. if (reply == 0) {
  212. ssu_e_log(3, "ssu_external: denied external auth for '%s'",
  213. b_name);
  214. return (ISC_FALSE);
  215. } else if (reply == 1) {
  216. ssu_e_log(3, "ssu_external: allowed external auth for '%s'",
  217. b_name);
  218. return (ISC_TRUE);
  219. }
  220. ssu_e_log(3, "ssu_external: invalid reply 0x%08x", reply);
  221. return (ISC_FALSE);
  222. }