Line data Source code
1 : /*
2 : * Copyright (c) 2001 - 2003 Kungliga Tekniska Högskolan
3 : * (Royal Institute of Technology, Stockholm, Sweden).
4 : * All rights reserved.
5 : *
6 : * Portions Copyright (c) 2010 Apple Inc. All rights reserved.
7 : *
8 : * Redistribution and use in source and binary forms, with or without
9 : * modification, are permitted provided that the following conditions
10 : * are met:
11 : *
12 : * 1. Redistributions of source code must retain the above copyright
13 : * notice, this list of conditions and the following disclaimer.
14 : *
15 : * 2. Redistributions in binary form must reproduce the above copyright
16 : * notice, this list of conditions and the following disclaimer in the
17 : * documentation and/or other materials provided with the distribution.
18 : *
19 : * 3. Neither the name of the Institute nor the names of its contributors
20 : * may be used to endorse or promote products derived from this software
21 : * without specific prior written permission.
22 : *
23 : * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
24 : * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
25 : * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
26 : * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
27 : * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
28 : * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
29 : * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
30 : * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
31 : * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
32 : * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
33 : * SUCH DAMAGE.
34 : */
35 :
36 : #include "krb5_locl.h"
37 : #include <resolve.h>
38 : #include "locate_plugin.h"
39 :
40 : static int
41 153 : string_to_proto(const char *string)
42 : {
43 153 : if(strcasecmp(string, "udp") == 0)
44 71 : return KRB5_KRBHST_UDP;
45 82 : else if(strcasecmp(string, "tcp") == 0)
46 46 : return KRB5_KRBHST_TCP;
47 36 : else if(strcasecmp(string, "http") == 0)
48 36 : return KRB5_KRBHST_HTTP;
49 0 : return -1;
50 : }
51 :
52 : static int
53 45 : is_invalid_tld_srv_target(const char *target)
54 : {
55 45 : return (strncmp("your-dns-needs-immediate-attention.",
56 : target, 35) == 0
57 45 : && strchr(&target[35], '.') == NULL);
58 : }
59 :
60 : /*
61 : * set `res' and `count' to the result of looking up SRV RR in DNS for
62 : * `proto', `proto', `realm' using `dns_type'.
63 : * if `port' != 0, force that port number
64 : */
65 :
66 : static krb5_error_code
67 153 : srv_find_realm(krb5_context context, krb5_krbhst_info ***res, int *count,
68 : const char *realm, const char *dns_type, const char *sitename,
69 : const char *proto, const char *service, int port)
70 : {
71 0 : char domain[1024];
72 0 : struct rk_dns_reply *r;
73 0 : struct rk_resource_record *rr;
74 0 : int num_srv;
75 0 : int proto_num;
76 0 : int def_port;
77 :
78 153 : *res = NULL;
79 153 : *count = 0;
80 :
81 153 : proto_num = string_to_proto(proto);
82 153 : if(proto_num < 0) {
83 0 : krb5_set_error_message(context, EINVAL,
84 0 : N_("unknown protocol `%s' to lookup", ""),
85 : proto);
86 0 : return EINVAL;
87 : }
88 :
89 153 : if(proto_num == KRB5_KRBHST_HTTP)
90 36 : def_port = ntohs(krb5_getportbyname (context, "http", "tcp", 80));
91 117 : else if(port == 0)
92 117 : def_port = ntohs(krb5_getportbyname (context, service, proto, 88));
93 : else
94 0 : def_port = port;
95 :
96 153 : if (sitename)
97 0 : snprintf(domain, sizeof(domain), "_%s._%s.%s._sites.%s.",
98 : service, proto, sitename, realm);
99 : else
100 153 : snprintf(domain, sizeof(domain), "_%s._%s.%s.", service, proto, realm);
101 :
102 153 : r = rk_dns_lookup(domain, dns_type);
103 153 : if(r == NULL) {
104 72 : _krb5_debug(context, 0,
105 : "DNS lookup failed domain: %s", domain);
106 72 : return KRB5_KDC_UNREACH;
107 : }
108 :
109 171 : for(num_srv = 0, rr = r->head; rr; rr = rr->next)
110 90 : if(rr->type == rk_ns_t_srv) {
111 45 : if (num_srv >= INT_MAX) {
112 0 : rk_dns_free_data(r);
113 0 : return KRB5_KDC_UNREACH;
114 : }
115 45 : if (num_srv >= SIZE_MAX / sizeof(**res)) {
116 0 : rk_dns_free_data(r);
117 0 : return KRB5_KDC_UNREACH;
118 : }
119 45 : num_srv++;
120 : }
121 :
122 81 : if (num_srv == 0) {
123 36 : _krb5_debug(context, 0,
124 : "DNS SRV RR lookup domain nodata: %s", domain);
125 36 : rk_dns_free_data(r);
126 36 : return KRB5_KDC_UNREACH;
127 : }
128 :
129 45 : *res = malloc(num_srv * sizeof(**res));
130 45 : if(*res == NULL) {
131 0 : rk_dns_free_data(r);
132 0 : return krb5_enomem(context);
133 : }
134 :
135 45 : rk_dns_srv_order(r);
136 :
137 135 : for(num_srv = 0, rr = r->head; rr; rr = rr->next)
138 90 : if(rr->type == rk_ns_t_srv) {
139 45 : krb5_krbhst_info *hi = NULL;
140 0 : size_t len;
141 45 : int invalid_tld = 1;
142 :
143 : /* Test for top-level domain controlled interruptions */
144 45 : if (!is_invalid_tld_srv_target(rr->u.srv->target)) {
145 45 : invalid_tld = 0;
146 45 : len = strlen(rr->u.srv->target);
147 45 : hi = calloc(1, sizeof(*hi) + len);
148 : }
149 45 : if(hi == NULL) {
150 0 : rk_dns_free_data(r);
151 0 : while(--num_srv >= 0)
152 0 : free((*res)[num_srv]);
153 0 : free(*res);
154 0 : *res = NULL;
155 0 : if (invalid_tld) {
156 0 : krb5_warnx(context,
157 : "Domain lookup failed: "
158 : "Realm %s needs immediate attention "
159 : "see https://icann.org/namecollision",
160 : realm);
161 0 : return KRB5_KDC_UNREACH;
162 : }
163 0 : return krb5_enomem(context);
164 : }
165 45 : (*res)[num_srv++] = hi;
166 :
167 45 : hi->proto = proto_num;
168 :
169 45 : hi->def_port = def_port;
170 45 : if (port != 0)
171 0 : hi->port = port;
172 : else
173 45 : hi->port = rr->u.srv->port;
174 :
175 45 : strlcpy(hi->hostname, rr->u.srv->target, len + 1);
176 : }
177 :
178 45 : *count = num_srv;
179 :
180 45 : rk_dns_free_data(r);
181 45 : return 0;
182 : }
183 :
184 :
185 : struct krb5_krbhst_data {
186 : const char *config_param;
187 : const char *srv_label;
188 : char *realm;
189 : unsigned int flags;
190 : int def_port;
191 : int port; /* hardwired port number if != 0 */
192 : #define KD_CONFIG 0x0001
193 : #define KD_SRV_UDP 0x0002
194 : #define KD_SRV_TCP 0x0004
195 : #define KD_SITE_SRV_UDP 0x0008
196 : #define KD_SITE_SRV_TCP 0x0010
197 : #define KD_SRV_HTTP 0x0020
198 : #define KD_SRV_KKDCP 0x0040
199 : #define KD_FALLBACK 0x0080
200 : #define KD_CONFIG_EXISTS 0x0100
201 : #define KD_LARGE_MSG 0x0200
202 : #define KD_PLUGIN 0x0400
203 : #define KD_HOSTNAMES 0x0800
204 : krb5_error_code (*get_next)(krb5_context, struct krb5_krbhst_data *,
205 : krb5_krbhst_info**);
206 :
207 : char *hostname;
208 : char *sitename;
209 : unsigned int fallback_count;
210 :
211 : struct krb5_krbhst_info *hosts, **index, **end;
212 : };
213 :
214 : static krb5_boolean
215 0 : krbhst_empty(const struct krb5_krbhst_data *kd)
216 : {
217 0 : return kd->index == &kd->hosts;
218 : }
219 :
220 : /*
221 : * Return the default protocol for the `kd' (either TCP or UDP)
222 : */
223 :
224 : static int
225 75147 : krbhst_get_default_proto(struct krb5_krbhst_data *kd)
226 : {
227 75147 : if (kd->flags & KD_LARGE_MSG)
228 49400 : return KRB5_KRBHST_TCP;
229 24577 : return KRB5_KRBHST_UDP;
230 : }
231 :
232 : static int
233 0 : krbhst_get_default_port(struct krb5_krbhst_data *kd)
234 : {
235 0 : return kd->def_port;
236 : }
237 :
238 : /*
239 : *
240 : */
241 :
242 : KRB5_LIB_FUNCTION const char * KRB5_LIB_CALL
243 0 : _krb5_krbhst_get_realm(krb5_krbhst_handle handle)
244 : {
245 0 : return handle->realm;
246 : }
247 :
248 : /*
249 : * parse `spec' into a krb5_krbhst_info, defaulting the port to `def_port'
250 : * and forcing it to `port' if port != 0
251 : */
252 :
253 : static struct krb5_krbhst_info*
254 75111 : parse_hostspec(krb5_context context, struct krb5_krbhst_data *kd,
255 : const char *spec, int def_port, int port)
256 : {
257 75111 : const char *p = spec, *q;
258 3413 : struct krb5_krbhst_info *hi;
259 :
260 75111 : hi = calloc(1, sizeof(*hi) + strlen(spec));
261 75111 : if(hi == NULL)
262 0 : return NULL;
263 :
264 75111 : hi->proto = krbhst_get_default_proto(kd);
265 :
266 75111 : if(strncmp(p, "http://", 7) == 0){
267 0 : hi->proto = KRB5_KRBHST_HTTP;
268 0 : p += 7;
269 75111 : } else if(strncmp(p, "http/", 5) == 0) {
270 0 : hi->proto = KRB5_KRBHST_HTTP;
271 0 : p += 5;
272 0 : def_port = ntohs(krb5_getportbyname (context, "http", "tcp", 80));
273 75111 : }else if(strncmp(p, "tcp/", 4) == 0){
274 0 : hi->proto = KRB5_KRBHST_TCP;
275 0 : p += 4;
276 75111 : } else if(strncmp(p, "udp/", 4) == 0) {
277 0 : hi->proto = KRB5_KRBHST_UDP;
278 0 : p += 4;
279 : }
280 :
281 75111 : if (p[0] == '[' && (q = strchr(p, ']')) != NULL) {
282 : /* if address looks like [foo:bar] or [foo:bar]: its a ipv6
283 : adress, strip of [] */
284 652 : memcpy(hi->hostname, &p[1], q - p - 1);
285 652 : hi->hostname[q - p - 1] = '\0';
286 652 : p = q + 1;
287 : /* get trailing : */
288 652 : if (p[0] == ':')
289 652 : p++;
290 74459 : } else if(strsep_copy(&p, ":", hi->hostname, strlen(spec) + 1) < 0) {
291 : /* copy everything before : */
292 0 : free(hi);
293 0 : return NULL;
294 : }
295 : /* get rid of trailing /, and convert to lower case */
296 75111 : hi->hostname[strcspn(hi->hostname, "/")] = '\0';
297 75111 : strlwr(hi->hostname);
298 :
299 75111 : hi->port = hi->def_port = def_port;
300 75111 : if(p != NULL && p[0]) {
301 3413 : char *end;
302 74141 : hi->port = strtol(p, &end, 0);
303 74141 : if(end == p) {
304 0 : free(hi);
305 0 : return NULL;
306 : }
307 : }
308 75111 : if (port)
309 0 : hi->port = port;
310 71698 : return hi;
311 : }
312 :
313 : KRB5_LIB_FUNCTION void KRB5_LIB_CALL
314 75156 : _krb5_free_krbhst_info(krb5_krbhst_info *hi)
315 : {
316 75156 : if (hi->ai != NULL)
317 74366 : freeaddrinfo(hi->ai);
318 75156 : free(hi);
319 75156 : }
320 :
321 : KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
322 0 : _krb5_krbhost_info_move(krb5_context context,
323 : krb5_krbhst_info *from,
324 : krb5_krbhst_info **to)
325 : {
326 0 : size_t hostnamelen = strlen(from->hostname);
327 : /* trailing NUL is included in structure */
328 0 : *to = calloc(1, sizeof(**to) + hostnamelen);
329 0 : if (*to == NULL)
330 0 : return krb5_enomem(context);
331 :
332 0 : (*to)->proto = from->proto;
333 0 : (*to)->port = from->port;
334 0 : (*to)->def_port = from->def_port;
335 0 : (*to)->ai = from->ai;
336 0 : from->ai = NULL;
337 0 : (*to)->next = NULL;
338 0 : memcpy((*to)->hostname, from->hostname, hostnamelen + 1);
339 0 : return 0;
340 : }
341 :
342 :
343 : static void
344 75156 : append_host_hostinfo(struct krb5_krbhst_data *kd, struct krb5_krbhst_info *host)
345 : {
346 3413 : struct krb5_krbhst_info *h;
347 :
348 75859 : for(h = kd->hosts; h; h = h->next)
349 790 : if(h->proto == host->proto &&
350 790 : h->port == host->port &&
351 790 : strcmp(h->hostname, host->hostname) == 0) {
352 87 : _krb5_free_krbhst_info(host);
353 87 : return;
354 : }
355 : /*
356 : * We should always initialize kd->end in common_init(), but static
357 : * analyzers may not see that we do, and the compiler might conclude
358 : * there's UB here.
359 : */
360 75069 : if (kd->end)
361 75069 : *kd->end = host;
362 75069 : kd->end = &host->next;
363 : }
364 :
365 : static krb5_error_code
366 75111 : append_host_string(krb5_context context, struct krb5_krbhst_data *kd,
367 : const char *host, int def_port, int port)
368 : {
369 3413 : struct krb5_krbhst_info *hi;
370 :
371 75111 : hi = parse_hostspec(context, kd, host, def_port, port);
372 75111 : if(hi == NULL)
373 0 : return krb5_enomem(context);
374 :
375 75111 : append_host_hostinfo(kd, hi);
376 75111 : return 0;
377 : }
378 :
379 : /*
380 : * return a readable representation of `host' in `hostname, hostlen'
381 : */
382 :
383 : KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
384 0 : krb5_krbhst_format_string(krb5_context context, const krb5_krbhst_info *host,
385 : char *hostname, size_t hostlen)
386 : {
387 0 : const char *proto = "";
388 0 : if(host->proto == KRB5_KRBHST_TCP)
389 0 : proto = "tcp/";
390 0 : else if(host->proto == KRB5_KRBHST_HTTP)
391 0 : proto = "http://";
392 0 : if (host->port != host->def_port)
393 0 : snprintf(hostname, hostlen, "%s%s:%d", proto, host->hostname, (int)host->port);
394 : else
395 0 : snprintf(hostname, hostlen, "%s%s", proto, host->hostname);
396 0 : return 0;
397 : }
398 :
399 : /*
400 : * create a getaddrinfo `hints' based on `proto'
401 : */
402 :
403 : static void
404 74402 : make_hints(struct addrinfo *hints, int proto)
405 : {
406 74402 : memset(hints, 0, sizeof(*hints));
407 74402 : hints->ai_family = AF_UNSPEC;
408 74402 : switch(proto) {
409 25420 : case KRB5_KRBHST_UDP :
410 25420 : hints->ai_socktype = SOCK_DGRAM;
411 25420 : break;
412 48982 : case KRB5_KRBHST_HTTP :
413 : case KRB5_KRBHST_TCP :
414 48982 : hints->ai_socktype = SOCK_STREAM;
415 48982 : break;
416 : }
417 74402 : }
418 :
419 : /**
420 : * Return an `struct addrinfo *' for a KDC host.
421 : *
422 : * Returns an the struct addrinfo in in that corresponds to the
423 : * information in `host'. free:ing is handled by krb5_krbhst_free, so
424 : * the returned ai must not be released.
425 : *
426 : * @ingroup krb5
427 : */
428 :
429 : KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
430 74366 : krb5_krbhst_get_addrinfo(krb5_context context, krb5_krbhst_info *host,
431 : struct addrinfo **ai)
432 : {
433 74366 : int ret = 0;
434 :
435 74366 : if (host->ai == NULL) {
436 3413 : struct addrinfo hints;
437 3413 : char portstr[NI_MAXSERV];
438 :
439 74366 : snprintf (portstr, sizeof(portstr), "%d", host->port);
440 74366 : make_hints(&hints, host->proto);
441 :
442 74366 : if (krb5_config_get_bool(context, NULL, "libdefaults", "block_dns",
443 : NULL)) {
444 0 : hints.ai_flags &= ~AI_CANONNAME;
445 0 : hints.ai_flags |= AI_NUMERICHOST|AI_NUMERICSERV;
446 : }
447 74366 : ret = getaddrinfo(host->hostname, portstr, &hints, &host->ai);
448 74366 : if (ret) {
449 0 : ret = krb5_eai_to_heim_errno(ret, errno);
450 0 : goto out;
451 : }
452 : }
453 0 : out:
454 74366 : *ai = host->ai;
455 74366 : return ret;
456 : }
457 :
458 : static krb5_boolean
459 329532 : get_next(struct krb5_krbhst_data *kd, krb5_krbhst_info **host)
460 : {
461 346597 : struct krb5_krbhst_info *hi = kd ? *kd->index : NULL;
462 319293 : if(hi != NULL) {
463 74366 : *host = hi;
464 74366 : kd->index = &(*kd->index)->next;
465 74366 : return TRUE;
466 : }
467 244927 : return FALSE;
468 : }
469 :
470 : static void
471 153 : srv_get_hosts(krb5_context context, struct krb5_krbhst_data *kd,
472 : const char *sitename, const char *proto, const char *service)
473 : {
474 0 : krb5_error_code ret;
475 0 : krb5_krbhst_info **res;
476 0 : int count, i;
477 :
478 153 : if (krb5_realm_is_lkdc(kd->realm))
479 108 : return;
480 :
481 153 : ret = srv_find_realm(context, &res, &count, kd->realm, "SRV",
482 : sitename, proto, service, kd->port);
483 153 : _krb5_debug(context, 2, "searching DNS for realm %s %s.%s -> %d",
484 : kd->realm, proto, service, ret);
485 153 : if (ret)
486 108 : return;
487 90 : for(i = 0; i < count; i++)
488 45 : append_host_hostinfo(kd, res[i]);
489 45 : free(res);
490 : }
491 :
492 : /*
493 : * read the configuration for `conf_string', defaulting to kd->def_port and
494 : * forcing it to `kd->port' if kd->port != 0
495 : */
496 :
497 : static void
498 82342 : config_get_hosts(krb5_context context, struct krb5_krbhst_data *kd,
499 : const char *conf_string)
500 : {
501 3413 : int i;
502 3413 : char **hostlist;
503 82342 : hostlist = krb5_config_get_strings(context, NULL,
504 : "realms", kd->realm, conf_string, NULL);
505 :
506 82342 : _krb5_debug(context, 2, "configuration file for realm %s%s found",
507 : kd->realm, hostlist ? "" : " not");
508 :
509 82342 : if(hostlist == NULL)
510 8021 : return;
511 74321 : kd->flags |= KD_CONFIG_EXISTS;
512 149432 : for(i = 0; hostlist && hostlist[i] != NULL; i++)
513 75111 : append_host_string(context, kd, hostlist[i], kd->def_port, kd->port);
514 :
515 74321 : krb5_config_free_strings(hostlist);
516 : }
517 :
518 : /*
519 : * as a fallback, look for `serv_string.kd->realm' (typically
520 : * kerberos.REALM, kerberos-1.REALM, ...
521 : * `port' is the default port for the service, and `proto' the
522 : * protocol
523 : */
524 :
525 : static krb5_error_code
526 36 : fallback_get_hosts(krb5_context context, struct krb5_krbhst_data *kd,
527 : const char *serv_string, int port, int proto)
528 : {
529 36 : char *host = NULL;
530 0 : int ret;
531 0 : struct addrinfo *ai;
532 0 : struct addrinfo hints;
533 0 : char portstr[NI_MAXSERV];
534 :
535 36 : ret = krb5_config_get_bool_default(context, NULL, KRB5_FALLBACK_DEFAULT,
536 : "libdefaults", "use_fallback", NULL);
537 36 : if (!ret) {
538 0 : kd->flags |= KD_FALLBACK;
539 0 : return 0;
540 : }
541 :
542 36 : _krb5_debug(context, 2, "fallback lookup %d for realm %s (service %s)",
543 : kd->fallback_count, kd->realm, serv_string);
544 :
545 : /*
546 : * Don't try forever in case the DNS server keep returning us
547 : * entries (like wildcard entries or the .nu TLD)
548 : *
549 : * Also don't try LKDC realms since fallback wont work on them at all.
550 : */
551 36 : if(kd->fallback_count >= 5 || krb5_realm_is_lkdc(kd->realm)) {
552 0 : kd->flags |= KD_FALLBACK;
553 0 : return 0;
554 : }
555 :
556 36 : if(kd->fallback_count == 0)
557 36 : ret = asprintf(&host, "%s.%s.", serv_string, kd->realm);
558 : else
559 0 : ret = asprintf(&host, "%s-%d.%s.",
560 : serv_string, kd->fallback_count, kd->realm);
561 :
562 36 : if (ret < 0 || host == NULL)
563 0 : return krb5_enomem(context);
564 :
565 36 : make_hints(&hints, proto);
566 36 : snprintf(portstr, sizeof(portstr), "%d", port);
567 36 : if (krb5_config_get_bool(context, NULL, "libdefaults", "block_dns",
568 : NULL)) {
569 0 : hints.ai_flags &= ~AI_CANONNAME;
570 0 : hints.ai_flags |= AI_NUMERICHOST|AI_NUMERICSERV;
571 : }
572 36 : ret = getaddrinfo(host, portstr, &hints, &ai);
573 36 : if (ret) {
574 : /* no more hosts, so we're done here */
575 36 : free(host);
576 36 : kd->flags |= KD_FALLBACK;
577 : } else {
578 0 : struct krb5_krbhst_info *hi;
579 0 : size_t hostlen;
580 :
581 : /* Check for ICANN gTLD Name Collision address (127.0.53.53) */
582 0 : if (ai->ai_family == AF_INET) {
583 0 : struct sockaddr_in *sin = (struct sockaddr_in *)ai->ai_addr;
584 0 : if (sin->sin_addr.s_addr == htonl(0x7f003535)) {
585 0 : krb5_warnx(context,
586 : "Fallback lookup failed: "
587 : "Realm %s needs immediate attention "
588 : "see https://icann.org/namecollision",
589 : kd->realm);
590 0 : free(host);
591 0 : freeaddrinfo(ai);
592 0 : return KRB5_KDC_UNREACH;
593 : }
594 : }
595 :
596 0 : hostlen = strlen(host);
597 0 : hi = calloc(1, sizeof(*hi) + hostlen);
598 0 : if(hi == NULL) {
599 0 : free(host);
600 0 : freeaddrinfo(ai);
601 0 : return krb5_enomem(context);
602 : }
603 :
604 0 : hi->proto = proto;
605 0 : hi->port = hi->def_port = port;
606 0 : hi->ai = ai;
607 0 : memmove(hi->hostname, host, hostlen);
608 0 : hi->hostname[hostlen] = '\0';
609 0 : free(host);
610 0 : append_host_hostinfo(kd, hi);
611 0 : kd->fallback_count++;
612 : }
613 36 : return 0;
614 : }
615 :
616 : /*
617 : * Fetch hosts from plugin
618 : */
619 :
620 : static krb5_error_code
621 0 : add_plugin_host(struct krb5_krbhst_data *kd,
622 : const char *host,
623 : const char *port,
624 : int portnum,
625 : int proto)
626 : {
627 0 : struct krb5_krbhst_info *hi;
628 0 : struct addrinfo hints, *ai;
629 0 : size_t hostlen;
630 0 : int ret;
631 :
632 0 : make_hints(&hints, proto);
633 0 : ret = getaddrinfo(host, port, &hints, &ai);
634 0 : if (ret)
635 0 : return 0;
636 :
637 0 : hostlen = strlen(host);
638 :
639 0 : hi = calloc(1, sizeof(*hi) + hostlen);
640 0 : if (hi == NULL) {
641 0 : freeaddrinfo(ai);
642 0 : return ENOMEM;
643 : }
644 :
645 0 : hi->proto = proto;
646 0 : hi->port = hi->def_port = portnum;
647 0 : hi->ai = ai;
648 0 : memmove(hi->hostname, host, hostlen);
649 0 : hi->hostname[hostlen] = '\0';
650 0 : append_host_hostinfo(kd, hi);
651 :
652 0 : return 0;
653 : }
654 :
655 : static krb5_error_code
656 0 : add_locate(void *ctx, int type, struct sockaddr *addr)
657 : {
658 0 : struct krb5_krbhst_data *kd = ctx;
659 0 : char host[NI_MAXHOST], port[NI_MAXSERV];
660 0 : socklen_t socklen;
661 0 : krb5_error_code ret;
662 0 : int proto, portnum;
663 :
664 0 : socklen = socket_sockaddr_size(addr);
665 0 : portnum = socket_get_port(addr);
666 :
667 0 : ret = getnameinfo(addr, socklen, host, sizeof(host), port, sizeof(port),
668 : NI_NUMERICHOST|NI_NUMERICSERV|NI_NUMERICSCOPE);
669 0 : if (ret != 0)
670 0 : return 0;
671 :
672 0 : if (kd->port)
673 0 : snprintf(port, sizeof(port), "%d", kd->port);
674 0 : else if (atoi(port) == 0)
675 0 : snprintf(port, sizeof(port), "%d", krbhst_get_default_port(kd));
676 :
677 0 : proto = krbhst_get_default_proto(kd);
678 :
679 0 : ret = add_plugin_host(kd, host, port, portnum, proto);
680 0 : if (ret)
681 0 : return ret;
682 :
683 : /*
684 : * This is really kind of broken and should be solved a different
685 : * way, some sites block UDP, and we don't, in the general case,
686 : * fall back to TCP, that should also be done. But since that
687 : * should require us to invert the whole "find kdc" stack, let put
688 : * this in for now.
689 : */
690 :
691 0 : if (proto == KRB5_KRBHST_UDP) {
692 0 : ret = add_plugin_host(kd, host, port, portnum, KRB5_KRBHST_TCP);
693 0 : if (ret)
694 0 : return ret;
695 : }
696 :
697 0 : return 0;
698 : }
699 :
700 : struct plctx {
701 : enum locate_service_type type;
702 : struct krb5_krbhst_data *kd;
703 : unsigned long flags;
704 : };
705 :
706 : static KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
707 0 : plcallback(krb5_context context,
708 : const void *plug, void *plugctx, void *userctx)
709 : {
710 0 : const krb5plugin_service_locate_ftable *locate = plug;
711 0 : struct plctx *plctx = userctx;
712 :
713 0 : if (locate->minor_version >= KRB5_PLUGIN_LOCATE_VERSION_2)
714 0 : return locate->lookup(plugctx, plctx->flags, plctx->type, plctx->kd->realm, 0, 0, add_locate, plctx->kd);
715 :
716 0 : if (plctx->flags & KRB5_PLF_ALLOW_HOMEDIR)
717 0 : return locate->old_lookup(plugctx, plctx->type, plctx->kd->realm, 0, 0, add_locate, plctx->kd);
718 :
719 0 : return KRB5_PLUGIN_NO_HANDLE;
720 : }
721 :
722 : static const char *const locate_plugin_deps[] = { "krb5", NULL };
723 :
724 : static const struct heim_plugin_data
725 : locate_plugin_data = {
726 : "krb5",
727 : KRB5_PLUGIN_LOCATE,
728 : KRB5_PLUGIN_LOCATE_VERSION_0,
729 : locate_plugin_deps,
730 : krb5_get_instance
731 : };
732 :
733 : static void
734 82342 : plugin_get_hosts(krb5_context context,
735 : struct krb5_krbhst_data *kd,
736 : enum locate_service_type type)
737 : {
738 82342 : struct plctx ctx = { type, kd, 0 };
739 :
740 : /*
741 : * XXX Need a way to pass this through -- unsure if any of this is
742 : * useful without DNS, though.
743 : */
744 82342 : if (krb5_config_get_bool(context, NULL, "libdefaults", "block_dns", NULL))
745 0 : return;
746 :
747 82342 : if (_krb5_homedir_access(context))
748 82342 : ctx.flags |= KRB5_PLF_ALLOW_HOMEDIR;
749 :
750 82342 : _krb5_plugin_run_f(context, &locate_plugin_data,
751 : 0, &ctx, plcallback);
752 : }
753 :
754 : /*
755 : *
756 : */
757 :
758 : static void
759 82313 : hostnames_get_hosts(krb5_context context,
760 : struct krb5_krbhst_data *kd,
761 : const char *type)
762 : {
763 82313 : kd->flags |= KD_HOSTNAMES;
764 82313 : if (kd->hostname)
765 0 : append_host_string(context, kd, kd->hostname, kd->def_port, kd->port);
766 82313 : }
767 :
768 :
769 : /*
770 : *
771 : */
772 :
773 : static krb5_error_code
774 82317 : kdc_get_next(krb5_context context,
775 : struct krb5_krbhst_data *kd,
776 : krb5_krbhst_info **host)
777 : {
778 3413 : krb5_error_code ret;
779 :
780 82317 : if ((kd->flags & KD_HOSTNAMES) == 0) {
781 82313 : hostnames_get_hosts(context, kd, "kdc");
782 82313 : if(get_next(kd, host))
783 0 : return 0;
784 : }
785 :
786 82317 : if ((kd->flags & KD_PLUGIN) == 0) {
787 82313 : plugin_get_hosts(context, kd, locate_service_kdc);
788 82313 : kd->flags |= KD_PLUGIN;
789 82313 : if(get_next(kd, host))
790 0 : return 0;
791 : }
792 :
793 82317 : if((kd->flags & KD_CONFIG) == 0) {
794 82313 : config_get_hosts(context, kd, kd->config_param);
795 82313 : kd->flags |= KD_CONFIG;
796 82313 : if(get_next(kd, host))
797 74321 : return 0;
798 : }
799 :
800 7996 : if (kd->flags & KD_CONFIG_EXISTS) {
801 7944 : _krb5_debug(context, 1,
802 : "Configuration exists for realm %s, wont go to DNS",
803 : kd->realm);
804 7944 : return KRB5_KDC_UNREACH;
805 : }
806 :
807 52 : if (!krb5_config_get_bool(context, NULL, "libdefaults", "block_dns",
808 52 : NULL) &&
809 52 : context->srv_lookup) {
810 52 : if(kd->sitename && (kd->flags & KD_SITE_SRV_TCP) == 0) {
811 0 : srv_get_hosts(context, kd, kd->sitename, "tcp", "kerberos");
812 0 : kd->flags |= KD_SITE_SRV_TCP;
813 0 : if(get_next(kd, host))
814 0 : return 0;
815 : }
816 :
817 52 : if((kd->flags & KD_SRV_UDP) == 0 && (kd->flags & KD_LARGE_MSG) == 0) {
818 42 : srv_get_hosts(context, kd, NULL, "udp", kd->srv_label);
819 42 : kd->flags |= KD_SRV_UDP;
820 42 : if(get_next(kd, host))
821 6 : return 0;
822 : }
823 :
824 46 : if((kd->flags & KD_SRV_TCP) == 0) {
825 46 : srv_get_hosts(context, kd, NULL, "tcp", kd->srv_label);
826 46 : kd->flags |= KD_SRV_TCP;
827 46 : if(get_next(kd, host))
828 10 : return 0;
829 : }
830 36 : if((kd->flags & KD_SRV_HTTP) == 0) {
831 36 : srv_get_hosts(context, kd, NULL, "http", kd->srv_label);
832 36 : kd->flags |= KD_SRV_HTTP;
833 36 : if(get_next(kd, host))
834 0 : return 0;
835 : }
836 : }
837 :
838 72 : while((kd->flags & KD_FALLBACK) == 0) {
839 36 : ret = fallback_get_hosts(context, kd, "kerberos",
840 : kd->def_port,
841 : krbhst_get_default_proto(kd));
842 36 : if(ret)
843 0 : return ret;
844 36 : if(get_next(kd, host))
845 0 : return 0;
846 : }
847 :
848 36 : _krb5_debug(context, 0, "No KDC entries found for %s", kd->realm);
849 :
850 36 : return KRB5_KDC_UNREACH; /* XXX */
851 : }
852 :
853 : static krb5_error_code
854 0 : admin_get_next(krb5_context context,
855 : struct krb5_krbhst_data *kd,
856 : krb5_krbhst_info **host)
857 : {
858 0 : krb5_error_code ret;
859 :
860 0 : if ((kd->flags & KD_PLUGIN) == 0) {
861 0 : plugin_get_hosts(context, kd, locate_service_kadmin);
862 0 : kd->flags |= KD_PLUGIN;
863 0 : if(get_next(kd, host))
864 0 : return 0;
865 : }
866 :
867 0 : if((kd->flags & KD_CONFIG) == 0) {
868 0 : config_get_hosts(context, kd, kd->config_param);
869 0 : kd->flags |= KD_CONFIG;
870 0 : if(get_next(kd, host))
871 0 : return 0;
872 : }
873 :
874 0 : if (kd->flags & KD_CONFIG_EXISTS) {
875 0 : _krb5_debug(context, 1,
876 : "Configuration exists for realm %s, wont go to DNS",
877 : kd->realm);
878 0 : return KRB5_KDC_UNREACH;
879 : }
880 :
881 0 : if (!krb5_config_get_bool(context, NULL, "libdefaults", "block_dns",
882 0 : NULL) &&
883 0 : context->srv_lookup) {
884 0 : if((kd->flags & KD_SRV_TCP) == 0) {
885 0 : srv_get_hosts(context, kd, NULL, "tcp", kd->srv_label);
886 0 : kd->flags |= KD_SRV_TCP;
887 0 : if(get_next(kd, host))
888 0 : return 0;
889 : }
890 : }
891 :
892 0 : if (krbhst_empty(kd)
893 0 : && (kd->flags & KD_FALLBACK) == 0) {
894 0 : ret = fallback_get_hosts(context, kd, "kerberos",
895 : kd->def_port,
896 : krbhst_get_default_proto(kd));
897 0 : if(ret)
898 0 : return ret;
899 0 : kd->flags |= KD_FALLBACK;
900 0 : if(get_next(kd, host))
901 0 : return 0;
902 : }
903 :
904 0 : _krb5_debug(context, 0, "No admin entries found for realm %s", kd->realm);
905 :
906 0 : return KRB5_KDC_UNREACH; /* XXX */
907 : }
908 :
909 : static krb5_error_code
910 29 : kpasswd_get_next(krb5_context context,
911 : struct krb5_krbhst_data *kd,
912 : krb5_krbhst_info **host)
913 : {
914 0 : krb5_error_code ret;
915 :
916 29 : if ((kd->flags & KD_PLUGIN) == 0) {
917 29 : plugin_get_hosts(context, kd, locate_service_kpasswd);
918 29 : kd->flags |= KD_PLUGIN;
919 29 : if(get_next(kd, host))
920 0 : return 0;
921 : }
922 :
923 29 : if((kd->flags & KD_CONFIG) == 0) {
924 29 : config_get_hosts(context, kd, kd->config_param);
925 29 : kd->flags |= KD_CONFIG;
926 29 : if(get_next(kd, host))
927 0 : return 0;
928 : }
929 :
930 29 : if (kd->flags & KD_CONFIG_EXISTS) {
931 0 : _krb5_debug(context, 1,
932 : "Configuration exists for realm %s, wont go to DNS",
933 : kd->realm);
934 0 : return KRB5_KDC_UNREACH;
935 : }
936 :
937 29 : if (!krb5_config_get_bool(context, NULL, "libdefaults", "block_dns",
938 29 : NULL) &&
939 29 : context->srv_lookup) {
940 29 : if((kd->flags & KD_SRV_UDP) == 0) {
941 29 : srv_get_hosts(context, kd, NULL, "udp", kd->srv_label);
942 29 : kd->flags |= KD_SRV_UDP;
943 29 : if(get_next(kd, host))
944 29 : return 0;
945 : }
946 0 : if((kd->flags & KD_SRV_TCP) == 0) {
947 0 : srv_get_hosts(context, kd, NULL, "tcp", kd->srv_label);
948 0 : kd->flags |= KD_SRV_TCP;
949 0 : if(get_next(kd, host))
950 0 : return 0;
951 : }
952 : }
953 :
954 : /* no matches -> try admin */
955 :
956 0 : if (krbhst_empty(kd)) {
957 0 : kd->flags = 0;
958 0 : kd->port = kd->def_port;
959 0 : kd->get_next = admin_get_next;
960 0 : ret = (*kd->get_next)(context, kd, host);
961 0 : if (ret == 0)
962 0 : (*host)->proto = krbhst_get_default_proto(kd);
963 0 : return ret;
964 : }
965 :
966 0 : _krb5_debug(context, 0, "No kpasswd entries found for realm %s", kd->realm);
967 :
968 0 : return KRB5_KDC_UNREACH;
969 : }
970 :
971 : static void KRB5_CALLCONV
972 82342 : krbhost_dealloc(void *ptr)
973 : {
974 82342 : struct krb5_krbhst_data *handle = (struct krb5_krbhst_data *)ptr;
975 3413 : krb5_krbhst_info *h, *next;
976 :
977 157411 : for (h = handle->hosts; h != NULL; h = next) {
978 75069 : next = h->next;
979 75069 : _krb5_free_krbhst_info(h);
980 : }
981 82342 : if (handle->hostname)
982 0 : free(handle->hostname);
983 82342 : if (handle->sitename)
984 0 : free(handle->sitename);
985 :
986 82342 : free(handle->realm);
987 82342 : }
988 :
989 : static struct krb5_krbhst_data*
990 82342 : common_init(krb5_context context,
991 : const char *config_param,
992 : const char *srv_label,
993 : const char *service,
994 : const char *realm,
995 : int flags)
996 : {
997 3413 : struct krb5_krbhst_data *kd;
998 :
999 82342 : if ((kd = heim_alloc(sizeof(*kd), "krbhst-context", krbhost_dealloc)) == NULL)
1000 0 : return NULL;
1001 :
1002 82342 : if((kd->realm = strdup(realm)) == NULL) {
1003 0 : heim_release(kd);
1004 0 : return NULL;
1005 : }
1006 :
1007 82342 : kd->config_param = config_param;
1008 82342 : kd->srv_label = srv_label;
1009 :
1010 82342 : _krb5_debug(context, 2, "Trying to find service %s for realm %s flags %x",
1011 : service, realm, flags);
1012 :
1013 : /* For 'realms' without a . do not even think of going to DNS */
1014 82342 : if (!strchr(realm, '.'))
1015 10600 : kd->flags |= KD_CONFIG_EXISTS;
1016 :
1017 82342 : if (flags & KRB5_KRBHST_FLAGS_LARGE_MSG)
1018 48982 : kd->flags |= KD_LARGE_MSG;
1019 82342 : kd->end = kd->index = &kd->hosts;
1020 82342 : return kd;
1021 : }
1022 :
1023 : /*
1024 : * initialize `handle' to look for hosts of type `type' in realm `realm'
1025 : */
1026 :
1027 : KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
1028 29 : krb5_krbhst_init(krb5_context context,
1029 : const char *realm,
1030 : unsigned int type,
1031 : krb5_krbhst_handle *handle)
1032 : {
1033 29 : return krb5_krbhst_init_flags(context, realm, type, 0, handle);
1034 : }
1035 :
1036 : KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
1037 82342 : krb5_krbhst_init_flags(krb5_context context,
1038 : const char *realm,
1039 : unsigned int type,
1040 : int flags,
1041 : krb5_krbhst_handle *handle)
1042 : {
1043 3413 : struct krb5_krbhst_data *kd;
1044 3413 : krb5_error_code (*next)(krb5_context, struct krb5_krbhst_data *,
1045 : krb5_krbhst_info **);
1046 3413 : int def_port;
1047 3413 : const char *config_param;
1048 3413 : const char *srv_label;
1049 3413 : const char *service;
1050 :
1051 82342 : *handle = NULL;
1052 :
1053 82342 : switch(type) {
1054 82313 : case KRB5_KRBHST_KDC:
1055 82313 : next = kdc_get_next;
1056 82313 : def_port = ntohs(krb5_getportbyname(context, "kerberos", "udp", 88));
1057 82313 : config_param = "kdc";
1058 82313 : srv_label = "kerberos";
1059 82313 : service = "kdc";
1060 82313 : break;
1061 0 : case KRB5_KRBHST_ADMIN:
1062 0 : next = admin_get_next;
1063 0 : def_port = ntohs(krb5_getportbyname(context, "kerberos-adm",
1064 : "tcp", 749));
1065 0 : config_param = "admin_server";
1066 0 : srv_label = "kerberos-adm";
1067 0 : service = "admin";
1068 0 : break;
1069 0 : case KRB5_KRBHST_READONLY_ADMIN:
1070 0 : next = admin_get_next;
1071 0 : def_port = ntohs(krb5_getportbyname(context, "kerberos-adm",
1072 : "tcp", 749));
1073 0 : config_param = "readonly_admin_server";
1074 0 : srv_label = "kerberos-adm-readonly";
1075 0 : service = "admin";
1076 0 : break;
1077 29 : case KRB5_KRBHST_CHANGEPW:
1078 29 : next = kpasswd_get_next;
1079 29 : def_port = ntohs(krb5_getportbyname(context, "kpasswd", "udp",
1080 : KPASSWD_PORT));
1081 29 : config_param = "kpasswd_server";
1082 29 : srv_label = "kpasswd";
1083 29 : service = "change_password";
1084 29 : break;
1085 0 : case KRB5_KRBHST_TKTBRIDGEAP:
1086 0 : next = kdc_get_next;
1087 0 : def_port = ntohs(krb5_getportbyname(context, "kerberos", "tcp", 88));
1088 0 : config_param = "tktbridgeap";
1089 0 : srv_label = "kerberos-tkt-bridge";
1090 0 : service = "kdc";
1091 0 : break;
1092 0 : default:
1093 0 : krb5_set_error_message(context, ENOTTY,
1094 0 : N_("unknown krbhst type (%u)", ""), type);
1095 0 : return ENOTTY;
1096 : }
1097 82342 : if((kd = common_init(context, config_param, srv_label, service, realm,
1098 : flags)) == NULL)
1099 0 : return ENOMEM;
1100 82342 : kd->get_next = next;
1101 82342 : kd->def_port = def_port;
1102 82342 : *handle = kd;
1103 82342 : return 0;
1104 : }
1105 :
1106 : /*
1107 : * return the next host information from `handle' in `host'
1108 : */
1109 :
1110 : KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
1111 82346 : krb5_krbhst_next(krb5_context context,
1112 : krb5_krbhst_handle handle,
1113 : krb5_krbhst_info **host)
1114 : {
1115 82346 : if(get_next(handle, host))
1116 0 : return 0;
1117 :
1118 82346 : return (*handle->get_next)(context, handle, host);
1119 : }
1120 :
1121 : /*
1122 : * return the next host information from `handle' as a host name
1123 : * in `hostname' (or length `hostlen)
1124 : */
1125 :
1126 : KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
1127 0 : krb5_krbhst_next_as_string(krb5_context context,
1128 : krb5_krbhst_handle handle,
1129 : char *hostname,
1130 : size_t hostlen)
1131 : {
1132 0 : krb5_error_code ret;
1133 0 : krb5_krbhst_info *host;
1134 0 : ret = krb5_krbhst_next(context, handle, &host);
1135 0 : if(ret)
1136 0 : return ret;
1137 0 : return krb5_krbhst_format_string(context, host, hostname, hostlen);
1138 : }
1139 :
1140 : /*
1141 : *
1142 : */
1143 :
1144 : KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
1145 0 : krb5_krbhst_set_hostname(krb5_context context,
1146 : krb5_krbhst_handle handle,
1147 : const char *hostname)
1148 : {
1149 0 : if (handle->hostname)
1150 0 : free(handle->hostname);
1151 0 : handle->hostname = strdup(hostname);
1152 0 : if (handle->hostname == NULL)
1153 0 : return ENOMEM;
1154 0 : return 0;
1155 : }
1156 :
1157 : krb5_error_code KRB5_LIB_FUNCTION
1158 0 : krb5_krbhst_set_sitename(krb5_context context,
1159 : krb5_krbhst_handle handle,
1160 : const char *sitename)
1161 : {
1162 0 : if (handle->sitename)
1163 0 : free(handle->sitename);
1164 0 : handle->sitename = strdup(sitename);
1165 0 : if (handle->sitename == NULL)
1166 0 : return krb5_enomem(context);
1167 0 : return 0;
1168 : }
1169 :
1170 : KRB5_LIB_FUNCTION void KRB5_LIB_CALL
1171 0 : krb5_krbhst_reset(krb5_context context, krb5_krbhst_handle handle)
1172 : {
1173 0 : handle->index = &handle->hosts;
1174 0 : }
1175 :
1176 : KRB5_LIB_FUNCTION void KRB5_LIB_CALL
1177 82342 : krb5_krbhst_free(krb5_context context, krb5_krbhst_handle handle)
1178 : {
1179 82342 : heim_release(handle);
1180 82342 : }
1181 :
1182 : #ifndef HEIMDAL_SMALLER
1183 :
1184 : /* backwards compatibility ahead */
1185 :
1186 : static krb5_error_code
1187 0 : gethostlist(krb5_context context, const char *realm,
1188 : unsigned int type, char ***hostlist)
1189 : {
1190 0 : krb5_error_code ret;
1191 0 : int nhost = 0;
1192 0 : krb5_krbhst_handle handle;
1193 0 : char host[MAXHOSTNAMELEN];
1194 0 : krb5_krbhst_info *hostinfo;
1195 :
1196 0 : ret = krb5_krbhst_init(context, realm, type, &handle);
1197 0 : if (ret)
1198 0 : return ret;
1199 :
1200 0 : while (krb5_krbhst_next(context, handle, &hostinfo) == 0)
1201 0 : nhost++;
1202 0 : if (nhost == 0) {
1203 0 : krb5_set_error_message(context, KRB5_KDC_UNREACH,
1204 0 : N_("No KDC found for realm %s", ""), realm);
1205 0 : krb5_krbhst_free(context, handle);
1206 0 : return KRB5_KDC_UNREACH;
1207 : }
1208 0 : *hostlist = calloc(nhost + 1, sizeof(**hostlist));
1209 0 : if (*hostlist == NULL) {
1210 0 : krb5_krbhst_free(context, handle);
1211 0 : return krb5_enomem(context);
1212 : }
1213 :
1214 0 : krb5_krbhst_reset(context, handle);
1215 0 : nhost = 0;
1216 0 : while (krb5_krbhst_next_as_string(context, handle,
1217 0 : host, sizeof(host)) == 0) {
1218 0 : if (((*hostlist)[nhost++] = strdup(host)) == NULL) {
1219 0 : krb5_free_krbhst(context, *hostlist);
1220 0 : krb5_krbhst_free(context, handle);
1221 0 : return krb5_enomem(context);
1222 : }
1223 : }
1224 0 : (*hostlist)[nhost] = NULL;
1225 0 : krb5_krbhst_free(context, handle);
1226 0 : return 0;
1227 : }
1228 :
1229 : /*
1230 : * Return a malloced list of kadmin-hosts for `realm' in `hostlist'
1231 : */
1232 :
1233 : KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
1234 0 : krb5_get_krb_admin_hst(krb5_context context,
1235 : const krb5_realm *realm,
1236 : char ***hostlist)
1237 : {
1238 0 : return gethostlist(context, *realm, KRB5_KRBHST_ADMIN, hostlist);
1239 : }
1240 :
1241 : /*
1242 : * Return a malloced list of writable kadmin-hosts for `realm' in `hostlist'
1243 : */
1244 :
1245 : KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
1246 0 : krb5_get_krb_readonly_admin_hst(krb5_context context,
1247 : const krb5_realm *realm,
1248 : char ***hostlist)
1249 : {
1250 0 : return gethostlist(context, *realm, KRB5_KRBHST_READONLY_ADMIN, hostlist);
1251 : }
1252 :
1253 : /*
1254 : * return an malloced list of changepw-hosts for `realm' in `hostlist'
1255 : */
1256 :
1257 : KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
1258 0 : krb5_get_krb_changepw_hst (krb5_context context,
1259 : const krb5_realm *realm,
1260 : char ***hostlist)
1261 : {
1262 0 : return gethostlist(context, *realm, KRB5_KRBHST_CHANGEPW, hostlist);
1263 : }
1264 :
1265 : /*
1266 : * return an malloced list of 524-hosts for `realm' in `hostlist'
1267 : */
1268 :
1269 : KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
1270 0 : krb5_get_krb524hst (krb5_context context,
1271 : const krb5_realm *realm,
1272 : char ***hostlist)
1273 : {
1274 0 : return gethostlist(context, *realm, KRB5_KRBHST_KRB524, hostlist);
1275 : }
1276 :
1277 : /*
1278 : * return an malloced list of KDC's for `realm' in `hostlist'
1279 : */
1280 :
1281 : KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
1282 0 : krb5_get_krbhst (krb5_context context,
1283 : const krb5_realm *realm,
1284 : char ***hostlist)
1285 : {
1286 0 : return gethostlist(context, *realm, KRB5_KRBHST_KDC, hostlist);
1287 : }
1288 :
1289 : /*
1290 : * free all the memory allocated in `hostlist'
1291 : */
1292 :
1293 : KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
1294 0 : krb5_free_krbhst (krb5_context context,
1295 : char **hostlist)
1296 : {
1297 0 : char **p;
1298 :
1299 0 : for (p = hostlist; *p; ++p)
1300 0 : free (*p);
1301 0 : free (hostlist);
1302 0 : return 0;
1303 : }
1304 :
1305 : #endif /* HEIMDAL_SMALLER */
|