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