1 /* 2 * Copyright 2008 Sun Microsystems, Inc. All rights reserved. 3 * Use is subject to license terms. 4 */ 5 6 #pragma ident "%Z%%M% %I% %E% SMI" 7 8 /* 9 * lib/kad5/kadm_host_srv_names.c 10 */ 11 12 #include "admin.h" 13 #include <stdio.h> 14 #include <os-proto.h> 15 16 #define KADM5_MASTER "admin_server" 17 #define KADM5_KPASSWD "kpasswd_server" 18 19 /* 20 * Find the admin server for the given realm. If the realm is null or 21 * the empty string, find the admin server for the default realm. 22 * Returns 0 on succsess (KADM5_OK). It is the callers responsibility to 23 * free the storage allocated to the admin server, master. 24 */ 25 kadm5_ret_t 26 kadm5_get_master(krb5_context context, const char *realm, char **master) 27 { 28 char *def_realm; 29 char *delim; 30 #ifdef KRB5_DNS_LOOKUP 31 struct sockaddr *addrs; 32 int naddrs; 33 unsigned short dns_portno; 34 char dns_host[MAX_DNS_NAMELEN]; 35 krb5_data dns_realm; 36 krb5_error_code dns_ret = 1; 37 #endif /* KRB5_DNS_LOOKUP */ 38 39 if (realm == 0 || *realm == '\0') 40 krb5_get_default_realm(context, &def_realm); 41 42 (void) profile_get_string(context->profile, "realms", 43 realm ? realm : def_realm, 44 KADM5_MASTER, 0, master); 45 46 if ((*master != NULL) && ((delim = strchr(*master, ':')) != NULL)) 47 *delim = '\0'; 48 #ifdef KRB5_DNS_LOOKUP 49 if (*master == NULL) { 50 /* 51 * Initialize realm info for (possible) DNS lookups. 52 */ 53 dns_realm.data = strdup(realm ? realm : def_realm); 54 dns_realm.length = strlen(realm ? realm : def_realm); 55 dns_realm.magic = 0; 56 57 dns_ret = krb5_get_servername(context, &dns_realm, 58 "_kerberos-adm", "_udp", 59 dns_host, &dns_portno); 60 if (dns_ret == 0) 61 *master = strdup(dns_host); 62 63 if (dns_realm.data) 64 free(dns_realm.data); 65 } 66 #endif /* KRB5_DNS_LOOKUP */ 67 return (*master ? KADM5_OK : KADM5_NO_SRV); 68 } 69 70 /* 71 * Find the kpasswd server for the given realm. If the realm is null or 72 * the empty string, find the admin server for the default realm. 73 * Returns 0 on succsess (KADM5_OK). It is the callers responsibility to 74 * free the storage allocated to the admin server, master. 75 */ 76 kadm5_ret_t 77 kadm5_get_kpasswd(krb5_context context, const char *realm, char **kpasswd) 78 { 79 char *def_realm = NULL; 80 char *delim; 81 #ifdef KRB5_DNS_LOOKUP 82 struct sockaddr *addrs; 83 int naddrs; 84 unsigned short dns_portno; 85 char dns_host[MAX_DNS_NAMELEN]; 86 krb5_data dns_realm; 87 krb5_error_code dns_ret = 1, ret; 88 #endif /* KRB5_DNS_LOOKUP */ 89 90 if (realm == 0 || *realm == '\0') { 91 ret = krb5_get_default_realm(context, &def_realm); 92 if (ret != 0) 93 return (ret); 94 } 95 96 (void) profile_get_string(context->profile, "realms", 97 realm ? realm : def_realm, 98 KADM5_KPASSWD, 0, kpasswd); 99 100 if ((*kpasswd != NULL) && ((delim = strchr(*kpasswd, ':')) != NULL)) 101 *delim = '\0'; 102 #ifdef KRB5_DNS_LOOKUP 103 if (*kpasswd == NULL) { 104 /* 105 * Initialize realm info for (possible) DNS lookups. 106 */ 107 dns_realm.data = strdup(realm ? realm : def_realm); 108 if (dns_realm.data == NULL) { 109 if (def_realm != NULL) 110 free(def_realm); 111 return (ENOMEM); 112 } 113 dns_realm.length = strlen(realm ? realm : def_realm); 114 dns_realm.magic = 0; 115 116 dns_ret = krb5_get_servername(context, &dns_realm, 117 "_kpasswd", "_tcp", 118 dns_host, &dns_portno); 119 if (dns_ret == 0) { 120 *kpasswd = strdup(dns_host); 121 122 if (*kpasswd == NULL) { 123 free(dns_realm.data); 124 if (def_realm != NULL) 125 free(def_realm); 126 return (ENOMEM); 127 } 128 } 129 130 free(dns_realm.data); 131 } 132 #endif /* KRB5_DNS_LOOKUP */ 133 134 if (def_realm != NULL) 135 free(def_realm); 136 return (*kpasswd ? KADM5_OK : KADM5_NO_SRV); 137 } 138 139 /* 140 * Get the host base service name for the admin principal. Returns 141 * KADM5_OK on success. Caller must free the storage allocated for 142 * host_service_name. 143 */ 144 kadm5_ret_t 145 kadm5_get_adm_host_srv_name(krb5_context context, 146 const char *realm, char **host_service_name) 147 { 148 kadm5_ret_t ret; 149 char *name; 150 char *host; 151 152 153 if (ret = kadm5_get_master(context, realm, &host)) 154 return (ret); 155 156 name = malloc(strlen(KADM5_ADMIN_HOST_SERVICE)+ strlen(host) + 2); 157 if (name == NULL) { 158 free(host); 159 return (ENOMEM); 160 } 161 sprintf(name, "%s@%s", KADM5_ADMIN_HOST_SERVICE, host); 162 free(host); 163 *host_service_name = name; 164 165 return (KADM5_OK); 166 } 167 168 /* 169 * Get the host base service name for the changepw principal. Returns 170 * KADM5_OK on success. Caller must free the storage allocated for 171 * host_service_name. 172 */ 173 kadm5_ret_t 174 kadm5_get_cpw_host_srv_name(krb5_context context, 175 const char *realm, char **host_service_name) 176 { 177 kadm5_ret_t ret; 178 char *name; 179 char *host; 180 181 /* 182 * First try to find the kpasswd server, after all we are about to 183 * try to change our password. If this fails then try admin_server. 184 */ 185 if (ret = kadm5_get_kpasswd(context, realm, &host)) { 186 if (ret = kadm5_get_master(context, realm, &host)) 187 return (ret); 188 } 189 190 name = malloc(strlen(KADM5_CHANGEPW_HOST_SERVICE) + strlen(host) + 2); 191 if (name == NULL) { 192 free(host); 193 return (ENOMEM); 194 } 195 sprintf(name, "%s@%s", KADM5_CHANGEPW_HOST_SERVICE, host); 196 free(host); 197 *host_service_name = name; 198 199 return (KADM5_OK); 200 } 201 202 /* 203 * Get the host base service name for the kiprop principal. Returns 204 * KADM5_OK on success. Caller must free the storage allocated 205 * for host_service_name. 206 */ 207 kadm5_ret_t kadm5_get_kiprop_host_srv_name(krb5_context context, 208 const char *realm, 209 char **host_service_name) { 210 kadm5_ret_t ret; 211 char *name; 212 char *host; 213 214 215 if (ret = kadm5_get_master(context, realm, &host)) 216 return (ret); 217 218 name = malloc(strlen(KADM5_KIPROP_HOST_SERVICE) + strlen(host) + 2); 219 if (name == NULL) { 220 free(host); 221 return (ENOMEM); 222 } 223 sprintf(name, "%s@%s", KADM5_KIPROP_HOST_SERVICE, host); 224 free(host); 225 *host_service_name = name; 226 227 return (KADM5_OK); 228 } 229 230 /* 231 * Solaris Kerberos: 232 * Try to determine if this is the master KDC for a given realm 233 */ 234 kadm5_ret_t kadm5_is_master(krb5_context context, const char *realm, 235 krb5_boolean *is_master) { 236 237 kadm5_ret_t ret; 238 char *admin_host = NULL; 239 krb5_address **master_addr = NULL; 240 krb5_address **local_addr = NULL; 241 242 if (is_master) 243 *is_master = FALSE; 244 else 245 return (KADM5_FAILURE); 246 247 /* Locate the master KDC */ 248 if (ret = kadm5_get_master(context, realm, &admin_host)) 249 return (ret); 250 251 if (ret = krb5_os_hostaddr(context, admin_host, &master_addr)) { 252 free(admin_host); 253 return (ret); 254 } 255 256 /* Get the local addresses */ 257 if (ret = krb5_os_localaddr(context, &local_addr)) { 258 krb5_free_addresses(context, master_addr); 259 free(admin_host); 260 return (ret); 261 } 262 263 /* Compare them */ 264 for (; *master_addr; master_addr++) { 265 if (krb5_address_search(context, *master_addr, local_addr)) { 266 *is_master = TRUE; 267 break; 268 } 269 } 270 271 krb5_free_addresses(context, local_addr); 272 krb5_free_addresses(context, master_addr); 273 free(admin_host); 274 275 return (KADM5_OK); 276 } 277