Fix the build. Looks like no one ever compiled this on a system
[kai/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  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions
8  * are met:
9  *
10  * 1. Redistributions of source code must retain the above copyright
11  *    notice, this list of conditions and the following disclaimer.
12  *
13  * 2. Redistributions in binary form must reproduce the above copyright
14  *    notice, this list of conditions and the following disclaimer in the
15  *    documentation and/or other materials provided with the distribution.
16  *
17  * 3. Neither the name of the Institute nor the names of its contributors
18  *    may be used to endorse or promote products derived from this software
19  *    without specific prior written permission.
20  *
21  * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
22  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24  * ARE DISCLAIMED.  IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
25  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31  * SUCH DAMAGE.
32  */
33
34 #include "krb5_locl.h"
35 #include <com_err.h>
36
37 RCSID("$Id$");
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  *
91  */
92
93 static krb5_error_code
94 copy_etypes (krb5_context context,
95              krb5_enctype *enctypes,
96              krb5_enctype **ret_enctypes)
97 {
98     unsigned int i;
99
100     for (i = 0; enctypes[i]; i++)
101         ;
102     i++;
103
104     *ret_enctypes = malloc(sizeof(ret_enctypes[0]) * i);
105     if (*ret_enctypes == NULL) {
106         krb5_set_error_message(context, ENOMEM, 
107                                N_("malloc: out of memory", ""));
108         return ENOMEM;
109     }
110     memcpy(*ret_enctypes, enctypes, sizeof(ret_enctypes[0]) * i);
111     return 0;
112 }
113
114
115 /*
116  * read variables from the configuration file and set in `context'
117  */
118
119 static krb5_error_code
120 init_context_from_config_file(krb5_context context)
121 {
122     krb5_error_code ret;
123     const char * tmp;
124     krb5_enctype *tmptypes;
125
126     INIT_FIELD(context, time, max_skew, 5 * 60, "clockskew");
127     INIT_FIELD(context, time, kdc_timeout, 3, "kdc_timeout");
128     INIT_FIELD(context, int, max_retries, 3, "max_retries");
129
130     INIT_FIELD(context, string, http_proxy, NULL, "http_proxy");
131
132     ret = set_etypes (context, "default_etypes", &tmptypes);
133     if(ret)
134         return ret;
135     free(context->etypes);
136     context->etypes = tmptypes;
137
138     ret = set_etypes (context, "default_etypes_des", &tmptypes);
139     if(ret)
140         return ret;
141     free(context->etypes_des);
142     context->etypes_des = tmptypes;
143
144     /* default keytab name */
145     tmp = NULL;
146     if(!issuid())
147         tmp = getenv("KRB5_KTNAME");
148     if(tmp != NULL)
149         context->default_keytab = tmp;
150     else
151         INIT_FIELD(context, string, default_keytab,
152                    KEYTAB_DEFAULT, "default_keytab_name");
153
154     INIT_FIELD(context, string, default_keytab_modify,
155                NULL, "default_keytab_modify_name");
156
157     INIT_FIELD(context, string, time_fmt,
158                "%Y-%m-%dT%H:%M:%S", "time_format");
159
160     INIT_FIELD(context, string, date_fmt,
161                "%Y-%m-%d", "date_format");
162
163     INIT_FIELD(context, bool, log_utc,
164                FALSE, "log_utc");
165
166
167
168     /* init dns-proxy slime */
169     tmp = krb5_config_get_string(context, NULL, "libdefaults",
170                                  "dns_proxy", NULL);
171     if(tmp)
172         roken_gethostby_setup(context->http_proxy, tmp);
173     krb5_free_host_realm (context, context->default_realms);
174     context->default_realms = NULL;
175
176     {
177         krb5_addresses addresses;
178         char **adr, **a;
179
180         krb5_set_extra_addresses(context, NULL);
181         adr = krb5_config_get_strings(context, NULL,
182                                       "libdefaults",
183                                       "extra_addresses",
184                                       NULL);
185         memset(&addresses, 0, sizeof(addresses));
186         for(a = adr; a && *a; a++) {
187             ret = krb5_parse_address(context, *a, &addresses);
188             if (ret == 0) {
189                 krb5_add_extra_addresses(context, &addresses);
190                 krb5_free_addresses(context, &addresses);
191             }
192         }
193         krb5_config_free_strings(adr);
194
195         krb5_set_ignore_addresses(context, NULL);
196         adr = krb5_config_get_strings(context, NULL,
197                                       "libdefaults",
198                                       "ignore_addresses",
199                                       NULL);
200         memset(&addresses, 0, sizeof(addresses));
201         for(a = adr; a && *a; a++) {
202             ret = krb5_parse_address(context, *a, &addresses);
203             if (ret == 0) {
204                 krb5_add_ignore_addresses(context, &addresses);
205                 krb5_free_addresses(context, &addresses);
206             }
207         }
208         krb5_config_free_strings(adr);
209     }
210
211     INIT_FIELD(context, bool, scan_interfaces, TRUE, "scan_interfaces");
212     INIT_FIELD(context, int, fcache_vno, 0, "fcache_version");
213     /* prefer dns_lookup_kdc over srv_lookup. */
214     INIT_FIELD(context, bool, srv_lookup, TRUE, "srv_lookup");
215     INIT_FIELD(context, bool, srv_lookup, context->srv_lookup, "dns_lookup_kdc");
216     INIT_FIELD(context, int, large_msg_size, 1400, "large_message_size");
217     INIT_FLAG(context, flags, KRB5_CTX_F_DNS_CANONICALIZE_HOSTNAME, TRUE, "dns_canonicalize_hostname");
218     INIT_FLAG(context, flags, KRB5_CTX_F_CHECK_PAC, TRUE, "check_pac");
219     context->default_cc_name = NULL;
220     context->default_cc_name_set = 0;
221
222     ret = krb5_config_get_bool_default(context, NULL, FALSE,
223                                        "libdefaults",
224                                        "allow_weak_crypto", NULL);
225     if (ret) {
226         krb5_enctype_enable(context, ETYPE_DES_CBC_CRC);
227         krb5_enctype_enable(context, ETYPE_DES_CBC_MD4);
228         krb5_enctype_enable(context, ETYPE_DES_CBC_MD5);
229         krb5_enctype_enable(context, ETYPE_DES_CBC_NONE);
230         krb5_enctype_enable(context, ETYPE_DES_CFB64_NONE);
231         krb5_enctype_enable(context, ETYPE_DES_PCBC_NONE);
232     }
233
234     return 0;
235 }
236
237 static krb5_error_code
238 cc_ops_register(krb5_context context)
239 {
240     context->cc_ops = NULL;
241     context->num_cc_ops = 0;
242
243     krb5_cc_register(context, &krb5_acc_ops, TRUE);
244     krb5_cc_register(context, &krb5_fcc_ops, TRUE);
245     krb5_cc_register(context, &krb5_mcc_ops, TRUE);
246 #ifdef HAVE_SQLITE
247     krb5_cc_register(context, &krb5_scc_ops, TRUE);
248 #endif
249 #ifdef HAVE_KCM
250     krb5_cc_register(context, &krb5_kcm_ops, TRUE);
251 #endif
252     return 0;
253 }
254
255 static krb5_error_code
256 kt_ops_register(krb5_context context)
257 {
258     context->num_kt_types = 0;
259     context->kt_types     = NULL;
260
261     krb5_kt_register (context, &krb5_fkt_ops);
262     krb5_kt_register (context, &krb5_wrfkt_ops);
263     krb5_kt_register (context, &krb5_javakt_ops);
264     krb5_kt_register (context, &krb5_mkt_ops);
265 #ifndef HEIMDAL_SMALLER
266     krb5_kt_register (context, &krb5_akf_ops);
267 #endif
268     krb5_kt_register (context, &krb5_any_ops);
269     return 0;
270 }
271
272
273 /**
274  * Initializes the context structure and reads the configuration file
275  * /etc/krb5.conf. The structure should be freed by calling
276  * krb5_free_context() when it is no longer being used.
277  *
278  * @param context pointer to returned context
279  *
280  * @return Returns 0 to indicate success.  Otherwise an errno code is
281  * returned.  Failure means either that something bad happened during
282  * initialization (typically ENOMEM) or that Kerberos should not be
283  * used ENXIO.
284  *
285  * @ingroup krb5
286  */
287
288 krb5_error_code KRB5_LIB_FUNCTION
289 krb5_init_context(krb5_context *context)
290 {
291     krb5_context p;
292     krb5_error_code ret;
293     char **files;
294
295     *context = NULL;
296
297     /* should have a run_once */
298 #if defined(HEIMDAL_LOCALEDIR)
299     bindtextdomain(HEIMDAL_TEXTDOMAIN, HEIMDAL_LOCALEDIR);
300 #endif
301
302     p = calloc(1, sizeof(*p));
303     if(!p)
304         return ENOMEM;
305
306     p->mutex = malloc(sizeof(HEIMDAL_MUTEX));
307     if (p->mutex == NULL) {
308         free(p);
309         return ENOMEM;
310     }
311     HEIMDAL_MUTEX_init(p->mutex);
312
313     ret = krb5_get_default_config_files(&files);
314     if(ret)
315         goto out;
316     ret = krb5_set_config_files(p, files);
317     krb5_free_config_files(files);
318     if(ret)
319         goto out;
320
321     /* init error tables */
322     krb5_init_ets(p);
323     cc_ops_register(p);
324     kt_ops_register(p);
325
326 out:
327     if(ret) {
328         krb5_free_context(p);
329         p = NULL;
330     }
331     *context = p;
332     return ret;
333 }
334
335 /**
336  * Make a copy for the Kerberos 5 context, allocated krb5_contex shoud
337  * be freed with krb5_free_context().
338  *
339  * @param in the Kerberos context to copy
340  * @param out the copy of the Kerberos, set to NULL error.
341  *
342  * @return Returns 0 to indicate success.  Otherwise an kerberos et
343  * error code is returned, see krb5_get_error_message().
344  *
345  * @ingroup krb5
346  */
347
348 krb5_error_code KRB5_LIB_FUNCTION
349 krb5_copy_context(krb5_context context, krb5_context *out)
350 {
351     krb5_error_code ret;
352     krb5_context p;
353
354     *out = NULL;
355
356     p = calloc(1, sizeof(*p));
357     if (p == NULL) {
358         krb5_set_error_message(context, ENOMEM, N_("malloc: out of memory", ""));
359         return ENOMEM;
360     }
361
362     p->mutex = malloc(sizeof(HEIMDAL_MUTEX));
363     if (p->mutex == NULL) {
364         krb5_set_error_message(context, ENOMEM, N_("malloc: out of memory", ""));
365         free(p);
366         return ENOMEM;
367     }
368     HEIMDAL_MUTEX_init(p->mutex);
369
370
371     if (context->default_cc_name)
372         p->default_cc_name = strdup(context->default_cc_name);
373     if (context->default_cc_name_env)
374         p->default_cc_name_env = strdup(context->default_cc_name_env);
375     
376     if (context->etypes) {
377         ret = copy_etypes(context, context->etypes, &p->etypes);
378         if (ret)
379             goto out;
380     }
381     if (context->etypes_des) {
382         ret = copy_etypes(context, context->etypes_des, &p->etypes_des);
383         if (ret)
384             goto out;
385     }
386
387     if (context->default_realms) {
388         ret = krb5_copy_host_realm(context, 
389                                    context->default_realms, &p->default_realms);
390         if (ret)
391             goto out;
392     }
393
394     ret = _krb5_config_copy(context, context->cf, &p->cf);
395     if (ret)
396         goto out;
397
398     /* XXX should copy */
399     krb5_init_ets(p);
400     cc_ops_register(p);
401     kt_ops_register(p);
402
403 #if 0 /* XXX */
404     if(context->warn_dest != NULL)
405         ;
406 #endif
407
408     ret = krb5_set_extra_addresses(p, context->extra_addresses);
409     if (ret)
410         goto out;
411     ret = krb5_set_extra_addresses(p, context->ignore_addresses);
412     if (ret)
413         goto out;
414
415     ret = _krb5_copy_send_to_kdc_func(p, context);
416     if (ret)
417         goto out;
418
419     *out = p;
420
421     return 0;
422
423  out:
424     krb5_free_context(p);
425     return ret;
426 }
427
428 /**
429  * Frees the krb5_context allocated by krb5_init_context().
430  *
431  * @param context context to be freed.
432  *
433  * @ingroup krb5
434  */
435
436 void KRB5_LIB_FUNCTION
437 krb5_free_context(krb5_context context)
438 {
439     if (context->default_cc_name)
440         free(context->default_cc_name);
441     if (context->default_cc_name_env)
442         free(context->default_cc_name_env);
443     free(context->etypes);
444     free(context->etypes_des);
445     krb5_free_host_realm (context, context->default_realms);
446     krb5_config_file_free (context, context->cf);
447     free_error_table (context->et_list);
448     free(context->cc_ops);
449     free(context->kt_types);
450     krb5_clear_error_message(context);
451     if(context->warn_dest != NULL)
452         krb5_closelog(context, context->warn_dest);
453     krb5_set_extra_addresses(context, NULL);
454     krb5_set_ignore_addresses(context, NULL);
455     krb5_set_send_to_kdc_func(context, NULL, NULL);
456     if (context->mutex != NULL) {
457         HEIMDAL_MUTEX_destroy(context->mutex);
458         free(context->mutex);
459     }
460     memset(context, 0, sizeof(*context));
461     free(context);
462 }
463
464 /**
465  * Reinit the context from a new set of filenames.
466  *
467  * @param context context to add configuration too.
468  * @param filenames array of filenames, end of list is indicated with a NULL filename.
469  *
470  * @return Returns 0 to indicate success.  Otherwise an kerberos et
471  * error code is returned, see krb5_get_error_message().
472  *
473  * @ingroup krb5
474  */
475
476 krb5_error_code KRB5_LIB_FUNCTION
477 krb5_set_config_files(krb5_context context, char **filenames)
478 {
479     krb5_error_code ret;
480     krb5_config_binding *tmp = NULL;
481     while(filenames != NULL && *filenames != NULL && **filenames != '\0') {
482         ret = krb5_config_parse_file_multi(context, *filenames, &tmp);
483         if(ret != 0 && ret != ENOENT && ret != EACCES) {
484             krb5_config_file_free(context, tmp);
485             return ret;
486         }
487         filenames++;
488     }
489 #if 0
490     /* with this enabled and if there are no config files, Kerberos is
491        considererd disabled */
492     if(tmp == NULL)
493         return ENXIO;
494 #endif
495     krb5_config_file_free(context, context->cf);
496     context->cf = tmp;
497     ret = init_context_from_config_file(context);
498     return ret;
499 }
500
501 static krb5_error_code
502 add_file(char ***pfilenames, int *len, char *file)
503 {
504     char **pp = *pfilenames;
505     int i;
506
507     for(i = 0; i < *len; i++) {
508         if(strcmp(pp[i], file) == 0) {
509             free(file);
510             return 0;
511         }
512     }
513
514     pp = realloc(*pfilenames, (*len + 2) * sizeof(*pp));
515     if (pp == NULL) {
516         free(file);
517         return ENOMEM;
518     }
519
520     pp[*len] = file;
521     pp[*len + 1] = NULL;
522     *pfilenames = pp;
523     *len += 1;
524     return 0;
525 }
526
527 /*
528  *  `pq' isn't free, it's up the the caller
529  */
530
531 krb5_error_code KRB5_LIB_FUNCTION
532 krb5_prepend_config_files(const char *filelist, char **pq, char ***ret_pp)
533 {
534     krb5_error_code ret;
535     const char *p, *q;
536     char **pp;
537     int len;
538     char *fn;
539
540     pp = NULL;
541
542     len = 0;
543     p = filelist;
544     while(1) {
545         ssize_t l;
546         q = p;
547         l = strsep_copy(&q, ":", NULL, 0);
548         if(l == -1)
549             break;
550         fn = malloc(l + 1);
551         if(fn == NULL) {
552             krb5_free_config_files(pp);
553             return ENOMEM;
554         }
555         l = strsep_copy(&p, ":", fn, l + 1);
556         ret = add_file(&pp, &len, fn);
557         if (ret) {
558             krb5_free_config_files(pp);
559             return ret;
560         }
561     }
562
563     if (pq != NULL) {
564         int i;
565
566         for (i = 0; pq[i] != NULL; i++) {
567             fn = strdup(pq[i]);
568             if (fn == NULL) {
569                 krb5_free_config_files(pp);
570                 return ENOMEM;
571             }
572             ret = add_file(&pp, &len, fn);
573             if (ret) {
574                 krb5_free_config_files(pp);
575                 return ret;
576             }
577         }
578     }
579
580     *ret_pp = pp;
581     return 0;
582 }
583
584 /**
585  * Prepend the filename to the global configuration list.
586  *
587  * @param filelist a filename to add to the default list of filename
588  * @param pfilenames return array of filenames, should be freed with krb5_free_config_files().
589  *
590  * @return Returns 0 to indicate success.  Otherwise an kerberos et
591  * error code is returned, see krb5_get_error_message().
592  *
593  * @ingroup krb5
594  */
595
596 krb5_error_code KRB5_LIB_FUNCTION
597 krb5_prepend_config_files_default(const char *filelist, char ***pfilenames)
598 {
599     krb5_error_code ret;
600     char **defpp, **pp = NULL;
601
602     ret = krb5_get_default_config_files(&defpp);
603     if (ret)
604         return ret;
605
606     ret = krb5_prepend_config_files(filelist, defpp, &pp);
607     krb5_free_config_files(defpp);
608     if (ret) {
609         return ret;
610     }   
611     *pfilenames = pp;
612     return 0;
613 }
614
615 /**
616  * Get the global configuration list.
617  *
618  * @param pfilenames return array of filenames, should be freed with krb5_free_config_files().
619  *
620  * @return Returns 0 to indicate success.  Otherwise an kerberos et
621  * error code is returned, see krb5_get_error_message().
622  *
623  * @ingroup krb5
624  */
625
626 krb5_error_code KRB5_LIB_FUNCTION
627 krb5_get_default_config_files(char ***pfilenames)
628 {
629     const char *files = NULL;
630
631     if (pfilenames == NULL)
632         return EINVAL;
633     if(!issuid())
634         files = getenv("KRB5_CONFIG");
635     if (files == NULL)
636         files = krb5_config_file;
637
638     return krb5_prepend_config_files(files, NULL, pfilenames);
639 }
640
641 /**
642  * Free a list of configuration files.
643  *
644  * @param filenames list to be freed.
645  *
646  * @return Returns 0 to indicate success. Otherwise an kerberos et
647  * error code is returned, see krb5_get_error_message().
648  *
649  * @ingroup krb5
650  */
651
652 void KRB5_LIB_FUNCTION
653 krb5_free_config_files(char **filenames)
654 {
655     char **p;
656     for(p = filenames; *p != NULL; p++)
657         free(*p);
658     free(filenames);
659 }
660
661 /**
662  * Returns the list of Kerberos encryption types sorted in order of
663  * most preferred to least preferred encryption type.  Note that some
664  * encryption types might be disabled, so you need to check with
665  * krb5_enctype_valid() before using the encryption type.
666  *
667  * @return list of enctypes, terminated with ETYPE_NULL. Its a static
668  * array completed into the Kerberos library so the content doesn't
669  * need to be freed.
670  *
671  * @ingroup krb5
672  */
673
674 const krb5_enctype * KRB5_LIB_FUNCTION
675 krb5_kerberos_enctypes(krb5_context context)
676 {
677     static const krb5_enctype p[] = {
678         ETYPE_AES256_CTS_HMAC_SHA1_96,
679         ETYPE_AES128_CTS_HMAC_SHA1_96,
680         ETYPE_DES3_CBC_SHA1,
681         ETYPE_DES3_CBC_MD5,
682         ETYPE_ARCFOUR_HMAC_MD5,
683         ETYPE_DES_CBC_MD5,
684         ETYPE_DES_CBC_MD4,
685         ETYPE_DES_CBC_CRC,
686         ETYPE_NULL
687     };
688     return p;
689 }
690
691 /*
692  * set `etype' to a malloced list of the default enctypes
693  */
694
695 static krb5_error_code
696 default_etypes(krb5_context context, krb5_enctype **etype)
697 {
698     const krb5_enctype *p;
699     krb5_enctype *e = NULL, *ep;
700     int i, n = 0;
701
702     p = krb5_kerberos_enctypes(context);
703
704     for (i = 0; p[i] != ETYPE_NULL; i++) {
705         if (krb5_enctype_valid(context, p[i]) != 0)
706             continue;
707         ep = realloc(e, (n + 2) * sizeof(*e));
708         if (ep == NULL) {
709             free(e);
710             krb5_set_error_message (context, ENOMEM, N_("malloc: out of memory", ""));
711             return ENOMEM;
712         }
713         e = ep;
714         e[n] = p[i];
715         e[n + 1] = ETYPE_NULL;
716         n++;
717     }
718     *etype = e;
719     return 0;
720 }
721
722 /**
723  * Set the default encryption types that will be use in communcation
724  * with the KDC, clients and servers.
725  *
726  * @param context Kerberos 5 context.
727  * @param etypes Encryption types, array terminated with ETYPE_NULL (0).
728  *
729  * @return Returns 0 to indicate success. Otherwise an kerberos et
730  * error code is returned, see krb5_get_error_message().
731  *
732  * @ingroup krb5
733  */
734
735 krb5_error_code KRB5_LIB_FUNCTION
736 krb5_set_default_in_tkt_etypes(krb5_context context,
737                                const krb5_enctype *etypes)
738 {
739     krb5_enctype *p = NULL;
740     int i;
741
742     if(etypes) {
743         for (i = 0; etypes[i]; ++i) {
744             krb5_error_code ret;
745             ret = krb5_enctype_valid(context, etypes[i]);
746             if (ret)
747                 return ret;
748         }
749         ++i;
750         ALLOC(p, i);
751         if(!p) {
752             krb5_set_error_message (context, ENOMEM, N_("malloc: out of memory", ""));
753             return ENOMEM;
754         }
755         memmove(p, etypes, i * sizeof(krb5_enctype));
756     }
757     if(context->etypes)
758         free(context->etypes);
759     context->etypes = p;
760     return 0;
761 }
762
763 /**
764  * Get the default encryption types that will be use in communcation
765  * with the KDC, clients and servers.
766  *
767  * @param context Kerberos 5 context.
768  * @param etypes Encryption types, array terminated with
769  * ETYPE_NULL(0), caller should free array with krb5_xfree():
770  *
771  * @return Returns 0 to indicate success. Otherwise an kerberos et
772  * error code is returned, see krb5_get_error_message().
773  *
774  * @ingroup krb5
775  */
776
777 krb5_error_code KRB5_LIB_FUNCTION
778 krb5_get_default_in_tkt_etypes(krb5_context context,
779                                krb5_enctype **etypes)
780 {
781     krb5_enctype *p;
782     int i;
783     krb5_error_code ret;
784
785     if(context->etypes) {
786         for(i = 0; context->etypes[i]; i++);
787         ++i;
788         ALLOC(p, i);
789         if(!p) {
790             krb5_set_error_message (context, ENOMEM, N_("malloc: out of memory", ""));
791             return ENOMEM;
792         }
793         memmove(p, context->etypes, i * sizeof(krb5_enctype));
794     } else {
795         ret = default_etypes(context, &p);
796         if (ret)
797             return ret;
798     }
799     *etypes = p;
800     return 0;
801 }
802
803 /**
804  * Return the error string for the error code. The caller must not
805  * free the string.
806  *
807  * @param context Kerberos 5 context.
808  * @param code Kerberos error code.
809  *
810  * @return the error message matching code
811  *
812  * @ingroup krb5
813  */
814
815 const char* KRB5_LIB_FUNCTION
816 krb5_get_err_text(krb5_context context, krb5_error_code code)
817 {
818     const char *p = NULL;
819     if(context != NULL)
820         p = com_right(context->et_list, code);
821     if(p == NULL)
822         p = strerror(code);
823     if (p == NULL)
824         p = "Unknown error";
825     return p;
826 }
827
828 /**
829  * Init the built-in ets in the Kerberos library.
830  *
831  * @param context kerberos context to add the ets too
832  *
833  * @ingroup krb5
834  */
835
836 void KRB5_LIB_FUNCTION
837 krb5_init_ets(krb5_context context)
838 {
839     if(context->et_list == NULL){
840         krb5_add_et_list(context, initialize_krb5_error_table_r);
841 #if defined(HEIMDAL_LOCALEDIR)
842         bindtextdomain(COM_ERR_BINDDOMAIN_krb5, HEIMDAL_LOCALEDIR);
843 #endif
844
845         krb5_add_et_list(context, initialize_asn1_error_table_r);
846 #if defined(HEIMDAL_LOCALEDIR)
847         bindtextdomain(COM_ERR_BINDDOMAIN_asn1, HEIMDAL_LOCALEDIR);
848 #endif
849
850         krb5_add_et_list(context, initialize_heim_error_table_r);
851 #if defined(HEIMDAL_LOCALEDIR)
852         bindtextdomain(COM_ERR_BINDDOMAIN_heim, HEIMDAL_LOCALEDIR);
853 #endif
854
855         krb5_add_et_list(context, initialize_k524_error_table_r);
856 #if defined(HEIMDAL_LOCALEDIR)
857         bindtextdomain(COM_ERR_BINDDOMAIN_k524, HEIMDAL_LOCALEDIR);
858 #endif
859
860 #ifdef PKINIT
861         krb5_add_et_list(context, initialize_hx_error_table_r);
862 #if defined(HEIMDAL_LOCALEDIR)
863         bindtextdomain(COM_ERR_BINDDOMAIN_hx, HEIMDAL_LOCALEDIR);
864 #endif
865 #endif
866     }
867 }
868
869 /**
870  * Make the kerberos library default to the admin KDC.
871  *
872  * @param context Kerberos 5 context.
873  * @param flag boolean flag to select if the use the admin KDC or not.
874  *
875  * @ingroup krb5
876  */
877
878 void KRB5_LIB_FUNCTION
879 krb5_set_use_admin_kdc (krb5_context context, krb5_boolean flag)
880 {
881     context->use_admin_kdc = flag;
882 }
883
884 /**
885  * Make the kerberos library default to the admin KDC.
886  *
887  * @param context Kerberos 5 context.
888  *
889  * @return boolean flag to telling the context will use admin KDC as the default KDC.
890  *
891  * @ingroup krb5
892  */
893
894 krb5_boolean KRB5_LIB_FUNCTION
895 krb5_get_use_admin_kdc (krb5_context context)
896 {
897     return context->use_admin_kdc;
898 }
899
900 /**
901  * Add extra address to the address list that the library will add to
902  * the client's address list when communicating with the KDC.
903  *
904  * @param context Kerberos 5 context.
905  * @param addresses addreses to add
906  *
907  * @return Returns 0 to indicate success. Otherwise an kerberos et
908  * error code is returned, see krb5_get_error_message().
909  *
910  * @ingroup krb5
911  */
912
913 krb5_error_code KRB5_LIB_FUNCTION
914 krb5_add_extra_addresses(krb5_context context, krb5_addresses *addresses)
915 {
916
917     if(context->extra_addresses)
918         return krb5_append_addresses(context,
919                                      context->extra_addresses, addresses);
920     else
921         return krb5_set_extra_addresses(context, addresses);
922 }
923
924 /**
925  * Set extra address to the address list that the library will add to
926  * the client's address list when communicating with the KDC.
927  *
928  * @param context Kerberos 5 context.
929  * @param addresses addreses to set
930  *
931  * @return Returns 0 to indicate success. Otherwise an kerberos et
932  * error code is returned, see krb5_get_error_message().
933  *
934  * @ingroup krb5
935  */
936
937 krb5_error_code KRB5_LIB_FUNCTION
938 krb5_set_extra_addresses(krb5_context context, const krb5_addresses *addresses)
939 {
940     if(context->extra_addresses)
941         krb5_free_addresses(context, context->extra_addresses);
942
943     if(addresses == NULL) {
944         if(context->extra_addresses != NULL) {
945             free(context->extra_addresses);
946             context->extra_addresses = NULL;
947         }
948         return 0;
949     }
950     if(context->extra_addresses == NULL) {
951         context->extra_addresses = malloc(sizeof(*context->extra_addresses));
952         if(context->extra_addresses == NULL) {
953             krb5_set_error_message (context, ENOMEM, N_("malloc: out of memory", ""));
954             return ENOMEM;
955         }
956     }
957     return krb5_copy_addresses(context, addresses, context->extra_addresses);
958 }
959
960 /**
961  * Get extra address to the address list that the library will add to
962  * the client's address list when communicating with the KDC.
963  *
964  * @param context Kerberos 5 context.
965  * @param addresses addreses to set
966  *
967  * @return Returns 0 to indicate success. Otherwise an kerberos et
968  * error code is returned, see krb5_get_error_message().
969  *
970  * @ingroup krb5
971  */
972
973 krb5_error_code KRB5_LIB_FUNCTION
974 krb5_get_extra_addresses(krb5_context context, krb5_addresses *addresses)
975 {
976     if(context->extra_addresses == NULL) {
977         memset(addresses, 0, sizeof(*addresses));
978         return 0;
979     }
980     return krb5_copy_addresses(context,context->extra_addresses, addresses);
981 }
982
983 /**
984  * Add extra addresses to ignore when fetching addresses from the
985  * underlaying operating system.
986  *
987  * @param context Kerberos 5 context.
988  * @param addresses addreses to ignore
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_error_code KRB5_LIB_FUNCTION
997 krb5_add_ignore_addresses(krb5_context context, krb5_addresses *addresses)
998 {
999
1000     if(context->ignore_addresses)
1001         return krb5_append_addresses(context,
1002                                      context->ignore_addresses, addresses);
1003     else
1004         return krb5_set_ignore_addresses(context, addresses);
1005 }
1006
1007 /**
1008  * Set extra addresses to ignore when fetching addresses from the
1009  * underlaying operating system.
1010  *
1011  * @param context Kerberos 5 context.
1012  * @param addresses addreses to ignore
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_error_code KRB5_LIB_FUNCTION
1021 krb5_set_ignore_addresses(krb5_context context, const krb5_addresses *addresses)
1022 {
1023     if(context->ignore_addresses)
1024         krb5_free_addresses(context, context->ignore_addresses);
1025     if(addresses == NULL) {
1026         if(context->ignore_addresses != NULL) {
1027             free(context->ignore_addresses);
1028             context->ignore_addresses = NULL;
1029         }
1030         return 0;
1031     }
1032     if(context->ignore_addresses == NULL) {
1033         context->ignore_addresses = malloc(sizeof(*context->ignore_addresses));
1034         if(context->ignore_addresses == NULL) {
1035             krb5_set_error_message (context, ENOMEM, N_("malloc: out of memory", ""));
1036             return ENOMEM;
1037         }
1038     }
1039     return krb5_copy_addresses(context, addresses, context->ignore_addresses);
1040 }
1041
1042 /**
1043  * Get extra addresses to ignore when fetching addresses from the
1044  * underlaying operating system.
1045  *
1046  * @param context Kerberos 5 context.
1047  * @param addresses list addreses ignored
1048  *
1049  * @return Returns 0 to indicate success. Otherwise an kerberos et
1050  * error code is returned, see krb5_get_error_message().
1051  *
1052  * @ingroup krb5
1053  */
1054
1055 krb5_error_code KRB5_LIB_FUNCTION
1056 krb5_get_ignore_addresses(krb5_context context, krb5_addresses *addresses)
1057 {
1058     if(context->ignore_addresses == NULL) {
1059         memset(addresses, 0, sizeof(*addresses));
1060         return 0;
1061     }
1062     return krb5_copy_addresses(context, context->ignore_addresses, addresses);
1063 }
1064
1065 /**
1066  * Set version of fcache that the library should use.
1067  *
1068  * @param context Kerberos 5 context.
1069  * @param version version number.
1070  *
1071  * @return Returns 0 to indicate success. Otherwise an kerberos et
1072  * error code is returned, see krb5_get_error_message().
1073  *
1074  * @ingroup krb5
1075  */
1076
1077 krb5_error_code KRB5_LIB_FUNCTION
1078 krb5_set_fcache_version(krb5_context context, int version)
1079 {
1080     context->fcache_vno = version;
1081     return 0;
1082 }
1083
1084 /**
1085  * Get version of fcache that the library should use.
1086  *
1087  * @param context Kerberos 5 context.
1088  * @param version version number.
1089  *
1090  * @return Returns 0 to indicate success. Otherwise an kerberos et
1091  * error code is returned, see krb5_get_error_message().
1092  *
1093  * @ingroup krb5
1094  */
1095
1096 krb5_error_code KRB5_LIB_FUNCTION
1097 krb5_get_fcache_version(krb5_context context, int *version)
1098 {
1099     *version = context->fcache_vno;
1100     return 0;
1101 }
1102
1103 /**
1104  * Runtime check if the Kerberos library was complied with thread support.
1105  *
1106  * @return TRUE if the library was compiled with thread support, FALSE if not.
1107  *
1108  * @ingroup krb5
1109  */
1110
1111
1112 krb5_boolean KRB5_LIB_FUNCTION
1113 krb5_is_thread_safe(void)
1114 {
1115 #ifdef ENABLE_PTHREAD_SUPPORT
1116     return TRUE;
1117 #else
1118     return FALSE;
1119 #endif
1120 }
1121
1122 /**
1123  * Set if the library should use DNS to canonicalize hostnames.
1124  *
1125  * @param context Kerberos 5 context.
1126  * @param flag if its dns canonicalizion is used or not.
1127  *
1128  * @ingroup krb5
1129  */
1130
1131 void KRB5_LIB_FUNCTION
1132 krb5_set_dns_canonicalize_hostname (krb5_context context, krb5_boolean flag)
1133 {
1134     if (flag)
1135         context->flags |= KRB5_CTX_F_DNS_CANONICALIZE_HOSTNAME;
1136     else
1137         context->flags &= ~KRB5_CTX_F_DNS_CANONICALIZE_HOSTNAME;
1138 }
1139
1140 /**
1141  * Get if the library uses DNS to canonicalize hostnames.
1142  *
1143  * @param context Kerberos 5 context.
1144  *
1145  * @return return non zero if the library uses DNS to canonicalize hostnames.
1146  *
1147  * @ingroup krb5
1148  */
1149
1150 krb5_boolean KRB5_LIB_FUNCTION
1151 krb5_get_dns_canonicalize_hostname (krb5_context context)
1152 {
1153     return (context->flags & KRB5_CTX_F_DNS_CANONICALIZE_HOSTNAME) ? 1 : 0;
1154 }
1155
1156 /**
1157  * Get current offset in time to the KDC.
1158  *
1159  * @param context Kerberos 5 context.
1160  * @param sec seconds part of offset.
1161  * @param usec micro seconds part of offset.
1162  *
1163  * @return returns zero
1164  *
1165  * @ingroup krb5
1166  */
1167
1168 krb5_error_code KRB5_LIB_FUNCTION
1169 krb5_get_kdc_sec_offset (krb5_context context, int32_t *sec, int32_t *usec)
1170 {
1171     if (sec)
1172         *sec = context->kdc_sec_offset;
1173     if (usec)
1174         *usec = context->kdc_usec_offset;
1175     return 0;
1176 }
1177
1178 /**
1179  * Set current offset in time to the KDC.
1180  *
1181  * @param context Kerberos 5 context.
1182  * @param sec seconds part of offset.
1183  * @param usec micro seconds part of offset.
1184  *
1185  * @return returns zero
1186  *
1187  * @ingroup krb5
1188  */
1189
1190 krb5_error_code KRB5_LIB_FUNCTION
1191 krb5_set_kdc_sec_offset (krb5_context context, int32_t sec, int32_t usec)
1192 {
1193     context->kdc_sec_offset = sec;
1194     if (usec >= 0)
1195         context->kdc_usec_offset = usec;
1196     return 0;
1197 }
1198
1199 /**
1200  * Get max time skew allowed.
1201  *
1202  * @param context Kerberos 5 context.
1203  *
1204  * @return timeskew in seconds.
1205  *
1206  * @ingroup krb5
1207  */
1208
1209 time_t KRB5_LIB_FUNCTION
1210 krb5_get_max_time_skew (krb5_context context)
1211 {
1212     return context->max_skew;
1213 }
1214
1215 /**
1216  * Set max time skew allowed.
1217  *
1218  * @param context Kerberos 5 context.
1219  * @param t timeskew in seconds.
1220  *
1221  * @ingroup krb5
1222  */
1223
1224 void KRB5_LIB_FUNCTION
1225 krb5_set_max_time_skew (krb5_context context, time_t t)
1226 {
1227     context->max_skew = t;
1228 }