1/*	$NetBSD: context.c,v 1.8 2023/09/11 15:12:12 christos Exp $	*/
2
3/*
4 * Copyright (c) 1997 - 2010 Kungliga Tekniska H��gskolan
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
56static krb5_error_code
57copy_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
66static krb5_error_code
67set_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
103static krb5_error_code
104init_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
277static krb5_error_code
278cc_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
302static krb5_error_code
303cc_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
328static krb5_error_code
329kt_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
345static krb5_error_code
346kt_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
365static 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
381static void
382init_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
424KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
425krb5_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
480out:
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
491KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
492krb5_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
502static krb5_error_code
503copy_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
533KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
534krb5_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
622KRB5_LIB_FUNCTION void KRB5_LIB_CALL
623krb5_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
673KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
674krb5_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
704static krb5_error_code
705add_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
734KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
735krb5_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
799KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
800krb5_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 */
827KRB5_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
868KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
869krb5_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
911KRB5_LIB_FUNCTION void KRB5_LIB_CALL
912krb5_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
933KRB5_LIB_FUNCTION const krb5_enctype * KRB5_LIB_CALL
934krb5_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
980static krb5_error_code
981copy_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
1015static krb5_error_code
1016default_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
1037KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
1038krb5_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
1074KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
1075krb5_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
1115KRB5_LIB_FUNCTION void KRB5_LIB_CALL
1116krb5_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
1150KRB5_LIB_FUNCTION void KRB5_LIB_CALL
1151krb5_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
1166KRB5_LIB_FUNCTION krb5_boolean KRB5_LIB_CALL
1167krb5_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
1185KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
1186krb5_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
1209KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
1210krb5_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
1243KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
1244krb5_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
1266KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
1267krb5_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
1290KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
1291krb5_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
1323KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
1324krb5_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
1345KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
1346krb5_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
1364KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
1365krb5_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
1380KRB5_LIB_FUNCTION krb5_boolean KRB5_LIB_CALL
1381krb5_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
1399KRB5_LIB_FUNCTION void KRB5_LIB_CALL
1400krb5_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
1418KRB5_LIB_FUNCTION krb5_boolean KRB5_LIB_CALL
1419krb5_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
1436KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
1437krb5_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
1458KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
1459krb5_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
1477KRB5_LIB_FUNCTION time_t KRB5_LIB_CALL
1478krb5_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
1492KRB5_LIB_FUNCTION void KRB5_LIB_CALL
1493krb5_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
1513KRB5_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
1541static HEIMDAL_MUTEX homedir_mutex = HEIMDAL_MUTEX_INITIALIZER;
1542static krb5_boolean allow_homedir = TRUE;
1543
1544KRB5_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
1574KRB5_LIB_FUNCTION krb5_boolean KRB5_LIB_CALL
1575krb5_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