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