dff7a700c4f31802354f256cfd37de0624306ecd
[sfrench/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     hx509_context_free(&context->hx509ctx);
539 #endif
540
541     HEIMDAL_MUTEX_destroy(context->mutex);
542     free(context->mutex);
543     if (context->flags & KRB5_CTX_F_SOCKETS_INITIALIZED) {
544         rk_SOCK_EXIT();
545     }
546
547     memset(context, 0, sizeof(*context));
548     free(context);
549 }
550
551 /**
552  * Reinit the context from a new set of filenames.
553  *
554  * @param context context to add configuration too.
555  * @param filenames array of filenames, end of list is indicated with a NULL filename.
556  *
557  * @return Returns 0 to indicate success.  Otherwise an kerberos et
558  * error code is returned, see krb5_get_error_message().
559  *
560  * @ingroup krb5
561  */
562
563 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
564 krb5_set_config_files(krb5_context context, char **filenames)
565 {
566     krb5_error_code ret;
567     krb5_config_binding *tmp = NULL;
568     while(filenames != NULL && *filenames != NULL && **filenames != '\0') {
569         ret = krb5_config_parse_file_multi(context, *filenames, &tmp);
570         if(ret != 0 && ret != ENOENT && ret != EACCES && ret != EPERM) {
571             krb5_config_file_free(context, tmp);
572             return ret;
573         }
574         filenames++;
575     }
576 #if 0
577     /* with this enabled and if there are no config files, Kerberos is
578        considererd disabled */
579     if(tmp == NULL)
580         return ENXIO;
581 #endif
582     krb5_config_file_free(context, context->cf);
583     context->cf = tmp;
584     ret = init_context_from_config_file(context);
585     return ret;
586 }
587
588 static krb5_error_code
589 add_file(char ***pfilenames, int *len, char *file)
590 {
591     char **pp = *pfilenames;
592     int i;
593
594     for(i = 0; i < *len; i++) {
595         if(strcmp(pp[i], file) == 0) {
596             free(file);
597             return 0;
598         }
599     }
600
601     pp = realloc(*pfilenames, (*len + 2) * sizeof(*pp));
602     if (pp == NULL) {
603         free(file);
604         return ENOMEM;
605     }
606
607     pp[*len] = file;
608     pp[*len + 1] = NULL;
609     *pfilenames = pp;
610     *len += 1;
611     return 0;
612 }
613
614 /*
615  *  `pq' isn't free, it's up the the caller
616  */
617
618 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
619 krb5_prepend_config_files(const char *filelist, char **pq, char ***ret_pp)
620 {
621     krb5_error_code ret;
622     const char *p, *q;
623     char **pp;
624     int len;
625     char *fn;
626
627     pp = NULL;
628
629     len = 0;
630     p = filelist;
631     while(1) {
632         ssize_t l;
633         q = p;
634         l = strsep_copy(&q, ":", NULL, 0);
635         if(l == -1)
636             break;
637         fn = malloc(l + 1);
638         if(fn == NULL) {
639             krb5_free_config_files(pp);
640             return ENOMEM;
641         }
642         (void)strsep_copy(&p, ":", fn, l + 1);
643         ret = add_file(&pp, &len, fn);
644         if (ret) {
645             krb5_free_config_files(pp);
646             return ret;
647         }
648     }
649
650     if (pq != NULL) {
651         int i;
652
653         for (i = 0; pq[i] != NULL; i++) {
654             fn = strdup(pq[i]);
655             if (fn == NULL) {
656                 krb5_free_config_files(pp);
657                 return ENOMEM;
658             }
659             ret = add_file(&pp, &len, fn);
660             if (ret) {
661                 krb5_free_config_files(pp);
662                 return ret;
663             }
664         }
665     }
666
667     *ret_pp = pp;
668     return 0;
669 }
670
671 /**
672  * Prepend the filename to the global configuration list.
673  *
674  * @param filelist a filename to add to the default list of filename
675  * @param pfilenames return array of filenames, should be freed with krb5_free_config_files().
676  *
677  * @return Returns 0 to indicate success.  Otherwise an kerberos et
678  * error code is returned, see krb5_get_error_message().
679  *
680  * @ingroup krb5
681  */
682
683 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
684 krb5_prepend_config_files_default(const char *filelist, char ***pfilenames)
685 {
686     krb5_error_code ret;
687     char **defpp, **pp = NULL;
688
689     ret = krb5_get_default_config_files(&defpp);
690     if (ret)
691         return ret;
692
693     ret = krb5_prepend_config_files(filelist, defpp, &pp);
694     krb5_free_config_files(defpp);
695     if (ret) {
696         return ret;
697     }   
698     *pfilenames = pp;
699     return 0;
700 }
701
702 /**
703  * Get the global configuration list.
704  *
705  * @param pfilenames return array of filenames, should be freed with krb5_free_config_files().
706  *
707  * @return Returns 0 to indicate success.  Otherwise an kerberos et
708  * error code is returned, see krb5_get_error_message().
709  *
710  * @ingroup krb5
711  */
712
713 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
714 krb5_get_default_config_files(char ***pfilenames)
715 {
716     const char *files = NULL;
717
718     if (pfilenames == NULL)
719         return EINVAL;
720     if(!issuid())
721         files = getenv("KRB5_CONFIG");
722     if (files == NULL)
723         files = krb5_config_file;
724
725     return krb5_prepend_config_files(files, NULL, pfilenames);
726 }
727
728 /**
729  * Free a list of configuration files.
730  *
731  * @param filenames list, terminated with a NULL pointer, to be
732  * freed. NULL is an valid argument.
733  *
734  * @return Returns 0 to indicate success. Otherwise an kerberos et
735  * error code is returned, see krb5_get_error_message().
736  *
737  * @ingroup krb5
738  */
739
740 KRB5_LIB_FUNCTION void KRB5_LIB_CALL
741 krb5_free_config_files(char **filenames)
742 {
743     char **p;
744     for(p = filenames; p && *p != NULL; p++)
745         free(*p);
746     free(filenames);
747 }
748
749 /**
750  * Returns the list of Kerberos encryption types sorted in order of
751  * most preferred to least preferred encryption type.  Note that some
752  * encryption types might be disabled, so you need to check with
753  * krb5_enctype_valid() before using the encryption type.
754  *
755  * @return list of enctypes, terminated with ETYPE_NULL. Its a static
756  * array completed into the Kerberos library so the content doesn't
757  * need to be freed.
758  *
759  * @ingroup krb5
760  */
761
762 KRB5_LIB_FUNCTION const krb5_enctype * KRB5_LIB_CALL
763 krb5_kerberos_enctypes(krb5_context context)
764 {
765     static const krb5_enctype p[] = {
766         ETYPE_AES256_CTS_HMAC_SHA1_96,
767         ETYPE_AES128_CTS_HMAC_SHA1_96,
768         ETYPE_DES3_CBC_SHA1,
769         ETYPE_DES3_CBC_MD5,
770         ETYPE_ARCFOUR_HMAC_MD5,
771         ETYPE_DES_CBC_MD5,
772         ETYPE_DES_CBC_MD4,
773         ETYPE_DES_CBC_CRC,
774         ETYPE_NULL
775     };
776     return p;
777 }
778
779 /*
780  * set `etype' to a malloced list of the default enctypes
781  */
782
783 static krb5_error_code
784 default_etypes(krb5_context context, krb5_enctype **etype)
785 {
786     const krb5_enctype *p;
787     krb5_enctype *e = NULL, *ep;
788     int i, n = 0;
789
790     p = krb5_kerberos_enctypes(context);
791
792     for (i = 0; p[i] != ETYPE_NULL; i++) {
793         if (krb5_enctype_valid(context, p[i]) != 0)
794             continue;
795         ep = realloc(e, (n + 2) * sizeof(*e));
796         if (ep == NULL) {
797             free(e);
798             krb5_set_error_message (context, ENOMEM, N_("malloc: out of memory", ""));
799             return ENOMEM;
800         }
801         e = ep;
802         e[n] = p[i];
803         e[n + 1] = ETYPE_NULL;
804         n++;
805     }
806     *etype = e;
807     return 0;
808 }
809
810 /**
811  * Set the default encryption types that will be use in communcation
812  * with the KDC, clients and servers.
813  *
814  * @param context Kerberos 5 context.
815  * @param etypes Encryption types, array terminated with ETYPE_NULL (0).
816  *
817  * @return Returns 0 to indicate success. Otherwise an kerberos et
818  * error code is returned, see krb5_get_error_message().
819  *
820  * @ingroup krb5
821  */
822
823 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
824 krb5_set_default_in_tkt_etypes(krb5_context context,
825                                const krb5_enctype *etypes)
826 {
827     krb5_enctype *p = NULL;
828     int i;
829
830     if(etypes) {
831         for (i = 0; etypes[i]; ++i) {
832             krb5_error_code ret;
833             ret = krb5_enctype_valid(context, etypes[i]);
834             if (ret)
835                 return ret;
836         }
837         ++i;
838         ALLOC(p, i);
839         if(!p) {
840             krb5_set_error_message (context, ENOMEM, N_("malloc: out of memory", ""));
841             return ENOMEM;
842         }
843         memmove(p, etypes, i * sizeof(krb5_enctype));
844     }
845     if(context->etypes)
846         free(context->etypes);
847     context->etypes = p;
848     return 0;
849 }
850
851 /**
852  * Get the default encryption types that will be use in communcation
853  * with the KDC, clients and servers.
854  *
855  * @param context Kerberos 5 context.
856  * @param etypes Encryption types, array terminated with
857  * ETYPE_NULL(0), caller should free array with krb5_xfree():
858  *
859  * @return Returns 0 to indicate success. Otherwise an kerberos et
860  * error code is returned, see krb5_get_error_message().
861  *
862  * @ingroup krb5
863  */
864
865 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
866 krb5_get_default_in_tkt_etypes(krb5_context context,
867                                krb5_enctype **etypes)
868 {
869     krb5_enctype *p;
870     int i;
871     krb5_error_code ret;
872
873     if(context->etypes) {
874         for(i = 0; context->etypes[i]; i++);
875         ++i;
876         ALLOC(p, i);
877         if(!p) {
878             krb5_set_error_message (context, ENOMEM, N_("malloc: out of memory", ""));
879             return ENOMEM;
880         }
881         memmove(p, context->etypes, i * sizeof(krb5_enctype));
882     } else {
883         ret = default_etypes(context, &p);
884         if (ret)
885             return ret;
886     }
887     *etypes = p;
888     return 0;
889 }
890
891 /**
892  * Init the built-in ets in the Kerberos library.
893  *
894  * @param context kerberos context to add the ets too
895  *
896  * @ingroup krb5
897  */
898
899 KRB5_LIB_FUNCTION void KRB5_LIB_CALL
900 krb5_init_ets(krb5_context context)
901 {
902     if(context->et_list == NULL){
903         krb5_add_et_list(context, initialize_krb5_error_table_r);
904         krb5_add_et_list(context, initialize_asn1_error_table_r);
905         krb5_add_et_list(context, initialize_heim_error_table_r);
906
907         krb5_add_et_list(context, initialize_k524_error_table_r);
908
909 #ifdef COM_ERR_BINDDOMAIN_krb5
910         bindtextdomain(COM_ERR_BINDDOMAIN_krb5, HEIMDAL_LOCALEDIR);
911         bindtextdomain(COM_ERR_BINDDOMAIN_asn1, HEIMDAL_LOCALEDIR);
912         bindtextdomain(COM_ERR_BINDDOMAIN_heim, HEIMDAL_LOCALEDIR);
913         bindtextdomain(COM_ERR_BINDDOMAIN_k524, HEIMDAL_LOCALEDIR);
914 #endif
915
916 #ifdef PKINIT
917         krb5_add_et_list(context, initialize_hx_error_table_r);
918 #ifdef COM_ERR_BINDDOMAIN_hx
919         bindtextdomain(COM_ERR_BINDDOMAIN_hx, HEIMDAL_LOCALEDIR);
920 #endif
921 #endif
922     }
923 }
924
925 /**
926  * Make the kerberos library default to the admin KDC.
927  *
928  * @param context Kerberos 5 context.
929  * @param flag boolean flag to select if the use the admin KDC or not.
930  *
931  * @ingroup krb5
932  */
933
934 KRB5_LIB_FUNCTION void KRB5_LIB_CALL
935 krb5_set_use_admin_kdc (krb5_context context, krb5_boolean flag)
936 {
937     context->use_admin_kdc = flag;
938 }
939
940 /**
941  * Make the kerberos library default to the admin KDC.
942  *
943  * @param context Kerberos 5 context.
944  *
945  * @return boolean flag to telling the context will use admin KDC as the default KDC.
946  *
947  * @ingroup krb5
948  */
949
950 KRB5_LIB_FUNCTION krb5_boolean KRB5_LIB_CALL
951 krb5_get_use_admin_kdc (krb5_context context)
952 {
953     return context->use_admin_kdc;
954 }
955
956 /**
957  * Add extra address to the address list that the library will add to
958  * the client's address list when communicating with the KDC.
959  *
960  * @param context Kerberos 5 context.
961  * @param addresses addreses to add
962  *
963  * @return Returns 0 to indicate success. Otherwise an kerberos et
964  * error code is returned, see krb5_get_error_message().
965  *
966  * @ingroup krb5
967  */
968
969 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
970 krb5_add_extra_addresses(krb5_context context, krb5_addresses *addresses)
971 {
972
973     if(context->extra_addresses)
974         return krb5_append_addresses(context,
975                                      context->extra_addresses, addresses);
976     else
977         return krb5_set_extra_addresses(context, addresses);
978 }
979
980 /**
981  * Set extra address to the address list that the library will add to
982  * the client's address list when communicating with the KDC.
983  *
984  * @param context Kerberos 5 context.
985  * @param addresses addreses to set
986  *
987  * @return Returns 0 to indicate success. Otherwise an kerberos et
988  * error code is returned, see krb5_get_error_message().
989  *
990  * @ingroup krb5
991  */
992
993 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
994 krb5_set_extra_addresses(krb5_context context, const krb5_addresses *addresses)
995 {
996     if(context->extra_addresses)
997         krb5_free_addresses(context, context->extra_addresses);
998
999     if(addresses == NULL) {
1000         if(context->extra_addresses != NULL) {
1001             free(context->extra_addresses);
1002             context->extra_addresses = NULL;
1003         }
1004         return 0;
1005     }
1006     if(context->extra_addresses == NULL) {
1007         context->extra_addresses = malloc(sizeof(*context->extra_addresses));
1008         if(context->extra_addresses == NULL) {
1009             krb5_set_error_message (context, ENOMEM, N_("malloc: out of memory", ""));
1010             return ENOMEM;
1011         }
1012     }
1013     return krb5_copy_addresses(context, addresses, context->extra_addresses);
1014 }
1015
1016 /**
1017  * Get extra address to the address list that the library will add to
1018  * the client's address list when communicating with the KDC.
1019  *
1020  * @param context Kerberos 5 context.
1021  * @param addresses addreses to set
1022  *
1023  * @return Returns 0 to indicate success. Otherwise an kerberos et
1024  * error code is returned, see krb5_get_error_message().
1025  *
1026  * @ingroup krb5
1027  */
1028
1029 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
1030 krb5_get_extra_addresses(krb5_context context, krb5_addresses *addresses)
1031 {
1032     if(context->extra_addresses == NULL) {
1033         memset(addresses, 0, sizeof(*addresses));
1034         return 0;
1035     }
1036     return krb5_copy_addresses(context,context->extra_addresses, addresses);
1037 }
1038
1039 /**
1040  * Add extra addresses to ignore when fetching addresses from the
1041  * underlaying operating system.
1042  *
1043  * @param context Kerberos 5 context.
1044  * @param addresses addreses to ignore
1045  *
1046  * @return Returns 0 to indicate success. Otherwise an kerberos et
1047  * error code is returned, see krb5_get_error_message().
1048  *
1049  * @ingroup krb5
1050  */
1051
1052 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
1053 krb5_add_ignore_addresses(krb5_context context, krb5_addresses *addresses)
1054 {
1055
1056     if(context->ignore_addresses)
1057         return krb5_append_addresses(context,
1058                                      context->ignore_addresses, addresses);
1059     else
1060         return krb5_set_ignore_addresses(context, addresses);
1061 }
1062
1063 /**
1064  * Set extra addresses to ignore when fetching addresses from the
1065  * underlaying operating system.
1066  *
1067  * @param context Kerberos 5 context.
1068  * @param addresses addreses to ignore
1069  *
1070  * @return Returns 0 to indicate success. Otherwise an kerberos et
1071  * error code is returned, see krb5_get_error_message().
1072  *
1073  * @ingroup krb5
1074  */
1075
1076 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
1077 krb5_set_ignore_addresses(krb5_context context, const krb5_addresses *addresses)
1078 {
1079     if(context->ignore_addresses)
1080         krb5_free_addresses(context, context->ignore_addresses);
1081     if(addresses == NULL) {
1082         if(context->ignore_addresses != NULL) {
1083             free(context->ignore_addresses);
1084             context->ignore_addresses = NULL;
1085         }
1086         return 0;
1087     }
1088     if(context->ignore_addresses == NULL) {
1089         context->ignore_addresses = malloc(sizeof(*context->ignore_addresses));
1090         if(context->ignore_addresses == NULL) {
1091             krb5_set_error_message (context, ENOMEM, N_("malloc: out of memory", ""));
1092             return ENOMEM;
1093         }
1094     }
1095     return krb5_copy_addresses(context, addresses, context->ignore_addresses);
1096 }
1097
1098 /**
1099  * Get extra addresses to ignore when fetching addresses from the
1100  * underlaying operating system.
1101  *
1102  * @param context Kerberos 5 context.
1103  * @param addresses list addreses ignored
1104  *
1105  * @return Returns 0 to indicate success. Otherwise an kerberos et
1106  * error code is returned, see krb5_get_error_message().
1107  *
1108  * @ingroup krb5
1109  */
1110
1111 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
1112 krb5_get_ignore_addresses(krb5_context context, krb5_addresses *addresses)
1113 {
1114     if(context->ignore_addresses == NULL) {
1115         memset(addresses, 0, sizeof(*addresses));
1116         return 0;
1117     }
1118     return krb5_copy_addresses(context, context->ignore_addresses, addresses);
1119 }
1120
1121 /**
1122  * Set version of fcache that the library should use.
1123  *
1124  * @param context Kerberos 5 context.
1125  * @param version version number.
1126  *
1127  * @return Returns 0 to indicate success. Otherwise an kerberos et
1128  * error code is returned, see krb5_get_error_message().
1129  *
1130  * @ingroup krb5
1131  */
1132
1133 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
1134 krb5_set_fcache_version(krb5_context context, int version)
1135 {
1136     context->fcache_vno = version;
1137     return 0;
1138 }
1139
1140 /**
1141  * Get version of fcache that the library should use.
1142  *
1143  * @param context Kerberos 5 context.
1144  * @param version version number.
1145  *
1146  * @return Returns 0 to indicate success. Otherwise an kerberos et
1147  * error code is returned, see krb5_get_error_message().
1148  *
1149  * @ingroup krb5
1150  */
1151
1152 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
1153 krb5_get_fcache_version(krb5_context context, int *version)
1154 {
1155     *version = context->fcache_vno;
1156     return 0;
1157 }
1158
1159 /**
1160  * Runtime check if the Kerberos library was complied with thread support.
1161  *
1162  * @return TRUE if the library was compiled with thread support, FALSE if not.
1163  *
1164  * @ingroup krb5
1165  */
1166
1167
1168 KRB5_LIB_FUNCTION krb5_boolean KRB5_LIB_CALL
1169 krb5_is_thread_safe(void)
1170 {
1171 #ifdef ENABLE_PTHREAD_SUPPORT
1172     return TRUE;
1173 #else
1174     return FALSE;
1175 #endif
1176 }
1177
1178 /**
1179  * Set if the library should use DNS to canonicalize hostnames.
1180  *
1181  * @param context Kerberos 5 context.
1182  * @param flag if its dns canonicalizion is used or not.
1183  *
1184  * @ingroup krb5
1185  */
1186
1187 KRB5_LIB_FUNCTION void KRB5_LIB_CALL
1188 krb5_set_dns_canonicalize_hostname (krb5_context context, krb5_boolean flag)
1189 {
1190     if (flag)
1191         context->flags |= KRB5_CTX_F_DNS_CANONICALIZE_HOSTNAME;
1192     else
1193         context->flags &= ~KRB5_CTX_F_DNS_CANONICALIZE_HOSTNAME;
1194 }
1195
1196 /**
1197  * Get if the library uses DNS to canonicalize hostnames.
1198  *
1199  * @param context Kerberos 5 context.
1200  *
1201  * @return return non zero if the library uses DNS to canonicalize hostnames.
1202  *
1203  * @ingroup krb5
1204  */
1205
1206 KRB5_LIB_FUNCTION krb5_boolean KRB5_LIB_CALL
1207 krb5_get_dns_canonicalize_hostname (krb5_context context)
1208 {
1209     return (context->flags & KRB5_CTX_F_DNS_CANONICALIZE_HOSTNAME) ? 1 : 0;
1210 }
1211
1212 /**
1213  * Get current offset in time to the KDC.
1214  *
1215  * @param context Kerberos 5 context.
1216  * @param sec seconds part of offset.
1217  * @param usec micro seconds part of offset.
1218  *
1219  * @return returns zero
1220  *
1221  * @ingroup krb5
1222  */
1223
1224 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
1225 krb5_get_kdc_sec_offset (krb5_context context, int32_t *sec, int32_t *usec)
1226 {
1227     if (sec)
1228         *sec = context->kdc_sec_offset;
1229     if (usec)
1230         *usec = context->kdc_usec_offset;
1231     return 0;
1232 }
1233
1234 /**
1235  * Set current offset in time to the KDC.
1236  *
1237  * @param context Kerberos 5 context.
1238  * @param sec seconds part of offset.
1239  * @param usec micro seconds part of offset.
1240  *
1241  * @return returns zero
1242  *
1243  * @ingroup krb5
1244  */
1245
1246 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
1247 krb5_set_kdc_sec_offset (krb5_context context, int32_t sec, int32_t usec)
1248 {
1249     context->kdc_sec_offset = sec;
1250     if (usec >= 0)
1251         context->kdc_usec_offset = usec;
1252     return 0;
1253 }
1254
1255 /**
1256  * Get max time skew allowed.
1257  *
1258  * @param context Kerberos 5 context.
1259  *
1260  * @return timeskew in seconds.
1261  *
1262  * @ingroup krb5
1263  */
1264
1265 KRB5_LIB_FUNCTION time_t KRB5_LIB_CALL
1266 krb5_get_max_time_skew (krb5_context context)
1267 {
1268     return context->max_skew;
1269 }
1270
1271 /**
1272  * Set max time skew allowed.
1273  *
1274  * @param context Kerberos 5 context.
1275  * @param t timeskew in seconds.
1276  *
1277  * @ingroup krb5
1278  */
1279
1280 KRB5_LIB_FUNCTION void KRB5_LIB_CALL
1281 krb5_set_max_time_skew (krb5_context context, time_t t)
1282 {
1283     context->max_skew = t;
1284 }
1285
1286 /**
1287  * Init encryption types in len, val with etypes.
1288  *
1289  * @param context Kerberos 5 context.
1290  * @param len output length of val.
1291  * @param val output array of enctypes.
1292  * @param etypes etypes to set val and len to, if NULL, use default enctypes.
1293
1294  * @return Returns 0 to indicate success. Otherwise an kerberos et
1295  * error code is returned, see krb5_get_error_message().
1296  *
1297  * @ingroup krb5
1298  */
1299
1300 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
1301 krb5_init_etype (krb5_context context,
1302                  unsigned *len,
1303                  krb5_enctype **val,
1304                  const krb5_enctype *etypes)
1305 {
1306     unsigned int i;
1307     krb5_error_code ret;
1308     krb5_enctype *tmp = NULL;
1309
1310     ret = 0;
1311     if (etypes == NULL) {
1312         ret = krb5_get_default_in_tkt_etypes(context, &tmp);
1313         if (ret)
1314             return ret;
1315         etypes = tmp;
1316     }
1317
1318     for (i = 0; etypes[i]; ++i)
1319         ;
1320     *len = i;
1321     *val = malloc(i * sizeof(**val));
1322     if (i != 0 && *val == NULL) {
1323         ret = ENOMEM;
1324         krb5_set_error_message(context, ret, N_("malloc: out of memory", ""));
1325         goto cleanup;
1326     }
1327     memmove (*val,
1328              etypes,
1329              i * sizeof(*tmp));
1330 cleanup:
1331     if (tmp != NULL)
1332         free (tmp);
1333     return ret;
1334 }
1335
1336 /*
1337  * Allow homedir accces
1338  */
1339
1340 static HEIMDAL_MUTEX homedir_mutex = HEIMDAL_MUTEX_INITIALIZER;
1341 static krb5_boolean allow_homedir = TRUE;
1342
1343 krb5_boolean
1344 _krb5_homedir_access(krb5_context context)
1345 {
1346     krb5_boolean allow;
1347
1348 #ifdef HAVE_GETEUID
1349     /* is never allowed for root */
1350     if (geteuid() == 0)
1351         return FALSE;
1352 #endif
1353
1354     if (context && (context->flags & KRB5_CTX_F_HOMEDIR_ACCESS) == 0)
1355         return FALSE;
1356
1357     HEIMDAL_MUTEX_lock(&homedir_mutex);
1358     allow = allow_homedir;
1359     HEIMDAL_MUTEX_unlock(&homedir_mutex);
1360     return allow;
1361 }
1362
1363 /**
1364  * Enable and disable home directory access on either the global state
1365  * or the krb5_context state. By calling krb5_set_home_dir_access()
1366  * with context set to NULL, the global state is configured otherwise
1367  * the state for the krb5_context is modified.
1368  *
1369  * For home directory access to be allowed, both the global state and
1370  * the krb5_context state have to be allowed.
1371  *
1372  * Administrator (root user), never uses the home directory.
1373  *
1374  * @param context a Kerberos 5 context or NULL
1375  * @param allow allow if TRUE home directory
1376  * @return the old value
1377  *
1378  */
1379
1380 krb5_boolean
1381 krb5_set_home_dir_access(krb5_context context, krb5_boolean allow)
1382 {
1383     krb5_boolean old;
1384     if (context) {
1385         old = (context->flags & KRB5_CTX_F_HOMEDIR_ACCESS) ? TRUE : FALSE;
1386         if (allow)
1387             context->flags |= KRB5_CTX_F_HOMEDIR_ACCESS;
1388         else
1389             context->flags &= ~KRB5_CTX_F_HOMEDIR_ACCESS;
1390     } else {
1391         HEIMDAL_MUTEX_lock(&homedir_mutex);
1392         old = allow_homedir;
1393         allow_homedir = allow;
1394         HEIMDAL_MUTEX_unlock(&homedir_mutex);
1395     }
1396
1397     return old;
1398 }