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