#include "k5-int.h"
#include <ctype.h>
#include "brand.c"
#if defined(unix) || TARGET_OS_MAC
#include "../krb5_libinit.h"
#endif
#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 "
#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 KRB5_CALLCONV
krb5_init_context(krb5_context *context)
{
return init_common (context, FALSE, FALSE);
}
krb5_error_code KRB5_CALLCONV
krb5_init_secure_context(krb5_context *context)
{
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;
{
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))
krb5_win_ccdll_load(ctx);
retval = krb5_vercheck();
if (retval)
return retval;
#endif
*context = 0;
ctx = calloc(1, sizeof(struct _krb5_context));
if (!ctx)
return ENOMEM;
ctx->magic = KV5M_CONTEXT;
ctx->profile_secure = secure;
if ((retval = krb5_set_default_in_tkt_ktypes(ctx, NULL)))
goto cleanup;
if ((retval = krb5_set_default_tgs_ktypes(ctx, NULL)))
goto cleanup;
if ((retval = krb5_os_init_context(ctx, kdc)))
goto cleanup;
{
static pid_t done_seeding = 0;
static pthread_mutex_t m = PTHREAD_MUTEX_INITIALIZER;
int success = 0;
pthread_mutex_lock(&m);
if (done_seeding != getpid()) {
retval = krb5_c_random_os_entropy( ctx, 0, &success);
if (retval == 0 && success)
done_seeding = getpid();
}
pthread_mutex_unlock(&m);
if (retval)
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
profile_get_integer(ctx->profile, "libdefaults", "tkt_lifetime",
0, 10 * 60 * 60, &tmp);
ctx->tkt_lifetime = tmp;
#endif
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;
#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->prompt_types = 0;
ctx->use_conf_ktypes = 0;
ctx->udp_pref_limit = -1;
*context = ctx;
return 0;
cleanup:
krb5_free_context(ctx);
return retval;
}
void KRB5_CALLCONV
krb5_free_context(krb5_context ctx)
{
krb5_os_free_context(ctx);
if (ctx->in_tkt_ktypes) {
free(ctx->in_tkt_ktypes);
ctx->in_tkt_ktypes = 0;
}
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;
}
krb5_clear_error_message(ctx);
ctx->magic = 0;
free(ctx);
}
krb5_error_code
krb5_set_default_in_tkt_ktypes(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;
}
if ((new_ktypes = (krb5_enctype *)malloc(sizeof(krb5_enctype) * i)))
memcpy(new_ktypes, ktypes, sizeof(krb5_enctype) * i);
else
return ENOMEM;
} else {
i = 0;
new_ktypes = 0;
}
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) {
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 {
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) {
profile_release_string(retval);
return ENOMEM;
}
sp = retval;
j = 0;
i = 1;
while (1) {
if (! krb5_string_to_enctype(sp, &old_ktypes[j]))
j++;
if (i++ >= count)
break;
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;
}
*ktypes = old_ktypes;
return 0;
}
krb5_error_code
krb5_get_default_in_tkt_ktypes(krb5_context context, krb5_enctype **ktypes)
{
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;
}
if ((new_ktypes = (krb5_enctype *)malloc(sizeof(krb5_enctype) * i)))
memcpy(new_ktypes, ktypes, sizeof(krb5_enctype) * i);
else
return ENOMEM;
} else {
i = 0;
new_ktypes = (krb5_enctype *)NULL;
}
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)
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);
}
krb5_boolean
krb5_is_permitted_enctype_ext ( krb5_context context,
krb5_etypes_permitted *etypes)
{
krb5_enctype *list, *ptr;
krb5_boolean ret = 0;
int i = 0;
if (krb5_get_permitted_enctypes(context, &list))
return(0);
for ( i=0; i< etypes->etype_count; i++ )
{
for (ptr = list; *ptr; ptr++)
{
if (*ptr == etypes->etype[i])
{
etypes->etype_ok[i] = TRUE;
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;
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->dal_handle = 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;
}