/*
* lib/krb5/krb/init_ctx.c
*
- * Copyright 1994 by the Massachusetts Institute of Technology.
+ * Copyright 1994,1999,2000, 2002, 2003 by the Massachusetts Institute of Technology.
* All Rights Reserved.
*
* Export of this software from the United States of America may
* this permission notice appear in supporting documentation, and that
* the name of M.I.T. not be used in advertising or publicity pertaining
* to distribution of the software without specific, written prior
- * permission. M.I.T. makes no representations about the suitability of
+ * permission. Furthermore if you modify this software you must label
+ * your software as modified software and not distribute it in such a
+ * fashion that it might be confused with the original M.I.T. software.
+ * M.I.T. makes no representations about the suitability of
* this software for any purpose. It is provided "as is" without express
* or implied warranty.
*
* krb5_init_contex()
*/
+/*
+ * Copyright (C) 1998 by the FundsXpress, INC.
+ *
+ * All rights reserved.
+ *
+ * Export of this software from the United States of America may require
+ * a specific license from the United States Government. It is the
+ * responsibility of any person or organization contemplating export to
+ * obtain such a license before exporting.
+ *
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of FundsXpress. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission. FundsXpress makes no representations about the suitability of
+ * this software for any purpose. It is provided "as is" without express
+ * or implied warranty.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
#include "k5-int.h"
+#include <ctype.h>
+#include "brand.c"
+/* There has to be a better way for windows... */
+#if defined(unix) || TARGET_OS_MAC
+#include "../krb5_libinit.h"
+#endif
+
+/* The des-mdX entries are last for now, because it's easy to
+ configure KDCs to issue TGTs with des-mdX keys and then not accept
+ them. This'll be fixed, but for better compatibility, let's prefer
+ des-crc for now. */
+#define DEFAULT_ETYPE_LIST \
+ "aes256-cts-hmac-sha1-96 " \
+ "aes128-cts-hmac-sha1-96 " \
+ "des3-cbc-sha1 arcfour-hmac-md5 " \
+ "des-cbc-crc des-cbc-md5 des-cbc-md4 "
+
+/* Not included:
+ "aes128-cts-hmac-sha1-96 " \
+ */
+
+#if (defined(_WIN32))
+extern krb5_error_code krb5_vercheck();
+extern void krb5_win_ccdll_load(krb5_context context);
+#endif
+
+static krb5_error_code init_common (krb5_context *, krb5_boolean, krb5_boolean);
-krb5_error_code INTERFACE
-krb5_init_context(context)
- krb5_context *context;
+krb5_error_code KRB5_CALLCONV
+krb5_init_context(krb5_context *context)
{
- krb5_context ctx;
+
+ return init_common (context, FALSE, FALSE);
+}
+
+krb5_error_code KRB5_CALLCONV
+krb5_init_secure_context(krb5_context *context)
+{
+
+ /* This is to make gcc -Wall happy */
+ if(0) krb5_brand[0] = krb5_brand[0];
+ return init_common (context, TRUE, FALSE);
+}
+
+krb5_error_code
+krb5int_init_context_kdc(krb5_context *context)
+{
+ return init_common (context, FALSE, TRUE);
+}
+
+static krb5_error_code
+init_common (krb5_context *context, krb5_boolean secure, krb5_boolean kdc)
+{
+ krb5_context ctx = 0;
krb5_error_code retval;
+ struct {
+ krb5_int32 now, now_usec;
+ long pid;
+ } seed_data;
+ krb5_data seed;
+ int tmp;
+
+ /* Verify some assumptions. If the assumptions hold and the
+ compiler is optimizing, this should result in no code being
+ executed. If we're guessing "unsigned long long" instead
+ of using uint64_t, the possibility does exist that we're
+ wrong. */
+ {
+ krb5_ui_8 i64;
+ assert(sizeof(i64) == 8);
+ i64 = 0, i64--, i64 >>= 62;
+ assert(i64 == 3);
+ i64 = 1, i64 <<= 31, i64 <<= 31, i64 <<= 1;
+ assert(i64 != 0);
+ i64 <<= 1;
+ assert(i64 == 0);
+ }
+
+ retval = krb5int_initialize_library();
+ if (retval)
+ return retval;
+
+#if (defined(_WIN32))
+ /*
+ * Load the krbcc32.dll if necessary. We do this here so that
+ * we know to use API: later on during initialization.
+ * The context being NULL is ok.
+ */
+ krb5_win_ccdll_load(ctx);
+
+ /*
+ * krb5_vercheck() is defined in win_glue.c, and this is
+ * where we handle the timebomb and version server checks.
+ */
+ retval = krb5_vercheck();
+ if (retval)
+ return retval;
+#endif
*context = 0;
memset(ctx, 0, sizeof(struct _krb5_context));
ctx->magic = KV5M_CONTEXT;
+ ctx->profile_secure = secure;
+
/* Set the default encryption types, possible defined in krb5/conf */
- if ((retval = krb5_set_default_in_tkt_etypes(ctx, NULL)))
+ if ((retval = krb5_set_default_in_tkt_ktypes(ctx, NULL)))
goto cleanup;
- if ((retval = krb5_os_init_context(ctx)))
+ if ((retval = krb5_set_default_tgs_ktypes(ctx, NULL)))
+ goto cleanup;
+
+ if ((retval = krb5_os_init_context(ctx, kdc)))
+ goto cleanup;
+
+ /* initialize the prng (not well, but passable) */
+ if ((retval = krb5_c_random_os_entropy( ctx, 0, NULL)) !=0)
+ goto cleanup;
+ if ((retval = krb5_crypto_us_timeofday(&seed_data.now, &seed_data.now_usec)))
+ goto cleanup;
+ seed_data.pid = getpid ();
+ seed.length = sizeof(seed_data);
+ seed.data = (char *) &seed_data;
+ if ((retval = krb5_c_random_add_entropy(ctx, KRB5_C_RANDSOURCE_TIMING, &seed)))
goto cleanup;
-
ctx->default_realm = 0;
+ profile_get_integer(ctx->profile, "libdefaults", "clockskew",
+ 0, 5 * 60, &tmp);
+ ctx->clockskew = tmp;
+
+#if 0
+ /* Default ticket lifetime is currently not supported */
+ profile_get_integer(ctx->profile, "libdefaults", "tkt_lifetime",
+ 0, 10 * 60 * 60, &tmp);
+ ctx->tkt_lifetime = tmp;
+#endif
+
+ /* DCE 1.1 and below only support CKSUMTYPE_RSA_MD4 (2) */
+ /* DCE add kdc_req_checksum_type = 2 to krb5.conf */
+ profile_get_integer(ctx->profile, "libdefaults",
+ "kdc_req_checksum_type", 0, CKSUMTYPE_RSA_MD5,
+ &tmp);
+ ctx->kdc_req_sumtype = tmp;
+
+ profile_get_integer(ctx->profile, "libdefaults",
+ "ap_req_checksum_type", 0, CKSUMTYPE_RSA_MD5,
+ &tmp);
+ ctx->default_ap_req_sumtype = tmp;
+ profile_get_integer(ctx->profile, "libdefaults",
+ "safe_checksum_type", 0,
+ CKSUMTYPE_RSA_MD5_DES, &tmp);
+ ctx->default_safe_sumtype = tmp;
+
+ profile_get_integer(ctx->profile, "libdefaults",
+ "kdc_default_options", 0,
+ KDC_OPT_RENEWABLE_OK, &tmp);
+ ctx->kdc_default_options = tmp;
+#define DEFAULT_KDC_TIMESYNC 1
+ profile_get_integer(ctx->profile, "libdefaults",
+ "kdc_timesync", 0, DEFAULT_KDC_TIMESYNC,
+ &tmp);
+ ctx->library_options = tmp ? KRB5_LIBOPT_SYNC_KDCTIME : 0;
+
+ /*
+ * We use a default file credentials cache of 3. See
+ * lib/krb5/krb/ccache/file/fcc.h for a description of the
+ * credentials cache types.
+ *
+ * Note: DCE 1.0.3a only supports a cache type of 1
+ * DCE 1.1 supports a cache type of 2.
+ */
+#define DEFAULT_CCACHE_TYPE 4
+ profile_get_integer(ctx->profile, "libdefaults", "ccache_type",
+ 0, DEFAULT_CCACHE_TYPE, &tmp);
+ ctx->fcc_default_format = tmp + 0x0500;
+ ctx->scc_default_format = tmp + 0x0500;
+ ctx->prompt_types = 0;
+ ctx->use_conf_ktypes = 0;
+
+ ctx->udp_pref_limit = -1;
*context = ctx;
return 0;
return retval;
}
-void
-krb5_free_context(ctx)
- krb5_context ctx;
+void KRB5_CALLCONV
+krb5_free_context(krb5_context ctx)
{
krb5_os_free_context(ctx);
- if (ctx->etypes)
- free(ctx->etypes);
+ if (ctx->in_tkt_ktypes) {
+ free(ctx->in_tkt_ktypes);
+ ctx->in_tkt_ktypes = 0;
+ }
- if (ctx->default_realm)
+ if (ctx->tgs_ktypes) {
+ free(ctx->tgs_ktypes);
+ ctx->tgs_ktypes = 0;
+ }
+
+ if (ctx->default_realm) {
free(ctx->default_realm);
+ ctx->default_realm = 0;
+ }
+
+ if (ctx->ser_ctx_count && ctx->ser_ctx) {
+ free(ctx->ser_ctx);
+ ctx->ser_ctx = 0;
+ }
- if (ctx->ser_ctx_count && ctx->ser_ctx)
- free(ctx->ser_ctx);
+ krb5_clear_error_message(ctx);
ctx->magic = 0;
free(ctx);
}
/*
- * Set the desired default etypes, making sure they are valid.
+ * Set the desired default ktypes, making sure they are valid.
*/
krb5_error_code
-krb5_set_default_in_tkt_etypes(context, etypes)
- krb5_context context;
- const krb5_enctype *etypes;
+krb5_set_default_in_tkt_ktypes(krb5_context context, const krb5_enctype *ktypes)
{
- krb5_enctype * new_etypes;
+ krb5_enctype * new_ktypes;
int i;
- if (etypes) {
- for (i = 0; etypes[i]; i++) {
- if (!valid_etype(etypes[i]))
+ if (ktypes) {
+ for (i = 0; ktypes[i]; i++) {
+ if (!krb5_c_valid_enctype(ktypes[i]))
return KRB5_PROG_ETYPE_NOSUPP;
}
- /* Now copy the default etypes into the context pointer */
- if ((new_etypes = (krb5_enctype *)malloc(sizeof(krb5_enctype) * i)))
- memcpy(new_etypes, etypes, sizeof(krb5_enctype) * i);
+ /* Now copy the default ktypes into the context pointer */
+ if ((new_ktypes = (krb5_enctype *)malloc(sizeof(krb5_enctype) * i)))
+ memcpy(new_ktypes, ktypes, sizeof(krb5_enctype) * i);
else
return ENOMEM;
} else {
- i = 2;
+ i = 0;
+ new_ktypes = 0;
+ }
- /* Should reset the list to the runtime defaults */
- if ((new_etypes = (krb5_enctype *)malloc(sizeof(krb5_enctype) * i))) {
- new_etypes[0] = ETYPE_DES_CBC_MD5;
- new_etypes[1] = ETYPE_DES_CBC_CRC;
+ if (context->in_tkt_ktypes)
+ free(context->in_tkt_ktypes);
+ context->in_tkt_ktypes = new_ktypes;
+ context->in_tkt_ktype_count = i;
+ return 0;
+}
+
+static krb5_error_code
+get_profile_etype_list(krb5_context context, krb5_enctype **ktypes, char *profstr,
+ unsigned int ctx_count, krb5_enctype *ctx_list)
+{
+ krb5_enctype *old_ktypes;
+
+ if (ctx_count) {
+ /* application-set defaults */
+ if ((old_ktypes =
+ (krb5_enctype *)malloc(sizeof(krb5_enctype) *
+ (ctx_count + 1)))) {
+ memcpy(old_ktypes, ctx_list, sizeof(krb5_enctype) * ctx_count);
+ old_ktypes[ctx_count] = 0;
} else {
return ENOMEM;
}
+ } else {
+ /*
+ XXX - For now, we only support libdefaults
+ Perhaps this should be extended to allow for per-host / per-realm
+ session key types.
+ */
+
+ char *retval;
+ char *sp, *ep;
+ int i, j, count;
+ krb5_error_code code;
+
+ code = profile_get_string(context->profile, "libdefaults", profstr,
+ NULL, DEFAULT_ETYPE_LIST, &retval);
+ if (code)
+ return code;
+
+ count = 0;
+ sp = retval;
+ while (*sp) {
+ for (ep = sp; *ep && (*ep != ',') && !isspace((int) (*ep)); ep++)
+ ;
+ if (*ep) {
+ *ep++ = '\0';
+ while (isspace((int) (*ep)) || *ep == ',')
+ *ep++ = '\0';
+ }
+ count++;
+ sp = ep;
+ }
+
+ if ((old_ktypes =
+ (krb5_enctype *)malloc(sizeof(krb5_enctype) * (count + 1))) ==
+ (krb5_enctype *) NULL)
+ return ENOMEM;
+
+ sp = retval;
+ j = 0;
+ i = 1;
+ while (1) {
+ if (! krb5_string_to_enctype(sp, &old_ktypes[j]))
+ j++;
+
+ if (i++ >= count)
+ break;
+
+ /* skip to next token */
+ while (*sp) sp++;
+ while (! *sp) sp++;
+ }
+
+ old_ktypes[j] = (krb5_enctype) 0;
+ profile_release_string(retval);
+ }
+
+ if (old_ktypes[0] == 0) {
+ free (old_ktypes);
+ *ktypes = 0;
+ return KRB5_CONFIG_ETYPE_NOSUPP;
}
- if (context->etypes)
- free(context->etypes);
- context->etypes = new_etypes;
- context->etype_count = i;
+ *ktypes = old_ktypes;
return 0;
}
krb5_error_code
-krb5_get_default_in_tkt_etypes(context, etypes)
- krb5_context context;
- krb5_enctype **etypes;
+krb5_get_default_in_tkt_ktypes(krb5_context context, krb5_enctype **ktypes)
{
- krb5_enctype * old_etypes;
+ return(get_profile_etype_list(context, ktypes, "default_tkt_enctypes",
+ context->in_tkt_ktype_count,
+ context->in_tkt_ktypes));
+}
+
+krb5_error_code KRB5_CALLCONV
+krb5_set_default_tgs_enctypes (krb5_context context, const krb5_enctype *ktypes)
+{
+ krb5_enctype * new_ktypes;
+ int i;
+
+ if (ktypes) {
+ for (i = 0; ktypes[i]; i++) {
+ if (!krb5_c_valid_enctype(ktypes[i]))
+ return KRB5_PROG_ETYPE_NOSUPP;
+ }
+
+ /* Now copy the default ktypes into the context pointer */
+ if ((new_ktypes = (krb5_enctype *)malloc(sizeof(krb5_enctype) * i)))
+ memcpy(new_ktypes, ktypes, sizeof(krb5_enctype) * i);
+ else
+ return ENOMEM;
- if ((old_etypes = (krb5_enctype *)malloc(sizeof(krb5_enctype) *
- (context->etype_count + 1)))) {
- memcpy(old_etypes, context->etypes, sizeof(krb5_enctype) *
- context->etype_count);
- old_etypes[context->etype_count] = 0;
} else {
- return ENOMEM;
+ i = 0;
+ new_ktypes = (krb5_enctype *)NULL;
}
- *etypes = old_etypes;
+ if (context->tgs_ktypes)
+ krb5_free_ktypes(context, context->tgs_ktypes);
+ context->tgs_ktypes = new_ktypes;
+ context->tgs_ktype_count = i;
return 0;
-
+}
+
+krb5_error_code krb5_set_default_tgs_ktypes
+(krb5_context context, const krb5_enctype *etypes)
+{
+ return (krb5_set_default_tgs_enctypes (context, etypes));
+}
+
+
+void
+KRB5_CALLCONV
+krb5_free_ktypes (krb5_context context, krb5_enctype *val)
+{
+ free (val);
+}
+
+krb5_error_code
+KRB5_CALLCONV
+krb5_get_tgs_ktypes(krb5_context context, krb5_const_principal princ, krb5_enctype **ktypes)
+{
+ if (context->use_conf_ktypes)
+ /* This one is set *only* by reading the config file; it's not
+ set by the application. */
+ return(get_profile_etype_list(context, ktypes, "default_tgs_enctypes",
+ 0, NULL));
+ else
+ return(get_profile_etype_list(context, ktypes, "default_tgs_enctypes",
+ context->tgs_ktype_count,
+ context->tgs_ktypes));
+}
+
+krb5_error_code KRB5_CALLCONV
+krb5_get_permitted_enctypes(krb5_context context, krb5_enctype **ktypes)
+{
+ return(get_profile_etype_list(context, ktypes, "permitted_enctypes",
+ context->tgs_ktype_count,
+ context->tgs_ktypes));
+}
+
+krb5_boolean
+krb5_is_permitted_enctype(krb5_context context, krb5_enctype etype)
+{
+ krb5_enctype *list, *ptr;
+ krb5_boolean ret;
+
+ if (krb5_get_permitted_enctypes(context, &list))
+ return(0);
+
+
+ ret = 0;
+
+ for (ptr = list; *ptr; ptr++)
+ if (*ptr == etype)
+ ret = 1;
+
+ krb5_free_ktypes (context, list);
+
+ return(ret);
+}
+
+static krb5_error_code
+copy_ktypes(krb5_context ctx,
+ unsigned int nktypes,
+ krb5_enctype *oldktypes,
+ krb5_enctype **newktypes)
+{
+ unsigned int i;
+
+ *newktypes = NULL;
+ if (!nktypes)
+ return 0;
+
+ *newktypes = malloc(nktypes * sizeof(krb5_enctype));
+ if (*newktypes == NULL)
+ return ENOMEM;
+ for (i = 0; i < nktypes; i++)
+ (*newktypes)[i] = oldktypes[i];
+ return 0;
+}
+
+krb5_error_code KRB5_CALLCONV
+krb5_copy_context(krb5_context ctx, krb5_context *nctx_out)
+{
+ krb5_error_code ret;
+ krb5_context nctx;
+
+ *nctx_out = NULL;
+ if (ctx == NULL)
+ return EINVAL; /* XXX */
+
+ nctx = malloc(sizeof(*nctx));
+ if (nctx == NULL)
+ return ENOMEM;
+
+ *nctx = *ctx;
+
+ nctx->in_tkt_ktypes = NULL;
+ nctx->in_tkt_ktype_count = 0;
+ nctx->tgs_ktypes = NULL;
+ nctx->tgs_ktype_count = 0;
+ nctx->default_realm = NULL;
+ nctx->profile = NULL;
+ nctx->db_context = NULL;
+ nctx->ser_ctx_count = 0;
+ nctx->ser_ctx = NULL;
+ nctx->prompt_types = NULL;
+ nctx->os_context->default_ccname = NULL;
+
+ memset(&nctx->preauth_plugins, 0, sizeof(nctx->preauth_plugins));
+ nctx->preauth_context = NULL;
+
+ memset(&nctx->libkrb5_plugins, 0, sizeof(nctx->libkrb5_plugins));
+ nctx->vtbl = NULL;
+ nctx->locate_fptrs = NULL;
+
+ memset(&nctx->err, 0, sizeof(nctx->err));
+
+ ret = copy_ktypes(nctx, ctx->in_tkt_ktype_count,
+ ctx->in_tkt_ktypes, &nctx->in_tkt_ktypes);
+ if (ret)
+ goto errout;
+ nctx->in_tkt_ktype_count = ctx->in_tkt_ktype_count;
+
+ ret = copy_ktypes(nctx, ctx->tgs_ktype_count,
+ ctx->tgs_ktypes, &nctx->in_tkt_ktypes);
+ if (ret)
+ goto errout;
+ nctx->tgs_ktype_count = ctx->tgs_ktype_count;
+
+ if (ctx->os_context->default_ccname != NULL) {
+ nctx->os_context->default_ccname =
+ strdup(ctx->os_context->default_ccname);
+ if (nctx->os_context->default_ccname == NULL) {
+ ret = ENOMEM;
+ goto errout;
+ }
+ }
+ ret = krb5_get_profile(ctx, &nctx->profile);
+ if (ret)
+ goto errout;
+
+errout:
+ if (ret) {
+ krb5_free_context(nctx);
+ } else {
+ *nctx_out = nctx;
+ }
+ return ret;
}