1 /* 2 * Copyright 2008 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 char *def_realm; 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 return (*master ? KADM5_OK : KADM5_NO_SRV); 69 } 70 71 /* 72 * Find the kpasswd server for the given realm. If the realm is null or 73 * the empty string, find the admin server for the default realm. 74 * Returns 0 on succsess (KADM5_OK). It is the callers responsibility to 75 * free the storage allocated to the admin server, master. 76 */ 77 kadm5_ret_t 78 kadm5_get_kpasswd(krb5_context context, const char *realm, char **kpasswd) 79 { 80 char *def_realm = NULL; 81 char *delim; 82 #ifdef KRB5_DNS_LOOKUP 83 struct sockaddr *addrs; 84 int naddrs; 85 unsigned short dns_portno; 86 char dns_host[MAX_DNS_NAMELEN]; 87 krb5_data dns_realm; 88 krb5_error_code dns_ret = 1, ret; 89 #endif /* KRB5_DNS_LOOKUP */ 90 91 if (realm == 0 || *realm == '\0') { 92 ret = krb5_get_default_realm(context, &def_realm); 93 if (ret != 0) 94 return (ret); 95 } 96 97 (void) profile_get_string(context->profile, "realms", 98 realm ? realm : def_realm, 99 KADM5_KPASSWD, 0, kpasswd); 100 101 if ((*kpasswd != NULL) && ((delim = strchr(*kpasswd, ':')) != NULL)) 102 *delim = '\0'; 103 #ifdef KRB5_DNS_LOOKUP 104 if (*kpasswd == NULL) { 105 /* 106 * Initialize realm info for (possible) DNS lookups. 107 */ 108 dns_realm.data = strdup(realm ? realm : def_realm); 109 if (dns_realm.data == NULL) { 110 if (def_realm != NULL) 111 free(def_realm); 112 return (ENOMEM); 113 } 114 dns_realm.length = strlen(realm ? realm : def_realm); 115 dns_realm.magic = 0; 116 117 dns_ret = krb5_get_servername(context, &dns_realm, 118 "_kpasswd", "_tcp", 119 dns_host, &dns_portno); 120 if (dns_ret == 0) { 121 *kpasswd = strdup(dns_host); 122 123 if (*kpasswd == NULL) { 124 free(dns_realm.data); 125 if (def_realm != NULL) 126 free(def_realm); 127 return (ENOMEM); 128 } 129 } 130 131 free(dns_realm.data); 132 } 133 #endif /* KRB5_DNS_LOOKUP */ 134 135 if (def_realm != NULL) 136 free(def_realm); 137 return (*kpasswd ? KADM5_OK : KADM5_NO_SRV); 138 } 139 140 /* 141 * Get the host base service name for the admin principal. Returns 142 * KADM5_OK on success. Caller must free the storage allocated for 143 * host_service_name. 144 */ 145 kadm5_ret_t 146 kadm5_get_adm_host_srv_name(krb5_context context, 147 const char *realm, char **host_service_name) 148 { 149 kadm5_ret_t ret; 150 char *name; 151 char *host; 152 153 154 if (ret = kadm5_get_master(context, realm, &host)) 155 return (ret); 156 157 name = malloc(strlen(KADM5_ADMIN_HOST_SERVICE)+ strlen(host) + 2); 158 if (name == NULL) { 159 free(host); 160 return (ENOMEM); 161 } 162 sprintf(name, "%s@%s", KADM5_ADMIN_HOST_SERVICE, host); 163 free(host); 164 *host_service_name = name; 165 166 return (KADM5_OK); 167 } 168 169 /* 170 * Get the host base service name for the changepw principal. Returns 171 * KADM5_OK on success. Caller must free the storage allocated for 172 * host_service_name. 173 */ 174 kadm5_ret_t 175 kadm5_get_cpw_host_srv_name(krb5_context context, 176 const char *realm, char **host_service_name) 177 { 178 kadm5_ret_t ret; 179 char *name; 180 char *host; 181 182 /* 183 * First try to find the kpasswd server, after all we are about to 184 * try to change our password. If this fails then try admin_server. 185 */ 186 if (ret = kadm5_get_kpasswd(context, realm, &host)) { 187 if (ret = kadm5_get_master(context, realm, &host)) 188 return (ret); 189 } 190 191 name = malloc(strlen(KADM5_CHANGEPW_HOST_SERVICE) + strlen(host) + 2); 192 if (name == NULL) { 193 free(host); 194 return (ENOMEM); 195 } 196 sprintf(name, "%s@%s", KADM5_CHANGEPW_HOST_SERVICE, host); 197 free(host); 198 *host_service_name = name; 199 200 return (KADM5_OK); 201 } 202 203 /* 204 * Get the host base service name for the kiprop principal. Returns 205 * KADM5_OK on success. Caller must free the storage allocated 206 * for host_service_name. 207 */ 208 kadm5_ret_t kadm5_get_kiprop_host_srv_name(krb5_context context, 209 const char *realm, 210 char **host_service_name) { 211 kadm5_ret_t ret; 212 char *name; 213 char *host; 214 215 216 if (ret = kadm5_get_master(context, realm, &host)) 217 return (ret); 218 219 name = malloc(strlen(KADM5_KIPROP_HOST_SERVICE) + strlen(host) + 2); 220 if (name == NULL) { 221 free(host); 222 return (ENOMEM); 223 } 224 sprintf(name, "%s@%s", KADM5_KIPROP_HOST_SERVICE, host); 225 free(host); 226 *host_service_name = name; 227 228 return (KADM5_OK); 229 } 230 231 /* 232 * Solaris Kerberos: 233 * Try to determine if this is the master KDC for a given realm 234 */ 235 kadm5_ret_t kadm5_is_master(krb5_context context, const char *realm, 236 krb5_boolean *is_master) { 237 238 kadm5_ret_t ret; 239 char *admin_host = NULL; 240 krb5_address **master_addr = NULL; 241 krb5_address **local_addr = NULL; 242 243 if (is_master) 244 *is_master = FALSE; 245 else 246 return (KADM5_FAILURE); 247 248 /* Locate the master KDC */ 249 if (ret = kadm5_get_master(context, realm, &admin_host)) 250 return (ret); 251 252 if (ret = krb5_os_hostaddr(context, admin_host, &master_addr)) { 253 free(admin_host); 254 return (ret); 255 } 256 257 /* Get the local addresses */ 258 if (ret = krb5_os_localaddr(context, &local_addr)) { 259 krb5_free_addresses(context, master_addr); 260 free(admin_host); 261 return (ret); 262 } 263 264 /* Compare them */ 265 for (; *master_addr; master_addr++) { 266 if (krb5_address_search(context, *master_addr, local_addr)) { 267 *is_master = TRUE; 268 break; 269 } 270 } 271 272 krb5_free_addresses(context, local_addr); 273 krb5_free_addresses(context, master_addr); 274 free(admin_host); 275 276 return (KADM5_OK); 277 } 278