xref: /illumos-gate/usr/src/lib/krb5/kadm5/kadm_host_srv_names.c (revision 44bac77bf8165ebe38afb85dda247b928d88edf8)
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 
18 /*
19  * Find the admin server for the given realm. If the realm is null or
20  * the empty string, find the admin server for the default realm.
21  * Returns 0 on succsess (KADM5_OK). It is the callers responsibility to
22  * free the storage allocated to the admin server, master.
23  */
24 kadm5_ret_t
25 kadm5_get_master(krb5_context context, const char *realm, char **master)
26 {
27 	char *def_realm;
28 	char *delim;
29 #ifdef KRB5_DNS_LOOKUP
30 	struct sockaddr *addrs;
31 	int naddrs;
32 	unsigned short dns_portno;
33 	char dns_host[MAX_DNS_NAMELEN];
34 	krb5_data dns_realm;
35 	krb5_error_code dns_ret = 1;
36 #endif /* KRB5_DNS_LOOKUP */
37 
38 	if (realm == 0 || *realm == '\0')
39 		krb5_get_default_realm(context, &def_realm);
40 
41 	(void) profile_get_string(context->profile, "realms",
42 	    realm ? realm : def_realm,
43 	    KADM5_MASTER, 0, master);
44 
45 	if ((*master != NULL) && ((delim = strchr(*master, ':')) != NULL))
46 		*delim = '\0';
47 #ifdef KRB5_DNS_LOOKUP
48 	if (*master == NULL) {
49 		/*
50 		 * Initialize realm info for (possible) DNS lookups.
51 		 */
52 		dns_realm.data = strdup(realm ? realm : def_realm);
53 		dns_realm.length = strlen(realm ? realm : def_realm);
54 		dns_realm.magic = 0;
55 
56 		dns_ret = krb5_get_servername(context, &dns_realm,
57 		    "_kerberos-adm", "_udp",
58 		    dns_host, &dns_portno);
59 		if (dns_ret == 0)
60 			*master = strdup(dns_host);
61 
62 		if (dns_realm.data)
63 			free(dns_realm.data);
64 	}
65 #endif /* KRB5_DNS_LOOKUP */
66 	return (*master ? KADM5_OK : KADM5_NO_SRV);
67 }
68 
69 /*
70  * Get the host base service name for the admin principal. Returns
71  * KADM5_OK on success. Caller must free the storage allocated for
72  * host_service_name.
73  */
74 kadm5_ret_t
75 kadm5_get_adm_host_srv_name(krb5_context context,
76 			    const char *realm, char **host_service_name)
77 {
78 	kadm5_ret_t ret;
79 	char *name;
80 	char *host;
81 
82 
83 	if (ret = kadm5_get_master(context, realm, &host))
84 		return (ret);
85 
86 	name = malloc(strlen(KADM5_ADMIN_HOST_SERVICE)+ strlen(host) + 2);
87 	if (name == NULL) {
88 		free(host);
89 		return (ENOMEM);
90 	}
91 	sprintf(name, "%s@%s", KADM5_ADMIN_HOST_SERVICE, host);
92 	free(host);
93 	*host_service_name = name;
94 
95 	return (KADM5_OK);
96 }
97 
98 /*
99  * Get the host base service name for the changepw principal. Returns
100  * KADM5_OK on success. Caller must free the storage allocated for
101  * host_service_name.
102  */
103 kadm5_ret_t
104 kadm5_get_cpw_host_srv_name(krb5_context context,
105 			    const char *realm, char **host_service_name)
106 {
107 	kadm5_ret_t ret;
108 	char *name;
109 	char *host;
110 
111 
112 	if (ret = kadm5_get_master(context, realm, &host))
113 		return (ret);
114 
115 	name = malloc(strlen(KADM5_CHANGEPW_HOST_SERVICE) + strlen(host) + 2);
116 	if (name == NULL) {
117 		free(host);
118 		return (ENOMEM);
119 	}
120 	sprintf(name, "%s@%s", KADM5_CHANGEPW_HOST_SERVICE, host);
121 	free(host);
122 	*host_service_name = name;
123 
124 	return (KADM5_OK);
125 }
126 
127 /*
128  * Get the host base service name for the kiprop principal. Returns
129  * KADM5_OK on success. Caller must free the storage allocated
130  * for host_service_name.
131  */
132 kadm5_ret_t kadm5_get_kiprop_host_srv_name(krb5_context context,
133 				    const char *realm,
134 				    char **host_service_name) {
135 	kadm5_ret_t ret;
136 	char *name;
137 	char *host;
138 
139 
140 	if (ret = kadm5_get_master(context, realm, &host))
141 		return (ret);
142 
143 	name = malloc(strlen(KADM5_KIPROP_HOST_SERVICE) + strlen(host) + 2);
144 	if (name == NULL) {
145 		free(host);
146 		return (ENOMEM);
147 	}
148 	sprintf(name, "%s@%s", KADM5_KIPROP_HOST_SERVICE, host);
149 	free(host);
150 	*host_service_name = name;
151 
152 	return (KADM5_OK);
153 }
154 
155 /*
156  * Solaris Kerberos:
157  * Try to determine if this is the master KDC for a given realm
158  */
159 kadm5_ret_t kadm5_is_master(krb5_context context, const char *realm,
160     krb5_boolean *is_master) {
161 
162 	kadm5_ret_t ret;
163 	char *admin_host = NULL;
164 	krb5_address **master_addr = NULL;
165 	krb5_address **local_addr = NULL;
166 
167 	if (is_master)
168 		*is_master = FALSE;
169 	else
170 		return (KADM5_FAILURE);
171 
172 	/* Locate the master KDC */
173 	if (ret = kadm5_get_master(context, realm, &admin_host))
174 		return (ret);
175 
176 	if (ret = krb5_os_hostaddr(context, admin_host, &master_addr)) {
177 		free(admin_host);
178 		return (ret);
179 	}
180 
181 	/* Get the local addresses */
182 	if (ret = krb5_os_localaddr(context, &local_addr)) {
183 		krb5_free_addresses(context, master_addr);
184 		free(admin_host);
185 		return (ret);
186 	}
187 
188 	/* Compare them */
189 	for (; *master_addr; master_addr++) {
190 		if (krb5_address_search(context, *master_addr, local_addr)) {
191 			*is_master = TRUE;
192 			break;
193 		}
194 	}
195 
196 	krb5_free_addresses(context, local_addr);
197 	krb5_free_addresses(context, master_addr);
198 	free(admin_host);
199 
200 	return (KADM5_OK);
201 }
202