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
krb5_init_context(krb5_context * context)111 krb5_init_context(krb5_context *context)
112 {
113
114 return init_common (context, FALSE, FALSE);
115 }
116
117 krb5_error_code KRB5_CALLCONV
krb5_init_secure_context(krb5_context * context)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
krb5int_init_context_kdc(krb5_context * context)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
krb5_open_pkcs11_session(CK_SESSION_HANDLE * hSession)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
krb5_reinit_ef_handle(krb5_context ctx)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
krb5_pthread_atfork_child_handler()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
krb5_ld_init()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
krb5_init_ef_handle(krb5_context ctx)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
krb5_free_ef_handle(krb5_context ctx)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
init_common(krb5_context * context,krb5_boolean secure,krb5_boolean kdc)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
krb5_free_context(krb5_context ctx)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
krb5_set_default_in_tkt_ktypes(krb5_context context,const krb5_enctype * ktypes)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
get_profile_etype_list(krb5_context context,krb5_enctype ** ktypes,char * profstr,unsigned int ctx_count,krb5_enctype * ctx_list)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
krb5_get_default_in_tkt_ktypes(krb5_context context,krb5_enctype ** ktypes)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
krb5_set_default_tgs_enctypes(krb5_context context,const krb5_enctype * ktypes)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
krb5_set_default_tgs_ktypes(krb5_context context,const krb5_enctype * etypes)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
krb5_free_ktypes(krb5_context context,krb5_enctype * val)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
krb5_get_tgs_ktypes(krb5_context context,krb5_const_principal princ,krb5_enctype ** ktypes)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
krb5_get_permitted_enctypes(krb5_context context,krb5_enctype ** ktypes)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
krb5_is_permitted_enctype(krb5_context context,krb5_enctype etype)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
copy_ktypes(krb5_context ctx,unsigned int nktypes,krb5_enctype * oldktypes,krb5_enctype ** newktypes)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
krb5_copy_context(krb5_context ctx,krb5_context * nctx_out)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