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