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