17c478bd9Sstevel@tonic-gate /*
2*212bfef1SMark Phalan * Copyright (c) 1998, 2010, Oracle and/or its affiliates. All rights reserved.
37c478bd9Sstevel@tonic-gate */
47c478bd9Sstevel@tonic-gate
57c478bd9Sstevel@tonic-gate /*
67c478bd9Sstevel@tonic-gate * lib/kad5/kadm_host_srv_names.c
77c478bd9Sstevel@tonic-gate */
87c478bd9Sstevel@tonic-gate
9159d09a2SMark Phalan #include <k5-int.h>
107c478bd9Sstevel@tonic-gate #include "admin.h"
117c478bd9Sstevel@tonic-gate #include <stdio.h>
127c478bd9Sstevel@tonic-gate #include <os-proto.h>
137c478bd9Sstevel@tonic-gate
14159d09a2SMark Phalan
157c478bd9Sstevel@tonic-gate #define KADM5_MASTER "admin_server"
16bd211b85Ssemery #define KADM5_KPASSWD "kpasswd_server"
177c478bd9Sstevel@tonic-gate
187c478bd9Sstevel@tonic-gate /*
197c478bd9Sstevel@tonic-gate * Find the admin server for the given realm. If the realm is null or
207c478bd9Sstevel@tonic-gate * the empty string, find the admin server for the default realm.
217c478bd9Sstevel@tonic-gate * Returns 0 on succsess (KADM5_OK). It is the callers responsibility to
227c478bd9Sstevel@tonic-gate * free the storage allocated to the admin server, master.
237c478bd9Sstevel@tonic-gate */
247c478bd9Sstevel@tonic-gate kadm5_ret_t
kadm5_get_master(krb5_context context,const char * realm,char ** master)257c478bd9Sstevel@tonic-gate kadm5_get_master(krb5_context context, const char *realm, char **master)
267c478bd9Sstevel@tonic-gate {
27dc25fd74SMark Phalan /* Solaris Kerberos */
28dc25fd74SMark Phalan char *def_realm = NULL;
29dc25fd74SMark Phalan
307c478bd9Sstevel@tonic-gate char *delim;
317c478bd9Sstevel@tonic-gate #ifdef KRB5_DNS_LOOKUP
327c478bd9Sstevel@tonic-gate struct sockaddr *addrs;
337c478bd9Sstevel@tonic-gate int naddrs;
347c478bd9Sstevel@tonic-gate unsigned short dns_portno;
357c478bd9Sstevel@tonic-gate char dns_host[MAX_DNS_NAMELEN];
367c478bd9Sstevel@tonic-gate krb5_data dns_realm;
377c478bd9Sstevel@tonic-gate krb5_error_code dns_ret = 1;
387c478bd9Sstevel@tonic-gate #endif /* KRB5_DNS_LOOKUP */
397c478bd9Sstevel@tonic-gate
407c478bd9Sstevel@tonic-gate if (realm == 0 || *realm == '\0')
417c478bd9Sstevel@tonic-gate krb5_get_default_realm(context, &def_realm);
427c478bd9Sstevel@tonic-gate
437c478bd9Sstevel@tonic-gate (void) profile_get_string(context->profile, "realms",
447c478bd9Sstevel@tonic-gate realm ? realm : def_realm,
457c478bd9Sstevel@tonic-gate KADM5_MASTER, 0, master);
467c478bd9Sstevel@tonic-gate
477c478bd9Sstevel@tonic-gate if ((*master != NULL) && ((delim = strchr(*master, ':')) != NULL))
487c478bd9Sstevel@tonic-gate *delim = '\0';
497c478bd9Sstevel@tonic-gate #ifdef KRB5_DNS_LOOKUP
507c478bd9Sstevel@tonic-gate if (*master == NULL) {
517c478bd9Sstevel@tonic-gate /*
527c478bd9Sstevel@tonic-gate * Initialize realm info for (possible) DNS lookups.
537c478bd9Sstevel@tonic-gate */
547c478bd9Sstevel@tonic-gate dns_realm.data = strdup(realm ? realm : def_realm);
557c478bd9Sstevel@tonic-gate dns_realm.length = strlen(realm ? realm : def_realm);
567c478bd9Sstevel@tonic-gate dns_realm.magic = 0;
577c478bd9Sstevel@tonic-gate
587c478bd9Sstevel@tonic-gate dns_ret = krb5_get_servername(context, &dns_realm,
597c478bd9Sstevel@tonic-gate "_kerberos-adm", "_udp",
607c478bd9Sstevel@tonic-gate dns_host, &dns_portno);
617c478bd9Sstevel@tonic-gate if (dns_ret == 0)
627c478bd9Sstevel@tonic-gate *master = strdup(dns_host);
637c478bd9Sstevel@tonic-gate
647c478bd9Sstevel@tonic-gate if (dns_realm.data)
657c478bd9Sstevel@tonic-gate free(dns_realm.data);
667c478bd9Sstevel@tonic-gate }
677c478bd9Sstevel@tonic-gate #endif /* KRB5_DNS_LOOKUP */
68dc25fd74SMark Phalan
69dc25fd74SMark Phalan /* Solaris Kerberos */
70dc25fd74SMark Phalan if (def_realm != NULL)
71dc25fd74SMark Phalan krb5_free_default_realm(context, def_realm);
72dc25fd74SMark Phalan
737c478bd9Sstevel@tonic-gate return (*master ? KADM5_OK : KADM5_NO_SRV);
747c478bd9Sstevel@tonic-gate }
757c478bd9Sstevel@tonic-gate
767c478bd9Sstevel@tonic-gate /*
77bd211b85Ssemery * Find the kpasswd server for the given realm. If the realm is null or
78bd211b85Ssemery * the empty string, find the admin server for the default realm.
79bd211b85Ssemery * Returns 0 on succsess (KADM5_OK). It is the callers responsibility to
80bd211b85Ssemery * free the storage allocated to the admin server, master.
81bd211b85Ssemery */
82bd211b85Ssemery kadm5_ret_t
kadm5_get_kpasswd(krb5_context context,const char * realm,char ** kpasswd)83bd211b85Ssemery kadm5_get_kpasswd(krb5_context context, const char *realm, char **kpasswd)
84bd211b85Ssemery {
85bd211b85Ssemery char *def_realm = NULL;
86bd211b85Ssemery char *delim;
87bd211b85Ssemery #ifdef KRB5_DNS_LOOKUP
88bd211b85Ssemery struct sockaddr *addrs;
89bd211b85Ssemery int naddrs;
90bd211b85Ssemery unsigned short dns_portno;
91bd211b85Ssemery char dns_host[MAX_DNS_NAMELEN];
92bd211b85Ssemery krb5_data dns_realm;
93bd211b85Ssemery krb5_error_code dns_ret = 1, ret;
94bd211b85Ssemery #endif /* KRB5_DNS_LOOKUP */
95bd211b85Ssemery
96bd211b85Ssemery if (realm == 0 || *realm == '\0') {
97bd211b85Ssemery ret = krb5_get_default_realm(context, &def_realm);
98bd211b85Ssemery if (ret != 0)
99bd211b85Ssemery return (ret);
100bd211b85Ssemery }
101bd211b85Ssemery
102bd211b85Ssemery (void) profile_get_string(context->profile, "realms",
103bd211b85Ssemery realm ? realm : def_realm,
104bd211b85Ssemery KADM5_KPASSWD, 0, kpasswd);
105bd211b85Ssemery
106bd211b85Ssemery if ((*kpasswd != NULL) && ((delim = strchr(*kpasswd, ':')) != NULL))
107bd211b85Ssemery *delim = '\0';
108bd211b85Ssemery #ifdef KRB5_DNS_LOOKUP
109bd211b85Ssemery if (*kpasswd == NULL) {
110bd211b85Ssemery /*
111bd211b85Ssemery * Initialize realm info for (possible) DNS lookups.
112bd211b85Ssemery */
113bd211b85Ssemery dns_realm.data = strdup(realm ? realm : def_realm);
114bd211b85Ssemery if (dns_realm.data == NULL) {
115bd211b85Ssemery if (def_realm != NULL)
116bd211b85Ssemery free(def_realm);
117bd211b85Ssemery return (ENOMEM);
118bd211b85Ssemery }
119bd211b85Ssemery dns_realm.length = strlen(realm ? realm : def_realm);
120bd211b85Ssemery dns_realm.magic = 0;
121bd211b85Ssemery
122bd211b85Ssemery dns_ret = krb5_get_servername(context, &dns_realm,
123bd211b85Ssemery "_kpasswd", "_tcp",
124bd211b85Ssemery dns_host, &dns_portno);
125bd211b85Ssemery if (dns_ret == 0) {
126bd211b85Ssemery *kpasswd = strdup(dns_host);
127bd211b85Ssemery
128bd211b85Ssemery if (*kpasswd == NULL) {
129bd211b85Ssemery free(dns_realm.data);
130bd211b85Ssemery if (def_realm != NULL)
131bd211b85Ssemery free(def_realm);
132bd211b85Ssemery return (ENOMEM);
133bd211b85Ssemery }
134bd211b85Ssemery }
135bd211b85Ssemery
136bd211b85Ssemery free(dns_realm.data);
137bd211b85Ssemery }
138bd211b85Ssemery #endif /* KRB5_DNS_LOOKUP */
139bd211b85Ssemery
140bd211b85Ssemery if (def_realm != NULL)
141bd211b85Ssemery free(def_realm);
142bd211b85Ssemery return (*kpasswd ? KADM5_OK : KADM5_NO_SRV);
143bd211b85Ssemery }
144bd211b85Ssemery
145bd211b85Ssemery /*
1467c478bd9Sstevel@tonic-gate * Get the host base service name for the admin principal. Returns
1477c478bd9Sstevel@tonic-gate * KADM5_OK on success. Caller must free the storage allocated for
1487c478bd9Sstevel@tonic-gate * host_service_name.
1497c478bd9Sstevel@tonic-gate */
1507c478bd9Sstevel@tonic-gate kadm5_ret_t
kadm5_get_adm_host_srv_name(krb5_context context,const char * realm,char ** host_service_name)1517c478bd9Sstevel@tonic-gate kadm5_get_adm_host_srv_name(krb5_context context,
1527c478bd9Sstevel@tonic-gate const char *realm, char **host_service_name)
1537c478bd9Sstevel@tonic-gate {
1547c478bd9Sstevel@tonic-gate kadm5_ret_t ret;
1557c478bd9Sstevel@tonic-gate char *name;
1567c478bd9Sstevel@tonic-gate char *host;
1577c478bd9Sstevel@tonic-gate
1587c478bd9Sstevel@tonic-gate
1597c478bd9Sstevel@tonic-gate if (ret = kadm5_get_master(context, realm, &host))
1607c478bd9Sstevel@tonic-gate return (ret);
1617c478bd9Sstevel@tonic-gate
1627c478bd9Sstevel@tonic-gate name = malloc(strlen(KADM5_ADMIN_HOST_SERVICE)+ strlen(host) + 2);
1637c478bd9Sstevel@tonic-gate if (name == NULL) {
1647c478bd9Sstevel@tonic-gate free(host);
1657c478bd9Sstevel@tonic-gate return (ENOMEM);
1667c478bd9Sstevel@tonic-gate }
1677c478bd9Sstevel@tonic-gate sprintf(name, "%s@%s", KADM5_ADMIN_HOST_SERVICE, host);
1687c478bd9Sstevel@tonic-gate free(host);
1697c478bd9Sstevel@tonic-gate *host_service_name = name;
1707c478bd9Sstevel@tonic-gate
1717c478bd9Sstevel@tonic-gate return (KADM5_OK);
1727c478bd9Sstevel@tonic-gate }
1737c478bd9Sstevel@tonic-gate
1747c478bd9Sstevel@tonic-gate /*
1757c478bd9Sstevel@tonic-gate * Get the host base service name for the changepw principal. Returns
1767c478bd9Sstevel@tonic-gate * KADM5_OK on success. Caller must free the storage allocated for
1777c478bd9Sstevel@tonic-gate * host_service_name.
1787c478bd9Sstevel@tonic-gate */
1797c478bd9Sstevel@tonic-gate kadm5_ret_t
kadm5_get_cpw_host_srv_name(krb5_context context,const char * realm,char ** host_service_name)1807c478bd9Sstevel@tonic-gate kadm5_get_cpw_host_srv_name(krb5_context context,
1817c478bd9Sstevel@tonic-gate const char *realm, char **host_service_name)
1827c478bd9Sstevel@tonic-gate {
1837c478bd9Sstevel@tonic-gate kadm5_ret_t ret;
1847c478bd9Sstevel@tonic-gate char *name;
1857c478bd9Sstevel@tonic-gate char *host;
1867c478bd9Sstevel@tonic-gate
187bd211b85Ssemery /*
188bd211b85Ssemery * First try to find the kpasswd server, after all we are about to
189bd211b85Ssemery * try to change our password. If this fails then try admin_server.
190bd211b85Ssemery */
191bd211b85Ssemery if (ret = kadm5_get_kpasswd(context, realm, &host)) {
1927c478bd9Sstevel@tonic-gate if (ret = kadm5_get_master(context, realm, &host))
1937c478bd9Sstevel@tonic-gate return (ret);
194bd211b85Ssemery }
1957c478bd9Sstevel@tonic-gate
1967c478bd9Sstevel@tonic-gate name = malloc(strlen(KADM5_CHANGEPW_HOST_SERVICE) + strlen(host) + 2);
1977c478bd9Sstevel@tonic-gate if (name == NULL) {
1987c478bd9Sstevel@tonic-gate free(host);
1997c478bd9Sstevel@tonic-gate return (ENOMEM);
2007c478bd9Sstevel@tonic-gate }
2017c478bd9Sstevel@tonic-gate sprintf(name, "%s@%s", KADM5_CHANGEPW_HOST_SERVICE, host);
2027c478bd9Sstevel@tonic-gate free(host);
2037c478bd9Sstevel@tonic-gate *host_service_name = name;
2047c478bd9Sstevel@tonic-gate
2057c478bd9Sstevel@tonic-gate return (KADM5_OK);
2067c478bd9Sstevel@tonic-gate }
2077c478bd9Sstevel@tonic-gate
2087c478bd9Sstevel@tonic-gate /*
2097c478bd9Sstevel@tonic-gate * Get the host base service name for the kiprop principal. Returns
2107c478bd9Sstevel@tonic-gate * KADM5_OK on success. Caller must free the storage allocated
2117c478bd9Sstevel@tonic-gate * for host_service_name.
2127c478bd9Sstevel@tonic-gate */
kadm5_get_kiprop_host_srv_name(krb5_context context,const char * realm,char ** host_service_name)2137c478bd9Sstevel@tonic-gate kadm5_ret_t kadm5_get_kiprop_host_srv_name(krb5_context context,
2147c478bd9Sstevel@tonic-gate const char *realm,
2157c478bd9Sstevel@tonic-gate char **host_service_name) {
2167c478bd9Sstevel@tonic-gate kadm5_ret_t ret;
2177c478bd9Sstevel@tonic-gate char *name;
2187c478bd9Sstevel@tonic-gate char *host;
2197c478bd9Sstevel@tonic-gate
2207c478bd9Sstevel@tonic-gate
2217c478bd9Sstevel@tonic-gate if (ret = kadm5_get_master(context, realm, &host))
2227c478bd9Sstevel@tonic-gate return (ret);
2237c478bd9Sstevel@tonic-gate
2247c478bd9Sstevel@tonic-gate name = malloc(strlen(KADM5_KIPROP_HOST_SERVICE) + strlen(host) + 2);
2257c478bd9Sstevel@tonic-gate if (name == NULL) {
2267c478bd9Sstevel@tonic-gate free(host);
2277c478bd9Sstevel@tonic-gate return (ENOMEM);
2287c478bd9Sstevel@tonic-gate }
2297c478bd9Sstevel@tonic-gate sprintf(name, "%s@%s", KADM5_KIPROP_HOST_SERVICE, host);
2307c478bd9Sstevel@tonic-gate free(host);
2317c478bd9Sstevel@tonic-gate *host_service_name = name;
2327c478bd9Sstevel@tonic-gate
2337c478bd9Sstevel@tonic-gate return (KADM5_OK);
2347c478bd9Sstevel@tonic-gate }
2357c64d375Smp153739
2367c64d375Smp153739 /*
2377c64d375Smp153739 * Solaris Kerberos:
2387c64d375Smp153739 * Try to determine if this is the master KDC for a given realm
2397c64d375Smp153739 */
kadm5_is_master(krb5_context context,const char * realm,krb5_boolean * is_master)2407c64d375Smp153739 kadm5_ret_t kadm5_is_master(krb5_context context, const char *realm,
2417c64d375Smp153739 krb5_boolean *is_master) {
2427c64d375Smp153739
2437c64d375Smp153739 kadm5_ret_t ret;
2447c64d375Smp153739 char *admin_host = NULL;
245*212bfef1SMark Phalan krb5_address **tmp_addr, **master_addr = NULL;
2467c64d375Smp153739 krb5_address **local_addr = NULL;
2477c64d375Smp153739
2487c64d375Smp153739 if (is_master)
2497c64d375Smp153739 *is_master = FALSE;
2507c64d375Smp153739 else
2517c64d375Smp153739 return (KADM5_FAILURE);
2527c64d375Smp153739
2537c64d375Smp153739 /* Locate the master KDC */
2547c64d375Smp153739 if (ret = kadm5_get_master(context, realm, &admin_host))
2557c64d375Smp153739 return (ret);
2567c64d375Smp153739
2577c64d375Smp153739 if (ret = krb5_os_hostaddr(context, admin_host, &master_addr)) {
2587c64d375Smp153739 free(admin_host);
2597c64d375Smp153739 return (ret);
2607c64d375Smp153739 }
2617c64d375Smp153739
2627c64d375Smp153739 /* Get the local addresses */
2637c64d375Smp153739 if (ret = krb5_os_localaddr(context, &local_addr)) {
2647c64d375Smp153739 krb5_free_addresses(context, master_addr);
2657c64d375Smp153739 free(admin_host);
2667c64d375Smp153739 return (ret);
2677c64d375Smp153739 }
2687c64d375Smp153739
2697c64d375Smp153739 /* Compare them */
270*212bfef1SMark Phalan for (tmp_addr = master_addr; *tmp_addr; tmp_addr++) {
271*212bfef1SMark Phalan if (krb5_address_search(context, *tmp_addr, local_addr)) {
2727c64d375Smp153739 *is_master = TRUE;
2737c64d375Smp153739 break;
2747c64d375Smp153739 }
2757c64d375Smp153739 }
2767c64d375Smp153739
2777c64d375Smp153739 krb5_free_addresses(context, local_addr);
2787c64d375Smp153739 krb5_free_addresses(context, master_addr);
2797c64d375Smp153739 free(admin_host);
2807c64d375Smp153739
2817c64d375Smp153739 return (KADM5_OK);
2827c64d375Smp153739 }
283