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