Line data Source code
1 : /*
2 : * Copyright (c) 1997 - 2001, 2003 Kungliga Tekniska Högskolan
3 : * (Royal Institute of Technology, Stockholm, Sweden).
4 : * All rights reserved.
5 : *
6 : * Redistribution and use in source and binary forms, with or without
7 : * modification, are permitted provided that the following conditions
8 : * are met:
9 : *
10 : * 1. Redistributions of source code must retain the above copyright
11 : * notice, this list of conditions and the following disclaimer.
12 : *
13 : * 2. Redistributions in binary form must reproduce the above copyright
14 : * notice, this list of conditions and the following disclaimer in the
15 : * documentation and/or other materials provided with the distribution.
16 : *
17 : * 3. Neither the name of the Institute nor the names of its contributors
18 : * may be used to endorse or promote products derived from this software
19 : * without specific prior written permission.
20 : *
21 : * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
22 : * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 : * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24 : * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
25 : * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26 : * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27 : * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28 : * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29 : * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30 : * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31 : * SUCH DAMAGE.
32 : */
33 :
34 : #include "krb5_locl.h"
35 :
36 : /* this is an attempt at one of the most horrible `compression'
37 : schemes that has ever been invented; it's so amazingly brain-dead
38 : that words can not describe it, and all this just to save a few
39 : silly bytes */
40 :
41 : struct tr_realm {
42 : char *realm;
43 : unsigned leading_space:1;
44 : unsigned leading_slash:1;
45 : unsigned trailing_dot:1;
46 : struct tr_realm *next;
47 : };
48 :
49 : static void
50 0 : free_realms(struct tr_realm *r)
51 : {
52 0 : struct tr_realm *p;
53 0 : while(r){
54 0 : p = r;
55 0 : r = r->next;
56 0 : free(p->realm);
57 0 : free(p);
58 : }
59 0 : }
60 :
61 : static int
62 0 : make_path(krb5_context context, struct tr_realm *r,
63 : const char *from, const char *to)
64 : {
65 0 : struct tr_realm *tmp;
66 0 : const char *p;
67 :
68 0 : if(strlen(from) < strlen(to)){
69 0 : const char *str;
70 0 : str = from;
71 0 : from = to;
72 0 : to = str;
73 : }
74 :
75 0 : if(strcmp(from + strlen(from) - strlen(to), to) == 0){
76 0 : p = from;
77 0 : while(1){
78 0 : p = strchr(p, '.');
79 0 : if(p == NULL) {
80 0 : krb5_clear_error_message (context);
81 0 : return KRB5KDC_ERR_POLICY;
82 : }
83 0 : p++;
84 0 : if(strcmp(p, to) == 0)
85 0 : break;
86 0 : tmp = calloc(1, sizeof(*tmp));
87 0 : if(tmp == NULL)
88 0 : return krb5_enomem(context);
89 0 : tmp->next = r->next;
90 0 : r->next = tmp;
91 0 : tmp->realm = strdup(p);
92 0 : if(tmp->realm == NULL){
93 0 : r->next = tmp->next;
94 0 : free(tmp);
95 0 : return krb5_enomem(context);
96 : }
97 : }
98 0 : }else if(strncmp(from, to, strlen(to)) == 0){
99 0 : p = from + strlen(from);
100 0 : while(1){
101 0 : while(p >= from && *p != '/') p--;
102 0 : if(p == from)
103 0 : return KRB5KDC_ERR_POLICY;
104 :
105 0 : if(strncmp(to, from, p - from) == 0)
106 0 : break;
107 0 : tmp = calloc(1, sizeof(*tmp));
108 0 : if(tmp == NULL)
109 0 : return krb5_enomem(context);
110 0 : tmp->next = r->next;
111 0 : r->next = tmp;
112 0 : tmp->realm = malloc(p - from + 1);
113 0 : if(tmp->realm == NULL){
114 0 : r->next = tmp->next;
115 0 : free(tmp);
116 0 : return krb5_enomem(context);
117 : }
118 0 : memcpy(tmp->realm, from, p - from);
119 0 : tmp->realm[p - from] = '\0';
120 0 : p--;
121 : }
122 : } else {
123 0 : krb5_clear_error_message (context);
124 0 : return KRB5KDC_ERR_POLICY;
125 : }
126 :
127 0 : return 0;
128 : }
129 :
130 : static int
131 0 : make_paths(krb5_context context,
132 : struct tr_realm *realms, const char *client_realm,
133 : const char *server_realm)
134 : {
135 0 : struct tr_realm *r;
136 0 : int ret;
137 0 : const char *prev_realm = client_realm;
138 0 : const char *next_realm = NULL;
139 0 : for(r = realms; r; r = r->next){
140 : /* it *might* be that you can have more than one empty
141 : component in a row, at least that's how I interpret the
142 : "," exception in 1510 */
143 0 : if(r->realm[0] == '\0'){
144 0 : while(r->next && r->next->realm[0] == '\0')
145 0 : r = r->next;
146 0 : if(r->next)
147 0 : next_realm = r->next->realm;
148 : else
149 0 : next_realm = server_realm;
150 0 : ret = make_path(context, r, prev_realm, next_realm);
151 0 : if(ret){
152 0 : free_realms(realms);
153 0 : return ret;
154 : }
155 : }
156 0 : prev_realm = r->realm;
157 : }
158 0 : return 0;
159 : }
160 :
161 : static int
162 0 : expand_realms(krb5_context context,
163 : struct tr_realm *realms, const char *client_realm)
164 : {
165 0 : struct tr_realm *r;
166 0 : const char *prev_realm = NULL;
167 0 : for(r = realms; r; r = r->next){
168 0 : if(r->trailing_dot){
169 0 : char *tmp;
170 0 : size_t len;
171 :
172 0 : if(prev_realm == NULL)
173 0 : prev_realm = client_realm;
174 :
175 0 : len = strlen(r->realm) + strlen(prev_realm) + 1;
176 :
177 0 : tmp = realloc(r->realm, len);
178 0 : if(tmp == NULL){
179 0 : free_realms(realms);
180 0 : return krb5_enomem(context);
181 : }
182 0 : r->realm = tmp;
183 0 : strlcat(r->realm, prev_realm, len);
184 0 : }else if(r->leading_slash && !r->leading_space && prev_realm){
185 : /* yet another exception: if you use x500-names, the
186 : leading realm doesn't have to be "quoted" with a space */
187 0 : char *tmp;
188 0 : size_t len = strlen(r->realm) + strlen(prev_realm) + 1;
189 :
190 0 : tmp = malloc(len);
191 0 : if(tmp == NULL){
192 0 : free_realms(realms);
193 0 : return krb5_enomem(context);
194 : }
195 0 : strlcpy(tmp, prev_realm, len);
196 0 : strlcat(tmp, r->realm, len);
197 0 : free(r->realm);
198 0 : r->realm = tmp;
199 : }
200 0 : prev_realm = r->realm;
201 : }
202 0 : return 0;
203 : }
204 :
205 : static struct tr_realm *
206 0 : make_realm(char *realm)
207 : {
208 0 : struct tr_realm *r;
209 0 : char *p, *q;
210 0 : int quote = 0;
211 0 : r = calloc(1, sizeof(*r));
212 0 : if(r == NULL){
213 0 : free(realm);
214 0 : return NULL;
215 : }
216 0 : r->realm = realm;
217 0 : for(p = q = r->realm; *p; p++){
218 0 : if(p == r->realm && *p == ' '){
219 0 : r->leading_space = 1;
220 0 : continue;
221 : }
222 0 : if(q == r->realm && *p == '/')
223 0 : r->leading_slash = 1;
224 0 : if(quote){
225 0 : *q++ = *p;
226 0 : quote = 0;
227 0 : continue;
228 : }
229 0 : if(*p == '\\'){
230 0 : quote = 1;
231 0 : continue;
232 : }
233 0 : if(p[0] == '.' && p[1] == '\0')
234 0 : r->trailing_dot = 1;
235 0 : *q++ = *p;
236 : }
237 0 : *q = '\0';
238 0 : return r;
239 : }
240 :
241 : static struct tr_realm*
242 0 : append_realm(struct tr_realm *head, struct tr_realm *r)
243 : {
244 0 : struct tr_realm *p;
245 0 : if(head == NULL){
246 0 : r->next = NULL;
247 0 : return r;
248 : }
249 0 : p = head;
250 0 : while(p->next) p = p->next;
251 0 : p->next = r;
252 0 : return head;
253 : }
254 :
255 : static int
256 0 : decode_realms(krb5_context context,
257 : const char *tr, int length, struct tr_realm **realms)
258 : {
259 0 : struct tr_realm *r = NULL;
260 :
261 0 : char *tmp;
262 0 : int quote = 0;
263 0 : const char *start = tr;
264 0 : int i;
265 :
266 0 : for(i = 0; i < length; i++){
267 0 : if(quote){
268 0 : quote = 0;
269 0 : continue;
270 : }
271 0 : if(tr[i] == '\\'){
272 0 : quote = 1;
273 0 : continue;
274 : }
275 0 : if(tr[i] == ','){
276 0 : tmp = malloc(tr + i - start + 1);
277 0 : if(tmp == NULL) {
278 0 : free_realms(*realms);
279 0 : *realms = NULL;
280 0 : return krb5_enomem(context);
281 : }
282 0 : memcpy(tmp, start, tr + i - start);
283 0 : tmp[tr + i - start] = '\0';
284 0 : r = make_realm(tmp);
285 0 : if(r == NULL){
286 0 : free_realms(*realms);
287 0 : *realms = NULL;
288 0 : return krb5_enomem(context);
289 : }
290 0 : *realms = append_realm(*realms, r);
291 0 : start = tr + i + 1;
292 : }
293 : }
294 0 : tmp = malloc(tr + i - start + 1);
295 0 : if(tmp == NULL){
296 0 : free_realms(*realms);
297 0 : *realms = NULL;
298 0 : return krb5_enomem(context);
299 : }
300 0 : memcpy(tmp, start, tr + i - start);
301 0 : tmp[tr + i - start] = '\0';
302 0 : r = make_realm(tmp);
303 0 : if(r == NULL){
304 0 : free_realms(*realms);
305 0 : *realms = NULL;
306 0 : return krb5_enomem(context);
307 : }
308 0 : *realms = append_realm(*realms, r);
309 :
310 0 : return 0;
311 : }
312 :
313 :
314 : KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
315 49297 : krb5_domain_x500_decode(krb5_context context,
316 : krb5_data tr, char ***realms, unsigned int *num_realms,
317 : const char *client_realm, const char *server_realm)
318 : {
319 49297 : struct tr_realm *r = NULL;
320 1658 : struct tr_realm *p, **q;
321 1658 : int ret;
322 :
323 49297 : if(tr.length == 0) {
324 49297 : *realms = NULL;
325 49297 : *num_realms = 0;
326 49297 : return 0;
327 : }
328 :
329 : /* split string in components */
330 0 : ret = decode_realms(context, tr.data, tr.length, &r);
331 0 : if(ret)
332 0 : return ret;
333 :
334 : /* apply prefix rule */
335 0 : ret = expand_realms(context, r, client_realm);
336 0 : if(ret)
337 0 : return ret;
338 :
339 0 : ret = make_paths(context, r, client_realm, server_realm);
340 0 : if(ret)
341 0 : return ret;
342 :
343 : /* remove empty components and count realms */
344 0 : *num_realms = 0;
345 0 : for(q = &r; *q; ){
346 0 : if((*q)->realm[0] == '\0'){
347 0 : p = *q;
348 0 : *q = (*q)->next;
349 0 : free(p->realm);
350 0 : free(p);
351 : }else{
352 0 : q = &(*q)->next;
353 0 : (*num_realms)++;
354 : }
355 : }
356 0 : if (*num_realms + 1 > UINT_MAX/sizeof(**realms))
357 0 : return ERANGE;
358 :
359 : {
360 0 : char **R;
361 0 : R = malloc((*num_realms + 1) * sizeof(*R));
362 0 : *realms = R;
363 0 : while(r){
364 0 : *R++ = r->realm;
365 0 : p = r->next;
366 0 : free(r);
367 0 : r = p;
368 : }
369 0 : if (*realms == NULL)
370 0 : return krb5_enomem(context);
371 : }
372 0 : return 0;
373 : }
374 :
375 : KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
376 49297 : krb5_domain_x500_encode(char **realms, unsigned int num_realms,
377 : krb5_data *encoding)
378 : {
379 49297 : char *s = NULL;
380 49297 : int len = 0;
381 1658 : unsigned int i;
382 49297 : krb5_data_zero(encoding);
383 49297 : if (num_realms == 0)
384 47639 : return 0;
385 0 : for(i = 0; i < num_realms; i++){
386 0 : len += strlen(realms[i]);
387 0 : if(realms[i][0] == '/')
388 0 : len++;
389 : }
390 0 : len += num_realms - 1;
391 0 : s = malloc(len + 1);
392 0 : if (s == NULL)
393 0 : return ENOMEM;
394 0 : *s = '\0';
395 0 : for(i = 0; i < num_realms; i++){
396 0 : if(i)
397 0 : strlcat(s, ",", len + 1);
398 0 : if(realms[i][0] == '/')
399 0 : strlcat(s, " ", len + 1);
400 0 : strlcat(s, realms[i], len + 1);
401 : }
402 0 : encoding->data = s;
403 0 : encoding->length = strlen(s);
404 0 : return 0;
405 : }
406 :
407 : KRB5_LIB_FUNCTION void KRB5_LIB_CALL
408 100453 : _krb5_free_capath(krb5_context context, char **capath)
409 : {
410 3316 : char **s;
411 :
412 100609 : for (s = capath; s && *s; ++s)
413 156 : free(*s);
414 100453 : free(capath);
415 100453 : }
416 :
417 : struct hier_iter {
418 : const char *local_realm;
419 : const char *server_realm;
420 : const char *lr; /* Pointer into tail of local realm */
421 : const char *sr; /* Pointer into tail of server realm */
422 : size_t llen; /* Length of local_realm */
423 : size_t slen; /* Length of server_realm */
424 : size_t len; /* Length of common suffix */
425 : size_t num; /* Path element count */
426 : };
427 :
428 : /*
429 : * Step up from local_realm to common suffix, or else down to server_realm.
430 : */
431 : static const char *
432 416 : hier_next(struct hier_iter *state)
433 : {
434 416 : const char *lr = state->lr;
435 416 : const char *sr = state->sr;
436 416 : const char *lsuffix = state->local_realm + state->llen - state->len;
437 416 : const char *server_realm = state->server_realm;
438 :
439 416 : if (lr != NULL) {
440 1344 : while (lr < lsuffix)
441 1240 : if (*lr++ == '.')
442 190 : return state->lr = lr;
443 104 : state->lr = NULL;
444 : }
445 226 : if (sr != NULL) {
446 1252 : while (--sr >= server_realm)
447 1148 : if (sr == server_realm || sr[-1] == '.')
448 122 : return state->sr = sr;
449 104 : state->sr = NULL;
450 : }
451 104 : return NULL;
452 : }
453 :
454 : static void
455 49297 : hier_init(struct hier_iter *state, const char *local_realm, const char *server_realm)
456 : {
457 1658 : size_t llen;
458 1658 : size_t slen;
459 49297 : size_t len = 0;
460 1658 : const char *lr;
461 1658 : const char *sr;
462 :
463 49297 : state->local_realm = local_realm;
464 49297 : state->server_realm = server_realm;
465 49297 : state->llen = llen = strlen(local_realm);
466 49297 : state->slen = slen = strlen(server_realm);
467 49297 : state->len = 0;
468 49297 : state->num = 0;
469 :
470 49297 : if (slen == 0 || llen == 0)
471 0 : return;
472 :
473 : /* Find first difference from the back */
474 49297 : for (lr = local_realm + llen, sr = server_realm + slen;
475 1100093 : lr != local_realm && sr != server_realm;
476 1050796 : --lr, --sr) {
477 1050855 : if (lr[-1] != sr[-1])
478 59 : break;
479 1050796 : if (lr[-1] == '.')
480 123286 : len = llen - (lr - local_realm);
481 : }
482 :
483 : /* Nothing in common? */
484 49297 : if (*lr == '\0')
485 7 : return;
486 :
487 : /* Everything in common? */
488 49290 : if (llen == slen && lr == local_realm)
489 47580 : return;
490 :
491 : /* Is one realm is a suffix of the other? */
492 52 : if ((llen < slen && lr == local_realm && sr[-1] == '.') ||
493 25 : (llen > slen && sr == server_realm && lr[-1] == '.'))
494 0 : len = llen - (lr - local_realm);
495 :
496 52 : state->len = len;
497 : /* `lr` starts at local realm and walks up the tree to common suffix */
498 52 : state->lr = local_realm;
499 : /* `sr` starts at common suffix in server realm and walks down the tree */
500 52 : state->sr = server_realm + slen - len;
501 :
502 : /* Count elements and reset */
503 208 : while (hier_next(state) != NULL)
504 156 : ++state->num;
505 52 : state->lr = local_realm;
506 52 : state->sr = server_realm + slen - len;
507 : }
508 :
509 : /*
510 : * Find a referral path from client_realm to server_realm via local_realm.
511 : * Either via [capaths] or hierarchicaly.
512 : */
513 : KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
514 49297 : _krb5_find_capath(krb5_context context,
515 : const char *client_realm,
516 : const char *local_realm,
517 : const char *server_realm,
518 : krb5_boolean use_hierarchical,
519 : char ***rpath,
520 : size_t *npath)
521 : {
522 1658 : char **confpath;
523 1658 : char **capath;
524 1658 : struct hier_iter hier_state;
525 1658 : char **rp;
526 1658 : const char *r;
527 :
528 49297 : *rpath = NULL;
529 49297 : *npath = 0;
530 :
531 49297 : confpath = krb5_config_get_strings(context, NULL, "capaths",
532 : client_realm, server_realm, NULL);
533 49297 : if (confpath == NULL)
534 49297 : confpath = krb5_config_get_strings(context, NULL, "capaths",
535 : local_realm, server_realm, NULL);
536 : /*
537 : * With a [capaths] setting from the client to the server we look for our
538 : * own realm in the list. If our own realm is not present, we return the
539 : * full list. Otherwise, we return our realm's successors, or possibly
540 : * NULL. Ignoring a [capaths] settings risks loops plus would violate
541 : * explicit policy and the principle of least surpise.
542 : */
543 49297 : if (confpath != NULL) {
544 0 : char **start = confpath;
545 : size_t i;
546 : size_t n;
547 :
548 0 : for (rp = start; *rp; rp++)
549 0 : if (strcmp(*rp, local_realm) == 0)
550 0 : start = rp+1;
551 0 : n = rp - start;
552 :
553 0 : if (n == 0) {
554 0 : krb5_config_free_strings(confpath);
555 0 : return 0;
556 : }
557 :
558 0 : capath = calloc(n + 1, sizeof(*capath));
559 0 : if (capath == NULL) {
560 0 : krb5_config_free_strings(confpath);
561 0 : return krb5_enomem(context);
562 : }
563 :
564 0 : for (i = 0, rp = start; *rp; rp++) {
565 0 : if ((capath[i++] = strdup(*rp)) == NULL) {
566 0 : _krb5_free_capath(context, capath);
567 0 : krb5_config_free_strings(confpath);
568 0 : return krb5_enomem(context);
569 : }
570 : }
571 0 : krb5_config_free_strings(confpath);
572 0 : capath[i] = NULL;
573 0 : *rpath = capath;
574 0 : *npath = n;
575 0 : return 0;
576 : }
577 :
578 : /* The use_hierarchical flag makes hierarchical path lookup unconditional */
579 98594 : if (! use_hierarchical &&
580 49297 : ! krb5_config_get_bool_default(context, NULL, TRUE, "libdefaults",
581 : "allow_hierarchical_capaths", NULL))
582 0 : return 0;
583 :
584 : /*
585 : * When validating transit paths, local_realm == client_realm. Otherwise,
586 : * with hierarchical referrals, they may differ, and we may be building a
587 : * path forward from our own realm!
588 : */
589 49297 : hier_init(&hier_state, local_realm, server_realm);
590 49297 : if (hier_state.num == 0)
591 47587 : return 0;
592 :
593 52 : rp = capath = calloc(hier_state.num + 1, sizeof(*capath));
594 52 : if (capath == NULL)
595 0 : return krb5_enomem(context);
596 208 : while ((r = hier_next(&hier_state)) != NULL) {
597 156 : if ((*rp++ = strdup(r)) == NULL) {
598 0 : _krb5_free_capath(context, capath);
599 0 : return krb5_enomem(context);
600 : }
601 : }
602 :
603 52 : *rp = NULL;
604 52 : *rpath = capath;
605 52 : *npath = hier_state.num;
606 52 : return 0;
607 : }
608 :
609 : KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
610 49297 : krb5_check_transited(krb5_context context,
611 : krb5_const_realm client_realm,
612 : krb5_const_realm server_realm,
613 : krb5_realm *realms,
614 : unsigned int num_realms,
615 : int *bad_realm)
616 : {
617 49297 : krb5_error_code ret = 0;
618 49297 : char **capath = NULL;
619 49297 : size_t num_capath = 0;
620 49297 : size_t i = 0;
621 49297 : size_t j = 0;
622 :
623 : /* In transit checks hierarchical capaths are optional */
624 49297 : ret = _krb5_find_capath(context, client_realm, client_realm, server_realm,
625 : FALSE, &capath, &num_capath);
626 49297 : if (ret)
627 0 : return ret;
628 :
629 49297 : for (i = 0; i < num_realms; i++) {
630 0 : for (j = 0; j < num_capath && capath[j]; ++j) {
631 : /* `capath[j]' can't be NULL, but compilers be dumb */
632 0 : if (strcmp(realms[i], capath[j]) == 0)
633 0 : break;
634 : }
635 0 : if (j == num_capath || !capath[j]) {
636 0 : _krb5_free_capath(context, capath);
637 0 : krb5_set_error_message (context, KRB5KRB_AP_ERR_ILL_CR_TKT,
638 0 : N_("no transit allowed "
639 : "through realm %s from %s to %s", ""),
640 0 : realms[i], client_realm, server_realm);
641 0 : if (bad_realm)
642 0 : *bad_realm = i;
643 0 : return KRB5KRB_AP_ERR_ILL_CR_TKT;
644 : }
645 : }
646 :
647 49297 : _krb5_free_capath(context, capath);
648 49297 : return 0;
649 : }
650 :
651 : KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
652 0 : krb5_check_transited_realms(krb5_context context,
653 : const char *const *realms,
654 : unsigned int num_realms,
655 : int *bad_realm)
656 : {
657 0 : size_t i;
658 0 : int ret = 0;
659 0 : char **bad_realms = krb5_config_get_strings(context, NULL,
660 : "libdefaults",
661 : "transited_realms_reject",
662 : NULL);
663 0 : if(bad_realms == NULL)
664 0 : return 0;
665 :
666 0 : for(i = 0; i < num_realms; i++) {
667 : char **p;
668 0 : for(p = bad_realms; *p; p++)
669 0 : if(strcmp(*p, realms[i]) == 0) {
670 0 : ret = KRB5KRB_AP_ERR_ILL_CR_TKT;
671 0 : krb5_set_error_message (context, ret,
672 0 : N_("no transit allowed "
673 : "through realm %s", ""),
674 : *p);
675 0 : if(bad_realm)
676 0 : *bad_realm = i;
677 0 : break;
678 : }
679 : }
680 0 : krb5_config_free_strings(bad_realms);
681 0 : return ret;
682 : }
683 :
684 : #if 0
685 : int
686 : main(int argc, char **argv)
687 : {
688 : krb5_data x;
689 : char **r;
690 : int num, i;
691 : x.data = argv[1];
692 : x.length = strlen(x.data);
693 : if(domain_expand(x, &r, &num, argv[2], argv[3]))
694 : exit(1);
695 : for(i = 0; i < num; i++)
696 : printf("%s\n", r[i]);
697 : return 0;
698 : }
699 : #endif
|