Fix trace logging initialization
[krb5.git] / src / lib / krb5 / krb / init_ctx.c
1 /* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */
2 /* lib/krb5/krb/init_ctx.c */
3 /*
4  * Copyright 1994,1999,2000, 2002, 2003, 2007, 2008, 2009  by the Massachusetts Institute of Technology.
5  * All Rights Reserved.
6  *
7  * Export of this software from the United States of America may
8  *   require a specific license from the United States Government.
9  *   It is the responsibility of any person or organization contemplating
10  *   export to obtain such a license before exporting.
11  *
12  * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
13  * distribute this software and its documentation for any purpose and
14  * without fee is hereby granted, provided that the above copyright
15  * notice appear in all copies and that both that copyright notice and
16  * this permission notice appear in supporting documentation, and that
17  * the name of M.I.T. not be used in advertising or publicity pertaining
18  * to distribution of the software without specific, written prior
19  * permission.  Furthermore if you modify this software you must label
20  * your software as modified software and not distribute it in such a
21  * fashion that it might be confused with the original M.I.T. software.
22  * M.I.T. makes no representations about the suitability of
23  * this software for any purpose.  It is provided "as is" without express
24  * or implied warranty.
25  */
26 /*
27  * Copyright (C) 1998 by the FundsXpress, INC.
28  *
29  * All rights reserved.
30  *
31  * Export of this software from the United States of America may require
32  * a specific license from the United States Government.  It is the
33  * responsibility of any person or organization contemplating export to
34  * obtain such a license before exporting.
35  *
36  * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
37  * distribute this software and its documentation for any purpose and
38  * without fee is hereby granted, provided that the above copyright
39  * notice appear in all copies and that both that copyright notice and
40  * this permission notice appear in supporting documentation, and that
41  * the name of FundsXpress. not be used in advertising or publicity pertaining
42  * to distribution of the software without specific, written prior
43  * permission.  FundsXpress makes no representations about the suitability of
44  * this software for any purpose.  It is provided "as is" without express
45  * or implied warranty.
46  *
47  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
48  * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
49  * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
50  */
51
52 #include "k5-int.h"
53 #include "int-proto.h"
54 #include <ctype.h>
55 #include "brand.c"
56 #include "../krb5_libinit.h"
57
58 /* The des-mdX entries are last for now, because it's easy to
59    configure KDCs to issue TGTs with des-mdX keys and then not accept
60    them.  This'll be fixed, but for better compatibility, let's prefer
61    des-crc for now.  */
62 static krb5_enctype default_enctype_list[] = {
63     ENCTYPE_AES256_CTS_HMAC_SHA1_96, ENCTYPE_AES128_CTS_HMAC_SHA1_96,
64     ENCTYPE_DES3_CBC_SHA1,
65     ENCTYPE_ARCFOUR_HMAC,
66     ENCTYPE_DES_CBC_CRC, ENCTYPE_DES_CBC_MD5, ENCTYPE_DES_CBC_MD4,
67     0
68 };
69
70 #if (defined(_WIN32))
71 extern krb5_error_code krb5_vercheck();
72 extern void krb5_win_ccdll_load(krb5_context context);
73 #endif
74
75 #define DEFAULT_CLOCKSKEW  300 /* 5 min */
76
77 static krb5_error_code
78 get_integer(krb5_context ctx, const char *name, int def_val, int *int_out)
79 {
80     krb5_error_code retval;
81
82     retval = profile_get_integer(ctx->profile, KRB5_CONF_LIBDEFAULTS,
83                                  name, NULL, def_val, int_out);
84     if (retval)
85         TRACE_PROFILE_ERR(ctx, name, KRB5_CONF_LIBDEFAULTS, retval);
86     return retval;
87 }
88
89 static krb5_error_code
90 get_boolean(krb5_context ctx, const char *name, int def_val, int *boolean_out)
91 {
92     krb5_error_code retval;
93
94     retval = profile_get_boolean(ctx->profile, KRB5_CONF_LIBDEFAULTS,
95                                  name, NULL, def_val, boolean_out);
96     if (retval)
97         TRACE_PROFILE_ERR(ctx, name, KRB5_CONF_LIBDEFAULTS, retval);
98     return retval;
99 }
100
101 krb5_error_code KRB5_CALLCONV
102 krb5_init_context(krb5_context *context)
103 {
104     /*
105      * This is rather silly, but should improve our chances of
106      * retaining the krb5_brand array in the final linked library,
107      * better than a static variable that's unreferenced after
108      * optimization, or even a non-static symbol that's not exported
109      * from the library nor referenced from anywhere else in the
110      * library.
111      *
112      * If someday we grow an API to actually return the string, we can
113      * get rid of this silliness.
114      */
115     int my_zero = (krb5_brand[0] == 0);
116
117     return krb5_init_context_profile(NULL, my_zero, context);
118 }
119
120 krb5_error_code KRB5_CALLCONV
121 krb5_init_secure_context(krb5_context *context)
122 {
123     return krb5_init_context_profile(NULL, KRB5_INIT_CONTEXT_SECURE, context);
124 }
125
126 krb5_error_code
127 krb5int_init_context_kdc(krb5_context *context)
128 {
129     return krb5_init_context_profile(NULL, KRB5_INIT_CONTEXT_KDC, context);
130 }
131
132 krb5_error_code KRB5_CALLCONV
133 krb5_init_context_profile(profile_t profile, krb5_flags flags,
134                           krb5_context *context_out)
135 {
136     krb5_context ctx = 0;
137     krb5_error_code retval;
138     struct {
139         krb5_int32 now, now_usec;
140         long pid;
141     } seed_data;
142     krb5_data seed;
143     int tmp;
144
145     /* Verify some assumptions.  If the assumptions hold and the
146        compiler is optimizing, this should result in no code being
147        executed.  If we're guessing "unsigned long long" instead
148        of using uint64_t, the possibility does exist that we're
149        wrong.  */
150     {
151         krb5_ui_8 i64;
152         assert(sizeof(i64) == 8);
153         i64 = 0, i64--, i64 >>= 62;
154         assert(i64 == 3);
155         i64 = 1, i64 <<= 31, i64 <<= 31, i64 <<= 1;
156         assert(i64 != 0);
157         i64 <<= 1;
158         assert(i64 == 0);
159     }
160
161     retval = krb5int_initialize_library();
162     if (retval)
163         return retval;
164
165 #if (defined(_WIN32))
166     /*
167      * Load the krbcc32.dll if necessary.  We do this here so that
168      * we know to use API: later on during initialization.
169      * The context being NULL is ok.
170      */
171     krb5_win_ccdll_load(ctx);
172
173     /*
174      * krb5_vercheck() is defined in win_glue.c, and this is
175      * where we handle the timebomb and version server checks.
176      */
177     retval = krb5_vercheck();
178     if (retval)
179         return retval;
180 #endif
181
182     *context_out = NULL;
183
184     ctx = calloc(1, sizeof(struct _krb5_context));
185     if (!ctx)
186         return ENOMEM;
187     ctx->magic = KV5M_CONTEXT;
188
189     ctx->profile_secure = (flags & KRB5_INIT_CONTEXT_SECURE) != 0;
190
191     if ((retval = krb5_os_init_context(ctx, profile, flags)) != 0)
192         goto cleanup;
193
194     ctx->trace_callback = NULL;
195 #ifndef DISABLE_TRACING
196     if (!ctx->profile_secure)
197         krb5int_init_trace(ctx);
198 #endif
199
200     retval = get_boolean(ctx, KRB5_CONF_ALLOW_WEAK_CRYPTO, 0, &tmp);
201     if (retval)
202         goto cleanup;
203     ctx->allow_weak_crypto = tmp;
204
205     retval = get_boolean(ctx, KRB5_CONF_IGNORE_ACCEPTOR_HOSTNAME, 0, &tmp);
206     if (retval)
207         goto cleanup;
208     ctx->ignore_acceptor_hostname = tmp;
209
210     /* initialize the prng (not well, but passable) */
211     if ((retval = krb5_c_random_os_entropy( ctx, 0, NULL)) !=0)
212         goto cleanup;
213     if ((retval = krb5_crypto_us_timeofday(&seed_data.now, &seed_data.now_usec)))
214         goto cleanup;
215     seed_data.pid = getpid ();
216     seed.length = sizeof(seed_data);
217     seed.data = (char *) &seed_data;
218     if ((retval = krb5_c_random_add_entropy(ctx, KRB5_C_RANDSOURCE_TIMING, &seed)))
219         goto cleanup;
220
221     ctx->default_realm = 0;
222     get_integer(ctx, KRB5_CONF_CLOCKSKEW, DEFAULT_CLOCKSKEW, &tmp);
223     ctx->clockskew = tmp;
224
225 #if 0
226     /* Default ticket lifetime is currently not supported */
227     profile_get_integer(ctx->profile, KRB5_CONF_LIBDEFAULTS, "tkt_lifetime",
228                         0, 10 * 60 * 60, &tmp);
229     ctx->tkt_lifetime = tmp;
230 #endif
231
232     /* DCE 1.1 and below only support CKSUMTYPE_RSA_MD4 (2)  */
233     /* DCE add kdc_req_checksum_type = 2 to krb5.conf */
234     get_integer(ctx, KRB5_CONF_KDC_REQ_CHECKSUM_TYPE, CKSUMTYPE_RSA_MD5,
235                 &tmp);
236     ctx->kdc_req_sumtype = tmp;
237
238     get_integer(ctx, KRB5_CONF_AP_REQ_CHECKSUM_TYPE, 0, &tmp);
239     ctx->default_ap_req_sumtype = tmp;
240
241     get_integer(ctx, KRB5_CONF_SAFE_CHECKSUM_TYPE, CKSUMTYPE_RSA_MD5_DES,
242                 &tmp);
243     ctx->default_safe_sumtype = tmp;
244
245     get_integer(ctx, KRB5_CONF_KDC_DEFAULT_OPTIONS, KDC_OPT_RENEWABLE_OK,
246                 &tmp);
247     ctx->kdc_default_options = tmp;
248 #define DEFAULT_KDC_TIMESYNC 1
249     get_integer(ctx, KRB5_CONF_KDC_TIMESYNC, DEFAULT_KDC_TIMESYNC, &tmp);
250     ctx->library_options = tmp ? KRB5_LIBOPT_SYNC_KDCTIME : 0;
251
252     retval = profile_get_string(ctx->profile, KRB5_CONF_LIBDEFAULTS,
253                                 KRB5_CONF_PLUGIN_BASE_DIR, 0,
254                                 DEFAULT_PLUGIN_BASE_DIR,
255                                 &ctx->plugin_base_dir);
256     if (retval) {
257         TRACE_PROFILE_ERR(ctx, KRB5_CONF_PLUGIN_BASE_DIR,
258                           KRB5_CONF_LIBDEFAULTS, retval);
259         goto cleanup;
260     }
261
262     /*
263      * We use a default file credentials cache of 3.  See
264      * lib/krb5/krb/ccache/file/fcc.h for a description of the
265      * credentials cache types.
266      *
267      * Note: DCE 1.0.3a only supports a cache type of 1
268      *      DCE 1.1 supports a cache type of 2.
269      */
270 #define DEFAULT_CCACHE_TYPE 4
271     get_integer(ctx, KRB5_CONF_CCACHE_TYPE, DEFAULT_CCACHE_TYPE, &tmp);
272     ctx->fcc_default_format = tmp + 0x0500;
273     ctx->prompt_types = 0;
274     ctx->use_conf_ktypes = 0;
275     ctx->udp_pref_limit = -1;
276     *context_out = ctx;
277     return 0;
278
279 cleanup:
280     krb5_free_context(ctx);
281     return retval;
282 }
283
284 void KRB5_CALLCONV
285 krb5_free_context(krb5_context ctx)
286 {
287     if (ctx == NULL)
288         return;
289     krb5_os_free_context(ctx);
290
291     free(ctx->in_tkt_etypes);
292     ctx->in_tkt_etypes = NULL;
293     free(ctx->tgs_etypes);
294     ctx->tgs_etypes = NULL;
295     free(ctx->default_realm);
296     ctx->default_realm = 0;
297     if (ctx->ser_ctx_count && ctx->ser_ctx) {
298         free(ctx->ser_ctx);
299         ctx->ser_ctx = 0;
300     }
301
302     krb5_clear_error_message(ctx);
303
304 #ifndef DISABLE_TRACING
305     if (ctx->trace_callback)
306         ctx->trace_callback(ctx, NULL, ctx->trace_callback_data);
307 #endif
308
309     k5_ccselect_free_context(ctx);
310     k5_plugin_free_context(ctx);
311     free(ctx->plugin_base_dir);
312
313     ctx->magic = 0;
314     free(ctx);
315 }
316
317 /*
318  * Set the desired default ktypes, making sure they are valid.
319  */
320 static krb5_error_code
321 set_default_etype_var(krb5_context context, const krb5_enctype *etypes,
322                       krb5_enctype **var)
323 {
324     krb5_error_code code;
325     krb5_enctype *list;
326     size_t src, dst;
327
328     if (etypes) {
329         /* Empty list passed in. */
330         if (etypes[0] == 0)
331             return EINVAL;
332         code = krb5int_copy_etypes(etypes, &list);
333         if (code)
334             return code;
335
336         /* Filter list in place to exclude invalid and (optionally) weak
337          * enctypes. */
338         for (src = dst = 0; list[src]; src++) {
339             if (!krb5_c_valid_enctype(list[src]))
340                 continue;
341             if (!context->allow_weak_crypto
342                 && krb5int_c_weak_enctype(list[src]))
343                 continue;
344             list[dst++] = list[src];
345         }
346         list[dst] = 0;          /* Zero-terminate. */
347         if (dst == 0) {
348             free(list);
349             return KRB5_CONFIG_ETYPE_NOSUPP;
350         }
351     } else {
352         list = NULL;
353     }
354
355     free(*var);
356     *var = list;
357     return 0;
358 }
359
360 krb5_error_code
361 krb5_set_default_in_tkt_ktypes(krb5_context context,
362                                const krb5_enctype *etypes)
363 {
364     return set_default_etype_var(context, etypes, &context->in_tkt_etypes);
365 }
366
367 krb5_error_code KRB5_CALLCONV
368 krb5_set_default_tgs_enctypes(krb5_context context, const krb5_enctype *etypes)
369 {
370     return set_default_etype_var(context, etypes, &context->tgs_etypes);
371 }
372
373 /* Old name for above function. */
374 krb5_error_code
375 krb5_set_default_tgs_ktypes(krb5_context context, const krb5_enctype *etypes)
376 {
377     return set_default_etype_var(context, etypes, &context->tgs_etypes);
378 }
379
380 /*
381  * Add etype to, or remove etype from, the zero-terminated list *list_ptr,
382  * reallocating if the list size changes.  Filter out weak enctypes if
383  * allow_weak is false.  If memory allocation fails, set *list_ptr to NULL and
384  * do nothing for subsequent operations.
385  */
386 static void
387 mod_list(krb5_enctype etype, krb5_boolean add, krb5_boolean allow_weak,
388          krb5_enctype **list_ptr)
389 {
390     size_t i;
391     krb5_enctype *list = *list_ptr;
392
393     /* Stop now if a previous allocation failed or the enctype is filtered. */
394     if (list == NULL || (!allow_weak && krb5int_c_weak_enctype(etype)))
395         return;
396     if (add) {
397         /* Count entries; do nothing if etype is a duplicate. */
398         for (i = 0; list[i] != 0; i++) {
399             if (list[i] == etype)
400                 return;
401         }
402         /* Make room for the new entry and add it. */
403         list = realloc(list, (i + 2) * sizeof(krb5_enctype));
404         if (list != NULL) {
405             list[i] = etype;
406             list[i + 1] = 0;
407         }
408     } else {
409         /* Look for etype in the list. */
410         for (i = 0; list[i] != 0; i++) {
411             if (list[i] != etype)
412                 continue;
413             /* Perform removal. */
414             for (; list[i + 1] != 0; i++)
415                 list[i] = list[i + 1];
416             list[i] = 0;
417             list = realloc(list, (i + 1) * sizeof(krb5_enctype));
418             break;
419         }
420     }
421     /* Update *list_ptr, freeing the old value if realloc failed. */
422     if (list == NULL)
423         free(*list_ptr);
424     *list_ptr = list;
425 }
426
427 /*
428  * Set *result to a zero-terminated list of enctypes resulting from
429  * parsing profstr.  profstr may be modified during parsing.
430  */
431 krb5_error_code
432 krb5int_parse_enctype_list(krb5_context context, const char *profkey,
433                            char *profstr, krb5_enctype *default_list,
434                            krb5_enctype **result)
435 {
436     char *token, *delim = " \t\r\n,", *save = NULL;
437     krb5_boolean sel, weak = context->allow_weak_crypto;
438     krb5_enctype etype, *list;
439     unsigned int i;
440
441     *result = NULL;
442
443     /* Set up an empty list.  Allocation failure is detected at the end. */
444     list = malloc(sizeof(krb5_enctype));
445     if (list != NULL)
446         list[0] = 0;
447
448     /* Walk through the words in profstr. */
449     for (token = strtok_r(profstr, delim, &save); token;
450          token = strtok_r(NULL, delim, &save)) {
451         /* Determine if we are adding or removing enctypes. */
452         sel = TRUE;
453         if (*token == '+' || *token == '-')
454             sel = (*token++ == '+');
455
456         if (strcasecmp(token, "DEFAULT") == 0) {
457             /* Set all enctypes in the default list. */
458             for (i = 0; default_list[i]; i++)
459                 mod_list(default_list[i], sel, weak, &list);
460         } else if (strcasecmp(token, "des") == 0) {
461             mod_list(ENCTYPE_DES_CBC_CRC, sel, weak, &list);
462             mod_list(ENCTYPE_DES_CBC_MD5, sel, weak, &list);
463             mod_list(ENCTYPE_DES_CBC_MD4, sel, weak, &list);
464         } else if (strcasecmp(token, "des3") == 0) {
465             mod_list(ENCTYPE_DES3_CBC_SHA1, sel, weak, &list);
466         } else if (strcasecmp(token, "aes") == 0) {
467             mod_list(ENCTYPE_AES256_CTS_HMAC_SHA1_96, sel, weak, &list);
468             mod_list(ENCTYPE_AES128_CTS_HMAC_SHA1_96, sel, weak, &list);
469         } else if (strcasecmp(token, "rc4") == 0) {
470             mod_list(ENCTYPE_ARCFOUR_HMAC, sel, weak, &list);
471 #ifdef CAMELLIA
472         } else if (strcasecmp(token, "camellia") == 0) {
473             mod_list(ENCTYPE_CAMELLIA256_CTS_CMAC, sel, weak, &list);
474             mod_list(ENCTYPE_CAMELLIA128_CTS_CMAC, sel, weak, &list);
475 #endif
476         } else if (krb5_string_to_enctype(token, &etype) == 0) {
477             /* Set a specific enctype. */
478             mod_list(etype, sel, weak, &list);
479         } else {
480             TRACE_ENCTYPE_LIST_UNKNOWN(context, profkey, token);
481         }
482     }
483
484     if (list == NULL)
485         return ENOMEM;
486     *result = list;
487     return 0;
488 }
489
490 /*
491  * Set *etypes_ptr to a zero-terminated list of enctypes.  ctx_list
492  * (containing application-specified enctypes) is used if non-NULL;
493  * otherwise the libdefaults profile string specified by profkey is
494  * used.  default_list is the default enctype list to be used while
495  * parsing profile strings, and is also used if the profile string is
496  * not set.
497  */
498 static krb5_error_code
499 get_profile_etype_list(krb5_context context, krb5_enctype **etypes_ptr,
500                        char *profkey, krb5_enctype *ctx_list,
501                        krb5_enctype *default_list)
502 {
503     krb5_enctype *etypes;
504     krb5_error_code code;
505     char *profstr;
506
507     *etypes_ptr = NULL;
508
509     if (ctx_list) {
510         /* Use application defaults. */
511         code = krb5int_copy_etypes(ctx_list, &etypes);
512         if (code)
513             return code;
514     } else {
515         /* Parse profile setting, or "DEFAULT" if not specified. */
516         code = profile_get_string(context->profile, KRB5_CONF_LIBDEFAULTS,
517                                   profkey, NULL, "DEFAULT", &profstr);
518         if (code)
519             return code;
520         code = krb5int_parse_enctype_list(context, profkey, profstr,
521                                           default_list, &etypes);
522         profile_release_string(profstr);
523         if (code)
524             return code;
525     }
526
527     if (etypes[0] == 0) {
528         free(etypes);
529         return KRB5_CONFIG_ETYPE_NOSUPP;
530     }
531
532     *etypes_ptr = etypes;
533     return 0;
534 }
535
536 krb5_error_code
537 krb5_get_default_in_tkt_ktypes(krb5_context context, krb5_enctype **ktypes)
538 {
539     return get_profile_etype_list(context, ktypes,
540                                   KRB5_CONF_DEFAULT_TKT_ENCTYPES,
541                                   context->in_tkt_etypes,
542                                   default_enctype_list);
543 }
544
545 void
546 KRB5_CALLCONV
547 krb5_free_ktypes (krb5_context context, krb5_enctype *val)
548 {
549     free (val);
550 }
551
552 krb5_error_code
553 KRB5_CALLCONV
554 krb5_get_tgs_ktypes(krb5_context context, krb5_const_principal princ, krb5_enctype **ktypes)
555 {
556     if (context->use_conf_ktypes)
557         /* This one is set *only* by reading the config file; it's not
558            set by the application.  */
559         return get_profile_etype_list(context, ktypes,
560                                       KRB5_CONF_DEFAULT_TKT_ENCTYPES, NULL,
561                                       default_enctype_list);
562     else
563         return get_profile_etype_list(context, ktypes,
564                                       KRB5_CONF_DEFAULT_TGS_ENCTYPES,
565                                       context->tgs_etypes,
566                                       default_enctype_list);
567 }
568
569 krb5_error_code KRB5_CALLCONV
570 krb5_get_permitted_enctypes(krb5_context context, krb5_enctype **ktypes)
571 {
572     return get_profile_etype_list(context, ktypes,
573                                   KRB5_CONF_PERMITTED_ENCTYPES,
574                                   context->tgs_etypes, default_enctype_list);
575 }
576
577 krb5_boolean
578 krb5_is_permitted_enctype(krb5_context context, krb5_enctype etype)
579 {
580     krb5_enctype *list, *ptr;
581     krb5_boolean ret;
582
583     if (krb5_get_permitted_enctypes(context, &list))
584         return(0);
585
586
587     ret = 0;
588
589     for (ptr = list; *ptr; ptr++)
590         if (*ptr == etype)
591             ret = 1;
592
593     krb5_free_ktypes (context, list);
594
595     return(ret);
596 }
597
598 /* The same as krb5_is_permitted_enctype, but verifies multiple etype's
599  * Returns 0 is either the list of the permitted enc types is not available
600  * or all requested etypes are not permitted. Otherwise returns 1.
601  */
602
603 krb5_boolean
604 krb5_is_permitted_enctype_ext ( krb5_context context,
605                                 krb5_etypes_permitted *etypes)
606 {
607     krb5_enctype *list, *ptr;
608     krb5_boolean ret = 0;
609     int i = 0;
610
611     if (krb5_get_permitted_enctypes(context, &list))
612         return(0);
613
614     for ( i=0; i< etypes->etype_count; i++ )
615     {
616         for (ptr = list; *ptr; ptr++)
617         {
618             if (*ptr == etypes->etype[i])
619             {
620                 etypes->etype_ok[i] =  TRUE;
621                 ret = 1;
622             }
623         }
624     }
625     krb5_free_ktypes (context, list);
626
627     return(ret);
628 }