10Sstevel@tonic-gate /*
2*12361SMark.Phalan@Sun.COM * Copyright (c) 1998, 2010, Oracle and/or its affiliates. All rights reserved.
30Sstevel@tonic-gate */
40Sstevel@tonic-gate
50Sstevel@tonic-gate /*
60Sstevel@tonic-gate * lib/kad5/kadm_host_srv_names.c
70Sstevel@tonic-gate */
80Sstevel@tonic-gate
97934SMark.Phalan@Sun.COM #include <k5-int.h>
100Sstevel@tonic-gate #include "admin.h"
110Sstevel@tonic-gate #include <stdio.h>
120Sstevel@tonic-gate #include <os-proto.h>
130Sstevel@tonic-gate
147934SMark.Phalan@Sun.COM
150Sstevel@tonic-gate #define KADM5_MASTER "admin_server"
166656Ssemery #define KADM5_KPASSWD "kpasswd_server"
170Sstevel@tonic-gate
180Sstevel@tonic-gate /*
190Sstevel@tonic-gate * Find the admin server for the given realm. If the realm is null or
200Sstevel@tonic-gate * the empty string, find the admin server for the default realm.
210Sstevel@tonic-gate * Returns 0 on succsess (KADM5_OK). It is the callers responsibility to
220Sstevel@tonic-gate * free the storage allocated to the admin server, master.
230Sstevel@tonic-gate */
240Sstevel@tonic-gate kadm5_ret_t
kadm5_get_master(krb5_context context,const char * realm,char ** master)250Sstevel@tonic-gate kadm5_get_master(krb5_context context, const char *realm, char **master)
260Sstevel@tonic-gate {
2711490SMark.Phalan@Sun.COM /* Solaris Kerberos */
2811490SMark.Phalan@Sun.COM char *def_realm = NULL;
2911490SMark.Phalan@Sun.COM
300Sstevel@tonic-gate char *delim;
310Sstevel@tonic-gate #ifdef KRB5_DNS_LOOKUP
320Sstevel@tonic-gate struct sockaddr *addrs;
330Sstevel@tonic-gate int naddrs;
340Sstevel@tonic-gate unsigned short dns_portno;
350Sstevel@tonic-gate char dns_host[MAX_DNS_NAMELEN];
360Sstevel@tonic-gate krb5_data dns_realm;
370Sstevel@tonic-gate krb5_error_code dns_ret = 1;
380Sstevel@tonic-gate #endif /* KRB5_DNS_LOOKUP */
390Sstevel@tonic-gate
400Sstevel@tonic-gate if (realm == 0 || *realm == '\0')
410Sstevel@tonic-gate krb5_get_default_realm(context, &def_realm);
420Sstevel@tonic-gate
430Sstevel@tonic-gate (void) profile_get_string(context->profile, "realms",
446426Smp153739 realm ? realm : def_realm,
456426Smp153739 KADM5_MASTER, 0, master);
460Sstevel@tonic-gate
470Sstevel@tonic-gate if ((*master != NULL) && ((delim = strchr(*master, ':')) != NULL))
480Sstevel@tonic-gate *delim = '\0';
490Sstevel@tonic-gate #ifdef KRB5_DNS_LOOKUP
500Sstevel@tonic-gate if (*master == NULL) {
510Sstevel@tonic-gate /*
520Sstevel@tonic-gate * Initialize realm info for (possible) DNS lookups.
530Sstevel@tonic-gate */
540Sstevel@tonic-gate dns_realm.data = strdup(realm ? realm : def_realm);
550Sstevel@tonic-gate dns_realm.length = strlen(realm ? realm : def_realm);
560Sstevel@tonic-gate dns_realm.magic = 0;
570Sstevel@tonic-gate
580Sstevel@tonic-gate dns_ret = krb5_get_servername(context, &dns_realm,
596426Smp153739 "_kerberos-adm", "_udp",
606426Smp153739 dns_host, &dns_portno);
610Sstevel@tonic-gate if (dns_ret == 0)
620Sstevel@tonic-gate *master = strdup(dns_host);
630Sstevel@tonic-gate
640Sstevel@tonic-gate if (dns_realm.data)
650Sstevel@tonic-gate free(dns_realm.data);
660Sstevel@tonic-gate }
670Sstevel@tonic-gate #endif /* KRB5_DNS_LOOKUP */
6811490SMark.Phalan@Sun.COM
6911490SMark.Phalan@Sun.COM /* Solaris Kerberos */
7011490SMark.Phalan@Sun.COM if (def_realm != NULL)
7111490SMark.Phalan@Sun.COM krb5_free_default_realm(context, def_realm);
7211490SMark.Phalan@Sun.COM
730Sstevel@tonic-gate return (*master ? KADM5_OK : KADM5_NO_SRV);
740Sstevel@tonic-gate }
750Sstevel@tonic-gate
760Sstevel@tonic-gate /*
776656Ssemery * Find the kpasswd server for the given realm. If the realm is null or
786656Ssemery * the empty string, find the admin server for the default realm.
796656Ssemery * Returns 0 on succsess (KADM5_OK). It is the callers responsibility to
806656Ssemery * free the storage allocated to the admin server, master.
816656Ssemery */
826656Ssemery kadm5_ret_t
kadm5_get_kpasswd(krb5_context context,const char * realm,char ** kpasswd)836656Ssemery kadm5_get_kpasswd(krb5_context context, const char *realm, char **kpasswd)
846656Ssemery {
856656Ssemery char *def_realm = NULL;
866656Ssemery char *delim;
876656Ssemery #ifdef KRB5_DNS_LOOKUP
886656Ssemery struct sockaddr *addrs;
896656Ssemery int naddrs;
906656Ssemery unsigned short dns_portno;
916656Ssemery char dns_host[MAX_DNS_NAMELEN];
926656Ssemery krb5_data dns_realm;
936656Ssemery krb5_error_code dns_ret = 1, ret;
946656Ssemery #endif /* KRB5_DNS_LOOKUP */
956656Ssemery
966656Ssemery if (realm == 0 || *realm == '\0') {
976656Ssemery ret = krb5_get_default_realm(context, &def_realm);
986656Ssemery if (ret != 0)
996656Ssemery return (ret);
1006656Ssemery }
1016656Ssemery
1026656Ssemery (void) profile_get_string(context->profile, "realms",
1036656Ssemery realm ? realm : def_realm,
1046656Ssemery KADM5_KPASSWD, 0, kpasswd);
1056656Ssemery
1066656Ssemery if ((*kpasswd != NULL) && ((delim = strchr(*kpasswd, ':')) != NULL))
1076656Ssemery *delim = '\0';
1086656Ssemery #ifdef KRB5_DNS_LOOKUP
1096656Ssemery if (*kpasswd == NULL) {
1106656Ssemery /*
1116656Ssemery * Initialize realm info for (possible) DNS lookups.
1126656Ssemery */
1136656Ssemery dns_realm.data = strdup(realm ? realm : def_realm);
1146656Ssemery if (dns_realm.data == NULL) {
1156656Ssemery if (def_realm != NULL)
1166656Ssemery free(def_realm);
1176656Ssemery return (ENOMEM);
1186656Ssemery }
1196656Ssemery dns_realm.length = strlen(realm ? realm : def_realm);
1206656Ssemery dns_realm.magic = 0;
1216656Ssemery
1226656Ssemery dns_ret = krb5_get_servername(context, &dns_realm,
1236656Ssemery "_kpasswd", "_tcp",
1246656Ssemery dns_host, &dns_portno);
1256656Ssemery if (dns_ret == 0) {
1266656Ssemery *kpasswd = strdup(dns_host);
1276656Ssemery
1286656Ssemery if (*kpasswd == NULL) {
1296656Ssemery free(dns_realm.data);
1306656Ssemery if (def_realm != NULL)
1316656Ssemery free(def_realm);
1326656Ssemery return (ENOMEM);
1336656Ssemery }
1346656Ssemery }
1356656Ssemery
1366656Ssemery free(dns_realm.data);
1376656Ssemery }
1386656Ssemery #endif /* KRB5_DNS_LOOKUP */
1396656Ssemery
1406656Ssemery if (def_realm != NULL)
1416656Ssemery free(def_realm);
1426656Ssemery return (*kpasswd ? KADM5_OK : KADM5_NO_SRV);
1436656Ssemery }
1446656Ssemery
1456656Ssemery /*
1460Sstevel@tonic-gate * Get the host base service name for the admin principal. Returns
1470Sstevel@tonic-gate * KADM5_OK on success. Caller must free the storage allocated for
1480Sstevel@tonic-gate * host_service_name.
1490Sstevel@tonic-gate */
1500Sstevel@tonic-gate kadm5_ret_t
kadm5_get_adm_host_srv_name(krb5_context context,const char * realm,char ** host_service_name)1510Sstevel@tonic-gate kadm5_get_adm_host_srv_name(krb5_context context,
1520Sstevel@tonic-gate const char *realm, char **host_service_name)
1530Sstevel@tonic-gate {
1540Sstevel@tonic-gate kadm5_ret_t ret;
1550Sstevel@tonic-gate char *name;
1560Sstevel@tonic-gate char *host;
1570Sstevel@tonic-gate
1580Sstevel@tonic-gate
1590Sstevel@tonic-gate if (ret = kadm5_get_master(context, realm, &host))
1600Sstevel@tonic-gate return (ret);
1610Sstevel@tonic-gate
1620Sstevel@tonic-gate name = malloc(strlen(KADM5_ADMIN_HOST_SERVICE)+ strlen(host) + 2);
1630Sstevel@tonic-gate if (name == NULL) {
1640Sstevel@tonic-gate free(host);
1650Sstevel@tonic-gate return (ENOMEM);
1660Sstevel@tonic-gate }
1670Sstevel@tonic-gate sprintf(name, "%s@%s", KADM5_ADMIN_HOST_SERVICE, host);
1680Sstevel@tonic-gate free(host);
1690Sstevel@tonic-gate *host_service_name = name;
1700Sstevel@tonic-gate
1710Sstevel@tonic-gate return (KADM5_OK);
1720Sstevel@tonic-gate }
1730Sstevel@tonic-gate
1740Sstevel@tonic-gate /*
1750Sstevel@tonic-gate * Get the host base service name for the changepw principal. Returns
1760Sstevel@tonic-gate * KADM5_OK on success. Caller must free the storage allocated for
1770Sstevel@tonic-gate * host_service_name.
1780Sstevel@tonic-gate */
1790Sstevel@tonic-gate kadm5_ret_t
kadm5_get_cpw_host_srv_name(krb5_context context,const char * realm,char ** host_service_name)1800Sstevel@tonic-gate kadm5_get_cpw_host_srv_name(krb5_context context,
1810Sstevel@tonic-gate const char *realm, char **host_service_name)
1820Sstevel@tonic-gate {
1830Sstevel@tonic-gate kadm5_ret_t ret;
1840Sstevel@tonic-gate char *name;
1850Sstevel@tonic-gate char *host;
1860Sstevel@tonic-gate
1876656Ssemery /*
1886656Ssemery * First try to find the kpasswd server, after all we are about to
1896656Ssemery * try to change our password. If this fails then try admin_server.
1906656Ssemery */
1916656Ssemery if (ret = kadm5_get_kpasswd(context, realm, &host)) {
1926656Ssemery if (ret = kadm5_get_master(context, realm, &host))
1936656Ssemery return (ret);
1946656Ssemery }
1950Sstevel@tonic-gate
1960Sstevel@tonic-gate name = malloc(strlen(KADM5_CHANGEPW_HOST_SERVICE) + strlen(host) + 2);
1970Sstevel@tonic-gate if (name == NULL) {
1980Sstevel@tonic-gate free(host);
1990Sstevel@tonic-gate return (ENOMEM);
2000Sstevel@tonic-gate }
2010Sstevel@tonic-gate sprintf(name, "%s@%s", KADM5_CHANGEPW_HOST_SERVICE, host);
2020Sstevel@tonic-gate free(host);
2030Sstevel@tonic-gate *host_service_name = name;
2040Sstevel@tonic-gate
2050Sstevel@tonic-gate return (KADM5_OK);
2060Sstevel@tonic-gate }
2070Sstevel@tonic-gate
2080Sstevel@tonic-gate /*
2090Sstevel@tonic-gate * Get the host base service name for the kiprop principal. Returns
2100Sstevel@tonic-gate * KADM5_OK on success. Caller must free the storage allocated
2110Sstevel@tonic-gate * for host_service_name.
2120Sstevel@tonic-gate */
kadm5_get_kiprop_host_srv_name(krb5_context context,const char * realm,char ** host_service_name)2130Sstevel@tonic-gate kadm5_ret_t kadm5_get_kiprop_host_srv_name(krb5_context context,
2140Sstevel@tonic-gate const char *realm,
2150Sstevel@tonic-gate char **host_service_name) {
2160Sstevel@tonic-gate kadm5_ret_t ret;
2170Sstevel@tonic-gate char *name;
2180Sstevel@tonic-gate char *host;
2190Sstevel@tonic-gate
2200Sstevel@tonic-gate
2210Sstevel@tonic-gate if (ret = kadm5_get_master(context, realm, &host))
2220Sstevel@tonic-gate return (ret);
2230Sstevel@tonic-gate
2240Sstevel@tonic-gate name = malloc(strlen(KADM5_KIPROP_HOST_SERVICE) + strlen(host) + 2);
2250Sstevel@tonic-gate if (name == NULL) {
2260Sstevel@tonic-gate free(host);
2270Sstevel@tonic-gate return (ENOMEM);
2280Sstevel@tonic-gate }
2290Sstevel@tonic-gate sprintf(name, "%s@%s", KADM5_KIPROP_HOST_SERVICE, host);
2300Sstevel@tonic-gate free(host);
2310Sstevel@tonic-gate *host_service_name = name;
2320Sstevel@tonic-gate
2330Sstevel@tonic-gate return (KADM5_OK);
2340Sstevel@tonic-gate }
2356426Smp153739
2366426Smp153739 /*
2376426Smp153739 * Solaris Kerberos:
2386426Smp153739 * Try to determine if this is the master KDC for a given realm
2396426Smp153739 */
kadm5_is_master(krb5_context context,const char * realm,krb5_boolean * is_master)2406426Smp153739 kadm5_ret_t kadm5_is_master(krb5_context context, const char *realm,
2416426Smp153739 krb5_boolean *is_master) {
2426426Smp153739
2436426Smp153739 kadm5_ret_t ret;
2446426Smp153739 char *admin_host = NULL;
245*12361SMark.Phalan@Sun.COM krb5_address **tmp_addr, **master_addr = NULL;
2466426Smp153739 krb5_address **local_addr = NULL;
2476426Smp153739
2486426Smp153739 if (is_master)
2496426Smp153739 *is_master = FALSE;
2506426Smp153739 else
2516426Smp153739 return (KADM5_FAILURE);
2526426Smp153739
2536426Smp153739 /* Locate the master KDC */
2546426Smp153739 if (ret = kadm5_get_master(context, realm, &admin_host))
2556426Smp153739 return (ret);
2566426Smp153739
2576426Smp153739 if (ret = krb5_os_hostaddr(context, admin_host, &master_addr)) {
2586426Smp153739 free(admin_host);
2596426Smp153739 return (ret);
2606426Smp153739 }
2616426Smp153739
2626426Smp153739 /* Get the local addresses */
2636426Smp153739 if (ret = krb5_os_localaddr(context, &local_addr)) {
2646426Smp153739 krb5_free_addresses(context, master_addr);
2656426Smp153739 free(admin_host);
2666426Smp153739 return (ret);
2676426Smp153739 }
2686426Smp153739
2696426Smp153739 /* Compare them */
270*12361SMark.Phalan@Sun.COM for (tmp_addr = master_addr; *tmp_addr; tmp_addr++) {
271*12361SMark.Phalan@Sun.COM if (krb5_address_search(context, *tmp_addr, local_addr)) {
2726426Smp153739 *is_master = TRUE;
2736426Smp153739 break;
2746426Smp153739 }
2756426Smp153739 }
2766426Smp153739
2776426Smp153739 krb5_free_addresses(context, local_addr);
2786426Smp153739 krb5_free_addresses(context, master_addr);
2796426Smp153739 free(admin_host);
2806426Smp153739
2816426Smp153739 return (KADM5_OK);
2826426Smp153739 }
283