etc/services - sync with NetBSD-8
[minix.git] / crypto / external / bsd / heimdal / dist / lib / krb5 / principal.c
blob45785471c6d6d538c8f7632f4630574a7e7c054b
1 /* $NetBSD: principal.c,v 1.1.1.2 2014/04/24 12:45:51 pettai Exp $ */
3 /*
4 * Copyright (c) 1997-2007 Kungliga Tekniska Högskolan
5 * (Royal Institute of Technology, Stockholm, Sweden).
6 * All rights reserved.
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
10 * are met:
12 * 1. Redistributions of source code must retain the above copyright
13 * notice, this list of conditions and the following disclaimer.
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.
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.
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.
36 /**
37 * @page krb5_principal_intro The principal handing functions.
39 * A Kerberos principal is a email address looking string that
40 * contains to parts separeted by a @. The later part is the kerbero
41 * realm the principal belongs to and the former is a list of 0 or
42 * more components. For example
43 * @verbatim
44 lha@SU.SE
45 host/hummel.it.su.se@SU.SE
46 host/admin@H5L.ORG
47 @endverbatim
49 * See the library functions here: @ref krb5_principal
52 #include "krb5_locl.h"
53 #ifdef HAVE_RES_SEARCH
54 #define USE_RESOLVER
55 #endif
56 #ifdef HAVE_ARPA_NAMESER_H
57 #include <arpa/nameser.h>
58 #endif
59 #include <fnmatch.h>
60 #include <krb5/resolve.h>
62 #define princ_num_comp(P) ((P)->name.name_string.len)
63 #define princ_type(P) ((P)->name.name_type)
64 #define princ_comp(P) ((P)->name.name_string.val)
65 #define princ_ncomp(P, N) ((P)->name.name_string.val[(N)])
66 #define princ_realm(P) ((P)->realm)
68 /**
69 * Frees a Kerberos principal allocated by the library with
70 * krb5_parse_name(), krb5_make_principal() or any other related
71 * principal functions.
73 * @param context A Kerberos context.
74 * @param p a principal to free.
76 * @return An krb5 error code, see krb5_get_error_message().
78 * @ingroup krb5_principal
81 KRB5_LIB_FUNCTION void KRB5_LIB_CALL
82 krb5_free_principal(krb5_context context,
83 krb5_principal p)
85 if(p){
86 free_Principal(p);
87 free(p);
91 /**
92 * Set the type of the principal
94 * @param context A Kerberos context.
95 * @param principal principal to set the type for
96 * @param type the new type
98 * @return An krb5 error code, see krb5_get_error_message().
100 * @ingroup krb5_principal
103 KRB5_LIB_FUNCTION void KRB5_LIB_CALL
104 krb5_principal_set_type(krb5_context context,
105 krb5_principal principal,
106 int type)
108 princ_type(principal) = type;
112 * Get the type of the principal
114 * @param context A Kerberos context.
115 * @param principal principal to get the type for
117 * @return the type of principal
119 * @ingroup krb5_principal
122 KRB5_LIB_FUNCTION int KRB5_LIB_CALL
123 krb5_principal_get_type(krb5_context context,
124 krb5_const_principal principal)
126 return princ_type(principal);
130 * Get the realm of the principal
132 * @param context A Kerberos context.
133 * @param principal principal to get the realm for
135 * @return realm of the principal, don't free or use after krb5_principal is freed
137 * @ingroup krb5_principal
140 KRB5_LIB_FUNCTION const char* KRB5_LIB_CALL
141 krb5_principal_get_realm(krb5_context context,
142 krb5_const_principal principal)
144 return princ_realm(principal);
147 KRB5_LIB_FUNCTION const char* KRB5_LIB_CALL
148 krb5_principal_get_comp_string(krb5_context context,
149 krb5_const_principal principal,
150 unsigned int component)
152 if(component >= princ_num_comp(principal))
153 return NULL;
154 return princ_ncomp(principal, component);
158 * Get number of component is principal.
160 * @param context Kerberos 5 context
161 * @param principal principal to query
163 * @return number of components in string
165 * @ingroup krb5_principal
168 KRB5_LIB_FUNCTION unsigned int KRB5_LIB_CALL
169 krb5_principal_get_num_comp(krb5_context context,
170 krb5_const_principal principal)
172 return princ_num_comp(principal);
176 * Parse a name into a krb5_principal structure, flags controls the behavior.
178 * @param context Kerberos 5 context
179 * @param name name to parse into a Kerberos principal
180 * @param flags flags to control the behavior
181 * @param principal returned principal, free with krb5_free_principal().
183 * @return An krb5 error code, see krb5_get_error_message().
185 * @ingroup krb5_principal
188 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
189 krb5_parse_name_flags(krb5_context context,
190 const char *name,
191 int flags,
192 krb5_principal *principal)
194 krb5_error_code ret;
195 heim_general_string *comp;
196 heim_general_string realm = NULL;
197 int ncomp;
199 const char *p;
200 char *q;
201 char *s;
202 char *start;
204 int n;
205 char c;
206 int got_realm = 0;
207 int first_at = 1;
208 int enterprise = (flags & KRB5_PRINCIPAL_PARSE_ENTERPRISE);
210 *principal = NULL;
212 #define RFLAGS (KRB5_PRINCIPAL_PARSE_NO_REALM|KRB5_PRINCIPAL_PARSE_REQUIRE_REALM)
214 if ((flags & RFLAGS) == RFLAGS) {
215 krb5_set_error_message(context, KRB5_ERR_NO_SERVICE,
216 N_("Can't require both realm and "
217 "no realm at the same time", ""));
218 return KRB5_ERR_NO_SERVICE;
220 #undef RFLAGS
222 /* count number of component,
223 * enterprise names only have one component
225 ncomp = 1;
226 if (!enterprise) {
227 for(p = name; *p; p++){
228 if(*p=='\\'){
229 if(!p[1]) {
230 krb5_set_error_message(context, KRB5_PARSE_MALFORMED,
231 N_("trailing \\ in principal name", ""));
232 return KRB5_PARSE_MALFORMED;
234 p++;
235 } else if(*p == '/')
236 ncomp++;
237 else if(*p == '@')
238 break;
241 comp = calloc(ncomp, sizeof(*comp));
242 if (comp == NULL) {
243 krb5_set_error_message(context, ENOMEM,
244 N_("malloc: out of memory", ""));
245 return ENOMEM;
248 n = 0;
249 p = start = q = s = strdup(name);
250 if (start == NULL) {
251 free (comp);
252 krb5_set_error_message(context, ENOMEM,
253 N_("malloc: out of memory", ""));
254 return ENOMEM;
256 while(*p){
257 c = *p++;
258 if(c == '\\'){
259 c = *p++;
260 if(c == 'n')
261 c = '\n';
262 else if(c == 't')
263 c = '\t';
264 else if(c == 'b')
265 c = '\b';
266 else if(c == '0')
267 c = '\0';
268 else if(c == '\0') {
269 ret = KRB5_PARSE_MALFORMED;
270 krb5_set_error_message(context, ret,
271 N_("trailing \\ in principal name", ""));
272 goto exit;
274 }else if(enterprise && first_at) {
275 if (c == '@')
276 first_at = 0;
277 }else if((c == '/' && !enterprise) || c == '@'){
278 if(got_realm){
279 ret = KRB5_PARSE_MALFORMED;
280 krb5_set_error_message(context, ret,
281 N_("part after realm in principal name", ""));
282 goto exit;
283 }else{
284 comp[n] = malloc(q - start + 1);
285 if (comp[n] == NULL) {
286 ret = ENOMEM;
287 krb5_set_error_message(context, ret,
288 N_("malloc: out of memory", ""));
289 goto exit;
291 memcpy(comp[n], start, q - start);
292 comp[n][q - start] = 0;
293 n++;
295 if(c == '@')
296 got_realm = 1;
297 start = q;
298 continue;
300 if(got_realm && (c == '/' || c == '\0')) {
301 ret = KRB5_PARSE_MALFORMED;
302 krb5_set_error_message(context, ret,
303 N_("part after realm in principal name", ""));
304 goto exit;
306 *q++ = c;
308 if(got_realm){
309 if (flags & KRB5_PRINCIPAL_PARSE_NO_REALM) {
310 ret = KRB5_PARSE_MALFORMED;
311 krb5_set_error_message(context, ret,
312 N_("realm found in 'short' principal "
313 "expected to be without one", ""));
314 goto exit;
316 realm = malloc(q - start + 1);
317 if (realm == NULL) {
318 ret = ENOMEM;
319 krb5_set_error_message(context, ret,
320 N_("malloc: out of memory", ""));
321 goto exit;
323 memcpy(realm, start, q - start);
324 realm[q - start] = 0;
325 }else{
326 if (flags & KRB5_PRINCIPAL_PARSE_REQUIRE_REALM) {
327 ret = KRB5_PARSE_MALFORMED;
328 krb5_set_error_message(context, ret,
329 N_("realm NOT found in principal "
330 "expected to be with one", ""));
331 goto exit;
332 } else if (flags & KRB5_PRINCIPAL_PARSE_NO_REALM) {
333 realm = NULL;
334 } else {
335 ret = krb5_get_default_realm (context, &realm);
336 if (ret)
337 goto exit;
340 comp[n] = malloc(q - start + 1);
341 if (comp[n] == NULL) {
342 ret = ENOMEM;
343 krb5_set_error_message(context, ret,
344 N_("malloc: out of memory", ""));
345 goto exit;
347 memcpy(comp[n], start, q - start);
348 comp[n][q - start] = 0;
349 n++;
351 *principal = malloc(sizeof(**principal));
352 if (*principal == NULL) {
353 ret = ENOMEM;
354 krb5_set_error_message(context, ret,
355 N_("malloc: out of memory", ""));
356 goto exit;
358 if (enterprise)
359 (*principal)->name.name_type = KRB5_NT_ENTERPRISE_PRINCIPAL;
360 else
361 (*principal)->name.name_type = KRB5_NT_PRINCIPAL;
362 (*principal)->name.name_string.val = comp;
363 princ_num_comp(*principal) = n;
364 (*principal)->realm = realm;
365 free(s);
366 return 0;
367 exit:
368 while(n>0){
369 free(comp[--n]);
371 free(comp);
372 free(realm);
373 free(s);
374 return ret;
378 * Parse a name into a krb5_principal structure
380 * @param context Kerberos 5 context
381 * @param name name to parse into a Kerberos principal
382 * @param principal returned principal, free with krb5_free_principal().
384 * @return An krb5 error code, see krb5_get_error_message().
386 * @ingroup krb5_principal
389 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
390 krb5_parse_name(krb5_context context,
391 const char *name,
392 krb5_principal *principal)
394 return krb5_parse_name_flags(context, name, 0, principal);
397 static const char quotable_chars[] = " \n\t\b\\/@";
398 static const char replace_chars[] = " ntb\\/@";
399 static const char nq_chars[] = " \\/@";
401 #define add_char(BASE, INDEX, LEN, C) do { if((INDEX) < (LEN)) (BASE)[(INDEX)++] = (C); }while(0);
403 static size_t
404 quote_string(const char *s, char *out, size_t idx, size_t len, int display)
406 const char *p, *q;
407 for(p = s; *p && idx < len; p++){
408 q = strchr(quotable_chars, *p);
409 if (q && display) {
410 add_char(out, idx, len, replace_chars[q - quotable_chars]);
411 } else if (q) {
412 add_char(out, idx, len, '\\');
413 add_char(out, idx, len, replace_chars[q - quotable_chars]);
414 }else
415 add_char(out, idx, len, *p);
417 if(idx < len)
418 out[idx] = '\0';
419 return idx;
423 static krb5_error_code
424 unparse_name_fixed(krb5_context context,
425 krb5_const_principal principal,
426 char *name,
427 size_t len,
428 int flags)
430 size_t idx = 0;
431 size_t i;
432 int short_form = (flags & KRB5_PRINCIPAL_UNPARSE_SHORT) != 0;
433 int no_realm = (flags & KRB5_PRINCIPAL_UNPARSE_NO_REALM) != 0;
434 int display = (flags & KRB5_PRINCIPAL_UNPARSE_DISPLAY) != 0;
436 if (!no_realm && princ_realm(principal) == NULL) {
437 krb5_set_error_message(context, ERANGE,
438 N_("Realm missing from principal, "
439 "can't unparse", ""));
440 return ERANGE;
443 for(i = 0; i < princ_num_comp(principal); i++){
444 if(i)
445 add_char(name, idx, len, '/');
446 idx = quote_string(princ_ncomp(principal, i), name, idx, len, display);
447 if(idx == len) {
448 krb5_set_error_message(context, ERANGE,
449 N_("Out of space printing principal", ""));
450 return ERANGE;
453 /* add realm if different from default realm */
454 if(short_form && !no_realm) {
455 krb5_realm r;
456 krb5_error_code ret;
457 ret = krb5_get_default_realm(context, &r);
458 if(ret)
459 return ret;
460 if(strcmp(princ_realm(principal), r) != 0)
461 short_form = 0;
462 free(r);
464 if(!short_form && !no_realm) {
465 add_char(name, idx, len, '@');
466 idx = quote_string(princ_realm(principal), name, idx, len, display);
467 if(idx == len) {
468 krb5_set_error_message(context, ERANGE,
469 N_("Out of space printing "
470 "realm of principal", ""));
471 return ERANGE;
474 return 0;
478 * Unparse the principal name to a fixed buffer
480 * @param context A Kerberos context.
481 * @param principal principal to unparse
482 * @param name buffer to write name to
483 * @param len length of buffer
485 * @return An krb5 error code, see krb5_get_error_message().
487 * @ingroup krb5_principal
490 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
491 krb5_unparse_name_fixed(krb5_context context,
492 krb5_const_principal principal,
493 char *name,
494 size_t len)
496 return unparse_name_fixed(context, principal, name, len, 0);
500 * Unparse the principal name to a fixed buffer. The realm is skipped
501 * if its a default realm.
503 * @param context A Kerberos context.
504 * @param principal principal to unparse
505 * @param name buffer to write name to
506 * @param len length of buffer
508 * @return An krb5 error code, see krb5_get_error_message().
510 * @ingroup krb5_principal
513 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
514 krb5_unparse_name_fixed_short(krb5_context context,
515 krb5_const_principal principal,
516 char *name,
517 size_t len)
519 return unparse_name_fixed(context, principal, name, len,
520 KRB5_PRINCIPAL_UNPARSE_SHORT);
524 * Unparse the principal name with unparse flags to a fixed buffer.
526 * @param context A Kerberos context.
527 * @param principal principal to unparse
528 * @param flags unparse flags
529 * @param name buffer to write name to
530 * @param len length of buffer
532 * @return An krb5 error code, see krb5_get_error_message().
534 * @ingroup krb5_principal
537 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
538 krb5_unparse_name_fixed_flags(krb5_context context,
539 krb5_const_principal principal,
540 int flags,
541 char *name,
542 size_t len)
544 return unparse_name_fixed(context, principal, name, len, flags);
547 static krb5_error_code
548 unparse_name(krb5_context context,
549 krb5_const_principal principal,
550 char **name,
551 int flags)
553 size_t len = 0, plen;
554 size_t i;
555 krb5_error_code ret;
556 /* count length */
557 if (princ_realm(principal)) {
558 plen = strlen(princ_realm(principal));
560 if(strcspn(princ_realm(principal), quotable_chars) == plen)
561 len += plen;
562 else
563 len += 2*plen;
564 len++; /* '@' */
566 for(i = 0; i < princ_num_comp(principal); i++){
567 plen = strlen(princ_ncomp(principal, i));
568 if(strcspn(princ_ncomp(principal, i), quotable_chars) == plen)
569 len += plen;
570 else
571 len += 2*plen;
572 len++;
574 len++; /* '\0' */
575 *name = malloc(len);
576 if(*name == NULL) {
577 krb5_set_error_message(context, ENOMEM,
578 N_("malloc: out of memory", ""));
579 return ENOMEM;
581 ret = unparse_name_fixed(context, principal, *name, len, flags);
582 if(ret) {
583 free(*name);
584 *name = NULL;
586 return ret;
590 * Unparse the Kerberos name into a string
592 * @param context Kerberos 5 context
593 * @param principal principal to query
594 * @param name resulting string, free with krb5_xfree()
596 * @return An krb5 error code, see krb5_get_error_message().
598 * @ingroup krb5_principal
601 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
602 krb5_unparse_name(krb5_context context,
603 krb5_const_principal principal,
604 char **name)
606 return unparse_name(context, principal, name, 0);
610 * Unparse the Kerberos name into a string
612 * @param context Kerberos 5 context
613 * @param principal principal to query
614 * @param flags flag to determine the behavior
615 * @param name resulting string, free with krb5_xfree()
617 * @return An krb5 error code, see krb5_get_error_message().
619 * @ingroup krb5_principal
622 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
623 krb5_unparse_name_flags(krb5_context context,
624 krb5_const_principal principal,
625 int flags,
626 char **name)
628 return unparse_name(context, principal, name, flags);
632 * Unparse the principal name to a allocated buffer. The realm is
633 * skipped if its a default realm.
635 * @param context A Kerberos context.
636 * @param principal principal to unparse
637 * @param name returned buffer, free with krb5_xfree()
639 * @return An krb5 error code, see krb5_get_error_message().
641 * @ingroup krb5_principal
644 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
645 krb5_unparse_name_short(krb5_context context,
646 krb5_const_principal principal,
647 char **name)
649 return unparse_name(context, principal, name, KRB5_PRINCIPAL_UNPARSE_SHORT);
653 * Set a new realm for a principal, and as a side-effect free the
654 * previous realm.
656 * @param context A Kerberos context.
657 * @param principal principal set the realm for
658 * @param realm the new realm to set
660 * @return An krb5 error code, see krb5_get_error_message().
662 * @ingroup krb5_principal
665 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
666 krb5_principal_set_realm(krb5_context context,
667 krb5_principal principal,
668 krb5_const_realm realm)
670 if (princ_realm(principal))
671 free(princ_realm(principal));
673 princ_realm(principal) = strdup(realm);
674 if (princ_realm(principal) == NULL) {
675 krb5_set_error_message(context, ENOMEM,
676 N_("malloc: out of memory", ""));
677 return ENOMEM;
679 return 0;
682 #ifndef HEIMDAL_SMALLER
684 * Build a principal using vararg style building
686 * @param context A Kerberos context.
687 * @param principal returned principal
688 * @param rlen length of realm
689 * @param realm realm name
690 * @param ... a list of components ended with NULL.
692 * @return An krb5 error code, see krb5_get_error_message().
694 * @ingroup krb5_principal
697 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
698 krb5_build_principal(krb5_context context,
699 krb5_principal *principal,
700 int rlen,
701 krb5_const_realm realm,
702 ...)
704 krb5_error_code ret;
705 va_list ap;
706 va_start(ap, realm);
707 ret = krb5_build_principal_va(context, principal, rlen, realm, ap);
708 va_end(ap);
709 return ret;
711 #endif
714 * Build a principal using vararg style building
716 * @param context A Kerberos context.
717 * @param principal returned principal
718 * @param realm realm name
719 * @param ... a list of components ended with NULL.
721 * @return An krb5 error code, see krb5_get_error_message().
723 * @ingroup krb5_principal
726 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
727 krb5_make_principal(krb5_context context,
728 krb5_principal *principal,
729 krb5_const_realm realm,
730 ...)
732 krb5_error_code ret;
733 krb5_realm r = NULL;
734 va_list ap;
735 if(realm == NULL) {
736 ret = krb5_get_default_realm(context, &r);
737 if(ret)
738 return ret;
739 realm = r;
741 va_start(ap, realm);
742 ret = krb5_build_principal_va(context, principal, strlen(realm), realm, ap);
743 va_end(ap);
744 if(r)
745 free(r);
746 return ret;
749 static krb5_error_code
750 append_component(krb5_context context, krb5_principal p,
751 const char *comp,
752 size_t comp_len)
754 heim_general_string *tmp;
755 size_t len = princ_num_comp(p);
757 tmp = realloc(princ_comp(p), (len + 1) * sizeof(*tmp));
758 if(tmp == NULL) {
759 krb5_set_error_message(context, ENOMEM,
760 N_("malloc: out of memory", ""));
761 return ENOMEM;
763 princ_comp(p) = tmp;
764 princ_ncomp(p, len) = malloc(comp_len + 1);
765 if (princ_ncomp(p, len) == NULL) {
766 krb5_set_error_message(context, ENOMEM,
767 N_("malloc: out of memory", ""));
768 return ENOMEM;
770 memcpy (princ_ncomp(p, len), comp, comp_len);
771 princ_ncomp(p, len)[comp_len] = '\0';
772 princ_num_comp(p)++;
773 return 0;
776 static void
777 va_ext_princ(krb5_context context, krb5_principal p, va_list ap)
779 while(1){
780 const char *s;
781 int len;
782 len = va_arg(ap, int);
783 if(len == 0)
784 break;
785 s = va_arg(ap, const char*);
786 append_component(context, p, s, len);
790 static void
791 va_princ(krb5_context context, krb5_principal p, va_list ap)
793 while(1){
794 const char *s;
795 s = va_arg(ap, const char*);
796 if(s == NULL)
797 break;
798 append_component(context, p, s, strlen(s));
802 static krb5_error_code
803 build_principal(krb5_context context,
804 krb5_principal *principal,
805 int rlen,
806 krb5_const_realm realm,
807 void (*func)(krb5_context, krb5_principal, va_list),
808 va_list ap)
810 krb5_principal p;
812 p = calloc(1, sizeof(*p));
813 if (p == NULL) {
814 krb5_set_error_message(context, ENOMEM,
815 N_("malloc: out of memory", ""));
816 return ENOMEM;
818 princ_type(p) = KRB5_NT_PRINCIPAL;
820 princ_realm(p) = strdup(realm);
821 if(p->realm == NULL){
822 free(p);
823 krb5_set_error_message(context, ENOMEM,
824 N_("malloc: out of memory", ""));
825 return ENOMEM;
828 (*func)(context, p, ap);
829 *principal = p;
830 return 0;
833 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
834 krb5_build_principal_va(krb5_context context,
835 krb5_principal *principal,
836 int rlen,
837 krb5_const_realm realm,
838 va_list ap)
840 return build_principal(context, principal, rlen, realm, va_princ, ap);
843 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
844 krb5_build_principal_va_ext(krb5_context context,
845 krb5_principal *principal,
846 int rlen,
847 krb5_const_realm realm,
848 va_list ap)
850 return build_principal(context, principal, rlen, realm, va_ext_princ, ap);
854 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
855 krb5_build_principal_ext(krb5_context context,
856 krb5_principal *principal,
857 int rlen,
858 krb5_const_realm realm,
859 ...)
861 krb5_error_code ret;
862 va_list ap;
863 va_start(ap, realm);
864 ret = krb5_build_principal_va_ext(context, principal, rlen, realm, ap);
865 va_end(ap);
866 return ret;
870 * Copy a principal
872 * @param context A Kerberos context.
873 * @param inprinc principal to copy
874 * @param outprinc copied principal, free with krb5_free_principal()
876 * @return An krb5 error code, see krb5_get_error_message().
878 * @ingroup krb5_principal
882 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
883 krb5_copy_principal(krb5_context context,
884 krb5_const_principal inprinc,
885 krb5_principal *outprinc)
887 krb5_principal p = malloc(sizeof(*p));
888 if (p == NULL) {
889 krb5_set_error_message(context, ENOMEM,
890 N_("malloc: out of memory", ""));
891 return ENOMEM;
893 if(copy_Principal(inprinc, p)) {
894 free(p);
895 krb5_set_error_message(context, ENOMEM,
896 N_("malloc: out of memory", ""));
897 return ENOMEM;
899 *outprinc = p;
900 return 0;
904 * Return TRUE iff princ1 == princ2 (without considering the realm)
906 * @param context Kerberos 5 context
907 * @param princ1 first principal to compare
908 * @param princ2 second principal to compare
910 * @return non zero if equal, 0 if not
912 * @ingroup krb5_principal
913 * @see krb5_principal_compare()
914 * @see krb5_realm_compare()
917 KRB5_LIB_FUNCTION krb5_boolean KRB5_LIB_CALL
918 krb5_principal_compare_any_realm(krb5_context context,
919 krb5_const_principal princ1,
920 krb5_const_principal princ2)
922 size_t i;
923 if(princ_num_comp(princ1) != princ_num_comp(princ2))
924 return FALSE;
925 for(i = 0; i < princ_num_comp(princ1); i++){
926 if(strcmp(princ_ncomp(princ1, i), princ_ncomp(princ2, i)) != 0)
927 return FALSE;
929 return TRUE;
932 KRB5_LIB_FUNCTION krb5_boolean KRB5_LIB_CALL
933 _krb5_principal_compare_PrincipalName(krb5_context context,
934 krb5_const_principal princ1,
935 PrincipalName *princ2)
937 size_t i;
938 if (princ_num_comp(princ1) != princ2->name_string.len)
939 return FALSE;
940 for(i = 0; i < princ_num_comp(princ1); i++){
941 if(strcmp(princ_ncomp(princ1, i), princ2->name_string.val[i]) != 0)
942 return FALSE;
944 return TRUE;
949 * Compares the two principals, including realm of the principals and returns
950 * TRUE if they are the same and FALSE if not.
952 * @param context Kerberos 5 context
953 * @param princ1 first principal to compare
954 * @param princ2 second principal to compare
956 * @ingroup krb5_principal
957 * @see krb5_principal_compare_any_realm()
958 * @see krb5_realm_compare()
962 * return TRUE iff princ1 == princ2
965 KRB5_LIB_FUNCTION krb5_boolean KRB5_LIB_CALL
966 krb5_principal_compare(krb5_context context,
967 krb5_const_principal princ1,
968 krb5_const_principal princ2)
970 if(!krb5_realm_compare(context, princ1, princ2))
971 return FALSE;
972 return krb5_principal_compare_any_realm(context, princ1, princ2);
976 * return TRUE iff realm(princ1) == realm(princ2)
978 * @param context Kerberos 5 context
979 * @param princ1 first principal to compare
980 * @param princ2 second principal to compare
982 * @ingroup krb5_principal
983 * @see krb5_principal_compare_any_realm()
984 * @see krb5_principal_compare()
987 KRB5_LIB_FUNCTION krb5_boolean KRB5_LIB_CALL
988 krb5_realm_compare(krb5_context context,
989 krb5_const_principal princ1,
990 krb5_const_principal princ2)
992 return strcmp(princ_realm(princ1), princ_realm(princ2)) == 0;
996 * return TRUE iff princ matches pattern
998 * @ingroup krb5_principal
1001 KRB5_LIB_FUNCTION krb5_boolean KRB5_LIB_CALL
1002 krb5_principal_match(krb5_context context,
1003 krb5_const_principal princ,
1004 krb5_const_principal pattern)
1006 size_t i;
1007 if(princ_num_comp(princ) != princ_num_comp(pattern))
1008 return FALSE;
1009 if(fnmatch(princ_realm(pattern), princ_realm(princ), 0) != 0)
1010 return FALSE;
1011 for(i = 0; i < princ_num_comp(princ); i++){
1012 if(fnmatch(princ_ncomp(pattern, i), princ_ncomp(princ, i), 0) != 0)
1013 return FALSE;
1015 return TRUE;
1019 * Create a principal for the service running on hostname. If
1020 * KRB5_NT_SRV_HST is used, the hostname is canonization using DNS (or
1021 * some other service), this is potentially insecure.
1023 * @param context A Kerberos context.
1024 * @param hostname hostname to use
1025 * @param sname Service name to use
1026 * @param type name type of pricipal, use KRB5_NT_SRV_HST or KRB5_NT_UNKNOWN.
1027 * @param ret_princ return principal, free with krb5_free_principal().
1029 * @return An krb5 error code, see krb5_get_error_message().
1031 * @ingroup krb5_principal
1034 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
1035 krb5_sname_to_principal (krb5_context context,
1036 const char *hostname,
1037 const char *sname,
1038 int32_t type,
1039 krb5_principal *ret_princ)
1041 krb5_error_code ret;
1042 char localhost[MAXHOSTNAMELEN];
1043 char **realms, *host = NULL;
1045 if(type != KRB5_NT_SRV_HST && type != KRB5_NT_UNKNOWN) {
1046 krb5_set_error_message(context, KRB5_SNAME_UNSUPP_NAMETYPE,
1047 N_("unsupported name type %d", ""),
1048 (int)type);
1049 return KRB5_SNAME_UNSUPP_NAMETYPE;
1051 if(hostname == NULL) {
1052 ret = gethostname(localhost, sizeof(localhost) - 1);
1053 if (ret != 0) {
1054 ret = errno;
1055 krb5_set_error_message(context, ret,
1056 N_("Failed to get local hostname", ""));
1057 return ret;
1059 localhost[sizeof(localhost) - 1] = '\0';
1060 hostname = localhost;
1062 if(sname == NULL)
1063 sname = "host";
1064 if(type == KRB5_NT_SRV_HST) {
1065 ret = krb5_expand_hostname_realms (context, hostname,
1066 &host, &realms);
1067 if (ret)
1068 return ret;
1069 strlwr(host);
1070 hostname = host;
1071 } else {
1072 ret = krb5_get_host_realm(context, hostname, &realms);
1073 if(ret)
1074 return ret;
1077 ret = krb5_make_principal(context, ret_princ, realms[0], sname,
1078 hostname, NULL);
1079 if(host)
1080 free(host);
1081 krb5_free_host_realm(context, realms);
1082 return ret;
1085 static const struct {
1086 const char *type;
1087 int32_t value;
1088 } nametypes[] = {
1089 { "UNKNOWN", KRB5_NT_UNKNOWN },
1090 { "PRINCIPAL", KRB5_NT_PRINCIPAL },
1091 { "SRV_INST", KRB5_NT_SRV_INST },
1092 { "SRV_HST", KRB5_NT_SRV_HST },
1093 { "SRV_XHST", KRB5_NT_SRV_XHST },
1094 { "UID", KRB5_NT_UID },
1095 { "X500_PRINCIPAL", KRB5_NT_X500_PRINCIPAL },
1096 { "SMTP_NAME", KRB5_NT_SMTP_NAME },
1097 { "ENTERPRISE_PRINCIPAL", KRB5_NT_ENTERPRISE_PRINCIPAL },
1098 { "ENT_PRINCIPAL_AND_ID", KRB5_NT_ENT_PRINCIPAL_AND_ID },
1099 { "MS_PRINCIPAL", KRB5_NT_MS_PRINCIPAL },
1100 { "MS_PRINCIPAL_AND_ID", KRB5_NT_MS_PRINCIPAL_AND_ID },
1101 { NULL, 0 }
1105 * Parse nametype string and return a nametype integer
1107 * @ingroup krb5_principal
1110 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
1111 krb5_parse_nametype(krb5_context context, const char *str, int32_t *nametype)
1113 size_t i;
1115 for(i = 0; nametypes[i].type; i++) {
1116 if (strcasecmp(nametypes[i].type, str) == 0) {
1117 *nametype = nametypes[i].value;
1118 return 0;
1121 krb5_set_error_message(context, KRB5_PARSE_MALFORMED,
1122 N_("Failed to find name type %s", ""), str);
1123 return KRB5_PARSE_MALFORMED;
1127 * Check if the cname part of the principal is a krbtgt principal
1129 * @ingroup krb5_principal
1132 KRB5_LIB_FUNCTION krb5_boolean KRB5_LIB_CALL
1133 krb5_principal_is_krbtgt(krb5_context context, krb5_const_principal p)
1135 return p->name.name_string.len == 2 &&
1136 strcmp(p->name.name_string.val[0], KRB5_TGS_NAME) == 0;