Files
heimdal/lib/krb5/context.c
Asanka Herath a0ae9f5a0e Merge remote branch 'h-github/master' into win32-port2
* h-github/master: (64 commits)
  refix socket wrappers with rk_
  Patch from Secure Endpoints/Asanka Herath for windows support
  unset KRB5CCNAME
  its really just LIBADD more most of them
  correct quoting
  Use -lpthread for modern freebsd instead
  clean KRB5CCNAME and KRB5_CONFIG, require test to reset them
  more up ${env_setup}
  use PTHREADS_LIBADD for freebsd6 and newer
  add PTHREAD_LIBADD
  add PTHREAD_LIBADD
  add PTHREAD_LIBADD
  switch to PTHREADS_LIBADD
  log what the error string say too
  More debug logging
  sprinkle more 'echo "test failed"'
  sprinkle 'echo "test failed"'
  use calloc(), indent more prettier
  in sh, equal compare is really = for strings, not ==
  Check for duplicates, already loaded mechs
  ...

Conflicts (resolved):
	lib/krb5/auth_context.c
	lib/krb5/changepw.c
	lib/krb5/context.c
	lib/krb5/error_string.c
	lib/krb5/kuserok.c
	lib/krb5/libkrb5-exports.def.in
	lib/krb5/net_write.c
	lib/krb5/store_fd.c
	lib/krb5/test_cc.c
	lib/roken/strerror_r.c
2009-12-21 13:44:00 -05:00

1404 lines
35 KiB
C

/*
* Copyright (c) 1997 - 2005 Kungliga Tekniska Högskolan
* (Royal Institute of Technology, Stockholm, Sweden).
* All rights reserved.
*
* Portions Copyright (c) 2009 Apple Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* 3. Neither the name of the Institute nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#include "krb5_locl.h"
#include <com_err.h>
#define INIT_FIELD(C, T, E, D, F) \
(C)->E = krb5_config_get_ ## T ## _default ((C), NULL, (D), \
"libdefaults", F, NULL)
#define INIT_FLAG(C, O, V, D, F) \
do { \
if (krb5_config_get_bool_default((C), NULL, (D),"libdefaults", F, NULL)) { \
(C)->O |= V; \
} \
} while(0)
/*
* Set the list of etypes `ret_etypes' from the configuration variable
* `name'
*/
static krb5_error_code
set_etypes (krb5_context context,
const char *name,
krb5_enctype **ret_enctypes)
{
char **etypes_str;
krb5_enctype *etypes = NULL;
etypes_str = krb5_config_get_strings(context, NULL, "libdefaults",
name, NULL);
if(etypes_str){
int i, j, k;
for(i = 0; etypes_str[i]; i++);
etypes = malloc((i+1) * sizeof(*etypes));
if (etypes == NULL) {
krb5_config_free_strings (etypes_str);
krb5_set_error_message (context, ENOMEM, N_("malloc: out of memory", ""));
return ENOMEM;
}
for(j = 0, k = 0; j < i; j++) {
krb5_enctype e;
if(krb5_string_to_enctype(context, etypes_str[j], &e) != 0)
continue;
if (krb5_enctype_valid(context, e) != 0)
continue;
etypes[k++] = e;
}
etypes[k] = ETYPE_NULL;
krb5_config_free_strings(etypes_str);
}
*ret_enctypes = etypes;
return 0;
}
/*
* read variables from the configuration file and set in `context'
*/
static krb5_error_code
init_context_from_config_file(krb5_context context)
{
krb5_error_code ret;
const char * tmp;
char **s;
krb5_enctype *tmptypes;
INIT_FIELD(context, time, max_skew, 5 * 60, "clockskew");
INIT_FIELD(context, time, kdc_timeout, 3, "kdc_timeout");
INIT_FIELD(context, int, max_retries, 3, "max_retries");
INIT_FIELD(context, string, http_proxy, NULL, "http_proxy");
ret = set_etypes (context, "default_etypes", &tmptypes);
if(ret)
return ret;
free(context->etypes);
context->etypes = tmptypes;
ret = set_etypes (context, "default_etypes_des", &tmptypes);
if(ret)
return ret;
free(context->etypes_des);
context->etypes_des = tmptypes;
/* default keytab name */
tmp = NULL;
if(!issuid())
tmp = getenv("KRB5_KTNAME");
if(tmp != NULL)
context->default_keytab = tmp;
else
INIT_FIELD(context, string, default_keytab,
KEYTAB_DEFAULT, "default_keytab_name");
INIT_FIELD(context, string, default_keytab_modify,
NULL, "default_keytab_modify_name");
INIT_FIELD(context, string, time_fmt,
"%Y-%m-%dT%H:%M:%S", "time_format");
INIT_FIELD(context, string, date_fmt,
"%Y-%m-%d", "date_format");
INIT_FIELD(context, bool, log_utc,
FALSE, "log_utc");
/* init dns-proxy slime */
tmp = krb5_config_get_string(context, NULL, "libdefaults",
"dns_proxy", NULL);
if(tmp)
roken_gethostby_setup(context->http_proxy, tmp);
krb5_free_host_realm (context, context->default_realms);
context->default_realms = NULL;
{
krb5_addresses addresses;
char **adr, **a;
krb5_set_extra_addresses(context, NULL);
adr = krb5_config_get_strings(context, NULL,
"libdefaults",
"extra_addresses",
NULL);
memset(&addresses, 0, sizeof(addresses));
for(a = adr; a && *a; a++) {
ret = krb5_parse_address(context, *a, &addresses);
if (ret == 0) {
krb5_add_extra_addresses(context, &addresses);
krb5_free_addresses(context, &addresses);
}
}
krb5_config_free_strings(adr);
krb5_set_ignore_addresses(context, NULL);
adr = krb5_config_get_strings(context, NULL,
"libdefaults",
"ignore_addresses",
NULL);
memset(&addresses, 0, sizeof(addresses));
for(a = adr; a && *a; a++) {
ret = krb5_parse_address(context, *a, &addresses);
if (ret == 0) {
krb5_add_ignore_addresses(context, &addresses);
krb5_free_addresses(context, &addresses);
}
}
krb5_config_free_strings(adr);
}
INIT_FIELD(context, bool, scan_interfaces, TRUE, "scan_interfaces");
INIT_FIELD(context, int, fcache_vno, 0, "fcache_version");
/* prefer dns_lookup_kdc over srv_lookup. */
INIT_FIELD(context, bool, srv_lookup, TRUE, "srv_lookup");
INIT_FIELD(context, bool, srv_lookup, context->srv_lookup, "dns_lookup_kdc");
INIT_FIELD(context, int, large_msg_size, 1400, "large_message_size");
INIT_FLAG(context, flags, KRB5_CTX_F_DNS_CANONICALIZE_HOSTNAME, TRUE, "dns_canonicalize_hostname");
INIT_FLAG(context, flags, KRB5_CTX_F_CHECK_PAC, TRUE, "check_pac");
context->default_cc_name = NULL;
context->default_cc_name_set = 0;
ret = krb5_config_get_bool_default(context, NULL, FALSE,
"libdefaults",
"allow_weak_crypto", NULL);
if (ret) {
krb5_enctype_enable(context, ETYPE_DES_CBC_CRC);
krb5_enctype_enable(context, ETYPE_DES_CBC_MD4);
krb5_enctype_enable(context, ETYPE_DES_CBC_MD5);
krb5_enctype_enable(context, ETYPE_DES_CBC_NONE);
krb5_enctype_enable(context, ETYPE_DES_CFB64_NONE);
krb5_enctype_enable(context, ETYPE_DES_PCBC_NONE);
}
s = krb5_config_get_strings(context, NULL, "logging", "krb5", NULL);
if(s) {
char **p;
krb5_initlog(context, "libkrb5", &context->debug_dest);
for(p = s; *p; p++)
krb5_addlog_dest(context, context->debug_dest, *p);
krb5_config_free_strings(s);
}
return 0;
}
static krb5_error_code
cc_ops_register(krb5_context context)
{
context->cc_ops = NULL;
context->num_cc_ops = 0;
#ifndef KCM_IS_API_CACHE
krb5_cc_register(context, &krb5_acc_ops, TRUE);
#endif
krb5_cc_register(context, &krb5_fcc_ops, TRUE);
krb5_cc_register(context, &krb5_mcc_ops, TRUE);
#ifdef HAVE_SCC
krb5_cc_register(context, &krb5_scc_ops, TRUE);
#endif
#ifdef HAVE_KCM
#ifdef KCM_IS_API_CACHE
krb5_cc_register(context, &krb5_akcm_ops, TRUE);
#endif
krb5_cc_register(context, &krb5_kcm_ops, TRUE);
#endif
return 0;
}
static krb5_error_code
cc_ops_copy(krb5_context context, const krb5_context src_context)
{
context->cc_ops = NULL;
context->num_cc_ops = 0;
if (src_context->num_cc_ops == 0)
return 0;
context->cc_ops = malloc(sizeof(context->cc_ops[0]) * src_context->num_cc_ops);
if (context->cc_ops == NULL) {
krb5_set_error_message(context, KRB5_CC_NOMEM,
N_("malloc: out of memory", ""));
return KRB5_CC_NOMEM;
}
context->num_cc_ops = src_context->num_cc_ops;
memcpy(context->cc_ops, src_context->cc_ops,
sizeof(context->cc_ops[0]) * src_context->num_cc_ops);
return 0;
}
static krb5_error_code
kt_ops_register(krb5_context context)
{
context->num_kt_types = 0;
context->kt_types = NULL;
krb5_kt_register (context, &krb5_fkt_ops);
krb5_kt_register (context, &krb5_wrfkt_ops);
krb5_kt_register (context, &krb5_javakt_ops);
krb5_kt_register (context, &krb5_mkt_ops);
#ifndef HEIMDAL_SMALLER
krb5_kt_register (context, &krb5_akf_ops);
#endif
krb5_kt_register (context, &krb5_any_ops);
return 0;
}
static krb5_error_code
kt_ops_copy(krb5_context context, const krb5_context src_context)
{
context->num_kt_types = 0;
context->kt_types = NULL;
if (src_context->num_kt_types == 0)
return 0;
context->kt_types = malloc(sizeof(context->kt_types[0]) * src_context->num_kt_types);
if (context->kt_types == NULL) {
krb5_set_error_message(context, ENOMEM,
N_("malloc: out of memory", ""));
return ENOMEM;
}
context->num_kt_types = src_context->num_kt_types;
memcpy(context->kt_types, src_context->kt_types,
sizeof(context->kt_types[0]) * src_context->num_kt_types);
return 0;
}
/**
* Initializes the context structure and reads the configuration file
* /etc/krb5.conf. The structure should be freed by calling
* krb5_free_context() when it is no longer being used.
*
* @param context pointer to returned context
*
* @return Returns 0 to indicate success. Otherwise an errno code is
* returned. Failure means either that something bad happened during
* initialization (typically ENOMEM) or that Kerberos should not be
* used ENXIO.
*
* @ingroup krb5
*/
KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
krb5_init_context(krb5_context *context)
{
krb5_context p;
krb5_error_code ret;
char **files;
*context = NULL;
/* should have a run_once */
bindtextdomain(HEIMDAL_TEXTDOMAIN, HEIMDAL_LOCALEDIR);
p = calloc(1, sizeof(*p));
if(!p)
return ENOMEM;
p->mutex = malloc(sizeof(HEIMDAL_MUTEX));
if (p->mutex == NULL) {
free(p);
return ENOMEM;
}
HEIMDAL_MUTEX_init(p->mutex);
p->flags |= KRB5_CTX_F_HOMEDIR_ACCESS;
ret = krb5_get_default_config_files(&files);
if(ret)
goto out;
ret = krb5_set_config_files(p, files);
krb5_free_config_files(files);
if(ret)
goto out;
/* init error tables */
krb5_init_ets(p);
cc_ops_register(p);
kt_ops_register(p);
#ifdef PKINIT
ret = hx509_context_init(&p->hx509ctx);
if (ret)
goto out;
#endif
if (rk_SOCK_INIT())
p->flags |= KRB5_CTX_F_SOCKETS_INITIALIZED;
out:
if(ret) {
krb5_free_context(p);
p = NULL;
}
*context = p;
return ret;
}
#ifndef HEIMDAL_SMALLER
/*
*
*/
static krb5_error_code
copy_etypes (krb5_context context,
krb5_enctype *enctypes,
krb5_enctype **ret_enctypes)
{
unsigned int i;
for (i = 0; enctypes[i]; i++)
;
i++;
*ret_enctypes = malloc(sizeof(ret_enctypes[0]) * i);
if (*ret_enctypes == NULL) {
krb5_set_error_message(context, ENOMEM,
N_("malloc: out of memory", ""));
return ENOMEM;
}
memcpy(*ret_enctypes, enctypes, sizeof(ret_enctypes[0]) * i);
return 0;
}
/**
* Make a copy for the Kerberos 5 context, the new krb5_context shoud
* be freed with krb5_free_context().
*
* @param context the Kerberos context to copy
* @param out the copy of the Kerberos, set to NULL error.
*
* @return Returns 0 to indicate success. Otherwise an kerberos et
* error code is returned, see krb5_get_error_message().
*
* @ingroup krb5
*/
KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
krb5_copy_context(krb5_context context, krb5_context *out)
{
krb5_error_code ret;
krb5_context p;
*out = NULL;
p = calloc(1, sizeof(*p));
if (p == NULL) {
krb5_set_error_message(context, ENOMEM, N_("malloc: out of memory", ""));
return ENOMEM;
}
p->mutex = malloc(sizeof(HEIMDAL_MUTEX));
if (p->mutex == NULL) {
krb5_set_error_message(context, ENOMEM, N_("malloc: out of memory", ""));
free(p);
return ENOMEM;
}
HEIMDAL_MUTEX_init(p->mutex);
if (context->default_cc_name)
p->default_cc_name = strdup(context->default_cc_name);
if (context->default_cc_name_env)
p->default_cc_name_env = strdup(context->default_cc_name_env);
if (context->etypes) {
ret = copy_etypes(context, context->etypes, &p->etypes);
if (ret)
goto out;
}
if (context->etypes_des) {
ret = copy_etypes(context, context->etypes_des, &p->etypes_des);
if (ret)
goto out;
}
if (context->default_realms) {
ret = krb5_copy_host_realm(context,
context->default_realms, &p->default_realms);
if (ret)
goto out;
}
ret = _krb5_config_copy(context, context->cf, &p->cf);
if (ret)
goto out;
/* XXX should copy */
krb5_init_ets(p);
cc_ops_copy(p, context);
kt_ops_copy(p, context);
#if 0 /* XXX */
if(context->warn_dest != NULL)
;
if(context->debug_dest != NULL)
;
#endif
ret = krb5_set_extra_addresses(p, context->extra_addresses);
if (ret)
goto out;
ret = krb5_set_extra_addresses(p, context->ignore_addresses);
if (ret)
goto out;
ret = _krb5_copy_send_to_kdc_func(p, context);
if (ret)
goto out;
*out = p;
return 0;
out:
krb5_free_context(p);
return ret;
}
#endif
/**
* Frees the krb5_context allocated by krb5_init_context().
*
* @param context context to be freed.
*
* @ingroup krb5
*/
KRB5_LIB_FUNCTION void KRB5_LIB_CALL
krb5_free_context(krb5_context context)
{
if (context->default_cc_name)
free(context->default_cc_name);
if (context->default_cc_name_env)
free(context->default_cc_name_env);
free(context->etypes);
free(context->etypes_des);
krb5_free_host_realm (context, context->default_realms);
krb5_config_file_free (context, context->cf);
free_error_table (context->et_list);
free(context->cc_ops);
free(context->kt_types);
krb5_clear_error_message(context);
if(context->warn_dest != NULL)
krb5_closelog(context, context->warn_dest);
if(context->debug_dest != NULL)
krb5_closelog(context, context->debug_dest);
krb5_set_extra_addresses(context, NULL);
krb5_set_ignore_addresses(context, NULL);
krb5_set_send_to_kdc_func(context, NULL, NULL);
#ifdef PKINIT
hx509_context_free(&context->hx509ctx);
#endif
HEIMDAL_MUTEX_destroy(context->mutex);
free(context->mutex);
<<<<<<< HEAD
if (context->flags & KRB5_CTX_F_SOCKETS_INITIALIZED) {
rk_SOCK_EXIT();
}
=======
#ifdef NEED_SOCK_INIT
if (context->flags & KRB5_CTX_F_SOCKETS_INITIALIZED) {
SOCK_EXIT;
}
#endif
>>>>>>> h-github/master
memset(context, 0, sizeof(*context));
free(context);
}
/**
* Reinit the context from a new set of filenames.
*
* @param context context to add configuration too.
* @param filenames array of filenames, end of list is indicated with a NULL filename.
*
* @return Returns 0 to indicate success. Otherwise an kerberos et
* error code is returned, see krb5_get_error_message().
*
* @ingroup krb5
*/
KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
krb5_set_config_files(krb5_context context, char **filenames)
{
krb5_error_code ret;
krb5_config_binding *tmp = NULL;
while(filenames != NULL && *filenames != NULL && **filenames != '\0') {
ret = krb5_config_parse_file_multi(context, *filenames, &tmp);
if(ret != 0 && ret != ENOENT && ret != EACCES && ret != EPERM) {
krb5_config_file_free(context, tmp);
return ret;
}
filenames++;
}
#if 0
/* with this enabled and if there are no config files, Kerberos is
considererd disabled */
if(tmp == NULL)
return ENXIO;
#endif
krb5_config_file_free(context, context->cf);
context->cf = tmp;
ret = init_context_from_config_file(context);
return ret;
}
static krb5_error_code
add_file(char ***pfilenames, int *len, char *file)
{
char **pp = *pfilenames;
int i;
for(i = 0; i < *len; i++) {
if(strcmp(pp[i], file) == 0) {
free(file);
return 0;
}
}
pp = realloc(*pfilenames, (*len + 2) * sizeof(*pp));
if (pp == NULL) {
free(file);
return ENOMEM;
}
pp[*len] = file;
pp[*len + 1] = NULL;
*pfilenames = pp;
*len += 1;
return 0;
}
/*
* `pq' isn't free, it's up the the caller
*/
KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
krb5_prepend_config_files(const char *filelist, char **pq, char ***ret_pp)
{
krb5_error_code ret;
const char *p, *q;
char **pp;
int len;
char *fn;
pp = NULL;
len = 0;
p = filelist;
while(1) {
ssize_t l;
q = p;
l = strsep_copy(&q, ":", NULL, 0);
if(l == -1)
break;
fn = malloc(l + 1);
if(fn == NULL) {
krb5_free_config_files(pp);
return ENOMEM;
}
(void)strsep_copy(&p, ":", fn, l + 1);
ret = add_file(&pp, &len, fn);
if (ret) {
krb5_free_config_files(pp);
return ret;
}
}
if (pq != NULL) {
int i;
for (i = 0; pq[i] != NULL; i++) {
fn = strdup(pq[i]);
if (fn == NULL) {
krb5_free_config_files(pp);
return ENOMEM;
}
ret = add_file(&pp, &len, fn);
if (ret) {
krb5_free_config_files(pp);
return ret;
}
}
}
*ret_pp = pp;
return 0;
}
/**
* Prepend the filename to the global configuration list.
*
* @param filelist a filename to add to the default list of filename
* @param pfilenames return array of filenames, should be freed with krb5_free_config_files().
*
* @return Returns 0 to indicate success. Otherwise an kerberos et
* error code is returned, see krb5_get_error_message().
*
* @ingroup krb5
*/
KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
krb5_prepend_config_files_default(const char *filelist, char ***pfilenames)
{
krb5_error_code ret;
char **defpp, **pp = NULL;
ret = krb5_get_default_config_files(&defpp);
if (ret)
return ret;
ret = krb5_prepend_config_files(filelist, defpp, &pp);
krb5_free_config_files(defpp);
if (ret) {
return ret;
}
*pfilenames = pp;
return 0;
}
/**
* Get the global configuration list.
*
* @param pfilenames return array of filenames, should be freed with krb5_free_config_files().
*
* @return Returns 0 to indicate success. Otherwise an kerberos et
* error code is returned, see krb5_get_error_message().
*
* @ingroup krb5
*/
KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
krb5_get_default_config_files(char ***pfilenames)
{
const char *files = NULL;
if (pfilenames == NULL)
return EINVAL;
if(!issuid())
files = getenv("KRB5_CONFIG");
if (files == NULL)
files = krb5_config_file;
return krb5_prepend_config_files(files, NULL, pfilenames);
}
/**
* Free a list of configuration files.
*
* @param filenames list, terminated with a NULL pointer, to be
* freed. NULL is an valid argument.
*
* @return Returns 0 to indicate success. Otherwise an kerberos et
* error code is returned, see krb5_get_error_message().
*
* @ingroup krb5
*/
KRB5_LIB_FUNCTION void KRB5_LIB_CALL
krb5_free_config_files(char **filenames)
{
char **p;
for(p = filenames; p && *p != NULL; p++)
free(*p);
free(filenames);
}
/**
* Returns the list of Kerberos encryption types sorted in order of
* most preferred to least preferred encryption type. Note that some
* encryption types might be disabled, so you need to check with
* krb5_enctype_valid() before using the encryption type.
*
* @return list of enctypes, terminated with ETYPE_NULL. Its a static
* array completed into the Kerberos library so the content doesn't
* need to be freed.
*
* @ingroup krb5
*/
KRB5_LIB_FUNCTION const krb5_enctype * KRB5_LIB_CALL
krb5_kerberos_enctypes(krb5_context context)
{
static const krb5_enctype p[] = {
ETYPE_AES256_CTS_HMAC_SHA1_96,
ETYPE_AES128_CTS_HMAC_SHA1_96,
ETYPE_DES3_CBC_SHA1,
ETYPE_DES3_CBC_MD5,
ETYPE_ARCFOUR_HMAC_MD5,
ETYPE_DES_CBC_MD5,
ETYPE_DES_CBC_MD4,
ETYPE_DES_CBC_CRC,
ETYPE_NULL
};
return p;
}
/*
* set `etype' to a malloced list of the default enctypes
*/
static krb5_error_code
default_etypes(krb5_context context, krb5_enctype **etype)
{
const krb5_enctype *p;
krb5_enctype *e = NULL, *ep;
int i, n = 0;
p = krb5_kerberos_enctypes(context);
for (i = 0; p[i] != ETYPE_NULL; i++) {
if (krb5_enctype_valid(context, p[i]) != 0)
continue;
ep = realloc(e, (n + 2) * sizeof(*e));
if (ep == NULL) {
free(e);
krb5_set_error_message (context, ENOMEM, N_("malloc: out of memory", ""));
return ENOMEM;
}
e = ep;
e[n] = p[i];
e[n + 1] = ETYPE_NULL;
n++;
}
*etype = e;
return 0;
}
/**
* Set the default encryption types that will be use in communcation
* with the KDC, clients and servers.
*
* @param context Kerberos 5 context.
* @param etypes Encryption types, array terminated with ETYPE_NULL (0).
*
* @return Returns 0 to indicate success. Otherwise an kerberos et
* error code is returned, see krb5_get_error_message().
*
* @ingroup krb5
*/
KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
krb5_set_default_in_tkt_etypes(krb5_context context,
const krb5_enctype *etypes)
{
krb5_enctype *p = NULL;
int i;
if(etypes) {
for (i = 0; etypes[i]; ++i) {
krb5_error_code ret;
ret = krb5_enctype_valid(context, etypes[i]);
if (ret)
return ret;
}
++i;
ALLOC(p, i);
if(!p) {
krb5_set_error_message (context, ENOMEM, N_("malloc: out of memory", ""));
return ENOMEM;
}
memmove(p, etypes, i * sizeof(krb5_enctype));
}
if(context->etypes)
free(context->etypes);
context->etypes = p;
return 0;
}
/**
* Get the default encryption types that will be use in communcation
* with the KDC, clients and servers.
*
* @param context Kerberos 5 context.
* @param etypes Encryption types, array terminated with
* ETYPE_NULL(0), caller should free array with krb5_xfree():
*
* @return Returns 0 to indicate success. Otherwise an kerberos et
* error code is returned, see krb5_get_error_message().
*
* @ingroup krb5
*/
KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
krb5_get_default_in_tkt_etypes(krb5_context context,
krb5_enctype **etypes)
{
krb5_enctype *p;
int i;
krb5_error_code ret;
if(context->etypes) {
for(i = 0; context->etypes[i]; i++);
++i;
ALLOC(p, i);
if(!p) {
krb5_set_error_message (context, ENOMEM, N_("malloc: out of memory", ""));
return ENOMEM;
}
memmove(p, context->etypes, i * sizeof(krb5_enctype));
} else {
ret = default_etypes(context, &p);
if (ret)
return ret;
}
*etypes = p;
return 0;
}
/**
* Init the built-in ets in the Kerberos library.
*
* @param context kerberos context to add the ets too
*
* @ingroup krb5
*/
KRB5_LIB_FUNCTION void KRB5_LIB_CALL
krb5_init_ets(krb5_context context)
{
if(context->et_list == NULL){
krb5_add_et_list(context, initialize_krb5_error_table_r);
krb5_add_et_list(context, initialize_asn1_error_table_r);
krb5_add_et_list(context, initialize_heim_error_table_r);
krb5_add_et_list(context, initialize_k524_error_table_r);
#ifdef COM_ERR_BINDDOMAIN_krb5
bindtextdomain(COM_ERR_BINDDOMAIN_krb5, HEIMDAL_LOCALEDIR);
bindtextdomain(COM_ERR_BINDDOMAIN_asn1, HEIMDAL_LOCALEDIR);
bindtextdomain(COM_ERR_BINDDOMAIN_heim, HEIMDAL_LOCALEDIR);
bindtextdomain(COM_ERR_BINDDOMAIN_k524, HEIMDAL_LOCALEDIR);
#endif
#ifdef PKINIT
krb5_add_et_list(context, initialize_hx_error_table_r);
#ifdef COM_ERR_BINDDOMAIN_hx
bindtextdomain(COM_ERR_BINDDOMAIN_hx, HEIMDAL_LOCALEDIR);
#endif
#endif
}
}
/**
* Make the kerberos library default to the admin KDC.
*
* @param context Kerberos 5 context.
* @param flag boolean flag to select if the use the admin KDC or not.
*
* @ingroup krb5
*/
KRB5_LIB_FUNCTION void KRB5_LIB_CALL
krb5_set_use_admin_kdc (krb5_context context, krb5_boolean flag)
{
context->use_admin_kdc = flag;
}
/**
* Make the kerberos library default to the admin KDC.
*
* @param context Kerberos 5 context.
*
* @return boolean flag to telling the context will use admin KDC as the default KDC.
*
* @ingroup krb5
*/
KRB5_LIB_FUNCTION krb5_boolean KRB5_LIB_CALL
krb5_get_use_admin_kdc (krb5_context context)
{
return context->use_admin_kdc;
}
/**
* Add extra address to the address list that the library will add to
* the client's address list when communicating with the KDC.
*
* @param context Kerberos 5 context.
* @param addresses addreses to add
*
* @return Returns 0 to indicate success. Otherwise an kerberos et
* error code is returned, see krb5_get_error_message().
*
* @ingroup krb5
*/
KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
krb5_add_extra_addresses(krb5_context context, krb5_addresses *addresses)
{
if(context->extra_addresses)
return krb5_append_addresses(context,
context->extra_addresses, addresses);
else
return krb5_set_extra_addresses(context, addresses);
}
/**
* Set extra address to the address list that the library will add to
* the client's address list when communicating with the KDC.
*
* @param context Kerberos 5 context.
* @param addresses addreses to set
*
* @return Returns 0 to indicate success. Otherwise an kerberos et
* error code is returned, see krb5_get_error_message().
*
* @ingroup krb5
*/
KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
krb5_set_extra_addresses(krb5_context context, const krb5_addresses *addresses)
{
if(context->extra_addresses)
krb5_free_addresses(context, context->extra_addresses);
if(addresses == NULL) {
if(context->extra_addresses != NULL) {
free(context->extra_addresses);
context->extra_addresses = NULL;
}
return 0;
}
if(context->extra_addresses == NULL) {
context->extra_addresses = malloc(sizeof(*context->extra_addresses));
if(context->extra_addresses == NULL) {
krb5_set_error_message (context, ENOMEM, N_("malloc: out of memory", ""));
return ENOMEM;
}
}
return krb5_copy_addresses(context, addresses, context->extra_addresses);
}
/**
* Get extra address to the address list that the library will add to
* the client's address list when communicating with the KDC.
*
* @param context Kerberos 5 context.
* @param addresses addreses to set
*
* @return Returns 0 to indicate success. Otherwise an kerberos et
* error code is returned, see krb5_get_error_message().
*
* @ingroup krb5
*/
KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
krb5_get_extra_addresses(krb5_context context, krb5_addresses *addresses)
{
if(context->extra_addresses == NULL) {
memset(addresses, 0, sizeof(*addresses));
return 0;
}
return krb5_copy_addresses(context,context->extra_addresses, addresses);
}
/**
* Add extra addresses to ignore when fetching addresses from the
* underlaying operating system.
*
* @param context Kerberos 5 context.
* @param addresses addreses to ignore
*
* @return Returns 0 to indicate success. Otherwise an kerberos et
* error code is returned, see krb5_get_error_message().
*
* @ingroup krb5
*/
KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
krb5_add_ignore_addresses(krb5_context context, krb5_addresses *addresses)
{
if(context->ignore_addresses)
return krb5_append_addresses(context,
context->ignore_addresses, addresses);
else
return krb5_set_ignore_addresses(context, addresses);
}
/**
* Set extra addresses to ignore when fetching addresses from the
* underlaying operating system.
*
* @param context Kerberos 5 context.
* @param addresses addreses to ignore
*
* @return Returns 0 to indicate success. Otherwise an kerberos et
* error code is returned, see krb5_get_error_message().
*
* @ingroup krb5
*/
KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
krb5_set_ignore_addresses(krb5_context context, const krb5_addresses *addresses)
{
if(context->ignore_addresses)
krb5_free_addresses(context, context->ignore_addresses);
if(addresses == NULL) {
if(context->ignore_addresses != NULL) {
free(context->ignore_addresses);
context->ignore_addresses = NULL;
}
return 0;
}
if(context->ignore_addresses == NULL) {
context->ignore_addresses = malloc(sizeof(*context->ignore_addresses));
if(context->ignore_addresses == NULL) {
krb5_set_error_message (context, ENOMEM, N_("malloc: out of memory", ""));
return ENOMEM;
}
}
return krb5_copy_addresses(context, addresses, context->ignore_addresses);
}
/**
* Get extra addresses to ignore when fetching addresses from the
* underlaying operating system.
*
* @param context Kerberos 5 context.
* @param addresses list addreses ignored
*
* @return Returns 0 to indicate success. Otherwise an kerberos et
* error code is returned, see krb5_get_error_message().
*
* @ingroup krb5
*/
KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
krb5_get_ignore_addresses(krb5_context context, krb5_addresses *addresses)
{
if(context->ignore_addresses == NULL) {
memset(addresses, 0, sizeof(*addresses));
return 0;
}
return krb5_copy_addresses(context, context->ignore_addresses, addresses);
}
/**
* Set version of fcache that the library should use.
*
* @param context Kerberos 5 context.
* @param version version number.
*
* @return Returns 0 to indicate success. Otherwise an kerberos et
* error code is returned, see krb5_get_error_message().
*
* @ingroup krb5
*/
KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
krb5_set_fcache_version(krb5_context context, int version)
{
context->fcache_vno = version;
return 0;
}
/**
* Get version of fcache that the library should use.
*
* @param context Kerberos 5 context.
* @param version version number.
*
* @return Returns 0 to indicate success. Otherwise an kerberos et
* error code is returned, see krb5_get_error_message().
*
* @ingroup krb5
*/
KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
krb5_get_fcache_version(krb5_context context, int *version)
{
*version = context->fcache_vno;
return 0;
}
/**
* Runtime check if the Kerberos library was complied with thread support.
*
* @return TRUE if the library was compiled with thread support, FALSE if not.
*
* @ingroup krb5
*/
KRB5_LIB_FUNCTION krb5_boolean KRB5_LIB_CALL
krb5_is_thread_safe(void)
{
#ifdef ENABLE_PTHREAD_SUPPORT
return TRUE;
#else
return FALSE;
#endif
}
/**
* Set if the library should use DNS to canonicalize hostnames.
*
* @param context Kerberos 5 context.
* @param flag if its dns canonicalizion is used or not.
*
* @ingroup krb5
*/
KRB5_LIB_FUNCTION void KRB5_LIB_CALL
krb5_set_dns_canonicalize_hostname (krb5_context context, krb5_boolean flag)
{
if (flag)
context->flags |= KRB5_CTX_F_DNS_CANONICALIZE_HOSTNAME;
else
context->flags &= ~KRB5_CTX_F_DNS_CANONICALIZE_HOSTNAME;
}
/**
* Get if the library uses DNS to canonicalize hostnames.
*
* @param context Kerberos 5 context.
*
* @return return non zero if the library uses DNS to canonicalize hostnames.
*
* @ingroup krb5
*/
KRB5_LIB_FUNCTION krb5_boolean KRB5_LIB_CALL
krb5_get_dns_canonicalize_hostname (krb5_context context)
{
return (context->flags & KRB5_CTX_F_DNS_CANONICALIZE_HOSTNAME) ? 1 : 0;
}
/**
* Get current offset in time to the KDC.
*
* @param context Kerberos 5 context.
* @param sec seconds part of offset.
* @param usec micro seconds part of offset.
*
* @return returns zero
*
* @ingroup krb5
*/
KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
krb5_get_kdc_sec_offset (krb5_context context, int32_t *sec, int32_t *usec)
{
if (sec)
*sec = context->kdc_sec_offset;
if (usec)
*usec = context->kdc_usec_offset;
return 0;
}
/**
* Set current offset in time to the KDC.
*
* @param context Kerberos 5 context.
* @param sec seconds part of offset.
* @param usec micro seconds part of offset.
*
* @return returns zero
*
* @ingroup krb5
*/
KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
krb5_set_kdc_sec_offset (krb5_context context, int32_t sec, int32_t usec)
{
context->kdc_sec_offset = sec;
if (usec >= 0)
context->kdc_usec_offset = usec;
return 0;
}
/**
* Get max time skew allowed.
*
* @param context Kerberos 5 context.
*
* @return timeskew in seconds.
*
* @ingroup krb5
*/
KRB5_LIB_FUNCTION time_t KRB5_LIB_CALL
krb5_get_max_time_skew (krb5_context context)
{
return context->max_skew;
}
/**
* Set max time skew allowed.
*
* @param context Kerberos 5 context.
* @param t timeskew in seconds.
*
* @ingroup krb5
*/
KRB5_LIB_FUNCTION void KRB5_LIB_CALL
krb5_set_max_time_skew (krb5_context context, time_t t)
{
context->max_skew = t;
}
/**
* Init encryption types in len, val with etypes.
*
* @param context Kerberos 5 context.
* @param len output length of val.
* @param val output array of enctypes.
* @param etypes etypes to set val and len to, if NULL, use default enctypes.
* @return Returns 0 to indicate success. Otherwise an kerberos et
* error code is returned, see krb5_get_error_message().
*
* @ingroup krb5
*/
KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
krb5_init_etype (krb5_context context,
unsigned *len,
krb5_enctype **val,
const krb5_enctype *etypes)
{
unsigned int i;
krb5_error_code ret;
krb5_enctype *tmp = NULL;
ret = 0;
if (etypes == NULL) {
ret = krb5_get_default_in_tkt_etypes(context, &tmp);
if (ret)
return ret;
etypes = tmp;
}
for (i = 0; etypes[i]; ++i)
;
*len = i;
*val = malloc(i * sizeof(**val));
if (i != 0 && *val == NULL) {
ret = ENOMEM;
krb5_set_error_message(context, ret, N_("malloc: out of memory", ""));
goto cleanup;
}
memmove (*val,
etypes,
i * sizeof(*tmp));
cleanup:
if (tmp != NULL)
free (tmp);
return ret;
}
/*
* Allow homedir accces
*/
static HEIMDAL_MUTEX homedir_mutex = HEIMDAL_MUTEX_INITIALIZER;
static krb5_boolean allow_homedir = TRUE;
krb5_boolean
_krb5_homedir_access(krb5_context context)
{
krb5_boolean allow;
#ifdef HAVE_GETEUID
/* is never allowed for root */
if (geteuid() == 0)
return FALSE;
#endif
if (context && (context->flags & KRB5_CTX_F_HOMEDIR_ACCESS) == 0)
return FALSE;
HEIMDAL_MUTEX_lock(&homedir_mutex);
allow = allow_homedir;
HEIMDAL_MUTEX_unlock(&homedir_mutex);
return allow;
}
/**
* Enable and disable home directory access on either the global state
* or the krb5_context state. By calling krb5_set_home_dir_access()
* with context set to NULL, the global state is configured otherwise
* the state for the krb5_context is modified.
*
* For home directory access to be allowed, both the global state and
* the krb5_context state have to be allowed.
*
* Administrator (root user), never uses the home directory.
*
* @param context a Kerberos 5 context or NULL
* @param allow allow if TRUE home directory
* @return the old value
*
*/
krb5_boolean
krb5_set_home_dir_access(krb5_context context, krb5_boolean allow)
{
krb5_boolean old;
if (context) {
old = (context->flags & KRB5_CTX_F_HOMEDIR_ACCESS) ? TRUE : FALSE;
if (allow)
context->flags |= KRB5_CTX_F_HOMEDIR_ACCESS;
else
context->flags &= ~KRB5_CTX_F_HOMEDIR_ACCESS;
} else {
HEIMDAL_MUTEX_lock(&homedir_mutex);
old = allow_homedir;
allow_homedir = allow;
HEIMDAL_MUTEX_unlock(&homedir_mutex);
}
return old;
}