No empty .Rs/.Re
[netbsd-mini2440.git] / crypto / dist / heimdal / lib / krb5 / principal.c
blob1d641a8e77b19626ba1364ad980dfecbcdde37c9
1 /*
2 * Copyright (c) 1997-2007 Kungliga Tekniska Högskolan
3 * (Royal Institute of Technology, Stockholm, Sweden).
4 * All rights reserved.
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
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.
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.
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.
34 #include "krb5_locl.h"
35 #ifdef HAVE_RES_SEARCH
36 #define USE_RESOLVER
37 #endif
38 #ifdef HAVE_ARPA_NAMESER_H
39 #include <arpa/nameser.h>
40 #endif
41 #include <fnmatch.h>
42 #include "resolve.h"
44 __RCSID("$Heimdal: principal.c 21741 2007-07-31 16:00:37Z lha $"
45 "$NetBSD$");
47 #define princ_num_comp(P) ((P)->name.name_string.len)
48 #define princ_type(P) ((P)->name.name_type)
49 #define princ_comp(P) ((P)->name.name_string.val)
50 #define princ_ncomp(P, N) ((P)->name.name_string.val[(N)])
51 #define princ_realm(P) ((P)->realm)
53 void KRB5_LIB_FUNCTION
54 krb5_free_principal(krb5_context context,
55 krb5_principal p)
57 if(p){
58 free_Principal(p);
59 free(p);
63 void KRB5_LIB_FUNCTION
64 krb5_principal_set_type(krb5_context context,
65 krb5_principal principal,
66 int type)
68 princ_type(principal) = type;
71 int KRB5_LIB_FUNCTION
72 krb5_principal_get_type(krb5_context context,
73 krb5_const_principal principal)
75 return princ_type(principal);
78 const char* KRB5_LIB_FUNCTION
79 krb5_principal_get_realm(krb5_context context,
80 krb5_const_principal principal)
82 return princ_realm(principal);
85 const char* KRB5_LIB_FUNCTION
86 krb5_principal_get_comp_string(krb5_context context,
87 krb5_const_principal principal,
88 unsigned int component)
90 if(component >= princ_num_comp(principal))
91 return NULL;
92 return princ_ncomp(principal, component);
95 krb5_error_code KRB5_LIB_FUNCTION
96 krb5_parse_name_flags(krb5_context context,
97 const char *name,
98 int flags,
99 krb5_principal *principal)
101 krb5_error_code ret;
102 heim_general_string *comp;
103 heim_general_string realm = NULL;
104 int ncomp;
106 const char *p;
107 char *q;
108 char *s;
109 char *start;
111 int n;
112 char c;
113 int got_realm = 0;
114 int first_at = 1;
115 int enterprise = (flags & KRB5_PRINCIPAL_PARSE_ENTERPRISE);
117 *principal = NULL;
119 #define RFLAGS (KRB5_PRINCIPAL_PARSE_NO_REALM|KRB5_PRINCIPAL_PARSE_MUST_REALM)
121 if ((flags & RFLAGS) == RFLAGS) {
122 krb5_set_error_string(context, "Can't require both realm and "
123 "no realm at the same time");
124 return KRB5_ERR_NO_SERVICE;
126 #undef RFLAGS
128 /* count number of component,
129 * enterprise names only have one component
131 ncomp = 1;
132 if (!enterprise) {
133 for(p = name; *p; p++){
134 if(*p=='\\'){
135 if(!p[1]) {
136 krb5_set_error_string (context,
137 "trailing \\ in principal name");
138 return KRB5_PARSE_MALFORMED;
140 p++;
141 } else if(*p == '/')
142 ncomp++;
143 else if(*p == '@')
144 break;
147 comp = calloc(ncomp, sizeof(*comp));
148 if (comp == NULL) {
149 krb5_set_error_string (context, "malloc: out of memory");
150 return ENOMEM;
153 n = 0;
154 p = start = q = s = strdup(name);
155 if (start == NULL) {
156 free (comp);
157 krb5_set_error_string (context, "malloc: out of memory");
158 return ENOMEM;
160 while(*p){
161 c = *p++;
162 if(c == '\\'){
163 c = *p++;
164 if(c == 'n')
165 c = '\n';
166 else if(c == 't')
167 c = '\t';
168 else if(c == 'b')
169 c = '\b';
170 else if(c == '0')
171 c = '\0';
172 else if(c == '\0') {
173 krb5_set_error_string (context,
174 "trailing \\ in principal name");
175 ret = KRB5_PARSE_MALFORMED;
176 goto exit;
178 }else if(enterprise && first_at) {
179 if (c == '@')
180 first_at = 0;
181 }else if((c == '/' && !enterprise) || c == '@'){
182 if(got_realm){
183 krb5_set_error_string (context,
184 "part after realm in principal name");
185 ret = KRB5_PARSE_MALFORMED;
186 goto exit;
187 }else{
188 comp[n] = malloc(q - start + 1);
189 if (comp[n] == NULL) {
190 krb5_set_error_string (context, "malloc: out of memory");
191 ret = ENOMEM;
192 goto exit;
194 memcpy(comp[n], start, q - start);
195 comp[n][q - start] = 0;
196 n++;
198 if(c == '@')
199 got_realm = 1;
200 start = q;
201 continue;
203 if(got_realm && (c == ':' || c == '/' || c == '\0')) {
204 krb5_set_error_string (context,
205 "part after realm in principal name");
206 ret = KRB5_PARSE_MALFORMED;
207 goto exit;
209 *q++ = c;
211 if(got_realm){
212 if (flags & KRB5_PRINCIPAL_PARSE_NO_REALM) {
213 krb5_set_error_string (context, "realm found in 'short' principal "
214 "expected to be without one");
215 ret = KRB5_PARSE_MALFORMED;
216 goto exit;
218 realm = malloc(q - start + 1);
219 if (realm == NULL) {
220 krb5_set_error_string (context, "malloc: out of memory");
221 ret = ENOMEM;
222 goto exit;
224 memcpy(realm, start, q - start);
225 realm[q - start] = 0;
226 }else{
227 if (flags & KRB5_PRINCIPAL_PARSE_MUST_REALM) {
228 krb5_set_error_string (context, "realm NOT found in principal "
229 "expected to be with one");
230 ret = KRB5_PARSE_MALFORMED;
231 goto exit;
232 } else if (flags & KRB5_PRINCIPAL_PARSE_NO_REALM) {
233 realm = NULL;
234 } else {
235 ret = krb5_get_default_realm (context, &realm);
236 if (ret)
237 goto exit;
240 comp[n] = malloc(q - start + 1);
241 if (comp[n] == NULL) {
242 krb5_set_error_string (context, "malloc: out of memory");
243 ret = ENOMEM;
244 goto exit;
246 memcpy(comp[n], start, q - start);
247 comp[n][q - start] = 0;
248 n++;
250 *principal = malloc(sizeof(**principal));
251 if (*principal == NULL) {
252 krb5_set_error_string (context, "malloc: out of memory");
253 ret = ENOMEM;
254 goto exit;
256 if (enterprise)
257 (*principal)->name.name_type = KRB5_NT_ENTERPRISE_PRINCIPAL;
258 else
259 (*principal)->name.name_type = KRB5_NT_PRINCIPAL;
260 (*principal)->name.name_string.val = comp;
261 princ_num_comp(*principal) = n;
262 (*principal)->realm = realm;
263 free(s);
264 return 0;
265 exit:
266 while(n>0){
267 free(comp[--n]);
269 free(comp);
270 free(realm);
271 free(s);
272 return ret;
275 krb5_error_code KRB5_LIB_FUNCTION
276 krb5_parse_name(krb5_context context,
277 const char *name,
278 krb5_principal *principal)
280 return krb5_parse_name_flags(context, name, 0, principal);
283 static const char quotable_chars[] = " \n\t\b\\/@";
284 static const char replace_chars[] = " ntb\\/@";
285 static const char nq_chars[] = " \\/@";
287 #define add_char(BASE, INDEX, LEN, C) do { if((INDEX) < (LEN)) (BASE)[(INDEX)++] = (C); }while(0);
289 static size_t
290 quote_string(const char *s, char *out, size_t idx, size_t len, int display)
292 const char *p, *q;
293 for(p = s; *p && idx < len; p++){
294 q = strchr(quotable_chars, *p);
295 if (q && display) {
296 add_char(out, idx, len, replace_chars[q - quotable_chars]);
297 } else if (q) {
298 add_char(out, idx, len, '\\');
299 add_char(out, idx, len, replace_chars[q - quotable_chars]);
300 }else
301 add_char(out, idx, len, *p);
303 if(idx < len)
304 out[idx] = '\0';
305 return idx;
309 static krb5_error_code
310 unparse_name_fixed(krb5_context context,
311 krb5_const_principal principal,
312 char *name,
313 size_t len,
314 int flags)
316 size_t idx = 0;
317 int i;
318 int short_form = (flags & KRB5_PRINCIPAL_UNPARSE_SHORT) != 0;
319 int no_realm = (flags & KRB5_PRINCIPAL_UNPARSE_NO_REALM) != 0;
320 int display = (flags & KRB5_PRINCIPAL_UNPARSE_DISPLAY) != 0;
322 if (!no_realm && princ_realm(principal) == NULL) {
323 krb5_set_error_string(context, "Realm missing from principal, "
324 "can't unparse");
325 return ERANGE;
328 for(i = 0; i < princ_num_comp(principal); i++){
329 if(i)
330 add_char(name, idx, len, '/');
331 idx = quote_string(princ_ncomp(principal, i), name, idx, len, display);
332 if(idx == len) {
333 krb5_set_error_string(context, "Out of space printing principal");
334 return ERANGE;
337 /* add realm if different from default realm */
338 if(short_form && !no_realm) {
339 krb5_realm r;
340 krb5_error_code ret;
341 ret = krb5_get_default_realm(context, &r);
342 if(ret)
343 return ret;
344 if(strcmp(princ_realm(principal), r) != 0)
345 short_form = 0;
346 free(r);
348 if(!short_form && !no_realm) {
349 add_char(name, idx, len, '@');
350 idx = quote_string(princ_realm(principal), name, idx, len, display);
351 if(idx == len) {
352 krb5_set_error_string(context,
353 "Out of space printing realm of principal");
354 return ERANGE;
357 return 0;
360 krb5_error_code KRB5_LIB_FUNCTION
361 krb5_unparse_name_fixed(krb5_context context,
362 krb5_const_principal principal,
363 char *name,
364 size_t len)
366 return unparse_name_fixed(context, principal, name, len, 0);
369 krb5_error_code KRB5_LIB_FUNCTION
370 krb5_unparse_name_fixed_short(krb5_context context,
371 krb5_const_principal principal,
372 char *name,
373 size_t len)
375 return unparse_name_fixed(context, principal, name, len,
376 KRB5_PRINCIPAL_UNPARSE_SHORT);
379 krb5_error_code KRB5_LIB_FUNCTION
380 krb5_unparse_name_fixed_flags(krb5_context context,
381 krb5_const_principal principal,
382 int flags,
383 char *name,
384 size_t len)
386 return unparse_name_fixed(context, principal, name, len, flags);
389 static krb5_error_code
390 unparse_name(krb5_context context,
391 krb5_const_principal principal,
392 char **name,
393 int flags)
395 size_t len = 0, plen;
396 int i;
397 krb5_error_code ret;
398 /* count length */
399 if (princ_realm(principal)) {
400 plen = strlen(princ_realm(principal));
402 if(strcspn(princ_realm(principal), quotable_chars) == plen)
403 len += plen;
404 else
405 len += 2*plen;
406 len++; /* '@' */
408 for(i = 0; i < princ_num_comp(principal); i++){
409 plen = strlen(princ_ncomp(principal, i));
410 if(strcspn(princ_ncomp(principal, i), quotable_chars) == plen)
411 len += plen;
412 else
413 len += 2*plen;
414 len++;
416 len++; /* '\0' */
417 *name = malloc(len);
418 if(*name == NULL) {
419 krb5_set_error_string (context, "malloc: out of memory");
420 return ENOMEM;
422 ret = unparse_name_fixed(context, principal, *name, len, flags);
423 if(ret) {
424 free(*name);
425 *name = NULL;
427 return ret;
430 krb5_error_code KRB5_LIB_FUNCTION
431 krb5_unparse_name(krb5_context context,
432 krb5_const_principal principal,
433 char **name)
435 return unparse_name(context, principal, name, 0);
438 krb5_error_code KRB5_LIB_FUNCTION
439 krb5_unparse_name_flags(krb5_context context,
440 krb5_const_principal principal,
441 int flags,
442 char **name)
444 return unparse_name(context, principal, name, flags);
447 krb5_error_code KRB5_LIB_FUNCTION
448 krb5_unparse_name_short(krb5_context context,
449 krb5_const_principal principal,
450 char **name)
452 return unparse_name(context, principal, name, KRB5_PRINCIPAL_UNPARSE_SHORT);
455 #if 0 /* not implemented */
457 krb5_error_code KRB5_LIB_FUNCTION
458 krb5_unparse_name_ext(krb5_context context,
459 krb5_const_principal principal,
460 char **name,
461 size_t *size)
463 krb5_abortx(context, "unimplemented krb5_unparse_name_ext called");
466 #endif
468 krb5_realm * KRB5_LIB_FUNCTION
469 krb5_princ_realm(krb5_context context,
470 krb5_principal principal)
472 return &princ_realm(principal);
476 void KRB5_LIB_FUNCTION
477 krb5_princ_set_realm(krb5_context context,
478 krb5_principal principal,
479 krb5_realm *realm)
481 princ_realm(principal) = *realm;
485 krb5_error_code KRB5_LIB_FUNCTION
486 krb5_build_principal(krb5_context context,
487 krb5_principal *principal,
488 int rlen,
489 krb5_const_realm realm,
490 ...)
492 krb5_error_code ret;
493 va_list ap;
494 va_start(ap, realm);
495 ret = krb5_build_principal_va(context, principal, rlen, realm, ap);
496 va_end(ap);
497 return ret;
500 static krb5_error_code
501 append_component(krb5_context context, krb5_principal p,
502 const char *comp,
503 size_t comp_len)
505 heim_general_string *tmp;
506 size_t len = princ_num_comp(p);
508 tmp = realloc(princ_comp(p), (len + 1) * sizeof(*tmp));
509 if(tmp == NULL) {
510 krb5_set_error_string (context, "malloc: out of memory");
511 return ENOMEM;
513 princ_comp(p) = tmp;
514 princ_ncomp(p, len) = malloc(comp_len + 1);
515 if (princ_ncomp(p, len) == NULL) {
516 krb5_set_error_string (context, "malloc: out of memory");
517 return ENOMEM;
519 memcpy (princ_ncomp(p, len), comp, comp_len);
520 princ_ncomp(p, len)[comp_len] = '\0';
521 princ_num_comp(p)++;
522 return 0;
525 static void
526 va_ext_princ(krb5_context context, krb5_principal p, va_list ap)
528 while(1){
529 const char *s;
530 int len;
531 len = va_arg(ap, int);
532 if(len == 0)
533 break;
534 s = va_arg(ap, const char*);
535 append_component(context, p, s, len);
539 static void
540 va_princ(krb5_context context, krb5_principal p, va_list ap)
542 while(1){
543 const char *s;
544 s = va_arg(ap, const char*);
545 if(s == NULL)
546 break;
547 append_component(context, p, s, strlen(s));
552 static krb5_error_code
553 build_principal(krb5_context context,
554 krb5_principal *principal,
555 int rlen,
556 krb5_const_realm realm,
557 void (*func)(krb5_context, krb5_principal, va_list),
558 va_list ap)
560 krb5_principal p;
562 p = calloc(1, sizeof(*p));
563 if (p == NULL) {
564 krb5_set_error_string (context, "malloc: out of memory");
565 return ENOMEM;
567 princ_type(p) = KRB5_NT_PRINCIPAL;
569 princ_realm(p) = strdup(realm);
570 if(p->realm == NULL){
571 free(p);
572 krb5_set_error_string (context, "malloc: out of memory");
573 return ENOMEM;
576 (*func)(context, p, ap);
577 *principal = p;
578 return 0;
581 krb5_error_code KRB5_LIB_FUNCTION
582 krb5_make_principal(krb5_context context,
583 krb5_principal *principal,
584 krb5_const_realm realm,
585 ...)
587 krb5_error_code ret;
588 krb5_realm r = NULL;
589 va_list ap;
590 if(realm == NULL) {
591 ret = krb5_get_default_realm(context, &r);
592 if(ret)
593 return ret;
594 realm = r;
596 va_start(ap, realm);
597 ret = krb5_build_principal_va(context, principal, strlen(realm), realm, ap);
598 va_end(ap);
599 if(r)
600 free(r);
601 return ret;
604 krb5_error_code KRB5_LIB_FUNCTION
605 krb5_build_principal_va(krb5_context context,
606 krb5_principal *principal,
607 int rlen,
608 krb5_const_realm realm,
609 va_list ap)
611 return build_principal(context, principal, rlen, realm, va_princ, ap);
614 krb5_error_code KRB5_LIB_FUNCTION
615 krb5_build_principal_va_ext(krb5_context context,
616 krb5_principal *principal,
617 int rlen,
618 krb5_const_realm realm,
619 va_list ap)
621 return build_principal(context, principal, rlen, realm, va_ext_princ, ap);
625 krb5_error_code KRB5_LIB_FUNCTION
626 krb5_build_principal_ext(krb5_context context,
627 krb5_principal *principal,
628 int rlen,
629 krb5_const_realm realm,
630 ...)
632 krb5_error_code ret;
633 va_list ap;
634 va_start(ap, realm);
635 ret = krb5_build_principal_va_ext(context, principal, rlen, realm, ap);
636 va_end(ap);
637 return ret;
641 krb5_error_code KRB5_LIB_FUNCTION
642 krb5_copy_principal(krb5_context context,
643 krb5_const_principal inprinc,
644 krb5_principal *outprinc)
646 krb5_principal p = malloc(sizeof(*p));
647 if (p == NULL) {
648 krb5_set_error_string (context, "malloc: out of memory");
649 return ENOMEM;
651 if(copy_Principal(inprinc, p)) {
652 free(p);
653 krb5_set_error_string (context, "malloc: out of memory");
654 return ENOMEM;
656 *outprinc = p;
657 return 0;
661 * return TRUE iff princ1 == princ2 (without considering the realm)
664 krb5_boolean KRB5_LIB_FUNCTION
665 krb5_principal_compare_any_realm(krb5_context context,
666 krb5_const_principal princ1,
667 krb5_const_principal princ2)
669 int i;
670 if(princ_num_comp(princ1) != princ_num_comp(princ2))
671 return FALSE;
672 for(i = 0; i < princ_num_comp(princ1); i++){
673 if(strcmp(princ_ncomp(princ1, i), princ_ncomp(princ2, i)) != 0)
674 return FALSE;
676 return TRUE;
680 * return TRUE iff princ1 == princ2
683 krb5_boolean KRB5_LIB_FUNCTION
684 krb5_principal_compare(krb5_context context,
685 krb5_const_principal princ1,
686 krb5_const_principal princ2)
688 if(!krb5_realm_compare(context, princ1, princ2))
689 return FALSE;
690 return krb5_principal_compare_any_realm(context, princ1, princ2);
694 * return TRUE iff realm(princ1) == realm(princ2)
697 krb5_boolean KRB5_LIB_FUNCTION
698 krb5_realm_compare(krb5_context context,
699 krb5_const_principal princ1,
700 krb5_const_principal princ2)
702 return strcmp(princ_realm(princ1), princ_realm(princ2)) == 0;
706 * return TRUE iff princ matches pattern
709 krb5_boolean KRB5_LIB_FUNCTION
710 krb5_principal_match(krb5_context context,
711 krb5_const_principal princ,
712 krb5_const_principal pattern)
714 int i;
715 if(princ_num_comp(princ) != princ_num_comp(pattern))
716 return FALSE;
717 if(fnmatch(princ_realm(pattern), princ_realm(princ), 0) != 0)
718 return FALSE;
719 for(i = 0; i < princ_num_comp(princ); i++){
720 if(fnmatch(princ_ncomp(pattern, i), princ_ncomp(princ, i), 0) != 0)
721 return FALSE;
723 return TRUE;
727 static struct v4_name_convert {
728 const char *from;
729 const char *to;
730 } default_v4_name_convert[] = {
731 { "ftp", "ftp" },
732 { "hprop", "hprop" },
733 { "pop", "pop" },
734 { "imap", "imap" },
735 { "rcmd", "host" },
736 { "smtp", "smtp" },
737 { NULL, NULL }
741 * return the converted instance name of `name' in `realm'.
742 * look in the configuration file and then in the default set above.
743 * return NULL if no conversion is appropriate.
746 static const char*
747 get_name_conversion(krb5_context context, const char *realm, const char *name)
749 struct v4_name_convert *q;
750 const char *p;
752 p = krb5_config_get_string(context, NULL, "realms", realm,
753 "v4_name_convert", "host", name, NULL);
754 if(p == NULL)
755 p = krb5_config_get_string(context, NULL, "libdefaults",
756 "v4_name_convert", "host", name, NULL);
757 if(p)
758 return p;
760 /* XXX should be possible to override default list */
761 p = krb5_config_get_string(context, NULL,
762 "realms",
763 realm,
764 "v4_name_convert",
765 "plain",
766 name,
767 NULL);
768 if(p)
769 return NULL;
770 p = krb5_config_get_string(context, NULL,
771 "libdefaults",
772 "v4_name_convert",
773 "plain",
774 name,
775 NULL);
776 if(p)
777 return NULL;
778 for(q = default_v4_name_convert; q->from; q++)
779 if(strcmp(q->from, name) == 0)
780 return q->to;
781 return NULL;
785 * convert the v4 principal `name.instance@realm' to a v5 principal in `princ'.
786 * if `resolve', use DNS.
787 * if `func', use that function for validating the conversion
790 krb5_error_code KRB5_LIB_FUNCTION
791 krb5_425_conv_principal_ext2(krb5_context context,
792 const char *name,
793 const char *instance,
794 const char *realm,
795 krb5_boolean (*func)(krb5_context,
796 void *, krb5_principal),
797 void *funcctx,
798 krb5_boolean resolve,
799 krb5_principal *princ)
801 const char *p;
802 krb5_error_code ret;
803 krb5_principal pr;
804 char host[MAXHOSTNAMELEN];
805 char local_hostname[MAXHOSTNAMELEN];
807 /* do the following: if the name is found in the
808 `v4_name_convert:host' part, is assumed to be a `host' type
809 principal, and the instance is looked up in the
810 `v4_instance_convert' part. if not found there the name is
811 (optionally) looked up as a hostname, and if that doesn't yield
812 anything, the `default_domain' is appended to the instance
815 if(instance == NULL)
816 goto no_host;
817 if(instance[0] == 0){
818 instance = NULL;
819 goto no_host;
821 p = get_name_conversion(context, realm, name);
822 if(p == NULL)
823 goto no_host;
824 name = p;
825 p = krb5_config_get_string(context, NULL, "realms", realm,
826 "v4_instance_convert", instance, NULL);
827 if(p){
828 instance = p;
829 ret = krb5_make_principal(context, &pr, realm, name, instance, NULL);
830 if(func == NULL || (*func)(context, funcctx, pr)){
831 *princ = pr;
832 return 0;
834 krb5_free_principal(context, pr);
835 *princ = NULL;
836 krb5_clear_error_string (context);
837 return HEIM_ERR_V4_PRINC_NO_CONV;
839 if(resolve){
840 krb5_boolean passed = FALSE;
841 char *inst = NULL;
842 #ifdef USE_RESOLVER
843 struct dns_reply *r;
845 r = dns_lookup(instance, "aaaa");
846 if (r) {
847 if (r->head && r->head->type == T_AAAA) {
848 inst = strdup(r->head->domain);
849 passed = TRUE;
851 dns_free_data(r);
852 } else {
853 r = dns_lookup(instance, "a");
854 if (r) {
855 if(r->head && r->head->type == T_A) {
856 inst = strdup(r->head->domain);
857 passed = TRUE;
859 dns_free_data(r);
862 #else
863 struct addrinfo hints, *ai;
865 memset (&hints, 0, sizeof(hints));
866 hints.ai_flags = AI_CANONNAME;
867 ret = getaddrinfo(instance, NULL, &hints, &ai);
868 if (ret == 0) {
869 const struct addrinfo *a;
870 for (a = ai; a != NULL; a = a->ai_next) {
871 if (a->ai_canonname != NULL) {
872 inst = strdup (a->ai_canonname);
873 passed = TRUE;
874 break;
877 freeaddrinfo (ai);
879 #endif
880 if (passed) {
881 if (inst == NULL) {
882 krb5_set_error_string (context, "malloc: out of memory");
883 return ENOMEM;
885 strlwr(inst);
886 ret = krb5_make_principal(context, &pr, realm, name, inst,
887 NULL);
888 free (inst);
889 if(ret == 0) {
890 if(func == NULL || (*func)(context, funcctx, pr)){
891 *princ = pr;
892 return 0;
894 krb5_free_principal(context, pr);
898 if(func != NULL) {
899 snprintf(host, sizeof(host), "%s.%s", instance, realm);
900 strlwr(host);
901 ret = krb5_make_principal(context, &pr, realm, name, host, NULL);
902 if((*func)(context, funcctx, pr)){
903 *princ = pr;
904 return 0;
906 krb5_free_principal(context, pr);
910 * if the instance is the first component of the local hostname,
911 * the converted host should be the long hostname.
914 if (func == NULL &&
915 gethostname (local_hostname, sizeof(local_hostname)) == 0 &&
916 strncmp(instance, local_hostname, strlen(instance)) == 0 &&
917 local_hostname[strlen(instance)] == '.') {
918 strlcpy(host, local_hostname, sizeof(host));
919 goto local_host;
923 char **domains, **d;
924 domains = krb5_config_get_strings(context, NULL, "realms", realm,
925 "v4_domains", NULL);
926 for(d = domains; d && *d; d++){
927 snprintf(host, sizeof(host), "%s.%s", instance, *d);
928 ret = krb5_make_principal(context, &pr, realm, name, host, NULL);
929 if(func == NULL || (*func)(context, funcctx, pr)){
930 *princ = pr;
931 krb5_config_free_strings(domains);
932 return 0;
934 krb5_free_principal(context, pr);
936 krb5_config_free_strings(domains);
940 p = krb5_config_get_string(context, NULL, "realms", realm,
941 "default_domain", NULL);
942 if(p == NULL){
943 /* this should be an error, just faking a name is not good */
944 krb5_clear_error_string (context);
945 return HEIM_ERR_V4_PRINC_NO_CONV;
948 if (*p == '.')
949 ++p;
950 snprintf(host, sizeof(host), "%s.%s", instance, p);
951 local_host:
952 ret = krb5_make_principal(context, &pr, realm, name, host, NULL);
953 if(func == NULL || (*func)(context, funcctx, pr)){
954 *princ = pr;
955 return 0;
957 krb5_free_principal(context, pr);
958 krb5_clear_error_string (context);
959 return HEIM_ERR_V4_PRINC_NO_CONV;
960 no_host:
961 p = krb5_config_get_string(context, NULL,
962 "realms",
963 realm,
964 "v4_name_convert",
965 "plain",
966 name,
967 NULL);
968 if(p == NULL)
969 p = krb5_config_get_string(context, NULL,
970 "libdefaults",
971 "v4_name_convert",
972 "plain",
973 name,
974 NULL);
975 if(p)
976 name = p;
978 ret = krb5_make_principal(context, &pr, realm, name, instance, NULL);
979 if(func == NULL || (*func)(context, funcctx, pr)){
980 *princ = pr;
981 return 0;
983 krb5_free_principal(context, pr);
984 krb5_clear_error_string (context);
985 return HEIM_ERR_V4_PRINC_NO_CONV;
988 static krb5_boolean
989 convert_func(krb5_context conxtext, void *funcctx, krb5_principal principal)
991 krb5_boolean (*func)(krb5_context, krb5_principal) = funcctx;
992 return (*func)(conxtext, principal);
995 krb5_error_code KRB5_LIB_FUNCTION
996 krb5_425_conv_principal_ext(krb5_context context,
997 const char *name,
998 const char *instance,
999 const char *realm,
1000 krb5_boolean (*func)(krb5_context, krb5_principal),
1001 krb5_boolean resolve,
1002 krb5_principal *principal)
1004 return krb5_425_conv_principal_ext2(context,
1005 name,
1006 instance,
1007 realm,
1008 func ? convert_func : NULL,
1009 func,
1010 resolve,
1011 principal);
1016 krb5_error_code KRB5_LIB_FUNCTION
1017 krb5_425_conv_principal(krb5_context context,
1018 const char *name,
1019 const char *instance,
1020 const char *realm,
1021 krb5_principal *princ)
1023 krb5_boolean resolve = krb5_config_get_bool(context,
1024 NULL,
1025 "libdefaults",
1026 "v4_instance_resolve",
1027 NULL);
1029 return krb5_425_conv_principal_ext(context, name, instance, realm,
1030 NULL, resolve, princ);
1034 static int
1035 check_list(const krb5_config_binding *l, const char *name, const char **out)
1037 while(l){
1038 if (l->type != krb5_config_string)
1039 continue;
1040 if(strcmp(name, l->u.string) == 0) {
1041 *out = l->name;
1042 return 1;
1044 l = l->next;
1046 return 0;
1049 static int
1050 name_convert(krb5_context context, const char *name, const char *realm,
1051 const char **out)
1053 const krb5_config_binding *l;
1054 l = krb5_config_get_list (context,
1055 NULL,
1056 "realms",
1057 realm,
1058 "v4_name_convert",
1059 "host",
1060 NULL);
1061 if(l && check_list(l, name, out))
1062 return KRB5_NT_SRV_HST;
1063 l = krb5_config_get_list (context,
1064 NULL,
1065 "libdefaults",
1066 "v4_name_convert",
1067 "host",
1068 NULL);
1069 if(l && check_list(l, name, out))
1070 return KRB5_NT_SRV_HST;
1071 l = krb5_config_get_list (context,
1072 NULL,
1073 "realms",
1074 realm,
1075 "v4_name_convert",
1076 "plain",
1077 NULL);
1078 if(l && check_list(l, name, out))
1079 return KRB5_NT_UNKNOWN;
1080 l = krb5_config_get_list (context,
1081 NULL,
1082 "libdefaults",
1083 "v4_name_convert",
1084 "host",
1085 NULL);
1086 if(l && check_list(l, name, out))
1087 return KRB5_NT_UNKNOWN;
1089 /* didn't find it in config file, try built-in list */
1091 struct v4_name_convert *q;
1092 for(q = default_v4_name_convert; q->from; q++) {
1093 if(strcmp(name, q->to) == 0) {
1094 *out = q->from;
1095 return KRB5_NT_SRV_HST;
1099 return -1;
1103 * convert the v5 principal in `principal' into a v4 corresponding one
1104 * in `name, instance, realm'
1105 * this is limited interface since there's no length given for these
1106 * three parameters. They have to be 40 bytes each (ANAME_SZ).
1109 krb5_error_code KRB5_LIB_FUNCTION
1110 krb5_524_conv_principal(krb5_context context,
1111 const krb5_principal principal,
1112 char *name,
1113 char *instance,
1114 char *realm)
1116 const char *n, *i, *r;
1117 char tmpinst[40];
1118 int type = princ_type(principal);
1119 const int aname_sz = 40;
1121 r = principal->realm;
1123 switch(principal->name.name_string.len){
1124 case 1:
1125 n = principal->name.name_string.val[0];
1126 i = "";
1127 break;
1128 case 2:
1129 n = principal->name.name_string.val[0];
1130 i = principal->name.name_string.val[1];
1131 break;
1132 default:
1133 krb5_set_error_string (context,
1134 "cannot convert a %d component principal",
1135 principal->name.name_string.len);
1136 return KRB5_PARSE_MALFORMED;
1140 const char *tmp;
1141 int t = name_convert(context, n, r, &tmp);
1142 if(t >= 0) {
1143 type = t;
1144 n = tmp;
1148 if(type == KRB5_NT_SRV_HST){
1149 char *p;
1151 strlcpy (tmpinst, i, sizeof(tmpinst));
1152 p = strchr(tmpinst, '.');
1153 if(p)
1154 *p = 0;
1155 i = tmpinst;
1158 if (strlcpy (name, n, aname_sz) >= aname_sz) {
1159 krb5_set_error_string (context,
1160 "too long name component to convert");
1161 return KRB5_PARSE_MALFORMED;
1163 if (strlcpy (instance, i, aname_sz) >= aname_sz) {
1164 krb5_set_error_string (context,
1165 "too long instance component to convert");
1166 return KRB5_PARSE_MALFORMED;
1168 if (strlcpy (realm, r, aname_sz) >= aname_sz) {
1169 krb5_set_error_string (context,
1170 "too long realm component to convert");
1171 return KRB5_PARSE_MALFORMED;
1173 return 0;
1177 * Create a principal in `ret_princ' for the service `sname' running
1178 * on host `hostname'. */
1180 krb5_error_code KRB5_LIB_FUNCTION
1181 krb5_sname_to_principal (krb5_context context,
1182 const char *hostname,
1183 const char *sname,
1184 int32_t type,
1185 krb5_principal *ret_princ)
1187 krb5_error_code ret;
1188 char localhost[MAXHOSTNAMELEN];
1189 char **realms, *host = NULL;
1191 if(type != KRB5_NT_SRV_HST && type != KRB5_NT_UNKNOWN) {
1192 krb5_set_error_string (context, "unsupported name type %d",
1193 type);
1194 return KRB5_SNAME_UNSUPP_NAMETYPE;
1196 if(hostname == NULL) {
1197 gethostname(localhost, sizeof(localhost));
1198 hostname = localhost;
1200 if(sname == NULL)
1201 sname = "host";
1202 if(type == KRB5_NT_SRV_HST) {
1203 ret = krb5_expand_hostname_realms (context, hostname,
1204 &host, &realms);
1205 if (ret)
1206 return ret;
1207 strlwr(host);
1208 hostname = host;
1209 } else {
1210 ret = krb5_get_host_realm(context, hostname, &realms);
1211 if(ret)
1212 return ret;
1215 ret = krb5_make_principal(context, ret_princ, realms[0], sname,
1216 hostname, NULL);
1217 if(host)
1218 free(host);
1219 krb5_free_host_realm(context, realms);
1220 return ret;
1223 static const struct {
1224 const char *type;
1225 int32_t value;
1226 } nametypes[] = {
1227 { "UNKNOWN", KRB5_NT_UNKNOWN },
1228 { "PRINCIPAL", KRB5_NT_PRINCIPAL },
1229 { "SRV_INST", KRB5_NT_SRV_INST },
1230 { "SRV_HST", KRB5_NT_SRV_HST },
1231 { "SRV_XHST", KRB5_NT_SRV_XHST },
1232 { "UID", KRB5_NT_UID },
1233 { "X500_PRINCIPAL", KRB5_NT_X500_PRINCIPAL },
1234 { "SMTP_NAME", KRB5_NT_SMTP_NAME },
1235 { "ENTERPRISE_PRINCIPAL", KRB5_NT_ENTERPRISE_PRINCIPAL },
1236 { "ENT_PRINCIPAL_AND_ID", KRB5_NT_ENT_PRINCIPAL_AND_ID },
1237 { "MS_PRINCIPAL", KRB5_NT_MS_PRINCIPAL },
1238 { "MS_PRINCIPAL_AND_ID", KRB5_NT_MS_PRINCIPAL_AND_ID },
1239 { NULL }
1242 krb5_error_code
1243 krb5_parse_nametype(krb5_context context, const char *str, int32_t *nametype)
1245 size_t i;
1247 for(i = 0; nametypes[i].type; i++) {
1248 if (strcasecmp(nametypes[i].type, str) == 0) {
1249 *nametype = nametypes[i].value;
1250 return 0;
1253 krb5_set_error_string(context, "Failed to find name type %s", str);
1254 return KRB5_PARSE_MALFORMED;