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