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