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