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