From 954c01728e0c7485b72c9a5d5737e5f6bd0cf0b9 Mon Sep 17 00:00:00 2001 From: Heimdal Import User Date: Mon, 11 Jul 2005 01:16:55 +0000 Subject: r8302: import mini HEIMDAL into the tree (This used to be commit 118be28a7aef233799956615a99d1a2a74dac175) --- source4/heimdal/lib/krb5/principal.c | 1125 ++++++++++++++++++++++++++++++++++ 1 file changed, 1125 insertions(+) create mode 100644 source4/heimdal/lib/krb5/principal.c (limited to 'source4/heimdal/lib/krb5/principal.c') diff --git a/source4/heimdal/lib/krb5/principal.c b/source4/heimdal/lib/krb5/principal.c new file mode 100644 index 0000000000..b7194b4c41 --- /dev/null +++ b/source4/heimdal/lib/krb5/principal.c @@ -0,0 +1,1125 @@ +/* + * Copyright (c) 1997-2002 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. + */ + +#include "krb5_locl.h" +#ifdef HAVE_RES_SEARCH +#define USE_RESOLVER +#endif +#ifdef HAVE_ARPA_NAMESER_H +#include +#endif +#include +#include "resolve.h" + +RCSID("$Id: principal.c,v 1.90 2005/06/30 01:38:15 lha Exp $"); + +#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) + +void KRB5_LIB_FUNCTION +krb5_free_principal(krb5_context context, + krb5_principal p) +{ + if(p){ + free_Principal(p); + free(p); + } +} + +void KRB5_LIB_FUNCTION +krb5_principal_set_type(krb5_context context, + krb5_principal principal, + int type) +{ + princ_type(principal) = type; +} + +int KRB5_LIB_FUNCTION +krb5_principal_get_type(krb5_context context, + krb5_principal principal) +{ + return princ_type(principal); +} + +const char* KRB5_LIB_FUNCTION +krb5_principal_get_realm(krb5_context context, + krb5_const_principal principal) +{ + return princ_realm(principal); +} + +const char* KRB5_LIB_FUNCTION +krb5_principal_get_comp_string(krb5_context context, + krb5_principal principal, + unsigned int component) +{ + if(component >= princ_num_comp(principal)) + return NULL; + return princ_ncomp(principal, component); +} + +krb5_error_code KRB5_LIB_FUNCTION +krb5_parse_name(krb5_context context, + const char *name, + krb5_principal *principal) +{ + krb5_error_code ret; + heim_general_string *comp; + heim_general_string realm; + int ncomp; + + const char *p; + char *q; + char *s; + char *start; + + int n; + char c; + int got_realm = 0; + + /* count number of component */ + ncomp = 1; + for(p = name; *p; p++){ + if(*p=='\\'){ + if(!p[1]) { + krb5_set_error_string (context, + "trailing \\ in principal name"); + return KRB5_PARSE_MALFORMED; + } + p++; + } else if(*p == '/') + ncomp++; + } + comp = calloc(ncomp, sizeof(*comp)); + if (comp == NULL) { + krb5_set_error_string (context, "malloc: out of memory"); + return ENOMEM; + } + + n = 0; + p = start = q = s = strdup(name); + if (start == NULL) { + free (comp); + krb5_set_error_string (context, "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') { + krb5_set_error_string (context, + "trailing \\ in principal name"); + ret = KRB5_PARSE_MALFORMED; + goto exit; + } + }else if(c == '/' || c == '@'){ + if(got_realm){ + krb5_set_error_string (context, + "part after realm in principal name"); + ret = KRB5_PARSE_MALFORMED; + goto exit; + }else{ + comp[n] = malloc(q - start + 1); + if (comp[n] == NULL) { + krb5_set_error_string (context, "malloc: out of memory"); + ret = ENOMEM; + 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 == '/' || c == '\0')) { + krb5_set_error_string (context, + "part after realm in principal name"); + ret = KRB5_PARSE_MALFORMED; + goto exit; + } + *q++ = c; + } + if(got_realm){ + realm = malloc(q - start + 1); + if (realm == NULL) { + krb5_set_error_string (context, "malloc: out of memory"); + ret = ENOMEM; + goto exit; + } + memcpy(realm, start, q - start); + realm[q - start] = 0; + }else{ + ret = krb5_get_default_realm (context, &realm); + if (ret) + goto exit; + + comp[n] = malloc(q - start + 1); + if (comp[n] == NULL) { + krb5_set_error_string (context, "malloc: out of memory"); + ret = ENOMEM; + goto exit; + } + memcpy(comp[n], start, q - start); + comp[n][q - start] = 0; + n++; + } + *principal = malloc(sizeof(**principal)); + if (*principal == NULL) { + krb5_set_error_string (context, "malloc: out of memory"); + ret = ENOMEM; + goto exit; + } + (*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(s); + return ret; +} + +static const char quotable_chars[] = " \n\t\b\\/@"; +static const char replace_chars[] = " ntb\\/@"; + +#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 string_index, size_t len) +{ + const char *p, *q; + for(p = s; *p && string_index < len; p++){ + if((q = strchr(quotable_chars, *p))){ + add_char(out, string_index, len, '\\'); + add_char(out, string_index, len, replace_chars[q - quotable_chars]); + }else + add_char(out, string_index, len, *p); + } + if(string_index < len) + out[string_index] = '\0'; + return string_index; +} + + +static krb5_error_code +unparse_name_fixed(krb5_context context, + krb5_const_principal principal, + char *name, + size_t len, + krb5_boolean short_form) +{ + size_t idx = 0; + int i; + 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); + if(idx == len) + return ERANGE; + } + /* add realm if different from default realm */ + if(short_form) { + 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) { + add_char(name, idx, len, '@'); + idx = quote_string(princ_realm(principal), name, idx, len); + if(idx == len) + return ERANGE; + } + return 0; +} + +krb5_error_code KRB5_LIB_FUNCTION +krb5_unparse_name_fixed(krb5_context context, + krb5_const_principal principal, + char *name, + size_t len) +{ + return unparse_name_fixed(context, principal, name, len, FALSE); +} + +krb5_error_code KRB5_LIB_FUNCTION +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, TRUE); +} + +static krb5_error_code +unparse_name(krb5_context context, + krb5_const_principal principal, + char **name, + krb5_boolean short_flag) +{ + size_t len = 0, plen; + int i; + krb5_error_code ret; + /* count length */ + 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++; + *name = malloc(len); + if(*name == NULL) { + krb5_set_error_string (context, "malloc: out of memory"); + return ENOMEM; + } + ret = unparse_name_fixed(context, principal, *name, len, short_flag); + if(ret) { + free(*name); + *name = NULL; + } + return ret; +} + +krb5_error_code KRB5_LIB_FUNCTION +krb5_unparse_name(krb5_context context, + krb5_const_principal principal, + char **name) +{ + return unparse_name(context, principal, name, FALSE); +} + +krb5_error_code KRB5_LIB_FUNCTION +krb5_unparse_name_short(krb5_context context, + krb5_const_principal principal, + char **name) +{ + return unparse_name(context, principal, name, TRUE); +} + +#if 0 /* not implemented */ + +krb5_error_code KRB5_LIB_FUNCTION +krb5_unparse_name_ext(krb5_context context, + krb5_const_principal principal, + char **name, + size_t *size) +{ + krb5_abortx(context, "unimplemented krb5_unparse_name_ext called"); +} + +#endif + +krb5_realm* +krb5_princ_realm(krb5_context context, + krb5_principal principal) +{ + return &princ_realm(principal); +} + + +void KRB5_LIB_FUNCTION +krb5_princ_set_realm(krb5_context context, + krb5_principal principal, + krb5_realm *realm) +{ + princ_realm(principal) = *realm; +} + + +krb5_error_code KRB5_LIB_FUNCTION +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; +} + +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_string (context, "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_string (context, "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_string (context, "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_string (context, "malloc: out of memory"); + return ENOMEM; + } + + (*func)(context, p, ap); + *principal = p; + return 0; +} + +krb5_error_code KRB5_LIB_FUNCTION +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; +} + +krb5_error_code KRB5_LIB_FUNCTION +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_error_code KRB5_LIB_FUNCTION +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_error_code KRB5_LIB_FUNCTION +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; +} + + +krb5_error_code KRB5_LIB_FUNCTION +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_string (context, "malloc: out of memory"); + return ENOMEM; + } + if(copy_Principal(inprinc, p)) { + free(p); + krb5_set_error_string (context, "malloc: out of memory"); + return ENOMEM; + } + *outprinc = p; + return 0; +} + +/* + * return TRUE iff princ1 == princ2 (without considering the realm) + */ + +krb5_boolean KRB5_LIB_FUNCTION +krb5_principal_compare_any_realm(krb5_context context, + krb5_const_principal princ1, + krb5_const_principal princ2) +{ + int 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; +} + +/* + * return TRUE iff princ1 == princ2 + */ + +krb5_boolean KRB5_LIB_FUNCTION +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) + */ + +krb5_boolean KRB5_LIB_FUNCTION +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 + */ + +krb5_boolean KRB5_LIB_FUNCTION +krb5_principal_match(krb5_context context, + krb5_const_principal princ, + krb5_const_principal pattern) +{ + int 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; +} + + +static struct v4_name_convert { + const char *from; + const char *to; +} default_v4_name_convert[] = { + { "ftp", "ftp" }, + { "hprop", "hprop" }, + { "pop", "pop" }, + { "imap", "imap" }, + { "rcmd", "host" }, + { "smtp", "smtp" }, + { NULL, NULL } +}; + +/* + * return the converted instance name of `name' in `realm'. + * look in the configuration file and then in the default set above. + * return NULL if no conversion is appropriate. + */ + +static const char* +get_name_conversion(krb5_context context, const char *realm, const char *name) +{ + struct v4_name_convert *q; + const char *p; + + p = krb5_config_get_string(context, NULL, "realms", realm, + "v4_name_convert", "host", name, NULL); + if(p == NULL) + p = krb5_config_get_string(context, NULL, "libdefaults", + "v4_name_convert", "host", name, NULL); + if(p) + return p; + + /* XXX should be possible to override default list */ + p = krb5_config_get_string(context, NULL, + "realms", + realm, + "v4_name_convert", + "plain", + name, + NULL); + if(p) + return NULL; + p = krb5_config_get_string(context, NULL, + "libdefaults", + "v4_name_convert", + "plain", + name, + NULL); + if(p) + return NULL; + for(q = default_v4_name_convert; q->from; q++) + if(strcmp(q->from, name) == 0) + return q->to; + return NULL; +} + +/* + * convert the v4 principal `name.instance@realm' to a v5 principal in `princ'. + * if `resolve', use DNS. + * if `func', use that function for validating the conversion + */ + +krb5_error_code KRB5_LIB_FUNCTION +krb5_425_conv_principal_ext2(krb5_context context, + const char *name, + const char *instance, + const char *realm, + krb5_boolean (*func)(krb5_context, + void *, krb5_principal), + void *funcctx, + krb5_boolean resolve, + krb5_principal *princ) +{ + const char *p; + krb5_error_code ret; + krb5_principal pr; + char host[MAXHOSTNAMELEN]; + char local_hostname[MAXHOSTNAMELEN]; + + /* do the following: if the name is found in the + `v4_name_convert:host' part, is is assumed to be a `host' type + principal, and the instance is looked up in the + `v4_instance_convert' part. if not found there the name is + (optionally) looked up as a hostname, and if that doesn't yield + anything, the `default_domain' is appended to the instance + */ + + if(instance == NULL) + goto no_host; + if(instance[0] == 0){ + instance = NULL; + goto no_host; + } + p = get_name_conversion(context, realm, name); + if(p == NULL) + goto no_host; + name = p; + p = krb5_config_get_string(context, NULL, "realms", realm, + "v4_instance_convert", instance, NULL); + if(p){ + instance = p; + ret = krb5_make_principal(context, &pr, realm, name, instance, NULL); + if(func == NULL || (*func)(context, funcctx, pr)){ + *princ = pr; + return 0; + } + krb5_free_principal(context, pr); + *princ = NULL; + krb5_clear_error_string (context); + return HEIM_ERR_V4_PRINC_NO_CONV; + } + if(resolve){ + krb5_boolean passed = FALSE; + char *inst = NULL; +#ifdef USE_RESOLVER + struct dns_reply *r; + + r = dns_lookup(instance, "aaaa"); + if (r && r->head && r->head->type == T_AAAA) { + inst = strdup(r->head->domain); + dns_free_data(r); + passed = TRUE; + } else { + r = dns_lookup(instance, "a"); + if(r && r->head && r->head->type == T_A) { + inst = strdup(r->head->domain); + dns_free_data(r); + passed = TRUE; + } + } +#else + struct addrinfo hints, *ai; + int ret; + + memset (&hints, 0, sizeof(hints)); + hints.ai_flags = AI_CANONNAME; + ret = getaddrinfo(instance, NULL, &hints, &ai); + if (ret == 0) { + const struct addrinfo *a; + for (a = ai; a != NULL; a = a->ai_next) { + if (a->ai_canonname != NULL) { + inst = strdup (a->ai_canonname); + passed = TRUE; + break; + } + } + freeaddrinfo (ai); + } +#endif + if (passed) { + if (inst == NULL) { + krb5_set_error_string (context, "malloc: out of memory"); + return ENOMEM; + } + strlwr(inst); + ret = krb5_make_principal(context, &pr, realm, name, inst, + NULL); + free (inst); + if(ret == 0) { + if(func == NULL || (*func)(context, funcctx, pr)){ + *princ = pr; + return 0; + } + krb5_free_principal(context, pr); + } + } + } + if(func != NULL) { + snprintf(host, sizeof(host), "%s.%s", instance, realm); + strlwr(host); + ret = krb5_make_principal(context, &pr, realm, name, host, NULL); + if((*func)(context, funcctx, pr)){ + *princ = pr; + return 0; + } + krb5_free_principal(context, pr); + } + + /* + * if the instance is the first component of the local hostname, + * the converted host should be the long hostname. + */ + + if (func == NULL && + gethostname (local_hostname, sizeof(local_hostname)) == 0 && + strncmp(instance, local_hostname, strlen(instance)) == 0 && + local_hostname[strlen(instance)] == '.') { + strlcpy(host, local_hostname, sizeof(host)); + goto local_host; + } + + { + char **domains, **d; + domains = krb5_config_get_strings(context, NULL, "realms", realm, + "v4_domains", NULL); + for(d = domains; d && *d; d++){ + snprintf(host, sizeof(host), "%s.%s", instance, *d); + ret = krb5_make_principal(context, &pr, realm, name, host, NULL); + if(func == NULL || (*func)(context, funcctx, pr)){ + *princ = pr; + krb5_config_free_strings(domains); + return 0; + } + krb5_free_principal(context, pr); + } + krb5_config_free_strings(domains); + } + + + p = krb5_config_get_string(context, NULL, "realms", realm, + "default_domain", NULL); + if(p == NULL){ + /* this should be an error, just faking a name is not good */ + krb5_clear_error_string (context); + return HEIM_ERR_V4_PRINC_NO_CONV; + } + + if (*p == '.') + ++p; + snprintf(host, sizeof(host), "%s.%s", instance, p); +local_host: + ret = krb5_make_principal(context, &pr, realm, name, host, NULL); + if(func == NULL || (*func)(context, funcctx, pr)){ + *princ = pr; + return 0; + } + krb5_free_principal(context, pr); + krb5_clear_error_string (context); + return HEIM_ERR_V4_PRINC_NO_CONV; +no_host: + p = krb5_config_get_string(context, NULL, + "realms", + realm, + "v4_name_convert", + "plain", + name, + NULL); + if(p == NULL) + p = krb5_config_get_string(context, NULL, + "libdefaults", + "v4_name_convert", + "plain", + name, + NULL); + if(p) + name = p; + + ret = krb5_make_principal(context, &pr, realm, name, instance, NULL); + if(func == NULL || (*func)(context, funcctx, pr)){ + *princ = pr; + return 0; + } + krb5_free_principal(context, pr); + krb5_clear_error_string (context); + return HEIM_ERR_V4_PRINC_NO_CONV; +} + +static krb5_boolean +convert_func(krb5_context conxtext, void *funcctx, krb5_principal principal) +{ + krb5_boolean (*func)(krb5_context, krb5_principal) = funcctx; + return (*func)(conxtext, principal); +} + +krb5_error_code KRB5_LIB_FUNCTION +krb5_425_conv_principal_ext(krb5_context context, + const char *name, + const char *instance, + const char *realm, + krb5_boolean (*func)(krb5_context, krb5_principal), + krb5_boolean resolve, + krb5_principal *principal) +{ + return krb5_425_conv_principal_ext2(context, + name, + instance, + realm, + func ? convert_func : NULL, + func, + resolve, + principal); +} + + + +krb5_error_code KRB5_LIB_FUNCTION +krb5_425_conv_principal(krb5_context context, + const char *name, + const char *instance, + const char *realm, + krb5_principal *princ) +{ + krb5_boolean resolve = krb5_config_get_bool(context, + NULL, + "libdefaults", + "v4_instance_resolve", + NULL); + + return krb5_425_conv_principal_ext(context, name, instance, realm, + NULL, resolve, princ); +} + + +static int +check_list(const krb5_config_binding *l, const char *name, const char **out) +{ + while(l){ + if (l->type != krb5_config_string) + continue; + if(strcmp(name, l->u.string) == 0) { + *out = l->name; + return 1; + } + l = l->next; + } + return 0; +} + +static int +name_convert(krb5_context context, const char *name, const char *realm, + const char **out) +{ + const krb5_config_binding *l; + l = krb5_config_get_list (context, + NULL, + "realms", + realm, + "v4_name_convert", + "host", + NULL); + if(l && check_list(l, name, out)) + return KRB5_NT_SRV_HST; + l = krb5_config_get_list (context, + NULL, + "libdefaults", + "v4_name_convert", + "host", + NULL); + if(l && check_list(l, name, out)) + return KRB5_NT_SRV_HST; + l = krb5_config_get_list (context, + NULL, + "realms", + realm, + "v4_name_convert", + "plain", + NULL); + if(l && check_list(l, name, out)) + return KRB5_NT_UNKNOWN; + l = krb5_config_get_list (context, + NULL, + "libdefaults", + "v4_name_convert", + "host", + NULL); + if(l && check_list(l, name, out)) + return KRB5_NT_UNKNOWN; + + /* didn't find it in config file, try built-in list */ + { + struct v4_name_convert *q; + for(q = default_v4_name_convert; q->from; q++) { + if(strcmp(name, q->to) == 0) { + *out = q->from; + return KRB5_NT_SRV_HST; + } + } + } + return -1; +} + +/* + * convert the v5 principal in `principal' into a v4 corresponding one + * in `name, instance, realm' + * this is limited interface since there's no length given for these + * three parameters. They have to be 40 bytes each (ANAME_SZ). + */ + +krb5_error_code KRB5_LIB_FUNCTION +krb5_524_conv_principal(krb5_context context, + const krb5_principal principal, + char *name, + char *instance, + char *realm) +{ + const char *n, *i, *r; + char tmpinst[40]; + int type = princ_type(principal); + const int aname_sz = 40; + + r = principal->realm; + + switch(principal->name.name_string.len){ + case 1: + n = principal->name.name_string.val[0]; + i = ""; + break; + case 2: + n = principal->name.name_string.val[0]; + i = principal->name.name_string.val[1]; + break; + default: + krb5_set_error_string (context, + "cannot convert a %d component principal", + principal->name.name_string.len); + return KRB5_PARSE_MALFORMED; + } + + { + const char *tmp; + int t = name_convert(context, n, r, &tmp); + if(t >= 0) { + type = t; + n = tmp; + } + } + + if(type == KRB5_NT_SRV_HST){ + char *p; + + strlcpy (tmpinst, i, sizeof(tmpinst)); + p = strchr(tmpinst, '.'); + if(p) + *p = 0; + i = tmpinst; + } + + if (strlcpy (name, n, aname_sz) >= aname_sz) { + krb5_set_error_string (context, + "too long name component to convert"); + return KRB5_PARSE_MALFORMED; + } + if (strlcpy (instance, i, aname_sz) >= aname_sz) { + krb5_set_error_string (context, + "too long instance component to convert"); + return KRB5_PARSE_MALFORMED; + } + if (strlcpy (realm, r, aname_sz) >= aname_sz) { + krb5_set_error_string (context, + "too long realm component to convert"); + return KRB5_PARSE_MALFORMED; + } + return 0; +} + +/* + * Create a principal in `ret_princ' for the service `sname' running + * on host `hostname'. */ + +krb5_error_code KRB5_LIB_FUNCTION +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_string (context, "unsupported name type %d", + type); + return KRB5_SNAME_UNSUPP_NAMETYPE; + } + if(hostname == NULL) { + gethostname(localhost, sizeof(localhost)); + 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; +} -- cgit