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 154 : string_to_proto(const char *string)
42 : {
43 154 : if(strcasecmp(string, "udp") == 0)
44 71 : return KRB5_KRBHST_UDP;
45 83 : else if(strcasecmp(string, "tcp") == 0)
46 47 : 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 46 : is_invalid_tld_srv_target(const char *target)
54 : {
55 46 : return (strncmp("your-dns-needs-immediate-attention.",
56 : target, 35) == 0
57 46 : && 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 154 : 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 154 : *res = NULL;
79 154 : *count = 0;
80 :
81 154 : proto_num = string_to_proto(proto);
82 154 : 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 154 : if(proto_num == KRB5_KRBHST_HTTP)
90 36 : def_port = ntohs(krb5_getportbyname (context, "http", "tcp", 80));
91 118 : else if(port == 0)
92 118 : def_port = ntohs(krb5_getportbyname (context, service, proto, 88));
93 : else
94 0 : def_port = port;
95 :
96 154 : if (sitename)
97 0 : snprintf(domain, sizeof(domain), "_%s._%s.%s._sites.%s.",
98 : service, proto, sitename, realm);
99 : else
100 154 : snprintf(domain, sizeof(domain), "_%s._%s.%s.", service, proto, realm);
101 :
102 154 : r = rk_dns_lookup(domain, dns_type);
103 154 : 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 174 : for(num_srv = 0, rr = r->head; rr; rr = rr->next)
110 92 : if(rr->type == rk_ns_t_srv) {
111 46 : if (num_srv >= INT_MAX) {
112 0 : rk_dns_free_data(r);
113 0 : return KRB5_KDC_UNREACH;
114 : }
115 46 : if (num_srv >= SIZE_MAX / sizeof(**res)) {
116 0 : rk_dns_free_data(r);
117 0 : return KRB5_KDC_UNREACH;
118 : }
119 46 : num_srv++;
120 : }
121 :
122 82 : 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 46 : *res = malloc(num_srv * sizeof(**res));
130 46 : if(*res == NULL) {
131 0 : rk_dns_free_data(r);
132 0 : return krb5_enomem(context);
133 : }
134 :
135 46 : rk_dns_srv_order(r);
136 :
137 138 : for(num_srv = 0, rr = r->head; rr; rr = rr->next)
138 92 : if(rr->type == rk_ns_t_srv) {
139 46 : krb5_krbhst_info *hi = NULL;
140 0 : size_t len;
141 46 : int invalid_tld = 1;
142 :
143 : /* Test for top-level domain controlled interruptions */
144 46 : if (!is_invalid_tld_srv_target(rr->u.srv->target)) {
145 46 : invalid_tld = 0;
146 46 : len = strlen(rr->u.srv->target);
147 46 : hi = calloc(1, sizeof(*hi) + len);
148 : }
149 46 : 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 46 : (*res)[num_srv++] = hi;
166 :
167 46 : hi->proto = proto_num;
168 :
169 46 : hi->def_port = def_port;
170 46 : if (port != 0)
171 0 : hi->port = port;
172 : else
173 46 : hi->port = rr->u.srv->port;
174 :
175 46 : strlcpy(hi->hostname, rr->u.srv->target, len + 1);
176 : }
177 :
178 46 : *count = num_srv;
179 :
180 46 : rk_dns_free_data(r);
181 46 : 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 74233 : krbhst_get_default_proto(struct krb5_krbhst_data *kd)
226 : {
227 74233 : if (kd->flags & KD_LARGE_MSG)
228 48975 : return KRB5_KRBHST_TCP;
229 24088 : 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 74197 : parse_hostspec(krb5_context context, struct krb5_krbhst_data *kd,
255 : const char *spec, int def_port, int port)
256 : {
257 74197 : const char *p = spec, *q;
258 3413 : struct krb5_krbhst_info *hi;
259 :
260 74197 : hi = calloc(1, sizeof(*hi) + strlen(spec));
261 74197 : if(hi == NULL)
262 0 : return NULL;
263 :
264 74197 : hi->proto = krbhst_get_default_proto(kd);
265 :
266 74197 : if(strncmp(p, "http://", 7) == 0){
267 0 : hi->proto = KRB5_KRBHST_HTTP;
268 0 : p += 7;
269 74197 : } 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 74197 : }else if(strncmp(p, "tcp/", 4) == 0){
274 0 : hi->proto = KRB5_KRBHST_TCP;
275 0 : p += 4;
276 74197 : } else if(strncmp(p, "udp/", 4) == 0) {
277 0 : hi->proto = KRB5_KRBHST_UDP;
278 0 : p += 4;
279 : }
280 :
281 74197 : 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 73545 : } 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 74197 : hi->hostname[strcspn(hi->hostname, "/")] = '\0';
297 74197 : strlwr(hi->hostname);
298 :
299 74197 : hi->port = hi->def_port = def_port;
300 74197 : if(p != NULL && p[0]) {
301 3413 : char *end;
302 73218 : hi->port = strtol(p, &end, 0);
303 73218 : if(end == p) {
304 0 : free(hi);
305 0 : return NULL;
306 : }
307 : }
308 74197 : if (port)
309 0 : hi->port = port;
310 70784 : return hi;
311 : }
312 :
313 : KRB5_LIB_FUNCTION void KRB5_LIB_CALL
314 74243 : _krb5_free_krbhst_info(krb5_krbhst_info *hi)
315 : {
316 74243 : if (hi->ai != NULL)
317 73453 : freeaddrinfo(hi->ai);
318 74243 : free(hi);
319 74243 : }
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 74243 : append_host_hostinfo(struct krb5_krbhst_data *kd, struct krb5_krbhst_info *host)
345 : {
346 3413 : struct krb5_krbhst_info *h;
347 :
348 74946 : 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 74156 : if (kd->end)
361 74156 : *kd->end = host;
362 74156 : kd->end = &host->next;
363 : }
364 :
365 : static krb5_error_code
366 74197 : 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 74197 : hi = parse_hostspec(context, kd, host, def_port, port);
372 74197 : if(hi == NULL)
373 0 : return krb5_enomem(context);
374 :
375 74197 : append_host_hostinfo(kd, hi);
376 74197 : 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 73489 : make_hints(struct addrinfo *hints, int proto)
405 : {
406 73489 : memset(hints, 0, sizeof(*hints));
407 73489 : hints->ai_family = AF_UNSPEC;
408 73489 : switch(proto) {
409 24931 : case KRB5_KRBHST_UDP :
410 24931 : hints->ai_socktype = SOCK_DGRAM;
411 24931 : break;
412 48558 : case KRB5_KRBHST_HTTP :
413 : case KRB5_KRBHST_TCP :
414 48558 : hints->ai_socktype = SOCK_STREAM;
415 48558 : break;
416 : }
417 73489 : }
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 73453 : krb5_krbhst_get_addrinfo(krb5_context context, krb5_krbhst_info *host,
431 : struct addrinfo **ai)
432 : {
433 73453 : int ret = 0;
434 :
435 73453 : if (host->ai == NULL) {
436 3413 : struct addrinfo hints;
437 3413 : char portstr[NI_MAXSERV];
438 :
439 73453 : snprintf (portstr, sizeof(portstr), "%d", host->port);
440 73453 : make_hints(&hints, host->proto);
441 :
442 73453 : ret = getaddrinfo(host->hostname, portstr, &hints, &host->ai);
443 73453 : if (ret) {
444 0 : ret = krb5_eai_to_heim_errno(ret, errno);
445 0 : goto out;
446 : }
447 : }
448 0 : out:
449 73453 : *ai = host->ai;
450 73453 : return ret;
451 : }
452 :
453 : static krb5_boolean
454 325105 : get_next(struct krb5_krbhst_data *kd, krb5_krbhst_info **host)
455 : {
456 342170 : struct krb5_krbhst_info *hi = kd ? *kd->index : NULL;
457 314866 : if(hi != NULL) {
458 73453 : *host = hi;
459 73453 : kd->index = &(*kd->index)->next;
460 73453 : return TRUE;
461 : }
462 241413 : return FALSE;
463 : }
464 :
465 : static void
466 154 : srv_get_hosts(krb5_context context, struct krb5_krbhst_data *kd,
467 : const char *sitename, const char *proto, const char *service)
468 : {
469 0 : krb5_error_code ret;
470 0 : krb5_krbhst_info **res;
471 0 : int count, i;
472 :
473 154 : if (krb5_realm_is_lkdc(kd->realm))
474 108 : return;
475 :
476 154 : ret = srv_find_realm(context, &res, &count, kd->realm, "SRV",
477 : sitename, proto, service, kd->port);
478 154 : _krb5_debug(context, 2, "searching DNS for realm %s %s.%s -> %d",
479 : kd->realm, proto, service, ret);
480 154 : if (ret)
481 108 : return;
482 92 : for(i = 0; i < count; i++)
483 46 : append_host_hostinfo(kd, res[i]);
484 46 : free(res);
485 : }
486 :
487 : /*
488 : * read the configuration for `conf_string', defaulting to kd->def_port and
489 : * forcing it to `kd->port' if kd->port != 0
490 : */
491 :
492 : static void
493 81235 : config_get_hosts(krb5_context context, struct krb5_krbhst_data *kd,
494 : const char *conf_string)
495 : {
496 3413 : int i;
497 3413 : char **hostlist;
498 81235 : hostlist = krb5_config_get_strings(context, NULL,
499 : "realms", kd->realm, conf_string, NULL);
500 :
501 81235 : _krb5_debug(context, 2, "configuration file for realm %s%s found",
502 : kd->realm, hostlist ? "" : " not");
503 :
504 81235 : if(hostlist == NULL)
505 7828 : return;
506 73407 : kd->flags |= KD_CONFIG_EXISTS;
507 147604 : for(i = 0; hostlist && hostlist[i] != NULL; i++)
508 74197 : append_host_string(context, kd, hostlist[i], kd->def_port, kd->port);
509 :
510 73407 : krb5_config_free_strings(hostlist);
511 : }
512 :
513 : /*
514 : * as a fallback, look for `serv_string.kd->realm' (typically
515 : * kerberos.REALM, kerberos-1.REALM, ...
516 : * `port' is the default port for the service, and `proto' the
517 : * protocol
518 : */
519 :
520 : static krb5_error_code
521 36 : fallback_get_hosts(krb5_context context, struct krb5_krbhst_data *kd,
522 : const char *serv_string, int port, int proto)
523 : {
524 36 : char *host = NULL;
525 0 : int ret;
526 0 : struct addrinfo *ai;
527 0 : struct addrinfo hints;
528 0 : char portstr[NI_MAXSERV];
529 :
530 36 : ret = krb5_config_get_bool_default(context, NULL, KRB5_FALLBACK_DEFAULT,
531 : "libdefaults", "use_fallback", NULL);
532 36 : if (!ret) {
533 0 : kd->flags |= KD_FALLBACK;
534 0 : return 0;
535 : }
536 :
537 36 : _krb5_debug(context, 2, "fallback lookup %d for realm %s (service %s)",
538 : kd->fallback_count, kd->realm, serv_string);
539 :
540 : /*
541 : * Don't try forever in case the DNS server keep returning us
542 : * entries (like wildcard entries or the .nu TLD)
543 : *
544 : * Also don't try LKDC realms since fallback wont work on them at all.
545 : */
546 36 : if(kd->fallback_count >= 5 || krb5_realm_is_lkdc(kd->realm)) {
547 0 : kd->flags |= KD_FALLBACK;
548 0 : return 0;
549 : }
550 :
551 36 : if(kd->fallback_count == 0)
552 36 : ret = asprintf(&host, "%s.%s.", serv_string, kd->realm);
553 : else
554 0 : ret = asprintf(&host, "%s-%d.%s.",
555 : serv_string, kd->fallback_count, kd->realm);
556 :
557 36 : if (ret < 0 || host == NULL)
558 0 : return krb5_enomem(context);
559 :
560 36 : make_hints(&hints, proto);
561 36 : snprintf(portstr, sizeof(portstr), "%d", port);
562 36 : ret = getaddrinfo(host, portstr, &hints, &ai);
563 36 : if (ret) {
564 : /* no more hosts, so we're done here */
565 36 : free(host);
566 36 : kd->flags |= KD_FALLBACK;
567 : } else {
568 0 : struct krb5_krbhst_info *hi;
569 0 : size_t hostlen;
570 :
571 : /* Check for ICANN gTLD Name Collision address (127.0.53.53) */
572 0 : if (ai->ai_family == AF_INET) {
573 0 : struct sockaddr_in *sin = (struct sockaddr_in *)ai->ai_addr;
574 0 : if (sin->sin_addr.s_addr == htonl(0x7f003535)) {
575 0 : krb5_warnx(context,
576 : "Fallback lookup failed: "
577 : "Realm %s needs immediate attention "
578 : "see https://icann.org/namecollision",
579 : kd->realm);
580 0 : free(host);
581 0 : freeaddrinfo(ai);
582 0 : return KRB5_KDC_UNREACH;
583 : }
584 : }
585 :
586 0 : hostlen = strlen(host);
587 0 : hi = calloc(1, sizeof(*hi) + hostlen);
588 0 : if(hi == NULL) {
589 0 : free(host);
590 0 : freeaddrinfo(ai);
591 0 : return krb5_enomem(context);
592 : }
593 :
594 0 : hi->proto = proto;
595 0 : hi->port = hi->def_port = port;
596 0 : hi->ai = ai;
597 0 : memmove(hi->hostname, host, hostlen);
598 0 : hi->hostname[hostlen] = '\0';
599 0 : free(host);
600 0 : append_host_hostinfo(kd, hi);
601 0 : kd->fallback_count++;
602 : }
603 36 : return 0;
604 : }
605 :
606 : /*
607 : * Fetch hosts from plugin
608 : */
609 :
610 : static krb5_error_code
611 0 : add_plugin_host(struct krb5_krbhst_data *kd,
612 : const char *host,
613 : const char *port,
614 : int portnum,
615 : int proto)
616 : {
617 0 : struct krb5_krbhst_info *hi;
618 0 : struct addrinfo hints, *ai;
619 0 : size_t hostlen;
620 0 : int ret;
621 :
622 0 : make_hints(&hints, proto);
623 0 : ret = getaddrinfo(host, port, &hints, &ai);
624 0 : if (ret)
625 0 : return 0;
626 :
627 0 : hostlen = strlen(host);
628 :
629 0 : hi = calloc(1, sizeof(*hi) + hostlen);
630 0 : if (hi == NULL) {
631 0 : freeaddrinfo(ai);
632 0 : return ENOMEM;
633 : }
634 :
635 0 : hi->proto = proto;
636 0 : hi->port = hi->def_port = portnum;
637 0 : hi->ai = ai;
638 0 : memmove(hi->hostname, host, hostlen);
639 0 : hi->hostname[hostlen] = '\0';
640 0 : append_host_hostinfo(kd, hi);
641 :
642 0 : return 0;
643 : }
644 :
645 : static krb5_error_code
646 0 : add_locate(void *ctx, int type, struct sockaddr *addr)
647 : {
648 0 : struct krb5_krbhst_data *kd = ctx;
649 0 : char host[NI_MAXHOST], port[NI_MAXSERV];
650 0 : socklen_t socklen;
651 0 : krb5_error_code ret;
652 0 : int proto, portnum;
653 :
654 0 : socklen = socket_sockaddr_size(addr);
655 0 : portnum = socket_get_port(addr);
656 :
657 0 : ret = getnameinfo(addr, socklen, host, sizeof(host), port, sizeof(port),
658 : NI_NUMERICHOST|NI_NUMERICSERV);
659 0 : if (ret != 0)
660 0 : return 0;
661 :
662 0 : if (kd->port)
663 0 : snprintf(port, sizeof(port), "%d", kd->port);
664 0 : else if (atoi(port) == 0)
665 0 : snprintf(port, sizeof(port), "%d", krbhst_get_default_port(kd));
666 :
667 0 : proto = krbhst_get_default_proto(kd);
668 :
669 0 : ret = add_plugin_host(kd, host, port, portnum, proto);
670 0 : if (ret)
671 0 : return ret;
672 :
673 : /*
674 : * This is really kind of broken and should be solved a different
675 : * way, some sites block UDP, and we don't, in the general case,
676 : * fall back to TCP, that should also be done. But since that
677 : * should require us to invert the whole "find kdc" stack, let put
678 : * this in for now.
679 : */
680 :
681 0 : if (proto == KRB5_KRBHST_UDP) {
682 0 : ret = add_plugin_host(kd, host, port, portnum, KRB5_KRBHST_TCP);
683 0 : if (ret)
684 0 : return ret;
685 : }
686 :
687 0 : return 0;
688 : }
689 :
690 : struct plctx {
691 : enum locate_service_type type;
692 : struct krb5_krbhst_data *kd;
693 : unsigned long flags;
694 : };
695 :
696 : static KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
697 0 : plcallback(krb5_context context,
698 : const void *plug, void *plugctx, void *userctx)
699 : {
700 0 : const krb5plugin_service_locate_ftable *locate = plug;
701 0 : struct plctx *plctx = userctx;
702 :
703 0 : if (locate->minor_version >= KRB5_PLUGIN_LOCATE_VERSION_2)
704 0 : return locate->lookup(plugctx, plctx->flags, plctx->type, plctx->kd->realm, 0, 0, add_locate, plctx->kd);
705 :
706 0 : if (plctx->flags & KRB5_PLF_ALLOW_HOMEDIR)
707 0 : return locate->old_lookup(plugctx, plctx->type, plctx->kd->realm, 0, 0, add_locate, plctx->kd);
708 :
709 0 : return KRB5_PLUGIN_NO_HANDLE;
710 : }
711 :
712 : static const char *const locate_plugin_deps[] = { "krb5", NULL };
713 :
714 : static const struct heim_plugin_data
715 : locate_plugin_data = {
716 : "krb5",
717 : KRB5_PLUGIN_LOCATE,
718 : KRB5_PLUGIN_LOCATE_VERSION_0,
719 : locate_plugin_deps,
720 : krb5_get_instance
721 : };
722 :
723 : static void
724 81235 : plugin_get_hosts(krb5_context context,
725 : struct krb5_krbhst_data *kd,
726 : enum locate_service_type type)
727 : {
728 81235 : struct plctx ctx = { type, kd, 0 };
729 :
730 81235 : if (_krb5_homedir_access(context))
731 81235 : ctx.flags |= KRB5_PLF_ALLOW_HOMEDIR;
732 :
733 81235 : _krb5_plugin_run_f(context, &locate_plugin_data,
734 : 0, &ctx, plcallback);
735 81235 : }
736 :
737 : /*
738 : *
739 : */
740 :
741 : static void
742 81206 : hostnames_get_hosts(krb5_context context,
743 : struct krb5_krbhst_data *kd,
744 : const char *type)
745 : {
746 81206 : kd->flags |= KD_HOSTNAMES;
747 81206 : if (kd->hostname)
748 0 : append_host_string(context, kd, kd->hostname, kd->def_port, kd->port);
749 81206 : }
750 :
751 :
752 : /*
753 : *
754 : */
755 :
756 : static krb5_error_code
757 81210 : kdc_get_next(krb5_context context,
758 : struct krb5_krbhst_data *kd,
759 : krb5_krbhst_info **host)
760 : {
761 3413 : krb5_error_code ret;
762 :
763 81210 : if ((kd->flags & KD_HOSTNAMES) == 0) {
764 81206 : hostnames_get_hosts(context, kd, "kdc");
765 81206 : if(get_next(kd, host))
766 0 : return 0;
767 : }
768 :
769 81210 : if ((kd->flags & KD_PLUGIN) == 0) {
770 81206 : plugin_get_hosts(context, kd, locate_service_kdc);
771 81206 : kd->flags |= KD_PLUGIN;
772 81206 : if(get_next(kd, host))
773 0 : return 0;
774 : }
775 :
776 81210 : if((kd->flags & KD_CONFIG) == 0) {
777 81206 : config_get_hosts(context, kd, kd->config_param);
778 81206 : kd->flags |= KD_CONFIG;
779 81206 : if(get_next(kd, host))
780 73407 : return 0;
781 : }
782 :
783 7803 : if (kd->flags & KD_CONFIG_EXISTS) {
784 7750 : _krb5_debug(context, 1,
785 : "Configuration exists for realm %s, wont go to DNS",
786 : kd->realm);
787 7750 : return KRB5_KDC_UNREACH;
788 : }
789 :
790 53 : if(context->srv_lookup) {
791 53 : if(kd->sitename && (kd->flags & KD_SITE_SRV_TCP) == 0) {
792 0 : srv_get_hosts(context, kd, kd->sitename, "tcp", "kerberos");
793 0 : kd->flags |= KD_SITE_SRV_TCP;
794 0 : if(get_next(kd, host))
795 0 : return 0;
796 : }
797 :
798 53 : if((kd->flags & KD_SRV_UDP) == 0 && (kd->flags & KD_LARGE_MSG) == 0) {
799 42 : srv_get_hosts(context, kd, NULL, "udp", kd->srv_label);
800 42 : kd->flags |= KD_SRV_UDP;
801 42 : if(get_next(kd, host))
802 6 : return 0;
803 : }
804 :
805 47 : if((kd->flags & KD_SRV_TCP) == 0) {
806 47 : srv_get_hosts(context, kd, NULL, "tcp", kd->srv_label);
807 47 : kd->flags |= KD_SRV_TCP;
808 47 : if(get_next(kd, host))
809 11 : return 0;
810 : }
811 36 : if((kd->flags & KD_SRV_HTTP) == 0) {
812 36 : srv_get_hosts(context, kd, NULL, "http", kd->srv_label);
813 36 : kd->flags |= KD_SRV_HTTP;
814 36 : if(get_next(kd, host))
815 0 : return 0;
816 : }
817 : }
818 :
819 72 : while((kd->flags & KD_FALLBACK) == 0) {
820 36 : ret = fallback_get_hosts(context, kd, "kerberos",
821 : kd->def_port,
822 : krbhst_get_default_proto(kd));
823 36 : if(ret)
824 0 : return ret;
825 36 : if(get_next(kd, host))
826 0 : return 0;
827 : }
828 :
829 36 : _krb5_debug(context, 0, "No KDC entries found for %s", kd->realm);
830 :
831 36 : return KRB5_KDC_UNREACH; /* XXX */
832 : }
833 :
834 : static krb5_error_code
835 0 : admin_get_next(krb5_context context,
836 : struct krb5_krbhst_data *kd,
837 : krb5_krbhst_info **host)
838 : {
839 0 : krb5_error_code ret;
840 :
841 0 : if ((kd->flags & KD_PLUGIN) == 0) {
842 0 : plugin_get_hosts(context, kd, locate_service_kadmin);
843 0 : kd->flags |= KD_PLUGIN;
844 0 : if(get_next(kd, host))
845 0 : return 0;
846 : }
847 :
848 0 : if((kd->flags & KD_CONFIG) == 0) {
849 0 : config_get_hosts(context, kd, kd->config_param);
850 0 : kd->flags |= KD_CONFIG;
851 0 : if(get_next(kd, host))
852 0 : return 0;
853 : }
854 :
855 0 : if (kd->flags & KD_CONFIG_EXISTS) {
856 0 : _krb5_debug(context, 1,
857 : "Configuration exists for realm %s, wont go to DNS",
858 : kd->realm);
859 0 : return KRB5_KDC_UNREACH;
860 : }
861 :
862 0 : if(context->srv_lookup) {
863 0 : if((kd->flags & KD_SRV_TCP) == 0) {
864 0 : srv_get_hosts(context, kd, NULL, "tcp", kd->srv_label);
865 0 : kd->flags |= KD_SRV_TCP;
866 0 : if(get_next(kd, host))
867 0 : return 0;
868 : }
869 : }
870 :
871 0 : if (krbhst_empty(kd)
872 0 : && (kd->flags & KD_FALLBACK) == 0) {
873 0 : ret = fallback_get_hosts(context, kd, "kerberos",
874 : kd->def_port,
875 : krbhst_get_default_proto(kd));
876 0 : if(ret)
877 0 : return ret;
878 0 : kd->flags |= KD_FALLBACK;
879 0 : if(get_next(kd, host))
880 0 : return 0;
881 : }
882 :
883 0 : _krb5_debug(context, 0, "No admin entries found for realm %s", kd->realm);
884 :
885 0 : return KRB5_KDC_UNREACH; /* XXX */
886 : }
887 :
888 : static krb5_error_code
889 29 : kpasswd_get_next(krb5_context context,
890 : struct krb5_krbhst_data *kd,
891 : krb5_krbhst_info **host)
892 : {
893 0 : krb5_error_code ret;
894 :
895 29 : if ((kd->flags & KD_PLUGIN) == 0) {
896 29 : plugin_get_hosts(context, kd, locate_service_kpasswd);
897 29 : kd->flags |= KD_PLUGIN;
898 29 : if(get_next(kd, host))
899 0 : return 0;
900 : }
901 :
902 29 : if((kd->flags & KD_CONFIG) == 0) {
903 29 : config_get_hosts(context, kd, kd->config_param);
904 29 : kd->flags |= KD_CONFIG;
905 29 : if(get_next(kd, host))
906 0 : return 0;
907 : }
908 :
909 29 : if (kd->flags & KD_CONFIG_EXISTS) {
910 0 : _krb5_debug(context, 1,
911 : "Configuration exists for realm %s, wont go to DNS",
912 : kd->realm);
913 0 : return KRB5_KDC_UNREACH;
914 : }
915 :
916 29 : if(context->srv_lookup) {
917 29 : if((kd->flags & KD_SRV_UDP) == 0) {
918 29 : srv_get_hosts(context, kd, NULL, "udp", kd->srv_label);
919 29 : kd->flags |= KD_SRV_UDP;
920 29 : if(get_next(kd, host))
921 29 : return 0;
922 : }
923 0 : if((kd->flags & KD_SRV_TCP) == 0) {
924 0 : srv_get_hosts(context, kd, NULL, "tcp", kd->srv_label);
925 0 : kd->flags |= KD_SRV_TCP;
926 0 : if(get_next(kd, host))
927 0 : return 0;
928 : }
929 : }
930 :
931 : /* no matches -> try admin */
932 :
933 0 : if (krbhst_empty(kd)) {
934 0 : kd->flags = 0;
935 0 : kd->port = kd->def_port;
936 0 : kd->get_next = admin_get_next;
937 0 : ret = (*kd->get_next)(context, kd, host);
938 0 : if (ret == 0)
939 0 : (*host)->proto = krbhst_get_default_proto(kd);
940 0 : return ret;
941 : }
942 :
943 0 : _krb5_debug(context, 0, "No kpasswd entries found for realm %s", kd->realm);
944 :
945 0 : return KRB5_KDC_UNREACH;
946 : }
947 :
948 : static void KRB5_CALLCONV
949 81235 : krbhost_dealloc(void *ptr)
950 : {
951 81235 : struct krb5_krbhst_data *handle = (struct krb5_krbhst_data *)ptr;
952 3413 : krb5_krbhst_info *h, *next;
953 :
954 155391 : for (h = handle->hosts; h != NULL; h = next) {
955 74156 : next = h->next;
956 74156 : _krb5_free_krbhst_info(h);
957 : }
958 81235 : if (handle->hostname)
959 0 : free(handle->hostname);
960 81235 : if (handle->sitename)
961 0 : free(handle->sitename);
962 :
963 81235 : free(handle->realm);
964 81235 : }
965 :
966 : static struct krb5_krbhst_data*
967 81235 : common_init(krb5_context context,
968 : const char *config_param,
969 : const char *srv_label,
970 : const char *service,
971 : const char *realm,
972 : int flags)
973 : {
974 3413 : struct krb5_krbhst_data *kd;
975 :
976 81235 : if ((kd = heim_alloc(sizeof(*kd), "krbhst-context", krbhost_dealloc)) == NULL)
977 0 : return NULL;
978 :
979 81235 : if((kd->realm = strdup(realm)) == NULL) {
980 0 : heim_release(kd);
981 0 : return NULL;
982 : }
983 :
984 81235 : kd->config_param = config_param;
985 81235 : kd->srv_label = srv_label;
986 :
987 81235 : _krb5_debug(context, 2, "Trying to find service %s for realm %s flags %x",
988 : service, realm, flags);
989 :
990 : /* For 'realms' without a . do not even think of going to DNS */
991 81235 : if (!strchr(realm, '.'))
992 10433 : kd->flags |= KD_CONFIG_EXISTS;
993 :
994 81235 : if (flags & KRB5_KRBHST_FLAGS_LARGE_MSG)
995 48558 : kd->flags |= KD_LARGE_MSG;
996 81235 : kd->end = kd->index = &kd->hosts;
997 81235 : return kd;
998 : }
999 :
1000 : /*
1001 : * initialize `handle' to look for hosts of type `type' in realm `realm'
1002 : */
1003 :
1004 : KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
1005 29 : krb5_krbhst_init(krb5_context context,
1006 : const char *realm,
1007 : unsigned int type,
1008 : krb5_krbhst_handle *handle)
1009 : {
1010 29 : return krb5_krbhst_init_flags(context, realm, type, 0, handle);
1011 : }
1012 :
1013 : KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
1014 81235 : krb5_krbhst_init_flags(krb5_context context,
1015 : const char *realm,
1016 : unsigned int type,
1017 : int flags,
1018 : krb5_krbhst_handle *handle)
1019 : {
1020 3413 : struct krb5_krbhst_data *kd;
1021 3413 : krb5_error_code (*next)(krb5_context, struct krb5_krbhst_data *,
1022 : krb5_krbhst_info **);
1023 3413 : int def_port;
1024 3413 : const char *config_param;
1025 3413 : const char *srv_label;
1026 3413 : const char *service;
1027 :
1028 81235 : *handle = NULL;
1029 :
1030 81235 : switch(type) {
1031 81206 : case KRB5_KRBHST_KDC:
1032 81206 : next = kdc_get_next;
1033 81206 : def_port = ntohs(krb5_getportbyname(context, "kerberos", "udp", 88));
1034 81206 : config_param = "kdc";
1035 81206 : srv_label = "kerberos";
1036 81206 : service = "kdc";
1037 81206 : break;
1038 0 : case KRB5_KRBHST_ADMIN:
1039 0 : next = admin_get_next;
1040 0 : def_port = ntohs(krb5_getportbyname(context, "kerberos-adm",
1041 : "tcp", 749));
1042 0 : config_param = "admin_server";
1043 0 : srv_label = "kerberos-adm";
1044 0 : service = "admin";
1045 0 : break;
1046 0 : case KRB5_KRBHST_READONLY_ADMIN:
1047 0 : next = admin_get_next;
1048 0 : def_port = ntohs(krb5_getportbyname(context, "kerberos-adm",
1049 : "tcp", 749));
1050 0 : config_param = "readonly_admin_server";
1051 0 : srv_label = "kerberos-adm-readonly";
1052 0 : service = "admin";
1053 0 : break;
1054 29 : case KRB5_KRBHST_CHANGEPW:
1055 29 : next = kpasswd_get_next;
1056 29 : def_port = ntohs(krb5_getportbyname(context, "kpasswd", "udp",
1057 : KPASSWD_PORT));
1058 29 : config_param = "kpasswd_server";
1059 29 : srv_label = "kpasswd";
1060 29 : service = "change_password";
1061 29 : break;
1062 0 : case KRB5_KRBHST_TKTBRIDGEAP:
1063 0 : next = kdc_get_next;
1064 0 : def_port = ntohs(krb5_getportbyname(context, "kerberos", "tcp", 88));
1065 0 : config_param = "tktbridgeap";
1066 0 : srv_label = "kerberos-tkt-bridge";
1067 0 : service = "kdc";
1068 0 : break;
1069 0 : default:
1070 0 : krb5_set_error_message(context, ENOTTY,
1071 0 : N_("unknown krbhst type (%u)", ""), type);
1072 0 : return ENOTTY;
1073 : }
1074 81235 : if((kd = common_init(context, config_param, srv_label, service, realm,
1075 : flags)) == NULL)
1076 0 : return ENOMEM;
1077 81235 : kd->get_next = next;
1078 81235 : kd->def_port = def_port;
1079 81235 : *handle = kd;
1080 81235 : return 0;
1081 : }
1082 :
1083 : /*
1084 : * return the next host information from `handle' in `host'
1085 : */
1086 :
1087 : KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
1088 81239 : krb5_krbhst_next(krb5_context context,
1089 : krb5_krbhst_handle handle,
1090 : krb5_krbhst_info **host)
1091 : {
1092 81239 : if(get_next(handle, host))
1093 0 : return 0;
1094 :
1095 81239 : return (*handle->get_next)(context, handle, host);
1096 : }
1097 :
1098 : /*
1099 : * return the next host information from `handle' as a host name
1100 : * in `hostname' (or length `hostlen)
1101 : */
1102 :
1103 : KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
1104 0 : krb5_krbhst_next_as_string(krb5_context context,
1105 : krb5_krbhst_handle handle,
1106 : char *hostname,
1107 : size_t hostlen)
1108 : {
1109 0 : krb5_error_code ret;
1110 0 : krb5_krbhst_info *host;
1111 0 : ret = krb5_krbhst_next(context, handle, &host);
1112 0 : if(ret)
1113 0 : return ret;
1114 0 : return krb5_krbhst_format_string(context, host, hostname, hostlen);
1115 : }
1116 :
1117 : /*
1118 : *
1119 : */
1120 :
1121 : KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
1122 0 : krb5_krbhst_set_hostname(krb5_context context,
1123 : krb5_krbhst_handle handle,
1124 : const char *hostname)
1125 : {
1126 0 : if (handle->hostname)
1127 0 : free(handle->hostname);
1128 0 : handle->hostname = strdup(hostname);
1129 0 : if (handle->hostname == NULL)
1130 0 : return ENOMEM;
1131 0 : return 0;
1132 : }
1133 :
1134 : krb5_error_code KRB5_LIB_FUNCTION
1135 0 : krb5_krbhst_set_sitename(krb5_context context,
1136 : krb5_krbhst_handle handle,
1137 : const char *sitename)
1138 : {
1139 0 : if (handle->sitename)
1140 0 : free(handle->sitename);
1141 0 : handle->sitename = strdup(sitename);
1142 0 : if (handle->sitename == NULL)
1143 0 : return krb5_enomem(context);
1144 0 : return 0;
1145 : }
1146 :
1147 : KRB5_LIB_FUNCTION void KRB5_LIB_CALL
1148 0 : krb5_krbhst_reset(krb5_context context, krb5_krbhst_handle handle)
1149 : {
1150 0 : handle->index = &handle->hosts;
1151 0 : }
1152 :
1153 : KRB5_LIB_FUNCTION void KRB5_LIB_CALL
1154 81235 : krb5_krbhst_free(krb5_context context, krb5_krbhst_handle handle)
1155 : {
1156 81235 : heim_release(handle);
1157 81235 : }
1158 :
1159 : #ifndef HEIMDAL_SMALLER
1160 :
1161 : /* backwards compatibility ahead */
1162 :
1163 : static krb5_error_code
1164 0 : gethostlist(krb5_context context, const char *realm,
1165 : unsigned int type, char ***hostlist)
1166 : {
1167 0 : krb5_error_code ret;
1168 0 : int nhost = 0;
1169 0 : krb5_krbhst_handle handle;
1170 0 : char host[MAXHOSTNAMELEN];
1171 0 : krb5_krbhst_info *hostinfo;
1172 :
1173 0 : ret = krb5_krbhst_init(context, realm, type, &handle);
1174 0 : if (ret)
1175 0 : return ret;
1176 :
1177 0 : while (krb5_krbhst_next(context, handle, &hostinfo) == 0)
1178 0 : nhost++;
1179 0 : if (nhost == 0) {
1180 0 : krb5_set_error_message(context, KRB5_KDC_UNREACH,
1181 0 : N_("No KDC found for realm %s", ""), realm);
1182 0 : krb5_krbhst_free(context, handle);
1183 0 : return KRB5_KDC_UNREACH;
1184 : }
1185 0 : *hostlist = calloc(nhost + 1, sizeof(**hostlist));
1186 0 : if (*hostlist == NULL) {
1187 0 : krb5_krbhst_free(context, handle);
1188 0 : return krb5_enomem(context);
1189 : }
1190 :
1191 0 : krb5_krbhst_reset(context, handle);
1192 0 : nhost = 0;
1193 0 : while (krb5_krbhst_next_as_string(context, handle,
1194 0 : host, sizeof(host)) == 0) {
1195 0 : if (((*hostlist)[nhost++] = strdup(host)) == NULL) {
1196 0 : krb5_free_krbhst(context, *hostlist);
1197 0 : krb5_krbhst_free(context, handle);
1198 0 : return krb5_enomem(context);
1199 : }
1200 : }
1201 0 : (*hostlist)[nhost] = NULL;
1202 0 : krb5_krbhst_free(context, handle);
1203 0 : return 0;
1204 : }
1205 :
1206 : /*
1207 : * Return a malloced list of kadmin-hosts for `realm' in `hostlist'
1208 : */
1209 :
1210 : KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
1211 0 : krb5_get_krb_admin_hst(krb5_context context,
1212 : const krb5_realm *realm,
1213 : char ***hostlist)
1214 : {
1215 0 : return gethostlist(context, *realm, KRB5_KRBHST_ADMIN, hostlist);
1216 : }
1217 :
1218 : /*
1219 : * Return a malloced list of writable kadmin-hosts for `realm' in `hostlist'
1220 : */
1221 :
1222 : KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
1223 0 : krb5_get_krb_readonly_admin_hst(krb5_context context,
1224 : const krb5_realm *realm,
1225 : char ***hostlist)
1226 : {
1227 0 : return gethostlist(context, *realm, KRB5_KRBHST_READONLY_ADMIN, hostlist);
1228 : }
1229 :
1230 : /*
1231 : * return an malloced list of changepw-hosts for `realm' in `hostlist'
1232 : */
1233 :
1234 : KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
1235 0 : krb5_get_krb_changepw_hst (krb5_context context,
1236 : const krb5_realm *realm,
1237 : char ***hostlist)
1238 : {
1239 0 : return gethostlist(context, *realm, KRB5_KRBHST_CHANGEPW, hostlist);
1240 : }
1241 :
1242 : /*
1243 : * return an malloced list of 524-hosts for `realm' in `hostlist'
1244 : */
1245 :
1246 : KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
1247 0 : krb5_get_krb524hst (krb5_context context,
1248 : const krb5_realm *realm,
1249 : char ***hostlist)
1250 : {
1251 0 : return gethostlist(context, *realm, KRB5_KRBHST_KRB524, hostlist);
1252 : }
1253 :
1254 : /*
1255 : * return an malloced list of KDC's for `realm' in `hostlist'
1256 : */
1257 :
1258 : KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
1259 0 : krb5_get_krbhst (krb5_context context,
1260 : const krb5_realm *realm,
1261 : char ***hostlist)
1262 : {
1263 0 : return gethostlist(context, *realm, KRB5_KRBHST_KDC, hostlist);
1264 : }
1265 :
1266 : /*
1267 : * free all the memory allocated in `hostlist'
1268 : */
1269 :
1270 : KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
1271 0 : krb5_free_krbhst (krb5_context context,
1272 : char **hostlist)
1273 : {
1274 0 : char **p;
1275 :
1276 0 : for (p = hostlist; *p; ++p)
1277 0 : free (*p);
1278 0 : free (hostlist);
1279 0 : return 0;
1280 : }
1281 :
1282 : #endif /* HEIMDAL_SMALLER */
|