diff options
| author | Stanislav Sedov <stas@FreeBSD.org> | 2011-10-05 07:23:29 +0000 |
|---|---|---|
| committer | Stanislav Sedov <stas@FreeBSD.org> | 2011-10-05 07:23:29 +0000 |
| commit | 7c450da7b446c557e05f34a100b597800967d987 (patch) | |
| tree | 57a48e7e9b592f2d5b713e80a4455820625c2b7b /lib/krb5/context.c | |
| parent | b4e3a10e9339a8400197298021d6ca9b8e3aa039 (diff) | |
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; +} |
