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 2020 Nexenta by DDN, 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 #include <synch.h> 28 #include <thread.h> 29 30 #include <ads/dsgetdc.h> 31 32 #include "idmapd.h" 33 #include "libadutils.h" 34 #include "locate_plugin.h" 35 36 /* osconf.h - sigh */ 37 #define KRB5_DEFAULT_PORT 88 38 #define DEFAULT_KADM5_PORT 749 39 #define DEFAULT_KPASSWD_PORT 464 40 41 /* 42 * This is an "override plugin" used by libkrb5. See: 43 * lib/gss_mechs/mech_krb5/krb5/os/locate_kdc.c 44 * 45 * The interface is based on: 46 * http://web.mit.edu/~kerberos/krb5-1.12/doc/plugindev/locate.html 47 */ 48 49 /* 50 * Called by krb5int_locate_server / override_locate_server 51 */ 52 53 krb5_error_code 54 _krb5_override_service_locator( 55 void *arg0, 56 enum locate_service_type svc, 57 const char *realm, 58 int socktype, 59 int family, 60 int (*cbfunc)(void *, int, struct sockaddr *), 61 void *cbdata) 62 { 63 _NOTE(ARGUNUSED(arg0)) 64 idmap_pg_config_t *pgcfg; 65 ad_disc_ds_t *ds; 66 int rc = KRB5_PLUGIN_NO_HANDLE; 67 short port; 68 69 /* 70 * Is this a service we want to override? 71 */ 72 switch (svc) { 73 case locate_service_kdc: 74 case locate_service_master_kdc: 75 port = htons(KRB5_DEFAULT_PORT); 76 break; 77 case locate_service_kadmin: 78 port = htons(DEFAULT_KADM5_PORT); 79 break; 80 case locate_service_kpasswd: 81 port = htons(DEFAULT_KPASSWD_PORT); 82 break; 83 case locate_service_krb524: 84 default: 85 return (rc); 86 } 87 88 RDLOCK_CONFIG(); 89 pgcfg = &_idmapdstate.cfg->pgcfg; 90 91 /* 92 * Is this a realm we want to override? 93 */ 94 if (pgcfg->domain_name == NULL) 95 goto out; 96 if (0 != strcasecmp(realm, pgcfg->domain_name)) 97 goto out; 98 99 /* 100 * Yes, this is our domain. Have a DC? 101 */ 102 if ((ds = pgcfg->domain_controller) == NULL) { 103 rc = KRB5_REALM_CANT_RESOLVE; 104 goto out; 105 } 106 107 if ((ds->flags & DS_KDC_FLAG) == 0) { 108 idmapdlog(LOG_WARNING, "Domain Controller is not a KDC: " 109 "Kerberos auth may be slow"); 110 goto out; 111 } 112 113 switch (family) { 114 case AF_UNSPEC: 115 break; /* OK */ 116 case AF_INET: 117 case AF_INET6: 118 if (family == ds->addr.ss_family) 119 break; /* OK */ 120 /* else fallthrough */ 121 default: 122 rc = KRB5_ERR_NO_SERVICE; 123 goto out; 124 } 125 126 /* 127 * Provide the service address we have. 128 */ 129 switch (ds->addr.ss_family) { 130 case AF_INET: { 131 struct sockaddr_in sin; 132 struct sockaddr_in *dsa = (void *)&ds->addr; 133 (void) memset(&sin, 0, sizeof (sin)); 134 sin.sin_family = AF_INET; 135 sin.sin_port = port; 136 (void) memcpy(&sin.sin_addr, &dsa->sin_addr, 137 sizeof (sin.sin_addr)); 138 rc = cbfunc(cbdata, socktype, (struct sockaddr *)&sin); 139 break; 140 } 141 case AF_INET6: { 142 struct sockaddr_in6 sin6; 143 struct sockaddr_in6 *dsa6 = (void *)&ds->addr; 144 (void) memset(&sin6, 0, sizeof (sin6)); 145 sin6.sin6_family = AF_INET6; 146 sin6.sin6_port = port; 147 (void) memcpy(&sin6.sin6_addr, &dsa6->sin6_addr, 148 sizeof (sin6.sin6_addr)); 149 rc = cbfunc(cbdata, socktype, (struct sockaddr *)&sin6); 150 break; 151 } 152 default: 153 rc = KRB5_ERR_NO_SERVICE; 154 goto out; 155 } 156 /* rc from cbfunc is special. */ 157 if (rc) 158 rc = ENOMEM; 159 160 out: 161 UNLOCK_CONFIG(); 162 163 return (rc); 164 } 165