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