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