diff options
Diffstat (limited to 'lib/krb5/context.c')
| -rw-r--r-- | lib/krb5/context.c | 879 | 
1 files changed, 681 insertions, 198 deletions
| diff --git a/lib/krb5/context.c b/lib/krb5/context.c index 256783310e93..99bf1b419b0a 100644 --- a/lib/krb5/context.c +++ b/lib/krb5/context.c @@ -1,41 +1,42 @@  /* - * Copyright (c) 1997 - 2005 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.  + * Copyright (c) 1997 - 2010 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Portions Copyright (c) 2009 Apple Inc. 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" +#include <assert.h>  #include <com_err.h> -RCSID("$Id: context.c 22293 2007-12-14 05:25:59Z lha $"); -  #define INIT_FIELD(C, T, E, D, F)					\      (C)->E = krb5_config_get_ ## T ## _default ((C), NULL, (D), 	\  						"libdefaults", F, NULL) @@ -60,7 +61,7 @@ set_etypes (krb5_context context,      char **etypes_str;      krb5_enctype *etypes = NULL; -    etypes_str = krb5_config_get_strings(context, NULL, "libdefaults",  +    etypes_str = krb5_config_get_strings(context, NULL, "libdefaults",  					 name, NULL);      if(etypes_str){  	int i, j, k; @@ -68,7 +69,7 @@ set_etypes (krb5_context context,  	etypes = malloc((i+1) * sizeof(*etypes));  	if (etypes == NULL) {  	    krb5_config_free_strings (etypes_str); -	    krb5_set_error_string (context, "malloc: out of memory"); +	    krb5_set_error_message (context, ENOMEM, N_("malloc: out of memory", ""));  	    return ENOMEM;  	}  	for(j = 0, k = 0; j < i; j++) { @@ -81,7 +82,7 @@ set_etypes (krb5_context context,  	}  	etypes[k] = ETYPE_NULL;  	krb5_config_free_strings(etypes_str); -    }  +    }      *ret_enctypes = etypes;      return 0;  } @@ -95,6 +96,7 @@ init_context_from_config_file(krb5_context context)  {      krb5_error_code ret;      const char * tmp; +    char **s;      krb5_enctype *tmptypes;      INIT_FIELD(context, time, max_skew, 5 * 60, "clockskew"); @@ -102,19 +104,49 @@ init_context_from_config_file(krb5_context context)      INIT_FIELD(context, int, max_retries, 3, "max_retries");      INIT_FIELD(context, string, http_proxy, NULL, "http_proxy"); -     + +    ret = krb5_config_get_bool_default(context, NULL, FALSE, +				       "libdefaults", +				       "allow_weak_crypto", NULL); +    if (ret) { +	krb5_enctype_enable(context, ETYPE_DES_CBC_CRC); +	krb5_enctype_enable(context, ETYPE_DES_CBC_MD4); +	krb5_enctype_enable(context, ETYPE_DES_CBC_MD5); +	krb5_enctype_enable(context, ETYPE_DES_CBC_NONE); +	krb5_enctype_enable(context, ETYPE_DES_CFB64_NONE); +	krb5_enctype_enable(context, ETYPE_DES_PCBC_NONE); +    } +      ret = set_etypes (context, "default_etypes", &tmptypes);      if(ret)  	return ret;      free(context->etypes);      context->etypes = tmptypes; -     +      ret = set_etypes (context, "default_etypes_des", &tmptypes);      if(ret)  	return ret;      free(context->etypes_des);      context->etypes_des = tmptypes; +    ret = set_etypes (context, "default_as_etypes", &tmptypes); +    if(ret) +	return ret; +    free(context->as_etypes); +    context->as_etypes = tmptypes; + +    ret = set_etypes (context, "default_tgs_etypes", &tmptypes); +    if(ret) +	return ret; +    free(context->tgs_etypes); +    context->tgs_etypes = tmptypes; + +    ret = set_etypes (context, "permitted_enctypes", &tmptypes); +    if(ret) +	return ret; +    free(context->permitted_enctypes); +    context->permitted_enctypes = tmptypes; +      /* default keytab name */      tmp = NULL;      if(!issuid()) @@ -122,27 +154,27 @@ init_context_from_config_file(krb5_context context)      if(tmp != NULL)  	context->default_keytab = tmp;      else -	INIT_FIELD(context, string, default_keytab,  +	INIT_FIELD(context, string, default_keytab,  		   KEYTAB_DEFAULT, "default_keytab_name"); -    INIT_FIELD(context, string, default_keytab_modify,  +    INIT_FIELD(context, string, default_keytab_modify,  	       NULL, "default_keytab_modify_name"); -    INIT_FIELD(context, string, time_fmt,  +    INIT_FIELD(context, string, time_fmt,  	       "%Y-%m-%dT%H:%M:%S", "time_format"); -    INIT_FIELD(context, string, date_fmt,  +    INIT_FIELD(context, string, date_fmt,  	       "%Y-%m-%d", "date_format"); -    INIT_FIELD(context, bool, log_utc,  +    INIT_FIELD(context, bool, log_utc,  	       FALSE, "log_utc"); -     +      /* init dns-proxy slime */ -    tmp = krb5_config_get_string(context, NULL, "libdefaults",  +    tmp = krb5_config_get_string(context, NULL, "libdefaults",  				 "dns_proxy", NULL); -    if(tmp)  +    if(tmp)  	roken_gethostby_setup(context->http_proxy, tmp);      krb5_free_host_realm (context, context->default_realms);      context->default_realms = NULL; @@ -152,9 +184,9 @@ init_context_from_config_file(krb5_context context)  	char **adr, **a;  	krb5_set_extra_addresses(context, NULL); -	adr = krb5_config_get_strings(context, NULL,  -				      "libdefaults",  -				      "extra_addresses",  +	adr = krb5_config_get_strings(context, NULL, +				      "libdefaults", +				      "extra_addresses",  				      NULL);  	memset(&addresses, 0, sizeof(addresses));  	for(a = adr; a && *a; a++) { @@ -167,9 +199,9 @@ init_context_from_config_file(krb5_context context)  	krb5_config_free_strings(adr);  	krb5_set_ignore_addresses(context, NULL); -	adr = krb5_config_get_strings(context, NULL,  -				      "libdefaults",  -				      "ignore_addresses",  +	adr = krb5_config_get_strings(context, NULL, +				      "libdefaults", +				      "ignore_addresses",  				      NULL);  	memset(&addresses, 0, sizeof(addresses));  	for(a = adr; a && *a; a++) { @@ -181,7 +213,7 @@ init_context_from_config_file(krb5_context context)  	}  	krb5_config_free_strings(adr);      } -     +      INIT_FIELD(context, bool, scan_interfaces, TRUE, "scan_interfaces");      INIT_FIELD(context, int, fcache_vno, 0, "fcache_version");      /* prefer dns_lookup_kdc over srv_lookup. */ @@ -192,9 +224,138 @@ init_context_from_config_file(krb5_context context)      INIT_FLAG(context, flags, KRB5_CTX_F_CHECK_PAC, TRUE, "check_pac");      context->default_cc_name = NULL;      context->default_cc_name_set = 0; + +    s = krb5_config_get_strings(context, NULL, "logging", "krb5", NULL); +    if(s) { +	char **p; +	krb5_initlog(context, "libkrb5", &context->debug_dest); +	for(p = s; *p; p++) +	    krb5_addlog_dest(context, context->debug_dest, *p); +	krb5_config_free_strings(s); +    } + +    tmp = krb5_config_get_string(context, NULL, "libdefaults", +				 "check-rd-req-server", NULL); +    if (tmp == NULL && !issuid()) +	tmp = getenv("KRB5_CHECK_RD_REQ_SERVER"); +    if(tmp) { +	if (strcasecmp(tmp, "ignore") == 0) +	    context->flags |= KRB5_CTX_F_RD_REQ_IGNORE; +    } +      return 0;  } +static krb5_error_code +cc_ops_register(krb5_context context) +{ +    context->cc_ops = NULL; +    context->num_cc_ops = 0; + +#ifndef KCM_IS_API_CACHE +    krb5_cc_register(context, &krb5_acc_ops, TRUE); +#endif +    krb5_cc_register(context, &krb5_fcc_ops, TRUE); +    krb5_cc_register(context, &krb5_mcc_ops, TRUE); +#ifdef HAVE_SCC +    krb5_cc_register(context, &krb5_scc_ops, TRUE); +#endif +#ifdef HAVE_KCM +#ifdef KCM_IS_API_CACHE +    krb5_cc_register(context, &krb5_akcm_ops, TRUE); +#endif +    krb5_cc_register(context, &krb5_kcm_ops, TRUE); +#endif +    _krb5_load_ccache_plugins(context); +    return 0; +} + +static krb5_error_code +cc_ops_copy(krb5_context context, const krb5_context src_context) +{ +    const krb5_cc_ops **cc_ops; + +    context->cc_ops = NULL; +    context->num_cc_ops = 0; + +    if (src_context->num_cc_ops == 0) +	return 0; + +    cc_ops = malloc(sizeof(cc_ops[0]) * src_context->num_cc_ops); +    if (cc_ops == NULL) { +	krb5_set_error_message(context, KRB5_CC_NOMEM, +			       N_("malloc: out of memory", "")); +	return KRB5_CC_NOMEM; +    } + +    memcpy(rk_UNCONST(cc_ops), src_context->cc_ops, +	   sizeof(cc_ops[0]) * src_context->num_cc_ops); +    context->cc_ops = cc_ops; +    context->num_cc_ops = src_context->num_cc_ops; + +    return 0; +} + +static krb5_error_code +kt_ops_register(krb5_context context) +{ +    context->num_kt_types = 0; +    context->kt_types     = NULL; + +    krb5_kt_register (context, &krb5_fkt_ops); +    krb5_kt_register (context, &krb5_wrfkt_ops); +    krb5_kt_register (context, &krb5_javakt_ops); +    krb5_kt_register (context, &krb5_mkt_ops); +#ifndef HEIMDAL_SMALLER +    krb5_kt_register (context, &krb5_akf_ops); +#endif +    krb5_kt_register (context, &krb5_any_ops); +    return 0; +} + +static krb5_error_code +kt_ops_copy(krb5_context context, const krb5_context src_context) +{ +    context->num_kt_types = 0; +    context->kt_types     = NULL; + +    if (src_context->num_kt_types == 0) +	return 0; + +    context->kt_types = malloc(sizeof(context->kt_types[0]) * src_context->num_kt_types); +    if (context->kt_types == NULL) { +	krb5_set_error_message(context, ENOMEM, +			       N_("malloc: out of memory", "")); +	return ENOMEM; +    } + +    context->num_kt_types = src_context->num_kt_types; +    memcpy(context->kt_types, src_context->kt_types, +	   sizeof(context->kt_types[0]) * src_context->num_kt_types); + +    return 0; +} + +static const char *sysplugin_dirs[] =  { +    LIBDIR "/plugin/krb5", +#ifdef __APPLE__ +    "/Library/KerberosPlugins/KerberosFrameworkPlugins", +    "/System/Library/KerberosPlugins/KerberosFrameworkPlugins", +#endif +    NULL +}; + +static void +init_context_once(void *ctx) +{ +    krb5_context context = ctx; + +    _krb5_load_plugins(context, "krb5", sysplugin_dirs); + +    bindtextdomain(HEIMDAL_TEXTDOMAIN, HEIMDAL_LOCALEDIR); +} + +  /**   * Initializes the context structure and reads the configuration file   * /etc/krb5.conf. The structure should be freed by calling @@ -210,9 +371,10 @@ init_context_from_config_file(krb5_context context)   * @ingroup krb5   */ -krb5_error_code KRB5_LIB_FUNCTION +KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL  krb5_init_context(krb5_context *context)  { +    static heim_base_once_t init_context = HEIM_BASE_ONCE_INIT;      krb5_context p;      krb5_error_code ret;      char **files; @@ -230,55 +392,181 @@ krb5_init_context(krb5_context *context)      }      HEIMDAL_MUTEX_init(p->mutex); +    p->flags |= KRB5_CTX_F_HOMEDIR_ACCESS; +      ret = krb5_get_default_config_files(&files); -    if(ret)  +    if(ret)  	goto out;      ret = krb5_set_config_files(p, files);      krb5_free_config_files(files); -    if(ret)  +    if(ret)  	goto out;      /* init error tables */      krb5_init_ets(p); +    cc_ops_register(p); +    kt_ops_register(p); -    p->cc_ops = NULL; -    p->num_cc_ops = 0; -    krb5_cc_register(p, &krb5_acc_ops, TRUE); -    krb5_cc_register(p, &krb5_fcc_ops, TRUE); -    krb5_cc_register(p, &krb5_mcc_ops, TRUE); -#ifdef HAVE_KCM -    krb5_cc_register(p, &krb5_kcm_ops, TRUE); +#ifdef PKINIT +    ret = hx509_context_init(&p->hx509ctx); +    if (ret) +	goto out;  #endif - -    p->num_kt_types = 0; -    p->kt_types     = NULL; -    krb5_kt_register (p, &krb5_fkt_ops); -    krb5_kt_register (p, &krb5_wrfkt_ops); -    krb5_kt_register (p, &krb5_javakt_ops); -    krb5_kt_register (p, &krb5_mkt_ops); -    krb5_kt_register (p, &krb5_akf_ops); -    krb5_kt_register (p, &krb4_fkt_ops); -    krb5_kt_register (p, &krb5_srvtab_fkt_ops); -    krb5_kt_register (p, &krb5_any_ops); +    if (rk_SOCK_INIT()) +	p->flags |= KRB5_CTX_F_SOCKETS_INITIALIZED;  out:      if(ret) {  	krb5_free_context(p);  	p = NULL; +    } else { +	heim_base_once_f(&init_context, p, init_context_once);      }      *context = p;      return ret;  } +#ifndef HEIMDAL_SMALLER + +KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL +krb5_get_permitted_enctypes(krb5_context context, +			    krb5_enctype **etypes) +{ +    return krb5_get_default_in_tkt_etypes(context, KRB5_PDU_NONE, etypes); +} + +/* + * + */ + +static krb5_error_code +copy_etypes (krb5_context context, +	     krb5_enctype *enctypes, +	     krb5_enctype **ret_enctypes) +{ +    unsigned int i; + +    for (i = 0; enctypes[i]; i++) +	; +    i++; + +    *ret_enctypes = malloc(sizeof(ret_enctypes[0]) * i); +    if (*ret_enctypes == NULL) { +	krb5_set_error_message(context, ENOMEM, +			       N_("malloc: out of memory", "")); +	return ENOMEM; +    } +    memcpy(*ret_enctypes, enctypes, sizeof(ret_enctypes[0]) * i); +    return 0; +} + +/** + * Make a copy for the Kerberos 5 context, the new krb5_context shoud + * be freed with krb5_free_context(). + * + * @param context the Kerberos context to copy + * @param out the copy of the Kerberos, set to NULL error. + * + * @return Returns 0 to indicate success.  Otherwise an kerberos et + * error code is returned, see krb5_get_error_message(). + * + * @ingroup krb5 + */ + +KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL +krb5_copy_context(krb5_context context, krb5_context *out) +{ +    krb5_error_code ret; +    krb5_context p; + +    *out = NULL; + +    p = calloc(1, sizeof(*p)); +    if (p == NULL) { +	krb5_set_error_message(context, ENOMEM, N_("malloc: out of memory", "")); +	return ENOMEM; +    } + +    p->mutex = malloc(sizeof(HEIMDAL_MUTEX)); +    if (p->mutex == NULL) { +	krb5_set_error_message(context, ENOMEM, N_("malloc: out of memory", "")); +	free(p); +	return ENOMEM; +    } +    HEIMDAL_MUTEX_init(p->mutex); + + +    if (context->default_cc_name) +	p->default_cc_name = strdup(context->default_cc_name); +    if (context->default_cc_name_env) +	p->default_cc_name_env = strdup(context->default_cc_name_env); + +    if (context->etypes) { +	ret = copy_etypes(context, context->etypes, &p->etypes); +	if (ret) +	    goto out; +    } +    if (context->etypes_des) { +	ret = copy_etypes(context, context->etypes_des, &p->etypes_des); +	if (ret) +	    goto out; +    } + +    if (context->default_realms) { +	ret = krb5_copy_host_realm(context, +				   context->default_realms, &p->default_realms); +	if (ret) +	    goto out; +    } + +    ret = _krb5_config_copy(context, context->cf, &p->cf); +    if (ret) +	goto out; + +    /* XXX should copy */ +    krb5_init_ets(p); + +    cc_ops_copy(p, context); +    kt_ops_copy(p, context); + +#if 0 /* XXX */ +    if(context->warn_dest != NULL) +	; +    if(context->debug_dest != NULL) +	; +#endif + +    ret = krb5_set_extra_addresses(p, context->extra_addresses); +    if (ret) +	goto out; +    ret = krb5_set_extra_addresses(p, context->ignore_addresses); +    if (ret) +	goto out; + +    ret = _krb5_copy_send_to_kdc_func(p, context); +    if (ret) +	goto out; + +    *out = p; + +    return 0; + + out: +    krb5_free_context(p); +    return ret; +} + +#endif +  /**   * Frees the krb5_context allocated by krb5_init_context().   *   * @param context context to be freed.   * - *  @ingroup krb5 -*/ + * @ingroup krb5 + */ -void KRB5_LIB_FUNCTION +KRB5_LIB_FUNCTION void KRB5_LIB_CALL  krb5_free_context(krb5_context context)  {      if (context->default_cc_name) @@ -290,18 +578,28 @@ krb5_free_context(krb5_context context)      krb5_free_host_realm (context, context->default_realms);      krb5_config_file_free (context, context->cf);      free_error_table (context->et_list); -    free(context->cc_ops); +    free(rk_UNCONST(context->cc_ops));      free(context->kt_types); -    krb5_clear_error_string(context); +    krb5_clear_error_message(context);      if(context->warn_dest != NULL)  	krb5_closelog(context, context->warn_dest); +    if(context->debug_dest != NULL) +	krb5_closelog(context, context->debug_dest);      krb5_set_extra_addresses(context, NULL);      krb5_set_ignore_addresses(context, NULL);      krb5_set_send_to_kdc_func(context, NULL, NULL); -    if (context->mutex != NULL) { -	HEIMDAL_MUTEX_destroy(context->mutex); -	free(context->mutex); + +#ifdef PKINIT +    if (context->hx509ctx) +	hx509_context_free(&context->hx509ctx); +#endif + +    HEIMDAL_MUTEX_destroy(context->mutex); +    free(context->mutex); +    if (context->flags & KRB5_CTX_F_SOCKETS_INITIALIZED) { + 	rk_SOCK_EXIT();      } +      memset(context, 0, sizeof(*context));      free(context);  } @@ -318,14 +616,14 @@ krb5_free_context(krb5_context context)   * @ingroup krb5   */ -krb5_error_code KRB5_LIB_FUNCTION +KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL  krb5_set_config_files(krb5_context context, char **filenames)  {      krb5_error_code ret;      krb5_config_binding *tmp = NULL;      while(filenames != NULL && *filenames != NULL && **filenames != '\0') {  	ret = krb5_config_parse_file_multi(context, *filenames, &tmp); -	if(ret != 0 && ret != ENOENT && ret != EACCES) { +	if(ret != 0 && ret != ENOENT && ret != EACCES && ret != EPERM) {  	    krb5_config_file_free(context, tmp);  	    return ret;  	} @@ -337,6 +635,11 @@ krb5_set_config_files(krb5_context context, char **filenames)      if(tmp == NULL)  	return ENXIO;  #endif + +#ifdef _WIN32 +    _krb5_load_config_from_registry(context, &tmp); +#endif +      krb5_config_file_free(context, context->cf);      context->cf = tmp;      ret = init_context_from_config_file(context); @@ -373,7 +676,7 @@ add_file(char ***pfilenames, int *len, char *file)   *  `pq' isn't free, it's up the the caller   */ -krb5_error_code KRB5_LIB_FUNCTION +KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL  krb5_prepend_config_files(const char *filelist, char **pq, char ***ret_pp)  {      krb5_error_code ret; @@ -389,7 +692,7 @@ krb5_prepend_config_files(const char *filelist, char **pq, char ***ret_pp)      while(1) {  	ssize_t l;  	q = p; -	l = strsep_copy(&q, ":", NULL, 0); +	l = strsep_copy(&q, PATH_SEP, NULL, 0);  	if(l == -1)  	    break;  	fn = malloc(l + 1); @@ -397,7 +700,7 @@ krb5_prepend_config_files(const char *filelist, char **pq, char ***ret_pp)  	    krb5_free_config_files(pp);  	    return ENOMEM;  	} -	l = strsep_copy(&p, ":", fn, l + 1); +	(void)strsep_copy(&p, PATH_SEP, fn, l + 1);  	ret = add_file(&pp, &len, fn);  	if (ret) {  	    krb5_free_config_files(pp); @@ -438,12 +741,12 @@ krb5_prepend_config_files(const char *filelist, char **pq, char ***ret_pp)   * @ingroup krb5   */ -krb5_error_code KRB5_LIB_FUNCTION +KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL  krb5_prepend_config_files_default(const char *filelist, char ***pfilenames)  {      krb5_error_code ret;      char **defpp, **pp = NULL; -     +      ret = krb5_get_default_config_files(&defpp);      if (ret)  	return ret; @@ -452,11 +755,50 @@ krb5_prepend_config_files_default(const char *filelist, char ***pfilenames)      krb5_free_config_files(defpp);      if (ret) {  	return ret; -    }	 +    }      *pfilenames = pp;      return 0;  } +#ifdef _WIN32 + +/** + * Checks the registry for configuration file location + * + * Kerberos for Windows and other legacy Kerberos applications expect + * to find the configuration file location in the + * SOFTWARE\MIT\Kerberos registry key under the value "config". + */ +char * +_krb5_get_default_config_config_files_from_registry() +{ +    static const char * KeyName = "Software\\MIT\\Kerberos"; +    char *config_file = NULL; +    LONG rcode; +    HKEY key; + +    rcode = RegOpenKeyEx(HKEY_CURRENT_USER, KeyName, 0, KEY_READ, &key); +    if (rcode == ERROR_SUCCESS) { +        config_file = _krb5_parse_reg_value_as_multi_string(NULL, key, "config", +                                                            REG_NONE, 0, PATH_SEP); +        RegCloseKey(key); +    } + +    if (config_file) +        return config_file; + +    rcode = RegOpenKeyEx(HKEY_LOCAL_MACHINE, KeyName, 0, KEY_READ, &key); +    if (rcode == ERROR_SUCCESS) { +        config_file = _krb5_parse_reg_value_as_multi_string(NULL, key, "config", +                                                            REG_NONE, 0, PATH_SEP); +        RegCloseKey(key); +    } + +    return config_file; +} + +#endif +  /**   * Get the global configuration list.   * @@ -468,7 +810,7 @@ krb5_prepend_config_files_default(const char *filelist, char ***pfilenames)   * @ingroup krb5   */ -krb5_error_code KRB5_LIB_FUNCTION  +KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL  krb5_get_default_config_files(char ***pfilenames)  {      const char *files = NULL; @@ -477,6 +819,22 @@ krb5_get_default_config_files(char ***pfilenames)          return EINVAL;      if(!issuid())  	files = getenv("KRB5_CONFIG"); + +#ifdef _WIN32 +    if (files == NULL) { +        char * reg_files; +        reg_files = _krb5_get_default_config_config_files_from_registry(); +        if (reg_files != NULL) { +            krb5_error_code code; + +            code = krb5_prepend_config_files(reg_files, NULL, pfilenames); +            free(reg_files); + +            return code; +        } +    } +#endif +      if (files == NULL)  	files = krb5_config_file; @@ -486,7 +844,8 @@ krb5_get_default_config_files(char ***pfilenames)  /**   * Free a list of configuration files.   * - * @param filenames list to be freed. + * @param filenames list, terminated with a NULL pointer, to be + * freed. NULL is an valid argument.   *   * @return Returns 0 to indicate success. Otherwise an kerberos et   * error code is returned, see krb5_get_error_message(). @@ -494,11 +853,11 @@ krb5_get_default_config_files(char ***pfilenames)   * @ingroup krb5   */ -void KRB5_LIB_FUNCTION +KRB5_LIB_FUNCTION void KRB5_LIB_CALL  krb5_free_config_files(char **filenames)  {      char **p; -    for(p = filenames; *p != NULL; p++) +    for(p = filenames; p && *p != NULL; p++)  	free(*p);      free(filenames);  } @@ -516,7 +875,7 @@ krb5_free_config_files(char **filenames)   * @ingroup krb5   */ -const krb5_enctype * KRB5_LIB_FUNCTION +KRB5_LIB_FUNCTION const krb5_enctype * KRB5_LIB_CALL  krb5_kerberos_enctypes(krb5_context context)  {      static const krb5_enctype p[] = { @@ -534,36 +893,51 @@ krb5_kerberos_enctypes(krb5_context context)  }  /* - * set `etype' to a malloced list of the default enctypes + *   */  static krb5_error_code -default_etypes(krb5_context context, krb5_enctype **etype) +copy_enctypes(krb5_context context, +	      const krb5_enctype *in, +	      krb5_enctype **out)  { -    const krb5_enctype *p; -    krb5_enctype *e = NULL, *ep; -    int i, n = 0; - -    p = krb5_kerberos_enctypes(context); +    krb5_enctype *p = NULL; +    size_t m, n; -    for (i = 0; p[i] != ETYPE_NULL; i++) { -	if (krb5_enctype_valid(context, p[i]) != 0) +    for (n = 0; in[n]; n++) +	; +    n++; +    ALLOC(p, n); +    if(p == NULL) +	return krb5_enomem(context); +    for (n = 0, m = 0; in[n]; n++) { +	if (krb5_enctype_valid(context, in[n]) != 0)  	    continue; -	ep = realloc(e, (n + 2) * sizeof(*e)); -	if (ep == NULL) { -	    free(e); -	    krb5_set_error_string (context, "malloc: out of memory"); -	    return ENOMEM; -	} -	e = ep; -	e[n] = p[i]; -	e[n + 1] = ETYPE_NULL; -	n++; +	p[m++] = in[n];      } -    *etype = e; +    p[m] = KRB5_ENCTYPE_NULL; +    if (m == 0) { +	free(p); +	krb5_set_error_message (context, KRB5_PROG_ETYPE_NOSUPP, +				N_("no valid enctype set", "")); +	return KRB5_PROG_ETYPE_NOSUPP; +    } +    *out = p;      return 0;  } + +/* + * set `etype' to a malloced list of the default enctypes + */ + +static krb5_error_code +default_etypes(krb5_context context, krb5_enctype **etype) +{ +    const krb5_enctype *p = krb5_kerberos_enctypes(context); +    return copy_enctypes(context, p, etype); +} +  /**   * Set the default encryption types that will be use in communcation   * with the KDC, clients and servers. @@ -577,27 +951,17 @@ default_etypes(krb5_context context, krb5_enctype **etype)   * @ingroup krb5   */ -krb5_error_code KRB5_LIB_FUNCTION -krb5_set_default_in_tkt_etypes(krb5_context context,  +KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL +krb5_set_default_in_tkt_etypes(krb5_context context,  			       const krb5_enctype *etypes)  { +    krb5_error_code ret;      krb5_enctype *p = NULL; -    int i;      if(etypes) { -	for (i = 0; etypes[i]; ++i) { -	    krb5_error_code ret; -	    ret = krb5_enctype_valid(context, etypes[i]); -	    if (ret) -		return ret; -	} -	++i; -	ALLOC(p, i); -	if(!p) { -	    krb5_set_error_string (context, "malloc: out of memory"); -	    return ENOMEM; -	} -	memmove(p, etypes, i * sizeof(krb5_enctype)); +	ret = copy_enctypes(context, etypes, &p); +	if (ret) +	    return ret;      }      if(context->etypes)  	free(context->etypes); @@ -619,75 +983,69 @@ krb5_set_default_in_tkt_etypes(krb5_context context,   * @ingroup krb5   */ -krb5_error_code KRB5_LIB_FUNCTION +KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL  krb5_get_default_in_tkt_etypes(krb5_context context, +			       krb5_pdu pdu_type,  			       krb5_enctype **etypes)  { -  krb5_enctype *p; -  int i; -  krb5_error_code ret; - -  if(context->etypes) { -    for(i = 0; context->etypes[i]; i++); -    ++i; -    ALLOC(p, i); -    if(!p) { -      krb5_set_error_string (context, "malloc: out of memory"); -      return ENOMEM; +    krb5_enctype *enctypes = NULL; +    krb5_error_code ret; +    krb5_enctype *p; + +    heim_assert(pdu_type == KRB5_PDU_AS_REQUEST ||  +		pdu_type == KRB5_PDU_TGS_REQUEST || +		pdu_type == KRB5_PDU_NONE, "pdu contant not as expected"); + +    if (pdu_type == KRB5_PDU_AS_REQUEST && context->as_etypes != NULL) +	enctypes = context->as_etypes; +    else if (pdu_type == KRB5_PDU_TGS_REQUEST && context->tgs_etypes != NULL) +	enctypes = context->tgs_etypes; +    else if (context->etypes != NULL) +	enctypes = context->etypes; + +    if (enctypes != NULL) { +	ret = copy_enctypes(context, enctypes, &p); +	if (ret) +	    return ret; +    } else { +	ret = default_etypes(context, &p); +	if (ret) +	    return ret;      } -    memmove(p, context->etypes, i * sizeof(krb5_enctype)); -  } else { -    ret = default_etypes(context, &p); -    if (ret) -      return ret; -  } -  *etypes = p; -  return 0; -} - -/** - * Return the error string for the error code. The caller must not - * free the string. - * - * @param context Kerberos 5 context. - * @param code Kerberos error code. - * - * @return the error message matching code - * - * @ingroup krb5 - */ - -const char* KRB5_LIB_FUNCTION -krb5_get_err_text(krb5_context context, krb5_error_code code) -{ -    const char *p = NULL; -    if(context != NULL) -	p = com_right(context->et_list, code); -    if(p == NULL) -	p = strerror(code); -    if (p == NULL) -	p = "Unknown error"; -    return p; +    *etypes = p; +    return 0;  }  /** - * Init the built-in ets in the Kerberos library.  + * Init the built-in ets in the Kerberos library.   *   * @param context kerberos context to add the ets too   *   * @ingroup krb5   */ -void KRB5_LIB_FUNCTION +KRB5_LIB_FUNCTION void KRB5_LIB_CALL  krb5_init_ets(krb5_context context)  {      if(context->et_list == NULL){  	krb5_add_et_list(context, initialize_krb5_error_table_r);  	krb5_add_et_list(context, initialize_asn1_error_table_r);  	krb5_add_et_list(context, initialize_heim_error_table_r); +  	krb5_add_et_list(context, initialize_k524_error_table_r); + +#ifdef COM_ERR_BINDDOMAIN_krb5 +	bindtextdomain(COM_ERR_BINDDOMAIN_krb5, HEIMDAL_LOCALEDIR); +	bindtextdomain(COM_ERR_BINDDOMAIN_asn1, HEIMDAL_LOCALEDIR); +	bindtextdomain(COM_ERR_BINDDOMAIN_heim, HEIMDAL_LOCALEDIR); +	bindtextdomain(COM_ERR_BINDDOMAIN_k524, HEIMDAL_LOCALEDIR); +#endif +  #ifdef PKINIT  	krb5_add_et_list(context, initialize_hx_error_table_r); +#ifdef COM_ERR_BINDDOMAIN_hx +	bindtextdomain(COM_ERR_BINDDOMAIN_hx, HEIMDAL_LOCALEDIR); +#endif  #endif      }  } @@ -701,7 +1059,7 @@ krb5_init_ets(krb5_context context)   * @ingroup krb5   */ -void KRB5_LIB_FUNCTION +KRB5_LIB_FUNCTION void KRB5_LIB_CALL  krb5_set_use_admin_kdc (krb5_context context, krb5_boolean flag)  {      context->use_admin_kdc = flag; @@ -717,7 +1075,7 @@ krb5_set_use_admin_kdc (krb5_context context, krb5_boolean flag)   * @ingroup krb5   */ -krb5_boolean KRB5_LIB_FUNCTION +KRB5_LIB_FUNCTION krb5_boolean KRB5_LIB_CALL  krb5_get_use_admin_kdc (krb5_context context)  {      return context->use_admin_kdc; @@ -736,12 +1094,12 @@ krb5_get_use_admin_kdc (krb5_context context)   * @ingroup krb5   */ -krb5_error_code KRB5_LIB_FUNCTION +KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL  krb5_add_extra_addresses(krb5_context context, krb5_addresses *addresses)  {      if(context->extra_addresses) -	return krb5_append_addresses(context,  +	return krb5_append_addresses(context,  				     context->extra_addresses, addresses);      else  	return krb5_set_extra_addresses(context, addresses); @@ -760,7 +1118,7 @@ krb5_add_extra_addresses(krb5_context context, krb5_addresses *addresses)   * @ingroup krb5   */ -krb5_error_code KRB5_LIB_FUNCTION +KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL  krb5_set_extra_addresses(krb5_context context, const krb5_addresses *addresses)  {      if(context->extra_addresses) @@ -776,7 +1134,7 @@ krb5_set_extra_addresses(krb5_context context, const krb5_addresses *addresses)      if(context->extra_addresses == NULL) {  	context->extra_addresses = malloc(sizeof(*context->extra_addresses));  	if(context->extra_addresses == NULL) { -	    krb5_set_error_string (context, "malloc: out of memory"); +	    krb5_set_error_message (context, ENOMEM, N_("malloc: out of memory", ""));  	    return ENOMEM;  	}      } @@ -796,7 +1154,7 @@ krb5_set_extra_addresses(krb5_context context, const krb5_addresses *addresses)   * @ingroup krb5   */ -krb5_error_code KRB5_LIB_FUNCTION +KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL  krb5_get_extra_addresses(krb5_context context, krb5_addresses *addresses)  {      if(context->extra_addresses == NULL) { @@ -819,12 +1177,12 @@ krb5_get_extra_addresses(krb5_context context, krb5_addresses *addresses)   * @ingroup krb5   */ -krb5_error_code KRB5_LIB_FUNCTION +KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL  krb5_add_ignore_addresses(krb5_context context, krb5_addresses *addresses)  {      if(context->ignore_addresses) -	return krb5_append_addresses(context,  +	return krb5_append_addresses(context,  				     context->ignore_addresses, addresses);      else  	return krb5_set_ignore_addresses(context, addresses); @@ -843,7 +1201,7 @@ krb5_add_ignore_addresses(krb5_context context, krb5_addresses *addresses)   * @ingroup krb5   */ -krb5_error_code KRB5_LIB_FUNCTION +KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL  krb5_set_ignore_addresses(krb5_context context, const krb5_addresses *addresses)  {      if(context->ignore_addresses) @@ -858,7 +1216,7 @@ krb5_set_ignore_addresses(krb5_context context, const krb5_addresses *addresses)      if(context->ignore_addresses == NULL) {  	context->ignore_addresses = malloc(sizeof(*context->ignore_addresses));  	if(context->ignore_addresses == NULL) { -	    krb5_set_error_string (context, "malloc: out of memory"); +	    krb5_set_error_message (context, ENOMEM, N_("malloc: out of memory", ""));  	    return ENOMEM;  	}      } @@ -878,7 +1236,7 @@ krb5_set_ignore_addresses(krb5_context context, const krb5_addresses *addresses)   * @ingroup krb5   */ -krb5_error_code KRB5_LIB_FUNCTION +KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL  krb5_get_ignore_addresses(krb5_context context, krb5_addresses *addresses)  {      if(context->ignore_addresses == NULL) { @@ -900,7 +1258,7 @@ krb5_get_ignore_addresses(krb5_context context, krb5_addresses *addresses)   * @ingroup krb5   */ -krb5_error_code KRB5_LIB_FUNCTION +KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL  krb5_set_fcache_version(krb5_context context, int version)  {      context->fcache_vno = version; @@ -919,7 +1277,7 @@ krb5_set_fcache_version(krb5_context context, int version)   * @ingroup krb5   */ -krb5_error_code KRB5_LIB_FUNCTION +KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL  krb5_get_fcache_version(krb5_context context, int *version)  {      *version = context->fcache_vno; @@ -935,7 +1293,7 @@ krb5_get_fcache_version(krb5_context context, int *version)   */ -krb5_boolean KRB5_LIB_FUNCTION +KRB5_LIB_FUNCTION krb5_boolean KRB5_LIB_CALL  krb5_is_thread_safe(void)  {  #ifdef ENABLE_PTHREAD_SUPPORT @@ -954,7 +1312,7 @@ krb5_is_thread_safe(void)   * @ingroup krb5   */ -void KRB5_LIB_FUNCTION +KRB5_LIB_FUNCTION void KRB5_LIB_CALL  krb5_set_dns_canonicalize_hostname (krb5_context context, krb5_boolean flag)  {      if (flag) @@ -973,7 +1331,7 @@ krb5_set_dns_canonicalize_hostname (krb5_context context, krb5_boolean flag)   * @ingroup krb5   */ -krb5_boolean KRB5_LIB_FUNCTION +KRB5_LIB_FUNCTION krb5_boolean KRB5_LIB_CALL  krb5_get_dns_canonicalize_hostname (krb5_context context)  {      return (context->flags & KRB5_CTX_F_DNS_CANONICALIZE_HOSTNAME) ? 1 : 0; @@ -986,12 +1344,12 @@ krb5_get_dns_canonicalize_hostname (krb5_context context)   * @param sec seconds part of offset.   * @param usec micro seconds part of offset.   * - * @return return non zero if the library uses DNS to canonicalize hostnames. + * @return returns zero   *   * @ingroup krb5   */ -krb5_error_code KRB5_LIB_FUNCTION +KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL  krb5_get_kdc_sec_offset (krb5_context context, int32_t *sec, int32_t *usec)  {      if (sec) @@ -1002,6 +1360,27 @@ krb5_get_kdc_sec_offset (krb5_context context, int32_t *sec, int32_t *usec)  }  /** + * Set current offset in time to the KDC. + * + * @param context Kerberos 5 context. + * @param sec seconds part of offset. + * @param usec micro seconds part of offset. + * + * @return returns zero + * + * @ingroup krb5 + */ + +KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL +krb5_set_kdc_sec_offset (krb5_context context, int32_t sec, int32_t usec) +{ +    context->kdc_sec_offset = sec; +    if (usec >= 0) +	context->kdc_usec_offset = usec; +    return 0; +} + +/**   * Get max time skew allowed.   *   * @param context Kerberos 5 context. @@ -1011,7 +1390,7 @@ krb5_get_kdc_sec_offset (krb5_context context, int32_t *sec, int32_t *usec)   * @ingroup krb5   */ -time_t KRB5_LIB_FUNCTION +KRB5_LIB_FUNCTION time_t KRB5_LIB_CALL  krb5_get_max_time_skew (krb5_context context)  {      return context->max_skew; @@ -1026,8 +1405,112 @@ krb5_get_max_time_skew (krb5_context context)   * @ingroup krb5   */ -void KRB5_LIB_FUNCTION +KRB5_LIB_FUNCTION void KRB5_LIB_CALL  krb5_set_max_time_skew (krb5_context context, time_t t)  {      context->max_skew = t;  } + +/* + * Init encryption types in len, val with etypes. + * + * @param context Kerberos 5 context. + * @param pdu_type type of pdu + * @param len output length of val. + * @param val output array of enctypes. + * @param etypes etypes to set val and len to, if NULL, use default enctypes. + + * @return Returns 0 to indicate success. Otherwise an kerberos et + * error code is returned, see krb5_get_error_message(). + * + * @ingroup krb5 + */ + +KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL +_krb5_init_etype(krb5_context context, +		 krb5_pdu pdu_type, +		 unsigned *len, +		 krb5_enctype **val, +		 const krb5_enctype *etypes) +{ +    krb5_error_code ret; + +    if (etypes == NULL) +	ret = krb5_get_default_in_tkt_etypes(context, pdu_type, val); +    else +	ret = copy_enctypes(context, etypes, val); +    if (ret) +	return ret; + +    if (len) { +	*len = 0; +	while ((*val)[*len] != KRB5_ENCTYPE_NULL) +	    (*len)++; +    } +    return 0; +} + +/* + * Allow homedir accces + */ + +static HEIMDAL_MUTEX homedir_mutex = HEIMDAL_MUTEX_INITIALIZER; +static krb5_boolean allow_homedir = TRUE; + +krb5_boolean +_krb5_homedir_access(krb5_context context) +{ +    krb5_boolean allow; + +#ifdef HAVE_GETEUID +    /* is never allowed for root */ +    if (geteuid() == 0) +	return FALSE; +#endif + +    if (context && (context->flags & KRB5_CTX_F_HOMEDIR_ACCESS) == 0) +	return FALSE; + +    HEIMDAL_MUTEX_lock(&homedir_mutex); +    allow = allow_homedir; +    HEIMDAL_MUTEX_unlock(&homedir_mutex); +    return allow; +} + +/** + * Enable and disable home directory access on either the global state + * or the krb5_context state. By calling krb5_set_home_dir_access() + * with context set to NULL, the global state is configured otherwise + * the state for the krb5_context is modified. + * + * For home directory access to be allowed, both the global state and + * the krb5_context state have to be allowed. + * + * Administrator (root user), never uses the home directory. + * + * @param context a Kerberos 5 context or NULL + * @param allow allow if TRUE home directory + * @return the old value + * + * @ingroup krb5 + */ + +KRB5_LIB_FUNCTION krb5_boolean KRB5_LIB_CALL +krb5_set_home_dir_access(krb5_context context, krb5_boolean allow) +{ +    krb5_boolean old; +    if (context) { +	old = (context->flags & KRB5_CTX_F_HOMEDIR_ACCESS) ? TRUE : FALSE; +	if (allow) +	    context->flags |= KRB5_CTX_F_HOMEDIR_ACCESS; +	else +	    context->flags &= ~KRB5_CTX_F_HOMEDIR_ACCESS; +    } else { +	HEIMDAL_MUTEX_lock(&homedir_mutex); +	old = allow_homedir; +	allow_homedir = allow; +	HEIMDAL_MUTEX_unlock(&homedir_mutex); +    } + +    return old; +} | 
