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