2 * Copyright (c) 1997 Kungliga Tekniska Högskolan
3 * (Royal Institute of Technology, Stockholm, Sweden).
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
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. All advertising materials mentioning features or use of this software
18 * must display the following acknowledgement:
19 * This product includes software developed by Kungliga Tekniska
20 * Högskolan and its contributors.
22 * 4. Neither the name of the Institute nor the names of its contributors
23 * may be used to endorse or promote products derived from this software
24 * without specific prior written permission.
26 * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
27 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
28 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
29 * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
30 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
31 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
32 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
33 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
34 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
35 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
39 #include "krb5_locl.h"
43 /* Public principal handling functions */
45 #define princ_num_comp(P) ((P)->name.name_string.len)
46 #define princ_type(P) ((P)->name.name_type)
47 #define princ_comp(P) ((P)->name.name_string.val)
48 #define princ_ncomp(P, N) ((P)->name.name_string.val[(N)])
49 #define princ_realm(P) ((P)->realm)
52 krb5_free_principal(krb5_context context
,
62 krb5_parse_name(krb5_context context
,
64 krb5_principal
*principal
)
80 /* count number of component */
82 for(p
= (char*)name
; *p
; p
++){
85 return KRB5_PARSE_MALFORMED
;
90 comp
= calloc(ncomp
, sizeof(*comp
));
93 start
= q
= p
= s
= strdup(name
);
106 }else if(c
== '/' || c
== '@'){
114 return KRB5_PARSE_MALFORMED
;
116 comp
[n
] = malloc(q
- start
+ 1);
117 strncpy(comp
[n
], start
, q
- start
);
118 comp
[n
][q
- start
] = 0;
126 if(got_realm
&& (c
== ':' || c
== '/' || c
== '\0'))
131 realm
= malloc(q
- start
+ 1);
132 strncpy(realm
, start
, q
- start
);
133 realm
[q
- start
] = 0;
135 krb5_get_default_realm (context
, &realm
);
137 comp
[n
] = malloc(q
- start
+ 1);
138 strncpy(comp
[n
], start
, q
- start
);
139 comp
[n
][q
- start
] = 0;
142 *principal
= malloc(sizeof(**principal
));
143 (*principal
)->name
.name_type
= KRB5_NT_PRINCIPAL
;
144 (*principal
)->name
.name_string
.val
= comp
;
145 princ_num_comp(*principal
) = n
;
146 (*principal
)->realm
= realm
;
151 static const char quotable_chars
[] = "\n\t\b\\/@";
152 static const char replace_chars
[] = "ntb\\/@";
154 #define add_char(BASE, INDEX, LEN, C) do { if((INDEX) < (LEN)) (BASE)[(INDEX)++] = (C); }while(0);
157 quote_string(const char *s
, char *out
, size_t index
, size_t len
)
160 for(p
= s
; *p
&& index
< len
; p
++){
161 if((q
= strchr(quotable_chars
, *p
))){
162 add_char(out
, index
, len
, '\\');
163 add_char(out
, index
, len
, replace_chars
[q
- quotable_chars
]);
165 add_char(out
, index
, len
, *p
);
174 krb5_unparse_name_fixed(krb5_context context
,
175 krb5_const_principal principal
,
181 for(i
= 0; i
< princ_num_comp(principal
); i
++){
183 add_char(name
, index
, len
, '/');
184 index
= quote_string(princ_ncomp(principal
, i
), name
, index
, len
);
186 add_char(name
, index
, len
, '@');
187 index
= quote_string(princ_realm(principal
), name
, index
, len
);
189 return ENOMEM
; /* XXX */
194 krb5_unparse_name(krb5_context context
,
195 krb5_const_principal principal
,
198 size_t len
= 0, plen
;
202 plen
= strlen(princ_realm(principal
));
203 if(strcspn(princ_realm(principal
), quotable_chars
) == plen
)
208 for(i
= 0; i
< princ_num_comp(principal
); i
++){
209 plen
= strlen(princ_ncomp(principal
, i
));
210 if(strcspn(princ_ncomp(principal
, i
), quotable_chars
) == plen
)
219 ret
= krb5_unparse_name_fixed(context
, principal
, *name
, len
);
225 #if 0 /* not implemented */
228 krb5_unparse_name_ext(krb5_context context
,
229 krb5_const_principal principal
,
233 fprintf(stderr
, "krb5_unparse_name_ext: not implemented\n");
240 krb5_princ_realm(krb5_context context
,
241 krb5_principal principal
)
243 return &princ_realm(principal
);
248 krb5_princ_set_realm(krb5_context context
,
249 krb5_principal principal
,
252 princ_realm(principal
) = *realm
;
257 krb5_build_principal(krb5_context context
,
258 krb5_principal
*principal
,
260 krb5_const_realm realm
,
266 ret
= krb5_build_principal_va(context
, principal
, rlen
, realm
, ap
);
271 static krb5_error_code
272 append_component(krb5_context context
, krb5_principal p
,
277 size_t len
= princ_num_comp(p
);
278 tmp
= realloc(princ_comp(p
), (len
+ 1) * sizeof(*tmp
));
282 princ_ncomp(p
, len
) = malloc(comp_len
+ 1);
283 memcpy (princ_ncomp(p
, len
), comp
, comp_len
);
284 princ_ncomp(p
, len
)[comp_len
] = '\0';
290 va_ext_princ(krb5_context context
, krb5_principal p
, va_list ap
)
295 len
= va_arg(ap
, int);
298 s
= va_arg(ap
, char*);
299 append_component(context
, p
, s
, len
);
304 va_princ(krb5_context context
, krb5_principal p
, va_list ap
)
308 s
= va_arg(ap
, char*);
311 append_component(context
, p
, s
, strlen(s
));
316 static krb5_error_code
317 build_principal(krb5_context context
,
318 krb5_principal
*principal
,
320 krb5_const_realm realm
,
321 void (*func
)(krb5_context
, krb5_principal
, va_list),
326 p
= calloc(1, sizeof(*p
));
329 princ_type(p
) = KRB5_NT_PRINCIPAL
;
331 princ_realm(p
) = strdup(realm
);
332 if(p
->realm
== NULL
){
337 (*func
)(context
, p
, ap
);
343 krb5_make_principal(krb5_context context
,
344 krb5_principal
*principal
,
345 krb5_const_realm realm
,
352 ret
= krb5_get_default_realm(context
, &r
);
358 ret
= krb5_build_principal_va(context
, principal
, strlen(realm
), realm
, ap
);
366 krb5_build_principal_va(krb5_context context
,
367 krb5_principal
*principal
,
369 krb5_const_realm realm
,
372 return build_principal(context
, principal
, rlen
, realm
, va_princ
, ap
);
376 krb5_build_principal_va_ext(krb5_context context
,
377 krb5_principal
*principal
,
379 krb5_const_realm realm
,
382 return build_principal(context
, principal
, rlen
, realm
, va_ext_princ
, ap
);
387 krb5_build_principal_ext(krb5_context context
,
388 krb5_principal
*principal
,
390 krb5_const_realm realm
,
396 ret
= krb5_build_principal_va_ext(context
, principal
, rlen
, realm
, ap
);
403 krb5_copy_principal(krb5_context context
,
404 krb5_const_principal inprinc
,
405 krb5_principal
*outprinc
)
407 krb5_principal p
= malloc(sizeof(*p
));
410 if(copy_Principal(inprinc
, p
))
418 krb5_principal_compare_any_realm(krb5_context context
,
419 krb5_const_principal princ1
,
420 krb5_const_principal princ2
)
423 if(princ_num_comp(princ1
) != princ_num_comp(princ2
))
425 for(i
= 0; i
< princ_num_comp(princ1
); i
++){
426 if(strcmp(princ_ncomp(princ1
, i
), princ_ncomp(princ2
, i
)) != 0)
433 krb5_principal_compare(krb5_context context
,
434 krb5_const_principal princ1
,
435 krb5_const_principal princ2
)
437 if(!krb5_realm_compare(context
, princ1
, princ2
))
439 return krb5_principal_compare_any_realm(context
, princ1
, princ2
);
444 krb5_realm_compare(krb5_context context
,
445 krb5_const_principal princ1
,
446 krb5_const_principal princ2
)
448 return strcmp(princ_realm(princ1
), princ_realm(princ2
)) == 0;
452 krb5_425_conv_principal_ext(krb5_context context
,
454 const char *instance
,
456 krb5_boolean (*func
)(krb5_context
, krb5_principal
),
457 krb5_boolean resolve
,
458 krb5_principal
*princ
)
465 /* do the following: if the name is found in the
466 `v4_name_convert:host' part, is is assumed to be a `host' type
467 principal, and the instance is looked up in the
468 `v4_instance_convert' part. if not found there the name is
469 (optionally) looked up as a hostname, and if that doesn't yield
470 anything, the `default_domain' is appended to the instance
475 if(instance
[0] == 0){
479 p
= krb5_config_get_string(context
->cf
, "realms", realm
,
480 "v4_name_convert", "host", name
, NULL
);
482 p
= krb5_config_get_string(context
->cf
, "libdefaults",
483 "v4_name_convert", "host", name
, NULL
);
487 p
= krb5_config_get_string(context
->cf
, "realms", realm
,
488 "v4_instance_convert", instance
, NULL
);
491 ret
= krb5_make_principal(context
, &pr
, realm
, name
, instance
, NULL
);
492 if(func
== NULL
|| (*func
)(context
, pr
)){
496 krb5_free_principal(context
, pr
);
498 return HEIM_ERR_V4_PRINC_NO_CONV
;
501 struct hostent
*hp
= roken_gethostbyname(instance
);
503 instance
= hp
->h_name
;
504 ret
= krb5_make_principal(context
, &pr
,
505 realm
, name
, instance
, NULL
);
506 if(func
== NULL
|| (*func
)(context
, pr
)){
510 krb5_free_principal(context
, pr
);
515 domains
= krb5_config_get_strings(context
->cf
, "realms", realm
,
517 for(d
= domains
; d
&& *d
; d
++){
518 snprintf(host
, sizeof(host
), "%s.%s", instance
, *d
);
519 ret
= krb5_make_principal(context
, &pr
, realm
, name
, host
, NULL
);
520 if(func
== NULL
|| (*func
)(context
, pr
)){
522 krb5_config_free_strings(domains
);
525 krb5_free_principal(context
, pr
);
527 krb5_config_free_strings(domains
);
531 p
= krb5_config_get_string(context
->cf
, "realms", realm
,
532 "default_domain", NULL
);
534 /* should this be an error or should it silently
536 return HEIM_ERR_V4_PRINC_NO_CONV
;
539 snprintf(host
, sizeof(host
), "%s.%s", instance
, p
);
540 ret
= krb5_make_principal(context
, &pr
, realm
, name
, host
, NULL
);
541 if(func
== NULL
|| (*func
)(context
, pr
)){
545 krb5_free_principal(context
, pr
);
546 return HEIM_ERR_V4_PRINC_NO_CONV
;
548 p
= krb5_config_get_string(context
->cf
,
556 p
= krb5_config_get_string(context
->cf
,
565 ret
= krb5_make_principal(context
, &pr
, realm
, name
, instance
, NULL
);
566 if(func
== NULL
|| (*func
)(context
, pr
)){
570 krb5_free_principal(context
, pr
);
571 return HEIM_ERR_V4_PRINC_NO_CONV
;
575 krb5_425_conv_principal(krb5_context context
,
577 const char *instance
,
579 krb5_principal
*princ
)
581 krb5_boolean resolve
= krb5_config_get_bool(context
->cf
,
583 "v4_instance_resolve",
586 return krb5_425_conv_principal_ext(context
, name
, instance
, realm
,
587 NULL
, resolve
, princ
);
592 name_convert(krb5_context context
, const char *name
, const char *realm
,
595 const krb5_config_binding
*l
;
596 l
= krb5_config_get_list (context
->cf
,
603 l
= krb5_config_get_list (context
->cf
,
610 if (l
->type
!= krb5_config_string
)
612 if(strcmp(name
, l
->u
.string
) == 0)
620 krb5_524_conv_principal(krb5_context context
,
621 const krb5_principal principal
,
628 int type
= princ_type(principal
);
630 r
= principal
->realm
;
632 switch(principal
->name
.name_string
.len
){
634 n
= principal
->name
.name_string
.val
[0];
638 n
= principal
->name
.name_string
.val
[0];
639 i
= principal
->name
.name_string
.val
[1];
642 return KRB5_PARSE_MALFORMED
;
646 char *tmp
= name_convert(context
, n
, r
, "host");
648 type
= KRB5_NT_SRV_HST
;
651 tmp
= name_convert(context
, n
, r
, "plain");
653 type
= KRB5_NT_UNKNOWN
;
659 if(type
== KRB5_NT_SRV_HST
){
661 strncpy(tmpinst
, i
, sizeof(tmpinst
));
662 tmpinst
[sizeof(tmpinst
) - 1] = 0;
663 p
= strchr(tmpinst
, '.');
669 return KRB5_PARSE_MALFORMED
;
671 return KRB5_PARSE_MALFORMED
;
673 return KRB5_PARSE_MALFORMED
;
683 krb5_sname_to_principal (krb5_context context
,
684 const char *hostname
,
687 krb5_principal
*ret_princ
)
691 char **realms
, *host
= NULL
;
693 if(type
!= KRB5_NT_SRV_HST
&& type
!= KRB5_NT_UNKNOWN
)
694 return KRB5_SNAME_UNSUPP_NAMETYPE
;
695 if(hostname
== NULL
){
696 gethostname(localhost
, sizeof(localhost
));
697 hostname
= localhost
;
701 if(type
== KRB5_NT_SRV_HST
){
703 hp
= roken_gethostbyname(hostname
);
705 hostname
= hp
->h_name
;
707 if(type
== KRB5_NT_SRV_HST
){
708 host
= strdup(hostname
);
715 ret
= krb5_get_host_realm(context
, hostname
, &realms
);
718 ret
= krb5_make_principal(context
, ret_princ
, realms
[0], sname
,
722 krb5_free_host_realm(context
, realms
);