1 /* 2 * This file and its contents are supplied under the terms of the 3 * Common Development and Distribution License ("CDDL"), version 1.0. 4 * You may only use this file in accordance with the terms of version 5 * 1.0 of the CDDL. 6 * 7 * A full copy of the text of the CDDL should have accompanied this 8 * source. A copy of the CDDL is also available via the Internet at 9 * http://www.illumos.org/license/CDDL. 10 */ 11 12 /* 13 * Copyright 2014 Nexenta Systems, Inc. All rights reserved. 14 */ 15 16 #include <stdio.h> 17 #include <stdlib.h> 18 #include <stdarg.h> 19 #include <string.h> 20 #include <syslog.h> 21 22 #include <sys/types.h> 23 #include <sys/errno.h> 24 #include <sys/socket.h> 25 #include <netinet/in.h> 26 #include <sys/note.h> 27 28 #include <smbsrv/libsmbns.h> 29 30 #include "smbd.h" 31 #include "locate_plugin.h" 32 33 /* osconf.h - sigh */ 34 #define KRB5_DEFAULT_PORT 88 35 #define DEFAULT_KADM5_PORT 749 36 #define DEFAULT_KPASSWD_PORT 464 37 38 /* 39 * This is an "override plugin" used by libkrb5. See: 40 * lib/gss_mechs/mech_krb5/krb5/os/locate_kdc.c 41 * 42 * The interface is based on: 43 * http://web.mit.edu/~kerberos/krb5-1.12/doc/plugindev/locate.html 44 */ 45 46 /* 47 * Called by krb5int_locate_server / override_locate_server 48 */ 49 50 krb5_error_code 51 _krb5_override_service_locator( 52 void *arg0, 53 enum locate_service_type svc, 54 const char *realm, 55 int socktype, 56 int family, 57 int (*cbfunc)(void *, int, struct sockaddr *), 58 void *cbdata) 59 { 60 _NOTE(ARGUNUSED(arg0)) 61 smb_domainex_t dxi; 62 int rc = KRB5_PLUGIN_NO_HANDLE; 63 short port; 64 65 /* 66 * Is this a service we want to override? 67 */ 68 switch (svc) { 69 case locate_service_kdc: 70 case locate_service_master_kdc: 71 port = htons(KRB5_DEFAULT_PORT); 72 break; 73 case locate_service_kadmin: 74 port = htons(DEFAULT_KADM5_PORT); 75 break; 76 case locate_service_kpasswd: 77 port = htons(DEFAULT_KPASSWD_PORT); 78 break; 79 case locate_service_krb524: 80 default: 81 return (rc); 82 } 83 84 /* 85 * What's my domain? Note: have to get this in a way 86 * that works while join domain is underway. 87 */ 88 if (!smb_domain_getinfo(&dxi)) { 89 smbd_report("_krb5_override_service_locator " 90 "failed getting domain info"); 91 return (KRB5_ERR_HOST_REALM_UNKNOWN); 92 } 93 94 /* 95 * Is this a realm we want to override? 96 */ 97 if (0 != strcasecmp(realm, dxi.d_primary.di_fqname)) { 98 syslog(LOG_DEBUG, "_krb5_override_service_locator, " 99 "realm=%s, fqdn=%s", realm, dxi.d_primary.di_fqname); 100 return (rc); 101 } 102 103 /* 104 * Yes, this is our domain. Have a DC? 105 */ 106 if (dxi.d_dci.dc_name[0] == '\0' || 107 dxi.d_dci.dc_addr.a_family == 0) 108 return (KRB5_REALM_CANT_RESOLVE); 109 110 switch (family) { 111 case AF_UNSPEC: 112 break; /* OK */ 113 case AF_INET: 114 case AF_INET6: 115 if (family == dxi.d_dci.dc_addr.a_family) 116 break; /* OK */ 117 /* else fallthrough */ 118 default: 119 return (KRB5_ERR_NO_SERVICE); 120 } 121 122 /* 123 * Provide the service address we have. 124 */ 125 switch (dxi.d_dci.dc_addr.a_family) { 126 case AF_INET: { 127 struct sockaddr_in sin; 128 (void) memset(&sin, 0, sizeof (sin)); 129 sin.sin_family = AF_INET; 130 sin.sin_port = port; 131 (void) memcpy(&sin.sin_addr, &dxi.d_dci.dc_addr.a_ipv4, 132 sizeof (sin.sin_addr)); 133 rc = cbfunc(cbdata, socktype, (struct sockaddr *)&sin); 134 /* rc from cbfunc is special. */ 135 if (rc) 136 rc = ENOMEM; 137 break; 138 } 139 case AF_INET6: { 140 struct sockaddr_in6 sin6; 141 (void) memset(&sin6, 0, sizeof (sin6)); 142 sin6.sin6_family = AF_INET6; 143 sin6.sin6_port = port; 144 (void) memcpy(&sin6.sin6_addr, &dxi.d_dci.dc_addr.a_ipv6, 145 sizeof (sin6.sin6_addr)); 146 rc = cbfunc(cbdata, socktype, (struct sockaddr *)&sin6); 147 /* rc from cbfunc is special. */ 148 if (rc) 149 rc = ENOMEM; 150 break; 151 } 152 default: 153 rc = KRB5_ERR_NO_SERVICE; 154 break; 155 } 156 157 return (rc); 158 } 159