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