summaryrefslogtreecommitdiff
path: root/source4/heimdal/lib/krb5
diff options
context:
space:
mode:
authorHeimdal Import User <samba-bugs@samba.org>2005-07-11 01:16:55 +0000
committerGerald (Jerry) Carter <jerry@samba.org>2007-10-10 13:19:33 -0500
commit954c01728e0c7485b72c9a5d5737e5f6bd0cf0b9 (patch)
treefc11a048c8a582e2ca66415ff04dacf74f9abf22 /source4/heimdal/lib/krb5
parent7ead5ab06cea9f33e954a4579163262f97ea06ff (diff)
downloadsamba-954c01728e0c7485b72c9a5d5737e5f6bd0cf0b9.tar.gz
samba-954c01728e0c7485b72c9a5d5737e5f6bd0cf0b9.tar.bz2
samba-954c01728e0c7485b72c9a5d5737e5f6bd0cf0b9.zip
r8302: import mini HEIMDAL into the tree
(This used to be commit 118be28a7aef233799956615a99d1a2a74dac175)
Diffstat (limited to 'source4/heimdal/lib/krb5')
-rw-r--r--source4/heimdal/lib/krb5/acache.c781
-rw-r--r--source4/heimdal/lib/krb5/add_et_list.c50
-rw-r--r--source4/heimdal/lib/krb5/addr_families.c1180
-rw-r--r--source4/heimdal/lib/krb5/appdefault.c142
-rw-r--r--source4/heimdal/lib/krb5/asn1_glue.c59
-rw-r--r--source4/heimdal/lib/krb5/auth_context.c517
-rw-r--r--source4/heimdal/lib/krb5/build_ap_req.c76
-rw-r--r--source4/heimdal/lib/krb5/build_auth.c205
-rw-r--r--source4/heimdal/lib/krb5/cache.c657
-rw-r--r--source4/heimdal/lib/krb5/changepw.c816
-rw-r--r--source4/heimdal/lib/krb5/codec.c196
-rw-r--r--source4/heimdal/lib/krb5/config_file.c773
-rw-r--r--source4/heimdal/lib/krb5/config_file_netinfo.c180
-rw-r--r--source4/heimdal/lib/krb5/constants.c43
-rw-r--r--source4/heimdal/lib/krb5/context.c663
-rw-r--r--source4/heimdal/lib/krb5/copy_host_realm.c69
-rw-r--r--source4/heimdal/lib/krb5/crc.c71
-rw-r--r--source4/heimdal/lib/krb5/creds.c215
-rw-r--r--source4/heimdal/lib/krb5/crypto.c4410
-rw-r--r--source4/heimdal/lib/krb5/data.c119
-rw-r--r--source4/heimdal/lib/krb5/eai_to_heim_errno.c98
-rw-r--r--source4/heimdal/lib/krb5/error_string.c109
-rw-r--r--source4/heimdal/lib/krb5/expand_hostname.c153
-rw-r--r--source4/heimdal/lib/krb5/fcache.c718
-rw-r--r--source4/heimdal/lib/krb5/free.c53
-rw-r--r--source4/heimdal/lib/krb5/free_host_realm.c54
-rw-r--r--source4/heimdal/lib/krb5/generate_seq_number.c62
-rw-r--r--source4/heimdal/lib/krb5/generate_subkey.c72
-rw-r--r--source4/heimdal/lib/krb5/get_addrs.c291
-rw-r--r--source4/heimdal/lib/krb5/get_cred.c909
-rw-r--r--source4/heimdal/lib/krb5/get_default_principal.c115
-rw-r--r--source4/heimdal/lib/krb5/get_default_realm.c84
-rw-r--r--source4/heimdal/lib/krb5/get_for_creds.c427
-rw-r--r--source4/heimdal/lib/krb5/get_host_realm.c220
-rw-r--r--source4/heimdal/lib/krb5/get_in_tkt.c823
-rw-r--r--source4/heimdal/lib/krb5/get_in_tkt_with_keytab.c99
-rw-r--r--source4/heimdal/lib/krb5/get_port.c54
-rw-r--r--source4/heimdal/lib/krb5/heim_err.et44
-rwxr-xr-xsource4/heimdal/lib/krb5/heim_threads.h175
-rw-r--r--source4/heimdal/lib/krb5/init_creds.c331
-rw-r--r--source4/heimdal/lib/krb5/init_creds_pw.c1554
-rw-r--r--source4/heimdal/lib/krb5/k524_err.et20
-rw-r--r--source4/heimdal/lib/krb5/kcm.c1095
-rw-r--r--source4/heimdal/lib/krb5/keyblock.c133
-rw-r--r--source4/heimdal/lib/krb5/keytab.c491
-rw-r--r--source4/heimdal/lib/krb5/keytab_any.c256
-rw-r--r--source4/heimdal/lib/krb5/keytab_file.c678
-rw-r--r--source4/heimdal/lib/krb5/keytab_keyfile.c389
-rw-r--r--source4/heimdal/lib/krb5/keytab_krb4.c443
-rw-r--r--source4/heimdal/lib/krb5/keytab_memory.c229
-rw-r--r--source4/heimdal/lib/krb5/krb5-private.h358
-rw-r--r--source4/heimdal/lib/krb5/krb5-protos.h3407
-rw-r--r--source4/heimdal/lib/krb5/krb5-v4compat.h176
-rw-r--r--source4/heimdal/lib/krb5/krb5.h754
-rw-r--r--source4/heimdal/lib/krb5/krb5_ccapi.h215
-rw-r--r--source4/heimdal/lib/krb5/krb5_err.et258
-rw-r--r--source4/heimdal/lib/krb5/krb5_locl.h188
-rw-r--r--source4/heimdal/lib/krb5/krbhst.c861
-rw-r--r--source4/heimdal/lib/krb5/log.c467
-rw-r--r--source4/heimdal/lib/krb5/mcache.c353
-rw-r--r--source4/heimdal/lib/krb5/misc.c36
-rwxr-xr-xsource4/heimdal/lib/krb5/mit_glue.c327
-rw-r--r--source4/heimdal/lib/krb5/mk_error.c92
-rw-r--r--source4/heimdal/lib/krb5/mk_priv.c153
-rw-r--r--source4/heimdal/lib/krb5/mk_rep.c126
-rw-r--r--source4/heimdal/lib/krb5/mk_req.c116
-rw-r--r--source4/heimdal/lib/krb5/mk_req_ext.c180
-rw-r--r--source4/heimdal/lib/krb5/n-fold.c126
-rw-r--r--source4/heimdal/lib/krb5/padata.c66
-rwxr-xr-xsource4/heimdal/lib/krb5/pkinit.c2583
-rw-r--r--source4/heimdal/lib/krb5/principal.c1125
-rw-r--r--source4/heimdal/lib/krb5/rd_cred.c299
-rw-r--r--source4/heimdal/lib/krb5/rd_error.c121
-rw-r--r--source4/heimdal/lib/krb5/rd_priv.c176
-rw-r--r--source4/heimdal/lib/krb5/rd_rep.c133
-rw-r--r--source4/heimdal/lib/krb5/rd_req.c649
-rw-r--r--source4/heimdal/lib/krb5/replay.c304
-rw-r--r--source4/heimdal/lib/krb5/send_to_kdc.c416
-rw-r--r--source4/heimdal/lib/krb5/set_default_realm.c90
-rw-r--r--source4/heimdal/lib/krb5/store-int.h47
-rw-r--r--source4/heimdal/lib/krb5/store.c888
-rw-r--r--source4/heimdal/lib/krb5/store_emem.c132
-rw-r--r--source4/heimdal/lib/krb5/store_fd.c95
-rw-r--r--source4/heimdal/lib/krb5/store_mem.c119
-rw-r--r--source4/heimdal/lib/krb5/ticket.c125
-rw-r--r--source4/heimdal/lib/krb5/time.c114
-rw-r--r--source4/heimdal/lib/krb5/transited.c481
-rw-r--r--source4/heimdal/lib/krb5/v4_glue.c922
-rw-r--r--source4/heimdal/lib/krb5/version.c43
-rw-r--r--source4/heimdal/lib/krb5/warn.c205
90 files changed, 38727 insertions, 0 deletions
diff --git a/source4/heimdal/lib/krb5/acache.c b/source4/heimdal/lib/krb5/acache.c
new file mode 100644
index 0000000000..75f5315c71
--- /dev/null
+++ b/source4/heimdal/lib/krb5/acache.c
@@ -0,0 +1,781 @@
+/*
+ * Copyright (c) 2004 - 2005 Kungliga Tekniska Högskolan
+ * (Royal Institute of Technology, Stockholm, Sweden).
+ * 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 <krb5_ccapi.h>
+#ifdef HAVE_DLFCN_H
+#include <dlfcn.h>
+#endif
+
+RCSID("$Id: acache.c,v 1.11 2005/06/16 19:32:44 lha Exp $");
+
+/* XXX should we fetch these for each open ? */
+static HEIMDAL_MUTEX acc_mutex = HEIMDAL_MUTEX_INITIALIZER;
+static cc_initialize_func init_func;
+
+#ifdef HAVE_DLOPEN
+static void *cc_handle;
+#endif
+
+typedef struct krb5_acc {
+ char *cache_name;
+ cc_context_t context;
+ cc_ccache_t ccache;
+} krb5_acc;
+
+static krb5_error_code acc_close(krb5_context, krb5_ccache);
+
+#define ACACHE(X) ((krb5_acc *)(X)->data.data)
+
+static const struct {
+ cc_int32 error;
+ krb5_error_code ret;
+} cc_errors[] = {
+ { ccErrBadName, KRB5_CC_BADNAME },
+ { ccErrCredentialsNotFound, KRB5_CC_NOTFOUND },
+ { ccErrCCacheNotFound, KRB5_FCC_NOFILE },
+ { ccErrContextNotFound, KRB5_CC_NOTFOUND },
+ { ccIteratorEnd, KRB5_CC_END },
+ { ccErrNoMem, KRB5_CC_NOMEM },
+ { ccErrServerUnavailable, KRB5_CC_BADNAME },
+ { ccNoError, 0 }
+};
+
+static krb5_error_code
+translate_cc_error(krb5_context context, cc_int32 error)
+{
+ int i;
+ krb5_clear_error_string(context);
+ for(i = 0; i < sizeof(cc_errors)/sizeof(cc_errors[0]); i++)
+ if (cc_errors[i].error == error)
+ return cc_errors[i].ret;
+ return KRB5_FCC_INTERNAL;
+}
+
+static krb5_error_code
+init_ccapi(krb5_context context)
+{
+ const char *lib;
+
+ HEIMDAL_MUTEX_lock(&acc_mutex);
+ if (init_func) {
+ HEIMDAL_MUTEX_unlock(&acc_mutex);
+ krb5_clear_error_string(context);
+ return 0;
+ }
+
+ lib = krb5_config_get_string(context, NULL,
+ "libdefaults", "ccapi_library",
+ NULL);
+ if (lib == NULL) {
+#ifdef __APPLE__
+ lib = "/System/Library/Frameworks/Kerberos.framework/Kerberos";
+#else
+ lib = "/usr/lib/libkrb5_cc.so";
+#endif
+ }
+
+#ifdef HAVE_DLOPEN
+ cc_handle = dlopen(lib, 0);
+ if (cc_handle == NULL) {
+ HEIMDAL_MUTEX_unlock(&acc_mutex);
+ krb5_set_error_string(context, "Failed to load %s", lib);
+ return ccErrServerUnavailable;
+ }
+
+ init_func = dlsym(cc_handle, "cc_initialize");
+ HEIMDAL_MUTEX_unlock(&acc_mutex);
+ if (init_func == NULL) {
+ krb5_set_error_string(context, "Failed to find cc_initialize"
+ "in %s: %s", lib, dlerror());
+ dlclose(cc_handle);
+ return ccErrServerUnavailable;
+ }
+
+ return 0;
+#else
+ HEIMDAL_MUTEX_unlock(&acc_mutex);
+ krb5_set_error_string(context, "no support for shared object");
+ return ccErrServerUnavailable;
+#endif
+}
+
+static krb5_error_code
+make_cred_from_ccred(krb5_context context,
+ const cc_credentials_v5_t *incred,
+ krb5_creds *cred)
+{
+ krb5_error_code ret;
+ int i;
+
+ memset(cred, 0, sizeof(*cred));
+
+ ret = krb5_parse_name(context, incred->client, &cred->client);
+ if (ret)
+ goto fail;
+
+ ret = krb5_parse_name(context, incred->server, &cred->server);
+ if (ret)
+ goto fail;
+
+ cred->session.keytype = incred->keyblock.type;
+ cred->session.keyvalue.length = incred->keyblock.length;
+ cred->session.keyvalue.data = malloc(incred->keyblock.length);
+ if (cred->session.keyvalue.data == NULL)
+ goto nomem;
+ memcpy(cred->session.keyvalue.data, incred->keyblock.data,
+ incred->keyblock.length);
+
+ cred->times.authtime = incred->authtime;
+ cred->times.starttime = incred->starttime;
+ cred->times.endtime = incred->endtime;
+ cred->times.renew_till = incred->renew_till;
+
+ ret = krb5_data_copy(&cred->ticket,
+ incred->ticket.data,
+ incred->ticket.length);
+ if (ret)
+ goto nomem;
+
+ ret = krb5_data_copy(&cred->second_ticket,
+ incred->second_ticket.data,
+ incred->second_ticket.length);
+ if (ret)
+ goto nomem;
+
+ cred->authdata.val = NULL;
+ cred->authdata.len = 0;
+
+ cred->addresses.val = NULL;
+ cred->addresses.len = 0;
+
+ for (i = 0; incred->authdata && incred->authdata[i]; i++)
+ ;
+
+ if (i) {
+ cred->authdata.val = malloc(sizeof(cred->authdata.val[0]) * i);
+ if (cred->authdata.val == NULL)
+ goto nomem;
+ cred->authdata.len = i;
+ memset(cred->authdata.val, 0, sizeof(cred->authdata.val[0]) * i);
+ for (i = 0; i < cred->authdata.len; i++) {
+ cred->authdata.val[i].ad_type = incred->authdata[i]->type;
+ ret = krb5_data_copy(&cred->authdata.val[i].ad_data,
+ incred->authdata[i]->data,
+ incred->authdata[i]->length);
+ if (ret)
+ goto nomem;
+ }
+ }
+
+ for (i = 0; incred->addresses && incred->addresses[i]; i++)
+ ;
+
+ if (i) {
+ cred->addresses.val = malloc(sizeof(cred->addresses.val[0]) * i);
+ if (cred->addresses.val == NULL)
+ goto nomem;
+ cred->addresses.len = i;
+ memset(cred->addresses.val, 0, sizeof(cred->addresses.val[0]) * i);
+
+ for (i = 0; i < cred->addresses.len; i++) {
+ cred->addresses.val[i].addr_type = incred->addresses[i]->type;
+ ret = krb5_data_copy(&cred->addresses.val[i].address,
+ incred->addresses[i]->data,
+ incred->addresses[i]->length);
+ if (ret)
+ goto nomem;
+ }
+ }
+
+ cred->flags.b = int2TicketFlags(incred->ticket_flags); /* XXX */
+ return 0;
+
+nomem:
+ ret = ENOMEM;
+ krb5_set_error_string(context, "malloc - out of memory");
+
+fail:
+ krb5_free_creds_contents(context, cred);
+ return ret;
+}
+
+static void
+free_ccred(cc_credentials_v5_t *cred)
+{
+ int i;
+
+ if (cred->addresses) {
+ for (i = 0; cred->addresses[i] != 0; i++) {
+ if (cred->addresses[i]->data)
+ free(cred->addresses[i]->data);
+ free(cred->addresses[i]);
+ }
+ free(cred->addresses);
+ }
+ if (cred->server)
+ free(cred->server);
+ if (cred->client)
+ free(cred->client);
+ memset(cred, 0, sizeof(*cred));
+}
+
+static krb5_error_code
+make_ccred_from_cred(krb5_context context,
+ const krb5_creds *incred,
+ cc_credentials_v5_t *cred)
+{
+ krb5_error_code ret;
+ int i;
+
+ memset(cred, 0, sizeof(*cred));
+
+ ret = krb5_unparse_name(context, incred->client, &cred->client);
+ if (ret)
+ goto fail;
+
+ ret = krb5_unparse_name(context, incred->server, &cred->server);
+ if (ret)
+ goto fail;
+
+ cred->keyblock.type = incred->session.keytype;
+ cred->keyblock.length = incred->session.keyvalue.length;
+ cred->keyblock.data = incred->session.keyvalue.data;
+
+ cred->authtime = incred->times.authtime;
+ cred->starttime = incred->times.starttime;
+ cred->endtime = incred->times.endtime;
+ cred->renew_till = incred->times.renew_till;
+
+ cred->ticket.length = incred->ticket.length;
+ cred->ticket.data = incred->ticket.data;
+
+ cred->second_ticket.length = incred->second_ticket.length;
+ cred->second_ticket.data = incred->second_ticket.data;
+
+ /* XXX this one should also be filled in */
+ cred->authdata = NULL;
+
+ cred->addresses = calloc(incred->addresses.len + 1,
+ sizeof(cred->addresses[0]));
+ if (cred->addresses == NULL) {
+
+ ret = ENOMEM;
+ goto fail;
+ }
+
+ for (i = 0; i < incred->addresses.len; i++) {
+ cc_data *addr;
+ addr = malloc(sizeof(*addr));
+ addr->type = incred->addresses.val[i].addr_type;
+ addr->length = incred->addresses.val[i].address.length;
+ addr->data = malloc(addr->length);
+ if (addr->data == NULL) {
+ ret = ENOMEM;
+ goto fail;
+ }
+ memcpy(addr->data, incred->addresses.val[i].address.data,
+ addr->length);
+ cred->addresses[i] = addr;
+ }
+ cred->addresses[i] = NULL;
+
+ cred->ticket_flags = TicketFlags2int(incred->flags.b); /* XXX */
+ return 0;
+
+fail:
+ free_ccred(cred);
+
+ krb5_clear_error_string(context);
+ return ret;
+}
+
+static char *
+get_cc_name(cc_ccache_t cache)
+{
+ cc_string_t name;
+ cc_int32 error;
+ char *str;
+
+ error = (*cache->func->get_name)(cache, &name);
+ if (error)
+ return NULL;
+
+ str = strdup(name->data);
+ (*name->func->release)(name);
+ return str;
+}
+
+
+static const char*
+acc_get_name(krb5_context context,
+ krb5_ccache id)
+{
+ krb5_acc *a = ACACHE(id);
+ static char n[255];
+ char *name;
+
+ name = get_cc_name(a->ccache);
+ if (name == NULL) {
+ krb5_set_error_string(context, "malloc: out of memory");
+ return NULL;
+ }
+ strlcpy(n, name, sizeof(n));
+ free(name);
+ return n;
+}
+
+static krb5_error_code
+acc_alloc(krb5_context context, krb5_ccache *id)
+{
+ krb5_error_code ret;
+ cc_int32 error;
+ krb5_acc *a;
+
+ ret = init_ccapi(context);
+ if (ret)
+ return ret;
+
+ ret = krb5_data_alloc(&(*id)->data, sizeof(*a));
+ if (ret) {
+ krb5_clear_error_string(context);
+ return ret;
+ }
+
+ a = ACACHE(*id);
+
+ error = (*init_func)(&a->context, ccapi_version_3, NULL, NULL);
+ if (error) {
+ krb5_data_free(&(*id)->data);
+ return translate_cc_error(context, error);
+ }
+
+ a->cache_name = NULL;
+
+ return 0;
+}
+
+static krb5_error_code
+get_default_principal(krb5_context context, char **p)
+{
+ krb5_error_code ret;
+ krb5_principal principal;
+
+ *p = NULL;
+
+ ret = _krb5_get_default_principal_local(context, &principal);
+ if (ret)
+ return ret;
+
+ ret = krb5_unparse_name(context, principal, p);
+ krb5_free_principal(context, principal);
+ return ret;
+}
+
+static krb5_error_code
+acc_resolve(krb5_context context, krb5_ccache *id, const char *res)
+{
+ krb5_error_code ret;
+ cc_int32 error;
+ krb5_acc *a;
+
+ ret = acc_alloc(context, id);
+ if (ret)
+ return ret;
+
+ a = ACACHE(*id);
+
+ if (res == NULL || res[0] == '\0') {
+ error = (*a->context->func->open_default_ccache)(a->context,
+ &a->ccache);
+ if (error == ccErrCCacheNotFound) {
+ char *p;
+
+ ret = get_default_principal(context, &p);
+ if (ret == 0) {
+ error = (*a->context->func->create_default_ccache)(a->context,
+ cc_credentials_v5,
+ p,
+ &a->ccache);
+ free(p);
+ }
+ }
+ if (error == 0)
+ a->cache_name = get_cc_name(a->ccache);
+ } else {
+ error = (*a->context->func->open_ccache)(a->context, res, &a->ccache);
+ if (error == 0)
+ a->cache_name = strdup(res);
+ }
+ if (error != 0) {
+ *id = NULL;
+ return translate_cc_error(context, error);
+ }
+ if (a->cache_name == NULL) {
+ acc_close(context, *id);
+ *id = NULL;
+ krb5_set_error_string(context, "malloc: out of memory");
+ return ENOMEM;
+ }
+
+ return 0;
+}
+
+static krb5_error_code
+acc_gen_new(krb5_context context, krb5_ccache *id)
+{
+ krb5_error_code ret;
+ cc_int32 error;
+ krb5_acc *a;
+ char *p;
+
+ ret = get_default_principal(context, &p);
+
+ ret = acc_alloc(context, id);
+ if (ret) {
+ free(p);
+ return ret;
+ }
+
+ a = ACACHE(*id);
+
+ error = (*a->context->func->create_new_ccache)(a->context,
+ cc_credentials_v5,
+ p, &a->ccache);
+ free(p);
+ if (error) {
+ *id = NULL;
+ return translate_cc_error(context, error);
+ }
+ a->cache_name = get_cc_name(a->ccache);
+ if (a->cache_name == NULL) {
+ acc_close(context, *id);
+ *id = NULL;
+ krb5_set_error_string(context, "malloc: out of memory");
+ return ENOMEM;
+ }
+ return 0;
+}
+
+static krb5_error_code
+acc_initialize(krb5_context context,
+ krb5_ccache id,
+ krb5_principal primary_principal)
+{
+ cc_credentials_iterator_t iter;
+ krb5_acc *a = ACACHE(id);
+ cc_credentials_t ccred;
+ krb5_error_code ret;
+ int32_t error;
+ char *name;
+
+ ret = krb5_unparse_name(context, primary_principal, &name);
+ if (ret)
+ return ret;
+
+ if (a->ccache == NULL) {
+ error = (*a->context->func->create_new_ccache)(a->context,
+ cc_credentials_v5,
+ name,
+ &a->ccache);
+ } else {
+
+ error = (*a->ccache->func->new_credentials_iterator)(a->ccache, &iter);
+ if (error) {
+ free(name);
+ return translate_cc_error(context, error);
+ }
+
+ while (1) {
+ error = (*iter->func->next)(iter, &ccred);
+ if (error)
+ break;
+ (*a->ccache->func->remove_credentials)(a->ccache, ccred);
+ (*ccred->func->release)(ccred);
+ }
+ (*iter->func->release)(iter);
+
+ error = (*a->ccache->func->set_principal)(a->ccache,
+ cc_credentials_v5,
+ name);
+ }
+
+ free(name);
+
+ return translate_cc_error(context, error);
+}
+
+static krb5_error_code
+acc_close(krb5_context context,
+ krb5_ccache id)
+{
+ krb5_acc *a = ACACHE(id);
+
+ if (a->ccache) {
+ (*a->ccache->func->release)(a->ccache);
+ a->ccache = NULL;
+ }
+ if (a->cache_name) {
+ free(a->cache_name);
+ a->cache_name = NULL;
+ }
+ (*a->context->func->release)(a->context);
+ a->context = NULL;
+ krb5_data_free(&id->data);
+ return 0;
+}
+
+static krb5_error_code
+acc_destroy(krb5_context context,
+ krb5_ccache id)
+{
+ krb5_acc *a = ACACHE(id);
+ cc_int32 error = 0;
+
+ if (a->ccache) {
+ error = (*a->ccache->func->destroy)(a->ccache);
+ a->ccache = NULL;
+ }
+ return translate_cc_error(context, error);
+}
+
+static krb5_error_code
+acc_store_cred(krb5_context context,
+ krb5_ccache id,
+ krb5_creds *creds)
+{
+ krb5_acc *a = ACACHE(id);
+ cc_credentials_union cred;
+ cc_credentials_v5_t v5cred;
+ krb5_error_code ret;
+ cc_int32 error;
+
+ cred.version = cc_credentials_v5;
+ cred.credentials.credentials_v5 = &v5cred;
+
+ ret = make_ccred_from_cred(context,
+ creds,
+ &v5cred);
+ if (ret)
+ return ret;
+
+ error = (*a->ccache->func->store_credentials)(a->ccache, &cred);
+ if (error)
+ ret = translate_cc_error(context, error);
+
+ free_ccred(&v5cred);
+
+ return ret;
+}
+
+static krb5_error_code
+acc_get_principal(krb5_context context,
+ krb5_ccache id,
+ krb5_principal *principal)
+{
+ krb5_acc *a = ACACHE(id);
+ krb5_error_code ret;
+ int32_t error;
+ cc_string_t name;
+
+ if (a->ccache == NULL)
+ return ENOENT;
+
+ error = (*a->ccache->func->get_principal)(a->ccache,
+ cc_credentials_v5,
+ &name);
+ if (error)
+ return translate_cc_error(context, error);
+
+ ret = krb5_parse_name(context, name->data, principal);
+
+ (*name->func->release)(name);
+ return ret;
+}
+
+static krb5_error_code
+acc_get_first (krb5_context context,
+ krb5_ccache id,
+ krb5_cc_cursor *cursor)
+{
+ cc_credentials_iterator_t iter;
+ krb5_acc *a = ACACHE(id);
+ int32_t error;
+
+ error = (*a->ccache->func->new_credentials_iterator)(a->ccache, &iter);
+ if (error)
+ return ENOENT;
+ *cursor = iter;
+ return 0;
+}
+
+
+static krb5_error_code
+acc_get_next (krb5_context context,
+ krb5_ccache id,
+ krb5_cc_cursor *cursor,
+ krb5_creds *creds)
+{
+ cc_credentials_iterator_t iter = *cursor;
+ cc_credentials_t cred;
+ krb5_error_code ret;
+ int32_t error;
+
+ while (1) {
+ error = (*iter->func->next)(iter, &cred);
+ if (error)
+ return translate_cc_error(context, error);
+ if (cred->data->version == cc_credentials_v5)
+ break;
+ (*cred->func->release)(cred);
+ }
+
+ ret = make_cred_from_ccred(context,
+ cred->data->credentials.credentials_v5,
+ creds);
+ (*cred->func->release)(cred);
+ return ret;
+}
+
+static krb5_error_code
+acc_end_get (krb5_context context,
+ krb5_ccache id,
+ krb5_cc_cursor *cursor)
+{
+ cc_credentials_iterator_t iter = *cursor;
+ (*iter->func->release)(iter);
+ return 0;
+}
+
+static krb5_error_code
+acc_remove_cred(krb5_context context,
+ krb5_ccache id,
+ krb5_flags which,
+ krb5_creds *cred)
+{
+ cc_credentials_iterator_t iter;
+ krb5_acc *a = ACACHE(id);
+ cc_credentials_t ccred;
+ krb5_error_code ret;
+ cc_int32 error;
+ char *client, *server;
+
+ if (cred->client) {
+ ret = krb5_unparse_name(context, cred->client, &client);
+ if (ret)
+ return ret;
+ } else
+ client = NULL;
+
+ ret = krb5_unparse_name(context, cred->server, &server);
+ if (ret) {
+ free(client);
+ return ret;
+ }
+
+ error = (*a->ccache->func->new_credentials_iterator)(a->ccache, &iter);
+ if (error) {
+ free(server);
+ free(client);
+ return translate_cc_error(context, error);
+ }
+
+ ret = KRB5_CC_NOTFOUND;
+ while (1) {
+ cc_credentials_v5_t *v5cred;
+
+ error = (*iter->func->next)(iter, &ccred);
+ if (error)
+ break;
+
+ if (ccred->data->version != cc_credentials_v5)
+ goto next;
+
+ v5cred = ccred->data->credentials.credentials_v5;
+
+ if (client && strcmp(v5cred->client, client) != 0)
+ goto next;
+
+ if (strcmp(v5cred->server, server) != 0)
+ goto next;
+
+ (*a->ccache->func->remove_credentials)(a->ccache, ccred);
+ ret = 0;
+ next:
+ (*ccred->func->release)(ccred);
+ }
+
+ (*iter->func->release)(iter);
+
+ if (ret)
+ krb5_set_error_string(context, "Can't find credential %s in cache",
+ server);
+ free(server);
+ free(client);
+
+ return ret;
+}
+
+static krb5_error_code
+acc_set_flags(krb5_context context,
+ krb5_ccache id,
+ krb5_flags flags)
+{
+ return 0;
+}
+
+static krb5_error_code
+acc_get_version(krb5_context context,
+ krb5_ccache id)
+{
+ return 0;
+}
+
+const krb5_cc_ops krb5_acc_ops = {
+ "API",
+ acc_get_name,
+ acc_resolve,
+ acc_gen_new,
+ acc_initialize,
+ acc_destroy,
+ acc_close,
+ acc_store_cred,
+ NULL, /* acc_retrieve */
+ acc_get_principal,
+ acc_get_first,
+ acc_get_next,
+ acc_end_get,
+ acc_remove_cred,
+ acc_set_flags,
+ acc_get_version
+};
diff --git a/source4/heimdal/lib/krb5/add_et_list.c b/source4/heimdal/lib/krb5/add_et_list.c
new file mode 100644
index 0000000000..3b9773bebb
--- /dev/null
+++ b/source4/heimdal/lib/krb5/add_et_list.c
@@ -0,0 +1,50 @@
+/*
+ * Copyright (c) 1999 Kungliga Tekniska Högskolan
+ * (Royal Institute of Technology, Stockholm, Sweden).
+ * 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"
+
+RCSID("$Id: add_et_list.c,v 1.3 2004/04/13 14:33:45 lha Exp $");
+
+/*
+ * Add a specified list of error messages to the et list in context.
+ * Call func (probably a comerr-generated function) with a pointer to
+ * the current et_list.
+ */
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_add_et_list (krb5_context context,
+ void (*func)(struct et_list **))
+{
+ (*func)(&context->et_list);
+ return 0;
+}
diff --git a/source4/heimdal/lib/krb5/addr_families.c b/source4/heimdal/lib/krb5/addr_families.c
new file mode 100644
index 0000000000..ccc97f412d
--- /dev/null
+++ b/source4/heimdal/lib/krb5/addr_families.c
@@ -0,0 +1,1180 @@
+/*
+ * Copyright (c) 1997-2005 Kungliga Tekniska Högskolan
+ * (Royal Institute of Technology, Stockholm, Sweden).
+ * 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"
+
+RCSID("$Id: addr_families.c,v 1.49 2005/06/16 20:16:12 lha Exp $");
+
+struct addr_operations {
+ int af;
+ krb5_address_type atype;
+ size_t max_sockaddr_size;
+ krb5_error_code (*sockaddr2addr)(const struct sockaddr *, krb5_address *);
+ krb5_error_code (*sockaddr2port)(const struct sockaddr *, int16_t *);
+ void (*addr2sockaddr)(const krb5_address *, struct sockaddr *,
+ krb5_socklen_t *sa_size, int port);
+ void (*h_addr2sockaddr)(const char *, struct sockaddr *, krb5_socklen_t *, int);
+ krb5_error_code (*h_addr2addr)(const char *, krb5_address *);
+ krb5_boolean (*uninteresting)(const struct sockaddr *);
+ void (*anyaddr)(struct sockaddr *, krb5_socklen_t *, int);
+ int (*print_addr)(const krb5_address *, char *, size_t);
+ int (*parse_addr)(krb5_context, const char*, krb5_address *);
+ int (*order_addr)(krb5_context, const krb5_address*, const krb5_address*);
+ int (*free_addr)(krb5_context, krb5_address*);
+ int (*copy_addr)(krb5_context, const krb5_address*, krb5_address*);
+ int (*mask_boundary)(krb5_context, const krb5_address*, unsigned long,
+ krb5_address*, krb5_address*);
+};
+
+/*
+ * AF_INET - aka IPv4 implementation
+ */
+
+static krb5_error_code
+ipv4_sockaddr2addr (const struct sockaddr *sa, krb5_address *a)
+{
+ const struct sockaddr_in *sin4 = (const struct sockaddr_in *)sa;
+ unsigned char buf[4];
+
+ a->addr_type = KRB5_ADDRESS_INET;
+ memcpy (buf, &sin4->sin_addr, 4);
+ return krb5_data_copy(&a->address, buf, 4);
+}
+
+static krb5_error_code
+ipv4_sockaddr2port (const struct sockaddr *sa, int16_t *port)
+{
+ const struct sockaddr_in *sin4 = (const struct sockaddr_in *)sa;
+
+ *port = sin4->sin_port;
+ return 0;
+}
+
+static void
+ipv4_addr2sockaddr (const krb5_address *a,
+ struct sockaddr *sa,
+ krb5_socklen_t *sa_size,
+ int port)
+{
+ struct sockaddr_in tmp;
+
+ memset (&tmp, 0, sizeof(tmp));
+ tmp.sin_family = AF_INET;
+ memcpy (&tmp.sin_addr, a->address.data, 4);
+ tmp.sin_port = port;
+ memcpy(sa, &tmp, min(sizeof(tmp), *sa_size));
+ *sa_size = sizeof(tmp);
+}
+
+static void
+ipv4_h_addr2sockaddr(const char *addr,
+ struct sockaddr *sa,
+ krb5_socklen_t *sa_size,
+ int port)
+{
+ struct sockaddr_in tmp;
+
+ memset (&tmp, 0, sizeof(tmp));
+ tmp.sin_family = AF_INET;
+ tmp.sin_port = port;
+ tmp.sin_addr = *((const struct in_addr *)addr);
+ memcpy(sa, &tmp, min(sizeof(tmp), *sa_size));
+ *sa_size = sizeof(tmp);
+}
+
+static krb5_error_code
+ipv4_h_addr2addr (const char *addr,
+ krb5_address *a)
+{
+ unsigned char buf[4];
+
+ a->addr_type = KRB5_ADDRESS_INET;
+ memcpy(buf, addr, 4);
+ return krb5_data_copy(&a->address, buf, 4);
+}
+
+/*
+ * Are there any addresses that should be considered `uninteresting'?
+ */
+
+static krb5_boolean
+ipv4_uninteresting (const struct sockaddr *sa)
+{
+ const struct sockaddr_in *sin4 = (const struct sockaddr_in *)sa;
+
+ if (sin4->sin_addr.s_addr == INADDR_ANY)
+ return TRUE;
+
+ return FALSE;
+}
+
+static void
+ipv4_anyaddr (struct sockaddr *sa, krb5_socklen_t *sa_size, int port)
+{
+ struct sockaddr_in tmp;
+
+ memset (&tmp, 0, sizeof(tmp));
+ tmp.sin_family = AF_INET;
+ tmp.sin_port = port;
+ tmp.sin_addr.s_addr = INADDR_ANY;
+ memcpy(sa, &tmp, min(sizeof(tmp), *sa_size));
+ *sa_size = sizeof(tmp);
+}
+
+static int
+ipv4_print_addr (const krb5_address *addr, char *str, size_t len)
+{
+ struct in_addr ia;
+
+ memcpy (&ia, addr->address.data, 4);
+
+ return snprintf (str, len, "IPv4:%s", inet_ntoa(ia));
+}
+
+static int
+ipv4_parse_addr (krb5_context context, const char *address, krb5_address *addr)
+{
+ const char *p;
+ struct in_addr a;
+
+ p = strchr(address, ':');
+ if(p) {
+ p++;
+ if(strncasecmp(address, "ip:", p - address) != 0 &&
+ strncasecmp(address, "ip4:", p - address) != 0 &&
+ strncasecmp(address, "ipv4:", p - address) != 0 &&
+ strncasecmp(address, "inet:", p - address) != 0)
+ return -1;
+ } else
+ p = address;
+#ifdef HAVE_INET_ATON
+ if(inet_aton(p, &a) == 0)
+ return -1;
+#elif defined(HAVE_INET_ADDR)
+ a.s_addr = inet_addr(p);
+ if(a.s_addr == INADDR_NONE)
+ return -1;
+#else
+ return -1;
+#endif
+ addr->addr_type = KRB5_ADDRESS_INET;
+ if(krb5_data_alloc(&addr->address, 4) != 0)
+ return -1;
+ _krb5_put_int(addr->address.data, ntohl(a.s_addr), addr->address.length);
+ return 0;
+}
+
+static int
+ipv4_mask_boundary(krb5_context context, const krb5_address *inaddr,
+ unsigned long len, krb5_address *low, krb5_address *high)
+{
+ unsigned long ia;
+ u_int32_t l, h, m = 0xffffffff;
+
+ if (len > 32) {
+ krb5_set_error_string(context, "IPv4 prefix too large (%ld)", len);
+ return KRB5_PROG_ATYPE_NOSUPP;
+ }
+ m = m << (32 - len);
+
+ _krb5_get_int(inaddr->address.data, &ia, inaddr->address.length);
+
+ l = ia & m;
+ h = l | ~m;
+
+ low->addr_type = KRB5_ADDRESS_INET;
+ if(krb5_data_alloc(&low->address, 4) != 0)
+ return -1;
+ _krb5_put_int(low->address.data, l, low->address.length);
+
+ high->addr_type = KRB5_ADDRESS_INET;
+ if(krb5_data_alloc(&high->address, 4) != 0) {
+ krb5_free_address(context, low);
+ return -1;
+ }
+ _krb5_put_int(high->address.data, h, high->address.length);
+
+ return 0;
+}
+
+
+/*
+ * AF_INET6 - aka IPv6 implementation
+ */
+
+#ifdef HAVE_IPV6
+
+static krb5_error_code
+ipv6_sockaddr2addr (const struct sockaddr *sa, krb5_address *a)
+{
+ const struct sockaddr_in6 *sin6 = (const struct sockaddr_in6 *)sa;
+
+ if (IN6_IS_ADDR_V4MAPPED(&sin6->sin6_addr)) {
+ unsigned char buf[4];
+
+ a->addr_type = KRB5_ADDRESS_INET;
+#ifndef IN6_ADDR_V6_TO_V4
+#ifdef IN6_EXTRACT_V4ADDR
+#define IN6_ADDR_V6_TO_V4(x) (&IN6_EXTRACT_V4ADDR(x))
+#else
+#define IN6_ADDR_V6_TO_V4(x) ((const struct in_addr *)&(x)->s6_addr[12])
+#endif
+#endif
+ memcpy (buf, IN6_ADDR_V6_TO_V4(&sin6->sin6_addr), 4);
+ return krb5_data_copy(&a->address, buf, 4);
+ } else {
+ a->addr_type = KRB5_ADDRESS_INET6;
+ return krb5_data_copy(&a->address,
+ &sin6->sin6_addr,
+ sizeof(sin6->sin6_addr));
+ }
+}
+
+static krb5_error_code
+ipv6_sockaddr2port (const struct sockaddr *sa, int16_t *port)
+{
+ const struct sockaddr_in6 *sin6 = (const struct sockaddr_in6 *)sa;
+
+ *port = sin6->sin6_port;
+ return 0;
+}
+
+static void
+ipv6_addr2sockaddr (const krb5_address *a,
+ struct sockaddr *sa,
+ krb5_socklen_t *sa_size,
+ int port)
+{
+ struct sockaddr_in6 tmp;
+
+ memset (&tmp, 0, sizeof(tmp));
+ tmp.sin6_family = AF_INET6;
+ memcpy (&tmp.sin6_addr, a->address.data, sizeof(tmp.sin6_addr));
+ tmp.sin6_port = port;
+ memcpy(sa, &tmp, min(sizeof(tmp), *sa_size));
+ *sa_size = sizeof(tmp);
+}
+
+static void
+ipv6_h_addr2sockaddr(const char *addr,
+ struct sockaddr *sa,
+ krb5_socklen_t *sa_size,
+ int port)
+{
+ struct sockaddr_in6 tmp;
+
+ memset (&tmp, 0, sizeof(tmp));
+ tmp.sin6_family = AF_INET6;
+ tmp.sin6_port = port;
+ tmp.sin6_addr = *((const struct in6_addr *)addr);
+ memcpy(sa, &tmp, min(sizeof(tmp), *sa_size));
+ *sa_size = sizeof(tmp);
+}
+
+static krb5_error_code
+ipv6_h_addr2addr (const char *addr,
+ krb5_address *a)
+{
+ a->addr_type = KRB5_ADDRESS_INET6;
+ return krb5_data_copy(&a->address, addr, sizeof(struct in6_addr));
+}
+
+/*
+ *
+ */
+
+static krb5_boolean
+ipv6_uninteresting (const struct sockaddr *sa)
+{
+ const struct sockaddr_in6 *sin6 = (const struct sockaddr_in6 *)sa;
+ const struct in6_addr *in6 = (const struct in6_addr *)&sin6->sin6_addr;
+
+ return
+ IN6_IS_ADDR_LINKLOCAL(in6)
+ || IN6_IS_ADDR_V4COMPAT(in6);
+}
+
+static void
+ipv6_anyaddr (struct sockaddr *sa, krb5_socklen_t *sa_size, int port)
+{
+ struct sockaddr_in6 tmp;
+
+ memset (&tmp, 0, sizeof(tmp));
+ tmp.sin6_family = AF_INET6;
+ tmp.sin6_port = port;
+ tmp.sin6_addr = in6addr_any;
+ *sa_size = sizeof(tmp);
+}
+
+static int
+ipv6_print_addr (const krb5_address *addr, char *str, size_t len)
+{
+ char buf[128], buf2[3];
+#ifdef HAVE_INET_NTOP
+ if(inet_ntop(AF_INET6, addr->address.data, buf, sizeof(buf)) == NULL)
+#endif
+ {
+ /* XXX this is pretty ugly, but better than abort() */
+ int i;
+ unsigned char *p = addr->address.data;
+ buf[0] = '\0';
+ for(i = 0; i < addr->address.length; i++) {
+ snprintf(buf2, sizeof(buf2), "%02x", p[i]);
+ if(i > 0 && (i & 1) == 0)
+ strlcat(buf, ":", sizeof(buf));
+ strlcat(buf, buf2, sizeof(buf));
+ }
+ }
+ return snprintf(str, len, "IPv6:%s", buf);
+}
+
+static int
+ipv6_parse_addr (krb5_context context, const char *address, krb5_address *addr)
+{
+ int ret;
+ struct in6_addr in6;
+ const char *p;
+
+ p = strchr(address, ':');
+ if(p) {
+ p++;
+ if(strncasecmp(address, "ip6:", p - address) == 0 ||
+ strncasecmp(address, "ipv6:", p - address) == 0 ||
+ strncasecmp(address, "inet6:", p - address) == 0)
+ address = p;
+ }
+
+ ret = inet_pton(AF_INET6, address, &in6.s6_addr);
+ if(ret == 1) {
+ addr->addr_type = KRB5_ADDRESS_INET6;
+ ret = krb5_data_alloc(&addr->address, sizeof(in6.s6_addr));
+ if (ret)
+ return -1;
+ memcpy(addr->address.data, in6.s6_addr, sizeof(in6.s6_addr));
+ return 0;
+ }
+ return -1;
+}
+
+static int
+ipv6_mask_boundary(krb5_context context, const krb5_address *inaddr,
+ unsigned long len, krb5_address *low, krb5_address *high)
+{
+ struct in6_addr addr, laddr, haddr;
+ u_int32_t m;
+ int i, sub_len;
+
+ if (len > 128) {
+ krb5_set_error_string(context, "IPv6 prefix too large (%ld)", len);
+ return KRB5_PROG_ATYPE_NOSUPP;
+ }
+
+ if (inaddr->address.length != sizeof(addr)) {
+ krb5_set_error_string(context, "IPv6 addr bad length");
+ return KRB5_PROG_ATYPE_NOSUPP;
+ }
+
+ memcpy(&addr, inaddr->address.data, inaddr->address.length);
+
+ for (i = 0; i < 16; i++) {
+ sub_len = min(8, len);
+
+ m = 0xff << (8 - sub_len);
+
+ laddr.s6_addr[i] = addr.s6_addr[i] & m;
+ haddr.s6_addr[i] = (addr.s6_addr[i] & m) | ~m;
+
+ if (len > 8)
+ len -= 8;
+ else
+ len = 0;
+ }
+
+ low->addr_type = KRB5_ADDRESS_INET6;
+ if (krb5_data_alloc(&low->address, sizeof(laddr.s6_addr)) != 0)
+ return -1;
+ memcpy(low->address.data, laddr.s6_addr, sizeof(laddr.s6_addr));
+
+ high->addr_type = KRB5_ADDRESS_INET6;
+ if (krb5_data_alloc(&high->address, sizeof(haddr.s6_addr)) != 0) {
+ krb5_free_address(context, low);
+ return -1;
+ }
+ memcpy(high->address.data, haddr.s6_addr, sizeof(haddr.s6_addr));
+
+ return 0;
+}
+
+#endif /* IPv6 */
+
+/*
+ * table
+ */
+
+#define KRB5_ADDRESS_ARANGE (-100)
+
+struct arange {
+ krb5_address low;
+ krb5_address high;
+};
+
+static int
+arange_parse_addr (krb5_context context,
+ const char *address, krb5_address *addr)
+{
+ char buf[1024], *p;
+ krb5_address low0, high0;
+ struct arange *a;
+ krb5_error_code ret;
+
+ if(strncasecmp(address, "RANGE:", 6) != 0)
+ return -1;
+
+ address += 6;
+
+ p = strrchr(address, '/');
+ if (p) {
+ krb5_addresses addrmask;
+ char *q;
+ long num;
+
+ if (strlcpy(buf, address, sizeof(buf)) > sizeof(buf))
+ return -1;
+ buf[p - address] = '\0';
+ ret = krb5_parse_address(context, buf, &addrmask);
+ if (ret)
+ return ret;
+ if(addrmask.len != 1) {
+ krb5_free_addresses(context, &addrmask);
+ return -1;
+ }
+
+ address += p - address + 1;
+
+ num = strtol(address, &q, 10);
+ if (q == address || *q != '\0' || num < 0) {
+ krb5_free_addresses(context, &addrmask);
+ return -1;
+ }
+
+ ret = krb5_address_prefixlen_boundary(context, &addrmask.val[0], num,
+ &low0, &high0);
+ krb5_free_addresses(context, &addrmask);
+ if (ret)
+ return ret;
+
+ } else {
+ krb5_addresses low, high;
+
+ strsep_copy(&address, "-", buf, sizeof(buf));
+ ret = krb5_parse_address(context, buf, &low);
+ if(ret)
+ return ret;
+ if(low.len != 1) {
+ krb5_free_addresses(context, &low);
+ return -1;
+ }
+
+ strsep_copy(&address, "-", buf, sizeof(buf));
+ ret = krb5_parse_address(context, buf, &high);
+ if(ret) {
+ krb5_free_addresses(context, &low);
+ return ret;
+ }
+
+ if(high.len != 1 && high.val[0].addr_type != low.val[0].addr_type) {
+ krb5_free_addresses(context, &low);
+ krb5_free_addresses(context, &high);
+ return -1;
+ }
+
+ ret = krb5_copy_address(context, &high.val[0], &high0);
+ if (ret == 0) {
+ ret = krb5_copy_address(context, &low.val[0], &low0);
+ if (ret)
+ krb5_free_address(context, &high0);
+ }
+ krb5_free_addresses(context, &low);
+ krb5_free_addresses(context, &high);
+ if (ret)
+ return ret;
+ }
+
+ krb5_data_alloc(&addr->address, sizeof(*a));
+ addr->addr_type = KRB5_ADDRESS_ARANGE;
+ a = addr->address.data;
+
+ if(krb5_address_order(context, &low0, &high0) < 0) {
+ a->low = low0;
+ a->high = high0;
+ } else {
+ a->low = high0;
+ a->high = low0;
+ }
+ return 0;
+}
+
+static int
+arange_free (krb5_context context, krb5_address *addr)
+{
+ struct arange *a;
+ a = addr->address.data;
+ krb5_free_address(context, &a->low);
+ krb5_free_address(context, &a->high);
+ return 0;
+}
+
+
+static int
+arange_copy (krb5_context context, const krb5_address *inaddr,
+ krb5_address *outaddr)
+{
+ krb5_error_code ret;
+ struct arange *i, *o;
+
+ outaddr->addr_type = KRB5_ADDRESS_ARANGE;
+ ret = krb5_data_alloc(&outaddr->address, sizeof(*o));
+ if(ret)
+ return ret;
+ i = inaddr->address.data;
+ o = outaddr->address.data;
+ ret = krb5_copy_address(context, &i->low, &o->low);
+ if(ret) {
+ krb5_data_free(&outaddr->address);
+ return ret;
+ }
+ ret = krb5_copy_address(context, &i->high, &o->high);
+ if(ret) {
+ krb5_free_address(context, &o->low);
+ krb5_data_free(&outaddr->address);
+ return ret;
+ }
+ return 0;
+}
+
+static int
+arange_print_addr (const krb5_address *addr, char *str, size_t len)
+{
+ struct arange *a;
+ krb5_error_code ret;
+ size_t l, size, ret_len;
+
+ a = addr->address.data;
+
+ l = strlcpy(str, "RANGE:", len);
+ ret_len = l;
+ if (l > len)
+ l = len;
+ size = l;
+
+ ret = krb5_print_address (&a->low, str + size, len - size, &l);
+ if (ret)
+ return ret;
+ ret_len += l;
+ if (len - size > l)
+ size += l;
+ else
+ size = len;
+
+ l = strlcat(str + size, "-", len - size);
+ ret_len += l;
+ if (len - size > l)
+ size += l;
+ else
+ size = len;
+
+ ret = krb5_print_address (&a->high, str + size, len - size, &l);
+ if (ret)
+ return ret;
+ ret_len += l;
+
+ return ret_len;
+}
+
+static int
+arange_order_addr(krb5_context context,
+ const krb5_address *addr1,
+ const krb5_address *addr2)
+{
+ int tmp1, tmp2, sign;
+ struct arange *a;
+ const krb5_address *a2;
+
+ if(addr1->addr_type == KRB5_ADDRESS_ARANGE) {
+ a = addr1->address.data;
+ a2 = addr2;
+ sign = 1;
+ } else if(addr2->addr_type == KRB5_ADDRESS_ARANGE) {
+ a = addr2->address.data;
+ a2 = addr1;
+ sign = -1;
+ } else
+ abort();
+
+ if(a2->addr_type == KRB5_ADDRESS_ARANGE) {
+ struct arange *b = a2->address.data;
+ tmp1 = krb5_address_order(context, &a->low, &b->low);
+ if(tmp1 != 0)
+ return sign * tmp1;
+ return sign * krb5_address_order(context, &a->high, &b->high);
+ } else if(a2->addr_type == a->low.addr_type) {
+ tmp1 = krb5_address_order(context, &a->low, a2);
+ if(tmp1 > 0)
+ return sign;
+ tmp2 = krb5_address_order(context, &a->high, a2);
+ if(tmp2 < 0)
+ return -sign;
+ return 0;
+ } else {
+ return sign * (addr1->addr_type - addr2->addr_type);
+ }
+}
+
+static int
+addrport_print_addr (const krb5_address *addr, char *str, size_t len)
+{
+ krb5_error_code ret;
+ krb5_address addr1, addr2;
+ uint16_t port = 0;
+ size_t ret_len = 0, l, size = 0;
+ krb5_storage *sp;
+
+ sp = krb5_storage_from_data((krb5_data*)rk_UNCONST(&addr->address));
+ /* for totally obscure reasons, these are not in network byteorder */
+ krb5_storage_set_byteorder(sp, KRB5_STORAGE_BYTEORDER_LE);
+
+ krb5_storage_seek(sp, 2, SEEK_CUR); /* skip first two bytes */
+ krb5_ret_address(sp, &addr1);
+
+ krb5_storage_seek(sp, 2, SEEK_CUR); /* skip two bytes */
+ krb5_ret_address(sp, &addr2);
+ krb5_storage_free(sp);
+ if(addr2.addr_type == KRB5_ADDRESS_IPPORT && addr2.address.length == 2) {
+ unsigned long value;
+ _krb5_get_int(addr2.address.data, &value, 2);
+ port = value;
+ }
+ l = strlcpy(str, "ADDRPORT:", len);
+ ret_len += l;
+ if (len > l)
+ size += l;
+ else
+ size = len;
+
+ ret = krb5_print_address(&addr1, str + size, len - size, &l);
+ if (ret)
+ return ret;
+ ret_len += l;
+ if (len - size > l)
+ size += l;
+ else
+ size = len;
+
+ ret = snprintf(str + size, len - size, ",PORT=%u", port);
+ if (ret < 0)
+ return EINVAL;
+ ret_len += ret;
+ return ret_len;
+}
+
+static struct addr_operations at[] = {
+ {AF_INET, KRB5_ADDRESS_INET, sizeof(struct sockaddr_in),
+ ipv4_sockaddr2addr,
+ ipv4_sockaddr2port,
+ ipv4_addr2sockaddr,
+ ipv4_h_addr2sockaddr,
+ ipv4_h_addr2addr,
+ ipv4_uninteresting, ipv4_anyaddr, ipv4_print_addr, ipv4_parse_addr,
+ NULL, NULL, NULL, ipv4_mask_boundary },
+#ifdef HAVE_IPV6
+ {AF_INET6, KRB5_ADDRESS_INET6, sizeof(struct sockaddr_in6),
+ ipv6_sockaddr2addr,
+ ipv6_sockaddr2port,
+ ipv6_addr2sockaddr,
+ ipv6_h_addr2sockaddr,
+ ipv6_h_addr2addr,
+ ipv6_uninteresting, ipv6_anyaddr, ipv6_print_addr, ipv6_parse_addr,
+ NULL, NULL, NULL, ipv6_mask_boundary } ,
+#endif
+ {KRB5_ADDRESS_ADDRPORT, KRB5_ADDRESS_ADDRPORT, 0,
+ NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, addrport_print_addr, NULL, NULL, NULL, NULL },
+ /* fake address type */
+ {KRB5_ADDRESS_ARANGE, KRB5_ADDRESS_ARANGE, sizeof(struct arange),
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ arange_print_addr, arange_parse_addr,
+ arange_order_addr, arange_free, arange_copy }
+};
+
+static int num_addrs = sizeof(at) / sizeof(at[0]);
+
+static size_t max_sockaddr_size = 0;
+
+/*
+ * generic functions
+ */
+
+static struct addr_operations *
+find_af(int af)
+{
+ struct addr_operations *a;
+
+ for (a = at; a < at + num_addrs; ++a)
+ if (af == a->af)
+ return a;
+ return NULL;
+}
+
+static struct addr_operations *
+find_atype(int atype)
+{
+ struct addr_operations *a;
+
+ for (a = at; a < at + num_addrs; ++a)
+ if (atype == a->atype)
+ return a;
+ return NULL;
+}
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_sockaddr2address (krb5_context context,
+ const struct sockaddr *sa, krb5_address *addr)
+{
+ struct addr_operations *a = find_af(sa->sa_family);
+ if (a == NULL) {
+ krb5_set_error_string (context, "Address family %d not supported",
+ sa->sa_family);
+ return KRB5_PROG_ATYPE_NOSUPP;
+ }
+ return (*a->sockaddr2addr)(sa, addr);
+}
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_sockaddr2port (krb5_context context,
+ const struct sockaddr *sa, int16_t *port)
+{
+ struct addr_operations *a = find_af(sa->sa_family);
+ if (a == NULL) {
+ krb5_set_error_string (context, "Address family %d not supported",
+ sa->sa_family);
+ return KRB5_PROG_ATYPE_NOSUPP;
+ }
+ return (*a->sockaddr2port)(sa, port);
+}
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_addr2sockaddr (krb5_context context,
+ const krb5_address *addr,
+ struct sockaddr *sa,
+ krb5_socklen_t *sa_size,
+ int port)
+{
+ struct addr_operations *a = find_atype(addr->addr_type);
+
+ if (a == NULL) {
+ krb5_set_error_string (context, "Address type %d not supported",
+ addr->addr_type);
+ return KRB5_PROG_ATYPE_NOSUPP;
+ }
+ if (a->addr2sockaddr == NULL) {
+ krb5_set_error_string (context, "Can't convert address type %d to sockaddr",
+ addr->addr_type);
+ return KRB5_PROG_ATYPE_NOSUPP;
+ }
+ (*a->addr2sockaddr)(addr, sa, sa_size, port);
+ return 0;
+}
+
+size_t KRB5_LIB_FUNCTION
+krb5_max_sockaddr_size (void)
+{
+ if (max_sockaddr_size == 0) {
+ struct addr_operations *a;
+
+ for(a = at; a < at + num_addrs; ++a)
+ max_sockaddr_size = max(max_sockaddr_size, a->max_sockaddr_size);
+ }
+ return max_sockaddr_size;
+}
+
+krb5_boolean KRB5_LIB_FUNCTION
+krb5_sockaddr_uninteresting(const struct sockaddr *sa)
+{
+ struct addr_operations *a = find_af(sa->sa_family);
+ if (a == NULL || a->uninteresting == NULL)
+ return TRUE;
+ return (*a->uninteresting)(sa);
+}
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_h_addr2sockaddr (krb5_context context,
+ int af,
+ const char *addr, struct sockaddr *sa,
+ krb5_socklen_t *sa_size,
+ int port)
+{
+ struct addr_operations *a = find_af(af);
+ if (a == NULL) {
+ krb5_set_error_string (context, "Address family %d not supported", af);
+ return KRB5_PROG_ATYPE_NOSUPP;
+ }
+ (*a->h_addr2sockaddr)(addr, sa, sa_size, port);
+ return 0;
+}
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_h_addr2addr (krb5_context context,
+ int af,
+ const char *haddr, krb5_address *addr)
+{
+ struct addr_operations *a = find_af(af);
+ if (a == NULL) {
+ krb5_set_error_string (context, "Address family %d not supported", af);
+ return KRB5_PROG_ATYPE_NOSUPP;
+ }
+ return (*a->h_addr2addr)(haddr, addr);
+}
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_anyaddr (krb5_context context,
+ int af,
+ struct sockaddr *sa,
+ krb5_socklen_t *sa_size,
+ int port)
+{
+ struct addr_operations *a = find_af (af);
+
+ if (a == NULL) {
+ krb5_set_error_string (context, "Address family %d not supported", af);
+ return KRB5_PROG_ATYPE_NOSUPP;
+ }
+
+ (*a->anyaddr)(sa, sa_size, port);
+ return 0;
+}
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_print_address (const krb5_address *addr,
+ char *str, size_t len, size_t *ret_len)
+{
+ struct addr_operations *a = find_atype(addr->addr_type);
+ int ret;
+
+ if (a == NULL || a->print_addr == NULL) {
+ char *s;
+ int l;
+ int i;
+
+ s = str;
+ l = snprintf(s, len, "TYPE_%d:", addr->addr_type);
+ if (l < 0 || l >= len)
+ return EINVAL;
+ s += l;
+ len -= l;
+ for(i = 0; i < addr->address.length; i++) {
+ l = snprintf(s, len, "%02x", ((char*)addr->address.data)[i]);
+ if (l < 0 || l >= len)
+ return EINVAL;
+ len -= l;
+ s += l;
+ }
+ if(ret_len != NULL)
+ *ret_len = s - str;
+ return 0;
+ }
+ ret = (*a->print_addr)(addr, str, len);
+ if (ret < 0)
+ return EINVAL;
+ if(ret_len != NULL)
+ *ret_len = ret;
+ return 0;
+}
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_parse_address(krb5_context context,
+ const char *string,
+ krb5_addresses *addresses)
+{
+ int i, n;
+ struct addrinfo *ai, *a;
+ int error;
+ int save_errno;
+
+ for(i = 0; i < num_addrs; i++) {
+ if(at[i].parse_addr) {
+ krb5_address addr;
+ if((*at[i].parse_addr)(context, string, &addr) == 0) {
+ ALLOC_SEQ(addresses, 1);
+ addresses->val[0] = addr;
+ return 0;
+ }
+ }
+ }
+
+ error = getaddrinfo (string, NULL, NULL, &ai);
+ if (error) {
+ save_errno = errno;
+ krb5_set_error_string (context, "%s: %s", string, gai_strerror(error));
+ return krb5_eai_to_heim_errno(error, save_errno);
+ }
+
+ n = 0;
+ for (a = ai; a != NULL; a = a->ai_next)
+ ++n;
+
+ ALLOC_SEQ(addresses, n);
+ if (addresses->val == NULL) {
+ krb5_set_error_string(context, "malloc: out of memory");
+ freeaddrinfo(ai);
+ return ENOMEM;
+ }
+
+ addresses->len = 0;
+ for (a = ai, i = 0; a != NULL; a = a->ai_next) {
+ if (krb5_sockaddr2address (context, ai->ai_addr, &addresses->val[i]))
+ continue;
+ if(krb5_address_search(context, &addresses->val[i], addresses))
+ continue;
+ addresses->len = i;
+ i++;
+ }
+ freeaddrinfo (ai);
+ return 0;
+}
+
+int KRB5_LIB_FUNCTION
+krb5_address_order(krb5_context context,
+ const krb5_address *addr1,
+ const krb5_address *addr2)
+{
+ /* this sucks; what if both addresses have order functions, which
+ should we call? this works for now, though */
+ struct addr_operations *a;
+ a = find_atype(addr1->addr_type);
+ if(a == NULL) {
+ krb5_set_error_string (context, "Address family %d not supported",
+ addr1->addr_type);
+ return KRB5_PROG_ATYPE_NOSUPP;
+ }
+ if(a->order_addr != NULL)
+ return (*a->order_addr)(context, addr1, addr2);
+ a = find_atype(addr2->addr_type);
+ if(a == NULL) {
+ krb5_set_error_string (context, "Address family %d not supported",
+ addr2->addr_type);
+ return KRB5_PROG_ATYPE_NOSUPP;
+ }
+ if(a->order_addr != NULL)
+ return (*a->order_addr)(context, addr1, addr2);
+
+ if(addr1->addr_type != addr2->addr_type)
+ return addr1->addr_type - addr2->addr_type;
+ if(addr1->address.length != addr2->address.length)
+ return addr1->address.length - addr2->address.length;
+ return memcmp (addr1->address.data,
+ addr2->address.data,
+ addr1->address.length);
+}
+
+krb5_boolean KRB5_LIB_FUNCTION
+krb5_address_compare(krb5_context context,
+ const krb5_address *addr1,
+ const krb5_address *addr2)
+{
+ return krb5_address_order (context, addr1, addr2) == 0;
+}
+
+krb5_boolean KRB5_LIB_FUNCTION
+krb5_address_search(krb5_context context,
+ const krb5_address *addr,
+ const krb5_addresses *addrlist)
+{
+ int i;
+
+ for (i = 0; i < addrlist->len; ++i)
+ if (krb5_address_compare (context, addr, &addrlist->val[i]))
+ return TRUE;
+ return FALSE;
+}
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_free_address(krb5_context context,
+ krb5_address *address)
+{
+ struct addr_operations *a = find_atype (address->addr_type);
+ if(a != NULL && a->free_addr != NULL)
+ return (*a->free_addr)(context, address);
+ krb5_data_free (&address->address);
+ memset(address, 0, sizeof(*address));
+ return 0;
+}
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_free_addresses(krb5_context context,
+ krb5_addresses *addresses)
+{
+ int i;
+ for(i = 0; i < addresses->len; i++)
+ krb5_free_address(context, &addresses->val[i]);
+ free(addresses->val);
+ return 0;
+}
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_copy_address(krb5_context context,
+ const krb5_address *inaddr,
+ krb5_address *outaddr)
+{
+ struct addr_operations *a = find_af (inaddr->addr_type);
+ if(a != NULL && a->copy_addr != NULL)
+ return (*a->copy_addr)(context, inaddr, outaddr);
+ return copy_HostAddress(inaddr, outaddr);
+}
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_copy_addresses(krb5_context context,
+ const krb5_addresses *inaddr,
+ krb5_addresses *outaddr)
+{
+ int i;
+ ALLOC_SEQ(outaddr, inaddr->len);
+ if(inaddr->len > 0 && outaddr->val == NULL)
+ return ENOMEM;
+ for(i = 0; i < inaddr->len; i++)
+ krb5_copy_address(context, &inaddr->val[i], &outaddr->val[i]);
+ return 0;
+}
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_append_addresses(krb5_context context,
+ krb5_addresses *dest,
+ const krb5_addresses *source)
+{
+ krb5_address *tmp;
+ krb5_error_code ret;
+ int i;
+ if(source->len > 0) {
+ tmp = realloc(dest->val, (dest->len + source->len) * sizeof(*tmp));
+ if(tmp == NULL) {
+ krb5_set_error_string(context, "realloc: out of memory");
+ return ENOMEM;
+ }
+ dest->val = tmp;
+ for(i = 0; i < source->len; i++) {
+ /* skip duplicates */
+ if(krb5_address_search(context, &source->val[i], dest))
+ continue;
+ ret = krb5_copy_address(context,
+ &source->val[i],
+ &dest->val[dest->len]);
+ if(ret)
+ return ret;
+ dest->len++;
+ }
+ }
+ return 0;
+}
+
+/*
+ * Create an address of type KRB5_ADDRESS_ADDRPORT from (addr, port)
+ */
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_make_addrport (krb5_context context,
+ krb5_address **res, const krb5_address *addr, int16_t port)
+{
+ krb5_error_code ret;
+ size_t len = addr->address.length + 2 + 4 * 4;
+ u_char *p;
+
+ *res = malloc (sizeof(**res));
+ if (*res == NULL) {
+ krb5_set_error_string(context, "malloc: out of memory");
+ return ENOMEM;
+ }
+ (*res)->addr_type = KRB5_ADDRESS_ADDRPORT;
+ ret = krb5_data_alloc (&(*res)->address, len);
+ if (ret) {
+ krb5_set_error_string(context, "malloc: out of memory");
+ free (*res);
+ return ret;
+ }
+ p = (*res)->address.data;
+ *p++ = 0;
+ *p++ = 0;
+ *p++ = (addr->addr_type ) & 0xFF;
+ *p++ = (addr->addr_type >> 8) & 0xFF;
+
+ *p++ = (addr->address.length ) & 0xFF;
+ *p++ = (addr->address.length >> 8) & 0xFF;
+ *p++ = (addr->address.length >> 16) & 0xFF;
+ *p++ = (addr->address.length >> 24) & 0xFF;
+
+ memcpy (p, addr->address.data, addr->address.length);
+ p += addr->address.length;
+
+ *p++ = 0;
+ *p++ = 0;
+ *p++ = (KRB5_ADDRESS_IPPORT ) & 0xFF;
+ *p++ = (KRB5_ADDRESS_IPPORT >> 8) & 0xFF;
+
+ *p++ = (2 ) & 0xFF;
+ *p++ = (2 >> 8) & 0xFF;
+ *p++ = (2 >> 16) & 0xFF;
+ *p++ = (2 >> 24) & 0xFF;
+
+ memcpy (p, &port, 2);
+ p += 2;
+
+ return 0;
+}
+
+/*
+ * Calculate the boundary addresses of `inaddr'/`prefixlen' and store
+ * them in `low' and `high'.
+ */
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_address_prefixlen_boundary(krb5_context context,
+ const krb5_address *inaddr,
+ unsigned long prefixlen,
+ krb5_address *low,
+ krb5_address *high)
+{
+ struct addr_operations *a = find_atype (inaddr->addr_type);
+ if(a != NULL && a->mask_boundary != NULL)
+ return (*a->mask_boundary)(context, inaddr, prefixlen, low, high);
+ krb5_set_error_string(context, "Address family %d doesn't support "
+ "address mask operation", inaddr->addr_type);
+ return KRB5_PROG_ATYPE_NOSUPP;
+}
diff --git a/source4/heimdal/lib/krb5/appdefault.c b/source4/heimdal/lib/krb5/appdefault.c
new file mode 100644
index 0000000000..03fa933b6f
--- /dev/null
+++ b/source4/heimdal/lib/krb5/appdefault.c
@@ -0,0 +1,142 @@
+/*
+ * Copyright (c) 2000 - 2001 Kungliga Tekniska Högskolan
+ * (Royal Institute of Technology, Stockholm, Sweden).
+ * 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"
+
+RCSID("$Id: appdefault.c,v 1.10 2005/01/05 05:40:59 lukeh Exp $");
+
+void KRB5_LIB_FUNCTION
+krb5_appdefault_boolean(krb5_context context, const char *appname,
+ krb5_const_realm realm, const char *option,
+ krb5_boolean def_val, krb5_boolean *ret_val)
+{
+
+ if(appname == NULL)
+ appname = getprogname();
+
+ def_val = krb5_config_get_bool_default(context, NULL, def_val,
+ "libdefaults", option, NULL);
+ if(realm != NULL)
+ def_val = krb5_config_get_bool_default(context, NULL, def_val,
+ "realms", realm, option, NULL);
+
+ def_val = krb5_config_get_bool_default(context, NULL, def_val,
+ "appdefaults",
+ option,
+ NULL);
+ if(realm != NULL)
+ def_val = krb5_config_get_bool_default(context, NULL, def_val,
+ "appdefaults",
+ realm,
+ option,
+ NULL);
+ if(appname != NULL) {
+ def_val = krb5_config_get_bool_default(context, NULL, def_val,
+ "appdefaults",
+ appname,
+ option,
+ NULL);
+ if(realm != NULL)
+ def_val = krb5_config_get_bool_default(context, NULL, def_val,
+ "appdefaults",
+ appname,
+ realm,
+ option,
+ NULL);
+ }
+ *ret_val = def_val;
+}
+
+void KRB5_LIB_FUNCTION
+krb5_appdefault_string(krb5_context context, const char *appname,
+ krb5_const_realm realm, const char *option,
+ const char *def_val, char **ret_val)
+{
+ if(appname == NULL)
+ appname = getprogname();
+
+ def_val = krb5_config_get_string_default(context, NULL, def_val,
+ "libdefaults", option, NULL);
+ if(realm != NULL)
+ def_val = krb5_config_get_string_default(context, NULL, def_val,
+ "realms", realm, option, NULL);
+
+ def_val = krb5_config_get_string_default(context, NULL, def_val,
+ "appdefaults",
+ option,
+ NULL);
+ if(realm != NULL)
+ def_val = krb5_config_get_string_default(context, NULL, def_val,
+ "appdefaults",
+ realm,
+ option,
+ NULL);
+ if(appname != NULL) {
+ def_val = krb5_config_get_string_default(context, NULL, def_val,
+ "appdefaults",
+ appname,
+ option,
+ NULL);
+ if(realm != NULL)
+ def_val = krb5_config_get_string_default(context, NULL, def_val,
+ "appdefaults",
+ appname,
+ realm,
+ option,
+ NULL);
+ }
+ if(def_val != NULL)
+ *ret_val = strdup(def_val);
+ else
+ *ret_val = NULL;
+}
+
+void KRB5_LIB_FUNCTION
+krb5_appdefault_time(krb5_context context, const char *appname,
+ krb5_const_realm realm, const char *option,
+ time_t def_val, time_t *ret_val)
+{
+ krb5_deltat t;
+ char *val;
+
+ krb5_appdefault_string(context, appname, realm, option, NULL, &val);
+ if (val == NULL) {
+ *ret_val = def_val;
+ return;
+ }
+ if (krb5_string_to_deltat(val, &t))
+ *ret_val = def_val;
+ else
+ *ret_val = t;
+ free(val);
+}
diff --git a/source4/heimdal/lib/krb5/asn1_glue.c b/source4/heimdal/lib/krb5/asn1_glue.c
new file mode 100644
index 0000000000..01b5d3ee44
--- /dev/null
+++ b/source4/heimdal/lib/krb5/asn1_glue.c
@@ -0,0 +1,59 @@
+/*
+ * Copyright (c) 1997 Kungliga Tekniska Högskolan
+ * (Royal Institute of Technology, Stockholm, Sweden).
+ * 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"
+
+RCSID("$Id: asn1_glue.c,v 1.9 2004/12/29 18:54:15 lha Exp $");
+
+krb5_error_code KRB5_LIB_FUNCTION
+_krb5_principal2principalname (PrincipalName *p,
+ const krb5_principal from)
+{
+ return copy_PrincipalName(&from->name, p);
+}
+
+krb5_error_code KRB5_LIB_FUNCTION
+_krb5_principalname2krb5_principal (krb5_principal *principal,
+ const PrincipalName from,
+ const Realm realm)
+{
+ krb5_principal p = malloc(sizeof(*p));
+ copy_PrincipalName(&from, &p->name);
+ p->realm = strdup(realm);
+ *principal = p;
+ return 0;
+}
diff --git a/source4/heimdal/lib/krb5/auth_context.c b/source4/heimdal/lib/krb5/auth_context.c
new file mode 100644
index 0000000000..b8ce65d9a5
--- /dev/null
+++ b/source4/heimdal/lib/krb5/auth_context.c
@@ -0,0 +1,517 @@
+/*
+ * Copyright (c) 1997 - 2002 Kungliga Tekniska Högskolan
+ * (Royal Institute of Technology, Stockholm, Sweden).
+ * 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"
+
+RCSID("$Id: auth_context.c,v 1.62 2005/01/05 02:34:08 lukeh Exp $");
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_auth_con_init(krb5_context context,
+ krb5_auth_context *auth_context)
+{
+ krb5_auth_context p;
+
+ ALLOC(p, 1);
+ if(!p) {
+ krb5_set_error_string(context, "malloc: out of memory");
+ return ENOMEM;
+ }
+ memset(p, 0, sizeof(*p));
+ ALLOC(p->authenticator, 1);
+ if (!p->authenticator) {
+ krb5_set_error_string(context, "malloc: out of memory");
+ free(p);
+ return ENOMEM;
+ }
+ memset (p->authenticator, 0, sizeof(*p->authenticator));
+ p->flags = KRB5_AUTH_CONTEXT_DO_TIME;
+
+ p->local_address = NULL;
+ p->remote_address = NULL;
+ p->local_port = 0;
+ p->remote_port = 0;
+ p->keytype = KEYTYPE_NULL;
+ p->cksumtype = CKSUMTYPE_NONE;
+ *auth_context = p;
+ return 0;
+}
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_auth_con_free(krb5_context context,
+ krb5_auth_context auth_context)
+{
+ if (auth_context != NULL) {
+ krb5_free_authenticator(context, &auth_context->authenticator);
+ if(auth_context->local_address){
+ free_HostAddress(auth_context->local_address);
+ free(auth_context->local_address);
+ }
+ if(auth_context->remote_address){
+ free_HostAddress(auth_context->remote_address);
+ free(auth_context->remote_address);
+ }
+ krb5_free_keyblock(context, auth_context->keyblock);
+ krb5_free_keyblock(context, auth_context->remote_subkey);
+ krb5_free_keyblock(context, auth_context->local_subkey);
+ free (auth_context);
+ }
+ return 0;
+}
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_auth_con_setflags(krb5_context context,
+ krb5_auth_context auth_context,
+ int32_t flags)
+{
+ auth_context->flags = flags;
+ return 0;
+}
+
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_auth_con_getflags(krb5_context context,
+ krb5_auth_context auth_context,
+ int32_t *flags)
+{
+ *flags = auth_context->flags;
+ return 0;
+}
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_auth_con_addflags(krb5_context context,
+ krb5_auth_context auth_context,
+ int32_t addflags,
+ int32_t *flags)
+{
+ if (flags)
+ *flags = auth_context->flags;
+ auth_context->flags |= addflags;
+ return 0;
+}
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_auth_con_removeflags(krb5_context context,
+ krb5_auth_context auth_context,
+ int32_t removeflags,
+ int32_t *flags)
+{
+ if (flags)
+ *flags = auth_context->flags;
+ auth_context->flags &= ~removeflags;
+ return 0;
+}
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_auth_con_setaddrs(krb5_context context,
+ krb5_auth_context auth_context,
+ krb5_address *local_addr,
+ krb5_address *remote_addr)
+{
+ if (local_addr) {
+ if (auth_context->local_address)
+ krb5_free_address (context, auth_context->local_address);
+ else
+ auth_context->local_address = malloc(sizeof(krb5_address));
+ krb5_copy_address(context, local_addr, auth_context->local_address);
+ }
+ if (remote_addr) {
+ if (auth_context->remote_address)
+ krb5_free_address (context, auth_context->remote_address);
+ else
+ auth_context->remote_address = malloc(sizeof(krb5_address));
+ krb5_copy_address(context, remote_addr, auth_context->remote_address);
+ }
+ return 0;
+}
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_auth_con_genaddrs(krb5_context context,
+ krb5_auth_context auth_context,
+ int fd, int flags)
+{
+ krb5_error_code ret;
+ krb5_address local_k_address, remote_k_address;
+ krb5_address *lptr = NULL, *rptr = NULL;
+ struct sockaddr_storage ss_local, ss_remote;
+ struct sockaddr *local = (struct sockaddr *)&ss_local;
+ struct sockaddr *remote = (struct sockaddr *)&ss_remote;
+ socklen_t len;
+
+ if(flags & KRB5_AUTH_CONTEXT_GENERATE_LOCAL_ADDR) {
+ if (auth_context->local_address == NULL) {
+ len = sizeof(ss_local);
+ if(getsockname(fd, local, &len) < 0) {
+ ret = errno;
+ krb5_set_error_string (context, "getsockname: %s",
+ strerror(ret));
+ goto out;
+ }
+ ret = krb5_sockaddr2address (context, local, &local_k_address);
+ if(ret) goto out;
+ if(flags & KRB5_AUTH_CONTEXT_GENERATE_LOCAL_FULL_ADDR) {
+ krb5_sockaddr2port (context, local, &auth_context->local_port);
+ } else
+ auth_context->local_port = 0;
+ lptr = &local_k_address;
+ }
+ }
+ if(flags & KRB5_AUTH_CONTEXT_GENERATE_REMOTE_ADDR) {
+ len = sizeof(ss_remote);
+ if(getpeername(fd, remote, &len) < 0) {
+ ret = errno;
+ krb5_set_error_string (context, "getpeername: %s", strerror(ret));
+ goto out;
+ }
+ ret = krb5_sockaddr2address (context, remote, &remote_k_address);
+ if(ret) goto out;
+ if(flags & KRB5_AUTH_CONTEXT_GENERATE_REMOTE_FULL_ADDR) {
+ krb5_sockaddr2port (context, remote, &auth_context->remote_port);
+ } else
+ auth_context->remote_port = 0;
+ rptr = &remote_k_address;
+ }
+ ret = krb5_auth_con_setaddrs (context,
+ auth_context,
+ lptr,
+ rptr);
+ out:
+ if (lptr)
+ krb5_free_address (context, lptr);
+ if (rptr)
+ krb5_free_address (context, rptr);
+ return ret;
+
+}
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_auth_con_setaddrs_from_fd (krb5_context context,
+ krb5_auth_context auth_context,
+ void *p_fd)
+{
+ int fd = *(int*)p_fd;
+ int flags = 0;
+ if(auth_context->local_address == NULL)
+ flags |= KRB5_AUTH_CONTEXT_GENERATE_LOCAL_FULL_ADDR;
+ if(auth_context->remote_address == NULL)
+ flags |= KRB5_AUTH_CONTEXT_GENERATE_REMOTE_FULL_ADDR;
+ return krb5_auth_con_genaddrs(context, auth_context, fd, flags);
+}
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_auth_con_getaddrs(krb5_context context,
+ krb5_auth_context auth_context,
+ krb5_address **local_addr,
+ krb5_address **remote_addr)
+{
+ if(*local_addr)
+ krb5_free_address (context, *local_addr);
+ *local_addr = malloc (sizeof(**local_addr));
+ if (*local_addr == NULL) {
+ krb5_set_error_string(context, "malloc: out of memory");
+ return ENOMEM;
+ }
+ krb5_copy_address(context,
+ auth_context->local_address,
+ *local_addr);
+
+ if(*remote_addr)
+ krb5_free_address (context, *remote_addr);
+ *remote_addr = malloc (sizeof(**remote_addr));
+ if (*remote_addr == NULL) {
+ krb5_set_error_string(context, "malloc: out of memory");
+ krb5_free_address (context, *local_addr);
+ *local_addr = NULL;
+ return ENOMEM;
+ }
+ krb5_copy_address(context,
+ auth_context->remote_address,
+ *remote_addr);
+ return 0;
+}
+
+static krb5_error_code
+copy_key(krb5_context context,
+ krb5_keyblock *in,
+ krb5_keyblock **out)
+{
+ if(in)
+ return krb5_copy_keyblock(context, in, out);
+ *out = NULL; /* is this right? */
+ return 0;
+}
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_auth_con_getkey(krb5_context context,
+ krb5_auth_context auth_context,
+ krb5_keyblock **keyblock)
+{
+ return copy_key(context, auth_context->keyblock, keyblock);
+}
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_auth_con_getlocalsubkey(krb5_context context,
+ krb5_auth_context auth_context,
+ krb5_keyblock **keyblock)
+{
+ return copy_key(context, auth_context->local_subkey, keyblock);
+}
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_auth_con_getremotesubkey(krb5_context context,
+ krb5_auth_context auth_context,
+ krb5_keyblock **keyblock)
+{
+ return copy_key(context, auth_context->remote_subkey, keyblock);
+}
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_auth_con_setkey(krb5_context context,
+ krb5_auth_context auth_context,
+ krb5_keyblock *keyblock)
+{
+ if(auth_context->keyblock)
+ krb5_free_keyblock(context, auth_context->keyblock);
+ return copy_key(context, keyblock, &auth_context->keyblock);
+}
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_auth_con_setlocalsubkey(krb5_context context,
+ krb5_auth_context auth_context,
+ krb5_keyblock *keyblock)
+{
+ if(auth_context->local_subkey)
+ krb5_free_keyblock(context, auth_context->local_subkey);
+ return copy_key(context, keyblock, &auth_context->local_subkey);
+}
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_auth_con_generatelocalsubkey(krb5_context context,
+ krb5_auth_context auth_context,
+ krb5_keyblock *key)
+{
+ krb5_error_code ret;
+ krb5_keyblock *subkey;
+
+ ret = krb5_generate_subkey_extended (context, key,
+ auth_context->keytype,
+ &subkey);
+ if(ret)
+ return ret;
+ if(auth_context->local_subkey)
+ krb5_free_keyblock(context, auth_context->local_subkey);
+ auth_context->local_subkey = subkey;
+ return 0;
+}
+
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_auth_con_setremotesubkey(krb5_context context,
+ krb5_auth_context auth_context,
+ krb5_keyblock *keyblock)
+{
+ if(auth_context->remote_subkey)
+ krb5_free_keyblock(context, auth_context->remote_subkey);
+ return copy_key(context, keyblock, &auth_context->remote_subkey);
+}
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_auth_con_setcksumtype(krb5_context context,
+ krb5_auth_context auth_context,
+ krb5_cksumtype cksumtype)
+{
+ auth_context->cksumtype = cksumtype;
+ return 0;
+}
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_auth_con_getcksumtype(krb5_context context,
+ krb5_auth_context auth_context,
+ krb5_cksumtype *cksumtype)
+{
+ *cksumtype = auth_context->cksumtype;
+ return 0;
+}
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_auth_con_setkeytype (krb5_context context,
+ krb5_auth_context auth_context,
+ krb5_keytype keytype)
+{
+ auth_context->keytype = keytype;
+ return 0;
+}
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_auth_con_getkeytype (krb5_context context,
+ krb5_auth_context auth_context,
+ krb5_keytype *keytype)
+{
+ *keytype = auth_context->keytype;
+ return 0;
+}
+
+#if 0
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_auth_con_setenctype(krb5_context context,
+ krb5_auth_context auth_context,
+ krb5_enctype etype)
+{
+ if(auth_context->keyblock)
+ krb5_free_keyblock(context, auth_context->keyblock);
+ ALLOC(auth_context->keyblock, 1);
+ if(auth_context->keyblock == NULL)
+ return ENOMEM;
+ auth_context->keyblock->keytype = etype;
+ return 0;
+}
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_auth_con_getenctype(krb5_context context,
+ krb5_auth_context auth_context,
+ krb5_enctype *etype)
+{
+ krb5_abortx(context, "unimplemented krb5_auth_getenctype called");
+}
+#endif
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_auth_con_getlocalseqnumber(krb5_context context,
+ krb5_auth_context auth_context,
+ int32_t *seqnumber)
+{
+ *seqnumber = auth_context->local_seqnumber;
+ return 0;
+}
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_auth_con_setlocalseqnumber (krb5_context context,
+ krb5_auth_context auth_context,
+ int32_t seqnumber)
+{
+ auth_context->local_seqnumber = seqnumber;
+ return 0;
+}
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_auth_getremoteseqnumber(krb5_context context,
+ krb5_auth_context auth_context,
+ int32_t *seqnumber)
+{
+ *seqnumber = auth_context->remote_seqnumber;
+ return 0;
+}
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_auth_con_setremoteseqnumber (krb5_context context,
+ krb5_auth_context auth_context,
+ int32_t seqnumber)
+{
+ auth_context->remote_seqnumber = seqnumber;
+ return 0;
+}
+
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_auth_con_getauthenticator(krb5_context context,
+ krb5_auth_context auth_context,
+ krb5_authenticator *authenticator)
+{
+ *authenticator = malloc(sizeof(**authenticator));
+ if (*authenticator == NULL) {
+ krb5_set_error_string(context, "malloc: out of memory");
+ return ENOMEM;
+ }
+
+ copy_Authenticator(auth_context->authenticator,
+ *authenticator);
+ return 0;
+}
+
+
+void KRB5_LIB_FUNCTION
+krb5_free_authenticator(krb5_context context,
+ krb5_authenticator *authenticator)
+{
+ free_Authenticator (*authenticator);
+ free (*authenticator);
+ *authenticator = NULL;
+}
+
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_auth_con_setuserkey(krb5_context context,
+ krb5_auth_context auth_context,
+ krb5_keyblock *keyblock)
+{
+ if(auth_context->keyblock)
+ krb5_free_keyblock(context, auth_context->keyblock);
+ return krb5_copy_keyblock(context, keyblock, &auth_context->keyblock);
+}
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_auth_con_getrcache(krb5_context context,
+ krb5_auth_context auth_context,
+ krb5_rcache *rcache)
+{
+ *rcache = auth_context->rcache;
+ return 0;
+}
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_auth_con_setrcache(krb5_context context,
+ krb5_auth_context auth_context,
+ krb5_rcache rcache)
+{
+ auth_context->rcache = rcache;
+ return 0;
+}
+
+#if 0 /* not implemented */
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_auth_con_initivector(krb5_context context,
+ krb5_auth_context auth_context)
+{
+ krb5_abortx(context, "unimplemented krb5_auth_con_initivector called");
+}
+
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_auth_con_setivector(krb5_context context,
+ krb5_auth_context auth_context,
+ krb5_pointer ivector)
+{
+ krb5_abortx(context, "unimplemented krb5_auth_con_setivector called");
+}
+
+#endif /* not implemented */
diff --git a/source4/heimdal/lib/krb5/build_ap_req.c b/source4/heimdal/lib/krb5/build_ap_req.c
new file mode 100644
index 0000000000..e11744cc3a
--- /dev/null
+++ b/source4/heimdal/lib/krb5/build_ap_req.c
@@ -0,0 +1,76 @@
+/*
+ * Copyright (c) 1997 - 2002 Kungliga Tekniska Högskolan
+ * (Royal Institute of Technology, Stockholm, Sweden).
+ * 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>
+
+RCSID("$Id: build_ap_req.c,v 1.20 2004/05/25 21:18:17 lha Exp $");
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_build_ap_req (krb5_context context,
+ krb5_enctype enctype,
+ krb5_creds *cred,
+ krb5_flags ap_options,
+ krb5_data authenticator,
+ krb5_data *retdata)
+{
+ krb5_error_code ret = 0;
+ AP_REQ ap;
+ Ticket t;
+ size_t len;
+
+ ap.pvno = 5;
+ ap.msg_type = krb_ap_req;
+ memset(&ap.ap_options, 0, sizeof(ap.ap_options));
+ ap.ap_options.use_session_key = (ap_options & AP_OPTS_USE_SESSION_KEY) > 0;
+ ap.ap_options.mutual_required = (ap_options & AP_OPTS_MUTUAL_REQUIRED) > 0;
+
+ ap.ticket.tkt_vno = 5;
+ copy_Realm(&cred->server->realm, &ap.ticket.realm);
+ copy_PrincipalName(&cred->server->name, &ap.ticket.sname);
+
+ decode_Ticket(cred->ticket.data, cred->ticket.length, &t, &len);
+ copy_EncryptedData(&t.enc_part, &ap.ticket.enc_part);
+ free_Ticket(&t);
+
+ ap.authenticator.etype = enctype;
+ ap.authenticator.kvno = NULL;
+ ap.authenticator.cipher = authenticator;
+
+ ASN1_MALLOC_ENCODE(AP_REQ, retdata->data, retdata->length,
+ &ap, &len, ret);
+ if(ret == 0 && retdata->length != len)
+ krb5_abortx(context, "internal error in ASN.1 encoder");
+ free_AP_REQ(&ap);
+ return ret;
+
+}
diff --git a/source4/heimdal/lib/krb5/build_auth.c b/source4/heimdal/lib/krb5/build_auth.c
new file mode 100644
index 0000000000..1c38721b02
--- /dev/null
+++ b/source4/heimdal/lib/krb5/build_auth.c
@@ -0,0 +1,205 @@
+/*
+ * Copyright (c) 1997 - 2003 Kungliga Tekniska Högskolan
+ * (Royal Institute of Technology, Stockholm, Sweden).
+ * 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>
+
+RCSID("$Id: build_auth.c,v 1.42 2005/01/05 02:34:53 lukeh Exp $");
+
+static krb5_error_code
+make_etypelist(krb5_context context,
+ krb5_authdata **auth_data)
+{
+ EtypeList etypes;
+ krb5_error_code ret;
+ krb5_authdata ad;
+ u_char *buf;
+ size_t len;
+ size_t buf_size;
+
+ ret = krb5_init_etype(context, &etypes.len, &etypes.val, NULL);
+ if (ret)
+ return ret;
+
+ ASN1_MALLOC_ENCODE(EtypeList, buf, buf_size, &etypes, &len, ret);
+ if (ret) {
+ free_EtypeList(&etypes);
+ return ret;
+ }
+ if(buf_size != len)
+ krb5_abortx(context, "internal error in ASN.1 encoder");
+ free_EtypeList(&etypes);
+
+ ALLOC_SEQ(&ad, 1);
+ if (ad.val == NULL) {
+ free(buf);
+ krb5_set_error_string(context, "malloc: out of memory");
+ return ENOMEM;
+ }
+
+ ad.val[0].ad_type = KRB5_AUTHDATA_GSS_API_ETYPE_NEGOTIATION;
+ ad.val[0].ad_data.length = len;
+ ad.val[0].ad_data.data = buf;
+
+ ASN1_MALLOC_ENCODE(AD_IF_RELEVANT, buf, buf_size, &ad, &len, ret);
+ if (ret) {
+ free_AuthorizationData(&ad);
+ return ret;
+ }
+ if(buf_size != len)
+ krb5_abortx(context, "internal error in ASN.1 encoder");
+ free_AuthorizationData(&ad);
+
+ ALLOC(*auth_data, 1);
+ if (*auth_data == NULL) {
+ krb5_set_error_string(context, "malloc: out of memory");
+ return ENOMEM;
+ }
+
+ ALLOC_SEQ(*auth_data, 1);
+ if ((*auth_data)->val == NULL) {
+ free(buf);
+ krb5_set_error_string(context, "malloc: out of memory");
+ return ENOMEM;
+ }
+
+ (*auth_data)->val[0].ad_type = KRB5_AUTHDATA_IF_RELEVANT;
+ (*auth_data)->val[0].ad_data.length = len;
+ (*auth_data)->val[0].ad_data.data = buf;
+
+ return 0;
+}
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_build_authenticator (krb5_context context,
+ krb5_auth_context auth_context,
+ krb5_enctype enctype,
+ krb5_creds *cred,
+ Checksum *cksum,
+ Authenticator **auth_result,
+ krb5_data *result,
+ krb5_key_usage usage)
+{
+ Authenticator *auth;
+ u_char *buf = NULL;
+ size_t buf_size;
+ size_t len;
+ krb5_error_code ret;
+ krb5_crypto crypto;
+
+ auth = malloc(sizeof(*auth));
+ if (auth == NULL) {
+ krb5_set_error_string(context, "malloc: out of memory");
+ return ENOMEM;
+ }
+
+ memset (auth, 0, sizeof(*auth));
+ auth->authenticator_vno = 5;
+ copy_Realm(&cred->client->realm, &auth->crealm);
+ copy_PrincipalName(&cred->client->name, &auth->cname);
+
+ krb5_us_timeofday (context, &auth->ctime, &auth->cusec);
+
+ ret = krb5_auth_con_getlocalsubkey(context, auth_context, &auth->subkey);
+ if(ret)
+ goto fail;
+
+ if (auth_context->flags & KRB5_AUTH_CONTEXT_DO_SEQUENCE) {
+ if(auth_context->local_seqnumber == 0)
+ krb5_generate_seq_number (context,
+ &cred->session,
+ &auth_context->local_seqnumber);
+ ALLOC(auth->seq_number, 1);
+ if(auth->seq_number == NULL) {
+ ret = ENOMEM;
+ goto fail;
+ }
+ *auth->seq_number = auth_context->local_seqnumber;
+ } else
+ auth->seq_number = NULL;
+ auth->authorization_data = NULL;
+ auth->cksum = cksum;
+
+ if (cksum != NULL && cksum->cksumtype == CKSUMTYPE_GSSAPI) {
+ /*
+ * This is not GSS-API specific, we only enable it for
+ * GSS for now
+ */
+ ret = make_etypelist(context, &auth->authorization_data);
+ if (ret)
+ goto fail;
+ }
+
+ /* XXX - Copy more to auth_context? */
+
+ if (auth_context) {
+ auth_context->authenticator->ctime = auth->ctime;
+ auth_context->authenticator->cusec = auth->cusec;
+ }
+
+ ASN1_MALLOC_ENCODE(Authenticator, buf, buf_size, auth, &len, ret);
+ if (ret)
+ goto fail;
+ if(buf_size != len)
+ krb5_abortx(context, "internal error in ASN.1 encoder");
+
+ ret = krb5_crypto_init(context, &cred->session, enctype, &crypto);
+ if (ret)
+ goto fail;
+ ret = krb5_encrypt (context,
+ crypto,
+ usage /* KRB5_KU_AP_REQ_AUTH */,
+ buf + buf_size - len,
+ len,
+ result);
+ krb5_crypto_destroy(context, crypto);
+
+ if (ret)
+ goto fail;
+
+ free (buf);
+
+ if (auth_result)
+ *auth_result = auth;
+ else {
+ /* Don't free the `cksum', it's allocated by the caller */
+ auth->cksum = NULL;
+ free_Authenticator (auth);
+ free (auth);
+ }
+ return ret;
+ fail:
+ free_Authenticator (auth);
+ free (auth);
+ free (buf);
+ return ret;
+}
diff --git a/source4/heimdal/lib/krb5/cache.c b/source4/heimdal/lib/krb5/cache.c
new file mode 100644
index 0000000000..f293a96ed9
--- /dev/null
+++ b/source4/heimdal/lib/krb5/cache.c
@@ -0,0 +1,657 @@
+/*
+ * Copyright (c) 1997-2005 Kungliga Tekniska Högskolan
+ * (Royal Institute of Technology, Stockholm, Sweden).
+ * 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"
+
+RCSID("$Id: cache.c,v 1.71 2005/06/16 20:19:57 lha Exp $");
+
+/*
+ * Add a new ccache type with operations `ops', overwriting any
+ * existing one if `override'.
+ * Return an error code or 0.
+ */
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_cc_register(krb5_context context,
+ const krb5_cc_ops *ops,
+ krb5_boolean override)
+{
+ int i;
+
+ for(i = 0; i < context->num_cc_ops && context->cc_ops[i].prefix; i++) {
+ if(strcmp(context->cc_ops[i].prefix, ops->prefix) == 0) {
+ if(!override) {
+ krb5_set_error_string(context,
+ "ccache type %s already exists",
+ ops->prefix);
+ return KRB5_CC_TYPE_EXISTS;
+ }
+ break;
+ }
+ }
+ if(i == context->num_cc_ops) {
+ krb5_cc_ops *o = realloc(context->cc_ops,
+ (context->num_cc_ops + 1) *
+ sizeof(*context->cc_ops));
+ if(o == NULL) {
+ krb5_set_error_string(context, "malloc: out of memory");
+ return KRB5_CC_NOMEM;
+ }
+ context->num_cc_ops++;
+ context->cc_ops = o;
+ memset(context->cc_ops + i, 0,
+ (context->num_cc_ops - i) * sizeof(*context->cc_ops));
+ }
+ memcpy(&context->cc_ops[i], ops, sizeof(context->cc_ops[i]));
+ return 0;
+}
+
+/*
+ * Allocate memory for a new ccache in `id' with operations `ops'
+ * and name `residual'.
+ * Return 0 or an error code.
+ */
+
+static krb5_error_code
+allocate_ccache (krb5_context context,
+ const krb5_cc_ops *ops,
+ const char *residual,
+ krb5_ccache *id)
+{
+ krb5_error_code ret;
+ krb5_ccache p;
+
+ p = malloc(sizeof(*p));
+ if(p == NULL) {
+ krb5_set_error_string(context, "malloc: out of memory");
+ return KRB5_CC_NOMEM;
+ }
+ p->ops = ops;
+ *id = p;
+ ret = p->ops->resolve(context, id, residual);
+ if(ret)
+ free(p);
+ return ret;
+}
+
+/*
+ * Find and allocate a ccache in `id' from the specification in `residual'.
+ * If the ccache name doesn't contain any colon, interpret it as a file name.
+ * Return 0 or an error code.
+ */
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_cc_resolve(krb5_context context,
+ const char *name,
+ krb5_ccache *id)
+{
+ int i;
+
+ for(i = 0; i < context->num_cc_ops && context->cc_ops[i].prefix; i++) {
+ size_t prefix_len = strlen(context->cc_ops[i].prefix);
+
+ if(strncmp(context->cc_ops[i].prefix, name, prefix_len) == 0
+ && name[prefix_len] == ':') {
+ return allocate_ccache (context, &context->cc_ops[i],
+ name + prefix_len + 1,
+ id);
+ }
+ }
+ if (strchr (name, ':') == NULL)
+ return allocate_ccache (context, &krb5_fcc_ops, name, id);
+ else {
+ krb5_set_error_string(context, "unknown ccache type %s", name);
+ return KRB5_CC_UNKNOWN_TYPE;
+ }
+}
+
+/*
+ * Generate a new ccache of type `ops' in `id'.
+ * Return 0 or an error code.
+ */
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_cc_gen_new(krb5_context context,
+ const krb5_cc_ops *ops,
+ krb5_ccache *id)
+{
+ krb5_ccache p;
+
+ p = malloc (sizeof(*p));
+ if (p == NULL) {
+ krb5_set_error_string(context, "malloc: out of memory");
+ return KRB5_CC_NOMEM;
+ }
+ p->ops = ops;
+ *id = p;
+ return p->ops->gen_new(context, id);
+}
+
+/*
+ * Generates a new unique ccache of `type` in `id'. If `type' is NULL,
+ * the library chooses the default credential cache type. The supplied
+ * `hint' (that can be NULL) is a string that the credential cache
+ * type can use to base the name of the credential on, this is to make
+ * its easier for the user to differentiate the credentials.
+ *
+ * Returns 0 or an error code.
+ */
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_cc_new_unique(krb5_context context, const char *type,
+ const char *hint, krb5_ccache *id)
+{
+ const krb5_cc_ops *ops;
+
+ if (type == NULL)
+ type = "FILE";
+
+ ops = krb5_cc_get_prefix_ops(context, type);
+ if (ops == NULL) {
+ krb5_set_error_string(context, "Credential cache type %s is unknown",
+ type);
+ return KRB5_CC_UNKNOWN_TYPE;
+ }
+
+ return krb5_cc_gen_new(context, ops, id);
+}
+
+/*
+ * Return the name of the ccache `id'
+ */
+
+const char* KRB5_LIB_FUNCTION
+krb5_cc_get_name(krb5_context context,
+ krb5_ccache id)
+{
+ return id->ops->get_name(context, id);
+}
+
+/*
+ * Return the type of the ccache `id'.
+ */
+
+const char* KRB5_LIB_FUNCTION
+krb5_cc_get_type(krb5_context context,
+ krb5_ccache id)
+{
+ return id->ops->prefix;
+}
+
+/*
+ * Return krb5_cc_ops of a the ccache `id'.
+ */
+
+const krb5_cc_ops *
+krb5_cc_get_ops(krb5_context context, krb5_ccache id)
+{
+ return id->ops;
+}
+
+/*
+ * Expand variables in `str' into `res'
+ */
+
+krb5_error_code
+_krb5_expand_default_cc_name(krb5_context context, const char *str, char **res)
+{
+ size_t tlen, len = 0;
+ char *tmp, *tmp2, *append;
+
+ *res = NULL;
+
+ while (str && *str) {
+ tmp = strstr(str, "%{");
+ if (tmp && tmp != str) {
+ append = malloc((tmp - str) + 1);
+ if (append) {
+ memcpy(append, str, tmp - str);
+ append[tmp - str] = '\0';
+ }
+ str = tmp;
+ } else if (tmp) {
+ tmp2 = strchr(tmp, '}');
+ if (tmp2 == NULL) {
+ free(*res);
+ *res = NULL;
+ krb5_set_error_string(context, "variable missing }");
+ return KRB5_CONFIG_BADFORMAT;
+ }
+ if (strncasecmp(tmp, "%{uid}", 6) == 0)
+ asprintf(&append, "%u", (unsigned)getuid());
+ else if (strncasecmp(tmp, "%{null}", 7) == 0)
+ append = strdup("");
+ else {
+ free(*res);
+ *res = NULL;
+ krb5_set_error_string(context,
+ "expand default cache unknown "
+ "variable \"%.*s\"",
+ (int)(tmp2 - tmp) - 2, tmp + 2);
+ return KRB5_CONFIG_BADFORMAT;
+ }
+ str = tmp2 + 1;
+ } else {
+ append = strdup(str);
+ str = NULL;
+ }
+ if (append == NULL) {
+ free(*res);
+ res = NULL;
+ krb5_set_error_string(context, "malloc - out of memory");
+ return ENOMEM;
+ }
+
+ tlen = strlen(append);
+ tmp = realloc(*res, len + tlen + 1);
+ if (tmp == NULL) {
+ free(*res);
+ *res = NULL;
+ krb5_set_error_string(context, "malloc - out of memory");
+ return ENOMEM;
+ }
+ *res = tmp;
+ memcpy(*res + len, append, tlen + 1);
+ len = len + tlen;
+ free(append);
+ }
+ return 0;
+}
+
+/*
+ * Set the default cc name for `context' to `name'.
+ */
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_cc_set_default_name(krb5_context context, const char *name)
+{
+ krb5_error_code ret = 0;
+ char *p;
+
+ if (name == NULL) {
+ const char *e = NULL;
+
+ if(!issuid()) {
+ e = getenv("KRB5CCNAME");
+ if (e)
+ p = strdup(e);
+ }
+ if (e == NULL) {
+ e = krb5_config_get_string(context, NULL, "libdefaults",
+ "default_cc_name", NULL);
+ if (e) {
+ ret = _krb5_expand_default_cc_name(context, e, &p);
+ if (ret)
+ return ret;
+ }
+ }
+ if (e == NULL)
+ asprintf(&p,"FILE:/tmp/krb5cc_%u", (unsigned)getuid());
+ } else
+ p = strdup(name);
+
+ if (p == NULL) {
+ krb5_set_error_string(context, "malloc - out of memory");
+ return ENOMEM;
+ }
+
+ if (context->default_cc_name)
+ free(context->default_cc_name);
+
+ context->default_cc_name = p;
+
+ return ret;
+}
+
+/*
+ * Return a pointer to a context static string containing the default
+ * ccache name.
+ */
+
+const char* KRB5_LIB_FUNCTION
+krb5_cc_default_name(krb5_context context)
+{
+ if (context->default_cc_name == NULL)
+ krb5_cc_set_default_name(context, NULL);
+
+ return context->default_cc_name;
+}
+
+/*
+ * Open the default ccache in `id'.
+ * Return 0 or an error code.
+ */
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_cc_default(krb5_context context,
+ krb5_ccache *id)
+{
+ const char *p = krb5_cc_default_name(context);
+
+ if (p == NULL) {
+ krb5_set_error_string(context, "malloc - out of memory");
+ return ENOMEM;
+ }
+ return krb5_cc_resolve(context, p, id);
+}
+
+/*
+ * Create a new ccache in `id' for `primary_principal'.
+ * Return 0 or an error code.
+ */
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_cc_initialize(krb5_context context,
+ krb5_ccache id,
+ krb5_principal primary_principal)
+{
+ return id->ops->init(context, id, primary_principal);
+}
+
+
+/*
+ * Remove the ccache `id'.
+ * Return 0 or an error code.
+ */
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_cc_destroy(krb5_context context,
+ krb5_ccache id)
+{
+ krb5_error_code ret;
+
+ ret = id->ops->destroy(context, id);
+ krb5_cc_close (context, id);
+ return ret;
+}
+
+/*
+ * Stop using the ccache `id' and free the related resources.
+ * Return 0 or an error code.
+ */
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_cc_close(krb5_context context,
+ krb5_ccache id)
+{
+ krb5_error_code ret;
+ ret = id->ops->close(context, id);
+ free(id);
+ return ret;
+}
+
+/*
+ * Store `creds' in the ccache `id'.
+ * Return 0 or an error code.
+ */
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_cc_store_cred(krb5_context context,
+ krb5_ccache id,
+ krb5_creds *creds)
+{
+ return id->ops->store(context, id, creds);
+}
+
+/*
+ * Retrieve the credential identified by `mcreds' (and `whichfields')
+ * from `id' in `creds'.
+ * Return 0 or an error code.
+ */
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_cc_retrieve_cred(krb5_context context,
+ krb5_ccache id,
+ krb5_flags whichfields,
+ const krb5_creds *mcreds,
+ krb5_creds *creds)
+{
+ krb5_error_code ret;
+ krb5_cc_cursor cursor;
+
+ if (id->ops->retrieve != NULL) {
+ return id->ops->retrieve(context, id, whichfields,
+ mcreds, creds);
+ }
+
+ krb5_cc_start_seq_get(context, id, &cursor);
+ while((ret = krb5_cc_next_cred(context, id, &cursor, creds)) == 0){
+ if(krb5_compare_creds(context, whichfields, mcreds, creds)){
+ ret = 0;
+ break;
+ }
+ krb5_free_cred_contents (context, creds);
+ }
+ krb5_cc_end_seq_get(context, id, &cursor);
+ return ret;
+}
+
+/*
+ * Return the principal of `id' in `principal'.
+ * Return 0 or an error code.
+ */
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_cc_get_principal(krb5_context context,
+ krb5_ccache id,
+ krb5_principal *principal)
+{
+ return id->ops->get_princ(context, id, principal);
+}
+
+/*
+ * Start iterating over `id', `cursor' is initialized to the
+ * beginning.
+ * Return 0 or an error code.
+ */
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_cc_start_seq_get (krb5_context context,
+ const krb5_ccache id,
+ krb5_cc_cursor *cursor)
+{
+ return id->ops->get_first(context, id, cursor);
+}
+
+/*
+ * Retrieve the next cred pointed to by (`id', `cursor') in `creds'
+ * and advance `cursor'.
+ * Return 0 or an error code.
+ */
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_cc_next_cred (krb5_context context,
+ const krb5_ccache id,
+ krb5_cc_cursor *cursor,
+ krb5_creds *creds)
+{
+ return id->ops->get_next(context, id, cursor, creds);
+}
+
+/* like krb5_cc_next_cred, but allow for selective retrieval */
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_cc_next_cred_match(krb5_context context,
+ const krb5_ccache id,
+ krb5_cc_cursor * cursor,
+ krb5_creds * creds,
+ krb5_flags whichfields,
+ const krb5_creds * mcreds)
+{
+ krb5_error_code ret;
+ while (1) {
+ ret = krb5_cc_next_cred(context, id, cursor, creds);
+ if (ret)
+ return ret;
+ if (mcreds == NULL || krb5_compare_creds(context, whichfields, mcreds, creds))
+ return 0;
+ krb5_free_cred_contents(context, creds);
+ }
+}
+
+/*
+ * Destroy the cursor `cursor'.
+ */
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_cc_end_seq_get (krb5_context context,
+ const krb5_ccache id,
+ krb5_cc_cursor *cursor)
+{
+ return id->ops->end_get(context, id, cursor);
+}
+
+/*
+ * Remove the credential identified by `cred', `which' from `id'.
+ */
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_cc_remove_cred(krb5_context context,
+ krb5_ccache id,
+ krb5_flags which,
+ krb5_creds *cred)
+{
+ if(id->ops->remove_cred == NULL) {
+ krb5_set_error_string(context,
+ "ccache %s does not support remove_cred",
+ id->ops->prefix);
+ return EACCES; /* XXX */
+ }
+ return (*id->ops->remove_cred)(context, id, which, cred);
+}
+
+/*
+ * Set the flags of `id' to `flags'.
+ */
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_cc_set_flags(krb5_context context,
+ krb5_ccache id,
+ krb5_flags flags)
+{
+ return id->ops->set_flags(context, id, flags);
+}
+
+/*
+ * Copy the contents of `from' to `to'.
+ */
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_cc_copy_cache_match(krb5_context context,
+ const krb5_ccache from,
+ krb5_ccache to,
+ krb5_flags whichfields,
+ const krb5_creds * mcreds,
+ unsigned int *matched)
+{
+ krb5_error_code ret;
+ krb5_cc_cursor cursor;
+ krb5_creds cred;
+ krb5_principal princ;
+
+ ret = krb5_cc_get_principal(context, from, &princ);
+ if (ret)
+ return ret;
+ ret = krb5_cc_initialize(context, to, princ);
+ if (ret) {
+ krb5_free_principal(context, princ);
+ return ret;
+ }
+ ret = krb5_cc_start_seq_get(context, from, &cursor);
+ if (ret) {
+ krb5_free_principal(context, princ);
+ return ret;
+ }
+ if (matched)
+ *matched = 0;
+ while (ret == 0 &&
+ krb5_cc_next_cred_match(context, from, &cursor, &cred,
+ whichfields, mcreds) == 0) {
+ if (matched)
+ (*matched)++;
+ ret = krb5_cc_store_cred(context, to, &cred);
+ krb5_free_cred_contents(context, &cred);
+ }
+ krb5_cc_end_seq_get(context, from, &cursor);
+ krb5_free_principal(context, princ);
+ return ret;
+}
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_cc_copy_cache(krb5_context context,
+ const krb5_ccache from,
+ krb5_ccache to)
+{
+ return krb5_cc_copy_cache_match(context, from, to, 0, NULL, NULL);
+}
+
+/*
+ * Return the version of `id'.
+ */
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_cc_get_version(krb5_context context,
+ const krb5_ccache id)
+{
+ if(id->ops->get_version)
+ return id->ops->get_version(context, id);
+ else
+ return 0;
+}
+
+/*
+ * Clear `mcreds' so it can be used with krb5_cc_retrieve_cred
+ */
+
+void KRB5_LIB_FUNCTION
+krb5_cc_clear_mcred(krb5_creds *mcred)
+{
+ memset(mcred, 0, sizeof(*mcred));
+}
+
+/*
+ * Get the cc ops that is registered in `context' to handle the
+ * `prefix'. Returns NULL if ops not found.
+ */
+
+const krb5_cc_ops *
+krb5_cc_get_prefix_ops(krb5_context context, const char *prefix)
+{
+ int i;
+
+ for(i = 0; i < context->num_cc_ops && context->cc_ops[i].prefix; i++) {
+ if(strcmp(context->cc_ops[i].prefix, prefix) == 0)
+ return &context->cc_ops[i];
+ }
+ return NULL;
+}
diff --git a/source4/heimdal/lib/krb5/changepw.c b/source4/heimdal/lib/krb5/changepw.c
new file mode 100644
index 0000000000..e6ef1d9d9b
--- /dev/null
+++ b/source4/heimdal/lib/krb5/changepw.c
@@ -0,0 +1,816 @@
+/*
+ * Copyright (c) 1997 - 2005 Kungliga Tekniska Högskolan
+ * (Royal Institute of Technology, Stockholm, Sweden).
+ * 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>
+
+RCSID("$Id: changepw.c,v 1.53 2005/05/25 05:30:42 lha Exp $");
+
+static void
+str2data (krb5_data *d,
+ const char *fmt,
+ ...) __attribute__ ((format (printf, 2, 3)));
+
+static void
+str2data (krb5_data *d,
+ const char *fmt,
+ ...)
+{
+ va_list args;
+
+ va_start(args, fmt);
+ d->length = vasprintf ((char **)&d->data, fmt, args);
+ va_end(args);
+}
+
+/*
+ * Change password protocol defined by
+ * draft-ietf-cat-kerb-chg-password-02.txt
+ *
+ * Share the response part of the protocol with MS set password
+ * (RFC3244)
+ */
+
+static krb5_error_code
+chgpw_send_request (krb5_context context,
+ krb5_auth_context *auth_context,
+ krb5_creds *creds,
+ krb5_principal targprinc,
+ int is_stream,
+ int sock,
+ char *passwd,
+ const char *host)
+{
+ krb5_error_code ret;
+ krb5_data ap_req_data;
+ krb5_data krb_priv_data;
+ krb5_data passwd_data;
+ size_t len;
+ u_char header[6];
+ u_char *p;
+ struct iovec iov[3];
+ struct msghdr msghdr;
+
+ if (is_stream)
+ return KRB5_KPASSWD_MALFORMED;
+
+ if (targprinc &&
+ krb5_principal_compare(context, creds->client, targprinc) != TRUE)
+ return KRB5_KPASSWD_MALFORMED;
+
+ krb5_data_zero (&ap_req_data);
+
+ ret = krb5_mk_req_extended (context,
+ auth_context,
+ AP_OPTS_MUTUAL_REQUIRED | AP_OPTS_USE_SUBKEY,
+ NULL, /* in_data */
+ creds,
+ &ap_req_data);
+ if (ret)
+ return ret;
+
+ passwd_data.data = passwd;
+ passwd_data.length = strlen(passwd);
+
+ krb5_data_zero (&krb_priv_data);
+
+ ret = krb5_mk_priv (context,
+ *auth_context,
+ &passwd_data,
+ &krb_priv_data,
+ NULL);
+ if (ret)
+ goto out2;
+
+ len = 6 + ap_req_data.length + krb_priv_data.length;
+ p = header;
+ *p++ = (len >> 8) & 0xFF;
+ *p++ = (len >> 0) & 0xFF;
+ *p++ = 0;
+ *p++ = 1;
+ *p++ = (ap_req_data.length >> 8) & 0xFF;
+ *p++ = (ap_req_data.length >> 0) & 0xFF;
+
+ memset(&msghdr, 0, sizeof(msghdr));
+ msghdr.msg_name = NULL;
+ msghdr.msg_namelen = 0;
+ msghdr.msg_iov = iov;
+ msghdr.msg_iovlen = sizeof(iov)/sizeof(*iov);
+#if 0
+ msghdr.msg_control = NULL;
+ msghdr.msg_controllen = 0;
+#endif
+
+ iov[0].iov_base = (void*)header;
+ iov[0].iov_len = 6;
+ iov[1].iov_base = ap_req_data.data;
+ iov[1].iov_len = ap_req_data.length;
+ iov[2].iov_base = krb_priv_data.data;
+ iov[2].iov_len = krb_priv_data.length;
+
+ if (sendmsg (sock, &msghdr, 0) < 0) {
+ ret = errno;
+ krb5_set_error_string(context, "sendmsg %s: %s", host, strerror(ret));
+ }
+
+ krb5_data_free (&krb_priv_data);
+out2:
+ krb5_data_free (&ap_req_data);
+ return ret;
+}
+
+/*
+ * Set password protocol as defined by RFC3244 --
+ * Microsoft Windows 2000 Kerberos Change Password and Set Password Protocols
+ */
+
+static krb5_error_code
+setpw_send_request (krb5_context context,
+ krb5_auth_context *auth_context,
+ krb5_creds *creds,
+ krb5_principal targprinc,
+ int is_stream,
+ int sock,
+ char *passwd,
+ const char *host)
+{
+ krb5_error_code ret;
+ krb5_data ap_req_data;
+ krb5_data krb_priv_data;
+ krb5_data pwd_data;
+ ChangePasswdDataMS chpw;
+ size_t len;
+ u_char header[4 + 6];
+ u_char *p;
+ struct iovec iov[3];
+ struct msghdr msghdr;
+
+ krb5_data_zero (&ap_req_data);
+
+ ret = krb5_mk_req_extended (context,
+ auth_context,
+ AP_OPTS_MUTUAL_REQUIRED | AP_OPTS_USE_SUBKEY,
+ NULL, /* in_data */
+ creds,
+ &ap_req_data);
+ if (ret)
+ return ret;
+
+ chpw.newpasswd.length = strlen(passwd);
+ chpw.newpasswd.data = passwd;
+ if (targprinc) {
+ chpw.targname = &targprinc->name;
+ chpw.targrealm = &targprinc->realm;
+ } else {
+ chpw.targname = NULL;
+ chpw.targrealm = NULL;
+ }
+
+ ASN1_MALLOC_ENCODE(ChangePasswdDataMS, pwd_data.data, pwd_data.length,
+ &chpw, &len, ret);
+ if (ret) {
+ krb5_data_free (&ap_req_data);
+ return ret;
+ }
+
+ if(pwd_data.length != len)
+ krb5_abortx(context, "internal error in ASN.1 encoder");
+
+ ret = krb5_mk_priv (context,
+ *auth_context,
+ &pwd_data,
+ &krb_priv_data,
+ NULL);
+ if (ret)
+ goto out2;
+
+ len = 6 + ap_req_data.length + krb_priv_data.length;
+ p = header;
+ if (is_stream) {
+ _krb5_put_int(p, len, 4);
+ p += 4;
+ }
+ *p++ = (len >> 8) & 0xFF;
+ *p++ = (len >> 0) & 0xFF;
+ *p++ = 0xff;
+ *p++ = 0x80;
+ *p++ = (ap_req_data.length >> 8) & 0xFF;
+ *p++ = (ap_req_data.length >> 0) & 0xFF;
+
+ memset(&msghdr, 0, sizeof(msghdr));
+ msghdr.msg_name = NULL;
+ msghdr.msg_namelen = 0;
+ msghdr.msg_iov = iov;
+ msghdr.msg_iovlen = sizeof(iov)/sizeof(*iov);
+#if 0
+ msghdr.msg_control = NULL;
+ msghdr.msg_controllen = 0;
+#endif
+
+ iov[0].iov_base = (void*)header;
+ if (is_stream)
+ iov[0].iov_len = 10;
+ else
+ iov[0].iov_len = 6;
+ iov[1].iov_base = ap_req_data.data;
+ iov[1].iov_len = ap_req_data.length;
+ iov[2].iov_base = krb_priv_data.data;
+ iov[2].iov_len = krb_priv_data.length;
+
+ if (sendmsg (sock, &msghdr, 0) < 0) {
+ ret = errno;
+ krb5_set_error_string(context, "sendmsg %s: %s", host, strerror(ret));
+ }
+
+ krb5_data_free (&krb_priv_data);
+out2:
+ krb5_data_free (&ap_req_data);
+ krb5_data_free (&pwd_data);
+ return ret;
+}
+
+static krb5_error_code
+process_reply (krb5_context context,
+ krb5_auth_context auth_context,
+ int is_stream,
+ int sock,
+ int *result_code,
+ krb5_data *result_code_string,
+ krb5_data *result_string,
+ const char *host)
+{
+ krb5_error_code ret;
+ u_char reply[1024 * 3];
+ ssize_t len;
+ u_int16_t pkt_len, pkt_ver;
+ krb5_data ap_rep_data;
+ int save_errno;
+
+ len = 0;
+ if (is_stream) {
+ while (len < sizeof(reply)) {
+ unsigned long size;
+
+ ret = recvfrom (sock, reply + len, sizeof(reply) - len,
+ 0, NULL, NULL);
+ if (ret < 0) {
+ save_errno = errno;
+ krb5_set_error_string(context, "recvfrom %s: %s",
+ host, strerror(save_errno));
+ return save_errno;
+ } else if (ret == 0) {
+ krb5_set_error_string(context, "recvfrom timeout %s", host);
+ return 1;
+ }
+ len += ret;
+ if (len < 4)
+ continue;
+ _krb5_get_int(reply, &size, 4);
+ if (size + 4 < len)
+ continue;
+ memmove(reply, reply + 4, size);
+ len = size;
+ break;
+ }
+ if (len == sizeof(reply)) {
+ krb5_set_error_string(context, "message too large from %s",
+ host);
+ return ENOMEM;
+ }
+ } else {
+ ret = recvfrom (sock, reply, sizeof(reply), 0, NULL, NULL);
+ if (ret < 0) {
+ save_errno = errno;
+ krb5_set_error_string(context, "recvfrom %s: %s",
+ host, strerror(save_errno));
+ return save_errno;
+ }
+ len = ret;
+ }
+
+ if (len < 6) {
+ str2data (result_string, "server %s sent to too short message "
+ "(%ld bytes)", host, (long)len);
+ *result_code = KRB5_KPASSWD_MALFORMED;
+ return 0;
+ }
+
+ pkt_len = (reply[0] << 8) | (reply[1]);
+ pkt_ver = (reply[2] << 8) | (reply[3]);
+
+ if ((pkt_len != len) || (reply[1] == 0x7e || reply[1] == 0x5e)) {
+ KRB_ERROR error;
+ size_t size;
+ u_char *p;
+
+ memset(&error, 0, sizeof(error));
+
+ ret = decode_KRB_ERROR(reply, len, &error, &size);
+ if (ret)
+ return ret;
+
+ if (error.e_data->length < 2) {
+ str2data(result_string, "server %s sent too short "
+ "e_data to print anything usable", host);
+ free_KRB_ERROR(&error);
+ *result_code = KRB5_KPASSWD_MALFORMED;
+ return 0;
+ }
+
+ p = error.e_data->data;
+ *result_code = (p[0] << 8) | p[1];
+ if (error.e_data->length == 2)
+ str2data(result_string, "server only sent error code");
+ else
+ krb5_data_copy (result_string,
+ p + 2,
+ error.e_data->length - 2);
+ free_KRB_ERROR(&error);
+ return 0;
+ }
+
+ if (pkt_len != len) {
+ str2data (result_string, "client: wrong len in reply");
+ *result_code = KRB5_KPASSWD_MALFORMED;
+ return 0;
+ }
+ if (pkt_ver != KRB5_KPASSWD_VERS_CHANGEPW) {
+ str2data (result_string,
+ "client: wrong version number (%d)", pkt_ver);
+ *result_code = KRB5_KPASSWD_MALFORMED;
+ return 0;
+ }
+
+ ap_rep_data.data = reply + 6;
+ ap_rep_data.length = (reply[4] << 8) | (reply[5]);
+
+ if (reply + len < (u_char *)ap_rep_data.data + ap_rep_data.length) {
+ str2data (result_string, "client: wrong AP len in reply");
+ *result_code = KRB5_KPASSWD_MALFORMED;
+ return 0;
+ }
+
+ if (ap_rep_data.length) {
+ krb5_ap_rep_enc_part *ap_rep;
+ krb5_data priv_data;
+ u_char *p;
+
+ priv_data.data = (u_char*)ap_rep_data.data + ap_rep_data.length;
+ priv_data.length = len - ap_rep_data.length - 6;
+
+ ret = krb5_rd_rep (context,
+ auth_context,
+ &ap_rep_data,
+ &ap_rep);
+ if (ret)
+ return ret;
+
+ krb5_free_ap_rep_enc_part (context, ap_rep);
+
+ ret = krb5_rd_priv (context,
+ auth_context,
+ &priv_data,
+ result_code_string,
+ NULL);
+ if (ret) {
+ krb5_data_free (result_code_string);
+ return ret;
+ }
+
+ if (result_code_string->length < 2) {
+ *result_code = KRB5_KPASSWD_MALFORMED;
+ str2data (result_string,
+ "client: bad length in result");
+ return 0;
+ }
+
+ p = result_code_string->data;
+
+ *result_code = (p[0] << 8) | p[1];
+ krb5_data_copy (result_string,
+ (unsigned char*)result_code_string->data + 2,
+ result_code_string->length - 2);
+ return 0;
+ } else {
+ KRB_ERROR error;
+ size_t size;
+ u_char *p;
+
+ ret = decode_KRB_ERROR(reply + 6, len - 6, &error, &size);
+ if (ret) {
+ return ret;
+ }
+ if (error.e_data->length < 2) {
+ krb5_warnx (context, "too short e_data to print anything usable");
+ return 1; /* XXX */
+ }
+
+ p = error.e_data->data;
+ *result_code = (p[0] << 8) | p[1];
+ krb5_data_copy (result_string,
+ p + 2,
+ error.e_data->length - 2);
+ return 0;
+ }
+}
+
+
+/*
+ * change the password using the credentials in `creds' (for the
+ * principal indicated in them) to `newpw', storing the result of
+ * the operation in `result_*' and an error code or 0.
+ */
+
+typedef krb5_error_code (*kpwd_send_request) (krb5_context,
+ krb5_auth_context *,
+ krb5_creds *,
+ krb5_principal,
+ int,
+ int,
+ char *,
+ const char *);
+typedef krb5_error_code (*kpwd_process_reply) (krb5_context,
+ krb5_auth_context,
+ int,
+ int,
+ int *,
+ krb5_data *,
+ krb5_data *,
+ const char *);
+
+static struct kpwd_proc {
+ const char *name;
+ int flags;
+#define SUPPORT_TCP 1
+#define SUPPORT_UDP 2
+ kpwd_send_request send_req;
+ kpwd_process_reply process_rep;
+} procs[] = {
+ {
+ "MS set password",
+ SUPPORT_TCP|SUPPORT_UDP,
+ setpw_send_request,
+ process_reply
+ },
+ {
+ "change password",
+ SUPPORT_UDP,
+ chgpw_send_request,
+ process_reply
+ },
+ { NULL }
+};
+
+static struct kpwd_proc *
+find_chpw_proto(const char *name)
+{
+ struct kpwd_proc *p;
+ for (p = procs; p->name != NULL; p++) {
+ if (strcmp(p->name, name) == 0)
+ return p;
+ }
+ return NULL;
+}
+
+/*
+ *
+ */
+
+static krb5_error_code
+change_password_loop (krb5_context context,
+ krb5_creds *creds,
+ krb5_principal targprinc,
+ char *newpw,
+ int *result_code,
+ krb5_data *result_code_string,
+ krb5_data *result_string,
+ struct kpwd_proc *proc)
+{
+ krb5_error_code ret;
+ krb5_auth_context auth_context = NULL;
+ krb5_krbhst_handle handle = NULL;
+ krb5_krbhst_info *hi;
+ int sock;
+ int i;
+ int done = 0;
+ krb5_realm realm = creds->client->realm;
+
+ ret = krb5_auth_con_init (context, &auth_context);
+ if (ret)
+ return ret;
+
+ krb5_auth_con_setflags (context, auth_context,
+ KRB5_AUTH_CONTEXT_DO_SEQUENCE);
+
+ ret = krb5_krbhst_init (context, realm, KRB5_KRBHST_CHANGEPW, &handle);
+ if (ret)
+ goto out;
+
+ while (!done && (ret = krb5_krbhst_next(context, handle, &hi)) == 0) {
+ struct addrinfo *ai, *a;
+ int is_stream;
+
+ switch (hi->proto) {
+ case KRB5_KRBHST_UDP:
+ if ((proc->flags & SUPPORT_UDP) == 0)
+ continue;
+ is_stream = 0;
+ break;
+ case KRB5_KRBHST_TCP:
+ if ((proc->flags & SUPPORT_TCP) == 0)
+ continue;
+ is_stream = 1;
+ break;
+ default:
+ continue;
+ }
+
+ ret = krb5_krbhst_get_addrinfo(context, hi, &ai);
+ if (ret)
+ continue;
+
+ for (a = ai; !done && a != NULL; a = a->ai_next) {
+ int replied = 0;
+
+ sock = socket (a->ai_family, a->ai_socktype, a->ai_protocol);
+ if (sock < 0)
+ continue;
+
+ ret = connect(sock, a->ai_addr, a->ai_addrlen);
+ if (ret < 0) {
+ close (sock);
+ goto out;
+ }
+
+ ret = krb5_auth_con_genaddrs (context, auth_context, sock,
+ KRB5_AUTH_CONTEXT_GENERATE_LOCAL_ADDR);
+ if (ret) {
+ close (sock);
+ goto out;
+ }
+
+ for (i = 0; !done && i < 5; ++i) {
+ fd_set fdset;
+ struct timeval tv;
+
+ if (!replied) {
+ replied = 0;
+
+ ret = (*proc->send_req) (context,
+ &auth_context,
+ creds,
+ targprinc,
+ is_stream,
+ sock,
+ newpw,
+ hi->hostname);
+ if (ret) {
+ close(sock);
+ goto out;
+ }
+ }
+
+ if (sock >= FD_SETSIZE) {
+ krb5_set_error_string(context, "fd %d too large", sock);
+ ret = ERANGE;
+ close (sock);
+ goto out;
+ }
+
+ FD_ZERO(&fdset);
+ FD_SET(sock, &fdset);
+ tv.tv_usec = 0;
+ tv.tv_sec = 1 + (1 << i);
+
+ ret = select (sock + 1, &fdset, NULL, NULL, &tv);
+ if (ret < 0 && errno != EINTR) {
+ close(sock);
+ goto out;
+ }
+ if (ret == 1) {
+ ret = (*proc->process_rep) (context,
+ auth_context,
+ is_stream,
+ sock,
+ result_code,
+ result_code_string,
+ result_string,
+ hi->hostname);
+ if (ret == 0)
+ done = 1;
+ else if (i > 0 && ret == KRB5KRB_AP_ERR_MUT_FAIL)
+ replied = 1;
+ } else {
+ ret = KRB5_KDC_UNREACH;
+ }
+ }
+ close (sock);
+ }
+ }
+
+ out:
+ krb5_krbhst_free (context, handle);
+ krb5_auth_con_free (context, auth_context);
+ if (done)
+ return 0;
+ else {
+ if (ret == KRB5_KDC_UNREACH) {
+ krb5_set_error_string(context,
+ "unable to reach any changepw server "
+ " in realm %s", realm);
+ *result_code = KRB5_KPASSWD_HARDERROR;
+ }
+ return ret;
+ }
+}
+
+
+/*
+ * change the password using the credentials in `creds' (for the
+ * principal indicated in them) to `newpw', storing the result of
+ * the operation in `result_*' and an error code or 0.
+ */
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_change_password (krb5_context context,
+ krb5_creds *creds,
+ char *newpw,
+ int *result_code,
+ krb5_data *result_code_string,
+ krb5_data *result_string)
+{
+ struct kpwd_proc *p = find_chpw_proto("change password");
+
+ *result_code = KRB5_KPASSWD_MALFORMED;
+ result_code_string->data = result_string->data = NULL;
+ result_code_string->length = result_string->length = 0;
+
+ if (p == NULL)
+ return KRB5_KPASSWD_MALFORMED;
+
+ return change_password_loop(context, creds, NULL, newpw,
+ result_code, result_code_string,
+ result_string, p);
+}
+
+/*
+ *
+ */
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_set_password(krb5_context context,
+ krb5_creds *creds,
+ char *newpw,
+ krb5_principal targprinc,
+ int *result_code,
+ krb5_data *result_code_string,
+ krb5_data *result_string)
+{
+ krb5_principal principal = NULL;
+ krb5_error_code ret = 0;
+ int i;
+
+ *result_code = KRB5_KPASSWD_MALFORMED;
+ result_code_string->data = result_string->data = NULL;
+ result_code_string->length = result_string->length = 0;
+
+ if (targprinc == NULL) {
+ ret = krb5_get_default_principal(context, &principal);
+ if (ret)
+ return ret;
+ } else
+ principal = targprinc;
+
+ for (i = 0; procs[i].name != NULL; i++) {
+ *result_code = 0;
+ ret = change_password_loop(context, creds, targprinc, newpw,
+ result_code, result_code_string,
+ result_string,
+ &procs[i]);
+ if (ret == 0 && *result_code == 0)
+ break;
+ }
+
+ if (targprinc == NULL)
+ krb5_free_principal(context, principal);
+ return ret;
+}
+
+/*
+ *
+ */
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_set_password_using_ccache(krb5_context context,
+ krb5_ccache ccache,
+ char *newpw,
+ krb5_principal targprinc,
+ int *result_code,
+ krb5_data *result_code_string,
+ krb5_data *result_string)
+{
+ krb5_creds creds, *credsp;
+ krb5_error_code ret;
+ krb5_principal principal = NULL;
+
+ *result_code = KRB5_KPASSWD_MALFORMED;
+ result_code_string->data = result_string->data = NULL;
+ result_code_string->length = result_string->length = 0;
+
+ memset(&creds, 0, sizeof(creds));
+
+ if (targprinc == NULL) {
+ ret = krb5_cc_get_principal(context, ccache, &principal);
+ if (ret)
+ return ret;
+ } else
+ principal = targprinc;
+
+ ret = krb5_make_principal(context, &creds.server,
+ krb5_principal_get_realm(context, principal),
+ "kadmin", "changepw", NULL);
+ if (ret)
+ goto out;
+
+ ret = krb5_cc_get_principal(context, ccache, &creds.client);
+ if (ret) {
+ krb5_free_principal(context, creds.server);
+ goto out;
+ }
+
+ ret = krb5_get_credentials(context, 0, ccache, &creds, &credsp);
+ krb5_free_principal(context, creds.server);
+ krb5_free_principal(context, creds.client);
+ if (ret)
+ goto out;
+
+ ret = krb5_set_password(context,
+ credsp,
+ newpw,
+ principal,
+ result_code,
+ result_code_string,
+ result_string);
+
+ krb5_free_creds(context, credsp);
+
+ return ret;
+ out:
+ if (targprinc == NULL)
+ krb5_free_principal(context, principal);
+ return ret;
+}
+
+/*
+ *
+ */
+
+const char* KRB5_LIB_FUNCTION
+krb5_passwd_result_to_string (krb5_context context,
+ int result)
+{
+ static const char *strings[] = {
+ "Success",
+ "Malformed",
+ "Hard error",
+ "Auth error",
+ "Soft error" ,
+ "Access denied",
+ "Bad version",
+ "Initial flag needed"
+ };
+
+ if (result < 0 || result > KRB5_KPASSWD_INITIAL_FLAG_NEEDED)
+ return "unknown result code";
+ else
+ return strings[result];
+}
diff --git a/source4/heimdal/lib/krb5/codec.c b/source4/heimdal/lib/krb5/codec.c
new file mode 100644
index 0000000000..080e8a6511
--- /dev/null
+++ b/source4/heimdal/lib/krb5/codec.c
@@ -0,0 +1,196 @@
+/*
+ * Copyright (c) 1998 - 2001 Kungliga Tekniska Högskolan
+ * (Royal Institute of Technology, Stockholm, Sweden).
+ * 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"
+
+RCSID("$Id: codec.c,v 1.9 2004/05/25 21:19:37 lha Exp $");
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_decode_EncTicketPart (krb5_context context,
+ const void *data,
+ size_t length,
+ EncTicketPart *t,
+ size_t *len)
+{
+ return decode_EncTicketPart(data, length, t, len);
+}
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_encode_EncTicketPart (krb5_context context,
+ void *data,
+ size_t length,
+ EncTicketPart *t,
+ size_t *len)
+{
+ return encode_EncTicketPart(data, length, t, len);
+}
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_decode_EncASRepPart (krb5_context context,
+ const void *data,
+ size_t length,
+ EncASRepPart *t,
+ size_t *len)
+{
+ return decode_EncASRepPart(data, length, t, len);
+}
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_encode_EncASRepPart (krb5_context context,
+ void *data,
+ size_t length,
+ EncASRepPart *t,
+ size_t *len)
+{
+ return encode_EncASRepPart(data, length, t, len);
+}
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_decode_EncTGSRepPart (krb5_context context,
+ const void *data,
+ size_t length,
+ EncTGSRepPart *t,
+ size_t *len)
+{
+ return decode_EncTGSRepPart(data, length, t, len);
+}
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_encode_EncTGSRepPart (krb5_context context,
+ void *data,
+ size_t length,
+ EncTGSRepPart *t,
+ size_t *len)
+{
+ return encode_EncTGSRepPart(data, length, t, len);
+}
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_decode_EncAPRepPart (krb5_context context,
+ const void *data,
+ size_t length,
+ EncAPRepPart *t,
+ size_t *len)
+{
+ return decode_EncAPRepPart(data, length, t, len);
+}
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_encode_EncAPRepPart (krb5_context context,
+ void *data,
+ size_t length,
+ EncAPRepPart *t,
+ size_t *len)
+{
+ return encode_EncAPRepPart(data, length, t, len);
+}
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_decode_Authenticator (krb5_context context,
+ const void *data,
+ size_t length,
+ Authenticator *t,
+ size_t *len)
+{
+ return decode_Authenticator(data, length, t, len);
+}
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_encode_Authenticator (krb5_context context,
+ void *data,
+ size_t length,
+ Authenticator *t,
+ size_t *len)
+{
+ return encode_Authenticator(data, length, t, len);
+}
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_decode_EncKrbCredPart (krb5_context context,
+ const void *data,
+ size_t length,
+ EncKrbCredPart *t,
+ size_t *len)
+{
+ return decode_EncKrbCredPart(data, length, t, len);
+}
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_encode_EncKrbCredPart (krb5_context context,
+ void *data,
+ size_t length,
+ EncKrbCredPart *t,
+ size_t *len)
+{
+ return encode_EncKrbCredPart (data, length, t, len);
+}
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_decode_ETYPE_INFO (krb5_context context,
+ const void *data,
+ size_t length,
+ ETYPE_INFO *t,
+ size_t *len)
+{
+ return decode_ETYPE_INFO(data, length, t, len);
+}
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_encode_ETYPE_INFO (krb5_context context,
+ void *data,
+ size_t length,
+ ETYPE_INFO *t,
+ size_t *len)
+{
+ return encode_ETYPE_INFO (data, length, t, len);
+}
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_decode_ETYPE_INFO2 (krb5_context context,
+ const void *data,
+ size_t length,
+ ETYPE_INFO2 *t,
+ size_t *len)
+{
+ return decode_ETYPE_INFO2(data, length, t, len);
+}
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_encode_ETYPE_INFO2 (krb5_context context,
+ void *data,
+ size_t length,
+ ETYPE_INFO2 *t,
+ size_t *len)
+{
+ return encode_ETYPE_INFO2 (data, length, t, len);
+}
diff --git a/source4/heimdal/lib/krb5/config_file.c b/source4/heimdal/lib/krb5/config_file.c
new file mode 100644
index 0000000000..86e286c638
--- /dev/null
+++ b/source4/heimdal/lib/krb5/config_file.c
@@ -0,0 +1,773 @@
+/*
+ * Copyright (c) 1997 - 2004 Kungliga Tekniska Högskolan
+ * (Royal Institute of Technology, Stockholm, Sweden).
+ * 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"
+RCSID("$Id: config_file.c,v 1.53 2005/06/16 20:22:53 lha Exp $");
+
+#ifndef HAVE_NETINFO
+
+/* Gaah! I want a portable funopen */
+struct fileptr {
+ const char *s;
+ FILE *f;
+};
+
+static char *
+config_fgets(char *str, size_t len, struct fileptr *ptr)
+{
+ /* XXX this is not correct, in that they don't do the same if the
+ line is longer than len */
+ if(ptr->f != NULL)
+ return fgets(str, len, ptr->f);
+ else {
+ /* this is almost strsep_copy */
+ const char *p;
+ ssize_t l;
+ if(*ptr->s == '\0')
+ return NULL;
+ p = ptr->s + strcspn(ptr->s, "\n");
+ if(*p == '\n')
+ p++;
+ l = min(len, p - ptr->s);
+ if(len > 0) {
+ memcpy(str, ptr->s, l);
+ str[l] = '\0';
+ }
+ ptr->s = p;
+ return str;
+ }
+}
+
+static krb5_error_code parse_section(char *p, krb5_config_section **s,
+ krb5_config_section **res,
+ const char **error_message);
+static krb5_error_code parse_binding(struct fileptr *f, unsigned *lineno, char *p,
+ krb5_config_binding **b,
+ krb5_config_binding **parent,
+ const char **error_message);
+static krb5_error_code parse_list(struct fileptr *f, unsigned *lineno,
+ krb5_config_binding **parent,
+ const char **error_message);
+
+static krb5_config_section *
+get_entry(krb5_config_section **parent, const char *name, int type)
+{
+ krb5_config_section **q;
+
+ for(q = parent; *q != NULL; q = &(*q)->next)
+ if(type == krb5_config_list &&
+ type == (*q)->type &&
+ strcmp(name, (*q)->name) == 0)
+ return *q;
+ *q = calloc(1, sizeof(**q));
+ if(*q == NULL)
+ return NULL;
+ (*q)->name = strdup(name);
+ (*q)->type = type;
+ if((*q)->name == NULL) {
+ free(*q);
+ *q = NULL;
+ return NULL;
+ }
+ return *q;
+}
+
+/*
+ * Parse a section:
+ *
+ * [section]
+ * foo = bar
+ * b = {
+ * a
+ * }
+ * ...
+ *
+ * starting at the line in `p', storing the resulting structure in
+ * `s' and hooking it into `parent'.
+ * Store the error message in `error_message'.
+ */
+
+static krb5_error_code
+parse_section(char *p, krb5_config_section **s, krb5_config_section **parent,
+ const char **error_message)
+{
+ char *p1;
+ krb5_config_section *tmp;
+
+ p1 = strchr (p + 1, ']');
+ if (p1 == NULL) {
+ *error_message = "missing ]";
+ return KRB5_CONFIG_BADFORMAT;
+ }
+ *p1 = '\0';
+ tmp = get_entry(parent, p + 1, krb5_config_list);
+ if(tmp == NULL) {
+ *error_message = "out of memory";
+ return KRB5_CONFIG_BADFORMAT;
+ }
+ *s = tmp;
+ return 0;
+}
+
+/*
+ * Parse a brace-enclosed list from `f', hooking in the structure at
+ * `parent'.
+ * Store the error message in `error_message'.
+ */
+
+static krb5_error_code
+parse_list(struct fileptr *f, unsigned *lineno, krb5_config_binding **parent,
+ const char **error_message)
+{
+ char buf[BUFSIZ];
+ krb5_error_code ret;
+ krb5_config_binding *b = NULL;
+ unsigned beg_lineno = *lineno;
+
+ while(config_fgets(buf, sizeof(buf), f) != NULL) {
+ char *p;
+
+ ++*lineno;
+ if (buf[strlen(buf) - 1] == '\n')
+ buf[strlen(buf) - 1] = '\0';
+ p = buf;
+ while(isspace((unsigned char)*p))
+ ++p;
+ if (*p == '#' || *p == ';' || *p == '\0')
+ continue;
+ while(isspace((unsigned char)*p))
+ ++p;
+ if (*p == '}')
+ return 0;
+ if (*p == '\0')
+ continue;
+ ret = parse_binding (f, lineno, p, &b, parent, error_message);
+ if (ret)
+ return ret;
+ }
+ *lineno = beg_lineno;
+ *error_message = "unclosed {";
+ return KRB5_CONFIG_BADFORMAT;
+}
+
+/*
+ *
+ */
+
+static krb5_error_code
+parse_binding(struct fileptr *f, unsigned *lineno, char *p,
+ krb5_config_binding **b, krb5_config_binding **parent,
+ const char **error_message)
+{
+ krb5_config_binding *tmp;
+ char *p1, *p2;
+ krb5_error_code ret = 0;
+
+ p1 = p;
+ while (*p && *p != '=' && !isspace((unsigned char)*p))
+ ++p;
+ if (*p == '\0') {
+ *error_message = "missing =";
+ return KRB5_CONFIG_BADFORMAT;
+ }
+ p2 = p;
+ while (isspace((unsigned char)*p))
+ ++p;
+ if (*p != '=') {
+ *error_message = "missing =";
+ return KRB5_CONFIG_BADFORMAT;
+ }
+ ++p;
+ while(isspace((unsigned char)*p))
+ ++p;
+ *p2 = '\0';
+ if (*p == '{') {
+ tmp = get_entry(parent, p1, krb5_config_list);
+ if (tmp == NULL) {
+ *error_message = "out of memory";
+ return KRB5_CONFIG_BADFORMAT;
+ }
+ ret = parse_list (f, lineno, &tmp->u.list, error_message);
+ } else {
+ tmp = get_entry(parent, p1, krb5_config_string);
+ if (tmp == NULL) {
+ *error_message = "out of memory";
+ return KRB5_CONFIG_BADFORMAT;
+ }
+ p1 = p;
+ p = p1 + strlen(p1);
+ while(p > p1 && isspace((unsigned char)*(p-1)))
+ --p;
+ *p = '\0';
+ tmp->u.string = strdup(p1);
+ }
+ *b = tmp;
+ return ret;
+}
+
+/*
+ * Parse the config file `fname', generating the structures into `res'
+ * returning error messages in `error_message'
+ */
+
+static krb5_error_code
+krb5_config_parse_debug (struct fileptr *f,
+ krb5_config_section **res,
+ unsigned *lineno,
+ const char **error_message)
+{
+ krb5_config_section *s = NULL;
+ krb5_config_binding *b = NULL;
+ char buf[BUFSIZ];
+ krb5_error_code ret;
+
+ while (config_fgets(buf, sizeof(buf), f) != NULL) {
+ char *p;
+
+ ++*lineno;
+ if(buf[strlen(buf) - 1] == '\n')
+ buf[strlen(buf) - 1] = '\0';
+ p = buf;
+ while(isspace((unsigned char)*p))
+ ++p;
+ if (*p == '#' || *p == ';')
+ continue;
+ if (*p == '[') {
+ ret = parse_section(p, &s, res, error_message);
+ if (ret)
+ return ret;
+ b = NULL;
+ } else if (*p == '}') {
+ *error_message = "unmatched }";
+ return EINVAL; /* XXX */
+ } else if(*p != '\0') {
+ if (s == NULL) {
+ *error_message = "binding before section";
+ return EINVAL;
+ }
+ ret = parse_binding(f, lineno, p, &b, &s->u.list, error_message);
+ if (ret)
+ return ret;
+ }
+ }
+ return 0;
+}
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_config_parse_string_multi(krb5_context context,
+ const char *string,
+ krb5_config_section **res)
+{
+ const char *str;
+ unsigned lineno = 0;
+ krb5_error_code ret;
+ struct fileptr f;
+ f.f = NULL;
+ f.s = string;
+
+ ret = krb5_config_parse_debug (&f, res, &lineno, &str);
+ if (ret) {
+ krb5_set_error_string (context, "%s:%u: %s", "<constant>", lineno, str);
+ return ret;
+ }
+ return 0;
+}
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_config_parse_file_multi (krb5_context context,
+ const char *fname,
+ krb5_config_section **res)
+{
+ const char *str;
+ unsigned lineno = 0;
+ krb5_error_code ret;
+ struct fileptr f;
+ f.f = fopen(fname, "r");
+ f.s = NULL;
+ if(f.f == NULL) {
+ ret = errno;
+ krb5_set_error_string (context, "open %s: %s", fname, strerror(ret));
+ return ret;
+ }
+
+ ret = krb5_config_parse_debug (&f, res, &lineno, &str);
+ fclose(f.f);
+ if (ret) {
+ krb5_set_error_string (context, "%s:%u: %s", fname, lineno, str);
+ return ret;
+ }
+ return 0;
+}
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_config_parse_file (krb5_context context,
+ const char *fname,
+ krb5_config_section **res)
+{
+ *res = NULL;
+ return krb5_config_parse_file_multi(context, fname, res);
+}
+
+#endif /* !HAVE_NETINFO */
+
+static void
+free_binding (krb5_context context, krb5_config_binding *b)
+{
+ krb5_config_binding *next_b;
+
+ while (b) {
+ free (b->name);
+ if (b->type == krb5_config_string)
+ free (b->u.string);
+ else if (b->type == krb5_config_list)
+ free_binding (context, b->u.list);
+ else
+ krb5_abortx(context, "unknown binding type (%d) in free_binding",
+ b->type);
+ next_b = b->next;
+ free (b);
+ b = next_b;
+ }
+}
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_config_file_free (krb5_context context, krb5_config_section *s)
+{
+ free_binding (context, s);
+ return 0;
+}
+
+const void *
+krb5_config_get_next (krb5_context context,
+ const krb5_config_section *c,
+ const krb5_config_binding **pointer,
+ int type,
+ ...)
+{
+ const char *ret;
+ va_list args;
+
+ va_start(args, type);
+ ret = krb5_config_vget_next (context, c, pointer, type, args);
+ va_end(args);
+ return ret;
+}
+
+static const void *
+vget_next(krb5_context context,
+ const krb5_config_binding *b,
+ const krb5_config_binding **pointer,
+ int type,
+ const char *name,
+ va_list args)
+{
+ const char *p = va_arg(args, const char *);
+ while(b != NULL) {
+ if(strcmp(b->name, name) == 0) {
+ if(b->type == type && p == NULL) {
+ *pointer = b;
+ return b->u.generic;
+ } else if(b->type == krb5_config_list && p != NULL) {
+ return vget_next(context, b->u.list, pointer, type, p, args);
+ }
+ }
+ b = b->next;
+ }
+ return NULL;
+}
+
+const void *
+krb5_config_vget_next (krb5_context context,
+ const krb5_config_section *c,
+ const krb5_config_binding **pointer,
+ int type,
+ va_list args)
+{
+ const krb5_config_binding *b;
+ const char *p;
+
+ if(c == NULL)
+ c = context->cf;
+
+ if (c == NULL)
+ return NULL;
+
+ if (*pointer == NULL) {
+ /* first time here, walk down the tree looking for the right
+ section */
+ p = va_arg(args, const char *);
+ if (p == NULL)
+ return NULL;
+ return vget_next(context, c, pointer, type, p, args);
+ }
+
+ /* we were called again, so just look for more entries with the
+ same name and type */
+ for (b = (*pointer)->next; b != NULL; b = b->next) {
+ if(strcmp(b->name, (*pointer)->name) == 0 && b->type == type) {
+ *pointer = b;
+ return b->u.generic;
+ }
+ }
+ return NULL;
+}
+
+const void *
+krb5_config_get (krb5_context context,
+ const krb5_config_section *c,
+ int type,
+ ...)
+{
+ const void *ret;
+ va_list args;
+
+ va_start(args, type);
+ ret = krb5_config_vget (context, c, type, args);
+ va_end(args);
+ return ret;
+}
+
+const void *
+krb5_config_vget (krb5_context context,
+ const krb5_config_section *c,
+ int type,
+ va_list args)
+{
+ const krb5_config_binding *foo = NULL;
+
+ return krb5_config_vget_next (context, c, &foo, type, args);
+}
+
+const krb5_config_binding *
+krb5_config_get_list (krb5_context context,
+ const krb5_config_section *c,
+ ...)
+{
+ const krb5_config_binding *ret;
+ va_list args;
+
+ va_start(args, c);
+ ret = krb5_config_vget_list (context, c, args);
+ va_end(args);
+ return ret;
+}
+
+const krb5_config_binding *
+krb5_config_vget_list (krb5_context context,
+ const krb5_config_section *c,
+ va_list args)
+{
+ return krb5_config_vget (context, c, krb5_config_list, args);
+}
+
+const char* KRB5_LIB_FUNCTION
+krb5_config_get_string (krb5_context context,
+ const krb5_config_section *c,
+ ...)
+{
+ const char *ret;
+ va_list args;
+
+ va_start(args, c);
+ ret = krb5_config_vget_string (context, c, args);
+ va_end(args);
+ return ret;
+}
+
+const char* KRB5_LIB_FUNCTION
+krb5_config_vget_string (krb5_context context,
+ const krb5_config_section *c,
+ va_list args)
+{
+ return krb5_config_vget (context, c, krb5_config_string, args);
+}
+
+const char* KRB5_LIB_FUNCTION
+krb5_config_vget_string_default (krb5_context context,
+ const krb5_config_section *c,
+ const char *def_value,
+ va_list args)
+{
+ const char *ret;
+
+ ret = krb5_config_vget_string (context, c, args);
+ if (ret == NULL)
+ ret = def_value;
+ return ret;
+}
+
+const char* KRB5_LIB_FUNCTION
+krb5_config_get_string_default (krb5_context context,
+ const krb5_config_section *c,
+ const char *def_value,
+ ...)
+{
+ const char *ret;
+ va_list args;
+
+ va_start(args, def_value);
+ ret = krb5_config_vget_string_default (context, c, def_value, args);
+ va_end(args);
+ return ret;
+}
+
+char ** KRB5_LIB_FUNCTION
+krb5_config_vget_strings(krb5_context context,
+ const krb5_config_section *c,
+ va_list args)
+{
+ char **strings = NULL;
+ int nstr = 0;
+ const krb5_config_binding *b = NULL;
+ const char *p;
+
+ while((p = krb5_config_vget_next(context, c, &b,
+ krb5_config_string, args))) {
+ char *tmp = strdup(p);
+ char *pos = NULL;
+ char *s;
+ if(tmp == NULL)
+ goto cleanup;
+ s = strtok_r(tmp, " \t", &pos);
+ while(s){
+ char **tmp2 = realloc(strings, (nstr + 1) * sizeof(*strings));
+ if(tmp2 == NULL)
+ goto cleanup;
+ strings = tmp2;
+ strings[nstr] = strdup(s);
+ nstr++;
+ if(strings[nstr-1] == NULL)
+ goto cleanup;
+ s = strtok_r(NULL, " \t", &pos);
+ }
+ free(tmp);
+ }
+ if(nstr){
+ char **tmp = realloc(strings, (nstr + 1) * sizeof(*strings));
+ if(strings == NULL)
+ goto cleanup;
+ strings = tmp;
+ strings[nstr] = NULL;
+ }
+ return strings;
+cleanup:
+ while(nstr--)
+ free(strings[nstr]);
+ free(strings);
+ return NULL;
+
+}
+
+char**
+krb5_config_get_strings(krb5_context context,
+ const krb5_config_section *c,
+ ...)
+{
+ va_list ap;
+ char **ret;
+ va_start(ap, c);
+ ret = krb5_config_vget_strings(context, c, ap);
+ va_end(ap);
+ return ret;
+}
+
+void KRB5_LIB_FUNCTION
+krb5_config_free_strings(char **strings)
+{
+ char **s = strings;
+ while(s && *s){
+ free(*s);
+ s++;
+ }
+ free(strings);
+}
+
+krb5_boolean KRB5_LIB_FUNCTION
+krb5_config_vget_bool_default (krb5_context context,
+ const krb5_config_section *c,
+ krb5_boolean def_value,
+ va_list args)
+{
+ const char *str;
+ str = krb5_config_vget_string (context, c, args);
+ if(str == NULL)
+ return def_value;
+ if(strcasecmp(str, "yes") == 0 ||
+ strcasecmp(str, "true") == 0 ||
+ atoi(str)) return TRUE;
+ return FALSE;
+}
+
+krb5_boolean KRB5_LIB_FUNCTION
+krb5_config_vget_bool (krb5_context context,
+ const krb5_config_section *c,
+ va_list args)
+{
+ return krb5_config_vget_bool_default (context, c, FALSE, args);
+}
+
+krb5_boolean KRB5_LIB_FUNCTION
+krb5_config_get_bool_default (krb5_context context,
+ const krb5_config_section *c,
+ krb5_boolean def_value,
+ ...)
+{
+ va_list ap;
+ krb5_boolean ret;
+ va_start(ap, def_value);
+ ret = krb5_config_vget_bool_default(context, c, def_value, ap);
+ va_end(ap);
+ return ret;
+}
+
+krb5_boolean KRB5_LIB_FUNCTION
+krb5_config_get_bool (krb5_context context,
+ const krb5_config_section *c,
+ ...)
+{
+ va_list ap;
+ krb5_boolean ret;
+ va_start(ap, c);
+ ret = krb5_config_vget_bool (context, c, ap);
+ va_end(ap);
+ return ret;
+}
+
+int KRB5_LIB_FUNCTION
+krb5_config_vget_time_default (krb5_context context,
+ const krb5_config_section *c,
+ int def_value,
+ va_list args)
+{
+ const char *str;
+ krb5_deltat t;
+
+ str = krb5_config_vget_string (context, c, args);
+ if(str == NULL)
+ return def_value;
+ if (krb5_string_to_deltat(str, &t))
+ return def_value;
+ return t;
+}
+
+int KRB5_LIB_FUNCTION
+krb5_config_vget_time (krb5_context context,
+ const krb5_config_section *c,
+ va_list args)
+{
+ return krb5_config_vget_time_default (context, c, -1, args);
+}
+
+int KRB5_LIB_FUNCTION
+krb5_config_get_time_default (krb5_context context,
+ const krb5_config_section *c,
+ int def_value,
+ ...)
+{
+ va_list ap;
+ int ret;
+ va_start(ap, def_value);
+ ret = krb5_config_vget_time_default(context, c, def_value, ap);
+ va_end(ap);
+ return ret;
+}
+
+int KRB5_LIB_FUNCTION
+krb5_config_get_time (krb5_context context,
+ const krb5_config_section *c,
+ ...)
+{
+ va_list ap;
+ int ret;
+ va_start(ap, c);
+ ret = krb5_config_vget_time (context, c, ap);
+ va_end(ap);
+ return ret;
+}
+
+
+int KRB5_LIB_FUNCTION
+krb5_config_vget_int_default (krb5_context context,
+ const krb5_config_section *c,
+ int def_value,
+ va_list args)
+{
+ const char *str;
+ str = krb5_config_vget_string (context, c, args);
+ if(str == NULL)
+ return def_value;
+ else {
+ char *endptr;
+ long l;
+ l = strtol(str, &endptr, 0);
+ if (endptr == str)
+ return def_value;
+ else
+ return l;
+ }
+}
+
+int KRB5_LIB_FUNCTION
+krb5_config_vget_int (krb5_context context,
+ const krb5_config_section *c,
+ va_list args)
+{
+ return krb5_config_vget_int_default (context, c, -1, args);
+}
+
+int KRB5_LIB_FUNCTION
+krb5_config_get_int_default (krb5_context context,
+ const krb5_config_section *c,
+ int def_value,
+ ...)
+{
+ va_list ap;
+ int ret;
+ va_start(ap, def_value);
+ ret = krb5_config_vget_int_default(context, c, def_value, ap);
+ va_end(ap);
+ return ret;
+}
+
+int KRB5_LIB_FUNCTION
+krb5_config_get_int (krb5_context context,
+ const krb5_config_section *c,
+ ...)
+{
+ va_list ap;
+ int ret;
+ va_start(ap, c);
+ ret = krb5_config_vget_int (context, c, ap);
+ va_end(ap);
+ return ret;
+}
diff --git a/source4/heimdal/lib/krb5/config_file_netinfo.c b/source4/heimdal/lib/krb5/config_file_netinfo.c
new file mode 100644
index 0000000000..6e72509ab6
--- /dev/null
+++ b/source4/heimdal/lib/krb5/config_file_netinfo.c
@@ -0,0 +1,180 @@
+/*
+ * Copyright (c) 1997 - 2001 Kungliga Tekniska Högskolan
+ * (Royal Institute of Technology, Stockholm, Sweden).
+ * 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"
+RCSID("$Id: config_file_netinfo.c,v 1.4 2004/05/25 21:20:18 lha Exp $");
+
+/*
+ * Netinfo implementation from Luke Howard <lukeh@xedoc.com.au>
+ */
+
+#ifdef HAVE_NETINFO
+#include <netinfo/ni.h>
+static ni_status
+ni_proplist2binding(ni_proplist *pl, krb5_config_section **ret)
+{
+ int i, j;
+ krb5_config_section **next = NULL;
+
+ for (i = 0; i < pl->ni_proplist_len; i++) {
+ if (!strcmp(pl->nipl_val[i].nip_name, "name"))
+ continue;
+
+ for (j = 0; j < pl->nipl_val[i].nip_val.ni_namelist_len; j++) {
+ krb5_config_binding *b;
+
+ b = malloc(sizeof(*b));
+ if (b == NULL)
+ return NI_FAILED;
+
+ b->next = NULL;
+ b->type = krb5_config_string;
+ b->name = ni_name_dup(pl->nipl_val[i].nip_name);
+ b->u.string = ni_name_dup(pl->nipl_val[i].nip_val.ninl_val[j]);
+
+ if (next == NULL) {
+ *ret = b;
+ } else {
+ *next = b;
+ }
+ next = &b->next;
+ }
+ }
+ return NI_OK;
+}
+
+static ni_status
+ni_idlist2binding(void *ni, ni_idlist *idlist, krb5_config_section **ret)
+{
+ int i;
+ ni_status nis;
+ krb5_config_section **next;
+
+ for (i = 0; i < idlist->ni_idlist_len; i++) {
+ ni_proplist pl;
+ ni_id nid;
+ ni_idlist children;
+ krb5_config_binding *b;
+ ni_index index;
+
+ nid.nii_instance = 0;
+ nid.nii_object = idlist->ni_idlist_val[i];
+
+ nis = ni_read(ni, &nid, &pl);
+
+ if (nis != NI_OK) {
+ return nis;
+ }
+ index = ni_proplist_match(pl, "name", NULL);
+ b = malloc(sizeof(*b));
+ if (b == NULL) return NI_FAILED;
+
+ if (i == 0) {
+ *ret = b;
+ } else {
+ *next = b;
+ }
+
+ b->type = krb5_config_list;
+ b->name = ni_name_dup(pl.nipl_val[index].nip_val.ninl_val[0]);
+ b->next = NULL;
+ b->u.list = NULL;
+
+ /* get the child directories */
+ nis = ni_children(ni, &nid, &children);
+ if (nis == NI_OK) {
+ nis = ni_idlist2binding(ni, &children, &b->u.list);
+ if (nis != NI_OK) {
+ return nis;
+ }
+ }
+
+ nis = ni_proplist2binding(&pl, b->u.list == NULL ? &b->u.list : &b->u.list->next);
+ ni_proplist_free(&pl);
+ if (nis != NI_OK) {
+ return nis;
+ }
+ next = &b->next;
+ }
+ ni_idlist_free(idlist);
+ return NI_OK;
+}
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_config_parse_file (krb5_context context,
+ const char *fname,
+ krb5_config_section **res)
+{
+ void *ni = NULL, *lastni = NULL;
+ int i;
+ ni_status nis;
+ ni_id nid;
+ ni_idlist children;
+
+ krb5_config_section *s;
+ int ret;
+
+ s = NULL;
+
+ for (i = 0; i < 256; i++) {
+ if (i == 0) {
+ nis = ni_open(NULL, ".", &ni);
+ } else {
+ if (lastni != NULL) ni_free(lastni);
+ lastni = ni;
+ nis = ni_open(lastni, "..", &ni);
+ }
+ if (nis != NI_OK)
+ break;
+ nis = ni_pathsearch(ni, &nid, "/locations/kerberos");
+ if (nis == NI_OK) {
+ nis = ni_children(ni, &nid, &children);
+ if (nis != NI_OK)
+ break;
+ nis = ni_idlist2binding(ni, &children, &s);
+ break;
+ }
+ }
+
+ if (ni != NULL) ni_free(ni);
+ if (ni != lastni && lastni != NULL) ni_free(lastni);
+
+ ret = (nis == NI_OK) ? 0 : -1;
+ if (ret == 0) {
+ *res = s;
+ } else {
+ *res = NULL;
+ }
+ return ret;
+}
+#endif /* HAVE_NETINFO */
diff --git a/source4/heimdal/lib/krb5/constants.c b/source4/heimdal/lib/krb5/constants.c
new file mode 100644
index 0000000000..89ebc34a1a
--- /dev/null
+++ b/source4/heimdal/lib/krb5/constants.c
@@ -0,0 +1,43 @@
+/*
+ * Copyright (c) 1997-2004 Kungliga Tekniska Högskolan
+ * (Royal Institute of Technology, Stockholm, Sweden).
+ * 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"
+
+RCSID("$Id: constants.c,v 1.8 2004/09/23 07:57:37 joda Exp $");
+
+const char *krb5_config_file =
+#ifdef __APPLE__
+"/Library/Preferences/edu.mit.Kerberos:"
+#endif
+SYSCONFDIR "/krb5.conf:/etc/krb5.conf";
+const char *krb5_defkeyname = KEYTAB_DEFAULT;
diff --git a/source4/heimdal/lib/krb5/context.c b/source4/heimdal/lib/krb5/context.c
new file mode 100644
index 0000000000..62fb92d666
--- /dev/null
+++ b/source4/heimdal/lib/krb5/context.c
@@ -0,0 +1,663 @@
+/*
+ * Copyright (c) 1997 - 2005 Kungliga Tekniska Högskolan
+ * (Royal Institute of Technology, Stockholm, Sweden).
+ * 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>
+
+RCSID("$Id: context.c,v 1.102 2005/05/18 04:20:50 lha Exp $");
+
+#define INIT_FIELD(C, T, E, D, F) \
+ (C)->E = krb5_config_get_ ## T ## _default ((C), NULL, (D), \
+ "libdefaults", F, NULL)
+
+/*
+ * 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_string (context, "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;
+ 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, 6000, "large_message_size");
+ context->default_cc_name = NULL;
+ return 0;
+}
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_init_context(krb5_context *context)
+{
+ krb5_context p;
+ krb5_error_code ret;
+ char **files;
+
+ *context = NULL;
+
+ 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);
+
+ 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);
+
+ p->cc_ops = NULL;
+ p->num_cc_ops = 0;
+ krb5_cc_register(p, &krb5_acc_ops, TRUE);
+ krb5_cc_register(p, &krb5_fcc_ops, TRUE);
+ krb5_cc_register(p, &krb5_mcc_ops, TRUE);
+#ifdef HAVE_KCM
+ krb5_cc_register(p, &krb5_kcm_ops, TRUE);
+#endif
+
+ p->num_kt_types = 0;
+ p->kt_types = NULL;
+ krb5_kt_register (p, &krb5_fkt_ops);
+ krb5_kt_register (p, &krb5_wrfkt_ops);
+ krb5_kt_register (p, &krb5_javakt_ops);
+ krb5_kt_register (p, &krb5_mkt_ops);
+ krb5_kt_register (p, &krb5_mktw_ops);
+ krb5_kt_register (p, &krb5_akf_ops);
+ krb5_kt_register (p, &krb4_fkt_ops);
+ krb5_kt_register (p, &krb5_srvtab_fkt_ops);
+ krb5_kt_register (p, &krb5_any_ops);
+
+out:
+ if(ret) {
+ krb5_free_context(p);
+ p = NULL;
+ }
+ *context = p;
+ return ret;
+}
+
+void KRB5_LIB_FUNCTION
+krb5_free_context(krb5_context context)
+{
+ if (context->default_cc_name)
+ free(context->default_cc_name);
+ 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_string(context);
+ if(context->warn_dest != NULL)
+ krb5_closelog(context, context->warn_dest);
+ krb5_set_extra_addresses(context, NULL);
+ krb5_set_ignore_addresses(context, NULL);
+ if (context->mutex != NULL) {
+ HEIMDAL_MUTEX_destroy(context->mutex);
+ free(context->mutex);
+ }
+ memset(context, 0, sizeof(*context));
+ free(context);
+}
+
+krb5_error_code KRB5_LIB_FUNCTION
+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) {
+ 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, its up the the caller
+ */
+
+krb5_error_code KRB5_LIB_FUNCTION
+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;
+ }
+ l = 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;
+}
+
+krb5_error_code KRB5_LIB_FUNCTION
+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;
+}
+
+krb5_error_code KRB5_LIB_FUNCTION
+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);
+}
+
+void KRB5_LIB_FUNCTION
+krb5_free_config_files(char **filenames)
+{
+ char **p;
+ for(p = filenames; *p != NULL; p++)
+ free(*p);
+ free(filenames);
+}
+
+/*
+ * set `etype' to a malloced list of the default enctypes
+ */
+
+static krb5_error_code
+default_etypes(krb5_context context, krb5_enctype **etype)
+{
+ 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
+ };
+ krb5_enctype *e = NULL, *ep;
+ int i, n = 0;
+
+ for (i = 0; i < sizeof(p)/sizeof(p[0]); 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_string (context, "malloc: out of memory");
+ return ENOMEM;
+ }
+ e = ep;
+ e[n] = p[i];
+ e[n + 1] = ETYPE_NULL;
+ n++;
+ }
+ *etype = e;
+ return 0;
+}
+
+krb5_error_code KRB5_LIB_FUNCTION
+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_string (context, "malloc: out of memory");
+ return ENOMEM;
+ }
+ memmove(p, etypes, i * sizeof(krb5_enctype));
+ }
+ if(context->etypes)
+ free(context->etypes);
+ context->etypes = p;
+ return 0;
+}
+
+
+krb5_error_code KRB5_LIB_FUNCTION
+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_string (context, "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;
+}
+
+const char* KRB5_LIB_FUNCTION
+krb5_get_err_text(krb5_context context, krb5_error_code code)
+{
+ const char *p = NULL;
+ if(context != NULL)
+ p = com_right(context->et_list, code);
+ if(p == NULL)
+ p = strerror(code);
+ if (p == NULL)
+ p = "Unknown error";
+ return p;
+}
+
+void KRB5_LIB_FUNCTION
+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);
+ }
+}
+
+void KRB5_LIB_FUNCTION
+krb5_set_use_admin_kdc (krb5_context context, krb5_boolean flag)
+{
+ context->use_admin_kdc = flag;
+}
+
+krb5_boolean KRB5_LIB_FUNCTION
+krb5_get_use_admin_kdc (krb5_context context)
+{
+ return context->use_admin_kdc;
+}
+
+krb5_error_code KRB5_LIB_FUNCTION
+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);
+}
+
+krb5_error_code KRB5_LIB_FUNCTION
+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_string (context, "malloc: out of memory");
+ return ENOMEM;
+ }
+ }
+ return krb5_copy_addresses(context, addresses, context->extra_addresses);
+}
+
+krb5_error_code KRB5_LIB_FUNCTION
+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);
+}
+
+krb5_error_code KRB5_LIB_FUNCTION
+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);
+}
+
+krb5_error_code KRB5_LIB_FUNCTION
+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_string (context, "malloc: out of memory");
+ return ENOMEM;
+ }
+ }
+ return krb5_copy_addresses(context, addresses, context->ignore_addresses);
+}
+
+krb5_error_code KRB5_LIB_FUNCTION
+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);
+}
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_set_fcache_version(krb5_context context, int version)
+{
+ context->fcache_vno = version;
+ return 0;
+}
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_get_fcache_version(krb5_context context, int *version)
+{
+ *version = context->fcache_vno;
+ return 0;
+}
+
+krb5_boolean KRB5_LIB_FUNCTION
+krb5_is_thread_safe(void)
+{
+#ifdef ENABLE_PTHREAD_SUPPORT
+ return TRUE;
+#else
+ return FALSE;
+#endif
+}
diff --git a/source4/heimdal/lib/krb5/copy_host_realm.c b/source4/heimdal/lib/krb5/copy_host_realm.c
new file mode 100644
index 0000000000..eb77fba024
--- /dev/null
+++ b/source4/heimdal/lib/krb5/copy_host_realm.c
@@ -0,0 +1,69 @@
+/*
+ * Copyright (c) 1999 - 2001 Kungliga Tekniska Högskolan
+ * (Royal Institute of Technology, Stockholm, Sweden).
+ * 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"
+
+RCSID("$Id: copy_host_realm.c,v 1.5 2004/05/25 21:21:17 lha Exp $");
+
+/*
+ * Copy the list of realms from `from' to `to'.
+ */
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_copy_host_realm(krb5_context context,
+ const krb5_realm *from,
+ krb5_realm **to)
+{
+ int n, i;
+ const krb5_realm *p;
+
+ for (n = 0, p = from; *p != NULL; ++p)
+ ++n;
+ ++n;
+ *to = malloc (n * sizeof(**to));
+ if (*to == NULL) {
+ krb5_set_error_string (context, "malloc: out of memory");
+ return ENOMEM;
+ }
+ for (i = 0; i < n; ++i)
+ (*to)[i] = NULL;
+ for (i = 0, p = from; *p != NULL; ++p, ++i) {
+ (*to)[i] = strdup(*p);
+ if ((*to)[i] == NULL) {
+ krb5_free_host_realm (context, *to);
+ krb5_set_error_string (context, "malloc: out of memory");
+ return ENOMEM;
+ }
+ }
+ return 0;
+}
diff --git a/source4/heimdal/lib/krb5/crc.c b/source4/heimdal/lib/krb5/crc.c
new file mode 100644
index 0000000000..c7cedd8c9e
--- /dev/null
+++ b/source4/heimdal/lib/krb5/crc.c
@@ -0,0 +1,71 @@
+/*
+ * Copyright (c) 1997 - 2000 Kungliga Tekniska Högskolan
+ * (Royal Institute of Technology, Stockholm, Sweden).
+ * 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"
+
+RCSID("$Id: crc.c,v 1.9 2000/08/03 01:45:14 assar Exp $");
+
+static u_long table[256];
+
+#define CRC_GEN 0xEDB88320L
+
+void
+_krb5_crc_init_table(void)
+{
+ static int flag = 0;
+ unsigned long crc, poly;
+ int i, j;
+
+ if(flag) return;
+ poly = CRC_GEN;
+ for (i = 0; i < 256; i++) {
+ crc = i;
+ for (j = 8; j > 0; j--) {
+ if (crc & 1) {
+ crc = (crc >> 1) ^ poly;
+ } else {
+ crc >>= 1;
+ }
+ }
+ table[i] = crc;
+ }
+ flag = 1;
+}
+
+u_int32_t
+_krb5_crc_update (const char *p, size_t len, u_int32_t res)
+{
+ while (len--)
+ res = table[(res ^ *p++) & 0xFF] ^ (res >> 8);
+ return res & 0xFFFFFFFF;
+}
diff --git a/source4/heimdal/lib/krb5/creds.c b/source4/heimdal/lib/krb5/creds.c
new file mode 100644
index 0000000000..2afd0725f1
--- /dev/null
+++ b/source4/heimdal/lib/krb5/creds.c
@@ -0,0 +1,215 @@
+/*
+ * Copyright (c) 1997 - 2005 Kungliga Tekniska Högskolan
+ * (Royal Institute of Technology, Stockholm, Sweden).
+ * 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"
+
+RCSID("$Id: creds.c,v 1.20 2005/05/18 04:21:04 lha Exp $");
+
+/* keep this for compatibility with older code */
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_free_creds_contents (krb5_context context, krb5_creds *c)
+{
+ return krb5_free_cred_contents (context, c);
+}
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_free_cred_contents (krb5_context context, krb5_creds *c)
+{
+ krb5_free_principal (context, c->client);
+ c->client = NULL;
+ krb5_free_principal (context, c->server);
+ c->server = NULL;
+ krb5_free_keyblock_contents (context, &c->session);
+ krb5_data_free (&c->ticket);
+ krb5_data_free (&c->second_ticket);
+ free_AuthorizationData (&c->authdata);
+ krb5_free_addresses (context, &c->addresses);
+ memset(c, 0, sizeof(*c));
+ return 0;
+}
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_copy_creds_contents (krb5_context context,
+ const krb5_creds *incred,
+ krb5_creds *c)
+{
+ krb5_error_code ret;
+
+ memset(c, 0, sizeof(*c));
+ ret = krb5_copy_principal (context, incred->client, &c->client);
+ if (ret)
+ goto fail;
+ ret = krb5_copy_principal (context, incred->server, &c->server);
+ if (ret)
+ goto fail;
+ ret = krb5_copy_keyblock_contents (context, &incred->session, &c->session);
+ if (ret)
+ goto fail;
+ c->times = incred->times;
+ ret = krb5_data_copy (&c->ticket,
+ incred->ticket.data,
+ incred->ticket.length);
+ if (ret)
+ goto fail;
+ ret = krb5_data_copy (&c->second_ticket,
+ incred->second_ticket.data,
+ incred->second_ticket.length);
+ if (ret)
+ goto fail;
+ ret = copy_AuthorizationData(&incred->authdata, &c->authdata);
+ if (ret)
+ goto fail;
+ ret = krb5_copy_addresses (context,
+ &incred->addresses,
+ &c->addresses);
+ if (ret)
+ goto fail;
+ c->flags = incred->flags;
+ return 0;
+
+fail:
+ krb5_free_cred_contents (context, c);
+ return ret;
+}
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_copy_creds (krb5_context context,
+ const krb5_creds *incred,
+ krb5_creds **outcred)
+{
+ krb5_creds *c;
+
+ c = malloc (sizeof (*c));
+ if (c == NULL) {
+ krb5_set_error_string (context, "malloc: out of memory");
+ return ENOMEM;
+ }
+ memset (c, 0, sizeof(*c));
+ *outcred = c;
+ return krb5_copy_creds_contents (context, incred, c);
+}
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_free_creds (krb5_context context, krb5_creds *c)
+{
+ krb5_free_cred_contents (context, c);
+ free (c);
+ return 0;
+}
+
+/* XXX these do not belong here */
+static krb5_boolean
+krb5_data_equal(const krb5_data *a, const krb5_data *b)
+{
+ if(a->length != b->length)
+ return FALSE;
+ return memcmp(a->data, b->data, a->length) == 0;
+}
+
+static krb5_boolean
+krb5_times_equal(const krb5_times *a, const krb5_times *b)
+{
+ return a->starttime == b->starttime &&
+ a->authtime == b->authtime &&
+ a->endtime == b->endtime &&
+ a->renew_till == b->renew_till;
+}
+
+/*
+ * Return TRUE if `mcreds' and `creds' are equal (`whichfields'
+ * determines what equal means).
+ */
+
+krb5_boolean KRB5_LIB_FUNCTION
+krb5_compare_creds(krb5_context context, krb5_flags whichfields,
+ const krb5_creds * mcreds, const krb5_creds * creds)
+{
+ krb5_boolean match = TRUE;
+
+ if (match && mcreds->server) {
+ if (whichfields & (KRB5_TC_DONT_MATCH_REALM | KRB5_TC_MATCH_SRV_NAMEONLY))
+ match = krb5_principal_compare_any_realm (context, mcreds->server,
+ creds->server);
+ else
+ match = krb5_principal_compare (context, mcreds->server,
+ creds->server);
+ }
+
+ if (match && mcreds->client) {
+ if(whichfields & KRB5_TC_DONT_MATCH_REALM)
+ match = krb5_principal_compare_any_realm (context, mcreds->client,
+ creds->client);
+ else
+ match = krb5_principal_compare (context, mcreds->client,
+ creds->client);
+ }
+
+ if (match && (whichfields & KRB5_TC_MATCH_KEYTYPE))
+ match = krb5_enctypes_compatible_keys(context,
+ mcreds->session.keytype,
+ creds->session.keytype);
+
+ if (match && (whichfields & KRB5_TC_MATCH_FLAGS_EXACT))
+ match = mcreds->flags.i == creds->flags.i;
+
+ if (match && (whichfields & KRB5_TC_MATCH_FLAGS))
+ match = (creds->flags.i & mcreds->flags.i) == mcreds->flags.i;
+
+ if (match && (whichfields & KRB5_TC_MATCH_TIMES_EXACT))
+ match = krb5_times_equal(&mcreds->times, &creds->times);
+
+ if (match && (whichfields & KRB5_TC_MATCH_TIMES))
+ /* compare only expiration times */
+ match = (mcreds->times.renew_till <= creds->times.renew_till) &&
+ (mcreds->times.endtime <= creds->times.endtime);
+
+ if (match && (whichfields & KRB5_TC_MATCH_AUTHDATA)) {
+ unsigned int i;
+ if(mcreds->authdata.len != creds->authdata.len)
+ match = FALSE;
+ else
+ for(i = 0; match && i < mcreds->authdata.len; i++)
+ match = (mcreds->authdata.val[i].ad_type ==
+ creds->authdata.val[i].ad_type) &&
+ krb5_data_equal(&mcreds->authdata.val[i].ad_data,
+ &creds->authdata.val[i].ad_data);
+ }
+ if (match && (whichfields & KRB5_TC_MATCH_2ND_TKT))
+ match = krb5_data_equal(&mcreds->second_ticket, &creds->second_ticket);
+
+ if (match && (whichfields & KRB5_TC_MATCH_IS_SKEY))
+ match = ((mcreds->second_ticket.length == 0) ==
+ (creds->second_ticket.length == 0));
+
+ return match;
+}
diff --git a/source4/heimdal/lib/krb5/crypto.c b/source4/heimdal/lib/krb5/crypto.c
new file mode 100644
index 0000000000..2b1ac3a5c4
--- /dev/null
+++ b/source4/heimdal/lib/krb5/crypto.c
@@ -0,0 +1,4410 @@
+/*
+ * Copyright (c) 1997 - 2005 Kungliga Tekniska Högskolan
+ * (Royal Institute of Technology, Stockholm, Sweden).
+ * 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"
+RCSID("$Id: crypto.c,v 1.123 2005/06/29 22:20:33 lha Exp $");
+
+#undef CRYPTO_DEBUG
+#ifdef CRYPTO_DEBUG
+static void krb5_crypto_debug(krb5_context, int, size_t, krb5_keyblock*);
+#endif
+
+
+struct key_data {
+ krb5_keyblock *key;
+ krb5_data *schedule;
+};
+
+struct key_usage {
+ unsigned usage;
+ struct key_data key;
+};
+
+struct krb5_crypto_data {
+ struct encryption_type *et;
+ struct key_data key;
+ int num_key_usage;
+ struct key_usage *key_usage;
+ void *params;
+};
+
+#define kcrypto_oid_enc(n) { sizeof(n)/sizeof(n[0]), n }
+
+#define CRYPTO_ETYPE(C) ((C)->et->type)
+
+/* bits for `flags' below */
+#define F_KEYED 1 /* checksum is keyed */
+#define F_CPROOF 2 /* checksum is collision proof */
+#define F_DERIVED 4 /* uses derived keys */
+#define F_VARIANT 8 /* uses `variant' keys (6.4.3) */
+#define F_PSEUDO 16 /* not a real protocol type */
+#define F_SPECIAL 32 /* backwards */
+#define F_DISABLED 64 /* enctype/checksum disabled */
+#define F_PADCMS 128 /* padding done like in CMS */
+
+struct salt_type {
+ krb5_salttype type;
+ const char *name;
+ krb5_error_code (*string_to_key)(krb5_context, krb5_enctype, krb5_data,
+ krb5_salt, krb5_data, krb5_keyblock*);
+};
+
+struct key_type {
+ krb5_keytype type; /* XXX */
+ const char *name;
+ size_t bits;
+ size_t size;
+ size_t minsize;
+ size_t schedule_size;
+#if 0
+ krb5_enctype best_etype;
+#endif
+ void (*random_key)(krb5_context, krb5_keyblock*);
+ void (*schedule)(krb5_context, struct key_data *, const void *);
+ struct salt_type *string_to_key;
+ void (*random_to_key)(krb5_context, krb5_keyblock*, const void*, size_t);
+ krb5_error_code (*get_params)(krb5_context, const krb5_data *,
+ void **, krb5_data *);
+ krb5_error_code (*set_params)(krb5_context, const void *,
+ const krb5_data *, krb5_data *);
+};
+
+struct checksum_type {
+ krb5_cksumtype type;
+ const char *name;
+ size_t blocksize;
+ size_t checksumsize;
+ unsigned flags;
+ void (*checksum)(krb5_context context,
+ struct key_data *key,
+ const void *buf, size_t len,
+ unsigned usage,
+ Checksum *csum);
+ krb5_error_code (*verify)(krb5_context context,
+ struct key_data *key,
+ const void *buf, size_t len,
+ unsigned usage,
+ Checksum *csum);
+};
+
+struct encryption_type {
+ krb5_enctype type;
+ const char *name;
+ heim_oid *oid;
+ size_t blocksize;
+ size_t padsize;
+ size_t confoundersize;
+ struct key_type *keytype;
+ struct checksum_type *checksum;
+ struct checksum_type *keyed_checksum;
+ unsigned flags;
+ krb5_error_code (*encrypt)(krb5_context context,
+ struct key_data *key,
+ void *data, size_t len,
+ krb5_boolean encryptp,
+ int usage,
+ void *ivec);
+};
+
+#define ENCRYPTION_USAGE(U) (((U) << 8) | 0xAA)
+#define INTEGRITY_USAGE(U) (((U) << 8) | 0x55)
+#define CHECKSUM_USAGE(U) (((U) << 8) | 0x99)
+
+static struct checksum_type *_find_checksum(krb5_cksumtype type);
+static struct encryption_type *_find_enctype(krb5_enctype type);
+static struct key_type *_find_keytype(krb5_keytype type);
+static krb5_error_code _get_derived_key(krb5_context, krb5_crypto,
+ unsigned, struct key_data**);
+static struct key_data *_new_derived_key(krb5_crypto crypto, unsigned usage);
+static krb5_error_code derive_key(krb5_context context,
+ struct encryption_type *et,
+ struct key_data *key,
+ const void *constant,
+ size_t len);
+static krb5_error_code hmac(krb5_context context,
+ struct checksum_type *cm,
+ const void *data,
+ size_t len,
+ unsigned usage,
+ struct key_data *keyblock,
+ Checksum *result);
+static void free_key_data(krb5_context context, struct key_data *key);
+static krb5_error_code usage2arcfour (krb5_context, unsigned *);
+static void xor (DES_cblock *, const unsigned char *);
+
+/************************************************************
+ * *
+ ************************************************************/
+
+static HEIMDAL_MUTEX crypto_mutex = HEIMDAL_MUTEX_INITIALIZER;
+
+
+static void
+krb5_DES_random_key(krb5_context context,
+ krb5_keyblock *key)
+{
+ DES_cblock *k = key->keyvalue.data;
+ do {
+ krb5_generate_random_block(k, sizeof(DES_cblock));
+ DES_set_odd_parity(k);
+ } while(DES_is_weak_key(k));
+}
+
+static void
+krb5_DES_schedule(krb5_context context,
+ struct key_data *key,
+ const void *params)
+{
+ DES_set_key(key->key->keyvalue.data, key->schedule->data);
+}
+
+static void
+DES_string_to_key_int(unsigned char *data, size_t length, DES_cblock *key)
+{
+ DES_key_schedule schedule;
+ int i;
+ int reverse = 0;
+ unsigned char *p;
+
+ unsigned char swap[] = { 0x0, 0x8, 0x4, 0xc, 0x2, 0xa, 0x6, 0xe,
+ 0x1, 0x9, 0x5, 0xd, 0x3, 0xb, 0x7, 0xf };
+ memset(key, 0, 8);
+
+ p = (unsigned char*)key;
+ for (i = 0; i < length; i++) {
+ unsigned char tmp = data[i];
+ if (!reverse)
+ *p++ ^= (tmp << 1);
+ else
+ *--p ^= (swap[tmp & 0xf] << 4) | swap[(tmp & 0xf0) >> 4];
+ if((i % 8) == 7)
+ reverse = !reverse;
+ }
+ DES_set_odd_parity(key);
+ if(DES_is_weak_key(key))
+ (*key)[7] ^= 0xF0;
+ DES_set_key(key, &schedule);
+ DES_cbc_cksum((void*)data, key, length, &schedule, key);
+ memset(&schedule, 0, sizeof(schedule));
+ DES_set_odd_parity(key);
+ if(DES_is_weak_key(key))
+ (*key)[7] ^= 0xF0;
+}
+
+static krb5_error_code
+krb5_DES_string_to_key(krb5_context context,
+ krb5_enctype enctype,
+ krb5_data password,
+ krb5_salt salt,
+ krb5_data opaque,
+ krb5_keyblock *key)
+{
+ unsigned char *s;
+ size_t len;
+ DES_cblock tmp;
+
+ len = password.length + salt.saltvalue.length;
+ s = malloc(len);
+ if(len > 0 && s == NULL) {
+ krb5_set_error_string(context, "malloc: out of memory");
+ return ENOMEM;
+ }
+ memcpy(s, password.data, password.length);
+ memcpy(s + password.length, salt.saltvalue.data, salt.saltvalue.length);
+ DES_string_to_key_int(s, len, &tmp);
+ key->keytype = enctype;
+ krb5_data_copy(&key->keyvalue, tmp, sizeof(tmp));
+ memset(&tmp, 0, sizeof(tmp));
+ memset(s, 0, len);
+ free(s);
+ return 0;
+}
+
+#ifdef ENABLE_AFS_STRING_TO_KEY
+
+/* This defines the Andrew string_to_key function. It accepts a password
+ * string as input and converts its via a one-way encryption algorithm to a DES
+ * encryption key. It is compatible with the original Andrew authentication
+ * service password database.
+ */
+
+/*
+ * Short passwords, i.e 8 characters or less.
+ */
+static void
+krb5_DES_AFS3_CMU_string_to_key (krb5_data pw,
+ krb5_data cell,
+ DES_cblock *key)
+{
+ char password[8+1]; /* crypt is limited to 8 chars anyway */
+ int i;
+
+ for(i = 0; i < 8; i++) {
+ char c = ((i < pw.length) ? ((char*)pw.data)[i] : 0) ^
+ ((i < cell.length) ?
+ tolower(((unsigned char*)cell.data)[i]) : 0);
+ password[i] = c ? c : 'X';
+ }
+ password[8] = '\0';
+
+ memcpy(key, crypt(password, "p1") + 2, sizeof(DES_cblock));
+
+ /* parity is inserted into the LSB so left shift each byte up one
+ bit. This allows ascii characters with a zero MSB to retain as
+ much significance as possible. */
+ for (i = 0; i < sizeof(DES_cblock); i++)
+ ((unsigned char*)key)[i] <<= 1;
+ DES_set_odd_parity (key);
+}
+
+/*
+ * Long passwords, i.e 9 characters or more.
+ */
+static void
+krb5_DES_AFS3_Transarc_string_to_key (krb5_data pw,
+ krb5_data cell,
+ DES_cblock *key)
+{
+ DES_key_schedule schedule;
+ DES_cblock temp_key;
+ DES_cblock ivec;
+ char password[512];
+ size_t passlen;
+
+ memcpy(password, pw.data, min(pw.length, sizeof(password)));
+ if(pw.length < sizeof(password)) {
+ int len = min(cell.length, sizeof(password) - pw.length);
+ int i;
+
+ memcpy(password + pw.length, cell.data, len);
+ for (i = pw.length; i < pw.length + len; ++i)
+ password[i] = tolower((unsigned char)password[i]);
+ }
+ passlen = min(sizeof(password), pw.length + cell.length);
+ memcpy(&ivec, "kerberos", 8);
+ memcpy(&temp_key, "kerberos", 8);
+ DES_set_odd_parity (&temp_key);
+ DES_set_key (&temp_key, &schedule);
+ DES_cbc_cksum ((void*)password, &ivec, passlen, &schedule, &ivec);
+
+ memcpy(&temp_key, &ivec, 8);
+ DES_set_odd_parity (&temp_key);
+ DES_set_key (&temp_key, &schedule);
+ DES_cbc_cksum ((void*)password, key, passlen, &schedule, &ivec);
+ memset(&schedule, 0, sizeof(schedule));
+ memset(&temp_key, 0, sizeof(temp_key));
+ memset(&ivec, 0, sizeof(ivec));
+ memset(password, 0, sizeof(password));
+
+ DES_set_odd_parity (key);
+}
+
+static krb5_error_code
+DES_AFS3_string_to_key(krb5_context context,
+ krb5_enctype enctype,
+ krb5_data password,
+ krb5_salt salt,
+ krb5_data opaque,
+ krb5_keyblock *key)
+{
+ DES_cblock tmp;
+ if(password.length > 8)
+ krb5_DES_AFS3_Transarc_string_to_key(password, salt.saltvalue, &tmp);
+ else
+ krb5_DES_AFS3_CMU_string_to_key(password, salt.saltvalue, &tmp);
+ key->keytype = enctype;
+ krb5_data_copy(&key->keyvalue, tmp, sizeof(tmp));
+ memset(&key, 0, sizeof(key));
+ return 0;
+}
+#endif /* ENABLE_AFS_STRING_TO_KEY */
+
+static void
+krb5_DES_random_to_key(krb5_context context,
+ krb5_keyblock *key,
+ const void *data,
+ size_t size)
+{
+ DES_cblock *k = key->keyvalue.data;
+ memcpy(k, data, key->keyvalue.length);
+ DES_set_odd_parity(k);
+ if(DES_is_weak_key(k))
+ xor(k, (const unsigned char*)"\0\0\0\0\0\0\0\xf0");
+}
+
+/*
+ *
+ */
+
+static void
+DES3_random_key(krb5_context context,
+ krb5_keyblock *key)
+{
+ DES_cblock *k = key->keyvalue.data;
+ do {
+ krb5_generate_random_block(k, 3 * sizeof(DES_cblock));
+ DES_set_odd_parity(&k[0]);
+ DES_set_odd_parity(&k[1]);
+ DES_set_odd_parity(&k[2]);
+ } while(DES_is_weak_key(&k[0]) ||
+ DES_is_weak_key(&k[1]) ||
+ DES_is_weak_key(&k[2]));
+}
+
+static void
+DES3_schedule(krb5_context context,
+ struct key_data *key,
+ const void *params)
+{
+ DES_cblock *k = key->key->keyvalue.data;
+ DES_key_schedule *s = key->schedule->data;
+ DES_set_key(&k[0], &s[0]);
+ DES_set_key(&k[1], &s[1]);
+ DES_set_key(&k[2], &s[2]);
+}
+
+/*
+ * A = A xor B. A & B are 8 bytes.
+ */
+
+static void
+xor (DES_cblock *key, const unsigned char *b)
+{
+ unsigned char *a = (unsigned char*)key;
+ a[0] ^= b[0];
+ a[1] ^= b[1];
+ a[2] ^= b[2];
+ a[3] ^= b[3];
+ a[4] ^= b[4];
+ a[5] ^= b[5];
+ a[6] ^= b[6];
+ a[7] ^= b[7];
+}
+
+static krb5_error_code
+DES3_string_to_key(krb5_context context,
+ krb5_enctype enctype,
+ krb5_data password,
+ krb5_salt salt,
+ krb5_data opaque,
+ krb5_keyblock *key)
+{
+ char *str;
+ size_t len;
+ unsigned char tmp[24];
+ DES_cblock keys[3];
+
+ len = password.length + salt.saltvalue.length;
+ str = malloc(len);
+ if(len != 0 && str == NULL) {
+ krb5_set_error_string(context, "malloc: out of memory");
+ return ENOMEM;
+ }
+ memcpy(str, password.data, password.length);
+ memcpy(str + password.length, salt.saltvalue.data, salt.saltvalue.length);
+ {
+ DES_cblock ivec;
+ DES_key_schedule s[3];
+ int i;
+
+ _krb5_n_fold(str, len, tmp, 24);
+
+ for(i = 0; i < 3; i++){
+ memcpy(keys + i, tmp + i * 8, sizeof(keys[i]));
+ DES_set_odd_parity(keys + i);
+ if(DES_is_weak_key(keys + i))
+ xor(keys + i, (const unsigned char*)"\0\0\0\0\0\0\0\xf0");
+ DES_set_key(keys + i, &s[i]);
+ }
+ memset(&ivec, 0, sizeof(ivec));
+ DES_ede3_cbc_encrypt(tmp,
+ tmp, sizeof(tmp),
+ &s[0], &s[1], &s[2], &ivec, DES_ENCRYPT);
+ memset(s, 0, sizeof(s));
+ memset(&ivec, 0, sizeof(ivec));
+ for(i = 0; i < 3; i++){
+ memcpy(keys + i, tmp + i * 8, sizeof(keys[i]));
+ DES_set_odd_parity(keys + i);
+ if(DES_is_weak_key(keys + i))
+ xor(keys + i, (const unsigned char*)"\0\0\0\0\0\0\0\xf0");
+ }
+ memset(tmp, 0, sizeof(tmp));
+ }
+ key->keytype = enctype;
+ krb5_data_copy(&key->keyvalue, keys, sizeof(keys));
+ memset(keys, 0, sizeof(keys));
+ memset(str, 0, len);
+ free(str);
+ return 0;
+}
+
+static krb5_error_code
+DES3_string_to_key_derived(krb5_context context,
+ krb5_enctype enctype,
+ krb5_data password,
+ krb5_salt salt,
+ krb5_data opaque,
+ krb5_keyblock *key)
+{
+ krb5_error_code ret;
+ size_t len = password.length + salt.saltvalue.length;
+ char *s;
+
+ s = malloc(len);
+ if(len != 0 && s == NULL) {
+ krb5_set_error_string(context, "malloc: out of memory");
+ return ENOMEM;
+ }
+ memcpy(s, password.data, password.length);
+ memcpy(s + password.length, salt.saltvalue.data, salt.saltvalue.length);
+ ret = krb5_string_to_key_derived(context,
+ s,
+ len,
+ enctype,
+ key);
+ memset(s, 0, len);
+ free(s);
+ return ret;
+}
+
+static void
+DES3_random_to_key(krb5_context context,
+ krb5_keyblock *key,
+ const void *data,
+ size_t size)
+{
+ unsigned char *x = key->keyvalue.data;
+ const u_char *q = data;
+ DES_cblock *k;
+ int i, j;
+
+ memset(x, 0, sizeof(x));
+ for (i = 0; i < 3; ++i) {
+ unsigned char foo;
+ for (j = 0; j < 7; ++j) {
+ unsigned char b = q[7 * i + j];
+
+ x[8 * i + j] = b;
+ }
+ foo = 0;
+ for (j = 6; j >= 0; --j) {
+ foo |= q[7 * i + j] & 1;
+ foo <<= 1;
+ }
+ x[8 * i + 7] = foo;
+ }
+ k = key->keyvalue.data;
+ for (i = 0; i < 3; i++) {
+ DES_set_odd_parity(&k[i]);
+ if(DES_is_weak_key(&k[i]))
+ xor(&k[i], (const unsigned char*)"\0\0\0\0\0\0\0\xf0");
+ }
+}
+
+/*
+ * ARCFOUR
+ */
+
+static void
+ARCFOUR_schedule(krb5_context context,
+ struct key_data *kd,
+ const void *params)
+{
+ RC4_set_key (kd->schedule->data,
+ kd->key->keyvalue.length, kd->key->keyvalue.data);
+}
+
+static krb5_error_code
+ARCFOUR_string_to_key(krb5_context context,
+ krb5_enctype enctype,
+ krb5_data password,
+ krb5_salt salt,
+ krb5_data opaque,
+ krb5_keyblock *key)
+{
+ char *s, *p;
+ size_t len;
+ int i;
+ MD4_CTX m;
+
+ len = 2 * password.length;
+ s = malloc (len);
+ if (len != 0 && s == NULL) {
+ krb5_set_error_string(context, "malloc: out of memory");
+ return ENOMEM;
+ }
+ for (p = s, i = 0; i < password.length; ++i) {
+ *p++ = ((char *)password.data)[i];
+ *p++ = 0;
+ }
+ MD4_Init (&m);
+ MD4_Update (&m, s, len);
+ key->keytype = enctype;
+ krb5_data_alloc (&key->keyvalue, 16);
+ MD4_Final (key->keyvalue.data, &m);
+ memset (s, 0, len);
+ free (s);
+ return 0;
+}
+
+/*
+ * AES
+ */
+
+/* iter is really 1 based, so iter == 0 will be 1 iteration */
+
+krb5_error_code KRB5_LIB_FUNCTION
+_krb5_PKCS5_PBKDF2(krb5_context context, krb5_cksumtype cktype,
+ krb5_data password, krb5_salt salt, u_int32_t iter,
+ krb5_keytype type, krb5_keyblock *key)
+{
+ struct checksum_type *c = _find_checksum(cktype);
+ struct key_type *kt;
+ size_t datalen, leftofkey;
+ krb5_error_code ret;
+ u_int32_t keypart;
+ struct key_data ksign;
+ krb5_keyblock kb;
+ Checksum result;
+ char *data, *tmpcksum;
+ int i, j;
+ char *p;
+
+ if (c == NULL) {
+ krb5_set_error_string(context, "checksum %d not supported", cktype);
+ return KRB5_PROG_KEYTYPE_NOSUPP;
+ }
+
+ kt = _find_keytype(type);
+ if (kt == NULL) {
+ krb5_set_error_string(context, "key type %d not supported", type);
+ return KRB5_PROG_KEYTYPE_NOSUPP;
+ }
+
+ key->keytype = type;
+ ret = krb5_data_alloc (&key->keyvalue, kt->bits / 8);
+ if (ret) {
+ krb5_set_error_string(context, "malloc: out of memory");
+ return ret;
+ }
+
+ ret = krb5_data_alloc (&result.checksum, c->checksumsize);
+ if (ret) {
+ krb5_set_error_string(context, "malloc: out of memory");
+ krb5_data_free (&key->keyvalue);
+ return ret;
+ }
+
+ tmpcksum = malloc(c->checksumsize);
+ if (tmpcksum == NULL) {
+ krb5_set_error_string(context, "malloc: out of memory");
+ krb5_data_free (&key->keyvalue);
+ krb5_data_free (&result.checksum);
+ return ENOMEM;
+ }
+
+ datalen = salt.saltvalue.length + 4;
+ data = malloc(datalen);
+ if (data == NULL) {
+ krb5_set_error_string(context, "malloc: out of memory");
+ free(tmpcksum);
+ krb5_data_free (&key->keyvalue);
+ krb5_data_free (&result.checksum);
+ return ENOMEM;
+ }
+
+ kb.keyvalue = password;
+ ksign.key = &kb;
+
+ memcpy(data, salt.saltvalue.data, salt.saltvalue.length);
+
+ keypart = 1;
+ leftofkey = key->keyvalue.length;
+ p = key->keyvalue.data;
+
+ while (leftofkey) {
+ int len;
+
+ if (leftofkey > c->checksumsize)
+ len = c->checksumsize;
+ else
+ len = leftofkey;
+
+ _krb5_put_int(data + datalen - 4, keypart, 4);
+
+ ret = hmac(context, c, data, datalen, 0, &ksign, &result);
+ if (ret)
+ krb5_abortx(context, "hmac failed");
+ memcpy(p, result.checksum.data, len);
+ memcpy(tmpcksum, result.checksum.data, result.checksum.length);
+ for (i = 0; i < iter; i++) {
+ ret = hmac(context, c, tmpcksum, result.checksum.length,
+ 0, &ksign, &result);
+ if (ret)
+ krb5_abortx(context, "hmac failed");
+ memcpy(tmpcksum, result.checksum.data, result.checksum.length);
+ for (j = 0; j < len; j++)
+ p[j] ^= tmpcksum[j];
+ }
+
+ p += len;
+ leftofkey -= len;
+ keypart++;
+ }
+
+ free(data);
+ free(tmpcksum);
+ krb5_data_free (&result.checksum);
+
+ return 0;
+}
+
+int _krb5_AES_string_to_default_iterator = 4096;
+
+static krb5_error_code
+AES_string_to_key(krb5_context context,
+ krb5_enctype enctype,
+ krb5_data password,
+ krb5_salt salt,
+ krb5_data opaque,
+ krb5_keyblock *key)
+{
+ krb5_error_code ret;
+ u_int32_t iter;
+ struct encryption_type *et;
+ struct key_data kd;
+
+ if (opaque.length == 0)
+ iter = _krb5_AES_string_to_default_iterator - 1;
+ else if (opaque.length == 4) {
+ unsigned long v;
+ _krb5_get_int(opaque.data, &v, 4);
+ iter = ((u_int32_t)v) - 1;
+ } else
+ return KRB5_PROG_KEYTYPE_NOSUPP; /* XXX */
+
+
+ et = _find_enctype(enctype);
+ if (et == NULL)
+ return KRB5_PROG_KEYTYPE_NOSUPP;
+
+ ret = _krb5_PKCS5_PBKDF2(context, CKSUMTYPE_SHA1, password, salt,
+ iter, enctype, key);
+ if (ret)
+ return ret;
+
+ ret = krb5_copy_keyblock(context, key, &kd.key);
+ kd.schedule = NULL;
+
+ ret = derive_key(context, et, &kd, "kerberos", strlen("kerberos"));
+ krb5_free_keyblock_contents(context, key);
+ if (ret == 0) {
+ ret = krb5_copy_keyblock_contents(context, kd.key, key);
+ free_key_data(context, &kd);
+ }
+
+ return ret;
+}
+
+struct krb5_aes_schedule {
+ AES_KEY ekey;
+ AES_KEY dkey;
+};
+
+static void
+AES_schedule(krb5_context context,
+ struct key_data *kd,
+ const void *params)
+{
+ struct krb5_aes_schedule *key = kd->schedule->data;
+ int bits = kd->key->keyvalue.length * 8;
+
+ memset(key, 0, sizeof(*key));
+ AES_set_encrypt_key(kd->key->keyvalue.data, bits, &key->ekey);
+ AES_set_decrypt_key(kd->key->keyvalue.data, bits, &key->dkey);
+}
+
+/*
+ * RC2
+ */
+
+struct _RC2_params {
+ int maximum_effective_key;
+};
+
+static krb5_error_code
+rc2_get_params(krb5_context context,
+ const krb5_data *data,
+ void **params,
+ krb5_data *ivec)
+{
+ RC2CBCParameter rc2params;
+ struct _RC2_params *p;
+ krb5_error_code ret;
+ size_t size;
+
+ ret = decode_RC2CBCParameter(data->data, data->length, &rc2params, &size);
+ if (ret) {
+ krb5_set_error_string(context, "Can't decode RC2 parameters");
+ return ret;
+ }
+ p = malloc(sizeof(*p));
+ if (p == NULL) {
+ free_RC2CBCParameter(&rc2params);
+ krb5_set_error_string(context, "malloc - out of memory");
+ return ENOMEM;
+ }
+ /* XXX */
+ switch(rc2params.rc2ParameterVersion) {
+ case 160:
+ p->maximum_effective_key = 40;
+ break;
+ case 120:
+ p->maximum_effective_key = 64;
+ break;
+ case 58:
+ p->maximum_effective_key = 128;
+ break;
+
+ }
+ if (ivec)
+ ret = copy_octet_string(&rc2params.iv, ivec);
+ free_RC2CBCParameter(&rc2params);
+ *params = p;
+
+ return ret;
+}
+
+static krb5_error_code
+rc2_set_params(krb5_context context,
+ const void *params,
+ const krb5_data *ivec,
+ krb5_data *data)
+{
+ RC2CBCParameter rc2params;
+ const struct _RC2_params *p = params;
+ int maximum_effective_key = 128;
+ krb5_error_code ret;
+ size_t size;
+
+ memset(&rc2params, 0, sizeof(rc2params));
+
+ if (p)
+ maximum_effective_key = p->maximum_effective_key;
+
+ /* XXX */
+ switch(maximum_effective_key) {
+ case 40:
+ rc2params.rc2ParameterVersion = 160;
+ break;
+ case 64:
+ rc2params.rc2ParameterVersion = 120;
+ break;
+ case 128:
+ rc2params.rc2ParameterVersion = 58;
+ break;
+ }
+ ret = copy_octet_string(ivec, &rc2params.iv);
+ if (ret)
+ return ret;
+
+ ASN1_MALLOC_ENCODE(RC2CBCParameter, data->data, data->length,
+ &rc2params, &size, ret);
+ if (ret == 0 && size != data->length)
+ krb5_abortx(context, "Internal asn1 encoder failure");
+ free_RC2CBCParameter(&rc2params);
+
+ return ret;
+}
+
+static void
+rc2_schedule(krb5_context context,
+ struct key_data *kd,
+ const void *params)
+{
+ const struct _RC2_params *p = params;
+ int maximum_effective_key = 128;
+ if (p)
+ maximum_effective_key = p->maximum_effective_key;
+ RC2_set_key (kd->schedule->data,
+ kd->key->keyvalue.length,
+ kd->key->keyvalue.data,
+ maximum_effective_key);
+}
+
+
+/*
+ *
+ */
+
+static struct salt_type des_salt[] = {
+ {
+ KRB5_PW_SALT,
+ "pw-salt",
+ krb5_DES_string_to_key
+ },
+#ifdef ENABLE_AFS_STRING_TO_KEY
+ {
+ KRB5_AFS3_SALT,
+ "afs3-salt",
+ DES_AFS3_string_to_key
+ },
+#endif
+ { 0 }
+};
+
+static struct salt_type des3_salt[] = {
+ {
+ KRB5_PW_SALT,
+ "pw-salt",
+ DES3_string_to_key
+ },
+ { 0 }
+};
+
+static struct salt_type des3_salt_derived[] = {
+ {
+ KRB5_PW_SALT,
+ "pw-salt",
+ DES3_string_to_key_derived
+ },
+ { 0 }
+};
+
+static struct salt_type AES_salt[] = {
+ {
+ KRB5_PW_SALT,
+ "pw-salt",
+ AES_string_to_key
+ },
+ { 0 }
+};
+
+static struct salt_type arcfour_salt[] = {
+ {
+ KRB5_PW_SALT,
+ "pw-salt",
+ ARCFOUR_string_to_key
+ },
+ { 0 }
+};
+
+/*
+ *
+ */
+
+static struct key_type keytype_null = {
+ KEYTYPE_NULL,
+ "null",
+ 0,
+ 0,
+ 0,
+ 0,
+ NULL,
+ NULL,
+ NULL
+};
+
+static struct key_type keytype_des = {
+ KEYTYPE_DES,
+ "des",
+ 56,
+ sizeof(DES_cblock),
+ sizeof(DES_cblock),
+ sizeof(DES_key_schedule),
+ krb5_DES_random_key,
+ krb5_DES_schedule,
+ des_salt,
+ krb5_DES_random_to_key
+};
+
+static struct key_type keytype_des3 = {
+ KEYTYPE_DES3,
+ "des3",
+ 168,
+ 3 * sizeof(DES_cblock),
+ 3 * sizeof(DES_cblock),
+ 3 * sizeof(DES_key_schedule),
+ DES3_random_key,
+ DES3_schedule,
+ des3_salt,
+ DES3_random_to_key
+};
+
+static struct key_type keytype_des3_derived = {
+ KEYTYPE_DES3,
+ "des3",
+ 168,
+ 3 * sizeof(DES_cblock),
+ 3 * sizeof(DES_cblock),
+ 3 * sizeof(DES_key_schedule),
+ DES3_random_key,
+ DES3_schedule,
+ des3_salt_derived,
+ DES3_random_to_key
+};
+
+static struct key_type keytype_aes128 = {
+ KEYTYPE_AES128,
+ "aes-128",
+ 128,
+ 16,
+ 16,
+ sizeof(struct krb5_aes_schedule),
+ NULL,
+ AES_schedule,
+ AES_salt
+};
+
+static struct key_type keytype_aes192 = {
+ KEYTYPE_AES192,
+ "aes-192",
+ 192,
+ 24,
+ 24,
+ sizeof(struct krb5_aes_schedule),
+ NULL,
+ AES_schedule,
+ AES_salt
+};
+
+static struct key_type keytype_aes256 = {
+ KEYTYPE_AES256,
+ "aes-256",
+ 256,
+ 32,
+ 32,
+ sizeof(struct krb5_aes_schedule),
+ NULL,
+ AES_schedule,
+ AES_salt
+};
+
+static struct key_type keytype_arcfour = {
+ KEYTYPE_ARCFOUR,
+ "arcfour",
+ 128,
+ 16,
+ 16,
+ sizeof(RC4_KEY),
+ NULL,
+ ARCFOUR_schedule,
+ arcfour_salt
+};
+
+static struct key_type keytype_rc2 = {
+ KEYTYPE_RC2,
+ "rc2",
+ 128,
+ 16,
+ 1,
+ sizeof(RC2_KEY),
+ NULL,
+ rc2_schedule,
+ NULL, /* XXX salt */
+ NULL,
+ rc2_get_params,
+ rc2_set_params
+};
+
+static struct key_type *keytypes[] = {
+ &keytype_null,
+ &keytype_des,
+ &keytype_des3_derived,
+ &keytype_des3,
+ &keytype_aes128,
+ &keytype_aes192,
+ &keytype_aes256,
+ &keytype_rc2,
+ &keytype_arcfour
+};
+
+static int num_keytypes = sizeof(keytypes) / sizeof(keytypes[0]);
+
+static struct key_type *
+_find_keytype(krb5_keytype type)
+{
+ int i;
+ for(i = 0; i < num_keytypes; i++)
+ if(keytypes[i]->type == type)
+ return keytypes[i];
+ return NULL;
+}
+
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_salttype_to_string (krb5_context context,
+ krb5_enctype etype,
+ krb5_salttype stype,
+ char **string)
+{
+ struct encryption_type *e;
+ struct salt_type *st;
+
+ e = _find_enctype (etype);
+ if (e == NULL) {
+ krb5_set_error_string(context, "encryption type %d not supported",
+ etype);
+ return KRB5_PROG_ETYPE_NOSUPP;
+ }
+ for (st = e->keytype->string_to_key; st && st->type; st++) {
+ if (st->type == stype) {
+ *string = strdup (st->name);
+ if (*string == NULL) {
+ krb5_set_error_string(context, "malloc: out of memory");
+ return ENOMEM;
+ }
+ return 0;
+ }
+ }
+ krb5_set_error_string(context, "salttype %d not supported", stype);
+ return HEIM_ERR_SALTTYPE_NOSUPP;
+}
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_string_to_salttype (krb5_context context,
+ krb5_enctype etype,
+ const char *string,
+ krb5_salttype *salttype)
+{
+ struct encryption_type *e;
+ struct salt_type *st;
+
+ e = _find_enctype (etype);
+ if (e == NULL) {
+ krb5_set_error_string(context, "encryption type %d not supported",
+ etype);
+ return KRB5_PROG_ETYPE_NOSUPP;
+ }
+ for (st = e->keytype->string_to_key; st && st->type; st++) {
+ if (strcasecmp (st->name, string) == 0) {
+ *salttype = st->type;
+ return 0;
+ }
+ }
+ krb5_set_error_string(context, "salttype %s not supported", string);
+ return HEIM_ERR_SALTTYPE_NOSUPP;
+}
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_get_pw_salt(krb5_context context,
+ krb5_const_principal principal,
+ krb5_salt *salt)
+{
+ size_t len;
+ int i;
+ krb5_error_code ret;
+ char *p;
+
+ salt->salttype = KRB5_PW_SALT;
+ len = strlen(principal->realm);
+ for (i = 0; i < principal->name.name_string.len; ++i)
+ len += strlen(principal->name.name_string.val[i]);
+ ret = krb5_data_alloc (&salt->saltvalue, len);
+ if (ret)
+ return ret;
+ p = salt->saltvalue.data;
+ memcpy (p, principal->realm, strlen(principal->realm));
+ p += strlen(principal->realm);
+ for (i = 0; i < principal->name.name_string.len; ++i) {
+ memcpy (p,
+ principal->name.name_string.val[i],
+ strlen(principal->name.name_string.val[i]));
+ p += strlen(principal->name.name_string.val[i]);
+ }
+ return 0;
+}
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_free_salt(krb5_context context,
+ krb5_salt salt)
+{
+ krb5_data_free(&salt.saltvalue);
+ return 0;
+}
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_string_to_key_data (krb5_context context,
+ krb5_enctype enctype,
+ krb5_data password,
+ krb5_principal principal,
+ krb5_keyblock *key)
+{
+ krb5_error_code ret;
+ krb5_salt salt;
+
+ ret = krb5_get_pw_salt(context, principal, &salt);
+ if(ret)
+ return ret;
+ ret = krb5_string_to_key_data_salt(context, enctype, password, salt, key);
+ krb5_free_salt(context, salt);
+ return ret;
+}
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_string_to_key (krb5_context context,
+ krb5_enctype enctype,
+ const char *password,
+ krb5_principal principal,
+ krb5_keyblock *key)
+{
+ krb5_data pw;
+ pw.data = rk_UNCONST(password);
+ pw.length = strlen(password);
+ return krb5_string_to_key_data(context, enctype, pw, principal, key);
+}
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_string_to_key_data_salt (krb5_context context,
+ krb5_enctype enctype,
+ krb5_data password,
+ krb5_salt salt,
+ krb5_keyblock *key)
+{
+ krb5_data opaque;
+ krb5_data_zero(&opaque);
+ return krb5_string_to_key_data_salt_opaque(context, enctype, password,
+ salt, opaque, key);
+}
+
+/*
+ * Do a string -> key for encryption type `enctype' operation on
+ * `password' (with salt `salt' and the enctype specific data string
+ * `opaque'), returning the resulting key in `key'
+ */
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_string_to_key_data_salt_opaque (krb5_context context,
+ krb5_enctype enctype,
+ krb5_data password,
+ krb5_salt salt,
+ krb5_data opaque,
+ krb5_keyblock *key)
+{
+ struct encryption_type *et =_find_enctype(enctype);
+ struct salt_type *st;
+ if(et == NULL) {
+ krb5_set_error_string(context, "encryption type %d not supported",
+ enctype);
+ return KRB5_PROG_ETYPE_NOSUPP;
+ }
+ for(st = et->keytype->string_to_key; st && st->type; st++)
+ if(st->type == salt.salttype)
+ return (*st->string_to_key)(context, enctype, password,
+ salt, opaque, key);
+ krb5_set_error_string(context, "salt type %d not supported",
+ salt.salttype);
+ return HEIM_ERR_SALTTYPE_NOSUPP;
+}
+
+/*
+ * Do a string -> key for encryption type `enctype' operation on the
+ * string `password' (with salt `salt'), returning the resulting key
+ * in `key'
+ */
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_string_to_key_salt (krb5_context context,
+ krb5_enctype enctype,
+ const char *password,
+ krb5_salt salt,
+ krb5_keyblock *key)
+{
+ krb5_data pw;
+ pw.data = rk_UNCONST(password);
+ pw.length = strlen(password);
+ return krb5_string_to_key_data_salt(context, enctype, pw, salt, key);
+}
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_string_to_key_salt_opaque (krb5_context context,
+ krb5_enctype enctype,
+ const char *password,
+ krb5_salt salt,
+ krb5_data opaque,
+ krb5_keyblock *key)
+{
+ krb5_data pw;
+ pw.data = rk_UNCONST(password);
+ pw.length = strlen(password);
+ return krb5_string_to_key_data_salt_opaque(context, enctype,
+ pw, salt, opaque, key);
+}
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_keytype_to_string(krb5_context context,
+ krb5_keytype keytype,
+ char **string)
+{
+ struct key_type *kt = _find_keytype(keytype);
+ if(kt == NULL) {
+ krb5_set_error_string(context, "key type %d not supported", keytype);
+ return KRB5_PROG_KEYTYPE_NOSUPP;
+ }
+ *string = strdup(kt->name);
+ if(*string == NULL) {
+ krb5_set_error_string(context, "malloc: out of memory");
+ return ENOMEM;
+ }
+ return 0;
+}
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_string_to_keytype(krb5_context context,
+ const char *string,
+ krb5_keytype *keytype)
+{
+ int i;
+ for(i = 0; i < num_keytypes; i++)
+ if(strcasecmp(keytypes[i]->name, string) == 0){
+ *keytype = keytypes[i]->type;
+ return 0;
+ }
+ krb5_set_error_string(context, "key type %s not supported", string);
+ return KRB5_PROG_KEYTYPE_NOSUPP;
+}
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_enctype_keysize(krb5_context context,
+ krb5_enctype type,
+ size_t *keysize)
+{
+ struct encryption_type *et = _find_enctype(type);
+ if(et == NULL) {
+ krb5_set_error_string(context, "encryption type %d not supported",
+ type);
+ return KRB5_PROG_ETYPE_NOSUPP;
+ }
+ *keysize = et->keytype->size;
+ return 0;
+}
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_generate_random_keyblock(krb5_context context,
+ krb5_enctype type,
+ krb5_keyblock *key)
+{
+ krb5_error_code ret;
+ struct encryption_type *et = _find_enctype(type);
+ if(et == NULL) {
+ krb5_set_error_string(context, "encryption type %d not supported",
+ type);
+ return KRB5_PROG_ETYPE_NOSUPP;
+ }
+ ret = krb5_data_alloc(&key->keyvalue, et->keytype->size);
+ if(ret)
+ return ret;
+ key->keytype = type;
+ if(et->keytype->random_key)
+ (*et->keytype->random_key)(context, key);
+ else
+ krb5_generate_random_block(key->keyvalue.data,
+ key->keyvalue.length);
+ return 0;
+}
+
+static krb5_error_code
+_key_schedule(krb5_context context,
+ struct key_data *key,
+ const void *params)
+{
+ krb5_error_code ret;
+ struct encryption_type *et = _find_enctype(key->key->keytype);
+ struct key_type *kt = et->keytype;
+
+ if(kt->schedule == NULL)
+ return 0;
+ if (key->schedule != NULL)
+ return 0;
+ ALLOC(key->schedule, 1);
+ if(key->schedule == NULL) {
+ krb5_set_error_string(context, "malloc: out of memory");
+ return ENOMEM;
+ }
+ ret = krb5_data_alloc(key->schedule, kt->schedule_size);
+ if(ret) {
+ free(key->schedule);
+ key->schedule = NULL;
+ return ret;
+ }
+ (*kt->schedule)(context, key, params);
+ return 0;
+}
+
+/************************************************************
+ * *
+ ************************************************************/
+
+static void
+NONE_checksum(krb5_context context,
+ struct key_data *key,
+ const void *data,
+ size_t len,
+ unsigned usage,
+ Checksum *C)
+{
+}
+
+static void
+CRC32_checksum(krb5_context context,
+ struct key_data *key,
+ const void *data,
+ size_t len,
+ unsigned usage,
+ Checksum *C)
+{
+ u_int32_t crc;
+ unsigned char *r = C->checksum.data;
+ _krb5_crc_init_table ();
+ crc = _krb5_crc_update (data, len, 0);
+ r[0] = crc & 0xff;
+ r[1] = (crc >> 8) & 0xff;
+ r[2] = (crc >> 16) & 0xff;
+ r[3] = (crc >> 24) & 0xff;
+}
+
+static void
+RSA_MD4_checksum(krb5_context context,
+ struct key_data *key,
+ const void *data,
+ size_t len,
+ unsigned usage,
+ Checksum *C)
+{
+ MD4_CTX m;
+
+ MD4_Init (&m);
+ MD4_Update (&m, data, len);
+ MD4_Final (C->checksum.data, &m);
+}
+
+static void
+RSA_MD4_DES_checksum(krb5_context context,
+ struct key_data *key,
+ const void *data,
+ size_t len,
+ unsigned usage,
+ Checksum *cksum)
+{
+ MD4_CTX md4;
+ DES_cblock ivec;
+ unsigned char *p = cksum->checksum.data;
+
+ krb5_generate_random_block(p, 8);
+ MD4_Init (&md4);
+ MD4_Update (&md4, p, 8);
+ MD4_Update (&md4, data, len);
+ MD4_Final (p + 8, &md4);
+ memset (&ivec, 0, sizeof(ivec));
+ DES_cbc_encrypt(p,
+ p,
+ 24,
+ key->schedule->data,
+ &ivec,
+ DES_ENCRYPT);
+}
+
+static krb5_error_code
+RSA_MD4_DES_verify(krb5_context context,
+ struct key_data *key,
+ const void *data,
+ size_t len,
+ unsigned usage,
+ Checksum *C)
+{
+ MD4_CTX md4;
+ unsigned char tmp[24];
+ unsigned char res[16];
+ DES_cblock ivec;
+ krb5_error_code ret = 0;
+
+ memset(&ivec, 0, sizeof(ivec));
+ DES_cbc_encrypt(C->checksum.data,
+ (void*)tmp,
+ C->checksum.length,
+ key->schedule->data,
+ &ivec,
+ DES_DECRYPT);
+ MD4_Init (&md4);
+ MD4_Update (&md4, tmp, 8); /* confounder */
+ MD4_Update (&md4, data, len);
+ MD4_Final (res, &md4);
+ if(memcmp(res, tmp + 8, sizeof(res)) != 0) {
+ krb5_clear_error_string (context);
+ ret = KRB5KRB_AP_ERR_BAD_INTEGRITY;
+ }
+ memset(tmp, 0, sizeof(tmp));
+ memset(res, 0, sizeof(res));
+ return ret;
+}
+
+static void
+RSA_MD5_checksum(krb5_context context,
+ struct key_data *key,
+ const void *data,
+ size_t len,
+ unsigned usage,
+ Checksum *C)
+{
+ MD5_CTX m;
+
+ MD5_Init (&m);
+ MD5_Update(&m, data, len);
+ MD5_Final (C->checksum.data, &m);
+}
+
+static void
+RSA_MD5_DES_checksum(krb5_context context,
+ struct key_data *key,
+ const void *data,
+ size_t len,
+ unsigned usage,
+ Checksum *C)
+{
+ MD5_CTX md5;
+ DES_cblock ivec;
+ unsigned char *p = C->checksum.data;
+
+ krb5_generate_random_block(p, 8);
+ MD5_Init (&md5);
+ MD5_Update (&md5, p, 8);
+ MD5_Update (&md5, data, len);
+ MD5_Final (p + 8, &md5);
+ memset (&ivec, 0, sizeof(ivec));
+ DES_cbc_encrypt(p,
+ p,
+ 24,
+ key->schedule->data,
+ &ivec,
+ DES_ENCRYPT);
+}
+
+static krb5_error_code
+RSA_MD5_DES_verify(krb5_context context,
+ struct key_data *key,
+ const void *data,
+ size_t len,
+ unsigned usage,
+ Checksum *C)
+{
+ MD5_CTX md5;
+ unsigned char tmp[24];
+ unsigned char res[16];
+ DES_cblock ivec;
+ DES_key_schedule *sched = key->schedule->data;
+ krb5_error_code ret = 0;
+
+ memset(&ivec, 0, sizeof(ivec));
+ DES_cbc_encrypt(C->checksum.data,
+ (void*)tmp,
+ C->checksum.length,
+ &sched[0],
+ &ivec,
+ DES_DECRYPT);
+ MD5_Init (&md5);
+ MD5_Update (&md5, tmp, 8); /* confounder */
+ MD5_Update (&md5, data, len);
+ MD5_Final (res, &md5);
+ if(memcmp(res, tmp + 8, sizeof(res)) != 0) {
+ krb5_clear_error_string (context);
+ ret = KRB5KRB_AP_ERR_BAD_INTEGRITY;
+ }
+ memset(tmp, 0, sizeof(tmp));
+ memset(res, 0, sizeof(res));
+ return ret;
+}
+
+static void
+RSA_MD5_DES3_checksum(krb5_context context,
+ struct key_data *key,
+ const void *data,
+ size_t len,
+ unsigned usage,
+ Checksum *C)
+{
+ MD5_CTX md5;
+ DES_cblock ivec;
+ unsigned char *p = C->checksum.data;
+ DES_key_schedule *sched = key->schedule->data;
+
+ krb5_generate_random_block(p, 8);
+ MD5_Init (&md5);
+ MD5_Update (&md5, p, 8);
+ MD5_Update (&md5, data, len);
+ MD5_Final (p + 8, &md5);
+ memset (&ivec, 0, sizeof(ivec));
+ DES_ede3_cbc_encrypt(p,
+ p,
+ 24,
+ &sched[0], &sched[1], &sched[2],
+ &ivec,
+ DES_ENCRYPT);
+}
+
+static krb5_error_code
+RSA_MD5_DES3_verify(krb5_context context,
+ struct key_data *key,
+ const void *data,
+ size_t len,
+ unsigned usage,
+ Checksum *C)
+{
+ MD5_CTX md5;
+ unsigned char tmp[24];
+ unsigned char res[16];
+ DES_cblock ivec;
+ DES_key_schedule *sched = key->schedule->data;
+ krb5_error_code ret = 0;
+
+ memset(&ivec, 0, sizeof(ivec));
+ DES_ede3_cbc_encrypt(C->checksum.data,
+ (void*)tmp,
+ C->checksum.length,
+ &sched[0], &sched[1], &sched[2],
+ &ivec,
+ DES_DECRYPT);
+ MD5_Init (&md5);
+ MD5_Update (&md5, tmp, 8); /* confounder */
+ MD5_Update (&md5, data, len);
+ MD5_Final (res, &md5);
+ if(memcmp(res, tmp + 8, sizeof(res)) != 0) {
+ krb5_clear_error_string (context);
+ ret = KRB5KRB_AP_ERR_BAD_INTEGRITY;
+ }
+ memset(tmp, 0, sizeof(tmp));
+ memset(res, 0, sizeof(res));
+ return ret;
+}
+
+static void
+SHA1_checksum(krb5_context context,
+ struct key_data *key,
+ const void *data,
+ size_t len,
+ unsigned usage,
+ Checksum *C)
+{
+ SHA_CTX m;
+
+ SHA1_Init(&m);
+ SHA1_Update(&m, data, len);
+ SHA1_Final(C->checksum.data, &m);
+}
+
+/* HMAC according to RFC2104 */
+static krb5_error_code
+hmac(krb5_context context,
+ struct checksum_type *cm,
+ const void *data,
+ size_t len,
+ unsigned usage,
+ struct key_data *keyblock,
+ Checksum *result)
+{
+ unsigned char *ipad, *opad;
+ unsigned char *key;
+ size_t key_len;
+ int i;
+
+ ipad = malloc(cm->blocksize + len);
+ if (ipad == NULL)
+ return ENOMEM;
+ opad = malloc(cm->blocksize + cm->checksumsize);
+ if (opad == NULL) {
+ free(ipad);
+ return ENOMEM;
+ }
+ memset(ipad, 0x36, cm->blocksize);
+ memset(opad, 0x5c, cm->blocksize);
+
+ if(keyblock->key->keyvalue.length > cm->blocksize){
+ (*cm->checksum)(context,
+ keyblock,
+ keyblock->key->keyvalue.data,
+ keyblock->key->keyvalue.length,
+ usage,
+ result);
+ key = result->checksum.data;
+ key_len = result->checksum.length;
+ } else {
+ key = keyblock->key->keyvalue.data;
+ key_len = keyblock->key->keyvalue.length;
+ }
+ for(i = 0; i < key_len; i++){
+ ipad[i] ^= key[i];
+ opad[i] ^= key[i];
+ }
+ memcpy(ipad + cm->blocksize, data, len);
+ (*cm->checksum)(context, keyblock, ipad, cm->blocksize + len,
+ usage, result);
+ memcpy(opad + cm->blocksize, result->checksum.data,
+ result->checksum.length);
+ (*cm->checksum)(context, keyblock, opad,
+ cm->blocksize + cm->checksumsize, usage, result);
+ memset(ipad, 0, cm->blocksize + len);
+ free(ipad);
+ memset(opad, 0, cm->blocksize + cm->checksumsize);
+ free(opad);
+
+ return 0;
+}
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_hmac(krb5_context context,
+ krb5_cksumtype cktype,
+ const void *data,
+ size_t len,
+ unsigned usage,
+ krb5_keyblock *key,
+ Checksum *result)
+{
+ struct checksum_type *c = _find_checksum(cktype);
+ struct key_data kd;
+ krb5_error_code ret;
+
+ if (c == NULL) {
+ krb5_set_error_string (context, "checksum type %d not supported",
+ cktype);
+ return KRB5_PROG_SUMTYPE_NOSUPP;
+ }
+
+ kd.key = key;
+ kd.schedule = NULL;
+
+ ret = hmac(context, c, data, len, usage, &kd, result);
+
+ if (kd.schedule)
+ krb5_free_data(context, kd.schedule);
+
+ return ret;
+ }
+
+static void
+SP_HMAC_SHA1_checksum(krb5_context context,
+ struct key_data *key,
+ const void *data,
+ size_t len,
+ unsigned usage,
+ Checksum *result)
+{
+ struct checksum_type *c = _find_checksum(CKSUMTYPE_SHA1);
+ Checksum res;
+ char sha1_data[20];
+ krb5_error_code ret;
+
+ res.checksum.data = sha1_data;
+ res.checksum.length = sizeof(sha1_data);
+
+ ret = hmac(context, c, data, len, usage, key, &res);
+ if (ret)
+ krb5_abortx(context, "hmac failed");
+ memcpy(result->checksum.data, res.checksum.data, result->checksum.length);
+}
+
+/*
+ * checksum according to section 5. of draft-brezak-win2k-krb-rc4-hmac-03.txt
+ */
+
+static void
+HMAC_MD5_checksum(krb5_context context,
+ struct key_data *key,
+ const void *data,
+ size_t len,
+ unsigned usage,
+ Checksum *result)
+{
+ MD5_CTX md5;
+ struct checksum_type *c = _find_checksum (CKSUMTYPE_RSA_MD5);
+ const char signature[] = "signaturekey";
+ Checksum ksign_c;
+ struct key_data ksign;
+ krb5_keyblock kb;
+ unsigned char t[4];
+ unsigned char tmp[16];
+ unsigned char ksign_c_data[16];
+ krb5_error_code ret;
+
+ ksign_c.checksum.length = sizeof(ksign_c_data);
+ ksign_c.checksum.data = ksign_c_data;
+ ret = hmac(context, c, signature, sizeof(signature), 0, key, &ksign_c);
+ if (ret)
+ krb5_abortx(context, "hmac failed");
+ ksign.key = &kb;
+ kb.keyvalue = ksign_c.checksum;
+ MD5_Init (&md5);
+ t[0] = (usage >> 0) & 0xFF;
+ t[1] = (usage >> 8) & 0xFF;
+ t[2] = (usage >> 16) & 0xFF;
+ t[3] = (usage >> 24) & 0xFF;
+ MD5_Update (&md5, t, 4);
+ MD5_Update (&md5, data, len);
+ MD5_Final (tmp, &md5);
+ ret = hmac(context, c, tmp, sizeof(tmp), 0, &ksign, result);
+ if (ret)
+ krb5_abortx(context, "hmac failed");
+}
+
+/*
+ * same as previous but being used while encrypting.
+ */
+
+static void
+HMAC_MD5_checksum_enc(krb5_context context,
+ struct key_data *key,
+ const void *data,
+ size_t len,
+ unsigned usage,
+ Checksum *result)
+{
+ struct checksum_type *c = _find_checksum (CKSUMTYPE_RSA_MD5);
+ Checksum ksign_c;
+ struct key_data ksign;
+ krb5_keyblock kb;
+ unsigned char t[4];
+ unsigned char ksign_c_data[16];
+ krb5_error_code ret;
+
+ t[0] = (usage >> 0) & 0xFF;
+ t[1] = (usage >> 8) & 0xFF;
+ t[2] = (usage >> 16) & 0xFF;
+ t[3] = (usage >> 24) & 0xFF;
+
+ ksign_c.checksum.length = sizeof(ksign_c_data);
+ ksign_c.checksum.data = ksign_c_data;
+ ret = hmac(context, c, t, sizeof(t), 0, key, &ksign_c);
+ if (ret)
+ krb5_abortx(context, "hmac failed");
+ ksign.key = &kb;
+ kb.keyvalue = ksign_c.checksum;
+ ret = hmac(context, c, data, len, 0, &ksign, result);
+ if (ret)
+ krb5_abortx(context, "hmac failed");
+}
+
+static struct checksum_type checksum_none = {
+ CKSUMTYPE_NONE,
+ "none",
+ 1,
+ 0,
+ 0,
+ NONE_checksum,
+ NULL
+};
+static struct checksum_type checksum_crc32 = {
+ CKSUMTYPE_CRC32,
+ "crc32",
+ 1,
+ 4,
+ 0,
+ CRC32_checksum,
+ NULL
+};
+static struct checksum_type checksum_rsa_md4 = {
+ CKSUMTYPE_RSA_MD4,
+ "rsa-md4",
+ 64,
+ 16,
+ F_CPROOF,
+ RSA_MD4_checksum,
+ NULL
+};
+static struct checksum_type checksum_rsa_md4_des = {
+ CKSUMTYPE_RSA_MD4_DES,
+ "rsa-md4-des",
+ 64,
+ 24,
+ F_KEYED | F_CPROOF | F_VARIANT,
+ RSA_MD4_DES_checksum,
+ RSA_MD4_DES_verify
+};
+#if 0
+static struct checksum_type checksum_des_mac = {
+ CKSUMTYPE_DES_MAC,
+ "des-mac",
+ 0,
+ 0,
+ 0,
+ DES_MAC_checksum
+};
+static struct checksum_type checksum_des_mac_k = {
+ CKSUMTYPE_DES_MAC_K,
+ "des-mac-k",
+ 0,
+ 0,
+ 0,
+ DES_MAC_K_checksum
+};
+static struct checksum_type checksum_rsa_md4_des_k = {
+ CKSUMTYPE_RSA_MD4_DES_K,
+ "rsa-md4-des-k",
+ 0,
+ 0,
+ 0,
+ RSA_MD4_DES_K_checksum,
+ RSA_MD4_DES_K_verify
+};
+#endif
+static struct checksum_type checksum_rsa_md5 = {
+ CKSUMTYPE_RSA_MD5,
+ "rsa-md5",
+ 64,
+ 16,
+ F_CPROOF,
+ RSA_MD5_checksum,
+ NULL
+};
+static struct checksum_type checksum_rsa_md5_des = {
+ CKSUMTYPE_RSA_MD5_DES,
+ "rsa-md5-des",
+ 64,
+ 24,
+ F_KEYED | F_CPROOF | F_VARIANT,
+ RSA_MD5_DES_checksum,
+ RSA_MD5_DES_verify
+};
+static struct checksum_type checksum_rsa_md5_des3 = {
+ CKSUMTYPE_RSA_MD5_DES3,
+ "rsa-md5-des3",
+ 64,
+ 24,
+ F_KEYED | F_CPROOF | F_VARIANT,
+ RSA_MD5_DES3_checksum,
+ RSA_MD5_DES3_verify
+};
+static struct checksum_type checksum_sha1 = {
+ CKSUMTYPE_SHA1,
+ "sha1",
+ 64,
+ 20,
+ F_CPROOF,
+ SHA1_checksum,
+ NULL
+};
+static struct checksum_type checksum_hmac_sha1_des3 = {
+ CKSUMTYPE_HMAC_SHA1_DES3,
+ "hmac-sha1-des3",
+ 64,
+ 20,
+ F_KEYED | F_CPROOF | F_DERIVED,
+ SP_HMAC_SHA1_checksum,
+ NULL
+};
+
+static struct checksum_type checksum_hmac_sha1_aes128 = {
+ CKSUMTYPE_HMAC_SHA1_96_AES_128,
+ "hmac-sha1-96-aes128",
+ 64,
+ 12,
+ F_KEYED | F_CPROOF | F_DERIVED,
+ SP_HMAC_SHA1_checksum,
+ NULL
+};
+
+static struct checksum_type checksum_hmac_sha1_aes256 = {
+ CKSUMTYPE_HMAC_SHA1_96_AES_256,
+ "hmac-sha1-96-aes256",
+ 64,
+ 12,
+ F_KEYED | F_CPROOF | F_DERIVED,
+ SP_HMAC_SHA1_checksum,
+ NULL
+};
+
+static struct checksum_type checksum_hmac_md5 = {
+ CKSUMTYPE_HMAC_MD5,
+ "hmac-md5",
+ 64,
+ 16,
+ F_KEYED | F_CPROOF,
+ HMAC_MD5_checksum,
+ NULL
+};
+
+static struct checksum_type checksum_hmac_md5_enc = {
+ CKSUMTYPE_HMAC_MD5_ENC,
+ "hmac-md5-enc",
+ 64,
+ 16,
+ F_KEYED | F_CPROOF | F_PSEUDO,
+ HMAC_MD5_checksum_enc,
+ NULL
+};
+
+static struct checksum_type *checksum_types[] = {
+ &checksum_none,
+ &checksum_crc32,
+ &checksum_rsa_md4,
+ &checksum_rsa_md4_des,
+#if 0
+ &checksum_des_mac,
+ &checksum_des_mac_k,
+ &checksum_rsa_md4_des_k,
+#endif
+ &checksum_rsa_md5,
+ &checksum_rsa_md5_des,
+ &checksum_rsa_md5_des3,
+ &checksum_sha1,
+ &checksum_hmac_sha1_des3,
+ &checksum_hmac_sha1_aes128,
+ &checksum_hmac_sha1_aes256,
+ &checksum_hmac_md5,
+ &checksum_hmac_md5_enc
+};
+
+static int num_checksums = sizeof(checksum_types) / sizeof(checksum_types[0]);
+
+static struct checksum_type *
+_find_checksum(krb5_cksumtype type)
+{
+ int i;
+ for(i = 0; i < num_checksums; i++)
+ if(checksum_types[i]->type == type)
+ return checksum_types[i];
+ return NULL;
+}
+
+static krb5_error_code
+get_checksum_key(krb5_context context,
+ krb5_crypto crypto,
+ unsigned usage, /* not krb5_key_usage */
+ struct checksum_type *ct,
+ struct key_data **key)
+{
+ krb5_error_code ret = 0;
+
+ if(ct->flags & F_DERIVED)
+ ret = _get_derived_key(context, crypto, usage, key);
+ else if(ct->flags & F_VARIANT) {
+ int i;
+
+ *key = _new_derived_key(crypto, 0xff/* KRB5_KU_RFC1510_VARIANT */);
+ if(*key == NULL) {
+ krb5_set_error_string(context, "malloc: out of memory");
+ return ENOMEM;
+ }
+ ret = krb5_copy_keyblock(context, crypto->key.key, &(*key)->key);
+ if(ret)
+ return ret;
+ for(i = 0; i < (*key)->key->keyvalue.length; i++)
+ ((unsigned char*)(*key)->key->keyvalue.data)[i] ^= 0xF0;
+ } else {
+ *key = &crypto->key;
+ }
+ if(ret == 0)
+ ret = _key_schedule(context, *key, crypto->params);
+ return ret;
+}
+
+static krb5_error_code
+create_checksum (krb5_context context,
+ struct checksum_type *ct,
+ krb5_crypto crypto,
+ unsigned usage,
+ void *data,
+ size_t len,
+ Checksum *result)
+{
+ krb5_error_code ret;
+ struct key_data *dkey;
+ int keyed_checksum;
+
+ if (ct->flags & F_DISABLED) {
+ krb5_clear_error_string (context);
+ return KRB5_PROG_SUMTYPE_NOSUPP;
+ }
+ keyed_checksum = (ct->flags & F_KEYED) != 0;
+ if(keyed_checksum && crypto == NULL) {
+ krb5_clear_error_string (context);
+ return KRB5_PROG_SUMTYPE_NOSUPP; /* XXX */
+ }
+ if(keyed_checksum) {
+ ret = get_checksum_key(context, crypto, usage, ct, &dkey);
+ if (ret)
+ return ret;
+ } else
+ dkey = NULL;
+ result->cksumtype = ct->type;
+ krb5_data_alloc(&result->checksum, ct->checksumsize);
+ (*ct->checksum)(context, dkey, data, len, usage, result);
+ return 0;
+}
+
+static int
+arcfour_checksum_p(struct checksum_type *ct, krb5_crypto crypto)
+{
+ return (ct->type == CKSUMTYPE_HMAC_MD5) &&
+ (crypto->key.key->keytype == KEYTYPE_ARCFOUR);
+}
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_create_checksum(krb5_context context,
+ krb5_crypto crypto,
+ krb5_key_usage usage,
+ int type,
+ void *data,
+ size_t len,
+ Checksum *result)
+{
+ struct checksum_type *ct = NULL;
+ unsigned keyusage;
+
+ /* type 0 -> pick from crypto */
+ if (type) {
+ ct = _find_checksum(type);
+ } else if (crypto) {
+ ct = crypto->et->keyed_checksum;
+ if (ct == NULL)
+ ct = crypto->et->checksum;
+ }
+
+ if(ct == NULL) {
+ krb5_set_error_string (context, "checksum type %d not supported",
+ type);
+ return KRB5_PROG_SUMTYPE_NOSUPP;
+ }
+
+ if (arcfour_checksum_p(ct, crypto)) {
+ keyusage = usage;
+ usage2arcfour(context, &keyusage);
+ } else
+ keyusage = CHECKSUM_USAGE(usage);
+
+ return create_checksum(context, ct, crypto, keyusage,
+ data, len, result);
+}
+
+static krb5_error_code
+verify_checksum(krb5_context context,
+ krb5_crypto crypto,
+ unsigned usage, /* not krb5_key_usage */
+ void *data,
+ size_t len,
+ Checksum *cksum)
+{
+ krb5_error_code ret;
+ struct key_data *dkey;
+ int keyed_checksum;
+ Checksum c;
+ struct checksum_type *ct;
+
+ ct = _find_checksum(cksum->cksumtype);
+ if (ct == NULL || (ct->flags & F_DISABLED)) {
+ krb5_set_error_string (context, "checksum type %d not supported",
+ cksum->cksumtype);
+ return KRB5_PROG_SUMTYPE_NOSUPP;
+ }
+ if(ct->checksumsize != cksum->checksum.length) {
+ krb5_clear_error_string (context);
+ return KRB5KRB_AP_ERR_BAD_INTEGRITY; /* XXX */
+ }
+ keyed_checksum = (ct->flags & F_KEYED) != 0;
+ if(keyed_checksum && crypto == NULL) {
+ krb5_clear_error_string (context);
+ return KRB5_PROG_SUMTYPE_NOSUPP; /* XXX */
+ }
+ if(keyed_checksum)
+ ret = get_checksum_key(context, crypto, usage, ct, &dkey);
+ else
+ dkey = NULL;
+ if(ct->verify)
+ return (*ct->verify)(context, dkey, data, len, usage, cksum);
+
+ ret = krb5_data_alloc (&c.checksum, ct->checksumsize);
+ if (ret)
+ return ret;
+
+ (*ct->checksum)(context, dkey, data, len, usage, &c);
+
+ if(c.checksum.length != cksum->checksum.length ||
+ memcmp(c.checksum.data, cksum->checksum.data, c.checksum.length)) {
+ krb5_clear_error_string (context);
+ ret = KRB5KRB_AP_ERR_BAD_INTEGRITY;
+ } else {
+ ret = 0;
+ }
+ krb5_data_free (&c.checksum);
+ return ret;
+}
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_verify_checksum(krb5_context context,
+ krb5_crypto crypto,
+ krb5_key_usage usage,
+ void *data,
+ size_t len,
+ Checksum *cksum)
+{
+ struct checksum_type *ct;
+ unsigned keyusage;
+
+ ct = _find_checksum(cksum->cksumtype);
+ if(ct == NULL) {
+ krb5_set_error_string (context, "checksum type %d not supported",
+ cksum->cksumtype);
+ return KRB5_PROG_SUMTYPE_NOSUPP;
+ }
+
+ if (arcfour_checksum_p(ct, crypto)) {
+ keyusage = usage;
+ usage2arcfour(context, &keyusage);
+ } else
+ keyusage = CHECKSUM_USAGE(usage);
+
+ return verify_checksum(context, crypto, keyusage,
+ data, len, cksum);
+}
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_crypto_get_checksum_type(krb5_context context,
+ krb5_crypto crypto,
+ krb5_cksumtype *type)
+{
+ struct checksum_type *ct = NULL;
+
+ if (crypto != NULL) {
+ ct = crypto->et->keyed_checksum;
+ if (ct == NULL)
+ ct = crypto->et->checksum;
+ }
+
+ if (ct == NULL) {
+ krb5_set_error_string (context, "checksum type not found");
+ return KRB5_PROG_SUMTYPE_NOSUPP;
+ }
+
+ *type = ct->type;
+
+ return 0;
+}
+
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_checksumsize(krb5_context context,
+ krb5_cksumtype type,
+ size_t *size)
+{
+ struct checksum_type *ct = _find_checksum(type);
+ if(ct == NULL) {
+ krb5_set_error_string (context, "checksum type %d not supported",
+ type);
+ return KRB5_PROG_SUMTYPE_NOSUPP;
+ }
+ *size = ct->checksumsize;
+ return 0;
+}
+
+krb5_boolean KRB5_LIB_FUNCTION
+krb5_checksum_is_keyed(krb5_context context,
+ krb5_cksumtype type)
+{
+ struct checksum_type *ct = _find_checksum(type);
+ if(ct == NULL) {
+ if (context)
+ krb5_set_error_string (context, "checksum type %d not supported",
+ type);
+ return KRB5_PROG_SUMTYPE_NOSUPP;
+ }
+ return ct->flags & F_KEYED;
+}
+
+krb5_boolean KRB5_LIB_FUNCTION
+krb5_checksum_is_collision_proof(krb5_context context,
+ krb5_cksumtype type)
+{
+ struct checksum_type *ct = _find_checksum(type);
+ if(ct == NULL) {
+ if (context)
+ krb5_set_error_string (context, "checksum type %d not supported",
+ type);
+ return KRB5_PROG_SUMTYPE_NOSUPP;
+ }
+ return ct->flags & F_CPROOF;
+}
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_checksum_disable(krb5_context context,
+ krb5_cksumtype type)
+{
+ struct checksum_type *ct = _find_checksum(type);
+ if(ct == NULL) {
+ if (context)
+ krb5_set_error_string (context, "checksum type %d not supported",
+ type);
+ return KRB5_PROG_SUMTYPE_NOSUPP;
+ }
+ ct->flags |= F_DISABLED;
+ return 0;
+}
+
+/************************************************************
+ * *
+ ************************************************************/
+
+static krb5_error_code
+NULL_encrypt(krb5_context context,
+ struct key_data *key,
+ void *data,
+ size_t len,
+ krb5_boolean encryptp,
+ int usage,
+ void *ivec)
+{
+ return 0;
+}
+
+static krb5_error_code
+DES_CBC_encrypt_null_ivec(krb5_context context,
+ struct key_data *key,
+ void *data,
+ size_t len,
+ krb5_boolean encryptp,
+ int usage,
+ void *ignore_ivec)
+{
+ DES_cblock ivec;
+ DES_key_schedule *s = key->schedule->data;
+ memset(&ivec, 0, sizeof(ivec));
+ DES_cbc_encrypt(data, data, len, s, &ivec, encryptp);
+ return 0;
+}
+
+static krb5_error_code
+DES_CBC_encrypt_key_ivec(krb5_context context,
+ struct key_data *key,
+ void *data,
+ size_t len,
+ krb5_boolean encryptp,
+ int usage,
+ void *ignore_ivec)
+{
+ DES_cblock ivec;
+ DES_key_schedule *s = key->schedule->data;
+ memcpy(&ivec, key->key->keyvalue.data, sizeof(ivec));
+ DES_cbc_encrypt(data, data, len, s, &ivec, encryptp);
+ return 0;
+}
+
+static krb5_error_code
+DES3_CBC_encrypt(krb5_context context,
+ struct key_data *key,
+ void *data,
+ size_t len,
+ krb5_boolean encryptp,
+ int usage,
+ void *ivec)
+{
+ DES_cblock local_ivec;
+ DES_key_schedule *s = key->schedule->data;
+ if(ivec == NULL) {
+ ivec = &local_ivec;
+ memset(local_ivec, 0, sizeof(local_ivec));
+ }
+ DES_ede3_cbc_encrypt(data, data, len, &s[0], &s[1], &s[2], ivec, encryptp);
+ return 0;
+}
+
+static krb5_error_code
+DES_CFB64_encrypt_null_ivec(krb5_context context,
+ struct key_data *key,
+ void *data,
+ size_t len,
+ krb5_boolean encryptp,
+ int usage,
+ void *ignore_ivec)
+{
+ DES_cblock ivec;
+ int num = 0;
+ DES_key_schedule *s = key->schedule->data;
+ memset(&ivec, 0, sizeof(ivec));
+
+ DES_cfb64_encrypt(data, data, len, s, &ivec, &num, encryptp);
+ return 0;
+}
+
+static krb5_error_code
+DES_PCBC_encrypt_key_ivec(krb5_context context,
+ struct key_data *key,
+ void *data,
+ size_t len,
+ krb5_boolean encryptp,
+ int usage,
+ void *ignore_ivec)
+{
+ DES_cblock ivec;
+ DES_key_schedule *s = key->schedule->data;
+ memcpy(&ivec, key->key->keyvalue.data, sizeof(ivec));
+
+ DES_pcbc_encrypt(data, data, len, s, &ivec, encryptp);
+ return 0;
+}
+
+/*
+ * AES draft-raeburn-krb-rijndael-krb-02
+ */
+
+void KRB5_LIB_FUNCTION
+_krb5_aes_cts_encrypt(const unsigned char *in, unsigned char *out,
+ size_t len, const void *aes_key,
+ unsigned char *ivec, const int encryptp)
+{
+ unsigned char tmp[AES_BLOCK_SIZE];
+ const AES_KEY *key = aes_key; /* XXX remove this when we always have AES */
+ int i;
+
+ /*
+ * In the framework of kerberos, the length can never be shorter
+ * then at least one blocksize.
+ */
+
+ if (encryptp) {
+
+ while(len > AES_BLOCK_SIZE) {
+ for (i = 0; i < AES_BLOCK_SIZE; i++)
+ tmp[i] = in[i] ^ ivec[i];
+ AES_encrypt(tmp, out, key);
+ memcpy(ivec, out, AES_BLOCK_SIZE);
+ len -= AES_BLOCK_SIZE;
+ in += AES_BLOCK_SIZE;
+ out += AES_BLOCK_SIZE;
+ }
+
+ for (i = 0; i < len; i++)
+ tmp[i] = in[i] ^ ivec[i];
+ for (; i < AES_BLOCK_SIZE; i++)
+ tmp[i] = 0 ^ ivec[i];
+
+ AES_encrypt(tmp, out - AES_BLOCK_SIZE, key);
+
+ memcpy(out, ivec, len);
+ memcpy(ivec, out - AES_BLOCK_SIZE, AES_BLOCK_SIZE);
+
+ } else {
+ unsigned char tmp2[AES_BLOCK_SIZE];
+ unsigned char tmp3[AES_BLOCK_SIZE];
+
+ while(len > AES_BLOCK_SIZE * 2) {
+ memcpy(tmp, in, AES_BLOCK_SIZE);
+ AES_decrypt(in, out, key);
+ for (i = 0; i < AES_BLOCK_SIZE; i++)
+ out[i] ^= ivec[i];
+ memcpy(ivec, tmp, AES_BLOCK_SIZE);
+ len -= AES_BLOCK_SIZE;
+ in += AES_BLOCK_SIZE;
+ out += AES_BLOCK_SIZE;
+ }
+
+ len -= AES_BLOCK_SIZE;
+
+ memcpy(tmp, in, AES_BLOCK_SIZE); /* save last iv */
+ AES_decrypt(in, tmp2, key);
+
+ memcpy(tmp3, in + AES_BLOCK_SIZE, len);
+ memcpy(tmp3 + len, tmp2 + len, AES_BLOCK_SIZE - len); /* xor 0 */
+
+ for (i = 0; i < len; i++)
+ out[i + AES_BLOCK_SIZE] = tmp2[i] ^ tmp3[i];
+
+ AES_decrypt(tmp3, out, key);
+ for (i = 0; i < AES_BLOCK_SIZE; i++)
+ out[i] ^= ivec[i];
+ memcpy(ivec, tmp, AES_BLOCK_SIZE);
+ }
+}
+
+static krb5_error_code
+AES_CTS_encrypt(krb5_context context,
+ struct key_data *key,
+ void *data,
+ size_t len,
+ krb5_boolean encryptp,
+ int usage,
+ void *ivec)
+{
+ struct krb5_aes_schedule *aeskey = key->schedule->data;
+ char local_ivec[AES_BLOCK_SIZE];
+ AES_KEY *k;
+
+ if (encryptp)
+ k = &aeskey->ekey;
+ else
+ k = &aeskey->dkey;
+
+ if (len < AES_BLOCK_SIZE)
+ krb5_abortx(context, "invalid use of AES_CTS_encrypt");
+ if (len == AES_BLOCK_SIZE) {
+ if (encryptp)
+ AES_encrypt(data, data, k);
+ else
+ AES_decrypt(data, data, k);
+ } else {
+ if(ivec == NULL) {
+ memset(local_ivec, 0, sizeof(local_ivec));
+ ivec = local_ivec;
+ }
+ _krb5_aes_cts_encrypt(data, data, len, k, ivec, encryptp);
+ }
+
+ return 0;
+}
+
+static krb5_error_code
+AES_CBC_encrypt(krb5_context context,
+ struct key_data *key,
+ void *data,
+ size_t len,
+ krb5_boolean encryptp,
+ int usage,
+ void *ivec)
+{
+ struct krb5_aes_schedule *aeskey = key->schedule->data;
+ char local_ivec[AES_BLOCK_SIZE];
+ AES_KEY *k;
+
+ if (encryptp)
+ k = &aeskey->ekey;
+ else
+ k = &aeskey->dkey;
+
+ if(ivec == NULL) {
+ ivec = &local_ivec;
+ memset(local_ivec, 0, sizeof(local_ivec));
+ }
+ AES_cbc_encrypt(data, data, len, k, ivec, encryptp);
+ return 0;
+}
+
+/*
+ * RC2
+ */
+
+static krb5_error_code
+RC2_CBC_encrypt(krb5_context context,
+ struct key_data *key,
+ void *data,
+ size_t len,
+ krb5_boolean encryptp,
+ int usage,
+ void *ivec)
+{
+ unsigned char local_ivec[8];
+ RC2_KEY *s = key->schedule->data;
+ if(ivec == NULL) {
+ ivec = &local_ivec;
+ memset(local_ivec, 0, sizeof(local_ivec));
+ }
+ RC2_cbc_encrypt(data, data, len, s, ivec, encryptp);
+ return 0;
+}
+
+/*
+ * section 6 of draft-brezak-win2k-krb-rc4-hmac-03
+ *
+ * warning: not for small children
+ */
+
+static krb5_error_code
+ARCFOUR_subencrypt(krb5_context context,
+ struct key_data *key,
+ void *data,
+ size_t len,
+ unsigned usage,
+ void *ivec)
+{
+ struct checksum_type *c = _find_checksum (CKSUMTYPE_RSA_MD5);
+ Checksum k1_c, k2_c, k3_c, cksum;
+ struct key_data ke;
+ krb5_keyblock kb;
+ unsigned char t[4];
+ RC4_KEY rc4_key;
+ unsigned char *cdata = data;
+ unsigned char k1_c_data[16], k2_c_data[16], k3_c_data[16];
+ krb5_error_code ret;
+
+ t[0] = (usage >> 0) & 0xFF;
+ t[1] = (usage >> 8) & 0xFF;
+ t[2] = (usage >> 16) & 0xFF;
+ t[3] = (usage >> 24) & 0xFF;
+
+ k1_c.checksum.length = sizeof(k1_c_data);
+ k1_c.checksum.data = k1_c_data;
+
+ ret = hmac(NULL, c, t, sizeof(t), 0, key, &k1_c);
+ if (ret)
+ krb5_abortx(context, "hmac failed");
+
+ memcpy (k2_c_data, k1_c_data, sizeof(k1_c_data));
+
+ k2_c.checksum.length = sizeof(k2_c_data);
+ k2_c.checksum.data = k2_c_data;
+
+ ke.key = &kb;
+ kb.keyvalue = k2_c.checksum;
+
+ cksum.checksum.length = 16;
+ cksum.checksum.data = data;
+
+ ret = hmac(NULL, c, cdata + 16, len - 16, 0, &ke, &cksum);
+ if (ret)
+ krb5_abortx(context, "hmac failed");
+
+ ke.key = &kb;
+ kb.keyvalue = k1_c.checksum;
+
+ k3_c.checksum.length = sizeof(k3_c_data);
+ k3_c.checksum.data = k3_c_data;
+
+ ret = hmac(NULL, c, data, 16, 0, &ke, &k3_c);
+ if (ret)
+ krb5_abortx(context, "hmac failed");
+
+ RC4_set_key (&rc4_key, k3_c.checksum.length, k3_c.checksum.data);
+ RC4 (&rc4_key, len - 16, cdata + 16, cdata + 16);
+ memset (k1_c_data, 0, sizeof(k1_c_data));
+ memset (k2_c_data, 0, sizeof(k2_c_data));
+ memset (k3_c_data, 0, sizeof(k3_c_data));
+ return 0;
+}
+
+static krb5_error_code
+ARCFOUR_subdecrypt(krb5_context context,
+ struct key_data *key,
+ void *data,
+ size_t len,
+ unsigned usage,
+ void *ivec)
+{
+ struct checksum_type *c = _find_checksum (CKSUMTYPE_RSA_MD5);
+ Checksum k1_c, k2_c, k3_c, cksum;
+ struct key_data ke;
+ krb5_keyblock kb;
+ unsigned char t[4];
+ RC4_KEY rc4_key;
+ unsigned char *cdata = data;
+ unsigned char k1_c_data[16], k2_c_data[16], k3_c_data[16];
+ unsigned char cksum_data[16];
+ krb5_error_code ret;
+
+ t[0] = (usage >> 0) & 0xFF;
+ t[1] = (usage >> 8) & 0xFF;
+ t[2] = (usage >> 16) & 0xFF;
+ t[3] = (usage >> 24) & 0xFF;
+
+ k1_c.checksum.length = sizeof(k1_c_data);
+ k1_c.checksum.data = k1_c_data;
+
+ ret = hmac(NULL, c, t, sizeof(t), 0, key, &k1_c);
+ if (ret)
+ krb5_abortx(context, "hmac failed");
+
+ memcpy (k2_c_data, k1_c_data, sizeof(k1_c_data));
+
+ k2_c.checksum.length = sizeof(k2_c_data);
+ k2_c.checksum.data = k2_c_data;
+
+ ke.key = &kb;
+ kb.keyvalue = k1_c.checksum;
+
+ k3_c.checksum.length = sizeof(k3_c_data);
+ k3_c.checksum.data = k3_c_data;
+
+ ret = hmac(NULL, c, cdata, 16, 0, &ke, &k3_c);
+ if (ret)
+ krb5_abortx(context, "hmac failed");
+
+ RC4_set_key (&rc4_key, k3_c.checksum.length, k3_c.checksum.data);
+ RC4 (&rc4_key, len - 16, cdata + 16, cdata + 16);
+
+ ke.key = &kb;
+ kb.keyvalue = k2_c.checksum;
+
+ cksum.checksum.length = 16;
+ cksum.checksum.data = cksum_data;
+
+ ret = hmac(NULL, c, cdata + 16, len - 16, 0, &ke, &cksum);
+ if (ret)
+ krb5_abortx(context, "hmac failed");
+
+ memset (k1_c_data, 0, sizeof(k1_c_data));
+ memset (k2_c_data, 0, sizeof(k2_c_data));
+ memset (k3_c_data, 0, sizeof(k3_c_data));
+
+ if (memcmp (cksum.checksum.data, data, 16) != 0) {
+ krb5_clear_error_string (context);
+ return KRB5KRB_AP_ERR_BAD_INTEGRITY;
+ } else {
+ return 0;
+ }
+}
+
+/*
+ * convert the usage numbers used in
+ * draft-ietf-cat-kerb-key-derivation-00.txt to the ones in
+ * draft-brezak-win2k-krb-rc4-hmac-04.txt
+ */
+
+static krb5_error_code
+usage2arcfour (krb5_context context, unsigned *usage)
+{
+ switch (*usage) {
+ case KRB5_KU_AS_REP_ENC_PART : /* 3 */
+ case KRB5_KU_TGS_REP_ENC_PART_SUB_KEY : /* 9 */
+ *usage = 8;
+ return 0;
+ case KRB5_KU_USAGE_SEAL : /* 22 */
+ *usage = 13;
+ return 0;
+ case KRB5_KU_USAGE_SIGN : /* 23 */
+ *usage = 15;
+ return 0;
+ case KRB5_KU_USAGE_SEQ: /* 24 */
+ *usage = 0;
+ return 0;
+ default :
+ return 0;
+ }
+}
+
+static krb5_error_code
+ARCFOUR_encrypt(krb5_context context,
+ struct key_data *key,
+ void *data,
+ size_t len,
+ krb5_boolean encryptp,
+ int usage,
+ void *ivec)
+{
+ krb5_error_code ret;
+ unsigned keyusage = usage;
+
+ if((ret = usage2arcfour (context, &keyusage)) != 0)
+ return ret;
+
+ if (encryptp)
+ return ARCFOUR_subencrypt (context, key, data, len, keyusage, ivec);
+ else
+ return ARCFOUR_subdecrypt (context, key, data, len, keyusage, ivec);
+}
+
+
+/*
+ * these should currently be in reverse preference order.
+ * (only relevant for !F_PSEUDO) */
+
+static struct encryption_type enctype_null = {
+ ETYPE_NULL,
+ "null",
+ NULL,
+ 1,
+ 1,
+ 0,
+ &keytype_null,
+ &checksum_none,
+ NULL,
+ F_DISABLED,
+ NULL_encrypt,
+};
+static struct encryption_type enctype_des_cbc_crc = {
+ ETYPE_DES_CBC_CRC,
+ "des-cbc-crc",
+ NULL,
+ 8,
+ 8,
+ 8,
+ &keytype_des,
+ &checksum_crc32,
+ NULL,
+ 0,
+ DES_CBC_encrypt_key_ivec,
+};
+static struct encryption_type enctype_des_cbc_md4 = {
+ ETYPE_DES_CBC_MD4,
+ "des-cbc-md4",
+ NULL,
+ 8,
+ 8,
+ 8,
+ &keytype_des,
+ &checksum_rsa_md4,
+ &checksum_rsa_md4_des,
+ 0,
+ DES_CBC_encrypt_null_ivec,
+};
+static struct encryption_type enctype_des_cbc_md5 = {
+ ETYPE_DES_CBC_MD5,
+ "des-cbc-md5",
+ NULL,
+ 8,
+ 8,
+ 8,
+ &keytype_des,
+ &checksum_rsa_md5,
+ &checksum_rsa_md5_des,
+ 0,
+ DES_CBC_encrypt_null_ivec,
+};
+static struct encryption_type enctype_arcfour_hmac_md5 = {
+ ETYPE_ARCFOUR_HMAC_MD5,
+ "arcfour-hmac-md5",
+ NULL,
+ 1,
+ 1,
+ 8,
+ &keytype_arcfour,
+ &checksum_hmac_md5,
+ NULL,
+ F_SPECIAL,
+ ARCFOUR_encrypt
+};
+static struct encryption_type enctype_des3_cbc_md5 = {
+ ETYPE_DES3_CBC_MD5,
+ "des3-cbc-md5",
+ NULL,
+ 8,
+ 8,
+ 8,
+ &keytype_des3,
+ &checksum_rsa_md5,
+ &checksum_rsa_md5_des3,
+ 0,
+ DES3_CBC_encrypt,
+};
+static struct encryption_type enctype_des3_cbc_sha1 = {
+ ETYPE_DES3_CBC_SHA1,
+ "des3-cbc-sha1",
+ NULL,
+ 8,
+ 8,
+ 8,
+ &keytype_des3_derived,
+ &checksum_sha1,
+ &checksum_hmac_sha1_des3,
+ F_DERIVED,
+ DES3_CBC_encrypt,
+};
+static struct encryption_type enctype_old_des3_cbc_sha1 = {
+ ETYPE_OLD_DES3_CBC_SHA1,
+ "old-des3-cbc-sha1",
+ NULL,
+ 8,
+ 8,
+ 8,
+ &keytype_des3,
+ &checksum_sha1,
+ &checksum_hmac_sha1_des3,
+ 0,
+ DES3_CBC_encrypt,
+};
+static struct encryption_type enctype_aes128_cts_hmac_sha1 = {
+ ETYPE_AES128_CTS_HMAC_SHA1_96,
+ "aes128-cts-hmac-sha1-96",
+ NULL,
+ 16,
+ 1,
+ 16,
+ &keytype_aes128,
+ &checksum_sha1,
+ &checksum_hmac_sha1_aes128,
+ F_DERIVED,
+ AES_CTS_encrypt,
+};
+static struct encryption_type enctype_aes256_cts_hmac_sha1 = {
+ ETYPE_AES256_CTS_HMAC_SHA1_96,
+ "aes256-cts-hmac-sha1-96",
+ NULL,
+ 16,
+ 1,
+ 16,
+ &keytype_aes256,
+ &checksum_sha1,
+ &checksum_hmac_sha1_aes256,
+ F_DERIVED,
+ AES_CTS_encrypt,
+};
+static unsigned aes_128_cbc_num[] = { 2, 16, 840, 1, 101, 3, 4, 1, 2 };
+static heim_oid aes_128_cbc_oid = kcrypto_oid_enc(aes_128_cbc_num);
+static struct encryption_type enctype_aes128_cbc_none = {
+ ETYPE_AES128_CBC_NONE,
+ "aes128-cbc-none",
+ &aes_128_cbc_oid,
+ 16,
+ 16,
+ 16,
+ &keytype_aes128,
+ &checksum_none,
+ NULL,
+ F_PSEUDO|F_PADCMS,
+ AES_CBC_encrypt,
+};
+static unsigned aes_192_cbc_num[] = { 2, 16, 840, 1, 101, 3, 4, 1, 22 };
+static heim_oid aes_192_cbc_oid = kcrypto_oid_enc(aes_192_cbc_num);
+static struct encryption_type enctype_aes192_cbc_none = {
+ ETYPE_AES192_CBC_NONE,
+ "aes192-cbc-none",
+ &aes_192_cbc_oid,
+ 16,
+ 16,
+ 16,
+ &keytype_aes192,
+ &checksum_none,
+ NULL,
+ F_PSEUDO|F_PADCMS,
+ AES_CBC_encrypt,
+};
+static unsigned aes_256_cbc_num[] = { 2, 16, 840, 1, 101, 3, 4, 1, 42 };
+static heim_oid aes_256_cbc_oid = kcrypto_oid_enc(aes_256_cbc_num);
+static struct encryption_type enctype_aes256_cbc_none = {
+ ETYPE_AES256_CBC_NONE,
+ "aes256-cbc-none",
+ &aes_256_cbc_oid,
+ 16,
+ 16,
+ 16,
+ &keytype_aes256,
+ &checksum_none,
+ NULL,
+ F_PSEUDO|F_PADCMS,
+ AES_CBC_encrypt,
+};
+static struct encryption_type enctype_des_cbc_none = {
+ ETYPE_DES_CBC_NONE,
+ "des-cbc-none",
+ NULL,
+ 8,
+ 8,
+ 0,
+ &keytype_des,
+ &checksum_none,
+ NULL,
+ F_PSEUDO,
+ DES_CBC_encrypt_null_ivec,
+};
+static struct encryption_type enctype_des_cfb64_none = {
+ ETYPE_DES_CFB64_NONE,
+ "des-cfb64-none",
+ NULL,
+ 1,
+ 1,
+ 0,
+ &keytype_des,
+ &checksum_none,
+ NULL,
+ F_PSEUDO,
+ DES_CFB64_encrypt_null_ivec,
+};
+static struct encryption_type enctype_des_pcbc_none = {
+ ETYPE_DES_PCBC_NONE,
+ "des-pcbc-none",
+ NULL,
+ 8,
+ 8,
+ 0,
+ &keytype_des,
+ &checksum_none,
+ NULL,
+ F_PSEUDO,
+ DES_PCBC_encrypt_key_ivec,
+};
+static unsigned des_ede3_cbc_num[] = { 1, 2, 840, 113549, 3, 7 };
+static heim_oid des_ede3_cbc_oid = kcrypto_oid_enc(des_ede3_cbc_num);
+static struct encryption_type enctype_des3_cbc_none_cms = {
+ ETYPE_DES3_CBC_NONE_CMS,
+ "des3-cbc-none-cms",
+ &des_ede3_cbc_oid,
+ 8,
+ 8,
+ 0,
+ &keytype_des3_derived,
+ &checksum_none,
+ NULL,
+ F_PSEUDO|F_PADCMS,
+ DES3_CBC_encrypt,
+};
+static struct encryption_type enctype_des3_cbc_none = {
+ ETYPE_DES3_CBC_NONE,
+ "des3-cbc-none",
+ NULL,
+ 8,
+ 8,
+ 0,
+ &keytype_des3_derived,
+ &checksum_none,
+ NULL,
+ F_PSEUDO,
+ DES3_CBC_encrypt,
+};
+static unsigned rc2CBC_num[] = { 1, 2, 840, 113549, 3, 2 };
+static heim_oid rc2CBC_oid = kcrypto_oid_enc(rc2CBC_num);
+static struct encryption_type enctype_rc2_cbc_none = {
+ ETYPE_RC2_CBC_NONE,
+ "rc2-cbc-none",
+ &rc2CBC_oid,
+ 8,
+ 8,
+ 0,
+ &keytype_rc2,
+ &checksum_none,
+ NULL,
+ F_PSEUDO|F_PADCMS,
+ RC2_CBC_encrypt,
+};
+
+static struct encryption_type *etypes[] = {
+ &enctype_null,
+ &enctype_des_cbc_crc,
+ &enctype_des_cbc_md4,
+ &enctype_des_cbc_md5,
+ &enctype_arcfour_hmac_md5,
+ &enctype_des3_cbc_md5,
+ &enctype_des3_cbc_sha1,
+ &enctype_old_des3_cbc_sha1,
+ &enctype_aes128_cts_hmac_sha1,
+ &enctype_aes256_cts_hmac_sha1,
+ &enctype_aes128_cbc_none,
+ &enctype_aes192_cbc_none,
+ &enctype_aes256_cbc_none,
+ &enctype_des_cbc_none,
+ &enctype_des_cfb64_none,
+ &enctype_des_pcbc_none,
+ &enctype_des3_cbc_none,
+ &enctype_des3_cbc_none_cms,
+ &enctype_rc2_cbc_none
+};
+
+static unsigned num_etypes = sizeof(etypes) / sizeof(etypes[0]);
+
+
+static struct encryption_type *
+_find_enctype(krb5_enctype type)
+{
+ int i;
+ for(i = 0; i < num_etypes; i++)
+ if(etypes[i]->type == type)
+ return etypes[i];
+ return NULL;
+}
+
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_enctype_to_string(krb5_context context,
+ krb5_enctype etype,
+ char **string)
+{
+ struct encryption_type *e;
+ e = _find_enctype(etype);
+ if(e == NULL) {
+ krb5_set_error_string (context, "encryption type %d not supported",
+ etype);
+ return KRB5_PROG_ETYPE_NOSUPP;
+ }
+ *string = strdup(e->name);
+ if(*string == NULL) {
+ krb5_set_error_string(context, "malloc: out of memory");
+ return ENOMEM;
+ }
+ return 0;
+}
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_string_to_enctype(krb5_context context,
+ const char *string,
+ krb5_enctype *etype)
+{
+ int i;
+ for(i = 0; i < num_etypes; i++)
+ if(strcasecmp(etypes[i]->name, string) == 0){
+ *etype = etypes[i]->type;
+ return 0;
+ }
+ krb5_set_error_string (context, "encryption type %s not supported",
+ string);
+ return KRB5_PROG_ETYPE_NOSUPP;
+}
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_enctype_to_oid(krb5_context context,
+ krb5_enctype etype,
+ heim_oid *oid)
+{
+ struct encryption_type *et = _find_enctype(etype);
+ if(et == NULL) {
+ krb5_set_error_string (context, "encryption type %d not supported",
+ etype);
+ return KRB5_PROG_ETYPE_NOSUPP;
+ }
+ if(et->oid == NULL) {
+ krb5_set_error_string (context, "%s have not oid", et->name);
+ return KRB5_PROG_ETYPE_NOSUPP;
+ }
+ krb5_clear_error_string(context);
+ return copy_oid(et->oid, oid);
+}
+
+krb5_error_code KRB5_LIB_FUNCTION
+_krb5_oid_to_enctype(krb5_context context,
+ const heim_oid *oid,
+ krb5_enctype *etype)
+{
+ int i;
+ for(i = 0; i < num_etypes; i++) {
+ if(etypes[i]->oid && heim_oid_cmp(etypes[i]->oid, oid) == 0) {
+ *etype = etypes[i]->type;
+ return 0;
+ }
+ }
+ krb5_set_error_string(context, "enctype for oid not supported");
+ return KRB5_PROG_ETYPE_NOSUPP;
+}
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_enctype_to_keytype(krb5_context context,
+ krb5_enctype etype,
+ krb5_keytype *keytype)
+{
+ struct encryption_type *e = _find_enctype(etype);
+ if(e == NULL) {
+ krb5_set_error_string (context, "encryption type %d not supported",
+ etype);
+ return KRB5_PROG_ETYPE_NOSUPP;
+ }
+ *keytype = e->keytype->type; /* XXX */
+ return 0;
+}
+
+#if 0
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_keytype_to_enctype(krb5_context context,
+ krb5_keytype keytype,
+ krb5_enctype *etype)
+{
+ struct key_type *kt = _find_keytype(keytype);
+ krb5_warnx(context, "krb5_keytype_to_enctype(%u)", keytype);
+ if(kt == NULL)
+ return KRB5_PROG_KEYTYPE_NOSUPP;
+ *etype = kt->best_etype;
+ return 0;
+}
+#endif
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_keytype_to_enctypes (krb5_context context,
+ krb5_keytype keytype,
+ unsigned *len,
+ krb5_enctype **val)
+{
+ int i;
+ unsigned n = 0;
+ krb5_enctype *ret;
+
+ for (i = num_etypes - 1; i >= 0; --i) {
+ if (etypes[i]->keytype->type == keytype
+ && !(etypes[i]->flags & F_PSEUDO))
+ ++n;
+ }
+ ret = malloc(n * sizeof(*ret));
+ if (ret == NULL && n != 0) {
+ krb5_set_error_string(context, "malloc: out of memory");
+ return ENOMEM;
+ }
+ n = 0;
+ for (i = num_etypes - 1; i >= 0; --i) {
+ if (etypes[i]->keytype->type == keytype
+ && !(etypes[i]->flags & F_PSEUDO))
+ ret[n++] = etypes[i]->type;
+ }
+ *len = n;
+ *val = ret;
+ return 0;
+}
+
+/*
+ * First take the configured list of etypes for `keytype' if available,
+ * else, do `krb5_keytype_to_enctypes'.
+ */
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_keytype_to_enctypes_default (krb5_context context,
+ krb5_keytype keytype,
+ unsigned *len,
+ krb5_enctype **val)
+{
+ int i, n;
+ krb5_enctype *ret;
+
+ if (keytype != KEYTYPE_DES || context->etypes_des == NULL)
+ return krb5_keytype_to_enctypes (context, keytype, len, val);
+
+ for (n = 0; context->etypes_des[n]; ++n)
+ ;
+ ret = malloc (n * sizeof(*ret));
+ if (ret == NULL && n != 0) {
+ krb5_set_error_string(context, "malloc: out of memory");
+ return ENOMEM;
+ }
+ for (i = 0; i < n; ++i)
+ ret[i] = context->etypes_des[i];
+ *len = n;
+ *val = ret;
+ return 0;
+}
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_enctype_valid(krb5_context context,
+ krb5_enctype etype)
+{
+ struct encryption_type *e = _find_enctype(etype);
+ if(e == NULL) {
+ krb5_set_error_string (context, "encryption type %d not supported",
+ etype);
+ return KRB5_PROG_ETYPE_NOSUPP;
+ }
+ if (e->flags & F_DISABLED) {
+ krb5_set_error_string (context, "encryption type %s is disabled",
+ e->name);
+ return KRB5_PROG_ETYPE_NOSUPP;
+ }
+ return 0;
+}
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_cksumtype_valid(krb5_context context,
+ krb5_cksumtype ctype)
+{
+ struct checksum_type *c = _find_checksum(ctype);
+ if (c == NULL) {
+ krb5_set_error_string (context, "checksum type %d not supported",
+ ctype);
+ return KRB5_PROG_SUMTYPE_NOSUPP;
+ }
+ if (c->flags & F_DISABLED) {
+ krb5_set_error_string (context, "checksum type %s is disabled",
+ c->name);
+ return KRB5_PROG_SUMTYPE_NOSUPP;
+ }
+ return 0;
+}
+
+
+/* if two enctypes have compatible keys */
+krb5_boolean KRB5_LIB_FUNCTION
+krb5_enctypes_compatible_keys(krb5_context context,
+ krb5_enctype etype1,
+ krb5_enctype etype2)
+{
+ struct encryption_type *e1 = _find_enctype(etype1);
+ struct encryption_type *e2 = _find_enctype(etype2);
+ return e1 != NULL && e2 != NULL && e1->keytype == e2->keytype;
+}
+
+static krb5_boolean
+derived_crypto(krb5_context context,
+ krb5_crypto crypto)
+{
+ return (crypto->et->flags & F_DERIVED) != 0;
+}
+
+static krb5_boolean
+special_crypto(krb5_context context,
+ krb5_crypto crypto)
+{
+ return (crypto->et->flags & F_SPECIAL) != 0;
+}
+
+#define CHECKSUMSIZE(C) ((C)->checksumsize)
+#define CHECKSUMTYPE(C) ((C)->type)
+
+static krb5_error_code
+encrypt_internal_derived(krb5_context context,
+ krb5_crypto crypto,
+ unsigned usage,
+ void *data,
+ size_t len,
+ krb5_data *result,
+ void *ivec)
+{
+ size_t sz, block_sz, checksum_sz, total_sz;
+ Checksum cksum;
+ unsigned char *p, *q;
+ krb5_error_code ret;
+ struct key_data *dkey;
+ const struct encryption_type *et = crypto->et;
+
+ checksum_sz = CHECKSUMSIZE(et->keyed_checksum);
+
+ sz = et->confoundersize + len;
+ block_sz = (sz + et->padsize - 1) &~ (et->padsize - 1); /* pad */
+ total_sz = block_sz + checksum_sz;
+ p = calloc(1, total_sz);
+ if(p == NULL) {
+ krb5_set_error_string(context, "malloc: out of memory");
+ return ENOMEM;
+ }
+
+ q = p;
+ krb5_generate_random_block(q, et->confoundersize); /* XXX */
+ q += et->confoundersize;
+ memcpy(q, data, len);
+
+ ret = create_checksum(context,
+ et->keyed_checksum,
+ crypto,
+ INTEGRITY_USAGE(usage),
+ p,
+ block_sz,
+ &cksum);
+ if(ret == 0 && cksum.checksum.length != checksum_sz) {
+ free_Checksum (&cksum);
+ krb5_clear_error_string (context);
+ ret = KRB5_CRYPTO_INTERNAL;
+ }
+ if(ret)
+ goto fail;
+ memcpy(p + block_sz, cksum.checksum.data, cksum.checksum.length);
+ free_Checksum (&cksum);
+ ret = _get_derived_key(context, crypto, ENCRYPTION_USAGE(usage), &dkey);
+ if(ret)
+ goto fail;
+ ret = _key_schedule(context, dkey, crypto->params);
+ if(ret)
+ goto fail;
+#ifdef CRYPTO_DEBUG
+ krb5_crypto_debug(context, 1, block_sz, dkey->key);
+#endif
+ ret = (*et->encrypt)(context, dkey, p, block_sz, 1, usage, ivec);
+ if (ret)
+ goto fail;
+ result->data = p;
+ result->length = total_sz;
+ return 0;
+ fail:
+ memset(p, 0, total_sz);
+ free(p);
+ return ret;
+}
+
+
+static krb5_error_code
+encrypt_internal(krb5_context context,
+ krb5_crypto crypto,
+ void *data,
+ size_t len,
+ krb5_data *result,
+ void *ivec)
+{
+ size_t sz, block_sz, checksum_sz, padsize = 0;
+ Checksum cksum;
+ unsigned char *p, *q;
+ krb5_error_code ret;
+ const struct encryption_type *et = crypto->et;
+
+ checksum_sz = CHECKSUMSIZE(et->checksum);
+
+ sz = et->confoundersize + checksum_sz + len;
+ block_sz = (sz + et->padsize - 1) &~ (et->padsize - 1); /* pad */
+ if ((et->flags & F_PADCMS) && et->padsize != 1) {
+ padsize = et->padsize - (sz % et->padsize);
+ if (padsize == et->padsize)
+ block_sz += et->padsize;
+ }
+ p = calloc(1, block_sz);
+ if(p == NULL) {
+ krb5_set_error_string(context, "malloc: out of memory");
+ return ENOMEM;
+ }
+
+ q = p;
+ krb5_generate_random_block(q, et->confoundersize); /* XXX */
+ q += et->confoundersize;
+ memset(q, 0, checksum_sz);
+ q += checksum_sz;
+ memcpy(q, data, len);
+
+ ret = create_checksum(context,
+ et->checksum,
+ crypto,
+ 0,
+ p,
+ block_sz,
+ &cksum);
+ if(ret == 0 && cksum.checksum.length != checksum_sz) {
+ krb5_clear_error_string (context);
+ free_Checksum(&cksum);
+ ret = KRB5_CRYPTO_INTERNAL;
+ }
+ if(ret)
+ goto fail;
+ memcpy(p + et->confoundersize, cksum.checksum.data, cksum.checksum.length);
+ free_Checksum(&cksum);
+ ret = _key_schedule(context, &crypto->key, crypto->params);
+ if(ret)
+ goto fail;
+ if (et->flags & F_PADCMS) {
+ int i;
+ q = p + len + checksum_sz + et->confoundersize;
+ for (i = 0; i < padsize; i++)
+ q[i] = padsize;
+ }
+#ifdef CRYPTO_DEBUG
+ krb5_crypto_debug(context, 1, block_sz, crypto->key.key);
+#endif
+ ret = (*et->encrypt)(context, &crypto->key, p, block_sz, 1, 0, ivec);
+ if (ret) {
+ memset(p, 0, block_sz);
+ free(p);
+ return ret;
+ }
+ result->data = p;
+ result->length = block_sz;
+ return 0;
+ fail:
+ memset(p, 0, block_sz);
+ free(p);
+ return ret;
+}
+
+static krb5_error_code
+encrypt_internal_special(krb5_context context,
+ krb5_crypto crypto,
+ int usage,
+ void *data,
+ size_t len,
+ krb5_data *result,
+ void *ivec)
+{
+ struct encryption_type *et = crypto->et;
+ size_t cksum_sz = CHECKSUMSIZE(et->checksum);
+ size_t sz = len + cksum_sz + et->confoundersize;
+ char *tmp, *p;
+ krb5_error_code ret;
+
+ tmp = malloc (sz);
+ if (tmp == NULL) {
+ krb5_set_error_string(context, "malloc: out of memory");
+ return ENOMEM;
+ }
+ p = tmp;
+ memset (p, 0, cksum_sz);
+ p += cksum_sz;
+ krb5_generate_random_block(p, et->confoundersize);
+ p += et->confoundersize;
+ memcpy (p, data, len);
+ ret = (*et->encrypt)(context, &crypto->key, tmp, sz, TRUE, usage, ivec);
+ if (ret) {
+ memset(tmp, 0, sz);
+ free(tmp);
+ return ret;
+ }
+ result->data = tmp;
+ result->length = sz;
+ return 0;
+}
+
+static krb5_error_code
+decrypt_internal_derived(krb5_context context,
+ krb5_crypto crypto,
+ unsigned usage,
+ void *data,
+ size_t len,
+ krb5_data *result,
+ void *ivec)
+{
+ size_t checksum_sz;
+ Checksum cksum;
+ unsigned char *p;
+ krb5_error_code ret;
+ struct key_data *dkey;
+ struct encryption_type *et = crypto->et;
+ unsigned long l;
+
+ checksum_sz = CHECKSUMSIZE(et->keyed_checksum);
+ if (len < checksum_sz) {
+ krb5_clear_error_string (context);
+ return EINVAL; /* XXX - better error code? */
+ }
+
+ if (((len - checksum_sz) % et->padsize) != 0) {
+ krb5_clear_error_string(context);
+ return KRB5_BAD_MSIZE;
+ }
+
+ p = malloc(len);
+ if(len != 0 && p == NULL) {
+ krb5_set_error_string(context, "malloc: out of memory");
+ return ENOMEM;
+ }
+ memcpy(p, data, len);
+
+ len -= checksum_sz;
+
+ ret = _get_derived_key(context, crypto, ENCRYPTION_USAGE(usage), &dkey);
+ if(ret) {
+ free(p);
+ return ret;
+ }
+ ret = _key_schedule(context, dkey, crypto->params);
+ if(ret) {
+ free(p);
+ return ret;
+ }
+#ifdef CRYPTO_DEBUG
+ krb5_crypto_debug(context, 0, len, dkey->key);
+#endif
+ ret = (*et->encrypt)(context, dkey, p, len, 0, usage, ivec);
+ if (ret) {
+ free(p);
+ return ret;
+ }
+
+ cksum.checksum.data = p + len;
+ cksum.checksum.length = checksum_sz;
+ cksum.cksumtype = CHECKSUMTYPE(et->keyed_checksum);
+
+ ret = verify_checksum(context,
+ crypto,
+ INTEGRITY_USAGE(usage),
+ p,
+ len,
+ &cksum);
+ if(ret) {
+ free(p);
+ return ret;
+ }
+ l = len - et->confoundersize;
+ memmove(p, p + et->confoundersize, l);
+ result->data = realloc(p, l);
+ if(result->data == NULL) {
+ free(p);
+ krb5_set_error_string(context, "malloc: out of memory");
+ return ENOMEM;
+ }
+ result->length = l;
+ return 0;
+}
+
+static krb5_error_code
+decrypt_internal(krb5_context context,
+ krb5_crypto crypto,
+ void *data,
+ size_t len,
+ krb5_data *result,
+ void *ivec)
+{
+ krb5_error_code ret;
+ unsigned char *p;
+ Checksum cksum;
+ size_t checksum_sz, l;
+ struct encryption_type *et = crypto->et;
+
+ if ((len % et->padsize) != 0) {
+ krb5_clear_error_string(context);
+ return KRB5_BAD_MSIZE;
+ }
+
+ checksum_sz = CHECKSUMSIZE(et->checksum);
+ p = malloc(len);
+ if(len != 0 && p == NULL) {
+ krb5_set_error_string(context, "malloc: out of memory");
+ return ENOMEM;
+ }
+ memcpy(p, data, len);
+
+ ret = _key_schedule(context, &crypto->key, crypto->params);
+ if(ret) {
+ free(p);
+ return ret;
+ }
+#ifdef CRYPTO_DEBUG
+ krb5_crypto_debug(context, 0, len, crypto->key.key);
+#endif
+ ret = (*et->encrypt)(context, &crypto->key, p, len, 0, 0, ivec);
+ if (ret) {
+ free(p);
+ return ret;
+ }
+ ret = krb5_data_copy(&cksum.checksum, p + et->confoundersize, checksum_sz);
+ if(ret) {
+ free(p);
+ return ret;
+ }
+ memset(p + et->confoundersize, 0, checksum_sz);
+ cksum.cksumtype = CHECKSUMTYPE(et->checksum);
+ ret = verify_checksum(context, NULL, 0, p, len, &cksum);
+ free_Checksum(&cksum);
+ if(ret) {
+ free(p);
+ return ret;
+ }
+ l = len - et->confoundersize - checksum_sz;
+ memmove(p, p + et->confoundersize + checksum_sz, l);
+ result->data = realloc(p, l);
+ if(result->data == NULL) {
+ free(p);
+ krb5_set_error_string(context, "malloc: out of memory");
+ return ENOMEM;
+ }
+ result->length = l;
+ return 0;
+}
+
+static krb5_error_code
+decrypt_internal_special(krb5_context context,
+ krb5_crypto crypto,
+ int usage,
+ void *data,
+ size_t len,
+ krb5_data *result,
+ void *ivec)
+{
+ struct encryption_type *et = crypto->et;
+ size_t cksum_sz = CHECKSUMSIZE(et->checksum);
+ size_t sz = len - cksum_sz - et->confoundersize;
+ unsigned char *p;
+ krb5_error_code ret;
+
+ if ((len % et->padsize) != 0) {
+ krb5_clear_error_string(context);
+ return KRB5_BAD_MSIZE;
+ }
+
+ p = malloc (len);
+ if (p == NULL) {
+ krb5_set_error_string(context, "malloc: out of memory");
+ return ENOMEM;
+ }
+ memcpy(p, data, len);
+
+ ret = (*et->encrypt)(context, &crypto->key, p, len, FALSE, usage, ivec);
+ if (ret) {
+ free(p);
+ return ret;
+ }
+
+ memmove (p, p + cksum_sz + et->confoundersize, sz);
+ result->data = realloc(p, sz);
+ if(result->data == NULL) {
+ free(p);
+ krb5_set_error_string(context, "malloc: out of memory");
+ return ENOMEM;
+ }
+ result->length = sz;
+ return 0;
+}
+
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_encrypt_ivec(krb5_context context,
+ krb5_crypto crypto,
+ unsigned usage,
+ void *data,
+ size_t len,
+ krb5_data *result,
+ void *ivec)
+{
+ if(derived_crypto(context, crypto))
+ return encrypt_internal_derived(context, crypto, usage,
+ data, len, result, ivec);
+ else if (special_crypto(context, crypto))
+ return encrypt_internal_special (context, crypto, usage,
+ data, len, result, ivec);
+ else
+ return encrypt_internal(context, crypto, data, len, result, ivec);
+}
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_encrypt(krb5_context context,
+ krb5_crypto crypto,
+ unsigned usage,
+ void *data,
+ size_t len,
+ krb5_data *result)
+{
+ return krb5_encrypt_ivec(context, crypto, usage, data, len, result, NULL);
+}
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_encrypt_EncryptedData(krb5_context context,
+ krb5_crypto crypto,
+ unsigned usage,
+ void *data,
+ size_t len,
+ int kvno,
+ EncryptedData *result)
+{
+ result->etype = CRYPTO_ETYPE(crypto);
+ if(kvno){
+ ALLOC(result->kvno, 1);
+ *result->kvno = kvno;
+ }else
+ result->kvno = NULL;
+ return krb5_encrypt(context, crypto, usage, data, len, &result->cipher);
+}
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_decrypt_ivec(krb5_context context,
+ krb5_crypto crypto,
+ unsigned usage,
+ void *data,
+ size_t len,
+ krb5_data *result,
+ void *ivec)
+{
+ if(derived_crypto(context, crypto))
+ return decrypt_internal_derived(context, crypto, usage,
+ data, len, result, ivec);
+ else if (special_crypto (context, crypto))
+ return decrypt_internal_special(context, crypto, usage,
+ data, len, result, ivec);
+ else
+ return decrypt_internal(context, crypto, data, len, result, ivec);
+}
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_decrypt(krb5_context context,
+ krb5_crypto crypto,
+ unsigned usage,
+ void *data,
+ size_t len,
+ krb5_data *result)
+{
+ return krb5_decrypt_ivec (context, crypto, usage, data, len, result,
+ NULL);
+}
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_decrypt_EncryptedData(krb5_context context,
+ krb5_crypto crypto,
+ unsigned usage,
+ const EncryptedData *e,
+ krb5_data *result)
+{
+ return krb5_decrypt(context, crypto, usage,
+ e->cipher.data, e->cipher.length, result);
+}
+
+/************************************************************
+ * *
+ ************************************************************/
+
+#ifdef HAVE_OPENSSL
+#include <openssl/rand.h>
+
+/* From openssl/crypto/rand/rand_lcl.h */
+#define ENTROPY_NEEDED 20
+static int
+seed_something(void)
+{
+ char buf[1024], seedfile[256];
+
+ /* If there is a seed file, load it. But such a file cannot be trusted,
+ so use 0 for the entropy estimate */
+ if (RAND_file_name(seedfile, sizeof(seedfile))) {
+ int fd;
+ fd = open(seedfile, O_RDONLY);
+ if (fd >= 0) {
+ ssize_t ret;
+ ret = read(fd, buf, sizeof(buf));
+ if (ret > 0)
+ RAND_add(buf, ret, 0.0);
+ close(fd);
+ } else
+ seedfile[0] = '\0';
+ } else
+ seedfile[0] = '\0';
+
+ /* Calling RAND_status() will try to use /dev/urandom if it exists so
+ we do not have to deal with it. */
+ if (RAND_status() != 1) {
+ krb5_context context;
+ const char *p;
+
+ /* Try using egd */
+ if (!krb5_init_context(&context)) {
+ p = krb5_config_get_string(context, NULL, "libdefaults",
+ "egd_socket", NULL);
+ if (p != NULL)
+ RAND_egd_bytes(p, ENTROPY_NEEDED);
+ krb5_free_context(context);
+ }
+ }
+
+ if (RAND_status() == 1) {
+ /* Update the seed file */
+ if (seedfile[0])
+ RAND_write_file(seedfile);
+
+ return 0;
+ } else
+ return -1;
+}
+
+void KRB5_LIB_FUNCTION
+krb5_generate_random_block(void *buf, size_t len)
+{
+ static int rng_initialized = 0;
+
+ HEIMDAL_MUTEX_lock(&crypto_mutex);
+ if (!rng_initialized) {
+ if (seed_something())
+ krb5_abortx(NULL, "Fatal: could not seed the random number generator");
+
+ rng_initialized = 1;
+ }
+ HEIMDAL_MUTEX_unlock(&crypto_mutex);
+ RAND_bytes(buf, len);
+}
+
+#else
+
+void KRB5_LIB_FUNCTION
+krb5_generate_random_block(void *buf, size_t len)
+{
+ DES_cblock key, out;
+ static DES_cblock counter;
+ static DES_key_schedule schedule;
+ int i;
+ static int initialized = 0;
+
+ HEIMDAL_MUTEX_lock(&crypto_mutex);
+ if(!initialized) {
+ DES_new_random_key(&key);
+ DES_set_key(&key, &schedule);
+ memset(&key, 0, sizeof(key));
+ DES_new_random_key(&counter);
+ initialized = 1;
+ }
+ HEIMDAL_MUTEX_unlock(&crypto_mutex);
+ while(len > 0) {
+ DES_ecb_encrypt(&counter, &out, &schedule, DES_ENCRYPT);
+ for(i = 7; i >=0; i--)
+ if(counter[i]++)
+ break;
+ memcpy(buf, out, min(len, sizeof(out)));
+ len -= min(len, sizeof(out));
+ buf = (char*)buf + sizeof(out);
+ }
+}
+#endif
+
+static void
+DES3_postproc(krb5_context context,
+ unsigned char *k, size_t len, struct key_data *key)
+{
+ DES3_random_to_key(context, key->key, k, len);
+
+ if (key->schedule) {
+ krb5_free_data(context, key->schedule);
+ key->schedule = NULL;
+ }
+}
+
+static krb5_error_code
+derive_key(krb5_context context,
+ struct encryption_type *et,
+ struct key_data *key,
+ const void *constant,
+ size_t len)
+{
+ unsigned char *k;
+ unsigned int nblocks = 0, i;
+ krb5_error_code ret = 0;
+
+ struct key_type *kt = et->keytype;
+ /* since RC2 is only the weird crypto alg with parameter and this
+ * function not defined with work with RC2, this is ok */
+ ret = _key_schedule(context, key, NULL);
+ if(ret)
+ return ret;
+ if(et->blocksize * 8 < kt->bits ||
+ len != et->blocksize) {
+ nblocks = (kt->bits + et->blocksize * 8 - 1) / (et->blocksize * 8);
+ k = malloc(nblocks * et->blocksize);
+ if(k == NULL) {
+ krb5_set_error_string(context, "malloc: out of memory");
+ return ENOMEM;
+ }
+ _krb5_n_fold(constant, len, k, et->blocksize);
+ for(i = 0; i < nblocks; i++) {
+ if(i > 0)
+ memcpy(k + i * et->blocksize,
+ k + (i - 1) * et->blocksize,
+ et->blocksize);
+ (*et->encrypt)(context, key, k + i * et->blocksize, et->blocksize,
+ 1, 0, NULL);
+ }
+ } else {
+ /* this case is probably broken, but won't be run anyway */
+ void *c = malloc(len);
+ size_t res_len = (kt->bits + 7) / 8;
+
+ if(len != 0 && c == NULL) {
+ krb5_set_error_string(context, "malloc: out of memory");
+ return ENOMEM;
+ }
+ memcpy(c, constant, len);
+ (*et->encrypt)(context, key, c, len, 1, 0, NULL);
+ k = malloc(res_len);
+ if(res_len != 0 && k == NULL) {
+ free(c);
+ krb5_set_error_string(context, "malloc: out of memory");
+ return ENOMEM;
+ }
+ _krb5_n_fold(c, len, k, res_len);
+ free(c);
+ }
+
+ /* XXX keytype dependent post-processing */
+ switch(kt->type) {
+ case KEYTYPE_DES3:
+ DES3_postproc(context, k, nblocks * et->blocksize, key);
+ break;
+ case KEYTYPE_AES128:
+ case KEYTYPE_AES256:
+ memcpy(key->key->keyvalue.data, k, key->key->keyvalue.length);
+ break;
+ default:
+ krb5_set_error_string(context,
+ "derive_key() called with unknown keytype (%u)",
+ kt->type);
+ ret = KRB5_CRYPTO_INTERNAL;
+ break;
+ }
+ if (key->schedule) {
+ krb5_free_data(context, key->schedule);
+ key->schedule = NULL;
+ }
+ memset(k, 0, nblocks * et->blocksize);
+ free(k);
+ return ret;
+}
+
+static struct key_data *
+_new_derived_key(krb5_crypto crypto, unsigned usage)
+{
+ struct key_usage *d = crypto->key_usage;
+ d = realloc(d, (crypto->num_key_usage + 1) * sizeof(*d));
+ if(d == NULL)
+ return NULL;
+ crypto->key_usage = d;
+ d += crypto->num_key_usage++;
+ memset(d, 0, sizeof(*d));
+ d->usage = usage;
+ return &d->key;
+}
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_derive_key(krb5_context context,
+ const krb5_keyblock *key,
+ krb5_enctype etype,
+ const void *constant,
+ size_t constant_len,
+ krb5_keyblock **derived_key)
+{
+ krb5_error_code ret;
+ struct encryption_type *et;
+ struct key_data d;
+
+ et = _find_enctype (etype);
+ if (et == NULL) {
+ krb5_set_error_string(context, "encryption type %d not supported",
+ etype);
+ return KRB5_PROG_ETYPE_NOSUPP;
+ }
+
+ ret = krb5_copy_keyblock(context, key, derived_key);
+ if (ret)
+ return ret;
+
+ d.key = *derived_key;
+ d.schedule = NULL;
+ ret = derive_key(context, et, &d, constant, constant_len);
+ if (ret)
+ return ret;
+ ret = krb5_copy_keyblock(context, d.key, derived_key);
+ return ret;
+}
+
+static krb5_error_code
+_get_derived_key(krb5_context context,
+ krb5_crypto crypto,
+ unsigned usage,
+ struct key_data **key)
+{
+ int i;
+ struct key_data *d;
+ unsigned char constant[5];
+
+ for(i = 0; i < crypto->num_key_usage; i++)
+ if(crypto->key_usage[i].usage == usage) {
+ *key = &crypto->key_usage[i].key;
+ return 0;
+ }
+ d = _new_derived_key(crypto, usage);
+ if(d == NULL) {
+ krb5_set_error_string(context, "malloc: out of memory");
+ return ENOMEM;
+ }
+ krb5_copy_keyblock(context, crypto->key.key, &d->key);
+ _krb5_put_int(constant, usage, 5);
+ derive_key(context, crypto->et, d, constant, sizeof(constant));
+ *key = d;
+ return 0;
+}
+
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_crypto_init(krb5_context context,
+ const krb5_keyblock *key,
+ krb5_enctype etype,
+ krb5_crypto *crypto)
+{
+ krb5_error_code ret;
+ ALLOC(*crypto, 1);
+ if(*crypto == NULL) {
+ krb5_set_error_string(context, "malloc: out of memory");
+ return ENOMEM;
+ }
+ if(etype == ETYPE_NULL)
+ etype = key->keytype;
+ (*crypto)->et = _find_enctype(etype);
+ if((*crypto)->et == NULL || ((*crypto)->et->flags & F_DISABLED)) {
+ free(*crypto);
+ *crypto = NULL;
+ krb5_set_error_string (context, "encryption type %d not supported",
+ etype);
+ return KRB5_PROG_ETYPE_NOSUPP;
+ }
+ if((*crypto)->et->keytype->minsize > key->keyvalue.length) {
+ free(*crypto);
+ *crypto = NULL;
+ krb5_set_error_string (context, "encryption key has bad length");
+ return KRB5_BAD_KEYSIZE;
+ }
+ ret = krb5_copy_keyblock(context, key, &(*crypto)->key.key);
+ if(ret) {
+ free(*crypto);
+ *crypto = NULL;
+ return ret;
+ }
+ (*crypto)->key.schedule = NULL;
+ (*crypto)->num_key_usage = 0;
+ (*crypto)->key_usage = NULL;
+ (*crypto)->params = NULL;
+ return 0;
+}
+
+static void
+free_key_data(krb5_context context, struct key_data *key)
+{
+ krb5_free_keyblock(context, key->key);
+ if(key->schedule) {
+ memset(key->schedule->data, 0, key->schedule->length);
+ krb5_free_data(context, key->schedule);
+ }
+}
+
+static void
+free_key_usage(krb5_context context, struct key_usage *ku)
+{
+ free_key_data(context, &ku->key);
+}
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_crypto_destroy(krb5_context context,
+ krb5_crypto crypto)
+{
+ int i;
+
+ for(i = 0; i < crypto->num_key_usage; i++)
+ free_key_usage(context, &crypto->key_usage[i]);
+ free(crypto->key_usage);
+ free_key_data(context, &crypto->key);
+ free(crypto->params);
+ free (crypto);
+ return 0;
+}
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_crypto_get_params(krb5_context context,
+ const krb5_crypto crypto,
+ const krb5_data *params,
+ krb5_data *ivec)
+{
+ krb5_error_code (*gp)(krb5_context, const krb5_data *,void **,krb5_data *);
+ krb5_error_code ret;
+
+ gp = crypto->et->keytype->get_params;
+ if (gp) {
+ if (crypto->params) {
+ krb5_set_error_string(context,
+ "krb5_crypto_get_params called "
+ "more than once");
+ return KRB5_PROG_ETYPE_NOSUPP;
+ }
+ ret = (*gp)(context, params, &crypto->params, ivec);
+ } else {
+ size_t size;
+ if (ivec == NULL)
+ return 0;
+ ret = decode_CBCParameter(params->data, params->length, ivec, &size);
+ }
+ if (ret)
+ return ret;
+ if (ivec->length < crypto->et->blocksize) {
+ krb5_data_free(ivec);
+ krb5_set_error_string(context, "%s IV of wrong size",
+ crypto->et->name);
+ return ASN1_PARSE_ERROR;
+ }
+ return 0;
+}
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_crypto_set_params(krb5_context context,
+ const krb5_crypto crypto,
+ const krb5_data *ivec,
+ krb5_data *params)
+{
+ krb5_error_code (*sp)(krb5_context, const void *,
+ const krb5_data *, krb5_data *);
+ krb5_error_code ret;
+
+ sp = crypto->et->keytype->set_params;
+ if (sp == NULL) {
+ size_t size;
+ if (ivec == NULL)
+ return 0;
+ ASN1_MALLOC_ENCODE(CBCParameter, params->data, params->length,
+ ivec, &size, ret);
+ if (ret)
+ return ret;
+ if (size != params->length)
+ krb5_abortx(context, "Internal asn1 encoder failure");
+ return 0;
+ }
+ if (crypto->params) {
+ krb5_set_error_string(context,
+ "krb5_crypto_set_params called "
+ "more than once");
+ return KRB5_PROG_ETYPE_NOSUPP;
+ }
+ return (*sp)(context, crypto->params, ivec, params);
+}
+
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_crypto_getblocksize(krb5_context context,
+ krb5_crypto crypto,
+ size_t *blocksize)
+{
+ *blocksize = crypto->et->blocksize;
+ return 0;
+}
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_crypto_getenctype(krb5_context context,
+ krb5_crypto crypto,
+ krb5_enctype *enctype)
+{
+ *enctype = crypto->et->type;
+ return 0;
+}
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_crypto_getpadsize(krb5_context context,
+ krb5_crypto crypto,
+ size_t *padsize)
+{
+ *padsize = crypto->et->padsize;
+ return 0;
+}
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_crypto_getconfoundersize(krb5_context context,
+ krb5_crypto crypto,
+ size_t *confoundersize)
+{
+ *confoundersize = crypto->et->confoundersize;
+ return 0;
+}
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_enctype_disable(krb5_context context,
+ krb5_enctype enctype)
+{
+ struct encryption_type *et = _find_enctype(enctype);
+ if(et == NULL) {
+ if (context)
+ krb5_set_error_string (context, "encryption type %d not supported",
+ enctype);
+ return KRB5_PROG_ETYPE_NOSUPP;
+ }
+ et->flags |= F_DISABLED;
+ return 0;
+}
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_string_to_key_derived(krb5_context context,
+ const void *str,
+ size_t len,
+ krb5_enctype etype,
+ krb5_keyblock *key)
+{
+ struct encryption_type *et = _find_enctype(etype);
+ krb5_error_code ret;
+ struct key_data kd;
+ size_t keylen = et->keytype->bits / 8;
+ u_char *tmp;
+
+ if(et == NULL) {
+ krb5_set_error_string (context, "encryption type %d not supported",
+ etype);
+ return KRB5_PROG_ETYPE_NOSUPP;
+ }
+ ALLOC(kd.key, 1);
+ if(kd.key == NULL) {
+ krb5_set_error_string (context, "malloc: out of memory");
+ return ENOMEM;
+ }
+ ret = krb5_data_alloc(&kd.key->keyvalue, et->keytype->size);
+ if(ret) {
+ free(kd.key);
+ return ret;
+ }
+ kd.key->keytype = etype;
+ tmp = malloc (keylen);
+ if(tmp == NULL) {
+ krb5_free_keyblock(context, kd.key);
+ krb5_set_error_string (context, "malloc: out of memory");
+ return ENOMEM;
+ }
+ _krb5_n_fold(str, len, tmp, keylen);
+ kd.schedule = NULL;
+ DES3_postproc (context, tmp, keylen, &kd); /* XXX */
+ memset(tmp, 0, keylen);
+ free(tmp);
+ ret = derive_key(context,
+ et,
+ &kd,
+ "kerberos", /* XXX well known constant */
+ strlen("kerberos"));
+ ret = krb5_copy_keyblock_contents(context, kd.key, key);
+ free_key_data(context, &kd);
+ return ret;
+}
+
+static size_t
+wrapped_length (krb5_context context,
+ krb5_crypto crypto,
+ size_t data_len)
+{
+ struct encryption_type *et = crypto->et;
+ size_t padsize = et->padsize;
+ size_t checksumsize;
+ size_t res;
+
+ if (et->keyed_checksum)
+ checksumsize = et->keyed_checksum->checksumsize;
+ else
+ checksumsize = et->checksum->checksumsize;
+
+ res = et->confoundersize + checksumsize + data_len;
+ res = (res + padsize - 1) / padsize * padsize;
+ return res;
+}
+
+static size_t
+wrapped_length_dervied (krb5_context context,
+ krb5_crypto crypto,
+ size_t data_len)
+{
+ struct encryption_type *et = crypto->et;
+ size_t padsize = et->padsize;
+ size_t res;
+
+ res = et->confoundersize + data_len;
+ res = (res + padsize - 1) / padsize * padsize;
+ if (et->keyed_checksum)
+ res += et->keyed_checksum->checksumsize;
+ else
+ res += et->checksum->checksumsize;
+ return res;
+}
+
+/*
+ * Return the size of an encrypted packet of length `data_len'
+ */
+
+size_t
+krb5_get_wrapped_length (krb5_context context,
+ krb5_crypto crypto,
+ size_t data_len)
+{
+ if (derived_crypto (context, crypto))
+ return wrapped_length_dervied (context, crypto, data_len);
+ else
+ return wrapped_length (context, crypto, data_len);
+}
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_random_to_key(krb5_context context,
+ krb5_enctype type,
+ const void *data,
+ size_t size,
+ krb5_keyblock *key)
+{
+ krb5_error_code ret;
+ struct encryption_type *et = _find_enctype(type);
+ if(et == NULL) {
+ krb5_set_error_string(context, "encryption type %d not supported",
+ type);
+ return KRB5_PROG_ETYPE_NOSUPP;
+ }
+ if ((et->keytype->bits + 7) / 8 > size) {
+ krb5_set_error_string(context, "encryption key %s needs %d bytes "
+ "of random to make an encryption key out of it",
+ et->name, (int)et->keytype->size);
+ return KRB5_PROG_ETYPE_NOSUPP;
+ }
+ ret = krb5_data_alloc(&key->keyvalue, et->keytype->size);
+ if(ret)
+ return ret;
+ key->keytype = type;
+ if (et->keytype->random_to_key)
+ (*et->keytype->random_to_key)(context, key, data, size);
+ else
+ memcpy(key->keyvalue.data, data, et->keytype->size);
+
+ return 0;
+}
+
+#ifdef CRYPTO_DEBUG
+
+static krb5_error_code
+krb5_get_keyid(krb5_context context,
+ krb5_keyblock *key,
+ u_int32_t *keyid)
+{
+ MD5_CTX md5;
+ unsigned char tmp[16];
+
+ MD5_Init (&md5);
+ MD5_Update (&md5, key->keyvalue.data, key->keyvalue.length);
+ MD5_Final (tmp, &md5);
+ *keyid = (tmp[12] << 24) | (tmp[13] << 16) | (tmp[14] << 8) | tmp[15];
+ return 0;
+}
+
+static void
+krb5_crypto_debug(krb5_context context,
+ int encryptp,
+ size_t len,
+ krb5_keyblock *key)
+{
+ u_int32_t keyid;
+ char *kt;
+ krb5_get_keyid(context, key, &keyid);
+ krb5_enctype_to_string(context, key->keytype, &kt);
+ krb5_warnx(context, "%s %lu bytes with key-id %#x (%s)",
+ encryptp ? "encrypting" : "decrypting",
+ (unsigned long)len,
+ keyid,
+ kt);
+ free(kt);
+}
+
+#endif /* CRYPTO_DEBUG */
+
+#if 0
+int
+main()
+{
+#if 0
+ int i;
+ krb5_context context;
+ krb5_crypto crypto;
+ struct key_data *d;
+ krb5_keyblock key;
+ char constant[4];
+ unsigned usage = ENCRYPTION_USAGE(3);
+ krb5_error_code ret;
+
+ ret = krb5_init_context(&context);
+ if (ret)
+ errx (1, "krb5_init_context failed: %d", ret);
+
+ key.keytype = ETYPE_NEW_DES3_CBC_SHA1;
+ key.keyvalue.data = "\xb3\x85\x58\x94\xd9\xdc\x7c\xc8"
+ "\x25\xe9\x85\xab\x3e\xb5\xfb\x0e"
+ "\xc8\xdf\xab\x26\x86\x64\x15\x25";
+ key.keyvalue.length = 24;
+
+ krb5_crypto_init(context, &key, 0, &crypto);
+
+ d = _new_derived_key(crypto, usage);
+ if(d == NULL)
+ return ENOMEM;
+ krb5_copy_keyblock(context, crypto->key.key, &d->key);
+ _krb5_put_int(constant, usage, 4);
+ derive_key(context, crypto->et, d, constant, sizeof(constant));
+ return 0;
+#else
+ int i;
+ krb5_context context;
+ krb5_crypto crypto;
+ struct key_data *d;
+ krb5_keyblock key;
+ krb5_error_code ret;
+ Checksum res;
+
+ char *data = "what do ya want for nothing?";
+
+ ret = krb5_init_context(&context);
+ if (ret)
+ errx (1, "krb5_init_context failed: %d", ret);
+
+ key.keytype = ETYPE_NEW_DES3_CBC_SHA1;
+ key.keyvalue.data = "Jefe";
+ /* "\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b"
+ "\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b"; */
+ key.keyvalue.length = 4;
+
+ d = calloc(1, sizeof(*d));
+
+ d->key = &key;
+ res.checksum.length = 20;
+ res.checksum.data = malloc(res.checksum.length);
+ SP_HMAC_SHA1_checksum(context, d, data, 28, &res);
+
+ return 0;
+#endif
+}
+#endif
diff --git a/source4/heimdal/lib/krb5/data.c b/source4/heimdal/lib/krb5/data.c
new file mode 100644
index 0000000000..9cf1410e70
--- /dev/null
+++ b/source4/heimdal/lib/krb5/data.c
@@ -0,0 +1,119 @@
+/*
+ * Copyright (c) 1997 - 2001 Kungliga Tekniska Högskolan
+ * (Royal Institute of Technology, Stockholm, Sweden).
+ * 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"
+
+RCSID("$Id: data.c,v 1.19 2004/05/25 21:22:23 lha Exp $");
+
+void KRB5_LIB_FUNCTION
+krb5_data_zero(krb5_data *p)
+{
+ p->length = 0;
+ p->data = NULL;
+}
+
+void KRB5_LIB_FUNCTION
+krb5_data_free(krb5_data *p)
+{
+ if(p->data != NULL)
+ free(p->data);
+ krb5_data_zero(p);
+}
+
+void KRB5_LIB_FUNCTION
+krb5_free_data_contents(krb5_context context, krb5_data *data)
+{
+ krb5_data_free(data);
+}
+
+void KRB5_LIB_FUNCTION
+krb5_free_data(krb5_context context,
+ krb5_data *p)
+{
+ krb5_data_free(p);
+ free(p);
+}
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_data_alloc(krb5_data *p, int len)
+{
+ p->data = malloc(len);
+ if(len && p->data == NULL)
+ return ENOMEM;
+ p->length = len;
+ return 0;
+}
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_data_realloc(krb5_data *p, int len)
+{
+ void *tmp;
+ tmp = realloc(p->data, len);
+ if(len && !tmp)
+ return ENOMEM;
+ p->data = tmp;
+ p->length = len;
+ return 0;
+}
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_data_copy(krb5_data *p, const void *data, size_t len)
+{
+ if (len) {
+ if(krb5_data_alloc(p, len))
+ return ENOMEM;
+ memmove(p->data, data, len);
+ } else
+ p->data = NULL;
+ p->length = len;
+ return 0;
+}
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_copy_data(krb5_context context,
+ const krb5_data *indata,
+ krb5_data **outdata)
+{
+ krb5_error_code ret;
+ ALLOC(*outdata, 1);
+ if(*outdata == NULL) {
+ krb5_set_error_string(context, "malloc: out of memory");
+ return ENOMEM;
+ }
+ ret = copy_octet_string(indata, *outdata);
+ if(ret) {
+ krb5_clear_error_string (context);
+ free(*outdata);
+ }
+ return ret;
+}
diff --git a/source4/heimdal/lib/krb5/eai_to_heim_errno.c b/source4/heimdal/lib/krb5/eai_to_heim_errno.c
new file mode 100644
index 0000000000..f0d1f51033
--- /dev/null
+++ b/source4/heimdal/lib/krb5/eai_to_heim_errno.c
@@ -0,0 +1,98 @@
+/*
+ * Copyright (c) 2000 - 2001 Kungliga Tekniska Högskolan
+ * (Royal Institute of Technology, Stockholm, Sweden).
+ * 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>
+
+RCSID("$Id: eai_to_heim_errno.c,v 1.5 2004/05/25 21:23:35 lha Exp $");
+
+/*
+ * convert the getaddrinfo error code in `eai_errno' into a
+ * krb5_error_code. `system_error' should have the value of the errno
+ * after the failed call.
+ */
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_eai_to_heim_errno(int eai_errno, int system_error)
+{
+ switch(eai_errno) {
+ case EAI_NOERROR:
+ return 0;
+#ifdef EAI_ADDRFAMILY
+ case EAI_ADDRFAMILY:
+ return HEIM_EAI_ADDRFAMILY;
+#endif
+ case EAI_AGAIN:
+ return HEIM_EAI_AGAIN;
+ case EAI_BADFLAGS:
+ return HEIM_EAI_BADFLAGS;
+ case EAI_FAIL:
+ return HEIM_EAI_FAIL;
+ case EAI_FAMILY:
+ return HEIM_EAI_FAMILY;
+ case EAI_MEMORY:
+ return HEIM_EAI_MEMORY;
+#if defined(EAI_NODATA) && EAI_NODATA != EAI_NONAME
+ case EAI_NODATA:
+ return HEIM_EAI_NODATA;
+#endif
+ case EAI_NONAME:
+ return HEIM_EAI_NONAME;
+ case EAI_SERVICE:
+ return HEIM_EAI_SERVICE;
+ case EAI_SOCKTYPE:
+ return HEIM_EAI_SOCKTYPE;
+ case EAI_SYSTEM:
+ return system_error;
+ default:
+ return HEIM_EAI_UNKNOWN; /* XXX */
+ }
+}
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_h_errno_to_heim_errno(int eai_errno)
+{
+ switch(eai_errno) {
+ case 0:
+ return 0;
+ case HOST_NOT_FOUND:
+ return HEIM_EAI_NONAME;
+ case TRY_AGAIN:
+ return HEIM_EAI_AGAIN;
+ case NO_RECOVERY:
+ return HEIM_EAI_FAIL;
+ case NO_DATA:
+ return HEIM_EAI_NONAME;
+ default:
+ return HEIM_EAI_UNKNOWN; /* XXX */
+ }
+}
diff --git a/source4/heimdal/lib/krb5/error_string.c b/source4/heimdal/lib/krb5/error_string.c
new file mode 100644
index 0000000000..649bdd20fd
--- /dev/null
+++ b/source4/heimdal/lib/krb5/error_string.c
@@ -0,0 +1,109 @@
+/*
+ * Copyright (c) 2001 Kungliga Tekniska Högskolan
+ * (Royal Institute of Technology, Stockholm, Sweden).
+ * 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"
+
+RCSID("$Id: error_string.c,v 1.3 2004/05/25 21:23:55 lha Exp $");
+
+#undef __attribute__
+#define __attribute__(X)
+
+void KRB5_LIB_FUNCTION
+krb5_free_error_string(krb5_context context, char *str)
+{
+ HEIMDAL_MUTEX_lock(context->mutex);
+ if (str != context->error_buf)
+ free(str);
+ HEIMDAL_MUTEX_unlock(context->mutex);
+}
+
+void KRB5_LIB_FUNCTION
+krb5_clear_error_string(krb5_context context)
+{
+ HEIMDAL_MUTEX_lock(context->mutex);
+ if (context->error_string != NULL
+ && context->error_string != context->error_buf)
+ free(context->error_string);
+ context->error_string = NULL;
+ HEIMDAL_MUTEX_unlock(context->mutex);
+}
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_set_error_string(krb5_context context, const char *fmt, ...)
+ __attribute__((format (printf, 2, 3)))
+{
+ krb5_error_code ret;
+ va_list ap;
+
+ va_start(ap, fmt);
+ ret = krb5_vset_error_string (context, fmt, ap);
+ va_end(ap);
+ return ret;
+}
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_vset_error_string(krb5_context context, const char *fmt, va_list args)
+ __attribute__ ((format (printf, 2, 0)))
+{
+ krb5_clear_error_string(context);
+ HEIMDAL_MUTEX_lock(context->mutex);
+ vasprintf(&context->error_string, fmt, args);
+ if(context->error_string == NULL) {
+ vsnprintf (context->error_buf, sizeof(context->error_buf), fmt, args);
+ context->error_string = context->error_buf;
+ }
+ HEIMDAL_MUTEX_unlock(context->mutex);
+ return 0;
+}
+
+char * KRB5_LIB_FUNCTION
+krb5_get_error_string(krb5_context context)
+{
+ char *ret;
+
+ HEIMDAL_MUTEX_lock(context->mutex);
+ ret = context->error_string;
+ context->error_string = NULL;
+ HEIMDAL_MUTEX_unlock(context->mutex);
+ return ret;
+}
+
+krb5_boolean KRB5_LIB_FUNCTION
+krb5_have_error_string(krb5_context context)
+{
+ char *str;
+ HEIMDAL_MUTEX_lock(context->mutex);
+ str = context->error_string;
+ HEIMDAL_MUTEX_unlock(context->mutex);
+ return str != NULL;
+}
diff --git a/source4/heimdal/lib/krb5/expand_hostname.c b/source4/heimdal/lib/krb5/expand_hostname.c
new file mode 100644
index 0000000000..8488119552
--- /dev/null
+++ b/source4/heimdal/lib/krb5/expand_hostname.c
@@ -0,0 +1,153 @@
+/*
+ * Copyright (c) 1999 - 2001 Kungliga Tekniska Högskolan
+ * (Royal Institute of Technology, Stockholm, Sweden).
+ * 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"
+
+RCSID("$Id: expand_hostname.c,v 1.12 2004/05/25 21:24:14 lha Exp $");
+
+static krb5_error_code
+copy_hostname(krb5_context context,
+ const char *orig_hostname,
+ char **new_hostname)
+{
+ *new_hostname = strdup (orig_hostname);
+ if (*new_hostname == NULL) {
+ krb5_set_error_string(context, "malloc: out of memory");
+ return ENOMEM;
+ }
+ strlwr (*new_hostname);
+ return 0;
+}
+
+/*
+ * Try to make `orig_hostname' into a more canonical one in the newly
+ * allocated space returned in `new_hostname'.
+ */
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_expand_hostname (krb5_context context,
+ const char *orig_hostname,
+ char **new_hostname)
+{
+ struct addrinfo *ai, *a, hints;
+ int error;
+
+ memset (&hints, 0, sizeof(hints));
+ hints.ai_flags = AI_CANONNAME;
+
+ error = getaddrinfo (orig_hostname, NULL, &hints, &ai);
+ if (error)
+ return copy_hostname (context, orig_hostname, new_hostname);
+ for (a = ai; a != NULL; a = a->ai_next) {
+ if (a->ai_canonname != NULL) {
+ *new_hostname = strdup (a->ai_canonname);
+ freeaddrinfo (ai);
+ if (*new_hostname == NULL) {
+ krb5_set_error_string(context, "malloc: out of memory");
+ return ENOMEM;
+ } else {
+ return 0;
+ }
+ }
+ }
+ freeaddrinfo (ai);
+ return copy_hostname (context, orig_hostname, new_hostname);
+}
+
+/*
+ * handle the case of the hostname being unresolvable and thus identical
+ */
+
+static krb5_error_code
+vanilla_hostname (krb5_context context,
+ const char *orig_hostname,
+ char **new_hostname,
+ char ***realms)
+{
+ krb5_error_code ret;
+
+ ret = copy_hostname (context, orig_hostname, new_hostname);
+ if (ret)
+ return ret;
+ strlwr (*new_hostname);
+
+ ret = krb5_get_host_realm (context, *new_hostname, realms);
+ if (ret) {
+ free (*new_hostname);
+ return ret;
+ }
+ return 0;
+}
+
+/*
+ * expand `hostname' to a name we believe to be a hostname in newly
+ * allocated space in `host' and return realms in `realms'.
+ */
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_expand_hostname_realms (krb5_context context,
+ const char *orig_hostname,
+ char **new_hostname,
+ char ***realms)
+{
+ struct addrinfo *ai, *a, hints;
+ int error;
+ krb5_error_code ret = 0;
+
+ memset (&hints, 0, sizeof(hints));
+ hints.ai_flags = AI_CANONNAME;
+
+ error = getaddrinfo (orig_hostname, NULL, &hints, &ai);
+ if (error)
+ return vanilla_hostname (context, orig_hostname, new_hostname,
+ realms);
+
+ for (a = ai; a != NULL; a = a->ai_next) {
+ if (a->ai_canonname != NULL) {
+ ret = copy_hostname (context, a->ai_canonname, new_hostname);
+ if (ret) {
+ freeaddrinfo (ai);
+ return ret;
+ }
+ strlwr (*new_hostname);
+ ret = krb5_get_host_realm (context, *new_hostname, realms);
+ if (ret == 0) {
+ freeaddrinfo (ai);
+ return 0;
+ }
+ free (*new_hostname);
+ }
+ }
+ freeaddrinfo(ai);
+ return vanilla_hostname (context, orig_hostname, new_hostname, realms);
+}
diff --git a/source4/heimdal/lib/krb5/fcache.c b/source4/heimdal/lib/krb5/fcache.c
new file mode 100644
index 0000000000..03848abb9a
--- /dev/null
+++ b/source4/heimdal/lib/krb5/fcache.c
@@ -0,0 +1,718 @@
+/*
+ * Copyright (c) 1997 - 2004 Kungliga Tekniska Högskolan
+ * (Royal Institute of Technology, Stockholm, Sweden).
+ * 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"
+
+RCSID("$Id: fcache.c,v 1.49 2005/06/16 20:25:20 lha Exp $");
+
+typedef struct krb5_fcache{
+ char *filename;
+ int version;
+}krb5_fcache;
+
+struct fcc_cursor {
+ int fd;
+ krb5_storage *sp;
+};
+
+#define KRB5_FCC_FVNO_1 1
+#define KRB5_FCC_FVNO_2 2
+#define KRB5_FCC_FVNO_3 3
+#define KRB5_FCC_FVNO_4 4
+
+#define FCC_TAG_DELTATIME 1
+
+#define FCACHE(X) ((krb5_fcache*)(X)->data.data)
+
+#define FILENAME(X) (FCACHE(X)->filename)
+
+#define FCC_CURSOR(C) ((struct fcc_cursor*)(C))
+
+static const char*
+fcc_get_name(krb5_context context,
+ krb5_ccache id)
+{
+ return FILENAME(id);
+}
+
+int
+_krb5_xlock(krb5_context context, int fd, krb5_boolean exclusive,
+ const char *filename)
+{
+ int ret;
+#ifdef HAVE_FCNTL
+ struct flock l;
+
+ l.l_start = 0;
+ l.l_len = 0;
+ l.l_type = exclusive ? F_WRLCK : F_RDLCK;
+ l.l_whence = SEEK_SET;
+ ret = fcntl(fd, F_SETLKW, &l);
+#else
+ ret = flock(fd, exclusive ? LOCK_EX : LOCK_SH);
+#endif
+ if(ret < 0)
+ ret = errno;
+ if(ret == EACCES) /* fcntl can return EACCES instead of EAGAIN */
+ ret = EAGAIN;
+
+ switch (ret) {
+ case 0:
+ break;
+ case EINVAL: /* filesystem doesn't support locking, let the user have it */
+ ret = 0;
+ break;
+ case EAGAIN:
+ krb5_set_error_string(context, "timed out locking cache file %s",
+ filename);
+ break;
+ default:
+ krb5_set_error_string(context, "error locking cache file %s: %s",
+ filename, strerror(ret));
+ break;
+ }
+ return ret;
+}
+
+int
+_krb5_xunlock(krb5_context context, int fd)
+{
+ int ret;
+#ifdef HAVE_FCNTL_LOCK
+ struct flock l;
+ l.l_start = 0;
+ l.l_len = 0;
+ l.l_type = F_UNLCK;
+ l.l_whence = SEEK_SET;
+ ret = fcntl(fd, F_SETLKW, &l);
+#else
+ ret = flock(fd, LOCK_UN);
+#endif
+ if (ret < 0)
+ ret = errno;
+ switch (ret) {
+ case 0:
+ break;
+ case EINVAL: /* filesystem doesn't support locking, let the user have it */
+ ret = 0;
+ break;
+ default:
+ krb5_set_error_string(context,
+ "Failed to unlock file: %s", strerror(ret));
+ break;
+ }
+ return ret;
+}
+
+static krb5_error_code
+fcc_lock(krb5_context context, krb5_ccache id,
+ int fd, krb5_boolean exclusive)
+{
+ return _krb5_xlock(context, fd, exclusive, fcc_get_name(context, id));
+}
+
+static krb5_error_code
+fcc_unlock(krb5_context context, int fd)
+{
+ return _krb5_xunlock(context, fd);
+}
+
+static krb5_error_code
+fcc_resolve(krb5_context context, krb5_ccache *id, const char *res)
+{
+ krb5_fcache *f;
+ f = malloc(sizeof(*f));
+ if(f == NULL) {
+ krb5_set_error_string(context, "malloc: out of memory");
+ return KRB5_CC_NOMEM;
+ }
+ f->filename = strdup(res);
+ if(f->filename == NULL){
+ free(f);
+ krb5_set_error_string(context, "malloc: out of memory");
+ return KRB5_CC_NOMEM;
+ }
+ f->version = 0;
+ (*id)->data.data = f;
+ (*id)->data.length = sizeof(*f);
+ return 0;
+}
+
+/*
+ * Try to scrub the contents of `filename' safely.
+ */
+
+static int
+scrub_file (int fd)
+{
+ off_t pos;
+ char buf[128];
+
+ pos = lseek(fd, 0, SEEK_END);
+ if (pos < 0)
+ return errno;
+ if (lseek(fd, 0, SEEK_SET) < 0)
+ return errno;
+ memset(buf, 0, sizeof(buf));
+ while(pos > 0) {
+ ssize_t tmp = write(fd, buf, min(sizeof(buf), pos));
+
+ if (tmp < 0)
+ return errno;
+ pos -= tmp;
+ }
+ fsync (fd);
+ return 0;
+}
+
+/*
+ * Erase `filename' if it exists, trying to remove the contents if
+ * it's `safe'. We always try to remove the file, it it exists. It's
+ * only overwritten if it's a regular file (not a symlink and not a
+ * hardlink)
+ */
+
+static krb5_error_code
+erase_file(const char *filename)
+{
+ int fd;
+ struct stat sb1, sb2;
+ int ret;
+
+ ret = lstat (filename, &sb1);
+ if (ret < 0)
+ return errno;
+
+ fd = open(filename, O_RDWR | O_BINARY);
+ if(fd < 0) {
+ if(errno == ENOENT)
+ return 0;
+ else
+ return errno;
+ }
+ if (unlink(filename) < 0) {
+ close (fd);
+ return errno;
+ }
+ ret = fstat (fd, &sb2);
+ if (ret < 0) {
+ close (fd);
+ return errno;
+ }
+
+ /* check if someone was playing with symlinks */
+
+ if (sb1.st_dev != sb2.st_dev || sb1.st_ino != sb2.st_ino) {
+ close (fd);
+ return EPERM;
+ }
+
+ /* there are still hard links to this file */
+
+ if (sb2.st_nlink != 0) {
+ close (fd);
+ return 0;
+ }
+
+ ret = scrub_file (fd);
+ close (fd);
+ return ret;
+}
+
+static krb5_error_code
+fcc_gen_new(krb5_context context, krb5_ccache *id)
+{
+ krb5_fcache *f;
+ int fd;
+ char *file;
+
+ f = malloc(sizeof(*f));
+ if(f == NULL) {
+ krb5_set_error_string(context, "malloc: out of memory");
+ return KRB5_CC_NOMEM;
+ }
+ asprintf (&file, "%sXXXXXX", KRB5_DEFAULT_CCFILE_ROOT);
+ if(file == NULL) {
+ free(f);
+ krb5_set_error_string(context, "malloc: out of memory");
+ return KRB5_CC_NOMEM;
+ }
+ fd = mkstemp(file);
+ if(fd < 0) {
+ free(f);
+ free(file);
+ krb5_set_error_string(context, "mkstemp %s", file);
+ return errno;
+ }
+ close(fd);
+ f->filename = file;
+ f->version = 0;
+ (*id)->data.data = f;
+ (*id)->data.length = sizeof(*f);
+ return 0;
+}
+
+static void
+storage_set_flags(krb5_context context, krb5_storage *sp, int vno)
+{
+ int flags = 0;
+ switch(vno) {
+ case KRB5_FCC_FVNO_1:
+ flags |= KRB5_STORAGE_PRINCIPAL_WRONG_NUM_COMPONENTS;
+ flags |= KRB5_STORAGE_PRINCIPAL_NO_NAME_TYPE;
+ flags |= KRB5_STORAGE_HOST_BYTEORDER;
+ break;
+ case KRB5_FCC_FVNO_2:
+ flags |= KRB5_STORAGE_HOST_BYTEORDER;
+ break;
+ case KRB5_FCC_FVNO_3:
+ flags |= KRB5_STORAGE_KEYBLOCK_KEYTYPE_TWICE;
+ break;
+ case KRB5_FCC_FVNO_4:
+ break;
+ default:
+ krb5_abortx(context,
+ "storage_set_flags called with bad vno (%x)", vno);
+ }
+ krb5_storage_set_flags(sp, flags);
+}
+
+static krb5_error_code
+fcc_open(krb5_context context,
+ krb5_ccache id,
+ int *fd_ret,
+ int flags,
+ mode_t mode)
+{
+ krb5_boolean exclusive = ((flags | O_WRONLY) == flags ||
+ (flags | O_RDWR) == flags);
+ krb5_error_code ret;
+ const char *filename = FILENAME(id);
+ int fd;
+ fd = open(filename, flags, mode);
+ if(fd < 0) {
+ ret = errno;
+ krb5_set_error_string(context, "open(%s): %s", filename,
+ strerror(ret));
+ return ret;
+ }
+
+ if((ret = fcc_lock(context, id, fd, exclusive)) != 0) {
+ close(fd);
+ return ret;
+ }
+ *fd_ret = fd;
+ return 0;
+}
+
+static krb5_error_code
+fcc_initialize(krb5_context context,
+ krb5_ccache id,
+ krb5_principal primary_principal)
+{
+ krb5_fcache *f = FCACHE(id);
+ int ret = 0;
+ int fd;
+ char *filename = f->filename;
+
+ unlink (filename);
+
+ ret = fcc_open(context, id, &fd, O_RDWR | O_CREAT | O_EXCL | O_BINARY, 0600);
+ if(ret)
+ return ret;
+ {
+ krb5_storage *sp;
+ sp = krb5_storage_from_fd(fd);
+ krb5_storage_set_eof_code(sp, KRB5_CC_END);
+ if(context->fcache_vno != 0)
+ f->version = context->fcache_vno;
+ else
+ f->version = KRB5_FCC_FVNO_4;
+ ret |= krb5_store_int8(sp, 5);
+ ret |= krb5_store_int8(sp, f->version);
+ storage_set_flags(context, sp, f->version);
+ if(f->version == KRB5_FCC_FVNO_4 && ret == 0) {
+ /* V4 stuff */
+ if (context->kdc_sec_offset) {
+ ret |= krb5_store_int16 (sp, 12); /* length */
+ ret |= krb5_store_int16 (sp, FCC_TAG_DELTATIME); /* Tag */
+ ret |= krb5_store_int16 (sp, 8); /* length of data */
+ ret |= krb5_store_int32 (sp, context->kdc_sec_offset);
+ ret |= krb5_store_int32 (sp, context->kdc_usec_offset);
+ } else {
+ ret |= krb5_store_int16 (sp, 0);
+ }
+ }
+ ret |= krb5_store_principal(sp, primary_principal);
+
+ krb5_storage_free(sp);
+ }
+ fcc_unlock(context, fd);
+ if (close(fd) < 0)
+ if (ret == 0) {
+ ret = errno;
+ krb5_set_error_string (context, "close %s: %s",
+ FILENAME(id), strerror(ret));
+ }
+ return ret;
+}
+
+static krb5_error_code
+fcc_close(krb5_context context,
+ krb5_ccache id)
+{
+ free (FILENAME(id));
+ krb5_data_free(&id->data);
+ return 0;
+}
+
+static krb5_error_code
+fcc_destroy(krb5_context context,
+ krb5_ccache id)
+{
+ erase_file(FILENAME(id));
+ return 0;
+}
+
+static krb5_error_code
+fcc_store_cred(krb5_context context,
+ krb5_ccache id,
+ krb5_creds *creds)
+{
+ int ret;
+ int fd;
+
+ ret = fcc_open(context, id, &fd, O_WRONLY | O_APPEND | O_BINARY, 0);
+ if(ret)
+ return ret;
+ {
+ krb5_storage *sp;
+ sp = krb5_storage_from_fd(fd);
+ krb5_storage_set_eof_code(sp, KRB5_CC_END);
+ storage_set_flags(context, sp, FCACHE(id)->version);
+ if (!krb5_config_get_bool_default(context, NULL, TRUE,
+ "libdefaults",
+ "fcc-mit-ticketflags",
+ NULL))
+ krb5_storage_set_flags(sp, KRB5_STORAGE_CREDS_FLAGS_WRONG_BITORDER);
+ ret = krb5_store_creds(sp, creds);
+ krb5_storage_free(sp);
+ }
+ fcc_unlock(context, fd);
+ if (close(fd) < 0)
+ if (ret == 0) {
+ ret = errno;
+ krb5_set_error_string (context, "close %s: %s",
+ FILENAME(id), strerror(ret));
+ }
+ return ret;
+}
+
+static krb5_error_code
+init_fcc (krb5_context context,
+ krb5_ccache id,
+ krb5_storage **ret_sp,
+ int *ret_fd)
+{
+ int fd;
+ int8_t pvno, tag;
+ krb5_storage *sp;
+ krb5_error_code ret;
+
+ ret = fcc_open(context, id, &fd, O_RDONLY | O_BINARY, 0);
+ if(ret)
+ return ret;
+
+ sp = krb5_storage_from_fd(fd);
+ if(sp == NULL) {
+ krb5_clear_error_string(context);
+ ret = ENOMEM;
+ goto out;
+ }
+ krb5_storage_set_eof_code(sp, KRB5_CC_END);
+ ret = krb5_ret_int8(sp, &pvno);
+ if(ret != 0) {
+ if(ret == KRB5_CC_END)
+ ret = ENOENT; /* empty file */
+ krb5_clear_error_string(context);
+ goto out;
+ }
+ if(pvno != 5) {
+ krb5_set_error_string(context, "Bad version number in credential "
+ "cache file: %s", FILENAME(id));
+ ret = KRB5_CCACHE_BADVNO;
+ goto out;
+ }
+ ret = krb5_ret_int8(sp, &tag); /* should not be host byte order */
+ if(ret != 0) {
+ krb5_clear_error_string(context);
+ ret = KRB5_CC_FORMAT;
+ goto out;
+ }
+ FCACHE(id)->version = tag;
+ storage_set_flags(context, sp, FCACHE(id)->version);
+ switch (tag) {
+ case KRB5_FCC_FVNO_4: {
+ int16_t length;
+
+ ret = krb5_ret_int16 (sp, &length);
+ if(ret) {
+ ret = KRB5_CC_FORMAT;
+ krb5_clear_error_string(context);
+ goto out;
+ }
+ while(length > 0) {
+ int16_t dtag, data_len;
+ int i;
+ int8_t dummy;
+
+ ret = krb5_ret_int16 (sp, &dtag);
+ if(ret) {
+ krb5_clear_error_string(context);
+ ret = KRB5_CC_FORMAT;
+ goto out;
+ }
+ ret = krb5_ret_int16 (sp, &data_len);
+ if(ret) {
+ krb5_clear_error_string(context);
+ ret = KRB5_CC_FORMAT;
+ goto out;
+ }
+ switch (dtag) {
+ case FCC_TAG_DELTATIME :
+ ret = krb5_ret_int32 (sp, &context->kdc_sec_offset);
+ if(ret) {
+ krb5_clear_error_string(context);
+ ret = KRB5_CC_FORMAT;
+ goto out;
+ }
+ ret = krb5_ret_int32 (sp, &context->kdc_usec_offset);
+ if(ret) {
+ krb5_clear_error_string(context);
+ ret = KRB5_CC_FORMAT;
+ goto out;
+ }
+ break;
+ default :
+ for (i = 0; i < data_len; ++i) {
+ ret = krb5_ret_int8 (sp, &dummy);
+ if(ret) {
+ krb5_clear_error_string(context);
+ ret = KRB5_CC_FORMAT;
+ goto out;
+ }
+ }
+ break;
+ }
+ length -= 4 + data_len;
+ }
+ break;
+ }
+ case KRB5_FCC_FVNO_3:
+ case KRB5_FCC_FVNO_2:
+ case KRB5_FCC_FVNO_1:
+ break;
+ default :
+ ret = KRB5_CCACHE_BADVNO;
+ krb5_set_error_string(context, "Unknown version number (%d) in "
+ "credential cache file: %s",
+ (int)tag, FILENAME(id));
+ goto out;
+ }
+ *ret_sp = sp;
+ *ret_fd = fd;
+
+ return 0;
+ out:
+ if(sp != NULL)
+ krb5_storage_free(sp);
+ fcc_unlock(context, fd);
+ close(fd);
+ return ret;
+}
+
+static krb5_error_code
+fcc_get_principal(krb5_context context,
+ krb5_ccache id,
+ krb5_principal *principal)
+{
+ krb5_error_code ret;
+ int fd;
+ krb5_storage *sp;
+
+ ret = init_fcc (context, id, &sp, &fd);
+ if (ret)
+ return ret;
+ ret = krb5_ret_principal(sp, principal);
+ if (ret)
+ krb5_clear_error_string(context);
+ krb5_storage_free(sp);
+ fcc_unlock(context, fd);
+ close(fd);
+ return ret;
+}
+
+static krb5_error_code
+fcc_end_get (krb5_context context,
+ krb5_ccache id,
+ krb5_cc_cursor *cursor);
+
+static krb5_error_code
+fcc_get_first (krb5_context context,
+ krb5_ccache id,
+ krb5_cc_cursor *cursor)
+{
+ krb5_error_code ret;
+ krb5_principal principal;
+
+ *cursor = malloc(sizeof(struct fcc_cursor));
+ if (*cursor == NULL) {
+ krb5_set_error_string (context, "malloc: out of memory");
+ return ENOMEM;
+ }
+ memset(*cursor, 0, sizeof(struct fcc_cursor));
+
+ ret = init_fcc (context, id, &FCC_CURSOR(*cursor)->sp,
+ &FCC_CURSOR(*cursor)->fd);
+ if (ret) {
+ free(*cursor);
+ *cursor = NULL;
+ return ret;
+ }
+ ret = krb5_ret_principal (FCC_CURSOR(*cursor)->sp, &principal);
+ if(ret) {
+ krb5_clear_error_string(context);
+ fcc_end_get(context, id, cursor);
+ return ret;
+ }
+ krb5_free_principal (context, principal);
+ fcc_unlock(context, FCC_CURSOR(*cursor)->fd);
+ return 0;
+}
+
+static krb5_error_code
+fcc_get_next (krb5_context context,
+ krb5_ccache id,
+ krb5_cc_cursor *cursor,
+ krb5_creds *creds)
+{
+ krb5_error_code ret;
+ if((ret = fcc_lock(context, id, FCC_CURSOR(*cursor)->fd, FALSE)) != 0)
+ return ret;
+
+ ret = krb5_ret_creds(FCC_CURSOR(*cursor)->sp, creds);
+ if (ret)
+ krb5_clear_error_string(context);
+
+ fcc_unlock(context, FCC_CURSOR(*cursor)->fd);
+ return ret;
+}
+
+static krb5_error_code
+fcc_end_get (krb5_context context,
+ krb5_ccache id,
+ krb5_cc_cursor *cursor)
+{
+ krb5_storage_free(FCC_CURSOR(*cursor)->sp);
+ close (FCC_CURSOR(*cursor)->fd);
+ free(*cursor);
+ *cursor = NULL;
+ return 0;
+}
+
+static krb5_error_code
+fcc_remove_cred(krb5_context context,
+ krb5_ccache id,
+ krb5_flags which,
+ krb5_creds *cred)
+{
+ krb5_error_code ret;
+ krb5_ccache copy;
+
+ ret = krb5_cc_gen_new(context, &krb5_mcc_ops, &copy);
+ if (ret)
+ return ret;
+
+ ret = krb5_cc_copy_cache(context, id, copy);
+ if (ret) {
+ krb5_cc_destroy(context, copy);
+ return ret;
+ }
+
+ ret = krb5_cc_remove_cred(context, copy, which, cred);
+ if (ret) {
+ krb5_cc_destroy(context, copy);
+ return ret;
+ }
+
+ fcc_destroy(context, id);
+
+ ret = krb5_cc_copy_cache(context, copy, id);
+ krb5_cc_destroy(context, copy);
+
+ return ret;
+}
+
+static krb5_error_code
+fcc_set_flags(krb5_context context,
+ krb5_ccache id,
+ krb5_flags flags)
+{
+ return 0; /* XXX */
+}
+
+static krb5_error_code
+fcc_get_version(krb5_context context,
+ krb5_ccache id)
+{
+ return FCACHE(id)->version;
+}
+
+const krb5_cc_ops krb5_fcc_ops = {
+ "FILE",
+ fcc_get_name,
+ fcc_resolve,
+ fcc_gen_new,
+ fcc_initialize,
+ fcc_destroy,
+ fcc_close,
+ fcc_store_cred,
+ NULL, /* fcc_retrieve */
+ fcc_get_principal,
+ fcc_get_first,
+ fcc_get_next,
+ fcc_end_get,
+ fcc_remove_cred,
+ fcc_set_flags,
+ fcc_get_version
+};
diff --git a/source4/heimdal/lib/krb5/free.c b/source4/heimdal/lib/krb5/free.c
new file mode 100644
index 0000000000..84aa6f8c2c
--- /dev/null
+++ b/source4/heimdal/lib/krb5/free.c
@@ -0,0 +1,53 @@
+/*
+ * Copyright (c) 1997 - 1999, 2004 - 2005 Kungliga Tekniska Högskolan
+ * (Royal Institute of Technology, Stockholm, Sweden).
+ * 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"
+
+RCSID("$Id: free.c,v 1.8 2005/05/18 10:06:16 lha Exp $");
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_free_kdc_rep(krb5_context context, krb5_kdc_rep *rep)
+{
+ free_KDC_REP(&rep->kdc_rep);
+ free_EncTGSRepPart(&rep->enc_part);
+ free_KRB_ERROR(&rep->error);
+ memset(rep, 0, sizeof(*rep));
+ return 0;
+}
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_xfree (void *ptr)
+{
+ free (ptr);
+ return 0;
+}
diff --git a/source4/heimdal/lib/krb5/free_host_realm.c b/source4/heimdal/lib/krb5/free_host_realm.c
new file mode 100644
index 0000000000..27afcdbb23
--- /dev/null
+++ b/source4/heimdal/lib/krb5/free_host_realm.c
@@ -0,0 +1,54 @@
+/*
+ * Copyright (c) 1997, 1999 Kungliga Tekniska Högskolan
+ * (Royal Institute of Technology, Stockholm, Sweden).
+ * 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"
+
+RCSID("$Id: free_host_realm.c,v 1.5 2004/05/25 21:25:02 lha Exp $");
+
+/*
+ * Free all memory allocated by `realmlist'
+ */
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_free_host_realm(krb5_context context,
+ krb5_realm *realmlist)
+{
+ krb5_realm *p;
+
+ if(realmlist == NULL)
+ return 0;
+ for (p = realmlist; *p; ++p)
+ free (*p);
+ free (realmlist);
+ return 0;
+}
diff --git a/source4/heimdal/lib/krb5/generate_seq_number.c b/source4/heimdal/lib/krb5/generate_seq_number.c
new file mode 100644
index 0000000000..f9e9cded5f
--- /dev/null
+++ b/source4/heimdal/lib/krb5/generate_seq_number.c
@@ -0,0 +1,62 @@
+/*
+ * Copyright (c) 1997 - 2001 Kungliga Tekniska Högskolan
+ * (Royal Institute of Technology, Stockholm, Sweden).
+ * 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>
+
+RCSID("$Id: generate_seq_number.c,v 1.9 2004/05/25 21:25:22 lha Exp $");
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_generate_seq_number(krb5_context context,
+ const krb5_keyblock *key,
+ u_int32_t *seqno)
+{
+ krb5_error_code ret;
+ krb5_keyblock *subkey;
+ u_int32_t q;
+ u_char *p;
+ int i;
+
+ ret = krb5_generate_subkey (context, key, &subkey);
+ if (ret)
+ return ret;
+
+ q = 0;
+ for (p = (u_char *)subkey->keyvalue.data, i = 0;
+ i < subkey->keyvalue.length;
+ ++i, ++p)
+ q = (q << 8) | *p;
+ q &= 0xffffffff;
+ *seqno = q;
+ krb5_free_keyblock (context, subkey);
+ return 0;
+}
diff --git a/source4/heimdal/lib/krb5/generate_subkey.c b/source4/heimdal/lib/krb5/generate_subkey.c
new file mode 100644
index 0000000000..df4828d097
--- /dev/null
+++ b/source4/heimdal/lib/krb5/generate_subkey.c
@@ -0,0 +1,72 @@
+/*
+ * Copyright (c) 1997 - 2001 Kungliga Tekniska Högskolan
+ * (Royal Institute of Technology, Stockholm, Sweden).
+ * 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>
+
+RCSID("$Id: generate_subkey.c,v 1.11 2005/01/05 02:39:21 lukeh Exp $");
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_generate_subkey(krb5_context context,
+ const krb5_keyblock *key,
+ krb5_keyblock **subkey)
+{
+ return krb5_generate_subkey_extended(context, key, key->keytype, subkey);
+}
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_generate_subkey_extended(krb5_context context,
+ const krb5_keyblock *key,
+ krb5_enctype etype,
+ krb5_keyblock **subkey)
+{
+ krb5_error_code ret;
+
+ ALLOC(*subkey, 1);
+ if (*subkey == NULL) {
+ krb5_set_error_string(context, "malloc: out of memory");
+ return ENOMEM;
+ }
+
+ if (etype == ETYPE_NULL)
+ etype = key->keytype; /* use session key etype */
+
+ /* XXX should we use the session key as input to the RF? */
+ ret = krb5_generate_random_keyblock(context, etype, *subkey);
+ if (ret != 0) {
+ free(*subkey);
+ *subkey = NULL;
+ }
+
+ return ret;
+}
+
diff --git a/source4/heimdal/lib/krb5/get_addrs.c b/source4/heimdal/lib/krb5/get_addrs.c
new file mode 100644
index 0000000000..034516d7d4
--- /dev/null
+++ b/source4/heimdal/lib/krb5/get_addrs.c
@@ -0,0 +1,291 @@
+/*
+ * Copyright (c) 1997 - 2002 Kungliga Tekniska Högskolan
+ * (Royal Institute of Technology, Stockholm, Sweden).
+ * 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"
+
+RCSID("$Id: get_addrs.c,v 1.46 2004/05/25 21:26:05 lha Exp $");
+
+#ifdef __osf__
+/* hate */
+struct rtentry;
+struct mbuf;
+#endif
+#ifdef HAVE_NET_IF_H
+#include <net/if.h>
+#endif
+#include <ifaddrs.h>
+
+static krb5_error_code
+gethostname_fallback (krb5_context context, krb5_addresses *res)
+{
+ krb5_error_code ret;
+ char hostname[MAXHOSTNAMELEN];
+ struct hostent *hostent;
+
+ if (gethostname (hostname, sizeof(hostname))) {
+ ret = errno;
+ krb5_set_error_string (context, "gethostname: %s", strerror(ret));
+ return ret;
+ }
+ hostent = roken_gethostbyname (hostname);
+ if (hostent == NULL) {
+ ret = errno;
+ krb5_set_error_string (context, "gethostbyname %s: %s",
+ hostname, strerror(ret));
+ return ret;
+ }
+ res->len = 1;
+ res->val = malloc (sizeof(*res->val));
+ if (res->val == NULL) {
+ krb5_set_error_string(context, "malloc: out of memory");
+ return ENOMEM;
+ }
+ res->val[0].addr_type = hostent->h_addrtype;
+ res->val[0].address.data = NULL;
+ res->val[0].address.length = 0;
+ ret = krb5_data_copy (&res->val[0].address,
+ hostent->h_addr,
+ hostent->h_length);
+ if (ret) {
+ free (res->val);
+ return ret;
+ }
+ return 0;
+}
+
+enum {
+ LOOP = 1, /* do include loopback interfaces */
+ LOOP_IF_NONE = 2, /* include loopback if no other if's */
+ EXTRA_ADDRESSES = 4, /* include extra addresses */
+ SCAN_INTERFACES = 8 /* scan interfaces for addresses */
+};
+
+/*
+ * Try to figure out the addresses of all configured interfaces with a
+ * lot of magic ioctls.
+ */
+
+static krb5_error_code
+find_all_addresses (krb5_context context, krb5_addresses *res, int flags)
+{
+ struct sockaddr sa_zero;
+ struct ifaddrs *ifa0, *ifa;
+ krb5_error_code ret = ENXIO;
+ int num, idx;
+ krb5_addresses ignore_addresses;
+
+ res->val = NULL;
+
+ if (getifaddrs(&ifa0) == -1) {
+ ret = errno;
+ krb5_set_error_string(context, "getifaddrs: %s", strerror(ret));
+ return (ret);
+ }
+
+ memset(&sa_zero, 0, sizeof(sa_zero));
+
+ /* First, count all the ifaddrs. */
+ for (ifa = ifa0, num = 0; ifa != NULL; ifa = ifa->ifa_next, num++)
+ /* nothing */;
+
+ if (num == 0) {
+ freeifaddrs(ifa0);
+ krb5_set_error_string(context, "no addresses found");
+ return (ENXIO);
+ }
+
+ if (flags & EXTRA_ADDRESSES) {
+ /* we'll remove the addresses we don't care about */
+ ret = krb5_get_ignore_addresses(context, &ignore_addresses);
+ if(ret)
+ return ret;
+ }
+
+ /* Allocate storage for them. */
+ res->val = calloc(num, sizeof(*res->val));
+ if (res->val == NULL) {
+ krb5_free_addresses(context, &ignore_addresses);
+ freeifaddrs(ifa0);
+ krb5_set_error_string (context, "malloc: out of memory");
+ return (ENOMEM);
+ }
+
+ /* Now traverse the list. */
+ for (ifa = ifa0, idx = 0; ifa != NULL; ifa = ifa->ifa_next) {
+ if ((ifa->ifa_flags & IFF_UP) == 0)
+ continue;
+ if (ifa->ifa_addr == NULL)
+ continue;
+ if (memcmp(ifa->ifa_addr, &sa_zero, sizeof(sa_zero)) == 0)
+ continue;
+ if (krb5_sockaddr_uninteresting(ifa->ifa_addr))
+ continue;
+ if ((ifa->ifa_flags & IFF_LOOPBACK) != 0) {
+ /* We'll deal with the LOOP_IF_NONE case later. */
+ if ((flags & LOOP) == 0)
+ continue;
+ }
+
+ ret = krb5_sockaddr2address(context, ifa->ifa_addr, &res->val[idx]);
+ if (ret) {
+ /*
+ * The most likely error here is going to be "Program
+ * lacks support for address type". This is no big
+ * deal -- just continue, and we'll listen on the
+ * addresses who's type we *do* support.
+ */
+ continue;
+ }
+ /* possibly skip this address? */
+ if((flags & EXTRA_ADDRESSES) &&
+ krb5_address_search(context, &res->val[idx], &ignore_addresses)) {
+ krb5_free_address(context, &res->val[idx]);
+ flags &= ~LOOP_IF_NONE; /* we actually found an address,
+ so don't add any loop-back
+ addresses */
+ continue;
+ }
+
+ idx++;
+ }
+
+ /*
+ * If no addresses were found, and LOOP_IF_NONE is set, then find
+ * the loopback addresses and add them to our list.
+ */
+ if ((flags & LOOP_IF_NONE) != 0 && idx == 0) {
+ for (ifa = ifa0; ifa != NULL; ifa = ifa->ifa_next) {
+ if ((ifa->ifa_flags & IFF_UP) == 0)
+ continue;
+ if (ifa->ifa_addr == NULL)
+ continue;
+ if (memcmp(ifa->ifa_addr, &sa_zero, sizeof(sa_zero)) == 0)
+ continue;
+ if (krb5_sockaddr_uninteresting(ifa->ifa_addr))
+ continue;
+
+ if ((ifa->ifa_flags & IFF_LOOPBACK) != 0) {
+ ret = krb5_sockaddr2address(context,
+ ifa->ifa_addr, &res->val[idx]);
+ if (ret) {
+ /*
+ * See comment above.
+ */
+ continue;
+ }
+ if((flags & EXTRA_ADDRESSES) &&
+ krb5_address_search(context, &res->val[idx],
+ &ignore_addresses)) {
+ krb5_free_address(context, &res->val[idx]);
+ continue;
+ }
+ idx++;
+ }
+ }
+ }
+
+ if (flags & EXTRA_ADDRESSES)
+ krb5_free_addresses(context, &ignore_addresses);
+ freeifaddrs(ifa0);
+ if (ret)
+ free(res->val);
+ else
+ res->len = idx; /* Now a count. */
+ return (ret);
+}
+
+static krb5_error_code
+get_addrs_int (krb5_context context, krb5_addresses *res, int flags)
+{
+ krb5_error_code ret = -1;
+
+ if (flags & SCAN_INTERFACES) {
+ ret = find_all_addresses (context, res, flags);
+ if(ret || res->len == 0)
+ ret = gethostname_fallback (context, res);
+ } else {
+ res->len = 0;
+ res->val = NULL;
+ ret = 0;
+ }
+
+ if(ret == 0 && (flags & EXTRA_ADDRESSES)) {
+ krb5_addresses a;
+ /* append user specified addresses */
+ ret = krb5_get_extra_addresses(context, &a);
+ if(ret) {
+ krb5_free_addresses(context, res);
+ return ret;
+ }
+ ret = krb5_append_addresses(context, res, &a);
+ if(ret) {
+ krb5_free_addresses(context, res);
+ return ret;
+ }
+ krb5_free_addresses(context, &a);
+ }
+ if(res->len == 0) {
+ free(res->val);
+ res->val = NULL;
+ }
+ return ret;
+}
+
+/*
+ * Try to get all addresses, but return the one corresponding to
+ * `hostname' if we fail.
+ *
+ * Only include loopback address if there are no other.
+ */
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_get_all_client_addrs (krb5_context context, krb5_addresses *res)
+{
+ int flags = LOOP_IF_NONE | EXTRA_ADDRESSES;
+
+ if (context->scan_interfaces)
+ flags |= SCAN_INTERFACES;
+
+ return get_addrs_int (context, res, flags);
+}
+
+/*
+ * Try to get all local addresses that a server should listen to.
+ * If that fails, we return the address corresponding to `hostname'.
+ */
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_get_all_server_addrs (krb5_context context, krb5_addresses *res)
+{
+ return get_addrs_int (context, res, LOOP | SCAN_INTERFACES);
+}
diff --git a/source4/heimdal/lib/krb5/get_cred.c b/source4/heimdal/lib/krb5/get_cred.c
new file mode 100644
index 0000000000..63fb55608c
--- /dev/null
+++ b/source4/heimdal/lib/krb5/get_cred.c
@@ -0,0 +1,909 @@
+/*
+ * Copyright (c) 1997 - 2004 Kungliga Tekniska Högskolan
+ * (Royal Institute of Technology, Stockholm, Sweden).
+ * 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>
+
+RCSID("$Id: get_cred.c,v 1.107 2005/06/16 22:57:14 lha Exp $");
+
+/*
+ * Take the `body' and encode it into `padata' using the credentials
+ * in `creds'.
+ */
+
+static krb5_error_code
+make_pa_tgs_req(krb5_context context,
+ krb5_auth_context ac,
+ KDC_REQ_BODY *body,
+ PA_DATA *padata,
+ krb5_creds *creds,
+ krb5_key_usage usage)
+{
+ u_char *buf;
+ size_t buf_size;
+ size_t len;
+ krb5_data in_data;
+ krb5_error_code ret;
+
+ ASN1_MALLOC_ENCODE(KDC_REQ_BODY, buf, buf_size, body, &len, ret);
+ if (ret)
+ goto out;
+ if(buf_size != len)
+ krb5_abortx(context, "internal error in ASN.1 encoder");
+
+ in_data.length = len;
+ in_data.data = buf;
+ ret = _krb5_mk_req_internal(context, &ac, 0, &in_data, creds,
+ &padata->padata_value,
+ KRB5_KU_TGS_REQ_AUTH_CKSUM,
+ usage
+ /* KRB5_KU_TGS_REQ_AUTH */);
+ out:
+ free (buf);
+ if(ret)
+ return ret;
+ padata->padata_type = KRB5_PADATA_TGS_REQ;
+ return 0;
+}
+
+/*
+ * Set the `enc-authorization-data' in `req_body' based on `authdata'
+ */
+
+static krb5_error_code
+set_auth_data (krb5_context context,
+ KDC_REQ_BODY *req_body,
+ krb5_authdata *authdata,
+ krb5_keyblock *key)
+{
+ if(authdata->len) {
+ size_t len, buf_size;
+ unsigned char *buf;
+ krb5_crypto crypto;
+ krb5_error_code ret;
+
+ ASN1_MALLOC_ENCODE(AuthorizationData, buf, buf_size, authdata,
+ &len, ret);
+ if (ret)
+ return ret;
+ if (buf_size != len)
+ krb5_abortx(context, "internal error in ASN.1 encoder");
+
+ ALLOC(req_body->enc_authorization_data, 1);
+ if (req_body->enc_authorization_data == NULL) {
+ free (buf);
+ krb5_set_error_string(context, "malloc: out of memory");
+ return ENOMEM;
+ }
+ ret = krb5_crypto_init(context, key, 0, &crypto);
+ if (ret) {
+ free (buf);
+ free (req_body->enc_authorization_data);
+ req_body->enc_authorization_data = NULL;
+ return ret;
+ }
+ krb5_encrypt_EncryptedData(context,
+ crypto,
+ KRB5_KU_TGS_REQ_AUTH_DAT_SUBKEY,
+ /* KRB5_KU_TGS_REQ_AUTH_DAT_SESSION? */
+ buf,
+ len,
+ 0,
+ req_body->enc_authorization_data);
+ free (buf);
+ krb5_crypto_destroy(context, crypto);
+ } else {
+ req_body->enc_authorization_data = NULL;
+ }
+ return 0;
+}
+
+/*
+ * Create a tgs-req in `t' with `addresses', `flags', `second_ticket'
+ * (if not-NULL), `in_creds', `krbtgt', and returning the generated
+ * subkey in `subkey'.
+ */
+
+static krb5_error_code
+init_tgs_req (krb5_context context,
+ krb5_ccache ccache,
+ krb5_addresses *addresses,
+ krb5_kdc_flags flags,
+ Ticket *second_ticket,
+ krb5_creds *in_creds,
+ krb5_creds *krbtgt,
+ unsigned nonce,
+ krb5_keyblock **subkey,
+ TGS_REQ *t,
+ krb5_key_usage usage)
+{
+ krb5_error_code ret = 0;
+
+ memset(t, 0, sizeof(*t));
+ t->pvno = 5;
+ t->msg_type = krb_tgs_req;
+ if (in_creds->session.keytype) {
+ ALLOC_SEQ(&t->req_body.etype, 1);
+ if(t->req_body.etype.val == NULL) {
+ ret = ENOMEM;
+ krb5_set_error_string(context, "malloc: out of memory");
+ goto fail;
+ }
+ t->req_body.etype.val[0] = in_creds->session.keytype;
+ } else {
+ ret = krb5_init_etype(context,
+ &t->req_body.etype.len,
+ &t->req_body.etype.val,
+ NULL);
+ }
+ if (ret)
+ goto fail;
+ t->req_body.addresses = addresses;
+ t->req_body.kdc_options = flags.b;
+ ret = copy_Realm(&in_creds->server->realm, &t->req_body.realm);
+ if (ret)
+ goto fail;
+ ALLOC(t->req_body.sname, 1);
+ if (t->req_body.sname == NULL) {
+ ret = ENOMEM;
+ krb5_set_error_string(context, "malloc: out of memory");
+ goto fail;
+ }
+
+ /* some versions of some code might require that the client be
+ present in TGS-REQs, but this is clearly against the spec */
+
+ ret = copy_PrincipalName(&in_creds->server->name, t->req_body.sname);
+ if (ret)
+ goto fail;
+
+ /* req_body.till should be NULL if there is no endtime specified,
+ but old MIT code (like DCE secd) doesn't like that */
+ ALLOC(t->req_body.till, 1);
+ if(t->req_body.till == NULL){
+ ret = ENOMEM;
+ krb5_set_error_string(context, "malloc: out of memory");
+ goto fail;
+ }
+ *t->req_body.till = in_creds->times.endtime;
+
+ t->req_body.nonce = nonce;
+ if(second_ticket){
+ ALLOC(t->req_body.additional_tickets, 1);
+ if (t->req_body.additional_tickets == NULL) {
+ ret = ENOMEM;
+ krb5_set_error_string(context, "malloc: out of memory");
+ goto fail;
+ }
+ ALLOC_SEQ(t->req_body.additional_tickets, 1);
+ if (t->req_body.additional_tickets->val == NULL) {
+ ret = ENOMEM;
+ krb5_set_error_string(context, "malloc: out of memory");
+ goto fail;
+ }
+ ret = copy_Ticket(second_ticket, t->req_body.additional_tickets->val);
+ if (ret)
+ goto fail;
+ }
+ ALLOC(t->padata, 1);
+ if (t->padata == NULL) {
+ ret = ENOMEM;
+ krb5_set_error_string(context, "malloc: out of memory");
+ goto fail;
+ }
+ ALLOC_SEQ(t->padata, 1);
+ if (t->padata->val == NULL) {
+ ret = ENOMEM;
+ krb5_set_error_string(context, "malloc: out of memory");
+ goto fail;
+ }
+
+ {
+ krb5_auth_context ac;
+ krb5_keyblock *key = NULL;
+
+ ret = krb5_auth_con_init(context, &ac);
+ if(ret)
+ goto fail;
+
+ if (krb5_config_get_bool_default(context, NULL, FALSE,
+ "realms",
+ krbtgt->server->realm,
+ "tgs_require_subkey",
+ NULL))
+ {
+ ret = krb5_generate_subkey (context, &krbtgt->session, &key);
+ if (ret) {
+ krb5_auth_con_free (context, ac);
+ goto fail;
+ }
+
+ ret = krb5_auth_con_setlocalsubkey(context, ac, key);
+ if (ret) {
+ if (key)
+ krb5_free_keyblock (context, key);
+ krb5_auth_con_free (context, ac);
+ goto fail;
+ }
+ }
+
+ ret = set_auth_data (context, &t->req_body, &in_creds->authdata,
+ key ? key : &krbtgt->session);
+ if (ret) {
+ if (key)
+ krb5_free_keyblock (context, key);
+ krb5_auth_con_free (context, ac);
+ goto fail;
+ }
+
+ ret = make_pa_tgs_req(context,
+ ac,
+ &t->req_body,
+ t->padata->val,
+ krbtgt,
+ usage);
+ if(ret) {
+ if (key)
+ krb5_free_keyblock (context, key);
+ krb5_auth_con_free(context, ac);
+ goto fail;
+ }
+ *subkey = key;
+
+ krb5_auth_con_free(context, ac);
+ }
+fail:
+ if (ret) {
+ t->req_body.addresses = NULL;
+ free_TGS_REQ (t);
+ }
+ return ret;
+}
+
+krb5_error_code
+_krb5_get_krbtgt(krb5_context context,
+ krb5_ccache id,
+ krb5_realm realm,
+ krb5_creds **cred)
+{
+ krb5_error_code ret;
+ krb5_creds tmp_cred;
+
+ memset(&tmp_cred, 0, sizeof(tmp_cred));
+
+ ret = krb5_cc_get_principal(context, id, &tmp_cred.client);
+ if (ret)
+ return ret;
+
+ ret = krb5_make_principal(context,
+ &tmp_cred.server,
+ realm,
+ KRB5_TGS_NAME,
+ realm,
+ NULL);
+ if(ret) {
+ krb5_free_principal(context, tmp_cred.client);
+ return ret;
+ }
+ ret = krb5_get_credentials(context,
+ KRB5_GC_CACHED,
+ id,
+ &tmp_cred,
+ cred);
+ krb5_free_principal(context, tmp_cred.client);
+ krb5_free_principal(context, tmp_cred.server);
+ if(ret)
+ return ret;
+ return 0;
+}
+
+/* DCE compatible decrypt proc */
+static krb5_error_code
+decrypt_tkt_with_subkey (krb5_context context,
+ krb5_keyblock *key,
+ krb5_key_usage usage,
+ krb5_const_pointer subkey,
+ krb5_kdc_rep *dec_rep)
+{
+ krb5_error_code ret;
+ krb5_data data;
+ size_t size;
+ krb5_crypto crypto;
+
+ ret = krb5_crypto_init(context, key, 0, &crypto);
+ if (ret)
+ return ret;
+ ret = krb5_decrypt_EncryptedData (context,
+ crypto,
+ usage,
+ &dec_rep->kdc_rep.enc_part,
+ &data);
+ krb5_crypto_destroy(context, crypto);
+ if(ret && subkey){
+ /* DCE compat -- try to decrypt with subkey */
+ ret = krb5_crypto_init(context, subkey, 0, &crypto);
+ if (ret)
+ return ret;
+ ret = krb5_decrypt_EncryptedData (context,
+ crypto,
+ KRB5_KU_TGS_REP_ENC_PART_SUB_KEY,
+ &dec_rep->kdc_rep.enc_part,
+ &data);
+ krb5_crypto_destroy(context, crypto);
+ }
+ if (ret)
+ return ret;
+
+ ret = krb5_decode_EncASRepPart(context,
+ data.data,
+ data.length,
+ &dec_rep->enc_part,
+ &size);
+ if (ret)
+ ret = krb5_decode_EncTGSRepPart(context,
+ data.data,
+ data.length,
+ &dec_rep->enc_part,
+ &size);
+ krb5_data_free (&data);
+ return ret;
+}
+
+static krb5_error_code
+get_cred_kdc_usage(krb5_context context,
+ krb5_ccache id,
+ krb5_kdc_flags flags,
+ krb5_addresses *addresses,
+ krb5_creds *in_creds,
+ krb5_creds *krbtgt,
+ krb5_creds *out_creds,
+ krb5_key_usage usage)
+{
+ TGS_REQ req;
+ krb5_data enc;
+ krb5_data resp;
+ krb5_kdc_rep rep;
+ KRB_ERROR error;
+ krb5_error_code ret;
+ unsigned nonce;
+ krb5_keyblock *subkey = NULL;
+ size_t len;
+ Ticket second_ticket;
+ int send_to_kdc_flags = 0;
+
+ krb5_data_zero(&resp);
+ krb5_data_zero(&enc);
+
+ krb5_generate_random_block(&nonce, sizeof(nonce));
+ nonce &= 0xffffffff;
+
+ if(flags.b.enc_tkt_in_skey){
+ ret = decode_Ticket(in_creds->second_ticket.data,
+ in_creds->second_ticket.length,
+ &second_ticket, &len);
+ if(ret)
+ return ret;
+ }
+
+ ret = init_tgs_req (context,
+ id,
+ addresses,
+ flags,
+ flags.b.enc_tkt_in_skey ? &second_ticket : NULL,
+ in_creds,
+ krbtgt,
+ nonce,
+ &subkey,
+ &req,
+ usage);
+ if(flags.b.enc_tkt_in_skey)
+ free_Ticket(&second_ticket);
+ if (ret)
+ goto out;
+
+ ASN1_MALLOC_ENCODE(TGS_REQ, enc.data, enc.length, &req, &len, ret);
+ if (ret)
+ goto out;
+ if(enc.length != len)
+ krb5_abortx(context, "internal error in ASN.1 encoder");
+
+ /* don't free addresses */
+ req.req_body.addresses = NULL;
+ free_TGS_REQ(&req);
+
+ /*
+ * Send and receive
+ */
+again:
+ ret = krb5_sendto_kdc_flags (context, &enc,
+ &krbtgt->server->name.name_string.val[1],
+ &resp,
+ send_to_kdc_flags);
+ if(ret)
+ goto out;
+
+ memset(&rep, 0, sizeof(rep));
+ if(decode_TGS_REP(resp.data, resp.length, &rep.kdc_rep, &len) == 0){
+ ret = krb5_copy_principal(context,
+ in_creds->client,
+ &out_creds->client);
+ if(ret)
+ goto out;
+ ret = krb5_copy_principal(context,
+ in_creds->server,
+ &out_creds->server);
+ if(ret)
+ goto out;
+ /* this should go someplace else */
+ out_creds->times.endtime = in_creds->times.endtime;
+
+ ret = _krb5_extract_ticket(context,
+ &rep,
+ out_creds,
+ &krbtgt->session,
+ NULL,
+ KRB5_KU_TGS_REP_ENC_PART_SESSION,
+ &krbtgt->addresses,
+ nonce,
+ TRUE,
+ flags.b.request_anonymous,
+ decrypt_tkt_with_subkey,
+ subkey);
+ krb5_free_kdc_rep(context, &rep);
+ } else if(krb5_rd_error(context, &resp, &error) == 0) {
+ ret = krb5_error_from_rd_error(context, &error, in_creds);
+ krb5_free_error_contents(context, &error);
+
+ if (ret == KRB5KRB_ERR_RESPONSE_TOO_BIG && !(send_to_kdc_flags & KRB5_KRBHST_FLAGS_LARGE_MSG)) {
+ send_to_kdc_flags |= KRB5_KRBHST_FLAGS_LARGE_MSG;
+ krb5_data_free(&resp);
+ goto again;
+ }
+ } else if(resp.data && ((char*)resp.data)[0] == 4) {
+ ret = KRB5KRB_AP_ERR_V4_REPLY;
+ krb5_clear_error_string(context);
+ } else {
+ ret = KRB5KRB_AP_ERR_MSG_TYPE;
+ krb5_clear_error_string(context);
+ }
+
+out:
+ krb5_data_free(&resp);
+ krb5_data_free(&enc);
+ if(subkey){
+ krb5_free_keyblock_contents(context, subkey);
+ free(subkey);
+ }
+ return ret;
+
+}
+
+static krb5_error_code
+get_cred_kdc(krb5_context context,
+ krb5_ccache id,
+ krb5_kdc_flags flags,
+ krb5_addresses *addresses,
+ krb5_creds *in_creds,
+ krb5_creds *krbtgt,
+ krb5_creds *out_creds)
+{
+ krb5_error_code ret;
+
+ ret = get_cred_kdc_usage(context, id, flags, addresses, in_creds,
+ krbtgt, out_creds, KRB5_KU_TGS_REQ_AUTH);
+ if (ret == KRB5KRB_AP_ERR_BAD_INTEGRITY) {
+ krb5_clear_error_string (context);
+ ret = get_cred_kdc_usage(context, id, flags, addresses, in_creds,
+ krbtgt, out_creds, KRB5_KU_AP_REQ_AUTH);
+ }
+ return ret;
+}
+
+/* same as above, just get local addresses first */
+
+static krb5_error_code
+get_cred_kdc_la(krb5_context context, krb5_ccache id, krb5_kdc_flags flags,
+ krb5_creds *in_creds, krb5_creds *krbtgt,
+ krb5_creds *out_creds)
+{
+ krb5_error_code ret;
+ krb5_addresses addresses, *addrs = &addresses;
+
+ krb5_get_all_client_addrs(context, &addresses);
+ /* XXX this sucks. */
+ if(addresses.len == 0)
+ addrs = NULL;
+ ret = get_cred_kdc(context, id, flags, addrs,
+ in_creds, krbtgt, out_creds);
+ krb5_free_addresses(context, &addresses);
+ return ret;
+}
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_get_kdc_cred(krb5_context context,
+ krb5_ccache id,
+ krb5_kdc_flags flags,
+ krb5_addresses *addresses,
+ Ticket *second_ticket,
+ krb5_creds *in_creds,
+ krb5_creds **out_creds
+ )
+{
+ krb5_error_code ret;
+ krb5_creds *krbtgt;
+
+ *out_creds = calloc(1, sizeof(**out_creds));
+ if(*out_creds == NULL) {
+ krb5_set_error_string(context, "malloc: out of memory");
+ return ENOMEM;
+ }
+ ret = _krb5_get_krbtgt (context,
+ id,
+ in_creds->server->realm,
+ &krbtgt);
+ if(ret) {
+ free(*out_creds);
+ return ret;
+ }
+ ret = get_cred_kdc(context, id, flags, addresses,
+ in_creds, krbtgt, *out_creds);
+ krb5_free_creds (context, krbtgt);
+ if(ret)
+ free(*out_creds);
+ return ret;
+}
+
+
+static krb5_error_code
+find_cred(krb5_context context,
+ krb5_ccache id,
+ krb5_principal server,
+ krb5_creds **tgts,
+ krb5_creds *out_creds)
+{
+ krb5_error_code ret;
+ krb5_creds mcreds;
+
+ krb5_cc_clear_mcred(&mcreds);
+ mcreds.server = server;
+ ret = krb5_cc_retrieve_cred(context, id, KRB5_TC_DONT_MATCH_REALM,
+ &mcreds, out_creds);
+ if(ret == 0)
+ return 0;
+ while(tgts && *tgts){
+ if(krb5_compare_creds(context, KRB5_TC_DONT_MATCH_REALM,
+ &mcreds, *tgts)){
+ ret = krb5_copy_creds_contents(context, *tgts, out_creds);
+ return ret;
+ }
+ tgts++;
+ }
+ krb5_clear_error_string(context);
+ return KRB5_CC_NOTFOUND;
+}
+
+static krb5_error_code
+add_cred(krb5_context context, krb5_creds ***tgts, krb5_creds *tkt)
+{
+ int i;
+ krb5_error_code ret;
+ krb5_creds **tmp = *tgts;
+
+ for(i = 0; tmp && tmp[i]; i++); /* XXX */
+ tmp = realloc(tmp, (i+2)*sizeof(*tmp));
+ if(tmp == NULL) {
+ krb5_set_error_string(context, "malloc: out of memory");
+ return ENOMEM;
+ }
+ *tgts = tmp;
+ ret = krb5_copy_creds(context, tkt, &tmp[i]);
+ tmp[i+1] = NULL;
+ return ret;
+}
+
+/*
+get_cred(server)
+ creds = cc_get_cred(server)
+ if(creds) return creds
+ tgt = cc_get_cred(krbtgt/server_realm@any_realm)
+ if(tgt)
+ return get_cred_tgt(server, tgt)
+ if(client_realm == server_realm)
+ return NULL
+ tgt = get_cred(krbtgt/server_realm@client_realm)
+ while(tgt_inst != server_realm)
+ tgt = get_cred(krbtgt/server_realm@tgt_inst)
+ return get_cred_tgt(server, tgt)
+ */
+
+static krb5_error_code
+get_cred_from_kdc_flags(krb5_context context,
+ krb5_kdc_flags flags,
+ krb5_ccache ccache,
+ krb5_creds *in_creds,
+ krb5_creds **out_creds,
+ krb5_creds ***ret_tgts)
+{
+ krb5_error_code ret;
+ krb5_creds *tgt, tmp_creds;
+ krb5_const_realm client_realm, server_realm, try_realm;
+
+ *out_creds = NULL;
+
+ client_realm = krb5_principal_get_realm(context, in_creds->client);
+ server_realm = krb5_principal_get_realm(context, in_creds->server);
+ memset(&tmp_creds, 0, sizeof(tmp_creds));
+ ret = krb5_copy_principal(context, in_creds->client, &tmp_creds.client);
+ if(ret)
+ return ret;
+
+ try_realm = krb5_config_get_string(context, NULL, "capaths",
+ client_realm, server_realm, NULL);
+
+#if 1
+ /* XXX remove in future release */
+ if(try_realm == NULL)
+ try_realm = krb5_config_get_string(context, NULL, "libdefaults",
+ "capath", server_realm, NULL);
+#endif
+
+ if (try_realm == NULL)
+ try_realm = client_realm;
+
+ ret = krb5_make_principal(context,
+ &tmp_creds.server,
+ try_realm,
+ KRB5_TGS_NAME,
+ server_realm,
+ NULL);
+ if(ret){
+ krb5_free_principal(context, tmp_creds.client);
+ return ret;
+ }
+ {
+ krb5_creds tgts;
+ /* XXX try krb5_cc_retrieve_cred first? */
+ ret = find_cred(context, ccache, tmp_creds.server,
+ *ret_tgts, &tgts);
+ if(ret == 0){
+ *out_creds = calloc(1, sizeof(**out_creds));
+ if(*out_creds == NULL) {
+ krb5_set_error_string(context, "malloc: out of memory");
+ ret = ENOMEM;
+ } else {
+ krb5_boolean noaddr;
+
+ krb5_appdefault_boolean(context, NULL, tgts.server->realm,
+ "no-addresses", FALSE, &noaddr);
+
+ if (noaddr)
+ ret = get_cred_kdc(context, ccache, flags, NULL,
+ in_creds, &tgts, *out_creds);
+ else
+ ret = get_cred_kdc_la(context, ccache, flags,
+ in_creds, &tgts, *out_creds);
+ if (ret) {
+ free (*out_creds);
+ *out_creds = NULL;
+ }
+ }
+ krb5_free_cred_contents(context, &tgts);
+ krb5_free_principal(context, tmp_creds.server);
+ krb5_free_principal(context, tmp_creds.client);
+ return ret;
+ }
+ }
+ if(krb5_realm_compare(context, in_creds->client, in_creds->server)) {
+ krb5_clear_error_string (context);
+ return KRB5_CC_NOTFOUND;
+ }
+ /* XXX this can loop forever */
+ while(1){
+ heim_general_string tgt_inst;
+
+ ret = get_cred_from_kdc_flags(context, flags, ccache, &tmp_creds,
+ &tgt, ret_tgts);
+ if(ret) {
+ krb5_free_principal(context, tmp_creds.server);
+ krb5_free_principal(context, tmp_creds.client);
+ return ret;
+ }
+ ret = add_cred(context, ret_tgts, tgt);
+ if(ret) {
+ krb5_free_principal(context, tmp_creds.server);
+ krb5_free_principal(context, tmp_creds.client);
+ return ret;
+ }
+ tgt_inst = tgt->server->name.name_string.val[1];
+ if(strcmp(tgt_inst, server_realm) == 0)
+ break;
+ krb5_free_principal(context, tmp_creds.server);
+ ret = krb5_make_principal(context, &tmp_creds.server,
+ tgt_inst, KRB5_TGS_NAME, server_realm, NULL);
+ if(ret) {
+ krb5_free_principal(context, tmp_creds.server);
+ krb5_free_principal(context, tmp_creds.client);
+ return ret;
+ }
+ ret = krb5_free_creds(context, tgt);
+ if(ret) {
+ krb5_free_principal(context, tmp_creds.server);
+ krb5_free_principal(context, tmp_creds.client);
+ return ret;
+ }
+ }
+
+ krb5_free_principal(context, tmp_creds.server);
+ krb5_free_principal(context, tmp_creds.client);
+ *out_creds = calloc(1, sizeof(**out_creds));
+ if(*out_creds == NULL) {
+ krb5_set_error_string(context, "malloc: out of memory");
+ ret = ENOMEM;
+ } else {
+ krb5_boolean noaddr;
+
+ krb5_appdefault_boolean(context, NULL, tgt->server->realm,
+ "no-addresses", FALSE, &noaddr);
+ if (noaddr)
+ ret = get_cred_kdc (context, ccache, flags, NULL,
+ in_creds, tgt, *out_creds);
+ else
+ ret = get_cred_kdc_la(context, ccache, flags,
+ in_creds, tgt, *out_creds);
+ if (ret) {
+ free (*out_creds);
+ *out_creds = NULL;
+ }
+ }
+ krb5_free_creds(context, tgt);
+ return ret;
+}
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_get_cred_from_kdc_opt(krb5_context context,
+ krb5_ccache ccache,
+ krb5_creds *in_creds,
+ krb5_creds **out_creds,
+ krb5_creds ***ret_tgts,
+ krb5_flags flags)
+{
+ krb5_kdc_flags f;
+ f.i = flags;
+ return get_cred_from_kdc_flags(context, f, ccache,
+ in_creds, out_creds, ret_tgts);
+}
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_get_cred_from_kdc(krb5_context context,
+ krb5_ccache ccache,
+ krb5_creds *in_creds,
+ krb5_creds **out_creds,
+ krb5_creds ***ret_tgts)
+{
+ return krb5_get_cred_from_kdc_opt(context, ccache,
+ in_creds, out_creds, ret_tgts, 0);
+}
+
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_get_credentials_with_flags(krb5_context context,
+ krb5_flags options,
+ krb5_kdc_flags flags,
+ krb5_ccache ccache,
+ krb5_creds *in_creds,
+ krb5_creds **out_creds)
+{
+ krb5_error_code ret;
+ krb5_creds **tgts;
+ krb5_creds *res_creds;
+ int i;
+
+ *out_creds = NULL;
+ res_creds = calloc(1, sizeof(*res_creds));
+ if (res_creds == NULL) {
+ krb5_set_error_string(context, "malloc: out of memory");
+ return ENOMEM;
+ }
+
+ if (in_creds->session.keytype)
+ options |= KRB5_TC_MATCH_KEYTYPE;
+
+ ret = krb5_cc_retrieve_cred(context,
+ ccache,
+ options,
+ in_creds, res_creds);
+ /*
+ * If we got a credential, check if credential is expired before
+ * returning it.
+ */
+ ret = krb5_cc_retrieve_cred(context,
+ ccache,
+ in_creds->session.keytype ?
+ KRB5_TC_MATCH_KEYTYPE : 0,
+ in_creds, res_creds);
+ /*
+ * If we got a credential, check if credential is expired before
+ * returning it, but only if KRB5_GC_EXPIRED_OK is not set.
+ */
+ if (ret == 0) {
+ krb5_timestamp timeret;
+
+ /* If expired ok, don't bother checking */
+ if(options & KRB5_GC_EXPIRED_OK) {
+ *out_creds = res_creds;
+ return 0;
+ }
+
+ krb5_timeofday(context, &timeret);
+ if(res_creds->times.endtime > timeret) {
+ *out_creds = res_creds;
+ return 0;
+ }
+ if(options & KRB5_GC_CACHED)
+ krb5_cc_remove_cred(context, ccache, 0, res_creds);
+
+ } else if(ret != KRB5_CC_END) {
+ free(res_creds);
+ return ret;
+ }
+ free(res_creds);
+ if(options & KRB5_GC_CACHED) {
+ krb5_clear_error_string (context);
+ return KRB5_CC_NOTFOUND;
+ }
+ if(options & KRB5_GC_USER_USER)
+ flags.b.enc_tkt_in_skey = 1;
+ tgts = NULL;
+ ret = get_cred_from_kdc_flags(context, flags, ccache,
+ in_creds, out_creds, &tgts);
+ for(i = 0; tgts && tgts[i]; i++) {
+ krb5_cc_store_cred(context, ccache, tgts[i]);
+ krb5_free_creds(context, tgts[i]);
+ }
+ free(tgts);
+ if(ret == 0 && flags.b.enc_tkt_in_skey == 0)
+ krb5_cc_store_cred(context, ccache, *out_creds);
+ return ret;
+}
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_get_credentials(krb5_context context,
+ krb5_flags options,
+ krb5_ccache ccache,
+ krb5_creds *in_creds,
+ krb5_creds **out_creds)
+{
+ krb5_kdc_flags flags;
+ flags.i = 0;
+ return krb5_get_credentials_with_flags(context, options, flags,
+ ccache, in_creds, out_creds);
+}
diff --git a/source4/heimdal/lib/krb5/get_default_principal.c b/source4/heimdal/lib/krb5/get_default_principal.c
new file mode 100644
index 0000000000..03e8f0a823
--- /dev/null
+++ b/source4/heimdal/lib/krb5/get_default_principal.c
@@ -0,0 +1,115 @@
+/*
+ * Copyright (c) 1997 - 2001 Kungliga Tekniska Högskolan
+ * (Royal Institute of Technology, Stockholm, Sweden).
+ * 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"
+
+RCSID("$Id: get_default_principal.c,v 1.10 2005/04/20 20:53:29 lha Exp $");
+
+/*
+ * Try to find out what's a reasonable default principal.
+ */
+
+static const char*
+get_env_user(void)
+{
+ const char *user = getenv("USER");
+ if(user == NULL)
+ user = getenv("LOGNAME");
+ if(user == NULL)
+ user = getenv("USERNAME");
+ return user;
+}
+
+/*
+ * Will only use operating-system dependant operation to get the
+ * default principal, for use of functions that in ccache layer to
+ * avoid recursive calls.
+ */
+
+krb5_error_code
+_krb5_get_default_principal_local (krb5_context context,
+ krb5_principal *princ)
+{
+ krb5_error_code ret;
+ const char *user;
+ uid_t uid;
+
+ *princ = NULL;
+
+ uid = getuid();
+ if(uid == 0) {
+ user = getlogin();
+ if(user == NULL)
+ user = get_env_user();
+ if(user != NULL && strcmp(user, "root") != 0)
+ ret = krb5_make_principal(context, princ, NULL, user, "root", NULL);
+ else
+ ret = krb5_make_principal(context, princ, NULL, "root", NULL);
+ } else {
+ struct passwd *pw = getpwuid(uid);
+ if(pw != NULL)
+ user = pw->pw_name;
+ else {
+ user = get_env_user();
+ if(user == NULL)
+ user = getlogin();
+ }
+ if(user == NULL) {
+ krb5_set_error_string(context,
+ "unable to figure out current principal");
+ return ENOTTY; /* XXX */
+ }
+ ret = krb5_make_principal(context, princ, NULL, user, NULL);
+ }
+ return ret;
+}
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_get_default_principal (krb5_context context,
+ krb5_principal *princ)
+{
+ krb5_error_code ret;
+ krb5_ccache id;
+
+ *princ = NULL;
+
+ ret = krb5_cc_default (context, &id);
+ if (ret == 0) {
+ ret = krb5_cc_get_principal (context, id, princ);
+ krb5_cc_close (context, id);
+ if (ret == 0)
+ return 0;
+ }
+
+ return _krb5_get_default_principal_local(context, princ);
+}
diff --git a/source4/heimdal/lib/krb5/get_default_realm.c b/source4/heimdal/lib/krb5/get_default_realm.c
new file mode 100644
index 0000000000..bb72daf373
--- /dev/null
+++ b/source4/heimdal/lib/krb5/get_default_realm.c
@@ -0,0 +1,84 @@
+/*
+ * Copyright (c) 1997 - 2001, 2004 Kungliga Tekniska Högskolan
+ * (Royal Institute of Technology, Stockholm, Sweden).
+ * 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"
+
+RCSID("$Id: get_default_realm.c,v 1.13 2004/05/25 21:27:17 lha Exp $");
+
+/*
+ * Return a NULL-terminated list of default realms in `realms'.
+ * Free this memory with krb5_free_host_realm.
+ */
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_get_default_realms (krb5_context context,
+ krb5_realm **realms)
+{
+ if (context->default_realms == NULL) {
+ krb5_error_code ret = krb5_set_default_realm (context, NULL);
+ if (ret)
+ return KRB5_CONFIG_NODEFREALM;
+ }
+
+ return krb5_copy_host_realm (context,
+ context->default_realms,
+ realms);
+}
+
+/*
+ * Return the first default realm. For compatibility.
+ */
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_get_default_realm(krb5_context context,
+ krb5_realm *realm)
+{
+ krb5_error_code ret;
+ char *res;
+
+ if (context->default_realms == NULL
+ || context->default_realms[0] == NULL) {
+ krb5_clear_error_string(context);
+ ret = krb5_set_default_realm (context, NULL);
+ if (ret)
+ return ret;
+ }
+
+ res = strdup (context->default_realms[0]);
+ if (res == NULL) {
+ krb5_set_error_string(context, "malloc: out of memory");
+ return ENOMEM;
+ }
+ *realm = res;
+ return 0;
+}
diff --git a/source4/heimdal/lib/krb5/get_for_creds.c b/source4/heimdal/lib/krb5/get_for_creds.c
new file mode 100644
index 0000000000..ea0bc4ad9e
--- /dev/null
+++ b/source4/heimdal/lib/krb5/get_for_creds.c
@@ -0,0 +1,427 @@
+/*
+ * Copyright (c) 1997 - 2004 Kungliga Tekniska Högskolan
+ * (Royal Institute of Technology, Stockholm, Sweden).
+ * 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>
+
+RCSID("$Id: get_for_creds.c,v 1.45 2005/06/15 02:44:36 lha Exp $");
+
+static krb5_error_code
+add_addrs(krb5_context context,
+ krb5_addresses *addr,
+ struct addrinfo *ai)
+{
+ krb5_error_code ret;
+ unsigned n, i;
+ void *tmp;
+ struct addrinfo *a;
+
+ n = 0;
+ for (a = ai; a != NULL; a = a->ai_next)
+ ++n;
+
+ tmp = realloc(addr->val, (addr->len + n) * sizeof(*addr->val));
+ if (tmp == NULL) {
+ krb5_set_error_string(context, "malloc: out of memory");
+ ret = ENOMEM;
+ goto fail;
+ }
+ addr->val = tmp;
+ for (i = addr->len; i < (addr->len + n); ++i) {
+ addr->val[i].addr_type = 0;
+ krb5_data_zero(&addr->val[i].address);
+ }
+ i = addr->len;
+ for (a = ai; a != NULL; a = a->ai_next) {
+ krb5_address ad;
+
+ ret = krb5_sockaddr2address (context, a->ai_addr, &ad);
+ if (ret == 0) {
+ if (krb5_address_search(context, &ad, addr))
+ krb5_free_address(context, &ad);
+ else
+ addr->val[i++] = ad;
+ }
+ else if (ret == KRB5_PROG_ATYPE_NOSUPP)
+ krb5_clear_error_string (context);
+ else
+ goto fail;
+ addr->len = i;
+ }
+ return 0;
+fail:
+ krb5_free_addresses (context, addr);
+ return ret;
+}
+
+/*
+ * Forward credentials for `client' to host `hostname`,
+ * making them forwardable if `forwardable', and returning the
+ * blob of data to sent in `out_data'.
+ * If hostname == NULL, pick it from `server'
+ */
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_fwd_tgt_creds (krb5_context context,
+ krb5_auth_context auth_context,
+ const char *hostname,
+ krb5_principal client,
+ krb5_principal server,
+ krb5_ccache ccache,
+ int forwardable,
+ krb5_data *out_data)
+{
+ krb5_flags flags = 0;
+ krb5_creds creds;
+ krb5_error_code ret;
+ krb5_const_realm client_realm;
+
+ flags |= KDC_OPT_FORWARDED;
+
+ if (forwardable)
+ flags |= KDC_OPT_FORWARDABLE;
+
+ if (hostname == NULL &&
+ krb5_principal_get_type(context, server) == KRB5_NT_SRV_HST) {
+ const char *inst = krb5_principal_get_comp_string(context, server, 0);
+ const char *host = krb5_principal_get_comp_string(context, server, 1);
+
+ if (inst != NULL &&
+ strcmp(inst, "host") == 0 &&
+ host != NULL &&
+ krb5_principal_get_comp_string(context, server, 2) == NULL)
+ hostname = host;
+ }
+
+ client_realm = krb5_principal_get_realm(context, client);
+
+ memset (&creds, 0, sizeof(creds));
+ creds.client = client;
+
+ ret = krb5_build_principal(context,
+ &creds.server,
+ strlen(client_realm),
+ client_realm,
+ KRB5_TGS_NAME,
+ client_realm,
+ NULL);
+ if (ret)
+ return ret;
+
+ ret = krb5_get_forwarded_creds (context,
+ auth_context,
+ ccache,
+ flags,
+ hostname,
+ &creds,
+ out_data);
+ return ret;
+}
+
+/*
+ *
+ */
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_get_forwarded_creds (krb5_context context,
+ krb5_auth_context auth_context,
+ krb5_ccache ccache,
+ krb5_flags flags,
+ const char *hostname,
+ krb5_creds *in_creds,
+ krb5_data *out_data)
+{
+ krb5_error_code ret;
+ krb5_creds *out_creds;
+ krb5_addresses addrs, *paddrs;
+ KRB_CRED cred;
+ KrbCredInfo *krb_cred_info;
+ EncKrbCredPart enc_krb_cred_part;
+ size_t len;
+ unsigned char *buf;
+ size_t buf_size;
+ krb5_kdc_flags kdc_flags;
+ krb5_crypto crypto;
+ struct addrinfo *ai;
+ int save_errno;
+ krb5_creds *ticket;
+ char *realm;
+
+ if (in_creds->client && in_creds->client->realm)
+ realm = in_creds->client->realm;
+ else
+ realm = in_creds->server->realm;
+
+ addrs.len = 0;
+ addrs.val = NULL;
+ paddrs = &addrs;
+
+ /*
+ * If tickets are address-less, forward address-less tickets.
+ */
+
+ ret = _krb5_get_krbtgt (context,
+ ccache,
+ realm,
+ &ticket);
+ if(ret == 0) {
+ if (ticket->addresses.len == 0)
+ paddrs = NULL;
+ krb5_free_creds (context, ticket);
+ }
+
+ if (paddrs != NULL) {
+
+ ret = getaddrinfo (hostname, NULL, NULL, &ai);
+ if (ret) {
+ save_errno = errno;
+ krb5_set_error_string(context, "resolving %s: %s",
+ hostname, gai_strerror(ret));
+ return krb5_eai_to_heim_errno(ret, save_errno);
+ }
+
+ ret = add_addrs (context, &addrs, ai);
+ freeaddrinfo (ai);
+ if (ret)
+ return ret;
+ }
+
+ kdc_flags.b = int2KDCOptions(flags);
+
+ ret = krb5_get_kdc_cred (context,
+ ccache,
+ kdc_flags,
+ paddrs,
+ NULL,
+ in_creds,
+ &out_creds);
+ krb5_free_addresses (context, &addrs);
+ if (ret) {
+ return ret;
+ }
+
+ memset (&cred, 0, sizeof(cred));
+ cred.pvno = 5;
+ cred.msg_type = krb_cred;
+ ALLOC_SEQ(&cred.tickets, 1);
+ if (cred.tickets.val == NULL) {
+ ret = ENOMEM;
+ krb5_set_error_string(context, "malloc: out of memory");
+ goto out2;
+ }
+ ret = decode_Ticket(out_creds->ticket.data,
+ out_creds->ticket.length,
+ cred.tickets.val, &len);
+ if (ret)
+ goto out3;
+
+ memset (&enc_krb_cred_part, 0, sizeof(enc_krb_cred_part));
+ ALLOC_SEQ(&enc_krb_cred_part.ticket_info, 1);
+ if (enc_krb_cred_part.ticket_info.val == NULL) {
+ ret = ENOMEM;
+ krb5_set_error_string(context, "malloc: out of memory");
+ goto out4;
+ }
+
+ if (auth_context->flags & KRB5_AUTH_CONTEXT_DO_TIME) {
+ krb5_timestamp sec;
+ int32_t usec;
+
+ krb5_us_timeofday (context, &sec, &usec);
+
+ ALLOC(enc_krb_cred_part.timestamp, 1);
+ if (enc_krb_cred_part.timestamp == NULL) {
+ ret = ENOMEM;
+ krb5_set_error_string(context, "malloc: out of memory");
+ goto out4;
+ }
+ *enc_krb_cred_part.timestamp = sec;
+ ALLOC(enc_krb_cred_part.usec, 1);
+ if (enc_krb_cred_part.usec == NULL) {
+ ret = ENOMEM;
+ krb5_set_error_string(context, "malloc: out of memory");
+ goto out4;
+ }
+ *enc_krb_cred_part.usec = usec;
+ } else {
+ enc_krb_cred_part.timestamp = NULL;
+ enc_krb_cred_part.usec = NULL;
+ }
+
+ if (auth_context->local_address && auth_context->local_port) {
+ krb5_boolean noaddr;
+ krb5_const_realm srealm;
+
+ srealm = krb5_principal_get_realm(context, out_creds->server);
+ krb5_appdefault_boolean(context, NULL, srealm, "no-addresses",
+ paddrs == NULL, &noaddr);
+ if (!noaddr) {
+ ret = krb5_make_addrport (context,
+ &enc_krb_cred_part.s_address,
+ auth_context->local_address,
+ auth_context->local_port);
+ if (ret)
+ goto out4;
+ }
+ }
+
+ if (auth_context->remote_address) {
+ if (auth_context->remote_port) {
+ krb5_boolean noaddr;
+ krb5_const_realm srealm;
+
+ srealm = krb5_principal_get_realm(context, out_creds->server);
+ /* Is this correct, and should we use the paddrs == NULL
+ trick here as well? Having an address-less ticket may
+ indicate that we don't know our own global address, but
+ it does not necessary mean that we don't know the
+ server's. */
+ krb5_appdefault_boolean(context, NULL, srealm, "no-addresses",
+ FALSE, &noaddr);
+ if (!noaddr) {
+ ret = krb5_make_addrport (context,
+ &enc_krb_cred_part.r_address,
+ auth_context->remote_address,
+ auth_context->remote_port);
+ if (ret)
+ goto out4;
+ }
+ } else {
+ ALLOC(enc_krb_cred_part.r_address, 1);
+ if (enc_krb_cred_part.r_address == NULL) {
+ ret = ENOMEM;
+ krb5_set_error_string(context, "malloc: out of memory");
+ goto out4;
+ }
+
+ ret = krb5_copy_address (context, auth_context->remote_address,
+ enc_krb_cred_part.r_address);
+ if (ret)
+ goto out4;
+ }
+ }
+
+ /* fill ticket_info.val[0] */
+
+ enc_krb_cred_part.ticket_info.len = 1;
+
+ krb_cred_info = enc_krb_cred_part.ticket_info.val;
+
+ copy_EncryptionKey (&out_creds->session, &krb_cred_info->key);
+ ALLOC(krb_cred_info->prealm, 1);
+ copy_Realm (&out_creds->client->realm, krb_cred_info->prealm);
+ ALLOC(krb_cred_info->pname, 1);
+ copy_PrincipalName(&out_creds->client->name, krb_cred_info->pname);
+ ALLOC(krb_cred_info->flags, 1);
+ *krb_cred_info->flags = out_creds->flags.b;
+ ALLOC(krb_cred_info->authtime, 1);
+ *krb_cred_info->authtime = out_creds->times.authtime;
+ ALLOC(krb_cred_info->starttime, 1);
+ *krb_cred_info->starttime = out_creds->times.starttime;
+ ALLOC(krb_cred_info->endtime, 1);
+ *krb_cred_info->endtime = out_creds->times.endtime;
+ ALLOC(krb_cred_info->renew_till, 1);
+ *krb_cred_info->renew_till = out_creds->times.renew_till;
+ ALLOC(krb_cred_info->srealm, 1);
+ copy_Realm (&out_creds->server->realm, krb_cred_info->srealm);
+ ALLOC(krb_cred_info->sname, 1);
+ copy_PrincipalName (&out_creds->server->name, krb_cred_info->sname);
+ ALLOC(krb_cred_info->caddr, 1);
+ copy_HostAddresses (&out_creds->addresses, krb_cred_info->caddr);
+
+ krb5_free_creds (context, out_creds);
+
+ /* encode EncKrbCredPart */
+
+ ASN1_MALLOC_ENCODE(EncKrbCredPart, buf, buf_size,
+ &enc_krb_cred_part, &len, ret);
+ free_EncKrbCredPart (&enc_krb_cred_part);
+ if (ret) {
+ free_KRB_CRED(&cred);
+ return ret;
+ }
+ if(buf_size != len)
+ krb5_abortx(context, "internal error in ASN.1 encoder");
+
+ if (auth_context->flags & KRB5_AUTH_CONTEXT_CLEAR_FORWARDED_CRED) {
+ cred.enc_part.etype = ENCTYPE_NULL;
+ cred.enc_part.kvno = NULL;
+ cred.enc_part.cipher.data = buf;
+ cred.enc_part.cipher.length = buf_size;
+ } else {
+ krb5_keyblock *key;
+
+ if (auth_context->local_subkey)
+ key = auth_context->local_subkey;
+ else if (auth_context->remote_subkey)
+ key = auth_context->remote_subkey;
+ else
+ key = auth_context->keyblock;
+
+ ret = krb5_crypto_init(context, key, 0, &crypto);
+ if (ret) {
+ free(buf);
+ free_KRB_CRED(&cred);
+ return ret;
+ }
+ ret = krb5_encrypt_EncryptedData (context,
+ crypto,
+ KRB5_KU_KRB_CRED,
+ buf,
+ len,
+ 0,
+ &cred.enc_part);
+ free(buf);
+ krb5_crypto_destroy(context, crypto);
+ if (ret) {
+ free_KRB_CRED(&cred);
+ return ret;
+ }
+ }
+
+ ASN1_MALLOC_ENCODE(KRB_CRED, buf, buf_size, &cred, &len, ret);
+ free_KRB_CRED (&cred);
+ if (ret)
+ return ret;
+ if(buf_size != len)
+ krb5_abortx(context, "internal error in ASN.1 encoder");
+ out_data->length = len;
+ out_data->data = buf;
+ return 0;
+ out4:
+ free_EncKrbCredPart(&enc_krb_cred_part);
+ out3:
+ free_KRB_CRED(&cred);
+ out2:
+ krb5_free_creds (context, out_creds);
+ return ret;
+}
diff --git a/source4/heimdal/lib/krb5/get_host_realm.c b/source4/heimdal/lib/krb5/get_host_realm.c
new file mode 100644
index 0000000000..d9c5bd5dc1
--- /dev/null
+++ b/source4/heimdal/lib/krb5/get_host_realm.c
@@ -0,0 +1,220 @@
+/*
+ * Copyright (c) 1997 - 2005 Kungliga Tekniska Högskolan
+ * (Royal Institute of Technology, Stockholm, Sweden).
+ * 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 <resolve.h>
+
+RCSID("$Id: get_host_realm.c,v 1.34 2005/04/19 18:52:51 lha Exp $");
+
+/* To automagically find the correct realm of a host (without
+ * [domain_realm] in krb5.conf) add a text record for your domain with
+ * the name of your realm, like this:
+ *
+ * _kerberos IN TXT "FOO.SE"
+ *
+ * The search is recursive, so you can add entries for specific
+ * hosts. To find the realm of host a.b.c, it first tries
+ * _kerberos.a.b.c, then _kerberos.b.c and so on.
+ *
+ * This method is described in draft-ietf-cat-krb-dns-locate-03.txt.
+ *
+ */
+
+static int
+copy_txt_to_realms (struct resource_record *head,
+ krb5_realm **realms)
+{
+ struct resource_record *rr;
+ int n, i;
+
+ for(n = 0, rr = head; rr; rr = rr->next)
+ if (rr->type == T_TXT)
+ ++n;
+
+ if (n == 0)
+ return -1;
+
+ *realms = malloc ((n + 1) * sizeof(krb5_realm));
+ if (*realms == NULL)
+ return -1;
+
+ for (i = 0; i < n + 1; ++i)
+ (*realms)[i] = NULL;
+
+ for (i = 0, rr = head; rr; rr = rr->next) {
+ if (rr->type == T_TXT) {
+ char *tmp;
+
+ tmp = strdup(rr->u.txt);
+ if (tmp == NULL) {
+ for (i = 0; i < n; ++i)
+ free ((*realms)[i]);
+ free (*realms);
+ return -1;
+ }
+ (*realms)[i] = tmp;
+ ++i;
+ }
+ }
+ return 0;
+}
+
+static int
+dns_find_realm(krb5_context context,
+ const char *domain,
+ krb5_realm **realms)
+{
+ static char *default_labels[] = { "_kerberos", NULL };
+ char dom[MAXHOSTNAMELEN];
+ struct dns_reply *r;
+ char **labels;
+ int i, ret;
+
+ labels = krb5_config_get_strings(context, NULL, "libdefaults",
+ "dns_lookup_realm_labels", NULL);
+ if(labels == NULL)
+ labels = default_labels;
+ if(*domain == '.')
+ domain++;
+ for (i = 0; labels[i] != NULL; i++) {
+ ret = snprintf(dom, sizeof(dom), "%s.%s.", labels[i], domain);
+ if(ret < 0 || ret >= sizeof(dom))
+ return -1;
+ r = dns_lookup(dom, "TXT");
+ if(r != NULL) {
+ ret = copy_txt_to_realms (r->head, realms);
+ dns_free_data(r);
+ if(ret == 0)
+ return 0;
+ }
+ }
+ return -1;
+}
+
+/*
+ * Try to figure out what realms host in `domain' belong to from the
+ * configuration file.
+ */
+
+static int
+config_find_realm(krb5_context context,
+ const char *domain,
+ krb5_realm **realms)
+{
+ char **tmp = krb5_config_get_strings (context, NULL,
+ "domain_realm",
+ domain,
+ NULL);
+
+ if (tmp == NULL)
+ return -1;
+ *realms = tmp;
+ return 0;
+}
+
+/*
+ * This function assumes that `host' is a FQDN (and doesn't handle the
+ * special case of host == NULL either).
+ * Try to find mapping in the config file or DNS and it that fails,
+ * fall back to guessing
+ */
+
+krb5_error_code KRB5_LIB_FUNCTION
+_krb5_get_host_realm_int (krb5_context context,
+ const char *host,
+ krb5_boolean use_dns,
+ krb5_realm **realms)
+{
+ const char *p, *q;
+ krb5_boolean dns_locate_enable;
+
+ dns_locate_enable = krb5_config_get_bool_default(context, NULL, TRUE,
+ "libdefaults", "dns_lookup_realm", NULL);
+ for (p = host; p != NULL; p = strchr (p + 1, '.')) {
+ if(config_find_realm(context, p, realms) == 0) {
+ if(strcasecmp(*realms[0], "dns_locate") == 0) {
+ if(use_dns)
+ for (q = host; q != NULL; q = strchr(q + 1, '.'))
+ if(dns_find_realm(context, q, realms) == 0)
+ return 0;
+ continue;
+ } else
+ return 0;
+ }
+ else if(use_dns && dns_locate_enable) {
+ if(dns_find_realm(context, p, realms) == 0)
+ return 0;
+ }
+ }
+ p = strchr(host, '.');
+ if(p != NULL) {
+ p++;
+ *realms = malloc(2 * sizeof(krb5_realm));
+ if (*realms == NULL) {
+ krb5_set_error_string(context, "malloc: out of memory");
+ return ENOMEM;
+ }
+
+ (*realms)[0] = strdup(p);
+ if((*realms)[0] == NULL) {
+ free(*realms);
+ krb5_set_error_string(context, "malloc: out of memory");
+ return ENOMEM;
+ }
+ strupr((*realms)[0]);
+ (*realms)[1] = NULL;
+ return 0;
+ }
+ krb5_set_error_string(context, "unable to find realm of host %s", host);
+ return KRB5_ERR_HOST_REALM_UNKNOWN;
+}
+
+/*
+ * Return the realm(s) of `host' as a NULL-terminated list in `realms'.
+ */
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_get_host_realm(krb5_context context,
+ const char *host,
+ krb5_realm **realms)
+{
+ char hostname[MAXHOSTNAMELEN];
+
+ if (host == NULL) {
+ if (gethostname (hostname, sizeof(hostname)))
+ return errno;
+ host = hostname;
+ }
+
+ return _krb5_get_host_realm_int (context, host, 1, realms);
+}
diff --git a/source4/heimdal/lib/krb5/get_in_tkt.c b/source4/heimdal/lib/krb5/get_in_tkt.c
new file mode 100644
index 0000000000..24d6c29f52
--- /dev/null
+++ b/source4/heimdal/lib/krb5/get_in_tkt.c
@@ -0,0 +1,823 @@
+/*
+ * Copyright (c) 1997 - 2002 Kungliga Tekniska Högskolan
+ * (Royal Institute of Technology, Stockholm, Sweden).
+ * 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"
+
+RCSID("$Id: get_in_tkt.c,v 1.116 2005/06/15 02:53:20 lha Exp $");
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_init_etype (krb5_context context,
+ unsigned *len,
+ krb5_enctype **val,
+ const krb5_enctype *etypes)
+{
+ 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_string(context, "malloc: out of memory");
+ goto cleanup;
+ }
+ memmove (*val,
+ etypes,
+ i * sizeof(*tmp));
+cleanup:
+ if (tmp != NULL)
+ free (tmp);
+ return ret;
+}
+
+
+static krb5_error_code
+decrypt_tkt (krb5_context context,
+ krb5_keyblock *key,
+ krb5_key_usage usage,
+ krb5_const_pointer decrypt_arg,
+ krb5_kdc_rep *dec_rep)
+{
+ krb5_error_code ret;
+ krb5_data data;
+ size_t size;
+ krb5_crypto crypto;
+
+ ret = krb5_crypto_init(context, key, 0, &crypto);
+ if (ret)
+ return ret;
+
+ ret = krb5_decrypt_EncryptedData (context,
+ crypto,
+ usage,
+ &dec_rep->kdc_rep.enc_part,
+ &data);
+ krb5_crypto_destroy(context, crypto);
+
+ if (ret)
+ return ret;
+
+ ret = krb5_decode_EncASRepPart(context,
+ data.data,
+ data.length,
+ &dec_rep->enc_part,
+ &size);
+ if (ret)
+ ret = krb5_decode_EncTGSRepPart(context,
+ data.data,
+ data.length,
+ &dec_rep->enc_part,
+ &size);
+ krb5_data_free (&data);
+ if (ret)
+ return ret;
+ return 0;
+}
+
+int
+_krb5_extract_ticket(krb5_context context,
+ krb5_kdc_rep *rep,
+ krb5_creds *creds,
+ krb5_keyblock *key,
+ krb5_const_pointer keyseed,
+ krb5_key_usage key_usage,
+ krb5_addresses *addrs,
+ unsigned nonce,
+ krb5_boolean allow_server_mismatch,
+ krb5_boolean ignore_cname,
+ krb5_decrypt_proc decrypt_proc,
+ krb5_const_pointer decryptarg)
+{
+ krb5_error_code ret;
+ krb5_principal tmp_principal;
+ int tmp;
+ size_t len;
+ time_t tmp_time;
+ krb5_timestamp sec_now;
+
+ ret = _krb5_principalname2krb5_principal (&tmp_principal,
+ rep->kdc_rep.cname,
+ rep->kdc_rep.crealm);
+ if (ret)
+ goto out;
+
+ /* compare client */
+
+ if (!ignore_cname) {
+ tmp = krb5_principal_compare (context, tmp_principal, creds->client);
+ if (!tmp) {
+ krb5_free_principal (context, tmp_principal);
+ krb5_clear_error_string (context);
+ ret = KRB5KRB_AP_ERR_MODIFIED;
+ goto out;
+ }
+ }
+
+ krb5_free_principal (context, creds->client);
+ creds->client = tmp_principal;
+
+ /* extract ticket */
+ ASN1_MALLOC_ENCODE(Ticket, creds->ticket.data, creds->ticket.length,
+ &rep->kdc_rep.ticket, &len, ret);
+ if(ret)
+ goto out;
+ if (creds->ticket.length != len)
+ krb5_abortx(context, "internal error in ASN.1 encoder");
+ creds->second_ticket.length = 0;
+ creds->second_ticket.data = NULL;
+
+ /* compare server */
+
+ ret = _krb5_principalname2krb5_principal (&tmp_principal,
+ rep->kdc_rep.ticket.sname,
+ rep->kdc_rep.ticket.realm);
+ if (ret)
+ goto out;
+ if(allow_server_mismatch){
+ krb5_free_principal(context, creds->server);
+ creds->server = tmp_principal;
+ tmp_principal = NULL;
+ }else{
+ tmp = krb5_principal_compare (context, tmp_principal, creds->server);
+ krb5_free_principal (context, tmp_principal);
+ if (!tmp) {
+ ret = KRB5KRB_AP_ERR_MODIFIED;
+ krb5_clear_error_string (context);
+ goto out;
+ }
+ }
+
+ /* decrypt */
+
+ if (decrypt_proc == NULL)
+ decrypt_proc = decrypt_tkt;
+
+ ret = (*decrypt_proc)(context, key, key_usage, decryptarg, rep);
+ if (ret)
+ goto out;
+
+#if 0
+ /* XXX should this decode be here, or in the decrypt_proc? */
+ ret = krb5_decode_keyblock(context, &rep->enc_part.key, 1);
+ if(ret)
+ goto out;
+#endif
+
+ /* compare nonces */
+
+ if (nonce != rep->enc_part.nonce) {
+ ret = KRB5KRB_AP_ERR_MODIFIED;
+ krb5_set_error_string(context, "malloc: out of memory");
+ goto out;
+ }
+
+ /* set kdc-offset */
+
+ krb5_timeofday (context, &sec_now);
+ if (rep->enc_part.flags.initial
+ && context->kdc_sec_offset == 0
+ && krb5_config_get_bool (context, NULL,
+ "libdefaults",
+ "kdc_timesync",
+ NULL)) {
+ context->kdc_sec_offset = rep->enc_part.authtime - sec_now;
+ krb5_timeofday (context, &sec_now);
+ }
+
+ /* check all times */
+
+ if (rep->enc_part.starttime) {
+ tmp_time = *rep->enc_part.starttime;
+ } else
+ tmp_time = rep->enc_part.authtime;
+
+ if (creds->times.starttime == 0
+ && abs(tmp_time - sec_now) > context->max_skew) {
+ ret = KRB5KRB_AP_ERR_SKEW;
+ krb5_set_error_string (context,
+ "time skew (%d) larger than max (%d)",
+ abs(tmp_time - sec_now),
+ (int)context->max_skew);
+ goto out;
+ }
+
+ if (creds->times.starttime != 0
+ && tmp_time != creds->times.starttime) {
+ krb5_clear_error_string (context);
+ ret = KRB5KRB_AP_ERR_MODIFIED;
+ goto out;
+ }
+
+ creds->times.starttime = tmp_time;
+
+ if (rep->enc_part.renew_till) {
+ tmp_time = *rep->enc_part.renew_till;
+ } else
+ tmp_time = 0;
+
+ if (creds->times.renew_till != 0
+ && tmp_time > creds->times.renew_till) {
+ krb5_clear_error_string (context);
+ ret = KRB5KRB_AP_ERR_MODIFIED;
+ goto out;
+ }
+
+ creds->times.renew_till = tmp_time;
+
+ creds->times.authtime = rep->enc_part.authtime;
+
+ if (creds->times.endtime != 0
+ && rep->enc_part.endtime > creds->times.endtime) {
+ krb5_clear_error_string (context);
+ ret = KRB5KRB_AP_ERR_MODIFIED;
+ goto out;
+ }
+
+ creds->times.endtime = rep->enc_part.endtime;
+
+ if(rep->enc_part.caddr)
+ krb5_copy_addresses (context, rep->enc_part.caddr, &creds->addresses);
+ else if(addrs)
+ krb5_copy_addresses (context, addrs, &creds->addresses);
+ else {
+ creds->addresses.len = 0;
+ creds->addresses.val = NULL;
+ }
+ creds->flags.b = rep->enc_part.flags;
+
+ creds->authdata.len = 0;
+ creds->authdata.val = NULL;
+ creds->session.keyvalue.length = 0;
+ creds->session.keyvalue.data = NULL;
+ creds->session.keytype = rep->enc_part.key.keytype;
+ ret = krb5_data_copy (&creds->session.keyvalue,
+ rep->enc_part.key.keyvalue.data,
+ rep->enc_part.key.keyvalue.length);
+
+out:
+ memset (rep->enc_part.key.keyvalue.data, 0,
+ rep->enc_part.key.keyvalue.length);
+ return ret;
+}
+
+
+static krb5_error_code
+make_pa_enc_timestamp(krb5_context context, PA_DATA *pa,
+ krb5_enctype etype, krb5_keyblock *key)
+{
+ PA_ENC_TS_ENC p;
+ unsigned char *buf;
+ size_t buf_size;
+ size_t len;
+ EncryptedData encdata;
+ krb5_error_code ret;
+ int32_t usec;
+ int usec2;
+ krb5_crypto crypto;
+
+ krb5_us_timeofday (context, &p.patimestamp, &usec);
+ usec2 = usec;
+ p.pausec = &usec2;
+
+ ASN1_MALLOC_ENCODE(PA_ENC_TS_ENC, buf, buf_size, &p, &len, ret);
+ if (ret)
+ return ret;
+ if(buf_size != len)
+ krb5_abortx(context, "internal error in ASN.1 encoder");
+ ret = krb5_crypto_init(context, key, 0, &crypto);
+ if (ret) {
+ free(buf);
+ return ret;
+ }
+ ret = krb5_encrypt_EncryptedData(context,
+ crypto,
+ KRB5_KU_PA_ENC_TIMESTAMP,
+ buf,
+ len,
+ 0,
+ &encdata);
+ free(buf);
+ krb5_crypto_destroy(context, crypto);
+ if (ret)
+ return ret;
+
+ ASN1_MALLOC_ENCODE(EncryptedData, buf, buf_size, &encdata, &len, ret);
+ free_EncryptedData(&encdata);
+ if (ret)
+ return ret;
+ if(buf_size != len)
+ krb5_abortx(context, "internal error in ASN.1 encoder");
+ pa->padata_type = KRB5_PADATA_ENC_TIMESTAMP;
+ pa->padata_value.length = len;
+ pa->padata_value.data = buf;
+ return 0;
+}
+
+static krb5_error_code
+add_padata(krb5_context context,
+ METHOD_DATA *md,
+ krb5_principal client,
+ krb5_key_proc key_proc,
+ krb5_const_pointer keyseed,
+ krb5_enctype *enctypes,
+ unsigned netypes,
+ krb5_salt *salt)
+{
+ krb5_error_code ret;
+ PA_DATA *pa2;
+ krb5_salt salt2;
+ krb5_enctype *ep;
+ int i;
+
+ if(salt == NULL) {
+ /* default to standard salt */
+ ret = krb5_get_pw_salt (context, client, &salt2);
+ salt = &salt2;
+ }
+ if (!enctypes) {
+ enctypes = context->etypes;
+ netypes = 0;
+ for (ep = enctypes; *ep != ETYPE_NULL; ep++)
+ netypes++;
+ }
+ pa2 = realloc (md->val, (md->len + netypes) * sizeof(*md->val));
+ if (pa2 == NULL) {
+ krb5_set_error_string(context, "malloc: out of memory");
+ return ENOMEM;
+ }
+ md->val = pa2;
+
+ for (i = 0; i < netypes; ++i) {
+ krb5_keyblock *key;
+
+ ret = (*key_proc)(context, enctypes[i], *salt, keyseed, &key);
+ if (ret)
+ continue;
+ ret = make_pa_enc_timestamp (context, &md->val[md->len],
+ enctypes[i], key);
+ krb5_free_keyblock (context, key);
+ if (ret)
+ return ret;
+ ++md->len;
+ }
+ if(salt == &salt2)
+ krb5_free_salt(context, salt2);
+ return 0;
+}
+
+static krb5_error_code
+init_as_req (krb5_context context,
+ krb5_kdc_flags opts,
+ krb5_creds *creds,
+ const krb5_addresses *addrs,
+ const krb5_enctype *etypes,
+ const krb5_preauthtype *ptypes,
+ const krb5_preauthdata *preauth,
+ krb5_key_proc key_proc,
+ krb5_const_pointer keyseed,
+ unsigned nonce,
+ AS_REQ *a)
+{
+ krb5_error_code ret;
+ krb5_salt salt;
+
+ memset(a, 0, sizeof(*a));
+
+ a->pvno = 5;
+ a->msg_type = krb_as_req;
+ a->req_body.kdc_options = opts.b;
+ a->req_body.cname = malloc(sizeof(*a->req_body.cname));
+ if (a->req_body.cname == NULL) {
+ ret = ENOMEM;
+ krb5_set_error_string(context, "malloc: out of memory");
+ goto fail;
+ }
+ a->req_body.sname = malloc(sizeof(*a->req_body.sname));
+ if (a->req_body.sname == NULL) {
+ ret = ENOMEM;
+ krb5_set_error_string(context, "malloc: out of memory");
+ goto fail;
+ }
+ ret = _krb5_principal2principalname (a->req_body.cname, creds->client);
+ if (ret)
+ goto fail;
+ ret = _krb5_principal2principalname (a->req_body.sname, creds->server);
+ if (ret)
+ goto fail;
+ ret = copy_Realm(&creds->client->realm, &a->req_body.realm);
+ if (ret)
+ goto fail;
+
+ if(creds->times.starttime) {
+ a->req_body.from = malloc(sizeof(*a->req_body.from));
+ if (a->req_body.from == NULL) {
+ ret = ENOMEM;
+ krb5_set_error_string(context, "malloc: out of memory");
+ goto fail;
+ }
+ *a->req_body.from = creds->times.starttime;
+ }
+ if(creds->times.endtime){
+ ALLOC(a->req_body.till, 1);
+ *a->req_body.till = creds->times.endtime;
+ }
+ if(creds->times.renew_till){
+ a->req_body.rtime = malloc(sizeof(*a->req_body.rtime));
+ if (a->req_body.rtime == NULL) {
+ ret = ENOMEM;
+ krb5_set_error_string(context, "malloc: out of memory");
+ goto fail;
+ }
+ *a->req_body.rtime = creds->times.renew_till;
+ }
+ a->req_body.nonce = nonce;
+ ret = krb5_init_etype (context,
+ &a->req_body.etype.len,
+ &a->req_body.etype.val,
+ etypes);
+ if (ret)
+ goto fail;
+
+ /*
+ * This means no addresses
+ */
+
+ if (addrs && addrs->len == 0) {
+ a->req_body.addresses = NULL;
+ } else {
+ a->req_body.addresses = malloc(sizeof(*a->req_body.addresses));
+ if (a->req_body.addresses == NULL) {
+ ret = ENOMEM;
+ krb5_set_error_string(context, "malloc: out of memory");
+ goto fail;
+ }
+
+ if (addrs)
+ ret = krb5_copy_addresses(context, addrs, a->req_body.addresses);
+ else {
+ ret = krb5_get_all_client_addrs (context, a->req_body.addresses);
+ if(ret == 0 && a->req_body.addresses->len == 0) {
+ free(a->req_body.addresses);
+ a->req_body.addresses = NULL;
+ }
+ }
+ if (ret)
+ return ret;
+ }
+
+ a->req_body.enc_authorization_data = NULL;
+ a->req_body.additional_tickets = NULL;
+
+ if(preauth != NULL) {
+ int i;
+ ALLOC(a->padata, 1);
+ if(a->padata == NULL) {
+ ret = ENOMEM;
+ krb5_set_error_string(context, "malloc: out of memory");
+ goto fail;
+ }
+ a->padata->val = NULL;
+ a->padata->len = 0;
+ for(i = 0; i < preauth->len; i++) {
+ if(preauth->val[i].type == KRB5_PADATA_ENC_TIMESTAMP){
+ int j;
+
+ for(j = 0; j < preauth->val[i].info.len; j++) {
+ krb5_salt *sp = &salt;
+ if(preauth->val[i].info.val[j].salttype)
+ salt.salttype = *preauth->val[i].info.val[j].salttype;
+ else
+ salt.salttype = KRB5_PW_SALT;
+ if(preauth->val[i].info.val[j].salt)
+ salt.saltvalue = *preauth->val[i].info.val[j].salt;
+ else
+ if(salt.salttype == KRB5_PW_SALT)
+ sp = NULL;
+ else
+ krb5_data_zero(&salt.saltvalue);
+ ret = add_padata(context, a->padata, creds->client,
+ key_proc, keyseed,
+ &preauth->val[i].info.val[j].etype, 1,
+ sp);
+ if (ret == 0)
+ break;
+ }
+ }
+ }
+ } else
+ /* not sure this is the way to use `ptypes' */
+ if (ptypes == NULL || *ptypes == KRB5_PADATA_NONE)
+ a->padata = NULL;
+ else if (*ptypes == KRB5_PADATA_ENC_TIMESTAMP) {
+ ALLOC(a->padata, 1);
+ if (a->padata == NULL) {
+ ret = ENOMEM;
+ krb5_set_error_string(context, "malloc: out of memory");
+ goto fail;
+ }
+ a->padata->len = 0;
+ a->padata->val = NULL;
+
+ /* make a v5 salted pa-data */
+ add_padata(context, a->padata, creds->client,
+ key_proc, keyseed, a->req_body.etype.val,
+ a->req_body.etype.len, NULL);
+
+ /* make a v4 salted pa-data */
+ salt.salttype = KRB5_PW_SALT;
+ krb5_data_zero(&salt.saltvalue);
+ add_padata(context, a->padata, creds->client,
+ key_proc, keyseed, a->req_body.etype.val,
+ a->req_body.etype.len, &salt);
+ } else {
+ krb5_set_error_string (context, "pre-auth type %d not supported",
+ *ptypes);
+ ret = KRB5_PREAUTH_BAD_TYPE;
+ goto fail;
+ }
+ return 0;
+fail:
+ free_AS_REQ(a);
+ return ret;
+}
+
+static int
+set_ptypes(krb5_context context,
+ KRB_ERROR *error,
+ const krb5_preauthtype **ptypes,
+ krb5_preauthdata **preauth)
+{
+ static krb5_preauthdata preauth2;
+ static krb5_preauthtype ptypes2[] = { KRB5_PADATA_ENC_TIMESTAMP, KRB5_PADATA_NONE };
+
+ if(error->e_data) {
+ METHOD_DATA md;
+ int i;
+ decode_METHOD_DATA(error->e_data->data,
+ error->e_data->length,
+ &md,
+ NULL);
+ for(i = 0; i < md.len; i++){
+ switch(md.val[i].padata_type){
+ case KRB5_PADATA_ENC_TIMESTAMP:
+ *ptypes = ptypes2;
+ break;
+ case KRB5_PADATA_ETYPE_INFO:
+ *preauth = &preauth2;
+ ALLOC_SEQ(*preauth, 1);
+ (*preauth)->val[0].type = KRB5_PADATA_ENC_TIMESTAMP;
+ krb5_decode_ETYPE_INFO(context,
+ md.val[i].padata_value.data,
+ md.val[i].padata_value.length,
+ &(*preauth)->val[0].info,
+ NULL);
+ break;
+ default:
+ break;
+ }
+ }
+ free_METHOD_DATA(&md);
+ } else {
+ *ptypes = ptypes2;
+ }
+ return(1);
+}
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_get_in_cred(krb5_context context,
+ krb5_flags options,
+ const krb5_addresses *addrs,
+ const krb5_enctype *etypes,
+ const krb5_preauthtype *ptypes,
+ const krb5_preauthdata *preauth,
+ krb5_key_proc key_proc,
+ krb5_const_pointer keyseed,
+ krb5_decrypt_proc decrypt_proc,
+ krb5_const_pointer decryptarg,
+ krb5_creds *creds,
+ krb5_kdc_rep *ret_as_reply)
+{
+ krb5_error_code ret;
+ AS_REQ a;
+ krb5_kdc_rep rep;
+ krb5_data req, resp;
+ size_t len;
+ krb5_salt salt;
+ krb5_keyblock *key;
+ size_t size;
+ krb5_kdc_flags opts;
+ PA_DATA *pa;
+ krb5_enctype etype;
+ krb5_preauthdata *my_preauth = NULL;
+ unsigned nonce;
+ int done;
+
+ opts.i = options;
+
+ krb5_generate_random_block (&nonce, sizeof(nonce));
+ nonce &= 0xffffffff;
+
+ do {
+ done = 1;
+ ret = init_as_req (context,
+ opts,
+ creds,
+ addrs,
+ etypes,
+ ptypes,
+ preauth,
+ key_proc,
+ keyseed,
+ nonce,
+ &a);
+ if (my_preauth) {
+ free_ETYPE_INFO(&my_preauth->val[0].info);
+ free (my_preauth->val);
+ my_preauth = NULL;
+ }
+ if (ret)
+ return ret;
+
+ ASN1_MALLOC_ENCODE(AS_REQ, req.data, req.length, &a, &len, ret);
+ free_AS_REQ(&a);
+ if (ret)
+ return ret;
+ if(len != req.length)
+ krb5_abortx(context, "internal error in ASN.1 encoder");
+
+ ret = krb5_sendto_kdc (context, &req, &creds->client->realm, &resp);
+ krb5_data_free(&req);
+ if (ret)
+ return ret;
+
+ memset (&rep, 0, sizeof(rep));
+ ret = decode_AS_REP(resp.data, resp.length, &rep.kdc_rep, &size);
+ if(ret) {
+ /* let's try to parse it as a KRB-ERROR */
+ KRB_ERROR error;
+ int ret2;
+
+ ret2 = krb5_rd_error(context, &resp, &error);
+ if(ret2 && resp.data && ((char*)resp.data)[0] == 4)
+ ret = KRB5KRB_AP_ERR_V4_REPLY;
+ krb5_data_free(&resp);
+ if (ret2 == 0) {
+ ret = krb5_error_from_rd_error(context, &error, creds);
+ /* if no preauth was set and KDC requires it, give it
+ one more try */
+ if (!ptypes && !preauth
+ && ret == KRB5KDC_ERR_PREAUTH_REQUIRED
+#if 0
+ || ret == KRB5KDC_ERR_BADOPTION
+#endif
+ && set_ptypes(context, &error, &ptypes, &my_preauth)) {
+ done = 0;
+ preauth = my_preauth;
+ krb5_free_error_contents(context, &error);
+ krb5_clear_error_string(context);
+ continue;
+ }
+ if(ret_as_reply)
+ ret_as_reply->error = error;
+ else
+ free_KRB_ERROR (&error);
+ return ret;
+ }
+ return ret;
+ }
+ krb5_data_free(&resp);
+ } while(!done);
+
+ pa = NULL;
+ etype = rep.kdc_rep.enc_part.etype;
+ if(rep.kdc_rep.padata){
+ int i = 0;
+ pa = krb5_find_padata(rep.kdc_rep.padata->val, rep.kdc_rep.padata->len,
+ KRB5_PADATA_PW_SALT, &i);
+ if(pa == NULL) {
+ i = 0;
+ pa = krb5_find_padata(rep.kdc_rep.padata->val,
+ rep.kdc_rep.padata->len,
+ KRB5_PADATA_AFS3_SALT, &i);
+ }
+ }
+ if(pa) {
+ salt.salttype = pa->padata_type;
+ salt.saltvalue = pa->padata_value;
+
+ ret = (*key_proc)(context, etype, salt, keyseed, &key);
+ } else {
+ /* make a v5 salted pa-data */
+ ret = krb5_get_pw_salt (context, creds->client, &salt);
+
+ if (ret)
+ goto out;
+ ret = (*key_proc)(context, etype, salt, keyseed, &key);
+ krb5_free_salt(context, salt);
+ }
+ if (ret)
+ goto out;
+
+ ret = _krb5_extract_ticket(context,
+ &rep,
+ creds,
+ key,
+ keyseed,
+ KRB5_KU_AS_REP_ENC_PART,
+ NULL,
+ nonce,
+ FALSE,
+ opts.b.request_anonymous,
+ decrypt_proc,
+ decryptarg);
+ memset (key->keyvalue.data, 0, key->keyvalue.length);
+ krb5_free_keyblock_contents (context, key);
+ free (key);
+
+out:
+ if (ret == 0 && ret_as_reply)
+ *ret_as_reply = rep;
+ else
+ krb5_free_kdc_rep (context, &rep);
+ return ret;
+}
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_get_in_tkt(krb5_context context,
+ krb5_flags options,
+ const krb5_addresses *addrs,
+ const krb5_enctype *etypes,
+ const krb5_preauthtype *ptypes,
+ krb5_key_proc key_proc,
+ krb5_const_pointer keyseed,
+ krb5_decrypt_proc decrypt_proc,
+ krb5_const_pointer decryptarg,
+ krb5_creds *creds,
+ krb5_ccache ccache,
+ krb5_kdc_rep *ret_as_reply)
+{
+ krb5_error_code ret;
+ krb5_kdc_flags opts;
+ opts.i = 0;
+ opts.b = int2KDCOptions(options);
+
+ ret = krb5_get_in_cred (context,
+ opts.i,
+ addrs,
+ etypes,
+ ptypes,
+ NULL,
+ key_proc,
+ keyseed,
+ decrypt_proc,
+ decryptarg,
+ creds,
+ ret_as_reply);
+ if(ret)
+ return ret;
+ if (ccache)
+ ret = krb5_cc_store_cred (context, ccache, creds);
+ return ret;
+}
diff --git a/source4/heimdal/lib/krb5/get_in_tkt_with_keytab.c b/source4/heimdal/lib/krb5/get_in_tkt_with_keytab.c
new file mode 100644
index 0000000000..69da6c5ea7
--- /dev/null
+++ b/source4/heimdal/lib/krb5/get_in_tkt_with_keytab.c
@@ -0,0 +1,99 @@
+/*
+ * Copyright (c) 1997 - 2001 Kungliga Tekniska Högskolan
+ * (Royal Institute of Technology, Stockholm, Sweden).
+ * 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"
+
+RCSID("$Id: get_in_tkt_with_keytab.c,v 1.9 2005/06/17 04:56:44 lha Exp $");
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_keytab_key_proc (krb5_context context,
+ krb5_enctype enctype,
+ krb5_salt salt,
+ krb5_const_pointer keyseed,
+ krb5_keyblock **key)
+{
+ krb5_keytab_key_proc_args *args = rk_UNCONST(keyseed);
+ krb5_keytab keytab = args->keytab;
+ krb5_principal principal = args->principal;
+ krb5_error_code ret;
+ krb5_keytab real_keytab;
+ krb5_keytab_entry entry;
+
+ if(keytab == NULL)
+ krb5_kt_default(context, &real_keytab);
+ else
+ real_keytab = keytab;
+
+ ret = krb5_kt_get_entry (context, real_keytab, principal,
+ 0, enctype, &entry);
+
+ if (keytab == NULL)
+ krb5_kt_close (context, real_keytab);
+
+ if (ret)
+ return ret;
+
+ ret = krb5_copy_keyblock (context, &entry.keyblock, key);
+ krb5_kt_free_entry(context, &entry);
+ return ret;
+}
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_get_in_tkt_with_keytab (krb5_context context,
+ krb5_flags options,
+ krb5_addresses *addrs,
+ const krb5_enctype *etypes,
+ const krb5_preauthtype *pre_auth_types,
+ krb5_keytab keytab,
+ krb5_ccache ccache,
+ krb5_creds *creds,
+ krb5_kdc_rep *ret_as_reply)
+{
+ krb5_keytab_key_proc_args a;
+
+ a.principal = creds->client;
+ a.keytab = keytab;
+
+ return krb5_get_in_tkt (context,
+ options,
+ addrs,
+ etypes,
+ pre_auth_types,
+ krb5_keytab_key_proc,
+ &a,
+ NULL,
+ NULL,
+ creds,
+ ccache,
+ ret_as_reply);
+}
diff --git a/source4/heimdal/lib/krb5/get_port.c b/source4/heimdal/lib/krb5/get_port.c
new file mode 100644
index 0000000000..ba76466e06
--- /dev/null
+++ b/source4/heimdal/lib/krb5/get_port.c
@@ -0,0 +1,54 @@
+/*
+ * Copyright (c) 1997-2001 Kungliga Tekniska Högskolan
+ * (Royal Institute of Technology, Stockholm, Sweden).
+ * 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>
+
+RCSID("$Id: get_port.c,v 1.9 2004/05/25 21:29:59 lha Exp $");
+
+int KRB5_LIB_FUNCTION
+krb5_getportbyname (krb5_context context,
+ const char *service,
+ const char *proto,
+ int default_port)
+{
+ struct servent *sp;
+
+ if ((sp = roken_getservbyname (service, proto)) == NULL) {
+#if 0
+ krb5_warnx(context, "%s/%s unknown service, using default port %d",
+ service, proto, default_port);
+#endif
+ return htons(default_port);
+ } else
+ return sp->s_port;
+}
diff --git a/source4/heimdal/lib/krb5/heim_err.et b/source4/heimdal/lib/krb5/heim_err.et
new file mode 100644
index 0000000000..3c4f06edb1
--- /dev/null
+++ b/source4/heimdal/lib/krb5/heim_err.et
@@ -0,0 +1,44 @@
+#
+# Error messages for the krb5 library
+#
+# This might look like a com_err file, but is not
+#
+id "$Id: heim_err.et,v 1.13 2004/02/13 16:23:40 lha Exp $"
+
+error_table heim
+
+prefix HEIM_ERR
+
+error_code LOG_PARSE, "Error parsing log destination"
+error_code V4_PRINC_NO_CONV, "Failed to convert v4 principal"
+error_code SALTTYPE_NOSUPP, "Salt type is not supported by enctype"
+error_code NOHOST, "Host not found"
+error_code OPNOTSUPP, "Operation not supported"
+error_code EOF, "End of file"
+error_code BAD_MKEY, "Failed to get the master key"
+error_code SERVICE_NOMATCH, "Unacceptable service used"
+
+index 64
+prefix HEIM_PKINIT
+error_code NO_CERTIFICATE, "Certificate missing"
+error_code NO_PRIVATE_KEY, "Private key missing"
+error_code NO_VALID_CA, "No valid certificate authority"
+error_code CERTIFICATE_INVALID, "Certificate invalid"
+error_code PRIVATE_KEY_INVALID, "Private key invalid"
+
+index 128
+prefix HEIM_EAI
+#error_code NOERROR, "no error"
+error_code UNKNOWN, "unknown error from getaddrinfo"
+error_code ADDRFAMILY, "address family for nodename not supported"
+error_code AGAIN, "temporary failure in name resolution"
+error_code BADFLAGS, "invalid value for ai_flags"
+error_code FAIL, "non-recoverable failure in name resolution"
+error_code FAMILY, "ai_family not supported"
+error_code MEMORY, "memory allocation failure"
+error_code NODATA, "no address associated with nodename"
+error_code NONAME, "nodename nor servname provided, or not known"
+error_code SERVICE, "servname not supported for ai_socktype"
+error_code SOCKTYPE, "ai_socktype not supported"
+error_code SYSTEM, "system error returned in errno"
+end
diff --git a/source4/heimdal/lib/krb5/heim_threads.h b/source4/heimdal/lib/krb5/heim_threads.h
new file mode 100755
index 0000000000..3ebe66beee
--- /dev/null
+++ b/source4/heimdal/lib/krb5/heim_threads.h
@@ -0,0 +1,175 @@
+/*
+ * Copyright (c) 2003 Kungliga Tekniska Högskolan
+ * (Royal Institute of Technology, Stockholm, Sweden).
+ * 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.
+ */
+
+/* $Id: heim_threads.h,v 1.11 2004/12/18 16:03:38 lha Exp $ */
+
+/*
+ * Provide wrapper macros for thread synchronization primitives so we
+ * can use native thread functions for those operating system that
+ * supports it.
+ *
+ * This is so libkrb5.so (or more importantly, libgssapi.so) can have
+ * thread support while the program that that dlopen(3)s the library
+ * don't need to be linked to libpthread.
+ */
+
+#ifndef HEIM_THREADS_H
+#define HEIM_THREADS_H 1
+
+/* assume headers already included */
+
+#if defined(__NetBSD__) && __NetBSD_Version__ >= 106120000 && __NetBSD_Version__< 299001200 && defined(ENABLE_PTHREAD_SUPPORT)
+
+/*
+ * NetBSD have a thread lib that we can use that part of libc that
+ * works regardless if application are linked to pthreads or not.
+ * NetBSD newer then 2.99.11 just use pthread.h, and the same thing
+ * will happen.
+ */
+#include <threadlib.h>
+
+#define HEIMDAL_MUTEX mutex_t
+#define HEIMDAL_MUTEX_INITIALIZER MUTEX_INITIALIZER
+#define HEIMDAL_MUTEX_init(m) mutex_init(m, NULL)
+#define HEIMDAL_MUTEX_lock(m) mutex_lock(m)
+#define HEIMDAL_MUTEX_unlock(m) mutex_unlock(m)
+#define HEIMDAL_MUTEX_destroy(m) mutex_destroy(m)
+
+#define HEIMDAL_RWLOCK rwlock_t
+#define HEIMDAL_RWLOCK_INITIALIZER RWLOCK_INITIALIZER
+#define HEIMDAL_RWLOCK_init(l) rwlock_init(l, NULL)
+#define HEIMDAL_RWLOCK_rdlock(l) rwlock_rdlock(l)
+#define HEIMDAL_RWLOCK_wrlock(l) rwlock_wrlock(l)
+#define HEIMDAL_RWLOCK_tryrdlock(l) rwlock_tryrdlock(l)
+#define HEIMDAL_RWLOCK_trywrlock(l) rwlock_trywrlock(l)
+#define HEIMDAL_RWLOCK_unlock(l) rwlock_unlock(l)
+#define HEIMDAL_RWLOCK_destroy(l) rwlock_destroy(l)
+
+#define HEIMDAL_thread_key thread_key_t
+#define HEIMDAL_key_create(k,d,r) do { r = thr_keycreate(k,d); } while(0)
+#define HEIMDAL_setspecific(k,s,r) do { r = thr_setspecific(k,s); } while(0)
+#define HEIMDAL_getspecific(k) thr_getspecific(k)
+#define HEIMDAL_key_delete(k) thr_keydelete(k)
+
+#elif defined(ENABLE_PTHREAD_SUPPORT) && (!defined(__NetBSD__) || __NetBSD_Version__ >= 299001200)
+
+#include <pthread.h>
+
+#define HEIMDAL_MUTEX pthread_mutex_t
+#define HEIMDAL_MUTEX_INITIALIZER PTHREAD_MUTEX_INITIALIZER
+#define HEIMDAL_MUTEX_init(m) pthread_mutex_init(m, NULL)
+#define HEIMDAL_MUTEX_lock(m) pthread_mutex_lock(m)
+#define HEIMDAL_MUTEX_unlock(m) pthread_mutex_unlock(m)
+#define HEIMDAL_MUTEX_destroy(m) pthread_mutex_destroy(m)
+
+#define HEIMDAL_RWLOCK rwlock_t
+#define HEIMDAL_RWLOCK_INITIALIZER RWLOCK_INITIALIZER
+#define HEIMDAL_RWLOCK_init(l) pthread_rwlock_init(l, NULL)
+#define HEIMDAL_RWLOCK_rdlock(l) pthread_rwlock_rdlock(l)
+#define HEIMDAL_RWLOCK_wrlock(l) pthread_rwlock_wrlock(l)
+#define HEIMDAL_RWLOCK_tryrdlock(l) pthread_rwlock_tryrdlock(l)
+#define HEIMDAL_RWLOCK_trywrlock(l) pthread_rwlock_trywrlock(l)
+#define HEIMDAL_RWLOCK_unlock(l) pthread_rwlock_unlock(l)
+#define HEIMDAL_RWLOCK_destroy(l) pthread_rwlock_destroy(l)
+
+#define HEIMDAL_thread_key pthread_key_t
+#define HEIMDAL_key_create(k,d,r) do { r = pthread_key_create(k,d); } while(0)
+#define HEIMDAL_setspecific(k,s,r) do { r = pthread_setspecific(k,s); } while(0)
+#define HEIMDAL_getspecific(k) pthread_getspecific(k)
+#define HEIMDAL_key_delete(k) pthread_key_delete(k)
+
+#elif defined(HEIMDAL_DEBUG_THREADS)
+
+/* no threads support, just do consistency checks */
+#include <stdlib.h>
+
+#define HEIMDAL_MUTEX int
+#define HEIMDAL_MUTEX_INITIALIZER 0
+#define HEIMDAL_MUTEX_init(m) do { (*(m)) = 0; } while(0)
+#define HEIMDAL_MUTEX_lock(m) do { if ((*(m))++ != 0) abort(); } while(0)
+#define HEIMDAL_MUTEX_unlock(m) do { if ((*(m))-- != 1) abort(); } while(0)
+#define HEIMDAL_MUTEX_destroy(m) do {if ((*(m)) != 0) abort(); } while(0)
+
+#define HEIMDAL_RWLOCK rwlock_t int
+#define HEIMDAL_RWLOCK_INITIALIZER 0
+#define HEIMDAL_RWLOCK_init(l) do { } while(0)
+#define HEIMDAL_RWLOCK_rdlock(l) do { } while(0)
+#define HEIMDAL_RWLOCK_wrlock(l) do { } while(0)
+#define HEIMDAL_RWLOCK_tryrdlock(l) do { } while(0)
+#define HEIMDAL_RWLOCK_trywrlock(l) do { } while(0)
+#define HEIMDAL_RWLOCK_unlock(l) do { } while(0)
+#define HEIMDAL_RWLOCK_destroy(l) do { } while(0)
+
+#define HEIMDAL_internal_thread_key 1
+
+#else /* no thread support, no debug case */
+
+#define HEIMDAL_MUTEX int
+#define HEIMDAL_MUTEX_INITIALIZER 0
+#define HEIMDAL_MUTEX_init(m) do { (void)(m); } while(0)
+#define HEIMDAL_MUTEX_lock(m) do { (void)(m); } while(0)
+#define HEIMDAL_MUTEX_unlock(m) do { (void)(m); } while(0)
+#define HEIMDAL_MUTEX_destroy(m) do { (void)(m); } while(0)
+
+#define HEIMDAL_RWLOCK rwlock_t int
+#define HEIMDAL_RWLOCK_INITIALIZER 0
+#define HEIMDAL_RWLOCK_init(l) do { } while(0)
+#define HEIMDAL_RWLOCK_rdlock(l) do { } while(0)
+#define HEIMDAL_RWLOCK_wrlock(l) do { } while(0)
+#define HEIMDAL_RWLOCK_tryrdlock(l) do { } while(0)
+#define HEIMDAL_RWLOCK_trywrlock(l) do { } while(0)
+#define HEIMDAL_RWLOCK_unlock(l) do { } while(0)
+#define HEIMDAL_RWLOCK_destroy(l) do { } while(0)
+
+#define HEIMDAL_internal_thread_key 1
+
+#endif /* no thread support */
+
+#ifdef HEIMDAL_internal_thread_key
+
+typedef struct heim_thread_key {
+ void *value;
+ void (*destructor)(void *);
+} heim_thread_key;
+
+#define HEIMDAL_thread_key heim_thread_key
+#define HEIMDAL_key_create(k,d,r) \
+ do { (k)->value = NULL; (k)->destructor = (d); r = 0; } while(0)
+#define HEIMDAL_setspecific(k,s,r) do { (k).value = s ; r = 0; } while(0)
+#define HEIMDAL_getspecific(k) ((k).value)
+#define HEIMDAL_key_delete(k) do { (*(k).destructor)((k).value); } while(0)
+
+#undef HEIMDAL_internal_thread_key
+#endif /* HEIMDAL_internal_thread_key */
+
+#endif /* HEIM_THREADS_H */
diff --git a/source4/heimdal/lib/krb5/init_creds.c b/source4/heimdal/lib/krb5/init_creds.c
new file mode 100644
index 0000000000..95c980d92c
--- /dev/null
+++ b/source4/heimdal/lib/krb5/init_creds.c
@@ -0,0 +1,331 @@
+/*
+ * Copyright (c) 1997 - 2004 Kungliga Tekniska Högskolan
+ * (Royal Institute of Technology, Stockholm, Sweden).
+ * 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"
+
+RCSID("$Id: init_creds.c,v 1.20 2004/11/09 18:50:43 lha Exp $");
+
+void KRB5_LIB_FUNCTION
+krb5_get_init_creds_opt_init(krb5_get_init_creds_opt *opt)
+{
+ memset (opt, 0, sizeof(*opt));
+ opt->flags = 0;
+ opt->private = NULL;
+}
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_get_init_creds_opt_alloc(krb5_context context,
+ krb5_get_init_creds_opt **opt)
+{
+ krb5_get_init_creds_opt *o;
+
+ *opt = NULL;
+ o = calloc(1, sizeof(*o));
+ if (o == NULL) {
+ krb5_set_error_string(context, "out of memory");
+ return ENOMEM;
+ }
+ krb5_get_init_creds_opt_init(o);
+ o->private = calloc(1, sizeof(*o->private));
+ if (o->private == NULL) {
+ krb5_set_error_string(context, "out of memory");
+ free(o);
+ return ENOMEM;
+ }
+ o->private->refcount = 1;
+ *opt = o;
+ return 0;
+}
+
+krb5_error_code
+_krb5_get_init_creds_opt_copy(krb5_context context,
+ const krb5_get_init_creds_opt *in,
+ krb5_get_init_creds_opt **out)
+{
+ krb5_get_init_creds_opt *opt;
+
+ *out = NULL;
+ opt = malloc(sizeof(*opt));
+ if (opt == NULL) {
+ krb5_set_error_string(context, "out of memory");
+ return ENOMEM;
+ }
+ if (in)
+ *opt = *in;
+ if(opt->private == NULL) {
+ opt->private = calloc(1, sizeof(*opt->private));
+ if (opt->private == NULL) {
+ krb5_set_error_string(context, "out of memory");
+ free(opt);
+ return ENOMEM;
+ }
+ opt->private->refcount = 1;
+ } else
+ opt->private->refcount++;
+ *out = opt;
+ return 0;
+}
+
+void KRB5_LIB_FUNCTION
+krb5_get_init_creds_opt_free(krb5_get_init_creds_opt *opt)
+{
+ if (opt->private == NULL)
+ return;
+ if (opt->private->refcount < 1) /* abort ? */
+ return;
+ if (--opt->private->refcount == 0) {
+ _krb5_get_init_creds_opt_free_pkinit(opt);
+ free(opt->private);
+ }
+ memset(opt, 0, sizeof(*opt));
+ free(opt);
+}
+
+static int
+get_config_time (krb5_context context,
+ const char *realm,
+ const char *name,
+ int def)
+{
+ int ret;
+
+ ret = krb5_config_get_time (context, NULL,
+ "realms",
+ realm,
+ name,
+ NULL);
+ if (ret >= 0)
+ return ret;
+ ret = krb5_config_get_time (context, NULL,
+ "libdefaults",
+ name,
+ NULL);
+ if (ret >= 0)
+ return ret;
+ return def;
+}
+
+static krb5_boolean
+get_config_bool (krb5_context context,
+ const char *realm,
+ const char *name)
+{
+ return krb5_config_get_bool (context,
+ NULL,
+ "realms",
+ realm,
+ name,
+ NULL)
+ || krb5_config_get_bool (context,
+ NULL,
+ "libdefaults",
+ name,
+ NULL);
+}
+
+/*
+ * set all the values in `opt' to the appropriate values for
+ * application `appname' (default to getprogname() if NULL), and realm
+ * `realm'. First looks in [appdefaults] but falls back to
+ * [realms] or [libdefaults] for some of the values.
+ */
+
+static krb5_addresses no_addrs = {0, NULL};
+
+void KRB5_LIB_FUNCTION
+krb5_get_init_creds_opt_set_default_flags(krb5_context context,
+ const char *appname,
+ krb5_const_realm realm,
+ krb5_get_init_creds_opt *opt)
+{
+ krb5_boolean b;
+ time_t t;
+
+ b = get_config_bool (context, realm, "forwardable");
+ krb5_appdefault_boolean(context, appname, realm, "forwardable", b, &b);
+ krb5_get_init_creds_opt_set_forwardable(opt, b);
+
+ b = get_config_bool (context, realm, "proxiable");
+ krb5_appdefault_boolean(context, appname, realm, "proxiable", b, &b);
+ krb5_get_init_creds_opt_set_proxiable (opt, b);
+
+ krb5_appdefault_time(context, appname, realm, "ticket_lifetime", 0, &t);
+ if (t == 0)
+ t = get_config_time (context, realm, "ticket_lifetime", 0);
+ if(t != 0)
+ krb5_get_init_creds_opt_set_tkt_life(opt, t);
+
+ krb5_appdefault_time(context, appname, realm, "renew_lifetime", 0, &t);
+ if (t == 0)
+ t = get_config_time (context, realm, "renew_lifetime", 0);
+ if(t != 0)
+ krb5_get_init_creds_opt_set_renew_life(opt, t);
+
+ krb5_appdefault_boolean(context, appname, realm, "no-addresses", FALSE, &b);
+ if (b)
+ krb5_get_init_creds_opt_set_address_list (opt, &no_addrs);
+
+#if 0
+ krb5_appdefault_boolean(context, appname, realm, "anonymous", FALSE, &b);
+ krb5_get_init_creds_opt_set_anonymous (opt, b);
+
+ krb5_get_init_creds_opt_set_etype_list(opt, enctype,
+ etype_str.num_strings);
+
+ krb5_get_init_creds_opt_set_salt(krb5_get_init_creds_opt *opt,
+ krb5_data *salt);
+
+ krb5_get_init_creds_opt_set_preauth_list(krb5_get_init_creds_opt *opt,
+ krb5_preauthtype *preauth_list,
+ int preauth_list_length);
+#endif
+}
+
+
+void KRB5_LIB_FUNCTION
+krb5_get_init_creds_opt_set_tkt_life(krb5_get_init_creds_opt *opt,
+ krb5_deltat tkt_life)
+{
+ opt->flags |= KRB5_GET_INIT_CREDS_OPT_TKT_LIFE;
+ opt->tkt_life = tkt_life;
+}
+
+void KRB5_LIB_FUNCTION
+krb5_get_init_creds_opt_set_renew_life(krb5_get_init_creds_opt *opt,
+ krb5_deltat renew_life)
+{
+ opt->flags |= KRB5_GET_INIT_CREDS_OPT_RENEW_LIFE;
+ opt->renew_life = renew_life;
+}
+
+void KRB5_LIB_FUNCTION
+krb5_get_init_creds_opt_set_forwardable(krb5_get_init_creds_opt *opt,
+ int forwardable)
+{
+ opt->flags |= KRB5_GET_INIT_CREDS_OPT_FORWARDABLE;
+ opt->forwardable = forwardable;
+}
+
+void KRB5_LIB_FUNCTION
+krb5_get_init_creds_opt_set_proxiable(krb5_get_init_creds_opt *opt,
+ int proxiable)
+{
+ opt->flags |= KRB5_GET_INIT_CREDS_OPT_PROXIABLE;
+ opt->proxiable = proxiable;
+}
+
+void KRB5_LIB_FUNCTION
+krb5_get_init_creds_opt_set_etype_list(krb5_get_init_creds_opt *opt,
+ krb5_enctype *etype_list,
+ int etype_list_length)
+{
+ opt->flags |= KRB5_GET_INIT_CREDS_OPT_ETYPE_LIST;
+ opt->etype_list = etype_list;
+ opt->etype_list_length = etype_list_length;
+}
+
+void KRB5_LIB_FUNCTION
+krb5_get_init_creds_opt_set_address_list(krb5_get_init_creds_opt *opt,
+ krb5_addresses *addresses)
+{
+ opt->flags |= KRB5_GET_INIT_CREDS_OPT_ADDRESS_LIST;
+ opt->address_list = addresses;
+}
+
+void KRB5_LIB_FUNCTION
+krb5_get_init_creds_opt_set_preauth_list(krb5_get_init_creds_opt *opt,
+ krb5_preauthtype *preauth_list,
+ int preauth_list_length)
+{
+ opt->flags |= KRB5_GET_INIT_CREDS_OPT_PREAUTH_LIST;
+ opt->preauth_list_length = preauth_list_length;
+ opt->preauth_list = preauth_list;
+}
+
+void KRB5_LIB_FUNCTION
+krb5_get_init_creds_opt_set_salt(krb5_get_init_creds_opt *opt,
+ krb5_data *salt)
+{
+ opt->flags |= KRB5_GET_INIT_CREDS_OPT_SALT;
+ opt->salt = salt;
+}
+
+void KRB5_LIB_FUNCTION
+krb5_get_init_creds_opt_set_anonymous(krb5_get_init_creds_opt *opt,
+ int anonymous)
+{
+ opt->flags |= KRB5_GET_INIT_CREDS_OPT_ANONYMOUS;
+ opt->anonymous = anonymous;
+}
+
+static krb5_error_code
+require_ext_opt(krb5_context context,
+ krb5_get_init_creds_opt *opt,
+ const char *type)
+{
+ if (opt->private == NULL) {
+ krb5_set_error_string(context, "%s on non extendable opt", type);
+ return EINVAL;
+ }
+ return 0;
+}
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_get_init_creds_opt_set_pa_password(krb5_context context,
+ krb5_get_init_creds_opt *opt,
+ const char *password,
+ krb5_s2k_proc key_proc)
+{
+ krb5_error_code ret;
+ ret = require_ext_opt(context, opt, "init_creds_opt_set_pa_password");
+ if (ret)
+ return ret;
+ opt->private->password = password;
+ opt->private->key_proc = key_proc;
+ return 0;
+}
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_get_init_creds_opt_set_pac_request(krb5_context context,
+ krb5_get_init_creds_opt *opt,
+ krb5_boolean req_pac)
+{
+ krb5_error_code ret;
+ ret = require_ext_opt(context, opt, "init_creds_opt_set_pac_req");
+ if (ret)
+ return ret;
+ opt->private->req_pac = req_pac ?
+ KRB5_PA_PAC_REQ_TRUE :
+ KRB5_PA_PAC_REQ_FALSE;
+ return 0;
+}
diff --git a/source4/heimdal/lib/krb5/init_creds_pw.c b/source4/heimdal/lib/krb5/init_creds_pw.c
new file mode 100644
index 0000000000..8b3975f418
--- /dev/null
+++ b/source4/heimdal/lib/krb5/init_creds_pw.c
@@ -0,0 +1,1554 @@
+/*
+ * Copyright (c) 1997 - 2004 Kungliga Tekniska Högskolan
+ * (Royal Institute of Technology, Stockholm, Sweden).
+ * 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"
+
+RCSID("$Id: init_creds_pw.c,v 1.87 2005/06/17 04:15:20 lha Exp $");
+
+typedef struct krb5_get_init_creds_ctx {
+ krb5_kdc_flags flags;
+ krb5_creds cred;
+ krb5_addresses *addrs;
+ krb5_enctype *etypes;
+ krb5_preauthtype *pre_auth_types;
+ const char *in_tkt_service;
+ unsigned nonce;
+ unsigned pk_nonce;
+
+ AS_REQ as_req;
+ int pa_counter;
+
+ const char *password;
+ krb5_s2k_proc key_proc;
+
+ krb5_get_init_creds_req_pac req_pac;
+
+ krb5_pk_init_ctx pk_init_ctx;
+} krb5_get_init_creds_ctx;
+
+static krb5_error_code
+default_s2k_func(krb5_context context, krb5_enctype type,
+ krb5_const_pointer keyseed,
+ krb5_salt salt, krb5_data *s2kparms,
+ krb5_keyblock **key)
+{
+ krb5_error_code ret;
+ krb5_data password;
+ krb5_data opaque;
+
+ password.data = rk_UNCONST(keyseed);
+ password.length = strlen(keyseed);
+ if (s2kparms)
+ opaque = *s2kparms;
+ else
+ krb5_data_zero(&opaque);
+
+ *key = malloc(sizeof(**key));
+ if (*key == NULL)
+ return ENOMEM;
+ ret = krb5_string_to_key_data_salt_opaque(context, type, password,
+ salt, opaque, *key);
+ if (ret)
+ free(*key);
+ return ret;
+}
+
+static void
+free_init_creds_ctx(krb5_context context, krb5_get_init_creds_ctx *ctx)
+{
+ if (ctx->etypes)
+ free(ctx->etypes);
+ if (ctx->pre_auth_types)
+ free (ctx->pre_auth_types);
+ free_AS_REQ(&ctx->as_req);
+ memset(&ctx->as_req, 0, sizeof(ctx->as_req));
+}
+
+static int
+get_config_time (krb5_context context,
+ const char *realm,
+ const char *name,
+ int def)
+{
+ int ret;
+
+ ret = krb5_config_get_time (context, NULL,
+ "realms",
+ realm,
+ name,
+ NULL);
+ if (ret >= 0)
+ return ret;
+ ret = krb5_config_get_time (context, NULL,
+ "libdefaults",
+ name,
+ NULL);
+ if (ret >= 0)
+ return ret;
+ return def;
+}
+
+static krb5_error_code
+init_cred (krb5_context context,
+ krb5_creds *cred,
+ krb5_principal client,
+ krb5_deltat start_time,
+ const char *in_tkt_service,
+ krb5_get_init_creds_opt *options)
+{
+ krb5_error_code ret;
+ krb5_const_realm client_realm;
+ int tmp;
+ krb5_timestamp now;
+
+ krb5_timeofday (context, &now);
+
+ memset (cred, 0, sizeof(*cred));
+
+ if (client)
+ krb5_copy_principal(context, client, &cred->client);
+ else {
+ ret = krb5_get_default_principal (context,
+ &cred->client);
+ if (ret)
+ goto out;
+ }
+
+ client_realm = krb5_principal_get_realm (context, cred->client);
+
+ if (start_time)
+ cred->times.starttime = now + start_time;
+
+ if (options->flags & KRB5_GET_INIT_CREDS_OPT_TKT_LIFE)
+ tmp = options->tkt_life;
+ else
+ tmp = 10 * 60 * 60;
+ cred->times.endtime = now + tmp;
+
+ if ((options->flags & KRB5_GET_INIT_CREDS_OPT_RENEW_LIFE) &&
+ options->renew_life > 0) {
+ cred->times.renew_till = now + options->renew_life;
+ }
+
+ if (in_tkt_service) {
+ krb5_realm server_realm;
+
+ ret = krb5_parse_name (context, in_tkt_service, &cred->server);
+ if (ret)
+ goto out;
+ server_realm = strdup (client_realm);
+ free (*krb5_princ_realm(context, cred->server));
+ krb5_princ_set_realm (context, cred->server, &server_realm);
+ } else {
+ ret = krb5_make_principal(context, &cred->server,
+ client_realm, KRB5_TGS_NAME, client_realm,
+ NULL);
+ if (ret)
+ goto out;
+ }
+ return 0;
+
+out:
+ krb5_free_cred_contents (context, cred);
+ return ret;
+}
+
+/*
+ * Print a message (str) to the user about the expiration in `lr'
+ */
+
+static void
+report_expiration (krb5_context context,
+ krb5_prompter_fct prompter,
+ krb5_data *data,
+ const char *str,
+ time_t now)
+{
+ char *p;
+
+ asprintf (&p, "%s%s", str, ctime(&now));
+ (*prompter) (context, data, NULL, p, 0, NULL);
+ free (p);
+}
+
+/*
+ * Parse the last_req data and show it to the user if it's interesting
+ */
+
+static void
+print_expire (krb5_context context,
+ krb5_const_realm realm,
+ krb5_kdc_rep *rep,
+ krb5_prompter_fct prompter,
+ krb5_data *data)
+{
+ int i;
+ LastReq *lr = &rep->enc_part.last_req;
+ krb5_timestamp sec;
+ time_t t;
+ krb5_boolean reported = FALSE;
+
+ krb5_timeofday (context, &sec);
+
+ t = sec + get_config_time (context,
+ realm,
+ "warn_pwexpire",
+ 7 * 24 * 60 * 60);
+
+ for (i = 0; i < lr->len; ++i) {
+ if (lr->val[i].lr_value <= t) {
+ switch (abs(lr->val[i].lr_type)) {
+ case LR_PW_EXPTIME :
+ report_expiration(context, prompter, data,
+ "Your password will expire at ",
+ lr->val[i].lr_value);
+ reported = TRUE;
+ break;
+ case LR_ACCT_EXPTIME :
+ report_expiration(context, prompter, data,
+ "Your account will expire at ",
+ lr->val[i].lr_value);
+ reported = TRUE;
+ break;
+ }
+ }
+ }
+
+ if (!reported
+ && rep->enc_part.key_expiration
+ && *rep->enc_part.key_expiration <= t) {
+ report_expiration(context, prompter, data,
+ "Your password/account will expire at ",
+ *rep->enc_part.key_expiration);
+ }
+}
+
+static krb5_error_code
+get_init_creds_common(krb5_context context,
+ krb5_creds *creds,
+ krb5_principal client,
+ krb5_deltat start_time,
+ const char *in_tkt_service,
+ krb5_get_init_creds_opt *options,
+ krb5_get_init_creds_ctx *ctx)
+{
+ krb5_get_init_creds_opt default_opt;
+ krb5_error_code ret;
+ krb5_enctype *etypes;
+ krb5_preauthtype *pre_auth_types;
+
+ memset(ctx, 0, sizeof(*ctx));
+
+ if (options == NULL) {
+ krb5_get_init_creds_opt_init (&default_opt);
+ options = &default_opt;
+ }
+
+ if (options->private) {
+ ctx->password = options->private->password;
+ ctx->key_proc = options->private->key_proc;
+ ctx->req_pac = options->private->req_pac;
+ ctx->pk_init_ctx = options->private->pk_init_ctx;
+ } else
+ ctx->req_pac = KRB5_PA_PAC_DONT_CARE;
+
+ if (ctx->key_proc == NULL)
+ ctx->key_proc = default_s2k_func;
+
+ ctx->pre_auth_types = NULL;
+ ctx->flags.i = 0;
+ ctx->addrs = NULL;
+ ctx->etypes = NULL;
+ ctx->pre_auth_types = NULL;
+ ctx->in_tkt_service = in_tkt_service;
+
+ ret = init_cred (context, &ctx->cred, client, start_time,
+ in_tkt_service, options);
+ if (ret)
+ return ret;
+
+ ctx->flags.i = 0;
+
+ if (options->flags & KRB5_GET_INIT_CREDS_OPT_FORWARDABLE)
+ ctx->flags.b.forwardable = options->forwardable;
+
+ if (options->flags & KRB5_GET_INIT_CREDS_OPT_PROXIABLE)
+ ctx->flags.b.proxiable = options->proxiable;
+
+ if (start_time)
+ ctx->flags.b.postdated = 1;
+ if (ctx->cred.times.renew_till)
+ ctx->flags.b.renewable = 1;
+ if (options->flags & KRB5_GET_INIT_CREDS_OPT_ADDRESS_LIST)
+ ctx->addrs = options->address_list;
+ if (options->flags & KRB5_GET_INIT_CREDS_OPT_ETYPE_LIST) {
+ etypes = malloc((options->etype_list_length + 1)
+ * sizeof(krb5_enctype));
+ if (etypes == NULL) {
+ krb5_set_error_string(context, "malloc: out of memory");
+ return ENOMEM;
+ }
+ memcpy (etypes, options->etype_list,
+ options->etype_list_length * sizeof(krb5_enctype));
+ etypes[options->etype_list_length] = ETYPE_NULL;
+ ctx->etypes = etypes;
+ }
+ if (options->flags & KRB5_GET_INIT_CREDS_OPT_PREAUTH_LIST) {
+ pre_auth_types = malloc((options->preauth_list_length + 1)
+ * sizeof(krb5_preauthtype));
+ if (pre_auth_types == NULL) {
+ krb5_set_error_string(context, "malloc: out of memory");
+ return ENOMEM;
+ }
+ memcpy (pre_auth_types, options->preauth_list,
+ options->preauth_list_length * sizeof(krb5_preauthtype));
+ pre_auth_types[options->preauth_list_length] = KRB5_PADATA_NONE;
+ ctx->pre_auth_types = pre_auth_types;
+ }
+ if (options->flags & KRB5_GET_INIT_CREDS_OPT_SALT)
+ ; /* XXX */
+ if (options->flags & KRB5_GET_INIT_CREDS_OPT_ANONYMOUS)
+ ctx->flags.b.request_anonymous = options->anonymous;
+ return 0;
+}
+
+static krb5_error_code
+change_password (krb5_context context,
+ krb5_principal client,
+ const char *password,
+ char *newpw,
+ size_t newpw_sz,
+ krb5_prompter_fct prompter,
+ void *data,
+ krb5_get_init_creds_opt *old_options)
+{
+ krb5_prompt prompts[2];
+ krb5_error_code ret;
+ krb5_creds cpw_cred;
+ char buf1[BUFSIZ], buf2[BUFSIZ];
+ krb5_data password_data[2];
+ int result_code;
+ krb5_data result_code_string;
+ krb5_data result_string;
+ char *p;
+ krb5_get_init_creds_opt options;
+
+ memset (&cpw_cred, 0, sizeof(cpw_cred));
+
+ krb5_get_init_creds_opt_init (&options);
+ krb5_get_init_creds_opt_set_tkt_life (&options, 60);
+ krb5_get_init_creds_opt_set_forwardable (&options, FALSE);
+ krb5_get_init_creds_opt_set_proxiable (&options, FALSE);
+ if (old_options && old_options->flags & KRB5_GET_INIT_CREDS_OPT_PREAUTH_LIST)
+ krb5_get_init_creds_opt_set_preauth_list (&options,
+ old_options->preauth_list,
+ old_options->preauth_list_length);
+
+ krb5_data_zero (&result_code_string);
+ krb5_data_zero (&result_string);
+
+ ret = krb5_get_init_creds_password (context,
+ &cpw_cred,
+ client,
+ password,
+ prompter,
+ data,
+ 0,
+ "kadmin/changepw",
+ &options);
+ if (ret)
+ goto out;
+
+ for(;;) {
+ password_data[0].data = buf1;
+ password_data[0].length = sizeof(buf1);
+
+ prompts[0].hidden = 1;
+ prompts[0].prompt = "New password: ";
+ prompts[0].reply = &password_data[0];
+ prompts[0].type = KRB5_PROMPT_TYPE_NEW_PASSWORD;
+
+ password_data[1].data = buf2;
+ password_data[1].length = sizeof(buf2);
+
+ prompts[1].hidden = 1;
+ prompts[1].prompt = "Repeat new password: ";
+ prompts[1].reply = &password_data[1];
+ prompts[1].type = KRB5_PROMPT_TYPE_NEW_PASSWORD_AGAIN;
+
+ ret = (*prompter) (context, data, NULL, "Changing password",
+ 2, prompts);
+ if (ret) {
+ memset (buf1, 0, sizeof(buf1));
+ memset (buf2, 0, sizeof(buf2));
+ goto out;
+ }
+
+ if (strcmp (buf1, buf2) == 0)
+ break;
+ memset (buf1, 0, sizeof(buf1));
+ memset (buf2, 0, sizeof(buf2));
+ }
+
+ ret = krb5_change_password (context,
+ &cpw_cred,
+ buf1,
+ &result_code,
+ &result_code_string,
+ &result_string);
+ if (ret)
+ goto out;
+ asprintf (&p, "%s: %.*s\n",
+ result_code ? "Error" : "Success",
+ (int)result_string.length,
+ result_string.length > 0 ? (char*)result_string.data : "");
+
+ ret = (*prompter) (context, data, NULL, p, 0, NULL);
+ free (p);
+ if (result_code == 0) {
+ strlcpy (newpw, buf1, newpw_sz);
+ ret = 0;
+ } else {
+ krb5_set_error_string (context, "failed changing password");
+ ret = ENOTTY;
+ }
+
+out:
+ memset (buf1, 0, sizeof(buf1));
+ memset (buf2, 0, sizeof(buf2));
+ krb5_data_free (&result_string);
+ krb5_data_free (&result_code_string);
+ krb5_free_cred_contents (context, &cpw_cred);
+ return ret;
+}
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_keyblock_key_proc (krb5_context context,
+ krb5_keytype type,
+ krb5_data *salt,
+ krb5_const_pointer keyseed,
+ krb5_keyblock **key)
+{
+ return krb5_copy_keyblock (context, keyseed, key);
+}
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_get_init_creds_keytab(krb5_context context,
+ krb5_creds *creds,
+ krb5_principal client,
+ krb5_keytab keytab,
+ krb5_deltat start_time,
+ const char *in_tkt_service,
+ krb5_get_init_creds_opt *options)
+{
+ krb5_get_init_creds_ctx ctx;
+ krb5_error_code ret;
+ krb5_keytab_key_proc_args *a;
+
+ ret = get_init_creds_common(context, creds, client, start_time,
+ in_tkt_service, options, &ctx);
+ if (ret)
+ goto out;
+
+ a = malloc (sizeof(*a));
+ if (a == NULL) {
+ krb5_set_error_string(context, "malloc: out of memory");
+ ret = ENOMEM;
+ goto out;
+ }
+ a->principal = ctx.cred.client;
+ a->keytab = keytab;
+
+ ret = krb5_get_in_cred (context,
+ ctx.flags.i,
+ ctx.addrs,
+ ctx.etypes,
+ ctx.pre_auth_types,
+ NULL,
+ krb5_keytab_key_proc,
+ a,
+ NULL,
+ NULL,
+ &ctx.cred,
+ NULL);
+ free (a);
+
+ if (ret == 0 && creds)
+ *creds = ctx.cred;
+ else
+ krb5_free_cred_contents (context, &ctx.cred);
+
+ out:
+ free_init_creds_ctx(context, &ctx);
+ return ret;
+}
+
+/*
+ *
+ */
+
+static krb5_error_code
+init_creds_init_as_req (krb5_context context,
+ krb5_kdc_flags opts,
+ const krb5_creds *creds,
+ const krb5_addresses *addrs,
+ const krb5_enctype *etypes,
+ AS_REQ *a)
+{
+ krb5_error_code ret;
+
+ memset(a, 0, sizeof(*a));
+
+ a->pvno = 5;
+ a->msg_type = krb_as_req;
+ a->req_body.kdc_options = opts.b;
+ a->req_body.cname = malloc(sizeof(*a->req_body.cname));
+ if (a->req_body.cname == NULL) {
+ ret = ENOMEM;
+ krb5_set_error_string(context, "malloc: out of memory");
+ goto fail;
+ }
+ a->req_body.sname = malloc(sizeof(*a->req_body.sname));
+ if (a->req_body.sname == NULL) {
+ ret = ENOMEM;
+ krb5_set_error_string(context, "malloc: out of memory");
+ goto fail;
+ }
+ if (creds->client) {
+ ret = _krb5_principal2principalname (a->req_body.cname, creds->client);
+ if (ret)
+ goto fail;
+ ret = copy_Realm(&creds->client->realm, &a->req_body.realm);
+ if (ret)
+ goto fail;
+ } else {
+ krb5_realm realm;
+
+ a->req_body.cname = NULL;
+ ret = krb5_get_default_realm(context, &realm);
+ if (ret)
+ goto fail;
+ ret = copy_Realm(&realm, &a->req_body.realm);
+ free(realm);
+ }
+ ret = _krb5_principal2principalname (a->req_body.sname, creds->server);
+ if (ret)
+ goto fail;
+
+ if(creds->times.starttime) {
+ a->req_body.from = malloc(sizeof(*a->req_body.from));
+ if (a->req_body.from == NULL) {
+ ret = ENOMEM;
+ krb5_set_error_string(context, "malloc: out of memory");
+ goto fail;
+ }
+ *a->req_body.from = creds->times.starttime;
+ }
+ if(creds->times.endtime){
+ ALLOC(a->req_body.till, 1);
+ *a->req_body.till = creds->times.endtime;
+ }
+ if(creds->times.renew_till){
+ a->req_body.rtime = malloc(sizeof(*a->req_body.rtime));
+ if (a->req_body.rtime == NULL) {
+ ret = ENOMEM;
+ krb5_set_error_string(context, "malloc: out of memory");
+ goto fail;
+ }
+ *a->req_body.rtime = creds->times.renew_till;
+ }
+ a->req_body.nonce = 0;
+ ret = krb5_init_etype (context,
+ &a->req_body.etype.len,
+ &a->req_body.etype.val,
+ etypes);
+ if (ret)
+ goto fail;
+
+ /*
+ * This means no addresses
+ */
+
+ if (addrs && addrs->len == 0) {
+ a->req_body.addresses = NULL;
+ } else {
+ a->req_body.addresses = malloc(sizeof(*a->req_body.addresses));
+ if (a->req_body.addresses == NULL) {
+ ret = ENOMEM;
+ krb5_set_error_string(context, "malloc: out of memory");
+ goto fail;
+ }
+
+ if (addrs)
+ ret = krb5_copy_addresses(context, addrs, a->req_body.addresses);
+ else {
+ ret = krb5_get_all_client_addrs (context, a->req_body.addresses);
+ if(ret == 0 && a->req_body.addresses->len == 0) {
+ free(a->req_body.addresses);
+ a->req_body.addresses = NULL;
+ }
+ }
+ if (ret)
+ goto fail;
+ }
+
+ a->req_body.enc_authorization_data = NULL;
+ a->req_body.additional_tickets = NULL;
+
+ a->padata = NULL;
+
+ return 0;
+ fail:
+ free_AS_REQ(a);
+ memset(a, 0, sizeof(*a));
+ return ret;
+}
+
+struct pa_info_data {
+ krb5_enctype etype;
+ krb5_salt salt;
+ krb5_data *s2kparams;
+};
+
+static void
+free_paid(krb5_context context, struct pa_info_data *ppaid)
+{
+ krb5_free_salt(context, ppaid->salt);
+ if (ppaid->s2kparams)
+ krb5_data_free(ppaid->s2kparams);
+}
+
+
+static krb5_error_code
+set_paid(struct pa_info_data *paid, krb5_context context,
+ krb5_enctype etype,
+ krb5_salttype salttype, void *salt_string, size_t salt_len,
+ krb5_data *s2kparams)
+{
+ paid->etype = etype;
+ paid->salt.salttype = salttype;
+ paid->salt.saltvalue.data = malloc(salt_len + 1);
+ if (paid->salt.saltvalue.data == NULL) {
+ krb5_clear_error_string(context);
+ return ENOMEM;
+ }
+ memcpy(paid->salt.saltvalue.data, salt_string, salt_len);
+ ((char *)paid->salt.saltvalue.data)[salt_len] = '\0';
+ paid->salt.saltvalue.length = salt_len;
+ if (s2kparams) {
+ krb5_error_code ret;
+
+ ret = krb5_copy_data(context, s2kparams, &paid->s2kparams);
+ if (ret) {
+ krb5_clear_error_string(context);
+ krb5_free_salt(context, paid->salt);
+ return ret;
+ }
+ } else
+ paid->s2kparams = NULL;
+
+ return 0;
+}
+
+static struct pa_info_data *
+pa_etype_info2(krb5_context context,
+ const krb5_principal client,
+ const AS_REQ *asreq,
+ struct pa_info_data *paid,
+ heim_octet_string *data)
+{
+ krb5_error_code ret;
+ ETYPE_INFO2 e;
+ size_t sz;
+ int i, j;
+
+ memset(&e, 0, sizeof(e));
+ ret = decode_ETYPE_INFO2(data->data, data->length, &e, &sz);
+ if (ret)
+ goto out;
+ if (e.len == 0)
+ goto out;
+ for (j = 0; j < asreq->req_body.etype.len; j++) {
+ for (i = 0; i < e.len; i++) {
+ if (asreq->req_body.etype.val[j] == e.val[i].etype) {
+ krb5_salt salt;
+ if (e.val[i].salt == NULL)
+ ret = krb5_get_pw_salt(context, client, &salt);
+ else {
+ salt.saltvalue.data = *e.val[i].salt;
+ salt.saltvalue.length = strlen(*e.val[i].salt);
+ ret = 0;
+ }
+ if (ret == 0)
+ ret = set_paid(paid, context, e.val[i].etype,
+ KRB5_PW_SALT,
+ salt.saltvalue.data,
+ salt.saltvalue.length,
+ e.val[i].s2kparams);
+ if (e.val[i].salt == NULL)
+ krb5_free_salt(context, salt);
+ if (ret == 0) {
+ free_ETYPE_INFO2(&e);
+ return paid;
+ }
+ }
+ }
+ }
+ out:
+ free_ETYPE_INFO2(&e);
+ return NULL;
+}
+
+static struct pa_info_data *
+pa_etype_info(krb5_context context,
+ const krb5_principal client,
+ const AS_REQ *asreq,
+ struct pa_info_data *paid,
+ heim_octet_string *data)
+{
+ krb5_error_code ret;
+ ETYPE_INFO e;
+ size_t sz;
+ int i, j;
+
+ memset(&e, 0, sizeof(e));
+ ret = decode_ETYPE_INFO(data->data, data->length, &e, &sz);
+ if (ret)
+ goto out;
+ if (e.len == 0)
+ goto out;
+ for (j = 0; j < asreq->req_body.etype.len; j++) {
+ for (i = 0; i < e.len; i++) {
+ if (asreq->req_body.etype.val[j] == e.val[i].etype) {
+ krb5_salt salt;
+ salt.salttype = KRB5_PW_SALT;
+ if (e.val[i].salt == NULL)
+ ret = krb5_get_pw_salt(context, client, &salt);
+ else {
+ salt.saltvalue = *e.val[i].salt;
+ ret = 0;
+ }
+ if (e.val[i].salttype)
+ salt.salttype = *e.val[i].salttype;
+ if (ret == 0) {
+ ret = set_paid(paid, context, e.val[i].etype,
+ salt.salttype,
+ salt.saltvalue.data,
+ salt.saltvalue.length,
+ NULL);
+ if (e.val[i].salt == NULL)
+ krb5_free_salt(context, salt);
+ }
+ if (ret == 0) {
+ free_ETYPE_INFO(&e);
+ return paid;
+ }
+ }
+ }
+ }
+ out:
+ free_ETYPE_INFO(&e);
+ return NULL;
+}
+
+static struct pa_info_data *
+pa_pw_or_afs3_salt(krb5_context context,
+ const krb5_principal client,
+ const AS_REQ *asreq,
+ struct pa_info_data *paid,
+ heim_octet_string *data)
+{
+ krb5_error_code ret;
+ if (paid->etype == ENCTYPE_NULL)
+ return NULL;
+ ret = set_paid(paid, context,
+ paid->etype,
+ paid->salt.salttype,
+ data->data,
+ data->length,
+ NULL);
+ if (ret)
+ return NULL;
+ return paid;
+}
+
+
+struct pa_info {
+ krb5_preauthtype type;
+ struct pa_info_data *(*salt_info)(krb5_context,
+ const krb5_principal,
+ const AS_REQ *,
+ struct pa_info_data *,
+ heim_octet_string *);
+};
+
+static struct pa_info pa_prefs[] = {
+ { KRB5_PADATA_ETYPE_INFO2, pa_etype_info2 },
+ { KRB5_PADATA_ETYPE_INFO, pa_etype_info },
+ { KRB5_PADATA_PW_SALT, pa_pw_or_afs3_salt },
+ { KRB5_PADATA_AFS3_SALT, pa_pw_or_afs3_salt }
+};
+
+static PA_DATA *
+find_pa_data(const METHOD_DATA *md, int type)
+{
+ int i;
+ for (i = 0; i < md->len; i++)
+ if (md->val[i].padata_type == type)
+ return &md->val[i];
+ return NULL;
+}
+
+static struct pa_info_data *
+process_pa_info(krb5_context context,
+ const krb5_principal client,
+ const AS_REQ *asreq,
+ struct pa_info_data *paid,
+ METHOD_DATA *md)
+{
+ struct pa_info_data *p = NULL;
+ int i;
+
+ for (i = 0; p == NULL && i < sizeof(pa_prefs)/sizeof(pa_prefs[0]); i++) {
+ PA_DATA *pa = find_pa_data(md, pa_prefs[i].type);
+ if (pa == NULL)
+ continue;
+ paid->salt.salttype = pa_prefs[i].type;
+ p = (*pa_prefs[i].salt_info)(context, client, asreq,
+ paid, &pa->padata_value);
+ }
+ return p;
+}
+
+static krb5_error_code
+make_pa_enc_timestamp(krb5_context context, METHOD_DATA *md,
+ krb5_enctype etype, krb5_keyblock *key)
+{
+ PA_ENC_TS_ENC p;
+ unsigned char *buf;
+ size_t buf_size;
+ size_t len;
+ EncryptedData encdata;
+ krb5_error_code ret;
+ int32_t usec;
+ int usec2;
+ krb5_crypto crypto;
+
+ krb5_us_timeofday (context, &p.patimestamp, &usec);
+ usec2 = usec;
+ p.pausec = &usec2;
+
+ ASN1_MALLOC_ENCODE(PA_ENC_TS_ENC, buf, buf_size, &p, &len, ret);
+ if (ret)
+ return ret;
+ if(buf_size != len)
+ krb5_abortx(context, "internal error in ASN.1 encoder");
+
+ ret = krb5_crypto_init(context, key, 0, &crypto);
+ if (ret) {
+ free(buf);
+ return ret;
+ }
+ ret = krb5_encrypt_EncryptedData(context,
+ crypto,
+ KRB5_KU_PA_ENC_TIMESTAMP,
+ buf,
+ len,
+ 0,
+ &encdata);
+ free(buf);
+ krb5_crypto_destroy(context, crypto);
+ if (ret)
+ return ret;
+
+ ASN1_MALLOC_ENCODE(EncryptedData, buf, buf_size, &encdata, &len, ret);
+ free_EncryptedData(&encdata);
+ if (ret)
+ return ret;
+ if(buf_size != len)
+ krb5_abortx(context, "internal error in ASN.1 encoder");
+
+ ret = krb5_padata_add(context, md, KRB5_PADATA_ENC_TIMESTAMP, buf, len);
+ if (ret)
+ free(buf);
+ return ret;
+}
+
+static krb5_error_code
+add_enc_ts_padata(krb5_context context,
+ METHOD_DATA *md,
+ krb5_principal client,
+ krb5_s2k_proc key_proc,
+ krb5_const_pointer keyseed,
+ krb5_enctype *enctypes,
+ unsigned netypes,
+ krb5_salt *salt,
+ krb5_data *s2kparams)
+{
+ krb5_error_code ret;
+ krb5_salt salt2;
+ krb5_enctype *ep;
+ int i;
+
+ if(salt == NULL) {
+ /* default to standard salt */
+ ret = krb5_get_pw_salt (context, client, &salt2);
+ salt = &salt2;
+ }
+ if (!enctypes) {
+ enctypes = context->etypes;
+ netypes = 0;
+ for (ep = enctypes; *ep != ETYPE_NULL; ep++)
+ netypes++;
+ }
+
+ for (i = 0; i < netypes; ++i) {
+ krb5_keyblock *key;
+
+ ret = (*key_proc)(context, enctypes[i], keyseed,
+ *salt, s2kparams, &key);
+ if (ret)
+ continue;
+ ret = make_pa_enc_timestamp (context, md, enctypes[i], key);
+ krb5_free_keyblock (context, key);
+ if (ret)
+ return ret;
+ }
+ if(salt == &salt2)
+ krb5_free_salt(context, salt2);
+ return 0;
+}
+
+static krb5_error_code
+pa_data_to_md_ts_enc(krb5_context context,
+ const AS_REQ *a,
+ const krb5_principal client,
+ krb5_get_init_creds_ctx *ctx,
+ struct pa_info_data *ppaid,
+ METHOD_DATA *md)
+{
+ if (ctx->key_proc == NULL || ctx->password == NULL)
+ return 0;
+
+ if (ppaid) {
+ add_enc_ts_padata(context, md, client,
+ ctx->key_proc, ctx->password,
+ &ppaid->etype, 1,
+ &ppaid->salt, ppaid->s2kparams);
+ } else {
+ krb5_salt salt;
+
+ /* make a v5 salted pa-data */
+ add_enc_ts_padata(context, md, client,
+ ctx->key_proc, ctx->password,
+ a->req_body.etype.val, a->req_body.etype.len,
+ NULL, NULL);
+
+ /* make a v4 salted pa-data */
+ salt.salttype = KRB5_PW_SALT;
+ krb5_data_zero(&salt.saltvalue);
+ add_enc_ts_padata(context, md, client,
+ ctx->key_proc, ctx->password,
+ a->req_body.etype.val, a->req_body.etype.len,
+ &salt, NULL);
+ }
+ return 0;
+}
+
+static krb5_error_code
+pa_data_to_key_plain(krb5_context context,
+ const krb5_principal client,
+ krb5_get_init_creds_ctx *ctx,
+ krb5_salt salt,
+ krb5_data *s2kparams,
+ krb5_enctype etype,
+ krb5_keyblock **key)
+{
+ krb5_error_code ret;
+
+ ret = (*ctx->key_proc)(context, etype, ctx->password,
+ salt, s2kparams, key);
+ return ret;
+}
+
+
+static krb5_error_code
+pa_data_to_md_pkinit(krb5_context context,
+ const AS_REQ *a,
+ const krb5_principal client,
+ krb5_get_init_creds_ctx *ctx,
+ METHOD_DATA *md)
+{
+ if (ctx->pk_init_ctx == NULL)
+ return 0;
+#ifdef PKINIT
+ return _krb5_pk_mk_padata(context,
+ ctx->pk_init_ctx,
+ &a->req_body,
+ ctx->pk_nonce,
+ md);
+#else
+ krb5_set_error_string(context, "no support for PKINIT compiled in");
+ return EINVAL;
+#endif
+}
+
+static krb5_error_code
+pa_data_add_pac_request(krb5_context context,
+ krb5_get_init_creds_ctx *ctx,
+ METHOD_DATA *md)
+{
+ size_t len, length;
+ krb5_error_code ret;
+ PA_PAC_REQUEST req;
+ void *buf;
+
+ switch (ctx->req_pac) {
+ case KRB5_PA_PAC_DONT_CARE:
+ return 0; /* don't bother */
+ case KRB5_PA_PAC_REQ_TRUE:
+ req.include_pac = 1;
+ break;
+ case KRB5_PA_PAC_REQ_FALSE:
+ req.include_pac = 0;
+ }
+
+ ASN1_MALLOC_ENCODE(PA_PAC_REQUEST, buf, length,
+ &req, &len, ret);
+ if (ret)
+ return ret;
+ if(len != length)
+ krb5_abortx(context, "internal error in ASN.1 encoder");
+
+ ret = krb5_padata_add(context, md, KRB5_PADATA_PA_PAC_REQUEST, buf, len);
+ if (ret)
+ free(buf);
+
+ return 0;
+}
+
+/*
+ * Assumes caller always will free `out_md', even on error.
+ */
+
+static krb5_error_code
+process_pa_data_to_md(krb5_context context,
+ const krb5_creds *creds,
+ const AS_REQ *a,
+ krb5_get_init_creds_ctx *ctx,
+ METHOD_DATA *in_md,
+ METHOD_DATA **out_md,
+ krb5_prompter_fct prompter,
+ void *prompter_data)
+{
+ krb5_error_code ret;
+
+ ALLOC(*out_md, 1);
+ if (*out_md == NULL) {
+ krb5_set_error_string(context, "malloc: out of memory");
+ return ENOMEM;
+ }
+ (*out_md)->len = 0;
+ (*out_md)->val = NULL;
+
+ if (in_md->len != 0) {
+ struct pa_info_data paid, *ppaid;
+
+ memset(&paid, 0, sizeof(paid));
+
+ paid.etype = ENCTYPE_NULL;
+ ppaid = process_pa_info(context, creds->client, a, &paid, in_md);
+
+ pa_data_to_md_ts_enc(context, a, creds->client, ctx, ppaid, *out_md);
+ if (ppaid)
+ free_paid(context, ppaid);
+ }
+
+ pa_data_add_pac_request(context, ctx, *out_md);
+ ret = pa_data_to_md_pkinit(context, a, creds->client, ctx, *out_md);
+ if (ret)
+ return ret;
+
+ if ((*out_md)->len == 0) {
+ free(*out_md);
+ *out_md = NULL;
+ }
+
+ return 0;
+}
+
+static krb5_error_code
+process_pa_data_to_key(krb5_context context,
+ krb5_get_init_creds_ctx *ctx,
+ krb5_creds *creds,
+ AS_REQ *a,
+ krb5_kdc_rep *rep,
+ krb5_keyblock **key)
+{
+ struct pa_info_data paid, *ppaid = NULL;
+ krb5_error_code ret;
+ krb5_enctype etype;
+ PA_DATA *pa;
+
+ memset(&paid, 0, sizeof(paid));
+
+ etype = rep->kdc_rep.enc_part.etype;
+
+ if (rep->kdc_rep.padata) {
+ paid.etype = etype;
+ ppaid = process_pa_info(context, creds->client, a, &paid,
+ rep->kdc_rep.padata);
+ }
+ if (ppaid == NULL) {
+ ret = krb5_get_pw_salt (context, creds->client, &paid.salt);
+ if (ret)
+ return ret;
+ paid.etype = etype;
+ paid.s2kparams = NULL;
+ }
+
+ pa = NULL;
+ if (rep->kdc_rep.padata) {
+ int idx = 0;
+ pa = krb5_find_padata(rep->kdc_rep.padata->val,
+ rep->kdc_rep.padata->len,
+ KRB5_PADATA_PK_AS_REP,
+ &idx);
+ if (pa == NULL) {
+ idx = 0;
+ pa = krb5_find_padata(rep->kdc_rep.padata->val,
+ rep->kdc_rep.padata->len,
+ KRB5_PADATA_PK_AS_REP_19,
+ &idx);
+ }
+ }
+ if (pa && ctx->pk_init_ctx) {
+#ifdef PKINIT
+ ret = _krb5_pk_rd_pa_reply(context,
+ ctx->pk_init_ctx,
+ etype,
+ ctx->pk_nonce,
+ pa,
+ key);
+#else
+ krb5_set_error_string(context, "no support for PKINIT compiled in");
+ ret = EINVAL;
+#endif
+ } else if (ctx->password)
+ ret = pa_data_to_key_plain(context, creds->client, ctx,
+ paid.salt, paid.s2kparams, etype, key);
+ else {
+ krb5_set_error_string(context, "No usable pa data type");
+ ret = EINVAL;
+ }
+
+ free_paid(context, &paid);
+ return ret;
+}
+
+static krb5_error_code
+init_cred_loop(krb5_context context,
+ const krb5_get_init_creds_opt *init_cred_opts,
+ const krb5_prompter_fct prompter,
+ void *prompter_data,
+ krb5_get_init_creds_ctx *ctx,
+ krb5_creds *creds,
+ krb5_kdc_rep *ret_as_reply)
+{
+ krb5_error_code ret;
+ krb5_kdc_rep rep;
+ METHOD_DATA md;
+ krb5_data resp;
+ size_t len;
+ size_t size;
+ int send_to_kdc_flags = 0;
+
+ memset(&md, 0, sizeof(md));
+ memset(&rep, 0, sizeof(rep));
+
+ if (ret_as_reply)
+ memset(ret_as_reply, 0, sizeof(*ret_as_reply));
+
+ ret = init_creds_init_as_req(context, ctx->flags, creds,
+ ctx->addrs, ctx->etypes, &ctx->as_req);
+ if (ret)
+ return ret;
+
+ /* Set a new nonce. */
+ krb5_generate_random_block (&ctx->nonce, sizeof(ctx->nonce));
+ ctx->nonce &= 0xffffffff;
+ /* XXX these just needs to be the same when using Windows PK-INIT */
+ ctx->pk_nonce = ctx->nonce;
+
+ /*
+ * Increase counter when we want other pre-auth types then
+ * KRB5_PA_ENC_TIMESTAMP.
+ */
+#define MAX_PA_COUNTER 3
+
+ ctx->pa_counter = 0;
+ while (ctx->pa_counter < MAX_PA_COUNTER) {
+ krb5_data req;
+
+ ctx->pa_counter++;
+
+ if (ctx->as_req.padata) {
+ free_METHOD_DATA(ctx->as_req.padata);
+ free(ctx->as_req.padata);
+ ctx->as_req.padata = NULL;
+ }
+
+ /* Set a new nonce. */
+ ctx->as_req.req_body.nonce = ctx->nonce;
+
+ /* fill_in_md_data */
+ ret = process_pa_data_to_md(context, creds, &ctx->as_req, ctx,
+ &md, &ctx->as_req.padata,
+ prompter, prompter_data);
+ if (ret)
+ goto out;
+ ASN1_MALLOC_ENCODE(AS_REQ, req.data, req.length,
+ &ctx->as_req, &len, ret);
+ if (ret)
+ goto out;
+ if(len != req.length)
+ krb5_abortx(context, "internal error in ASN.1 encoder");
+
+ ret = krb5_sendto_kdc_flags (context, &req,
+ &creds->client->realm, &resp,
+ send_to_kdc_flags);
+ krb5_data_free(&req);
+ if (ret)
+ goto out;
+
+ memset (&rep, 0, sizeof(rep));
+ ret = decode_AS_REP(resp.data, resp.length, &rep.kdc_rep, &size);
+ if (ret == 0) {
+ krb5_data_free(&resp);
+ krb5_clear_error_string(context);
+ break;
+ } else {
+ /* let's try to parse it as a KRB-ERROR */
+ KRB_ERROR error;
+
+ ret = krb5_rd_error(context, &resp, &error);
+ if(ret && resp.data && ((char*)resp.data)[0] == 4)
+ ret = KRB5KRB_AP_ERR_V4_REPLY;
+ krb5_data_free(&resp);
+ if (ret)
+ goto out;
+
+ ret = krb5_error_from_rd_error(context, &error, creds);
+
+ /*
+ * If no preauth was set and KDC requires it, give it one
+ * more try.
+ */
+
+ if (ret == KRB5KDC_ERR_PREAUTH_REQUIRED) {
+ free_METHOD_DATA(&md);
+ memset(&md, 0, sizeof(md));
+
+ if (error.e_data) {
+ ret = decode_METHOD_DATA(error.e_data->data,
+ error.e_data->length,
+ &md,
+ NULL);
+ if (ret)
+ krb5_set_error_string(context,
+ "failed to decode METHOD DATA");
+ } else {
+ /* XXX guess what the server want here add add md */
+ }
+ krb5_free_error_contents(context, &error);
+ if (ret)
+ goto out;
+ } else if (ret == KRB5KRB_ERR_RESPONSE_TOO_BIG) {
+ if (send_to_kdc_flags & KRB5_KRBHST_FLAGS_LARGE_MSG) {
+ if (ret_as_reply)
+ rep.error = error;
+ else
+ krb5_free_error_contents(context, &error);
+ goto out;
+ }
+ krb5_free_error_contents(context, &error);
+ send_to_kdc_flags |= KRB5_KRBHST_FLAGS_LARGE_MSG;
+ } else {
+ if (ret_as_reply)
+ rep.error = error;
+ else
+ krb5_free_error_contents(context, &error);
+ goto out;
+ }
+ }
+ }
+
+ {
+ krb5_keyblock *key = NULL;
+
+ ret = process_pa_data_to_key(context, ctx, creds,
+ &ctx->as_req, &rep, &key);
+ if (ret)
+ goto out;
+
+ ret = _krb5_extract_ticket(context,
+ &rep,
+ creds,
+ key,
+ NULL,
+ KRB5_KU_AS_REP_ENC_PART,
+ NULL,
+ ctx->nonce,
+ FALSE,
+ ctx->flags.b.request_anonymous,
+ NULL,
+ NULL);
+ krb5_free_keyblock(context, key);
+ }
+out:
+ free_METHOD_DATA(&md);
+ memset(&md, 0, sizeof(md));
+
+ if (ret == 0 && ret_as_reply)
+ *ret_as_reply = rep;
+ else
+ krb5_free_kdc_rep (context, &rep);
+ return ret;
+}
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_get_init_creds(krb5_context context,
+ krb5_creds *creds,
+ krb5_principal client,
+ krb5_prompter_fct prompter,
+ void *data,
+ krb5_deltat start_time,
+ const char *in_tkt_service,
+ krb5_get_init_creds_opt *options)
+{
+ krb5_get_init_creds_ctx ctx;
+ krb5_kdc_rep kdc_reply;
+ krb5_error_code ret;
+ char buf[BUFSIZ];
+ int done;
+
+ memset(&kdc_reply, 0, sizeof(kdc_reply));
+
+ ret = get_init_creds_common(context, creds, client, start_time,
+ in_tkt_service, options, &ctx);
+ if (ret)
+ goto out;
+
+ done = 0;
+ while(!done) {
+ memset(&kdc_reply, 0, sizeof(kdc_reply));
+
+ ret = init_cred_loop(context,
+ options,
+ prompter,
+ data,
+ &ctx,
+ &ctx.cred,
+ &kdc_reply);
+
+ switch (ret) {
+ case 0 :
+ done = 1;
+ break;
+ case KRB5KDC_ERR_KEY_EXPIRED :
+ /* try to avoid recursion */
+
+ /* don't try to change password where then where none */
+ if (prompter == NULL || ctx.password == NULL)
+ goto out;
+
+ krb5_clear_error_string (context);
+
+ if (ctx.in_tkt_service != NULL
+ && strcmp (ctx.in_tkt_service, "kadmin/changepw") == 0)
+ goto out;
+
+ ret = change_password (context,
+ client,
+ ctx.password,
+ buf,
+ sizeof(buf),
+ prompter,
+ data,
+ options);
+ if (ret)
+ goto out;
+ ctx.password = buf;
+ break;
+ default:
+ goto out;
+ }
+ }
+
+ if (prompter)
+ print_expire (context,
+ krb5_principal_get_realm (context, ctx.cred.client),
+ &kdc_reply,
+ prompter,
+ data);
+
+ out:
+ memset (buf, 0, sizeof(buf));
+ free_init_creds_ctx(context, &ctx);
+ krb5_free_kdc_rep (context, &kdc_reply);
+ if (ret == 0)
+ *creds = ctx.cred;
+ else
+ krb5_free_cred_contents (context, &ctx.cred);
+
+ return ret;
+}
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_get_init_creds_password(krb5_context context,
+ krb5_creds *creds,
+ krb5_principal client,
+ const char *password,
+ krb5_prompter_fct prompter,
+ void *data,
+ krb5_deltat start_time,
+ const char *in_tkt_service,
+ krb5_get_init_creds_opt *in_options)
+{
+ krb5_get_init_creds_opt *options;
+ char buf[BUFSIZ];
+ krb5_error_code ret;
+
+ if (in_options == NULL)
+ ret = krb5_get_init_creds_opt_alloc(context, &options);
+ else
+ ret = _krb5_get_init_creds_opt_copy(context, in_options, &options);
+ if (ret)
+ return ret;
+
+ if (password == NULL &&
+ options->private->password == NULL &&
+ options->private->pk_init_ctx == NULL)
+ {
+ krb5_prompt prompt;
+ krb5_data password_data;
+ char *p, *q;
+
+ krb5_unparse_name (context, client, &p);
+ asprintf (&q, "%s's Password: ", p);
+ free (p);
+ prompt.prompt = q;
+ password_data.data = buf;
+ password_data.length = sizeof(buf);
+ prompt.hidden = 1;
+ prompt.reply = &password_data;
+ prompt.type = KRB5_PROMPT_TYPE_PASSWORD;
+
+ ret = (*prompter) (context, data, NULL, NULL, 1, &prompt);
+ free (q);
+ if (ret) {
+ memset (buf, 0, sizeof(buf));
+ krb5_get_init_creds_opt_free(options);
+ ret = KRB5_LIBOS_PWDINTR;
+ krb5_clear_error_string (context);
+ return ret;
+ }
+ password = password_data.data;
+ }
+
+ if (options->private->password == NULL) {
+ ret = krb5_get_init_creds_opt_set_pa_password(context, options,
+ password, NULL);
+ if (ret) {
+ krb5_get_init_creds_opt_free(options);
+ memset(buf, 0, sizeof(buf));
+ return ret;
+ }
+ }
+
+ ret = krb5_get_init_creds(context, creds, client, prompter,
+ data, start_time, in_tkt_service, options);
+ krb5_get_init_creds_opt_free(options);
+ memset(buf, 0, sizeof(buf));
+ return ret;
+}
+
+static krb5_error_code
+init_creds_keyblock_key_proc (krb5_context context,
+ krb5_enctype type,
+ krb5_salt salt,
+ krb5_const_pointer keyseed,
+ krb5_keyblock **key)
+{
+ return krb5_copy_keyblock (context, keyseed, key);
+}
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_get_init_creds_keyblock(krb5_context context,
+ krb5_creds *creds,
+ krb5_principal client,
+ krb5_keyblock *keyblock,
+ krb5_deltat start_time,
+ const char *in_tkt_service,
+ krb5_get_init_creds_opt *options)
+{
+ struct krb5_get_init_creds_ctx ctx;
+ krb5_error_code ret;
+
+ ret = get_init_creds_common(context, creds, client, start_time,
+ in_tkt_service, options, &ctx);
+ if (ret)
+ goto out;
+
+ ret = krb5_get_in_cred (context,
+ ctx.flags.i,
+ ctx.addrs,
+ ctx.etypes,
+ ctx.pre_auth_types,
+ NULL,
+ init_creds_keyblock_key_proc,
+ keyblock,
+ NULL,
+ NULL,
+ &ctx.cred,
+ NULL);
+
+ if (ret == 0 && creds)
+ *creds = ctx.cred;
+ else
+ krb5_free_cred_contents (context, &ctx.cred);
+
+ out:
+ free_init_creds_ctx(context, &ctx);
+ return ret;
+}
diff --git a/source4/heimdal/lib/krb5/k524_err.et b/source4/heimdal/lib/krb5/k524_err.et
new file mode 100644
index 0000000000..2dc60f46ae
--- /dev/null
+++ b/source4/heimdal/lib/krb5/k524_err.et
@@ -0,0 +1,20 @@
+#
+# Error messages for the k524 functions
+#
+# This might look like a com_err file, but is not
+#
+id "$Id: k524_err.et,v 1.1 2001/06/20 02:44:11 joda Exp $"
+
+error_table k524
+
+prefix KRB524
+error_code BADKEY, "wrong keytype in ticket"
+error_code BADADDR, "incorrect network address"
+error_code BADPRINC, "cannot convert V5 principal" #unused
+error_code BADREALM, "V5 realm name longer than V4 maximum" #unused
+error_code V4ERR, "kerberos V4 error server"
+error_code ENCFULL, "encoding too large at server"
+error_code DECEMPTY, "decoding out of data" #unused
+error_code NOTRESP, "service not responding" #unused
+end
+
diff --git a/source4/heimdal/lib/krb5/kcm.c b/source4/heimdal/lib/krb5/kcm.c
new file mode 100644
index 0000000000..b7873f33d5
--- /dev/null
+++ b/source4/heimdal/lib/krb5/kcm.c
@@ -0,0 +1,1095 @@
+/*
+ * Copyright (c) 2005, PADL Software Pty Ltd.
+ * 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 PADL Software 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 PADL SOFTWARE 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 PADL SOFTWARE 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"
+
+#ifdef HAVE_KCM
+/*
+ * Client library for Kerberos Credentials Manager (KCM) daemon
+ */
+
+#ifdef HAVE_SYS_UN_H
+#include <sys/un.h>
+#endif
+
+#include "kcm.h"
+
+RCSID("$Id: kcm.c,v 1.7 2005/06/17 04:20:11 lha Exp $");
+
+typedef struct krb5_kcmcache {
+ char *name;
+ struct sockaddr_un path;
+ char *door_path;
+} krb5_kcmcache;
+
+#define KCMCACHE(X) ((krb5_kcmcache *)(X)->data.data)
+#define CACHENAME(X) (KCMCACHE(X)->name)
+#define KCMCURSOR(C) (*(u_int32_t *)(C))
+
+static krb5_error_code
+try_door(krb5_context context, const krb5_kcmcache *k,
+ krb5_data *request_data,
+ krb5_data *response_data)
+{
+#ifdef HAVE_DOOR_CREATE
+ door_arg_t arg;
+ int fd;
+ int ret;
+
+ memset(&arg, 0, sizeof(arg));
+
+ fd = open(k->door_path, O_RDWR);
+ if (fd < 0)
+ return KRB5_CC_IO;
+
+ arg.data_ptr = request_data->data;
+ arg.data_size = request_data->length;
+ arg.desc_ptr = NULL;
+ arg.desc_num = 0;
+ arg.rbuf = NULL;
+ arg.rsize = 0;
+
+ ret = door_call(fd, &arg);
+ close(fd);
+ if (ret != 0)
+ return KRB5_CC_IO;
+
+ ret = krb5_data_copy(response_data, arg.rbuf, arg.rsize);
+ munmap(arg.rbuf, arg.rsize);
+ if (ret)
+ return ret;
+
+ return 0;
+#else
+ return KRB5_CC_IO;
+#endif
+}
+
+static krb5_error_code
+try_unix_socket(krb5_context context, const krb5_kcmcache *k,
+ krb5_data *request_data,
+ krb5_data *response_data)
+{
+ krb5_error_code ret;
+ int fd;
+
+ fd = socket(AF_UNIX, SOCK_STREAM, 0);
+ if (fd < 0)
+ return KRB5_CC_IO;
+
+ if (connect(fd, rk_UNCONST(&k->path), sizeof(k->path)) != 0) {
+ close(fd);
+ return KRB5_CC_IO;
+ }
+
+ ret = _krb5_send_and_recv_tcp(fd, context->kdc_timeout,
+ request_data, response_data);
+ close(fd);
+ return ret;
+}
+
+static krb5_error_code
+kcm_send_request(krb5_context context,
+ krb5_kcmcache *k,
+ krb5_storage *request,
+ krb5_data *response_data)
+{
+ krb5_error_code ret;
+ krb5_data request_data;
+ int i;
+
+ response_data->data = NULL;
+ response_data->length = 0;
+
+ ret = krb5_storage_to_data(request, &request_data);
+ if (ret) {
+ krb5_clear_error_string(context);
+ return KRB5_CC_NOMEM;
+ }
+
+ ret = KRB5_CC_IO;
+
+ for (i = 0; i < context->max_retries; i++) {
+ ret = try_door(context, k, &request_data, response_data);
+ if (ret == 0 && response_data->length != 0)
+ break;
+ ret = try_unix_socket(context, k, &request_data, response_data);
+ if (ret == 0 && response_data->length != 0)
+ break;
+ }
+
+ krb5_data_free(&request_data);
+
+ if (ret) {
+ krb5_clear_error_string(context);
+ ret = KRB5_CC_IO;
+ }
+
+ return ret;
+}
+
+static krb5_error_code
+kcm_storage_request(krb5_context context,
+ kcm_operation opcode,
+ krb5_storage **storage_p)
+{
+ krb5_storage *sp;
+ krb5_error_code ret;
+
+ *storage_p = NULL;
+
+ sp = krb5_storage_emem();
+ if (sp == NULL) {
+ krb5_set_error_string(context, "malloc: out of memory");
+ return KRB5_CC_NOMEM;
+ }
+
+ /* Send MAJOR | VERSION | OPCODE */
+ ret = krb5_store_int8(sp, KCM_PROTOCOL_VERSION_MAJOR);
+ if (ret)
+ goto fail;
+ ret = krb5_store_int8(sp, KCM_PROTOCOL_VERSION_MINOR);
+ if (ret)
+ goto fail;
+ ret = krb5_store_int16(sp, opcode);
+ if (ret)
+ goto fail;
+
+ *storage_p = sp;
+ fail:
+ if (ret) {
+ krb5_set_error_string(context, "Failed to encode request");
+ krb5_storage_free(sp);
+ }
+
+ return ret;
+}
+
+static krb5_error_code
+kcm_alloc(krb5_context context, const char *name, krb5_ccache *id)
+{
+ krb5_kcmcache *k;
+ const char *path;
+
+ k = malloc(sizeof(*k));
+ if (k == NULL) {
+ krb5_set_error_string(context, "malloc: out of memory");
+ return KRB5_CC_NOMEM;
+ }
+
+ if (name != NULL) {
+ k->name = strdup(name);
+ if (k->name == NULL) {
+ free(k);
+ krb5_set_error_string(context, "malloc: out of memory");
+ return KRB5_CC_NOMEM;
+ }
+ } else
+ k->name = NULL;
+
+ path = krb5_config_get_string_default(context, NULL,
+ _PATH_KCM_SOCKET,
+ "libdefaults",
+ "kcm_socket",
+ NULL);
+
+ k->path.sun_family = AF_UNIX;
+ strlcpy(k->path.sun_path, path, sizeof(k->path.sun_path));
+
+ path = krb5_config_get_string_default(context, NULL,
+ _PATH_KCM_DOOR,
+ "libdefaults",
+ "kcm_door",
+ NULL);
+ k->door_path = strdup(path);
+
+ (*id)->data.data = k;
+ (*id)->data.length = sizeof(*k);
+
+ return 0;
+}
+
+static krb5_error_code
+kcm_call(krb5_context context,
+ krb5_kcmcache *k,
+ krb5_storage *request,
+ krb5_storage **response_p,
+ krb5_data *response_data_p)
+{
+ krb5_data response_data;
+ krb5_error_code ret, status;
+ krb5_storage *response;
+
+ if (response_p != NULL)
+ *response_p = NULL;
+
+ ret = kcm_send_request(context, k, request, &response_data);
+ if (ret) {
+ return ret;
+ }
+
+ response = krb5_storage_from_data(&response_data);
+ if (response == NULL) {
+ krb5_data_free(&response_data);
+ return KRB5_CC_IO;
+ }
+
+ ret = krb5_ret_int32(response, &status);
+ if (ret) {
+ krb5_storage_free(response);
+ krb5_data_free(&response_data);
+ return KRB5_CC_FORMAT;
+ }
+
+ if (status) {
+ krb5_storage_free(response);
+ krb5_data_free(&response_data);
+ return status;
+ }
+
+ if (response_p != NULL) {
+ *response_data_p = response_data;
+ *response_p = response;
+
+ return 0;
+ }
+
+ krb5_storage_free(response);
+ krb5_data_free(&response_data);
+
+ return 0;
+}
+
+static void
+kcm_free(krb5_context context, krb5_ccache *id)
+{
+ krb5_kcmcache *k = KCMCACHE(*id);
+
+ if (k != NULL) {
+ if (k->name != NULL)
+ free(k->name);
+ if (k->door_path)
+ free(k->door_path);
+ memset(k, 0, sizeof(*k));
+ krb5_data_free(&(*id)->data);
+ }
+
+ *id = NULL;
+}
+
+static const char *
+kcm_get_name(krb5_context context,
+ krb5_ccache id)
+{
+ return CACHENAME(id);
+}
+
+static krb5_error_code
+kcm_resolve(krb5_context context, krb5_ccache *id, const char *res)
+{
+ return kcm_alloc(context, res, id);
+}
+
+/*
+ * Request:
+ *
+ * Response:
+ * NameZ
+ */
+static krb5_error_code
+kcm_gen_new(krb5_context context, krb5_ccache *id)
+{
+ krb5_kcmcache *k;
+ krb5_error_code ret;
+ krb5_storage *request, *response;
+ krb5_data response_data;
+
+ ret = kcm_alloc(context, NULL, id);
+ if (ret)
+ return ret;
+
+ k = KCMCACHE(*id);
+
+ ret = kcm_storage_request(context, KCM_OP_GEN_NEW, &request);
+ if (ret) {
+ kcm_free(context, id);
+ return ret;
+ }
+
+ ret = kcm_call(context, k, request, &response, &response_data);
+ if (ret) {
+ krb5_storage_free(request);
+ kcm_free(context, id);
+ return ret;
+ }
+
+ ret = krb5_ret_stringz(response, &k->name);
+ if (ret)
+ ret = KRB5_CC_IO;
+
+ krb5_storage_free(request);
+ krb5_storage_free(response);
+ krb5_data_free(&response_data);
+
+ if (ret)
+ kcm_free(context, id);
+
+ return ret;
+}
+
+/*
+ * Request:
+ * NameZ
+ * Principal
+ *
+ * Response:
+ *
+ */
+static krb5_error_code
+kcm_initialize(krb5_context context,
+ krb5_ccache id,
+ krb5_principal primary_principal)
+{
+ krb5_error_code ret;
+ krb5_kcmcache *k = KCMCACHE(id);
+ krb5_storage *request;
+
+ ret = kcm_storage_request(context, KCM_OP_INITIALIZE, &request);
+ if (ret)
+ return ret;
+
+ ret = krb5_store_stringz(request, k->name);
+ if (ret) {
+ krb5_storage_free(request);
+ return ret;
+ }
+
+ ret = krb5_store_principal(request, primary_principal);
+ if (ret) {
+ krb5_storage_free(request);
+ return ret;
+ }
+
+ ret = kcm_call(context, k, request, NULL, NULL);
+
+ krb5_storage_free(request);
+ return ret;
+}
+
+static krb5_error_code
+kcm_close(krb5_context context,
+ krb5_ccache id)
+{
+ kcm_free(context, &id);
+ return 0;
+}
+
+/*
+ * Request:
+ * NameZ
+ *
+ * Response:
+ *
+ */
+static krb5_error_code
+kcm_destroy(krb5_context context,
+ krb5_ccache id)
+{
+ krb5_error_code ret;
+ krb5_kcmcache *k = KCMCACHE(id);
+ krb5_storage *request;
+
+ ret = kcm_storage_request(context, KCM_OP_DESTROY, &request);
+ if (ret)
+ return ret;
+
+ ret = krb5_store_stringz(request, k->name);
+ if (ret) {
+ krb5_storage_free(request);
+ return ret;
+ }
+
+ ret = kcm_call(context, k, request, NULL, NULL);
+
+ krb5_storage_free(request);
+ return ret;
+}
+
+/*
+ * Request:
+ * NameZ
+ * Creds
+ *
+ * Response:
+ *
+ */
+static krb5_error_code
+kcm_store_cred(krb5_context context,
+ krb5_ccache id,
+ krb5_creds *creds)
+{
+ krb5_error_code ret;
+ krb5_kcmcache *k = KCMCACHE(id);
+ krb5_storage *request;
+
+ ret = kcm_storage_request(context, KCM_OP_STORE, &request);
+ if (ret)
+ return ret;
+
+ ret = krb5_store_stringz(request, k->name);
+ if (ret) {
+ krb5_storage_free(request);
+ return ret;
+ }
+
+ ret = krb5_store_creds(request, creds);
+ if (ret) {
+ krb5_storage_free(request);
+ return ret;
+ }
+
+ ret = kcm_call(context, k, request, NULL, NULL);
+
+ krb5_storage_free(request);
+ return ret;
+}
+
+/*
+ * Request:
+ * NameZ
+ * WhichFields
+ * MatchCreds
+ *
+ * Response:
+ * Creds
+ *
+ */
+static krb5_error_code
+kcm_retrieve(krb5_context context,
+ krb5_ccache id,
+ krb5_flags which,
+ const krb5_creds *mcred,
+ krb5_creds *creds)
+{
+ krb5_error_code ret;
+ krb5_kcmcache *k = KCMCACHE(id);
+ krb5_storage *request, *response;
+ krb5_data response_data;
+
+ ret = kcm_storage_request(context, KCM_OP_RETRIEVE, &request);
+ if (ret)
+ return ret;
+
+ ret = krb5_store_stringz(request, k->name);
+ if (ret) {
+ krb5_storage_free(request);
+ return ret;
+ }
+
+ ret = krb5_store_int32(request, which);
+ if (ret) {
+ krb5_storage_free(request);
+ return ret;
+ }
+
+ ret = krb5_store_creds_tag(request, rk_UNCONST(mcred));
+ if (ret) {
+ krb5_storage_free(request);
+ return ret;
+ }
+
+ ret = kcm_call(context, k, request, &response, &response_data);
+ if (ret) {
+ krb5_storage_free(request);
+ return ret;
+ }
+
+ ret = krb5_ret_creds(response, creds);
+ if (ret)
+ ret = KRB5_CC_IO;
+
+ krb5_storage_free(request);
+ krb5_storage_free(response);
+ krb5_data_free(&response_data);
+
+ return ret;
+}
+
+/*
+ * Request:
+ * NameZ
+ *
+ * Response:
+ * Principal
+ */
+static krb5_error_code
+kcm_get_principal(krb5_context context,
+ krb5_ccache id,
+ krb5_principal *principal)
+{
+ krb5_error_code ret;
+ krb5_kcmcache *k = KCMCACHE(id);
+ krb5_storage *request, *response;
+ krb5_data response_data;
+
+ ret = kcm_storage_request(context, KCM_OP_GET_PRINCIPAL, &request);
+ if (ret)
+ return ret;
+
+ ret = krb5_store_stringz(request, k->name);
+ if (ret) {
+ krb5_storage_free(request);
+ return ret;
+ }
+
+ ret = kcm_call(context, k, request, &response, &response_data);
+ if (ret) {
+ krb5_storage_free(request);
+ return ret;
+ }
+
+ ret = krb5_ret_principal(response, principal);
+ if (ret)
+ ret = KRB5_CC_IO;
+
+ krb5_storage_free(request);
+ krb5_storage_free(response);
+ krb5_data_free(&response_data);
+
+ return ret;
+}
+
+/*
+ * Request:
+ * NameZ
+ *
+ * Response:
+ * Cursor
+ *
+ */
+static krb5_error_code
+kcm_get_first (krb5_context context,
+ krb5_ccache id,
+ krb5_cc_cursor *cursor)
+{
+ krb5_error_code ret;
+ krb5_kcmcache *k = KCMCACHE(id);
+ krb5_storage *request, *response;
+ krb5_data response_data;
+ u_int32_t tmp;
+
+ ret = kcm_storage_request(context, KCM_OP_GET_FIRST, &request);
+ if (ret)
+ return ret;
+
+ ret = krb5_store_stringz(request, k->name);
+ if (ret) {
+ krb5_storage_free(request);
+ return ret;
+ }
+
+ ret = kcm_call(context, k, request, &response, &response_data);
+ if (ret) {
+ krb5_storage_free(request);
+ return ret;
+ }
+
+ ret = krb5_ret_int32(response, &tmp);
+ if (ret)
+ ret = KRB5_CC_IO;
+
+ krb5_storage_free(request);
+ krb5_storage_free(response);
+ krb5_data_free(&response_data);
+
+ if (ret)
+ return ret;
+
+ *cursor = malloc(sizeof(tmp));
+ if (*cursor == NULL)
+ return KRB5_CC_NOMEM;
+
+ KCMCURSOR(*cursor) = tmp;
+
+ return 0;
+}
+
+/*
+ * Request:
+ * NameZ
+ * Cursor
+ *
+ * Response:
+ * Creds
+ */
+static krb5_error_code
+kcm_get_next (krb5_context context,
+ krb5_ccache id,
+ krb5_cc_cursor *cursor,
+ krb5_creds *creds)
+{
+ krb5_error_code ret;
+ krb5_kcmcache *k = KCMCACHE(id);
+ krb5_storage *request, *response;
+ krb5_data response_data;
+
+ ret = kcm_storage_request(context, KCM_OP_GET_NEXT, &request);
+ if (ret)
+ return ret;
+
+ ret = krb5_store_stringz(request, k->name);
+ if (ret) {
+ krb5_storage_free(request);
+ return ret;
+ }
+
+ ret = krb5_store_int32(request, KCMCURSOR(*cursor));
+ if (ret) {
+ krb5_storage_free(request);
+ return ret;
+ }
+
+ ret = kcm_call(context, k, request, &response, &response_data);
+ if (ret) {
+ krb5_storage_free(request);
+ return ret;
+ }
+
+ ret = krb5_ret_creds(response, creds);
+ if (ret)
+ ret = KRB5_CC_IO;
+
+ krb5_storage_free(request);
+ krb5_storage_free(response);
+ krb5_data_free(&response_data);
+
+ return ret;
+}
+
+/*
+ * Request:
+ * NameZ
+ * Cursor
+ *
+ * Response:
+ *
+ */
+static krb5_error_code
+kcm_end_get (krb5_context context,
+ krb5_ccache id,
+ krb5_cc_cursor *cursor)
+{
+ krb5_error_code ret;
+ krb5_kcmcache *k = KCMCACHE(id);
+ krb5_storage *request;
+
+ ret = kcm_storage_request(context, KCM_OP_END_GET, &request);
+ if (ret)
+ return ret;
+
+ ret = krb5_store_stringz(request, k->name);
+ if (ret) {
+ krb5_storage_free(request);
+ return ret;
+ }
+
+ ret = krb5_store_int32(request, KCMCURSOR(*cursor));
+ if (ret) {
+ krb5_storage_free(request);
+ return ret;
+ }
+
+ ret = kcm_call(context, k, request, NULL, NULL);
+ if (ret) {
+ krb5_storage_free(request);
+ return ret;
+ }
+
+ krb5_storage_free(request);
+
+ KCMCURSOR(*cursor) = 0;
+ free(*cursor);
+ *cursor = NULL;
+
+ return ret;
+}
+
+/*
+ * Request:
+ * NameZ
+ * WhichFields
+ * MatchCreds
+ *
+ * Response:
+ *
+ */
+static krb5_error_code
+kcm_remove_cred(krb5_context context,
+ krb5_ccache id,
+ krb5_flags which,
+ krb5_creds *cred)
+{
+ krb5_error_code ret;
+ krb5_kcmcache *k = KCMCACHE(id);
+ krb5_storage *request;
+
+ ret = kcm_storage_request(context, KCM_OP_REMOVE_CRED, &request);
+ if (ret)
+ return ret;
+
+ ret = krb5_store_stringz(request, k->name);
+ if (ret) {
+ krb5_storage_free(request);
+ return ret;
+ }
+
+ ret = krb5_store_int32(request, which);
+ if (ret) {
+ krb5_storage_free(request);
+ return ret;
+ }
+
+ ret = krb5_store_creds_tag(request, cred);
+ if (ret) {
+ krb5_storage_free(request);
+ return ret;
+ }
+
+ ret = kcm_call(context, k, request, NULL, NULL);
+
+ krb5_storage_free(request);
+ return ret;
+}
+
+static krb5_error_code
+kcm_set_flags(krb5_context context,
+ krb5_ccache id,
+ krb5_flags flags)
+{
+ krb5_error_code ret;
+ krb5_kcmcache *k = KCMCACHE(id);
+ krb5_storage *request;
+
+ ret = kcm_storage_request(context, KCM_OP_SET_FLAGS, &request);
+ if (ret)
+ return ret;
+
+ ret = krb5_store_stringz(request, k->name);
+ if (ret) {
+ krb5_storage_free(request);
+ return ret;
+ }
+
+ ret = krb5_store_int32(request, flags);
+ if (ret) {
+ krb5_storage_free(request);
+ return ret;
+ }
+
+ ret = kcm_call(context, k, request, NULL, NULL);
+
+ krb5_storage_free(request);
+ return ret;
+}
+
+static krb5_error_code
+kcm_get_version(krb5_context context,
+ krb5_ccache id)
+{
+ return 0;
+}
+
+const krb5_cc_ops krb5_kcm_ops = {
+ "KCM",
+ kcm_get_name,
+ kcm_resolve,
+ kcm_gen_new,
+ kcm_initialize,
+ kcm_destroy,
+ kcm_close,
+ kcm_store_cred,
+ kcm_retrieve,
+ kcm_get_principal,
+ kcm_get_first,
+ kcm_get_next,
+ kcm_end_get,
+ kcm_remove_cred,
+ kcm_set_flags,
+ kcm_get_version
+};
+
+krb5_boolean
+_krb5_kcm_is_running(krb5_context context)
+{
+ krb5_error_code ret;
+ krb5_ccache_data ccdata;
+ krb5_ccache id = &ccdata;
+ krb5_boolean running;
+
+ ret = kcm_alloc(context, NULL, &id);
+ if (ret)
+ return 0;
+
+ running = (_krb5_kcm_noop(context, id) == 0);
+
+ kcm_free(context, &id);
+
+ return running;
+}
+
+/*
+ * Request:
+ *
+ * Response:
+ *
+ */
+krb5_error_code
+_krb5_kcm_noop(krb5_context context,
+ krb5_ccache id)
+{
+ krb5_error_code ret;
+ krb5_kcmcache *k = KCMCACHE(id);
+ krb5_storage *request;
+
+ ret = kcm_storage_request(context, KCM_OP_NOOP, &request);
+ if (ret)
+ return ret;
+
+ ret = kcm_call(context, k, request, NULL, NULL);
+
+ krb5_storage_free(request);
+ return ret;
+}
+
+
+/*
+ * Request:
+ * NameZ
+ * Mode
+ *
+ * Response:
+ *
+ */
+krb5_error_code
+_krb5_kcm_chmod(krb5_context context,
+ krb5_ccache id,
+ u_int16_t mode)
+{
+ krb5_error_code ret;
+ krb5_kcmcache *k = KCMCACHE(id);
+ krb5_storage *request;
+
+ ret = kcm_storage_request(context, KCM_OP_CHMOD, &request);
+ if (ret)
+ return ret;
+
+ ret = krb5_store_stringz(request, k->name);
+ if (ret) {
+ krb5_storage_free(request);
+ return ret;
+ }
+
+ ret = krb5_store_int16(request, mode);
+ if (ret) {
+ krb5_storage_free(request);
+ return ret;
+ }
+
+ ret = kcm_call(context, k, request, NULL, NULL);
+
+ krb5_storage_free(request);
+ return ret;
+}
+
+
+/*
+ * Request:
+ * NameZ
+ * UID
+ * GID
+ *
+ * Response:
+ *
+ */
+krb5_error_code
+_krb5_kcm_chown(krb5_context context,
+ krb5_ccache id,
+ u_int32_t uid,
+ u_int32_t gid)
+{
+ krb5_error_code ret;
+ krb5_kcmcache *k = KCMCACHE(id);
+ krb5_storage *request;
+
+ ret = kcm_storage_request(context, KCM_OP_CHOWN, &request);
+ if (ret)
+ return ret;
+
+ ret = krb5_store_stringz(request, k->name);
+ if (ret) {
+ krb5_storage_free(request);
+ return ret;
+ }
+
+ ret = krb5_store_int32(request, uid);
+ if (ret) {
+ krb5_storage_free(request);
+ return ret;
+ }
+
+ ret = krb5_store_int32(request, gid);
+ if (ret) {
+ krb5_storage_free(request);
+ return ret;
+ }
+
+ ret = kcm_call(context, k, request, NULL, NULL);
+
+ krb5_storage_free(request);
+ return ret;
+}
+
+
+/*
+ * Request:
+ * NameZ
+ * ServerPrincipalPresent
+ * ServerPrincipal OPTIONAL
+ * Key
+ *
+ * Repsonse:
+ *
+ */
+krb5_error_code
+_krb5_kcm_get_initial_ticket(krb5_context context,
+ krb5_ccache id,
+ krb5_principal server,
+ krb5_keyblock *key)
+{
+ krb5_error_code ret;
+ krb5_kcmcache *k = KCMCACHE(id);
+ krb5_storage *request;
+
+ ret = kcm_storage_request(context, KCM_OP_GET_INITIAL_TICKET, &request);
+ if (ret)
+ return ret;
+
+ ret = krb5_store_stringz(request, k->name);
+ if (ret) {
+ krb5_storage_free(request);
+ return ret;
+ }
+
+ ret = krb5_store_int8(request, (server == NULL) ? 0 : 1);
+ if (ret) {
+ krb5_storage_free(request);
+ return ret;
+ }
+
+ if (server != NULL) {
+ ret = krb5_store_principal(request, server);
+ if (ret) {
+ krb5_storage_free(request);
+ return ret;
+ }
+ }
+
+ ret = krb5_store_keyblock(request, *key);
+ if (ret) {
+ krb5_storage_free(request);
+ return ret;
+ }
+
+ ret = kcm_call(context, k, request, NULL, NULL);
+
+ krb5_storage_free(request);
+ return ret;
+}
+
+
+/*
+ * Request:
+ * NameZ
+ * KDCFlags
+ * EncryptionType
+ * ServerPrincipal
+ *
+ * Repsonse:
+ *
+ */
+krb5_error_code
+_krb5_kcm_get_ticket(krb5_context context,
+ krb5_ccache id,
+ krb5_kdc_flags flags,
+ krb5_enctype enctype,
+ krb5_principal server)
+{
+ krb5_error_code ret;
+ krb5_kcmcache *k = KCMCACHE(id);
+ krb5_storage *request;
+
+ ret = kcm_storage_request(context, KCM_OP_GET_TICKET, &request);
+ if (ret)
+ return ret;
+
+ ret = krb5_store_stringz(request, k->name);
+ if (ret) {
+ krb5_storage_free(request);
+ return ret;
+ }
+
+ ret = krb5_store_int32(request, flags.i);
+ if (ret) {
+ krb5_storage_free(request);
+ return ret;
+ }
+
+ ret = krb5_store_int32(request, enctype);
+ if (ret) {
+ krb5_storage_free(request);
+ return ret;
+ }
+
+ ret = krb5_store_principal(request, server);
+ if (ret) {
+ krb5_storage_free(request);
+ return ret;
+ }
+
+ ret = kcm_call(context, k, request, NULL, NULL);
+
+ krb5_storage_free(request);
+ return ret;
+}
+
+
+#endif /* HAVE_KCM */
diff --git a/source4/heimdal/lib/krb5/keyblock.c b/source4/heimdal/lib/krb5/keyblock.c
new file mode 100644
index 0000000000..314d97978b
--- /dev/null
+++ b/source4/heimdal/lib/krb5/keyblock.c
@@ -0,0 +1,133 @@
+/*
+ * Copyright (c) 1997 - 2001 Kungliga Tekniska Högskolan
+ * (Royal Institute of Technology, Stockholm, Sweden).
+ * 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"
+
+RCSID("$Id: keyblock.c,v 1.17 2005/05/18 04:21:31 lha Exp $");
+
+void KRB5_LIB_FUNCTION
+krb5_keyblock_zero(krb5_keyblock *keyblock)
+{
+ keyblock->keytype = 0;
+ krb5_data_zero(&keyblock->keyvalue);
+}
+
+void KRB5_LIB_FUNCTION
+krb5_free_keyblock_contents(krb5_context context,
+ krb5_keyblock *keyblock)
+{
+ if(keyblock) {
+ if (keyblock->keyvalue.data != NULL)
+ memset(keyblock->keyvalue.data, 0, keyblock->keyvalue.length);
+ krb5_data_free (&keyblock->keyvalue);
+ keyblock->keytype = ENCTYPE_NULL;
+ }
+}
+
+void KRB5_LIB_FUNCTION
+krb5_free_keyblock(krb5_context context,
+ krb5_keyblock *keyblock)
+{
+ if(keyblock){
+ krb5_free_keyblock_contents(context, keyblock);
+ free(keyblock);
+ }
+}
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_copy_keyblock_contents (krb5_context context,
+ const krb5_keyblock *inblock,
+ krb5_keyblock *to)
+{
+ return copy_EncryptionKey(inblock, to);
+}
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_copy_keyblock (krb5_context context,
+ const krb5_keyblock *inblock,
+ krb5_keyblock **to)
+{
+ krb5_keyblock *k;
+
+ k = malloc (sizeof(*k));
+ if (k == NULL) {
+ krb5_set_error_string(context, "malloc: out of memory");
+ return ENOMEM;
+ }
+ *to = k;
+ return krb5_copy_keyblock_contents (context, inblock, k);
+}
+
+krb5_enctype
+krb5_keyblock_get_enctype(const krb5_keyblock *block)
+{
+ return block->keytype;
+}
+
+/*
+ * Fill in `key' with key data of type `enctype' from `data' of length
+ * `size'. Key should be freed using krb5_free_keyblock_contents.
+ */
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_keyblock_init(krb5_context context,
+ krb5_enctype type,
+ const void *data,
+ size_t size,
+ krb5_keyblock *key)
+{
+ krb5_error_code ret;
+ size_t len;
+
+ memset(key, 0, sizeof(*key));
+
+ ret = krb5_enctype_keysize(context, type, &len);
+ if (ret)
+ return ret;
+
+ if (len != size) {
+ krb5_set_error_string(context, "Encryption key %d is %lu bytes "
+ "long, %lu was passed in",
+ type, (unsigned long)len, (unsigned long)size);
+ return KRB5_PROG_ETYPE_NOSUPP;
+ }
+ ret = krb5_data_copy(&key->keyvalue, data, len);
+ if(ret) {
+ krb5_set_error_string(context, "malloc failed: %lu",
+ (unsigned long)len);
+ return ret;
+ }
+ key->keytype = type;
+
+ return 0;
+}
diff --git a/source4/heimdal/lib/krb5/keytab.c b/source4/heimdal/lib/krb5/keytab.c
new file mode 100644
index 0000000000..a405664122
--- /dev/null
+++ b/source4/heimdal/lib/krb5/keytab.c
@@ -0,0 +1,491 @@
+/*
+ * Copyright (c) 1997 - 2005 Kungliga Tekniska Högskolan
+ * (Royal Institute of Technology, Stockholm, Sweden).
+ * 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"
+
+RCSID("$Id: keytab.c,v 1.60 2005/05/19 14:04:45 lha Exp $");
+
+/*
+ * Register a new keytab in `ops'
+ * Return 0 or an error.
+ */
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_kt_register(krb5_context context,
+ const krb5_kt_ops *ops)
+{
+ struct krb5_keytab_data *tmp;
+
+ if (strlen(ops->prefix) > KRB5_KT_PREFIX_MAX_LEN - 1) {
+ krb5_set_error_string(context, "krb5_kt_register; prefix too long");
+ return KRB5_KT_BADNAME;
+ }
+
+ tmp = realloc(context->kt_types,
+ (context->num_kt_types + 1) * sizeof(*context->kt_types));
+ if(tmp == NULL) {
+ krb5_set_error_string(context, "malloc: out of memory");
+ return ENOMEM;
+ }
+ memcpy(&tmp[context->num_kt_types], ops,
+ sizeof(tmp[context->num_kt_types]));
+ context->kt_types = tmp;
+ context->num_kt_types++;
+ return 0;
+}
+
+/*
+ * Resolve the keytab name (of the form `type:residual') in `name'
+ * into a keytab in `id'.
+ * Return 0 or an error
+ */
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_kt_resolve(krb5_context context,
+ const char *name,
+ krb5_keytab *id)
+{
+ krb5_keytab k;
+ int i;
+ const char *type, *residual;
+ size_t type_len;
+ krb5_error_code ret;
+
+ residual = strchr(name, ':');
+ if(residual == NULL) {
+ type = "FILE";
+ type_len = strlen(type);
+ residual = name;
+ } else {
+ type = name;
+ type_len = residual - name;
+ residual++;
+ }
+
+ for(i = 0; i < context->num_kt_types; i++) {
+ if(strncasecmp(type, context->kt_types[i].prefix, type_len) == 0)
+ break;
+ }
+ if(i == context->num_kt_types) {
+ krb5_set_error_string(context, "unknown keytab type %.*s",
+ (int)type_len, type);
+ return KRB5_KT_UNKNOWN_TYPE;
+ }
+
+ k = malloc (sizeof(*k));
+ if (k == NULL) {
+ krb5_set_error_string(context, "malloc: out of memory");
+ return ENOMEM;
+ }
+ memcpy(k, &context->kt_types[i], sizeof(*k));
+ k->data = NULL;
+ ret = (*k->resolve)(context, residual, k);
+ if(ret) {
+ free(k);
+ k = NULL;
+ }
+ *id = k;
+ return ret;
+}
+
+/*
+ * copy the name of the default keytab into `name'.
+ * Return 0 or KRB5_CONFIG_NOTENUFSPACE if `namesize' is too short.
+ */
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_kt_default_name(krb5_context context, char *name, size_t namesize)
+{
+ if (strlcpy (name, context->default_keytab, namesize) >= namesize) {
+ krb5_clear_error_string (context);
+ return KRB5_CONFIG_NOTENUFSPACE;
+ }
+ return 0;
+}
+
+/*
+ * copy the name of the default modify keytab into `name'.
+ * Return 0 or KRB5_CONFIG_NOTENUFSPACE if `namesize' is too short.
+ */
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_kt_default_modify_name(krb5_context context, char *name, size_t namesize)
+{
+ const char *kt = NULL;
+ if(context->default_keytab_modify == NULL) {
+ if(strncasecmp(context->default_keytab, "ANY:", 4) != 0)
+ kt = context->default_keytab;
+ else {
+ size_t len = strcspn(context->default_keytab + 4, ",");
+ if(len >= namesize) {
+ krb5_clear_error_string(context);
+ return KRB5_CONFIG_NOTENUFSPACE;
+ }
+ strlcpy(name, context->default_keytab + 4, namesize);
+ name[len] = '\0';
+ return 0;
+ }
+ } else
+ kt = context->default_keytab_modify;
+ if (strlcpy (name, kt, namesize) >= namesize) {
+ krb5_clear_error_string (context);
+ return KRB5_CONFIG_NOTENUFSPACE;
+ }
+ return 0;
+}
+
+/*
+ * Set `id' to the default keytab.
+ * Return 0 or an error.
+ */
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_kt_default(krb5_context context, krb5_keytab *id)
+{
+ return krb5_kt_resolve (context, context->default_keytab, id);
+}
+
+/*
+ * Read the key identified by `(principal, vno, enctype)' from the
+ * keytab in `keyprocarg' (the default if == NULL) into `*key'.
+ * Return 0 or an error.
+ */
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_kt_read_service_key(krb5_context context,
+ krb5_pointer keyprocarg,
+ krb5_principal principal,
+ krb5_kvno vno,
+ krb5_enctype enctype,
+ krb5_keyblock **key)
+{
+ krb5_keytab keytab;
+ krb5_keytab_entry entry;
+ krb5_error_code ret;
+
+ if (keyprocarg)
+ ret = krb5_kt_resolve (context, keyprocarg, &keytab);
+ else
+ ret = krb5_kt_default (context, &keytab);
+
+ if (ret)
+ return ret;
+
+ ret = krb5_kt_get_entry (context, keytab, principal, vno, enctype, &entry);
+ krb5_kt_close (context, keytab);
+ if (ret)
+ return ret;
+ ret = krb5_copy_keyblock (context, &entry.keyblock, key);
+ krb5_kt_free_entry(context, &entry);
+ return ret;
+}
+
+/*
+ * Return the type of the `keytab' in the string `prefix of length
+ * `prefixsize'.
+ */
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_kt_get_type(krb5_context context,
+ krb5_keytab keytab,
+ char *prefix,
+ size_t prefixsize)
+{
+ strlcpy(prefix, keytab->prefix, prefixsize);
+ return 0;
+}
+
+/*
+ * Retrieve the name of the keytab `keytab' into `name', `namesize'
+ * Return 0 or an error.
+ */
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_kt_get_name(krb5_context context,
+ krb5_keytab keytab,
+ char *name,
+ size_t namesize)
+{
+ return (*keytab->get_name)(context, keytab, name, namesize);
+}
+
+/*
+ * Finish using the keytab in `id'. All resources will be released.
+ * Return 0 or an error.
+ */
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_kt_close(krb5_context context,
+ krb5_keytab id)
+{
+ krb5_error_code ret;
+
+ ret = (*id->close)(context, id);
+ if(ret == 0)
+ free(id);
+ return ret;
+}
+
+/*
+ * Compare `entry' against `principal, vno, enctype'.
+ * Any of `principal, vno, enctype' might be 0 which acts as a wildcard.
+ * Return TRUE if they compare the same, FALSE otherwise.
+ */
+
+krb5_boolean KRB5_LIB_FUNCTION
+krb5_kt_compare(krb5_context context,
+ krb5_keytab_entry *entry,
+ krb5_const_principal principal,
+ krb5_kvno vno,
+ krb5_enctype enctype)
+{
+ if(principal != NULL &&
+ !krb5_principal_compare(context, entry->principal, principal))
+ return FALSE;
+ if(vno && vno != entry->vno)
+ return FALSE;
+ if(enctype && enctype != entry->keyblock.keytype)
+ return FALSE;
+ return TRUE;
+}
+
+/*
+ * Retrieve the keytab entry for `principal, kvno, enctype' into `entry'
+ * from the keytab `id'.
+ * kvno == 0 is a wildcard and gives the keytab with the highest vno.
+ * Return 0 or an error.
+ */
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_kt_get_entry(krb5_context context,
+ krb5_keytab id,
+ krb5_const_principal principal,
+ krb5_kvno kvno,
+ krb5_enctype enctype,
+ krb5_keytab_entry *entry)
+{
+ krb5_keytab_entry tmp;
+ krb5_error_code ret;
+ krb5_kt_cursor cursor;
+
+ if(id->get)
+ return (*id->get)(context, id, principal, kvno, enctype, entry);
+
+ ret = krb5_kt_start_seq_get (context, id, &cursor);
+ if (ret)
+ return KRB5_KT_NOTFOUND; /* XXX i.e. file not found */
+
+ entry->vno = 0;
+ while (krb5_kt_next_entry(context, id, &tmp, &cursor) == 0) {
+ if (krb5_kt_compare(context, &tmp, principal, 0, enctype)) {
+ /* the file keytab might only store the lower 8 bits of
+ the kvno, so only compare those bits */
+ if (kvno == tmp.vno
+ || (tmp.vno < 256 && kvno % 256 == tmp.vno)) {
+ krb5_kt_copy_entry_contents (context, &tmp, entry);
+ krb5_kt_free_entry (context, &tmp);
+ krb5_kt_end_seq_get(context, id, &cursor);
+ return 0;
+ } else if (kvno == 0 && tmp.vno > entry->vno) {
+ if (entry->vno)
+ krb5_kt_free_entry (context, entry);
+ krb5_kt_copy_entry_contents (context, &tmp, entry);
+ }
+ }
+ krb5_kt_free_entry(context, &tmp);
+ }
+ krb5_kt_end_seq_get (context, id, &cursor);
+ if (entry->vno) {
+ return 0;
+ } else {
+ char princ[256], kt_name[256], kvno_str[25];
+ char *enctype_str = NULL;
+
+ krb5_unparse_name_fixed (context, principal, princ, sizeof(princ));
+ krb5_kt_get_name (context, id, kt_name, sizeof(kt_name));
+ krb5_enctype_to_string(context, enctype, &enctype_str);
+
+ if (kvno)
+ snprintf(kvno_str, sizeof(kvno_str), "(kvno %d)", kvno);
+ else
+ kvno_str[0] = '\0';
+
+ krb5_set_error_string (context,
+ "failed to find %s%s in keytab %s (%s)",
+ princ,
+ kvno_str,
+ kt_name,
+ enctype_str ? enctype_str : "unknown enctype");
+ free(enctype_str);
+ return KRB5_KT_NOTFOUND;
+ }
+}
+
+/*
+ * Copy the contents of `in' into `out'.
+ * Return 0 or an error. */
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_kt_copy_entry_contents(krb5_context context,
+ const krb5_keytab_entry *in,
+ krb5_keytab_entry *out)
+{
+ krb5_error_code ret;
+
+ memset(out, 0, sizeof(*out));
+ out->vno = in->vno;
+
+ ret = krb5_copy_principal (context, in->principal, &out->principal);
+ if (ret)
+ goto fail;
+ ret = krb5_copy_keyblock_contents (context,
+ &in->keyblock,
+ &out->keyblock);
+ if (ret)
+ goto fail;
+ out->timestamp = in->timestamp;
+ return 0;
+fail:
+ krb5_kt_free_entry (context, out);
+ return ret;
+}
+
+/*
+ * Free the contents of `entry'.
+ */
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_kt_free_entry(krb5_context context,
+ krb5_keytab_entry *entry)
+{
+ krb5_free_principal (context, entry->principal);
+ krb5_free_keyblock_contents (context, &entry->keyblock);
+ memset(entry, 0, sizeof(*entry));
+ return 0;
+}
+
+/*
+ * Set `cursor' to point at the beginning of `id'.
+ * Return 0 or an error.
+ */
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_kt_start_seq_get(krb5_context context,
+ krb5_keytab id,
+ krb5_kt_cursor *cursor)
+{
+ if(id->start_seq_get == NULL) {
+ krb5_set_error_string(context,
+ "start_seq_get is not supported in the %s "
+ " keytab", id->prefix);
+ return HEIM_ERR_OPNOTSUPP;
+ }
+ return (*id->start_seq_get)(context, id, cursor);
+}
+
+/*
+ * Get the next entry from `id' pointed to by `cursor' and advance the
+ * `cursor'.
+ * Return 0 or an error.
+ */
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_kt_next_entry(krb5_context context,
+ krb5_keytab id,
+ krb5_keytab_entry *entry,
+ krb5_kt_cursor *cursor)
+{
+ if(id->next_entry == NULL) {
+ krb5_set_error_string(context,
+ "next_entry is not supported in the %s "
+ " keytab", id->prefix);
+ return HEIM_ERR_OPNOTSUPP;
+ }
+ return (*id->next_entry)(context, id, entry, cursor);
+}
+
+/*
+ * Release all resources associated with `cursor'.
+ */
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_kt_end_seq_get(krb5_context context,
+ krb5_keytab id,
+ krb5_kt_cursor *cursor)
+{
+ if(id->end_seq_get == NULL) {
+ krb5_set_error_string(context,
+ "end_seq_get is not supported in the %s "
+ " keytab", id->prefix);
+ return HEIM_ERR_OPNOTSUPP;
+ }
+ return (*id->end_seq_get)(context, id, cursor);
+}
+
+/*
+ * Add the entry in `entry' to the keytab `id'.
+ * Return 0 or an error.
+ */
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_kt_add_entry(krb5_context context,
+ krb5_keytab id,
+ krb5_keytab_entry *entry)
+{
+ if(id->add == NULL) {
+ krb5_set_error_string(context, "Add is not supported in the %s keytab",
+ id->prefix);
+ return KRB5_KT_NOWRITE;
+ }
+ entry->timestamp = time(NULL);
+ return (*id->add)(context, id,entry);
+}
+
+/*
+ * Remove the entry `entry' from the keytab `id'.
+ * Return 0 or an error.
+ */
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_kt_remove_entry(krb5_context context,
+ krb5_keytab id,
+ krb5_keytab_entry *entry)
+{
+ if(id->remove == NULL) {
+ krb5_set_error_string(context,
+ "Remove is not supported in the %s keytab",
+ id->prefix);
+ return KRB5_KT_NOWRITE;
+ }
+ return (*id->remove)(context, id, entry);
+}
diff --git a/source4/heimdal/lib/krb5/keytab_any.c b/source4/heimdal/lib/krb5/keytab_any.c
new file mode 100644
index 0000000000..667788c69d
--- /dev/null
+++ b/source4/heimdal/lib/krb5/keytab_any.c
@@ -0,0 +1,256 @@
+/*
+ * Copyright (c) 2001-2002 Kungliga Tekniska Högskolan
+ * (Royal Institute of Technology, Stockholm, Sweden).
+ * 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"
+
+RCSID("$Id: keytab_any.c,v 1.7 2002/10/21 13:36:59 joda Exp $");
+
+struct any_data {
+ krb5_keytab kt;
+ char *name;
+ struct any_data *next;
+};
+
+static void
+free_list (krb5_context context, struct any_data *a)
+{
+ struct any_data *next;
+
+ for (; a != NULL; a = next) {
+ next = a->next;
+ free (a->name);
+ if(a->kt)
+ krb5_kt_close(context, a->kt);
+ free (a);
+ }
+}
+
+static krb5_error_code
+any_resolve(krb5_context context, const char *name, krb5_keytab id)
+{
+ struct any_data *a, *a0 = NULL, *prev = NULL;
+ krb5_error_code ret;
+ char buf[256];
+
+ while (strsep_copy(&name, ",", buf, sizeof(buf)) != -1) {
+ a = malloc(sizeof(*a));
+ if (a == NULL) {
+ ret = ENOMEM;
+ goto fail;
+ }
+ if (a0 == NULL) {
+ a0 = a;
+ a->name = strdup(buf);
+ if (a->name == NULL) {
+ krb5_set_error_string(context, "malloc: out of memory");
+ ret = ENOMEM;
+ goto fail;
+ }
+ } else
+ a->name = NULL;
+ if (prev != NULL)
+ prev->next = a;
+ a->next = NULL;
+ ret = krb5_kt_resolve (context, buf, &a->kt);
+ if (ret)
+ goto fail;
+ prev = a;
+ }
+ if (a0 == NULL) {
+ krb5_set_error_string(context, "empty ANY: keytab");
+ return ENOENT;
+ }
+ id->data = a0;
+ return 0;
+ fail:
+ free_list (context, a0);
+ return ret;
+}
+
+static krb5_error_code
+any_get_name (krb5_context context,
+ krb5_keytab id,
+ char *name,
+ size_t namesize)
+{
+ struct any_data *a = id->data;
+ strlcpy(name, a->name, namesize);
+ return 0;
+}
+
+static krb5_error_code
+any_close (krb5_context context,
+ krb5_keytab id)
+{
+ struct any_data *a = id->data;
+
+ free_list (context, a);
+ return 0;
+}
+
+struct any_cursor_extra_data {
+ struct any_data *a;
+ krb5_kt_cursor cursor;
+};
+
+static krb5_error_code
+any_start_seq_get(krb5_context context,
+ krb5_keytab id,
+ krb5_kt_cursor *c)
+{
+ struct any_data *a = id->data;
+ struct any_cursor_extra_data *ed;
+ krb5_error_code ret;
+
+ c->data = malloc (sizeof(struct any_cursor_extra_data));
+ if(c->data == NULL){
+ krb5_set_error_string (context, "malloc: out of memory");
+ return ENOMEM;
+ }
+ ed = (struct any_cursor_extra_data *)c->data;
+ ed->a = a;
+ ret = krb5_kt_start_seq_get(context, ed->a->kt, &ed->cursor);
+ if (ret) {
+ free (c->data);
+ c->data = NULL;
+ return ret;
+ }
+ return 0;
+}
+
+static krb5_error_code
+any_next_entry (krb5_context context,
+ krb5_keytab id,
+ krb5_keytab_entry *entry,
+ krb5_kt_cursor *cursor)
+{
+ krb5_error_code ret, ret2;
+ struct any_cursor_extra_data *ed;
+
+ ed = (struct any_cursor_extra_data *)cursor->data;
+ do {
+ ret = krb5_kt_next_entry(context, ed->a->kt, entry, &ed->cursor);
+ if (ret == 0)
+ return 0;
+ else if (ret == KRB5_KT_END) {
+ ret2 = krb5_kt_end_seq_get (context, ed->a->kt, &ed->cursor);
+ if (ret2)
+ return ret2;
+ while ((ed->a = ed->a->next) != NULL) {
+ ret2 = krb5_kt_start_seq_get(context, ed->a->kt, &ed->cursor);
+ if (ret2 == 0)
+ break;
+ }
+ if (ed->a == NULL) {
+ krb5_clear_error_string (context);
+ return KRB5_KT_END;
+ }
+ } else
+ return ret;
+ } while (ret == KRB5_KT_END);
+ return ret;
+}
+
+static krb5_error_code
+any_end_seq_get(krb5_context context,
+ krb5_keytab id,
+ krb5_kt_cursor *cursor)
+{
+ krb5_error_code ret = 0;
+ struct any_cursor_extra_data *ed;
+
+ ed = (struct any_cursor_extra_data *)cursor->data;
+ if (ed->a != NULL)
+ ret = krb5_kt_end_seq_get(context, ed->a->kt, &ed->cursor);
+ free (ed);
+ cursor->data = NULL;
+ return ret;
+}
+
+static krb5_error_code
+any_add_entry(krb5_context context,
+ krb5_keytab id,
+ krb5_keytab_entry *entry)
+{
+ struct any_data *a = id->data;
+ krb5_error_code ret;
+ while(a != NULL) {
+ ret = krb5_kt_add_entry(context, a->kt, entry);
+ if(ret != 0 && ret != KRB5_KT_NOWRITE) {
+ krb5_set_error_string(context, "failed to add entry to %s",
+ a->name);
+ return ret;
+ }
+ a = a->next;
+ }
+ return 0;
+}
+
+static krb5_error_code
+any_remove_entry(krb5_context context,
+ krb5_keytab id,
+ krb5_keytab_entry *entry)
+{
+ struct any_data *a = id->data;
+ krb5_error_code ret;
+ int found = 0;
+ while(a != NULL) {
+ ret = krb5_kt_remove_entry(context, a->kt, entry);
+ if(ret == 0)
+ found++;
+ else {
+ if(ret != KRB5_KT_NOWRITE && ret != KRB5_KT_NOTFOUND) {
+ krb5_set_error_string(context, "failed to remove entry from %s",
+ a->name);
+ return ret;
+ }
+ }
+ a = a->next;
+ }
+ if(!found)
+ return KRB5_KT_NOTFOUND;
+ return 0;
+}
+
+const krb5_kt_ops krb5_any_ops = {
+ "ANY",
+ any_resolve,
+ any_get_name,
+ any_close,
+ NULL, /* get */
+ any_start_seq_get,
+ any_next_entry,
+ any_end_seq_get,
+ any_add_entry,
+ any_remove_entry
+};
diff --git a/source4/heimdal/lib/krb5/keytab_file.c b/source4/heimdal/lib/krb5/keytab_file.c
new file mode 100644
index 0000000000..dca09ff6f3
--- /dev/null
+++ b/source4/heimdal/lib/krb5/keytab_file.c
@@ -0,0 +1,678 @@
+/*
+ * Copyright (c) 1997 - 2002 Kungliga Tekniska Högskolan
+ * (Royal Institute of Technology, Stockholm, Sweden).
+ * 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"
+
+RCSID("$Id: keytab_file.c,v 1.18 2005/05/31 21:50:43 lha Exp $");
+
+#define KRB5_KT_VNO_1 1
+#define KRB5_KT_VNO_2 2
+#define KRB5_KT_VNO KRB5_KT_VNO_2
+
+#define KRB5_KT_FL_JAVA 1
+
+
+/* file operations -------------------------------------------- */
+
+struct fkt_data {
+ char *filename;
+ int flags;
+};
+
+static krb5_error_code
+krb5_kt_ret_data(krb5_context context,
+ krb5_storage *sp,
+ krb5_data *data)
+{
+ int ret;
+ int16_t size;
+ ret = krb5_ret_int16(sp, &size);
+ if(ret)
+ return ret;
+ data->length = size;
+ data->data = malloc(size);
+ if (data->data == NULL) {
+ krb5_set_error_string (context, "malloc: out of memory");
+ return ENOMEM;
+ }
+ ret = krb5_storage_read(sp, data->data, size);
+ if(ret != size)
+ return (ret < 0)? errno : KRB5_KT_END;
+ return 0;
+}
+
+static krb5_error_code
+krb5_kt_ret_string(krb5_context context,
+ krb5_storage *sp,
+ heim_general_string *data)
+{
+ int ret;
+ int16_t size;
+ ret = krb5_ret_int16(sp, &size);
+ if(ret)
+ return ret;
+ *data = malloc(size + 1);
+ if (*data == NULL) {
+ krb5_set_error_string (context, "malloc: out of memory");
+ return ENOMEM;
+ }
+ ret = krb5_storage_read(sp, *data, size);
+ (*data)[size] = '\0';
+ if(ret != size)
+ return (ret < 0)? errno : KRB5_KT_END;
+ return 0;
+}
+
+static krb5_error_code
+krb5_kt_store_data(krb5_context context,
+ krb5_storage *sp,
+ krb5_data data)
+{
+ int ret;
+ ret = krb5_store_int16(sp, data.length);
+ if(ret < 0)
+ return ret;
+ ret = krb5_storage_write(sp, data.data, data.length);
+ if(ret != data.length){
+ if(ret < 0)
+ return errno;
+ return KRB5_KT_END;
+ }
+ return 0;
+}
+
+static krb5_error_code
+krb5_kt_store_string(krb5_storage *sp,
+ heim_general_string data)
+{
+ int ret;
+ size_t len = strlen(data);
+ ret = krb5_store_int16(sp, len);
+ if(ret < 0)
+ return ret;
+ ret = krb5_storage_write(sp, data, len);
+ if(ret != len){
+ if(ret < 0)
+ return errno;
+ return KRB5_KT_END;
+ }
+ return 0;
+}
+
+static krb5_error_code
+krb5_kt_ret_keyblock(krb5_context context, krb5_storage *sp, krb5_keyblock *p)
+{
+ int ret;
+ int16_t tmp;
+
+ ret = krb5_ret_int16(sp, &tmp); /* keytype + etype */
+ if(ret) return ret;
+ p->keytype = tmp;
+ ret = krb5_kt_ret_data(context, sp, &p->keyvalue);
+ return ret;
+}
+
+static krb5_error_code
+krb5_kt_store_keyblock(krb5_context context,
+ krb5_storage *sp,
+ krb5_keyblock *p)
+{
+ int ret;
+
+ ret = krb5_store_int16(sp, p->keytype); /* keytype + etype */
+ if(ret) return ret;
+ ret = krb5_kt_store_data(context, sp, p->keyvalue);
+ return ret;
+}
+
+
+static krb5_error_code
+krb5_kt_ret_principal(krb5_context context,
+ krb5_storage *sp,
+ krb5_principal *princ)
+{
+ int i;
+ int ret;
+ krb5_principal p;
+ int16_t tmp;
+
+ ALLOC(p, 1);
+ if(p == NULL) {
+ krb5_set_error_string (context, "malloc: out of memory");
+ return ENOMEM;
+ }
+
+ ret = krb5_ret_int16(sp, &tmp);
+ if(ret)
+ return ret;
+ if(krb5_storage_is_flags(sp, KRB5_STORAGE_PRINCIPAL_WRONG_NUM_COMPONENTS))
+ tmp--;
+ p->name.name_string.len = tmp;
+ ret = krb5_kt_ret_string(context, sp, &p->realm);
+ if(ret)
+ return ret;
+ p->name.name_string.val = calloc(p->name.name_string.len,
+ sizeof(*p->name.name_string.val));
+ if(p->name.name_string.val == NULL) {
+ krb5_set_error_string (context, "malloc: out of memory");
+ return ENOMEM;
+ }
+ for(i = 0; i < p->name.name_string.len; i++){
+ ret = krb5_kt_ret_string(context, sp, p->name.name_string.val + i);
+ if(ret)
+ return ret;
+ }
+ if (krb5_storage_is_flags(sp, KRB5_STORAGE_PRINCIPAL_NO_NAME_TYPE))
+ p->name.name_type = KRB5_NT_UNKNOWN;
+ else {
+ int32_t tmp32;
+ ret = krb5_ret_int32(sp, &tmp32);
+ p->name.name_type = tmp32;
+ if (ret)
+ return ret;
+ }
+ *princ = p;
+ return 0;
+}
+
+static krb5_error_code
+krb5_kt_store_principal(krb5_context context,
+ krb5_storage *sp,
+ krb5_principal p)
+{
+ int i;
+ int ret;
+
+ if(krb5_storage_is_flags(sp, KRB5_STORAGE_PRINCIPAL_WRONG_NUM_COMPONENTS))
+ ret = krb5_store_int16(sp, p->name.name_string.len + 1);
+ else
+ ret = krb5_store_int16(sp, p->name.name_string.len);
+ if(ret) return ret;
+ ret = krb5_kt_store_string(sp, p->realm);
+ if(ret) return ret;
+ for(i = 0; i < p->name.name_string.len; i++){
+ ret = krb5_kt_store_string(sp, p->name.name_string.val[i]);
+ if(ret)
+ return ret;
+ }
+ if(!krb5_storage_is_flags(sp, KRB5_STORAGE_PRINCIPAL_NO_NAME_TYPE)) {
+ ret = krb5_store_int32(sp, p->name.name_type);
+ if(ret)
+ return ret;
+ }
+
+ return 0;
+}
+
+static krb5_error_code
+fkt_resolve(krb5_context context, const char *name, krb5_keytab id)
+{
+ struct fkt_data *d;
+
+ d = malloc(sizeof(*d));
+ if(d == NULL) {
+ krb5_set_error_string (context, "malloc: out of memory");
+ return ENOMEM;
+ }
+ d->filename = strdup(name);
+ if(d->filename == NULL) {
+ free(d);
+ krb5_set_error_string (context, "malloc: out of memory");
+ return ENOMEM;
+ }
+ d->flags = 0;
+ id->data = d;
+ return 0;
+}
+
+static krb5_error_code
+fkt_resolve_java14(krb5_context context, const char *name, krb5_keytab id)
+{
+ krb5_error_code ret;
+
+ ret = fkt_resolve(context, name, id);
+ if (ret == 0) {
+ struct fkt_data *d = id->data;
+ d->flags |= KRB5_KT_FL_JAVA;
+ }
+ return ret;
+}
+
+static krb5_error_code
+fkt_close(krb5_context context, krb5_keytab id)
+{
+ struct fkt_data *d = id->data;
+ free(d->filename);
+ free(d);
+ return 0;
+}
+
+static krb5_error_code
+fkt_get_name(krb5_context context,
+ krb5_keytab id,
+ char *name,
+ size_t namesize)
+{
+ /* This function is XXX */
+ struct fkt_data *d = id->data;
+ strlcpy(name, d->filename, namesize);
+ return 0;
+}
+
+static void
+storage_set_flags(krb5_context context, krb5_storage *sp, int vno)
+{
+ int flags = 0;
+ switch(vno) {
+ case KRB5_KT_VNO_1:
+ flags |= KRB5_STORAGE_PRINCIPAL_WRONG_NUM_COMPONENTS;
+ flags |= KRB5_STORAGE_PRINCIPAL_NO_NAME_TYPE;
+ flags |= KRB5_STORAGE_HOST_BYTEORDER;
+ break;
+ case KRB5_KT_VNO_2:
+ break;
+ default:
+ krb5_warnx(context,
+ "storage_set_flags called with bad vno (%d)", vno);
+ }
+ krb5_storage_set_flags(sp, flags);
+}
+
+static krb5_error_code
+fkt_start_seq_get_int(krb5_context context,
+ krb5_keytab id,
+ int flags,
+ int exclusive,
+ krb5_kt_cursor *c)
+{
+ int8_t pvno, tag;
+ krb5_error_code ret;
+ struct fkt_data *d = id->data;
+
+ c->fd = open (d->filename, flags);
+ if (c->fd < 0) {
+ ret = errno;
+ krb5_set_error_string(context, "%s: %s", d->filename,
+ strerror(ret));
+ return ret;
+ }
+ ret = _krb5_xlock(context, c->fd, exclusive, d->filename);
+ if (ret) {
+ close(c->fd);
+ return ret;
+ }
+ c->sp = krb5_storage_from_fd(c->fd);
+ krb5_storage_set_eof_code(c->sp, KRB5_KT_END);
+ ret = krb5_ret_int8(c->sp, &pvno);
+ if(ret) {
+ krb5_storage_free(c->sp);
+ _krb5_xunlock(context, c->fd);
+ close(c->fd);
+ krb5_clear_error_string(context);
+ return ret;
+ }
+ if(pvno != 5) {
+ krb5_storage_free(c->sp);
+ _krb5_xunlock(context, c->fd);
+ close(c->fd);
+ krb5_clear_error_string (context);
+ return KRB5_KEYTAB_BADVNO;
+ }
+ ret = krb5_ret_int8(c->sp, &tag);
+ if (ret) {
+ krb5_storage_free(c->sp);
+ _krb5_xunlock(context, c->fd);
+ close(c->fd);
+ krb5_clear_error_string(context);
+ return ret;
+ }
+ id->version = tag;
+ storage_set_flags(context, c->sp, id->version);
+ return 0;
+}
+
+static krb5_error_code
+fkt_start_seq_get(krb5_context context,
+ krb5_keytab id,
+ krb5_kt_cursor *c)
+{
+ return fkt_start_seq_get_int(context, id, O_RDONLY | O_BINARY, 0, c);
+}
+
+static krb5_error_code
+fkt_next_entry_int(krb5_context context,
+ krb5_keytab id,
+ krb5_keytab_entry *entry,
+ krb5_kt_cursor *cursor,
+ off_t *start,
+ off_t *end)
+{
+ int32_t len;
+ int ret;
+ int8_t tmp8;
+ int32_t tmp32;
+ off_t pos, curpos;
+
+ pos = krb5_storage_seek(cursor->sp, 0, SEEK_CUR);
+loop:
+ ret = krb5_ret_int32(cursor->sp, &len);
+ if (ret)
+ return ret;
+ if(len < 0) {
+ pos = krb5_storage_seek(cursor->sp, -len, SEEK_CUR);
+ goto loop;
+ }
+ ret = krb5_kt_ret_principal (context, cursor->sp, &entry->principal);
+ if (ret)
+ goto out;
+ ret = krb5_ret_int32(cursor->sp, &tmp32);
+ entry->timestamp = tmp32;
+ if (ret)
+ goto out;
+ ret = krb5_ret_int8(cursor->sp, &tmp8);
+ if (ret)
+ goto out;
+ entry->vno = tmp8;
+ ret = krb5_kt_ret_keyblock (context, cursor->sp, &entry->keyblock);
+ if (ret)
+ goto out;
+ /* there might be a 32 bit kvno here
+ * if it's zero, assume that the 8bit one was right,
+ * otherwise trust the new value */
+ curpos = krb5_storage_seek(cursor->sp, 0, SEEK_CUR);
+ if(len + 4 + pos - curpos == 4) {
+ ret = krb5_ret_int32(cursor->sp, &tmp32);
+ if (ret == 0 && tmp32 != 0) {
+ entry->vno = tmp32;
+ }
+ }
+ if(start) *start = pos;
+ if(end) *end = *start + 4 + len;
+ out:
+ krb5_storage_seek(cursor->sp, pos + 4 + len, SEEK_SET);
+ return ret;
+}
+
+static krb5_error_code
+fkt_next_entry(krb5_context context,
+ krb5_keytab id,
+ krb5_keytab_entry *entry,
+ krb5_kt_cursor *cursor)
+{
+ return fkt_next_entry_int(context, id, entry, cursor, NULL, NULL);
+}
+
+static krb5_error_code
+fkt_end_seq_get(krb5_context context,
+ krb5_keytab id,
+ krb5_kt_cursor *cursor)
+{
+ krb5_storage_free(cursor->sp);
+ _krb5_xunlock(context, cursor->fd);
+ close(cursor->fd);
+ return 0;
+}
+
+static krb5_error_code
+fkt_setup_keytab(krb5_context context,
+ krb5_keytab id,
+ krb5_storage *sp)
+{
+ krb5_error_code ret;
+ ret = krb5_store_int8(sp, 5);
+ if(ret)
+ return ret;
+ if(id->version == 0)
+ id->version = KRB5_KT_VNO;
+ return krb5_store_int8 (sp, id->version);
+}
+
+static krb5_error_code
+fkt_add_entry(krb5_context context,
+ krb5_keytab id,
+ krb5_keytab_entry *entry)
+{
+ int ret;
+ int fd;
+ krb5_storage *sp;
+ struct fkt_data *d = id->data;
+ krb5_data keytab;
+ int32_t len;
+
+ fd = open (d->filename, O_RDWR | O_BINARY);
+ if (fd < 0) {
+ fd = open (d->filename, O_RDWR | O_CREAT | O_EXCL | O_BINARY, 0600);
+ if (fd < 0) {
+ ret = errno;
+ krb5_set_error_string(context, "open(%s): %s", d->filename,
+ strerror(ret));
+ return ret;
+ }
+ ret = _krb5_xlock(context, fd, 1, d->filename);
+ if (ret) {
+ close(fd);
+ return ret;
+ }
+ sp = krb5_storage_from_fd(fd);
+ krb5_storage_set_eof_code(sp, KRB5_KT_END);
+ ret = fkt_setup_keytab(context, id, sp);
+ if(ret) {
+ goto out;
+ }
+ storage_set_flags(context, sp, id->version);
+ } else {
+ int8_t pvno, tag;
+ ret = _krb5_xlock(context, fd, 1, d->filename);
+ if (ret) {
+ close(fd);
+ return ret;
+ }
+ sp = krb5_storage_from_fd(fd);
+ krb5_storage_set_eof_code(sp, KRB5_KT_END);
+ ret = krb5_ret_int8(sp, &pvno);
+ if(ret) {
+ /* we probably have a zero byte file, so try to set it up
+ properly */
+ ret = fkt_setup_keytab(context, id, sp);
+ if(ret) {
+ krb5_set_error_string(context, "%s: keytab is corrupted: %s",
+ d->filename, strerror(ret));
+ goto out;
+ }
+ storage_set_flags(context, sp, id->version);
+ } else {
+ if(pvno != 5) {
+ ret = KRB5_KEYTAB_BADVNO;
+ krb5_set_error_string(context, "%s: %s",
+ d->filename, strerror(ret));
+ goto out;
+ }
+ ret = krb5_ret_int8 (sp, &tag);
+ if (ret) {
+ krb5_set_error_string(context, "%s: reading tag: %s",
+ d->filename, strerror(ret));
+ goto out;
+ }
+ id->version = tag;
+ storage_set_flags(context, sp, id->version);
+ }
+ }
+
+ {
+ krb5_storage *emem;
+ emem = krb5_storage_emem();
+ if(emem == NULL) {
+ ret = ENOMEM;
+ krb5_set_error_string (context, "malloc: out of memory");
+ goto out;
+ }
+ ret = krb5_kt_store_principal(context, emem, entry->principal);
+ if(ret) {
+ krb5_storage_free(emem);
+ goto out;
+ }
+ ret = krb5_store_int32 (emem, entry->timestamp);
+ if(ret) {
+ krb5_storage_free(emem);
+ goto out;
+ }
+ ret = krb5_store_int8 (emem, entry->vno % 256);
+ if(ret) {
+ krb5_storage_free(emem);
+ goto out;
+ }
+ ret = krb5_kt_store_keyblock (context, emem, &entry->keyblock);
+ if(ret) {
+ krb5_storage_free(emem);
+ goto out;
+ }
+ if ((d->flags & KRB5_KT_FL_JAVA) == 0) {
+ ret = krb5_store_int32 (emem, entry->vno);
+ if (ret) {
+ krb5_storage_free(emem);
+ goto out;
+ }
+ }
+
+ ret = krb5_storage_to_data(emem, &keytab);
+ krb5_storage_free(emem);
+ if(ret)
+ goto out;
+ }
+
+ while(1) {
+ ret = krb5_ret_int32(sp, &len);
+ if(ret == KRB5_KT_END) {
+ len = keytab.length;
+ break;
+ }
+ if(len < 0) {
+ len = -len;
+ if(len >= keytab.length) {
+ krb5_storage_seek(sp, -4, SEEK_CUR);
+ break;
+ }
+ }
+ krb5_storage_seek(sp, len, SEEK_CUR);
+ }
+ ret = krb5_store_int32(sp, len);
+ if(krb5_storage_write(sp, keytab.data, keytab.length) < 0)
+ ret = errno;
+ memset(keytab.data, 0, keytab.length);
+ krb5_data_free(&keytab);
+ out:
+ krb5_storage_free(sp);
+ _krb5_xunlock(context, fd);
+ close(fd);
+ return ret;
+}
+
+static krb5_error_code
+fkt_remove_entry(krb5_context context,
+ krb5_keytab id,
+ krb5_keytab_entry *entry)
+{
+ krb5_keytab_entry e;
+ krb5_kt_cursor cursor;
+ off_t pos_start, pos_end;
+ int found = 0;
+ krb5_error_code ret;
+
+ ret = fkt_start_seq_get_int(context, id, O_RDWR | O_BINARY, 1, &cursor);
+ if(ret != 0)
+ goto out; /* return other error here? */
+ while(fkt_next_entry_int(context, id, &e, &cursor,
+ &pos_start, &pos_end) == 0) {
+ if(krb5_kt_compare(context, &e, entry->principal,
+ entry->vno, entry->keyblock.keytype)) {
+ int32_t len;
+ unsigned char buf[128];
+ found = 1;
+ krb5_storage_seek(cursor.sp, pos_start, SEEK_SET);
+ len = pos_end - pos_start - 4;
+ krb5_store_int32(cursor.sp, -len);
+ memset(buf, 0, sizeof(buf));
+ while(len > 0) {
+ krb5_storage_write(cursor.sp, buf, min(len, sizeof(buf)));
+ len -= min(len, sizeof(buf));
+ }
+ }
+ krb5_kt_free_entry(context, &e);
+ }
+ krb5_kt_end_seq_get(context, id, &cursor);
+ out:
+ if (!found) {
+ krb5_clear_error_string (context);
+ return KRB5_KT_NOTFOUND;
+ }
+ return 0;
+}
+
+const krb5_kt_ops krb5_fkt_ops = {
+ "FILE",
+ fkt_resolve,
+ fkt_get_name,
+ fkt_close,
+ NULL, /* get */
+ fkt_start_seq_get,
+ fkt_next_entry,
+ fkt_end_seq_get,
+ fkt_add_entry,
+ fkt_remove_entry
+};
+
+const krb5_kt_ops krb5_wrfkt_ops = {
+ "WRFILE",
+ fkt_resolve,
+ fkt_get_name,
+ fkt_close,
+ NULL, /* get */
+ fkt_start_seq_get,
+ fkt_next_entry,
+ fkt_end_seq_get,
+ fkt_add_entry,
+ fkt_remove_entry
+};
+
+const krb5_kt_ops krb5_javakt_ops = {
+ "JAVA14",
+ fkt_resolve_java14,
+ fkt_get_name,
+ fkt_close,
+ NULL, /* get */
+ fkt_start_seq_get,
+ fkt_next_entry,
+ fkt_end_seq_get,
+ fkt_add_entry,
+ fkt_remove_entry
+};
diff --git a/source4/heimdal/lib/krb5/keytab_keyfile.c b/source4/heimdal/lib/krb5/keytab_keyfile.c
new file mode 100644
index 0000000000..b53fa36a03
--- /dev/null
+++ b/source4/heimdal/lib/krb5/keytab_keyfile.c
@@ -0,0 +1,389 @@
+/*
+ * Copyright (c) 1997 - 2002 Kungliga Tekniska Högskolan
+ * (Royal Institute of Technology, Stockholm, Sweden).
+ * 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"
+
+RCSID("$Id: keytab_keyfile.c,v 1.16 2005/01/08 22:57:18 lha Exp $");
+
+/* afs keyfile operations --------------------------------------- */
+
+/*
+ * Minimum tools to handle the AFS KeyFile.
+ *
+ * Format of the KeyFile is:
+ * <int32_t numkeys> {[<int32_t kvno> <char[8] deskey>] * numkeys}
+ *
+ * It just adds to the end of the keyfile, deleting isn't implemented.
+ * Use your favorite text/hex editor to delete keys.
+ *
+ */
+
+#define AFS_SERVERTHISCELL "/usr/afs/etc/ThisCell"
+#define AFS_SERVERMAGICKRBCONF "/usr/afs/etc/krb.conf"
+
+struct akf_data {
+ int num_entries;
+ char *filename;
+ char *cell;
+ char *realm;
+};
+
+/*
+ * set `d->cell' and `d->realm'
+ */
+
+static int
+get_cell_and_realm (krb5_context context,
+ struct akf_data *d)
+{
+ FILE *f;
+ char buf[BUFSIZ], *cp;
+ int ret;
+
+ f = fopen (AFS_SERVERTHISCELL, "r");
+ if (f == NULL) {
+ ret = errno;
+ krb5_set_error_string (context, "open %s: %s", AFS_SERVERTHISCELL,
+ strerror(ret));
+ return ret;
+ }
+ if (fgets (buf, sizeof(buf), f) == NULL) {
+ fclose (f);
+ krb5_set_error_string (context, "no cell in %s", AFS_SERVERTHISCELL);
+ return EINVAL;
+ }
+ buf[strcspn(buf, "\n")] = '\0';
+ fclose(f);
+
+ d->cell = strdup (buf);
+ if (d->cell == NULL) {
+ krb5_set_error_string (context, "malloc: out of memory");
+ return ENOMEM;
+ }
+
+ f = fopen (AFS_SERVERMAGICKRBCONF, "r");
+ if (f != NULL) {
+ if (fgets (buf, sizeof(buf), f) == NULL) {
+ fclose (f);
+ krb5_set_error_string (context, "no realm in %s",
+ AFS_SERVERMAGICKRBCONF);
+ return EINVAL;
+ }
+ buf[strcspn(buf, "\n")] = '\0';
+ fclose(f);
+ }
+ /* uppercase */
+ for (cp = buf; *cp != '\0'; cp++)
+ *cp = toupper((unsigned char)*cp);
+
+ d->realm = strdup (buf);
+ if (d->realm == NULL) {
+ free (d->cell);
+ krb5_set_error_string (context, "malloc: out of memory");
+ return ENOMEM;
+ }
+ return 0;
+}
+
+/*
+ * init and get filename
+ */
+
+static krb5_error_code
+akf_resolve(krb5_context context, const char *name, krb5_keytab id)
+{
+ int ret;
+ struct akf_data *d = malloc(sizeof (struct akf_data));
+
+ if (d == NULL) {
+ krb5_set_error_string (context, "malloc: out of memory");
+ return ENOMEM;
+ }
+
+ d->num_entries = 0;
+ ret = get_cell_and_realm (context, d);
+ if (ret) {
+ free (d);
+ return ret;
+ }
+ d->filename = strdup (name);
+ if (d->filename == NULL) {
+ free (d->cell);
+ free (d->realm);
+ free (d);
+ krb5_set_error_string (context, "malloc: out of memory");
+ return ENOMEM;
+ }
+ id->data = d;
+
+ return 0;
+}
+
+/*
+ * cleanup
+ */
+
+static krb5_error_code
+akf_close(krb5_context context, krb5_keytab id)
+{
+ struct akf_data *d = id->data;
+
+ free (d->filename);
+ free (d->cell);
+ free (d);
+ return 0;
+}
+
+/*
+ * Return filename
+ */
+
+static krb5_error_code
+akf_get_name(krb5_context context,
+ krb5_keytab id,
+ char *name,
+ size_t name_sz)
+{
+ struct akf_data *d = id->data;
+
+ strlcpy (name, d->filename, name_sz);
+ return 0;
+}
+
+/*
+ * Init
+ */
+
+static krb5_error_code
+akf_start_seq_get(krb5_context context,
+ krb5_keytab id,
+ krb5_kt_cursor *c)
+{
+ int32_t ret;
+ struct akf_data *d = id->data;
+
+ c->fd = open (d->filename, O_RDONLY|O_BINARY, 0600);
+ if (c->fd < 0) {
+ ret = errno;
+ krb5_set_error_string(context, "open(%s): %s", d->filename,
+ strerror(ret));
+ return ret;
+ }
+
+ c->sp = krb5_storage_from_fd(c->fd);
+ ret = krb5_ret_int32(c->sp, &d->num_entries);
+ if(ret) {
+ krb5_storage_free(c->sp);
+ close(c->fd);
+ krb5_clear_error_string (context);
+ if(ret == KRB5_KT_END)
+ return KRB5_KT_NOTFOUND;
+ return ret;
+ }
+
+ return 0;
+}
+
+static krb5_error_code
+akf_next_entry(krb5_context context,
+ krb5_keytab id,
+ krb5_keytab_entry *entry,
+ krb5_kt_cursor *cursor)
+{
+ struct akf_data *d = id->data;
+ int32_t kvno;
+ off_t pos;
+ int ret;
+
+ pos = krb5_storage_seek(cursor->sp, 0, SEEK_CUR);
+
+ if ((pos - 4) / (4 + 8) >= d->num_entries)
+ return KRB5_KT_END;
+
+ ret = krb5_make_principal (context, &entry->principal,
+ d->realm, "afs", d->cell, NULL);
+ if (ret)
+ goto out;
+
+ ret = krb5_ret_int32(cursor->sp, &kvno);
+ if (ret) {
+ krb5_free_principal (context, entry->principal);
+ goto out;
+ }
+
+ entry->vno = kvno;
+
+ entry->keyblock.keytype = ETYPE_DES_CBC_MD5;
+ entry->keyblock.keyvalue.length = 8;
+ entry->keyblock.keyvalue.data = malloc (8);
+ if (entry->keyblock.keyvalue.data == NULL) {
+ krb5_free_principal (context, entry->principal);
+ krb5_set_error_string (context, "malloc: out of memory");
+ ret = ENOMEM;
+ goto out;
+ }
+
+ ret = krb5_storage_read(cursor->sp, entry->keyblock.keyvalue.data, 8);
+ if(ret != 8)
+ ret = (ret < 0) ? errno : KRB5_KT_END;
+ else
+ ret = 0;
+
+ entry->timestamp = time(NULL);
+
+ out:
+ krb5_storage_seek(cursor->sp, pos + 4 + 8, SEEK_SET);
+ return ret;
+}
+
+static krb5_error_code
+akf_end_seq_get(krb5_context context,
+ krb5_keytab id,
+ krb5_kt_cursor *cursor)
+{
+ krb5_storage_free(cursor->sp);
+ close(cursor->fd);
+ return 0;
+}
+
+static krb5_error_code
+akf_add_entry(krb5_context context,
+ krb5_keytab id,
+ krb5_keytab_entry *entry)
+{
+ struct akf_data *d = id->data;
+ int fd, created = 0;
+ krb5_error_code ret;
+ int32_t len;
+ krb5_storage *sp;
+
+
+ if (entry->keyblock.keyvalue.length != 8
+ || entry->keyblock.keytype != ETYPE_DES_CBC_MD5)
+ return 0;
+
+ fd = open (d->filename, O_RDWR | O_BINARY);
+ if (fd < 0) {
+ fd = open (d->filename,
+ O_RDWR | O_BINARY | O_CREAT | O_EXCL, 0600);
+ if (fd < 0) {
+ ret = errno;
+ krb5_set_error_string(context, "open(%s): %s", d->filename,
+ strerror(ret));
+ return ret;
+ }
+ created = 1;
+ }
+
+ sp = krb5_storage_from_fd(fd);
+ if(sp == NULL) {
+ close(fd);
+ krb5_set_error_string (context, "malloc: out of memory");
+ return ENOMEM;
+ }
+ if (created)
+ len = 0;
+ else {
+ if(krb5_storage_seek(sp, 0, SEEK_SET) < 0) {
+ ret = errno;
+ krb5_storage_free(sp);
+ close(fd);
+ krb5_set_error_string (context, "seek: %s", strerror(ret));
+ return ret;
+ }
+
+ ret = krb5_ret_int32(sp, &len);
+ if(ret) {
+ krb5_storage_free(sp);
+ close(fd);
+ return ret;
+ }
+ }
+ len++;
+
+ if(krb5_storage_seek(sp, 0, SEEK_SET) < 0) {
+ ret = errno;
+ krb5_storage_free(sp);
+ close(fd);
+ krb5_set_error_string (context, "seek: %s", strerror(ret));
+ return ret;
+ }
+
+ ret = krb5_store_int32(sp, len);
+ if(ret) {
+ krb5_storage_free(sp);
+ close(fd);
+ return ret;
+ }
+
+
+ if(krb5_storage_seek(sp, (len - 1) * (8 + 4), SEEK_CUR) < 0) {
+ ret = errno;
+ krb5_storage_free(sp);
+ close(fd);
+ krb5_set_error_string (context, "seek: %s", strerror(ret));
+ return ret;
+ }
+
+ ret = krb5_store_int32(sp, entry->vno);
+ if(ret) {
+ krb5_storage_free(sp);
+ close(fd);
+ return ret;
+ }
+ ret = krb5_storage_write(sp, entry->keyblock.keyvalue.data,
+ entry->keyblock.keyvalue.length);
+ if(ret != entry->keyblock.keyvalue.length) {
+ krb5_storage_free(sp);
+ close(fd);
+ if(ret < 0)
+ return errno;
+ return ENOTTY;
+ }
+ krb5_storage_free(sp);
+ close (fd);
+ return 0;
+}
+
+const krb5_kt_ops krb5_akf_ops = {
+ "AFSKEYFILE",
+ akf_resolve,
+ akf_get_name,
+ akf_close,
+ NULL, /* get */
+ akf_start_seq_get,
+ akf_next_entry,
+ akf_end_seq_get,
+ akf_add_entry,
+ NULL /* remove */
+};
diff --git a/source4/heimdal/lib/krb5/keytab_krb4.c b/source4/heimdal/lib/krb5/keytab_krb4.c
new file mode 100644
index 0000000000..1a83faca57
--- /dev/null
+++ b/source4/heimdal/lib/krb5/keytab_krb4.c
@@ -0,0 +1,443 @@
+/*
+ * Copyright (c) 1997 - 2002 Kungliga Tekniska Högskolan
+ * (Royal Institute of Technology, Stockholm, Sweden).
+ * 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"
+
+RCSID("$Id: keytab_krb4.c,v 1.13 2005/05/19 04:13:18 lha Exp $");
+
+struct krb4_kt_data {
+ char *filename;
+};
+
+static krb5_error_code
+krb4_kt_resolve(krb5_context context, const char *name, krb5_keytab id)
+{
+ struct krb4_kt_data *d;
+
+ d = malloc (sizeof(*d));
+ if (d == NULL) {
+ krb5_set_error_string (context, "malloc: out of memory");
+ return ENOMEM;
+ }
+ d->filename = strdup (name);
+ if (d->filename == NULL) {
+ free(d);
+ krb5_set_error_string (context, "malloc: out of memory");
+ return ENOMEM;
+ }
+ id->data = d;
+ return 0;
+}
+
+static krb5_error_code
+krb4_kt_get_name (krb5_context context,
+ krb5_keytab id,
+ char *name,
+ size_t name_sz)
+{
+ struct krb4_kt_data *d = id->data;
+
+ strlcpy (name, d->filename, name_sz);
+ return 0;
+}
+
+static krb5_error_code
+krb4_kt_close (krb5_context context,
+ krb5_keytab id)
+{
+ struct krb4_kt_data *d = id->data;
+
+ free (d->filename);
+ free (d);
+ return 0;
+}
+
+struct krb4_cursor_extra_data {
+ krb5_keytab_entry entry;
+ int num;
+};
+
+static int
+open_flock(const char *filename, int flags, int mode)
+{
+ int lock_mode;
+ int tries = 0;
+ int fd = open(filename, flags, mode);
+ if(fd < 0)
+ return fd;
+ if((flags & O_ACCMODE) == O_RDONLY)
+ lock_mode = LOCK_SH | LOCK_NB;
+ else
+ lock_mode = LOCK_EX | LOCK_NB;
+ while(flock(fd, lock_mode) < 0) {
+ if(++tries < 5) {
+ sleep(1);
+ } else {
+ close(fd);
+ return -1;
+ }
+ }
+ return fd;
+}
+
+
+
+static krb5_error_code
+krb4_kt_start_seq_get_int (krb5_context context,
+ krb5_keytab id,
+ int flags,
+ krb5_kt_cursor *c)
+{
+ struct krb4_kt_data *d = id->data;
+ struct krb4_cursor_extra_data *ed;
+ int ret;
+
+ ed = malloc (sizeof(*ed));
+ if (ed == NULL) {
+ krb5_set_error_string (context, "malloc: out of memory");
+ return ENOMEM;
+ }
+ ed->entry.principal = NULL;
+ ed->num = -1;
+ c->data = ed;
+ c->fd = open_flock (d->filename, flags, 0);
+ if (c->fd < 0) {
+ ret = errno;
+ free (ed);
+ krb5_set_error_string(context, "open(%s): %s", d->filename,
+ strerror(ret));
+ return ret;
+ }
+ c->sp = krb5_storage_from_fd(c->fd);
+ krb5_storage_set_eof_code(c->sp, KRB5_KT_END);
+ return 0;
+}
+
+static krb5_error_code
+krb4_kt_start_seq_get (krb5_context context,
+ krb5_keytab id,
+ krb5_kt_cursor *c)
+{
+ return krb4_kt_start_seq_get_int (context, id, O_BINARY | O_RDONLY, c);
+}
+
+static krb5_error_code
+read_v4_entry (krb5_context context,
+ struct krb4_kt_data *d,
+ krb5_kt_cursor *c,
+ struct krb4_cursor_extra_data *ed)
+{
+ unsigned char des_key[8];
+ krb5_error_code ret;
+ char *service, *instance, *realm;
+ int8_t kvno;
+
+ ret = krb5_ret_stringz(c->sp, &service);
+ if (ret)
+ return ret;
+ ret = krb5_ret_stringz(c->sp, &instance);
+ if (ret) {
+ free (service);
+ return ret;
+ }
+ ret = krb5_ret_stringz(c->sp, &realm);
+ if (ret) {
+ free (service);
+ free (instance);
+ return ret;
+ }
+ ret = krb5_425_conv_principal (context, service, instance, realm,
+ &ed->entry.principal);
+ free (service);
+ free (instance);
+ free (realm);
+ if (ret)
+ return ret;
+ ret = krb5_ret_int8(c->sp, &kvno);
+ if (ret) {
+ krb5_free_principal (context, ed->entry.principal);
+ return ret;
+ }
+ ret = krb5_storage_read(c->sp, des_key, sizeof(des_key));
+ if (ret < 0) {
+ krb5_free_principal(context, ed->entry.principal);
+ return ret;
+ }
+ if (ret < 8) {
+ krb5_free_principal(context, ed->entry.principal);
+ return EINVAL;
+ }
+ ed->entry.vno = kvno;
+ ret = krb5_data_copy (&ed->entry.keyblock.keyvalue,
+ des_key, sizeof(des_key));
+ if (ret)
+ return ret;
+ ed->entry.timestamp = time(NULL);
+ ed->num = 0;
+ return 0;
+}
+
+static krb5_error_code
+krb4_kt_next_entry (krb5_context context,
+ krb5_keytab id,
+ krb5_keytab_entry *entry,
+ krb5_kt_cursor *c)
+{
+ krb5_error_code ret;
+ struct krb4_kt_data *d = id->data;
+ struct krb4_cursor_extra_data *ed = c->data;
+ const krb5_enctype keytypes[] = {ETYPE_DES_CBC_MD5,
+ ETYPE_DES_CBC_MD4,
+ ETYPE_DES_CBC_CRC};
+
+ if (ed->num == -1) {
+ ret = read_v4_entry (context, d, c, ed);
+ if (ret)
+ return ret;
+ }
+ ret = krb5_kt_copy_entry_contents (context,
+ &ed->entry,
+ entry);
+ if (ret)
+ return ret;
+ entry->keyblock.keytype = keytypes[ed->num];
+ if (++ed->num == 3) {
+ krb5_kt_free_entry (context, &ed->entry);
+ ed->num = -1;
+ }
+ return 0;
+}
+
+static krb5_error_code
+krb4_kt_end_seq_get (krb5_context context,
+ krb5_keytab id,
+ krb5_kt_cursor *c)
+{
+ struct krb4_cursor_extra_data *ed = c->data;
+
+ krb5_storage_free (c->sp);
+ if (ed->num != -1)
+ krb5_kt_free_entry (context, &ed->entry);
+ free (c->data);
+ close (c->fd);
+ return 0;
+}
+
+static krb5_error_code
+krb4_store_keytab_entry(krb5_context context,
+ krb5_keytab_entry *entry,
+ krb5_storage *sp)
+{
+ krb5_error_code ret;
+#define ANAME_SZ 40
+#define INST_SZ 40
+#define REALM_SZ 40
+ char service[ANAME_SZ];
+ char instance[INST_SZ];
+ char realm[REALM_SZ];
+ ret = krb5_524_conv_principal (context, entry->principal,
+ service, instance, realm);
+ if (ret)
+ return ret;
+ if (entry->keyblock.keyvalue.length == 8
+ && entry->keyblock.keytype == ETYPE_DES_CBC_MD5) {
+ ret = krb5_store_stringz(sp, service);
+ ret = krb5_store_stringz(sp, instance);
+ ret = krb5_store_stringz(sp, realm);
+ ret = krb5_store_int8(sp, entry->vno);
+ ret = krb5_storage_write(sp, entry->keyblock.keyvalue.data, 8);
+ }
+ return 0;
+}
+
+static krb5_error_code
+krb4_kt_add_entry (krb5_context context,
+ krb5_keytab id,
+ krb5_keytab_entry *entry)
+{
+ struct krb4_kt_data *d = id->data;
+ krb5_storage *sp;
+ krb5_error_code ret;
+ int fd;
+
+ fd = open_flock (d->filename, O_WRONLY | O_APPEND | O_BINARY, 0);
+ if (fd < 0) {
+ fd = open_flock (d->filename,
+ O_WRONLY | O_APPEND | O_BINARY | O_CREAT, 0600);
+ if (fd < 0) {
+ ret = errno;
+ krb5_set_error_string(context, "open(%s): %s", d->filename,
+ strerror(ret));
+ return ret;
+ }
+ }
+ sp = krb5_storage_from_fd(fd);
+ krb5_storage_set_eof_code(sp, KRB5_KT_END);
+ if(sp == NULL) {
+ close(fd);
+ return ENOMEM;
+ }
+ ret = krb4_store_keytab_entry(context, entry, sp);
+ krb5_storage_free(sp);
+ if(close (fd) < 0)
+ return errno;
+ return ret;
+}
+
+static krb5_error_code
+krb4_kt_remove_entry(krb5_context context,
+ krb5_keytab id,
+ krb5_keytab_entry *entry)
+{
+ struct krb4_kt_data *d = id->data;
+ krb5_error_code ret;
+ krb5_keytab_entry e;
+ krb5_kt_cursor cursor;
+ krb5_storage *sp;
+ int remove_flag = 0;
+
+ sp = krb5_storage_emem();
+ if (sp == NULL) {
+ krb5_set_error_string(context, "malloc: out of memory");
+ return ENOMEM;
+ }
+ ret = krb5_kt_start_seq_get(context, id, &cursor);
+ if (ret) {
+ krb5_storage_free(sp);
+ return ret;
+ }
+ while(krb5_kt_next_entry(context, id, &e, &cursor) == 0) {
+ if(!krb5_kt_compare(context, &e, entry->principal,
+ entry->vno, entry->keyblock.keytype)) {
+ ret = krb4_store_keytab_entry(context, &e, sp);
+ if(ret) {
+ krb5_kt_free_entry(context, &e);
+ krb5_storage_free(sp);
+ return ret;
+ }
+ } else
+ remove_flag = 1;
+ krb5_kt_free_entry(context, &e);
+ }
+ krb5_kt_end_seq_get(context, id, &cursor);
+ if(remove_flag) {
+ int fd;
+ unsigned char buf[1024];
+ ssize_t n;
+ krb5_data data;
+ struct stat st;
+
+ krb5_storage_to_data(sp, &data);
+ krb5_storage_free(sp);
+
+ fd = open_flock (d->filename, O_RDWR | O_BINARY, 0);
+ if(fd < 0) {
+ memset(data.data, 0, data.length);
+ krb5_data_free(&data);
+ if(errno == EACCES || errno == EROFS)
+ return KRB5_KT_NOWRITE;
+ return errno;
+ }
+
+ if(write(fd, data.data, data.length) != data.length) {
+ memset(data.data, 0, data.length);
+ krb5_data_free(&data);
+ close(fd);
+ krb5_set_error_string(context, "failed writing to \"%s\"", d->filename);
+ return errno;
+ }
+ memset(data.data, 0, data.length);
+ if(fstat(fd, &st) < 0) {
+ krb5_data_free(&data);
+ close(fd);
+ krb5_set_error_string(context, "failed getting size of \"%s\"", d->filename);
+ return errno;
+ }
+ st.st_size -= data.length;
+ memset(buf, 0, sizeof(buf));
+ while(st.st_size > 0) {
+ n = min(st.st_size, sizeof(buf));
+ n = write(fd, buf, n);
+ if(n <= 0) {
+ krb5_data_free(&data);
+ close(fd);
+ krb5_set_error_string(context, "failed writing to \"%s\"", d->filename);
+ return errno;
+
+ }
+ st.st_size -= n;
+ }
+ if(ftruncate(fd, data.length) < 0) {
+ krb5_data_free(&data);
+ close(fd);
+ krb5_set_error_string(context, "failed truncating \"%s\"", d->filename);
+ return errno;
+ }
+ krb5_data_free(&data);
+ if(close(fd) < 0) {
+ krb5_set_error_string(context, "error closing \"%s\"", d->filename);
+ return errno;
+ }
+ return 0;
+ } else {
+ krb5_storage_free(sp);
+ return KRB5_KT_NOTFOUND;
+ }
+}
+
+
+const krb5_kt_ops krb4_fkt_ops = {
+ "krb4",
+ krb4_kt_resolve,
+ krb4_kt_get_name,
+ krb4_kt_close,
+ NULL, /* get */
+ krb4_kt_start_seq_get,
+ krb4_kt_next_entry,
+ krb4_kt_end_seq_get,
+ krb4_kt_add_entry, /* add_entry */
+ krb4_kt_remove_entry /* remove_entry */
+};
+
+const krb5_kt_ops krb5_srvtab_fkt_ops = {
+ "SRVTAB",
+ krb4_kt_resolve,
+ krb4_kt_get_name,
+ krb4_kt_close,
+ NULL, /* get */
+ krb4_kt_start_seq_get,
+ krb4_kt_next_entry,
+ krb4_kt_end_seq_get,
+ krb4_kt_add_entry, /* add_entry */
+ krb4_kt_remove_entry /* remove_entry */
+};
diff --git a/source4/heimdal/lib/krb5/keytab_memory.c b/source4/heimdal/lib/krb5/keytab_memory.c
new file mode 100644
index 0000000000..3dca5154e3
--- /dev/null
+++ b/source4/heimdal/lib/krb5/keytab_memory.c
@@ -0,0 +1,229 @@
+/*
+ * Copyright (c) 1997 - 2001 Kungliga Tekniska Högskolan
+ * (Royal Institute of Technology, Stockholm, Sweden).
+ * 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"
+
+RCSID("$Id: keytab_memory.c,v 1.6 2005/05/18 04:44:40 lha Exp $");
+
+/* memory operations -------------------------------------------- */
+
+struct mkt_data {
+ krb5_keytab_entry *entries;
+ int num_entries;
+};
+
+static krb5_error_code
+mkt_resolve(krb5_context context, const char *name, krb5_keytab id)
+{
+ struct mkt_data *d;
+ d = malloc(sizeof(*d));
+ if(d == NULL) {
+ krb5_set_error_string (context, "malloc: out of memory");
+ return ENOMEM;
+ }
+ d->entries = NULL;
+ d->num_entries = 0;
+ id->data = d;
+ return 0;
+}
+
+static krb5_error_code
+mkt_close(krb5_context context, krb5_keytab id)
+{
+ struct mkt_data *d = id->data;
+ int i;
+ for(i = 0; i < d->num_entries; i++)
+ krb5_kt_free_entry(context, &d->entries[i]);
+ free(d->entries);
+ free(d);
+ return 0;
+}
+
+static krb5_error_code
+mkt_get_name(krb5_context context,
+ krb5_keytab id,
+ char *name,
+ size_t namesize)
+{
+ strlcpy(name, "", namesize);
+ return 0;
+}
+
+static krb5_error_code
+mkt_start_seq_get(krb5_context context,
+ krb5_keytab id,
+ krb5_kt_cursor *c)
+{
+ /* XXX */
+ c->fd = 0;
+ return 0;
+}
+
+static krb5_error_code
+mkt_next_entry(krb5_context context,
+ krb5_keytab id,
+ krb5_keytab_entry *entry,
+ krb5_kt_cursor *c)
+{
+ struct mkt_data *d = id->data;
+ if(c->fd >= d->num_entries)
+ return KRB5_KT_END;
+ return krb5_kt_copy_entry_contents(context, &d->entries[c->fd++], entry);
+}
+
+static krb5_error_code
+mkt_end_seq_get(krb5_context context,
+ krb5_keytab id,
+ krb5_kt_cursor *cursor)
+{
+ return 0;
+}
+
+static krb5_error_code
+mkt_add_entry(krb5_context context,
+ krb5_keytab id,
+ krb5_keytab_entry *entry)
+{
+ struct mkt_data *d = id->data;
+ krb5_keytab_entry *tmp;
+ tmp = realloc(d->entries, (d->num_entries + 1) * sizeof(*d->entries));
+ if(tmp == NULL) {
+ krb5_set_error_string (context, "malloc: out of memory");
+ return ENOMEM;
+ }
+ d->entries = tmp;
+ return krb5_kt_copy_entry_contents(context, entry,
+ &d->entries[d->num_entries++]);
+}
+
+static krb5_error_code
+mkt_remove_entry(krb5_context context,
+ krb5_keytab id,
+ krb5_keytab_entry *entry)
+{
+ struct mkt_data *d = id->data;
+ krb5_keytab_entry *e, *end;
+ int found = 0;
+
+ if (d->num_entries == 0) {
+ krb5_clear_error_string(context);
+ return KRB5_KT_NOTFOUND;
+ }
+
+ /* do this backwards to minimize copying */
+ for(end = d->entries + d->num_entries, e = end - 1; e >= d->entries; e--) {
+ if(krb5_kt_compare(context, e, entry->principal,
+ entry->vno, entry->keyblock.keytype)) {
+ krb5_kt_free_entry(context, e);
+ memmove(e, e + 1, (end - e - 1) * sizeof(*e));
+ memset(end - 1, 0, sizeof(*end));
+ d->num_entries--;
+ end--;
+ found = 1;
+ }
+ }
+ if (!found) {
+ krb5_clear_error_string (context);
+ return KRB5_KT_NOTFOUND;
+ }
+ e = realloc(d->entries, d->num_entries * sizeof(*d->entries));
+ if(e != NULL)
+ d->entries = e;
+ return 0;
+}
+
+const krb5_kt_ops krb5_mkt_ops = {
+ "MEMORY",
+ mkt_resolve,
+ mkt_get_name,
+ mkt_close,
+ NULL, /* get */
+ mkt_start_seq_get,
+ mkt_next_entry,
+ mkt_end_seq_get,
+ mkt_add_entry,
+ mkt_remove_entry
+};
+
+static krb5_error_code
+mktw_get_entry(krb5_context context,
+ krb5_keytab id,
+ krb5_const_principal principal,
+ krb5_kvno kvno,
+ krb5_enctype enctype,
+ krb5_keytab_entry *entry)
+{
+ krb5_keytab_entry tmp;
+ krb5_error_code ret;
+ krb5_kt_cursor cursor;
+
+ ret = krb5_kt_start_seq_get (context, id, &cursor);
+ if (ret)
+ return KRB5_KT_NOTFOUND; /* XXX i.e. file not found */
+
+ entry->vno = 0;
+ while (krb5_kt_next_entry(context, id, &tmp, &cursor) == 0) {
+ if (krb5_kt_compare(context, &tmp, NULL, 0, enctype)) {
+ if (kvno == tmp.vno) {
+ krb5_kt_copy_entry_contents (context, &tmp, entry);
+ krb5_kt_free_entry (context, &tmp);
+ krb5_kt_end_seq_get(context, id, &cursor);
+ return 0;
+ } else if (kvno == 0 && tmp.vno > entry->vno) {
+ if (entry->vno)
+ krb5_kt_free_entry (context, entry);
+ krb5_kt_copy_entry_contents (context, &tmp, entry);
+ }
+ }
+ krb5_kt_free_entry(context, &tmp);
+ }
+ krb5_kt_end_seq_get (context, id, &cursor);
+ if (entry->vno) {
+ return 0;
+ } else {
+ return KRB5_KT_NOTFOUND;
+ }
+};
+
+const krb5_kt_ops krb5_mktw_ops = {
+ "MEMORY_WILDCARD",
+ mkt_resolve,
+ mkt_get_name,
+ mkt_close,
+ mktw_get_entry, /* get */
+ mkt_start_seq_get,
+ mkt_next_entry,
+ mkt_end_seq_get,
+ mkt_add_entry,
+ mkt_remove_entry
+};
diff --git a/source4/heimdal/lib/krb5/krb5-private.h b/source4/heimdal/lib/krb5/krb5-private.h
new file mode 100644
index 0000000000..e59cab8ca7
--- /dev/null
+++ b/source4/heimdal/lib/krb5/krb5-private.h
@@ -0,0 +1,358 @@
+/* This is a generated file */
+#ifndef __krb5_private_h__
+#define __krb5_private_h__
+
+#include <stdarg.h>
+
+#ifndef KRB5_LIB_FUNCTION
+#if defined(_WIN32)
+#define KRB5_LIB_FUNCTION _stdcall
+#else
+#define KRB5_LIB_FUNCTION
+#endif
+#endif
+
+krb5_error_code KRB5_LIB_FUNCTION
+_krb5_PKCS5_PBKDF2 (
+ krb5_context /*context*/,
+ krb5_cksumtype /*cktype*/,
+ krb5_data /*password*/,
+ krb5_salt /*salt*/,
+ u_int32_t /*iter*/,
+ krb5_keytype /*type*/,
+ krb5_keyblock */*key*/);
+
+void KRB5_LIB_FUNCTION
+_krb5_aes_cts_encrypt (
+ const unsigned char */*in*/,
+ unsigned char */*out*/,
+ size_t /*len*/,
+ const void */*aes_key*/,
+ unsigned char */*ivec*/,
+ const int /*encryptp*/);
+
+void
+_krb5_crc_init_table (void);
+
+u_int32_t
+_krb5_crc_update (
+ const char */*p*/,
+ size_t /*len*/,
+ u_int32_t /*res*/);
+
+krb5_error_code
+_krb5_expand_default_cc_name (
+ krb5_context /*context*/,
+ const char */*str*/,
+ char **/*res*/);
+
+int
+_krb5_extract_ticket (
+ krb5_context /*context*/,
+ krb5_kdc_rep */*rep*/,
+ krb5_creds */*creds*/,
+ krb5_keyblock */*key*/,
+ krb5_const_pointer /*keyseed*/,
+ krb5_key_usage /*key_usage*/,
+ krb5_addresses */*addrs*/,
+ unsigned /*nonce*/,
+ krb5_boolean /*allow_server_mismatch*/,
+ krb5_boolean /*ignore_cname*/,
+ krb5_decrypt_proc /*decrypt_proc*/,
+ krb5_const_pointer /*decryptarg*/);
+
+krb5_error_code
+_krb5_get_default_principal_local (
+ krb5_context /*context*/,
+ krb5_principal */*princ*/);
+
+krb5_error_code KRB5_LIB_FUNCTION
+_krb5_get_host_realm_int (
+ krb5_context /*context*/,
+ const char */*host*/,
+ krb5_boolean /*use_dns*/,
+ krb5_realm **/*realms*/);
+
+krb5_error_code
+_krb5_get_init_creds_opt_copy (
+ krb5_context /*context*/,
+ const krb5_get_init_creds_opt */*in*/,
+ krb5_get_init_creds_opt **/*out*/);
+
+void KRB5_LIB_FUNCTION
+_krb5_get_init_creds_opt_free_pkinit (krb5_get_init_creds_opt */*opt*/);
+
+krb5_ssize_t KRB5_LIB_FUNCTION
+_krb5_get_int (
+ void */*buffer*/,
+ unsigned long */*value*/,
+ size_t /*size*/);
+
+krb5_error_code
+_krb5_get_krbtgt (
+ krb5_context /*context*/,
+ krb5_ccache /*id*/,
+ krb5_realm /*realm*/,
+ krb5_creds **/*cred*/);
+
+krb5_error_code
+_krb5_kcm_chmod (
+ krb5_context /*context*/,
+ krb5_ccache /*id*/,
+ u_int16_t /*mode*/);
+
+krb5_error_code
+_krb5_kcm_chown (
+ krb5_context /*context*/,
+ krb5_ccache /*id*/,
+ u_int32_t /*uid*/,
+ u_int32_t /*gid*/);
+
+krb5_error_code
+_krb5_kcm_get_initial_ticket (
+ krb5_context /*context*/,
+ krb5_ccache /*id*/,
+ krb5_principal /*server*/,
+ krb5_keyblock */*key*/);
+
+krb5_error_code
+_krb5_kcm_get_ticket (
+ krb5_context /*context*/,
+ krb5_ccache /*id*/,
+ krb5_kdc_flags /*flags*/,
+ krb5_enctype /*enctype*/,
+ krb5_principal /*server*/);
+
+krb5_boolean
+_krb5_kcm_is_running (krb5_context /*context*/);
+
+krb5_error_code
+_krb5_kcm_noop (
+ krb5_context /*context*/,
+ krb5_ccache /*id*/);
+
+krb5_error_code KRB5_LIB_FUNCTION
+_krb5_krb_cr_err_reply (
+ krb5_context /*context*/,
+ const char */*name*/,
+ const char */*inst*/,
+ const char */*realm*/,
+ u_int32_t /*time_ws*/,
+ u_int32_t /*e*/,
+ const char */*e_string*/,
+ krb5_data */*data*/);
+
+krb5_error_code KRB5_LIB_FUNCTION
+_krb5_krb_create_auth_reply (
+ krb5_context /*context*/,
+ const char */*pname*/,
+ const char */*pinst*/,
+ const char */*prealm*/,
+ int32_t /*time_ws*/,
+ int /*n*/,
+ u_int32_t /*x_date*/,
+ unsigned char /*kvno*/,
+ const krb5_data */*cipher*/,
+ krb5_data */*data*/);
+
+krb5_error_code KRB5_LIB_FUNCTION
+_krb5_krb_create_ciph (
+ krb5_context /*context*/,
+ const krb5_keyblock */*session*/,
+ const char */*service*/,
+ const char */*instance*/,
+ const char */*realm*/,
+ u_int32_t /*life*/,
+ unsigned char /*kvno*/,
+ const krb5_data */*ticket*/,
+ u_int32_t /*kdc_time*/,
+ const krb5_keyblock */*key*/,
+ krb5_data */*enc_data*/);
+
+krb5_error_code KRB5_LIB_FUNCTION
+_krb5_krb_create_ticket (
+ krb5_context /*context*/,
+ unsigned char /*flags*/,
+ const char */*pname*/,
+ const char */*pinstance*/,
+ const char */*prealm*/,
+ int32_t /*paddress*/,
+ const krb5_keyblock */*session*/,
+ int16_t /*life*/,
+ int32_t /*life_sec*/,
+ const char */*sname*/,
+ const char */*sinstance*/,
+ const krb5_keyblock */*key*/,
+ krb5_data */*enc_data*/);
+
+krb5_error_code KRB5_LIB_FUNCTION
+_krb5_krb_decomp_ticket (
+ krb5_context /*context*/,
+ const krb5_data */*enc_ticket*/,
+ const krb5_keyblock */*key*/,
+ const char */*local_realm*/,
+ char **/*sname*/,
+ char **/*sinstance*/,
+ struct _krb5_krb_auth_data */*ad*/);
+
+krb5_error_code KRB5_LIB_FUNCTION
+_krb5_krb_dest_tkt (
+ krb5_context /*context*/,
+ const char */*tkfile*/);
+
+void KRB5_LIB_FUNCTION
+_krb5_krb_free_auth_data (
+ krb5_context /*context*/,
+ struct _krb5_krb_auth_data */*ad*/);
+
+time_t KRB5_LIB_FUNCTION
+_krb5_krb_life_to_time (
+ int /*start*/,
+ int /*life_*/);
+
+krb5_error_code KRB5_LIB_FUNCTION
+_krb5_krb_rd_req (
+ krb5_context /*context*/,
+ krb5_data */*authent*/,
+ const char */*service*/,
+ const char */*instance*/,
+ const char */*local_realm*/,
+ int32_t /*from_addr*/,
+ const krb5_keyblock */*key*/,
+ struct _krb5_krb_auth_data */*ad*/);
+
+krb5_error_code KRB5_LIB_FUNCTION
+_krb5_krb_tf_setup (
+ krb5_context /*context*/,
+ struct credentials */*v4creds*/,
+ const char */*tkfile*/,
+ int /*append*/);
+
+int KRB5_LIB_FUNCTION
+_krb5_krb_time_to_life (
+ time_t /*start*/,
+ time_t /*end*/);
+
+krb5_error_code
+_krb5_mk_req_internal (
+ krb5_context /*context*/,
+ krb5_auth_context */*auth_context*/,
+ const krb5_flags /*ap_req_options*/,
+ krb5_data */*in_data*/,
+ krb5_creds */*in_creds*/,
+ krb5_data */*outbuf*/,
+ krb5_key_usage /*checksum_usage*/,
+ krb5_key_usage /*encrypt_usage*/);
+
+void KRB5_LIB_FUNCTION
+_krb5_n_fold (
+ const void */*str*/,
+ size_t /*len*/,
+ void */*key*/,
+ size_t /*size*/);
+
+krb5_error_code KRB5_LIB_FUNCTION
+_krb5_oid_to_enctype (
+ krb5_context /*context*/,
+ const heim_oid */*oid*/,
+ krb5_enctype */*etype*/);
+
+void KRB5_LIB_FUNCTION
+_krb5_pk_cert_free (struct krb5_pk_cert */*cert*/);
+
+krb5_error_code KRB5_LIB_FUNCTION
+_krb5_pk_create_sign (
+ krb5_context /*context*/,
+ const heim_oid */*eContentType*/,
+ krb5_data */*eContent*/,
+ struct krb5_pk_identity */*id*/,
+ krb5_data */*sd_data*/);
+
+krb5_error_code KRB5_LIB_FUNCTION
+_krb5_pk_load_openssl_id (
+ krb5_context /*context*/,
+ struct krb5_pk_identity **/*ret_id*/,
+ const char */*user_id*/,
+ const char */*x509_anchors*/,
+ krb5_prompter_fct /*prompter*/,
+ void */*prompter_data*/,
+ char */*password*/);
+
+krb5_error_code KRB5_LIB_FUNCTION
+_krb5_pk_mk_ContentInfo (
+ krb5_context /*context*/,
+ const krb5_data */*buf*/,
+ const heim_oid */*oid*/,
+ struct ContentInfo */*content_info*/);
+
+krb5_error_code KRB5_LIB_FUNCTION
+_krb5_pk_mk_padata (
+ krb5_context /*context*/,
+ void */*c*/,
+ const KDC_REQ_BODY */*req_body*/,
+ unsigned /*nonce*/,
+ METHOD_DATA */*md*/);
+
+krb5_error_code KRB5_LIB_FUNCTION
+_krb5_pk_rd_pa_reply (
+ krb5_context /*context*/,
+ void */*c*/,
+ krb5_enctype /*etype*/,
+ unsigned /*nonce*/,
+ PA_DATA */*pa*/,
+ krb5_keyblock **/*key*/);
+
+krb5_error_code KRB5_LIB_FUNCTION
+_krb5_pk_verify_sign (
+ krb5_context /*context*/,
+ const char */*data*/,
+ size_t /*length*/,
+ struct krb5_pk_identity */*id*/,
+ heim_oid */*contentType*/,
+ krb5_data */*content*/,
+ struct krb5_pk_cert **/*signer*/);
+
+krb5_error_code KRB5_LIB_FUNCTION
+_krb5_principal2principalname (
+ PrincipalName */*p*/,
+ const krb5_principal /*from*/);
+
+krb5_error_code KRB5_LIB_FUNCTION
+_krb5_principalname2krb5_principal (
+ krb5_principal */*principal*/,
+ const PrincipalName /*from*/,
+ const Realm /*realm*/);
+
+krb5_ssize_t KRB5_LIB_FUNCTION
+_krb5_put_int (
+ void */*buffer*/,
+ unsigned long /*value*/,
+ size_t /*size*/);
+
+int
+_krb5_send_and_recv_tcp (
+ int /*fd*/,
+ time_t /*tmout*/,
+ const krb5_data */*req*/,
+ krb5_data */*rep*/);
+
+int
+_krb5_xlock (
+ krb5_context /*context*/,
+ int /*fd*/,
+ krb5_boolean /*exclusive*/,
+ const char */*filename*/);
+
+int
+_krb5_xunlock (
+ krb5_context /*context*/,
+ int /*fd*/);
+
+krb5_error_code KRB5_LIB_FUNCTION
+_krb5_rd_rep_type(krb5_context context,
+ krb5_auth_context auth_context,
+ const krb5_data *inbuf,
+ krb5_ap_rep_enc_part **repl,
+ krb5_boolean dce_style_response);
+
+#endif /* __krb5_private_h__ */
diff --git a/source4/heimdal/lib/krb5/krb5-protos.h b/source4/heimdal/lib/krb5/krb5-protos.h
new file mode 100644
index 0000000000..cee8a02419
--- /dev/null
+++ b/source4/heimdal/lib/krb5/krb5-protos.h
@@ -0,0 +1,3407 @@
+/* This is a generated file */
+#ifndef __krb5_protos_h__
+#define __krb5_protos_h__
+
+#include <stdarg.h>
+
+#if !defined(__GNUC__) && !defined(__attribute__)
+#define __attribute__(x)
+#endif
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifndef KRB5_LIB_FUNCTION
+#if defined(_WIN32)
+#define KRB5_LIB_FUNCTION _stdcall
+#else
+#define KRB5_LIB_FUNCTION
+#endif
+#endif
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb524_convert_creds_kdc (
+ krb5_context /*context*/,
+ krb5_creds */*in_cred*/,
+ struct credentials */*v4creds*/);
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb524_convert_creds_kdc_ccache (
+ krb5_context /*context*/,
+ krb5_ccache /*ccache*/,
+ krb5_creds */*in_cred*/,
+ struct credentials */*v4creds*/);
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_425_conv_principal (
+ krb5_context /*context*/,
+ const char */*name*/,
+ const char */*instance*/,
+ const char */*realm*/,
+ krb5_principal */*princ*/);
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_425_conv_principal_ext (
+ krb5_context /*context*/,
+ const char */*name*/,
+ const char */*instance*/,
+ const char */*realm*/,
+ krb5_boolean (*/*func*/)(krb5_context, krb5_principal),
+ krb5_boolean /*resolve*/,
+ krb5_principal */*principal*/);
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_425_conv_principal_ext2 (
+ krb5_context /*context*/,
+ const char */*name*/,
+ const char */*instance*/,
+ const char */*realm*/,
+ krb5_boolean (*/*func*/)(krb5_context, void *, krb5_principal),
+ void */*funcctx*/,
+ krb5_boolean /*resolve*/,
+ krb5_principal */*princ*/);
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_524_conv_principal (
+ krb5_context /*context*/,
+ const krb5_principal /*principal*/,
+ char */*name*/,
+ char */*instance*/,
+ char */*realm*/);
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_abort (
+ krb5_context /*context*/,
+ krb5_error_code /*code*/,
+ const char */*fmt*/,
+ ...)
+ __attribute__ ((noreturn, format (printf, 3, 4)));
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_abortx (
+ krb5_context /*context*/,
+ const char */*fmt*/,
+ ...)
+ __attribute__ ((noreturn, format (printf, 2, 3)));
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_acl_match_file (
+ krb5_context /*context*/,
+ const char */*file*/,
+ const char */*format*/,
+ ...);
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_acl_match_string (
+ krb5_context /*context*/,
+ const char */*string*/,
+ const char */*format*/,
+ ...);
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_add_et_list (
+ krb5_context /*context*/,
+ void (*/*func*/)(struct et_list **));
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_add_extra_addresses (
+ krb5_context /*context*/,
+ krb5_addresses */*addresses*/);
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_add_ignore_addresses (
+ krb5_context /*context*/,
+ krb5_addresses */*addresses*/);
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_addlog_dest (
+ krb5_context /*context*/,
+ krb5_log_facility */*f*/,
+ const char */*orig*/);
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_addlog_func (
+ krb5_context /*context*/,
+ krb5_log_facility */*fac*/,
+ int /*min*/,
+ int /*max*/,
+ krb5_log_log_func_t /*log_func*/,
+ krb5_log_close_func_t /*close_func*/,
+ void */*data*/);
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_addr2sockaddr (
+ krb5_context /*context*/,
+ const krb5_address */*addr*/,
+ struct sockaddr */*sa*/,
+ krb5_socklen_t */*sa_size*/,
+ int /*port*/);
+
+krb5_boolean KRB5_LIB_FUNCTION
+krb5_address_compare (
+ krb5_context /*context*/,
+ const krb5_address */*addr1*/,
+ const krb5_address */*addr2*/);
+
+int KRB5_LIB_FUNCTION
+krb5_address_order (
+ krb5_context /*context*/,
+ const krb5_address */*addr1*/,
+ const krb5_address */*addr2*/);
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_address_prefixlen_boundary (
+ krb5_context /*context*/,
+ const krb5_address */*inaddr*/,
+ unsigned long /*prefixlen*/,
+ krb5_address */*low*/,
+ krb5_address */*high*/);
+
+krb5_boolean KRB5_LIB_FUNCTION
+krb5_address_search (
+ krb5_context /*context*/,
+ const krb5_address */*addr*/,
+ const krb5_addresses */*addrlist*/);
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_aname_to_localname (
+ krb5_context /*context*/,
+ krb5_const_principal /*aname*/,
+ size_t /*lnsize*/,
+ char */*lname*/);
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_anyaddr (
+ krb5_context /*context*/,
+ int /*af*/,
+ struct sockaddr */*sa*/,
+ krb5_socklen_t */*sa_size*/,
+ int /*port*/);
+
+void KRB5_LIB_FUNCTION
+krb5_appdefault_boolean (
+ krb5_context /*context*/,
+ const char */*appname*/,
+ krb5_const_realm /*realm*/,
+ const char */*option*/,
+ krb5_boolean /*def_val*/,
+ krb5_boolean */*ret_val*/);
+
+void KRB5_LIB_FUNCTION
+krb5_appdefault_string (
+ krb5_context /*context*/,
+ const char */*appname*/,
+ krb5_const_realm /*realm*/,
+ const char */*option*/,
+ const char */*def_val*/,
+ char **/*ret_val*/);
+
+void KRB5_LIB_FUNCTION
+krb5_appdefault_time (
+ krb5_context /*context*/,
+ const char */*appname*/,
+ krb5_const_realm /*realm*/,
+ const char */*option*/,
+ time_t /*def_val*/,
+ time_t */*ret_val*/);
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_append_addresses (
+ krb5_context /*context*/,
+ krb5_addresses */*dest*/,
+ const krb5_addresses */*source*/);
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_auth_con_addflags (
+ krb5_context /*context*/,
+ krb5_auth_context /*auth_context*/,
+ int32_t /*addflags*/,
+ int32_t */*flags*/);
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_auth_con_free (
+ krb5_context /*context*/,
+ krb5_auth_context /*auth_context*/);
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_auth_con_genaddrs (
+ krb5_context /*context*/,
+ krb5_auth_context /*auth_context*/,
+ int /*fd*/,
+ int /*flags*/);
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_auth_con_generatelocalsubkey (
+ krb5_context /*context*/,
+ krb5_auth_context /*auth_context*/,
+ krb5_keyblock */*key*/);
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_auth_con_getaddrs (
+ krb5_context /*context*/,
+ krb5_auth_context /*auth_context*/,
+ krb5_address **/*local_addr*/,
+ krb5_address **/*remote_addr*/);
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_auth_con_getauthenticator (
+ krb5_context /*context*/,
+ krb5_auth_context /*auth_context*/,
+ krb5_authenticator */*authenticator*/);
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_auth_con_getcksumtype (
+ krb5_context /*context*/,
+ krb5_auth_context /*auth_context*/,
+ krb5_cksumtype */*cksumtype*/);
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_auth_con_getflags (
+ krb5_context /*context*/,
+ krb5_auth_context /*auth_context*/,
+ int32_t */*flags*/);
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_auth_con_getkey (
+ krb5_context /*context*/,
+ krb5_auth_context /*auth_context*/,
+ krb5_keyblock **/*keyblock*/);
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_auth_con_getkeytype (
+ krb5_context /*context*/,
+ krb5_auth_context /*auth_context*/,
+ krb5_keytype */*keytype*/);
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_auth_con_getlocalseqnumber (
+ krb5_context /*context*/,
+ krb5_auth_context /*auth_context*/,
+ int32_t */*seqnumber*/);
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_auth_con_getlocalsubkey (
+ krb5_context /*context*/,
+ krb5_auth_context /*auth_context*/,
+ krb5_keyblock **/*keyblock*/);
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_auth_con_getrcache (
+ krb5_context /*context*/,
+ krb5_auth_context /*auth_context*/,
+ krb5_rcache */*rcache*/);
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_auth_con_getremotesubkey (
+ krb5_context /*context*/,
+ krb5_auth_context /*auth_context*/,
+ krb5_keyblock **/*keyblock*/);
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_auth_con_init (
+ krb5_context /*context*/,
+ krb5_auth_context */*auth_context*/);
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_auth_con_removeflags (
+ krb5_context /*context*/,
+ krb5_auth_context /*auth_context*/,
+ int32_t /*removeflags*/,
+ int32_t */*flags*/);
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_auth_con_setaddrs (
+ krb5_context /*context*/,
+ krb5_auth_context /*auth_context*/,
+ krb5_address */*local_addr*/,
+ krb5_address */*remote_addr*/);
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_auth_con_setaddrs_from_fd (
+ krb5_context /*context*/,
+ krb5_auth_context /*auth_context*/,
+ void */*p_fd*/);
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_auth_con_setcksumtype (
+ krb5_context /*context*/,
+ krb5_auth_context /*auth_context*/,
+ krb5_cksumtype /*cksumtype*/);
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_auth_con_setflags (
+ krb5_context /*context*/,
+ krb5_auth_context /*auth_context*/,
+ int32_t /*flags*/);
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_auth_con_setkey (
+ krb5_context /*context*/,
+ krb5_auth_context /*auth_context*/,
+ krb5_keyblock */*keyblock*/);
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_auth_con_setkeytype (
+ krb5_context /*context*/,
+ krb5_auth_context /*auth_context*/,
+ krb5_keytype /*keytype*/);
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_auth_con_setlocalseqnumber (
+ krb5_context /*context*/,
+ krb5_auth_context /*auth_context*/,
+ int32_t /*seqnumber*/);
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_auth_con_setlocalsubkey (
+ krb5_context /*context*/,
+ krb5_auth_context /*auth_context*/,
+ krb5_keyblock */*keyblock*/);
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_auth_con_setrcache (
+ krb5_context /*context*/,
+ krb5_auth_context /*auth_context*/,
+ krb5_rcache /*rcache*/);
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_auth_con_setremoteseqnumber (
+ krb5_context /*context*/,
+ krb5_auth_context /*auth_context*/,
+ int32_t /*seqnumber*/);
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_auth_con_setremotesubkey (
+ krb5_context /*context*/,
+ krb5_auth_context /*auth_context*/,
+ krb5_keyblock */*keyblock*/);
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_auth_con_setuserkey (
+ krb5_context /*context*/,
+ krb5_auth_context /*auth_context*/,
+ krb5_keyblock */*keyblock*/);
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_auth_getremoteseqnumber (
+ krb5_context /*context*/,
+ krb5_auth_context /*auth_context*/,
+ int32_t */*seqnumber*/);
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_build_ap_req (
+ krb5_context /*context*/,
+ krb5_enctype /*enctype*/,
+ krb5_creds */*cred*/,
+ krb5_flags /*ap_options*/,
+ krb5_data /*authenticator*/,
+ krb5_data */*retdata*/);
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_build_authenticator (
+ krb5_context /*context*/,
+ krb5_auth_context /*auth_context*/,
+ krb5_enctype /*enctype*/,
+ krb5_creds */*cred*/,
+ Checksum */*cksum*/,
+ Authenticator **/*auth_result*/,
+ krb5_data */*result*/,
+ krb5_key_usage /*usage*/);
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_build_principal (
+ krb5_context /*context*/,
+ krb5_principal */*principal*/,
+ int /*rlen*/,
+ krb5_const_realm /*realm*/,
+ ...);
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_build_principal_ext (
+ krb5_context /*context*/,
+ krb5_principal */*principal*/,
+ int /*rlen*/,
+ krb5_const_realm /*realm*/,
+ ...);
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_build_principal_va (
+ krb5_context /*context*/,
+ krb5_principal */*principal*/,
+ int /*rlen*/,
+ krb5_const_realm /*realm*/,
+ va_list /*ap*/);
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_build_principal_va_ext (
+ krb5_context /*context*/,
+ krb5_principal */*principal*/,
+ int /*rlen*/,
+ krb5_const_realm /*realm*/,
+ va_list /*ap*/);
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_c_block_size (
+ krb5_context /*context*/,
+ krb5_enctype /*enctype*/,
+ size_t */*blocksize*/);
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_c_checksum_length (
+ krb5_context /*context*/,
+ krb5_cksumtype /*cksumtype*/,
+ size_t */*length*/);
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_c_decrypt (
+ krb5_context /*context*/,
+ const krb5_keyblock /*key*/,
+ krb5_keyusage /*usage*/,
+ const krb5_data */*ivec*/,
+ krb5_enc_data */*input*/,
+ krb5_data */*output*/);
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_c_encrypt (
+ krb5_context /*context*/,
+ const krb5_keyblock */*key*/,
+ krb5_keyusage /*usage*/,
+ const krb5_data */*ivec*/,
+ const krb5_data */*input*/,
+ krb5_enc_data */*output*/);
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_c_encrypt_length (
+ krb5_context /*context*/,
+ krb5_enctype /*enctype*/,
+ size_t /*inputlen*/,
+ size_t */*length*/);
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_c_enctype_compare (
+ krb5_context /*context*/,
+ krb5_enctype /*e1*/,
+ krb5_enctype /*e2*/,
+ krb5_boolean */*similar*/);
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_c_get_checksum (
+ krb5_context /*context*/,
+ const krb5_checksum */*cksum*/,
+ krb5_cksumtype */*type*/,
+ krb5_data **/*data*/);
+
+krb5_boolean KRB5_LIB_FUNCTION
+krb5_c_is_coll_proof_cksum (krb5_cksumtype /*ctype*/);
+
+krb5_boolean KRB5_LIB_FUNCTION
+krb5_c_is_keyed_cksum (krb5_cksumtype /*ctype*/);
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_c_make_checksum (
+ krb5_context /*context*/,
+ krb5_cksumtype /*cksumtype*/,
+ const krb5_keyblock */*key*/,
+ krb5_keyusage /*usage*/,
+ const krb5_data */*input*/,
+ krb5_checksum */*cksum*/);
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_c_make_random_key (
+ krb5_context /*context*/,
+ krb5_enctype /*enctype*/,
+ krb5_keyblock */*random_key*/);
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_c_set_checksum (
+ krb5_context /*context*/,
+ krb5_checksum */*cksum*/,
+ krb5_cksumtype /*type*/,
+ const krb5_data */*data*/);
+
+krb5_boolean KRB5_LIB_FUNCTION
+krb5_c_valid_cksumtype (krb5_cksumtype /*ctype*/);
+
+krb5_boolean KRB5_LIB_FUNCTION
+krb5_c_valid_enctype (krb5_enctype /*etype*/);
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_c_verify_checksum (
+ krb5_context /*context*/,
+ const krb5_keyblock */*key*/,
+ krb5_keyusage /*usage*/,
+ const krb5_data */*data*/,
+ const krb5_checksum */*cksum*/,
+ krb5_boolean */*valid*/);
+
+void KRB5_LIB_FUNCTION
+krb5_cc_clear_mcred (krb5_creds */*mcred*/);
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_cc_close (
+ krb5_context /*context*/,
+ krb5_ccache /*id*/);
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_cc_copy_cache (
+ krb5_context /*context*/,
+ const krb5_ccache /*from*/,
+ krb5_ccache /*to*/);
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_cc_copy_cache_match (
+ krb5_context /*context*/,
+ const krb5_ccache /*from*/,
+ krb5_ccache /*to*/,
+ krb5_flags /*whichfields*/,
+ const krb5_creds * /*mcreds*/,
+ unsigned int */*matched*/);
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_cc_default (
+ krb5_context /*context*/,
+ krb5_ccache */*id*/);
+
+const char* KRB5_LIB_FUNCTION
+krb5_cc_default_name (krb5_context /*context*/);
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_cc_destroy (
+ krb5_context /*context*/,
+ krb5_ccache /*id*/);
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_cc_end_seq_get (
+ krb5_context /*context*/,
+ const krb5_ccache /*id*/,
+ krb5_cc_cursor */*cursor*/);
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_cc_gen_new (
+ krb5_context /*context*/,
+ const krb5_cc_ops */*ops*/,
+ krb5_ccache */*id*/);
+
+const char* KRB5_LIB_FUNCTION
+krb5_cc_get_name (
+ krb5_context /*context*/,
+ krb5_ccache /*id*/);
+
+const krb5_cc_ops *
+krb5_cc_get_ops (
+ krb5_context /*context*/,
+ krb5_ccache /*id*/);
+
+const krb5_cc_ops *
+krb5_cc_get_prefix_ops (
+ krb5_context /*context*/,
+ const char */*prefix*/);
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_cc_get_principal (
+ krb5_context /*context*/,
+ krb5_ccache /*id*/,
+ krb5_principal */*principal*/);
+
+const char* KRB5_LIB_FUNCTION
+krb5_cc_get_type (
+ krb5_context /*context*/,
+ krb5_ccache /*id*/);
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_cc_get_version (
+ krb5_context /*context*/,
+ const krb5_ccache /*id*/);
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_cc_initialize (
+ krb5_context /*context*/,
+ krb5_ccache /*id*/,
+ krb5_principal /*primary_principal*/);
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_cc_new_unique (
+ krb5_context /*context*/,
+ const char */*type*/,
+ const char */*hint*/,
+ krb5_ccache */*id*/);
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_cc_next_cred (
+ krb5_context /*context*/,
+ const krb5_ccache /*id*/,
+ krb5_cc_cursor */*cursor*/,
+ krb5_creds */*creds*/);
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_cc_next_cred_match (
+ krb5_context /*context*/,
+ const krb5_ccache /*id*/,
+ krb5_cc_cursor * /*cursor*/,
+ krb5_creds * /*creds*/,
+ krb5_flags /*whichfields*/,
+ const krb5_creds * /*mcreds*/);
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_cc_register (
+ krb5_context /*context*/,
+ const krb5_cc_ops */*ops*/,
+ krb5_boolean /*override*/);
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_cc_remove_cred (
+ krb5_context /*context*/,
+ krb5_ccache /*id*/,
+ krb5_flags /*which*/,
+ krb5_creds */*cred*/);
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_cc_resolve (
+ krb5_context /*context*/,
+ const char */*name*/,
+ krb5_ccache */*id*/);
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_cc_retrieve_cred (
+ krb5_context /*context*/,
+ krb5_ccache /*id*/,
+ krb5_flags /*whichfields*/,
+ const krb5_creds */*mcreds*/,
+ krb5_creds */*creds*/);
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_cc_set_default_name (
+ krb5_context /*context*/,
+ const char */*name*/);
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_cc_set_flags (
+ krb5_context /*context*/,
+ krb5_ccache /*id*/,
+ krb5_flags /*flags*/);
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_cc_start_seq_get (
+ krb5_context /*context*/,
+ const krb5_ccache /*id*/,
+ krb5_cc_cursor */*cursor*/);
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_cc_store_cred (
+ krb5_context /*context*/,
+ krb5_ccache /*id*/,
+ krb5_creds */*creds*/);
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_change_password (
+ krb5_context /*context*/,
+ krb5_creds */*creds*/,
+ char */*newpw*/,
+ int */*result_code*/,
+ krb5_data */*result_code_string*/,
+ krb5_data */*result_string*/);
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_check_transited (
+ krb5_context /*context*/,
+ krb5_const_realm /*client_realm*/,
+ krb5_const_realm /*server_realm*/,
+ krb5_realm */*realms*/,
+ int /*num_realms*/,
+ int */*bad_realm*/);
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_check_transited_realms (
+ krb5_context /*context*/,
+ const char *const */*realms*/,
+ int /*num_realms*/,
+ int */*bad_realm*/);
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_checksum_disable (
+ krb5_context /*context*/,
+ krb5_cksumtype /*type*/);
+
+void KRB5_LIB_FUNCTION
+krb5_checksum_free (
+ krb5_context /*context*/,
+ krb5_checksum */*cksum*/);
+
+krb5_boolean KRB5_LIB_FUNCTION
+krb5_checksum_is_collision_proof (
+ krb5_context /*context*/,
+ krb5_cksumtype /*type*/);
+
+krb5_boolean KRB5_LIB_FUNCTION
+krb5_checksum_is_keyed (
+ krb5_context /*context*/,
+ krb5_cksumtype /*type*/);
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_checksumsize (
+ krb5_context /*context*/,
+ krb5_cksumtype /*type*/,
+ size_t */*size*/);
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_cksumtype_valid (
+ krb5_context /*context*/,
+ krb5_cksumtype /*ctype*/);
+
+void KRB5_LIB_FUNCTION
+krb5_clear_error_string (krb5_context /*context*/);
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_closelog (
+ krb5_context /*context*/,
+ krb5_log_facility */*fac*/);
+
+krb5_boolean KRB5_LIB_FUNCTION
+krb5_compare_creds (
+ krb5_context /*context*/,
+ krb5_flags /*whichfields*/,
+ const krb5_creds * /*mcreds*/,
+ const krb5_creds * /*creds*/);
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_config_file_free (
+ krb5_context /*context*/,
+ krb5_config_section */*s*/);
+
+void KRB5_LIB_FUNCTION
+krb5_config_free_strings (char **/*strings*/);
+
+const void *
+krb5_config_get (
+ krb5_context /*context*/,
+ const krb5_config_section */*c*/,
+ int /*type*/,
+ ...);
+
+krb5_boolean KRB5_LIB_FUNCTION
+krb5_config_get_bool (
+ krb5_context /*context*/,
+ const krb5_config_section */*c*/,
+ ...);
+
+krb5_boolean KRB5_LIB_FUNCTION
+krb5_config_get_bool_default (
+ krb5_context /*context*/,
+ const krb5_config_section */*c*/,
+ krb5_boolean /*def_value*/,
+ ...);
+
+int KRB5_LIB_FUNCTION
+krb5_config_get_int (
+ krb5_context /*context*/,
+ const krb5_config_section */*c*/,
+ ...);
+
+int KRB5_LIB_FUNCTION
+krb5_config_get_int_default (
+ krb5_context /*context*/,
+ const krb5_config_section */*c*/,
+ int /*def_value*/,
+ ...);
+
+const krb5_config_binding *
+krb5_config_get_list (
+ krb5_context /*context*/,
+ const krb5_config_section */*c*/,
+ ...);
+
+const void *
+krb5_config_get_next (
+ krb5_context /*context*/,
+ const krb5_config_section */*c*/,
+ const krb5_config_binding **/*pointer*/,
+ int /*type*/,
+ ...);
+
+const char* KRB5_LIB_FUNCTION
+krb5_config_get_string (
+ krb5_context /*context*/,
+ const krb5_config_section */*c*/,
+ ...);
+
+const char* KRB5_LIB_FUNCTION
+krb5_config_get_string_default (
+ krb5_context /*context*/,
+ const krb5_config_section */*c*/,
+ const char */*def_value*/,
+ ...);
+
+char**
+krb5_config_get_strings (
+ krb5_context /*context*/,
+ const krb5_config_section */*c*/,
+ ...);
+
+int KRB5_LIB_FUNCTION
+krb5_config_get_time (
+ krb5_context /*context*/,
+ const krb5_config_section */*c*/,
+ ...);
+
+int KRB5_LIB_FUNCTION
+krb5_config_get_time_default (
+ krb5_context /*context*/,
+ const krb5_config_section */*c*/,
+ int /*def_value*/,
+ ...);
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_config_parse_file (
+ krb5_context /*context*/,
+ const char */*fname*/,
+ krb5_config_section **/*res*/);
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_config_parse_file_multi (
+ krb5_context /*context*/,
+ const char */*fname*/,
+ krb5_config_section **/*res*/);
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_config_parse_string_multi (
+ krb5_context /*context*/,
+ const char */*string*/,
+ krb5_config_section **/*res*/);
+
+const void *
+krb5_config_vget (
+ krb5_context /*context*/,
+ const krb5_config_section */*c*/,
+ int /*type*/,
+ va_list /*args*/);
+
+krb5_boolean KRB5_LIB_FUNCTION
+krb5_config_vget_bool (
+ krb5_context /*context*/,
+ const krb5_config_section */*c*/,
+ va_list /*args*/);
+
+krb5_boolean KRB5_LIB_FUNCTION
+krb5_config_vget_bool_default (
+ krb5_context /*context*/,
+ const krb5_config_section */*c*/,
+ krb5_boolean /*def_value*/,
+ va_list /*args*/);
+
+int KRB5_LIB_FUNCTION
+krb5_config_vget_int (
+ krb5_context /*context*/,
+ const krb5_config_section */*c*/,
+ va_list /*args*/);
+
+int KRB5_LIB_FUNCTION
+krb5_config_vget_int_default (
+ krb5_context /*context*/,
+ const krb5_config_section */*c*/,
+ int /*def_value*/,
+ va_list /*args*/);
+
+const krb5_config_binding *
+krb5_config_vget_list (
+ krb5_context /*context*/,
+ const krb5_config_section */*c*/,
+ va_list /*args*/);
+
+const void *
+krb5_config_vget_next (
+ krb5_context /*context*/,
+ const krb5_config_section */*c*/,
+ const krb5_config_binding **/*pointer*/,
+ int /*type*/,
+ va_list /*args*/);
+
+const char* KRB5_LIB_FUNCTION
+krb5_config_vget_string (
+ krb5_context /*context*/,
+ const krb5_config_section */*c*/,
+ va_list /*args*/);
+
+const char* KRB5_LIB_FUNCTION
+krb5_config_vget_string_default (
+ krb5_context /*context*/,
+ const krb5_config_section */*c*/,
+ const char */*def_value*/,
+ va_list /*args*/);
+
+char ** KRB5_LIB_FUNCTION
+krb5_config_vget_strings (
+ krb5_context /*context*/,
+ const krb5_config_section */*c*/,
+ va_list /*args*/);
+
+int KRB5_LIB_FUNCTION
+krb5_config_vget_time (
+ krb5_context /*context*/,
+ const krb5_config_section */*c*/,
+ va_list /*args*/);
+
+int KRB5_LIB_FUNCTION
+krb5_config_vget_time_default (
+ krb5_context /*context*/,
+ const krb5_config_section */*c*/,
+ int /*def_value*/,
+ va_list /*args*/);
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_copy_address (
+ krb5_context /*context*/,
+ const krb5_address */*inaddr*/,
+ krb5_address */*outaddr*/);
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_copy_addresses (
+ krb5_context /*context*/,
+ const krb5_addresses */*inaddr*/,
+ krb5_addresses */*outaddr*/);
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_copy_checksum (
+ krb5_context /*context*/,
+ const krb5_checksum */*old*/,
+ krb5_checksum **/*new*/);
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_copy_creds (
+ krb5_context /*context*/,
+ const krb5_creds */*incred*/,
+ krb5_creds **/*outcred*/);
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_copy_creds_contents (
+ krb5_context /*context*/,
+ const krb5_creds */*incred*/,
+ krb5_creds */*c*/);
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_copy_data (
+ krb5_context /*context*/,
+ const krb5_data */*indata*/,
+ krb5_data **/*outdata*/);
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_copy_host_realm (
+ krb5_context /*context*/,
+ const krb5_realm */*from*/,
+ krb5_realm **/*to*/);
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_copy_keyblock (
+ krb5_context /*context*/,
+ const krb5_keyblock */*inblock*/,
+ krb5_keyblock **/*to*/);
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_copy_keyblock_contents (
+ krb5_context /*context*/,
+ const krb5_keyblock */*inblock*/,
+ krb5_keyblock */*to*/);
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_copy_principal (
+ krb5_context /*context*/,
+ krb5_const_principal /*inprinc*/,
+ krb5_principal */*outprinc*/);
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_copy_ticket (
+ krb5_context /*context*/,
+ const krb5_ticket */*from*/,
+ krb5_ticket **/*to*/);
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_create_checksum (
+ krb5_context /*context*/,
+ krb5_crypto /*crypto*/,
+ krb5_key_usage /*usage*/,
+ int /*type*/,
+ void */*data*/,
+ size_t /*len*/,
+ Checksum */*result*/);
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_crypto_destroy (
+ krb5_context /*context*/,
+ krb5_crypto /*crypto*/);
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_crypto_get_checksum_type (
+ krb5_context /*context*/,
+ krb5_crypto /*crypto*/,
+ krb5_cksumtype */*type*/);
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_crypto_get_params (
+ krb5_context /*context*/,
+ const krb5_crypto /*crypto*/,
+ const krb5_data */*params*/,
+ krb5_data */*ivec*/);
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_crypto_getblocksize (
+ krb5_context /*context*/,
+ krb5_crypto /*crypto*/,
+ size_t */*blocksize*/);
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_crypto_getconfoundersize (
+ krb5_context /*context*/,
+ krb5_crypto /*crypto*/,
+ size_t */*confoundersize*/);
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_crypto_getenctype (
+ krb5_context /*context*/,
+ krb5_crypto /*crypto*/,
+ krb5_enctype */*enctype*/);
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_crypto_getpadsize (
+ krb5_context /*context*/,
+ krb5_crypto /*crypto*/,
+ size_t */*padsize*/);
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_crypto_init (
+ krb5_context /*context*/,
+ const krb5_keyblock */*key*/,
+ krb5_enctype /*etype*/,
+ krb5_crypto */*crypto*/);
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_crypto_set_params (
+ krb5_context /*context*/,
+ const krb5_crypto /*crypto*/,
+ const krb5_data */*ivec*/,
+ krb5_data */*params*/);
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_data_alloc (
+ krb5_data */*p*/,
+ int /*len*/);
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_data_copy (
+ krb5_data */*p*/,
+ const void */*data*/,
+ size_t /*len*/);
+
+void KRB5_LIB_FUNCTION
+krb5_data_free (krb5_data */*p*/);
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_data_realloc (
+ krb5_data */*p*/,
+ int /*len*/);
+
+void KRB5_LIB_FUNCTION
+krb5_data_zero (krb5_data */*p*/);
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_decode_Authenticator (
+ krb5_context /*context*/,
+ const void */*data*/,
+ size_t /*length*/,
+ Authenticator */*t*/,
+ size_t */*len*/);
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_decode_ETYPE_INFO (
+ krb5_context /*context*/,
+ const void */*data*/,
+ size_t /*length*/,
+ ETYPE_INFO */*t*/,
+ size_t */*len*/);
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_decode_ETYPE_INFO2 (
+ krb5_context /*context*/,
+ const void */*data*/,
+ size_t /*length*/,
+ ETYPE_INFO2 */*t*/,
+ size_t */*len*/);
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_decode_EncAPRepPart (
+ krb5_context /*context*/,
+ const void */*data*/,
+ size_t /*length*/,
+ EncAPRepPart */*t*/,
+ size_t */*len*/);
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_decode_EncASRepPart (
+ krb5_context /*context*/,
+ const void */*data*/,
+ size_t /*length*/,
+ EncASRepPart */*t*/,
+ size_t */*len*/);
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_decode_EncKrbCredPart (
+ krb5_context /*context*/,
+ const void */*data*/,
+ size_t /*length*/,
+ EncKrbCredPart */*t*/,
+ size_t */*len*/);
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_decode_EncTGSRepPart (
+ krb5_context /*context*/,
+ const void */*data*/,
+ size_t /*length*/,
+ EncTGSRepPart */*t*/,
+ size_t */*len*/);
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_decode_EncTicketPart (
+ krb5_context /*context*/,
+ const void */*data*/,
+ size_t /*length*/,
+ EncTicketPart */*t*/,
+ size_t */*len*/);
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_decode_ap_req (
+ krb5_context /*context*/,
+ const krb5_data */*inbuf*/,
+ krb5_ap_req */*ap_req*/);
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_decrypt (
+ krb5_context /*context*/,
+ krb5_crypto /*crypto*/,
+ unsigned /*usage*/,
+ void */*data*/,
+ size_t /*len*/,
+ krb5_data */*result*/);
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_decrypt_EncryptedData (
+ krb5_context /*context*/,
+ krb5_crypto /*crypto*/,
+ unsigned /*usage*/,
+ const EncryptedData */*e*/,
+ krb5_data */*result*/);
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_decrypt_ivec (
+ krb5_context /*context*/,
+ krb5_crypto /*crypto*/,
+ unsigned /*usage*/,
+ void */*data*/,
+ size_t /*len*/,
+ krb5_data */*result*/,
+ void */*ivec*/);
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_decrypt_ticket (
+ krb5_context /*context*/,
+ Ticket */*ticket*/,
+ krb5_keyblock */*key*/,
+ EncTicketPart */*out*/,
+ krb5_flags /*flags*/);
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_derive_key (
+ krb5_context /*context*/,
+ const krb5_keyblock */*key*/,
+ krb5_enctype /*etype*/,
+ const void */*constant*/,
+ size_t /*constant_len*/,
+ krb5_keyblock **/*derived_key*/);
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_domain_x500_decode (
+ krb5_context /*context*/,
+ krb5_data /*tr*/,
+ char ***/*realms*/,
+ int */*num_realms*/,
+ const char */*client_realm*/,
+ const char */*server_realm*/);
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_domain_x500_encode (
+ char **/*realms*/,
+ int /*num_realms*/,
+ krb5_data */*encoding*/);
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_eai_to_heim_errno (
+ int /*eai_errno*/,
+ int /*system_error*/);
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_encode_Authenticator (
+ krb5_context /*context*/,
+ void */*data*/,
+ size_t /*length*/,
+ Authenticator */*t*/,
+ size_t */*len*/);
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_encode_ETYPE_INFO (
+ krb5_context /*context*/,
+ void */*data*/,
+ size_t /*length*/,
+ ETYPE_INFO */*t*/,
+ size_t */*len*/);
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_encode_ETYPE_INFO2 (
+ krb5_context /*context*/,
+ void */*data*/,
+ size_t /*length*/,
+ ETYPE_INFO2 */*t*/,
+ size_t */*len*/);
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_encode_EncAPRepPart (
+ krb5_context /*context*/,
+ void */*data*/,
+ size_t /*length*/,
+ EncAPRepPart */*t*/,
+ size_t */*len*/);
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_encode_EncASRepPart (
+ krb5_context /*context*/,
+ void */*data*/,
+ size_t /*length*/,
+ EncASRepPart */*t*/,
+ size_t */*len*/);
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_encode_EncKrbCredPart (
+ krb5_context /*context*/,
+ void */*data*/,
+ size_t /*length*/,
+ EncKrbCredPart */*t*/,
+ size_t */*len*/);
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_encode_EncTGSRepPart (
+ krb5_context /*context*/,
+ void */*data*/,
+ size_t /*length*/,
+ EncTGSRepPart */*t*/,
+ size_t */*len*/);
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_encode_EncTicketPart (
+ krb5_context /*context*/,
+ void */*data*/,
+ size_t /*length*/,
+ EncTicketPart */*t*/,
+ size_t */*len*/);
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_encrypt (
+ krb5_context /*context*/,
+ krb5_crypto /*crypto*/,
+ unsigned /*usage*/,
+ void */*data*/,
+ size_t /*len*/,
+ krb5_data */*result*/);
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_encrypt_EncryptedData (
+ krb5_context /*context*/,
+ krb5_crypto /*crypto*/,
+ unsigned /*usage*/,
+ void */*data*/,
+ size_t /*len*/,
+ int /*kvno*/,
+ EncryptedData */*result*/);
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_encrypt_ivec (
+ krb5_context /*context*/,
+ krb5_crypto /*crypto*/,
+ unsigned /*usage*/,
+ void */*data*/,
+ size_t /*len*/,
+ krb5_data */*result*/,
+ void */*ivec*/);
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_enctype_disable (
+ krb5_context /*context*/,
+ krb5_enctype /*enctype*/);
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_enctype_keysize (
+ krb5_context /*context*/,
+ krb5_enctype /*type*/,
+ size_t */*keysize*/);
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_enctype_to_keytype (
+ krb5_context /*context*/,
+ krb5_enctype /*etype*/,
+ krb5_keytype */*keytype*/);
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_enctype_to_oid (
+ krb5_context /*context*/,
+ krb5_enctype /*etype*/,
+ heim_oid */*oid*/);
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_enctype_to_string (
+ krb5_context /*context*/,
+ krb5_enctype /*etype*/,
+ char **/*string*/);
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_enctype_valid (
+ krb5_context /*context*/,
+ krb5_enctype /*etype*/);
+
+krb5_boolean KRB5_LIB_FUNCTION
+krb5_enctypes_compatible_keys (
+ krb5_context /*context*/,
+ krb5_enctype /*etype1*/,
+ krb5_enctype /*etype2*/);
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_err (
+ krb5_context /*context*/,
+ int /*eval*/,
+ krb5_error_code /*code*/,
+ const char */*fmt*/,
+ ...)
+ __attribute__ ((noreturn, format (printf, 4, 5)));
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_error_from_rd_error (
+ krb5_context /*context*/,
+ const krb5_error */*error*/,
+ const krb5_creds */*creds*/);
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_errx (
+ krb5_context /*context*/,
+ int /*eval*/,
+ const char */*fmt*/,
+ ...)
+ __attribute__ ((noreturn, format (printf, 3, 4)));
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_expand_hostname (
+ krb5_context /*context*/,
+ const char */*orig_hostname*/,
+ char **/*new_hostname*/);
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_expand_hostname_realms (
+ krb5_context /*context*/,
+ const char */*orig_hostname*/,
+ char **/*new_hostname*/,
+ char ***/*realms*/);
+
+PA_DATA *
+krb5_find_padata (
+ PA_DATA */*val*/,
+ unsigned /*len*/,
+ int /*type*/,
+ int */*idx*/);
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_format_time (
+ krb5_context /*context*/,
+ time_t /*t*/,
+ char */*s*/,
+ size_t /*len*/,
+ krb5_boolean /*include_time*/);
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_free_address (
+ krb5_context /*context*/,
+ krb5_address */*address*/);
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_free_addresses (
+ krb5_context /*context*/,
+ krb5_addresses */*addresses*/);
+
+void KRB5_LIB_FUNCTION
+krb5_free_ap_rep_enc_part (
+ krb5_context /*context*/,
+ krb5_ap_rep_enc_part */*val*/);
+
+void KRB5_LIB_FUNCTION
+krb5_free_authenticator (
+ krb5_context /*context*/,
+ krb5_authenticator */*authenticator*/);
+
+void KRB5_LIB_FUNCTION
+krb5_free_checksum (
+ krb5_context /*context*/,
+ krb5_checksum */*cksum*/);
+
+void KRB5_LIB_FUNCTION
+krb5_free_checksum_contents (
+ krb5_context /*context*/,
+ krb5_checksum */*cksum*/);
+
+void KRB5_LIB_FUNCTION
+krb5_free_config_files (char **/*filenames*/);
+
+void KRB5_LIB_FUNCTION
+krb5_free_context (krb5_context /*context*/);
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_free_cred_contents (
+ krb5_context /*context*/,
+ krb5_creds */*c*/);
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_free_creds (
+ krb5_context /*context*/,
+ krb5_creds */*c*/);
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_free_creds_contents (
+ krb5_context /*context*/,
+ krb5_creds */*c*/);
+
+void KRB5_LIB_FUNCTION
+krb5_free_data (
+ krb5_context /*context*/,
+ krb5_data */*p*/);
+
+void KRB5_LIB_FUNCTION
+krb5_free_data_contents (
+ krb5_context /*context*/,
+ krb5_data */*data*/);
+
+void KRB5_LIB_FUNCTION
+krb5_free_error (
+ krb5_context /*context*/,
+ krb5_error */*error*/);
+
+void KRB5_LIB_FUNCTION
+krb5_free_error_contents (
+ krb5_context /*context*/,
+ krb5_error */*error*/);
+
+void KRB5_LIB_FUNCTION
+krb5_free_error_string (
+ krb5_context /*context*/,
+ char */*str*/);
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_free_host_realm (
+ krb5_context /*context*/,
+ krb5_realm */*realmlist*/);
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_free_kdc_rep (
+ krb5_context /*context*/,
+ krb5_kdc_rep */*rep*/);
+
+void KRB5_LIB_FUNCTION
+krb5_free_keyblock (
+ krb5_context /*context*/,
+ krb5_keyblock */*keyblock*/);
+
+void KRB5_LIB_FUNCTION
+krb5_free_keyblock_contents (
+ krb5_context /*context*/,
+ krb5_keyblock */*keyblock*/);
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_free_krbhst (
+ krb5_context /*context*/,
+ char **/*hostlist*/);
+
+void KRB5_LIB_FUNCTION
+krb5_free_principal (
+ krb5_context /*context*/,
+ krb5_principal /*p*/);
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_free_salt (
+ krb5_context /*context*/,
+ krb5_salt /*salt*/);
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_free_ticket (
+ krb5_context /*context*/,
+ krb5_ticket */*ticket*/);
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_fwd_tgt_creds (
+ krb5_context /*context*/,
+ krb5_auth_context /*auth_context*/,
+ const char */*hostname*/,
+ krb5_principal /*client*/,
+ krb5_principal /*server*/,
+ krb5_ccache /*ccache*/,
+ int /*forwardable*/,
+ krb5_data */*out_data*/);
+
+void KRB5_LIB_FUNCTION
+krb5_generate_random_block (
+ void */*buf*/,
+ size_t /*len*/);
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_generate_random_keyblock (
+ krb5_context /*context*/,
+ krb5_enctype /*type*/,
+ krb5_keyblock */*key*/);
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_generate_seq_number (
+ krb5_context /*context*/,
+ const krb5_keyblock */*key*/,
+ u_int32_t */*seqno*/);
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_generate_subkey (
+ krb5_context /*context*/,
+ const krb5_keyblock */*key*/,
+ krb5_keyblock **/*subkey*/);
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_generate_subkey_extended (
+ krb5_context /*context*/,
+ const krb5_keyblock */*key*/,
+ krb5_enctype /*etype*/,
+ krb5_keyblock **/*subkey*/);
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_get_all_client_addrs (
+ krb5_context /*context*/,
+ krb5_addresses */*res*/);
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_get_all_server_addrs (
+ krb5_context /*context*/,
+ krb5_addresses */*res*/);
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_get_cred_from_kdc (
+ krb5_context /*context*/,
+ krb5_ccache /*ccache*/,
+ krb5_creds */*in_creds*/,
+ krb5_creds **/*out_creds*/,
+ krb5_creds ***/*ret_tgts*/);
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_get_cred_from_kdc_opt (
+ krb5_context /*context*/,
+ krb5_ccache /*ccache*/,
+ krb5_creds */*in_creds*/,
+ krb5_creds **/*out_creds*/,
+ krb5_creds ***/*ret_tgts*/,
+ krb5_flags /*flags*/);
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_get_credentials (
+ krb5_context /*context*/,
+ krb5_flags /*options*/,
+ krb5_ccache /*ccache*/,
+ krb5_creds */*in_creds*/,
+ krb5_creds **/*out_creds*/);
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_get_credentials_with_flags (
+ krb5_context /*context*/,
+ krb5_flags /*options*/,
+ krb5_kdc_flags /*flags*/,
+ krb5_ccache /*ccache*/,
+ krb5_creds */*in_creds*/,
+ krb5_creds **/*out_creds*/);
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_get_default_config_files (char ***/*pfilenames*/);
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_get_default_in_tkt_etypes (
+ krb5_context /*context*/,
+ krb5_enctype **/*etypes*/);
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_get_default_principal (
+ krb5_context /*context*/,
+ krb5_principal */*princ*/);
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_get_default_realm (
+ krb5_context /*context*/,
+ krb5_realm */*realm*/);
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_get_default_realms (
+ krb5_context /*context*/,
+ krb5_realm **/*realms*/);
+
+const char* KRB5_LIB_FUNCTION
+krb5_get_err_text (
+ krb5_context /*context*/,
+ krb5_error_code /*code*/);
+
+char * KRB5_LIB_FUNCTION
+krb5_get_error_string (krb5_context /*context*/);
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_get_extra_addresses (
+ krb5_context /*context*/,
+ krb5_addresses */*addresses*/);
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_get_fcache_version (
+ krb5_context /*context*/,
+ int */*version*/);
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_get_forwarded_creds (
+ krb5_context /*context*/,
+ krb5_auth_context /*auth_context*/,
+ krb5_ccache /*ccache*/,
+ krb5_flags /*flags*/,
+ const char */*hostname*/,
+ krb5_creds */*in_creds*/,
+ krb5_data */*out_data*/);
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_get_host_realm (
+ krb5_context /*context*/,
+ const char */*host*/,
+ krb5_realm **/*realms*/);
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_get_ignore_addresses (
+ krb5_context /*context*/,
+ krb5_addresses */*addresses*/);
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_get_in_cred (
+ krb5_context /*context*/,
+ krb5_flags /*options*/,
+ const krb5_addresses */*addrs*/,
+ const krb5_enctype */*etypes*/,
+ const krb5_preauthtype */*ptypes*/,
+ const krb5_preauthdata */*preauth*/,
+ krb5_key_proc /*key_proc*/,
+ krb5_const_pointer /*keyseed*/,
+ krb5_decrypt_proc /*decrypt_proc*/,
+ krb5_const_pointer /*decryptarg*/,
+ krb5_creds */*creds*/,
+ krb5_kdc_rep */*ret_as_reply*/);
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_get_in_tkt (
+ krb5_context /*context*/,
+ krb5_flags /*options*/,
+ const krb5_addresses */*addrs*/,
+ const krb5_enctype */*etypes*/,
+ const krb5_preauthtype */*ptypes*/,
+ krb5_key_proc /*key_proc*/,
+ krb5_const_pointer /*keyseed*/,
+ krb5_decrypt_proc /*decrypt_proc*/,
+ krb5_const_pointer /*decryptarg*/,
+ krb5_creds */*creds*/,
+ krb5_ccache /*ccache*/,
+ krb5_kdc_rep */*ret_as_reply*/);
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_get_in_tkt_with_keytab (
+ krb5_context /*context*/,
+ krb5_flags /*options*/,
+ krb5_addresses */*addrs*/,
+ const krb5_enctype */*etypes*/,
+ const krb5_preauthtype */*pre_auth_types*/,
+ krb5_keytab /*keytab*/,
+ krb5_ccache /*ccache*/,
+ krb5_creds */*creds*/,
+ krb5_kdc_rep */*ret_as_reply*/);
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_get_in_tkt_with_password (
+ krb5_context /*context*/,
+ krb5_flags /*options*/,
+ krb5_addresses */*addrs*/,
+ const krb5_enctype */*etypes*/,
+ const krb5_preauthtype */*pre_auth_types*/,
+ const char */*password*/,
+ krb5_ccache /*ccache*/,
+ krb5_creds */*creds*/,
+ krb5_kdc_rep */*ret_as_reply*/);
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_get_in_tkt_with_skey (
+ krb5_context /*context*/,
+ krb5_flags /*options*/,
+ krb5_addresses */*addrs*/,
+ const krb5_enctype */*etypes*/,
+ const krb5_preauthtype */*pre_auth_types*/,
+ const krb5_keyblock */*key*/,
+ krb5_ccache /*ccache*/,
+ krb5_creds */*creds*/,
+ krb5_kdc_rep */*ret_as_reply*/);
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_get_init_creds (
+ krb5_context /*context*/,
+ krb5_creds */*creds*/,
+ krb5_principal /*client*/,
+ krb5_prompter_fct /*prompter*/,
+ void */*data*/,
+ krb5_deltat /*start_time*/,
+ const char */*in_tkt_service*/,
+ krb5_get_init_creds_opt */*options*/);
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_get_init_creds_keyblock (
+ krb5_context /*context*/,
+ krb5_creds */*creds*/,
+ krb5_principal /*client*/,
+ krb5_keyblock */*keyblock*/,
+ krb5_deltat /*start_time*/,
+ const char */*in_tkt_service*/,
+ krb5_get_init_creds_opt */*options*/);
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_get_init_creds_keytab (
+ krb5_context /*context*/,
+ krb5_creds */*creds*/,
+ krb5_principal /*client*/,
+ krb5_keytab /*keytab*/,
+ krb5_deltat /*start_time*/,
+ const char */*in_tkt_service*/,
+ krb5_get_init_creds_opt */*options*/);
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_get_init_creds_opt_alloc (
+ krb5_context /*context*/,
+ krb5_get_init_creds_opt **/*opt*/);
+
+void KRB5_LIB_FUNCTION
+krb5_get_init_creds_opt_free (krb5_get_init_creds_opt */*opt*/);
+
+void KRB5_LIB_FUNCTION
+krb5_get_init_creds_opt_init (krb5_get_init_creds_opt */*opt*/);
+
+void KRB5_LIB_FUNCTION
+krb5_get_init_creds_opt_set_address_list (
+ krb5_get_init_creds_opt */*opt*/,
+ krb5_addresses */*addresses*/);
+
+void KRB5_LIB_FUNCTION
+krb5_get_init_creds_opt_set_anonymous (
+ krb5_get_init_creds_opt */*opt*/,
+ int /*anonymous*/);
+
+void KRB5_LIB_FUNCTION
+krb5_get_init_creds_opt_set_default_flags (
+ krb5_context /*context*/,
+ const char */*appname*/,
+ krb5_const_realm /*realm*/,
+ krb5_get_init_creds_opt */*opt*/);
+
+void KRB5_LIB_FUNCTION
+krb5_get_init_creds_opt_set_etype_list (
+ krb5_get_init_creds_opt */*opt*/,
+ krb5_enctype */*etype_list*/,
+ int /*etype_list_length*/);
+
+void KRB5_LIB_FUNCTION
+krb5_get_init_creds_opt_set_forwardable (
+ krb5_get_init_creds_opt */*opt*/,
+ int /*forwardable*/);
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_get_init_creds_opt_set_pa_password (
+ krb5_context /*context*/,
+ krb5_get_init_creds_opt */*opt*/,
+ const char */*password*/,
+ krb5_s2k_proc /*key_proc*/);
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_get_init_creds_opt_set_pac_request (
+ krb5_context /*context*/,
+ krb5_get_init_creds_opt */*opt*/,
+ krb5_boolean /*req_pac*/);
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_get_init_creds_opt_set_pkinit (
+ krb5_context /*context*/,
+ krb5_get_init_creds_opt */*opt*/,
+ krb5_principal /*principal*/,
+ const char */*user_id*/,
+ const char */*x509_anchors*/,
+ int /*flags*/,
+ krb5_prompter_fct /*prompter*/,
+ void */*prompter_data*/,
+ char */*password*/);
+
+void KRB5_LIB_FUNCTION
+krb5_get_init_creds_opt_set_preauth_list (
+ krb5_get_init_creds_opt */*opt*/,
+ krb5_preauthtype */*preauth_list*/,
+ int /*preauth_list_length*/);
+
+void KRB5_LIB_FUNCTION
+krb5_get_init_creds_opt_set_proxiable (
+ krb5_get_init_creds_opt */*opt*/,
+ int /*proxiable*/);
+
+void KRB5_LIB_FUNCTION
+krb5_get_init_creds_opt_set_renew_life (
+ krb5_get_init_creds_opt */*opt*/,
+ krb5_deltat /*renew_life*/);
+
+void KRB5_LIB_FUNCTION
+krb5_get_init_creds_opt_set_salt (
+ krb5_get_init_creds_opt */*opt*/,
+ krb5_data */*salt*/);
+
+void KRB5_LIB_FUNCTION
+krb5_get_init_creds_opt_set_tkt_life (
+ krb5_get_init_creds_opt */*opt*/,
+ krb5_deltat /*tkt_life*/);
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_get_init_creds_password (
+ krb5_context /*context*/,
+ krb5_creds */*creds*/,
+ krb5_principal /*client*/,
+ const char */*password*/,
+ krb5_prompter_fct /*prompter*/,
+ void */*data*/,
+ krb5_deltat /*start_time*/,
+ const char */*in_tkt_service*/,
+ krb5_get_init_creds_opt */*in_options*/);
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_get_kdc_cred (
+ krb5_context /*context*/,
+ krb5_ccache /*id*/,
+ krb5_kdc_flags /*flags*/,
+ krb5_addresses */*addresses*/,
+ Ticket */*second_ticket*/,
+ krb5_creds */*in_creds*/,
+ krb5_creds **out_creds );
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_get_krb524hst (
+ krb5_context /*context*/,
+ const krb5_realm */*realm*/,
+ char ***/*hostlist*/);
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_get_krb_admin_hst (
+ krb5_context /*context*/,
+ const krb5_realm */*realm*/,
+ char ***/*hostlist*/);
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_get_krb_changepw_hst (
+ krb5_context /*context*/,
+ const krb5_realm */*realm*/,
+ char ***/*hostlist*/);
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_get_krbhst (
+ krb5_context /*context*/,
+ const krb5_realm */*realm*/,
+ char ***/*hostlist*/);
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_get_pw_salt (
+ krb5_context /*context*/,
+ krb5_const_principal /*principal*/,
+ krb5_salt */*salt*/);
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_get_server_rcache (
+ krb5_context /*context*/,
+ const krb5_data */*piece*/,
+ krb5_rcache */*id*/);
+
+krb5_boolean KRB5_LIB_FUNCTION
+krb5_get_use_admin_kdc (krb5_context /*context*/);
+
+size_t
+krb5_get_wrapped_length (
+ krb5_context /*context*/,
+ krb5_crypto /*crypto*/,
+ size_t /*data_len*/);
+
+int KRB5_LIB_FUNCTION
+krb5_getportbyname (
+ krb5_context /*context*/,
+ const char */*service*/,
+ const char */*proto*/,
+ int /*default_port*/);
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_h_addr2addr (
+ krb5_context /*context*/,
+ int /*af*/,
+ const char */*haddr*/,
+ krb5_address */*addr*/);
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_h_addr2sockaddr (
+ krb5_context /*context*/,
+ int /*af*/,
+ const char */*addr*/,
+ struct sockaddr */*sa*/,
+ krb5_socklen_t */*sa_size*/,
+ int /*port*/);
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_h_errno_to_heim_errno (int /*eai_errno*/);
+
+krb5_boolean KRB5_LIB_FUNCTION
+krb5_have_error_string (krb5_context /*context*/);
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_hmac (
+ krb5_context /*context*/,
+ krb5_cksumtype /*cktype*/,
+ const void */*data*/,
+ size_t /*len*/,
+ unsigned /*usage*/,
+ krb5_keyblock */*key*/,
+ Checksum */*result*/);
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_init_context (krb5_context */*context*/);
+
+void KRB5_LIB_FUNCTION
+krb5_init_ets (krb5_context /*context*/);
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_init_etype (
+ krb5_context /*context*/,
+ unsigned */*len*/,
+ krb5_enctype **/*val*/,
+ const krb5_enctype */*etypes*/);
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_initlog (
+ krb5_context /*context*/,
+ const char */*program*/,
+ krb5_log_facility **/*fac*/);
+
+krb5_boolean KRB5_LIB_FUNCTION
+krb5_is_thread_safe (void);
+
+krb5_enctype
+krb5_keyblock_get_enctype (const krb5_keyblock */*block*/);
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_keyblock_init (
+ krb5_context /*context*/,
+ krb5_enctype /*type*/,
+ const void */*data*/,
+ size_t /*size*/,
+ krb5_keyblock */*key*/);
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_keyblock_key_proc (
+ krb5_context /*context*/,
+ krb5_keytype /*type*/,
+ krb5_data */*salt*/,
+ krb5_const_pointer /*keyseed*/,
+ krb5_keyblock **/*key*/);
+
+void KRB5_LIB_FUNCTION
+krb5_keyblock_zero (krb5_keyblock */*keyblock*/);
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_keytab_key_proc (
+ krb5_context /*context*/,
+ krb5_enctype /*enctype*/,
+ krb5_salt /*salt*/,
+ krb5_const_pointer /*keyseed*/,
+ krb5_keyblock **/*key*/);
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_keytype_to_enctypes (
+ krb5_context /*context*/,
+ krb5_keytype /*keytype*/,
+ unsigned */*len*/,
+ krb5_enctype **/*val*/);
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_keytype_to_enctypes_default (
+ krb5_context /*context*/,
+ krb5_keytype /*keytype*/,
+ unsigned */*len*/,
+ krb5_enctype **/*val*/);
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_keytype_to_string (
+ krb5_context /*context*/,
+ krb5_keytype /*keytype*/,
+ char **/*string*/);
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_krbhst_format_string (
+ krb5_context /*context*/,
+ const krb5_krbhst_info */*host*/,
+ char */*hostname*/,
+ size_t /*hostlen*/);
+
+void KRB5_LIB_FUNCTION
+krb5_krbhst_free (
+ krb5_context /*context*/,
+ krb5_krbhst_handle /*handle*/);
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_krbhst_get_addrinfo (
+ krb5_context /*context*/,
+ krb5_krbhst_info */*host*/,
+ struct addrinfo **/*ai*/);
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_krbhst_init (
+ krb5_context /*context*/,
+ const char */*realm*/,
+ unsigned int /*type*/,
+ krb5_krbhst_handle */*handle*/);
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_krbhst_init_flags (
+ krb5_context /*context*/,
+ const char */*realm*/,
+ unsigned int /*type*/,
+ int /*flags*/,
+ krb5_krbhst_handle */*handle*/);
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_krbhst_next (
+ krb5_context /*context*/,
+ krb5_krbhst_handle /*handle*/,
+ krb5_krbhst_info **/*host*/);
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_krbhst_next_as_string (
+ krb5_context /*context*/,
+ krb5_krbhst_handle /*handle*/,
+ char */*hostname*/,
+ size_t /*hostlen*/);
+
+void KRB5_LIB_FUNCTION
+krb5_krbhst_reset (
+ krb5_context /*context*/,
+ krb5_krbhst_handle /*handle*/);
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_kt_add_entry (
+ krb5_context /*context*/,
+ krb5_keytab /*id*/,
+ krb5_keytab_entry */*entry*/);
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_kt_close (
+ krb5_context /*context*/,
+ krb5_keytab /*id*/);
+
+krb5_boolean KRB5_LIB_FUNCTION
+krb5_kt_compare (
+ krb5_context /*context*/,
+ krb5_keytab_entry */*entry*/,
+ krb5_const_principal /*principal*/,
+ krb5_kvno /*vno*/,
+ krb5_enctype /*enctype*/);
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_kt_copy_entry_contents (
+ krb5_context /*context*/,
+ const krb5_keytab_entry */*in*/,
+ krb5_keytab_entry */*out*/);
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_kt_default (
+ krb5_context /*context*/,
+ krb5_keytab */*id*/);
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_kt_default_modify_name (
+ krb5_context /*context*/,
+ char */*name*/,
+ size_t /*namesize*/);
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_kt_default_name (
+ krb5_context /*context*/,
+ char */*name*/,
+ size_t /*namesize*/);
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_kt_end_seq_get (
+ krb5_context /*context*/,
+ krb5_keytab /*id*/,
+ krb5_kt_cursor */*cursor*/);
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_kt_free_entry (
+ krb5_context /*context*/,
+ krb5_keytab_entry */*entry*/);
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_kt_get_entry (
+ krb5_context /*context*/,
+ krb5_keytab /*id*/,
+ krb5_const_principal /*principal*/,
+ krb5_kvno /*kvno*/,
+ krb5_enctype /*enctype*/,
+ krb5_keytab_entry */*entry*/);
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_kt_get_name (
+ krb5_context /*context*/,
+ krb5_keytab /*keytab*/,
+ char */*name*/,
+ size_t /*namesize*/);
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_kt_get_type (
+ krb5_context /*context*/,
+ krb5_keytab /*keytab*/,
+ char */*prefix*/,
+ size_t /*prefixsize*/);
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_kt_next_entry (
+ krb5_context /*context*/,
+ krb5_keytab /*id*/,
+ krb5_keytab_entry */*entry*/,
+ krb5_kt_cursor */*cursor*/);
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_kt_read_service_key (
+ krb5_context /*context*/,
+ krb5_pointer /*keyprocarg*/,
+ krb5_principal /*principal*/,
+ krb5_kvno /*vno*/,
+ krb5_enctype /*enctype*/,
+ krb5_keyblock **/*key*/);
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_kt_register (
+ krb5_context /*context*/,
+ const krb5_kt_ops */*ops*/);
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_kt_remove_entry (
+ krb5_context /*context*/,
+ krb5_keytab /*id*/,
+ krb5_keytab_entry */*entry*/);
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_kt_resolve (
+ krb5_context /*context*/,
+ const char */*name*/,
+ krb5_keytab */*id*/);
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_kt_start_seq_get (
+ krb5_context /*context*/,
+ krb5_keytab /*id*/,
+ krb5_kt_cursor */*cursor*/);
+
+krb5_boolean KRB5_LIB_FUNCTION
+krb5_kuserok (
+ krb5_context /*context*/,
+ krb5_principal /*principal*/,
+ const char */*luser*/);
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_log (
+ krb5_context /*context*/,
+ krb5_log_facility */*fac*/,
+ int /*level*/,
+ const char */*fmt*/,
+ ...)
+ __attribute__((format (printf, 4, 5)));
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_log_msg (
+ krb5_context /*context*/,
+ krb5_log_facility */*fac*/,
+ int /*level*/,
+ char **/*reply*/,
+ const char */*fmt*/,
+ ...)
+ __attribute__((format (printf, 5, 6)));
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_make_addrport (
+ krb5_context /*context*/,
+ krb5_address **/*res*/,
+ const krb5_address */*addr*/,
+ int16_t /*port*/);
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_make_principal (
+ krb5_context /*context*/,
+ krb5_principal */*principal*/,
+ krb5_const_realm /*realm*/,
+ ...);
+
+size_t KRB5_LIB_FUNCTION
+krb5_max_sockaddr_size (void);
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_mk_error (
+ krb5_context /*context*/,
+ krb5_error_code /*error_code*/,
+ const char */*e_text*/,
+ const krb5_data */*e_data*/,
+ const krb5_principal /*client*/,
+ const krb5_principal /*server*/,
+ time_t */*client_time*/,
+ int */*client_usec*/,
+ krb5_data */*reply*/);
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_mk_priv (
+ krb5_context /*context*/,
+ krb5_auth_context /*auth_context*/,
+ const krb5_data */*userdata*/,
+ krb5_data */*outbuf*/,
+ krb5_replay_data */*outdata*/);
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_mk_rep (
+ krb5_context /*context*/,
+ krb5_auth_context /*auth_context*/,
+ krb5_data */*outbuf*/);
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_mk_req (
+ krb5_context /*context*/,
+ krb5_auth_context */*auth_context*/,
+ const krb5_flags /*ap_req_options*/,
+ const char */*service*/,
+ const char */*hostname*/,
+ krb5_data */*in_data*/,
+ krb5_ccache /*ccache*/,
+ krb5_data */*outbuf*/);
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_mk_req_exact (
+ krb5_context /*context*/,
+ krb5_auth_context */*auth_context*/,
+ const krb5_flags /*ap_req_options*/,
+ const krb5_principal /*server*/,
+ krb5_data */*in_data*/,
+ krb5_ccache /*ccache*/,
+ krb5_data */*outbuf*/);
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_mk_req_extended (
+ krb5_context /*context*/,
+ krb5_auth_context */*auth_context*/,
+ const krb5_flags /*ap_req_options*/,
+ krb5_data */*in_data*/,
+ krb5_creds */*in_creds*/,
+ krb5_data */*outbuf*/);
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_mk_safe (
+ krb5_context /*context*/,
+ krb5_auth_context /*auth_context*/,
+ const krb5_data */*userdata*/,
+ krb5_data */*outbuf*/,
+ krb5_replay_data */*outdata*/);
+
+krb5_ssize_t KRB5_LIB_FUNCTION
+krb5_net_read (
+ krb5_context /*context*/,
+ void */*p_fd*/,
+ void */*buf*/,
+ size_t /*len*/);
+
+krb5_ssize_t KRB5_LIB_FUNCTION
+krb5_net_write (
+ krb5_context /*context*/,
+ void */*p_fd*/,
+ const void */*buf*/,
+ size_t /*len*/);
+
+krb5_ssize_t KRB5_LIB_FUNCTION
+krb5_net_write_block (
+ krb5_context /*context*/,
+ void */*p_fd*/,
+ const void */*buf*/,
+ size_t /*len*/,
+ time_t /*timeout*/);
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_openlog (
+ krb5_context /*context*/,
+ const char */*program*/,
+ krb5_log_facility **/*fac*/);
+
+int KRB5_LIB_FUNCTION
+krb5_padata_add (
+ krb5_context /*context*/,
+ METHOD_DATA */*md*/,
+ int /*type*/,
+ void */*buf*/,
+ size_t /*len*/);
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_parse_address (
+ krb5_context /*context*/,
+ const char */*string*/,
+ krb5_addresses */*addresses*/);
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_parse_name (
+ krb5_context /*context*/,
+ const char */*name*/,
+ krb5_principal */*principal*/);
+
+const char* KRB5_LIB_FUNCTION
+krb5_passwd_result_to_string (
+ krb5_context /*context*/,
+ int /*result*/);
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_password_key_proc (
+ krb5_context /*context*/,
+ krb5_enctype /*type*/,
+ krb5_salt /*salt*/,
+ krb5_const_pointer /*keyseed*/,
+ krb5_keyblock **/*key*/);
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_prepend_config_files (
+ const char */*filelist*/,
+ char **/*pq*/,
+ char ***/*ret_pp*/);
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_prepend_config_files_default (
+ const char */*filelist*/,
+ char ***/*pfilenames*/);
+
+krb5_realm*
+krb5_princ_realm (
+ krb5_context /*context*/,
+ krb5_principal /*principal*/);
+
+void KRB5_LIB_FUNCTION
+krb5_princ_set_realm (
+ krb5_context /*context*/,
+ krb5_principal /*principal*/,
+ krb5_realm */*realm*/);
+
+krb5_boolean KRB5_LIB_FUNCTION
+krb5_principal_compare (
+ krb5_context /*context*/,
+ krb5_const_principal /*princ1*/,
+ krb5_const_principal /*princ2*/);
+
+krb5_boolean KRB5_LIB_FUNCTION
+krb5_principal_compare_any_realm (
+ krb5_context /*context*/,
+ krb5_const_principal /*princ1*/,
+ krb5_const_principal /*princ2*/);
+
+const char* KRB5_LIB_FUNCTION
+krb5_principal_get_comp_string (
+ krb5_context /*context*/,
+ krb5_principal /*principal*/,
+ unsigned int /*component*/);
+
+const char* KRB5_LIB_FUNCTION
+krb5_principal_get_realm (
+ krb5_context /*context*/,
+ krb5_const_principal /*principal*/);
+
+int KRB5_LIB_FUNCTION
+krb5_principal_get_type (
+ krb5_context /*context*/,
+ krb5_principal /*principal*/);
+
+krb5_boolean KRB5_LIB_FUNCTION
+krb5_principal_match (
+ krb5_context /*context*/,
+ krb5_const_principal /*princ*/,
+ krb5_const_principal /*pattern*/);
+
+void KRB5_LIB_FUNCTION
+krb5_principal_set_type (
+ krb5_context /*context*/,
+ krb5_principal /*principal*/,
+ int /*type*/);
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_print_address (
+ const krb5_address */*addr*/,
+ char */*str*/,
+ size_t /*len*/,
+ size_t */*ret_len*/);
+
+int KRB5_LIB_FUNCTION
+krb5_program_setup (
+ krb5_context */*context*/,
+ int /*argc*/,
+ char **/*argv*/,
+ struct getargs */*args*/,
+ int /*num_args*/,
+ void (*/*usage*/)(int, struct getargs*, int));
+
+int KRB5_LIB_FUNCTION
+krb5_prompter_posix (
+ krb5_context /*context*/,
+ void */*data*/,
+ const char */*name*/,
+ const char */*banner*/,
+ int /*num_prompts*/,
+ krb5_prompt prompts[]);
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_random_to_key (
+ krb5_context /*context*/,
+ krb5_enctype /*type*/,
+ const void */*data*/,
+ size_t /*size*/,
+ krb5_keyblock */*key*/);
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_rc_close (
+ krb5_context /*context*/,
+ krb5_rcache /*id*/);
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_rc_default (
+ krb5_context /*context*/,
+ krb5_rcache */*id*/);
+
+const char* KRB5_LIB_FUNCTION
+krb5_rc_default_name (krb5_context /*context*/);
+
+const char* KRB5_LIB_FUNCTION
+krb5_rc_default_type (krb5_context /*context*/);
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_rc_destroy (
+ krb5_context /*context*/,
+ krb5_rcache /*id*/);
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_rc_expunge (
+ krb5_context /*context*/,
+ krb5_rcache /*id*/);
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_rc_get_lifespan (
+ krb5_context /*context*/,
+ krb5_rcache /*id*/,
+ krb5_deltat */*auth_lifespan*/);
+
+const char* KRB5_LIB_FUNCTION
+krb5_rc_get_name (
+ krb5_context /*context*/,
+ krb5_rcache /*id*/);
+
+const char* KRB5_LIB_FUNCTION
+krb5_rc_get_type (
+ krb5_context /*context*/,
+ krb5_rcache /*id*/);
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_rc_initialize (
+ krb5_context /*context*/,
+ krb5_rcache /*id*/,
+ krb5_deltat /*auth_lifespan*/);
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_rc_recover (
+ krb5_context /*context*/,
+ krb5_rcache /*id*/);
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_rc_resolve (
+ krb5_context /*context*/,
+ krb5_rcache /*id*/,
+ const char */*name*/);
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_rc_resolve_full (
+ krb5_context /*context*/,
+ krb5_rcache */*id*/,
+ const char */*string_name*/);
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_rc_resolve_type (
+ krb5_context /*context*/,
+ krb5_rcache */*id*/,
+ const char */*type*/);
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_rc_store (
+ krb5_context /*context*/,
+ krb5_rcache /*id*/,
+ krb5_donot_replay */*rep*/);
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_rd_cred (
+ krb5_context /*context*/,
+ krb5_auth_context /*auth_context*/,
+ krb5_data */*in_data*/,
+ krb5_creds ***/*ret_creds*/,
+ krb5_replay_data */*outdata*/);
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_rd_cred2 (
+ krb5_context /*context*/,
+ krb5_auth_context /*auth_context*/,
+ krb5_ccache /*ccache*/,
+ krb5_data */*in_data*/);
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_rd_error (
+ krb5_context /*context*/,
+ krb5_data */*msg*/,
+ KRB_ERROR */*result*/);
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_rd_priv (
+ krb5_context /*context*/,
+ krb5_auth_context /*auth_context*/,
+ const krb5_data */*inbuf*/,
+ krb5_data */*outbuf*/,
+ krb5_replay_data */*outdata*/);
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_rd_rep (
+ krb5_context /*context*/,
+ krb5_auth_context /*auth_context*/,
+ const krb5_data */*inbuf*/,
+ krb5_ap_rep_enc_part **/*repl*/);
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_rd_req (
+ krb5_context /*context*/,
+ krb5_auth_context */*auth_context*/,
+ const krb5_data */*inbuf*/,
+ krb5_const_principal /*server*/,
+ krb5_keytab /*keytab*/,
+ krb5_flags */*ap_req_options*/,
+ krb5_ticket **/*ticket*/);
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_rd_req_return_keyblock (
+ krb5_context /*context*/,
+ krb5_auth_context */*auth_context*/,
+ const krb5_data */*inbuf*/,
+ krb5_const_principal /*server*/,
+ krb5_keytab /*keytab*/,
+ krb5_flags */*ap_req_options*/,
+ krb5_ticket **/*ticket*/,
+ krb5_keyblock **/*keyblock*/);
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_rd_req_with_keyblock (
+ krb5_context /*context*/,
+ krb5_auth_context */*auth_context*/,
+ const krb5_data */*inbuf*/,
+ krb5_const_principal /*server*/,
+ krb5_keyblock */*keyblock*/,
+ krb5_flags */*ap_req_options*/,
+ krb5_ticket **/*ticket*/);
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_rd_safe (
+ krb5_context /*context*/,
+ krb5_auth_context /*auth_context*/,
+ const krb5_data */*inbuf*/,
+ krb5_data */*outbuf*/,
+ krb5_replay_data */*outdata*/);
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_read_message (
+ krb5_context /*context*/,
+ krb5_pointer /*p_fd*/,
+ krb5_data */*data*/);
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_read_priv_message (
+ krb5_context /*context*/,
+ krb5_auth_context /*ac*/,
+ krb5_pointer /*p_fd*/,
+ krb5_data */*data*/);
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_read_safe_message (
+ krb5_context /*context*/,
+ krb5_auth_context /*ac*/,
+ krb5_pointer /*p_fd*/,
+ krb5_data */*data*/);
+
+krb5_boolean KRB5_LIB_FUNCTION
+krb5_realm_compare (
+ krb5_context /*context*/,
+ krb5_const_principal /*princ1*/,
+ krb5_const_principal /*princ2*/);
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_recvauth (
+ krb5_context /*context*/,
+ krb5_auth_context */*auth_context*/,
+ krb5_pointer /*p_fd*/,
+ const char */*appl_version*/,
+ krb5_principal /*server*/,
+ int32_t /*flags*/,
+ krb5_keytab /*keytab*/,
+ krb5_ticket **/*ticket*/);
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_recvauth_match_version (
+ krb5_context /*context*/,
+ krb5_auth_context */*auth_context*/,
+ krb5_pointer /*p_fd*/,
+ krb5_boolean (*/*match_appl_version*/)(const void *, const char*),
+ const void */*match_data*/,
+ krb5_principal /*server*/,
+ int32_t /*flags*/,
+ krb5_keytab /*keytab*/,
+ krb5_ticket **/*ticket*/);
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_ret_address (
+ krb5_storage */*sp*/,
+ krb5_address */*adr*/);
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_ret_addrs (
+ krb5_storage */*sp*/,
+ krb5_addresses */*adr*/);
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_ret_authdata (
+ krb5_storage */*sp*/,
+ krb5_authdata */*auth*/);
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_ret_creds (
+ krb5_storage */*sp*/,
+ krb5_creds */*creds*/);
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_ret_creds_tag (
+ krb5_storage */*sp*/,
+ krb5_creds */*creds*/);
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_ret_data (
+ krb5_storage */*sp*/,
+ krb5_data */*data*/);
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_ret_int16 (
+ krb5_storage */*sp*/,
+ int16_t */*value*/);
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_ret_int32 (
+ krb5_storage */*sp*/,
+ int32_t */*value*/);
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_ret_int8 (
+ krb5_storage */*sp*/,
+ int8_t */*value*/);
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_ret_keyblock (
+ krb5_storage */*sp*/,
+ krb5_keyblock */*p*/);
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_ret_principal (
+ krb5_storage */*sp*/,
+ krb5_principal */*princ*/);
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_ret_string (
+ krb5_storage */*sp*/,
+ char **/*string*/);
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_ret_stringz (
+ krb5_storage */*sp*/,
+ char **/*string*/);
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_ret_times (
+ krb5_storage */*sp*/,
+ krb5_times */*times*/);
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_salttype_to_string (
+ krb5_context /*context*/,
+ krb5_enctype /*etype*/,
+ krb5_salttype /*stype*/,
+ char **/*string*/);
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_sendauth (
+ krb5_context /*context*/,
+ krb5_auth_context */*auth_context*/,
+ krb5_pointer /*p_fd*/,
+ const char */*appl_version*/,
+ krb5_principal /*client*/,
+ krb5_principal /*server*/,
+ krb5_flags /*ap_req_options*/,
+ krb5_data */*in_data*/,
+ krb5_creds */*in_creds*/,
+ krb5_ccache /*ccache*/,
+ krb5_error **/*ret_error*/,
+ krb5_ap_rep_enc_part **/*rep_result*/,
+ krb5_creds **/*out_creds*/);
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_sendto (
+ krb5_context /*context*/,
+ const krb5_data */*send_data*/,
+ krb5_krbhst_handle /*handle*/,
+ krb5_data */*receive*/);
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_sendto_kdc (
+ krb5_context /*context*/,
+ const krb5_data */*send_data*/,
+ const krb5_realm */*realm*/,
+ krb5_data */*receive*/);
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_sendto_kdc_flags (
+ krb5_context /*context*/,
+ const krb5_data */*send_data*/,
+ const krb5_realm */*realm*/,
+ krb5_data */*receive*/,
+ int /*flags*/);
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_set_config_files (
+ krb5_context /*context*/,
+ char **/*filenames*/);
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_set_default_in_tkt_etypes (
+ krb5_context /*context*/,
+ const krb5_enctype */*etypes*/);
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_set_default_realm (
+ krb5_context /*context*/,
+ const char */*realm*/);
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_set_error_string (
+ krb5_context /*context*/,
+ const char */*fmt*/,
+ ...)
+ __attribute__((format (printf, 2, 3)));
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_set_extra_addresses (
+ krb5_context /*context*/,
+ const krb5_addresses */*addresses*/);
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_set_fcache_version (
+ krb5_context /*context*/,
+ int /*version*/);
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_set_ignore_addresses (
+ krb5_context /*context*/,
+ const krb5_addresses */*addresses*/);
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_set_password (
+ krb5_context /*context*/,
+ krb5_creds */*creds*/,
+ char */*newpw*/,
+ krb5_principal /*targprinc*/,
+ int */*result_code*/,
+ krb5_data */*result_code_string*/,
+ krb5_data */*result_string*/);
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_set_password_using_ccache (
+ krb5_context /*context*/,
+ krb5_ccache /*ccache*/,
+ char */*newpw*/,
+ krb5_principal /*targprinc*/,
+ int */*result_code*/,
+ krb5_data */*result_code_string*/,
+ krb5_data */*result_string*/);
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_set_real_time (
+ krb5_context /*context*/,
+ krb5_timestamp /*sec*/,
+ int32_t /*usec*/);
+
+void KRB5_LIB_FUNCTION
+krb5_set_use_admin_kdc (
+ krb5_context /*context*/,
+ krb5_boolean /*flag*/);
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_set_warn_dest (
+ krb5_context /*context*/,
+ krb5_log_facility */*fac*/);
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_sname_to_principal (
+ krb5_context /*context*/,
+ const char */*hostname*/,
+ const char */*sname*/,
+ int32_t /*type*/,
+ krb5_principal */*ret_princ*/);
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_sock_to_principal (
+ krb5_context /*context*/,
+ int /*sock*/,
+ const char */*sname*/,
+ int32_t /*type*/,
+ krb5_principal */*ret_princ*/);
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_sockaddr2address (
+ krb5_context /*context*/,
+ const struct sockaddr */*sa*/,
+ krb5_address */*addr*/);
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_sockaddr2port (
+ krb5_context /*context*/,
+ const struct sockaddr */*sa*/,
+ int16_t */*port*/);
+
+krb5_boolean KRB5_LIB_FUNCTION
+krb5_sockaddr_uninteresting (const struct sockaddr */*sa*/);
+
+void KRB5_LIB_FUNCTION
+krb5_std_usage (
+ int /*code*/,
+ struct getargs */*args*/,
+ int /*num_args*/);
+
+void KRB5_LIB_FUNCTION
+krb5_storage_clear_flags (
+ krb5_storage */*sp*/,
+ krb5_flags /*flags*/);
+
+krb5_storage * KRB5_LIB_FUNCTION
+krb5_storage_emem (void);
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_storage_free (krb5_storage */*sp*/);
+
+krb5_storage * KRB5_LIB_FUNCTION
+krb5_storage_from_data (krb5_data */*data*/);
+
+krb5_storage * KRB5_LIB_FUNCTION
+krb5_storage_from_fd (int /*fd*/);
+
+krb5_storage * KRB5_LIB_FUNCTION
+krb5_storage_from_mem (
+ void */*buf*/,
+ size_t /*len*/);
+
+krb5_flags KRB5_LIB_FUNCTION
+krb5_storage_get_byteorder (
+ krb5_storage */*sp*/,
+ krb5_flags /*byteorder*/);
+
+krb5_boolean KRB5_LIB_FUNCTION
+krb5_storage_is_flags (
+ krb5_storage */*sp*/,
+ krb5_flags /*flags*/);
+
+krb5_ssize_t KRB5_LIB_FUNCTION
+krb5_storage_read (
+ krb5_storage */*sp*/,
+ void */*buf*/,
+ size_t /*len*/);
+
+off_t KRB5_LIB_FUNCTION
+krb5_storage_seek (
+ krb5_storage */*sp*/,
+ off_t /*offset*/,
+ int /*whence*/);
+
+void KRB5_LIB_FUNCTION
+krb5_storage_set_byteorder (
+ krb5_storage */*sp*/,
+ krb5_flags /*byteorder*/);
+
+void KRB5_LIB_FUNCTION
+krb5_storage_set_eof_code (
+ krb5_storage */*sp*/,
+ int /*code*/);
+
+void KRB5_LIB_FUNCTION
+krb5_storage_set_flags (
+ krb5_storage */*sp*/,
+ krb5_flags /*flags*/);
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_storage_to_data (
+ krb5_storage */*sp*/,
+ krb5_data */*data*/);
+
+krb5_ssize_t KRB5_LIB_FUNCTION
+krb5_storage_write (
+ krb5_storage */*sp*/,
+ const void */*buf*/,
+ size_t /*len*/);
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_store_address (
+ krb5_storage */*sp*/,
+ krb5_address /*p*/);
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_store_addrs (
+ krb5_storage */*sp*/,
+ krb5_addresses /*p*/);
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_store_authdata (
+ krb5_storage */*sp*/,
+ krb5_authdata /*auth*/);
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_store_creds (
+ krb5_storage */*sp*/,
+ krb5_creds */*creds*/);
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_store_creds_tag (
+ krb5_storage */*sp*/,
+ krb5_creds */*creds*/);
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_store_data (
+ krb5_storage */*sp*/,
+ krb5_data /*data*/);
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_store_int16 (
+ krb5_storage */*sp*/,
+ int16_t /*value*/);
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_store_int32 (
+ krb5_storage */*sp*/,
+ int32_t /*value*/);
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_store_int8 (
+ krb5_storage */*sp*/,
+ int8_t /*value*/);
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_store_keyblock (
+ krb5_storage */*sp*/,
+ krb5_keyblock /*p*/);
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_store_principal (
+ krb5_storage */*sp*/,
+ krb5_principal /*p*/);
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_store_string (
+ krb5_storage */*sp*/,
+ const char */*s*/);
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_store_stringz (
+ krb5_storage */*sp*/,
+ const char */*s*/);
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_store_times (
+ krb5_storage */*sp*/,
+ krb5_times /*times*/);
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_string_to_deltat (
+ const char */*string*/,
+ krb5_deltat */*deltat*/);
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_string_to_enctype (
+ krb5_context /*context*/,
+ const char */*string*/,
+ krb5_enctype */*etype*/);
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_string_to_key (
+ krb5_context /*context*/,
+ krb5_enctype /*enctype*/,
+ const char */*password*/,
+ krb5_principal /*principal*/,
+ krb5_keyblock */*key*/);
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_string_to_key_data (
+ krb5_context /*context*/,
+ krb5_enctype /*enctype*/,
+ krb5_data /*password*/,
+ krb5_principal /*principal*/,
+ krb5_keyblock */*key*/);
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_string_to_key_data_salt (
+ krb5_context /*context*/,
+ krb5_enctype /*enctype*/,
+ krb5_data /*password*/,
+ krb5_salt /*salt*/,
+ krb5_keyblock */*key*/);
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_string_to_key_data_salt_opaque (
+ krb5_context /*context*/,
+ krb5_enctype /*enctype*/,
+ krb5_data /*password*/,
+ krb5_salt /*salt*/,
+ krb5_data /*opaque*/,
+ krb5_keyblock */*key*/);
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_string_to_key_derived (
+ krb5_context /*context*/,
+ const void */*str*/,
+ size_t /*len*/,
+ krb5_enctype /*etype*/,
+ krb5_keyblock */*key*/);
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_string_to_key_salt (
+ krb5_context /*context*/,
+ krb5_enctype /*enctype*/,
+ const char */*password*/,
+ krb5_salt /*salt*/,
+ krb5_keyblock */*key*/);
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_string_to_key_salt_opaque (
+ krb5_context /*context*/,
+ krb5_enctype /*enctype*/,
+ const char */*password*/,
+ krb5_salt /*salt*/,
+ krb5_data /*opaque*/,
+ krb5_keyblock */*key*/);
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_string_to_keytype (
+ krb5_context /*context*/,
+ const char */*string*/,
+ krb5_keytype */*keytype*/);
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_string_to_salttype (
+ krb5_context /*context*/,
+ krb5_enctype /*etype*/,
+ const char */*string*/,
+ krb5_salttype */*salttype*/);
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_ticket_get_authorization_data_type (
+ krb5_context /*context*/,
+ krb5_ticket */*ticket*/,
+ int /*type*/,
+ krb5_data */*data*/);
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_ticket_get_client (
+ krb5_context /*context*/,
+ const krb5_ticket */*ticket*/,
+ krb5_principal */*client*/);
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_ticket_get_server (
+ krb5_context /*context*/,
+ const krb5_ticket */*ticket*/,
+ krb5_principal */*server*/);
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_timeofday (
+ krb5_context /*context*/,
+ krb5_timestamp */*timeret*/);
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_unparse_name (
+ krb5_context /*context*/,
+ krb5_const_principal /*principal*/,
+ char **/*name*/);
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_unparse_name_fixed (
+ krb5_context /*context*/,
+ krb5_const_principal /*principal*/,
+ char */*name*/,
+ size_t /*len*/);
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_unparse_name_fixed_short (
+ krb5_context /*context*/,
+ krb5_const_principal /*principal*/,
+ char */*name*/,
+ size_t /*len*/);
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_unparse_name_short (
+ krb5_context /*context*/,
+ krb5_const_principal /*principal*/,
+ char **/*name*/);
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_us_timeofday (
+ krb5_context /*context*/,
+ krb5_timestamp */*sec*/,
+ int32_t */*usec*/);
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_vabort (
+ krb5_context /*context*/,
+ krb5_error_code /*code*/,
+ const char */*fmt*/,
+ va_list /*ap*/)
+ __attribute__ ((noreturn, format (printf, 3, 0)));
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_vabortx (
+ krb5_context /*context*/,
+ const char */*fmt*/,
+ va_list /*ap*/)
+ __attribute__ ((noreturn, format (printf, 2, 0)));
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_verify_ap_req (
+ krb5_context /*context*/,
+ krb5_auth_context */*auth_context*/,
+ krb5_ap_req */*ap_req*/,
+ krb5_const_principal /*server*/,
+ krb5_keyblock */*keyblock*/,
+ krb5_flags /*flags*/,
+ krb5_flags */*ap_req_options*/,
+ krb5_ticket **/*ticket*/);
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_verify_ap_req2 (
+ krb5_context /*context*/,
+ krb5_auth_context */*auth_context*/,
+ krb5_ap_req */*ap_req*/,
+ krb5_const_principal /*server*/,
+ krb5_keyblock */*keyblock*/,
+ krb5_flags /*flags*/,
+ krb5_flags */*ap_req_options*/,
+ krb5_ticket **/*ticket*/,
+ krb5_key_usage /*usage*/);
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_verify_authenticator_checksum (
+ krb5_context /*context*/,
+ krb5_auth_context /*ac*/,
+ void */*data*/,
+ size_t /*len*/);
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_verify_checksum (
+ krb5_context /*context*/,
+ krb5_crypto /*crypto*/,
+ krb5_key_usage /*usage*/,
+ void */*data*/,
+ size_t /*len*/,
+ Checksum */*cksum*/);
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_verify_init_creds (
+ krb5_context /*context*/,
+ krb5_creds */*creds*/,
+ krb5_principal /*ap_req_server*/,
+ krb5_keytab /*ap_req_keytab*/,
+ krb5_ccache */*ccache*/,
+ krb5_verify_init_creds_opt */*options*/);
+
+void KRB5_LIB_FUNCTION
+krb5_verify_init_creds_opt_init (krb5_verify_init_creds_opt */*options*/);
+
+void KRB5_LIB_FUNCTION
+krb5_verify_init_creds_opt_set_ap_req_nofail (
+ krb5_verify_init_creds_opt */*options*/,
+ int /*ap_req_nofail*/);
+
+void KRB5_LIB_FUNCTION
+krb5_verify_opt_init (krb5_verify_opt */*opt*/);
+
+void KRB5_LIB_FUNCTION
+krb5_verify_opt_set_ccache (
+ krb5_verify_opt */*opt*/,
+ krb5_ccache /*ccache*/);
+
+void KRB5_LIB_FUNCTION
+krb5_verify_opt_set_flags (
+ krb5_verify_opt */*opt*/,
+ unsigned int /*flags*/);
+
+void KRB5_LIB_FUNCTION
+krb5_verify_opt_set_keytab (
+ krb5_verify_opt */*opt*/,
+ krb5_keytab /*keytab*/);
+
+void KRB5_LIB_FUNCTION
+krb5_verify_opt_set_secure (
+ krb5_verify_opt */*opt*/,
+ krb5_boolean /*secure*/);
+
+void KRB5_LIB_FUNCTION
+krb5_verify_opt_set_service (
+ krb5_verify_opt */*opt*/,
+ const char */*service*/);
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_verify_user (
+ krb5_context /*context*/,
+ krb5_principal /*principal*/,
+ krb5_ccache /*ccache*/,
+ const char */*password*/,
+ krb5_boolean /*secure*/,
+ const char */*service*/);
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_verify_user_lrealm (
+ krb5_context /*context*/,
+ krb5_principal /*principal*/,
+ krb5_ccache /*ccache*/,
+ const char */*password*/,
+ krb5_boolean /*secure*/,
+ const char */*service*/);
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_verify_user_opt (
+ krb5_context /*context*/,
+ krb5_principal /*principal*/,
+ const char */*password*/,
+ krb5_verify_opt */*opt*/);
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_verr (
+ krb5_context /*context*/,
+ int /*eval*/,
+ krb5_error_code /*code*/,
+ const char */*fmt*/,
+ va_list /*ap*/)
+ __attribute__ ((noreturn, format (printf, 4, 0)));
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_verrx (
+ krb5_context /*context*/,
+ int /*eval*/,
+ const char */*fmt*/,
+ va_list /*ap*/)
+ __attribute__ ((noreturn, format (printf, 3, 0)));
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_vlog (
+ krb5_context /*context*/,
+ krb5_log_facility */*fac*/,
+ int /*level*/,
+ const char */*fmt*/,
+ va_list /*ap*/)
+ __attribute__((format (printf, 4, 0)));
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_vlog_msg (
+ krb5_context /*context*/,
+ krb5_log_facility */*fac*/,
+ char **/*reply*/,
+ int /*level*/,
+ const char */*fmt*/,
+ va_list /*ap*/)
+ __attribute__((format (printf, 5, 0)));
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_vset_error_string (
+ krb5_context /*context*/,
+ const char */*fmt*/,
+ va_list /*args*/)
+ __attribute__ ((format (printf, 2, 0)));
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_vwarn (
+ krb5_context /*context*/,
+ krb5_error_code /*code*/,
+ const char */*fmt*/,
+ va_list /*ap*/)
+ __attribute__ ((format (printf, 3, 0)));
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_vwarnx (
+ krb5_context /*context*/,
+ const char */*fmt*/,
+ va_list /*ap*/)
+ __attribute__ ((format (printf, 2, 0)));
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_warn (
+ krb5_context /*context*/,
+ krb5_error_code /*code*/,
+ const char */*fmt*/,
+ ...)
+ __attribute__ ((format (printf, 3, 4)));
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_warnx (
+ krb5_context /*context*/,
+ const char */*fmt*/,
+ ...)
+ __attribute__ ((format (printf, 2, 3)));
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_write_message (
+ krb5_context /*context*/,
+ krb5_pointer /*p_fd*/,
+ krb5_data */*data*/);
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_write_priv_message (
+ krb5_context /*context*/,
+ krb5_auth_context /*ac*/,
+ krb5_pointer /*p_fd*/,
+ krb5_data */*data*/);
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_write_safe_message (
+ krb5_context /*context*/,
+ krb5_auth_context /*ac*/,
+ krb5_pointer /*p_fd*/,
+ krb5_data */*data*/);
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_xfree (void */*ptr*/);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __krb5_protos_h__ */
diff --git a/source4/heimdal/lib/krb5/krb5-v4compat.h b/source4/heimdal/lib/krb5/krb5-v4compat.h
new file mode 100644
index 0000000000..1d092dcbc9
--- /dev/null
+++ b/source4/heimdal/lib/krb5/krb5-v4compat.h
@@ -0,0 +1,176 @@
+/*
+ * Copyright (c) 1997 - 2003 Kungliga Tekniska Högskolan
+ * (Royal Institute of Technology, Stockholm, Sweden).
+ * 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.
+ */
+
+/* $Id: krb5-v4compat.h,v 1.6 2005/04/23 19:38:16 lha Exp $ */
+
+#ifndef __KRB5_V4COMPAT_H__
+#define __KRB5_V4COMPAT_H__
+
+/*
+ * This file must only be included with v4 compat glue stuff in
+ * heimdal sources.
+ *
+ * It MUST NOT be installed.
+ */
+
+#define KRB_PROT_VERSION 4
+
+#define AUTH_MSG_KDC_REQUEST (1<<1)
+#define AUTH_MSG_KDC_REPLY (2<<1)
+#define AUTH_MSG_APPL_REQUEST (3<<1)
+#define AUTH_MSG_APPL_REQUEST_MUTUAL (4<<1)
+#define AUTH_MSG_ERR_REPLY (5<<1)
+#define AUTH_MSG_PRIVATE (6<<1)
+#define AUTH_MSG_SAFE (7<<1)
+#define AUTH_MSG_APPL_ERR (8<<1)
+#define AUTH_MSG_KDC_FORWARD (9<<1)
+#define AUTH_MSG_KDC_RENEW (10<<1)
+#define AUTH_MSG_DIE (63<<1)
+
+/* values for kerb error codes */
+
+#define KERB_ERR_OK 0
+#define KERB_ERR_NAME_EXP 1
+#define KERB_ERR_SERVICE_EXP 2
+#define KERB_ERR_AUTH_EXP 3
+#define KERB_ERR_PKT_VER 4
+#define KERB_ERR_NAME_MAST_KEY_VER 5
+#define KERB_ERR_SERV_MAST_KEY_VER 6
+#define KERB_ERR_BYTE_ORDER 7
+#define KERB_ERR_PRINCIPAL_UNKNOWN 8
+#define KERB_ERR_PRINCIPAL_NOT_UNIQUE 9
+#define KERB_ERR_NULL_KEY 10
+#define KERB_ERR_TIMEOUT 11
+
+
+/* Error codes returned from the KDC */
+#define KDC_OK 0 /* Request OK */
+#define KDC_NAME_EXP 1 /* Principal expired */
+#define KDC_SERVICE_EXP 2 /* Service expired */
+#define KDC_AUTH_EXP 3 /* Auth expired */
+#define KDC_PKT_VER 4 /* Protocol version unknown */
+#define KDC_P_MKEY_VER 5 /* Wrong master key version */
+#define KDC_S_MKEY_VER 6 /* Wrong master key version */
+#define KDC_BYTE_ORDER 7 /* Byte order unknown */
+#define KDC_PR_UNKNOWN 8 /* Principal unknown */
+#define KDC_PR_N_UNIQUE 9 /* Principal not unique */
+#define KDC_NULL_KEY 10 /* Principal has null key */
+#define KDC_GEN_ERR 20 /* Generic error from KDC */
+
+/* General definitions */
+#define KSUCCESS 0
+#define KFAILURE 255
+
+/* Values returned by rd_ap_req */
+#define RD_AP_OK 0 /* Request authentic */
+#define RD_AP_UNDEC 31 /* Can't decode authenticator */
+#define RD_AP_EXP 32 /* Ticket expired */
+#define RD_AP_NYV 33 /* Ticket not yet valid */
+#define RD_AP_REPEAT 34 /* Repeated request */
+#define RD_AP_NOT_US 35 /* The ticket isn't for us */
+#define RD_AP_INCON 36 /* Request is inconsistent */
+#define RD_AP_TIME 37 /* delta_t too big */
+#define RD_AP_BADD 38 /* Incorrect net address */
+#define RD_AP_VERSION 39 /* protocol version mismatch */
+#define RD_AP_MSG_TYPE 40 /* invalid msg type */
+#define RD_AP_MODIFIED 41 /* message stream modified */
+#define RD_AP_ORDER 42 /* message out of order */
+#define RD_AP_UNAUTHOR 43 /* unauthorized request */
+
+/* */
+
+#define MAX_KTXT_LEN 1250
+
+#define ANAME_SZ 40
+#define REALM_SZ 40
+#define SNAME_SZ 40
+#define INST_SZ 40
+
+struct ktext {
+ unsigned int length; /* Length of the text */
+ unsigned char dat[MAX_KTXT_LEN]; /* The data itself */
+ u_int32_t mbz; /* zero to catch runaway strings */
+};
+
+struct credentials {
+ char service[ANAME_SZ]; /* Service name */
+ char instance[INST_SZ]; /* Instance */
+ char realm[REALM_SZ]; /* Auth domain */
+ char session[8]; /* Session key */
+ int lifetime; /* Lifetime */
+ int kvno; /* Key version number */
+ struct ktext ticket_st; /* The ticket itself */
+ int32_t issue_date; /* The issue time */
+ char pname[ANAME_SZ]; /* Principal's name */
+ char pinst[INST_SZ]; /* Principal's instance */
+};
+
+#define TKTLIFENUMFIXED 64
+#define TKTLIFEMINFIXED 0x80
+#define TKTLIFEMAXFIXED 0xBF
+#define TKTLIFENOEXPIRE 0xFF
+#define MAXTKTLIFETIME (30*24*3600) /* 30 days */
+#ifndef NEVERDATE
+#define NEVERDATE ((time_t)0x7fffffffL)
+#endif
+
+#define KERB_ERR_NULL_KEY 10
+
+#define CLOCK_SKEW 5*60
+
+#ifndef TKT_ROOT
+#define TKT_ROOT "/tmp/tkt"
+#endif
+
+struct _krb5_krb_auth_data {
+ int8_t k_flags; /* Flags from ticket */
+ char *pname; /* Principal's name */
+ char *pinst; /* His Instance */
+ char *prealm; /* His Realm */
+ u_int32_t checksum; /* Data checksum (opt) */
+ krb5_keyblock session; /* Session Key */
+ unsigned char life; /* Life of ticket */
+ u_int32_t time_sec; /* Time ticket issued */
+ u_int32_t address; /* Address in ticket */
+};
+
+time_t _krb5_krb_life_to_time (int, int);
+int _krb5_krb_time_to_life (time_t, time_t);
+krb5_error_code _krb5_krb_tf_setup (krb5_context, struct credentials *,
+ const char *, int);
+krb5_error_code _krb5_krb_dest_tkt(krb5_context, const char *);
+
+#define krb_time_to_life _krb5_krb_time_to_life
+#define krb_life_to_time _krb5_krb_life_to_time
+
+#endif /* __KRB5_V4COMPAT_H__ */
diff --git a/source4/heimdal/lib/krb5/krb5.h b/source4/heimdal/lib/krb5/krb5.h
new file mode 100644
index 0000000000..890a500caa
--- /dev/null
+++ b/source4/heimdal/lib/krb5/krb5.h
@@ -0,0 +1,754 @@
+/*
+ * Copyright (c) 1997 - 2004 Kungliga Tekniska Högskolan
+ * (Royal Institute of Technology, Stockholm, Sweden).
+ * 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.
+ */
+
+/* $Id: krb5.h,v 1.236 2005/06/11 00:05:24 lha Exp $ */
+
+#ifndef __KRB5_H__
+#define __KRB5_H__
+
+#include <time.h>
+#include <krb5-types.h>
+
+#include <asn1_err.h>
+#include <krb5_err.h>
+#include <heim_err.h>
+#include <k524_err.h>
+
+#include <krb5_asn1.h>
+
+/* name confusion with MIT */
+#ifndef KRB5KDC_ERR_KEY_EXP
+#define KRB5KDC_ERR_KEY_EXP KRB5KDC_ERR_KEY_EXPIRED
+#endif
+
+/* simple constants */
+
+#ifndef TRUE
+#define TRUE 1
+#define FALSE 0
+#endif
+
+typedef int krb5_boolean;
+
+typedef int32_t krb5_error_code;
+
+typedef int krb5_kvno;
+
+typedef u_int32_t krb5_flags;
+
+typedef void *krb5_pointer;
+typedef const void *krb5_const_pointer;
+
+struct krb5_crypto_data;
+typedef struct krb5_crypto_data *krb5_crypto;
+
+typedef CKSUMTYPE krb5_cksumtype;
+
+typedef Checksum krb5_checksum;
+
+typedef ENCTYPE krb5_enctype;
+
+typedef heim_octet_string krb5_data;
+
+/* PKINIT related forward declarations */
+struct ContentInfo;
+struct krb5_pk_identity;
+struct krb5_pk_cert;
+
+/* krb5_enc_data is a mit compat structure */
+typedef struct krb5_enc_data {
+ krb5_enctype enctype;
+ krb5_kvno kvno;
+ krb5_data ciphertext;
+} krb5_enc_data;
+
+/* alternative names */
+enum {
+ ENCTYPE_NULL = ETYPE_NULL,
+ ENCTYPE_DES_CBC_CRC = ETYPE_DES_CBC_CRC,
+ ENCTYPE_DES_CBC_MD4 = ETYPE_DES_CBC_MD4,
+ ENCTYPE_DES_CBC_MD5 = ETYPE_DES_CBC_MD5,
+ ENCTYPE_DES3_CBC_MD5 = ETYPE_DES3_CBC_MD5,
+ ENCTYPE_OLD_DES3_CBC_SHA1 = ETYPE_OLD_DES3_CBC_SHA1,
+ ENCTYPE_SIGN_DSA_GENERATE = ETYPE_SIGN_DSA_GENERATE,
+ ENCTYPE_ENCRYPT_RSA_PRIV = ETYPE_ENCRYPT_RSA_PRIV,
+ ENCTYPE_ENCRYPT_RSA_PUB = ETYPE_ENCRYPT_RSA_PUB,
+ ENCTYPE_DES3_CBC_SHA1 = ETYPE_DES3_CBC_SHA1,
+ ENCTYPE_AES128_CTS_HMAC_SHA1_96 = ETYPE_AES128_CTS_HMAC_SHA1_96,
+ ENCTYPE_AES256_CTS_HMAC_SHA1_96 = ETYPE_AES256_CTS_HMAC_SHA1_96,
+ ENCTYPE_ARCFOUR_HMAC = ETYPE_ARCFOUR_HMAC_MD5,
+ ENCTYPE_ARCFOUR_HMAC_MD5 = ETYPE_ARCFOUR_HMAC_MD5,
+ ENCTYPE_ARCFOUR_HMAC_MD5_56 = ETYPE_ARCFOUR_HMAC_MD5_56,
+ ENCTYPE_ENCTYPE_PK_CROSS = ETYPE_ENCTYPE_PK_CROSS,
+ ENCTYPE_DES_CBC_NONE = ETYPE_DES_CBC_NONE,
+ ENCTYPE_DES3_CBC_NONE = ETYPE_DES3_CBC_NONE,
+ ENCTYPE_DES_CFB64_NONE = ETYPE_DES_CFB64_NONE,
+ ENCTYPE_DES_PCBC_NONE = ETYPE_DES_PCBC_NONE
+};
+
+typedef PADATA_TYPE krb5_preauthtype;
+
+typedef enum krb5_key_usage {
+ KRB5_KU_PA_ENC_TIMESTAMP = 1,
+ /* AS-REQ PA-ENC-TIMESTAMP padata timestamp, encrypted with the
+ client key (section 5.4.1) */
+ KRB5_KU_TICKET = 2,
+ /* AS-REP Ticket and TGS-REP Ticket (includes tgs session key or
+ application session key), encrypted with the service key
+ (section 5.4.2) */
+ KRB5_KU_AS_REP_ENC_PART = 3,
+ /* AS-REP encrypted part (includes tgs session key or application
+ session key), encrypted with the client key (section 5.4.2) */
+ KRB5_KU_TGS_REQ_AUTH_DAT_SESSION = 4,
+ /* TGS-REQ KDC-REQ-BODY AuthorizationData, encrypted with the tgs
+ session key (section 5.4.1) */
+ KRB5_KU_TGS_REQ_AUTH_DAT_SUBKEY = 5,
+ /* TGS-REQ KDC-REQ-BODY AuthorizationData, encrypted with the tgs
+ authenticator subkey (section 5.4.1) */
+ KRB5_KU_TGS_REQ_AUTH_CKSUM = 6,
+ /* TGS-REQ PA-TGS-REQ padata AP-REQ Authenticator cksum, keyed
+ with the tgs session key (sections 5.3.2, 5.4.1) */
+ KRB5_KU_TGS_REQ_AUTH = 7,
+ /* TGS-REQ PA-TGS-REQ padata AP-REQ Authenticator (includes tgs
+ authenticator subkey), encrypted with the tgs session key
+ (section 5.3.2) */
+ KRB5_KU_TGS_REP_ENC_PART_SESSION = 8,
+ /* TGS-REP encrypted part (includes application session key),
+ encrypted with the tgs session key (section 5.4.2) */
+ KRB5_KU_TGS_REP_ENC_PART_SUB_KEY = 9,
+ /* TGS-REP encrypted part (includes application session key),
+ encrypted with the tgs authenticator subkey (section 5.4.2) */
+ KRB5_KU_AP_REQ_AUTH_CKSUM = 10,
+ /* AP-REQ Authenticator cksum, keyed with the application session
+ key (section 5.3.2) */
+ KRB5_KU_AP_REQ_AUTH = 11,
+ /* AP-REQ Authenticator (includes application authenticator
+ subkey), encrypted with the application session key (section
+ 5.3.2) */
+ KRB5_KU_AP_REQ_ENC_PART = 12,
+ /* AP-REP encrypted part (includes application session subkey),
+ encrypted with the application session key (section 5.5.2) */
+ KRB5_KU_KRB_PRIV = 13,
+ /* KRB-PRIV encrypted part, encrypted with a key chosen by the
+ application (section 5.7.1) */
+ KRB5_KU_KRB_CRED = 14,
+ /* KRB-CRED encrypted part, encrypted with a key chosen by the
+ application (section 5.8.1) */
+ KRB5_KU_KRB_SAFE_CKSUM = 15,
+ /* KRB-SAFE cksum, keyed with a key chosen by the application
+ (section 5.6.1) */
+ KRB5_KU_OTHER_ENCRYPTED = 16,
+ /* Data which is defined in some specification outside of
+ Kerberos to be encrypted using an RFC1510 encryption type. */
+ KRB5_KU_OTHER_CKSUM = 17,
+ /* Data which is defined in some specification outside of
+ Kerberos to be checksummed using an RFC1510 checksum type. */
+ KRB5_KU_KRB_ERROR = 18,
+ /* Krb-error checksum */
+ KRB5_KU_AD_KDC_ISSUED = 19,
+ /* AD-KDCIssued checksum */
+ KRB5_KU_MANDATORY_TICKET_EXTENSION = 20,
+ /* Checksum for Mandatory Ticket Extensions */
+ KRB5_KU_AUTH_DATA_TICKET_EXTENSION = 21,
+ /* Checksum in Authorization Data in Ticket Extensions */
+ KRB5_KU_USAGE_SEAL = 22,
+ /* seal in GSSAPI krb5 mechanism */
+ KRB5_KU_USAGE_SIGN = 23,
+ /* sign in GSSAPI krb5 mechanism */
+ KRB5_KU_USAGE_SEQ = 24,
+ /* SEQ in GSSAPI krb5 mechanism */
+ KRB5_KU_USAGE_ACCEPTOR_SEAL = 22,
+ /* acceptor sign in GSSAPI CFX krb5 mechanism */
+ KRB5_KU_USAGE_ACCEPTOR_SIGN = 23,
+ /* acceptor seal in GSSAPI CFX krb5 mechanism */
+ KRB5_KU_USAGE_INITIATOR_SEAL = 24,
+ /* initiator sign in GSSAPI CFX krb5 mechanism */
+ KRB5_KU_USAGE_INITIATOR_SIGN = 25,
+ /* initiator seal in GSSAPI CFX krb5 mechanism */
+ KRB5_KU_PA_SERVER_REFERRAL_DATA = 22,
+ /* encrypted server referral data */
+ KRB5_KU_SAM_CHECKSUM = 25,
+ /* Checksum for the SAM-CHECKSUM field */
+ KRB5_KU_SAM_ENC_TRACK_ID = 26,
+ /* Encryption of the SAM-TRACK-ID field */
+ KRB5_KU_PA_SERVER_REFERRAL = 26,
+ /* Keyusage for the server referral in a TGS req */
+ KRB5_KU_SAM_ENC_NONCE_SAD = 27
+ /* Encryption of the SAM-NONCE-OR-SAD field */
+} krb5_key_usage;
+
+typedef krb5_key_usage krb5_keyusage;
+
+typedef enum krb5_salttype {
+ KRB5_PW_SALT = KRB5_PADATA_PW_SALT,
+ KRB5_AFS3_SALT = KRB5_PADATA_AFS3_SALT
+}krb5_salttype;
+
+typedef struct krb5_salt {
+ krb5_salttype salttype;
+ krb5_data saltvalue;
+} krb5_salt;
+
+typedef ETYPE_INFO krb5_preauthinfo;
+
+typedef struct {
+ krb5_preauthtype type;
+ krb5_preauthinfo info; /* list of preauthinfo for this type */
+} krb5_preauthdata_entry;
+
+typedef struct krb5_preauthdata {
+ unsigned len;
+ krb5_preauthdata_entry *val;
+}krb5_preauthdata;
+
+typedef enum krb5_address_type {
+ KRB5_ADDRESS_INET = 2,
+ KRB5_ADDRESS_INET6 = 24,
+ KRB5_ADDRESS_ADDRPORT = 256,
+ KRB5_ADDRESS_IPPORT = 257
+} krb5_address_type;
+
+enum {
+ AP_OPTS_USE_SESSION_KEY = 1,
+ AP_OPTS_MUTUAL_REQUIRED = 2,
+ AP_OPTS_USE_SUBKEY = 4 /* library internal */
+};
+
+typedef HostAddress krb5_address;
+
+typedef HostAddresses krb5_addresses;
+
+typedef enum krb5_keytype {
+ KEYTYPE_NULL = 0,
+ KEYTYPE_DES = 1,
+ KEYTYPE_DES3 = 7,
+ KEYTYPE_AES128 = 17,
+ KEYTYPE_AES256 = 18,
+ KEYTYPE_ARCFOUR = 23,
+ KEYTYPE_ARCFOUR_56 = 24,
+ KEYTYPE_RC2 = -0x1005,
+ KEYTYPE_AES192 = -0x1006
+} krb5_keytype;
+
+typedef EncryptionKey krb5_keyblock;
+
+typedef AP_REQ krb5_ap_req;
+
+struct krb5_cc_ops;
+
+#define KRB5_DEFAULT_CCFILE_ROOT "/tmp/krb5cc_"
+
+#define KRB5_DEFAULT_CCROOT "FILE:" KRB5_DEFAULT_CCFILE_ROOT
+
+#define KRB5_ACCEPT_NULL_ADDRESSES(C) \
+ krb5_config_get_bool_default((C), NULL, TRUE, \
+ "libdefaults", "accept_null_addresses", \
+ NULL)
+
+typedef void *krb5_cc_cursor;
+
+typedef struct krb5_ccache_data {
+ const struct krb5_cc_ops *ops;
+ krb5_data data;
+}krb5_ccache_data;
+
+typedef struct krb5_ccache_data *krb5_ccache;
+
+typedef struct krb5_context_data *krb5_context;
+
+typedef Realm krb5_realm;
+typedef const char *krb5_const_realm; /* stupid language */
+
+#define krb5_realm_length(r) strlen(r)
+#define krb5_realm_data(r) (r)
+
+typedef Principal krb5_principal_data;
+typedef struct Principal *krb5_principal;
+typedef const struct Principal *krb5_const_principal;
+
+typedef time_t krb5_deltat;
+typedef time_t krb5_timestamp;
+
+typedef struct krb5_times {
+ krb5_timestamp authtime;
+ krb5_timestamp starttime;
+ krb5_timestamp endtime;
+ krb5_timestamp renew_till;
+} krb5_times;
+
+typedef union {
+ TicketFlags b;
+ krb5_flags i;
+} krb5_ticket_flags;
+
+/* options for krb5_get_in_tkt() */
+#define KDC_OPT_FORWARDABLE (1 << 1)
+#define KDC_OPT_FORWARDED (1 << 2)
+#define KDC_OPT_PROXIABLE (1 << 3)
+#define KDC_OPT_PROXY (1 << 4)
+#define KDC_OPT_ALLOW_POSTDATE (1 << 5)
+#define KDC_OPT_POSTDATED (1 << 6)
+#define KDC_OPT_RENEWABLE (1 << 8)
+#define KDC_OPT_REQUEST_ANONYMOUS (1 << 14)
+#define KDC_OPT_DISABLE_TRANSITED_CHECK (1 << 26)
+#define KDC_OPT_RENEWABLE_OK (1 << 27)
+#define KDC_OPT_ENC_TKT_IN_SKEY (1 << 28)
+#define KDC_OPT_RENEW (1 << 30)
+#define KDC_OPT_VALIDATE (1 << 31)
+
+typedef union {
+ KDCOptions b;
+ krb5_flags i;
+} krb5_kdc_flags;
+
+/* flags for krb5_verify_ap_req */
+
+#define KRB5_VERIFY_AP_REQ_IGNORE_INVALID (1 << 0)
+
+#define KRB5_GC_CACHED (1U << 0)
+#define KRB5_GC_USER_USER (1U << 1)
+#define KRB5_GC_EXPIRED_OK (1U << 2)
+
+/* constants for compare_creds (and cc_retrieve_cred) */
+#define KRB5_TC_DONT_MATCH_REALM (1U << 31)
+#define KRB5_TC_MATCH_KEYTYPE (1U << 30)
+#define KRB5_TC_MATCH_KTYPE KRB5_TC_MATCH_KEYTYPE /* MIT name */
+#define KRB5_TC_MATCH_SRV_NAMEONLY (1 << 29)
+#define KRB5_TC_MATCH_FLAGS_EXACT (1 << 28)
+#define KRB5_TC_MATCH_FLAGS (1 << 27)
+#define KRB5_TC_MATCH_TIMES_EXACT (1 << 26)
+#define KRB5_TC_MATCH_TIMES (1 << 25)
+#define KRB5_TC_MATCH_AUTHDATA (1 << 24)
+#define KRB5_TC_MATCH_2ND_TKT (1 << 23)
+#define KRB5_TC_MATCH_IS_SKEY (1 << 22)
+
+typedef AuthorizationData krb5_authdata;
+
+typedef KRB_ERROR krb5_error;
+
+typedef struct krb5_creds {
+ krb5_principal client;
+ krb5_principal server;
+ krb5_keyblock session;
+ krb5_times times;
+ krb5_data ticket;
+ krb5_data second_ticket;
+ krb5_authdata authdata;
+ krb5_addresses addresses;
+ krb5_ticket_flags flags;
+} krb5_creds;
+
+typedef struct krb5_cc_ops {
+ const char *prefix;
+ const char* (*get_name)(krb5_context, krb5_ccache);
+ krb5_error_code (*resolve)(krb5_context, krb5_ccache *, const char *);
+ krb5_error_code (*gen_new)(krb5_context, krb5_ccache *);
+ krb5_error_code (*init)(krb5_context, krb5_ccache, krb5_principal);
+ krb5_error_code (*destroy)(krb5_context, krb5_ccache);
+ krb5_error_code (*close)(krb5_context, krb5_ccache);
+ krb5_error_code (*store)(krb5_context, krb5_ccache, krb5_creds*);
+ krb5_error_code (*retrieve)(krb5_context, krb5_ccache,
+ krb5_flags, const krb5_creds*, krb5_creds *);
+ krb5_error_code (*get_princ)(krb5_context, krb5_ccache, krb5_principal*);
+ krb5_error_code (*get_first)(krb5_context, krb5_ccache, krb5_cc_cursor *);
+ krb5_error_code (*get_next)(krb5_context, krb5_ccache,
+ krb5_cc_cursor*, krb5_creds*);
+ krb5_error_code (*end_get)(krb5_context, krb5_ccache, krb5_cc_cursor*);
+ krb5_error_code (*remove_cred)(krb5_context, krb5_ccache,
+ krb5_flags, krb5_creds*);
+ krb5_error_code (*set_flags)(krb5_context, krb5_ccache, krb5_flags);
+ int (*get_version)(krb5_context, krb5_ccache);
+} krb5_cc_ops;
+
+struct krb5_log_facility;
+
+struct krb5_config_binding {
+ enum { krb5_config_string, krb5_config_list } type;
+ char *name;
+ struct krb5_config_binding *next;
+ union {
+ char *string;
+ struct krb5_config_binding *list;
+ void *generic;
+ } u;
+};
+
+typedef struct krb5_config_binding krb5_config_binding;
+
+typedef krb5_config_binding krb5_config_section;
+
+typedef struct krb5_context_data {
+ krb5_enctype *etypes;
+ krb5_enctype *etypes_des;
+ char **default_realms;
+ time_t max_skew;
+ time_t kdc_timeout;
+ unsigned max_retries;
+ int32_t kdc_sec_offset;
+ int32_t kdc_usec_offset;
+ krb5_config_section *cf;
+ struct et_list *et_list;
+ struct krb5_log_facility *warn_dest;
+ krb5_cc_ops *cc_ops;
+ int num_cc_ops;
+ const char *http_proxy;
+ const char *time_fmt;
+ krb5_boolean log_utc;
+ const char *default_keytab;
+ const char *default_keytab_modify;
+ krb5_boolean use_admin_kdc;
+ krb5_addresses *extra_addresses;
+ krb5_boolean scan_interfaces; /* `ifconfig -a' */
+ krb5_boolean srv_lookup; /* do SRV lookups */
+ krb5_boolean srv_try_txt; /* try TXT records also */
+ int32_t fcache_vno; /* create cache files w/ this
+ version */
+ int num_kt_types; /* # of registered keytab types */
+ struct krb5_keytab_data *kt_types; /* registered keytab types */
+ const char *date_fmt;
+ char *error_string;
+ char error_buf[256];
+ krb5_addresses *ignore_addresses;
+ char *default_cc_name;
+ int pkinit_flags;
+ void *mutex; /* protects error_string/error_buf */
+ int large_msg_size;
+} krb5_context_data;
+
+enum {
+ KRB5_PKINIT_WIN2K = 1, /* wire compatible with Windows 2k */
+ KRB5_PKINIT_PACKET_CABLE = 2 /* use packet cable standard */
+};
+
+typedef struct krb5_ticket {
+ EncTicketPart ticket;
+ krb5_principal client;
+ krb5_principal server;
+} krb5_ticket;
+
+typedef Authenticator krb5_authenticator_data;
+
+typedef krb5_authenticator_data *krb5_authenticator;
+
+struct krb5_rcache_data;
+typedef struct krb5_rcache_data *krb5_rcache;
+typedef Authenticator krb5_donot_replay;
+
+#define KRB5_STORAGE_HOST_BYTEORDER 0x01 /* old */
+#define KRB5_STORAGE_PRINCIPAL_WRONG_NUM_COMPONENTS 0x02
+#define KRB5_STORAGE_PRINCIPAL_NO_NAME_TYPE 0x04
+#define KRB5_STORAGE_KEYBLOCK_KEYTYPE_TWICE 0x08
+#define KRB5_STORAGE_BYTEORDER_MASK 0x60
+#define KRB5_STORAGE_BYTEORDER_BE 0x00 /* default */
+#define KRB5_STORAGE_BYTEORDER_LE 0x20
+#define KRB5_STORAGE_BYTEORDER_HOST 0x40
+#define KRB5_STORAGE_CREDS_FLAGS_WRONG_BITORDER 0x80
+
+struct krb5_storage_data;
+typedef struct krb5_storage_data krb5_storage;
+
+typedef struct krb5_keytab_entry {
+ krb5_principal principal;
+ krb5_kvno vno;
+ krb5_keyblock keyblock;
+ u_int32_t timestamp;
+} krb5_keytab_entry;
+
+typedef struct krb5_kt_cursor {
+ int fd;
+ krb5_storage *sp;
+ void *data;
+} krb5_kt_cursor;
+
+struct krb5_keytab_data;
+
+typedef struct krb5_keytab_data *krb5_keytab;
+
+#define KRB5_KT_PREFIX_MAX_LEN 30
+
+struct krb5_keytab_data {
+ const char *prefix;
+ krb5_error_code (*resolve)(krb5_context, const char*, krb5_keytab);
+ krb5_error_code (*get_name)(krb5_context, krb5_keytab, char*, size_t);
+ krb5_error_code (*close)(krb5_context, krb5_keytab);
+ krb5_error_code (*get)(krb5_context, krb5_keytab, krb5_const_principal,
+ krb5_kvno, krb5_enctype, krb5_keytab_entry*);
+ krb5_error_code (*start_seq_get)(krb5_context, krb5_keytab, krb5_kt_cursor*);
+ krb5_error_code (*next_entry)(krb5_context, krb5_keytab,
+ krb5_keytab_entry*, krb5_kt_cursor*);
+ krb5_error_code (*end_seq_get)(krb5_context, krb5_keytab, krb5_kt_cursor*);
+ krb5_error_code (*add)(krb5_context, krb5_keytab, krb5_keytab_entry*);
+ krb5_error_code (*remove)(krb5_context, krb5_keytab, krb5_keytab_entry*);
+ void *data;
+ int32_t version;
+};
+
+typedef struct krb5_keytab_data krb5_kt_ops;
+
+struct krb5_keytab_key_proc_args {
+ krb5_keytab keytab;
+ krb5_principal principal;
+};
+
+typedef struct krb5_keytab_key_proc_args krb5_keytab_key_proc_args;
+
+typedef struct krb5_replay_data {
+ krb5_timestamp timestamp;
+ int32_t usec;
+ u_int32_t seq;
+} krb5_replay_data;
+
+/* flags for krb5_auth_con_setflags */
+enum {
+ KRB5_AUTH_CONTEXT_DO_TIME = 1,
+ KRB5_AUTH_CONTEXT_RET_TIME = 2,
+ KRB5_AUTH_CONTEXT_DO_SEQUENCE = 4,
+ KRB5_AUTH_CONTEXT_RET_SEQUENCE = 8,
+ KRB5_AUTH_CONTEXT_PERMIT_ALL = 16,
+ KRB5_AUTH_CONTEXT_USE_SUBKEY = 32,
+ KRB5_AUTH_CONTEXT_CLEAR_FORWARDED_CRED = 64
+};
+
+/* flags for krb5_auth_con_genaddrs */
+enum {
+ KRB5_AUTH_CONTEXT_GENERATE_LOCAL_ADDR = 1,
+ KRB5_AUTH_CONTEXT_GENERATE_LOCAL_FULL_ADDR = 3,
+ KRB5_AUTH_CONTEXT_GENERATE_REMOTE_ADDR = 4,
+ KRB5_AUTH_CONTEXT_GENERATE_REMOTE_FULL_ADDR = 12
+};
+
+typedef struct krb5_auth_context_data {
+ unsigned int flags;
+
+ krb5_address *local_address;
+ krb5_address *remote_address;
+ int16_t local_port;
+ int16_t remote_port;
+ krb5_keyblock *keyblock;
+ krb5_keyblock *local_subkey;
+ krb5_keyblock *remote_subkey;
+
+ u_int32_t local_seqnumber;
+ u_int32_t remote_seqnumber;
+
+ krb5_authenticator authenticator;
+
+ krb5_pointer i_vector;
+
+ krb5_rcache rcache;
+
+ krb5_keytype keytype; /* ¿requested key type ? */
+ krb5_cksumtype cksumtype; /* ¡requested checksum type! */
+
+}krb5_auth_context_data, *krb5_auth_context;
+
+typedef struct {
+ KDC_REP kdc_rep;
+ EncKDCRepPart enc_part;
+ KRB_ERROR error;
+} krb5_kdc_rep;
+
+extern const char *heimdal_version, *heimdal_long_version;
+
+typedef void (*krb5_log_log_func_t)(const char*, const char*, void*);
+typedef void (*krb5_log_close_func_t)(void*);
+
+typedef struct krb5_log_facility {
+ char *program;
+ int len;
+ struct facility *val;
+} krb5_log_facility;
+
+typedef EncAPRepPart krb5_ap_rep_enc_part;
+
+#define KRB5_RECVAUTH_IGNORE_VERSION 1
+
+#define KRB5_SENDAUTH_VERSION "KRB5_SENDAUTH_V1.0"
+
+#define KRB5_TGS_NAME_SIZE (6)
+#define KRB5_TGS_NAME ("krbtgt")
+
+/* variables */
+
+extern const char *krb5_config_file;
+extern const char *krb5_defkeyname;
+
+typedef enum {
+ KRB5_PROMPT_TYPE_PASSWORD = 0x1,
+ KRB5_PROMPT_TYPE_NEW_PASSWORD = 0x2,
+ KRB5_PROMPT_TYPE_NEW_PASSWORD_AGAIN = 0x3,
+ KRB5_PROMPT_TYPE_PREAUTH = 0x4
+} krb5_prompt_type;
+
+typedef struct _krb5_prompt {
+ const char *prompt;
+ int hidden;
+ krb5_data *reply;
+ krb5_prompt_type type;
+} krb5_prompt;
+
+typedef int (*krb5_prompter_fct)(krb5_context context,
+ void *data,
+ const char *name,
+ const char *banner,
+ int num_prompts,
+ krb5_prompt prompts[]);
+typedef krb5_error_code (*krb5_key_proc)(krb5_context context,
+ krb5_enctype type,
+ krb5_salt salt,
+ krb5_const_pointer keyseed,
+ krb5_keyblock **key);
+typedef krb5_error_code (*krb5_decrypt_proc)(krb5_context context,
+ krb5_keyblock *key,
+ krb5_key_usage usage,
+ krb5_const_pointer decrypt_arg,
+ krb5_kdc_rep *dec_rep);
+typedef krb5_error_code (*krb5_s2k_proc)(krb5_context context,
+ krb5_enctype type,
+ krb5_const_pointer keyseed,
+ krb5_salt salt,
+ krb5_data *s2kparms,
+ krb5_keyblock **key);
+
+struct _krb5_get_init_creds_opt_private;
+
+typedef struct _krb5_get_init_creds_opt {
+ krb5_flags flags;
+ krb5_deltat tkt_life;
+ krb5_deltat renew_life;
+ int forwardable;
+ int proxiable;
+ int anonymous;
+ krb5_enctype *etype_list;
+ int etype_list_length;
+ krb5_addresses *address_list;
+ /* XXX the next three should not be used, as they may be
+ removed later */
+ krb5_preauthtype *preauth_list;
+ int preauth_list_length;
+ krb5_data *salt;
+ struct _krb5_get_init_creds_opt_private *private;
+} krb5_get_init_creds_opt;
+
+#define KRB5_GET_INIT_CREDS_OPT_TKT_LIFE 0x0001
+#define KRB5_GET_INIT_CREDS_OPT_RENEW_LIFE 0x0002
+#define KRB5_GET_INIT_CREDS_OPT_FORWARDABLE 0x0004
+#define KRB5_GET_INIT_CREDS_OPT_PROXIABLE 0x0008
+#define KRB5_GET_INIT_CREDS_OPT_ETYPE_LIST 0x0010
+#define KRB5_GET_INIT_CREDS_OPT_ADDRESS_LIST 0x0020
+#define KRB5_GET_INIT_CREDS_OPT_PREAUTH_LIST 0x0040
+#define KRB5_GET_INIT_CREDS_OPT_SALT 0x0080
+#define KRB5_GET_INIT_CREDS_OPT_ANONYMOUS 0x0100
+#define KRB5_GET_INIT_CREDS_OPT_DISABLE_TRANSITED_CHECK 0x0200
+
+typedef struct _krb5_verify_init_creds_opt {
+ krb5_flags flags;
+ int ap_req_nofail;
+} krb5_verify_init_creds_opt;
+
+#define KRB5_VERIFY_INIT_CREDS_OPT_AP_REQ_NOFAIL 0x0001
+
+typedef struct krb5_verify_opt {
+ unsigned int flags;
+ krb5_ccache ccache;
+ krb5_keytab keytab;
+ krb5_boolean secure;
+ const char *service;
+} krb5_verify_opt;
+
+#define KRB5_VERIFY_LREALMS 1
+#define KRB5_VERIFY_NO_ADDRESSES 2
+
+extern const krb5_cc_ops krb5_acc_ops;
+extern const krb5_cc_ops krb5_fcc_ops;
+extern const krb5_cc_ops krb5_mcc_ops;
+extern const krb5_cc_ops krb5_kcm_ops;
+
+extern const krb5_kt_ops krb5_fkt_ops;
+extern const krb5_kt_ops krb5_wrfkt_ops;
+extern const krb5_kt_ops krb5_javakt_ops;
+extern const krb5_kt_ops krb5_mkt_ops;
+extern const krb5_kt_ops krb5_mktw_ops;
+extern const krb5_kt_ops krb5_akf_ops;
+extern const krb5_kt_ops krb4_fkt_ops;
+extern const krb5_kt_ops krb5_srvtab_fkt_ops;
+extern const krb5_kt_ops krb5_any_ops;
+
+#define KRB5_KPASSWD_VERS_CHANGEPW 1
+#define KRB5_KPASSWD_VERS_SETPW 0xff80
+
+#define KRB5_KPASSWD_SUCCESS 0
+#define KRB5_KPASSWD_MALFORMED 1
+#define KRB5_KPASSWD_HARDERROR 2
+#define KRB5_KPASSWD_AUTHERROR 3
+#define KRB5_KPASSWD_SOFTERROR 4
+#define KRB5_KPASSWD_ACCESSDENIED 5
+#define KRB5_KPASSWD_BAD_VERSION 6
+#define KRB5_KPASSWD_INITIAL_FLAG_NEEDED 7
+
+#define KPASSWD_PORT 464
+
+/* types for the new krbhst interface */
+struct krb5_krbhst_data;
+typedef struct krb5_krbhst_data *krb5_krbhst_handle;
+
+#define KRB5_KRBHST_KDC 1
+#define KRB5_KRBHST_ADMIN 2
+#define KRB5_KRBHST_CHANGEPW 3
+#define KRB5_KRBHST_KRB524 4
+
+typedef struct krb5_krbhst_info {
+ enum { KRB5_KRBHST_UDP,
+ KRB5_KRBHST_TCP,
+ KRB5_KRBHST_HTTP } proto;
+ unsigned short port;
+ unsigned short def_port;
+ struct addrinfo *ai;
+ struct krb5_krbhst_info *next;
+ char hostname[1]; /* has to come last */
+} krb5_krbhst_info;
+
+/* flags for krb5_krbhst_init_flags (and krb5_send_to_kdc_flags) */
+enum {
+ KRB5_KRBHST_FLAGS_MASTER = 1,
+ KRB5_KRBHST_FLAGS_LARGE_MSG = 2
+};
+
+struct credentials; /* this is to keep the compiler happy */
+struct getargs;
+struct sockaddr;
+
+#include <krb5-protos.h>
+
+#endif /* __KRB5_H__ */
+
diff --git a/source4/heimdal/lib/krb5/krb5_ccapi.h b/source4/heimdal/lib/krb5/krb5_ccapi.h
new file mode 100644
index 0000000000..00c30d7791
--- /dev/null
+++ b/source4/heimdal/lib/krb5/krb5_ccapi.h
@@ -0,0 +1,215 @@
+/*
+ * Copyright (c) 2004 Kungliga Tekniska Högskolan
+ * (Royal Institute of Technology, Stockholm, Sweden).
+ * 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.
+ */
+
+/* $Id: krb5_ccapi.h,v 1.1 2004/09/11 04:00:42 lha Exp $ */
+
+#ifndef KRB5_CCAPI_H
+#define KRB5_CCAPI_H 1
+
+#include <krb5-types.h>
+
+enum {
+ cc_credentials_v5 = 2
+};
+
+enum {
+ ccapi_version_3 = 3
+};
+
+enum {
+ ccNoError = 0,
+
+ ccIteratorEnd = 201,
+ ccErrBadParam,
+ ccErrNoMem,
+ ccErrInvalidContext,
+ ccErrInvalidCCache,
+
+ ccErrInvalidString, /* 206 */
+ ccErrInvalidCredentials,
+ ccErrInvalidCCacheIterator,
+ ccErrInvalidCredentialsIterator,
+ ccErrInvalidLock,
+
+ ccErrBadName, /* 211 */
+ ccErrBadCredentialsVersion,
+ ccErrBadAPIVersion,
+ ccErrContextLocked,
+ ccErrContextUnlocked,
+
+ ccErrCCacheLocked, /* 216 */
+ ccErrCCacheUnlocked,
+ ccErrBadLockType,
+ ccErrNeverDefault,
+ ccErrCredentialsNotFound,
+
+ ccErrCCacheNotFound, /* 221 */
+ ccErrContextNotFound,
+ ccErrServerUnavailable,
+ ccErrServerInsecure,
+ ccErrServerCantBecomeUID,
+
+ ccErrTimeOffsetNotSet /* 226 */
+};
+
+typedef int32_t cc_int32;
+typedef u_int32_t cc_uint32;
+typedef struct cc_context_t *cc_context_t;
+typedef struct cc_ccache_t *cc_ccache_t;
+typedef struct cc_ccache_iterator_t *cc_ccache_iterator_t;
+typedef struct cc_credentials_v5_t cc_credentials_v5_t;
+typedef struct cc_credentials_t *cc_credentials_t;
+typedef struct cc_credentials_iterator_t *cc_credentials_iterator_t;
+typedef struct cc_string_t *cc_string_t;
+typedef time_t cc_time_t;
+
+typedef struct cc_data {
+ cc_uint32 type;
+ cc_uint32 length;
+ void *data;
+} cc_data;
+
+struct cc_credentials_v5_t {
+ char *client;
+ char *server;
+ cc_data keyblock;
+ cc_time_t authtime;
+ cc_time_t starttime;
+ cc_time_t endtime;
+ cc_time_t renew_till;
+ cc_uint32 is_skey;
+ cc_uint32 ticket_flags; /* XXX ticket flags undefined */
+ cc_data **addresses;
+ cc_data ticket;
+ cc_data second_ticket;
+ cc_data **authdata;
+};
+
+
+typedef struct cc_string_functions {
+ cc_int32 (*release)(cc_string_t);
+} cc_string_functions;
+
+struct cc_string_t {
+ const char *data;
+ const cc_string_functions *func;
+};
+
+typedef struct cc_credentials_union {
+ cc_int32 version;
+ union {
+ cc_credentials_v5_t* credentials_v5;
+ } credentials;
+} cc_credentials_union;
+
+struct cc_credentials_functions {
+ cc_int32 (*release)(cc_credentials_t);
+ cc_int32 (*compare)(cc_credentials_t, cc_credentials_t, cc_uint32*);
+};
+
+struct cc_credentials_t {
+ const cc_credentials_union* data;
+ const struct cc_credentials_functions* func;
+};
+
+struct cc_credentials_iterator_functions {
+ cc_int32 (*release)(cc_credentials_iterator_t);
+ cc_int32 (*next)(cc_credentials_iterator_t, cc_credentials_t*);
+};
+
+struct cc_credentials_iterator_t {
+ const struct cc_credentials_iterator_functions *func;
+};
+
+struct cc_ccache_iterator_functions {
+ cc_int32 (*release) (cc_ccache_iterator_t);
+ cc_int32 (*next)(cc_ccache_iterator_t, cc_ccache_t*);
+};
+
+struct cc_ccache_iterator_t {
+ const struct cc_ccache_iterator_functions* func;
+};
+
+typedef struct cc_ccache_functions {
+ cc_int32 (*release)(cc_ccache_t);
+ cc_int32 (*destroy)(cc_ccache_t);
+ cc_int32 (*set_default)(cc_ccache_t);
+ cc_int32 (*get_credentials_version)(cc_ccache_t, cc_uint32*);
+ cc_int32 (*get_name)(cc_ccache_t ccache,cc_string_t*);
+ cc_int32 (*get_principal)(cc_ccache_t, cc_uint32, cc_string_t*);
+ cc_int32 (*set_principal)(cc_ccache_t, cc_uint32, const char*);
+ cc_int32 (*store_credentials)(cc_ccache_t, const cc_credentials_union*);
+ cc_int32 (*remove_credentials)(cc_ccache_t, cc_credentials_t);
+ cc_int32 (*new_credentials_iterator)(cc_ccache_t,
+ cc_credentials_iterator_t*);
+ cc_int32 (*move)(cc_ccache_t source, cc_ccache_t);
+ cc_int32 (*lock)(cc_ccache_t, cc_uint32, cc_uint32);
+ cc_int32 (*unlock)(cc_ccache_t);
+ cc_int32 (*get_last_default_time)(cc_ccache_t, cc_time_t*);
+ cc_int32 (*get_change_time)(cc_ccache_t ccache, cc_time_t*);
+ cc_int32 (*compare)(cc_ccache_t, cc_ccache_t, cc_uint32*);
+ cc_int32 (*get_kdc_time_offset)(cc_ccache_t, cc_int32, cc_time_t *);
+ cc_int32 (*set_kdc_time_offset)(cc_ccache_t, cc_int32, cc_time_t);
+ cc_int32 (*clear_kdc_time_offset)(cc_ccache_t, cc_int32);
+} cc_ccache_functions;
+
+struct cc_ccache_t {
+ const cc_ccache_functions *func;
+};
+
+struct cc_context_functions {
+ cc_int32 (*release)(cc_context_t);
+ cc_int32 (*get_change_time)(cc_context_t, cc_time_t *);
+ cc_int32 (*get_default_ccache_name)(cc_context_t, cc_string_t*);
+ cc_int32 (*open_ccache)(cc_context_t, const char*, cc_ccache_t *);
+ cc_int32 (*open_default_ccache)(cc_context_t, cc_ccache_t*);
+ cc_int32 (*create_ccache)(cc_context_t,const char*, cc_uint32,
+ const char*, cc_ccache_t*);
+ cc_int32 (*create_default_ccache)(cc_context_t, cc_uint32,
+ const char*, cc_ccache_t*);
+ cc_int32 (*create_new_ccache)(cc_context_t, cc_uint32,
+ const char*, cc_ccache_t*);
+ cc_int32 (*new_ccache_iterator)(cc_context_t, cc_ccache_iterator_t*);
+ cc_int32 (*lock)(cc_context_t, cc_uint32, cc_uint32);
+ cc_int32 (*unlock)(cc_context_t);
+ cc_int32 (*compare)(cc_context_t, cc_context_t, cc_uint32*);
+};
+
+struct cc_context_t {
+ const struct cc_context_functions* func;
+};
+
+typedef cc_int32
+(*cc_initialize_func)(cc_context_t*, cc_int32, cc_int32 *, char const **);
+
+#endif /* KRB5_CCAPI_H */
diff --git a/source4/heimdal/lib/krb5/krb5_err.et b/source4/heimdal/lib/krb5/krb5_err.et
new file mode 100644
index 0000000000..1257b074fb
--- /dev/null
+++ b/source4/heimdal/lib/krb5/krb5_err.et
@@ -0,0 +1,258 @@
+#
+# Error messages for the krb5 library
+#
+# This might look like a com_err file, but is not
+#
+id "$Id: krb5_err.et,v 1.12 2004/10/14 15:30:29 lha Exp $"
+
+error_table krb5
+
+prefix KRB5KDC_ERR
+error_code NONE, "No error"
+error_code NAME_EXP, "Client's entry in database has expired"
+error_code SERVICE_EXP, "Server's entry in database has expired"
+error_code BAD_PVNO, "Requested protocol version not supported"
+error_code C_OLD_MAST_KVNO, "Client's key is encrypted in an old master key"
+error_code S_OLD_MAST_KVNO, "Server's key is encrypted in an old master key"
+error_code C_PRINCIPAL_UNKNOWN, "Client not found in Kerberos database"
+error_code S_PRINCIPAL_UNKNOWN, "Server not found in Kerberos database"
+error_code PRINCIPAL_NOT_UNIQUE,"Principal has multiple entries in Kerberos database"
+error_code NULL_KEY, "Client or server has a null key"
+error_code CANNOT_POSTDATE, "Ticket is ineligible for postdating"
+error_code NEVER_VALID, "Requested effective lifetime is negative or too short"
+error_code POLICY, "KDC policy rejects request"
+error_code BADOPTION, "KDC can't fulfill requested option"
+error_code ETYPE_NOSUPP, "KDC has no support for encryption type"
+error_code SUMTYPE_NOSUPP, "KDC has no support for checksum type"
+error_code PADATA_TYPE_NOSUPP, "KDC has no support for padata type"
+error_code TRTYPE_NOSUPP, "KDC has no support for transited type"
+error_code CLIENT_REVOKED, "Clients credentials have been revoked"
+error_code SERVICE_REVOKED, "Credentials for server have been revoked"
+error_code TGT_REVOKED, "TGT has been revoked"
+error_code CLIENT_NOTYET, "Client not yet valid - try again later"
+error_code SERVICE_NOTYET, "Server not yet valid - try again later"
+error_code KEY_EXPIRED, "Password has expired"
+error_code PREAUTH_FAILED, "Preauthentication failed"
+error_code PREAUTH_REQUIRED, "Additional pre-authentication required"
+error_code SERVER_NOMATCH, "Requested server and ticket don't match"
+
+# 27-30 are reserved
+index 31
+prefix KRB5KRB_AP
+error_code ERR_BAD_INTEGRITY, "Decrypt integrity check failed"
+error_code ERR_TKT_EXPIRED, "Ticket expired"
+error_code ERR_TKT_NYV, "Ticket not yet valid"
+error_code ERR_REPEAT, "Request is a replay"
+error_code ERR_NOT_US, "The ticket isn't for us"
+error_code ERR_BADMATCH, "Ticket/authenticator don't match"
+error_code ERR_SKEW, "Clock skew too great"
+error_code ERR_BADADDR, "Incorrect net address"
+error_code ERR_BADVERSION, "Protocol version mismatch"
+error_code ERR_MSG_TYPE, "Invalid message type"
+error_code ERR_MODIFIED, "Message stream modified"
+error_code ERR_BADORDER, "Message out of order"
+error_code ERR_ILL_CR_TKT, "Invalid cross-realm ticket"
+error_code ERR_BADKEYVER, "Key version is not available"
+error_code ERR_NOKEY, "Service key not available"
+error_code ERR_MUT_FAIL, "Mutual authentication failed"
+error_code ERR_BADDIRECTION, "Incorrect message direction"
+error_code ERR_METHOD, "Alternative authentication method required"
+error_code ERR_BADSEQ, "Incorrect sequence number in message"
+error_code ERR_INAPP_CKSUM, "Inappropriate type of checksum in message"
+error_code PATH_NOT_ACCEPTED, "Policy rejects transited path"
+
+prefix KRB5KRB_ERR
+error_code RESPONSE_TOO_BIG, "Response too big for UDP, retry with TCP"
+# 53-59 are reserved
+index 60
+error_code GENERIC, "Generic error (see e-text)"
+error_code FIELD_TOOLONG, "Field is too long for this implementation"
+
+# pkinit
+index 62
+prefix KRB5_KDC_ERR
+error_code CLIENT_NOT_TRUSTED, "Client not trusted"
+error_code KDC_NOT_TRUSTED, "KDC not trusted"
+error_code INVALID_SIG, "Invalid signature"
+error_code KEY_SIZE, "Key size too small/key too weak"
+error_code CERTIFICATE_MISMATCH, "Certificate mismatch"
+
+prefix KRB5_AP_ERR
+error_code USER_TO_USER_REQUIRED, "User to user required"
+
+index 70
+prefix KRB5_KDC_ERROR
+error_code CANT_VERIFY_CERTIFICATE, "Cannot verify certificate"
+error_code INVALID_CERTIFICATE, "Invalid certificate"
+error_code REVOKED_CERTIFICATE, "Revoked certificate"
+error_code REVOCATION_STATUS_UNKNOWN, "Revocation status unknown"
+error_code REVOCATION_STATUS_UNAVAILABLE, "Revocation status unknown"
+error_code CLIENT_NAME_MISMATCH, "Client name mismatch"
+index 75
+error_code KDC_NAME_MISMATCH, "KDC name mismatch"
+
+# 76-79 are reserved
+
+index 80
+prefix KRB5_IAKERB
+error_code ERR_KDC_NOT_FOUND, "IAKERB proxy could not find a KDC"
+error_code ERR_KDC_NO_RESPONSE, "IAKERB proxy never reeived a response from a KDC"
+
+# 82-127 are reserved
+
+index 128
+prefix
+error_code KRB5_ERR_RCSID, "$Id: krb5_err.et,v 1.12 2004/10/14 15:30:29 lha Exp $"
+
+error_code KRB5_LIBOS_BADLOCKFLAG, "Invalid flag for file lock mode"
+error_code KRB5_LIBOS_CANTREADPWD, "Cannot read password"
+error_code KRB5_LIBOS_BADPWDMATCH, "Password mismatch"
+error_code KRB5_LIBOS_PWDINTR, "Password read interrupted"
+
+error_code KRB5_PARSE_ILLCHAR, "Invalid character in component name"
+error_code KRB5_PARSE_MALFORMED, "Malformed representation of principal"
+
+error_code KRB5_CONFIG_CANTOPEN, "Can't open/find configuration file"
+error_code KRB5_CONFIG_BADFORMAT, "Improper format of configuration file"
+error_code KRB5_CONFIG_NOTENUFSPACE, "Insufficient space to return complete information"
+
+error_code KRB5_BADMSGTYPE, "Invalid message type specified for encoding"
+
+error_code KRB5_CC_BADNAME, "Credential cache name malformed"
+error_code KRB5_CC_UNKNOWN_TYPE, "Unknown credential cache type"
+error_code KRB5_CC_NOTFOUND, "Matching credential not found"
+error_code KRB5_CC_END, "End of credential cache reached"
+
+error_code KRB5_NO_TKT_SUPPLIED, "Request did not supply a ticket"
+
+error_code KRB5KRB_AP_WRONG_PRINC, "Wrong principal in request"
+error_code KRB5KRB_AP_ERR_TKT_INVALID, "Ticket has invalid flag set"
+
+error_code KRB5_PRINC_NOMATCH, "Requested principal and ticket don't match"
+error_code KRB5_KDCREP_MODIFIED, "KDC reply did not match expectations"
+error_code KRB5_KDCREP_SKEW, "Clock skew too great in KDC reply"
+error_code KRB5_IN_TKT_REALM_MISMATCH, "Client/server realm mismatch in initial ticket request"
+
+error_code KRB5_PROG_ETYPE_NOSUPP, "Program lacks support for encryption type"
+error_code KRB5_PROG_KEYTYPE_NOSUPP, "Program lacks support for key type"
+error_code KRB5_WRONG_ETYPE, "Requested encryption type not used in message"
+error_code KRB5_PROG_SUMTYPE_NOSUPP, "Program lacks support for checksum type"
+
+error_code KRB5_REALM_UNKNOWN, "Cannot find KDC for requested realm"
+error_code KRB5_SERVICE_UNKNOWN, "Kerberos service unknown"
+error_code KRB5_KDC_UNREACH, "Cannot contact any KDC for requested realm"
+error_code KRB5_NO_LOCALNAME, "No local name found for principal name"
+
+error_code KRB5_MUTUAL_FAILED, "Mutual authentication failed"
+
+# some of these should be combined/supplanted by system codes
+
+error_code KRB5_RC_TYPE_EXISTS, "Replay cache type is already registered"
+error_code KRB5_RC_MALLOC, "No more memory to allocate (in replay cache code)"
+error_code KRB5_RC_TYPE_NOTFOUND, "Replay cache type is unknown"
+error_code KRB5_RC_UNKNOWN, "Generic unknown RC error"
+error_code KRB5_RC_REPLAY, "Message is a replay"
+error_code KRB5_RC_IO, "Replay I/O operation failed XXX"
+error_code KRB5_RC_NOIO, "Replay cache type does not support non-volatile storage"
+error_code KRB5_RC_PARSE, "Replay cache name parse/format error"
+
+error_code KRB5_RC_IO_EOF, "End-of-file on replay cache I/O"
+error_code KRB5_RC_IO_MALLOC, "No more memory to allocate (in replay cache I/O code)"
+error_code KRB5_RC_IO_PERM, "Permission denied in replay cache code"
+error_code KRB5_RC_IO_IO, "I/O error in replay cache i/o code"
+error_code KRB5_RC_IO_UNKNOWN, "Generic unknown RC/IO error"
+error_code KRB5_RC_IO_SPACE, "Insufficient system space to store replay information"
+
+error_code KRB5_TRANS_CANTOPEN, "Can't open/find realm translation file"
+error_code KRB5_TRANS_BADFORMAT, "Improper format of realm translation file"
+
+error_code KRB5_LNAME_CANTOPEN, "Can't open/find lname translation database"
+error_code KRB5_LNAME_NOTRANS, "No translation available for requested principal"
+error_code KRB5_LNAME_BADFORMAT, "Improper format of translation database entry"
+
+error_code KRB5_CRYPTO_INTERNAL, "Cryptosystem internal error"
+
+error_code KRB5_KT_BADNAME, "Key table name malformed"
+error_code KRB5_KT_UNKNOWN_TYPE, "Unknown Key table type"
+error_code KRB5_KT_NOTFOUND, "Key table entry not found"
+error_code KRB5_KT_END, "End of key table reached"
+error_code KRB5_KT_NOWRITE, "Cannot write to specified key table"
+error_code KRB5_KT_IOERR, "Error writing to key table"
+
+error_code KRB5_NO_TKT_IN_RLM, "Cannot find ticket for requested realm"
+error_code KRB5DES_BAD_KEYPAR, "DES key has bad parity"
+error_code KRB5DES_WEAK_KEY, "DES key is a weak key"
+
+error_code KRB5_BAD_ENCTYPE, "Bad encryption type"
+error_code KRB5_BAD_KEYSIZE, "Key size is incompatible with encryption type"
+error_code KRB5_BAD_MSIZE, "Message size is incompatible with encryption type"
+
+error_code KRB5_CC_TYPE_EXISTS, "Credentials cache type is already registered."
+error_code KRB5_KT_TYPE_EXISTS, "Key table type is already registered."
+
+error_code KRB5_CC_IO, "Credentials cache I/O operation failed XXX"
+error_code KRB5_FCC_PERM, "Credentials cache file permissions incorrect"
+error_code KRB5_FCC_NOFILE, "No credentials cache file found"
+error_code KRB5_FCC_INTERNAL, "Internal file credentials cache error"
+error_code KRB5_CC_WRITE, "Error writing to credentials cache file"
+error_code KRB5_CC_NOMEM, "No more memory to allocate (in credentials cache code)"
+error_code KRB5_CC_FORMAT, "Bad format in credentials cache"
+error_code KRB5_CC_NOT_KTYPE, "No credentials found with supported encryption types"
+
+# errors for dual tgt library calls
+error_code KRB5_INVALID_FLAGS, "Invalid KDC option combination (library internal error)"
+error_code KRB5_NO_2ND_TKT, "Request missing second ticket"
+
+error_code KRB5_NOCREDS_SUPPLIED, "No credentials supplied to library routine"
+
+# errors for sendauth (and recvauth)
+
+error_code KRB5_SENDAUTH_BADAUTHVERS, "Bad sendauth version was sent"
+error_code KRB5_SENDAUTH_BADAPPLVERS, "Bad application version was sent (via sendauth)"
+error_code KRB5_SENDAUTH_BADRESPONSE, "Bad response (during sendauth exchange)"
+error_code KRB5_SENDAUTH_REJECTED, "Server rejected authentication (during sendauth exchange)"
+
+# errors for preauthentication
+
+error_code KRB5_PREAUTH_BAD_TYPE, "Unsupported preauthentication type"
+error_code KRB5_PREAUTH_NO_KEY, "Required preauthentication key not supplied"
+error_code KRB5_PREAUTH_FAILED, "Generic preauthentication failure"
+
+# version number errors
+
+error_code KRB5_RCACHE_BADVNO, "Unsupported replay cache format version number"
+error_code KRB5_CCACHE_BADVNO, "Unsupported credentials cache format version number"
+error_code KRB5_KEYTAB_BADVNO, "Unsupported key table format version number"
+
+#
+#
+
+error_code KRB5_PROG_ATYPE_NOSUPP, "Program lacks support for address type"
+error_code KRB5_RC_REQUIRED, "Message replay detection requires rcache parameter"
+error_code KRB5_ERR_BAD_HOSTNAME, "Hostname cannot be canonicalized"
+error_code KRB5_ERR_HOST_REALM_UNKNOWN, "Cannot determine realm for host"
+error_code KRB5_SNAME_UNSUPP_NAMETYPE, "Conversion to service principal undefined for name type"
+
+error_code KRB5KRB_AP_ERR_V4_REPLY, "Initial Ticket response appears to be Version 4"
+error_code KRB5_REALM_CANT_RESOLVE, "Cannot resolve KDC for requested realm"
+error_code KRB5_TKT_NOT_FORWARDABLE, "Requesting ticket can't get forwardable tickets"
+error_code KRB5_FWD_BAD_PRINCIPAL, "Bad principal name while trying to forward credentials"
+
+error_code KRB5_GET_IN_TKT_LOOP, "Looping detected inside krb5_get_in_tkt"
+error_code KRB5_CONFIG_NODEFREALM, "Configuration file does not specify default realm"
+
+error_code KRB5_SAM_UNSUPPORTED, "Bad SAM flags in obtain_sam_padata"
+error_code KRB5_SAM_INVALID_ETYPE, "Invalid encryption type in SAM challenge"
+error_code KRB5_SAM_NO_CHECKSUM, "Missing checksum in SAM challenge"
+error_code KRB5_SAM_BAD_CHECKSUM, "Bad checksum in SAM challenge"
+
+index 238
+error_code KRB5_OBSOLETE_FN, "Program called an obsolete, deleted function"
+
+index 245
+error_code KRB5_ERR_BAD_S2K_PARAMS, "Invalid key generation parameters from KDC"
+error_code KRB5_ERR_NO_SERVICE, "Service not available"
+error_code KRB5_CC_NOSUPP, "Credential cache function not supported"
+error_code KRB5_DELTAT_BADFORMAT, "Invalid format of Kerberos lifetime or clock skew string"
+
+end
diff --git a/source4/heimdal/lib/krb5/krb5_locl.h b/source4/heimdal/lib/krb5/krb5_locl.h
new file mode 100644
index 0000000000..a64ccc586e
--- /dev/null
+++ b/source4/heimdal/lib/krb5/krb5_locl.h
@@ -0,0 +1,188 @@
+/*
+ * Copyright (c) 1997-2002 Kungliga Tekniska Högskolan
+ * (Royal Institute of Technology, Stockholm, Sweden).
+ * 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.
+ */
+
+/* $Id: krb5_locl.h,v 1.81 2005/05/29 14:28:39 lha Exp $ */
+
+#ifndef __KRB5_LOCL_H__
+#define __KRB5_LOCL_H__
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <errno.h>
+#include <ctype.h>
+#include <string.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <limits.h>
+
+#ifdef HAVE_SYS_TYPES_H
+#include <sys/types.h>
+#endif
+#ifdef HAVE_SYS_MMAN_H
+#include <sys/mman.h>
+#endif
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+#ifdef HAVE_FCNTL_H
+#include <fcntl.h>
+#endif
+
+#if defined(HAVE_SYS_IOCTL_H) && SunOS != 40
+#include <sys/ioctl.h>
+#endif
+#ifdef HAVE_PWD_H
+#undef _POSIX_PTHREAD_SEMANTICS
+/* This gets us the 5-arg getpwnam_r on Solaris 9. */
+#define _POSIX_PTHREAD_SEMANTICS
+#include <pwd.h>
+#endif
+
+#ifdef HAVE_SYS_PARAM_H
+#include <sys/param.h>
+#endif
+#include <time.h>
+#ifdef HAVE_SYS_TIME_H
+#include <sys/time.h>
+#endif
+#ifdef HAVE_SYS_SELECT_H
+#include <sys/select.h>
+#endif
+#ifdef HAVE_SYS_SOCKET_H
+#include <sys/socket.h>
+#endif
+#ifdef HAVE_NETINET_IN_H
+#include <netinet/in.h>
+#endif
+#ifdef HAVE_NETINET_IN6_H
+#include <netinet/in6.h>
+#endif
+#ifdef HAVE_NETINET6_IN6_H
+#include <netinet6/in6.h>
+#endif
+#ifdef HAVE_NETDB_H
+#include <netdb.h>
+#endif
+#ifdef _AIX
+struct ether_addr;
+struct mbuf;
+struct sockaddr_dl;
+#endif
+#ifdef HAVE_ARPA_INET_H
+#include <arpa/inet.h>
+#endif
+#ifdef HAVE_ARPA_NAMESER_H
+#include <arpa/nameser.h>
+#endif
+#ifdef HAVE_SYS_UIO_H
+#include <sys/uio.h>
+#endif
+#ifdef HAVE_SYS_FILIO_H
+#include <sys/filio.h>
+#endif
+#ifdef HAVE_SYS_FILE_H
+#include <sys/file.h>
+#endif
+
+#ifdef HAVE_CRYPT_H
+#undef des_encrypt
+#define des_encrypt wingless_pigs_mostly_fail_to_fly
+#include <crypt.h>
+#undef des_encrypt
+#endif
+
+#ifdef HAVE_DOOR_CREATE
+#include <door.h>
+#endif
+
+#include <roken.h>
+#include <parse_time.h>
+#include <base64.h>
+
+#include "crypto-headers.h"
+
+
+#include <krb5_asn1.h>
+
+/* XXX glue for pkinit */
+struct krb5_pk_identity;
+struct krb5_pk_cert;
+struct ContentInfo;
+typedef struct krb5_pk_init_ctx_data *krb5_pk_init_ctx;
+
+/* v4 glue */
+struct _krb5_krb_auth_data;
+
+#include <der.h>
+
+#include <krb5.h>
+#include <krb5_err.h>
+#include <asn1_err.h>
+#include <krb5-private.h>
+
+#include "heim_threads.h"
+
+#define ALLOC(X, N) (X) = calloc((N), sizeof(*(X)))
+#define ALLOC_SEQ(X, N) do { (X)->len = (N); ALLOC((X)->val, (N)); } while(0)
+
+/* should this be public? */
+#define KEYTAB_DEFAULT "ANY:FILE:" SYSCONFDIR "/krb5.keytab,krb4:" SYSCONFDIR "/srvtab"
+#define KEYTAB_DEFAULT_MODIFY "FILE:" SYSCONFDIR "/krb5.keytab"
+
+#ifndef O_BINARY
+#define O_BINARY 0
+#endif
+
+#define KRB5_BUFSIZ 1024
+
+typedef enum {
+ KRB5_PA_PAC_DONT_CARE = 0,
+ KRB5_PA_PAC_REQ_TRUE,
+ KRB5_PA_PAC_REQ_FALSE
+} krb5_get_init_creds_req_pac;
+
+struct _krb5_get_init_creds_opt_private {
+ int refcount;
+ /* ENC_TIMESTAMP */
+ const char *password;
+ krb5_s2k_proc key_proc;
+ /* PA_PAC_REQUEST */
+ krb5_get_init_creds_req_pac req_pac;
+ /* PKINIT */
+ krb5_pk_init_ctx pk_init_ctx;
+ int canonicalize;
+};
+
+#endif /* __KRB5_LOCL_H__ */
diff --git a/source4/heimdal/lib/krb5/krbhst.c b/source4/heimdal/lib/krb5/krbhst.c
new file mode 100644
index 0000000000..49eee08ca5
--- /dev/null
+++ b/source4/heimdal/lib/krb5/krbhst.c
@@ -0,0 +1,861 @@
+/*
+ * Copyright (c) 2001 - 2003 Kungliga Tekniska Högskolan
+ * (Royal Institute of Technology, Stockholm, Sweden).
+ * 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 <resolve.h>
+
+RCSID("$Id: krbhst.c,v 1.52 2005/06/17 04:23:26 lha Exp $");
+
+static int
+string_to_proto(const char *string)
+{
+ if(strcasecmp(string, "udp") == 0)
+ return KRB5_KRBHST_UDP;
+ else if(strcasecmp(string, "tcp") == 0)
+ return KRB5_KRBHST_TCP;
+ else if(strcasecmp(string, "http") == 0)
+ return KRB5_KRBHST_HTTP;
+ return -1;
+}
+
+/*
+ * set `res' and `count' to the result of looking up SRV RR in DNS for
+ * `proto', `proto', `realm' using `dns_type'.
+ * if `port' != 0, force that port number
+ */
+
+static krb5_error_code
+srv_find_realm(krb5_context context, krb5_krbhst_info ***res, int *count,
+ const char *realm, const char *dns_type,
+ const char *proto, const char *service, int port)
+{
+ char domain[1024];
+ struct dns_reply *r;
+ struct resource_record *rr;
+ int num_srv;
+ int proto_num;
+ int def_port;
+
+ *res = NULL;
+ *count = 0;
+
+ proto_num = string_to_proto(proto);
+ if(proto_num < 0) {
+ krb5_set_error_string(context, "unknown protocol `%s'", proto);
+ return EINVAL;
+ }
+
+ if(proto_num == KRB5_KRBHST_HTTP)
+ def_port = ntohs(krb5_getportbyname (context, "http", "tcp", 80));
+ else if(port == 0)
+ def_port = ntohs(krb5_getportbyname (context, service, proto, 88));
+ else
+ def_port = port;
+
+ snprintf(domain, sizeof(domain), "_%s._%s.%s.", service, proto, realm);
+
+ r = dns_lookup(domain, dns_type);
+ if(r == NULL)
+ return KRB5_KDC_UNREACH;
+
+ for(num_srv = 0, rr = r->head; rr; rr = rr->next)
+ if(rr->type == T_SRV)
+ num_srv++;
+
+ *res = malloc(num_srv * sizeof(**res));
+ if(*res == NULL) {
+ dns_free_data(r);
+ krb5_set_error_string(context, "malloc: out of memory");
+ return ENOMEM;
+ }
+
+ dns_srv_order(r);
+
+ for(num_srv = 0, rr = r->head; rr; rr = rr->next)
+ if(rr->type == T_SRV) {
+ krb5_krbhst_info *hi;
+ size_t len = strlen(rr->u.srv->target);
+
+ hi = calloc(1, sizeof(*hi) + len);
+ if(hi == NULL) {
+ dns_free_data(r);
+ while(--num_srv >= 0)
+ free((*res)[num_srv]);
+ free(*res);
+ *res = NULL;
+ return ENOMEM;
+ }
+ (*res)[num_srv++] = hi;
+
+ hi->proto = proto_num;
+
+ hi->def_port = def_port;
+ if (port != 0)
+ hi->port = port;
+ else
+ hi->port = rr->u.srv->port;
+
+ strlcpy(hi->hostname, rr->u.srv->target, len + 1);
+ }
+
+ *count = num_srv;
+
+ dns_free_data(r);
+ return 0;
+}
+
+
+struct krb5_krbhst_data {
+ char *realm;
+ unsigned int flags;
+ int def_port;
+ int port; /* hardwired port number if != 0 */
+#define KD_CONFIG 1
+#define KD_SRV_UDP 2
+#define KD_SRV_TCP 4
+#define KD_SRV_HTTP 8
+#define KD_FALLBACK 16
+#define KD_CONFIG_EXISTS 32
+#define KD_LARGE_MSG 64
+ krb5_error_code (*get_next)(krb5_context, struct krb5_krbhst_data *,
+ krb5_krbhst_info**);
+
+ unsigned int fallback_count;
+
+ struct krb5_krbhst_info *hosts, **index, **end;
+};
+
+static krb5_boolean
+krbhst_empty(const struct krb5_krbhst_data *kd)
+{
+ return kd->index == &kd->hosts;
+}
+
+/*
+ * Return the default protocol for the `kd' (either TCP or UDP)
+ */
+
+static int
+krbhst_get_default_proto(struct krb5_krbhst_data *kd)
+{
+ if (kd->flags & KD_LARGE_MSG)
+ return KRB5_KRBHST_TCP;
+ return KRB5_KRBHST_UDP;
+}
+
+
+/*
+ * parse `spec' into a krb5_krbhst_info, defaulting the port to `def_port'
+ * and forcing it to `port' if port != 0
+ */
+
+static struct krb5_krbhst_info*
+parse_hostspec(krb5_context context, struct krb5_krbhst_data *kd,
+ const char *spec, int def_port, int port)
+{
+ const char *p = spec;
+ struct krb5_krbhst_info *hi;
+
+ hi = calloc(1, sizeof(*hi) + strlen(spec));
+ if(hi == NULL)
+ return NULL;
+
+ hi->proto = krbhst_get_default_proto(kd);
+
+ if(strncmp(p, "http://", 7) == 0){
+ hi->proto = KRB5_KRBHST_HTTP;
+ p += 7;
+ } else if(strncmp(p, "http/", 5) == 0) {
+ hi->proto = KRB5_KRBHST_HTTP;
+ p += 5;
+ def_port = ntohs(krb5_getportbyname (context, "http", "tcp", 80));
+ }else if(strncmp(p, "tcp/", 4) == 0){
+ hi->proto = KRB5_KRBHST_TCP;
+ p += 4;
+ } else if(strncmp(p, "udp/", 4) == 0) {
+ p += 4;
+ }
+
+ if(strsep_copy(&p, ":", hi->hostname, strlen(spec) + 1) < 0) {
+ free(hi);
+ return NULL;
+ }
+ /* get rid of trailing /, and convert to lower case */
+ hi->hostname[strcspn(hi->hostname, "/")] = '\0';
+ strlwr(hi->hostname);
+
+ hi->port = hi->def_port = def_port;
+ if(p != NULL) {
+ char *end;
+ hi->port = strtol(p, &end, 0);
+ if(end == p) {
+ free(hi);
+ return NULL;
+ }
+ }
+ if (port)
+ hi->port = port;
+ return hi;
+}
+
+static void
+free_krbhst_info(krb5_krbhst_info *hi)
+{
+ if (hi->ai != NULL)
+ freeaddrinfo(hi->ai);
+ free(hi);
+}
+
+static void
+append_host_hostinfo(struct krb5_krbhst_data *kd, struct krb5_krbhst_info *host)
+{
+ struct krb5_krbhst_info *h;
+
+ for(h = kd->hosts; h; h = h->next)
+ if(h->proto == host->proto &&
+ h->port == host->port &&
+ strcmp(h->hostname, host->hostname) == 0) {
+ free_krbhst_info(host);
+ return;
+ }
+ *kd->end = host;
+ kd->end = &host->next;
+}
+
+static krb5_error_code
+append_host_string(krb5_context context, struct krb5_krbhst_data *kd,
+ const char *host, int def_port, int port)
+{
+ struct krb5_krbhst_info *hi;
+
+ hi = parse_hostspec(context, kd, host, def_port, port);
+ if(hi == NULL)
+ return ENOMEM;
+
+ append_host_hostinfo(kd, hi);
+ return 0;
+}
+
+/*
+ * return a readable representation of `host' in `hostname, hostlen'
+ */
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_krbhst_format_string(krb5_context context, const krb5_krbhst_info *host,
+ char *hostname, size_t hostlen)
+{
+ const char *proto = "";
+ char portstr[7] = "";
+ if(host->proto == KRB5_KRBHST_TCP)
+ proto = "tcp/";
+ else if(host->proto == KRB5_KRBHST_HTTP)
+ proto = "http://";
+ if(host->port != host->def_port)
+ snprintf(portstr, sizeof(portstr), ":%d", host->port);
+ snprintf(hostname, hostlen, "%s%s%s", proto, host->hostname, portstr);
+ return 0;
+}
+
+/*
+ * create a getaddrinfo `hints' based on `proto'
+ */
+
+static void
+make_hints(struct addrinfo *hints, int proto)
+{
+ memset(hints, 0, sizeof(*hints));
+ hints->ai_family = AF_UNSPEC;
+ switch(proto) {
+ case KRB5_KRBHST_UDP :
+ hints->ai_socktype = SOCK_DGRAM;
+ break;
+ case KRB5_KRBHST_HTTP :
+ case KRB5_KRBHST_TCP :
+ hints->ai_socktype = SOCK_STREAM;
+ break;
+ }
+}
+
+/*
+ * return an `struct addrinfo *' in `ai' corresponding to the information
+ * in `host'. free:ing is handled by krb5_krbhst_free.
+ */
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_krbhst_get_addrinfo(krb5_context context, krb5_krbhst_info *host,
+ struct addrinfo **ai)
+{
+ struct addrinfo hints;
+ char portstr[NI_MAXSERV];
+ int ret;
+
+ if (host->ai == NULL) {
+ make_hints(&hints, host->proto);
+ snprintf (portstr, sizeof(portstr), "%d", host->port);
+ ret = getaddrinfo(host->hostname, portstr, &hints, &host->ai);
+ if (ret)
+ return krb5_eai_to_heim_errno(ret, errno);
+ }
+ *ai = host->ai;
+ return 0;
+}
+
+static krb5_boolean
+get_next(struct krb5_krbhst_data *kd, krb5_krbhst_info **host)
+{
+ struct krb5_krbhst_info *hi = *kd->index;
+ if(hi != NULL) {
+ *host = hi;
+ kd->index = &(*kd->index)->next;
+ return TRUE;
+ }
+ return FALSE;
+}
+
+static void
+srv_get_hosts(krb5_context context, struct krb5_krbhst_data *kd,
+ const char *proto, const char *service)
+{
+ krb5_krbhst_info **res;
+ int count, i;
+
+ if (srv_find_realm(context, &res, &count, kd->realm, "SRV", proto, service,
+ kd->port))
+ return;
+ for(i = 0; i < count; i++)
+ append_host_hostinfo(kd, res[i]);
+ free(res);
+}
+
+/*
+ * read the configuration for `conf_string', defaulting to kd->def_port and
+ * forcing it to `kd->port' if kd->port != 0
+ */
+
+static void
+config_get_hosts(krb5_context context, struct krb5_krbhst_data *kd,
+ const char *conf_string)
+{
+ int i;
+
+ char **hostlist;
+ hostlist = krb5_config_get_strings(context, NULL,
+ "realms", kd->realm, conf_string, NULL);
+
+ if(hostlist == NULL)
+ return;
+ kd->flags |= KD_CONFIG_EXISTS;
+ for(i = 0; hostlist && hostlist[i] != NULL; i++)
+ append_host_string(context, kd, hostlist[i], kd->def_port, kd->port);
+
+ krb5_config_free_strings(hostlist);
+}
+
+/*
+ * as a fallback, look for `serv_string.kd->realm' (typically
+ * kerberos.REALM, kerberos-1.REALM, ...
+ * `port' is the default port for the service, and `proto' the
+ * protocol
+ */
+
+static krb5_error_code
+fallback_get_hosts(krb5_context context, struct krb5_krbhst_data *kd,
+ const char *serv_string, int port, int proto)
+{
+ char *host;
+ int ret;
+ struct addrinfo *ai;
+ struct addrinfo hints;
+ char portstr[NI_MAXSERV];
+
+ if(kd->fallback_count == 0)
+ asprintf(&host, "%s.%s.", serv_string, kd->realm);
+ else
+ asprintf(&host, "%s-%d.%s.",
+ serv_string, kd->fallback_count, kd->realm);
+
+ if (host == NULL)
+ return ENOMEM;
+
+ make_hints(&hints, proto);
+ snprintf(portstr, sizeof(portstr), "%d", port);
+ ret = getaddrinfo(host, portstr, &hints, &ai);
+ if (ret) {
+ /* no more hosts, so we're done here */
+ free(host);
+ kd->flags |= KD_FALLBACK;
+ } else {
+ struct krb5_krbhst_info *hi;
+ size_t hostlen = strlen(host);
+
+ hi = calloc(1, sizeof(*hi) + hostlen);
+ if(hi == NULL) {
+ free(host);
+ return ENOMEM;
+ }
+
+ hi->proto = proto;
+ hi->port = hi->def_port = port;
+ hi->ai = ai;
+ memmove(hi->hostname, host, hostlen - 1);
+ hi->hostname[hostlen - 1] = '\0';
+ free(host);
+ append_host_hostinfo(kd, hi);
+ kd->fallback_count++;
+ }
+ return 0;
+}
+
+static krb5_error_code
+kdc_get_next(krb5_context context,
+ struct krb5_krbhst_data *kd,
+ krb5_krbhst_info **host)
+{
+ krb5_error_code ret;
+
+ if((kd->flags & KD_CONFIG) == 0) {
+ config_get_hosts(context, kd, "kdc");
+ kd->flags |= KD_CONFIG;
+ if(get_next(kd, host))
+ return 0;
+ }
+
+ if (kd->flags & KD_CONFIG_EXISTS)
+ return KRB5_KDC_UNREACH; /* XXX */
+
+ if(context->srv_lookup) {
+ if((kd->flags & KD_SRV_UDP) == 0 && (kd->flags & KD_LARGE_MSG) == 0) {
+ srv_get_hosts(context, kd, "udp", "kerberos");
+ kd->flags |= KD_SRV_UDP;
+ if(get_next(kd, host))
+ return 0;
+ }
+
+ if((kd->flags & KD_SRV_TCP) == 0) {
+ srv_get_hosts(context, kd, "tcp", "kerberos");
+ kd->flags |= KD_SRV_TCP;
+ if(get_next(kd, host))
+ return 0;
+ }
+ if((kd->flags & KD_SRV_HTTP) == 0) {
+ srv_get_hosts(context, kd, "http", "kerberos");
+ kd->flags |= KD_SRV_HTTP;
+ if(get_next(kd, host))
+ return 0;
+ }
+ }
+
+ while((kd->flags & KD_FALLBACK) == 0) {
+ ret = fallback_get_hosts(context, kd, "kerberos",
+ kd->def_port,
+ krbhst_get_default_proto(kd));
+ if(ret)
+ return ret;
+ if(get_next(kd, host))
+ return 0;
+ }
+
+ return KRB5_KDC_UNREACH; /* XXX */
+}
+
+static krb5_error_code
+admin_get_next(krb5_context context,
+ struct krb5_krbhst_data *kd,
+ krb5_krbhst_info **host)
+{
+ krb5_error_code ret;
+
+ if((kd->flags & KD_CONFIG) == 0) {
+ config_get_hosts(context, kd, "admin_server");
+ kd->flags |= KD_CONFIG;
+ if(get_next(kd, host))
+ return 0;
+ }
+
+ if (kd->flags & KD_CONFIG_EXISTS)
+ return KRB5_KDC_UNREACH; /* XXX */
+
+ if(context->srv_lookup) {
+ if((kd->flags & KD_SRV_TCP) == 0) {
+ srv_get_hosts(context, kd, "tcp", "kerberos-adm");
+ kd->flags |= KD_SRV_TCP;
+ if(get_next(kd, host))
+ return 0;
+ }
+ }
+
+ if (krbhst_empty(kd)
+ && (kd->flags & KD_FALLBACK) == 0) {
+ ret = fallback_get_hosts(context, kd, "kerberos",
+ kd->def_port,
+ krbhst_get_default_proto(kd));
+ if(ret)
+ return ret;
+ kd->flags |= KD_FALLBACK;
+ if(get_next(kd, host))
+ return 0;
+ }
+
+ return KRB5_KDC_UNREACH; /* XXX */
+}
+
+static krb5_error_code
+kpasswd_get_next(krb5_context context,
+ struct krb5_krbhst_data *kd,
+ krb5_krbhst_info **host)
+{
+ krb5_error_code ret;
+
+ if((kd->flags & KD_CONFIG) == 0) {
+ config_get_hosts(context, kd, "kpasswd_server");
+ kd->flags |= KD_CONFIG;
+ if(get_next(kd, host))
+ return 0;
+ }
+
+ if (kd->flags & KD_CONFIG_EXISTS)
+ return KRB5_KDC_UNREACH; /* XXX */
+
+ if(context->srv_lookup) {
+ if((kd->flags & KD_SRV_UDP) == 0) {
+ srv_get_hosts(context, kd, "udp", "kpasswd");
+ kd->flags |= KD_SRV_UDP;
+ if(get_next(kd, host))
+ return 0;
+ }
+ if((kd->flags & KD_SRV_TCP) == 0) {
+ srv_get_hosts(context, kd, "tcp", "kpasswd");
+ kd->flags |= KD_SRV_TCP;
+ if(get_next(kd, host))
+ return 0;
+ }
+ }
+
+ /* no matches -> try admin */
+
+ if (krbhst_empty(kd)) {
+ kd->flags = 0;
+ kd->port = kd->def_port;
+ kd->get_next = admin_get_next;
+ ret = (*kd->get_next)(context, kd, host);
+ if (ret == 0)
+ (*host)->proto = krbhst_get_default_proto(kd);
+ return ret;
+ }
+
+ return KRB5_KDC_UNREACH; /* XXX */
+}
+
+static krb5_error_code
+krb524_get_next(krb5_context context,
+ struct krb5_krbhst_data *kd,
+ krb5_krbhst_info **host)
+{
+ if((kd->flags & KD_CONFIG) == 0) {
+ config_get_hosts(context, kd, "krb524_server");
+ if(get_next(kd, host))
+ return 0;
+ kd->flags |= KD_CONFIG;
+ }
+
+ if (kd->flags & KD_CONFIG_EXISTS)
+ return KRB5_KDC_UNREACH; /* XXX */
+
+ if(context->srv_lookup) {
+ if((kd->flags & KD_SRV_UDP) == 0) {
+ srv_get_hosts(context, kd, "udp", "krb524");
+ kd->flags |= KD_SRV_UDP;
+ if(get_next(kd, host))
+ return 0;
+ }
+
+ if((kd->flags & KD_SRV_TCP) == 0) {
+ srv_get_hosts(context, kd, "tcp", "krb524");
+ kd->flags |= KD_SRV_TCP;
+ if(get_next(kd, host))
+ return 0;
+ }
+ }
+
+ /* no matches -> try kdc */
+
+ if (krbhst_empty(kd)) {
+ kd->flags = 0;
+ kd->port = kd->def_port;
+ kd->get_next = kdc_get_next;
+ return (*kd->get_next)(context, kd, host);
+ }
+
+ return KRB5_KDC_UNREACH; /* XXX */
+}
+
+static struct krb5_krbhst_data*
+common_init(krb5_context context,
+ const char *realm,
+ int flags)
+{
+ struct krb5_krbhst_data *kd;
+
+ if((kd = calloc(1, sizeof(*kd))) == NULL)
+ return NULL;
+
+ if((kd->realm = strdup(realm)) == NULL) {
+ free(kd);
+ return NULL;
+ }
+
+ if (flags & KRB5_KRBHST_FLAGS_LARGE_MSG)
+ kd->flags |= KD_LARGE_MSG;
+ kd->end = kd->index = &kd->hosts;
+ return kd;
+}
+
+/*
+ * initialize `handle' to look for hosts of type `type' in realm `realm'
+ */
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_krbhst_init(krb5_context context,
+ const char *realm,
+ unsigned int type,
+ krb5_krbhst_handle *handle)
+{
+ return krb5_krbhst_init_flags(context, realm, type, 0, handle);
+}
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_krbhst_init_flags(krb5_context context,
+ const char *realm,
+ unsigned int type,
+ int flags,
+ krb5_krbhst_handle *handle)
+{
+ struct krb5_krbhst_data *kd;
+ krb5_error_code (*next)(krb5_context, struct krb5_krbhst_data *,
+ krb5_krbhst_info **);
+ int def_port;
+
+ switch(type) {
+ case KRB5_KRBHST_KDC:
+ next = kdc_get_next;
+ def_port = ntohs(krb5_getportbyname (context, "kerberos", "udp", 88));
+ break;
+ case KRB5_KRBHST_ADMIN:
+ next = admin_get_next;
+ def_port = ntohs(krb5_getportbyname (context, "kerberos-adm",
+ "tcp", 749));
+ break;
+ case KRB5_KRBHST_CHANGEPW:
+ next = kpasswd_get_next;
+ def_port = ntohs(krb5_getportbyname (context, "kpasswd", "udp",
+ KPASSWD_PORT));
+ break;
+ case KRB5_KRBHST_KRB524:
+ next = krb524_get_next;
+ def_port = ntohs(krb5_getportbyname (context, "krb524", "udp", 4444));
+ break;
+ default:
+ krb5_set_error_string(context, "unknown krbhst type (%u)", type);
+ return ENOTTY;
+ }
+ if((kd = common_init(context, realm, flags)) == NULL)
+ return ENOMEM;
+ kd->get_next = next;
+ kd->def_port = def_port;
+ *handle = kd;
+ return 0;
+}
+
+/*
+ * return the next host information from `handle' in `host'
+ */
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_krbhst_next(krb5_context context,
+ krb5_krbhst_handle handle,
+ krb5_krbhst_info **host)
+{
+ if(get_next(handle, host))
+ return 0;
+
+ return (*handle->get_next)(context, handle, host);
+}
+
+/*
+ * return the next host information from `handle' as a host name
+ * in `hostname' (or length `hostlen)
+ */
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_krbhst_next_as_string(krb5_context context,
+ krb5_krbhst_handle handle,
+ char *hostname,
+ size_t hostlen)
+{
+ krb5_error_code ret;
+ krb5_krbhst_info *host;
+ ret = krb5_krbhst_next(context, handle, &host);
+ if(ret)
+ return ret;
+ return krb5_krbhst_format_string(context, host, hostname, hostlen);
+}
+
+
+void KRB5_LIB_FUNCTION
+krb5_krbhst_reset(krb5_context context, krb5_krbhst_handle handle)
+{
+ handle->index = &handle->hosts;
+}
+
+void KRB5_LIB_FUNCTION
+krb5_krbhst_free(krb5_context context, krb5_krbhst_handle handle)
+{
+ krb5_krbhst_info *h, *next;
+
+ if (handle == NULL)
+ return;
+
+ for (h = handle->hosts; h != NULL; h = next) {
+ next = h->next;
+ free_krbhst_info(h);
+ }
+
+ free(handle->realm);
+ free(handle);
+}
+
+/* backwards compatibility ahead */
+
+static krb5_error_code
+gethostlist(krb5_context context, const char *realm,
+ unsigned int type, char ***hostlist)
+{
+ krb5_error_code ret;
+ int nhost = 0;
+ krb5_krbhst_handle handle;
+ char host[MAXHOSTNAMELEN];
+ krb5_krbhst_info *hostinfo;
+
+ ret = krb5_krbhst_init(context, realm, type, &handle);
+ if (ret)
+ return ret;
+
+ while(krb5_krbhst_next(context, handle, &hostinfo) == 0)
+ nhost++;
+ if(nhost == 0)
+ return KRB5_KDC_UNREACH;
+ *hostlist = calloc(nhost + 1, sizeof(**hostlist));
+ if(*hostlist == NULL) {
+ krb5_krbhst_free(context, handle);
+ return ENOMEM;
+ }
+
+ krb5_krbhst_reset(context, handle);
+ nhost = 0;
+ while(krb5_krbhst_next_as_string(context, handle,
+ host, sizeof(host)) == 0) {
+ if(((*hostlist)[nhost++] = strdup(host)) == NULL) {
+ krb5_free_krbhst(context, *hostlist);
+ krb5_krbhst_free(context, handle);
+ return ENOMEM;
+ }
+ }
+ (*hostlist)[nhost++] = NULL;
+ krb5_krbhst_free(context, handle);
+ return 0;
+}
+
+/*
+ * return an malloced list of kadmin-hosts for `realm' in `hostlist'
+ */
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_get_krb_admin_hst (krb5_context context,
+ const krb5_realm *realm,
+ char ***hostlist)
+{
+ return gethostlist(context, *realm, KRB5_KRBHST_ADMIN, hostlist);
+}
+
+/*
+ * return an malloced list of changepw-hosts for `realm' in `hostlist'
+ */
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_get_krb_changepw_hst (krb5_context context,
+ const krb5_realm *realm,
+ char ***hostlist)
+{
+ return gethostlist(context, *realm, KRB5_KRBHST_CHANGEPW, hostlist);
+}
+
+/*
+ * return an malloced list of 524-hosts for `realm' in `hostlist'
+ */
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_get_krb524hst (krb5_context context,
+ const krb5_realm *realm,
+ char ***hostlist)
+{
+ return gethostlist(context, *realm, KRB5_KRBHST_KRB524, hostlist);
+}
+
+
+/*
+ * return an malloced list of KDC's for `realm' in `hostlist'
+ */
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_get_krbhst (krb5_context context,
+ const krb5_realm *realm,
+ char ***hostlist)
+{
+ return gethostlist(context, *realm, KRB5_KRBHST_KDC, hostlist);
+}
+
+/*
+ * free all the memory allocated in `hostlist'
+ */
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_free_krbhst (krb5_context context,
+ char **hostlist)
+{
+ char **p;
+
+ for (p = hostlist; *p; ++p)
+ free (*p);
+ free (hostlist);
+ return 0;
+}
diff --git a/source4/heimdal/lib/krb5/log.c b/source4/heimdal/lib/krb5/log.c
new file mode 100644
index 0000000000..4f6381c858
--- /dev/null
+++ b/source4/heimdal/lib/krb5/log.c
@@ -0,0 +1,467 @@
+/*
+ * Copyright (c) 1997-2002 Kungliga Tekniska Högskolan
+ * (Royal Institute of Technology, Stockholm, Sweden).
+ * 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"
+
+RCSID("$Id: log.c,v 1.36 2005/06/17 04:25:05 lha Exp $");
+
+struct facility {
+ int min;
+ int max;
+ krb5_log_log_func_t log_func;
+ krb5_log_close_func_t close_func;
+ void *data;
+};
+
+static struct facility*
+log_realloc(krb5_log_facility *f)
+{
+ struct facility *fp;
+ fp = realloc(f->val, (f->len + 1) * sizeof(*f->val));
+ if(fp == NULL)
+ return NULL;
+ f->len++;
+ f->val = fp;
+ fp += f->len - 1;
+ return fp;
+}
+
+struct s2i {
+ const char *s;
+ int val;
+};
+
+#define L(X) { #X, LOG_ ## X }
+
+static struct s2i syslogvals[] = {
+ L(EMERG),
+ L(ALERT),
+ L(CRIT),
+ L(ERR),
+ L(WARNING),
+ L(NOTICE),
+ L(INFO),
+ L(DEBUG),
+
+ L(AUTH),
+#ifdef LOG_AUTHPRIV
+ L(AUTHPRIV),
+#endif
+#ifdef LOG_CRON
+ L(CRON),
+#endif
+ L(DAEMON),
+#ifdef LOG_FTP
+ L(FTP),
+#endif
+ L(KERN),
+ L(LPR),
+ L(MAIL),
+#ifdef LOG_NEWS
+ L(NEWS),
+#endif
+ L(SYSLOG),
+ L(USER),
+#ifdef LOG_UUCP
+ L(UUCP),
+#endif
+ L(LOCAL0),
+ L(LOCAL1),
+ L(LOCAL2),
+ L(LOCAL3),
+ L(LOCAL4),
+ L(LOCAL5),
+ L(LOCAL6),
+ L(LOCAL7),
+ { NULL, -1 }
+};
+
+static int
+find_value(const char *s, struct s2i *table)
+{
+ while(table->s && strcasecmp(table->s, s))
+ table++;
+ return table->val;
+}
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_initlog(krb5_context context,
+ const char *program,
+ krb5_log_facility **fac)
+{
+ krb5_log_facility *f = calloc(1, sizeof(*f));
+ if(f == NULL) {
+ krb5_set_error_string (context, "malloc: out of memory");
+ return ENOMEM;
+ }
+ f->program = strdup(program);
+ if(f->program == NULL){
+ free(f);
+ krb5_set_error_string (context, "malloc: out of memory");
+ return ENOMEM;
+ }
+ *fac = f;
+ return 0;
+}
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_addlog_func(krb5_context context,
+ krb5_log_facility *fac,
+ int min,
+ int max,
+ krb5_log_log_func_t log_func,
+ krb5_log_close_func_t close_func,
+ void *data)
+{
+ struct facility *fp = log_realloc(fac);
+ if(fp == NULL) {
+ krb5_set_error_string (context, "malloc: out of memory");
+ return ENOMEM;
+ }
+ fp->min = min;
+ fp->max = max;
+ fp->log_func = log_func;
+ fp->close_func = close_func;
+ fp->data = data;
+ return 0;
+}
+
+
+struct _heimdal_syslog_data{
+ int priority;
+};
+
+static void
+log_syslog(const char *timestr,
+ const char *msg,
+ void *data)
+
+{
+ struct _heimdal_syslog_data *s = data;
+ syslog(s->priority, "%s", msg);
+}
+
+static void
+close_syslog(void *data)
+{
+ free(data);
+ closelog();
+}
+
+static krb5_error_code
+open_syslog(krb5_context context,
+ krb5_log_facility *facility, int min, int max,
+ const char *sev, const char *fac)
+{
+ struct _heimdal_syslog_data *sd = malloc(sizeof(*sd));
+ int i;
+
+ if(sd == NULL) {
+ krb5_set_error_string (context, "malloc: out of memory");
+ return ENOMEM;
+ }
+ i = find_value(sev, syslogvals);
+ if(i == -1)
+ i = LOG_ERR;
+ sd->priority = i;
+ i = find_value(fac, syslogvals);
+ if(i == -1)
+ i = LOG_AUTH;
+ sd->priority |= i;
+ roken_openlog(facility->program, LOG_PID | LOG_NDELAY, i);
+ return krb5_addlog_func(context, facility, min, max,
+ log_syslog, close_syslog, sd);
+}
+
+struct file_data{
+ const char *filename;
+ const char *mode;
+ FILE *fd;
+ int keep_open;
+};
+
+static void
+log_file(const char *timestr,
+ const char *msg,
+ void *data)
+{
+ struct file_data *f = data;
+ if(f->keep_open == 0)
+ f->fd = fopen(f->filename, f->mode);
+ if(f->fd == NULL)
+ return;
+ fprintf(f->fd, "%s %s\n", timestr, msg);
+ if(f->keep_open == 0)
+ fclose(f->fd);
+}
+
+static void
+close_file(void *data)
+{
+ struct file_data *f = data;
+ if(f->keep_open && f->filename)
+ fclose(f->fd);
+ free(data);
+}
+
+static krb5_error_code
+open_file(krb5_context context, krb5_log_facility *fac, int min, int max,
+ const char *filename, const char *mode, FILE *f, int keep_open)
+{
+ struct file_data *fd = malloc(sizeof(*fd));
+ if(fd == NULL) {
+ krb5_set_error_string (context, "malloc: out of memory");
+ return ENOMEM;
+ }
+ fd->filename = filename;
+ fd->mode = mode;
+ fd->fd = f;
+ fd->keep_open = keep_open;
+
+ return krb5_addlog_func(context, fac, min, max, log_file, close_file, fd);
+}
+
+
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_addlog_dest(krb5_context context, krb5_log_facility *f, const char *orig)
+{
+ krb5_error_code ret = 0;
+ int min = 0, max = -1, n;
+ char c;
+ const char *p = orig;
+
+ n = sscanf(p, "%d%c%d/", &min, &c, &max);
+ if(n == 2){
+ if(c == '/') {
+ if(min < 0){
+ max = -min;
+ min = 0;
+ }else{
+ max = min;
+ }
+ }
+ }
+ if(n){
+ p = strchr(p, '/');
+ if(p == NULL) {
+ krb5_set_error_string (context, "failed to parse \"%s\"", orig);
+ return HEIM_ERR_LOG_PARSE;
+ }
+ p++;
+ }
+ if(strcmp(p, "STDERR") == 0){
+ ret = open_file(context, f, min, max, NULL, NULL, stderr, 1);
+ }else if(strcmp(p, "CONSOLE") == 0){
+ ret = open_file(context, f, min, max, "/dev/console", "w", NULL, 0);
+ }else if(strncmp(p, "FILE:", 4) == 0 && (p[4] == ':' || p[4] == '=')){
+ char *fn;
+ FILE *file = NULL;
+ int keep_open = 0;
+ fn = strdup(p + 5);
+ if(fn == NULL) {
+ krb5_set_error_string (context, "malloc: out of memory");
+ return ENOMEM;
+ }
+ if(p[4] == '='){
+ int i = open(fn, O_WRONLY | O_CREAT |
+ O_TRUNC | O_APPEND, 0666);
+ if(i < 0) {
+ ret = errno;
+ krb5_set_error_string (context, "open(%s): %s", fn,
+ strerror(ret));
+ return ret;
+ }
+ file = fdopen(i, "a");
+ if(file == NULL){
+ ret = errno;
+ close(i);
+ krb5_set_error_string (context, "fdopen(%s): %s", fn,
+ strerror(ret));
+ return ret;
+ }
+ keep_open = 1;
+ }
+ ret = open_file(context, f, min, max, fn, "a", file, keep_open);
+ }else if(strncmp(p, "DEVICE=", 6) == 0){
+ ret = open_file(context, f, min, max, strdup(p + 7), "w", NULL, 0);
+ }else if(strncmp(p, "SYSLOG", 6) == 0 && (p[6] == '\0' || p[6] == ':')){
+ char severity[128] = "";
+ char facility[128] = "";
+ p += 6;
+ if(*p != '\0')
+ p++;
+ if(strsep_copy(&p, ":", severity, sizeof(severity)) != -1)
+ strsep_copy(&p, ":", facility, sizeof(facility));
+ if(*severity == '\0')
+ strlcpy(severity, "ERR", sizeof(severity));
+ if(*facility == '\0')
+ strlcpy(facility, "AUTH", sizeof(facility));
+ ret = open_syslog(context, f, min, max, severity, facility);
+ }else{
+ krb5_set_error_string (context, "unknown log type: %s", p);
+ ret = HEIM_ERR_LOG_PARSE; /* XXX */
+ }
+ return ret;
+}
+
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_openlog(krb5_context context,
+ const char *program,
+ krb5_log_facility **fac)
+{
+ krb5_error_code ret;
+ char **p, **q;
+
+ ret = krb5_initlog(context, program, fac);
+ if(ret)
+ return ret;
+
+ p = krb5_config_get_strings(context, NULL, "logging", program, NULL);
+ if(p == NULL)
+ p = krb5_config_get_strings(context, NULL, "logging", "default", NULL);
+ if(p){
+ for(q = p; *q; q++)
+ ret = krb5_addlog_dest(context, *fac, *q);
+ krb5_config_free_strings(p);
+ }else
+ ret = krb5_addlog_dest(context, *fac, "SYSLOG");
+ return 0;
+}
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_closelog(krb5_context context,
+ krb5_log_facility *fac)
+{
+ int i;
+ for(i = 0; i < fac->len; i++)
+ (*fac->val[i].close_func)(fac->val[i].data);
+ free(fac->val);
+ free(fac->program);
+ fac->val = NULL;
+ fac->len = 0;
+ fac->program = NULL;
+ free(fac);
+ return 0;
+}
+
+#undef __attribute__
+#define __attribute__(X)
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_vlog_msg(krb5_context context,
+ krb5_log_facility *fac,
+ char **reply,
+ int level,
+ const char *fmt,
+ va_list ap)
+ __attribute__((format (printf, 5, 0)))
+{
+
+ char *msg = NULL;
+ const char *actual = NULL;
+ char buf[64];
+ time_t t = 0;
+ int i;
+
+ for(i = 0; fac && i < fac->len; i++)
+ if(fac->val[i].min <= level &&
+ (fac->val[i].max < 0 || fac->val[i].max >= level)) {
+ if(t == 0) {
+ t = time(NULL);
+ krb5_format_time(context, t, buf, sizeof(buf), TRUE);
+ }
+ if(actual == NULL) {
+ vasprintf(&msg, fmt, ap);
+ if(msg == NULL)
+ actual = fmt;
+ else
+ actual = msg;
+ }
+ (*fac->val[i].log_func)(buf, actual, fac->val[i].data);
+ }
+ if(reply == NULL)
+ free(msg);
+ else
+ *reply = msg;
+ return 0;
+}
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_vlog(krb5_context context,
+ krb5_log_facility *fac,
+ int level,
+ const char *fmt,
+ va_list ap)
+ __attribute__((format (printf, 4, 0)))
+{
+ return krb5_vlog_msg(context, fac, NULL, level, fmt, ap);
+}
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_log_msg(krb5_context context,
+ krb5_log_facility *fac,
+ int level,
+ char **reply,
+ const char *fmt,
+ ...)
+ __attribute__((format (printf, 5, 6)))
+{
+ va_list ap;
+ krb5_error_code ret;
+
+ va_start(ap, fmt);
+ ret = krb5_vlog_msg(context, fac, reply, level, fmt, ap);
+ va_end(ap);
+ return ret;
+}
+
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_log(krb5_context context,
+ krb5_log_facility *fac,
+ int level,
+ const char *fmt,
+ ...)
+ __attribute__((format (printf, 4, 5)))
+{
+ va_list ap;
+ krb5_error_code ret;
+
+ va_start(ap, fmt);
+ ret = krb5_vlog(context, fac, level, fmt, ap);
+ va_end(ap);
+ return ret;
+}
+
diff --git a/source4/heimdal/lib/krb5/mcache.c b/source4/heimdal/lib/krb5/mcache.c
new file mode 100644
index 0000000000..0a65d53849
--- /dev/null
+++ b/source4/heimdal/lib/krb5/mcache.c
@@ -0,0 +1,353 @@
+/*
+ * Copyright (c) 1997-2004 Kungliga Tekniska Högskolan
+ * (Royal Institute of Technology, Stockholm, Sweden).
+ * 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"
+
+RCSID("$Id: mcache.c,v 1.19 2004/04/25 19:25:35 joda Exp $");
+
+typedef struct krb5_mcache {
+ char *name;
+ unsigned int refcnt;
+ int dead;
+ krb5_principal primary_principal;
+ struct link {
+ krb5_creds cred;
+ struct link *next;
+ } *creds;
+ struct krb5_mcache *next;
+} krb5_mcache;
+
+static HEIMDAL_MUTEX mcc_mutex = HEIMDAL_MUTEX_INITIALIZER;
+static struct krb5_mcache *mcc_head;
+
+#define MCACHE(X) ((krb5_mcache *)(X)->data.data)
+
+#define MISDEAD(X) ((X)->dead)
+
+#define MCC_CURSOR(C) ((struct link*)(C))
+
+static const char*
+mcc_get_name(krb5_context context,
+ krb5_ccache id)
+{
+ return MCACHE(id)->name;
+}
+
+static krb5_mcache *
+mcc_alloc(const char *name)
+{
+ krb5_mcache *m, *m_c;
+
+ ALLOC(m, 1);
+ if(m == NULL)
+ return NULL;
+ if(name == NULL)
+ asprintf(&m->name, "%p", m);
+ else
+ m->name = strdup(name);
+ if(m->name == NULL) {
+ free(m);
+ return NULL;
+ }
+ /* check for dups first */
+ HEIMDAL_MUTEX_lock(&mcc_mutex);
+ for (m_c = mcc_head; m_c != NULL; m_c = m_c->next)
+ if (strcmp(m->name, m_c->name) == 0)
+ break;
+ if (m_c) {
+ free(m->name);
+ free(m);
+ HEIMDAL_MUTEX_unlock(&mcc_mutex);
+ return NULL;
+ }
+
+ m->dead = 0;
+ m->refcnt = 1;
+ m->primary_principal = NULL;
+ m->creds = NULL;
+ m->next = mcc_head;
+ mcc_head = m;
+ HEIMDAL_MUTEX_unlock(&mcc_mutex);
+ return m;
+}
+
+static krb5_error_code
+mcc_resolve(krb5_context context, krb5_ccache *id, const char *res)
+{
+ krb5_mcache *m;
+
+ HEIMDAL_MUTEX_lock(&mcc_mutex);
+ for (m = mcc_head; m != NULL; m = m->next)
+ if (strcmp(m->name, res) == 0)
+ break;
+ HEIMDAL_MUTEX_unlock(&mcc_mutex);
+
+ if (m != NULL) {
+ m->refcnt++;
+ (*id)->data.data = m;
+ (*id)->data.length = sizeof(*m);
+ return 0;
+ }
+
+ m = mcc_alloc(res);
+ if (m == NULL) {
+ krb5_set_error_string (context, "malloc: out of memory");
+ return KRB5_CC_NOMEM;
+ }
+
+ (*id)->data.data = m;
+ (*id)->data.length = sizeof(*m);
+
+ return 0;
+}
+
+
+static krb5_error_code
+mcc_gen_new(krb5_context context, krb5_ccache *id)
+{
+ krb5_mcache *m;
+
+ m = mcc_alloc(NULL);
+
+ if (m == NULL) {
+ krb5_set_error_string (context, "malloc: out of memory");
+ return KRB5_CC_NOMEM;
+ }
+
+ (*id)->data.data = m;
+ (*id)->data.length = sizeof(*m);
+
+ return 0;
+}
+
+static krb5_error_code
+mcc_initialize(krb5_context context,
+ krb5_ccache id,
+ krb5_principal primary_principal)
+{
+ krb5_mcache *m = MCACHE(id);
+ m->dead = 0;
+ return krb5_copy_principal (context,
+ primary_principal,
+ &m->primary_principal);
+}
+
+static krb5_error_code
+mcc_close(krb5_context context,
+ krb5_ccache id)
+{
+ krb5_mcache *m = MCACHE(id);
+
+ if (--m->refcnt != 0)
+ return 0;
+
+ if (MISDEAD(m)) {
+ free (m->name);
+ krb5_data_free(&id->data);
+ }
+
+ return 0;
+}
+
+static krb5_error_code
+mcc_destroy(krb5_context context,
+ krb5_ccache id)
+{
+ krb5_mcache **n, *m = MCACHE(id);
+ struct link *l;
+
+ if (m->refcnt == 0)
+ krb5_abortx(context, "mcc_destroy: refcnt already 0");
+
+ if (!MISDEAD(m)) {
+ /* if this is an active mcache, remove it from the linked
+ list, and free all data */
+ HEIMDAL_MUTEX_lock(&mcc_mutex);
+ for(n = &mcc_head; n && *n; n = &(*n)->next) {
+ if(m == *n) {
+ *n = m->next;
+ break;
+ }
+ }
+ HEIMDAL_MUTEX_unlock(&mcc_mutex);
+ if (m->primary_principal != NULL) {
+ krb5_free_principal (context, m->primary_principal);
+ m->primary_principal = NULL;
+ }
+ m->dead = 1;
+
+ l = m->creds;
+ while (l != NULL) {
+ struct link *old;
+
+ krb5_free_cred_contents (context, &l->cred);
+ old = l;
+ l = l->next;
+ free (old);
+ }
+ m->creds = NULL;
+ }
+ return 0;
+}
+
+static krb5_error_code
+mcc_store_cred(krb5_context context,
+ krb5_ccache id,
+ krb5_creds *creds)
+{
+ krb5_mcache *m = MCACHE(id);
+ krb5_error_code ret;
+ struct link *l;
+
+ if (MISDEAD(m))
+ return ENOENT;
+
+ l = malloc (sizeof(*l));
+ if (l == NULL) {
+ krb5_set_error_string (context, "malloc: out of memory");
+ return KRB5_CC_NOMEM;
+ }
+ l->next = m->creds;
+ m->creds = l;
+ memset (&l->cred, 0, sizeof(l->cred));
+ ret = krb5_copy_creds_contents (context, creds, &l->cred);
+ if (ret) {
+ m->creds = l->next;
+ free (l);
+ return ret;
+ }
+ return 0;
+}
+
+static krb5_error_code
+mcc_get_principal(krb5_context context,
+ krb5_ccache id,
+ krb5_principal *principal)
+{
+ krb5_mcache *m = MCACHE(id);
+
+ if (MISDEAD(m) || m->primary_principal == NULL)
+ return ENOENT;
+ return krb5_copy_principal (context,
+ m->primary_principal,
+ principal);
+}
+
+static krb5_error_code
+mcc_get_first (krb5_context context,
+ krb5_ccache id,
+ krb5_cc_cursor *cursor)
+{
+ krb5_mcache *m = MCACHE(id);
+
+ if (MISDEAD(m))
+ return ENOENT;
+
+ *cursor = m->creds;
+ return 0;
+}
+
+static krb5_error_code
+mcc_get_next (krb5_context context,
+ krb5_ccache id,
+ krb5_cc_cursor *cursor,
+ krb5_creds *creds)
+{
+ krb5_mcache *m = MCACHE(id);
+ struct link *l;
+
+ if (MISDEAD(m))
+ return ENOENT;
+
+ l = *cursor;
+ if (l != NULL) {
+ *cursor = l->next;
+ return krb5_copy_creds_contents (context,
+ &l->cred,
+ creds);
+ } else
+ return KRB5_CC_END;
+}
+
+static krb5_error_code
+mcc_end_get (krb5_context context,
+ krb5_ccache id,
+ krb5_cc_cursor *cursor)
+{
+ return 0;
+}
+
+static krb5_error_code
+mcc_remove_cred(krb5_context context,
+ krb5_ccache id,
+ krb5_flags which,
+ krb5_creds *mcreds)
+{
+ krb5_mcache *m = MCACHE(id);
+ struct link **q, *p;
+ for(q = &m->creds, p = *q; p; p = *q) {
+ if(krb5_compare_creds(context, which, mcreds, &p->cred)) {
+ *q = p->next;
+ krb5_free_cred_contents(context, &p->cred);
+ free(p);
+ } else
+ q = &p->next;
+ }
+ return 0;
+}
+
+static krb5_error_code
+mcc_set_flags(krb5_context context,
+ krb5_ccache id,
+ krb5_flags flags)
+{
+ return 0; /* XXX */
+}
+
+const krb5_cc_ops krb5_mcc_ops = {
+ "MEMORY",
+ mcc_get_name,
+ mcc_resolve,
+ mcc_gen_new,
+ mcc_initialize,
+ mcc_destroy,
+ mcc_close,
+ mcc_store_cred,
+ NULL, /* mcc_retrieve */
+ mcc_get_principal,
+ mcc_get_first,
+ mcc_get_next,
+ mcc_end_get,
+ mcc_remove_cred,
+ mcc_set_flags
+};
diff --git a/source4/heimdal/lib/krb5/misc.c b/source4/heimdal/lib/krb5/misc.c
new file mode 100644
index 0000000000..baf63f6d52
--- /dev/null
+++ b/source4/heimdal/lib/krb5/misc.c
@@ -0,0 +1,36 @@
+/*
+ * Copyright (c) 1997 Kungliga Tekniska Högskolan
+ * (Royal Institute of Technology, Stockholm, Sweden).
+ * 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"
+
+RCSID("$Id: misc.c,v 1.5 1999/12/02 17:05:11 joda Exp $");
diff --git a/source4/heimdal/lib/krb5/mit_glue.c b/source4/heimdal/lib/krb5/mit_glue.c
new file mode 100755
index 0000000000..b7f06c1582
--- /dev/null
+++ b/source4/heimdal/lib/krb5/mit_glue.c
@@ -0,0 +1,327 @@
+/*
+ * Copyright (c) 2003 Kungliga Tekniska Högskolan
+ * (Royal Institute of Technology, Stockholm, Sweden).
+ * 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"
+RCSID("$Id: mit_glue.c,v 1.7 2005/05/18 04:21:44 lha Exp $");
+
+/*
+ * Glue for MIT API
+ */
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_c_make_checksum(krb5_context context,
+ krb5_cksumtype cksumtype,
+ const krb5_keyblock *key,
+ krb5_keyusage usage,
+ const krb5_data *input,
+ krb5_checksum *cksum)
+{
+ krb5_error_code ret;
+ krb5_crypto crypto;
+
+ ret = krb5_crypto_init(context, key, 0, &crypto);
+ if (ret)
+ return ret;
+
+ ret = krb5_create_checksum(context, crypto, usage, cksumtype,
+ input->data, input->length, cksum);
+ krb5_crypto_destroy(context, crypto);
+
+ return ret ;
+}
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_c_verify_checksum(krb5_context context, const krb5_keyblock *key,
+ krb5_keyusage usage, const krb5_data *data,
+ const krb5_checksum *cksum, krb5_boolean *valid)
+{
+ krb5_error_code ret;
+ krb5_checksum data_cksum;
+
+ *valid = 0;
+
+ ret = krb5_c_make_checksum(context, cksum->cksumtype,
+ key, usage, data, &data_cksum);
+ if (ret)
+ return ret;
+
+ if (data_cksum.cksumtype == cksum->cksumtype
+ && data_cksum.checksum.length == cksum->checksum.length
+ && memcmp(data_cksum.checksum.data, cksum->checksum.data, cksum->checksum.length) == 0)
+ *valid = 1;
+
+ krb5_free_checksum_contents(context, &data_cksum);
+
+ return 0;
+}
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_c_get_checksum(krb5_context context, const krb5_checksum *cksum,
+ krb5_cksumtype *type, krb5_data **data)
+{
+ krb5_error_code ret;
+
+ if (type)
+ *type = cksum->cksumtype;
+ if (data) {
+ *data = malloc(sizeof(**data));
+ if (*data == NULL)
+ return ENOMEM;
+
+ ret = copy_octet_string(&cksum->checksum, *data);
+ if (ret) {
+ free(*data);
+ *data = NULL;
+ return ret;
+ }
+ }
+ return 0;
+}
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_c_set_checksum(krb5_context context, krb5_checksum *cksum,
+ krb5_cksumtype type, const krb5_data *data)
+{
+ cksum->cksumtype = type;
+ return copy_octet_string(data, &cksum->checksum);
+}
+
+void KRB5_LIB_FUNCTION
+krb5_free_checksum (krb5_context context, krb5_checksum *cksum)
+{
+ krb5_checksum_free(context, cksum);
+ free(cksum);
+}
+
+void KRB5_LIB_FUNCTION
+krb5_free_checksum_contents(krb5_context context, krb5_checksum *cksum)
+{
+ krb5_checksum_free(context, cksum);
+ memset(cksum, 0, sizeof(*cksum));
+}
+
+void KRB5_LIB_FUNCTION
+krb5_checksum_free(krb5_context context, krb5_checksum *cksum)
+{
+ free_Checksum(cksum);
+}
+
+krb5_boolean KRB5_LIB_FUNCTION
+krb5_c_valid_enctype (krb5_enctype etype)
+{
+ return krb5_enctype_valid(NULL, etype);
+}
+
+krb5_boolean KRB5_LIB_FUNCTION
+krb5_c_valid_cksumtype(krb5_cksumtype ctype)
+{
+ return krb5_cksumtype_valid(NULL, ctype);
+}
+
+krb5_boolean KRB5_LIB_FUNCTION
+krb5_c_is_coll_proof_cksum(krb5_cksumtype ctype)
+{
+ return krb5_checksum_is_collision_proof(NULL, ctype);
+}
+
+krb5_boolean KRB5_LIB_FUNCTION
+krb5_c_is_keyed_cksum(krb5_cksumtype ctype)
+{
+ return krb5_checksum_is_keyed(NULL, ctype);
+}
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_copy_checksum (krb5_context context,
+ const krb5_checksum *old,
+ krb5_checksum **new)
+{
+ *new = malloc(sizeof(**new));
+ if (*new == NULL)
+ return ENOMEM;
+ return copy_Checksum(old, *new);
+}
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_c_checksum_length (krb5_context context, krb5_cksumtype cksumtype,
+ size_t *length)
+{
+ return krb5_checksumsize(context, cksumtype, length);
+}
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_c_block_size(krb5_context context,
+ krb5_enctype enctype,
+ size_t *blocksize)
+{
+ krb5_error_code ret;
+ krb5_crypto crypto;
+ krb5_keyblock key;
+
+ ret = krb5_generate_random_keyblock(context, enctype, &key);
+ if (ret)
+ return ret;
+
+ ret = krb5_crypto_init(context, &key, 0, &crypto);
+ krb5_free_keyblock_contents(context, &key);
+ if (ret)
+ return ret;
+ ret = krb5_crypto_getblocksize(context, crypto, blocksize);
+ krb5_crypto_destroy(context, crypto);
+
+ return ret;
+}
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_c_decrypt(krb5_context context,
+ const krb5_keyblock key,
+ krb5_keyusage usage,
+ const krb5_data *ivec,
+ krb5_enc_data *input,
+ krb5_data *output)
+{
+ krb5_error_code ret;
+ krb5_crypto crypto;
+
+ ret = krb5_crypto_init(context, &key, input->enctype, &crypto);
+ if (ret)
+ return ret;
+
+ if (ivec) {
+ size_t blocksize;
+
+ ret = krb5_crypto_getblocksize(context, crypto, &blocksize);
+ if (ret) {
+ krb5_crypto_destroy(context, crypto);
+ return ret;
+ }
+
+ if (blocksize > ivec->length) {
+ krb5_crypto_destroy(context, crypto);
+ return KRB5_BAD_MSIZE;
+ }
+ }
+
+ ret = krb5_decrypt_ivec(context, crypto, usage,
+ input->ciphertext.data, input->ciphertext.length,
+ output,
+ ivec ? ivec->data : NULL);
+
+ krb5_crypto_destroy(context, crypto);
+
+ return ret ;
+}
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_c_encrypt(krb5_context context,
+ const krb5_keyblock *key,
+ krb5_keyusage usage,
+ const krb5_data *ivec,
+ const krb5_data *input,
+ krb5_enc_data *output)
+{
+ krb5_error_code ret;
+ krb5_crypto crypto;
+
+ ret = krb5_crypto_init(context, key, 0, &crypto);
+ if (ret)
+ return ret;
+
+ if (ivec) {
+ size_t blocksize;
+
+ ret = krb5_crypto_getblocksize(context, crypto, &blocksize);
+ if (ret) {
+ krb5_crypto_destroy(context, crypto);
+ return ret;
+ }
+
+ if (blocksize > ivec->length) {
+ krb5_crypto_destroy(context, crypto);
+ return KRB5_BAD_MSIZE;
+ }
+ }
+
+ ret = krb5_encrypt_ivec(context, crypto, usage,
+ input->data, input->length,
+ &output->ciphertext,
+ ivec ? ivec->data : NULL);
+ output->kvno = 0;
+ krb5_crypto_getenctype(context, crypto, &output->enctype);
+
+ krb5_crypto_destroy(context, crypto);
+
+ return ret ;
+}
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_c_encrypt_length(krb5_context context,
+ krb5_enctype enctype,
+ size_t inputlen,
+ size_t *length)
+{
+ krb5_error_code ret;
+ krb5_crypto crypto;
+ krb5_keyblock key;
+
+ ret = krb5_generate_random_keyblock(context, enctype, &key);
+ if (ret)
+ return ret;
+
+ ret = krb5_crypto_init(context, &key, 0, &crypto);
+ krb5_free_keyblock_contents(context, &key);
+ if (ret)
+ return ret;
+
+ *length = krb5_get_wrapped_length(context, crypto, inputlen);
+ krb5_crypto_destroy(context, crypto);
+
+ return 0;
+}
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_c_enctype_compare(krb5_context context,
+ krb5_enctype e1,
+ krb5_enctype e2,
+ krb5_boolean *similar)
+{
+ *similar = krb5_enctypes_compatible_keys(context, e1, e2);
+ return 0;
+}
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_c_make_random_key(krb5_context context,
+ krb5_enctype enctype,
+ krb5_keyblock *random_key)
+{
+ return krb5_generate_random_keyblock(context, enctype, random_key);
+}
diff --git a/source4/heimdal/lib/krb5/mk_error.c b/source4/heimdal/lib/krb5/mk_error.c
new file mode 100644
index 0000000000..7a8b1ba06b
--- /dev/null
+++ b/source4/heimdal/lib/krb5/mk_error.c
@@ -0,0 +1,92 @@
+/*
+ * Copyright (c) 1997 - 2003 Kungliga Tekniska Högskolan
+ * (Royal Institute of Technology, Stockholm, Sweden).
+ * 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"
+
+RCSID("$Id: mk_error.c,v 1.22 2005/06/16 21:16:40 lha Exp $");
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_mk_error(krb5_context context,
+ krb5_error_code error_code,
+ const char *e_text,
+ const krb5_data *e_data,
+ const krb5_principal client,
+ const krb5_principal server,
+ time_t *client_time,
+ int *client_usec,
+ krb5_data *reply)
+{
+ KRB_ERROR msg;
+ krb5_timestamp sec;
+ int32_t usec;
+ size_t len;
+ krb5_error_code ret = 0;
+
+ krb5_us_timeofday (context, &sec, &usec);
+
+ memset(&msg, 0, sizeof(msg));
+ msg.pvno = 5;
+ msg.msg_type = krb_error;
+ msg.stime = sec;
+ msg.susec = usec;
+ msg.ctime = client_time;
+ msg.cusec = client_usec;
+ /* Make sure we only send `protocol' error codes */
+ if(error_code < KRB5KDC_ERR_NONE || error_code >= KRB5_ERR_RCSID) {
+ if(e_text == NULL)
+ e_text = krb5_get_err_text(context, error_code);
+ error_code = KRB5KRB_ERR_GENERIC;
+ }
+ msg.error_code = error_code - KRB5KDC_ERR_NONE;
+ if (e_text)
+ msg.e_text = rk_UNCONST(&e_text);
+ if (e_data)
+ msg.e_data = rk_UNCONST(e_data);
+ if(server){
+ msg.realm = server->realm;
+ msg.sname = server->name;
+ }else{
+ msg.realm = "<unspecified realm>";
+ }
+ if(client){
+ msg.crealm = &client->realm;
+ msg.cname = &client->name;
+ }
+
+ ASN1_MALLOC_ENCODE(KRB_ERROR, reply->data, reply->length, &msg, &len, ret);
+ if (ret)
+ return ret;
+ if(reply->length != len)
+ krb5_abortx(context, "internal error in ASN.1 encoder");
+ return 0;
+}
diff --git a/source4/heimdal/lib/krb5/mk_priv.c b/source4/heimdal/lib/krb5/mk_priv.c
new file mode 100644
index 0000000000..56112eea8c
--- /dev/null
+++ b/source4/heimdal/lib/krb5/mk_priv.c
@@ -0,0 +1,153 @@
+/*
+ * Copyright (c) 1997 - 2003 Kungliga Tekniska Högskolan
+ * (Royal Institute of Technology, Stockholm, Sweden).
+ * 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>
+
+RCSID("$Id: mk_priv.c,v 1.34 2004/05/25 21:33:32 lha Exp $");
+
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_mk_priv(krb5_context context,
+ krb5_auth_context auth_context,
+ const krb5_data *userdata,
+ krb5_data *outbuf,
+ krb5_replay_data *outdata)
+{
+ krb5_error_code ret;
+ KRB_PRIV s;
+ EncKrbPrivPart part;
+ u_char *buf = NULL;
+ size_t buf_size;
+ size_t len;
+ krb5_crypto crypto;
+ krb5_keyblock *key;
+ krb5_replay_data rdata;
+
+ if ((auth_context->flags &
+ (KRB5_AUTH_CONTEXT_RET_TIME | KRB5_AUTH_CONTEXT_RET_SEQUENCE)) &&
+ outdata == NULL)
+ return KRB5_RC_REQUIRED; /* XXX better error, MIT returns this */
+
+ if (auth_context->local_subkey)
+ key = auth_context->local_subkey;
+ else if (auth_context->remote_subkey)
+ key = auth_context->remote_subkey;
+ else
+ key = auth_context->keyblock;
+
+ memset(&rdata, 0, sizeof(rdata));
+
+ part.user_data = *userdata;
+
+ krb5_us_timeofday (context, &rdata.timestamp, &rdata.usec);
+
+ if (auth_context->flags & KRB5_AUTH_CONTEXT_DO_TIME) {
+ part.timestamp = &rdata.timestamp;
+ part.usec = &rdata.usec;
+ } else {
+ part.timestamp = NULL;
+ part.usec = NULL;
+ }
+
+ if (auth_context->flags & KRB5_AUTH_CONTEXT_RET_TIME) {
+ outdata->timestamp = rdata.timestamp;
+ outdata->usec = rdata.usec;
+ }
+
+ if (auth_context->flags & KRB5_AUTH_CONTEXT_DO_SEQUENCE) {
+ rdata.seq = auth_context->local_seqnumber;
+ part.seq_number = &rdata.seq;
+ } else
+ part.seq_number = NULL;
+
+ if (auth_context->flags & KRB5_AUTH_CONTEXT_RET_SEQUENCE)
+ outdata->seq = auth_context->local_seqnumber;
+
+ part.s_address = auth_context->local_address;
+ part.r_address = auth_context->remote_address;
+
+ krb5_data_zero (&s.enc_part.cipher);
+
+ ASN1_MALLOC_ENCODE(EncKrbPrivPart, buf, buf_size, &part, &len, ret);
+ if (ret)
+ goto fail;
+ if (buf_size != len)
+ krb5_abortx(context, "internal error in ASN.1 encoder");
+
+ s.pvno = 5;
+ s.msg_type = krb_priv;
+ s.enc_part.etype = key->keytype;
+ s.enc_part.kvno = NULL;
+
+ ret = krb5_crypto_init(context, key, 0, &crypto);
+ if (ret) {
+ free (buf);
+ return ret;
+ }
+ ret = krb5_encrypt (context,
+ crypto,
+ KRB5_KU_KRB_PRIV,
+ buf + buf_size - len,
+ len,
+ &s.enc_part.cipher);
+ krb5_crypto_destroy(context, crypto);
+ if (ret) {
+ free(buf);
+ return ret;
+ }
+ free(buf);
+
+
+ ASN1_MALLOC_ENCODE(KRB_PRIV, buf, buf_size, &s, &len, ret);
+
+ if(ret)
+ goto fail;
+ krb5_data_free (&s.enc_part.cipher);
+
+ ret = krb5_data_copy(outbuf, buf + buf_size - len, len);
+ if (ret) {
+ krb5_set_error_string (context, "malloc: out of memory");
+ free(buf);
+ return ENOMEM;
+ }
+ free (buf);
+ if (auth_context->flags & KRB5_AUTH_CONTEXT_DO_SEQUENCE)
+ auth_context->local_seqnumber =
+ (auth_context->local_seqnumber + 1) & 0xFFFFFFFF;
+ return 0;
+
+ fail:
+ free (buf);
+ krb5_data_free (&s.enc_part.cipher);
+ return ret;
+}
diff --git a/source4/heimdal/lib/krb5/mk_rep.c b/source4/heimdal/lib/krb5/mk_rep.c
new file mode 100644
index 0000000000..90823f9478
--- /dev/null
+++ b/source4/heimdal/lib/krb5/mk_rep.c
@@ -0,0 +1,126 @@
+/*
+ * Copyright (c) 1997 - 2003 Kungliga Tekniska Högskolan
+ * (Royal Institute of Technology, Stockholm, Sweden).
+ * 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>
+
+RCSID("$Id: mk_rep.c,v 1.26 2004/05/25 21:33:51 lha Exp $");
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_mk_rep(krb5_context context,
+ krb5_auth_context auth_context,
+ krb5_data *outbuf)
+{
+ krb5_error_code ret;
+ AP_REP ap;
+ EncAPRepPart body;
+ u_char *buf = NULL;
+ size_t buf_size;
+ size_t len;
+ krb5_crypto crypto;
+
+ ap.pvno = 5;
+ ap.msg_type = krb_ap_rep;
+
+ memset (&body, 0, sizeof(body));
+
+ body.ctime = auth_context->authenticator->ctime;
+ body.cusec = auth_context->authenticator->cusec;
+ if (auth_context->flags & KRB5_AUTH_CONTEXT_USE_SUBKEY) {
+ if (auth_context->local_subkey == NULL) {
+ ret = krb5_auth_con_generatelocalsubkey(context,
+ auth_context,
+ auth_context->keyblock);
+ if(ret) {
+ krb5_set_error_string (context,
+ "krb5_mk_rep: generating subkey");
+ free_EncAPRepPart(&body);
+ return ret;
+ }
+ }
+ ret = krb5_copy_keyblock(context, auth_context->local_subkey,
+ &body.subkey);
+ if (ret) {
+ krb5_set_error_string (context,
+ "krb5_copy_keyblock: out of memory");
+ free_EncAPRepPart(&body);
+ return ENOMEM;
+ }
+ } else
+ body.subkey = NULL;
+ if (auth_context->flags & KRB5_AUTH_CONTEXT_DO_SEQUENCE) {
+ if(auth_context->local_seqnumber == 0)
+ krb5_generate_seq_number (context,
+ auth_context->keyblock,
+ &auth_context->local_seqnumber);
+ ALLOC(body.seq_number, 1);
+ if (body.seq_number == NULL) {
+ krb5_set_error_string (context, "malloc: out of memory");
+ free_EncAPRepPart(&body);
+ return ENOMEM;
+ }
+ *(body.seq_number) = auth_context->local_seqnumber;
+ } else
+ body.seq_number = NULL;
+
+ ap.enc_part.etype = auth_context->keyblock->keytype;
+ ap.enc_part.kvno = NULL;
+
+ ASN1_MALLOC_ENCODE(EncAPRepPart, buf, buf_size, &body, &len, ret);
+ free_EncAPRepPart (&body);
+ if(ret)
+ return ret;
+ if (buf_size != len)
+ krb5_abortx(context, "internal error in ASN.1 encoder");
+ ret = krb5_crypto_init(context, auth_context->keyblock,
+ 0 /* ap.enc_part.etype */, &crypto);
+ if (ret) {
+ free (buf);
+ return ret;
+ }
+ ret = krb5_encrypt (context,
+ crypto,
+ KRB5_KU_AP_REQ_ENC_PART,
+ buf + buf_size - len,
+ len,
+ &ap.enc_part.cipher);
+ krb5_crypto_destroy(context, crypto);
+ free(buf);
+ if (ret)
+ return ret;
+
+ ASN1_MALLOC_ENCODE(AP_REP, outbuf->data, outbuf->length, &ap, &len, ret);
+ if (ret == 0 && outbuf->length != len)
+ krb5_abortx(context, "internal error in ASN.1 encoder");
+ free_AP_REP (&ap);
+ return ret;
+}
diff --git a/source4/heimdal/lib/krb5/mk_req.c b/source4/heimdal/lib/krb5/mk_req.c
new file mode 100644
index 0000000000..adc077e13f
--- /dev/null
+++ b/source4/heimdal/lib/krb5/mk_req.c
@@ -0,0 +1,116 @@
+/*
+ * Copyright (c) 1997 - 2004 Kungliga Tekniska Högskolan
+ * (Royal Institute of Technology, Stockholm, Sweden).
+ * 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>
+
+RCSID("$Id: mk_req.c,v 1.26 2004/05/25 21:34:11 lha Exp $");
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_mk_req_exact(krb5_context context,
+ krb5_auth_context *auth_context,
+ const krb5_flags ap_req_options,
+ const krb5_principal server,
+ krb5_data *in_data,
+ krb5_ccache ccache,
+ krb5_data *outbuf)
+{
+ krb5_error_code ret;
+ krb5_creds this_cred, *cred;
+
+ memset(&this_cred, 0, sizeof(this_cred));
+
+ ret = krb5_cc_get_principal(context, ccache, &this_cred.client);
+
+ if(ret)
+ return ret;
+
+ ret = krb5_copy_principal (context, server, &this_cred.server);
+ if (ret) {
+ krb5_free_cred_contents (context, &this_cred);
+ return ret;
+ }
+
+ this_cred.times.endtime = 0;
+ if (auth_context && *auth_context && (*auth_context)->keytype)
+ this_cred.session.keytype = (*auth_context)->keytype;
+
+ ret = krb5_get_credentials (context, 0, ccache, &this_cred, &cred);
+ krb5_free_cred_contents(context, &this_cred);
+ if (ret)
+ return ret;
+
+ ret = krb5_mk_req_extended (context,
+ auth_context,
+ ap_req_options,
+ in_data,
+ cred,
+ outbuf);
+ krb5_free_creds(context, cred);
+ return ret;
+}
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_mk_req(krb5_context context,
+ krb5_auth_context *auth_context,
+ const krb5_flags ap_req_options,
+ const char *service,
+ const char *hostname,
+ krb5_data *in_data,
+ krb5_ccache ccache,
+ krb5_data *outbuf)
+{
+ krb5_error_code ret;
+ char **realms;
+ char *real_hostname;
+ krb5_principal server;
+
+ ret = krb5_expand_hostname_realms (context, hostname,
+ &real_hostname, &realms);
+ if (ret)
+ return ret;
+
+ ret = krb5_build_principal (context, &server,
+ strlen(*realms),
+ *realms,
+ service,
+ real_hostname,
+ NULL);
+ free (real_hostname);
+ krb5_free_host_realm (context, realms);
+ if (ret)
+ return ret;
+ ret = krb5_mk_req_exact (context, auth_context, ap_req_options,
+ server, in_data, ccache, outbuf);
+ krb5_free_principal (context, server);
+ return ret;
+}
diff --git a/source4/heimdal/lib/krb5/mk_req_ext.c b/source4/heimdal/lib/krb5/mk_req_ext.c
new file mode 100644
index 0000000000..ab83d912ea
--- /dev/null
+++ b/source4/heimdal/lib/krb5/mk_req_ext.c
@@ -0,0 +1,180 @@
+/*
+ * Copyright (c) 1997 - 2002 Kungliga Tekniska Högskolan
+ * (Royal Institute of Technology, Stockholm, Sweden).
+ * 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>
+
+RCSID("$Id: mk_req_ext.c,v 1.30 2005/01/05 06:31:01 lukeh Exp $");
+
+krb5_error_code
+_krb5_mk_req_internal(krb5_context context,
+ krb5_auth_context *auth_context,
+ const krb5_flags ap_req_options,
+ krb5_data *in_data,
+ krb5_creds *in_creds,
+ krb5_data *outbuf,
+ krb5_key_usage checksum_usage,
+ krb5_key_usage encrypt_usage)
+{
+ krb5_error_code ret;
+ krb5_data authenticator;
+ Checksum c;
+ Checksum *c_opt;
+ krb5_auth_context ac;
+
+ if(auth_context) {
+ if(*auth_context == NULL)
+ ret = krb5_auth_con_init(context, auth_context);
+ else
+ ret = 0;
+ ac = *auth_context;
+ } else
+ ret = krb5_auth_con_init(context, &ac);
+ if(ret)
+ return ret;
+
+ if(ac->local_subkey == NULL && (ap_req_options & AP_OPTS_USE_SUBKEY)) {
+ ret = krb5_auth_con_generatelocalsubkey(context, ac, &in_creds->session);
+ if(ret)
+ return ret;
+ }
+
+#if 0
+ {
+ /* This is somewhat bogus since we're possibly overwriting a
+ value specified by the user, but it's the easiest way to make
+ the code use a compatible enctype */
+ Ticket ticket;
+ krb5_keytype ticket_keytype;
+
+ ret = decode_Ticket(in_creds->ticket.data,
+ in_creds->ticket.length,
+ &ticket,
+ NULL);
+ krb5_enctype_to_keytype (context,
+ ticket.enc_part.etype,
+ &ticket_keytype);
+
+ if (ticket_keytype == in_creds->session.keytype)
+ krb5_auth_setenctype(context,
+ ac,
+ ticket.enc_part.etype);
+ free_Ticket(&ticket);
+ }
+#endif
+
+ krb5_free_keyblock(context, ac->keyblock);
+ krb5_copy_keyblock(context, &in_creds->session, &ac->keyblock);
+
+ /* it's unclear what type of checksum we can use. try the best one, except:
+ * a) if it's configured differently for the current realm, or
+ * b) if the session key is des-cbc-crc
+ */
+
+ if (in_data) {
+ if(ac->keyblock->keytype == ETYPE_DES_CBC_CRC) {
+ /* this is to make DCE secd (and older MIT kdcs?) happy */
+ ret = krb5_create_checksum(context,
+ NULL,
+ 0,
+ CKSUMTYPE_RSA_MD4,
+ in_data->data,
+ in_data->length,
+ &c);
+ } else if(ac->keyblock->keytype == ETYPE_ARCFOUR_HMAC_MD5 ||
+ ac->keyblock->keytype == ETYPE_ARCFOUR_HMAC_MD5_56) {
+ /* this is to make MS kdc happy */
+ ret = krb5_create_checksum(context,
+ NULL,
+ 0,
+ CKSUMTYPE_RSA_MD5,
+ in_data->data,
+ in_data->length,
+ &c);
+ } else {
+ krb5_crypto crypto;
+
+ ret = krb5_crypto_init(context, ac->keyblock, 0, &crypto);
+ if (ret)
+ return ret;
+ ret = krb5_create_checksum(context,
+ crypto,
+ checksum_usage,
+ 0,
+ in_data->data,
+ in_data->length,
+ &c);
+
+ krb5_crypto_destroy(context, crypto);
+ }
+ c_opt = &c;
+ } else {
+ c_opt = NULL;
+ }
+
+ ret = krb5_build_authenticator (context,
+ ac,
+ ac->keyblock->keytype,
+ in_creds,
+ c_opt,
+ NULL,
+ &authenticator,
+ encrypt_usage);
+ if (c_opt)
+ free_Checksum (c_opt);
+ if (ret)
+ return ret;
+
+ ret = krb5_build_ap_req (context, ac->keyblock->keytype,
+ in_creds, ap_req_options, authenticator, outbuf);
+ if(auth_context == NULL)
+ krb5_auth_con_free(context, ac);
+ return ret;
+}
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_mk_req_extended(krb5_context context,
+ krb5_auth_context *auth_context,
+ const krb5_flags ap_req_options,
+ krb5_data *in_data,
+ krb5_creds *in_creds,
+ krb5_data *outbuf)
+{
+ return _krb5_mk_req_internal (context,
+ auth_context,
+ ap_req_options,
+ in_data,
+ in_creds,
+ outbuf,
+ KRB5_KU_AP_REQ_AUTH_CKSUM,
+ KRB5_KU_AP_REQ_AUTH);
+}
diff --git a/source4/heimdal/lib/krb5/n-fold.c b/source4/heimdal/lib/krb5/n-fold.c
new file mode 100644
index 0000000000..691e95eb86
--- /dev/null
+++ b/source4/heimdal/lib/krb5/n-fold.c
@@ -0,0 +1,126 @@
+/*
+ * Copyright (c) 1999 Kungliga Tekniska Högskolan
+ * (Royal Institute of Technology, Stockholm, Sweden).
+ * 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 KTH 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 KTH AND ITS 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 KTH OR ITS 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"
+
+RCSID("$Id: n-fold.c,v 1.7 2004/05/25 21:35:31 lha Exp $");
+
+static void
+rr13(unsigned char *buf, size_t len)
+{
+ unsigned char *tmp;
+ int bytes = (len + 7) / 8;
+ int i;
+ if(len == 0)
+ return;
+ {
+ const int bits = 13 % len;
+ const int lbit = len % 8;
+
+ tmp = malloc(bytes);
+ memcpy(tmp, buf, bytes);
+ if(lbit) {
+ /* pad final byte with inital bits */
+ tmp[bytes - 1] &= 0xff << (8 - lbit);
+ for(i = lbit; i < 8; i += len)
+ tmp[bytes - 1] |= buf[0] >> i;
+ }
+ for(i = 0; i < bytes; i++) {
+ int bb;
+ int b1, s1, b2, s2;
+ /* calculate first bit position of this byte */
+ bb = 8 * i - bits;
+ while(bb < 0)
+ bb += len;
+ /* byte offset and shift count */
+ b1 = bb / 8;
+ s1 = bb % 8;
+
+ if(bb + 8 > bytes * 8)
+ /* watch for wraparound */
+ s2 = (len + 8 - s1) % 8;
+ else
+ s2 = 8 - s1;
+ b2 = (b1 + 1) % bytes;
+ buf[i] = (tmp[b1] << s1) | (tmp[b2] >> s2);
+ }
+ free(tmp);
+ }
+}
+
+/* Add `b' to `a', both beeing one's complement numbers. */
+static void
+add1(unsigned char *a, unsigned char *b, size_t len)
+{
+ int i;
+ int carry = 0;
+ for(i = len - 1; i >= 0; i--){
+ int x = a[i] + b[i] + carry;
+ carry = x > 0xff;
+ a[i] = x & 0xff;
+ }
+ for(i = len - 1; carry && i >= 0; i--){
+ int x = a[i] + carry;
+ carry = x > 0xff;
+ a[i] = x & 0xff;
+ }
+}
+
+void KRB5_LIB_FUNCTION
+_krb5_n_fold(const void *str, size_t len, void *key, size_t size)
+{
+ /* if len < size we need at most N * len bytes, ie < 2 * size;
+ if len > size we need at most 2 * len */
+ size_t maxlen = 2 * max(size, len);
+ size_t l = 0;
+ unsigned char *tmp = malloc(maxlen);
+ unsigned char *buf = malloc(len);
+
+ memcpy(buf, str, len);
+ memset(key, 0, size);
+ do {
+ memcpy(tmp + l, buf, len);
+ l += len;
+ rr13(buf, len * 8);
+ while(l >= size) {
+ add1(key, tmp, size);
+ l -= size;
+ if(l == 0)
+ break;
+ memmove(tmp, tmp + size, l);
+ }
+ } while(l != 0);
+ memset(buf, 0, len);
+ free(buf);
+ memset(tmp, 0, maxlen);
+ free(tmp);
+}
diff --git a/source4/heimdal/lib/krb5/padata.c b/source4/heimdal/lib/krb5/padata.c
new file mode 100644
index 0000000000..d5c3f422a7
--- /dev/null
+++ b/source4/heimdal/lib/krb5/padata.c
@@ -0,0 +1,66 @@
+/*
+ * Copyright (c) 1997 Kungliga Tekniska Högskolan
+ * (Royal Institute of Technology, Stockholm, Sweden).
+ * 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"
+
+RCSID("$Id: padata.c,v 1.5 2005/06/17 04:28:35 lha Exp $");
+
+PA_DATA *
+krb5_find_padata(PA_DATA *val, unsigned len, int type, int *idx)
+{
+ for(; *idx < len; (*idx)++)
+ if(val[*idx].padata_type == type)
+ return val + *idx;
+ return NULL;
+}
+
+int KRB5_LIB_FUNCTION
+krb5_padata_add(krb5_context context, METHOD_DATA *md,
+ int type, void *buf, size_t len)
+{
+ PA_DATA *pa;
+
+ pa = realloc (md->val, (md->len + 1) * sizeof(*md->val));
+ if (pa == NULL) {
+ krb5_set_error_string(context, "malloc: out of memory");
+ return ENOMEM;
+ }
+ md->val = pa;
+
+ pa[md->len].padata_type = type;
+ pa[md->len].padata_value.length = len;
+ pa[md->len].padata_value.data = buf;
+ md->len++;
+
+ return 0;
+}
diff --git a/source4/heimdal/lib/krb5/pkinit.c b/source4/heimdal/lib/krb5/pkinit.c
new file mode 100755
index 0000000000..84db4fe544
--- /dev/null
+++ b/source4/heimdal/lib/krb5/pkinit.c
@@ -0,0 +1,2583 @@
+/*
+ * Copyright (c) 2003 - 2005 Kungliga Tekniska Högskolan
+ * (Royal Institute of Technology, Stockholm, Sweden).
+ * 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"
+
+RCSID("$Id: pkinit.c,v 1.55 2005/05/19 18:49:05 lha Exp $");
+
+#ifdef PKINIT
+
+#include <openssl/evp.h>
+#include <openssl/x509.h>
+#include <openssl/pem.h>
+#include <openssl/err.h>
+#include <openssl/dh.h>
+#include <openssl/bn.h>
+#include <openssl/engine.h>
+#include <openssl/ui.h>
+
+#ifdef HAVE_DIRENT_H
+#include <dirent.h>
+#endif
+
+#include "heim_asn1.h"
+#include "rfc2459_asn1.h"
+#include "cms_asn1.h"
+#include "pkinit_asn1.h"
+
+enum {
+ COMPAT_WIN2K = 1,
+ COMPAT_19 = 2,
+ COMPAT_25 = 3
+};
+
+
+
+#define OPENSSL_ASN1_MALLOC_ENCODE(T, B, BL, S, R) \
+{ \
+ unsigned char *p; \
+ (BL) = i2d_##T((S), NULL); \
+ if ((BL) <= 0) { \
+ (R) = EINVAL; \
+ } else { \
+ (B) = malloc((BL)); \
+ if ((B) == NULL) { \
+ (R) = ENOMEM; \
+ } else { \
+ p = (B); \
+ (R) = 0; \
+ (BL) = i2d_##T((S), &p); \
+ if ((BL) <= 0) { \
+ free((B)); \
+ (R) = ASN1_OVERRUN; \
+ } \
+ } \
+ } \
+}
+
+/* ENGING_load_private_key requires a UI_METHOD and data
+ * if to be usable from PAM
+ */
+
+struct krb5_ui_data {
+ krb5_context context;
+ krb5_prompter_fct prompter;
+ void * prompter_data;
+};
+
+struct krb5_pk_identity {
+ EVP_PKEY *private_key;
+ STACK_OF(X509) *cert;
+ STACK_OF(X509) *trusted_certs;
+ STACK_OF(X509_CRL) *crls;
+ ENGINE *engine;
+};
+
+struct krb5_pk_cert {
+ X509 *cert;
+};
+
+struct krb5_pk_init_ctx_data {
+ struct krb5_pk_identity *id;
+ DH *dh;
+};
+
+
+void KRB5_LIB_FUNCTION
+_krb5_pk_cert_free(struct krb5_pk_cert *cert)
+{
+ if (cert->cert)
+ X509_free(cert->cert);
+ free(cert);
+}
+
+static krb5_error_code
+BN_to_integer(krb5_context context, BIGNUM *bn, heim_integer *integer)
+{
+ integer->length = BN_num_bytes(bn);
+ integer->data = malloc(integer->length);
+ if (integer->data == NULL) {
+ krb5_clear_error_string(context);
+ return ENOMEM;
+ }
+ BN_bn2bin(bn, integer->data);
+ integer->negative = bn->neg;
+ return 0;
+}
+
+/*
+ * UI ex_data has the callback_data as passed to Engine. This is far
+ * from being complete, we will only process one prompt
+ */
+
+static int
+krb5_ui_method_read_string(UI *ui, UI_STRING *uis)
+{
+ char *buffer;
+ size_t length;
+ krb5_error_code ret;
+ krb5_prompt prompt;
+ krb5_data password_data;
+ struct krb5_ui_data *ui_data;
+
+ ui_data = (struct krb5_ui_data *)UI_get_app_data(ui);
+
+ switch (UI_get_string_type(uis)) {
+ case UIT_INFO:
+ case UIT_ERROR:
+ /* looks like the RedHat pam_prompter might handle
+ * INFO and ERROR, Will see what happens */
+ case UIT_VERIFY:
+ case UIT_PROMPT:
+ length = UI_get_result_maxsize(uis);
+ buffer = malloc(length);
+ if (buffer == NULL) {
+ krb5_set_error_string(ui_data->context, "malloc: out of memory");
+ return 0;
+ }
+ password_data.data = buffer;
+ password_data.length = length;
+
+ prompt.prompt = UI_get0_output_string(uis);
+ prompt.hidden = !(UI_get_input_flags(uis) & UI_INPUT_FLAG_ECHO);
+ prompt.reply = &password_data;
+ prompt.type = KRB5_PROMPT_TYPE_PASSWORD;
+
+ ret = (*ui_data->prompter)(ui_data->context,
+ ui_data->prompter_data,
+ NULL, NULL, 1, &prompt);
+ if (ret == 0) {
+ buffer[length - 1] = '\0';
+ UI_set_result(ui, uis, password_data.data);
+
+ /*
+ * RedHat pam_krb5 pam_prompter does a strdup but others
+ * may copy into buffer. XXX should we just leak the
+ * memory instead ?
+ */
+
+ if (buffer != password_data.data)
+ free(password_data.data);
+ memset (buffer, 0, length);
+ free(buffer);
+ return 1;
+ }
+ memset (buffer, 0, length);
+ free(buffer);
+ break;
+ case UIT_NONE:
+ case UIT_BOOLEAN:
+ /* XXX for now do not handle */
+ break;
+
+ }
+ return 0;
+}
+
+
+static krb5_error_code
+set_digest_alg(DigestAlgorithmIdentifier *id,
+ const heim_oid *oid,
+ void *param, size_t length)
+{
+ krb5_error_code ret;
+ if (param) {
+ id->parameters = malloc(sizeof(*id->parameters));
+ if (id->parameters == NULL)
+ return ENOMEM;
+ id->parameters->data = malloc(length);
+ if (id->parameters->data == NULL) {
+ free(id->parameters);
+ id->parameters = NULL;
+ return ENOMEM;
+ }
+ memcpy(id->parameters->data, param, length);
+ id->parameters->length = length;
+ } else
+ id->parameters = NULL;
+ ret = copy_oid(oid, &id->algorithm);
+ if (ret) {
+ if (id->parameters) {
+ free(id->parameters->data);
+ free(id->parameters);
+ id->parameters = NULL;
+ }
+ return ret;
+ }
+ return 0;
+}
+
+krb5_error_code KRB5_LIB_FUNCTION
+_krb5_pk_create_sign(krb5_context context,
+ const heim_oid *eContentType,
+ krb5_data *eContent,
+ struct krb5_pk_identity *id,
+ krb5_data *sd_data)
+{
+ SignerInfo *signer_info;
+ X509 *user_cert;
+ heim_integer *serial;
+ krb5_error_code ret;
+ krb5_data buf;
+ SignedData sd;
+ EVP_MD_CTX md;
+ int len, i;
+ size_t size;
+
+ X509_NAME *issuer_name;
+
+ memset(&sd, 0, sizeof(sd));
+
+ if (id == NULL)
+ return HEIM_PKINIT_NO_CERTIFICATE;
+ if (id->cert == NULL)
+ return HEIM_PKINIT_NO_CERTIFICATE;
+ if (id->private_key == NULL)
+ return HEIM_PKINIT_NO_PRIVATE_KEY;
+
+ if (sk_X509_num(id->cert) == 0)
+ return HEIM_PKINIT_NO_CERTIFICATE;
+
+ sd.version = 3;
+
+ sd.digestAlgorithms.len = 0;
+ sd.digestAlgorithms.val = NULL;
+ copy_oid(eContentType, &sd.encapContentInfo.eContentType);
+ ALLOC(sd.encapContentInfo.eContent, 1);
+ if (sd.encapContentInfo.eContent == NULL) {
+ krb5_clear_error_string(context);
+ ret = ENOMEM;
+ goto out;
+ }
+
+ ret = krb5_data_copy(&buf, eContent->data, eContent->length);
+ if (ret) {
+ krb5_clear_error_string(context);
+ ret = ENOMEM;
+ goto out;
+ }
+
+ sd.encapContentInfo.eContent->data = buf.data;
+ sd.encapContentInfo.eContent->length = buf.length;
+
+ ALLOC_SEQ(&sd.signerInfos, 1);
+ if (sd.signerInfos.val == NULL) {
+ krb5_set_error_string(context, "malloc: out of memory");
+ ret = ENOMEM;
+ goto out;
+ }
+
+ signer_info = &sd.signerInfos.val[0];
+
+ user_cert = sk_X509_value(id->cert, 0);
+ if (user_cert == NULL) {
+ krb5_set_error_string(context, "pkinit: no user certificate");
+ ret = HEIM_PKINIT_NO_CERTIFICATE;
+ goto out;
+ }
+
+ signer_info->version = 1;
+
+ issuer_name = X509_get_issuer_name(user_cert);
+
+ OPENSSL_ASN1_MALLOC_ENCODE(X509_NAME,
+ buf.data,
+ buf.length,
+ issuer_name,
+ ret);
+ if (ret) {
+ krb5_set_error_string(context, "pkinit: failed encoding name");
+ goto out;
+ }
+ ret = decode_Name(buf.data, buf.length,
+ &signer_info->sid.u.issuerAndSerialNumber.issuer,
+ NULL);
+ free(buf.data);
+ if (ret) {
+ krb5_set_error_string(context, "pkinit: failed to parse Name");
+ goto out;
+ }
+ signer_info->sid.element = choice_CMSIdentifier_issuerAndSerialNumber;
+
+ serial = &signer_info->sid.u.issuerAndSerialNumber.serialNumber;
+ {
+ ASN1_INTEGER *isn = X509_get_serialNumber(user_cert);
+ BIGNUM *bn = ASN1_INTEGER_to_BN(isn, NULL);
+ if (bn == NULL) {
+ ret = ENOMEM;
+ krb5_set_error_string(context, "pkinit: failed allocating "
+ "serial number");
+ goto out;
+ }
+ ret = BN_to_integer(context, bn, serial);
+ BN_free(bn);
+ if (ret) {
+ krb5_set_error_string(context, "pkinit: failed encoding "
+ "serial number");
+ goto out;
+ }
+ }
+
+ ret = set_digest_alg(&signer_info->digestAlgorithm,
+ oid_id_secsig_sha_1(), "\x05\x00", 2);
+ if (ret) {
+ krb5_set_error_string(context, "malloc: out of memory");
+ goto out;
+ }
+
+ signer_info->signedAttrs = NULL;
+ signer_info->unsignedAttrs = NULL;
+
+ copy_oid(oid_id_pkcs1_rsaEncryption(),
+ &signer_info->signatureAlgorithm.algorithm);
+ signer_info->signatureAlgorithm.parameters = NULL;
+
+ buf.data = malloc(EVP_PKEY_size(id->private_key));
+ if (buf.data == NULL) {
+ krb5_set_error_string(context, "malloc: out of memory");
+ ret = ENOMEM;
+ goto out;
+ }
+
+ EVP_SignInit(&md, EVP_sha1());
+ EVP_SignUpdate(&md,
+ sd.encapContentInfo.eContent->data,
+ sd.encapContentInfo.eContent->length);
+ ret = EVP_SignFinal(&md, buf.data, &len, id->private_key);
+ if (ret != 1) {
+ free(buf.data);
+ krb5_set_error_string(context, "PKINIT: failed to sign with "
+ "private key: %s",
+ ERR_error_string(ERR_get_error(), NULL));
+ ret = EINVAL;
+ goto out;
+ }
+
+ signer_info->signature.data = buf.data;
+ signer_info->signature.length = len;
+
+ ALLOC_SEQ(&sd.digestAlgorithms, 1);
+ if (sd.digestAlgorithms.val == NULL) {
+ krb5_clear_error_string(context);
+ ret = ENOMEM;
+ goto out;
+ }
+
+ ret = set_digest_alg(&sd.digestAlgorithms.val[0],
+ oid_id_secsig_sha_1(), "\x05\x00", 2);
+ if (ret) {
+ krb5_set_error_string(context, "malloc: out of memory");
+ goto out;
+ }
+
+ ALLOC(sd.certificates, 1);
+ if (sd.certificates == NULL) {
+ krb5_clear_error_string(context);
+ ret = ENOMEM;
+ goto out;
+ }
+
+ sd.certificates->data = NULL;
+ sd.certificates->length = 0;
+
+ for (i = 0; i < sk_X509_num(id->cert); i++) {
+ void *data;
+
+ OPENSSL_ASN1_MALLOC_ENCODE(X509,
+ buf.data,
+ buf.length,
+ sk_X509_value(id->cert, i),
+ ret);
+ if (ret) {
+ krb5_clear_error_string(context);
+ goto out;
+ }
+ data = realloc(sd.certificates->data,
+ sd.certificates->length + buf.length);
+ if (data == NULL) {
+ free(buf.data);
+ krb5_clear_error_string(context);
+ ret = ENOMEM;
+ goto out;
+ }
+ memcpy(((char *)data) + sd.certificates->length,
+ buf.data, buf.length);
+ sd.certificates->length += buf.length;
+ sd.certificates->data = data;
+ free(buf.data);
+ }
+
+ ASN1_MALLOC_ENCODE(SignedData, sd_data->data, sd_data->length,
+ &sd, &size, ret);
+ if (ret) {
+ krb5_set_error_string(context, "SignedData failed %d", ret);
+ goto out;
+ }
+ if (sd_data->length != size)
+ krb5_abortx(context, "internal ASN1 encoder error");
+
+ out:
+ free_SignedData(&sd);
+
+ return ret;
+}
+
+static krb5_error_code
+build_auth_pack_win2k(krb5_context context,
+ unsigned nonce,
+ const KDC_REQ_BODY *body,
+ AuthPack_Win2k *a)
+{
+ krb5_error_code ret;
+ krb5_timestamp sec;
+ int32_t usec;
+
+ /* fill in PKAuthenticator */
+ ret = copy_PrincipalName(body->sname, &a->pkAuthenticator.kdcName);
+ if (ret)
+ return ret;
+ ret = copy_Realm(&body->realm, &a->pkAuthenticator.kdcRealm);
+ if (ret)
+ return ret;
+
+ krb5_us_timeofday(context, &sec, &usec);
+ a->pkAuthenticator.ctime = sec;
+ a->pkAuthenticator.cusec = usec;
+ a->pkAuthenticator.nonce = nonce;
+
+ return 0;
+}
+
+static krb5_error_code
+build_auth_pack_19(krb5_context context,
+ unsigned nonce,
+ const KDC_REQ_BODY *body,
+ AuthPack_19 *a)
+{
+ size_t buf_size, len;
+ krb5_cksumtype cksum;
+ krb5_error_code ret;
+ void *buf;
+ krb5_timestamp sec;
+ int32_t usec;
+
+ krb5_clear_error_string(context);
+
+ /* XXX some PACKETCABLE needs implemetations need md5 */
+ cksum = CKSUMTYPE_RSA_MD5;
+
+ krb5_us_timeofday(context, &sec, &usec);
+ a->pkAuthenticator.ctime = sec;
+ a->pkAuthenticator.nonce = nonce;
+
+ ASN1_MALLOC_ENCODE(KDC_REQ_BODY, buf, buf_size, body, &len, ret);
+ if (ret)
+ return ret;
+ if (buf_size != len)
+ krb5_abortx(context, "internal error in ASN.1 encoder");
+
+ ret = krb5_create_checksum(context,
+ NULL,
+ 0,
+ cksum,
+ buf,
+ len,
+ &a->pkAuthenticator.paChecksum);
+ free(buf);
+
+ return ret;
+}
+
+static krb5_error_code
+build_auth_pack(krb5_context context,
+ unsigned nonce,
+ DH *dh,
+ const KDC_REQ_BODY *body,
+ AuthPack *a)
+{
+ size_t buf_size, len;
+ krb5_error_code ret;
+ void *buf;
+ krb5_timestamp sec;
+ int32_t usec;
+ Checksum checksum;
+
+ krb5_clear_error_string(context);
+
+ memset(&checksum, 0, sizeof(checksum));
+
+ krb5_us_timeofday(context, &sec, &usec);
+ a->pkAuthenticator.ctime = sec;
+ a->pkAuthenticator.nonce = nonce;
+
+ ASN1_MALLOC_ENCODE(KDC_REQ_BODY, buf, buf_size, body, &len, ret);
+ if (ret)
+ return ret;
+ if (buf_size != len)
+ krb5_abortx(context, "internal error in ASN.1 encoder");
+
+ ret = krb5_create_checksum(context,
+ NULL,
+ 0,
+ CKSUMTYPE_SHA1,
+ buf,
+ len,
+ &checksum);
+ free(buf);
+ if (ret == 0) {
+ ret = krb5_data_copy(&a->pkAuthenticator.paChecksum,
+ checksum.checksum.data, checksum.checksum.length);
+ free_Checksum(&checksum);
+ }
+
+ if (ret == 0 && dh) {
+ DomainParameters dp;
+ heim_integer dh_pub_key;
+ krb5_data buf;
+ size_t size;
+
+ ALLOC(a->clientPublicValue, 1);
+ if (a->clientPublicValue == NULL)
+ return ENOMEM;
+ ret = copy_oid(oid_id_dhpublicnumber(),
+ &a->clientPublicValue->algorithm.algorithm);
+ if (ret)
+ return ret;
+
+ memset(&dp, 0, sizeof(dp));
+
+ ret = BN_to_integer(context, dh->p, &dp.p);
+ if (ret) {
+ free_DomainParameters(&dp);
+ return ret;
+ }
+ ret = BN_to_integer(context, dh->g, &dp.g);
+ if (ret) {
+ free_DomainParameters(&dp);
+ return ret;
+ }
+ ret = BN_to_integer(context, dh->q, &dp.q);
+ if (ret) {
+ free_DomainParameters(&dp);
+ return ret;
+ }
+ dp.j = NULL;
+ dp.validationParms = NULL;
+
+ a->clientPublicValue->algorithm.parameters =
+ malloc(sizeof(*a->clientPublicValue->algorithm.parameters));
+ if (a->clientPublicValue->algorithm.parameters == NULL) {
+ free_DomainParameters(&dp);
+ return ret;
+ }
+
+ ASN1_MALLOC_ENCODE(DomainParameters,
+ a->clientPublicValue->algorithm.parameters->data,
+ a->clientPublicValue->algorithm.parameters->length,
+ &dp, &size, ret);
+ free_DomainParameters(&dp);
+ if (ret)
+ return ret;
+ if (size != a->clientPublicValue->algorithm.parameters->length)
+ krb5_abortx(context, "Internal ASN1 encoder error");
+
+ ret = BN_to_integer(context, dh->pub_key, &dh_pub_key);
+ if (ret)
+ return ret;
+
+ buf.length = length_heim_integer(&dh_pub_key);
+ buf.data = malloc(buf.length);
+ if (buf.data == NULL) {
+ free_heim_integer(&dh_pub_key);
+ krb5_set_error_string(context, "malloc: out of memory");
+ return ret;
+ }
+ ret = der_put_heim_integer((char *)buf.data + buf.length - 1,
+ buf.length, &dh_pub_key, &size);
+ free_heim_integer(&dh_pub_key);
+ if (ret) {
+ free(buf.data);
+ return ret;
+ }
+ if (size != buf.length)
+ krb5_abortx(context, "asn1 internal error");
+
+ a->clientPublicValue->subjectPublicKey.length = buf.length * 8;
+ a->clientPublicValue->subjectPublicKey.data = buf.data;
+ }
+
+ return ret;
+}
+
+krb5_error_code KRB5_LIB_FUNCTION
+_krb5_pk_mk_ContentInfo(krb5_context context,
+ const krb5_data *buf,
+ const heim_oid *oid,
+ struct ContentInfo *content_info)
+{
+ krb5_error_code ret;
+
+ ret = copy_oid(oid, &content_info->contentType);
+ if (ret)
+ return ret;
+ ALLOC(content_info->content, 1);
+ if (content_info->content == NULL)
+ return ENOMEM;
+ content_info->content->data = malloc(buf->length);
+ if (content_info->content->data == NULL)
+ return ENOMEM;
+ memcpy(content_info->content->data, buf->data, buf->length);
+ content_info->content->length = buf->length;
+ return 0;
+}
+
+static krb5_error_code
+pk_mk_padata(krb5_context context,
+ int compat,
+ krb5_pk_init_ctx ctx,
+ const KDC_REQ_BODY *req_body,
+ unsigned nonce,
+ METHOD_DATA *md)
+{
+ struct ContentInfo content_info;
+ krb5_error_code ret;
+ const heim_oid *oid;
+ PA_PK_AS_REQ req;
+ size_t size;
+ krb5_data buf, sd_buf;
+ int pa_type;
+
+ krb5_data_zero(&buf);
+ krb5_data_zero(&sd_buf);
+ memset(&req, 0, sizeof(req));
+ memset(&content_info, 0, sizeof(content_info));
+
+ if (compat == COMPAT_WIN2K) {
+ AuthPack_Win2k ap;
+
+ memset(&ap, 0, sizeof(ap));
+
+ ret = build_auth_pack_win2k(context, nonce, req_body, &ap);
+ if (ret) {
+ free_AuthPack_Win2k(&ap);
+ goto out;
+ }
+
+ ASN1_MALLOC_ENCODE(AuthPack_Win2k, buf.data, buf.length,
+ &ap, &size, ret);
+ free_AuthPack_Win2k(&ap);
+ if (ret) {
+ krb5_set_error_string(context, "AuthPack_Win2k: %d", ret);
+ goto out;
+ }
+ if (buf.length != size)
+ krb5_abortx(context, "internal ASN1 encoder error");
+
+ oid = oid_id_pkcs7_data();
+ } else if (compat == COMPAT_19) {
+ AuthPack_19 ap;
+
+ memset(&ap, 0, sizeof(ap));
+
+ ret = build_auth_pack_19(context, nonce, req_body, &ap);
+ if (ret) {
+ free_AuthPack_19(&ap);
+ goto out;
+ }
+
+ ASN1_MALLOC_ENCODE(AuthPack_19, buf.data, buf.length, &ap, &size, ret);
+ free_AuthPack_19(&ap);
+ if (ret) {
+ krb5_set_error_string(context, "AuthPack_19: %d", ret);
+ goto out;
+ }
+ if (buf.length != size)
+ krb5_abortx(context, "internal ASN1 encoder error");
+
+ oid = oid_id_pkauthdata();
+ } else if (compat == COMPAT_25) {
+ AuthPack ap;
+
+ memset(&ap, 0, sizeof(ap));
+
+ ret = build_auth_pack(context, nonce, ctx->dh, req_body, &ap);
+ if (ret) {
+ free_AuthPack(&ap);
+ goto out;
+ }
+
+ ASN1_MALLOC_ENCODE(AuthPack, buf.data, buf.length, &ap, &size, ret);
+ free_AuthPack(&ap);
+ if (ret) {
+ krb5_set_error_string(context, "AuthPack: %d", ret);
+ goto out;
+ }
+ if (buf.length != size)
+ krb5_abortx(context, "internal ASN1 encoder error");
+
+ oid = oid_id_pkauthdata();
+ } else
+ krb5_abortx(context, "internal pkinit error");
+
+ ret = _krb5_pk_create_sign(context,
+ oid,
+ &buf,
+ ctx->id,
+ &sd_buf);
+ krb5_data_free(&buf);
+ if (ret)
+ goto out;
+
+ ret = _krb5_pk_mk_ContentInfo(context, &sd_buf, oid_id_pkcs7_signedData(),
+ &content_info);
+ krb5_data_free(&sd_buf);
+ if (ret)
+ goto out;
+
+ /* XXX tell the kdc what CAs the client is willing to accept */
+ req.trustedCertifiers = NULL;
+ req.kdcPkId = NULL;
+
+ if (compat == COMPAT_WIN2K) {
+ PA_PK_AS_REQ_Win2k winreq;
+
+ pa_type = KRB5_PADATA_PK_AS_REQ_WIN;
+
+ memset(&winreq, 0, sizeof(winreq));
+
+ ASN1_MALLOC_ENCODE(ContentInfo,
+ winreq.signed_auth_pack.data,
+ winreq.signed_auth_pack.length,
+ &content_info,
+ &size,
+ ret);
+ if (ret)
+ goto out;
+ if (winreq.signed_auth_pack.length != size)
+ krb5_abortx(context, "Internal ASN1 encoder error");
+
+ ASN1_MALLOC_ENCODE(PA_PK_AS_REQ_Win2k, buf.data, buf.length,
+ &winreq, &size, ret);
+ free_PA_PK_AS_REQ_Win2k(&winreq);
+
+ } else if (compat == COMPAT_19) {
+ PA_PK_AS_REQ_19 req_19;
+
+ pa_type = KRB5_PADATA_PK_AS_REQ_19;
+
+ memset(&req_19, 0, sizeof(req_19));
+
+ ret = copy_ContentInfo(&content_info, &req_19.signedAuthPack);
+ if (ret) {
+ krb5_clear_error_string(context);
+ goto out;
+ }
+ req_19.kdcCert = NULL;
+ req_19.trustedCertifiers = NULL;
+ req_19.encryptionCert = NULL;
+
+ ASN1_MALLOC_ENCODE(PA_PK_AS_REQ_19, buf.data, buf.length,
+ &req_19, &size, ret);
+
+ free_PA_PK_AS_REQ_19(&req_19);
+
+ } else if (compat == COMPAT_25) {
+
+ pa_type = KRB5_PADATA_PK_AS_REQ;
+
+ ASN1_MALLOC_ENCODE(ContentInfo,
+ req.signedAuthPack.data,
+ req.signedAuthPack.length,
+ &content_info,
+ &size,
+ ret);
+ if (ret)
+ goto out;
+ if (req.signedAuthPack.length != size)
+ krb5_abortx(context, "Internal ASN1 encoder error");
+
+ ASN1_MALLOC_ENCODE(PA_PK_AS_REQ, buf.data, buf.length,
+ &req, &size, ret);
+
+ } else
+ krb5_abortx(context, "internal pkinit error");
+ if (ret) {
+ krb5_set_error_string(context, "PA-PK-AS-REQ %d", ret);
+ goto out;
+ }
+ if (buf.length != size)
+ krb5_abortx(context, "Internal ASN1 encoder error");
+
+ ret = krb5_padata_add(context, md, pa_type, buf.data, buf.length);
+ if (ret)
+ free(buf.data);
+ out:
+ free_ContentInfo(&content_info);
+
+ return ret;
+}
+
+
+krb5_error_code KRB5_LIB_FUNCTION
+_krb5_pk_mk_padata(krb5_context context,
+ void *c,
+ const KDC_REQ_BODY *req_body,
+ unsigned nonce,
+ METHOD_DATA *md)
+{
+ krb5_pk_init_ctx ctx = c;
+ krb5_error_code ret;
+ size_t size;
+ krb5_data buf;
+ const char *provisioning_server;
+ int win2k_compat;
+
+ win2k_compat = krb5_config_get_bool_default(context, NULL,
+ FALSE,
+ "realms",
+ req_body->realm,
+ "win2k_pkinit",
+ NULL);
+ if (context->pkinit_flags & KRB5_PKINIT_WIN2K)
+ win2k_compat = 1;
+
+ if (win2k_compat) {
+ ret = pk_mk_padata(context, COMPAT_WIN2K, ctx, req_body, nonce, md);
+ if (ret)
+ goto out;
+ } else {
+ ret = pk_mk_padata(context, COMPAT_19, ctx, req_body, nonce, md);
+ if (ret)
+ goto out;
+
+ ret = pk_mk_padata(context, COMPAT_25, ctx, req_body, nonce, md);
+ if (ret)
+ goto out;
+ }
+
+ provisioning_server =
+ krb5_config_get_string(context, NULL,
+ "realms",
+ req_body->realm,
+ "packet-cable-provisioning-server",
+ NULL);
+
+ if (provisioning_server) {
+ /* PacketCable requires the PROV-SRV-LOCATION authenticator */
+ const PROV_SRV_LOCATION prov_server = (char *)provisioning_server;
+
+ ASN1_MALLOC_ENCODE(PROV_SRV_LOCATION, buf.data, buf.length,
+ &prov_server, &size, ret);
+ if (ret)
+ goto out;
+ if (buf.length != size)
+ krb5_abortx(context, "Internal ASN1 encoder error");
+
+ /* PacketCable uses -1 (application specific) as the auth data type */
+ ret = krb5_padata_add(context, md, -1, buf.data, buf.length);
+ if (ret)
+ free(buf.data);
+ }
+ out:
+ return ret;
+}
+
+static krb5_boolean
+pk_peer_compare(krb5_context context,
+ const SignerIdentifier *peer1,
+ X509 *peer2)
+{
+ switch (peer1->element) {
+ case choice_CMSIdentifier_issuerAndSerialNumber: {
+ ASN1_INTEGER *i;
+ const heim_integer *serial;
+ X509_NAME *name;
+ unsigned char *p;
+ size_t len;
+
+ i = X509_get_serialNumber(peer2);
+ serial = &peer1->u.issuerAndSerialNumber.serialNumber;
+
+ if (i->length != serial->length ||
+ memcmp(i->data, serial->data, i->length) != 0)
+ return FALSE;
+
+ p = peer1->u.issuerAndSerialNumber.issuer._save.data;
+ len = peer1->u.issuerAndSerialNumber.issuer._save.length;
+ name = d2i_X509_NAME(NULL, &p, len);
+ if (name == NULL)
+ return FALSE;
+
+ if (X509_NAME_cmp(name, X509_get_issuer_name(peer2)) != 0) {
+ X509_NAME_free(name);
+ return FALSE;
+ }
+ X509_NAME_free(name);
+ break;
+ }
+ case choice_CMSIdentifier_subjectKeyIdentifier:
+ return FALSE;
+ default:
+ return FALSE;
+ }
+ return TRUE;
+}
+
+static krb5_error_code
+pk_decrypt_key(krb5_context context,
+ heim_octet_string *encrypted_key,
+ EVP_PKEY *priv_key,
+ krb5_keyblock *key)
+{
+ int ret;
+ unsigned char *buf;
+
+ buf = malloc(EVP_PKEY_size(priv_key));
+ if (buf == NULL) {
+ krb5_set_error_string(context, "malloc: out of memory");
+ return ENOMEM;
+ }
+ ret = EVP_PKEY_decrypt(buf,
+ encrypted_key->data,
+ encrypted_key->length,
+ priv_key);
+ if (ret <= 0) {
+ free(buf);
+ krb5_set_error_string(context, "Can't decrypt key: %s",
+ ERR_error_string(ERR_get_error(), NULL));
+ return ENOMEM;
+ }
+
+ key->keytype = 0;
+ key->keyvalue.length = ret;
+ key->keyvalue.data = malloc(ret);
+ if (key->keyvalue.data == NULL) {
+ free(buf);
+ krb5_set_error_string(context, "malloc: out of memory");
+ return ENOMEM;
+ }
+ memcpy(key->keyvalue.data, buf, ret);
+ free(buf);
+ return 0;
+}
+
+
+static krb5_error_code
+pk_verify_chain_standard(krb5_context context,
+ struct krb5_pk_identity *id,
+ const SignerIdentifier *client,
+ STACK_OF(X509) *chain,
+ X509 **client_cert)
+{
+ X509_STORE *cert_store = NULL;
+ X509_STORE_CTX *store_ctx = NULL;
+ X509 *cert = NULL;
+ int i;
+ int ret;
+
+ ret = KRB5_KDC_ERROR_CLIENT_NAME_MISMATCH;
+ for (i = 0; i < sk_X509_num(chain); i++) {
+ cert = sk_X509_value(chain, i);
+ if (pk_peer_compare(context, client, cert) == TRUE) {
+ ret = 0;
+ break;
+ }
+ }
+ if (ret) {
+ krb5_set_error_string(context, "PKINIT: verify chain failed "
+ "to find client in chain");
+ return ret;
+ }
+
+ cert_store = X509_STORE_new();
+ if (cert_store == NULL) {
+ ret = ENOMEM;
+ krb5_set_error_string(context, "PKINIT: can't create X509 store: %s",
+ ERR_error_string(ERR_get_error(), NULL));
+ }
+
+ store_ctx = X509_STORE_CTX_new();
+ if (store_ctx == NULL) {
+ ret = ENOMEM;
+ krb5_set_error_string(context,
+ "PKINIT: can't create X509 store ctx: %s",
+ ERR_error_string(ERR_get_error(), NULL));
+ goto end;
+ }
+
+ X509_STORE_CTX_init(store_ctx, cert_store, cert, chain);
+ X509_STORE_CTX_trusted_stack(store_ctx, id->trusted_certs);
+ X509_verify_cert(store_ctx);
+ /* the last checked certificate is in store_ctx->current_cert */
+ krb5_clear_error_string(context);
+ switch(store_ctx->error) {
+ case X509_V_OK:
+ ret = 0;
+ break;
+ case X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT_LOCALLY:
+ ret = KRB5_KDC_ERROR_CANT_VERIFY_CERTIFICATE;
+ krb5_set_error_string(context, "PKINIT: failed to verify "
+ "certificate: %s ",
+ X509_verify_cert_error_string(store_ctx->error));
+ break;
+ case X509_V_ERR_UNABLE_TO_DECODE_ISSUER_PUBLIC_KEY:
+ case X509_V_ERR_CERT_SIGNATURE_FAILURE:
+ case X509_V_ERR_ERROR_IN_CERT_NOT_BEFORE_FIELD:
+ case X509_V_ERR_CERT_NOT_YET_VALID:
+ case X509_V_ERR_ERROR_IN_CERT_NOT_AFTER_FIELD:
+ case X509_V_ERR_CERT_HAS_EXPIRED:
+ ret = KRB5_KDC_ERROR_INVALID_CERTIFICATE;
+ krb5_set_error_string(context, "PKINIT: invalid certificate: %s ",
+ X509_verify_cert_error_string(store_ctx->error));
+ break;
+ case X509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT:
+ case X509_V_ERR_SELF_SIGNED_CERT_IN_CHAIN:
+ case X509_V_ERR_UNABLE_TO_VERIFY_LEAF_SIGNATURE:
+ case X509_V_ERR_CERT_CHAIN_TOO_LONG:
+ case X509_V_ERR_PATH_LENGTH_EXCEEDED:
+ case X509_V_ERR_INVALID_CA:
+ ret = KRB5_KDC_ERROR_INVALID_CERTIFICATE;
+ krb5_set_error_string(context, "PKINIT: unknown CA or can't "
+ "verify certificate: %s",
+ X509_verify_cert_error_string(store_ctx->error));
+ break;
+ default:
+ ret = KRB5_KDC_ERROR_INVALID_CERTIFICATE; /* XXX */
+ krb5_set_error_string(context, "PKINIT: failed to verify "
+ "certificate: %s (%ld) ",
+ X509_verify_cert_error_string(store_ctx->error),
+ (long)store_ctx->error);
+ break;
+ }
+ if (ret)
+ goto end;
+
+ /*
+ * Since X509_verify_cert() doesn't do CRL checking at all, we have to
+ * perform own verification against CRLs
+ */
+#if 0
+ ret = pk_verify_crl(context, store_ctx, id->crls);
+ if (ret)
+ goto end;
+#endif
+
+ if (client_cert && cert)
+ *client_cert = X509_dup(cert);
+
+ end:
+ if (cert_store)
+ X509_STORE_free(cert_store);
+ if (store_ctx)
+ X509_STORE_CTX_free(store_ctx);
+ return ret;
+}
+
+static int
+cert_to_X509(krb5_context context, CertificateSetReal *set,
+ STACK_OF(X509_CRL) **certs)
+{
+ krb5_error_code ret;
+ int i;
+
+ *certs = sk_X509_new_null();
+
+ ret = 0;
+ for (i = 0; i < set->len; i++) {
+ unsigned char *p;
+ X509 *cert;
+
+ p = set->val[i].data;
+ cert = d2i_X509(NULL, &p, set->val[i].length);
+ if (cert == NULL) {
+ ret = ASN1_BAD_FORMAT;
+ break;
+ }
+ sk_X509_insert(*certs, cert, i);
+ }
+ if (ret) {
+ krb5_set_error_string(context,
+ "PKINIT: Failed to decode certificate chain");
+ sk_X509_free(*certs);
+ *certs = NULL;
+ }
+ return ret;
+}
+
+static krb5_error_code
+any_to_CertificateSet(krb5_context context, heim_any *cert,
+ CertificateSetReal *set)
+{
+ size_t size, len, length;
+ heim_any *val;
+ int ret;
+ char *p;
+
+ set->len = 0;
+ set->val = NULL;
+
+ len = 0;
+ p = cert->data;
+ length = cert->length;
+ while (len < cert->length) {
+ val = realloc(set->val, (set->len + 1) * sizeof(set->val[0]));
+ if (val == NULL) {
+ ret = ENOMEM;
+ goto out;
+ }
+ set->val = val;
+ ret = decode_heim_any(p, length, &set->val[set->len], &size);
+ if (ret)
+ goto out;
+ set->len++;
+
+ p += size;
+ len += size;
+ length -= size;
+ }
+ return 0;
+ out:
+ krb5_clear_error_string(context);
+ free_CertificateSetReal(set);
+ set->val = NULL;
+ return ret;
+}
+
+krb5_error_code KRB5_LIB_FUNCTION
+_krb5_pk_verify_sign(krb5_context context,
+ const char *data,
+ size_t length,
+ struct krb5_pk_identity *id,
+ heim_oid *contentType,
+ krb5_data *content,
+ struct krb5_pk_cert **signer)
+{
+ STACK_OF(X509) *certificates;
+ SignerInfo *signer_info;
+ const EVP_MD *evp_type;
+ EVP_PKEY *public_key;
+ krb5_error_code ret;
+ CertificateSetReal set;
+ EVP_MD_CTX md;
+ X509 *cert;
+ SignedData sd;
+ size_t size;
+
+ *signer = NULL;
+ krb5_data_zero(content);
+ contentType->length = 0;
+ contentType->components = NULL;
+
+ memset(&sd, 0, sizeof(sd));
+
+ ret = decode_SignedData(data, length, &sd, &size);
+ if (ret) {
+ krb5_set_error_string(context,
+ "PKINIT: decoding failed SignedData: %d",
+ ret);
+ goto out;
+ }
+
+ if (sd.encapContentInfo.eContent == NULL) {
+ krb5_set_error_string(context,
+ "PKINIT: signature missing encapContent");
+ ret = KRB5KRB_AP_ERR_MSG_TYPE;
+ goto out;
+ }
+
+ /* XXX Check CMS version */
+
+ if (sd.signerInfos.len < 1) {
+ krb5_set_error_string(context,
+ "PKINIT: signature information missing from "
+ "pkinit response");
+ ret = KRB5_KDC_ERR_INVALID_SIG;
+ goto out;
+ }
+
+ signer_info = &sd.signerInfos.val[0];
+
+ ret = any_to_CertificateSet(context, sd.certificates, &set);
+ if (ret) {
+ krb5_set_error_string(context,
+ "PKINIT: failed to decode CertificateSet");
+ goto out;
+ }
+
+ ret = cert_to_X509(context, &set, &certificates);
+ free_CertificateSetReal(&set);
+ if (ret) {
+ krb5_set_error_string(context,
+ "PKINIT: failed to decode Certificates");
+ goto out;
+ }
+
+ ret = pk_verify_chain_standard(context, id,
+ &signer_info->sid,
+ certificates,
+ &cert);
+ sk_X509_free(certificates);
+ if (ret)
+ goto out;
+
+ if (signer_info->signature.length == 0) {
+ free_SignedData(&sd);
+ X509_free(cert);
+ krb5_set_error_string(context, "PKINIT: signature missing from"
+ "pkinit response");
+ return KRB5_KDC_ERR_INVALID_SIG;
+ }
+
+ public_key = X509_get_pubkey(cert);
+
+ /* verify signature */
+ if (heim_oid_cmp(&signer_info->digestAlgorithm.algorithm,
+ oid_id_pkcs1_sha1WithRSAEncryption()) == 0)
+ evp_type = EVP_sha1();
+ else if (heim_oid_cmp(&signer_info->digestAlgorithm.algorithm,
+ oid_id_pkcs1_md5WithRSAEncryption()) == 0)
+ evp_type = EVP_md5();
+ else if (heim_oid_cmp(&signer_info->digestAlgorithm.algorithm,
+ oid_id_secsig_sha_1()) == 0)
+ evp_type = EVP_sha1();
+ else {
+ X509_free(cert);
+ krb5_set_error_string(context, "PKINIT: The requested digest "
+ "algorithm is not supported");
+ ret = KRB5_KDC_ERR_INVALID_SIG;
+ goto out;
+ }
+
+ EVP_VerifyInit(&md, evp_type);
+ EVP_VerifyUpdate(&md,
+ sd.encapContentInfo.eContent->data,
+ sd.encapContentInfo.eContent->length);
+ ret = EVP_VerifyFinal(&md,
+ signer_info->signature.data,
+ signer_info->signature.length,
+ public_key);
+ if (ret != 1) {
+ X509_free(cert);
+ krb5_set_error_string(context, "PKINIT: signature didn't verify: %s",
+ ERR_error_string(ERR_get_error(), NULL));
+ ret = KRB5_KDC_ERR_INVALID_SIG;
+ goto out;
+ }
+
+ ret = copy_oid(&sd.encapContentInfo.eContentType, contentType);
+ if (ret) {
+ krb5_clear_error_string(context);
+ goto out;
+ }
+
+ content->data = malloc(sd.encapContentInfo.eContent->length);
+ if (content->data == NULL) {
+ krb5_clear_error_string(context);
+ ret = ENOMEM;
+ goto out;
+ }
+ content->length = sd.encapContentInfo.eContent->length;
+ memcpy(content->data,sd.encapContentInfo.eContent->data,content->length);
+
+ *signer = malloc(sizeof(**signer));
+ if (*signer == NULL) {
+ krb5_clear_error_string(context);
+ ret = ENOMEM;
+ goto out;
+ }
+ (*signer)->cert = cert;
+
+ out:
+ free_SignedData(&sd);
+ if (ret) {
+ free_oid(contentType);
+ krb5_data_free(content);
+ }
+ return ret;
+}
+
+static krb5_error_code
+get_reply_key(krb5_context context,
+ const krb5_data *content,
+ unsigned nonce,
+ krb5_keyblock **key)
+{
+ ReplyKeyPack_19 key_pack;
+ krb5_error_code ret;
+ size_t size;
+
+ ret = decode_ReplyKeyPack_19(content->data,
+ content->length,
+ &key_pack,
+ &size);
+ if (ret) {
+ krb5_set_error_string(context, "PKINIT decoding reply key failed");
+ free_ReplyKeyPack_19(&key_pack);
+ return ret;
+ }
+
+ if (key_pack.nonce != nonce) {
+ krb5_set_error_string(context, "PKINIT enckey nonce is wrong");
+ free_ReplyKeyPack_19(&key_pack);
+ return KRB5KRB_AP_ERR_MODIFIED;
+ }
+
+ *key = malloc (sizeof (**key));
+ if (*key == NULL) {
+ krb5_set_error_string(context, "PKINIT failed allocating reply key");
+ free_ReplyKeyPack_19(&key_pack);
+ krb5_set_error_string(context, "malloc: out of memory");
+ return ENOMEM;
+ }
+
+ ret = copy_EncryptionKey(&key_pack.replyKey, *key);
+ free_ReplyKeyPack_19(&key_pack);
+ if (ret) {
+ krb5_set_error_string(context, "PKINIT failed copying reply key");
+ free(*key);
+ }
+
+ return ret;
+}
+
+static krb5_error_code
+pk_verify_host(krb5_context context, struct krb5_pk_cert *host)
+{
+ /* XXX */
+ return 0;
+}
+
+static krb5_error_code
+pk_rd_pa_reply_enckey(krb5_context context,
+ int win2k_compat,
+ ContentInfo *rep,
+ krb5_pk_init_ctx ctx,
+ krb5_enctype etype,
+ unsigned nonce,
+ PA_DATA *pa,
+ krb5_keyblock **key)
+{
+ krb5_error_code ret;
+ EnvelopedData ed;
+ krb5_keyblock tmp_key;
+ krb5_crypto crypto;
+ krb5_data plain;
+ KeyTransRecipientInfo *ri;
+ int length;
+ size_t size;
+ X509 *user_cert;
+ char *p;
+ krb5_boolean bret;
+ krb5_data content;
+ heim_oid contentType = { 0, NULL };
+ struct krb5_pk_cert *host = NULL;
+ heim_octet_string encryptedContent;
+ heim_octet_string *any;
+ krb5_data ivec;
+ krb5_data params;
+
+
+ memset(&tmp_key, 0, sizeof(tmp_key));
+ memset(&ed, 0, sizeof(ed));
+ krb5_data_zero(&plain);
+ krb5_data_zero(&content);
+ krb5_data_zero(&encryptedContent);
+ krb5_data_zero(&ivec);
+
+ user_cert = sk_X509_value(ctx->id->cert, 0);
+
+ if (heim_oid_cmp(oid_id_pkcs7_envelopedData(), &rep->contentType)) {
+ krb5_set_error_string(context, "PKINIT: Invalid content type");
+ return EINVAL;
+ }
+
+ if (rep->content == NULL) {
+ krb5_set_error_string(context, "PKINIT: No content in reply");
+ return EINVAL;
+ }
+
+ ret = decode_EnvelopedData(rep->content->data,
+ rep->content->length,
+ &ed,
+ &size);
+ if (ret) {
+ free_EnvelopedData(&ed);
+ return ret;
+ }
+
+ if (ed.recipientInfos.len != 1) {
+ free_EnvelopedData(&ed);
+ krb5_set_error_string(context, "pkinit: Number of recipient infos "
+ "not one (%d)",
+ ed.recipientInfos.len);
+ return EINVAL; /* XXX */
+ }
+
+ ri = &ed.recipientInfos.val[0];
+
+ /* XXX make SignerIdentifier and RecipientIdentifier the same */
+ bret = pk_peer_compare(context, (SignerIdentifier *)&ri->rid, user_cert);
+ if (bret == FALSE) {
+ ret = KRB5KRB_AP_ERR_BADMATCH; /* XXX */
+ goto out;
+ }
+
+ if (heim_oid_cmp(oid_id_pkcs1_rsaEncryption(),
+ &ri->keyEncryptionAlgorithm.algorithm)) {
+ krb5_set_error_string(context, "PKINIT: invalid content type");
+ return EINVAL;
+ }
+
+ ret = pk_decrypt_key(context, &ri->encryptedKey,
+ ctx->id->private_key, &tmp_key);
+ if (ret)
+ goto out;
+
+
+ /* verify content type */
+ if (win2k_compat) {
+ if (heim_oid_cmp(&ed.encryptedContentInfo.contentType, oid_id_pkcs7_data())) {
+ ret = KRB5KRB_AP_ERR_MSG_TYPE;
+ goto out;
+ }
+ } else {
+ if (heim_oid_cmp(&ed.encryptedContentInfo.contentType, oid_id_pkcs7_signedData())) {
+ ret = KRB5KRB_AP_ERR_MSG_TYPE;
+ goto out;
+ }
+ }
+
+ if (ed.encryptedContentInfo.encryptedContent == NULL) {
+ krb5_set_error_string(context, "PKINIT: OPTIONAL encryptedContent "
+ "field not filled in in KDC reply");
+ ret = KRB5_BADMSGTYPE;
+ goto out;
+ }
+
+ any = ed.encryptedContentInfo.encryptedContent;
+ ret = der_get_octet_string(any->data, any->length,
+ &encryptedContent, NULL);
+ if (ret) {
+ krb5_set_error_string(context,
+ "PKINIT: encryptedContent content invalid");
+ goto out;
+ }
+
+ if (ed.encryptedContentInfo.contentEncryptionAlgorithm.parameters == NULL){
+ krb5_set_error_string(context,
+ "PKINIT: encryptedContent parameter missing");
+ ret = KRB5_BADMSGTYPE;
+ goto out;
+ }
+
+ params.data = ed.encryptedContentInfo.contentEncryptionAlgorithm.parameters->data;
+ params.length = ed.encryptedContentInfo.contentEncryptionAlgorithm.parameters->length;
+
+ ret = _krb5_oid_to_enctype(context,
+ &ed.encryptedContentInfo.contentEncryptionAlgorithm.algorithm,
+ &tmp_key.keytype);
+ if (ret)
+ goto out;
+
+ ret = krb5_crypto_init(context, &tmp_key, 0, &crypto);
+ if (ret)
+ goto out;
+
+ ret = krb5_crypto_get_params(context, crypto, &params, &ivec);
+ if (ret)
+ goto out;
+
+ ret = krb5_decrypt_ivec(context, crypto,
+ 0,
+ encryptedContent.data,
+ encryptedContent.length,
+ &plain,
+ ivec.data);
+
+ p = plain.data;
+ length = plain.length;
+
+ /* win2k uses ContentInfo */
+ if (win2k_compat) {
+ ContentInfo ci;
+ size_t size;
+
+ ret = decode_ContentInfo(p, length, &ci, &size);
+ if (ret) {
+ krb5_set_error_string(context,
+ "PKINIT: failed decoding ContentInfo: %d",
+ ret);
+ goto out;
+ }
+
+ if (heim_oid_cmp(&ci.contentType, oid_id_pkcs7_signedData())) {
+ ret = EINVAL; /* XXX */
+ krb5_set_error_string(context, "PKINIT: Invalid content type");
+ goto out;
+ }
+ p = ci.content->data;
+ length = ci.content->length;
+ }
+
+ ret = _krb5_pk_verify_sign(context,
+ p,
+ length,
+ ctx->id,
+ &contentType,
+ &content,
+ &host);
+ if (ret)
+ goto out;
+
+ /* make sure that it is the kdc's certificate */
+ ret = pk_verify_host(context, host);
+ if (ret) {
+ krb5_set_error_string(context, "PKINIT: failed verify host: %d", ret);
+ goto out;
+ }
+
+ if (win2k_compat) {
+ if (heim_oid_cmp(&contentType, oid_id_pkcs7_data()) != 0) {
+ krb5_set_error_string(context, "PKINIT: reply key, wrong oid");
+ ret = KRB5KRB_AP_ERR_MSG_TYPE;
+ goto out;
+ }
+ } else {
+ if (heim_oid_cmp(&contentType, oid_id_pkrkeydata()) != 0) {
+ krb5_set_error_string(context, "PKINIT: reply key, wrong oid");
+ ret = KRB5KRB_AP_ERR_MSG_TYPE;
+ goto out;
+ }
+ }
+
+ ret = get_reply_key(context, &content, nonce, key);
+ if (ret)
+ goto out;
+
+ /* XXX compare given etype with key->etype */
+
+ out:
+ if (host)
+ _krb5_pk_cert_free(host);
+ free_oid(&contentType);
+ free_octet_string(&encryptedContent);
+ krb5_data_free(&content);
+ krb5_free_keyblock_contents(context, &tmp_key);
+ krb5_data_free(&plain);
+ krb5_data_free(&ivec);
+
+ return ret;
+}
+
+static krb5_error_code
+pk_rd_pa_reply_dh(krb5_context context,
+ ContentInfo *rep,
+ krb5_pk_init_ctx ctx,
+ krb5_enctype etype,
+ unsigned nonce,
+ PA_DATA *pa,
+ krb5_keyblock **key)
+{
+ unsigned char *p, *dh_gen_key = NULL;
+ ASN1_INTEGER *dh_pub_key = NULL;
+ struct krb5_pk_cert *host = NULL;
+ BIGNUM *kdc_dh_pubkey = NULL;
+ KDCDHKeyInfo kdc_dh_info;
+ heim_oid contentType = { 0, NULL };
+ krb5_data content;
+ krb5_error_code ret;
+ int dh_gen_keylen;
+ size_t size;
+
+ krb5_data_zero(&content);
+ memset(&kdc_dh_info, 0, sizeof(kdc_dh_info));
+
+ if (heim_oid_cmp(oid_id_pkcs7_signedData(), &rep->contentType)) {
+ krb5_set_error_string(context, "PKINIT: Invalid content type");
+ return EINVAL;
+ }
+
+ if (rep->content == NULL) {
+ krb5_set_error_string(context, "PKINIT: No content in reply");
+ return EINVAL;
+ }
+
+ ret = _krb5_pk_verify_sign(context,
+ rep->content->data,
+ rep->content->length,
+ ctx->id,
+ &contentType,
+ &content,
+ &host);
+ if (ret)
+ goto out;
+
+ /* make sure that it is the kdc's certificate */
+ ret = pk_verify_host(context, host);
+ if (ret)
+ goto out;
+
+ if (heim_oid_cmp(&contentType, oid_id_pkdhkeydata())) {
+ ret = KRB5KRB_AP_ERR_MSG_TYPE; /* XXX */
+ goto out;
+ }
+
+ ret = decode_KDCDHKeyInfo(content.data,
+ content.length,
+ &kdc_dh_info,
+ &size);
+
+ if (ret)
+ goto out;
+
+ if (kdc_dh_info.nonce != nonce) {
+ krb5_set_error_string(context, "PKINIT: DH nonce is wrong");
+ ret = KRB5KRB_AP_ERR_MODIFIED;
+ goto out;
+ }
+
+ p = kdc_dh_info.subjectPublicKey.data;
+ size = (kdc_dh_info.subjectPublicKey.length + 7) / 8;
+ dh_pub_key = d2i_ASN1_INTEGER(NULL, &p, size);
+ if (dh_pub_key == NULL) {
+ krb5_set_error_string(context,
+ "PKINIT: Can't parse KDC's DH public key");
+ ret = KRB5KRB_ERR_GENERIC;
+ goto out;
+ }
+
+ kdc_dh_pubkey = ASN1_INTEGER_to_BN(dh_pub_key, NULL);
+ if (kdc_dh_pubkey == NULL) {
+ krb5_set_error_string(context,
+ "PKINIT: Can't convert KDC's DH public key");
+ ret = KRB5KRB_ERR_GENERIC;
+ goto out;
+ }
+
+ dh_gen_key = malloc(DH_size(ctx->dh));
+ if (dh_gen_key == NULL) {
+ krb5_set_error_string(context, "malloc: out of memory");
+ ret = ENOMEM;
+ goto out;
+ }
+
+ dh_gen_keylen = DH_compute_key(dh_gen_key, kdc_dh_pubkey, ctx->dh);
+ if (dh_gen_keylen == -1) {
+ krb5_set_error_string(context,
+ "PKINIT: Can't compute Diffie-Hellman key (%s)",
+ ERR_error_string(ERR_get_error(), NULL));
+ ret = KRB5KRB_ERR_GENERIC;
+ goto out;
+ }
+
+ *key = malloc (sizeof (**key));
+ if (*key == NULL) {
+ krb5_set_error_string(context, "malloc: out of memory");
+ ret = ENOMEM;
+ goto out;
+ }
+
+ ret = krb5_random_to_key(context, etype, dh_gen_key, dh_gen_keylen, *key);
+ if (ret) {
+ krb5_set_error_string(context,
+ "PKINIT: can't create key from DH key");
+ free(*key);
+ *key = NULL;
+ goto out;
+ }
+
+ out:
+ if (kdc_dh_pubkey)
+ BN_free(kdc_dh_pubkey);
+ if (dh_gen_key) {
+ memset(dh_gen_key, 0, DH_size(ctx->dh));
+ free(dh_gen_key);
+ }
+ if (dh_pub_key)
+ ASN1_INTEGER_free(dh_pub_key);
+ if (host)
+ _krb5_pk_cert_free(host);
+ if (content.data)
+ krb5_data_free(&content);
+ free_KDCDHKeyInfo(&kdc_dh_info);
+
+ return ret;
+}
+
+krb5_error_code KRB5_LIB_FUNCTION
+_krb5_pk_rd_pa_reply(krb5_context context,
+ void *c,
+ krb5_enctype etype,
+ unsigned nonce,
+ PA_DATA *pa,
+ krb5_keyblock **key)
+{
+ krb5_pk_init_ctx ctx = c;
+ krb5_error_code ret;
+ ContentInfo ci;
+ size_t size;
+
+ /* Check for PK-INIT -25 */
+ if (pa->padata_type == KRB5_PADATA_PK_AS_REP) {
+ PA_PK_AS_REP rep;
+
+ memset(&rep, 0, sizeof(rep));
+
+ ret = decode_PA_PK_AS_REP(pa->padata_value.data,
+ pa->padata_value.length,
+ &rep,
+ &size);
+ if (ret)
+ return ret;
+
+ switch (rep.element) {
+ case choice_PA_PK_AS_REP_encKeyPack:
+ ret = decode_ContentInfo(rep.u.encKeyPack.data,
+ rep.u.encKeyPack.length,
+ &ci,
+ &size);
+ free_PA_PK_AS_REP(&rep);
+ if (ret) {
+ krb5_set_error_string(context,
+ "PKINIT: -25 decoding failed "
+ "ContentInfo: %d", ret);
+ break;
+ }
+ ret = pk_rd_pa_reply_enckey(context, 0, &ci, ctx,
+ etype, nonce, pa, key);
+ free_ContentInfo(&ci);
+ return ret;
+ default:
+ free_PA_PK_AS_REP(&rep);
+ krb5_set_error_string(context, "PKINIT: -25 reply "
+ "invalid content type");
+ break;
+ }
+ }
+
+ /* Check for PK-INIT -19 */
+ {
+ PA_PK_AS_REP_19 rep19;
+
+ memset(&rep19, 0, sizeof(rep19));
+
+ ret = decode_PA_PK_AS_REP_19(pa->padata_value.data,
+ pa->padata_value.length,
+ &rep19,
+ &size);
+ if (ret == 0) {
+ switch(rep19.element) {
+ case choice_PA_PK_AS_REP_19_dhSignedData:
+ ret = pk_rd_pa_reply_dh(context, &rep19.u.dhSignedData, ctx,
+ etype, nonce, pa, key);
+ break;
+ case choice_PA_PK_AS_REP_19_encKeyPack:
+ ret = pk_rd_pa_reply_enckey(context, 0,
+ &rep19.u.encKeyPack, ctx,
+ etype, nonce, pa, key);
+ break;
+ default:
+ krb5_set_error_string(context, "PKINIT: -19 reply invalid "
+ "content type");
+ ret = EINVAL;
+ break;
+ }
+ free_PA_PK_AS_REP_19(&rep19);
+ if (ret == 0)
+ return 0;
+ }
+ }
+
+ /* Check for Windows encoding of the AS-REP pa data */
+ {
+ PA_PK_AS_REP_Win2k w2krep;
+
+ memset(&w2krep, 0, sizeof(w2krep));
+
+ ret = decode_PA_PK_AS_REP_Win2k(pa->padata_value.data,
+ pa->padata_value.length,
+ &w2krep,
+ &size);
+ if (ret) {
+ krb5_set_error_string(context, "PKINIT: Failed decoding windows"
+ "pkinit reply %d", ret);
+ return ret;
+ }
+
+ switch (w2krep.element) {
+ case choice_PA_PK_AS_REP_Win2k_encKeyPack:
+ ret = decode_ContentInfo(w2krep.u.encKeyPack.data,
+ w2krep.u.encKeyPack.length,
+ &ci,
+ &size);
+ free_PA_PK_AS_REP_Win2k(&w2krep);
+ if (ret) {
+ krb5_set_error_string(context,
+ "PKINIT: decoding failed "
+ "ContentInfo: %d",
+ ret);
+ return ret;
+ }
+ ret = pk_rd_pa_reply_enckey(context, 1, &ci, ctx,
+ etype, nonce, pa, key);
+ free_ContentInfo(&ci);
+ break;
+ default:
+ free_PA_PK_AS_REP_Win2k(&w2krep);
+ krb5_set_error_string(context, "PKINIT: win2k reply invalid "
+ "content type");
+ ret = EINVAL;
+ break;
+ }
+
+ }
+
+ return ret;
+}
+
+static int
+ssl_pass_cb(char *buf, int size, int rwflag, void *u)
+{
+ krb5_error_code ret;
+ krb5_prompt prompt;
+ krb5_data password_data;
+ krb5_prompter_fct prompter = u;
+
+ password_data.data = buf;
+ password_data.length = size;
+ prompt.prompt = "Enter your private key passphrase: ";
+ prompt.hidden = 1;
+ prompt.reply = &password_data;
+ prompt.type = KRB5_PROMPT_TYPE_PASSWORD;
+
+ ret = (*prompter)(NULL, NULL, NULL, NULL, 1, &prompt);
+ if (ret) {
+ memset (buf, 0, size);
+ return 0;
+ }
+ return strlen(buf);
+}
+
+static krb5_error_code
+load_openssl_cert(krb5_context context,
+ const char *file,
+ STACK_OF(X509) **c)
+{
+ STACK_OF(X509) *certificate;
+ krb5_error_code ret;
+ FILE *f;
+
+ f = fopen(file, "r");
+ if (f == NULL) {
+ ret = errno;
+ krb5_set_error_string(context, "PKINIT: open failed %s: %s",
+ file, strerror(ret));
+ return ret;
+ }
+
+ certificate = sk_X509_new_null();
+ while (1) {
+ /* see http://www.openssl.org/docs/crypto/pem.html section BUGS */
+ X509 *cert;
+ cert = PEM_read_X509(f, NULL, NULL, NULL);
+ if (cert == NULL) {
+ if (ERR_GET_REASON(ERR_peek_error()) == PEM_R_NO_START_LINE) {
+ /* End of file reached. no error */
+ ERR_clear_error();
+ break;
+ }
+ krb5_set_error_string(context, "PKINIT: Can't read certificate");
+ fclose(f);
+ return HEIM_PKINIT_CERTIFICATE_INVALID;
+ }
+ sk_X509_insert(certificate, cert, sk_X509_num(certificate));
+ }
+ fclose(f);
+ if (sk_X509_num(certificate) == 0) {
+ krb5_set_error_string(context, "PKINIT: No certificate found");
+ return HEIM_PKINIT_NO_CERTIFICATE;
+ }
+ *c = certificate;
+ return 0;
+}
+
+static krb5_error_code
+load_openssl_file(krb5_context context,
+ char *password,
+ krb5_prompter_fct prompter,
+ void *prompter_data,
+ const char *user_id,
+ struct krb5_pk_identity *id)
+{
+ krb5_error_code ret;
+ STACK_OF(X509) *certificate = NULL;
+ char *cert_file = NULL, *key_file;
+ EVP_PKEY *private_key = NULL;
+ FILE *f;
+
+ cert_file = strdup(user_id);
+ if (cert_file == NULL) {
+ krb5_set_error_string(context, "malloc: out of memory");
+ return ENOMEM;
+ }
+ key_file = strchr(cert_file, ',');
+ if (key_file == NULL) {
+ krb5_set_error_string(context, "PKINIT: key file missing");
+ ret = HEIM_PKINIT_NO_PRIVATE_KEY;
+ goto out;
+ }
+ *key_file++ = '\0';
+
+ ret = load_openssl_cert(context, cert_file, &certificate);
+ if (ret)
+ goto out;
+
+ /* load private key */
+ f = fopen(key_file, "r");
+ if (f == NULL) {
+ ret = errno;
+ krb5_set_error_string(context, "PKINIT: open %s: %s",
+ key_file, strerror(ret));
+ goto out;
+ }
+ if (password == NULL || password[0] == '\0') {
+ if (prompter == NULL)
+ prompter = krb5_prompter_posix;
+ private_key = PEM_read_PrivateKey(f, NULL, ssl_pass_cb, prompter);
+ } else
+ private_key = PEM_read_PrivateKey(f, NULL, NULL, password);
+ fclose(f);
+ if (private_key == NULL) {
+ krb5_set_error_string(context, "PKINIT: Can't read private key");
+ ret = HEIM_PKINIT_PRIVATE_KEY_INVALID;
+ goto out;
+ }
+ ret = X509_check_private_key(sk_X509_value(certificate, 0), private_key);
+ if (ret != 1) {
+ ret = HEIM_PKINIT_PRIVATE_KEY_INVALID;
+ krb5_set_error_string(context,
+ "PKINIT: The private key doesn't match "
+ "the public key certificate");
+ goto out;
+ }
+
+ id->private_key = private_key;
+ id->cert = certificate;
+
+ return 0;
+ out:
+ if (cert_file)
+ free(cert_file);
+ if (certificate)
+ sk_X509_pop_free(certificate, X509_free);
+ if (private_key)
+ EVP_PKEY_free(private_key);
+
+ return ret;
+}
+
+static int
+add_pair(krb5_context context, char *str, char ***cmds, int *num)
+{
+ char **c;
+ char *p;
+ int i;
+
+ p = strchr(str, ':');
+ if (p) {
+ *p = '\0';
+ p++;
+ }
+
+ /* filter out dup keys */
+ for (i = 0; i < *num; i++)
+ if (strcmp((*cmds)[i * 2], str) == 0)
+ return 0;
+
+ c = realloc(*cmds, sizeof(*c) * ((*num + 1) * 2));
+ if (c == NULL) {
+ krb5_set_error_string(context, "malloc: out of memory");
+ return ENOMEM;
+ }
+
+ c[(*num * 2)] = str;
+ c[(*num * 2) + 1] = p;
+ *num += 1;
+ *cmds = c;
+ return 0;
+}
+
+static krb5_error_code
+eval_pairs(krb5_context context, ENGINE *e, const char *name,
+ const char *type, char **cmds, int num)
+{
+ int i;
+
+ for (i = 0; i < num; i++) {
+ char *a1 = cmds[i * 2], *a2 = cmds[(i * 2) + 1];
+ if(!ENGINE_ctrl_cmd_string(e, a1, a2, 0)) {
+ krb5_set_error_string(context,
+ "PKINIT: Failed %scommand (%s - %s:%s): %s",
+ type, name, a1, a2 ? a2 : "(NULL)",
+ ERR_error_string(ERR_get_error(), NULL));
+ return HEIM_PKINIT_NO_PRIVATE_KEY;
+ }
+ }
+ return 0;
+}
+
+struct engine_context {
+ char **pre_cmds;
+ char **post_cmds;
+ int num_pre;
+ int num_post;
+ char *engine_name;
+ char *cert_file;
+ char *key_id;
+};
+
+static krb5_error_code
+parse_openssl_engine_conf(krb5_context context,
+ struct engine_context *ctx,
+ char *line)
+{
+ krb5_error_code ret;
+ char *last, *p, *q;
+
+ for (p = strtok_r(line, ",", &last);
+ p != NULL;
+ p = strtok_r(NULL, ",", &last)) {
+
+ q = strchr(p, '=');
+ if (q == NULL) {
+ krb5_set_error_string(context,
+ "PKINIT: openssl engine configuration "
+ "key %s missing = and thus value", p);
+ return HEIM_PKINIT_NO_PRIVATE_KEY;
+ }
+ *q = '\0';
+ q++;
+ if (strcasecmp("PRE", p) == 0) {
+ ret = add_pair(context, q, &ctx->pre_cmds, &ctx->num_pre);
+ if (ret)
+ return ret;
+ } else if (strcasecmp("POST", p) == 0) {
+ ret = add_pair(context, q, &ctx->post_cmds, &ctx->num_post);
+ if (ret)
+ return ret;
+ } else if (strcasecmp("KEY", p) == 0) {
+ ctx->key_id = q;
+ } else if (strcasecmp("CERT", p) == 0) {
+ ctx->cert_file = q;
+ } else if (strcasecmp("ENGINE", p) == 0) {
+ ctx->engine_name = q;
+ } else {
+ krb5_set_error_string(context,
+ "PKINIT: openssl engine configuration "
+ "key %s is unknown", p);
+ return HEIM_PKINIT_NO_PRIVATE_KEY;
+ }
+ }
+ return 0;
+}
+
+
+static krb5_error_code
+load_openssl_engine(krb5_context context,
+ char *password,
+ krb5_prompter_fct prompter,
+ void *prompter_data,
+ const char *string,
+ struct krb5_pk_identity *id)
+{
+ struct engine_context ctx;
+ krb5_error_code ret;
+ const char *f;
+ char *file_conf = NULL, *user_conf = NULL;
+ ENGINE *e = NULL;
+
+ memset(&ctx, 0, sizeof(ctx));
+
+ ENGINE_load_builtin_engines();
+
+ user_conf = strdup(string);
+ if (user_conf == NULL) {
+ krb5_set_error_string(context, "malloc: out of memory");
+ return ENOMEM;
+ }
+
+ ret = parse_openssl_engine_conf(context, &ctx, user_conf);
+ if (ret)
+ goto out;
+
+ f = krb5_config_get_string_default(context, NULL, NULL,
+ "libdefaults",
+ "pkinit-openssl-engine",
+ NULL);
+ if (f) {
+ file_conf = strdup(f);
+ if (file_conf) {
+ ret = parse_openssl_engine_conf(context, &ctx, file_conf);
+ if (ret)
+ goto out;
+ }
+ }
+
+ if (ctx.cert_file == NULL) {
+ krb5_set_error_string(context,
+ "PKINIT: openssl engine missing certificate");
+ ret = HEIM_PKINIT_NO_CERTIFICATE;
+ goto out;
+ }
+ if (ctx.key_id == NULL) {
+ krb5_set_error_string(context,
+ "PKINIT: openssl engine missing key id");
+ ret = HEIM_PKINIT_NO_PRIVATE_KEY;
+ goto out;
+ }
+ if (ctx.engine_name == NULL) {
+ krb5_set_error_string(context,
+ "PKINIT: openssl engine missing engine name");
+ ret = HEIM_PKINIT_NO_PRIVATE_KEY;
+ goto out;
+ }
+
+ e = ENGINE_by_id(ctx.engine_name);
+ if (e == NULL) {
+ krb5_set_error_string(context,
+ "PKINIT: failed getting openssl engine %s: %s",
+ ctx.engine_name,
+ ERR_error_string(ERR_get_error(), NULL));
+ ret = HEIM_PKINIT_NO_PRIVATE_KEY;
+ goto out;
+ }
+
+ ret = eval_pairs(context, e, ctx.engine_name, "pre",
+ ctx.pre_cmds, ctx.num_pre);
+ if (ret)
+ goto out;
+
+ if(!ENGINE_init(e)) {
+ ret = HEIM_PKINIT_NO_PRIVATE_KEY;
+ krb5_set_error_string(context,
+ "PKINIT: openssl engine init %s failed: %s",
+ ctx.engine_name,
+ ERR_error_string(ERR_get_error(), NULL));
+ ENGINE_free(e);
+ goto out;
+ }
+
+ ret = eval_pairs(context, e, ctx.engine_name, "post",
+ ctx.post_cmds, ctx.num_post);
+ if (ret)
+ goto out;
+
+ /*
+ * If the engine supports a LOAD_CERT_CTRL function, lets try
+ * it. OpenSC support this function. Eventially this should be
+ * a ENGINE_load_cert function if it failes, treat it like a
+ * non fatal error.
+ */
+ {
+ struct {
+ const char * cert_id;
+ X509 * cert;
+ } parms;
+
+ parms.cert_id = ctx.cert_file;
+ parms.cert = NULL;
+ ENGINE_ctrl_cmd(e, "LOAD_CERT_CTRL", 0, &parms, NULL, 1);
+ if (parms.cert) {
+ id->cert = sk_X509_new_null();
+ sk_X509_insert(id->cert, parms.cert, 0);
+ }
+ }
+
+ if (id->cert == NULL) {
+ ret = load_openssl_cert(context, ctx.cert_file, &id->cert);
+ if (ret)
+ goto out;
+ }
+
+ {
+ UI_METHOD * krb5_ui_method = NULL;
+ struct krb5_ui_data ui_data;
+
+ krb5_ui_method = UI_create_method("Krb5 ui method");
+ if (krb5_ui_method == NULL) {
+ krb5_set_error_string(context,
+ "PKINIT: failed to setup prompter "
+ "function: %s",
+ ERR_error_string(ERR_get_error(), NULL));
+ ret = HEIM_PKINIT_NO_PRIVATE_KEY;
+ goto out;
+ }
+ UI_method_set_reader(krb5_ui_method, krb5_ui_method_read_string);
+
+ ui_data.context = context;
+ ui_data.prompter = prompter;
+ if (prompter == NULL)
+ ui_data.prompter = krb5_prompter_posix;
+ ui_data.prompter_data = prompter_data;
+
+ id->private_key = ENGINE_load_private_key(e,
+ ctx.key_id,
+ krb5_ui_method,
+ (void*) &ui_data);
+ UI_destroy_method(krb5_ui_method);
+ }
+
+ if (id->private_key == NULL) {
+ krb5_set_error_string(context,
+ "PKINIT: failed to load private key: %s",
+ ERR_error_string(ERR_get_error(), NULL));
+ ret = HEIM_PKINIT_NO_PRIVATE_KEY;
+ goto out;
+ }
+
+ ret = X509_check_private_key(sk_X509_value(id->cert, 0), id->private_key);
+ if (ret != 1) {
+ ret = HEIM_PKINIT_PRIVATE_KEY_INVALID;
+ krb5_set_error_string(context,
+ "PKINIT: The private key doesn't match "
+ "the public key certificate");
+ goto out;
+ }
+
+ if (user_conf)
+ free(user_conf);
+ if (file_conf)
+ free(file_conf);
+
+ id->engine = e;
+
+ return 0;
+
+ out:
+ if (user_conf)
+ free(user_conf);
+ if (file_conf)
+ free(file_conf);
+ if (e) {
+ ENGINE_finish(e); /* make sure all shared libs are unloaded */
+ ENGINE_free(e);
+ }
+
+ return ret;
+}
+
+krb5_error_code KRB5_LIB_FUNCTION
+_krb5_pk_load_openssl_id(krb5_context context,
+ struct krb5_pk_identity **ret_id,
+ const char *user_id,
+ const char *x509_anchors,
+ krb5_prompter_fct prompter,
+ void *prompter_data,
+ char *password)
+{
+ STACK_OF(X509) *trusted_certs = NULL;
+ struct krb5_pk_identity *id = NULL;
+ krb5_error_code ret;
+ struct dirent *file;
+ char *dirname = NULL;
+ DIR *dir;
+ FILE *f;
+ krb5_error_code (*load_pair)(krb5_context,
+ char *,
+ krb5_prompter_fct prompter,
+ void * prompter_data,
+ const char *,
+ struct krb5_pk_identity *) = NULL;
+
+
+ *ret_id = NULL;
+
+ if (x509_anchors == NULL) {
+ krb5_set_error_string(context, "PKINIT: No root ca directory given");
+ return HEIM_PKINIT_NO_VALID_CA;
+ }
+
+ if (user_id == NULL) {
+ krb5_set_error_string(context,
+ "PKINIT: No user X509 source given given");
+ return HEIM_PKINIT_NO_PRIVATE_KEY;
+ }
+
+ /*
+ *
+ */
+
+ if (strncasecmp(user_id, "FILE:", 5) == 0) {
+ load_pair = load_openssl_file;
+ user_id += 5;
+ } else if (strncasecmp(user_id, "ENGINE:", 7) == 0) {
+ load_pair = load_openssl_engine;
+ user_id += 7;
+ } else {
+ krb5_set_error_string(context, "PKINIT: user identity not FILE");
+ return HEIM_PKINIT_NO_CERTIFICATE;
+ }
+ if (strncasecmp(x509_anchors, "OPENSSL-ANCHOR-DIR:", 19) != 0) {
+ krb5_set_error_string(context, "PKINIT: anchor OPENSSL-ANCHOR-DIR");
+ return HEIM_PKINIT_NO_VALID_CA;
+ }
+ x509_anchors += 19;
+
+ id = malloc(sizeof(*id));
+ if (id == NULL) {
+ krb5_set_error_string(context, "malloc: out of memory");
+ ret = ENOMEM;
+ goto out;
+ }
+ memset(id, 0, sizeof(*id));
+
+ OpenSSL_add_all_algorithms();
+ ERR_load_crypto_strings();
+
+
+ ret = (*load_pair)(context, password, prompter, prompter_data, user_id, id);
+ if (ret)
+ goto out;
+
+ /* load anchors */
+
+ dirname = strdup(x509_anchors);
+ if (dirname == NULL) {
+ krb5_set_error_string(context, "malloc: out of memory");
+ ret = ENOMEM;
+ goto out;
+ }
+
+ {
+ size_t len;
+ len = strlen(dirname);
+ if (dirname[len - 1] == '/')
+ dirname[len - 1] = '\0';
+ }
+
+ /* read ca certificates */
+ dir = opendir(dirname);
+ if (dir == NULL) {
+ ret = errno;
+ krb5_set_error_string(context, "PKINIT: open directory %s: %s",
+ dirname, strerror(ret));
+ goto out;
+ }
+
+ trusted_certs = sk_X509_new_null();
+ while ((file = readdir(dir)) != NULL) {
+ X509 *cert;
+ char *filename;
+
+ /*
+ * Assume the certificate filenames constist of hashed subject
+ * name followed by suffix ".0"
+ */
+
+ if (strlen(file->d_name) == 10 && strcmp(&file->d_name[8],".0") == 0) {
+ asprintf(&filename, "%s/%s", dirname, file->d_name);
+ if (filename == NULL) {
+ ret = ENOMEM;
+ krb5_set_error_string(context, "malloc: out or memory");
+ goto out;
+ }
+ f = fopen(filename, "r");
+ if (f == NULL) {
+ ret = errno;
+ krb5_set_error_string(context, "PKINIT: open %s: %s",
+ filename, strerror(ret));
+ free(filename);
+ closedir(dir);
+ goto out;
+ }
+ cert = PEM_read_X509(f, NULL, NULL, NULL);
+ fclose(f);
+ if (cert != NULL) {
+ /* order of the certs is not important */
+ sk_X509_push(trusted_certs, cert);
+ }
+ free(filename);
+ }
+ }
+ closedir(dir);
+
+ if (sk_X509_num(trusted_certs) == 0) {
+ krb5_set_error_string(context,
+ "PKINIT: No CA certificate(s) found in %s",
+ dirname);
+ ret = HEIM_PKINIT_NO_VALID_CA;
+ goto out;
+ }
+
+ id->trusted_certs = trusted_certs;
+
+ *ret_id = id;
+
+ return 0;
+
+ out:
+ if (dirname)
+ free(dirname);
+ if (trusted_certs)
+ sk_X509_pop_free(trusted_certs, X509_free);
+ if (id) {
+ if (id->cert)
+ sk_X509_pop_free(id->cert, X509_free);
+ if (id->private_key)
+ EVP_PKEY_free(id->private_key);
+ free(id);
+ }
+
+ return ret;
+}
+
+#endif /* PKINIT */
+
+void KRB5_LIB_FUNCTION
+_krb5_get_init_creds_opt_free_pkinit(krb5_get_init_creds_opt *opt)
+{
+#ifdef PKINIT
+ krb5_pk_init_ctx ctx;
+
+ if (opt->private == NULL || opt->private->pk_init_ctx == NULL)
+ return;
+ ctx = opt->private->pk_init_ctx;
+ if (ctx->dh)
+ DH_free(ctx->dh);
+ ctx->dh = NULL;
+ if (ctx->id) {
+ if (ctx->id->cert)
+ sk_X509_pop_free(ctx->id->cert, X509_free);
+ if (ctx->id->trusted_certs)
+ sk_X509_pop_free(ctx->id->trusted_certs, X509_free);
+ if (ctx->id->private_key)
+ EVP_PKEY_free(ctx->id->private_key);
+ if (ctx->id->engine) {
+ ENGINE_finish(ctx->id->engine); /* unload shared libs etc */
+ ENGINE_free(ctx->id->engine);
+ ctx->id->engine = NULL;
+ }
+ free(ctx->id);
+ ctx->id = NULL;
+ }
+ opt->private->pk_init_ctx = NULL;
+#endif
+}
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_get_init_creds_opt_set_pkinit(krb5_context context,
+ krb5_get_init_creds_opt *opt,
+ krb5_principal principal,
+ const char *user_id,
+ const char *x509_anchors,
+ int flags,
+ krb5_prompter_fct prompter,
+ void *prompter_data,
+ char *password)
+{
+#ifdef PKINIT
+ krb5_error_code ret;
+
+ if (opt->private == NULL) {
+ krb5_set_error_string(context, "PKINIT: on non extendable opt");
+ return EINVAL;
+ }
+
+ opt->private->pk_init_ctx = malloc(sizeof(*opt->private->pk_init_ctx));
+ if (opt->private->pk_init_ctx == NULL) {
+ krb5_set_error_string(context, "malloc: out of memory");
+ return ENOMEM;
+ }
+ opt->private->pk_init_ctx->dh = NULL;
+ opt->private->pk_init_ctx->id = NULL;
+ ret = _krb5_pk_load_openssl_id(context,
+ &opt->private->pk_init_ctx->id,
+ user_id,
+ x509_anchors,
+ prompter,
+ prompter_data,
+ password);
+ if (ret) {
+ free(opt->private->pk_init_ctx);
+ opt->private->pk_init_ctx = NULL;
+ }
+
+ /* XXX */
+ if (ret == 0 && (flags & 1) && !(flags & 2)) {
+ DH *dh;
+ const char *P =
+ "FFFFFFFF" "FFFFFFFF" "C90FDAA2" "2168C234" "C4C6628B" "80DC1CD1"
+ "29024E08" "8A67CC74" "020BBEA6" "3B139B22" "514A0879" "8E3404DD"
+ "EF9519B3" "CD3A431B" "302B0A6D" "F25F1437" "4FE1356D" "6D51C245"
+ "E485B576" "625E7EC6" "F44C42E9" "A637ED6B" "0BFF5CB6" "F406B7ED"
+ "EE386BFB" "5A899FA5" "AE9F2411" "7C4B1FE6" "49286651" "ECE65381"
+ "FFFFFFFF" "FFFFFFFF";
+ const char *G = "2";
+ const char *Q =
+ "7FFFFFFF" "FFFFFFFF" "E487ED51" "10B4611A" "62633145" "C06E0E68"
+ "94812704" "4533E63A" "0105DF53" "1D89CD91" "28A5043C" "C71A026E"
+ "F7CA8CD9" "E69D218D" "98158536" "F92F8A1B" "A7F09AB6" "B6A8E122"
+ "F242DABB" "312F3F63" "7A262174" "D31BF6B5" "85FFAE5B" "7A035BF6"
+ "F71C35FD" "AD44CFD2" "D74F9208" "BE258FF3" "24943328" "F67329C0"
+ "FFFFFFFF" "FFFFFFFF";
+
+ dh = DH_new();
+ if (dh == NULL) {
+ _krb5_get_init_creds_opt_free_pkinit(opt);
+ return ENOMEM;
+ }
+ opt->private->pk_init_ctx->dh = dh;
+ if (!BN_hex2bn(&dh->p, P)) {
+ _krb5_get_init_creds_opt_free_pkinit(opt);
+ return ENOMEM;
+ }
+ if (!BN_hex2bn(&dh->g, G)) {
+ _krb5_get_init_creds_opt_free_pkinit(opt);
+ return ENOMEM;
+ }
+ if (!BN_hex2bn(&dh->q, Q)) {
+ _krb5_get_init_creds_opt_free_pkinit(opt);
+ return ENOMEM;
+ }
+ /* XXX generate a new key for each request ? */
+ if (DH_generate_key(dh) != 1) {
+ _krb5_get_init_creds_opt_free_pkinit(opt);
+ return ENOMEM;
+ }
+ }
+ return ret;
+#else
+ krb5_set_error_string(context, "no support for PKINIT compiled in");
+ return EINVAL;
+#endif
+}
diff --git a/source4/heimdal/lib/krb5/principal.c b/source4/heimdal/lib/krb5/principal.c
new file mode 100644
index 0000000000..b7194b4c41
--- /dev/null
+++ b/source4/heimdal/lib/krb5/principal.c
@@ -0,0 +1,1125 @@
+/*
+ * Copyright (c) 1997-2002 Kungliga Tekniska Högskolan
+ * (Royal Institute of Technology, Stockholm, Sweden).
+ * 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"
+#ifdef HAVE_RES_SEARCH
+#define USE_RESOLVER
+#endif
+#ifdef HAVE_ARPA_NAMESER_H
+#include <arpa/nameser.h>
+#endif
+#include <fnmatch.h>
+#include "resolve.h"
+
+RCSID("$Id: principal.c,v 1.90 2005/06/30 01:38:15 lha Exp $");
+
+#define princ_num_comp(P) ((P)->name.name_string.len)
+#define princ_type(P) ((P)->name.name_type)
+#define princ_comp(P) ((P)->name.name_string.val)
+#define princ_ncomp(P, N) ((P)->name.name_string.val[(N)])
+#define princ_realm(P) ((P)->realm)
+
+void KRB5_LIB_FUNCTION
+krb5_free_principal(krb5_context context,
+ krb5_principal p)
+{
+ if(p){
+ free_Principal(p);
+ free(p);
+ }
+}
+
+void KRB5_LIB_FUNCTION
+krb5_principal_set_type(krb5_context context,
+ krb5_principal principal,
+ int type)
+{
+ princ_type(principal) = type;
+}
+
+int KRB5_LIB_FUNCTION
+krb5_principal_get_type(krb5_context context,
+ krb5_principal principal)
+{
+ return princ_type(principal);
+}
+
+const char* KRB5_LIB_FUNCTION
+krb5_principal_get_realm(krb5_context context,
+ krb5_const_principal principal)
+{
+ return princ_realm(principal);
+}
+
+const char* KRB5_LIB_FUNCTION
+krb5_principal_get_comp_string(krb5_context context,
+ krb5_principal principal,
+ unsigned int component)
+{
+ if(component >= princ_num_comp(principal))
+ return NULL;
+ return princ_ncomp(principal, component);
+}
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_parse_name(krb5_context context,
+ const char *name,
+ krb5_principal *principal)
+{
+ krb5_error_code ret;
+ heim_general_string *comp;
+ heim_general_string realm;
+ int ncomp;
+
+ const char *p;
+ char *q;
+ char *s;
+ char *start;
+
+ int n;
+ char c;
+ int got_realm = 0;
+
+ /* count number of component */
+ ncomp = 1;
+ for(p = name; *p; p++){
+ if(*p=='\\'){
+ if(!p[1]) {
+ krb5_set_error_string (context,
+ "trailing \\ in principal name");
+ return KRB5_PARSE_MALFORMED;
+ }
+ p++;
+ } else if(*p == '/')
+ ncomp++;
+ }
+ comp = calloc(ncomp, sizeof(*comp));
+ if (comp == NULL) {
+ krb5_set_error_string (context, "malloc: out of memory");
+ return ENOMEM;
+ }
+
+ n = 0;
+ p = start = q = s = strdup(name);
+ if (start == NULL) {
+ free (comp);
+ krb5_set_error_string (context, "malloc: out of memory");
+ return ENOMEM;
+ }
+ while(*p){
+ c = *p++;
+ if(c == '\\'){
+ c = *p++;
+ if(c == 'n')
+ c = '\n';
+ else if(c == 't')
+ c = '\t';
+ else if(c == 'b')
+ c = '\b';
+ else if(c == '0')
+ c = '\0';
+ else if(c == '\0') {
+ krb5_set_error_string (context,
+ "trailing \\ in principal name");
+ ret = KRB5_PARSE_MALFORMED;
+ goto exit;
+ }
+ }else if(c == '/' || c == '@'){
+ if(got_realm){
+ krb5_set_error_string (context,
+ "part after realm in principal name");
+ ret = KRB5_PARSE_MALFORMED;
+ goto exit;
+ }else{
+ comp[n] = malloc(q - start + 1);
+ if (comp[n] == NULL) {
+ krb5_set_error_string (context, "malloc: out of memory");
+ ret = ENOMEM;
+ goto exit;
+ }
+ memcpy(comp[n], start, q - start);
+ comp[n][q - start] = 0;
+ n++;
+ }
+ if(c == '@')
+ got_realm = 1;
+ start = q;
+ continue;
+ }
+ if(got_realm && (c == ':' || c == '/' || c == '\0')) {
+ krb5_set_error_string (context,
+ "part after realm in principal name");
+ ret = KRB5_PARSE_MALFORMED;
+ goto exit;
+ }
+ *q++ = c;
+ }
+ if(got_realm){
+ realm = malloc(q - start + 1);
+ if (realm == NULL) {
+ krb5_set_error_string (context, "malloc: out of memory");
+ ret = ENOMEM;
+ goto exit;
+ }
+ memcpy(realm, start, q - start);
+ realm[q - start] = 0;
+ }else{
+ ret = krb5_get_default_realm (context, &realm);
+ if (ret)
+ goto exit;
+
+ comp[n] = malloc(q - start + 1);
+ if (comp[n] == NULL) {
+ krb5_set_error_string (context, "malloc: out of memory");
+ ret = ENOMEM;
+ goto exit;
+ }
+ memcpy(comp[n], start, q - start);
+ comp[n][q - start] = 0;
+ n++;
+ }
+ *principal = malloc(sizeof(**principal));
+ if (*principal == NULL) {
+ krb5_set_error_string (context, "malloc: out of memory");
+ ret = ENOMEM;
+ goto exit;
+ }
+ (*principal)->name.name_type = KRB5_NT_PRINCIPAL;
+ (*principal)->name.name_string.val = comp;
+ princ_num_comp(*principal) = n;
+ (*principal)->realm = realm;
+ free(s);
+ return 0;
+exit:
+ while(n>0){
+ free(comp[--n]);
+ }
+ free(comp);
+ free(s);
+ return ret;
+}
+
+static const char quotable_chars[] = " \n\t\b\\/@";
+static const char replace_chars[] = " ntb\\/@";
+
+#define add_char(BASE, INDEX, LEN, C) do { if((INDEX) < (LEN)) (BASE)[(INDEX)++] = (C); }while(0);
+
+static size_t
+quote_string(const char *s, char *out, size_t string_index, size_t len)
+{
+ const char *p, *q;
+ for(p = s; *p && string_index < len; p++){
+ if((q = strchr(quotable_chars, *p))){
+ add_char(out, string_index, len, '\\');
+ add_char(out, string_index, len, replace_chars[q - quotable_chars]);
+ }else
+ add_char(out, string_index, len, *p);
+ }
+ if(string_index < len)
+ out[string_index] = '\0';
+ return string_index;
+}
+
+
+static krb5_error_code
+unparse_name_fixed(krb5_context context,
+ krb5_const_principal principal,
+ char *name,
+ size_t len,
+ krb5_boolean short_form)
+{
+ size_t idx = 0;
+ int i;
+ for(i = 0; i < princ_num_comp(principal); i++){
+ if(i)
+ add_char(name, idx, len, '/');
+ idx = quote_string(princ_ncomp(principal, i), name, idx, len);
+ if(idx == len)
+ return ERANGE;
+ }
+ /* add realm if different from default realm */
+ if(short_form) {
+ krb5_realm r;
+ krb5_error_code ret;
+ ret = krb5_get_default_realm(context, &r);
+ if(ret)
+ return ret;
+ if(strcmp(princ_realm(principal), r) != 0)
+ short_form = 0;
+ free(r);
+ }
+ if(!short_form) {
+ add_char(name, idx, len, '@');
+ idx = quote_string(princ_realm(principal), name, idx, len);
+ if(idx == len)
+ return ERANGE;
+ }
+ return 0;
+}
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_unparse_name_fixed(krb5_context context,
+ krb5_const_principal principal,
+ char *name,
+ size_t len)
+{
+ return unparse_name_fixed(context, principal, name, len, FALSE);
+}
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_unparse_name_fixed_short(krb5_context context,
+ krb5_const_principal principal,
+ char *name,
+ size_t len)
+{
+ return unparse_name_fixed(context, principal, name, len, TRUE);
+}
+
+static krb5_error_code
+unparse_name(krb5_context context,
+ krb5_const_principal principal,
+ char **name,
+ krb5_boolean short_flag)
+{
+ size_t len = 0, plen;
+ int i;
+ krb5_error_code ret;
+ /* count length */
+ plen = strlen(princ_realm(principal));
+ if(strcspn(princ_realm(principal), quotable_chars) == plen)
+ len += plen;
+ else
+ len += 2*plen;
+ len++;
+ for(i = 0; i < princ_num_comp(principal); i++){
+ plen = strlen(princ_ncomp(principal, i));
+ if(strcspn(princ_ncomp(principal, i), quotable_chars) == plen)
+ len += plen;
+ else
+ len += 2*plen;
+ len++;
+ }
+ len++;
+ *name = malloc(len);
+ if(*name == NULL) {
+ krb5_set_error_string (context, "malloc: out of memory");
+ return ENOMEM;
+ }
+ ret = unparse_name_fixed(context, principal, *name, len, short_flag);
+ if(ret) {
+ free(*name);
+ *name = NULL;
+ }
+ return ret;
+}
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_unparse_name(krb5_context context,
+ krb5_const_principal principal,
+ char **name)
+{
+ return unparse_name(context, principal, name, FALSE);
+}
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_unparse_name_short(krb5_context context,
+ krb5_const_principal principal,
+ char **name)
+{
+ return unparse_name(context, principal, name, TRUE);
+}
+
+#if 0 /* not implemented */
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_unparse_name_ext(krb5_context context,
+ krb5_const_principal principal,
+ char **name,
+ size_t *size)
+{
+ krb5_abortx(context, "unimplemented krb5_unparse_name_ext called");
+}
+
+#endif
+
+krb5_realm*
+krb5_princ_realm(krb5_context context,
+ krb5_principal principal)
+{
+ return &princ_realm(principal);
+}
+
+
+void KRB5_LIB_FUNCTION
+krb5_princ_set_realm(krb5_context context,
+ krb5_principal principal,
+ krb5_realm *realm)
+{
+ princ_realm(principal) = *realm;
+}
+
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_build_principal(krb5_context context,
+ krb5_principal *principal,
+ int rlen,
+ krb5_const_realm realm,
+ ...)
+{
+ krb5_error_code ret;
+ va_list ap;
+ va_start(ap, realm);
+ ret = krb5_build_principal_va(context, principal, rlen, realm, ap);
+ va_end(ap);
+ return ret;
+}
+
+static krb5_error_code
+append_component(krb5_context context, krb5_principal p,
+ const char *comp,
+ size_t comp_len)
+{
+ heim_general_string *tmp;
+ size_t len = princ_num_comp(p);
+
+ tmp = realloc(princ_comp(p), (len + 1) * sizeof(*tmp));
+ if(tmp == NULL) {
+ krb5_set_error_string (context, "malloc: out of memory");
+ return ENOMEM;
+ }
+ princ_comp(p) = tmp;
+ princ_ncomp(p, len) = malloc(comp_len + 1);
+ if (princ_ncomp(p, len) == NULL) {
+ krb5_set_error_string (context, "malloc: out of memory");
+ return ENOMEM;
+ }
+ memcpy (princ_ncomp(p, len), comp, comp_len);
+ princ_ncomp(p, len)[comp_len] = '\0';
+ princ_num_comp(p)++;
+ return 0;
+}
+
+static void
+va_ext_princ(krb5_context context, krb5_principal p, va_list ap)
+{
+ while(1){
+ const char *s;
+ int len;
+ len = va_arg(ap, int);
+ if(len == 0)
+ break;
+ s = va_arg(ap, const char*);
+ append_component(context, p, s, len);
+ }
+}
+
+static void
+va_princ(krb5_context context, krb5_principal p, va_list ap)
+{
+ while(1){
+ const char *s;
+ s = va_arg(ap, const char*);
+ if(s == NULL)
+ break;
+ append_component(context, p, s, strlen(s));
+ }
+}
+
+
+static krb5_error_code
+build_principal(krb5_context context,
+ krb5_principal *principal,
+ int rlen,
+ krb5_const_realm realm,
+ void (*func)(krb5_context, krb5_principal, va_list),
+ va_list ap)
+{
+ krb5_principal p;
+
+ p = calloc(1, sizeof(*p));
+ if (p == NULL) {
+ krb5_set_error_string (context, "malloc: out of memory");
+ return ENOMEM;
+ }
+ princ_type(p) = KRB5_NT_PRINCIPAL;
+
+ princ_realm(p) = strdup(realm);
+ if(p->realm == NULL){
+ free(p);
+ krb5_set_error_string (context, "malloc: out of memory");
+ return ENOMEM;
+ }
+
+ (*func)(context, p, ap);
+ *principal = p;
+ return 0;
+}
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_make_principal(krb5_context context,
+ krb5_principal *principal,
+ krb5_const_realm realm,
+ ...)
+{
+ krb5_error_code ret;
+ krb5_realm r = NULL;
+ va_list ap;
+ if(realm == NULL) {
+ ret = krb5_get_default_realm(context, &r);
+ if(ret)
+ return ret;
+ realm = r;
+ }
+ va_start(ap, realm);
+ ret = krb5_build_principal_va(context, principal, strlen(realm), realm, ap);
+ va_end(ap);
+ if(r)
+ free(r);
+ return ret;
+}
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_build_principal_va(krb5_context context,
+ krb5_principal *principal,
+ int rlen,
+ krb5_const_realm realm,
+ va_list ap)
+{
+ return build_principal(context, principal, rlen, realm, va_princ, ap);
+}
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_build_principal_va_ext(krb5_context context,
+ krb5_principal *principal,
+ int rlen,
+ krb5_const_realm realm,
+ va_list ap)
+{
+ return build_principal(context, principal, rlen, realm, va_ext_princ, ap);
+}
+
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_build_principal_ext(krb5_context context,
+ krb5_principal *principal,
+ int rlen,
+ krb5_const_realm realm,
+ ...)
+{
+ krb5_error_code ret;
+ va_list ap;
+ va_start(ap, realm);
+ ret = krb5_build_principal_va_ext(context, principal, rlen, realm, ap);
+ va_end(ap);
+ return ret;
+}
+
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_copy_principal(krb5_context context,
+ krb5_const_principal inprinc,
+ krb5_principal *outprinc)
+{
+ krb5_principal p = malloc(sizeof(*p));
+ if (p == NULL) {
+ krb5_set_error_string (context, "malloc: out of memory");
+ return ENOMEM;
+ }
+ if(copy_Principal(inprinc, p)) {
+ free(p);
+ krb5_set_error_string (context, "malloc: out of memory");
+ return ENOMEM;
+ }
+ *outprinc = p;
+ return 0;
+}
+
+/*
+ * return TRUE iff princ1 == princ2 (without considering the realm)
+ */
+
+krb5_boolean KRB5_LIB_FUNCTION
+krb5_principal_compare_any_realm(krb5_context context,
+ krb5_const_principal princ1,
+ krb5_const_principal princ2)
+{
+ int i;
+ if(princ_num_comp(princ1) != princ_num_comp(princ2))
+ return FALSE;
+ for(i = 0; i < princ_num_comp(princ1); i++){
+ if(strcmp(princ_ncomp(princ1, i), princ_ncomp(princ2, i)) != 0)
+ return FALSE;
+ }
+ return TRUE;
+}
+
+/*
+ * return TRUE iff princ1 == princ2
+ */
+
+krb5_boolean KRB5_LIB_FUNCTION
+krb5_principal_compare(krb5_context context,
+ krb5_const_principal princ1,
+ krb5_const_principal princ2)
+{
+ if(!krb5_realm_compare(context, princ1, princ2))
+ return FALSE;
+ return krb5_principal_compare_any_realm(context, princ1, princ2);
+}
+
+/*
+ * return TRUE iff realm(princ1) == realm(princ2)
+ */
+
+krb5_boolean KRB5_LIB_FUNCTION
+krb5_realm_compare(krb5_context context,
+ krb5_const_principal princ1,
+ krb5_const_principal princ2)
+{
+ return strcmp(princ_realm(princ1), princ_realm(princ2)) == 0;
+}
+
+/*
+ * return TRUE iff princ matches pattern
+ */
+
+krb5_boolean KRB5_LIB_FUNCTION
+krb5_principal_match(krb5_context context,
+ krb5_const_principal princ,
+ krb5_const_principal pattern)
+{
+ int i;
+ if(princ_num_comp(princ) != princ_num_comp(pattern))
+ return FALSE;
+ if(fnmatch(princ_realm(pattern), princ_realm(princ), 0) != 0)
+ return FALSE;
+ for(i = 0; i < princ_num_comp(princ); i++){
+ if(fnmatch(princ_ncomp(pattern, i), princ_ncomp(princ, i), 0) != 0)
+ return FALSE;
+ }
+ return TRUE;
+}
+
+
+static struct v4_name_convert {
+ const char *from;
+ const char *to;
+} default_v4_name_convert[] = {
+ { "ftp", "ftp" },
+ { "hprop", "hprop" },
+ { "pop", "pop" },
+ { "imap", "imap" },
+ { "rcmd", "host" },
+ { "smtp", "smtp" },
+ { NULL, NULL }
+};
+
+/*
+ * return the converted instance name of `name' in `realm'.
+ * look in the configuration file and then in the default set above.
+ * return NULL if no conversion is appropriate.
+ */
+
+static const char*
+get_name_conversion(krb5_context context, const char *realm, const char *name)
+{
+ struct v4_name_convert *q;
+ const char *p;
+
+ p = krb5_config_get_string(context, NULL, "realms", realm,
+ "v4_name_convert", "host", name, NULL);
+ if(p == NULL)
+ p = krb5_config_get_string(context, NULL, "libdefaults",
+ "v4_name_convert", "host", name, NULL);
+ if(p)
+ return p;
+
+ /* XXX should be possible to override default list */
+ p = krb5_config_get_string(context, NULL,
+ "realms",
+ realm,
+ "v4_name_convert",
+ "plain",
+ name,
+ NULL);
+ if(p)
+ return NULL;
+ p = krb5_config_get_string(context, NULL,
+ "libdefaults",
+ "v4_name_convert",
+ "plain",
+ name,
+ NULL);
+ if(p)
+ return NULL;
+ for(q = default_v4_name_convert; q->from; q++)
+ if(strcmp(q->from, name) == 0)
+ return q->to;
+ return NULL;
+}
+
+/*
+ * convert the v4 principal `name.instance@realm' to a v5 principal in `princ'.
+ * if `resolve', use DNS.
+ * if `func', use that function for validating the conversion
+ */
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_425_conv_principal_ext2(krb5_context context,
+ const char *name,
+ const char *instance,
+ const char *realm,
+ krb5_boolean (*func)(krb5_context,
+ void *, krb5_principal),
+ void *funcctx,
+ krb5_boolean resolve,
+ krb5_principal *princ)
+{
+ const char *p;
+ krb5_error_code ret;
+ krb5_principal pr;
+ char host[MAXHOSTNAMELEN];
+ char local_hostname[MAXHOSTNAMELEN];
+
+ /* do the following: if the name is found in the
+ `v4_name_convert:host' part, is is assumed to be a `host' type
+ principal, and the instance is looked up in the
+ `v4_instance_convert' part. if not found there the name is
+ (optionally) looked up as a hostname, and if that doesn't yield
+ anything, the `default_domain' is appended to the instance
+ */
+
+ if(instance == NULL)
+ goto no_host;
+ if(instance[0] == 0){
+ instance = NULL;
+ goto no_host;
+ }
+ p = get_name_conversion(context, realm, name);
+ if(p == NULL)
+ goto no_host;
+ name = p;
+ p = krb5_config_get_string(context, NULL, "realms", realm,
+ "v4_instance_convert", instance, NULL);
+ if(p){
+ instance = p;
+ ret = krb5_make_principal(context, &pr, realm, name, instance, NULL);
+ if(func == NULL || (*func)(context, funcctx, pr)){
+ *princ = pr;
+ return 0;
+ }
+ krb5_free_principal(context, pr);
+ *princ = NULL;
+ krb5_clear_error_string (context);
+ return HEIM_ERR_V4_PRINC_NO_CONV;
+ }
+ if(resolve){
+ krb5_boolean passed = FALSE;
+ char *inst = NULL;
+#ifdef USE_RESOLVER
+ struct dns_reply *r;
+
+ r = dns_lookup(instance, "aaaa");
+ if (r && r->head && r->head->type == T_AAAA) {
+ inst = strdup(r->head->domain);
+ dns_free_data(r);
+ passed = TRUE;
+ } else {
+ r = dns_lookup(instance, "a");
+ if(r && r->head && r->head->type == T_A) {
+ inst = strdup(r->head->domain);
+ dns_free_data(r);
+ passed = TRUE;
+ }
+ }
+#else
+ struct addrinfo hints, *ai;
+ int ret;
+
+ memset (&hints, 0, sizeof(hints));
+ hints.ai_flags = AI_CANONNAME;
+ ret = getaddrinfo(instance, NULL, &hints, &ai);
+ if (ret == 0) {
+ const struct addrinfo *a;
+ for (a = ai; a != NULL; a = a->ai_next) {
+ if (a->ai_canonname != NULL) {
+ inst = strdup (a->ai_canonname);
+ passed = TRUE;
+ break;
+ }
+ }
+ freeaddrinfo (ai);
+ }
+#endif
+ if (passed) {
+ if (inst == NULL) {
+ krb5_set_error_string (context, "malloc: out of memory");
+ return ENOMEM;
+ }
+ strlwr(inst);
+ ret = krb5_make_principal(context, &pr, realm, name, inst,
+ NULL);
+ free (inst);
+ if(ret == 0) {
+ if(func == NULL || (*func)(context, funcctx, pr)){
+ *princ = pr;
+ return 0;
+ }
+ krb5_free_principal(context, pr);
+ }
+ }
+ }
+ if(func != NULL) {
+ snprintf(host, sizeof(host), "%s.%s", instance, realm);
+ strlwr(host);
+ ret = krb5_make_principal(context, &pr, realm, name, host, NULL);
+ if((*func)(context, funcctx, pr)){
+ *princ = pr;
+ return 0;
+ }
+ krb5_free_principal(context, pr);
+ }
+
+ /*
+ * if the instance is the first component of the local hostname,
+ * the converted host should be the long hostname.
+ */
+
+ if (func == NULL &&
+ gethostname (local_hostname, sizeof(local_hostname)) == 0 &&
+ strncmp(instance, local_hostname, strlen(instance)) == 0 &&
+ local_hostname[strlen(instance)] == '.') {
+ strlcpy(host, local_hostname, sizeof(host));
+ goto local_host;
+ }
+
+ {
+ char **domains, **d;
+ domains = krb5_config_get_strings(context, NULL, "realms", realm,
+ "v4_domains", NULL);
+ for(d = domains; d && *d; d++){
+ snprintf(host, sizeof(host), "%s.%s", instance, *d);
+ ret = krb5_make_principal(context, &pr, realm, name, host, NULL);
+ if(func == NULL || (*func)(context, funcctx, pr)){
+ *princ = pr;
+ krb5_config_free_strings(domains);
+ return 0;
+ }
+ krb5_free_principal(context, pr);
+ }
+ krb5_config_free_strings(domains);
+ }
+
+
+ p = krb5_config_get_string(context, NULL, "realms", realm,
+ "default_domain", NULL);
+ if(p == NULL){
+ /* this should be an error, just faking a name is not good */
+ krb5_clear_error_string (context);
+ return HEIM_ERR_V4_PRINC_NO_CONV;
+ }
+
+ if (*p == '.')
+ ++p;
+ snprintf(host, sizeof(host), "%s.%s", instance, p);
+local_host:
+ ret = krb5_make_principal(context, &pr, realm, name, host, NULL);
+ if(func == NULL || (*func)(context, funcctx, pr)){
+ *princ = pr;
+ return 0;
+ }
+ krb5_free_principal(context, pr);
+ krb5_clear_error_string (context);
+ return HEIM_ERR_V4_PRINC_NO_CONV;
+no_host:
+ p = krb5_config_get_string(context, NULL,
+ "realms",
+ realm,
+ "v4_name_convert",
+ "plain",
+ name,
+ NULL);
+ if(p == NULL)
+ p = krb5_config_get_string(context, NULL,
+ "libdefaults",
+ "v4_name_convert",
+ "plain",
+ name,
+ NULL);
+ if(p)
+ name = p;
+
+ ret = krb5_make_principal(context, &pr, realm, name, instance, NULL);
+ if(func == NULL || (*func)(context, funcctx, pr)){
+ *princ = pr;
+ return 0;
+ }
+ krb5_free_principal(context, pr);
+ krb5_clear_error_string (context);
+ return HEIM_ERR_V4_PRINC_NO_CONV;
+}
+
+static krb5_boolean
+convert_func(krb5_context conxtext, void *funcctx, krb5_principal principal)
+{
+ krb5_boolean (*func)(krb5_context, krb5_principal) = funcctx;
+ return (*func)(conxtext, principal);
+}
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_425_conv_principal_ext(krb5_context context,
+ const char *name,
+ const char *instance,
+ const char *realm,
+ krb5_boolean (*func)(krb5_context, krb5_principal),
+ krb5_boolean resolve,
+ krb5_principal *principal)
+{
+ return krb5_425_conv_principal_ext2(context,
+ name,
+ instance,
+ realm,
+ func ? convert_func : NULL,
+ func,
+ resolve,
+ principal);
+}
+
+
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_425_conv_principal(krb5_context context,
+ const char *name,
+ const char *instance,
+ const char *realm,
+ krb5_principal *princ)
+{
+ krb5_boolean resolve = krb5_config_get_bool(context,
+ NULL,
+ "libdefaults",
+ "v4_instance_resolve",
+ NULL);
+
+ return krb5_425_conv_principal_ext(context, name, instance, realm,
+ NULL, resolve, princ);
+}
+
+
+static int
+check_list(const krb5_config_binding *l, const char *name, const char **out)
+{
+ while(l){
+ if (l->type != krb5_config_string)
+ continue;
+ if(strcmp(name, l->u.string) == 0) {
+ *out = l->name;
+ return 1;
+ }
+ l = l->next;
+ }
+ return 0;
+}
+
+static int
+name_convert(krb5_context context, const char *name, const char *realm,
+ const char **out)
+{
+ const krb5_config_binding *l;
+ l = krb5_config_get_list (context,
+ NULL,
+ "realms",
+ realm,
+ "v4_name_convert",
+ "host",
+ NULL);
+ if(l && check_list(l, name, out))
+ return KRB5_NT_SRV_HST;
+ l = krb5_config_get_list (context,
+ NULL,
+ "libdefaults",
+ "v4_name_convert",
+ "host",
+ NULL);
+ if(l && check_list(l, name, out))
+ return KRB5_NT_SRV_HST;
+ l = krb5_config_get_list (context,
+ NULL,
+ "realms",
+ realm,
+ "v4_name_convert",
+ "plain",
+ NULL);
+ if(l && check_list(l, name, out))
+ return KRB5_NT_UNKNOWN;
+ l = krb5_config_get_list (context,
+ NULL,
+ "libdefaults",
+ "v4_name_convert",
+ "host",
+ NULL);
+ if(l && check_list(l, name, out))
+ return KRB5_NT_UNKNOWN;
+
+ /* didn't find it in config file, try built-in list */
+ {
+ struct v4_name_convert *q;
+ for(q = default_v4_name_convert; q->from; q++) {
+ if(strcmp(name, q->to) == 0) {
+ *out = q->from;
+ return KRB5_NT_SRV_HST;
+ }
+ }
+ }
+ return -1;
+}
+
+/*
+ * convert the v5 principal in `principal' into a v4 corresponding one
+ * in `name, instance, realm'
+ * this is limited interface since there's no length given for these
+ * three parameters. They have to be 40 bytes each (ANAME_SZ).
+ */
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_524_conv_principal(krb5_context context,
+ const krb5_principal principal,
+ char *name,
+ char *instance,
+ char *realm)
+{
+ const char *n, *i, *r;
+ char tmpinst[40];
+ int type = princ_type(principal);
+ const int aname_sz = 40;
+
+ r = principal->realm;
+
+ switch(principal->name.name_string.len){
+ case 1:
+ n = principal->name.name_string.val[0];
+ i = "";
+ break;
+ case 2:
+ n = principal->name.name_string.val[0];
+ i = principal->name.name_string.val[1];
+ break;
+ default:
+ krb5_set_error_string (context,
+ "cannot convert a %d component principal",
+ principal->name.name_string.len);
+ return KRB5_PARSE_MALFORMED;
+ }
+
+ {
+ const char *tmp;
+ int t = name_convert(context, n, r, &tmp);
+ if(t >= 0) {
+ type = t;
+ n = tmp;
+ }
+ }
+
+ if(type == KRB5_NT_SRV_HST){
+ char *p;
+
+ strlcpy (tmpinst, i, sizeof(tmpinst));
+ p = strchr(tmpinst, '.');
+ if(p)
+ *p = 0;
+ i = tmpinst;
+ }
+
+ if (strlcpy (name, n, aname_sz) >= aname_sz) {
+ krb5_set_error_string (context,
+ "too long name component to convert");
+ return KRB5_PARSE_MALFORMED;
+ }
+ if (strlcpy (instance, i, aname_sz) >= aname_sz) {
+ krb5_set_error_string (context,
+ "too long instance component to convert");
+ return KRB5_PARSE_MALFORMED;
+ }
+ if (strlcpy (realm, r, aname_sz) >= aname_sz) {
+ krb5_set_error_string (context,
+ "too long realm component to convert");
+ return KRB5_PARSE_MALFORMED;
+ }
+ return 0;
+}
+
+/*
+ * Create a principal in `ret_princ' for the service `sname' running
+ * on host `hostname'. */
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_sname_to_principal (krb5_context context,
+ const char *hostname,
+ const char *sname,
+ int32_t type,
+ krb5_principal *ret_princ)
+{
+ krb5_error_code ret;
+ char localhost[MAXHOSTNAMELEN];
+ char **realms, *host = NULL;
+
+ if(type != KRB5_NT_SRV_HST && type != KRB5_NT_UNKNOWN) {
+ krb5_set_error_string (context, "unsupported name type %d",
+ type);
+ return KRB5_SNAME_UNSUPP_NAMETYPE;
+ }
+ if(hostname == NULL) {
+ gethostname(localhost, sizeof(localhost));
+ hostname = localhost;
+ }
+ if(sname == NULL)
+ sname = "host";
+ if(type == KRB5_NT_SRV_HST) {
+ ret = krb5_expand_hostname_realms (context, hostname,
+ &host, &realms);
+ if (ret)
+ return ret;
+ strlwr(host);
+ hostname = host;
+ } else {
+ ret = krb5_get_host_realm(context, hostname, &realms);
+ if(ret)
+ return ret;
+ }
+
+ ret = krb5_make_principal(context, ret_princ, realms[0], sname,
+ hostname, NULL);
+ if(host)
+ free(host);
+ krb5_free_host_realm(context, realms);
+ return ret;
+}
diff --git a/source4/heimdal/lib/krb5/rd_cred.c b/source4/heimdal/lib/krb5/rd_cred.c
new file mode 100644
index 0000000000..9129eceeff
--- /dev/null
+++ b/source4/heimdal/lib/krb5/rd_cred.c
@@ -0,0 +1,299 @@
+/*
+ * Copyright (c) 1997 - 2005 Kungliga Tekniska Högskolan
+ * (Royal Institute of Technology, Stockholm, Sweden).
+ * 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>
+
+RCSID("$Id: rd_cred.c,v 1.23 2005/06/17 04:31:48 lha Exp $");
+
+static krb5_error_code
+compare_addrs(krb5_context context,
+ krb5_address *a,
+ krb5_address *b,
+ const char *message)
+{
+ char a_str[64], b_str[64];
+ size_t len;
+
+ if(krb5_address_compare (context, a, b))
+ return 0;
+
+ krb5_print_address (a, a_str, sizeof(a_str), &len);
+ krb5_print_address (b, b_str, sizeof(b_str), &len);
+ krb5_set_error_string(context, "%s: %s != %s", message, b_str, a_str);
+ return KRB5KRB_AP_ERR_BADADDR;
+}
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_rd_cred(krb5_context context,
+ krb5_auth_context auth_context,
+ krb5_data *in_data,
+ krb5_creds ***ret_creds,
+ krb5_replay_data *outdata)
+{
+ krb5_error_code ret;
+ size_t len;
+ KRB_CRED cred;
+ EncKrbCredPart enc_krb_cred_part;
+ krb5_data enc_krb_cred_part_data;
+ krb5_crypto crypto;
+ int i;
+
+ if ((auth_context->flags &
+ (KRB5_AUTH_CONTEXT_RET_TIME | KRB5_AUTH_CONTEXT_RET_SEQUENCE)) &&
+ outdata == NULL)
+ return KRB5_RC_REQUIRED; /* XXX better error, MIT returns this */
+
+ *ret_creds = NULL;
+
+ ret = decode_KRB_CRED(in_data->data, in_data->length,
+ &cred, &len);
+ if(ret)
+ return ret;
+
+ if (cred.pvno != 5) {
+ ret = KRB5KRB_AP_ERR_BADVERSION;
+ krb5_clear_error_string (context);
+ goto out;
+ }
+
+ if (cred.msg_type != krb_cred) {
+ ret = KRB5KRB_AP_ERR_MSG_TYPE;
+ krb5_clear_error_string (context);
+ goto out;
+ }
+
+ if (cred.enc_part.etype == ETYPE_NULL) {
+ /* DK: MIT GSS-API Compatibility */
+ enc_krb_cred_part_data.length = cred.enc_part.cipher.length;
+ enc_krb_cred_part_data.data = cred.enc_part.cipher.data;
+ } else {
+ if (auth_context->remote_subkey)
+ ret = krb5_crypto_init(context, auth_context->remote_subkey,
+ 0, &crypto);
+ else
+ ret = krb5_crypto_init(context, auth_context->keyblock,
+ 0, &crypto);
+ /* DK: MIT rsh */
+
+ if (ret)
+ goto out;
+
+ ret = krb5_decrypt_EncryptedData(context,
+ crypto,
+ KRB5_KU_KRB_CRED,
+ &cred.enc_part,
+ &enc_krb_cred_part_data);
+
+ krb5_crypto_destroy(context, crypto);
+ if (ret)
+ goto out;
+ }
+
+ ret = krb5_decode_EncKrbCredPart (context,
+ enc_krb_cred_part_data.data,
+ enc_krb_cred_part_data.length,
+ &enc_krb_cred_part,
+ &len);
+ if (ret)
+ goto out;
+
+ /* check sender address */
+
+ if (enc_krb_cred_part.s_address
+ && auth_context->remote_address
+ && auth_context->remote_port) {
+ krb5_address *a;
+
+ ret = krb5_make_addrport (context, &a,
+ auth_context->remote_address,
+ auth_context->remote_port);
+ if (ret)
+ goto out;
+
+
+ ret = compare_addrs(context, a, enc_krb_cred_part.s_address,
+ "sender address is wrong in received creds");
+ krb5_free_address(context, a);
+ free(a);
+ if(ret)
+ goto out;
+ }
+
+ /* check receiver address */
+
+ if (enc_krb_cred_part.r_address
+ && auth_context->local_address) {
+ if(auth_context->local_port &&
+ enc_krb_cred_part.r_address->addr_type == KRB5_ADDRESS_ADDRPORT) {
+ krb5_address *a;
+ ret = krb5_make_addrport (context, &a,
+ auth_context->local_address,
+ auth_context->local_port);
+ if (ret)
+ goto out;
+
+ ret = compare_addrs(context, a, enc_krb_cred_part.r_address,
+ "receiver address is wrong in received creds");
+ krb5_free_address(context, a);
+ free(a);
+ if(ret)
+ goto out;
+ } else {
+ ret = compare_addrs(context, auth_context->local_address,
+ enc_krb_cred_part.r_address,
+ "receiver address is wrong in received creds");
+ if(ret)
+ goto out;
+ }
+ }
+
+ /* check timestamp */
+ if (auth_context->flags & KRB5_AUTH_CONTEXT_DO_TIME) {
+ krb5_timestamp sec;
+
+ krb5_timeofday (context, &sec);
+
+ if (enc_krb_cred_part.timestamp == NULL ||
+ enc_krb_cred_part.usec == NULL ||
+ abs(*enc_krb_cred_part.timestamp - sec)
+ > context->max_skew) {
+ krb5_clear_error_string (context);
+ ret = KRB5KRB_AP_ERR_SKEW;
+ goto out;
+ }
+ }
+
+ if ((auth_context->flags &
+ (KRB5_AUTH_CONTEXT_RET_TIME | KRB5_AUTH_CONTEXT_RET_SEQUENCE))) {
+ /* if these fields are not present in the cred-part, silently
+ return zero */
+ memset(outdata, 0, sizeof(*outdata));
+ if(enc_krb_cred_part.timestamp)
+ outdata->timestamp = *enc_krb_cred_part.timestamp;
+ if(enc_krb_cred_part.usec)
+ outdata->usec = *enc_krb_cred_part.usec;
+ if(enc_krb_cred_part.nonce)
+ outdata->seq = *enc_krb_cred_part.nonce;
+ }
+
+ /* Convert to NULL terminated list of creds */
+
+ *ret_creds = calloc(enc_krb_cred_part.ticket_info.len + 1,
+ sizeof(**ret_creds));
+
+ if (*ret_creds == NULL) {
+ ret = ENOMEM;
+ krb5_set_error_string (context, "malloc: out of memory");
+ goto out;
+ }
+
+ for (i = 0; i < enc_krb_cred_part.ticket_info.len; ++i) {
+ KrbCredInfo *kci = &enc_krb_cred_part.ticket_info.val[i];
+ krb5_creds *creds;
+
+ creds = calloc(1, sizeof(*creds));
+ if(creds == NULL) {
+ ret = ENOMEM;
+ krb5_set_error_string (context, "malloc: out of memory");
+ goto out;
+ }
+
+ ASN1_MALLOC_ENCODE(Ticket, creds->ticket.data, creds->ticket.length,
+ &cred.tickets.val[i], &len, ret);
+ if (ret)
+ goto out;
+ if(creds->ticket.length != len)
+ krb5_abortx(context, "internal error in ASN.1 encoder");
+ copy_EncryptionKey (&kci->key, &creds->session);
+ if (kci->prealm && kci->pname)
+ _krb5_principalname2krb5_principal (&creds->client,
+ *kci->pname,
+ *kci->prealm);
+ if (kci->flags)
+ creds->flags.b = *kci->flags;
+ if (kci->authtime)
+ creds->times.authtime = *kci->authtime;
+ if (kci->starttime)
+ creds->times.starttime = *kci->starttime;
+ if (kci->endtime)
+ creds->times.endtime = *kci->endtime;
+ if (kci->renew_till)
+ creds->times.renew_till = *kci->renew_till;
+ if (kci->srealm && kci->sname)
+ _krb5_principalname2krb5_principal (&creds->server,
+ *kci->sname,
+ *kci->srealm);
+ if (kci->caddr)
+ krb5_copy_addresses (context,
+ kci->caddr,
+ &creds->addresses);
+
+ (*ret_creds)[i] = creds;
+
+ }
+ (*ret_creds)[i] = NULL;
+ return 0;
+
+ out:
+ free_KRB_CRED (&cred);
+ if(*ret_creds) {
+ for(i = 0; (*ret_creds)[i]; i++)
+ krb5_free_creds(context, (*ret_creds)[i]);
+ free(*ret_creds);
+ }
+ return ret;
+}
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_rd_cred2 (krb5_context context,
+ krb5_auth_context auth_context,
+ krb5_ccache ccache,
+ krb5_data *in_data)
+{
+ krb5_error_code ret;
+ krb5_creds **creds;
+ int i;
+
+ ret = krb5_rd_cred(context, auth_context, in_data, &creds, NULL);
+ if(ret)
+ return ret;
+
+ /* Store the creds in the ccache */
+
+ for(i = 0; creds && creds[i]; i++) {
+ krb5_cc_store_cred(context, ccache, creds[i]);
+ krb5_free_creds(context, creds[i]);
+ }
+ free(creds);
+ return 0;
+}
diff --git a/source4/heimdal/lib/krb5/rd_error.c b/source4/heimdal/lib/krb5/rd_error.c
new file mode 100644
index 0000000000..93e70c48bd
--- /dev/null
+++ b/source4/heimdal/lib/krb5/rd_error.c
@@ -0,0 +1,121 @@
+/*
+ * Copyright (c) 1997 - 2001 Kungliga Tekniska Högskolan
+ * (Royal Institute of Technology, Stockholm, Sweden).
+ * 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"
+
+RCSID("$Id: rd_error.c,v 1.8 2005/05/18 04:21:57 lha Exp $");
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_rd_error(krb5_context context,
+ krb5_data *msg,
+ KRB_ERROR *result)
+{
+
+ size_t len;
+ krb5_error_code ret;
+
+ ret = decode_KRB_ERROR(msg->data, msg->length, result, &len);
+ if(ret)
+ return ret;
+ result->error_code += KRB5KDC_ERR_NONE;
+ return 0;
+}
+
+void KRB5_LIB_FUNCTION
+krb5_free_error_contents (krb5_context context,
+ krb5_error *error)
+{
+ free_KRB_ERROR(error);
+ memset(error, 0, sizeof(*error));
+}
+
+void KRB5_LIB_FUNCTION
+krb5_free_error (krb5_context context,
+ krb5_error *error)
+{
+ krb5_free_error_contents (context, error);
+ free (error);
+}
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_error_from_rd_error(krb5_context context,
+ const krb5_error *error,
+ const krb5_creds *creds)
+{
+ krb5_error_code ret;
+
+ ret = error->error_code;
+ if (error->e_text != NULL) {
+ krb5_set_error_string(context, "%s", *error->e_text);
+ } else {
+ char clientname[256], servername[256];
+
+ if (creds != NULL) {
+ krb5_unparse_name_fixed(context, creds->client,
+ clientname, sizeof(clientname));
+ krb5_unparse_name_fixed(context, creds->server,
+ servername, sizeof(servername));
+ }
+
+ switch (ret) {
+ case KRB5KDC_ERR_NAME_EXP :
+ krb5_set_error_string(context, "Client %s%s%s expired",
+ creds ? "(" : "",
+ creds ? clientname : "",
+ creds ? ")" : "");
+ break;
+ case KRB5KDC_ERR_SERVICE_EXP :
+ krb5_set_error_string(context, "Server %s%s%s expired",
+ creds ? "(" : "",
+ creds ? servername : "",
+ creds ? ")" : "");
+ break;
+ case KRB5KDC_ERR_C_PRINCIPAL_UNKNOWN :
+ krb5_set_error_string(context, "Client %s%s%s unknown",
+ creds ? "(" : "",
+ creds ? clientname : "",
+ creds ? ")" : "");
+ break;
+ case KRB5KDC_ERR_S_PRINCIPAL_UNKNOWN :
+ krb5_set_error_string(context, "Server %s%s%s unknown",
+ creds ? "(" : "",
+ creds ? servername : "",
+ creds ? ")" : "");
+ break;
+ default :
+ krb5_clear_error_string(context);
+ break;
+ }
+ }
+ return ret;
+}
diff --git a/source4/heimdal/lib/krb5/rd_priv.c b/source4/heimdal/lib/krb5/rd_priv.c
new file mode 100644
index 0000000000..bafd23e995
--- /dev/null
+++ b/source4/heimdal/lib/krb5/rd_priv.c
@@ -0,0 +1,176 @@
+/*
+ * Copyright (c) 1997-2003 Kungliga Tekniska Högskolan
+ * (Royal Institute of Technology, Stockholm, Sweden).
+ * 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>
+
+RCSID("$Id: rd_priv.c,v 1.31 2004/05/25 21:39:13 lha Exp $");
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_rd_priv(krb5_context context,
+ krb5_auth_context auth_context,
+ const krb5_data *inbuf,
+ krb5_data *outbuf,
+ krb5_replay_data *outdata)
+{
+ krb5_error_code ret;
+ KRB_PRIV priv;
+ EncKrbPrivPart part;
+ size_t len;
+ krb5_data plain;
+ krb5_keyblock *key;
+ krb5_crypto crypto;
+
+ if ((auth_context->flags &
+ (KRB5_AUTH_CONTEXT_RET_TIME | KRB5_AUTH_CONTEXT_RET_SEQUENCE)) &&
+ outdata == NULL)
+ return KRB5_RC_REQUIRED; /* XXX better error, MIT returns this */
+
+ memset(&priv, 0, sizeof(priv));
+ ret = decode_KRB_PRIV (inbuf->data, inbuf->length, &priv, &len);
+ if (ret)
+ goto failure;
+ if (priv.pvno != 5) {
+ krb5_clear_error_string (context);
+ ret = KRB5KRB_AP_ERR_BADVERSION;
+ goto failure;
+ }
+ if (priv.msg_type != krb_priv) {
+ krb5_clear_error_string (context);
+ ret = KRB5KRB_AP_ERR_MSG_TYPE;
+ goto failure;
+ }
+
+ if (auth_context->remote_subkey)
+ key = auth_context->remote_subkey;
+ else if (auth_context->local_subkey)
+ key = auth_context->local_subkey;
+ else
+ key = auth_context->keyblock;
+
+ ret = krb5_crypto_init(context, key, 0, &crypto);
+ if (ret)
+ goto failure;
+ ret = krb5_decrypt_EncryptedData(context,
+ crypto,
+ KRB5_KU_KRB_PRIV,
+ &priv.enc_part,
+ &plain);
+ krb5_crypto_destroy(context, crypto);
+ if (ret)
+ goto failure;
+
+ ret = decode_EncKrbPrivPart (plain.data, plain.length, &part, &len);
+ krb5_data_free (&plain);
+ if (ret)
+ goto failure;
+
+ /* check sender address */
+
+ if (part.s_address
+ && auth_context->remote_address
+ && !krb5_address_compare (context,
+ auth_context->remote_address,
+ part.s_address)) {
+ krb5_clear_error_string (context);
+ ret = KRB5KRB_AP_ERR_BADADDR;
+ goto failure_part;
+ }
+
+ /* check receiver address */
+
+ if (part.r_address
+ && auth_context->local_address
+ && !krb5_address_compare (context,
+ auth_context->local_address,
+ part.r_address)) {
+ krb5_clear_error_string (context);
+ ret = KRB5KRB_AP_ERR_BADADDR;
+ goto failure_part;
+ }
+
+ /* check timestamp */
+ if (auth_context->flags & KRB5_AUTH_CONTEXT_DO_TIME) {
+ krb5_timestamp sec;
+
+ krb5_timeofday (context, &sec);
+ if (part.timestamp == NULL ||
+ part.usec == NULL ||
+ abs(*part.timestamp - sec) > context->max_skew) {
+ krb5_clear_error_string (context);
+ ret = KRB5KRB_AP_ERR_SKEW;
+ goto failure_part;
+ }
+ }
+
+ /* XXX - check replay cache */
+
+ /* check sequence number. since MIT krb5 cannot generate a sequence
+ number of zero but instead generates no sequence number, we accept that
+ */
+
+ if (auth_context->flags & KRB5_AUTH_CONTEXT_DO_SEQUENCE) {
+ if ((part.seq_number == NULL
+ && auth_context->remote_seqnumber != 0)
+ || (part.seq_number != NULL
+ && *part.seq_number != auth_context->remote_seqnumber)) {
+ krb5_clear_error_string (context);
+ ret = KRB5KRB_AP_ERR_BADORDER;
+ goto failure_part;
+ }
+ auth_context->remote_seqnumber++;
+ }
+
+ ret = krb5_data_copy (outbuf, part.user_data.data, part.user_data.length);
+ if (ret)
+ goto failure_part;
+
+ if ((auth_context->flags &
+ (KRB5_AUTH_CONTEXT_RET_TIME | KRB5_AUTH_CONTEXT_RET_SEQUENCE))) {
+ /* if these fields are not present in the priv-part, silently
+ return zero */
+ memset(outdata, 0, sizeof(*outdata));
+ if(part.timestamp)
+ outdata->timestamp = *part.timestamp;
+ if(part.usec)
+ outdata->usec = *part.usec;
+ if(part.seq_number)
+ outdata->seq = *part.seq_number;
+ }
+
+ failure_part:
+ free_EncKrbPrivPart (&part);
+
+ failure:
+ free_KRB_PRIV (&priv);
+ return ret;
+}
diff --git a/source4/heimdal/lib/krb5/rd_rep.c b/source4/heimdal/lib/krb5/rd_rep.c
new file mode 100644
index 0000000000..a92eea5c04
--- /dev/null
+++ b/source4/heimdal/lib/krb5/rd_rep.c
@@ -0,0 +1,133 @@
+/*
+ * Copyright (c) 1997 - 2001 Kungliga Tekniska Högskolan
+ * (Royal Institute of Technology, Stockholm, Sweden).
+ * 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>
+
+RCSID("$Id: rd_rep.c,v 1.25 2005/06/17 07:49:33 lha Exp $");
+
+krb5_error_code KRB5_LIB_FUNCTION
+_krb5_rd_rep_type(krb5_context context,
+ krb5_auth_context auth_context,
+ const krb5_data *inbuf,
+ krb5_ap_rep_enc_part **repl,
+ krb5_boolean dce_style_response)
+{
+ krb5_error_code ret;
+ AP_REP ap_rep;
+ size_t len;
+ krb5_data data;
+ krb5_crypto crypto;
+
+ krb5_data_zero (&data);
+ ret = 0;
+
+ ret = decode_AP_REP(inbuf->data, inbuf->length, &ap_rep, &len);
+ if (ret)
+ return ret;
+ if (ap_rep.pvno != 5) {
+ ret = KRB5KRB_AP_ERR_BADVERSION;
+ krb5_clear_error_string (context);
+ goto out;
+ }
+ if (ap_rep.msg_type != krb_ap_rep) {
+ ret = KRB5KRB_AP_ERR_MSG_TYPE;
+ krb5_clear_error_string (context);
+ goto out;
+ }
+
+ ret = krb5_crypto_init(context, auth_context->keyblock, 0, &crypto);
+ if (ret)
+ goto out;
+ ret = krb5_decrypt_EncryptedData (context,
+ crypto,
+ KRB5_KU_AP_REQ_ENC_PART,
+ &ap_rep.enc_part,
+ &data);
+ krb5_crypto_destroy(context, crypto);
+ if (ret)
+ goto out;
+
+ *repl = malloc(sizeof(**repl));
+ if (*repl == NULL) {
+ ret = ENOMEM;
+ krb5_set_error_string (context, "malloc: out of memory");
+ goto out;
+ }
+ ret = krb5_decode_EncAPRepPart(context,
+ data.data,
+ data.length,
+ *repl,
+ &len);
+ if (ret)
+ return ret;
+
+ if (!dce_style_response) {
+ if ((*repl)->ctime != auth_context->authenticator->ctime ||
+ (*repl)->cusec != auth_context->authenticator->cusec) {
+ ret = KRB5KRB_AP_ERR_MUT_FAIL;
+ krb5_set_error_string (context, "Mutual authentication failed: Timestamps mismatch");
+ goto out;
+ }
+ }
+ if ((*repl)->seq_number)
+ krb5_auth_con_setremoteseqnumber(context, auth_context,
+ *((*repl)->seq_number));
+ if ((*repl)->subkey)
+ krb5_auth_con_setremotesubkey(context, auth_context, (*repl)->subkey);
+
+out:
+ krb5_data_free (&data);
+ free_AP_REP (&ap_rep);
+ return ret;
+}
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_rd_rep(krb5_context context,
+ krb5_auth_context auth_context,
+ const krb5_data *inbuf,
+ krb5_ap_rep_enc_part **repl)
+{
+ return _krb5_rd_rep_type(context,
+ auth_context,
+ inbuf,
+ repl,
+ FALSE);
+}
+
+void KRB5_LIB_FUNCTION
+krb5_free_ap_rep_enc_part (krb5_context context,
+ krb5_ap_rep_enc_part *val)
+{
+ free_EncAPRepPart (val);
+ free (val);
+}
diff --git a/source4/heimdal/lib/krb5/rd_req.c b/source4/heimdal/lib/krb5/rd_req.c
new file mode 100644
index 0000000000..30ad08bd82
--- /dev/null
+++ b/source4/heimdal/lib/krb5/rd_req.c
@@ -0,0 +1,649 @@
+/*
+ * Copyright (c) 1997 - 2001, 2003 Kungliga Tekniska Högskolan
+ * (Royal Institute of Technology, Stockholm, Sweden).
+ * 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>
+
+RCSID("$Id: rd_req.c,v 1.57 2005/01/08 20:41:17 lha Exp $");
+
+static krb5_error_code
+decrypt_tkt_enc_part (krb5_context context,
+ krb5_keyblock *key,
+ EncryptedData *enc_part,
+ EncTicketPart *decr_part)
+{
+ krb5_error_code ret;
+ krb5_data plain;
+ size_t len;
+ krb5_crypto crypto;
+
+ ret = krb5_crypto_init(context, key, 0, &crypto);
+ if (ret)
+ return ret;
+ ret = krb5_decrypt_EncryptedData (context,
+ crypto,
+ KRB5_KU_TICKET,
+ enc_part,
+ &plain);
+ krb5_crypto_destroy(context, crypto);
+ if (ret)
+ return ret;
+
+ ret = krb5_decode_EncTicketPart(context, plain.data, plain.length,
+ decr_part, &len);
+ krb5_data_free (&plain);
+ return ret;
+}
+
+static krb5_error_code
+decrypt_authenticator (krb5_context context,
+ EncryptionKey *key,
+ EncryptedData *enc_part,
+ Authenticator *authenticator,
+ krb5_key_usage usage)
+{
+ krb5_error_code ret;
+ krb5_data plain;
+ size_t len;
+ krb5_crypto crypto;
+
+ ret = krb5_crypto_init(context, key, 0, &crypto);
+ if (ret)
+ return ret;
+ ret = krb5_decrypt_EncryptedData (context,
+ crypto,
+ usage /* KRB5_KU_AP_REQ_AUTH */,
+ enc_part,
+ &plain);
+ /* for backwards compatibility, also try the old usage */
+ if (ret && usage == KRB5_KU_TGS_REQ_AUTH)
+ ret = krb5_decrypt_EncryptedData (context,
+ crypto,
+ KRB5_KU_AP_REQ_AUTH,
+ enc_part,
+ &plain);
+ krb5_crypto_destroy(context, crypto);
+ if (ret)
+ return ret;
+
+ ret = krb5_decode_Authenticator(context, plain.data, plain.length,
+ authenticator, &len);
+ krb5_data_free (&plain);
+ return ret;
+}
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_decode_ap_req(krb5_context context,
+ const krb5_data *inbuf,
+ krb5_ap_req *ap_req)
+{
+ krb5_error_code ret;
+ size_t len;
+ ret = decode_AP_REQ(inbuf->data, inbuf->length, ap_req, &len);
+ if (ret)
+ return ret;
+ if (ap_req->pvno != 5){
+ free_AP_REQ(ap_req);
+ krb5_clear_error_string (context);
+ return KRB5KRB_AP_ERR_BADVERSION;
+ }
+ if (ap_req->msg_type != krb_ap_req){
+ free_AP_REQ(ap_req);
+ krb5_clear_error_string (context);
+ return KRB5KRB_AP_ERR_MSG_TYPE;
+ }
+ if (ap_req->ticket.tkt_vno != 5){
+ free_AP_REQ(ap_req);
+ krb5_clear_error_string (context);
+ return KRB5KRB_AP_ERR_BADVERSION;
+ }
+ return 0;
+}
+
+static krb5_error_code
+check_transited(krb5_context context, Ticket *ticket, EncTicketPart *enc)
+{
+ char **realms;
+ int num_realms;
+ krb5_error_code ret;
+
+ if(enc->transited.tr_type != DOMAIN_X500_COMPRESS)
+ return KRB5KDC_ERR_TRTYPE_NOSUPP;
+
+ if(enc->transited.contents.length == 0)
+ return 0;
+
+ ret = krb5_domain_x500_decode(context, enc->transited.contents,
+ &realms, &num_realms,
+ enc->crealm,
+ ticket->realm);
+ if(ret)
+ return ret;
+ ret = krb5_check_transited(context, enc->crealm,
+ ticket->realm,
+ realms, num_realms, NULL);
+ free(realms);
+ return ret;
+}
+
+static krb5_error_code
+find_etypelist(krb5_context context,
+ krb5_auth_context auth_context,
+ EtypeList *etypes)
+{
+ krb5_error_code ret;
+ krb5_authdata *ad;
+ krb5_authdata adIfRelevant;
+ unsigned i;
+
+ adIfRelevant.len = 0;
+
+ etypes->len = 0;
+ etypes->val = NULL;
+
+ ad = auth_context->authenticator->authorization_data;
+ if (ad == NULL)
+ return 0;
+
+ for (i = 0; i < ad->len; i++) {
+ if (ad->val[i].ad_type == KRB5_AUTHDATA_IF_RELEVANT) {
+ ret = decode_AD_IF_RELEVANT(ad->val[i].ad_data.data,
+ ad->val[i].ad_data.length,
+ &adIfRelevant,
+ NULL);
+ if (ret)
+ return ret;
+
+ if (adIfRelevant.len == 1 &&
+ adIfRelevant.val[0].ad_type ==
+ KRB5_AUTHDATA_GSS_API_ETYPE_NEGOTIATION) {
+ break;
+ }
+ free_AD_IF_RELEVANT(&adIfRelevant);
+ adIfRelevant.len = 0;
+ }
+ }
+
+ if (adIfRelevant.len == 0)
+ return 0;
+
+ ret = decode_EtypeList(adIfRelevant.val[0].ad_data.data,
+ adIfRelevant.val[0].ad_data.length,
+ etypes,
+ NULL);
+
+ free_AD_IF_RELEVANT(&adIfRelevant);
+
+ return ret;
+}
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_decrypt_ticket(krb5_context context,
+ Ticket *ticket,
+ krb5_keyblock *key,
+ EncTicketPart *out,
+ krb5_flags flags)
+{
+ EncTicketPart t;
+ krb5_error_code ret;
+ ret = decrypt_tkt_enc_part (context, key, &ticket->enc_part, &t);
+ if (ret)
+ return ret;
+
+ {
+ krb5_timestamp now;
+ time_t start = t.authtime;
+
+ krb5_timeofday (context, &now);
+ if(t.starttime)
+ start = *t.starttime;
+ if(start - now > context->max_skew
+ || (t.flags.invalid
+ && !(flags & KRB5_VERIFY_AP_REQ_IGNORE_INVALID))) {
+ free_EncTicketPart(&t);
+ krb5_clear_error_string (context);
+ return KRB5KRB_AP_ERR_TKT_NYV;
+ }
+ if(now - t.endtime > context->max_skew) {
+ free_EncTicketPart(&t);
+ krb5_clear_error_string (context);
+ return KRB5KRB_AP_ERR_TKT_EXPIRED;
+ }
+
+ if(!t.flags.transited_policy_checked) {
+ ret = check_transited(context, ticket, &t);
+ if(ret) {
+ free_EncTicketPart(&t);
+ return ret;
+ }
+ }
+ }
+
+ if(out)
+ *out = t;
+ else
+ free_EncTicketPart(&t);
+ return 0;
+}
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_verify_authenticator_checksum(krb5_context context,
+ krb5_auth_context ac,
+ void *data,
+ size_t len)
+{
+ krb5_error_code ret;
+ krb5_keyblock *key;
+ krb5_authenticator authenticator;
+ krb5_crypto crypto;
+
+ ret = krb5_auth_con_getauthenticator (context,
+ ac,
+ &authenticator);
+ if(ret)
+ return ret;
+ if(authenticator->cksum == NULL)
+ return -17;
+ ret = krb5_auth_con_getkey(context, ac, &key);
+ if(ret) {
+ krb5_free_authenticator(context, &authenticator);
+ return ret;
+ }
+ ret = krb5_crypto_init(context, key, 0, &crypto);
+ if(ret)
+ goto out;
+ ret = krb5_verify_checksum (context,
+ crypto,
+ KRB5_KU_AP_REQ_AUTH_CKSUM,
+ data,
+ len,
+ authenticator->cksum);
+ krb5_crypto_destroy(context, crypto);
+out:
+ krb5_free_authenticator(context, &authenticator);
+ krb5_free_keyblock(context, key);
+ return ret;
+}
+
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_verify_ap_req(krb5_context context,
+ krb5_auth_context *auth_context,
+ krb5_ap_req *ap_req,
+ krb5_const_principal server,
+ krb5_keyblock *keyblock,
+ krb5_flags flags,
+ krb5_flags *ap_req_options,
+ krb5_ticket **ticket)
+{
+ return krb5_verify_ap_req2 (context,
+ auth_context,
+ ap_req,
+ server,
+ keyblock,
+ flags,
+ ap_req_options,
+ ticket,
+ KRB5_KU_AP_REQ_AUTH);
+}
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_verify_ap_req2(krb5_context context,
+ krb5_auth_context *auth_context,
+ krb5_ap_req *ap_req,
+ krb5_const_principal server,
+ krb5_keyblock *keyblock,
+ krb5_flags flags,
+ krb5_flags *ap_req_options,
+ krb5_ticket **ticket,
+ krb5_key_usage usage)
+{
+ krb5_ticket *t;
+ krb5_auth_context ac;
+ krb5_error_code ret;
+ EtypeList etypes;
+
+ if (auth_context && *auth_context) {
+ ac = *auth_context;
+ } else {
+ ret = krb5_auth_con_init (context, &ac);
+ if (ret)
+ return ret;
+ }
+
+ t = malloc(sizeof(*t));
+ if (t == NULL) {
+ ret = ENOMEM;
+ krb5_clear_error_string (context);
+ goto out;
+ }
+ memset(t, 0, sizeof(*t));
+
+ if (ap_req->ap_options.use_session_key && ac->keyblock){
+ ret = krb5_decrypt_ticket(context, &ap_req->ticket,
+ ac->keyblock,
+ &t->ticket,
+ flags);
+ krb5_free_keyblock(context, ac->keyblock);
+ ac->keyblock = NULL;
+ }else
+ ret = krb5_decrypt_ticket(context, &ap_req->ticket,
+ keyblock,
+ &t->ticket,
+ flags);
+
+ if(ret)
+ goto out;
+
+ _krb5_principalname2krb5_principal(&t->server, ap_req->ticket.sname,
+ ap_req->ticket.realm);
+ _krb5_principalname2krb5_principal(&t->client, t->ticket.cname,
+ t->ticket.crealm);
+
+ /* save key */
+
+ krb5_copy_keyblock(context, &t->ticket.key, &ac->keyblock);
+
+ ret = decrypt_authenticator (context,
+ &t->ticket.key,
+ &ap_req->authenticator,
+ ac->authenticator,
+ usage);
+ if (ret)
+ goto out;
+
+ {
+ krb5_principal p1, p2;
+ krb5_boolean res;
+
+ _krb5_principalname2krb5_principal(&p1,
+ ac->authenticator->cname,
+ ac->authenticator->crealm);
+ _krb5_principalname2krb5_principal(&p2,
+ t->ticket.cname,
+ t->ticket.crealm);
+ res = krb5_principal_compare (context, p1, p2);
+ krb5_free_principal (context, p1);
+ krb5_free_principal (context, p2);
+ if (!res) {
+ ret = KRB5KRB_AP_ERR_BADMATCH;
+ krb5_clear_error_string (context);
+ goto out;
+ }
+ }
+
+ /* check addresses */
+
+ if (t->ticket.caddr
+ && ac->remote_address
+ && !krb5_address_search (context,
+ ac->remote_address,
+ t->ticket.caddr)) {
+ ret = KRB5KRB_AP_ERR_BADADDR;
+ krb5_clear_error_string (context);
+ goto out;
+ }
+
+ if (ac->authenticator->seq_number)
+ krb5_auth_con_setremoteseqnumber(context, ac,
+ *ac->authenticator->seq_number);
+
+ /* XXX - Xor sequence numbers */
+
+ if (ac->authenticator->subkey) {
+ ret = krb5_auth_con_setremotesubkey(context, ac,
+ ac->authenticator->subkey);
+ if (ret)
+ goto out;
+ }
+
+ ret = find_etypelist(context, ac, &etypes);
+ if (ret)
+ goto out;
+
+ ac->keytype = ETYPE_NULL;
+
+ if (etypes.val) {
+ int i;
+
+ for (i = 0; i < etypes.len; i++) {
+ if (krb5_enctype_valid(context, etypes.val[i]) == 0) {
+ ac->keytype = etypes.val[i];
+ break;
+ }
+ }
+ }
+
+ if (ap_req_options) {
+ *ap_req_options = 0;
+ if (ac->keytype != ETYPE_NULL)
+ *ap_req_options |= AP_OPTS_USE_SUBKEY;
+ if (ap_req->ap_options.use_session_key)
+ *ap_req_options |= AP_OPTS_USE_SESSION_KEY;
+ if (ap_req->ap_options.mutual_required)
+ *ap_req_options |= AP_OPTS_MUTUAL_REQUIRED;
+ }
+
+ if(ticket)
+ *ticket = t;
+ else
+ krb5_free_ticket (context, t);
+ if (auth_context) {
+ if (*auth_context == NULL)
+ *auth_context = ac;
+ } else
+ krb5_auth_con_free (context, ac);
+ free_EtypeList(&etypes);
+ return 0;
+ out:
+ if (t)
+ krb5_free_ticket (context, t);
+ if (auth_context == NULL || *auth_context == NULL)
+ krb5_auth_con_free (context, ac);
+ return ret;
+}
+
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_rd_req_with_keyblock(krb5_context context,
+ krb5_auth_context *auth_context,
+ const krb5_data *inbuf,
+ krb5_const_principal server,
+ krb5_keyblock *keyblock,
+ krb5_flags *ap_req_options,
+ krb5_ticket **ticket)
+{
+ krb5_error_code ret;
+ krb5_ap_req ap_req;
+
+ if (*auth_context == NULL) {
+ ret = krb5_auth_con_init(context, auth_context);
+ if (ret)
+ return ret;
+ }
+
+ ret = krb5_decode_ap_req(context, inbuf, &ap_req);
+ if(ret)
+ return ret;
+
+ ret = krb5_verify_ap_req(context,
+ auth_context,
+ &ap_req,
+ server,
+ keyblock,
+ 0,
+ ap_req_options,
+ ticket);
+
+ free_AP_REQ(&ap_req);
+ return ret;
+}
+
+static krb5_error_code
+get_key_from_keytab(krb5_context context,
+ krb5_auth_context *auth_context,
+ krb5_ap_req *ap_req,
+ krb5_const_principal server,
+ krb5_keytab keytab,
+ krb5_keyblock **out_key)
+{
+ krb5_keytab_entry entry;
+ krb5_error_code ret;
+ int kvno;
+ krb5_keytab real_keytab;
+
+ if(keytab == NULL)
+ krb5_kt_default(context, &real_keytab);
+ else
+ real_keytab = keytab;
+
+ if (ap_req->ticket.enc_part.kvno)
+ kvno = *ap_req->ticket.enc_part.kvno;
+ else
+ kvno = 0;
+
+ ret = krb5_kt_get_entry (context,
+ real_keytab,
+ server,
+ kvno,
+ ap_req->ticket.enc_part.etype,
+ &entry);
+ if(ret)
+ goto out;
+ ret = krb5_copy_keyblock(context, &entry.keyblock, out_key);
+ krb5_kt_free_entry (context, &entry);
+out:
+ if(keytab == NULL)
+ krb5_kt_close(context, real_keytab);
+
+ return ret;
+}
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_rd_req_return_keyblock(krb5_context context,
+ krb5_auth_context *auth_context,
+ const krb5_data *inbuf,
+ krb5_const_principal server,
+ krb5_keytab keytab,
+ krb5_flags *ap_req_options,
+ krb5_ticket **ticket,
+ krb5_keyblock **keyblock)
+{
+ krb5_error_code ret;
+ krb5_ap_req ap_req;
+ krb5_principal service = NULL;
+
+ if (*auth_context == NULL) {
+ ret = krb5_auth_con_init(context, auth_context);
+ if (ret)
+ return ret;
+ }
+
+ ret = krb5_decode_ap_req(context, inbuf, &ap_req);
+ if(ret)
+ return ret;
+
+ if(server == NULL){
+ _krb5_principalname2krb5_principal(&service,
+ ap_req.ticket.sname,
+ ap_req.ticket.realm);
+ server = service;
+ }
+ if (ap_req.ap_options.use_session_key &&
+ (*auth_context)->keyblock == NULL) {
+ krb5_set_error_string(context, "krb5_rd_req: user to user auth "
+ "without session key given");
+ ret = KRB5KRB_AP_ERR_NOKEY;
+ goto out;
+ }
+
+ if((*auth_context)->keyblock == NULL){
+ ret = get_key_from_keytab(context,
+ auth_context,
+ &ap_req,
+ server,
+ keytab,
+ keyblock);
+ if(ret)
+ goto out;
+ } else {
+ ret = krb5_copy_keyblock(context,
+ (*auth_context)->keyblock,
+ keyblock);
+ if (ret)
+ goto out;
+ }
+
+ ret = krb5_verify_ap_req(context,
+ auth_context,
+ &ap_req,
+ server,
+ *keyblock,
+ 0,
+ ap_req_options,
+ ticket);
+
+out:
+ free_AP_REQ(&ap_req);
+ if(service)
+ krb5_free_principal(context, service);
+ if (ret)
+ krb5_free_keyblock(context, *keyblock);
+
+ return ret;
+}
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_rd_req(krb5_context context,
+ krb5_auth_context *auth_context,
+ const krb5_data *inbuf,
+ krb5_const_principal server,
+ krb5_keytab keytab,
+ krb5_flags *ap_req_options,
+ krb5_ticket **ticket)
+{
+ krb5_error_code ret;
+ krb5_keyblock *keyblock;
+
+ ret = krb5_rd_req_return_keyblock(context,
+ auth_context,
+ inbuf,
+ server,
+ keytab,
+ ap_req_options,
+ ticket,
+ &keyblock);
+
+ krb5_free_keyblock(context, keyblock);
+ return ret;
+}
+
diff --git a/source4/heimdal/lib/krb5/replay.c b/source4/heimdal/lib/krb5/replay.c
new file mode 100644
index 0000000000..ec99f86c7c
--- /dev/null
+++ b/source4/heimdal/lib/krb5/replay.c
@@ -0,0 +1,304 @@
+/*
+ * Copyright (c) 1997-2001 Kungliga Tekniska Högskolan
+ * (Royal Institute of Technology, Stockholm, Sweden).
+ * 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 <vis.h>
+
+RCSID("$Id: replay.c,v 1.10 2004/05/25 21:41:15 lha Exp $");
+
+struct krb5_rcache_data {
+ char *name;
+};
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_rc_resolve(krb5_context context,
+ krb5_rcache id,
+ const char *name)
+{
+ id->name = strdup(name);
+ if(id->name == NULL) {
+ krb5_set_error_string (context, "malloc: out of memory");
+ return KRB5_RC_MALLOC;
+ }
+ return 0;
+}
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_rc_resolve_type(krb5_context context,
+ krb5_rcache *id,
+ const char *type)
+{
+ if(strcmp(type, "FILE")) {
+ krb5_set_error_string (context, "replay cache type %s not supported",
+ type);
+ return KRB5_RC_TYPE_NOTFOUND;
+ }
+ *id = calloc(1, sizeof(**id));
+ if(*id == NULL) {
+ krb5_set_error_string (context, "malloc: out of memory");
+ return KRB5_RC_MALLOC;
+ }
+ return 0;
+}
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_rc_resolve_full(krb5_context context,
+ krb5_rcache *id,
+ const char *string_name)
+{
+ krb5_error_code ret;
+ if(strncmp(string_name, "FILE:", 5)) {
+ krb5_set_error_string (context, "replay cache type %s not supported",
+ string_name);
+ return KRB5_RC_TYPE_NOTFOUND;
+ }
+ ret = krb5_rc_resolve_type(context, id, "FILE");
+ if(ret)
+ return ret;
+ ret = krb5_rc_resolve(context, *id, string_name + 5);
+ return ret;
+}
+
+const char* KRB5_LIB_FUNCTION
+krb5_rc_default_name(krb5_context context)
+{
+ return "FILE:/var/run/default_rcache";
+}
+
+const char* KRB5_LIB_FUNCTION
+krb5_rc_default_type(krb5_context context)
+{
+ return "FILE";
+}
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_rc_default(krb5_context context,
+ krb5_rcache *id)
+{
+ return krb5_rc_resolve_full(context, id, krb5_rc_default_name(context));
+}
+
+struct rc_entry{
+ time_t stamp;
+ unsigned char data[16];
+};
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_rc_initialize(krb5_context context,
+ krb5_rcache id,
+ krb5_deltat auth_lifespan)
+{
+ FILE *f = fopen(id->name, "w");
+ struct rc_entry tmp;
+ int ret;
+
+ if(f == NULL) {
+ ret = errno;
+ krb5_set_error_string (context, "open(%s): %s", id->name,
+ strerror(ret));
+ return ret;
+ }
+ tmp.stamp = auth_lifespan;
+ fwrite(&tmp, 1, sizeof(tmp), f);
+ fclose(f);
+ return 0;
+}
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_rc_recover(krb5_context context,
+ krb5_rcache id)
+{
+ return 0;
+}
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_rc_destroy(krb5_context context,
+ krb5_rcache id)
+{
+ int ret;
+
+ if(remove(id->name) < 0) {
+ ret = errno;
+ krb5_set_error_string (context, "remove(%s): %s", id->name,
+ strerror(ret));
+ return ret;
+ }
+ return krb5_rc_close(context, id);
+}
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_rc_close(krb5_context context,
+ krb5_rcache id)
+{
+ free(id->name);
+ free(id);
+ return 0;
+}
+
+static void
+checksum_authenticator(Authenticator *auth, void *data)
+{
+ MD5_CTX md5;
+ int i;
+
+ MD5_Init (&md5);
+ MD5_Update (&md5, auth->crealm, strlen(auth->crealm));
+ for(i = 0; i < auth->cname.name_string.len; i++)
+ MD5_Update(&md5, auth->cname.name_string.val[i],
+ strlen(auth->cname.name_string.val[i]));
+ MD5_Update (&md5, &auth->ctime, sizeof(auth->ctime));
+ MD5_Update (&md5, &auth->cusec, sizeof(auth->cusec));
+ MD5_Final (data, &md5);
+}
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_rc_store(krb5_context context,
+ krb5_rcache id,
+ krb5_donot_replay *rep)
+{
+ struct rc_entry ent, tmp;
+ time_t t;
+ FILE *f;
+ int ret;
+
+ ent.stamp = time(NULL);
+ checksum_authenticator(rep, ent.data);
+ f = fopen(id->name, "r");
+ if(f == NULL) {
+ ret = errno;
+ krb5_set_error_string (context, "open(%s): %s", id->name,
+ strerror(ret));
+ return ret;
+ }
+ fread(&tmp, sizeof(ent), 1, f);
+ t = ent.stamp - tmp.stamp;
+ while(fread(&tmp, sizeof(ent), 1, f)){
+ if(tmp.stamp < t)
+ continue;
+ if(memcmp(tmp.data, ent.data, sizeof(ent.data)) == 0){
+ fclose(f);
+ krb5_clear_error_string (context);
+ return KRB5_RC_REPLAY;
+ }
+ }
+ if(ferror(f)){
+ ret = errno;
+ fclose(f);
+ krb5_set_error_string (context, "%s: %s", id->name, strerror(ret));
+ return ret;
+ }
+ fclose(f);
+ f = fopen(id->name, "a");
+ if(f == NULL) {
+ krb5_set_error_string (context, "open(%s): %s", id->name,
+ strerror(errno));
+ return KRB5_RC_IO_UNKNOWN;
+ }
+ fwrite(&ent, 1, sizeof(ent), f);
+ fclose(f);
+ return 0;
+}
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_rc_expunge(krb5_context context,
+ krb5_rcache id)
+{
+ return 0;
+}
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_rc_get_lifespan(krb5_context context,
+ krb5_rcache id,
+ krb5_deltat *auth_lifespan)
+{
+ FILE *f = fopen(id->name, "r");
+ int r;
+ struct rc_entry ent;
+ r = fread(&ent, sizeof(ent), 1, f);
+ fclose(f);
+ if(r){
+ *auth_lifespan = ent.stamp;
+ return 0;
+ }
+ krb5_clear_error_string (context);
+ return KRB5_RC_IO_UNKNOWN;
+}
+
+const char* KRB5_LIB_FUNCTION
+krb5_rc_get_name(krb5_context context,
+ krb5_rcache id)
+{
+ return id->name;
+}
+
+const char* KRB5_LIB_FUNCTION
+krb5_rc_get_type(krb5_context context,
+ krb5_rcache id)
+{
+ return "FILE";
+}
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_get_server_rcache(krb5_context context,
+ const krb5_data *piece,
+ krb5_rcache *id)
+{
+ krb5_rcache rcache;
+ krb5_error_code ret;
+
+ char *tmp = malloc(4 * piece->length + 1);
+ char *name;
+
+ if(tmp == NULL) {
+ krb5_set_error_string (context, "malloc: out of memory");
+ return ENOMEM;
+ }
+ strvisx(tmp, piece->data, piece->length, VIS_WHITE | VIS_OCTAL);
+#ifdef HAVE_GETEUID
+ asprintf(&name, "FILE:rc_%s_%u", tmp, (unsigned)geteuid());
+#else
+ asprintf(&name, "FILE:rc_%s", tmp);
+#endif
+ free(tmp);
+ if(name == NULL) {
+ krb5_set_error_string (context, "malloc: out of memory");
+ return ENOMEM;
+ }
+
+ ret = krb5_rc_resolve_full(context, &rcache, name);
+ free(name);
+ if(ret)
+ return ret;
+ *id = rcache;
+ return ret;
+}
diff --git a/source4/heimdal/lib/krb5/send_to_kdc.c b/source4/heimdal/lib/krb5/send_to_kdc.c
new file mode 100644
index 0000000000..d55f8dc692
--- /dev/null
+++ b/source4/heimdal/lib/krb5/send_to_kdc.c
@@ -0,0 +1,416 @@
+/*
+ * Copyright (c) 1997 - 2002 Kungliga Tekniska Högskolan
+ * (Royal Institute of Technology, Stockholm, Sweden).
+ * 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"
+
+RCSID("$Id: send_to_kdc.c,v 1.56 2005/06/17 04:33:11 lha Exp $");
+
+/*
+ * send the data in `req' on the socket `fd' (which is datagram iff udp)
+ * waiting `tmout' for a reply and returning the reply in `rep'.
+ * iff limit read up to this many bytes
+ * returns 0 and data in `rep' if succesful, otherwise -1
+ */
+
+static int
+recv_loop (int fd,
+ time_t tmout,
+ int udp,
+ size_t limit,
+ krb5_data *rep)
+{
+ fd_set fdset;
+ struct timeval timeout;
+ int ret;
+ int nbytes;
+
+ if (fd >= FD_SETSIZE) {
+ return -1;
+ }
+
+ krb5_data_zero(rep);
+ do {
+ FD_ZERO(&fdset);
+ FD_SET(fd, &fdset);
+ timeout.tv_sec = tmout;
+ timeout.tv_usec = 0;
+ ret = select (fd + 1, &fdset, NULL, NULL, &timeout);
+ if (ret < 0) {
+ if (errno == EINTR)
+ continue;
+ return -1;
+ } else if (ret == 0) {
+ return 0;
+ } else {
+ void *tmp;
+
+ if (ioctl (fd, FIONREAD, &nbytes) < 0) {
+ krb5_data_free (rep);
+ return -1;
+ }
+ if(nbytes == 0)
+ return 0;
+
+ if (limit)
+ nbytes = min(nbytes, limit - rep->length);
+
+ tmp = realloc (rep->data, rep->length + nbytes);
+ if (tmp == NULL) {
+ krb5_data_free (rep);
+ return -1;
+ }
+ rep->data = tmp;
+ ret = recv (fd, (char*)tmp + rep->length, nbytes, 0);
+ if (ret < 0) {
+ krb5_data_free (rep);
+ return -1;
+ }
+ rep->length += ret;
+ }
+ } while(!udp && (limit == 0 || rep->length < limit));
+ return 0;
+}
+
+/*
+ * Send kerberos requests and receive a reply on a udp or any other kind
+ * of a datagram socket. See `recv_loop'.
+ */
+
+static int
+send_and_recv_udp(int fd,
+ time_t tmout,
+ const krb5_data *req,
+ krb5_data *rep)
+{
+ if (send (fd, req->data, req->length, 0) < 0)
+ return -1;
+
+ return recv_loop(fd, tmout, 1, 0, rep);
+}
+
+/*
+ * `send_and_recv' for a TCP (or any other stream) socket.
+ * Since there are no record limits on a stream socket the protocol here
+ * is to prepend the request with 4 bytes of its length and the reply
+ * is similarly encoded.
+ */
+
+static int
+send_and_recv_tcp(int fd,
+ time_t tmout,
+ const krb5_data *req,
+ krb5_data *rep)
+{
+ unsigned char len[4];
+ unsigned long rep_len;
+ krb5_data len_data;
+
+ _krb5_put_int(len, req->length, 4);
+ if(net_write(fd, len, sizeof(len)) < 0)
+ return -1;
+ if(net_write(fd, req->data, req->length) < 0)
+ return -1;
+ if (recv_loop (fd, tmout, 0, 4, &len_data) < 0)
+ return -1;
+ if (len_data.length != 4) {
+ krb5_data_free (&len_data);
+ return -1;
+ }
+ _krb5_get_int(len_data.data, &rep_len, 4);
+ krb5_data_free (&len_data);
+ if (recv_loop (fd, tmout, 0, rep_len, rep) < 0)
+ return -1;
+ if(rep->length != rep_len) {
+ krb5_data_free (rep);
+ return -1;
+ }
+ return 0;
+}
+
+int
+_krb5_send_and_recv_tcp(int fd,
+ time_t tmout,
+ const krb5_data *req,
+ krb5_data *rep)
+{
+ return send_and_recv_tcp(fd, tmout, req, rep);
+}
+
+/*
+ * `send_and_recv' tailored for the HTTP protocol.
+ */
+
+static int
+send_and_recv_http(int fd,
+ time_t tmout,
+ const char *prefix,
+ const krb5_data *req,
+ krb5_data *rep)
+{
+ char *request;
+ char *str;
+ int ret;
+ int len = base64_encode(req->data, req->length, &str);
+
+ if(len < 0)
+ return -1;
+ asprintf(&request, "GET %s%s HTTP/1.0\r\n\r\n", prefix, str);
+ free(str);
+ if (request == NULL)
+ return -1;
+ ret = net_write (fd, request, strlen(request));
+ free (request);
+ if (ret < 0)
+ return ret;
+ ret = recv_loop(fd, tmout, 0, 0, rep);
+ if(ret)
+ return ret;
+ {
+ unsigned long rep_len;
+ char *s, *p;
+
+ s = realloc(rep->data, rep->length + 1);
+ if (s == NULL) {
+ krb5_data_free (rep);
+ return -1;
+ }
+ s[rep->length] = 0;
+ p = strstr(s, "\r\n\r\n");
+ if(p == NULL) {
+ free(s);
+ return -1;
+ }
+ p += 4;
+ rep->data = s;
+ rep->length -= p - s;
+ if(rep->length < 4) { /* remove length */
+ free(s);
+ return -1;
+ }
+ rep->length -= 4;
+ _krb5_get_int(p, &rep_len, 4);
+ if (rep_len != rep->length) {
+ free(s);
+ return -1;
+ }
+ memmove(rep->data, p + 4, rep->length);
+ }
+ return 0;
+}
+
+static int
+init_port(const char *s, int fallback)
+{
+ if (s) {
+ int tmp;
+
+ sscanf (s, "%d", &tmp);
+ return htons(tmp);
+ } else
+ return fallback;
+}
+
+/*
+ * Return 0 if succesful, otherwise 1
+ */
+
+static int
+send_via_proxy (krb5_context context,
+ const krb5_krbhst_info *hi,
+ const krb5_data *send_data,
+ krb5_data *receive)
+{
+ char *proxy2 = strdup(context->http_proxy);
+ char *proxy = proxy2;
+ char *prefix;
+ char *colon;
+ struct addrinfo hints;
+ struct addrinfo *ai, *a;
+ int ret;
+ int s = -1;
+ char portstr[NI_MAXSERV];
+
+ if (proxy == NULL)
+ return ENOMEM;
+ if (strncmp (proxy, "http://", 7) == 0)
+ proxy += 7;
+
+ colon = strchr(proxy, ':');
+ if(colon != NULL)
+ *colon++ = '\0';
+ memset (&hints, 0, sizeof(hints));
+ hints.ai_family = PF_UNSPEC;
+ hints.ai_socktype = SOCK_STREAM;
+ snprintf (portstr, sizeof(portstr), "%d",
+ ntohs(init_port (colon, htons(80))));
+ ret = getaddrinfo (proxy, portstr, &hints, &ai);
+ free (proxy2);
+ if (ret)
+ return krb5_eai_to_heim_errno(ret, errno);
+
+ for (a = ai; a != NULL; a = a->ai_next) {
+ s = socket (a->ai_family, a->ai_socktype, a->ai_protocol);
+ if (s < 0)
+ continue;
+ if (connect (s, a->ai_addr, a->ai_addrlen) < 0) {
+ close (s);
+ continue;
+ }
+ break;
+ }
+ if (a == NULL) {
+ freeaddrinfo (ai);
+ return 1;
+ }
+ freeaddrinfo (ai);
+
+ asprintf(&prefix, "http://%s/", hi->hostname);
+ if(prefix == NULL) {
+ close(s);
+ return 1;
+ }
+ ret = send_and_recv_http(s, context->kdc_timeout,
+ prefix, send_data, receive);
+ close (s);
+ free(prefix);
+ if(ret == 0 && receive->length != 0)
+ return 0;
+ return 1;
+}
+
+/*
+ * Send the data `send' to one host from `handle` and get back the reply
+ * in `receive'.
+ */
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_sendto (krb5_context context,
+ const krb5_data *send_data,
+ krb5_krbhst_handle handle,
+ krb5_data *receive)
+{
+ krb5_error_code ret = 0;
+ int fd;
+ int i;
+
+ for (i = 0; i < context->max_retries; ++i) {
+ krb5_krbhst_info *hi;
+
+ while (krb5_krbhst_next(context, handle, &hi) == 0) {
+ struct addrinfo *ai, *a;
+
+ if(hi->proto == KRB5_KRBHST_HTTP && context->http_proxy) {
+ if (send_via_proxy (context, hi, send_data, receive))
+ continue;
+ else
+ goto out;
+ }
+
+ ret = krb5_krbhst_get_addrinfo(context, hi, &ai);
+ if (ret)
+ continue;
+
+ for (a = ai; a != NULL; a = a->ai_next) {
+ fd = socket (a->ai_family, a->ai_socktype, a->ai_protocol);
+ if (fd < 0)
+ continue;
+ if (connect (fd, a->ai_addr, a->ai_addrlen) < 0) {
+ close (fd);
+ continue;
+ }
+ switch (hi->proto) {
+ case KRB5_KRBHST_HTTP :
+ ret = send_and_recv_http(fd, context->kdc_timeout,
+ "", send_data, receive);
+ break;
+ case KRB5_KRBHST_TCP :
+ ret = send_and_recv_tcp (fd, context->kdc_timeout,
+ send_data, receive);
+ break;
+ case KRB5_KRBHST_UDP :
+ ret = send_and_recv_udp (fd, context->kdc_timeout,
+ send_data, receive);
+ break;
+ }
+ close (fd);
+ if(ret == 0 && receive->length != 0)
+ goto out;
+ }
+ }
+ krb5_krbhst_reset(context, handle);
+ }
+ krb5_clear_error_string (context);
+ ret = KRB5_KDC_UNREACH;
+out:
+ return ret;
+}
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_sendto_kdc(krb5_context context,
+ const krb5_data *send_data,
+ const krb5_realm *realm,
+ krb5_data *receive)
+{
+ return krb5_sendto_kdc_flags(context, send_data, realm, receive, 0);
+}
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_sendto_kdc_flags(krb5_context context,
+ const krb5_data *send_data,
+ const krb5_realm *realm,
+ krb5_data *receive,
+ int flags)
+{
+ krb5_error_code ret;
+ krb5_krbhst_handle handle;
+ int type;
+
+ if ((flags & KRB5_KRBHST_FLAGS_MASTER) || context->use_admin_kdc)
+ type = KRB5_KRBHST_ADMIN;
+ else
+ type = KRB5_KRBHST_KDC;
+
+ if (send_data->length > context->large_msg_size)
+ flags |= KRB5_KRBHST_FLAGS_LARGE_MSG;
+
+ ret = krb5_krbhst_init_flags(context, *realm, type, flags, &handle);
+ if (ret)
+ return ret;
+
+ ret = krb5_sendto(context, send_data, handle, receive);
+ krb5_krbhst_free(context, handle);
+ if (ret == KRB5_KDC_UNREACH)
+ krb5_set_error_string(context,
+ "unable to reach any KDC in realm %s", *realm);
+ return ret;
+}
diff --git a/source4/heimdal/lib/krb5/set_default_realm.c b/source4/heimdal/lib/krb5/set_default_realm.c
new file mode 100644
index 0000000000..965883309c
--- /dev/null
+++ b/source4/heimdal/lib/krb5/set_default_realm.c
@@ -0,0 +1,90 @@
+/*
+ * Copyright (c) 1997 - 2001 Kungliga Tekniska Högskolan
+ * (Royal Institute of Technology, Stockholm, Sweden).
+ * 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"
+
+RCSID("$Id: set_default_realm.c,v 1.14 2004/05/25 21:42:26 lha Exp $");
+
+/*
+ * Convert the simple string `s' into a NULL-terminated and freshly allocated
+ * list in `list'. Return an error code.
+ */
+
+static krb5_error_code
+string_to_list (krb5_context context, const char *s, krb5_realm **list)
+{
+
+ *list = malloc (2 * sizeof(**list));
+ if (*list == NULL) {
+ krb5_set_error_string (context, "malloc: out of memory");
+ return ENOMEM;
+ }
+ (*list)[0] = strdup (s);
+ if ((*list)[0] == NULL) {
+ free (*list);
+ krb5_set_error_string (context, "malloc: out of memory");
+ return ENOMEM;
+ }
+ (*list)[1] = NULL;
+ return 0;
+}
+
+/*
+ * Set the knowledge of the default realm(s) in `context'.
+ * If realm != NULL, that's the new default realm.
+ * Otherwise, the realm(s) are figured out from configuration or DNS.
+ */
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_set_default_realm(krb5_context context,
+ const char *realm)
+{
+ krb5_error_code ret = 0;
+ krb5_realm *realms = NULL;
+
+ if (realm == NULL) {
+ realms = krb5_config_get_strings (context, NULL,
+ "libdefaults",
+ "default_realm",
+ NULL);
+ if (realms == NULL)
+ ret = krb5_get_host_realm(context, NULL, &realms);
+ } else {
+ ret = string_to_list (context, realm, &realms);
+ }
+ if (ret)
+ return ret;
+ krb5_free_host_realm (context, context->default_realms);
+ context->default_realms = realms;
+ return 0;
+}
diff --git a/source4/heimdal/lib/krb5/store-int.h b/source4/heimdal/lib/krb5/store-int.h
new file mode 100644
index 0000000000..42e695a11b
--- /dev/null
+++ b/source4/heimdal/lib/krb5/store-int.h
@@ -0,0 +1,47 @@
+/*
+ * Copyright (c) 2002 Kungliga Tekniska Högskolan
+ * (Royal Institute of Technology, Stockholm, Sweden).
+ * 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.
+ */
+
+#ifndef __store_int_h__
+#define __store_int_h__
+
+struct krb5_storage_data {
+ void *data;
+ ssize_t (*fetch)(struct krb5_storage_data*, void*, size_t);
+ ssize_t (*store)(struct krb5_storage_data*, const void*, size_t);
+ off_t (*seek)(struct krb5_storage_data*, off_t, int);
+ void (*free)(struct krb5_storage_data*);
+ krb5_flags flags;
+ int eof_code;
+};
+
+#endif /* __store_int_h__ */
diff --git a/source4/heimdal/lib/krb5/store.c b/source4/heimdal/lib/krb5/store.c
new file mode 100644
index 0000000000..42667765fb
--- /dev/null
+++ b/source4/heimdal/lib/krb5/store.c
@@ -0,0 +1,888 @@
+/*
+ * Copyright (c) 1997-2004 Kungliga Tekniska Högskolan
+ * (Royal Institute of Technology, Stockholm, Sweden).
+ * 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 "store-int.h"
+
+RCSID("$Id: store.c,v 1.50 2005/06/17 04:36:33 lha Exp $");
+
+#define BYTEORDER_IS(SP, V) (((SP)->flags & KRB5_STORAGE_BYTEORDER_MASK) == (V))
+#define BYTEORDER_IS_LE(SP) BYTEORDER_IS((SP), KRB5_STORAGE_BYTEORDER_LE)
+#define BYTEORDER_IS_BE(SP) BYTEORDER_IS((SP), KRB5_STORAGE_BYTEORDER_BE)
+#define BYTEORDER_IS_HOST(SP) (BYTEORDER_IS((SP), KRB5_STORAGE_BYTEORDER_HOST) || \
+ krb5_storage_is_flags((SP), KRB5_STORAGE_HOST_BYTEORDER))
+
+void KRB5_LIB_FUNCTION
+krb5_storage_set_flags(krb5_storage *sp, krb5_flags flags)
+{
+ sp->flags |= flags;
+}
+
+void KRB5_LIB_FUNCTION
+krb5_storage_clear_flags(krb5_storage *sp, krb5_flags flags)
+{
+ sp->flags &= ~flags;
+}
+
+krb5_boolean KRB5_LIB_FUNCTION
+krb5_storage_is_flags(krb5_storage *sp, krb5_flags flags)
+{
+ return (sp->flags & flags) == flags;
+}
+
+void KRB5_LIB_FUNCTION
+krb5_storage_set_byteorder(krb5_storage *sp, krb5_flags byteorder)
+{
+ sp->flags &= ~KRB5_STORAGE_BYTEORDER_MASK;
+ sp->flags |= byteorder;
+}
+
+krb5_flags KRB5_LIB_FUNCTION
+krb5_storage_get_byteorder(krb5_storage *sp, krb5_flags byteorder)
+{
+ return sp->flags & KRB5_STORAGE_BYTEORDER_MASK;
+}
+
+off_t KRB5_LIB_FUNCTION
+krb5_storage_seek(krb5_storage *sp, off_t offset, int whence)
+{
+ return (*sp->seek)(sp, offset, whence);
+}
+
+krb5_ssize_t KRB5_LIB_FUNCTION
+krb5_storage_read(krb5_storage *sp, void *buf, size_t len)
+{
+ return sp->fetch(sp, buf, len);
+}
+
+krb5_ssize_t KRB5_LIB_FUNCTION
+krb5_storage_write(krb5_storage *sp, const void *buf, size_t len)
+{
+ return sp->store(sp, buf, len);
+}
+
+void KRB5_LIB_FUNCTION
+krb5_storage_set_eof_code(krb5_storage *sp, int code)
+{
+ sp->eof_code = code;
+}
+
+krb5_ssize_t KRB5_LIB_FUNCTION
+_krb5_put_int(void *buffer, unsigned long value, size_t size)
+{
+ unsigned char *p = buffer;
+ int i;
+ for (i = size - 1; i >= 0; i--) {
+ p[i] = value & 0xff;
+ value >>= 8;
+ }
+ return size;
+}
+
+krb5_ssize_t KRB5_LIB_FUNCTION
+_krb5_get_int(void *buffer, unsigned long *value, size_t size)
+{
+ unsigned char *p = buffer;
+ unsigned long v = 0;
+ int i;
+ for (i = 0; i < size; i++)
+ v = (v << 8) + p[i];
+ *value = v;
+ return size;
+}
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_storage_free(krb5_storage *sp)
+{
+ if(sp->free)
+ (*sp->free)(sp);
+ free(sp->data);
+ free(sp);
+ return 0;
+}
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_storage_to_data(krb5_storage *sp, krb5_data *data)
+{
+ off_t pos;
+ size_t size;
+ krb5_error_code ret;
+
+ pos = sp->seek(sp, 0, SEEK_CUR);
+ size = (size_t)sp->seek(sp, 0, SEEK_END);
+ ret = krb5_data_alloc (data, size);
+ if (ret) {
+ sp->seek(sp, pos, SEEK_SET);
+ return ret;
+ }
+ if (size) {
+ sp->seek(sp, 0, SEEK_SET);
+ sp->fetch(sp, data->data, data->length);
+ sp->seek(sp, pos, SEEK_SET);
+ }
+ return 0;
+}
+
+static krb5_error_code
+krb5_store_int(krb5_storage *sp,
+ int32_t value,
+ size_t len)
+{
+ int ret;
+ unsigned char v[16];
+
+ if(len > sizeof(v))
+ return EINVAL;
+ _krb5_put_int(v, value, len);
+ ret = sp->store(sp, v, len);
+ if (ret != len)
+ return (ret<0)?errno:sp->eof_code;
+ return 0;
+}
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_store_int32(krb5_storage *sp,
+ int32_t value)
+{
+ if(BYTEORDER_IS_HOST(sp))
+ value = htonl(value);
+ else if(BYTEORDER_IS_LE(sp))
+ value = bswap32(value);
+ return krb5_store_int(sp, value, 4);
+}
+
+static krb5_error_code
+krb5_ret_int(krb5_storage *sp,
+ int32_t *value,
+ size_t len)
+{
+ int ret;
+ unsigned char v[4];
+ unsigned long w;
+ ret = sp->fetch(sp, v, len);
+ if(ret != len)
+ return (ret<0)?errno:sp->eof_code;
+ _krb5_get_int(v, &w, len);
+ *value = w;
+ return 0;
+}
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_ret_int32(krb5_storage *sp,
+ int32_t *value)
+{
+ krb5_error_code ret = krb5_ret_int(sp, value, 4);
+ if(ret)
+ return ret;
+ if(BYTEORDER_IS_HOST(sp))
+ *value = htonl(*value);
+ else if(BYTEORDER_IS_LE(sp))
+ *value = bswap32(*value);
+ return 0;
+}
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_store_int16(krb5_storage *sp,
+ int16_t value)
+{
+ if(BYTEORDER_IS_HOST(sp))
+ value = htons(value);
+ else if(BYTEORDER_IS_LE(sp))
+ value = bswap16(value);
+ return krb5_store_int(sp, value, 2);
+}
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_ret_int16(krb5_storage *sp,
+ int16_t *value)
+{
+ int32_t v;
+ int ret;
+ ret = krb5_ret_int(sp, &v, 2);
+ if(ret)
+ return ret;
+ *value = v;
+ if(BYTEORDER_IS_HOST(sp))
+ *value = htons(*value);
+ else if(BYTEORDER_IS_LE(sp))
+ *value = bswap16(*value);
+ return 0;
+}
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_store_int8(krb5_storage *sp,
+ int8_t value)
+{
+ int ret;
+
+ ret = sp->store(sp, &value, sizeof(value));
+ if (ret != sizeof(value))
+ return (ret<0)?errno:sp->eof_code;
+ return 0;
+}
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_ret_int8(krb5_storage *sp,
+ int8_t *value)
+{
+ int ret;
+
+ ret = sp->fetch(sp, value, sizeof(*value));
+ if (ret != sizeof(*value))
+ return (ret<0)?errno:sp->eof_code;
+ return 0;
+}
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_store_data(krb5_storage *sp,
+ krb5_data data)
+{
+ int ret;
+ ret = krb5_store_int32(sp, data.length);
+ if(ret < 0)
+ return ret;
+ ret = sp->store(sp, data.data, data.length);
+ if(ret != data.length){
+ if(ret < 0)
+ return errno;
+ return sp->eof_code;
+ }
+ return 0;
+}
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_ret_data(krb5_storage *sp,
+ krb5_data *data)
+{
+ int ret;
+ int32_t size;
+
+ ret = krb5_ret_int32(sp, &size);
+ if(ret)
+ return ret;
+ ret = krb5_data_alloc (data, size);
+ if (ret)
+ return ret;
+ if (size) {
+ ret = sp->fetch(sp, data->data, size);
+ if(ret != size)
+ return (ret < 0)? errno : sp->eof_code;
+ }
+ return 0;
+}
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_store_string(krb5_storage *sp, const char *s)
+{
+ krb5_data data;
+ data.length = strlen(s);
+ data.data = rk_UNCONST(s);
+ return krb5_store_data(sp, data);
+}
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_ret_string(krb5_storage *sp,
+ char **string)
+{
+ int ret;
+ krb5_data data;
+ ret = krb5_ret_data(sp, &data);
+ if(ret)
+ return ret;
+ *string = realloc(data.data, data.length + 1);
+ if(*string == NULL){
+ free(data.data);
+ return ENOMEM;
+ }
+ (*string)[data.length] = 0;
+ return 0;
+}
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_store_stringz(krb5_storage *sp, const char *s)
+{
+ size_t len = strlen(s) + 1;
+ ssize_t ret;
+
+ ret = sp->store(sp, s, len);
+ if(ret != len) {
+ if(ret < 0)
+ return ret;
+ else
+ return sp->eof_code;
+ }
+ return 0;
+}
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_ret_stringz(krb5_storage *sp,
+ char **string)
+{
+ char c;
+ char *s = NULL;
+ size_t len = 0;
+ ssize_t ret;
+
+ while((ret = sp->fetch(sp, &c, 1)) == 1){
+ char *tmp;
+
+ len++;
+ tmp = realloc (s, len);
+ if (tmp == NULL) {
+ free (s);
+ return ENOMEM;
+ }
+ s = tmp;
+ s[len - 1] = c;
+ if(c == 0)
+ break;
+ }
+ if(ret != 1){
+ free(s);
+ if(ret == 0)
+ return sp->eof_code;
+ return ret;
+ }
+ *string = s;
+ return 0;
+}
+
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_store_principal(krb5_storage *sp,
+ krb5_principal p)
+{
+ int i;
+ int ret;
+
+ if(!krb5_storage_is_flags(sp, KRB5_STORAGE_PRINCIPAL_NO_NAME_TYPE)) {
+ ret = krb5_store_int32(sp, p->name.name_type);
+ if(ret) return ret;
+ }
+ if(krb5_storage_is_flags(sp, KRB5_STORAGE_PRINCIPAL_WRONG_NUM_COMPONENTS))
+ ret = krb5_store_int32(sp, p->name.name_string.len + 1);
+ else
+ ret = krb5_store_int32(sp, p->name.name_string.len);
+
+ if(ret) return ret;
+ ret = krb5_store_string(sp, p->realm);
+ if(ret) return ret;
+ for(i = 0; i < p->name.name_string.len; i++){
+ ret = krb5_store_string(sp, p->name.name_string.val[i]);
+ if(ret) return ret;
+ }
+ return 0;
+}
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_ret_principal(krb5_storage *sp,
+ krb5_principal *princ)
+{
+ int i;
+ int ret;
+ krb5_principal p;
+ int32_t type;
+ int32_t ncomp;
+
+ p = calloc(1, sizeof(*p));
+ if(p == NULL)
+ return ENOMEM;
+
+ if(krb5_storage_is_flags(sp, KRB5_STORAGE_PRINCIPAL_NO_NAME_TYPE))
+ type = KRB5_NT_UNKNOWN;
+ else if((ret = krb5_ret_int32(sp, &type))){
+ free(p);
+ return ret;
+ }
+ if((ret = krb5_ret_int32(sp, &ncomp))){
+ free(p);
+ return ret;
+ }
+ if(krb5_storage_is_flags(sp, KRB5_STORAGE_PRINCIPAL_WRONG_NUM_COMPONENTS))
+ ncomp--;
+ p->name.name_type = type;
+ p->name.name_string.len = ncomp;
+ ret = krb5_ret_string(sp, &p->realm);
+ if(ret) return ret;
+ p->name.name_string.val = calloc(ncomp, sizeof(*p->name.name_string.val));
+ if(p->name.name_string.val == NULL){
+ free(p->realm);
+ return ENOMEM;
+ }
+ for(i = 0; i < ncomp; i++){
+ ret = krb5_ret_string(sp, &p->name.name_string.val[i]);
+ if(ret) return ret; /* XXX */
+ }
+ *princ = p;
+ return 0;
+}
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_store_keyblock(krb5_storage *sp, krb5_keyblock p)
+{
+ int ret;
+ ret = krb5_store_int16(sp, p.keytype);
+ if(ret) return ret;
+
+ if(krb5_storage_is_flags(sp, KRB5_STORAGE_KEYBLOCK_KEYTYPE_TWICE)){
+ /* this should really be enctype, but it is the same as
+ keytype nowadays */
+ ret = krb5_store_int16(sp, p.keytype);
+ if(ret) return ret;
+ }
+
+ ret = krb5_store_data(sp, p.keyvalue);
+ return ret;
+}
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_ret_keyblock(krb5_storage *sp, krb5_keyblock *p)
+{
+ int ret;
+ int16_t tmp;
+
+ ret = krb5_ret_int16(sp, &tmp);
+ if(ret) return ret;
+ p->keytype = tmp;
+
+ if(krb5_storage_is_flags(sp, KRB5_STORAGE_KEYBLOCK_KEYTYPE_TWICE)){
+ ret = krb5_ret_int16(sp, &tmp);
+ if(ret) return ret;
+ }
+
+ ret = krb5_ret_data(sp, &p->keyvalue);
+ return ret;
+}
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_store_times(krb5_storage *sp, krb5_times times)
+{
+ int ret;
+ ret = krb5_store_int32(sp, times.authtime);
+ if(ret) return ret;
+ ret = krb5_store_int32(sp, times.starttime);
+ if(ret) return ret;
+ ret = krb5_store_int32(sp, times.endtime);
+ if(ret) return ret;
+ ret = krb5_store_int32(sp, times.renew_till);
+ return ret;
+}
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_ret_times(krb5_storage *sp, krb5_times *times)
+{
+ int ret;
+ int32_t tmp;
+ ret = krb5_ret_int32(sp, &tmp);
+ times->authtime = tmp;
+ if(ret) return ret;
+ ret = krb5_ret_int32(sp, &tmp);
+ times->starttime = tmp;
+ if(ret) return ret;
+ ret = krb5_ret_int32(sp, &tmp);
+ times->endtime = tmp;
+ if(ret) return ret;
+ ret = krb5_ret_int32(sp, &tmp);
+ times->renew_till = tmp;
+ return ret;
+}
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_store_address(krb5_storage *sp, krb5_address p)
+{
+ int ret;
+ ret = krb5_store_int16(sp, p.addr_type);
+ if(ret) return ret;
+ ret = krb5_store_data(sp, p.address);
+ return ret;
+}
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_ret_address(krb5_storage *sp, krb5_address *adr)
+{
+ int16_t t;
+ int ret;
+ ret = krb5_ret_int16(sp, &t);
+ if(ret) return ret;
+ adr->addr_type = t;
+ ret = krb5_ret_data(sp, &adr->address);
+ return ret;
+}
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_store_addrs(krb5_storage *sp, krb5_addresses p)
+{
+ int i;
+ int ret;
+ ret = krb5_store_int32(sp, p.len);
+ if(ret) return ret;
+ for(i = 0; i<p.len; i++){
+ ret = krb5_store_address(sp, p.val[i]);
+ if(ret) break;
+ }
+ return ret;
+}
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_ret_addrs(krb5_storage *sp, krb5_addresses *adr)
+{
+ int i;
+ int ret;
+ int32_t tmp;
+
+ ret = krb5_ret_int32(sp, &tmp);
+ if(ret) return ret;
+ adr->len = tmp;
+ ALLOC(adr->val, adr->len);
+ if (adr->val == NULL && adr->len != 0)
+ return ENOMEM;
+ for(i = 0; i < adr->len; i++){
+ ret = krb5_ret_address(sp, &adr->val[i]);
+ if(ret) break;
+ }
+ return ret;
+}
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_store_authdata(krb5_storage *sp, krb5_authdata auth)
+{
+ krb5_error_code ret;
+ int i;
+ ret = krb5_store_int32(sp, auth.len);
+ if(ret) return ret;
+ for(i = 0; i < auth.len; i++){
+ ret = krb5_store_int16(sp, auth.val[i].ad_type);
+ if(ret) break;
+ ret = krb5_store_data(sp, auth.val[i].ad_data);
+ if(ret) break;
+ }
+ return 0;
+}
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_ret_authdata(krb5_storage *sp, krb5_authdata *auth)
+{
+ krb5_error_code ret;
+ int32_t tmp;
+ int16_t tmp2;
+ int i;
+ ret = krb5_ret_int32(sp, &tmp);
+ if(ret) return ret;
+ ALLOC_SEQ(auth, tmp);
+ if (auth->val == NULL && tmp != 0)
+ return ENOMEM;
+ for(i = 0; i < tmp; i++){
+ ret = krb5_ret_int16(sp, &tmp2);
+ if(ret) break;
+ auth->val[i].ad_type = tmp2;
+ ret = krb5_ret_data(sp, &auth->val[i].ad_data);
+ if(ret) break;
+ }
+ return ret;
+}
+
+static int32_t
+bitswap32(int32_t b)
+{
+ int32_t r = 0;
+ int i;
+ for (i = 0; i < 32; i++) {
+ r = r << 1 | (b & 1);
+ b = b >> 1;
+ }
+ return r;
+}
+
+
+/*
+ *
+ */
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_store_creds(krb5_storage *sp, krb5_creds *creds)
+{
+ int ret;
+
+ ret = krb5_store_principal(sp, creds->client);
+ if(ret)
+ return ret;
+ ret = krb5_store_principal(sp, creds->server);
+ if(ret)
+ return ret;
+ ret = krb5_store_keyblock(sp, creds->session);
+ if(ret)
+ return ret;
+ ret = krb5_store_times(sp, creds->times);
+ if(ret)
+ return ret;
+ ret = krb5_store_int8(sp, creds->second_ticket.length != 0); /* is_skey */
+ if(ret)
+ return ret;
+
+ if(krb5_storage_is_flags(sp, KRB5_STORAGE_CREDS_FLAGS_WRONG_BITORDER))
+ ret = krb5_store_int32(sp, creds->flags.i);
+ else
+ ret = krb5_store_int32(sp, bitswap32(TicketFlags2int(creds->flags.b)));
+ if(ret)
+ return ret;
+
+ ret = krb5_store_addrs(sp, creds->addresses);
+ if(ret)
+ return ret;
+ ret = krb5_store_authdata(sp, creds->authdata);
+ if(ret)
+ return ret;
+ ret = krb5_store_data(sp, creds->ticket);
+ if(ret)
+ return ret;
+ ret = krb5_store_data(sp, creds->second_ticket);
+ return ret;
+}
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_ret_creds(krb5_storage *sp, krb5_creds *creds)
+{
+ krb5_error_code ret;
+ int8_t dummy8;
+ int32_t dummy32;
+
+ memset(creds, 0, sizeof(*creds));
+ ret = krb5_ret_principal (sp, &creds->client);
+ if(ret) goto cleanup;
+ ret = krb5_ret_principal (sp, &creds->server);
+ if(ret) goto cleanup;
+ ret = krb5_ret_keyblock (sp, &creds->session);
+ if(ret) goto cleanup;
+ ret = krb5_ret_times (sp, &creds->times);
+ if(ret) goto cleanup;
+ ret = krb5_ret_int8 (sp, &dummy8);
+ if(ret) goto cleanup;
+ ret = krb5_ret_int32 (sp, &dummy32);
+ if(ret) goto cleanup;
+ /*
+ * Runtime detect the what is the higher bits of the bitfield. If
+ * any of the higher bits are set in the input data, its either a
+ * new ticket flag (and this code need to be removed), or its a
+ * MIT cache (or new Heimdal cache), lets change it to our current
+ * format.
+ */
+ {
+ u_int32_t mask = 0xffff0000;
+ creds->flags.i = 0;
+ creds->flags.b.anonymous = 1;
+ if (creds->flags.i & mask)
+ mask = ~mask;
+ if (dummy32 & mask)
+ dummy32 = bitswap32(dummy32);
+ }
+ creds->flags.i = dummy32;
+ ret = krb5_ret_addrs (sp, &creds->addresses);
+ if(ret) goto cleanup;
+ ret = krb5_ret_authdata (sp, &creds->authdata);
+ if(ret) goto cleanup;
+ ret = krb5_ret_data (sp, &creds->ticket);
+ if(ret) goto cleanup;
+ ret = krb5_ret_data (sp, &creds->second_ticket);
+cleanup:
+ if(ret) {
+#if 0
+ krb5_free_cred_contents(context, creds); /* XXX */
+#endif
+ }
+ return ret;
+}
+
+#define SC_CLIENT_PRINCIPAL 0x0001
+#define SC_SERVER_PRINCIPAL 0x0002
+#define SC_SESSION_KEY 0x0004
+#define SC_TICKET 0x0008
+#define SC_SECOND_TICKET 0x0010
+#define SC_AUTHDATA 0x0020
+#define SC_ADDRESSES 0x0040
+
+/*
+ *
+ */
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_store_creds_tag(krb5_storage *sp, krb5_creds *creds)
+{
+ int ret;
+ int32_t header = 0;
+
+ if (creds->client)
+ header |= SC_CLIENT_PRINCIPAL;
+ if (creds->server)
+ header |= SC_SERVER_PRINCIPAL;
+ if (creds->session.keyvalue.data)
+ header |= SC_SESSION_KEY;
+ if (creds->ticket.data)
+ header |= SC_TICKET;
+ if (creds->second_ticket.length)
+ header |= SC_SECOND_TICKET;
+ if (creds->authdata.len)
+ header |= SC_AUTHDATA;
+ if (creds->addresses.len)
+ header |= SC_ADDRESSES;
+
+ ret = krb5_store_int32(sp, header);
+
+ if (creds->client) {
+ ret = krb5_store_principal(sp, creds->client);
+ if(ret)
+ return ret;
+ }
+
+ if (creds->server) {
+ ret = krb5_store_principal(sp, creds->server);
+ if(ret)
+ return ret;
+ }
+
+ if (creds->session.keyvalue.data) {
+ ret = krb5_store_keyblock(sp, creds->session);
+ if(ret)
+ return ret;
+ }
+
+ ret = krb5_store_times(sp, creds->times);
+ if(ret)
+ return ret;
+ ret = krb5_store_int8(sp, creds->second_ticket.length != 0); /* is_skey */
+ if(ret)
+ return ret;
+
+ ret = krb5_store_int32(sp, bitswap32(TicketFlags2int(creds->flags.b)));
+ if(ret)
+ return ret;
+
+ if (creds->addresses.len) {
+ ret = krb5_store_addrs(sp, creds->addresses);
+ if(ret)
+ return ret;
+ }
+
+ if (creds->authdata.len) {
+ ret = krb5_store_authdata(sp, creds->authdata);
+ if(ret)
+ return ret;
+ }
+
+ if (creds->ticket.data) {
+ ret = krb5_store_data(sp, creds->ticket);
+ if(ret)
+ return ret;
+ }
+
+ if (creds->second_ticket.data) {
+ ret = krb5_store_data(sp, creds->second_ticket);
+ if (ret)
+ return ret;
+ }
+
+ return ret;
+}
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_ret_creds_tag(krb5_storage *sp,
+ krb5_creds *creds)
+{
+ krb5_error_code ret;
+ int8_t dummy8;
+ int32_t dummy32, header;
+
+ memset(creds, 0, sizeof(*creds));
+
+ ret = krb5_ret_int32 (sp, &header);
+ if (ret) goto cleanup;
+
+ if (header & SC_CLIENT_PRINCIPAL) {
+ ret = krb5_ret_principal (sp, &creds->client);
+ if(ret) goto cleanup;
+ }
+ if (header & SC_SERVER_PRINCIPAL) {
+ ret = krb5_ret_principal (sp, &creds->server);
+ if(ret) goto cleanup;
+ }
+ if (header & SC_SESSION_KEY) {
+ ret = krb5_ret_keyblock (sp, &creds->session);
+ if(ret) goto cleanup;
+ }
+ ret = krb5_ret_times (sp, &creds->times);
+ if(ret) goto cleanup;
+ ret = krb5_ret_int8 (sp, &dummy8);
+ if(ret) goto cleanup;
+ ret = krb5_ret_int32 (sp, &dummy32);
+ if(ret) goto cleanup;
+ /*
+ * Runtime detect the what is the higher bits of the bitfield. If
+ * any of the higher bits are set in the input data, its either a
+ * new ticket flag (and this code need to be removed), or its a
+ * MIT cache (or new Heimdal cache), lets change it to our current
+ * format.
+ */
+ {
+ u_int32_t mask = 0xffff0000;
+ creds->flags.i = 0;
+ creds->flags.b.anonymous = 1;
+ if (creds->flags.i & mask)
+ mask = ~mask;
+ if (dummy32 & mask)
+ dummy32 = bitswap32(dummy32);
+ }
+ creds->flags.i = dummy32;
+ if (header & SC_ADDRESSES) {
+ ret = krb5_ret_addrs (sp, &creds->addresses);
+ if(ret) goto cleanup;
+ }
+ if (header & SC_AUTHDATA) {
+ ret = krb5_ret_authdata (sp, &creds->authdata);
+ if(ret) goto cleanup;
+ }
+ if (header & SC_TICKET) {
+ ret = krb5_ret_data (sp, &creds->ticket);
+ if(ret) goto cleanup;
+ }
+ if (header & SC_SECOND_TICKET) {
+ ret = krb5_ret_data (sp, &creds->second_ticket);
+ if(ret) goto cleanup;
+ }
+
+cleanup:
+ if(ret) {
+#if 0
+ krb5_free_cred_contents(context, creds); /* XXX */
+#endif
+ }
+ return ret;
+}
diff --git a/source4/heimdal/lib/krb5/store_emem.c b/source4/heimdal/lib/krb5/store_emem.c
new file mode 100644
index 0000000000..b9f93728de
--- /dev/null
+++ b/source4/heimdal/lib/krb5/store_emem.c
@@ -0,0 +1,132 @@
+/*
+ * Copyright (c) 1997 - 2002 Kungliga Tekniska Högskolan
+ * (Royal Institute of Technology, Stockholm, Sweden).
+ * 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 "store-int.h"
+
+RCSID("$Id: store_emem.c,v 1.14 2004/05/25 21:43:29 lha Exp $");
+
+typedef struct emem_storage{
+ unsigned char *base;
+ size_t size;
+ size_t len;
+ unsigned char *ptr;
+}emem_storage;
+
+static ssize_t
+emem_fetch(krb5_storage *sp, void *data, size_t size)
+{
+ emem_storage *s = (emem_storage*)sp->data;
+ if(s->base + s->len - s->ptr < size)
+ size = s->base + s->len - s->ptr;
+ memmove(data, s->ptr, size);
+ sp->seek(sp, size, SEEK_CUR);
+ return size;
+}
+
+static ssize_t
+emem_store(krb5_storage *sp, const void *data, size_t size)
+{
+ emem_storage *s = (emem_storage*)sp->data;
+ if(size > s->base + s->size - s->ptr){
+ void *base;
+ size_t sz, off;
+ off = s->ptr - s->base;
+ sz = off + size;
+ if (sz < 4096)
+ sz *= 2;
+ base = realloc(s->base, sz);
+ if(base == NULL)
+ return 0;
+ s->size = sz;
+ s->base = base;
+ s->ptr = (unsigned char*)base + off;
+ }
+ memmove(s->ptr, data, size);
+ sp->seek(sp, size, SEEK_CUR);
+ return size;
+}
+
+static off_t
+emem_seek(krb5_storage *sp, off_t offset, int whence)
+{
+ emem_storage *s = (emem_storage*)sp->data;
+ switch(whence){
+ case SEEK_SET:
+ if(offset > s->size)
+ offset = s->size;
+ if(offset < 0)
+ offset = 0;
+ s->ptr = s->base + offset;
+ if(offset > s->len)
+ s->len = offset;
+ break;
+ case SEEK_CUR:
+ sp->seek(sp,s->ptr - s->base + offset, SEEK_SET);
+ break;
+ case SEEK_END:
+ sp->seek(sp, s->len + offset, SEEK_SET);
+ break;
+ default:
+ errno = EINVAL;
+ return -1;
+ }
+ return s->ptr - s->base;
+}
+
+static void
+emem_free(krb5_storage *sp)
+{
+ emem_storage *s = sp->data;
+ memset(s->base, 0, s->len);
+ free(s->base);
+}
+
+krb5_storage * KRB5_LIB_FUNCTION
+krb5_storage_emem(void)
+{
+ krb5_storage *sp = malloc(sizeof(krb5_storage));
+ emem_storage *s = malloc(sizeof(*s));
+ sp->data = s;
+ sp->flags = 0;
+ sp->eof_code = HEIM_ERR_EOF;
+ s->size = 1024;
+ s->base = malloc(s->size);
+ s->len = 0;
+ s->ptr = s->base;
+ sp->fetch = emem_fetch;
+ sp->store = emem_store;
+ sp->seek = emem_seek;
+ sp->free = emem_free;
+ return sp;
+}
diff --git a/source4/heimdal/lib/krb5/store_fd.c b/source4/heimdal/lib/krb5/store_fd.c
new file mode 100644
index 0000000000..46043a6761
--- /dev/null
+++ b/source4/heimdal/lib/krb5/store_fd.c
@@ -0,0 +1,95 @@
+/*
+ * Copyright (c) 1997 - 2004 Kungliga Tekniska Högskolan
+ * (Royal Institute of Technology, Stockholm, Sweden).
+ * 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 "store-int.h"
+
+RCSID("$Id: store_fd.c,v 1.12 2004/05/25 21:43:57 lha Exp $");
+
+typedef struct fd_storage {
+ int fd;
+} fd_storage;
+
+#define FD(S) (((fd_storage*)(S)->data)->fd)
+
+static ssize_t
+fd_fetch(krb5_storage * sp, void *data, size_t size)
+{
+ return net_read(FD(sp), data, size);
+}
+
+static ssize_t
+fd_store(krb5_storage * sp, const void *data, size_t size)
+{
+ return net_write(FD(sp), data, size);
+}
+
+static off_t
+fd_seek(krb5_storage * sp, off_t offset, int whence)
+{
+ return lseek(FD(sp), offset, whence);
+}
+
+static void
+fd_free(krb5_storage * sp)
+{
+ close(FD(sp));
+}
+
+krb5_storage * KRB5_LIB_FUNCTION
+krb5_storage_from_fd(int fd)
+{
+ krb5_storage *sp;
+
+ fd = dup(fd);
+ if (fd < 0)
+ return NULL;
+ sp = malloc(sizeof(krb5_storage));
+
+ if (sp == NULL)
+ return NULL;
+
+ sp->data = malloc(sizeof(fd_storage));
+ if (sp->data == NULL) {
+ free(sp);
+ return NULL;
+ }
+ sp->flags = 0;
+ sp->eof_code = HEIM_ERR_EOF;
+ FD(sp) = fd;
+ sp->fetch = fd_fetch;
+ sp->store = fd_store;
+ sp->seek = fd_seek;
+ sp->free = fd_free;
+ return sp;
+}
diff --git a/source4/heimdal/lib/krb5/store_mem.c b/source4/heimdal/lib/krb5/store_mem.c
new file mode 100644
index 0000000000..decf74adce
--- /dev/null
+++ b/source4/heimdal/lib/krb5/store_mem.c
@@ -0,0 +1,119 @@
+/*
+ * Copyright (c) 1997 - 2000, 2002 Kungliga Tekniska Högskolan
+ * (Royal Institute of Technology, Stockholm, Sweden).
+ * 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 "store-int.h"
+
+RCSID("$Id: store_mem.c,v 1.12 2004/05/25 21:44:17 lha Exp $");
+
+typedef struct mem_storage{
+ unsigned char *base;
+ size_t size;
+ unsigned char *ptr;
+}mem_storage;
+
+static ssize_t
+mem_fetch(krb5_storage *sp, void *data, size_t size)
+{
+ mem_storage *s = (mem_storage*)sp->data;
+ if(size > s->base + s->size - s->ptr)
+ size = s->base + s->size - s->ptr;
+ memmove(data, s->ptr, size);
+ sp->seek(sp, size, SEEK_CUR);
+ return size;
+}
+
+static ssize_t
+mem_store(krb5_storage *sp, const void *data, size_t size)
+{
+ mem_storage *s = (mem_storage*)sp->data;
+ if(size > s->base + s->size - s->ptr)
+ size = s->base + s->size - s->ptr;
+ memmove(s->ptr, data, size);
+ sp->seek(sp, size, SEEK_CUR);
+ return size;
+}
+
+static off_t
+mem_seek(krb5_storage *sp, off_t offset, int whence)
+{
+ mem_storage *s = (mem_storage*)sp->data;
+ switch(whence){
+ case SEEK_SET:
+ if(offset > s->size)
+ offset = s->size;
+ if(offset < 0)
+ offset = 0;
+ s->ptr = s->base + offset;
+ break;
+ case SEEK_CUR:
+ return sp->seek(sp, s->ptr - s->base + offset, SEEK_SET);
+ case SEEK_END:
+ return sp->seek(sp, s->size + offset, SEEK_SET);
+ default:
+ errno = EINVAL;
+ return -1;
+ }
+ return s->ptr - s->base;
+}
+
+krb5_storage * KRB5_LIB_FUNCTION
+krb5_storage_from_mem(void *buf, size_t len)
+{
+ krb5_storage *sp = malloc(sizeof(krb5_storage));
+ mem_storage *s;
+ if(sp == NULL)
+ return NULL;
+ s = malloc(sizeof(*s));
+ if(s == NULL) {
+ free(sp);
+ return NULL;
+ }
+ sp->data = s;
+ sp->flags = 0;
+ sp->eof_code = HEIM_ERR_EOF;
+ s->base = buf;
+ s->size = len;
+ s->ptr = buf;
+ sp->fetch = mem_fetch;
+ sp->store = mem_store;
+ sp->seek = mem_seek;
+ sp->free = NULL;
+ return sp;
+}
+
+krb5_storage * KRB5_LIB_FUNCTION
+krb5_storage_from_data(krb5_data *data)
+{
+ return krb5_storage_from_mem(data->data, data->length);
+}
diff --git a/source4/heimdal/lib/krb5/ticket.c b/source4/heimdal/lib/krb5/ticket.c
new file mode 100644
index 0000000000..734cd4d4ca
--- /dev/null
+++ b/source4/heimdal/lib/krb5/ticket.c
@@ -0,0 +1,125 @@
+/*
+ * Copyright (c) 1997 - 2001 Kungliga Tekniska Högskolan
+ * (Royal Institute of Technology, Stockholm, Sweden).
+ * 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"
+
+RCSID("$Id: ticket.c,v 1.12 2004/05/25 21:44:47 lha Exp $");
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_free_ticket(krb5_context context,
+ krb5_ticket *ticket)
+{
+ free_EncTicketPart(&ticket->ticket);
+ krb5_free_principal(context, ticket->client);
+ krb5_free_principal(context, ticket->server);
+ free(ticket);
+ return 0;
+}
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_copy_ticket(krb5_context context,
+ const krb5_ticket *from,
+ krb5_ticket **to)
+{
+ krb5_error_code ret;
+ krb5_ticket *tmp;
+
+ *to = NULL;
+ tmp = malloc(sizeof(*tmp));
+ if(tmp == NULL) {
+ krb5_set_error_string (context, "malloc: out of memory");
+ return ENOMEM;
+ }
+ if((ret = copy_EncTicketPart(&from->ticket, &tmp->ticket))){
+ free(tmp);
+ return ret;
+ }
+ ret = krb5_copy_principal(context, from->client, &tmp->client);
+ if(ret){
+ free_EncTicketPart(&tmp->ticket);
+ free(tmp);
+ return ret;
+ }
+ ret = krb5_copy_principal(context, from->server, &tmp->server);
+ if(ret){
+ krb5_free_principal(context, tmp->client);
+ free_EncTicketPart(&tmp->ticket);
+ free(tmp);
+ return ret;
+ }
+ *to = tmp;
+ return 0;
+}
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_ticket_get_client(krb5_context context,
+ const krb5_ticket *ticket,
+ krb5_principal *client)
+{
+ return krb5_copy_principal(context, ticket->client, client);
+}
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_ticket_get_server(krb5_context context,
+ const krb5_ticket *ticket,
+ krb5_principal *server)
+{
+ return krb5_copy_principal(context, ticket->server, server);
+}
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_ticket_get_authorization_data_type(krb5_context context,
+ krb5_ticket *ticket,
+ int type,
+ krb5_data *data)
+{
+ AuthorizationData *ad;
+ int i;
+
+ data->length = 0;
+ data->data = NULL;
+
+ ad = ticket->ticket.authorization_data;
+ if (ad == NULL) {
+ krb5_set_error_string(context, "Ticket have not authorization data");
+ return ENOENT; /* XXX */
+ }
+
+ for (i = 0; i < ad->len; i++) {
+ if (ad->val[i].ad_type == type)
+ return copy_octet_string(&ad->val[i].ad_data, data);
+ }
+ krb5_set_error_string(context, "Ticket have not authorization "
+ "data of type %d", type);
+ return ENOENT; /* XXX */
+}
diff --git a/source4/heimdal/lib/krb5/time.c b/source4/heimdal/lib/krb5/time.c
new file mode 100644
index 0000000000..4a120ab771
--- /dev/null
+++ b/source4/heimdal/lib/krb5/time.c
@@ -0,0 +1,114 @@
+/*
+ * Copyright (c) 1997-2004 Kungliga Tekniska Högskolan
+ * (Royal Institute of Technology, Stockholm, Sweden).
+ * 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"
+
+RCSID("$Id: time.c,v 1.13 2004/10/13 17:57:11 lha Exp $");
+
+/*
+ * Set the absolute time that the caller knows the kdc has so the
+ * kerberos library can calculate the relative diffrence beteen the
+ * KDC time and local system time.
+ */
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_set_real_time (krb5_context context,
+ krb5_timestamp sec,
+ int32_t usec)
+{
+ struct timeval tv;
+
+ gettimeofday(&tv, NULL);
+
+ context->kdc_sec_offset = sec - tv.tv_sec;
+ context->kdc_usec_offset = usec - tv.tv_usec;
+
+ if (context->kdc_usec_offset < 0) {
+ context->kdc_sec_offset--;
+ context->kdc_usec_offset += 1000000;
+ }
+ return 0;
+}
+
+/*
+ * return ``corrected'' time in `timeret'.
+ */
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_timeofday (krb5_context context,
+ krb5_timestamp *timeret)
+{
+ *timeret = time(NULL) + context->kdc_sec_offset;
+ return 0;
+}
+
+/*
+ * like gettimeofday but with time correction to the KDC
+ */
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_us_timeofday (krb5_context context,
+ krb5_timestamp *sec,
+ int32_t *usec)
+{
+ struct timeval tv;
+
+ gettimeofday (&tv, NULL);
+
+ *sec = tv.tv_sec + context->kdc_sec_offset;
+ *usec = tv.tv_usec; /* XXX */
+ return 0;
+}
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_format_time(krb5_context context, time_t t,
+ char *s, size_t len, krb5_boolean include_time)
+{
+ struct tm *tm;
+ if(context->log_utc)
+ tm = gmtime (&t);
+ else
+ tm = localtime(&t);
+ if(tm == NULL ||
+ strftime(s, len, include_time ? context->time_fmt : context->date_fmt, tm) == 0)
+ snprintf(s, len, "%ld", (long)t);
+ return 0;
+}
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_string_to_deltat(const char *string, krb5_deltat *deltat)
+{
+ if((*deltat = parse_time(string, "s")) == -1)
+ return KRB5_DELTAT_BADFORMAT;
+ return 0;
+}
diff --git a/source4/heimdal/lib/krb5/transited.c b/source4/heimdal/lib/krb5/transited.c
new file mode 100644
index 0000000000..9e24db0da0
--- /dev/null
+++ b/source4/heimdal/lib/krb5/transited.c
@@ -0,0 +1,481 @@
+/*
+ * Copyright (c) 1997 - 2001, 2003 Kungliga Tekniska Högskolan
+ * (Royal Institute of Technology, Stockholm, Sweden).
+ * 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"
+
+RCSID("$Id: transited.c,v 1.16 2005/06/17 04:53:35 lha Exp $");
+
+/* this is an attempt at one of the most horrible `compression'
+ schemes that has ever been invented; it's so amazingly brain-dead
+ that words can not describe it, and all this just to save a few
+ silly bytes */
+
+struct tr_realm {
+ char *realm;
+ unsigned leading_space:1;
+ unsigned leading_slash:1;
+ unsigned trailing_dot:1;
+ struct tr_realm *next;
+};
+
+static void
+free_realms(struct tr_realm *r)
+{
+ struct tr_realm *p;
+ while(r){
+ p = r;
+ r = r->next;
+ free(p->realm);
+ free(p);
+ }
+}
+
+static int
+make_path(krb5_context context, struct tr_realm *r,
+ const char *from, const char *to)
+{
+ const char *p;
+ struct tr_realm *path = r->next;
+ struct tr_realm *tmp;
+
+ if(strlen(from) < strlen(to)){
+ const char *str;
+ str = from;
+ from = to;
+ to = str;
+ }
+
+ if(strcmp(from + strlen(from) - strlen(to), to) == 0){
+ p = from;
+ while(1){
+ p = strchr(p, '.');
+ if(p == NULL) {
+ krb5_clear_error_string (context);
+ return KRB5KDC_ERR_POLICY;
+ }
+ p++;
+ if(strcmp(p, to) == 0)
+ break;
+ tmp = calloc(1, sizeof(*tmp));
+ tmp->next = path;
+ path = tmp;
+ path->realm = strdup(p);
+ if(path->realm == NULL){
+ r->next = path; /* XXX */
+ krb5_set_error_string (context, "malloc: out of memory");
+ return ENOMEM;;
+ }
+ }
+ }else if(strncmp(from, to, strlen(to)) == 0){
+ p = from + strlen(from);
+ while(1){
+ while(p >= from && *p != '/') p--;
+ if(p == from)
+ return KRB5KDC_ERR_POLICY;
+ if(strncmp(to, from, p - from) == 0)
+ break;
+ tmp = calloc(1, sizeof(*tmp));
+ tmp->next = path;
+ path = tmp;
+ path->realm = malloc(p - from + 1);
+ if(path->realm == NULL){
+ r->next = path; /* XXX */
+ krb5_set_error_string (context, "malloc: out of memory");
+ return ENOMEM;
+ }
+ memcpy(path->realm, from, p - from);
+ path->realm[p - from] = '\0';
+ p--;
+ }
+ } else {
+ krb5_clear_error_string (context);
+ return KRB5KDC_ERR_POLICY;
+ }
+ r->next = path;
+
+ return 0;
+}
+
+static int
+make_paths(krb5_context context,
+ struct tr_realm *realms, const char *client_realm,
+ const char *server_realm)
+{
+ struct tr_realm *r;
+ int ret;
+ const char *prev_realm = client_realm;
+ const char *next_realm = NULL;
+ for(r = realms; r; r = r->next){
+ /* it *might* be that you can have more than one empty
+ component in a row, at least that's how I interpret the
+ "," exception in 1510 */
+ if(r->realm[0] == '\0'){
+ while(r->next && r->next->realm[0] == '\0')
+ r = r->next;
+ if(r->next)
+ next_realm = r->next->realm;
+ else
+ next_realm = server_realm;
+ ret = make_path(context, r, prev_realm, next_realm);
+ if(ret){
+ free_realms(realms);
+ return ret;
+ }
+ }
+ prev_realm = r->realm;
+ }
+ return 0;
+}
+
+static int
+expand_realms(krb5_context context,
+ struct tr_realm *realms, const char *client_realm)
+{
+ struct tr_realm *r;
+ const char *prev_realm = NULL;
+ for(r = realms; r; r = r->next){
+ if(r->trailing_dot){
+ char *tmp;
+ size_t len = strlen(r->realm) + strlen(prev_realm) + 1;
+
+ if(prev_realm == NULL)
+ prev_realm = client_realm;
+ tmp = realloc(r->realm, len);
+ if(tmp == NULL){
+ free_realms(realms);
+ krb5_set_error_string (context, "malloc: out of memory");
+ return ENOMEM;
+ }
+ r->realm = tmp;
+ strlcat(r->realm, prev_realm, len);
+ }else if(r->leading_slash && !r->leading_space && prev_realm){
+ /* yet another exception: if you use x500-names, the
+ leading realm doesn't have to be "quoted" with a space */
+ char *tmp;
+ size_t len = strlen(r->realm) + strlen(prev_realm) + 1;
+
+ tmp = malloc(len);
+ if(tmp == NULL){
+ free_realms(realms);
+ krb5_set_error_string (context, "malloc: out of memory");
+ return ENOMEM;
+ }
+ strlcpy(tmp, prev_realm, len);
+ strlcat(tmp, r->realm, len);
+ free(r->realm);
+ r->realm = tmp;
+ }
+ prev_realm = r->realm;
+ }
+ return 0;
+}
+
+static struct tr_realm *
+make_realm(char *realm)
+{
+ struct tr_realm *r;
+ char *p, *q;
+ int quote = 0;
+ r = calloc(1, sizeof(*r));
+ if(r == NULL){
+ free(realm);
+ return NULL;
+ }
+ r->realm = realm;
+ for(p = q = r->realm; *p; p++){
+ if(p == r->realm && *p == ' '){
+ r->leading_space = 1;
+ continue;
+ }
+ if(q == r->realm && *p == '/')
+ r->leading_slash = 1;
+ if(quote){
+ *q++ = *p;
+ quote = 0;
+ continue;
+ }
+ if(*p == '\\'){
+ quote = 1;
+ continue;
+ }
+ if(p[0] == '.' && p[1] == '\0')
+ r->trailing_dot = 1;
+ *q++ = *p;
+ }
+ *q = '\0';
+ return r;
+}
+
+static struct tr_realm*
+append_realm(struct tr_realm *head, struct tr_realm *r)
+{
+ struct tr_realm *p;
+ if(head == NULL){
+ r->next = NULL;
+ return r;
+ }
+ p = head;
+ while(p->next) p = p->next;
+ p->next = r;
+ return head;
+}
+
+static int
+decode_realms(krb5_context context,
+ const char *tr, int length, struct tr_realm **realms)
+{
+ struct tr_realm *r = NULL;
+
+ char *tmp;
+ int quote = 0;
+ const char *start = tr;
+ int i;
+
+ for(i = 0; i < length; i++){
+ if(quote){
+ quote = 0;
+ continue;
+ }
+ if(tr[i] == '\\'){
+ quote = 1;
+ continue;
+ }
+ if(tr[i] == ','){
+ tmp = malloc(tr + i - start + 1);
+ memcpy(tmp, start, tr + i - start);
+ tmp[tr + i - start] = '\0';
+ r = make_realm(tmp);
+ if(r == NULL){
+ free_realms(*realms);
+ krb5_set_error_string (context, "malloc: out of memory");
+ return ENOMEM;
+ }
+ *realms = append_realm(*realms, r);
+ start = tr + i + 1;
+ }
+ }
+ tmp = malloc(tr + i - start + 1);
+ memcpy(tmp, start, tr + i - start);
+ tmp[tr + i - start] = '\0';
+ r = make_realm(tmp);
+ if(r == NULL){
+ free_realms(*realms);
+ krb5_set_error_string (context, "malloc: out of memory");
+ return ENOMEM;
+ }
+ *realms = append_realm(*realms, r);
+
+ return 0;
+}
+
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_domain_x500_decode(krb5_context context,
+ krb5_data tr, char ***realms, int *num_realms,
+ const char *client_realm, const char *server_realm)
+{
+ struct tr_realm *r = NULL;
+ struct tr_realm *p, **q;
+ int ret;
+
+ if(tr.length == 0) {
+ *realms = NULL;
+ *num_realms = 0;
+ return 0;
+ }
+
+ /* split string in components */
+ ret = decode_realms(context, tr.data, tr.length, &r);
+ if(ret)
+ return ret;
+
+ /* apply prefix rule */
+ ret = expand_realms(context, r, client_realm);
+ if(ret)
+ return ret;
+
+ ret = make_paths(context, r, client_realm, server_realm);
+ if(ret)
+ return ret;
+
+ /* remove empty components and count realms */
+ q = &r;
+ *num_realms = 0;
+ for(p = r; p; ){
+ if(p->realm[0] == '\0'){
+ free(p->realm);
+ *q = p->next;
+ free(p);
+ p = *q;
+ }else{
+ q = &p->next;
+ p = p->next;
+ (*num_realms)++;
+ }
+ }
+ if (*num_realms < 0 || *num_realms + 1 > UINT_MAX/sizeof(**realms))
+ return ERANGE;
+
+ {
+ char **R;
+ R = malloc((*num_realms + 1) * sizeof(*R));
+ if (R == NULL)
+ return ENOMEM;
+ *realms = R;
+ while(r){
+ *R++ = r->realm;
+ p = r->next;
+ free(r);
+ r = p;
+ }
+ }
+ return 0;
+}
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_domain_x500_encode(char **realms, int num_realms, krb5_data *encoding)
+{
+ char *s = NULL;
+ int len = 0;
+ int i;
+ krb5_data_zero(encoding);
+ if (num_realms == 0)
+ return 0;
+ for(i = 0; i < num_realms; i++){
+ len += strlen(realms[i]);
+ if(realms[i][0] == '/')
+ len++;
+ }
+ len += num_realms - 1;
+ s = malloc(len + 1);
+ if (s == NULL)
+ return ENOMEM;
+ *s = '\0';
+ for(i = 0; i < num_realms; i++){
+ if(i && i < num_realms - 1)
+ strlcat(s, ",", len + 1);
+ if(realms[i][0] == '/')
+ strlcat(s, " ", len + 1);
+ strlcat(s, realms[i], len + 1);
+ }
+ encoding->data = s;
+ encoding->length = strlen(s);
+ return 0;
+}
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_check_transited(krb5_context context,
+ krb5_const_realm client_realm,
+ krb5_const_realm server_realm,
+ krb5_realm *realms,
+ int num_realms,
+ int *bad_realm)
+{
+ char **tr_realms;
+ char **p;
+ int i;
+
+ if(num_realms == 0)
+ return 0;
+
+ tr_realms = krb5_config_get_strings(context, NULL,
+ "capaths",
+ client_realm,
+ server_realm,
+ NULL);
+ for(i = 0; i < num_realms; i++) {
+ for(p = tr_realms; p && *p; p++) {
+ if(strcmp(*p, realms[i]) == 0)
+ break;
+ }
+ if(p == NULL || *p == NULL) {
+ krb5_config_free_strings(tr_realms);
+ krb5_set_error_string (context, "no transit through realm %s",
+ realms[i]);
+ if(bad_realm)
+ *bad_realm = i;
+ return KRB5KRB_AP_ERR_ILL_CR_TKT;
+ }
+ }
+ krb5_config_free_strings(tr_realms);
+ return 0;
+}
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_check_transited_realms(krb5_context context,
+ const char *const *realms,
+ int num_realms,
+ int *bad_realm)
+{
+ int i;
+ int ret = 0;
+ char **bad_realms = krb5_config_get_strings(context, NULL,
+ "libdefaults",
+ "transited_realms_reject",
+ NULL);
+ if(bad_realms == NULL)
+ return 0;
+
+ for(i = 0; i < num_realms; i++) {
+ char **p;
+ for(p = bad_realms; *p; p++)
+ if(strcmp(*p, realms[i]) == 0) {
+ krb5_set_error_string (context, "no transit through realm %s",
+ *p);
+ ret = KRB5KRB_AP_ERR_ILL_CR_TKT;
+ if(bad_realm)
+ *bad_realm = i;
+ break;
+ }
+ }
+ krb5_config_free_strings(bad_realms);
+ return ret;
+}
+
+#if 0
+int
+main(int argc, char **argv)
+{
+ krb5_data x;
+ char **r;
+ int num, i;
+ x.data = argv[1];
+ x.length = strlen(x.data);
+ if(domain_expand(x, &r, &num, argv[2], argv[3]))
+ exit(1);
+ for(i = 0; i < num; i++)
+ printf("%s\n", r[i]);
+ return 0;
+}
+#endif
+
diff --git a/source4/heimdal/lib/krb5/v4_glue.c b/source4/heimdal/lib/krb5/v4_glue.c
new file mode 100644
index 0000000000..c66b06c09f
--- /dev/null
+++ b/source4/heimdal/lib/krb5/v4_glue.c
@@ -0,0 +1,922 @@
+/*
+ * Copyright (c) 1997 - 2005 Kungliga Tekniska Högskolan
+ * (Royal Institute of Technology, Stockholm, Sweden).
+ * 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"
+RCSID("$Id: v4_glue.c,v 1.2 2005/04/24 13:44:02 lha Exp $");
+
+#include "krb5-v4compat.h"
+
+/*
+ *
+ */
+
+#define RCHECK(r,func,label) \
+ do { (r) = func ; if (r) goto label; } while(0);
+
+
+/* include this here, to avoid dependencies on libkrb */
+
+static const int _tkt_lifetimes[TKTLIFENUMFIXED] = {
+ 38400, 41055, 43894, 46929, 50174, 53643, 57352, 61318,
+ 65558, 70091, 74937, 80119, 85658, 91581, 97914, 104684,
+ 111922, 119661, 127935, 136781, 146239, 156350, 167161, 178720,
+ 191077, 204289, 218415, 233517, 249664, 266926, 285383, 305116,
+ 326213, 348769, 372885, 398668, 426234, 455705, 487215, 520904,
+ 556921, 595430, 636601, 680618, 727680, 777995, 831789, 889303,
+ 950794, 1016537, 1086825, 1161973, 1242318, 1328218, 1420057, 1518247,
+ 1623226, 1735464, 1855462, 1983758, 2120925, 2267576, 2424367, 2592000
+};
+
+int KRB5_LIB_FUNCTION
+_krb5_krb_time_to_life(time_t start, time_t end)
+{
+ int i;
+ time_t life = end - start;
+
+ if (life > MAXTKTLIFETIME || life <= 0)
+ return 0;
+#if 0
+ if (krb_no_long_lifetimes)
+ return (life + 5*60 - 1)/(5*60);
+#endif
+
+ if (end >= NEVERDATE)
+ return TKTLIFENOEXPIRE;
+ if (life < _tkt_lifetimes[0])
+ return (life + 5*60 - 1)/(5*60);
+ for (i=0; i<TKTLIFENUMFIXED; i++)
+ if (life <= _tkt_lifetimes[i])
+ return i + TKTLIFEMINFIXED;
+ return 0;
+
+}
+
+time_t KRB5_LIB_FUNCTION
+_krb5_krb_life_to_time(int start, int life_)
+{
+ unsigned char life = (unsigned char) life_;
+
+#if 0
+ if (krb_no_long_lifetimes)
+ return start + life*5*60;
+#endif
+
+ if (life == TKTLIFENOEXPIRE)
+ return NEVERDATE;
+ if (life < TKTLIFEMINFIXED)
+ return start + life*5*60;
+ if (life > TKTLIFEMAXFIXED)
+ return start + MAXTKTLIFETIME;
+ return start + _tkt_lifetimes[life - TKTLIFEMINFIXED];
+}
+
+/*
+ * Get the name of the krb4 credentials cache, will use `tkfile' as
+ * the name if that is passed in. `cc' must be free()ed by caller,
+ */
+
+static krb5_error_code
+get_krb4_cc_name(const char *tkfile, char **cc)
+{
+
+ *cc = NULL;
+ if(tkfile == NULL) {
+ char *path;
+ if(!issuid()) {
+ path = getenv("KRBTKFILE");
+ if (path)
+ *cc = strdup(path);
+ }
+ if(*cc == NULL)
+ if (asprintf(cc, "%s%u", TKT_ROOT, (unsigned)getuid()) < 0)
+ return errno;
+ } else {
+ *cc = strdup(tkfile);
+ if (*cc == NULL)
+ return ENOMEM;
+ }
+ return 0;
+}
+
+/*
+ * Write a Kerberos 4 ticket file
+ */
+
+#define KRB5_TF_LCK_RETRY_COUNT 50
+#define KRB5_TF_LCK_RETRY 1
+
+static krb5_error_code
+write_v4_cc(krb5_context context, const char *tkfile,
+ krb5_storage *sp, int append)
+{
+ krb5_error_code ret;
+ struct stat sb;
+ krb5_data data;
+ char *path;
+ int fd, i;
+
+ ret = get_krb4_cc_name(tkfile, &path);
+ if (ret) {
+ krb5_set_error_string(context,
+ "krb5_krb_tf_setup: failed getting "
+ "the krb4 credentials cache name");
+ return ret;
+ }
+
+ fd = open(path, O_WRONLY|O_CREAT, 0600);
+ if (fd < 0) {
+ free(path);
+ krb5_set_error_string(context,
+ "krb5_krb_tf_setup: error opening file %s",
+ path);
+ return errno;
+ }
+
+ if (fstat(fd, &sb) != 0 || !S_ISREG(sb.st_mode)) {
+ free(path);
+ close(fd);
+ krb5_set_error_string(context,
+ "krb5_krb_tf_setup: tktfile %s is not a file",
+ path);
+ return KRB5_FCC_PERM;
+ }
+
+ for (i = 0; i < KRB5_TF_LCK_RETRY_COUNT; i++) {
+ if (flock(fd, LOCK_EX | LOCK_NB) < 0) {
+ sleep(KRB5_TF_LCK_RETRY);
+ } else
+ break;
+ }
+ if (i == KRB5_TF_LCK_RETRY_COUNT) {
+ free(path);
+ close(fd);
+ krb5_set_error_string(context,
+ "krb5_krb_tf_setup: failed to lock %s",
+ path);
+ return KRB5_FCC_PERM;
+ }
+
+ if (!append) {
+ ret = ftruncate(fd, 0);
+ if (ret < 0) {
+ flock(fd, LOCK_UN);
+ free(path);
+ close(fd);
+ krb5_set_error_string(context,
+ "krb5_krb_tf_setup: failed to truncate %s",
+ path);
+ return KRB5_FCC_PERM;
+ }
+ }
+ ret = lseek(fd, 0L, SEEK_END);
+ if (ret < 0) {
+ ret = errno;
+ flock(fd, LOCK_UN);
+ free(path);
+ close(fd);
+ return ret;
+ }
+
+ krb5_storage_to_data(sp, &data);
+
+ ret = write(fd, data.data, data.length);
+ if (ret != data.length)
+ ret = KRB5_CC_IO;
+
+ krb5_free_data_contents(context, &data);
+
+ flock(fd, LOCK_UN);
+ free(path);
+ close(fd);
+
+ return 0;
+}
+
+/*
+ *
+ */
+
+krb5_error_code KRB5_LIB_FUNCTION
+_krb5_krb_tf_setup(krb5_context context,
+ struct credentials *v4creds,
+ const char *tkfile,
+ int append)
+{
+ krb5_error_code ret;
+ krb5_storage *sp;
+
+ sp = krb5_storage_emem();
+ if (sp == NULL)
+ return ENOMEM;
+
+ krb5_storage_set_byteorder(sp, KRB5_STORAGE_BYTEORDER_HOST);
+ krb5_storage_set_eof_code(sp, KRB5_CC_IO);
+
+ krb5_clear_error_string(context);
+
+ if (!append) {
+ RCHECK(ret, krb5_store_stringz(sp, v4creds->pname), error);
+ RCHECK(ret, krb5_store_stringz(sp, v4creds->pinst), error);
+ }
+
+ /* cred */
+ RCHECK(ret, krb5_store_stringz(sp, v4creds->service), error);
+ RCHECK(ret, krb5_store_stringz(sp, v4creds->instance), error);
+ RCHECK(ret, krb5_store_stringz(sp, v4creds->realm), error);
+ ret = krb5_storage_write(sp, v4creds->session, 8);
+ if (ret != 8) {
+ ret = KRB5_CC_IO;
+ goto error;
+ }
+ RCHECK(ret, krb5_store_int32(sp, v4creds->lifetime), error);
+ RCHECK(ret, krb5_store_int32(sp, v4creds->kvno), error);
+ RCHECK(ret, krb5_store_int32(sp, v4creds->ticket_st.length), error);
+
+ ret = krb5_storage_write(sp, v4creds->ticket_st.dat,
+ v4creds->ticket_st.length);
+ if (ret != v4creds->ticket_st.length) {
+ ret = KRB5_CC_IO;
+ goto error;
+ }
+ RCHECK(ret, krb5_store_int32(sp, v4creds->issue_date), error);
+
+ ret = write_v4_cc(context, tkfile, sp, append);
+
+ error:
+ krb5_storage_free(sp);
+
+ return ret;
+}
+
+/*
+ *
+ */
+
+krb5_error_code KRB5_LIB_FUNCTION
+_krb5_krb_dest_tkt(krb5_context context, const char *tkfile)
+{
+ krb5_error_code ret;
+ char *path;
+
+ ret = get_krb4_cc_name(tkfile, &path);
+ if (ret) {
+ krb5_set_error_string(context,
+ "krb5_krb_tf_setup: failed getting "
+ "the krb4 credentials cache name");
+ return ret;
+ }
+
+ if (unlink(path) < 0) {
+ ret = errno;
+ krb5_set_error_string(context,
+ "krb5_krb_dest_tkt failed removing the cache "
+ "with error %s", strerror(ret));
+ }
+ free(path);
+
+ return ret;
+}
+
+/*
+ *
+ */
+
+static krb5_error_code
+decrypt_etext(krb5_context context, const krb5_keyblock *key,
+ const krb5_data *cdata, krb5_data *data)
+{
+ krb5_error_code ret;
+ krb5_crypto crypto;
+
+ ret = krb5_crypto_init(context, key, ETYPE_DES_PCBC_NONE, &crypto);
+ if (ret)
+ return ret;
+
+ ret = krb5_decrypt(context, crypto, 0, cdata->data, cdata->length, data);
+ krb5_crypto_destroy(context, crypto);
+
+ return ret;
+}
+
+
+/*
+ *
+ */
+
+static const char eightzeros[8] = "\x00\x00\x00\x00\x00\x00\x00\x00";
+
+static krb5_error_code
+storage_to_etext(krb5_context context,
+ krb5_storage *sp,
+ const krb5_keyblock *key,
+ krb5_data *enc_data)
+{
+ krb5_error_code ret;
+ krb5_crypto crypto;
+ krb5_ssize_t size;
+ krb5_data data;
+
+ /* multiple of eight bytes */
+
+ size = krb5_storage_seek(sp, 0, SEEK_END);
+ if (size < 0)
+ return EINVAL;
+ size = 8 - (size & 7);
+
+ ret = krb5_storage_write(sp, eightzeros, size);
+ if (ret != size)
+ return EINVAL;
+
+ ret = krb5_storage_to_data(sp, &data);
+ if (ret)
+ return ret;
+
+ ret = krb5_crypto_init(context, key, ETYPE_DES_PCBC_NONE, &crypto);
+ if (ret) {
+ krb5_data_free(&data);
+ return ret;
+ }
+
+ ret = krb5_encrypt(context, crypto, 0, data.data, data.length, enc_data);
+
+ krb5_data_free(&data);
+ krb5_crypto_destroy(context, crypto);
+
+ return ret;
+}
+
+/*
+ *
+ */
+
+static krb5_error_code
+put_nir(krb5_storage *sp, const char *name,
+ const char *instance, const char *realm)
+{
+ krb5_error_code ret;
+
+ RCHECK(ret, krb5_store_stringz(sp, name), error);
+ RCHECK(ret, krb5_store_stringz(sp, instance), error);
+ if (realm) {
+ RCHECK(ret, krb5_store_stringz(sp, realm), error);
+ }
+ error:
+ return ret;
+}
+
+/*
+ *
+ */
+
+krb5_error_code KRB5_LIB_FUNCTION
+_krb5_krb_create_ticket(krb5_context context,
+ unsigned char flags,
+ const char *pname,
+ const char *pinstance,
+ const char *prealm,
+ int32_t paddress,
+ const krb5_keyblock *session,
+ int16_t life,
+ int32_t life_sec,
+ const char *sname,
+ const char *sinstance,
+ const krb5_keyblock *key,
+ krb5_data *enc_data)
+{
+ krb5_error_code ret;
+ krb5_storage *sp;
+
+ krb5_data_zero(enc_data);
+
+ sp = krb5_storage_emem();
+ if (sp == NULL) {
+ krb5_set_error_string(context, "malloc: out of memory");
+ return ENOMEM;
+ }
+ krb5_storage_set_byteorder(sp, KRB5_STORAGE_BYTEORDER_BE);
+
+ RCHECK(ret, krb5_store_int8(sp, flags), error);
+ RCHECK(ret, put_nir(sp, pname, pinstance, prealm), error);
+ RCHECK(ret, krb5_store_int32(sp, ntohl(paddress)), error);
+
+ /* session key */
+ ret = krb5_storage_write(sp,
+ session->keyvalue.data,
+ session->keyvalue.length);
+ if (ret != session->keyvalue.length) {
+ ret = EINVAL;
+ goto error;
+ }
+
+ RCHECK(ret, krb5_store_int8(sp, life), error);
+ RCHECK(ret, krb5_store_int32(sp, life_sec), error);
+ RCHECK(ret, put_nir(sp, sname, sinstance, NULL), error);
+
+ ret = storage_to_etext(context, sp, key, enc_data);
+
+ error:
+ krb5_storage_free(sp);
+ if (ret)
+ krb5_set_error_string(context, "Failed to encode kerberos 4 ticket");
+
+ return ret;
+}
+
+/*
+ *
+ */
+
+krb5_error_code KRB5_LIB_FUNCTION
+_krb5_krb_create_ciph(krb5_context context,
+ const krb5_keyblock *session,
+ const char *service,
+ const char *instance,
+ const char *realm,
+ u_int32_t life,
+ unsigned char kvno,
+ const krb5_data *ticket,
+ u_int32_t kdc_time,
+ const krb5_keyblock *key,
+ krb5_data *enc_data)
+{
+ krb5_error_code ret;
+ krb5_storage *sp;
+
+ krb5_data_zero(enc_data);
+
+ sp = krb5_storage_emem();
+ if (sp == NULL) {
+ krb5_set_error_string(context, "malloc: out of memory");
+ return ENOMEM;
+ }
+ krb5_storage_set_byteorder(sp, KRB5_STORAGE_BYTEORDER_BE);
+
+ /* session key */
+ ret = krb5_storage_write(sp,
+ session->keyvalue.data,
+ session->keyvalue.length);
+ if (ret != session->keyvalue.length) {
+ ret = EINVAL;
+ goto error;
+ }
+
+ RCHECK(ret, put_nir(sp, service, instance, realm), error);
+ RCHECK(ret, krb5_store_int8(sp, life), error);
+ RCHECK(ret, krb5_store_int8(sp, kvno), error);
+ RCHECK(ret, krb5_store_int8(sp, ticket->length), error);
+ ret = krb5_storage_write(sp, ticket->data, ticket->length);
+ if (ret != ticket->length) {
+ ret = EINVAL;
+ goto error;
+ }
+ RCHECK(ret, krb5_store_int32(sp, kdc_time), error);
+
+ ret = storage_to_etext(context, sp, key, enc_data);
+
+ error:
+ krb5_storage_free(sp);
+ if (ret)
+ krb5_set_error_string(context, "Failed to encode kerberos 4 ticket");
+
+ return ret;
+}
+
+/*
+ *
+ */
+
+krb5_error_code KRB5_LIB_FUNCTION
+_krb5_krb_create_auth_reply(krb5_context context,
+ const char *pname,
+ const char *pinst,
+ const char *prealm,
+ int32_t time_ws,
+ int n,
+ u_int32_t x_date,
+ unsigned char kvno,
+ const krb5_data *cipher,
+ krb5_data *data)
+{
+ krb5_error_code ret;
+ krb5_storage *sp;
+
+ krb5_data_zero(data);
+
+ sp = krb5_storage_emem();
+ if (sp == NULL) {
+ krb5_set_error_string(context, "malloc: out of memory");
+ return ENOMEM;
+ }
+ krb5_storage_set_byteorder(sp, KRB5_STORAGE_BYTEORDER_BE);
+
+ RCHECK(ret, krb5_store_int8(sp, KRB_PROT_VERSION), error);
+ RCHECK(ret, krb5_store_int8(sp, AUTH_MSG_KDC_REPLY), error);
+ RCHECK(ret, put_nir(sp, pname, pinst, prealm), error);
+ RCHECK(ret, krb5_store_int32(sp, time_ws), error);
+ RCHECK(ret, krb5_store_int8(sp, n), error);
+ RCHECK(ret, krb5_store_int32(sp, x_date), error);
+ RCHECK(ret, krb5_store_int8(sp, kvno), error);
+ RCHECK(ret, krb5_store_int16(sp, cipher->length), error);
+ ret = krb5_storage_write(sp, cipher->data, cipher->length);
+ if (ret != cipher->length) {
+ ret = EINVAL;
+ goto error;
+ }
+
+ ret = krb5_storage_to_data(sp, data);
+
+ error:
+ krb5_storage_free(sp);
+ if (ret)
+ krb5_set_error_string(context, "Failed to encode kerberos 4 ticket");
+
+ return ret;
+}
+
+/*
+ *
+ */
+
+krb5_error_code KRB5_LIB_FUNCTION
+_krb5_krb_cr_err_reply(krb5_context context,
+ const char *name,
+ const char *inst,
+ const char *realm,
+ u_int32_t time_ws,
+ u_int32_t e,
+ const char *e_string,
+ krb5_data *data)
+{
+ krb5_error_code ret;
+ krb5_storage *sp;
+
+ krb5_data_zero(data);
+
+ if (name == NULL) name = "";
+ if (inst == NULL) inst = "";
+ if (realm == NULL) realm = "";
+ if (e_string == NULL) e_string = "";
+
+ sp = krb5_storage_emem();
+ if (sp == NULL) {
+ krb5_set_error_string(context, "malloc: out of memory");
+ return ENOMEM;
+ }
+ krb5_storage_set_byteorder(sp, KRB5_STORAGE_BYTEORDER_BE);
+
+ RCHECK(ret, krb5_store_int8(sp, KRB_PROT_VERSION), error);
+ RCHECK(ret, krb5_store_int8(sp, AUTH_MSG_ERR_REPLY), error);
+ RCHECK(ret, put_nir(sp, name, inst, realm), error);
+ RCHECK(ret, krb5_store_int32(sp, time_ws), error);
+ RCHECK(ret, krb5_store_int32(sp, e), error);
+ RCHECK(ret, krb5_store_stringz(sp, e_string), error);
+
+ ret = krb5_storage_to_data(sp, data);
+
+ error:
+ krb5_storage_free(sp);
+ if (ret)
+ krb5_set_error_string(context, "Failed to encode kerberos 4 error");
+
+ return 0;
+}
+
+static krb5_error_code
+get_v4_stringz(krb5_storage *sp, char **str, size_t max_len)
+{
+ krb5_error_code ret;
+
+ ret = krb5_ret_stringz(sp, str);
+ if (ret)
+ return ret;
+ if (strlen(*str) > max_len) {
+ free(*str);
+ *str = NULL;
+ return EINVAL;
+ }
+ return 0;
+}
+
+/*
+ *
+ */
+
+krb5_error_code KRB5_LIB_FUNCTION
+_krb5_krb_decomp_ticket(krb5_context context,
+ const krb5_data *enc_ticket,
+ const krb5_keyblock *key,
+ const char *local_realm,
+ char **sname,
+ char **sinstance,
+ struct _krb5_krb_auth_data *ad)
+{
+ krb5_error_code ret;
+ krb5_ssize_t size;
+ krb5_storage *sp = NULL;
+ krb5_data ticket;
+ unsigned char des_key[8];
+
+ memset(ad, 0, sizeof(*ad));
+ krb5_data_zero(&ticket);
+
+ *sname = NULL;
+ *sinstance = NULL;
+
+ RCHECK(ret, decrypt_etext(context, key, enc_ticket, &ticket), error);
+
+ sp = krb5_storage_from_data(&ticket);
+ if (sp == NULL) {
+ krb5_data_free(&ticket);
+ krb5_set_error_string(context, "alloc: out of memory");
+ return ENOMEM;
+ }
+
+ krb5_storage_set_eof_code(sp, EINVAL); /* XXX */
+
+ RCHECK(ret, krb5_ret_int8(sp, &ad->k_flags), error);
+ RCHECK(ret, get_v4_stringz(sp, &ad->pname, ANAME_SZ), error);
+ RCHECK(ret, get_v4_stringz(sp, &ad->pinst, INST_SZ), error);
+ RCHECK(ret, get_v4_stringz(sp, &ad->prealm, REALM_SZ), error);
+ RCHECK(ret, krb5_ret_int32(sp, &ad->address), error);
+
+ size = krb5_storage_read(sp, des_key, sizeof(des_key));
+ if (size != sizeof(des_key)) {
+ ret = EINVAL; /* XXX */
+ goto error;
+ }
+
+ RCHECK(ret, krb5_ret_int8(sp, &ad->life), error);
+
+ if (ad->k_flags & 1)
+ krb5_storage_set_byteorder(sp, KRB5_STORAGE_BYTEORDER_LE);
+ else
+ krb5_storage_set_byteorder(sp, KRB5_STORAGE_BYTEORDER_BE);
+
+ RCHECK(ret, krb5_ret_int32(sp, &ad->time_sec), error);
+
+ RCHECK(ret, get_v4_stringz(sp, sname, ANAME_SZ), error);
+ RCHECK(ret, get_v4_stringz(sp, sinstance, INST_SZ), error);
+
+ ret = krb5_keyblock_init(context, ETYPE_DES_PCBC_NONE,
+ des_key, sizeof(des_key), &ad->session);
+ if (ret)
+ goto error;
+
+ if (strlen(ad->prealm) == 0) {
+ free(ad->prealm);
+ ad->prealm = strdup(local_realm);
+ if (ad->prealm == NULL) {
+ ret = ENOMEM;
+ goto error;
+ }
+ }
+
+ error:
+ memset(des_key, 0, sizeof(des_key));
+ if (sp)
+ krb5_storage_free(sp);
+ krb5_data_free(&ticket);
+ if (ret) {
+ if (*sname) {
+ free(*sname);
+ *sname = NULL;
+ }
+ if (*sinstance) {
+ free(*sinstance);
+ *sinstance = NULL;
+ }
+ _krb5_krb_free_auth_data(context, ad);
+ krb5_set_error_string(context, "Failed to decode v4 ticket");
+ }
+ return ret;
+}
+
+/*
+ *
+ */
+
+krb5_error_code KRB5_LIB_FUNCTION
+_krb5_krb_rd_req(krb5_context context,
+ krb5_data *authent,
+ const char *service,
+ const char *instance,
+ const char *local_realm,
+ int32_t from_addr,
+ const krb5_keyblock *key,
+ struct _krb5_krb_auth_data *ad)
+{
+ krb5_error_code ret;
+ krb5_storage *sp;
+ krb5_data ticket, eaut, aut;
+ krb5_ssize_t size;
+ int little_endian;
+ int8_t pvno;
+ int8_t type;
+ int8_t s_kvno;
+ u_int8_t ticket_length;
+ u_int8_t eaut_length;
+ u_int8_t time_5ms;
+ char *realm = NULL;
+ char *sname = NULL;
+ char *sinstance = NULL;
+ char *r_realm = NULL;
+ char *r_name = NULL;
+ char *r_instance = NULL;
+
+ u_int32_t r_time_sec; /* Coarse time from authenticator */
+ unsigned long delta_t; /* Time in authenticator - local time */
+ long tkt_age; /* Age of ticket */
+
+ struct timeval tv;
+
+ krb5_data_zero(&ticket);
+ krb5_data_zero(&eaut);
+ krb5_data_zero(&aut);
+
+ sp = krb5_storage_from_data(authent);
+ if (sp == NULL) {
+ krb5_set_error_string(context, "alloc: out of memory");
+ return ENOMEM;
+ }
+
+ krb5_storage_set_eof_code(sp, EINVAL); /* XXX */
+
+ ret = krb5_ret_int8(sp, &pvno);
+ if (ret)
+ goto error;
+
+ if (pvno != KRB_PROT_VERSION) {
+ ret = EINVAL; /* XXX */
+ goto error;
+ }
+
+ ret = krb5_ret_int8(sp, &type);
+ if (ret)
+ goto error;
+
+ little_endian = type & 1;
+ type &= ~1;
+
+ if(type != AUTH_MSG_APPL_REQUEST && type != AUTH_MSG_APPL_REQUEST_MUTUAL) {
+ ret = EINVAL; /* RD_AP_MSG_TYPE */
+ goto error;
+ }
+
+ RCHECK(ret, krb5_ret_int8(sp, &s_kvno), error);
+ RCHECK(ret, get_v4_stringz(sp, &realm, REALM_SZ), error);
+ RCHECK(ret, krb5_ret_int8(sp, &ticket_length), error);
+ RCHECK(ret, krb5_ret_int8(sp, &eaut_length), error);
+ RCHECK(ret, krb5_data_alloc(&ticket, ticket_length), error);
+
+ size = krb5_storage_read(sp, ticket.data, ticket.length);
+ if (size != ticket.length) {
+ ret = EINVAL;
+ goto error;
+ }
+
+ /* Decrypt and take apart ticket */
+ ret = _krb5_krb_decomp_ticket(context, &ticket, key, local_realm,
+ &sname, &sinstance, ad);
+ if (ret)
+ goto error;
+
+ RCHECK(ret, krb5_data_alloc(&eaut, eaut_length), error);
+
+ size = krb5_storage_read(sp, eaut.data, eaut.length);
+ if (size != eaut.length) {
+ ret = EINVAL;
+ goto error;
+ }
+
+ krb5_storage_free(sp);
+ sp = NULL;
+
+ ret = decrypt_etext(context, &ad->session, &eaut, &aut);
+ if (ret)
+ goto error;
+
+ sp = krb5_storage_from_data(&aut);
+ if (sp == NULL) {
+ krb5_set_error_string(context, "alloc: out of memory");
+ ret = ENOMEM;
+ goto error;
+ }
+
+ if (little_endian)
+ krb5_storage_set_byteorder(sp, KRB5_STORAGE_BYTEORDER_LE);
+ else
+ krb5_storage_set_byteorder(sp, KRB5_STORAGE_BYTEORDER_BE);
+
+ RCHECK(ret, get_v4_stringz(sp, &r_name, ANAME_SZ), error);
+ RCHECK(ret, get_v4_stringz(sp, &r_instance, INST_SZ), error);
+ RCHECK(ret, get_v4_stringz(sp, &r_realm, REALM_SZ), error);
+
+ RCHECK(ret, krb5_ret_int32(sp, &ad->checksum), error);
+ RCHECK(ret, krb5_ret_int8(sp, &time_5ms), error);
+ RCHECK(ret, krb5_ret_int32(sp, &r_time_sec), error);
+
+ if (strcmp(ad->pname, r_name) != 0 ||
+ strcmp(ad->pinst, r_instance) != 0 ||
+ strcmp(ad->prealm, r_realm) != 0) {
+ ret = EINVAL; /* RD_AP_INCON */
+ goto error;
+ }
+
+ if (from_addr && from_addr == ad->address) {
+ ret = EINVAL; /* RD_AP_BADD */
+ goto error;
+ }
+
+ gettimeofday(&tv, NULL);
+ delta_t = abs((int)(tv.tv_sec - r_time_sec));
+ if (delta_t > CLOCK_SKEW) {
+ ret = EINVAL; /* RD_AP_TIME */
+ goto error;
+ }
+
+ /* Now check for expiration of ticket */
+
+ tkt_age = tv.tv_sec - ad->time_sec;
+
+ if ((tkt_age < 0) && (-tkt_age > CLOCK_SKEW)) {
+ ret = EINVAL; /* RD_AP_NYV */
+ goto error;
+ }
+
+ if (tv.tv_sec > _krb5_krb_life_to_time(ad->time_sec, ad->life)) {
+ ret = EINVAL; /* RD_AP_EXP */
+ goto error;
+ }
+
+ ret = 0;
+ error:
+ krb5_data_free(&ticket);
+ krb5_data_free(&eaut);
+ krb5_data_free(&aut);
+ if (realm)
+ free(realm);
+ if (sname)
+ free(sname);
+ if (sinstance)
+ free(sinstance);
+ if (r_name)
+ free(r_name);
+ if (r_instance)
+ free(r_instance);
+ if (r_realm)
+ free(r_realm);
+ if (sp)
+ krb5_storage_free(sp);
+
+ if (ret)
+ krb5_clear_error_string(context);
+
+ return ret;
+}
+
+/*
+ *
+ */
+
+void KRB5_LIB_FUNCTION
+_krb5_krb_free_auth_data(krb5_context context, struct _krb5_krb_auth_data *ad)
+{
+ if (ad->pname)
+ free(ad->pname);
+ if (ad->pinst)
+ free(ad->pinst);
+ if (ad->prealm)
+ free(ad->prealm);
+ krb5_free_keyblock_contents(context, &ad->session);
+ memset(ad, 0, sizeof(*ad));
+}
diff --git a/source4/heimdal/lib/krb5/version.c b/source4/heimdal/lib/krb5/version.c
new file mode 100644
index 0000000000..5f0fd6680b
--- /dev/null
+++ b/source4/heimdal/lib/krb5/version.c
@@ -0,0 +1,43 @@
+/*
+ * Copyright (c) 1997 Kungliga Tekniska Högskolan
+ * (Royal Institute of Technology, Stockholm, Sweden).
+ * 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"
+
+RCSID("$Id: version.c,v 1.3 1999/12/02 17:05:13 joda Exp $");
+
+/* this is just to get a version stamp in the library file */
+
+#define heimdal_version __heimdal_version
+#define heimdal_long_version __heimdal_long_version
+#include "version.h"
+
diff --git a/source4/heimdal/lib/krb5/warn.c b/source4/heimdal/lib/krb5/warn.c
new file mode 100644
index 0000000000..f9825914ee
--- /dev/null
+++ b/source4/heimdal/lib/krb5/warn.c
@@ -0,0 +1,205 @@
+/*
+ * Copyright (c) 1997 - 2001 Kungliga Tekniska Högskolan
+ * (Royal Institute of Technology, Stockholm, Sweden).
+ * 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 <err.h>
+
+RCSID("$Id: warn.c,v 1.15 2004/05/25 21:46:26 lha Exp $");
+
+static krb5_error_code _warnerr(krb5_context context, int do_errtext,
+ krb5_error_code code, int level, const char *fmt, va_list ap)
+ __attribute__((__format__(__printf__, 5, 0)));
+
+static krb5_error_code
+_warnerr(krb5_context context, int do_errtext,
+ krb5_error_code code, int level, const char *fmt, va_list ap)
+{
+ char xfmt[7] = "";
+ const char *args[2], **arg;
+ char *msg = NULL;
+ char *err_str = NULL;
+
+ args[0] = args[1] = NULL;
+ arg = args;
+ if(fmt){
+ strlcat(xfmt, "%s", sizeof(xfmt));
+ if(do_errtext)
+ strlcat(xfmt, ": ", sizeof(xfmt));
+ vasprintf(&msg, fmt, ap);
+ if(msg == NULL)
+ return ENOMEM;
+ *arg++ = msg;
+ }
+ if(context && do_errtext){
+ const char *err_msg;
+
+ strlcat(xfmt, "%s", sizeof(xfmt));
+
+ err_str = krb5_get_error_string(context);
+ if (err_str != NULL) {
+ *arg++ = err_str;
+ } else {
+ err_msg = krb5_get_err_text(context, code);
+ if (err_msg)
+ *arg++ = err_msg;
+ else
+ *arg++ = "<unknown error>";
+ }
+ }
+
+ if(context && context->warn_dest)
+ krb5_log(context, context->warn_dest, level, xfmt, args[0], args[1]);
+ else
+ warnx(xfmt, args[0], args[1]);
+ free(msg);
+ free(err_str);
+ return 0;
+}
+
+#define FUNC(ETEXT, CODE, LEVEL) \
+ krb5_error_code ret; \
+ va_list ap; \
+ va_start(ap, fmt); \
+ ret = _warnerr(context, ETEXT, CODE, LEVEL, fmt, ap); \
+ va_end(ap);
+
+#undef __attribute__
+#define __attribute__(X)
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_vwarn(krb5_context context, krb5_error_code code,
+ const char *fmt, va_list ap)
+ __attribute__ ((format (printf, 3, 0)))
+{
+ return _warnerr(context, 1, code, 1, fmt, ap);
+}
+
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_warn(krb5_context context, krb5_error_code code, const char *fmt, ...)
+ __attribute__ ((format (printf, 3, 4)))
+{
+ FUNC(1, code, 1);
+ return ret;
+}
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_vwarnx(krb5_context context, const char *fmt, va_list ap)
+ __attribute__ ((format (printf, 2, 0)))
+{
+ return _warnerr(context, 0, 0, 1, fmt, ap);
+}
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_warnx(krb5_context context, const char *fmt, ...)
+ __attribute__ ((format (printf, 2, 3)))
+{
+ FUNC(0, 0, 1);
+ return ret;
+}
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_verr(krb5_context context, int eval, krb5_error_code code,
+ const char *fmt, va_list ap)
+ __attribute__ ((noreturn, format (printf, 4, 0)))
+{
+ _warnerr(context, 1, code, 0, fmt, ap);
+ exit(eval);
+}
+
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_err(krb5_context context, int eval, krb5_error_code code,
+ const char *fmt, ...)
+ __attribute__ ((noreturn, format (printf, 4, 5)))
+{
+ FUNC(1, code, 0);
+ exit(eval);
+}
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_verrx(krb5_context context, int eval, const char *fmt, va_list ap)
+ __attribute__ ((noreturn, format (printf, 3, 0)))
+{
+ _warnerr(context, 0, 0, 0, fmt, ap);
+ exit(eval);
+}
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_errx(krb5_context context, int eval, const char *fmt, ...)
+ __attribute__ ((noreturn, format (printf, 3, 4)))
+{
+ FUNC(0, 0, 0);
+ exit(eval);
+}
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_vabort(krb5_context context, krb5_error_code code,
+ const char *fmt, va_list ap)
+ __attribute__ ((noreturn, format (printf, 3, 0)))
+{
+ _warnerr(context, 1, code, 0, fmt, ap);
+ abort();
+}
+
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_abort(krb5_context context, krb5_error_code code, const char *fmt, ...)
+ __attribute__ ((noreturn, format (printf, 3, 4)))
+{
+ FUNC(1, code, 0);
+ abort();
+}
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_vabortx(krb5_context context, const char *fmt, va_list ap)
+ __attribute__ ((noreturn, format (printf, 2, 0)))
+{
+ _warnerr(context, 0, 0, 0, fmt, ap);
+ abort();
+}
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_abortx(krb5_context context, const char *fmt, ...)
+ __attribute__ ((noreturn, format (printf, 2, 3)))
+{
+ FUNC(0, 0, 0);
+ abort();
+}
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_set_warn_dest(krb5_context context, krb5_log_facility *fac)
+{
+ context->warn_dest = fac;
+ return 0;
+}