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