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(void);
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, *timeout_str = 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 retval = profile_get_string(ctx->profile, KRB5_CONF_LIBDEFAULTS,
255 KRB5_CONF_REQUEST_TIMEOUT, NULL, NULL,
256 &timeout_str);
257 if (retval)
258 goto cleanup;
259 if (timeout_str != NULL) {
260 retval = krb5_string_to_deltat(timeout_str, &ctx->req_timeout);
261 if (retval)
262 goto cleanup;
263 }
264
265 get_integer(ctx, KRB5_CONF_KDC_DEFAULT_OPTIONS, KDC_OPT_RENEWABLE_OK,
266 &tmp);
267 ctx->kdc_default_options = tmp;
268 #define DEFAULT_KDC_TIMESYNC 1
269 get_integer(ctx, KRB5_CONF_KDC_TIMESYNC, DEFAULT_KDC_TIMESYNC, &tmp);
270 ctx->library_options = tmp ? KRB5_LIBOPT_SYNC_KDCTIME : 0;
271
272 retval = profile_get_string(ctx->profile, KRB5_CONF_LIBDEFAULTS,
273 KRB5_CONF_PLUGIN_BASE_DIR, 0,
274 DEFAULT_PLUGIN_BASE_DIR, &plugin_dir);
275 if (!retval)
276 retval = k5_expand_path_tokens(ctx, plugin_dir, &ctx->plugin_base_dir);
277 if (retval) {
278 TRACE_PROFILE_ERR(ctx, KRB5_CONF_PLUGIN_BASE_DIR,
279 KRB5_CONF_LIBDEFAULTS, retval);
280 goto cleanup;
281 }
282
283 /*
284 * We use a default file credentials cache of 3. See
285 * lib/krb5/krb/ccache/file/fcc.h for a description of the
286 * credentials cache types.
287 *
288 * Note: DCE 1.0.3a only supports a cache type of 1
289 * DCE 1.1 supports a cache type of 2.
290 */
291 #define DEFAULT_CCACHE_TYPE 4
292 get_integer(ctx, KRB5_CONF_CCACHE_TYPE, DEFAULT_CCACHE_TYPE, &tmp);
293 ctx->fcc_default_format = tmp + 0x0500;
294 ctx->prompt_types = 0;
295 ctx->use_conf_ktypes = 0;
296 ctx->udp_pref_limit = -1;
297
298 /* It's OK if this fails */
299 (void)profile_get_string(ctx->profile, KRB5_CONF_LIBDEFAULTS,
300 KRB5_CONF_ERR_FMT, NULL, NULL, &ctx->err_fmt);
301 *context_out = ctx;
302 ctx = NULL;
303
304 cleanup:
305 profile_release_string(plugin_dir);
306 profile_release_string(timeout_str);
307 krb5_free_context(ctx);
308 return retval;
309 }
310
311 void KRB5_CALLCONV
krb5_free_context(krb5_context ctx)312 krb5_free_context(krb5_context ctx)
313 {
314 if (ctx == NULL)
315 return;
316 k5_os_free_context(ctx);
317
318 free(ctx->tgs_etypes);
319 ctx->tgs_etypes = NULL;
320 free(ctx->default_realm);
321 ctx->default_realm = 0;
322
323 krb5_clear_error_message(ctx);
324 free(ctx->err_fmt);
325
326 #ifndef DISABLE_TRACING
327 if (ctx->trace_callback)
328 ctx->trace_callback(ctx, NULL, ctx->trace_callback_data);
329 #endif
330
331 k5_ccselect_free_context(ctx);
332 k5_hostrealm_free_context(ctx);
333 k5_localauth_free_context(ctx);
334 k5_plugin_free_context(ctx);
335 free(ctx->plugin_base_dir);
336 free(ctx->tls);
337
338 ctx->magic = 0;
339 free(ctx);
340 }
341
342 /*
343 * Set the desired default ktypes, making sure they are valid.
344 */
345 krb5_error_code KRB5_CALLCONV
krb5_set_default_tgs_enctypes(krb5_context context,const krb5_enctype * etypes)346 krb5_set_default_tgs_enctypes(krb5_context context, const krb5_enctype *etypes)
347 {
348 krb5_error_code code;
349 krb5_enctype *list;
350 size_t src, dst;
351
352 if (etypes) {
353 /* Empty list passed in. */
354 if (etypes[0] == 0)
355 return EINVAL;
356 code = k5_copy_etypes(etypes, &list);
357 if (code)
358 return code;
359
360 /* Filter list in place to exclude invalid and (optionally) weak
361 * enctypes. */
362 for (src = dst = 0; list[src]; src++) {
363 if (!krb5_c_valid_enctype(list[src]))
364 continue;
365 if (!context->allow_weak_crypto
366 && krb5int_c_weak_enctype(list[src]))
367 continue;
368 list[dst++] = list[src];
369 }
370 list[dst] = 0; /* Zero-terminate. */
371 if (dst == 0) {
372 free(list);
373 return KRB5_CONFIG_ETYPE_NOSUPP;
374 }
375 } else {
376 list = NULL;
377 }
378
379 free(context->tgs_etypes);
380 context->tgs_etypes = list;
381 return 0;
382 }
383
384 /* Old name for above function. This is not a public API, but Samba (as of
385 * 2021-02-12) uses this name if it finds it in the library. */
386 krb5_error_code
387 krb5_set_default_tgs_ktypes(krb5_context context, const krb5_enctype *etypes);
388
389 krb5_error_code
krb5_set_default_tgs_ktypes(krb5_context context,const krb5_enctype * etypes)390 krb5_set_default_tgs_ktypes(krb5_context context, const krb5_enctype *etypes)
391 {
392 return krb5_set_default_tgs_enctypes(context, etypes);
393 }
394
395 /*
396 * Add etype to, or remove etype from, the zero-terminated list *list_ptr,
397 * reallocating if the list size changes. Filter out weak enctypes if
398 * allow_weak is false. If memory allocation fails, set *list_ptr to NULL and
399 * do nothing for subsequent operations.
400 */
401 static void
mod_list(krb5_enctype etype,krb5_boolean add,krb5_boolean allow_weak,krb5_enctype ** list_ptr)402 mod_list(krb5_enctype etype, krb5_boolean add, krb5_boolean allow_weak,
403 krb5_enctype **list_ptr)
404 {
405 size_t i;
406 krb5_enctype *list = *list_ptr;
407
408 /* Stop now if a previous allocation failed or the enctype is filtered. */
409 if (list == NULL || (!allow_weak && krb5int_c_weak_enctype(etype)))
410 return;
411 if (add) {
412 /* Count entries; do nothing if etype is a duplicate. */
413 for (i = 0; list[i] != 0; i++) {
414 if (list[i] == etype)
415 return;
416 }
417 /* Make room for the new entry and add it. */
418 list = realloc(list, (i + 2) * sizeof(krb5_enctype));
419 if (list != NULL) {
420 list[i] = etype;
421 list[i + 1] = 0;
422 }
423 } else {
424 /* Look for etype in the list. */
425 for (i = 0; list[i] != 0; i++) {
426 if (list[i] != etype)
427 continue;
428 /* Perform removal. */
429 for (; list[i + 1] != 0; i++)
430 list[i] = list[i + 1];
431 list[i] = 0;
432 list = realloc(list, (i + 1) * sizeof(krb5_enctype));
433 break;
434 }
435 }
436 /* Update *list_ptr, freeing the old value if realloc failed. */
437 if (list == NULL)
438 free(*list_ptr);
439 *list_ptr = list;
440 }
441
442 /*
443 * Set *result to a zero-terminated list of enctypes resulting from
444 * parsing profstr. profstr may be modified during parsing.
445 */
446 krb5_error_code
krb5int_parse_enctype_list(krb5_context context,const char * profkey,char * profstr,krb5_enctype * default_list,krb5_enctype ** result)447 krb5int_parse_enctype_list(krb5_context context, const char *profkey,
448 char *profstr, krb5_enctype *default_list,
449 krb5_enctype **result)
450 {
451 char *token, *delim = " \t\r\n,", *save = NULL;
452 krb5_boolean sel, weak = context->allow_weak_crypto;
453 krb5_enctype etype, *list;
454 unsigned int i;
455
456 *result = NULL;
457
458 /* Set up an empty list. Allocation failure is detected at the end. */
459 list = malloc(sizeof(krb5_enctype));
460 if (list != NULL)
461 list[0] = 0;
462
463 /* Walk through the words in profstr. */
464 for (token = strtok_r(profstr, delim, &save); token;
465 token = strtok_r(NULL, delim, &save)) {
466 /* Determine if we are adding or removing enctypes. */
467 sel = TRUE;
468 if (*token == '+' || *token == '-')
469 sel = (*token++ == '+');
470
471 if (strcasecmp(token, "DEFAULT") == 0) {
472 /* Set all enctypes in the default list. */
473 for (i = 0; default_list[i]; i++)
474 mod_list(default_list[i], sel, weak, &list);
475 } else if (strcasecmp(token, "des3") == 0) {
476 mod_list(ENCTYPE_DES3_CBC_SHA1, sel, weak, &list);
477 } else if (strcasecmp(token, "aes") == 0) {
478 mod_list(ENCTYPE_AES256_CTS_HMAC_SHA1_96, sel, weak, &list);
479 mod_list(ENCTYPE_AES128_CTS_HMAC_SHA1_96, sel, weak, &list);
480 mod_list(ENCTYPE_AES256_CTS_HMAC_SHA384_192, sel, weak, &list);
481 mod_list(ENCTYPE_AES128_CTS_HMAC_SHA256_128, sel, weak, &list);
482 } else if (strcasecmp(token, "rc4") == 0) {
483 mod_list(ENCTYPE_ARCFOUR_HMAC, sel, weak, &list);
484 } else if (strcasecmp(token, "camellia") == 0) {
485 mod_list(ENCTYPE_CAMELLIA256_CTS_CMAC, sel, weak, &list);
486 mod_list(ENCTYPE_CAMELLIA128_CTS_CMAC, sel, weak, &list);
487 } else if (krb5_string_to_enctype(token, &etype) == 0) {
488 /* Set a specific enctype. */
489 mod_list(etype, sel, weak, &list);
490 } else {
491 TRACE_ENCTYPE_LIST_UNKNOWN(context, profkey, token);
492 }
493 }
494
495 if (list == NULL)
496 return ENOMEM;
497 if (list[0] == ENCTYPE_NULL) {
498 free(list);
499 return KRB5_CONFIG_ETYPE_NOSUPP;
500 }
501 *result = list;
502 return 0;
503 }
504
505 krb5_error_code
krb5_get_default_in_tkt_ktypes(krb5_context context,krb5_enctype ** ktypes)506 krb5_get_default_in_tkt_ktypes(krb5_context context, krb5_enctype **ktypes)
507 {
508 krb5_error_code ret;
509 char *profstr = NULL;
510 const char *profkey;
511
512 *ktypes = NULL;
513
514 profkey = KRB5_CONF_DEFAULT_TKT_ENCTYPES;
515 ret = profile_get_string(context->profile, KRB5_CONF_LIBDEFAULTS,
516 profkey, NULL, NULL, &profstr);
517 if (ret)
518 return ret;
519 if (profstr == NULL) {
520 profkey = KRB5_CONF_PERMITTED_ENCTYPES;
521 ret = profile_get_string(context->profile, KRB5_CONF_LIBDEFAULTS,
522 profkey, NULL, "DEFAULT", &profstr);
523 if (ret)
524 return ret;
525 }
526
527 ret = krb5int_parse_enctype_list(context, profkey, profstr,
528 default_enctype_list, ktypes);
529 profile_release_string(profstr);
530 return ret;
531 }
532
533 void
534 KRB5_CALLCONV
krb5_free_enctypes(krb5_context context,krb5_enctype * val)535 krb5_free_enctypes(krb5_context context, krb5_enctype *val)
536 {
537 free (val);
538 }
539
540 krb5_error_code KRB5_CALLCONV
krb5_get_tgs_ktypes(krb5_context context,krb5_const_principal princ,krb5_enctype ** ktypes)541 krb5_get_tgs_ktypes(krb5_context context, krb5_const_principal princ,
542 krb5_enctype **ktypes)
543 {
544 krb5_error_code ret;
545 char *profstr = NULL;
546 const char *profkey;
547
548 *ktypes = NULL;
549
550 /* Use only profile configuration when use_conf_ktypes is set. */
551 if (!context->use_conf_ktypes && context->tgs_etypes != NULL)
552 return k5_copy_etypes(context->tgs_etypes, ktypes);
553
554 profkey = KRB5_CONF_DEFAULT_TGS_ENCTYPES;
555 ret = profile_get_string(context->profile, KRB5_CONF_LIBDEFAULTS,
556 profkey, NULL, NULL, &profstr);
557 if (ret)
558 return ret;
559 if (profstr == NULL) {
560 profkey = KRB5_CONF_PERMITTED_ENCTYPES;
561 ret = profile_get_string(context->profile, KRB5_CONF_LIBDEFAULTS,
562 profkey, NULL, "DEFAULT", &profstr);
563 if (ret)
564 return ret;
565 }
566
567 ret = krb5int_parse_enctype_list(context, profkey, profstr,
568 default_enctype_list, ktypes);
569 profile_release_string(profstr);
570 return ret;
571 }
572
573 krb5_error_code KRB5_CALLCONV
krb5_get_permitted_enctypes(krb5_context context,krb5_enctype ** ktypes)574 krb5_get_permitted_enctypes(krb5_context context, krb5_enctype **ktypes)
575 {
576 krb5_error_code ret;
577 char *profstr = NULL;
578 const char *profkey;
579
580 *ktypes = NULL;
581
582 if (context->tgs_etypes != NULL)
583 return k5_copy_etypes(context->tgs_etypes, ktypes);
584
585 profkey = KRB5_CONF_PERMITTED_ENCTYPES;
586 ret = profile_get_string(context->profile, KRB5_CONF_LIBDEFAULTS,
587 profkey, NULL, "DEFAULT", &profstr);
588 if (ret)
589 return ret;
590
591 ret = krb5int_parse_enctype_list(context, profkey, profstr,
592 default_enctype_list, ktypes);
593 profile_release_string(profstr);
594 return ret;
595 }
596
597 krb5_boolean
krb5_is_permitted_enctype(krb5_context context,krb5_enctype etype)598 krb5_is_permitted_enctype(krb5_context context, krb5_enctype etype)
599 {
600 krb5_enctype *list;
601 krb5_boolean ret;
602
603 if (krb5_get_permitted_enctypes(context, &list))
604 return FALSE;
605 ret = k5_etypes_contains(list, etype);
606 krb5_free_enctypes(context, list);
607 return ret;
608 }
609