Home | History | Annotate | Line # | Download | only in krb5
      1 /*	$NetBSD: context.c,v 1.8 2023/09/11 15:12:12 christos Exp $	*/
      2 
      3 /*
      4  * Copyright (c) 1997 - 2010 Kungliga Tekniska Hgskolan
      5  * (Royal Institute of Technology, Stockholm, Sweden).
      6  * All rights reserved.
      7  *
      8  * Portions Copyright (c) 2009 Apple Inc. All rights reserved.
      9  *
     10  * Redistribution and use in source and binary forms, with or without
     11  * modification, are permitted provided that the following conditions
     12  * are met:
     13  *
     14  * 1. Redistributions of source code must retain the above copyright
     15  *    notice, this list of conditions and the following disclaimer.
     16  *
     17  * 2. Redistributions in binary form must reproduce the above copyright
     18  *    notice, this list of conditions and the following disclaimer in the
     19  *    documentation and/or other materials provided with the distribution.
     20  *
     21  * 3. Neither the name of the Institute nor the names of its contributors
     22  *    may be used to endorse or promote products derived from this software
     23  *    without specific prior written permission.
     24  *
     25  * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
     26  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
     27  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
     28  * ARE DISCLAIMED.  IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
     29  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
     30  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
     31  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
     32  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
     33  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
     34  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
     35  * SUCH DAMAGE.
     36  */
     37 
     38 #include "krb5_locl.h"
     39 #include <assert.h>
     40 #include <krb5/com_err.h>
     41 #if OPENSSL_VERSION_NUMBER >= 0x30000000UL
     42 #include <openssl/provider.h>
     43 #endif
     44 
     45 #define INIT_FIELD(C, T, E, D, F)					\
     46     (C)->E = krb5_config_get_ ## T ## _default ((C), NULL, (D), 	\
     47 						"libdefaults", F, NULL)
     48 
     49 #define INIT_FLAG(C, O, V, D, F)					\
     50     do {								\
     51 	if (krb5_config_get_bool_default((C), NULL, (D),"libdefaults", F, NULL)) { \
     52 	    (C)->O |= V;						\
     53         }								\
     54     } while(0)
     55 
     56 static krb5_error_code
     57 copy_enctypes(krb5_context context,
     58 	      const krb5_enctype *in,
     59 	      krb5_enctype **out);
     60 
     61 /*
     62  * Set the list of etypes `ret_etypes' from the configuration variable
     63  * `name'
     64  */
     65 
     66 static krb5_error_code
     67 set_etypes (krb5_context context,
     68 	    const char *name,
     69 	    krb5_enctype **ret_enctypes)
     70 {
     71     char **etypes_str;
     72     krb5_enctype *etypes = NULL;
     73 
     74     etypes_str = krb5_config_get_strings(context, NULL, "libdefaults",
     75 					 name, NULL);
     76     if(etypes_str){
     77 	int i, j, k;
     78 	for(i = 0; etypes_str[i]; i++);
     79 	etypes = malloc((i+1) * sizeof(*etypes));
     80 	if (etypes == NULL) {
     81 	    krb5_config_free_strings (etypes_str);
     82 	    return krb5_enomem(context);
     83 	}
     84 	for(j = 0, k = 0; j < i; j++) {
     85 	    krb5_enctype e;
     86 	    if(krb5_string_to_enctype(context, etypes_str[j], &e) != 0)
     87 		continue;
     88 	    if (krb5_enctype_valid(context, e) != 0)
     89 		continue;
     90 	    etypes[k++] = e;
     91 	}
     92 	etypes[k] = ETYPE_NULL;
     93 	krb5_config_free_strings(etypes_str);
     94     }
     95     *ret_enctypes = etypes;
     96     return 0;
     97 }
     98 
     99 /*
    100  * read variables from the configuration file and set in `context'
    101  */
    102 
    103 static krb5_error_code
    104 init_context_from_config_file(krb5_context context)
    105 {
    106     krb5_error_code ret;
    107     const char * tmp;
    108     char **s;
    109     krb5_enctype *tmptypes = NULL;
    110 
    111     INIT_FIELD(context, time, max_skew, 5 * 60, "clockskew");
    112     INIT_FIELD(context, time, kdc_timeout, 30, "kdc_timeout");
    113     INIT_FIELD(context, time, host_timeout, 3, "host_timeout");
    114     INIT_FIELD(context, int, max_retries, 3, "max_retries");
    115 
    116     INIT_FIELD(context, string, http_proxy, NULL, "http_proxy");
    117 
    118     ret = krb5_config_get_bool_default(context, NULL, FALSE,
    119 				       "libdefaults",
    120 				       "allow_weak_crypto", NULL);
    121     if (ret) {
    122 	krb5_enctype_enable(context, ETYPE_DES_CBC_CRC);
    123 	krb5_enctype_enable(context, ETYPE_DES_CBC_MD4);
    124 	krb5_enctype_enable(context, ETYPE_DES_CBC_MD5);
    125 	krb5_enctype_enable(context, ETYPE_DES_CBC_NONE);
    126 	krb5_enctype_enable(context, ETYPE_DES_CFB64_NONE);
    127 	krb5_enctype_enable(context, ETYPE_DES_PCBC_NONE);
    128     }
    129 
    130     ret = set_etypes (context, "default_etypes", &tmptypes);
    131     if(ret)
    132 	return ret;
    133     free(context->etypes);
    134     context->etypes = tmptypes;
    135 
    136     /* The etypes member may change during the lifetime
    137      * of the context. To be able to reset it to
    138      * config value, we keep another copy.
    139      */
    140     free(context->cfg_etypes);
    141     context->cfg_etypes = NULL;
    142     if (tmptypes) {
    143 	ret = copy_enctypes(context, tmptypes, &context->cfg_etypes);
    144 	if (ret)
    145 	    return ret;
    146     }
    147 
    148     ret = set_etypes (context, "default_etypes_des", &tmptypes);
    149     if(ret)
    150 	return ret;
    151     free(context->etypes_des);
    152     context->etypes_des = tmptypes;
    153 
    154     ret = set_etypes (context, "default_as_etypes", &tmptypes);
    155     if(ret)
    156 	return ret;
    157     free(context->as_etypes);
    158     context->as_etypes = tmptypes;
    159 
    160     ret = set_etypes (context, "default_tgs_etypes", &tmptypes);
    161     if(ret)
    162 	return ret;
    163     free(context->tgs_etypes);
    164     context->tgs_etypes = tmptypes;
    165 
    166     ret = set_etypes (context, "permitted_enctypes", &tmptypes);
    167     if(ret)
    168 	return ret;
    169     free(context->permitted_enctypes);
    170     context->permitted_enctypes = tmptypes;
    171 
    172     INIT_FIELD(context, string, default_keytab,
    173 	       KEYTAB_DEFAULT, "default_keytab_name");
    174 
    175     INIT_FIELD(context, string, default_keytab_modify,
    176 	       NULL, "default_keytab_modify_name");
    177 
    178     INIT_FIELD(context, string, time_fmt,
    179 	       "%Y-%m-%dT%H:%M:%S", "time_format");
    180 
    181     INIT_FIELD(context, string, date_fmt,
    182 	       "%Y-%m-%d", "date_format");
    183 
    184     INIT_FIELD(context, bool, log_utc,
    185 	       FALSE, "log_utc");
    186 
    187 
    188 
    189     /* init dns-proxy slime */
    190     tmp = krb5_config_get_string(context, NULL, "libdefaults",
    191 				 "dns_proxy", NULL);
    192     if(tmp)
    193 	roken_gethostby_setup(context->http_proxy, tmp);
    194     krb5_free_host_realm (context, context->default_realms);
    195     context->default_realms = NULL;
    196 
    197     {
    198 	krb5_addresses addresses;
    199 	char **adr, **a;
    200 
    201 	krb5_set_extra_addresses(context, NULL);
    202 	adr = krb5_config_get_strings(context, NULL,
    203 				      "libdefaults",
    204 				      "extra_addresses",
    205 				      NULL);
    206 	memset(&addresses, 0, sizeof(addresses));
    207 	for(a = adr; a && *a; a++) {
    208 	    ret = krb5_parse_address(context, *a, &addresses);
    209 	    if (ret == 0) {
    210 		krb5_add_extra_addresses(context, &addresses);
    211 		krb5_free_addresses(context, &addresses);
    212 	    }
    213 	}
    214 	krb5_config_free_strings(adr);
    215 
    216 	krb5_set_ignore_addresses(context, NULL);
    217 	adr = krb5_config_get_strings(context, NULL,
    218 				      "libdefaults",
    219 				      "ignore_addresses",
    220 				      NULL);
    221 	memset(&addresses, 0, sizeof(addresses));
    222 	for(a = adr; a && *a; a++) {
    223 	    ret = krb5_parse_address(context, *a, &addresses);
    224 	    if (ret == 0) {
    225 		krb5_add_ignore_addresses(context, &addresses);
    226 		krb5_free_addresses(context, &addresses);
    227 	    }
    228 	}
    229 	krb5_config_free_strings(adr);
    230     }
    231 
    232     INIT_FIELD(context, bool, scan_interfaces, TRUE, "scan_interfaces");
    233     INIT_FIELD(context, int, fcache_vno, 0, "fcache_version");
    234     /* prefer dns_lookup_kdc over srv_lookup. */
    235     INIT_FIELD(context, bool, srv_lookup, TRUE, "srv_lookup");
    236     INIT_FIELD(context, bool, srv_lookup, context->srv_lookup, "dns_lookup_kdc");
    237     INIT_FIELD(context, int, large_msg_size, 1400, "large_message_size");
    238     INIT_FIELD(context, int, max_msg_size, 1000 * 1024, "maximum_message_size");
    239     INIT_FLAG(context, flags, KRB5_CTX_F_DNS_CANONICALIZE_HOSTNAME, TRUE, "dns_canonicalize_hostname");
    240     INIT_FLAG(context, flags, KRB5_CTX_F_CHECK_PAC, TRUE, "check_pac");
    241 
    242     if (context->default_cc_name)
    243 	free(context->default_cc_name);
    244     context->default_cc_name = NULL;
    245     context->default_cc_name_set = 0;
    246 
    247     s = krb5_config_get_strings(context, NULL, "logging", "krb5", NULL);
    248     if(s) {
    249 	char **p;
    250 
    251 	if (context->debug_dest)
    252 	    krb5_closelog(context, context->debug_dest);
    253 
    254 	krb5_initlog(context, "libkrb5", &context->debug_dest);
    255 	for(p = s; *p; p++)
    256 	    krb5_addlog_dest(context, context->debug_dest, *p);
    257 	krb5_config_free_strings(s);
    258     }
    259 
    260     tmp = krb5_config_get_string(context, NULL, "libdefaults",
    261 				 "check-rd-req-server", NULL);
    262     if (tmp == NULL && !issuid())
    263 	tmp = getenv("KRB5_CHECK_RD_REQ_SERVER");
    264     if(tmp) {
    265 	if (strcasecmp(tmp, "ignore") == 0)
    266 	    context->flags |= KRB5_CTX_F_RD_REQ_IGNORE;
    267     }
    268     ret = krb5_config_get_bool_default(context, NULL, TRUE,
    269 				       "libdefaults",
    270 				       "fcache_strict_checking", NULL);
    271     if (ret)
    272 	context->flags |= KRB5_CTX_F_FCACHE_STRICT_CHECKING;
    273 
    274     return 0;
    275 }
    276 
    277 static krb5_error_code
    278 cc_ops_register(krb5_context context)
    279 {
    280     context->cc_ops = NULL;
    281     context->num_cc_ops = 0;
    282 
    283 #ifndef KCM_IS_API_CACHE
    284     krb5_cc_register(context, &krb5_acc_ops, TRUE);
    285 #endif
    286     krb5_cc_register(context, &krb5_fcc_ops, TRUE);
    287     krb5_cc_register(context, &krb5_dcc_ops, TRUE);
    288     krb5_cc_register(context, &krb5_mcc_ops, TRUE);
    289 #ifdef HAVE_SCC
    290     krb5_cc_register(context, &krb5_scc_ops, TRUE);
    291 #endif
    292 #ifdef HAVE_KCM
    293 #ifdef KCM_IS_API_CACHE
    294     krb5_cc_register(context, &krb5_akcm_ops, TRUE);
    295 #endif
    296     krb5_cc_register(context, &krb5_kcm_ops, TRUE);
    297 #endif
    298     _krb5_load_ccache_plugins(context);
    299     return 0;
    300 }
    301 
    302 static krb5_error_code
    303 cc_ops_copy(krb5_context context, const krb5_context src_context)
    304 {
    305     const krb5_cc_ops **cc_ops;
    306 
    307     context->cc_ops = NULL;
    308     context->num_cc_ops = 0;
    309 
    310     if (src_context->num_cc_ops == 0)
    311 	return 0;
    312 
    313     cc_ops = malloc(sizeof(cc_ops[0]) * src_context->num_cc_ops);
    314     if (cc_ops == NULL) {
    315 	krb5_set_error_message(context, KRB5_CC_NOMEM,
    316 			       N_("malloc: out of memory", ""));
    317 	return KRB5_CC_NOMEM;
    318     }
    319 
    320     memcpy(rk_UNCONST(cc_ops), src_context->cc_ops,
    321 	   sizeof(cc_ops[0]) * src_context->num_cc_ops);
    322     context->cc_ops = cc_ops;
    323     context->num_cc_ops = src_context->num_cc_ops;
    324 
    325     return 0;
    326 }
    327 
    328 static krb5_error_code
    329 kt_ops_register(krb5_context context)
    330 {
    331     context->num_kt_types = 0;
    332     context->kt_types     = NULL;
    333 
    334     krb5_kt_register (context, &krb5_fkt_ops);
    335     krb5_kt_register (context, &krb5_wrfkt_ops);
    336     krb5_kt_register (context, &krb5_javakt_ops);
    337     krb5_kt_register (context, &krb5_mkt_ops);
    338 #ifndef HEIMDAL_SMALLER
    339     krb5_kt_register (context, &krb5_akf_ops);
    340 #endif
    341     krb5_kt_register (context, &krb5_any_ops);
    342     return 0;
    343 }
    344 
    345 static krb5_error_code
    346 kt_ops_copy(krb5_context context, const krb5_context src_context)
    347 {
    348     context->num_kt_types = 0;
    349     context->kt_types     = NULL;
    350 
    351     if (src_context->num_kt_types == 0)
    352 	return 0;
    353 
    354     context->kt_types = malloc(sizeof(context->kt_types[0]) * src_context->num_kt_types);
    355     if (context->kt_types == NULL)
    356 	return krb5_enomem(context);
    357 
    358     context->num_kt_types = src_context->num_kt_types;
    359     memcpy(context->kt_types, src_context->kt_types,
    360 	   sizeof(context->kt_types[0]) * src_context->num_kt_types);
    361 
    362     return 0;
    363 }
    364 
    365 static const char *sysplugin_dirs[] =  {
    366 #ifdef _WIN32
    367     "$ORIGIN",
    368 #else
    369     "$ORIGIN/../lib/plugin/krb5",
    370 #endif
    371 #ifdef __APPLE__
    372     LIBDIR "/plugin/krb5",
    373 #ifdef HEIM_PLUGINS_SEARCH_SYSTEM
    374     "/Library/KerberosPlugins/KerberosFrameworkPlugins",
    375     "/System/Library/KerberosPlugins/KerberosFrameworkPlugins",
    376 #endif
    377 #endif
    378     NULL
    379 };
    380 
    381 static void
    382 init_context_once(void *ctx)
    383 {
    384     krb5_context context = ctx;
    385     char **dirs;
    386 
    387 #ifdef _WIN32
    388     dirs = rk_UNCONST(sysplugin_dirs);
    389 #else
    390     dirs = krb5_config_get_strings(context, NULL, "libdefaults",
    391 				   "plugin_dir", NULL);
    392     if (dirs == NULL)
    393 	dirs = rk_UNCONST(sysplugin_dirs);
    394 #endif
    395 
    396     _krb5_load_plugins(context, "krb5", (const char **)dirs);
    397 
    398     if (dirs != rk_UNCONST(sysplugin_dirs))
    399 	krb5_config_free_strings(dirs);
    400 
    401     bindtextdomain(HEIMDAL_TEXTDOMAIN, HEIMDAL_LOCALEDIR);
    402 #if OPENSSL_VERSION_NUMBER >= 0x30000000UL
    403     OSSL_PROVIDER_load(NULL, "legacy");
    404 #endif
    405 }
    406 
    407 
    408 /**
    409  * Initializes the context structure and reads the configuration file
    410  * /etc/krb5.conf. The structure should be freed by calling
    411  * krb5_free_context() when it is no longer being used.
    412  *
    413  * @param context pointer to returned context
    414  *
    415  * @return Returns 0 to indicate success.  Otherwise an errno code is
    416  * returned.  Failure means either that something bad happened during
    417  * initialization (typically ENOMEM) or that Kerberos should not be
    418  * used ENXIO. If the function returns HEIM_ERR_RANDOM_OFFLINE, the
    419  * random source is not available and later Kerberos calls might fail.
    420  *
    421  * @ingroup krb5
    422  */
    423 
    424 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
    425 krb5_init_context(krb5_context *context)
    426 {
    427     static heim_base_once_t init_context = HEIM_BASE_ONCE_INIT;
    428     krb5_context p;
    429     krb5_error_code ret;
    430     char **files;
    431     uint8_t rnd;
    432 
    433     *context = NULL;
    434 
    435     /**
    436      * krb5_init_context() will get one random byte to make sure our
    437      * random is alive.  Assumption is that once the non blocking
    438      * source allows us to pull bytes, its all seeded and allows us to
    439      * pull more bytes.
    440      *
    441      * Most Kerberos users calls krb5_init_context(), so this is
    442      * useful point where we can do the checking.
    443      */
    444     ret = krb5_generate_random(&rnd, sizeof(rnd));
    445     if (ret)
    446 	return ret;
    447 
    448     p = calloc(1, sizeof(*p));
    449     if(!p)
    450 	return ENOMEM;
    451 
    452     HEIMDAL_MUTEX_init(&p->mutex);
    453 
    454     p->flags |= KRB5_CTX_F_HOMEDIR_ACCESS;
    455 
    456     ret = krb5_get_default_config_files(&files);
    457     if(ret)
    458 	goto out;
    459     ret = krb5_set_config_files(p, files);
    460     krb5_free_config_files(files);
    461     if(ret)
    462 	goto out;
    463 
    464     /* done enough to load plugins */
    465     heim_base_once_f(&init_context, p, init_context_once);
    466 
    467     /* init error tables */
    468     krb5_init_ets(p);
    469     cc_ops_register(p);
    470     kt_ops_register(p);
    471 
    472 #ifdef PKINIT
    473     ret = hx509_context_init(&p->hx509ctx);
    474     if (ret)
    475 	goto out;
    476 #endif
    477     if (rk_SOCK_INIT())
    478 	p->flags |= KRB5_CTX_F_SOCKETS_INITIALIZED;
    479 
    480 out:
    481     if(ret) {
    482 	krb5_free_context(p);
    483 	p = NULL;
    484     }
    485     *context = p;
    486     return ret;
    487 }
    488 
    489 #ifndef HEIMDAL_SMALLER
    490 
    491 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
    492 krb5_get_permitted_enctypes(krb5_context context,
    493 			    krb5_enctype **etypes)
    494 {
    495     return krb5_get_default_in_tkt_etypes(context, KRB5_PDU_NONE, etypes);
    496 }
    497 
    498 /*
    499  *
    500  */
    501 
    502 static krb5_error_code
    503 copy_etypes (krb5_context context,
    504 	     krb5_enctype *enctypes,
    505 	     krb5_enctype **ret_enctypes)
    506 {
    507     unsigned int i;
    508 
    509     for (i = 0; enctypes[i]; i++)
    510 	;
    511     i++;
    512 
    513     *ret_enctypes = malloc(sizeof(enctypes[0]) * i);
    514     if (*ret_enctypes == NULL)
    515 	return krb5_enomem(context);
    516     memcpy(*ret_enctypes, enctypes, sizeof(enctypes[0]) * i);
    517     return 0;
    518 }
    519 
    520 /**
    521  * Make a copy for the Kerberos 5 context, the new krb5_context shoud
    522  * be freed with krb5_free_context().
    523  *
    524  * @param context the Kerberos context to copy
    525  * @param out the copy of the Kerberos, set to NULL error.
    526  *
    527  * @return Returns 0 to indicate success.  Otherwise an kerberos et
    528  * error code is returned, see krb5_get_error_message().
    529  *
    530  * @ingroup krb5
    531  */
    532 
    533 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
    534 krb5_copy_context(krb5_context context, krb5_context *out)
    535 {
    536     krb5_error_code ret;
    537     krb5_context p;
    538 
    539     *out = NULL;
    540 
    541     p = calloc(1, sizeof(*p));
    542     if (p == NULL)
    543 	return krb5_enomem(context);
    544 
    545     HEIMDAL_MUTEX_init(&p->mutex);
    546 
    547     if (context->default_cc_name)
    548 	p->default_cc_name = strdup(context->default_cc_name);
    549     if (context->default_cc_name_env)
    550 	p->default_cc_name_env = strdup(context->default_cc_name_env);
    551 
    552     if (context->etypes) {
    553 	ret = copy_etypes(context, context->etypes, &p->etypes);
    554 	if (ret)
    555 	    goto out;
    556     }
    557     if (context->cfg_etypes) {
    558 	ret = copy_etypes(context, context->cfg_etypes, &p->cfg_etypes);
    559 	if (ret)
    560 	    goto out;
    561     }
    562     if (context->etypes_des) {
    563 	ret = copy_etypes(context, context->etypes_des, &p->etypes_des);
    564 	if (ret)
    565 	    goto out;
    566     }
    567 
    568     if (context->default_realms) {
    569 	ret = krb5_copy_host_realm(context,
    570 				   context->default_realms, &p->default_realms);
    571 	if (ret)
    572 	    goto out;
    573     }
    574 
    575     ret = _krb5_config_copy(context, context->cf, &p->cf);
    576     if (ret)
    577 	goto out;
    578 
    579     /* XXX should copy */
    580     krb5_init_ets(p);
    581 
    582     cc_ops_copy(p, context);
    583     kt_ops_copy(p, context);
    584 
    585 #if 0 /* XXX */
    586     if(context->warn_dest != NULL)
    587 	;
    588     if(context->debug_dest != NULL)
    589 	;
    590 #endif
    591 
    592     ret = krb5_set_extra_addresses(p, context->extra_addresses);
    593     if (ret)
    594 	goto out;
    595     ret = krb5_set_extra_addresses(p, context->ignore_addresses);
    596     if (ret)
    597 	goto out;
    598 
    599     ret = _krb5_copy_send_to_kdc_func(p, context);
    600     if (ret)
    601 	goto out;
    602 
    603     *out = p;
    604 
    605     return 0;
    606 
    607  out:
    608     krb5_free_context(p);
    609     return ret;
    610 }
    611 
    612 #endif
    613 
    614 /**
    615  * Frees the krb5_context allocated by krb5_init_context().
    616  *
    617  * @param context context to be freed.
    618  *
    619  * @ingroup krb5
    620  */
    621 
    622 KRB5_LIB_FUNCTION void KRB5_LIB_CALL
    623 krb5_free_context(krb5_context context)
    624 {
    625     _krb5_free_name_canon_rules(context, context->name_canon_rules);
    626     if (context->default_cc_name)
    627 	free(context->default_cc_name);
    628     if (context->default_cc_name_env)
    629 	free(context->default_cc_name_env);
    630     free(context->etypes);
    631     free(context->cfg_etypes);
    632     free(context->etypes_des);
    633     krb5_free_host_realm (context, context->default_realms);
    634     krb5_config_file_free (context, context->cf);
    635     free_error_table (context->et_list);
    636     free(rk_UNCONST(context->cc_ops));
    637     free(context->kt_types);
    638     krb5_clear_error_message(context);
    639     if(context->warn_dest != NULL)
    640 	krb5_closelog(context, context->warn_dest);
    641     if(context->debug_dest != NULL)
    642 	krb5_closelog(context, context->debug_dest);
    643     krb5_set_extra_addresses(context, NULL);
    644     krb5_set_ignore_addresses(context, NULL);
    645     krb5_set_send_to_kdc_func(context, NULL, NULL);
    646 
    647 #ifdef PKINIT
    648     if (context->hx509ctx)
    649 	hx509_context_free(&context->hx509ctx);
    650 #endif
    651 
    652     HEIMDAL_MUTEX_destroy(&context->mutex);
    653     if (context->flags & KRB5_CTX_F_SOCKETS_INITIALIZED) {
    654  	rk_SOCK_EXIT();
    655     }
    656 
    657     memset(context, 0, sizeof(*context));
    658     free(context);
    659 }
    660 
    661 /**
    662  * Reinit the context from a new set of filenames.
    663  *
    664  * @param context context to add configuration too.
    665  * @param filenames array of filenames, end of list is indicated with a NULL filename.
    666  *
    667  * @return Returns 0 to indicate success.  Otherwise an kerberos et
    668  * error code is returned, see krb5_get_error_message().
    669  *
    670  * @ingroup krb5
    671  */
    672 
    673 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
    674 krb5_set_config_files(krb5_context context, char **filenames)
    675 {
    676     krb5_error_code ret;
    677     krb5_config_binding *tmp = NULL;
    678     while(filenames != NULL && *filenames != NULL && **filenames != '\0') {
    679 	ret = krb5_config_parse_file_multi(context, *filenames, &tmp);
    680 	if (ret != 0 && ret != ENOENT && ret != EACCES && ret != EPERM
    681 	    && ret != KRB5_CONFIG_BADFORMAT) {
    682 	    krb5_config_file_free(context, tmp);
    683 	    return ret;
    684 	}
    685 	filenames++;
    686     }
    687 #if 1
    688     /* with this enabled and if there are no config files, Kerberos is
    689        considererd disabled */
    690     if(tmp == NULL)
    691 	return ENXIO;
    692 #endif
    693 
    694 #ifdef _WIN32
    695     _krb5_load_config_from_registry(context, &tmp);
    696 #endif
    697 
    698     krb5_config_file_free(context, context->cf);
    699     context->cf = tmp;
    700     ret = init_context_from_config_file(context);
    701     return ret;
    702 }
    703 
    704 static krb5_error_code
    705 add_file(char ***pfilenames, int *len, char *file)
    706 {
    707     char **pp = *pfilenames;
    708     int i;
    709 
    710     for(i = 0; i < *len; i++) {
    711 	if(strcmp(pp[i], file) == 0) {
    712 	    free(file);
    713 	    return 0;
    714 	}
    715     }
    716 
    717     pp = realloc(*pfilenames, (*len + 2) * sizeof(*pp));
    718     if (pp == NULL) {
    719 	free(file);
    720 	return ENOMEM;
    721     }
    722 
    723     pp[*len] = file;
    724     pp[*len + 1] = NULL;
    725     *pfilenames = pp;
    726     *len += 1;
    727     return 0;
    728 }
    729 
    730 /*
    731  *  `pq' isn't free, it's up the the caller
    732  */
    733 
    734 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
    735 krb5_prepend_config_files(const char *filelist, char **pq, char ***ret_pp)
    736 {
    737     krb5_error_code ret;
    738     const char *p, *q;
    739     char **pp;
    740     int len;
    741     char *fn;
    742 
    743     pp = NULL;
    744 
    745     len = 0;
    746     p = filelist;
    747     while(1) {
    748 	ssize_t l;
    749 	q = p;
    750 	l = strsep_copy(&q, PATH_SEP, NULL, 0);
    751 	if(l == -1)
    752 	    break;
    753 	fn = malloc(l + 1);
    754 	if(fn == NULL) {
    755 	    krb5_free_config_files(pp);
    756 	    return ENOMEM;
    757 	}
    758 	(void)strsep_copy(&p, PATH_SEP, fn, l + 1);
    759 	ret = add_file(&pp, &len, fn);
    760 	if (ret) {
    761 	    krb5_free_config_files(pp);
    762 	    return ret;
    763 	}
    764     }
    765 
    766     if (pq != NULL) {
    767 	int i;
    768 
    769 	for (i = 0; pq[i] != NULL; i++) {
    770 	    fn = strdup(pq[i]);
    771 	    if (fn == NULL) {
    772 		krb5_free_config_files(pp);
    773 		return ENOMEM;
    774 	    }
    775 	    ret = add_file(&pp, &len, fn);
    776 	    if (ret) {
    777 		krb5_free_config_files(pp);
    778 		return ret;
    779 	    }
    780 	}
    781     }
    782 
    783     *ret_pp = pp;
    784     return 0;
    785 }
    786 
    787 /**
    788  * Prepend the filename to the global configuration list.
    789  *
    790  * @param filelist a filename to add to the default list of filename
    791  * @param pfilenames return array of filenames, should be freed with krb5_free_config_files().
    792  *
    793  * @return Returns 0 to indicate success.  Otherwise an kerberos et
    794  * error code is returned, see krb5_get_error_message().
    795  *
    796  * @ingroup krb5
    797  */
    798 
    799 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
    800 krb5_prepend_config_files_default(const char *filelist, char ***pfilenames)
    801 {
    802     krb5_error_code ret;
    803     char **defpp, **pp = NULL;
    804 
    805     ret = krb5_get_default_config_files(&defpp);
    806     if (ret)
    807 	return ret;
    808 
    809     ret = krb5_prepend_config_files(filelist, defpp, &pp);
    810     krb5_free_config_files(defpp);
    811     if (ret) {
    812 	return ret;
    813     }
    814     *pfilenames = pp;
    815     return 0;
    816 }
    817 
    818 #ifdef _WIN32
    819 
    820 /**
    821  * Checks the registry for configuration file location
    822  *
    823  * Kerberos for Windows and other legacy Kerberos applications expect
    824  * to find the configuration file location in the
    825  * SOFTWARE\MIT\Kerberos registry key under the value "config".
    826  */
    827 KRB5_LIB_FUNCTION char * KRB5_LIB_CALL
    828 _krb5_get_default_config_config_files_from_registry()
    829 {
    830     static const char * KeyName = "Software\\MIT\\Kerberos";
    831     char *config_file = NULL;
    832     LONG rcode;
    833     HKEY key;
    834 
    835     rcode = RegOpenKeyEx(HKEY_CURRENT_USER, KeyName, 0, KEY_READ, &key);
    836     if (rcode == ERROR_SUCCESS) {
    837         config_file = _krb5_parse_reg_value_as_multi_string(NULL, key, "config",
    838                                                             REG_NONE, 0, PATH_SEP);
    839         RegCloseKey(key);
    840     }
    841 
    842     if (config_file)
    843         return config_file;
    844 
    845     rcode = RegOpenKeyEx(HKEY_LOCAL_MACHINE, KeyName, 0, KEY_READ, &key);
    846     if (rcode == ERROR_SUCCESS) {
    847         config_file = _krb5_parse_reg_value_as_multi_string(NULL, key, "config",
    848                                                             REG_NONE, 0, PATH_SEP);
    849         RegCloseKey(key);
    850     }
    851 
    852     return config_file;
    853 }
    854 
    855 #endif
    856 
    857 /**
    858  * Get the global configuration list.
    859  *
    860  * @param pfilenames return array of filenames, should be freed with krb5_free_config_files().
    861  *
    862  * @return Returns 0 to indicate success.  Otherwise an kerberos et
    863  * error code is returned, see krb5_get_error_message().
    864  *
    865  * @ingroup krb5
    866  */
    867 
    868 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
    869 krb5_get_default_config_files(char ***pfilenames)
    870 {
    871     const char *files = NULL;
    872 
    873     if (pfilenames == NULL)
    874         return EINVAL;
    875     if(!issuid())
    876 	files = getenv("KRB5_CONFIG");
    877 
    878 #ifdef _WIN32
    879     if (files == NULL) {
    880         char * reg_files;
    881         reg_files = _krb5_get_default_config_config_files_from_registry();
    882         if (reg_files != NULL) {
    883             krb5_error_code code;
    884 
    885             code = krb5_prepend_config_files(reg_files, NULL, pfilenames);
    886             free(reg_files);
    887 
    888             return code;
    889         }
    890     }
    891 #endif
    892 
    893     if (files == NULL)
    894 	files = krb5_config_file;
    895 
    896     return krb5_prepend_config_files(files, NULL, pfilenames);
    897 }
    898 
    899 /**
    900  * Free a list of configuration files.
    901  *
    902  * @param filenames list, terminated with a NULL pointer, to be
    903  * freed. NULL is an valid argument.
    904  *
    905  * @return Returns 0 to indicate success. Otherwise an kerberos et
    906  * error code is returned, see krb5_get_error_message().
    907  *
    908  * @ingroup krb5
    909  */
    910 
    911 KRB5_LIB_FUNCTION void KRB5_LIB_CALL
    912 krb5_free_config_files(char **filenames)
    913 {
    914     char **p;
    915     for(p = filenames; p && *p != NULL; p++)
    916 	free(*p);
    917     free(filenames);
    918 }
    919 
    920 /**
    921  * Returns the list of Kerberos encryption types sorted in order of
    922  * most preferred to least preferred encryption type.  Note that some
    923  * encryption types might be disabled, so you need to check with
    924  * krb5_enctype_valid() before using the encryption type.
    925  *
    926  * @return list of enctypes, terminated with ETYPE_NULL. Its a static
    927  * array completed into the Kerberos library so the content doesn't
    928  * need to be freed.
    929  *
    930  * @ingroup krb5
    931  */
    932 
    933 KRB5_LIB_FUNCTION const krb5_enctype * KRB5_LIB_CALL
    934 krb5_kerberos_enctypes(krb5_context context)
    935 {
    936     static const krb5_enctype p[] = {
    937 	ETYPE_AES256_CTS_HMAC_SHA1_96,
    938 	ETYPE_AES128_CTS_HMAC_SHA1_96,
    939 	ETYPE_AES256_CTS_HMAC_SHA384_192,
    940 	ETYPE_AES128_CTS_HMAC_SHA256_128,
    941 	ETYPE_DES3_CBC_SHA1,
    942 	ETYPE_ARCFOUR_HMAC_MD5,
    943 	ETYPE_NULL
    944     };
    945 
    946     static const krb5_enctype weak[] = {
    947 	ETYPE_AES256_CTS_HMAC_SHA1_96,
    948 	ETYPE_AES128_CTS_HMAC_SHA1_96,
    949 	ETYPE_AES256_CTS_HMAC_SHA384_192,
    950 	ETYPE_AES128_CTS_HMAC_SHA256_128,
    951 	ETYPE_DES3_CBC_SHA1,
    952 	ETYPE_DES3_CBC_MD5,
    953 	ETYPE_ARCFOUR_HMAC_MD5,
    954 	ETYPE_DES_CBC_MD5,
    955 	ETYPE_DES_CBC_MD4,
    956 	ETYPE_DES_CBC_CRC,
    957 	ETYPE_NULL
    958     };
    959 
    960     /*
    961      * if the list of enctypes enabled by "allow_weak_crypto"
    962      * are valid, then return the former default enctype list
    963      * that contained the weak entries.
    964      */
    965     if (krb5_enctype_valid(context, ETYPE_DES_CBC_CRC) == 0 &&
    966         krb5_enctype_valid(context, ETYPE_DES_CBC_MD4) == 0 &&
    967         krb5_enctype_valid(context, ETYPE_DES_CBC_MD5) == 0 &&
    968         krb5_enctype_valid(context, ETYPE_DES_CBC_NONE) == 0 &&
    969         krb5_enctype_valid(context, ETYPE_DES_CFB64_NONE) == 0 &&
    970         krb5_enctype_valid(context, ETYPE_DES_PCBC_NONE) == 0)
    971         return weak;
    972 
    973     return p;
    974 }
    975 
    976 /*
    977  *
    978  */
    979 
    980 static krb5_error_code
    981 copy_enctypes(krb5_context context,
    982 	      const krb5_enctype *in,
    983 	      krb5_enctype **out)
    984 {
    985     krb5_enctype *p = NULL;
    986     size_t m, n;
    987 
    988     for (n = 0; in[n]; n++)
    989 	;
    990     n++;
    991     ALLOC(p, n);
    992     if(p == NULL)
    993 	return krb5_enomem(context);
    994     for (n = 0, m = 0; in[n]; n++) {
    995 	if (krb5_enctype_valid(context, in[n]) != 0)
    996 	    continue;
    997 	p[m++] = in[n];
    998     }
    999     p[m] = KRB5_ENCTYPE_NULL;
   1000     if (m == 0) {
   1001 	free(p);
   1002 	krb5_set_error_message (context, KRB5_PROG_ETYPE_NOSUPP,
   1003 				N_("no valid enctype set", ""));
   1004 	return KRB5_PROG_ETYPE_NOSUPP;
   1005     }
   1006     *out = p;
   1007     return 0;
   1008 }
   1009 
   1010 
   1011 /*
   1012  * set `etype' to a malloced list of the default enctypes
   1013  */
   1014 
   1015 static krb5_error_code
   1016 default_etypes(krb5_context context, krb5_enctype **etype)
   1017 {
   1018     const krb5_enctype *p = krb5_kerberos_enctypes(context);
   1019     return copy_enctypes(context, p, etype);
   1020 }
   1021 
   1022 /**
   1023  * Set the default encryption types that will be use in communcation
   1024  * with the KDC, clients and servers.
   1025  *
   1026  * @param context Kerberos 5 context.
   1027  * @param etypes Encryption types, array terminated with ETYPE_NULL (0).
   1028  * A value of NULL resets the encryption types to the defaults set in the
   1029  * configuration file.
   1030  *
   1031  * @return Returns 0 to indicate success. Otherwise an kerberos et
   1032  * error code is returned, see krb5_get_error_message().
   1033  *
   1034  * @ingroup krb5
   1035  */
   1036 
   1037 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
   1038 krb5_set_default_in_tkt_etypes(krb5_context context,
   1039 			       const krb5_enctype *etypes)
   1040 {
   1041     krb5_error_code ret;
   1042     krb5_enctype *p = NULL;
   1043 
   1044     if(!etypes) {
   1045 	etypes = context->cfg_etypes;
   1046     }
   1047 
   1048     if(etypes) {
   1049 	ret = copy_enctypes(context, etypes, &p);
   1050 	if (ret)
   1051 	    return ret;
   1052     }
   1053     if(context->etypes)
   1054 	free(context->etypes);
   1055     context->etypes = p;
   1056     return 0;
   1057 }
   1058 
   1059 /**
   1060  * Get the default encryption types that will be use in communcation
   1061  * with the KDC, clients and servers.
   1062  *
   1063  * @param context Kerberos 5 context.
   1064  * @param pdu_type request type (AS, TGS or none)
   1065  * @param etypes Encryption types, array terminated with
   1066  * ETYPE_NULL(0), caller should free array with krb5_xfree():
   1067  *
   1068  * @return Returns 0 to indicate success. Otherwise an kerberos et
   1069  * error code is returned, see krb5_get_error_message().
   1070  *
   1071  * @ingroup krb5
   1072  */
   1073 
   1074 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
   1075 krb5_get_default_in_tkt_etypes(krb5_context context,
   1076 			       krb5_pdu pdu_type,
   1077 			       krb5_enctype **etypes)
   1078 {
   1079     krb5_enctype *enctypes = NULL;
   1080     krb5_error_code ret;
   1081     krb5_enctype *p;
   1082 
   1083     heim_assert(pdu_type == KRB5_PDU_AS_REQUEST ||
   1084 		pdu_type == KRB5_PDU_TGS_REQUEST ||
   1085 		pdu_type == KRB5_PDU_NONE, "unexpected pdu type");
   1086 
   1087     if (pdu_type == KRB5_PDU_AS_REQUEST && context->as_etypes != NULL)
   1088 	enctypes = context->as_etypes;
   1089     else if (pdu_type == KRB5_PDU_TGS_REQUEST && context->tgs_etypes != NULL)
   1090 	enctypes = context->tgs_etypes;
   1091     else if (context->etypes != NULL)
   1092 	enctypes = context->etypes;
   1093 
   1094     if (enctypes != NULL) {
   1095 	ret = copy_enctypes(context, enctypes, &p);
   1096 	if (ret)
   1097 	    return ret;
   1098     } else {
   1099 	ret = default_etypes(context, &p);
   1100 	if (ret)
   1101 	    return ret;
   1102     }
   1103     *etypes = p;
   1104     return 0;
   1105 }
   1106 
   1107 /**
   1108  * Init the built-in ets in the Kerberos library.
   1109  *
   1110  * @param context kerberos context to add the ets too
   1111  *
   1112  * @ingroup krb5
   1113  */
   1114 
   1115 KRB5_LIB_FUNCTION void KRB5_LIB_CALL
   1116 krb5_init_ets(krb5_context context)
   1117 {
   1118     if(context->et_list == NULL){
   1119 	krb5_add_et_list(context, initialize_krb5_error_table_r);
   1120 	krb5_add_et_list(context, initialize_asn1_error_table_r);
   1121 	krb5_add_et_list(context, initialize_heim_error_table_r);
   1122 
   1123 	krb5_add_et_list(context, initialize_k524_error_table_r);
   1124 
   1125 #ifdef COM_ERR_BINDDOMAIN_krb5
   1126 	bindtextdomain(COM_ERR_BINDDOMAIN_krb5, HEIMDAL_LOCALEDIR);
   1127 	bindtextdomain(COM_ERR_BINDDOMAIN_asn1, HEIMDAL_LOCALEDIR);
   1128 	bindtextdomain(COM_ERR_BINDDOMAIN_heim, HEIMDAL_LOCALEDIR);
   1129 	bindtextdomain(COM_ERR_BINDDOMAIN_k524, HEIMDAL_LOCALEDIR);
   1130 #endif
   1131 
   1132 #ifdef PKINIT
   1133 	krb5_add_et_list(context, initialize_hx_error_table_r);
   1134 #ifdef COM_ERR_BINDDOMAIN_hx
   1135 	bindtextdomain(COM_ERR_BINDDOMAIN_hx, HEIMDAL_LOCALEDIR);
   1136 #endif
   1137 #endif
   1138     }
   1139 }
   1140 
   1141 /**
   1142  * Make the kerberos library default to the admin KDC.
   1143  *
   1144  * @param context Kerberos 5 context.
   1145  * @param flag boolean flag to select if the use the admin KDC or not.
   1146  *
   1147  * @ingroup krb5
   1148  */
   1149 
   1150 KRB5_LIB_FUNCTION void KRB5_LIB_CALL
   1151 krb5_set_use_admin_kdc (krb5_context context, krb5_boolean flag)
   1152 {
   1153     context->use_admin_kdc = flag;
   1154 }
   1155 
   1156 /**
   1157  * Make the kerberos library default to the admin KDC.
   1158  *
   1159  * @param context Kerberos 5 context.
   1160  *
   1161  * @return boolean flag to telling the context will use admin KDC as the default KDC.
   1162  *
   1163  * @ingroup krb5
   1164  */
   1165 
   1166 KRB5_LIB_FUNCTION krb5_boolean KRB5_LIB_CALL
   1167 krb5_get_use_admin_kdc (krb5_context context)
   1168 {
   1169     return context->use_admin_kdc;
   1170 }
   1171 
   1172 /**
   1173  * Add extra address to the address list that the library will add to
   1174  * the client's address list when communicating with the KDC.
   1175  *
   1176  * @param context Kerberos 5 context.
   1177  * @param addresses addreses to add
   1178  *
   1179  * @return Returns 0 to indicate success. Otherwise an kerberos et
   1180  * error code is returned, see krb5_get_error_message().
   1181  *
   1182  * @ingroup krb5
   1183  */
   1184 
   1185 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
   1186 krb5_add_extra_addresses(krb5_context context, krb5_addresses *addresses)
   1187 {
   1188 
   1189     if(context->extra_addresses)
   1190 	return krb5_append_addresses(context,
   1191 				     context->extra_addresses, addresses);
   1192     else
   1193 	return krb5_set_extra_addresses(context, addresses);
   1194 }
   1195 
   1196 /**
   1197  * Set extra address to the address list that the library will add to
   1198  * the client's address list when communicating with the KDC.
   1199  *
   1200  * @param context Kerberos 5 context.
   1201  * @param addresses addreses to set
   1202  *
   1203  * @return Returns 0 to indicate success. Otherwise an kerberos et
   1204  * error code is returned, see krb5_get_error_message().
   1205  *
   1206  * @ingroup krb5
   1207  */
   1208 
   1209 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
   1210 krb5_set_extra_addresses(krb5_context context, const krb5_addresses *addresses)
   1211 {
   1212     if(context->extra_addresses)
   1213 	krb5_free_addresses(context, context->extra_addresses);
   1214 
   1215     if(addresses == NULL) {
   1216 	if(context->extra_addresses != NULL) {
   1217 	    free(context->extra_addresses);
   1218 	    context->extra_addresses = NULL;
   1219 	}
   1220 	return 0;
   1221     }
   1222     if(context->extra_addresses == NULL) {
   1223 	context->extra_addresses = malloc(sizeof(*context->extra_addresses));
   1224 	if (context->extra_addresses == NULL)
   1225 	    return krb5_enomem(context);
   1226     }
   1227     return krb5_copy_addresses(context, addresses, context->extra_addresses);
   1228 }
   1229 
   1230 /**
   1231  * Get extra address to the address list that the library will add to
   1232  * the client's address list when communicating with the KDC.
   1233  *
   1234  * @param context Kerberos 5 context.
   1235  * @param addresses addreses to set
   1236  *
   1237  * @return Returns 0 to indicate success. Otherwise an kerberos et
   1238  * error code is returned, see krb5_get_error_message().
   1239  *
   1240  * @ingroup krb5
   1241  */
   1242 
   1243 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
   1244 krb5_get_extra_addresses(krb5_context context, krb5_addresses *addresses)
   1245 {
   1246     if(context->extra_addresses == NULL) {
   1247 	memset(addresses, 0, sizeof(*addresses));
   1248 	return 0;
   1249     }
   1250     return krb5_copy_addresses(context,context->extra_addresses, addresses);
   1251 }
   1252 
   1253 /**
   1254  * Add extra addresses to ignore when fetching addresses from the
   1255  * underlaying operating system.
   1256  *
   1257  * @param context Kerberos 5 context.
   1258  * @param addresses addreses to ignore
   1259  *
   1260  * @return Returns 0 to indicate success. Otherwise an kerberos et
   1261  * error code is returned, see krb5_get_error_message().
   1262  *
   1263  * @ingroup krb5
   1264  */
   1265 
   1266 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
   1267 krb5_add_ignore_addresses(krb5_context context, krb5_addresses *addresses)
   1268 {
   1269 
   1270     if(context->ignore_addresses)
   1271 	return krb5_append_addresses(context,
   1272 				     context->ignore_addresses, addresses);
   1273     else
   1274 	return krb5_set_ignore_addresses(context, addresses);
   1275 }
   1276 
   1277 /**
   1278  * Set extra addresses to ignore when fetching addresses from the
   1279  * underlaying operating system.
   1280  *
   1281  * @param context Kerberos 5 context.
   1282  * @param addresses addreses to ignore
   1283  *
   1284  * @return Returns 0 to indicate success. Otherwise an kerberos et
   1285  * error code is returned, see krb5_get_error_message().
   1286  *
   1287  * @ingroup krb5
   1288  */
   1289 
   1290 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
   1291 krb5_set_ignore_addresses(krb5_context context, const krb5_addresses *addresses)
   1292 {
   1293     if(context->ignore_addresses)
   1294 	krb5_free_addresses(context, context->ignore_addresses);
   1295     if(addresses == NULL) {
   1296 	if(context->ignore_addresses != NULL) {
   1297 	    free(context->ignore_addresses);
   1298 	    context->ignore_addresses = NULL;
   1299 	}
   1300 	return 0;
   1301     }
   1302     if(context->ignore_addresses == NULL) {
   1303 	context->ignore_addresses = malloc(sizeof(*context->ignore_addresses));
   1304 	if (context->ignore_addresses == NULL)
   1305 	    return krb5_enomem(context);
   1306     }
   1307     return krb5_copy_addresses(context, addresses, context->ignore_addresses);
   1308 }
   1309 
   1310 /**
   1311  * Get extra addresses to ignore when fetching addresses from the
   1312  * underlaying operating system.
   1313  *
   1314  * @param context Kerberos 5 context.
   1315  * @param addresses list addreses ignored
   1316  *
   1317  * @return Returns 0 to indicate success. Otherwise an kerberos et
   1318  * error code is returned, see krb5_get_error_message().
   1319  *
   1320  * @ingroup krb5
   1321  */
   1322 
   1323 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
   1324 krb5_get_ignore_addresses(krb5_context context, krb5_addresses *addresses)
   1325 {
   1326     if(context->ignore_addresses == NULL) {
   1327 	memset(addresses, 0, sizeof(*addresses));
   1328 	return 0;
   1329     }
   1330     return krb5_copy_addresses(context, context->ignore_addresses, addresses);
   1331 }
   1332 
   1333 /**
   1334  * Set version of fcache that the library should use.
   1335  *
   1336  * @param context Kerberos 5 context.
   1337  * @param version version number.
   1338  *
   1339  * @return Returns 0 to indicate success. Otherwise an kerberos et
   1340  * error code is returned, see krb5_get_error_message().
   1341  *
   1342  * @ingroup krb5
   1343  */
   1344 
   1345 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
   1346 krb5_set_fcache_version(krb5_context context, int version)
   1347 {
   1348     context->fcache_vno = version;
   1349     return 0;
   1350 }
   1351 
   1352 /**
   1353  * Get version of fcache that the library should use.
   1354  *
   1355  * @param context Kerberos 5 context.
   1356  * @param version version number.
   1357  *
   1358  * @return Returns 0 to indicate success. Otherwise an kerberos et
   1359  * error code is returned, see krb5_get_error_message().
   1360  *
   1361  * @ingroup krb5
   1362  */
   1363 
   1364 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
   1365 krb5_get_fcache_version(krb5_context context, int *version)
   1366 {
   1367     *version = context->fcache_vno;
   1368     return 0;
   1369 }
   1370 
   1371 /**
   1372  * Runtime check if the Kerberos library was complied with thread support.
   1373  *
   1374  * @return TRUE if the library was compiled with thread support, FALSE if not.
   1375  *
   1376  * @ingroup krb5
   1377  */
   1378 
   1379 
   1380 KRB5_LIB_FUNCTION krb5_boolean KRB5_LIB_CALL
   1381 krb5_is_thread_safe(void)
   1382 {
   1383 #ifdef ENABLE_PTHREAD_SUPPORT
   1384     return TRUE;
   1385 #else
   1386     return FALSE;
   1387 #endif
   1388 }
   1389 
   1390 /**
   1391  * Set if the library should use DNS to canonicalize hostnames.
   1392  *
   1393  * @param context Kerberos 5 context.
   1394  * @param flag if its dns canonicalizion is used or not.
   1395  *
   1396  * @ingroup krb5
   1397  */
   1398 
   1399 KRB5_LIB_FUNCTION void KRB5_LIB_CALL
   1400 krb5_set_dns_canonicalize_hostname (krb5_context context, krb5_boolean flag)
   1401 {
   1402     if (flag)
   1403 	context->flags |= KRB5_CTX_F_DNS_CANONICALIZE_HOSTNAME;
   1404     else
   1405 	context->flags &= ~KRB5_CTX_F_DNS_CANONICALIZE_HOSTNAME;
   1406 }
   1407 
   1408 /**
   1409  * Get if the library uses DNS to canonicalize hostnames.
   1410  *
   1411  * @param context Kerberos 5 context.
   1412  *
   1413  * @return return non zero if the library uses DNS to canonicalize hostnames.
   1414  *
   1415  * @ingroup krb5
   1416  */
   1417 
   1418 KRB5_LIB_FUNCTION krb5_boolean KRB5_LIB_CALL
   1419 krb5_get_dns_canonicalize_hostname (krb5_context context)
   1420 {
   1421     return (context->flags & KRB5_CTX_F_DNS_CANONICALIZE_HOSTNAME) ? 1 : 0;
   1422 }
   1423 
   1424 /**
   1425  * Get current offset in time to the KDC.
   1426  *
   1427  * @param context Kerberos 5 context.
   1428  * @param sec seconds part of offset.
   1429  * @param usec micro seconds part of offset.
   1430  *
   1431  * @return returns zero
   1432  *
   1433  * @ingroup krb5
   1434  */
   1435 
   1436 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
   1437 krb5_get_kdc_sec_offset (krb5_context context, int32_t *sec, int32_t *usec)
   1438 {
   1439     if (sec)
   1440 	*sec = context->kdc_sec_offset;
   1441     if (usec)
   1442 	*usec = context->kdc_usec_offset;
   1443     return 0;
   1444 }
   1445 
   1446 /**
   1447  * Set current offset in time to the KDC.
   1448  *
   1449  * @param context Kerberos 5 context.
   1450  * @param sec seconds part of offset.
   1451  * @param usec micro seconds part of offset.
   1452  *
   1453  * @return returns zero
   1454  *
   1455  * @ingroup krb5
   1456  */
   1457 
   1458 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
   1459 krb5_set_kdc_sec_offset (krb5_context context, int32_t sec, int32_t usec)
   1460 {
   1461     context->kdc_sec_offset = sec;
   1462     if (usec >= 0)
   1463 	context->kdc_usec_offset = usec;
   1464     return 0;
   1465 }
   1466 
   1467 /**
   1468  * Get max time skew allowed.
   1469  *
   1470  * @param context Kerberos 5 context.
   1471  *
   1472  * @return timeskew in seconds.
   1473  *
   1474  * @ingroup krb5
   1475  */
   1476 
   1477 KRB5_LIB_FUNCTION time_t KRB5_LIB_CALL
   1478 krb5_get_max_time_skew (krb5_context context)
   1479 {
   1480     return context->max_skew;
   1481 }
   1482 
   1483 /**
   1484  * Set max time skew allowed.
   1485  *
   1486  * @param context Kerberos 5 context.
   1487  * @param t timeskew in seconds.
   1488  *
   1489  * @ingroup krb5
   1490  */
   1491 
   1492 KRB5_LIB_FUNCTION void KRB5_LIB_CALL
   1493 krb5_set_max_time_skew (krb5_context context, time_t t)
   1494 {
   1495     context->max_skew = t;
   1496 }
   1497 
   1498 /*
   1499  * Init encryption types in len, val with etypes.
   1500  *
   1501  * @param context Kerberos 5 context.
   1502  * @param pdu_type type of pdu
   1503  * @param len output length of val.
   1504  * @param val output array of enctypes.
   1505  * @param etypes etypes to set val and len to, if NULL, use default enctypes.
   1506 
   1507  * @return Returns 0 to indicate success. Otherwise an kerberos et
   1508  * error code is returned, see krb5_get_error_message().
   1509  *
   1510  * @ingroup krb5
   1511  */
   1512 
   1513 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
   1514 _krb5_init_etype(krb5_context context,
   1515 		 krb5_pdu pdu_type,
   1516 		 unsigned *len,
   1517 		 krb5_enctype **val,
   1518 		 const krb5_enctype *etypes)
   1519 {
   1520     krb5_error_code ret;
   1521 
   1522     if (etypes == NULL)
   1523 	ret = krb5_get_default_in_tkt_etypes(context, pdu_type, val);
   1524     else
   1525 	ret = copy_enctypes(context, etypes, val);
   1526     if (ret)
   1527 	return ret;
   1528 
   1529     if (len) {
   1530 	*len = 0;
   1531 	while ((*val)[*len] != KRB5_ENCTYPE_NULL)
   1532 	    (*len)++;
   1533     }
   1534     return 0;
   1535 }
   1536 
   1537 /*
   1538  * Allow homedir accces
   1539  */
   1540 
   1541 static HEIMDAL_MUTEX homedir_mutex = HEIMDAL_MUTEX_INITIALIZER;
   1542 static krb5_boolean allow_homedir = TRUE;
   1543 
   1544 KRB5_LIB_FUNCTION krb5_boolean KRB5_LIB_CALL
   1545 _krb5_homedir_access(krb5_context context)
   1546 {
   1547     krb5_boolean allow;
   1548 
   1549     if (context && (context->flags & KRB5_CTX_F_HOMEDIR_ACCESS) == 0)
   1550 	return FALSE;
   1551 
   1552     HEIMDAL_MUTEX_lock(&homedir_mutex);
   1553     allow = allow_homedir;
   1554     HEIMDAL_MUTEX_unlock(&homedir_mutex);
   1555     return allow;
   1556 }
   1557 
   1558 /**
   1559  * Enable and disable home directory access on either the global state
   1560  * or the krb5_context state. By calling krb5_set_home_dir_access()
   1561  * with context set to NULL, the global state is configured otherwise
   1562  * the state for the krb5_context is modified.
   1563  *
   1564  * For home directory access to be allowed, both the global state and
   1565  * the krb5_context state have to be allowed.
   1566  *
   1567  * @param context a Kerberos 5 context or NULL
   1568  * @param allow allow if TRUE home directory
   1569  * @return the old value
   1570  *
   1571  * @ingroup krb5
   1572  */
   1573 
   1574 KRB5_LIB_FUNCTION krb5_boolean KRB5_LIB_CALL
   1575 krb5_set_home_dir_access(krb5_context context, krb5_boolean allow)
   1576 {
   1577     krb5_boolean old;
   1578     if (context) {
   1579 	old = (context->flags & KRB5_CTX_F_HOMEDIR_ACCESS) ? TRUE : FALSE;
   1580 	if (allow)
   1581 	    context->flags |= KRB5_CTX_F_HOMEDIR_ACCESS;
   1582 	else
   1583 	    context->flags &= ~KRB5_CTX_F_HOMEDIR_ACCESS;
   1584     } else {
   1585 	HEIMDAL_MUTEX_lock(&homedir_mutex);
   1586 	old = allow_homedir;
   1587 	allow_homedir = allow;
   1588 	HEIMDAL_MUTEX_unlock(&homedir_mutex);
   1589     }
   1590 
   1591     return old;
   1592 }
   1593