diff options
Diffstat (limited to 'crypto/heimdal/lib/krb5/principal.c')
-rw-r--r-- | crypto/heimdal/lib/krb5/principal.c | 1136 |
1 files changed, 1136 insertions, 0 deletions
diff --git a/crypto/heimdal/lib/krb5/principal.c b/crypto/heimdal/lib/krb5/principal.c new file mode 100644 index 0000000..a10d2d0 --- /dev/null +++ b/crypto/heimdal/lib/krb5/principal.c @@ -0,0 +1,1136 @@ +/* + * Copyright (c) 1997-2007 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/** + * @page krb5_principal_intro The principal handing functions. + * + * A Kerberos principal is a email address looking string that + * contains to parts separeted by a @. The later part is the kerbero + * realm the principal belongs to and the former is a list of 0 or + * more components. For example + * @verbatim +lha@SU.SE +host/hummel.it.su.se@SU.SE +host/admin@H5L.ORG +@endverbatim + * + * See the library functions here: @ref krb5_principal + */ + +#include "krb5_locl.h" +#ifdef HAVE_RES_SEARCH +#define USE_RESOLVER +#endif +#ifdef HAVE_ARPA_NAMESER_H +#include <arpa/nameser.h> +#endif +#include <fnmatch.h> +#include "resolve.h" + +#define princ_num_comp(P) ((P)->name.name_string.len) +#define princ_type(P) ((P)->name.name_type) +#define princ_comp(P) ((P)->name.name_string.val) +#define princ_ncomp(P, N) ((P)->name.name_string.val[(N)]) +#define princ_realm(P) ((P)->realm) + +/** + * Frees a Kerberos principal allocated by the library with + * krb5_parse_name(), krb5_make_principal() or any other related + * principal functions. + * + * @param context A Kerberos context. + * @param p a principal to free. + * + * @return An krb5 error code, see krb5_get_error_message(). + * + * @ingroup krb5_principal + */ + +KRB5_LIB_FUNCTION void KRB5_LIB_CALL +krb5_free_principal(krb5_context context, + krb5_principal p) +{ + if(p){ + free_Principal(p); + free(p); + } +} + +/** + * Set the type of the principal + * + * @param context A Kerberos context. + * @param principal principal to set the type for + * @param type the new type + * + * @return An krb5 error code, see krb5_get_error_message(). + * + * @ingroup krb5_principal + */ + +KRB5_LIB_FUNCTION void KRB5_LIB_CALL +krb5_principal_set_type(krb5_context context, + krb5_principal principal, + int type) +{ + princ_type(principal) = type; +} + +/** + * Get the type of the principal + * + * @param context A Kerberos context. + * @param principal principal to get the type for + * + * @return the type of principal + * + * @ingroup krb5_principal + */ + +KRB5_LIB_FUNCTION int KRB5_LIB_CALL +krb5_principal_get_type(krb5_context context, + krb5_const_principal principal) +{ + return princ_type(principal); +} + +/** + * Get the realm of the principal + * + * @param context A Kerberos context. + * @param principal principal to get the realm for + * + * @return realm of the principal, don't free or use after krb5_principal is freed + * + * @ingroup krb5_principal + */ + +KRB5_LIB_FUNCTION const char* KRB5_LIB_CALL +krb5_principal_get_realm(krb5_context context, + krb5_const_principal principal) +{ + return princ_realm(principal); +} + +KRB5_LIB_FUNCTION const char* KRB5_LIB_CALL +krb5_principal_get_comp_string(krb5_context context, + krb5_const_principal principal, + unsigned int component) +{ + if(component >= princ_num_comp(principal)) + return NULL; + return princ_ncomp(principal, component); +} + +/** + * Get number of component is principal. + * + * @param context Kerberos 5 context + * @param principal principal to query + * + * @return number of components in string + * + * @ingroup krb5_principal + */ + +KRB5_LIB_FUNCTION unsigned int KRB5_LIB_CALL +krb5_principal_get_num_comp(krb5_context context, + krb5_const_principal principal) +{ + return princ_num_comp(principal); +} + +/** + * Parse a name into a krb5_principal structure, flags controls the behavior. + * + * @param context Kerberos 5 context + * @param name name to parse into a Kerberos principal + * @param flags flags to control the behavior + * @param principal returned principal, free with krb5_free_principal(). + * + * @return An krb5 error code, see krb5_get_error_message(). + * + * @ingroup krb5_principal + */ + +KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL +krb5_parse_name_flags(krb5_context context, + const char *name, + int flags, + krb5_principal *principal) +{ + krb5_error_code ret; + heim_general_string *comp; + heim_general_string realm = NULL; + int ncomp; + + const char *p; + char *q; + char *s; + char *start; + + int n; + char c; + int got_realm = 0; + int first_at = 1; + int enterprise = (flags & KRB5_PRINCIPAL_PARSE_ENTERPRISE); + + *principal = NULL; + +#define RFLAGS (KRB5_PRINCIPAL_PARSE_NO_REALM|KRB5_PRINCIPAL_PARSE_REQUIRE_REALM) + + if ((flags & RFLAGS) == RFLAGS) { + krb5_set_error_message(context, KRB5_ERR_NO_SERVICE, + N_("Can't require both realm and " + "no realm at the same time", "")); + return KRB5_ERR_NO_SERVICE; + } +#undef RFLAGS + + /* count number of component, + * enterprise names only have one component + */ + ncomp = 1; + if (!enterprise) { + for(p = name; *p; p++){ + if(*p=='\\'){ + if(!p[1]) { + krb5_set_error_message(context, KRB5_PARSE_MALFORMED, + N_("trailing \\ in principal name", "")); + return KRB5_PARSE_MALFORMED; + } + p++; + } else if(*p == '/') + ncomp++; + else if(*p == '@') + break; + } + } + comp = calloc(ncomp, sizeof(*comp)); + if (comp == NULL) { + krb5_set_error_message(context, ENOMEM, + N_("malloc: out of memory", "")); + return ENOMEM; + } + + n = 0; + p = start = q = s = strdup(name); + if (start == NULL) { + free (comp); + krb5_set_error_message(context, ENOMEM, + N_("malloc: out of memory", "")); + return ENOMEM; + } + while(*p){ + c = *p++; + if(c == '\\'){ + c = *p++; + if(c == 'n') + c = '\n'; + else if(c == 't') + c = '\t'; + else if(c == 'b') + c = '\b'; + else if(c == '0') + c = '\0'; + else if(c == '\0') { + ret = KRB5_PARSE_MALFORMED; + krb5_set_error_message(context, ret, + N_("trailing \\ in principal name", "")); + goto exit; + } + }else if(enterprise && first_at) { + if (c == '@') + first_at = 0; + }else if((c == '/' && !enterprise) || c == '@'){ + if(got_realm){ + ret = KRB5_PARSE_MALFORMED; + krb5_set_error_message(context, ret, + N_("part after realm in principal name", "")); + goto exit; + }else{ + comp[n] = malloc(q - start + 1); + if (comp[n] == NULL) { + ret = ENOMEM; + krb5_set_error_message(context, ret, + N_("malloc: out of memory", "")); + goto exit; + } + memcpy(comp[n], start, q - start); + comp[n][q - start] = 0; + n++; + } + if(c == '@') + got_realm = 1; + start = q; + continue; + } + if(got_realm && (c == '/' || c == '\0')) { + ret = KRB5_PARSE_MALFORMED; + krb5_set_error_message(context, ret, + N_("part after realm in principal name", "")); + goto exit; + } + *q++ = c; + } + if(got_realm){ + if (flags & KRB5_PRINCIPAL_PARSE_NO_REALM) { + ret = KRB5_PARSE_MALFORMED; + krb5_set_error_message(context, ret, + N_("realm found in 'short' principal " + "expected to be without one", "")); + goto exit; + } + realm = malloc(q - start + 1); + if (realm == NULL) { + ret = ENOMEM; + krb5_set_error_message(context, ret, + N_("malloc: out of memory", "")); + goto exit; + } + memcpy(realm, start, q - start); + realm[q - start] = 0; + }else{ + if (flags & KRB5_PRINCIPAL_PARSE_REQUIRE_REALM) { + ret = KRB5_PARSE_MALFORMED; + krb5_set_error_message(context, ret, + N_("realm NOT found in principal " + "expected to be with one", "")); + goto exit; + } else if (flags & KRB5_PRINCIPAL_PARSE_NO_REALM) { + realm = NULL; + } else { + ret = krb5_get_default_realm (context, &realm); + if (ret) + goto exit; + } + + comp[n] = malloc(q - start + 1); + if (comp[n] == NULL) { + ret = ENOMEM; + krb5_set_error_message(context, ret, + N_("malloc: out of memory", "")); + goto exit; + } + memcpy(comp[n], start, q - start); + comp[n][q - start] = 0; + n++; + } + *principal = malloc(sizeof(**principal)); + if (*principal == NULL) { + ret = ENOMEM; + krb5_set_error_message(context, ret, + N_("malloc: out of memory", "")); + goto exit; + } + if (enterprise) + (*principal)->name.name_type = KRB5_NT_ENTERPRISE_PRINCIPAL; + else + (*principal)->name.name_type = KRB5_NT_PRINCIPAL; + (*principal)->name.name_string.val = comp; + princ_num_comp(*principal) = n; + (*principal)->realm = realm; + free(s); + return 0; +exit: + while(n>0){ + free(comp[--n]); + } + free(comp); + free(realm); + free(s); + return ret; +} + +/** + * Parse a name into a krb5_principal structure + * + * @param context Kerberos 5 context + * @param name name to parse into a Kerberos principal + * @param principal returned principal, free with krb5_free_principal(). + * + * @return An krb5 error code, see krb5_get_error_message(). + * + * @ingroup krb5_principal + */ + +KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL +krb5_parse_name(krb5_context context, + const char *name, + krb5_principal *principal) +{ + return krb5_parse_name_flags(context, name, 0, principal); +} + +static const char quotable_chars[] = " \n\t\b\\/@"; +static const char replace_chars[] = " ntb\\/@"; +static const char nq_chars[] = " \\/@"; + +#define add_char(BASE, INDEX, LEN, C) do { if((INDEX) < (LEN)) (BASE)[(INDEX)++] = (C); }while(0); + +static size_t +quote_string(const char *s, char *out, size_t idx, size_t len, int display) +{ + const char *p, *q; + for(p = s; *p && idx < len; p++){ + q = strchr(quotable_chars, *p); + if (q && display) { + add_char(out, idx, len, replace_chars[q - quotable_chars]); + } else if (q) { + add_char(out, idx, len, '\\'); + add_char(out, idx, len, replace_chars[q - quotable_chars]); + }else + add_char(out, idx, len, *p); + } + if(idx < len) + out[idx] = '\0'; + return idx; +} + + +static krb5_error_code +unparse_name_fixed(krb5_context context, + krb5_const_principal principal, + char *name, + size_t len, + int flags) +{ + size_t idx = 0; + size_t i; + int short_form = (flags & KRB5_PRINCIPAL_UNPARSE_SHORT) != 0; + int no_realm = (flags & KRB5_PRINCIPAL_UNPARSE_NO_REALM) != 0; + int display = (flags & KRB5_PRINCIPAL_UNPARSE_DISPLAY) != 0; + + if (!no_realm && princ_realm(principal) == NULL) { + krb5_set_error_message(context, ERANGE, + N_("Realm missing from principal, " + "can't unparse", "")); + return ERANGE; + } + + for(i = 0; i < princ_num_comp(principal); i++){ + if(i) + add_char(name, idx, len, '/'); + idx = quote_string(princ_ncomp(principal, i), name, idx, len, display); + if(idx == len) { + krb5_set_error_message(context, ERANGE, + N_("Out of space printing principal", "")); + return ERANGE; + } + } + /* add realm if different from default realm */ + if(short_form && !no_realm) { + krb5_realm r; + krb5_error_code ret; + ret = krb5_get_default_realm(context, &r); + if(ret) + return ret; + if(strcmp(princ_realm(principal), r) != 0) + short_form = 0; + free(r); + } + if(!short_form && !no_realm) { + add_char(name, idx, len, '@'); + idx = quote_string(princ_realm(principal), name, idx, len, display); + if(idx == len) { + krb5_set_error_message(context, ERANGE, + N_("Out of space printing " + "realm of principal", "")); + return ERANGE; + } + } + return 0; +} + +/** + * Unparse the principal name to a fixed buffer + * + * @param context A Kerberos context. + * @param principal principal to unparse + * @param name buffer to write name to + * @param len length of buffer + * + * @return An krb5 error code, see krb5_get_error_message(). + * + * @ingroup krb5_principal + */ + +KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL +krb5_unparse_name_fixed(krb5_context context, + krb5_const_principal principal, + char *name, + size_t len) +{ + return unparse_name_fixed(context, principal, name, len, 0); +} + +/** + * Unparse the principal name to a fixed buffer. The realm is skipped + * if its a default realm. + * + * @param context A Kerberos context. + * @param principal principal to unparse + * @param name buffer to write name to + * @param len length of buffer + * + * @return An krb5 error code, see krb5_get_error_message(). + * + * @ingroup krb5_principal + */ + +KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL +krb5_unparse_name_fixed_short(krb5_context context, + krb5_const_principal principal, + char *name, + size_t len) +{ + return unparse_name_fixed(context, principal, name, len, + KRB5_PRINCIPAL_UNPARSE_SHORT); +} + +/** + * Unparse the principal name with unparse flags to a fixed buffer. + * + * @param context A Kerberos context. + * @param principal principal to unparse + * @param flags unparse flags + * @param name buffer to write name to + * @param len length of buffer + * + * @return An krb5 error code, see krb5_get_error_message(). + * + * @ingroup krb5_principal + */ + +KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL +krb5_unparse_name_fixed_flags(krb5_context context, + krb5_const_principal principal, + int flags, + char *name, + size_t len) +{ + return unparse_name_fixed(context, principal, name, len, flags); +} + +static krb5_error_code +unparse_name(krb5_context context, + krb5_const_principal principal, + char **name, + int flags) +{ + size_t len = 0, plen; + size_t i; + krb5_error_code ret; + /* count length */ + if (princ_realm(principal)) { + plen = strlen(princ_realm(principal)); + + if(strcspn(princ_realm(principal), quotable_chars) == plen) + len += plen; + else + len += 2*plen; + len++; /* '@' */ + } + for(i = 0; i < princ_num_comp(principal); i++){ + plen = strlen(princ_ncomp(principal, i)); + if(strcspn(princ_ncomp(principal, i), quotable_chars) == plen) + len += plen; + else + len += 2*plen; + len++; + } + len++; /* '\0' */ + *name = malloc(len); + if(*name == NULL) { + krb5_set_error_message(context, ENOMEM, + N_("malloc: out of memory", "")); + return ENOMEM; + } + ret = unparse_name_fixed(context, principal, *name, len, flags); + if(ret) { + free(*name); + *name = NULL; + } + return ret; +} + +/** + * Unparse the Kerberos name into a string + * + * @param context Kerberos 5 context + * @param principal principal to query + * @param name resulting string, free with krb5_xfree() + * + * @return An krb5 error code, see krb5_get_error_message(). + * + * @ingroup krb5_principal + */ + +KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL +krb5_unparse_name(krb5_context context, + krb5_const_principal principal, + char **name) +{ + return unparse_name(context, principal, name, 0); +} + +/** + * Unparse the Kerberos name into a string + * + * @param context Kerberos 5 context + * @param principal principal to query + * @param flags flag to determine the behavior + * @param name resulting string, free with krb5_xfree() + * + * @return An krb5 error code, see krb5_get_error_message(). + * + * @ingroup krb5_principal + */ + +KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL +krb5_unparse_name_flags(krb5_context context, + krb5_const_principal principal, + int flags, + char **name) +{ + return unparse_name(context, principal, name, flags); +} + +/** + * Unparse the principal name to a allocated buffer. The realm is + * skipped if its a default realm. + * + * @param context A Kerberos context. + * @param principal principal to unparse + * @param name returned buffer, free with krb5_xfree() + * + * @return An krb5 error code, see krb5_get_error_message(). + * + * @ingroup krb5_principal + */ + +KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL +krb5_unparse_name_short(krb5_context context, + krb5_const_principal principal, + char **name) +{ + return unparse_name(context, principal, name, KRB5_PRINCIPAL_UNPARSE_SHORT); +} + +/** + * Set a new realm for a principal, and as a side-effect free the + * previous realm. + * + * @param context A Kerberos context. + * @param principal principal set the realm for + * @param realm the new realm to set + * + * @return An krb5 error code, see krb5_get_error_message(). + * + * @ingroup krb5_principal + */ + +KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL +krb5_principal_set_realm(krb5_context context, + krb5_principal principal, + krb5_const_realm realm) +{ + if (princ_realm(principal)) + free(princ_realm(principal)); + + princ_realm(principal) = strdup(realm); + if (princ_realm(principal) == NULL) { + krb5_set_error_message(context, ENOMEM, + N_("malloc: out of memory", "")); + return ENOMEM; + } + return 0; +} + +#ifndef HEIMDAL_SMALLER +/** + * Build a principal using vararg style building + * + * @param context A Kerberos context. + * @param principal returned principal + * @param rlen length of realm + * @param realm realm name + * @param ... a list of components ended with NULL. + * + * @return An krb5 error code, see krb5_get_error_message(). + * + * @ingroup krb5_principal + */ + +KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL +krb5_build_principal(krb5_context context, + krb5_principal *principal, + int rlen, + krb5_const_realm realm, + ...) +{ + krb5_error_code ret; + va_list ap; + va_start(ap, realm); + ret = krb5_build_principal_va(context, principal, rlen, realm, ap); + va_end(ap); + return ret; +} +#endif + +/** + * Build a principal using vararg style building + * + * @param context A Kerberos context. + * @param principal returned principal + * @param realm realm name + * @param ... a list of components ended with NULL. + * + * @return An krb5 error code, see krb5_get_error_message(). + * + * @ingroup krb5_principal + */ + +KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL +krb5_make_principal(krb5_context context, + krb5_principal *principal, + krb5_const_realm realm, + ...) +{ + krb5_error_code ret; + krb5_realm r = NULL; + va_list ap; + if(realm == NULL) { + ret = krb5_get_default_realm(context, &r); + if(ret) + return ret; + realm = r; + } + va_start(ap, realm); + ret = krb5_build_principal_va(context, principal, strlen(realm), realm, ap); + va_end(ap); + if(r) + free(r); + return ret; +} + +static krb5_error_code +append_component(krb5_context context, krb5_principal p, + const char *comp, + size_t comp_len) +{ + heim_general_string *tmp; + size_t len = princ_num_comp(p); + + tmp = realloc(princ_comp(p), (len + 1) * sizeof(*tmp)); + if(tmp == NULL) { + krb5_set_error_message(context, ENOMEM, + N_("malloc: out of memory", "")); + return ENOMEM; + } + princ_comp(p) = tmp; + princ_ncomp(p, len) = malloc(comp_len + 1); + if (princ_ncomp(p, len) == NULL) { + krb5_set_error_message(context, ENOMEM, + N_("malloc: out of memory", "")); + return ENOMEM; + } + memcpy (princ_ncomp(p, len), comp, comp_len); + princ_ncomp(p, len)[comp_len] = '\0'; + princ_num_comp(p)++; + return 0; +} + +static void +va_ext_princ(krb5_context context, krb5_principal p, va_list ap) +{ + while(1){ + const char *s; + int len; + len = va_arg(ap, int); + if(len == 0) + break; + s = va_arg(ap, const char*); + append_component(context, p, s, len); + } +} + +static void +va_princ(krb5_context context, krb5_principal p, va_list ap) +{ + while(1){ + const char *s; + s = va_arg(ap, const char*); + if(s == NULL) + break; + append_component(context, p, s, strlen(s)); + } +} + +static krb5_error_code +build_principal(krb5_context context, + krb5_principal *principal, + int rlen, + krb5_const_realm realm, + void (*func)(krb5_context, krb5_principal, va_list), + va_list ap) +{ + krb5_principal p; + + p = calloc(1, sizeof(*p)); + if (p == NULL) { + krb5_set_error_message(context, ENOMEM, + N_("malloc: out of memory", "")); + return ENOMEM; + } + princ_type(p) = KRB5_NT_PRINCIPAL; + + princ_realm(p) = strdup(realm); + if(p->realm == NULL){ + free(p); + krb5_set_error_message(context, ENOMEM, + N_("malloc: out of memory", "")); + return ENOMEM; + } + + (*func)(context, p, ap); + *principal = p; + return 0; +} + +KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL +krb5_build_principal_va(krb5_context context, + krb5_principal *principal, + int rlen, + krb5_const_realm realm, + va_list ap) +{ + return build_principal(context, principal, rlen, realm, va_princ, ap); +} + +KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL +krb5_build_principal_va_ext(krb5_context context, + krb5_principal *principal, + int rlen, + krb5_const_realm realm, + va_list ap) +{ + return build_principal(context, principal, rlen, realm, va_ext_princ, ap); +} + + +KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL +krb5_build_principal_ext(krb5_context context, + krb5_principal *principal, + int rlen, + krb5_const_realm realm, + ...) +{ + krb5_error_code ret; + va_list ap; + va_start(ap, realm); + ret = krb5_build_principal_va_ext(context, principal, rlen, realm, ap); + va_end(ap); + return ret; +} + +/** + * Copy a principal + * + * @param context A Kerberos context. + * @param inprinc principal to copy + * @param outprinc copied principal, free with krb5_free_principal() + * + * @return An krb5 error code, see krb5_get_error_message(). + * + * @ingroup krb5_principal + */ + + +KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL +krb5_copy_principal(krb5_context context, + krb5_const_principal inprinc, + krb5_principal *outprinc) +{ + krb5_principal p = malloc(sizeof(*p)); + if (p == NULL) { + krb5_set_error_message(context, ENOMEM, + N_("malloc: out of memory", "")); + return ENOMEM; + } + if(copy_Principal(inprinc, p)) { + free(p); + krb5_set_error_message(context, ENOMEM, + N_("malloc: out of memory", "")); + return ENOMEM; + } + *outprinc = p; + return 0; +} + +/** + * Return TRUE iff princ1 == princ2 (without considering the realm) + * + * @param context Kerberos 5 context + * @param princ1 first principal to compare + * @param princ2 second principal to compare + * + * @return non zero if equal, 0 if not + * + * @ingroup krb5_principal + * @see krb5_principal_compare() + * @see krb5_realm_compare() + */ + +KRB5_LIB_FUNCTION krb5_boolean KRB5_LIB_CALL +krb5_principal_compare_any_realm(krb5_context context, + krb5_const_principal princ1, + krb5_const_principal princ2) +{ + size_t i; + if(princ_num_comp(princ1) != princ_num_comp(princ2)) + return FALSE; + for(i = 0; i < princ_num_comp(princ1); i++){ + if(strcmp(princ_ncomp(princ1, i), princ_ncomp(princ2, i)) != 0) + return FALSE; + } + return TRUE; +} + +KRB5_LIB_FUNCTION krb5_boolean KRB5_LIB_CALL +_krb5_principal_compare_PrincipalName(krb5_context context, + krb5_const_principal princ1, + PrincipalName *princ2) +{ + size_t i; + if (princ_num_comp(princ1) != princ2->name_string.len) + return FALSE; + for(i = 0; i < princ_num_comp(princ1); i++){ + if(strcmp(princ_ncomp(princ1, i), princ2->name_string.val[i]) != 0) + return FALSE; + } + return TRUE; +} + + +/** + * Compares the two principals, including realm of the principals and returns + * TRUE if they are the same and FALSE if not. + * + * @param context Kerberos 5 context + * @param princ1 first principal to compare + * @param princ2 second principal to compare + * + * @ingroup krb5_principal + * @see krb5_principal_compare_any_realm() + * @see krb5_realm_compare() + */ + +/* + * return TRUE iff princ1 == princ2 + */ + +KRB5_LIB_FUNCTION krb5_boolean KRB5_LIB_CALL +krb5_principal_compare(krb5_context context, + krb5_const_principal princ1, + krb5_const_principal princ2) +{ + if(!krb5_realm_compare(context, princ1, princ2)) + return FALSE; + return krb5_principal_compare_any_realm(context, princ1, princ2); +} + +/** + * return TRUE iff realm(princ1) == realm(princ2) + * + * @param context Kerberos 5 context + * @param princ1 first principal to compare + * @param princ2 second principal to compare + * + * @ingroup krb5_principal + * @see krb5_principal_compare_any_realm() + * @see krb5_principal_compare() + */ + +KRB5_LIB_FUNCTION krb5_boolean KRB5_LIB_CALL +krb5_realm_compare(krb5_context context, + krb5_const_principal princ1, + krb5_const_principal princ2) +{ + return strcmp(princ_realm(princ1), princ_realm(princ2)) == 0; +} + +/** + * return TRUE iff princ matches pattern + * + * @ingroup krb5_principal + */ + +KRB5_LIB_FUNCTION krb5_boolean KRB5_LIB_CALL +krb5_principal_match(krb5_context context, + krb5_const_principal princ, + krb5_const_principal pattern) +{ + size_t i; + if(princ_num_comp(princ) != princ_num_comp(pattern)) + return FALSE; + if(fnmatch(princ_realm(pattern), princ_realm(princ), 0) != 0) + return FALSE; + for(i = 0; i < princ_num_comp(princ); i++){ + if(fnmatch(princ_ncomp(pattern, i), princ_ncomp(princ, i), 0) != 0) + return FALSE; + } + return TRUE; +} + +/** + * Create a principal for the service running on hostname. If + * KRB5_NT_SRV_HST is used, the hostname is canonization using DNS (or + * some other service), this is potentially insecure. + * + * @param context A Kerberos context. + * @param hostname hostname to use + * @param sname Service name to use + * @param type name type of pricipal, use KRB5_NT_SRV_HST or KRB5_NT_UNKNOWN. + * @param ret_princ return principal, free with krb5_free_principal(). + * + * @return An krb5 error code, see krb5_get_error_message(). + * + * @ingroup krb5_principal + */ + +KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL +krb5_sname_to_principal (krb5_context context, + const char *hostname, + const char *sname, + int32_t type, + krb5_principal *ret_princ) +{ + krb5_error_code ret; + char localhost[MAXHOSTNAMELEN]; + char **realms, *host = NULL; + + if(type != KRB5_NT_SRV_HST && type != KRB5_NT_UNKNOWN) { + krb5_set_error_message(context, KRB5_SNAME_UNSUPP_NAMETYPE, + N_("unsupported name type %d", ""), + (int)type); + return KRB5_SNAME_UNSUPP_NAMETYPE; + } + if(hostname == NULL) { + ret = gethostname(localhost, sizeof(localhost) - 1); + if (ret != 0) { + ret = errno; + krb5_set_error_message(context, ret, + N_("Failed to get local hostname", "")); + return ret; + } + localhost[sizeof(localhost) - 1] = '\0'; + hostname = localhost; + } + if(sname == NULL) + sname = "host"; + if(type == KRB5_NT_SRV_HST) { + ret = krb5_expand_hostname_realms (context, hostname, + &host, &realms); + if (ret) + return ret; + strlwr(host); + hostname = host; + } else { + ret = krb5_get_host_realm(context, hostname, &realms); + if(ret) + return ret; + } + + ret = krb5_make_principal(context, ret_princ, realms[0], sname, + hostname, NULL); + if(host) + free(host); + krb5_free_host_realm(context, realms); + return ret; +} + +static const struct { + const char *type; + int32_t value; +} nametypes[] = { + { "UNKNOWN", KRB5_NT_UNKNOWN }, + { "PRINCIPAL", KRB5_NT_PRINCIPAL }, + { "SRV_INST", KRB5_NT_SRV_INST }, + { "SRV_HST", KRB5_NT_SRV_HST }, + { "SRV_XHST", KRB5_NT_SRV_XHST }, + { "UID", KRB5_NT_UID }, + { "X500_PRINCIPAL", KRB5_NT_X500_PRINCIPAL }, + { "SMTP_NAME", KRB5_NT_SMTP_NAME }, + { "ENTERPRISE_PRINCIPAL", KRB5_NT_ENTERPRISE_PRINCIPAL }, + { "ENT_PRINCIPAL_AND_ID", KRB5_NT_ENT_PRINCIPAL_AND_ID }, + { "MS_PRINCIPAL", KRB5_NT_MS_PRINCIPAL }, + { "MS_PRINCIPAL_AND_ID", KRB5_NT_MS_PRINCIPAL_AND_ID }, + { NULL, 0 } +}; + +/** + * Parse nametype string and return a nametype integer + * + * @ingroup krb5_principal + */ + +KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL +krb5_parse_nametype(krb5_context context, const char *str, int32_t *nametype) +{ + size_t i; + + for(i = 0; nametypes[i].type; i++) { + if (strcasecmp(nametypes[i].type, str) == 0) { + *nametype = nametypes[i].value; + return 0; + } + } + krb5_set_error_message(context, KRB5_PARSE_MALFORMED, + N_("Failed to find name type %s", ""), str); + return KRB5_PARSE_MALFORMED; +} + +/** + * Check if the cname part of the principal is a krbtgt principal + * + * @ingroup krb5_principal + */ + +KRB5_LIB_FUNCTION krb5_boolean KRB5_LIB_CALL +krb5_principal_is_krbtgt(krb5_context context, krb5_const_principal p) +{ + return p->name.name_string.len == 2 && + strcmp(p->name.name_string.val[0], KRB5_TGS_NAME) == 0; + +} |