xref: /illumos-gate/usr/src/uts/common/gssapi/mechs/krb5/krb5/krb/init_ctx.c (revision d9976468b7ae1e0b4133ee59b2fa5678de9e9cf2)
1 /*
2  * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
3  * Use is subject to license terms.
4  */
5 
6 #pragma ident	"%Z%%M%	%I%	%E% SMI"
7 
8 /*
9  * lib/krb5/krb/init_ctx.c
10  *
11  * Copyright 1994,1999,2000, 2002, 2003  by the Massachusetts Institute of Technology.
12  * All Rights Reserved.
13  *
14  * Export of this software from the United States of America may
15  *   require a specific license from the United States Government.
16  *   It is the responsibility of any person or organization contemplating
17  *   export to obtain such a license before exporting.
18  *
19  * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
20  * distribute this software and its documentation for any purpose and
21  * without fee is hereby granted, provided that the above copyright
22  * notice appear in all copies and that both that copyright notice and
23  * this permission notice appear in supporting documentation, and that
24  * the name of M.I.T. not be used in advertising or publicity pertaining
25  * to distribution of the software without specific, written prior
26  * permission.  Furthermore if you modify this software you must label
27  * your software as modified software and not distribute it in such a
28  * fashion that it might be confused with the original M.I.T. software.
29  * M.I.T. makes no representations about the suitability of
30  * this software for any purpose.  It is provided "as is" without express
31  * or implied warranty.
32  *
33  * krb5_init_contex()
34  */
35 
36 /*
37  * Copyright (C) 1998 by the FundsXpress, INC.
38  *
39  * All rights reserved.
40  *
41  * Export of this software from the United States of America may require
42  * a specific license from the United States Government.  It is the
43  * responsibility of any person or organization contemplating export to
44  * obtain such a license before exporting.
45  *
46  * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
47  * distribute this software and its documentation for any purpose and
48  * without fee is hereby granted, provided that the above copyright
49  * notice appear in all copies and that both that copyright notice and
50  * this permission notice appear in supporting documentation, and that
51  * the name of FundsXpress. not be used in advertising or publicity pertaining
52  * to distribution of the software without specific, written prior
53  * permission.  FundsXpress makes no representations about the suitability of
54  * this software for any purpose.  It is provided "as is" without express
55  * or implied warranty.
56  *
57  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
58  * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
59  * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
60  */
61 
62 #include <k5-int.h>
63 
64 /*
65  * Solaris Kerberos: the code related to EF/pkcs11 and fork safety are mods Sun
66  * has made to the MIT code.
67  */
68 
69 #ifndef _KERNEL
70 #include <ctype.h>
71 
72 pid_t __krb5_current_pid; /* fork safety: contains the current process ID */
73 #endif
74 
75 #ifndef _KERNEL
76 #include <krb5_libinit.h>
77 #endif
78 
79 /* The des-mdX entries are last for now, because it's easy to
80    configure KDCs to issue TGTs with des-mdX keys and then not accept
81    them.  This'll be fixed, but for better compatibility, let's prefer
82    des-crc for now.  */
83 #define DEFAULT_ETYPE_LIST	\
84 	"aes256-cts-hmac-sha1-96 " \
85 	"aes128-cts-hmac-sha1-96 " \
86 	"des3-hmac-sha1 " \
87 	"arcfour-hmac-md5 " \
88 	"des-cbc-md5 " \
89 	"des-cbc-crc"
90 
91 
92 /* The only functions that are needed from this file when in kernel are
93  * krb5_init_context and krb5_free_context.
94  * In krb5_init_context we need only os_init_context since we don'it need the
95  * profile info unless we do init/accept in kernel. Currently only mport,
96  * delete , sign/verify, wrap/unwrap routines are ported to the kernel.
97  */
98 
99 #if (defined(_MSDOS) || defined(_WIN32))
100 extern krb5_error_code krb5_vercheck();
101 extern void krb5_win_ccdll_load(krb5_context context);
102 #endif
103 
104 static krb5_error_code init_common (krb5_context *, krb5_boolean);
105 
106 krb5_error_code KRB5_CALLCONV
107 krb5_init_context(context)
108 	krb5_context *context;
109 {
110 	return init_common (context, FALSE);
111 }
112 
113 krb5_error_code KRB5_CALLCONV
114 krb5_init_secure_context(context)
115 	krb5_context *context;
116 {
117 	return init_common (context, TRUE);
118 }
119 
120 #ifndef _KERNEL
121 krb5_error_code
122 krb5_open_pkcs11_session(CK_SESSION_HANDLE *hSession)
123 {
124 	krb5_error_code retval = 0;
125 	CK_RV rv;
126 	CK_SLOT_ID_PTR slotlist = NULL_PTR;
127 	CK_ULONG slotcount;
128 	CK_ULONG i;
129 
130 	/* List of all Slots */
131 	rv = C_GetSlotList(FALSE, NULL_PTR, &slotcount);
132 	if (rv != CKR_OK) {
133 		KRB5_LOG(KRB5_ERR, "C_GetSlotList failed with 0x%x.", rv);
134 		retval = PKCS_ERR;
135 		goto cleanup;
136 	}
137 
138 	if (slotcount == 0) {
139 		KRB5_LOG0(KRB5_ERR, "No slot is found in PKCS11.");
140 		retval = PKCS_ERR;
141 		goto cleanup;
142 	}
143 
144 	slotlist = (CK_SLOT_ID_PTR)malloc(slotcount * sizeof(CK_SLOT_ID));
145 	if (slotlist == NULL) {
146 		KRB5_LOG0(KRB5_ERR, "malloc failed for slotcount.");
147 		retval = PKCS_ERR;
148 		goto cleanup;
149 	}
150 
151 	rv = C_GetSlotList(FALSE, slotlist, &slotcount);
152 	if (rv != CKR_OK) {
153 		KRB5_LOG(KRB5_ERR, "C_GetSlotList failed with 0x%x", rv);
154 		retval = PKCS_ERR;
155 		goto cleanup;
156 	}
157 	for (i = 0; i < slotcount; i++) {
158 		if (slot_supports_krb5(slotlist + i))
159 			break;
160 	}
161 	if (i == slotcount){
162 		KRB5_LOG0(KRB5_ERR, "Could not find slot which supports "
163 		   "Kerberos");
164 		retval = PKCS_ERR;
165 		goto cleanup;
166 	}
167 	rv = C_OpenSession(slotlist[i], CKF_SERIAL_SESSION, NULL_PTR, NULL_PTR,
168 	    hSession);
169 	if (rv != CKR_OK) {
170 		retval = PKCS_ERR;
171 	}
172 cleanup:
173 	if (slotlist != NULL)
174 		free(slotlist);
175 	return(retval);
176 }
177 
178 /*
179  * krb5_reinit_ef_handle()
180  *
181  * deal with fork safety issue regarding the krb ctx and the pkcs11 hSession
182  * field.  This function is called if it is determined that the krb ctx hSession
183  * is being accessed in a child process after a fork().  This function
184  * re-initilizes the pkcs11 session and returns the session handle.
185  */
186 CK_SESSION_HANDLE
187 krb5_reinit_ef_handle(krb5_context ctx)
188 {
189     ctx->cryptoki_initialized = FALSE;
190 
191     if (krb5_init_ef_handle(ctx) != 0) {
192 	/*
193 	 * krb5_free_ef_handle() not needed here -- we assume that an equivalent
194 	 * of C_Finalize() was done in the child-side of the fork(), so all EF
195 	 * resources in this context will be invalid.
196 	 */
197 	return(CK_INVALID_HANDLE);
198     }
199 
200     /* reset the ctx pid since we're in a new process (child) */
201     ctx->pid = __krb5_current_pid;
202 
203     /* If the RC4 handles were initialized, reset them here */
204     if (ctx->arcfour_ctx.initialized) {
205 	krb5_error_code ret;
206 	ret = krb5_open_pkcs11_session(&ctx->arcfour_ctx.eSession);
207         if (ret) {
208 		ctx->arcfour_ctx.initialized = 0;
209 		ctx->arcfour_ctx.eSession = CK_INVALID_HANDLE;
210 		C_CloseSession(ctx->hSession);
211 		ctx->hSession = CK_INVALID_HANDLE;
212 	}
213         ret = krb5_open_pkcs11_session(&ctx->arcfour_ctx.dSession);
214         if (ret) {
215 		ctx->arcfour_ctx.initialized = 0;
216 		ctx->arcfour_ctx.eSession = CK_INVALID_HANDLE;
217 		ctx->arcfour_ctx.dSession = CK_INVALID_HANDLE;
218 		C_CloseSession(ctx->hSession);
219 		ctx->hSession = CK_INVALID_HANDLE;
220 	}
221     }
222 
223     /*
224      * It is safe for this function to access ctx->hSession directly.  Do
225      * NOT use the krb_ctx_hSession() here.
226      */
227     return(ctx->hSession);
228 }
229 
230 /*
231  * krb5_pthread_atfork_child_handler() sets a global that indicates the current
232  * PID.  This is an optimization to keep getpid() from being called a zillion
233  * times.
234  */
235 void
236 krb5_pthread_atfork_child_handler()
237 {
238     /*
239      * __krb5_current_pid should always be set to current process ID, see the
240      * definition of krb_ctx_hSession() for more info
241      */
242     __krb5_current_pid = getpid();
243 }
244 
245 /*
246  * krb5_ld_init() contains code that will be executed at load time (via the
247  * ld -zinitarray directive).
248  */
249 void
250 krb5_ld_init()
251 {
252     /*
253      * fork safety: __krb5_current_pid should always be set to current process
254      * ID, see the definition of krb_ctx_hSession() for more info
255      */
256     __krb5_current_pid = getpid();
257     /*
258      * The child handler below will help reduce the number of times getpid() is
259      * called by updating a global PID var. with the current PID whenever a fork
260      * occurrs.
261      */
262     (void) pthread_atfork(NULL, NULL, krb5_pthread_atfork_child_handler);
263 }
264 #endif /* !_KERNEL */
265 
266 krb5_error_code
267 krb5_init_ef_handle(krb5_context ctx)
268 {
269 	krb5_error_code retval = 0;
270 #ifndef _KERNEL
271 	CK_RV rv = C_Initialize(NULL_PTR);
272 	if ((rv != CKR_OK) && (rv != CKR_CRYPTOKI_ALREADY_INITIALIZED)) {
273 		KRB5_LOG(KRB5_ERR, "C_Initialize failed with 0x%x.", rv);
274 		return (PKCS_ERR);
275 
276 	}
277 	/*
278 	 * It is safe for this function to access ctx->hSession directly.  Do
279 	 * NOT use the krb_ctx_hSession() here.
280 	 */
281 	retval = krb5_open_pkcs11_session(&ctx->hSession);
282 	if (retval != 0)
283 		return (retval);
284 
285 	ctx->cryptoki_initialized = TRUE;
286 #else /* ! _KERNEL */
287 	ctx->kef_cipher_mt = CRYPTO_MECH_INVALID;
288 	ctx->kef_hash_mt = CRYPTO_MECH_INVALID;
289 	ctx->kef_cksum_mt = CRYPTO_MECH_INVALID;
290 
291 	setup_kef_keytypes();
292 	setup_kef_cksumtypes();
293 
294 #endif /* ! _KERNEL */
295 	return(retval);
296 }
297 
298 #ifndef _KERNEL
299 krb5_error_code
300 krb5_free_ef_handle(krb5_context ctx)
301 {
302 	/*
303 	 * fork safety: Don't free any PKCS state if we've forked since
304 	 * allocating the pkcs handles.
305 	 */
306 	if (ctx->cryptoki_initialized == TRUE &&
307 	    ctx->pid == __krb5_current_pid) {
308 		/*
309 		 * It is safe for this function to access ctx->hSession
310 		 * directly.  Do NOT use the krb_ctx_hSession() here.
311 		 */
312 		if (ctx->hSession) {
313 			C_CloseSession(ctx->hSession);
314 			ctx->hSession = 0;
315 		}
316 		if (ctx->arcfour_ctx.dKey) {
317 			C_DestroyObject(ctx->arcfour_ctx.dSession,
318 				ctx->arcfour_ctx.dKey);
319 			ctx->arcfour_ctx.dKey = 0;
320 		}
321 		if (ctx->arcfour_ctx.eKey) {
322 			C_DestroyObject(ctx->arcfour_ctx.eSession,
323 				ctx->arcfour_ctx.eKey);
324 			ctx->arcfour_ctx.eKey = 0;
325 		}
326 		if (ctx->arcfour_ctx.eSession) {
327 			C_CloseSession(ctx->arcfour_ctx.eSession);
328 			ctx->arcfour_ctx.eSession = 0;
329 		}
330 		if (ctx->arcfour_ctx.dSession) {
331 			C_CloseSession(ctx->arcfour_ctx.dSession);
332 			ctx->arcfour_ctx.eSession = 0;
333 		}
334 		ctx->arcfour_ctx.initialized = 0;
335 
336 		ctx->cryptoki_initialized = FALSE;
337 	}
338 	return(0);
339 }
340 #endif /* !_KERNEL */
341 
342 static krb5_error_code
343 init_common (krb5_context *context, krb5_boolean secure)
344 {
345 	krb5_context ctx = 0;
346 	krb5_error_code retval;
347 #ifndef _KERNEL
348 	struct {
349 	    krb5_int32 now, now_usec;
350 	    long pid;
351 	} seed_data;
352 	krb5_data seed;
353 	int tmp;
354 #endif
355 
356 #if (defined(_WIN32))
357 	/*
358 	 * Load the krbcc32.dll if necessary.  We do this here so that
359 	 * we know to use API: later on during initialization.
360 	 * The context being NULL is ok.
361 	 */
362 	krb5_win_ccdll_load(ctx);
363 
364 	/*
365 	 * krb5_vercheck() is defined in win_glue.c, and this is
366 	 * where we handle the timebomb and version server checks.
367 	 */
368 	retval = krb5_vercheck();
369 	if (retval)
370 		return retval;
371 #else /* assume UNIX for now */
372 #ifndef _KERNEL
373 	retval = krb5int_initialize_library ();
374 	if (retval)
375 	    return retval;
376 #endif /* !_KERNEL */
377 #endif
378 
379 	*context = 0;
380 
381 	ctx = MALLOC(sizeof(struct _krb5_context));
382 	if (!ctx)
383 		return ENOMEM;
384 	(void) memset(ctx, 0, sizeof(struct _krb5_context));
385 	ctx->magic = KV5M_CONTEXT;
386 
387 	ctx->profile_secure = secure;
388 
389 	if ((retval = krb5_os_init_context(ctx)))
390 		goto cleanup;
391 
392 	/*
393 	 * Initialize the EF handle, its needed before doing
394 	 * the random seed.
395 	 */
396 	if ((retval = krb5_init_ef_handle(ctx)))
397 		goto cleanup;
398 
399 #ifndef _KERNEL
400 
401 	/* fork safety: set pid to current process ID for later checking */
402 	ctx->pid = __krb5_current_pid;
403 
404 	/* Set the default encryption types, possible defined in krb5/conf */
405 	if ((retval = krb5_set_default_in_tkt_ktypes(ctx, NULL)))
406 		goto cleanup;
407 
408 	if ((retval = krb5_set_default_tgs_ktypes(ctx, NULL)))
409 		goto cleanup;
410 
411 	if (ctx->tgs_ktype_count != 0) {
412 		ctx->conf_tgs_ktypes = MALLOC(ctx->tgs_ktype_count *
413 					sizeof(krb5_enctype));
414 		if (ctx->conf_tgs_ktypes == NULL)
415 			goto cleanup;
416 
417 		(void) memcpy(ctx->conf_tgs_ktypes, ctx->tgs_ktypes,
418 				sizeof(krb5_enctype) * ctx->tgs_ktype_count);
419 	}
420 
421 	ctx->conf_tgs_ktypes_count = ctx->tgs_ktype_count;
422 
423 
424 	/* initialize the prng (not well, but passable) */
425 	if ((retval = krb5_crypto_us_timeofday(&seed_data.now, &seed_data.now_usec)))
426 		goto cleanup;
427 	seed_data.pid = getpid ();
428 	seed.length = sizeof(seed_data);
429 	seed.data = (char *) &seed_data;
430 	if ((retval = krb5_c_random_seed(ctx, &seed)))
431 		/*
432 		 * Solaris Kerberos: we use /dev/urandom, which is
433 		 * automatically seeded, so its OK if this fails.
434 		 */
435 		retval = 0;
436 
437 	ctx->default_realm = 0;
438 	profile_get_integer(ctx->profile, "libdefaults", "clockskew",
439 			    0, 5 * 60, &tmp);
440 	ctx->clockskew = tmp;
441 
442 #if 0
443 	/* Default ticket lifetime is currently not supported */
444 	profile_get_integer(ctx->profile, "libdefaults", "tkt_lifetime",
445 			    0, 10 * 60 * 60, &tmp);
446 	ctx->tkt_lifetime = tmp;
447 #endif
448 
449 	/* DCE 1.1 and below only support CKSUMTYPE_RSA_MD4 (2)  */
450 	/* DCE add kdc_req_checksum_type = 2 to krb5.conf */
451 	profile_get_integer(ctx->profile, "libdefaults",
452 			    "kdc_req_checksum_type", 0, CKSUMTYPE_RSA_MD5,
453 			    &tmp);
454 	ctx->kdc_req_sumtype = tmp;
455 
456 	profile_get_integer(ctx->profile, "libdefaults",
457 			    "ap_req_checksum_type", 0, CKSUMTYPE_RSA_MD5,
458 			    &tmp);
459 	ctx->default_ap_req_sumtype = tmp;
460 
461 	profile_get_integer(ctx->profile, "libdefaults",
462 			    "safe_checksum_type", 0,
463 			    CKSUMTYPE_RSA_MD5_DES, &tmp);
464 	ctx->default_safe_sumtype = tmp;
465 
466 	profile_get_integer(ctx->profile, "libdefaults",
467 			    "kdc_default_options", 0,
468 			    KDC_OPT_RENEWABLE_OK, &tmp);
469 	ctx->kdc_default_options = tmp;
470 #define DEFAULT_KDC_TIMESYNC 1
471 	profile_get_integer(ctx->profile, "libdefaults",
472 			    "kdc_timesync", 0, DEFAULT_KDC_TIMESYNC,
473 			    &tmp);
474 	ctx->library_options = tmp ? KRB5_LIBOPT_SYNC_KDCTIME : 0;
475 
476 	/*
477 	 * We use a default file credentials cache of 3.  See
478 	 * lib/krb5/krb/ccache/file/fcc.h for a description of the
479 	 * credentials cache types.
480 	 *
481 	 * Note: DCE 1.0.3a only supports a cache type of 1
482 	 * 	DCE 1.1 supports a cache type of 2.
483 	 */
484 #ifdef macintosh
485 #define DEFAULT_CCACHE_TYPE 4
486 #else
487 #define DEFAULT_CCACHE_TYPE 3
488 #endif
489 	profile_get_integer(ctx->profile, "libdefaults", "ccache_type",
490 			    0, DEFAULT_CCACHE_TYPE, &tmp);
491 	ctx->fcc_default_format = tmp + 0x0500;
492 	ctx->scc_default_format = tmp + 0x0500;
493 	ctx->prompt_types = 0;
494 	ctx->use_conf_ktypes = 0;
495 
496 	ctx->udp_pref_limit = -1;
497 
498 #endif  /* !_KERNEL */
499 
500 	*context = ctx;
501 	return 0;
502 
503 cleanup:
504 	krb5_free_context(ctx);
505 	return retval;
506 }
507 
508 void KRB5_CALLCONV
509 krb5_free_context(krb5_context ctx)
510 {
511 	KRB5_LOG0(KRB5_INFO,"krb5_free_context() start");
512 
513 #ifndef _KERNEL
514 	krb5_free_ef_handle(ctx);
515 
516      if (ctx->conf_tgs_ktypes) {
517 	 FREE(ctx->conf_tgs_ktypes, sizeof(krb5_enctype) *(ctx->conf_tgs_ktypes_count));
518 	 ctx->conf_tgs_ktypes = 0;
519 	 ctx->conf_tgs_ktypes_count = 0;
520      }
521 
522 #endif
523      krb5_os_free_context(ctx);
524 
525      if (ctx->in_tkt_ktypes) {
526           FREE(ctx->in_tkt_ktypes, sizeof(krb5_enctype) *(ctx->in_tkt_ktype_count+1) );
527 	  ctx->in_tkt_ktypes = 0;
528      }
529 
530      if (ctx->tgs_ktypes) {
531           FREE(ctx->tgs_ktypes, sizeof(krb5_enctype) *(ctx->tgs_ktype_count+1));
532 	  ctx->tgs_ktypes = 0;
533      }
534 
535      if (ctx->default_realm) {
536 	  FREE(ctx->default_realm, strlen(ctx->default_realm) + 1);
537 	  ctx->default_realm = 0;
538      }
539 
540      if (ctx->ser_ctx_count && ctx->ser_ctx) {
541 	  FREE(ctx->ser_ctx,sizeof(krb5_ser_entry) * (ctx->ser_ctx_count) );
542 	  ctx->ser_ctx = 0;
543 	  ctx->ser_ctx_count = 0;
544      }
545 
546      ctx->magic = 0;
547      FREE(ctx, sizeof(struct _krb5_context));
548 
549 }
550 
551 #ifndef _KERNEL
552 /*
553  * Set the desired default ktypes, making sure they are valid.
554  */
555 krb5_error_code
556 krb5_set_default_in_tkt_ktypes(krb5_context context, const krb5_enctype *ktypes)
557 {
558     krb5_enctype * new_ktypes;
559     int i;
560 
561     if (ktypes) {
562 	for (i = 0; ktypes[i]; i++) {
563 	    if (!krb5_c_valid_enctype(ktypes[i]))
564 		return KRB5_PROG_ETYPE_NOSUPP;
565 	}
566 
567 	/* Now copy the default ktypes into the context pointer */
568 	if ((new_ktypes = (krb5_enctype *)malloc(sizeof(krb5_enctype) * i)))
569 	    (void) memcpy(new_ktypes, ktypes, sizeof(krb5_enctype) * i);
570 	else
571 	    return ENOMEM;
572 
573     } else {
574 	i = 0;
575 	new_ktypes = 0;
576     }
577 
578     if (context->in_tkt_ktypes)
579         free(context->in_tkt_ktypes);
580     context->in_tkt_ktypes = new_ktypes;
581     context->in_tkt_ktype_count = i;
582     return 0;
583 }
584 
585 static krb5_error_code
586 get_profile_etype_list(krb5_context context, krb5_enctype **ktypes, char *profstr,
587 		       int ctx_count, krb5_enctype *ctx_list)
588 {
589     krb5_enctype *old_ktypes = NULL;
590 
591     if (ctx_count) {
592 	/* application-set defaults */
593 	if ((old_ktypes =
594 	     (krb5_enctype *)malloc(sizeof(krb5_enctype) *
595 				    (ctx_count + 1)))) {
596 	    (void) memcpy(old_ktypes, ctx_list,
597 		sizeof(krb5_enctype) * ctx_count);
598 	    old_ktypes[ctx_count] = 0;
599 	} else {
600 	    return ENOMEM;
601 	}
602     } else {
603         /*
604 	   XXX - For now, we only support libdefaults
605 	   Perhaps this should be extended to allow for per-host / per-realm
606 	   session key types.
607 	 */
608 
609 	char *retval = NULL;
610 	char *sp, *ep;
611 	int j, checked_enctypes, count;
612 	krb5_error_code code;
613 
614 	code = profile_get_string(context->profile, "libdefaults", profstr,
615 				  NULL, DEFAULT_ETYPE_LIST, &retval);
616 	if (code)
617 	    return code;
618 
619 	if (!retval)  /* SUNW14resync - just in case */
620             return PROF_EINVAL;  /* XXX */
621 
622 	count = 0;
623 	sp = retval;
624 	while (*sp) {
625 	    for (ep = sp; *ep && (*ep != ',') && !isspace((int) (*ep)); ep++)
626 		;
627 	    if (*ep) {
628 		*ep++ = '\0';
629 		while (isspace((int) (*ep)) || *ep == ',')
630 		    *ep++ = '\0';
631 	    }
632 	    count++;
633 	    sp = ep;
634 	}
635 
636 	if ((old_ktypes =
637 	     (krb5_enctype *)malloc(sizeof(krb5_enctype) * (count + 1))) ==
638 	    (krb5_enctype *) NULL)
639 	    return ENOMEM;
640 
641 	sp = retval;
642 	j = checked_enctypes = 0;
643 	/*CONSTCOND*/
644 	while (TRUE) {
645 	    checked_enctypes++;
646 	    if (krb5_string_to_enctype(sp, &old_ktypes[j]))
647 		old_ktypes[j] = (unsigned int)ENCTYPE_UNKNOWN;
648 
649 	    /*
650 	     * If 'null' has been specified as a tkt_enctype in
651 	     * krb5.conf, we need to assign an ENCTYPE_UNKNOWN
652 	     * value to the corresponding old_ktypes[j] entry.
653 	     */
654 	    if (old_ktypes[j] == (unsigned int)ENCTYPE_NULL)
655 		old_ktypes[j] = (unsigned int)ENCTYPE_UNKNOWN;
656 
657 	    /* Only include known/valid enctypes in the final list */
658 	    if (old_ktypes[j] != ENCTYPE_UNKNOWN) {
659 		j++;
660 	    }
661 	    /* If we checked all the enctypes, we are done */
662 	    if (checked_enctypes == count) {
663 		break;
664 	    }
665 
666 	    /* skip to next token */
667 	    while (*sp) sp++;
668 	    while (!*sp) sp++;
669 	}
670 
671 	old_ktypes[j] = (krb5_enctype) 0;
672 	profile_release_string(retval);
673     }
674 
675     if (old_ktypes[0] == 0) {
676 	free (old_ktypes);
677 	*ktypes = 0;
678 	return KRB5_CONFIG_ETYPE_NOSUPP;
679     }
680 
681 
682 
683     *ktypes = old_ktypes;
684     return 0;
685 }
686 
687 krb5_error_code
688 krb5_get_default_in_tkt_ktypes(krb5_context context, krb5_enctype **ktypes)
689 {
690     return(get_profile_etype_list(context, ktypes, "default_tkt_enctypes",
691 				  context->in_tkt_ktype_count,
692 				  context->in_tkt_ktypes));
693 }
694 
695 krb5_error_code
696 krb5_set_default_tgs_enctypes (krb5_context context, const krb5_enctype *ktypes)
697 {
698     krb5_enctype * new_ktypes;
699     int i;
700 
701     if (ktypes) {
702 	for (i = 0; ktypes[i]; i++) {
703 	    if (!valid_enctype(ktypes[i]))
704 		return KRB5_PROG_ETYPE_NOSUPP;
705 	}
706 
707 	/* Now copy the default ktypes into the context pointer */
708 	if ((new_ktypes = (krb5_enctype *)malloc(sizeof(krb5_enctype) * i)))
709 	    (void) memcpy(new_ktypes, ktypes, sizeof(krb5_enctype) * i);
710 	else
711 	    return ENOMEM;
712 
713     } else {
714 	i = 0;
715 	new_ktypes = (krb5_enctype *)NULL;
716     }
717 
718     if (context->tgs_ktypes)
719         krb5_free_ktypes(context, context->tgs_ktypes);
720     context->tgs_ktypes = new_ktypes;
721     context->tgs_ktype_count = i;
722     return 0;
723 }
724 
725 krb5_error_code krb5_set_default_tgs_ktypes
726 (krb5_context context, const krb5_enctype *etypes)
727 {
728   return (krb5_set_default_tgs_enctypes (context, etypes));
729 }
730 
731 
732 
733 
734 /*ARGSUSED*/
735 void
736 KRB5_CALLCONV
737 krb5_free_ktypes (krb5_context context, krb5_enctype *val)
738 {
739     free (val);
740 }
741 
742 /*ARGSUSED*/
743 krb5_error_code
744 KRB5_CALLCONV
745 krb5_get_tgs_ktypes(krb5_context context, krb5_const_principal princ, krb5_enctype **ktypes)
746 {
747     if (context->use_conf_ktypes)
748 	/* This one is set *only* by reading the config file; it's not
749 	   set by the application.  */
750 	return(get_profile_etype_list(context, ktypes, "default_tgs_enctypes",
751                                       context->conf_tgs_ktypes_count,
752                                       context->conf_tgs_ktypes));
753     else
754 	return(get_profile_etype_list(context, ktypes, "default_tgs_enctypes",
755 				  context->tgs_ktype_count,
756 				  context->tgs_ktypes));
757 }
758 
759 krb5_error_code
760 krb5_get_permitted_enctypes(krb5_context context, krb5_enctype **ktypes)
761 {
762     return(get_profile_etype_list(context, ktypes, "permitted_enctypes",
763 				  context->tgs_ktype_count,
764 				  context->tgs_ktypes));
765 }
766 
767 krb5_boolean
768 krb5_is_permitted_enctype(krb5_context context, krb5_enctype etype)
769 {
770     krb5_enctype *list, *ptr;
771     krb5_boolean ret;
772 
773     if (krb5_get_permitted_enctypes(context, &list))
774 	return(0);
775 
776 
777     ret = 0;
778 
779     for (ptr = list; *ptr; ptr++)
780 	if (*ptr == etype)
781 	    ret = 1;
782 
783     krb5_free_ktypes (context, list);
784 
785     return(ret);
786 }
787 #endif /* !KERNEL */
788