r8302: import mini HEIMDAL into the tree
authorHeimdal Import User <samba-bugs@samba.org>
Mon, 11 Jul 2005 01:16:55 +0000 (01:16 +0000)
committerGerald (Jerry) Carter <jerry@samba.org>
Wed, 10 Oct 2007 18:19:33 +0000 (13:19 -0500)
(This used to be commit 118be28a7aef233799956615a99d1a2a74dac175)

240 files changed:
source4/heimdal/kdc/524.c [new file with mode: 0644]
source4/heimdal/kdc/default_config.c [new file with mode: 0644]
source4/heimdal/kdc/headers.h [new file with mode: 0644]
source4/heimdal/kdc/kaserver.c [new file with mode: 0644]
source4/heimdal/kdc/kdc-protos.h [new file with mode: 0644]
source4/heimdal/kdc/kdc.h [new file with mode: 0644]
source4/heimdal/kdc/kdc_locl.h [new file with mode: 0644]
source4/heimdal/kdc/kerberos4.c [new file with mode: 0644]
source4/heimdal/kdc/kerberos5.c [new file with mode: 0644]
source4/heimdal/kdc/log.c [new file with mode: 0644]
source4/heimdal/kdc/misc.c [new file with mode: 0644]
source4/heimdal/kdc/pkinit.c [new file with mode: 0755]
source4/heimdal/kdc/process.c [new file with mode: 0644]
source4/heimdal/kdc/rx.h [new file with mode: 0644]
source4/heimdal/lib/asn1/asn1-common.h [new file with mode: 0644]
source4/heimdal/lib/asn1/asn1_err.et [new file with mode: 0644]
source4/heimdal/lib/asn1/der.h [new file with mode: 0644]
source4/heimdal/lib/asn1/der_cmp.c [new file with mode: 0755]
source4/heimdal/lib/asn1/der_copy.c [new file with mode: 0644]
source4/heimdal/lib/asn1/der_free.c [new file with mode: 0644]
source4/heimdal/lib/asn1/der_get.c [new file with mode: 0644]
source4/heimdal/lib/asn1/der_length.c [new file with mode: 0644]
source4/heimdal/lib/asn1/der_locl.h [new file with mode: 0644]
source4/heimdal/lib/asn1/der_put.c [new file with mode: 0644]
source4/heimdal/lib/asn1/gen.c [new file with mode: 0644]
source4/heimdal/lib/asn1/gen_copy.c [new file with mode: 0644]
source4/heimdal/lib/asn1/gen_decode.c [new file with mode: 0644]
source4/heimdal/lib/asn1/gen_encode.c [new file with mode: 0644]
source4/heimdal/lib/asn1/gen_free.c [new file with mode: 0644]
source4/heimdal/lib/asn1/gen_glue.c [new file with mode: 0644]
source4/heimdal/lib/asn1/gen_length.c [new file with mode: 0644]
source4/heimdal/lib/asn1/gen_locl.h [new file with mode: 0644]
source4/heimdal/lib/asn1/hash.c [new file with mode: 0644]
source4/heimdal/lib/asn1/hash.h [new file with mode: 0644]
source4/heimdal/lib/asn1/k5.asn1 [new file with mode: 0644]
source4/heimdal/lib/asn1/lex.h [new file with mode: 0644]
source4/heimdal/lib/asn1/lex.l [new file with mode: 0644]
source4/heimdal/lib/asn1/main.c [new file with mode: 0644]
source4/heimdal/lib/asn1/parse.y [new file with mode: 0644]
source4/heimdal/lib/asn1/symbol.c [new file with mode: 0644]
source4/heimdal/lib/asn1/symbol.h [new file with mode: 0644]
source4/heimdal/lib/asn1/timegm.c [new file with mode: 0644]
source4/heimdal/lib/com_err/com_err.c [new file with mode: 0644]
source4/heimdal/lib/com_err/com_err.h [new file with mode: 0644]
source4/heimdal/lib/com_err/com_right.h [new file with mode: 0644]
source4/heimdal/lib/com_err/compile_et.c [new file with mode: 0644]
source4/heimdal/lib/com_err/compile_et.h [new file with mode: 0644]
source4/heimdal/lib/com_err/error.c [new file with mode: 0644]
source4/heimdal/lib/com_err/lex.h [new file with mode: 0644]
source4/heimdal/lib/com_err/lex.l [new file with mode: 0644]
source4/heimdal/lib/com_err/parse.y [new file with mode: 0644]
source4/heimdal/lib/des/aes.c [new file with mode: 0755]
source4/heimdal/lib/des/aes.h [new file with mode: 0755]
source4/heimdal/lib/des/des-tables.h [new file with mode: 0644]
source4/heimdal/lib/des/des.c [new file with mode: 0644]
source4/heimdal/lib/des/des.h [new file with mode: 0644]
source4/heimdal/lib/des/hash.h [new file with mode: 0644]
source4/heimdal/lib/des/md4.c [new file with mode: 0644]
source4/heimdal/lib/des/md4.h [new file with mode: 0644]
source4/heimdal/lib/des/md5.c [new file with mode: 0644]
source4/heimdal/lib/des/md5.h [new file with mode: 0644]
source4/heimdal/lib/des/rc2.c [new file with mode: 0755]
source4/heimdal/lib/des/rc2.h [new file with mode: 0755]
source4/heimdal/lib/des/rc4.c [new file with mode: 0755]
source4/heimdal/lib/des/rc4.h [new file with mode: 0644]
source4/heimdal/lib/des/rijndael-alg-fst.c [new file with mode: 0755]
source4/heimdal/lib/des/rijndael-alg-fst.h [new file with mode: 0755]
source4/heimdal/lib/des/rnd_keys.c [new file with mode: 0644]
source4/heimdal/lib/des/sha.c [new file with mode: 0644]
source4/heimdal/lib/des/sha.h [new file with mode: 0644]
source4/heimdal/lib/des/ui.c [new file with mode: 0644]
source4/heimdal/lib/gssapi/8003.c [new file with mode: 0644]
source4/heimdal/lib/gssapi/accept_sec_context.c [new file with mode: 0644]
source4/heimdal/lib/gssapi/acquire_cred.c [new file with mode: 0644]
source4/heimdal/lib/gssapi/add_oid_set_member.c [new file with mode: 0644]
source4/heimdal/lib/gssapi/address_to_krb5addr.c [new file with mode: 0644]
source4/heimdal/lib/gssapi/arcfour.c [new file with mode: 0644]
source4/heimdal/lib/gssapi/arcfour.h [new file with mode: 0644]
source4/heimdal/lib/gssapi/ccache_name.c [new file with mode: 0755]
source4/heimdal/lib/gssapi/cfx.c [new file with mode: 0755]
source4/heimdal/lib/gssapi/cfx.h [new file with mode: 0755]
source4/heimdal/lib/gssapi/compat.c [new file with mode: 0644]
source4/heimdal/lib/gssapi/context_time.c [new file with mode: 0644]
source4/heimdal/lib/gssapi/copy_ccache.c [new file with mode: 0644]
source4/heimdal/lib/gssapi/create_emtpy_oid_set.c [new file with mode: 0644]
source4/heimdal/lib/gssapi/decapsulate.c [new file with mode: 0644]
source4/heimdal/lib/gssapi/delete_sec_context.c [new file with mode: 0644]
source4/heimdal/lib/gssapi/display_name.c [new file with mode: 0644]
source4/heimdal/lib/gssapi/display_status.c [new file with mode: 0644]
source4/heimdal/lib/gssapi/duplicate_name.c [new file with mode: 0644]
source4/heimdal/lib/gssapi/encapsulate.c [new file with mode: 0644]
source4/heimdal/lib/gssapi/external.c [new file with mode: 0644]
source4/heimdal/lib/gssapi/get_mic.c [new file with mode: 0644]
source4/heimdal/lib/gssapi/gssapi.h [new file with mode: 0644]
source4/heimdal/lib/gssapi/gssapi_locl.h [new file with mode: 0644]
source4/heimdal/lib/gssapi/import_name.c [new file with mode: 0644]
source4/heimdal/lib/gssapi/init.c [new file with mode: 0644]
source4/heimdal/lib/gssapi/init_sec_context.c [new file with mode: 0644]
source4/heimdal/lib/gssapi/inquire_cred.c [new file with mode: 0644]
source4/heimdal/lib/gssapi/release_buffer.c [new file with mode: 0644]
source4/heimdal/lib/gssapi/release_cred.c [new file with mode: 0644]
source4/heimdal/lib/gssapi/release_name.c [new file with mode: 0644]
source4/heimdal/lib/gssapi/release_oid_set.c [new file with mode: 0644]
source4/heimdal/lib/gssapi/sequence.c [new file with mode: 0755]
source4/heimdal/lib/gssapi/spnego.asn1 [new file with mode: 0755]
source4/heimdal/lib/gssapi/test_oid_set_member.c [new file with mode: 0644]
source4/heimdal/lib/gssapi/unwrap.c [new file with mode: 0644]
source4/heimdal/lib/gssapi/verify_mic.c [new file with mode: 0644]
source4/heimdal/lib/gssapi/wrap.c [new file with mode: 0644]
source4/heimdal/lib/hdb/db.c [new file with mode: 0644]
source4/heimdal/lib/hdb/hdb-private.h [new file with mode: 0644]
source4/heimdal/lib/hdb/hdb-protos.h [new file with mode: 0644]
source4/heimdal/lib/hdb/hdb.asn1 [new file with mode: 0644]
source4/heimdal/lib/hdb/hdb.c [new file with mode: 0644]
source4/heimdal/lib/hdb/hdb.h [new file with mode: 0644]
source4/heimdal/lib/hdb/hdb_err.et [new file with mode: 0644]
source4/heimdal/lib/hdb/hdb_locl.h [new file with mode: 0644]
source4/heimdal/lib/hdb/keys.c [new file with mode: 0644]
source4/heimdal/lib/hdb/ndbm.c [new file with mode: 0644]
source4/heimdal/lib/krb5/acache.c [new file with mode: 0644]
source4/heimdal/lib/krb5/add_et_list.c [new file with mode: 0644]
source4/heimdal/lib/krb5/addr_families.c [new file with mode: 0644]
source4/heimdal/lib/krb5/appdefault.c [new file with mode: 0644]
source4/heimdal/lib/krb5/asn1_glue.c [new file with mode: 0644]
source4/heimdal/lib/krb5/auth_context.c [new file with mode: 0644]
source4/heimdal/lib/krb5/build_ap_req.c [new file with mode: 0644]
source4/heimdal/lib/krb5/build_auth.c [new file with mode: 0644]
source4/heimdal/lib/krb5/cache.c [new file with mode: 0644]
source4/heimdal/lib/krb5/changepw.c [new file with mode: 0644]
source4/heimdal/lib/krb5/codec.c [new file with mode: 0644]
source4/heimdal/lib/krb5/config_file.c [new file with mode: 0644]
source4/heimdal/lib/krb5/config_file_netinfo.c [new file with mode: 0644]
source4/heimdal/lib/krb5/constants.c [new file with mode: 0644]
source4/heimdal/lib/krb5/context.c [new file with mode: 0644]
source4/heimdal/lib/krb5/copy_host_realm.c [new file with mode: 0644]
source4/heimdal/lib/krb5/crc.c [new file with mode: 0644]
source4/heimdal/lib/krb5/creds.c [new file with mode: 0644]
source4/heimdal/lib/krb5/crypto.c [new file with mode: 0644]
source4/heimdal/lib/krb5/data.c [new file with mode: 0644]
source4/heimdal/lib/krb5/eai_to_heim_errno.c [new file with mode: 0644]
source4/heimdal/lib/krb5/error_string.c [new file with mode: 0644]
source4/heimdal/lib/krb5/expand_hostname.c [new file with mode: 0644]
source4/heimdal/lib/krb5/fcache.c [new file with mode: 0644]
source4/heimdal/lib/krb5/free.c [new file with mode: 0644]
source4/heimdal/lib/krb5/free_host_realm.c [new file with mode: 0644]
source4/heimdal/lib/krb5/generate_seq_number.c [new file with mode: 0644]
source4/heimdal/lib/krb5/generate_subkey.c [new file with mode: 0644]
source4/heimdal/lib/krb5/get_addrs.c [new file with mode: 0644]
source4/heimdal/lib/krb5/get_cred.c [new file with mode: 0644]
source4/heimdal/lib/krb5/get_default_principal.c [new file with mode: 0644]
source4/heimdal/lib/krb5/get_default_realm.c [new file with mode: 0644]
source4/heimdal/lib/krb5/get_for_creds.c [new file with mode: 0644]
source4/heimdal/lib/krb5/get_host_realm.c [new file with mode: 0644]
source4/heimdal/lib/krb5/get_in_tkt.c [new file with mode: 0644]
source4/heimdal/lib/krb5/get_in_tkt_with_keytab.c [new file with mode: 0644]
source4/heimdal/lib/krb5/get_port.c [new file with mode: 0644]
source4/heimdal/lib/krb5/heim_err.et [new file with mode: 0644]
source4/heimdal/lib/krb5/heim_threads.h [new file with mode: 0755]
source4/heimdal/lib/krb5/init_creds.c [new file with mode: 0644]
source4/heimdal/lib/krb5/init_creds_pw.c [new file with mode: 0644]
source4/heimdal/lib/krb5/k524_err.et [new file with mode: 0644]
source4/heimdal/lib/krb5/kcm.c [new file with mode: 0644]
source4/heimdal/lib/krb5/keyblock.c [new file with mode: 0644]
source4/heimdal/lib/krb5/keytab.c [new file with mode: 0644]
source4/heimdal/lib/krb5/keytab_any.c [new file with mode: 0644]
source4/heimdal/lib/krb5/keytab_file.c [new file with mode: 0644]
source4/heimdal/lib/krb5/keytab_keyfile.c [new file with mode: 0644]
source4/heimdal/lib/krb5/keytab_krb4.c [new file with mode: 0644]
source4/heimdal/lib/krb5/keytab_memory.c [new file with mode: 0644]
source4/heimdal/lib/krb5/krb5-private.h [new file with mode: 0644]
source4/heimdal/lib/krb5/krb5-protos.h [new file with mode: 0644]
source4/heimdal/lib/krb5/krb5-v4compat.h [new file with mode: 0644]
source4/heimdal/lib/krb5/krb5.h [new file with mode: 0644]
source4/heimdal/lib/krb5/krb5_ccapi.h [new file with mode: 0644]
source4/heimdal/lib/krb5/krb5_err.et [new file with mode: 0644]
source4/heimdal/lib/krb5/krb5_locl.h [new file with mode: 0644]
source4/heimdal/lib/krb5/krbhst.c [new file with mode: 0644]
source4/heimdal/lib/krb5/log.c [new file with mode: 0644]
source4/heimdal/lib/krb5/mcache.c [new file with mode: 0644]
source4/heimdal/lib/krb5/misc.c [new file with mode: 0644]
source4/heimdal/lib/krb5/mit_glue.c [new file with mode: 0755]
source4/heimdal/lib/krb5/mk_error.c [new file with mode: 0644]
source4/heimdal/lib/krb5/mk_priv.c [new file with mode: 0644]
source4/heimdal/lib/krb5/mk_rep.c [new file with mode: 0644]
source4/heimdal/lib/krb5/mk_req.c [new file with mode: 0644]
source4/heimdal/lib/krb5/mk_req_ext.c [new file with mode: 0644]
source4/heimdal/lib/krb5/n-fold.c [new file with mode: 0644]
source4/heimdal/lib/krb5/padata.c [new file with mode: 0644]
source4/heimdal/lib/krb5/pkinit.c [new file with mode: 0755]
source4/heimdal/lib/krb5/principal.c [new file with mode: 0644]
source4/heimdal/lib/krb5/rd_cred.c [new file with mode: 0644]
source4/heimdal/lib/krb5/rd_error.c [new file with mode: 0644]
source4/heimdal/lib/krb5/rd_priv.c [new file with mode: 0644]
source4/heimdal/lib/krb5/rd_rep.c [new file with mode: 0644]
source4/heimdal/lib/krb5/rd_req.c [new file with mode: 0644]
source4/heimdal/lib/krb5/replay.c [new file with mode: 0644]
source4/heimdal/lib/krb5/send_to_kdc.c [new file with mode: 0644]
source4/heimdal/lib/krb5/set_default_realm.c [new file with mode: 0644]
source4/heimdal/lib/krb5/store-int.h [new file with mode: 0644]
source4/heimdal/lib/krb5/store.c [new file with mode: 0644]
source4/heimdal/lib/krb5/store_emem.c [new file with mode: 0644]
source4/heimdal/lib/krb5/store_fd.c [new file with mode: 0644]
source4/heimdal/lib/krb5/store_mem.c [new file with mode: 0644]
source4/heimdal/lib/krb5/ticket.c [new file with mode: 0644]
source4/heimdal/lib/krb5/time.c [new file with mode: 0644]
source4/heimdal/lib/krb5/transited.c [new file with mode: 0644]
source4/heimdal/lib/krb5/v4_glue.c [new file with mode: 0644]
source4/heimdal/lib/krb5/version.c [new file with mode: 0644]
source4/heimdal/lib/krb5/warn.c [new file with mode: 0644]
source4/heimdal/lib/roken/base64.c [new file with mode: 0644]
source4/heimdal/lib/roken/base64.h [new file with mode: 0644]
source4/heimdal/lib/roken/bswap.c [new file with mode: 0644]
source4/heimdal/lib/roken/emalloc.c [new file with mode: 0644]
source4/heimdal/lib/roken/get_window_size.c [new file with mode: 0644]
source4/heimdal/lib/roken/getarg.c [new file with mode: 0644]
source4/heimdal/lib/roken/getarg.h [new file with mode: 0644]
source4/heimdal/lib/roken/getifaddrs.c [new file with mode: 0644]
source4/heimdal/lib/roken/getprogname.c [new file with mode: 0644]
source4/heimdal/lib/roken/h_errno.c [new file with mode: 0644]
source4/heimdal/lib/roken/issuid.c [new file with mode: 0644]
source4/heimdal/lib/roken/net_read.c [new file with mode: 0644]
source4/heimdal/lib/roken/net_write.c [new file with mode: 0644]
source4/heimdal/lib/roken/parse_time.c [new file with mode: 0644]
source4/heimdal/lib/roken/parse_time.h [new file with mode: 0644]
source4/heimdal/lib/roken/parse_units.c [new file with mode: 0644]
source4/heimdal/lib/roken/parse_units.h [new file with mode: 0644]
source4/heimdal/lib/roken/print_version.c [new file with mode: 0644]
source4/heimdal/lib/roken/resolve.c [new file with mode: 0644]
source4/heimdal/lib/roken/resolve.h [new file with mode: 0644]
source4/heimdal/lib/roken/roken-common.h [new file with mode: 0644]
source4/heimdal/lib/roken/roken.h [new file with mode: 0644]
source4/heimdal/lib/roken/roken_gethostby.c [new file with mode: 0644]
source4/heimdal/lib/roken/setprogname.c [new file with mode: 0644]
source4/heimdal/lib/roken/signal.c [new file with mode: 0644]
source4/heimdal/lib/roken/strlwr.c [new file with mode: 0644]
source4/heimdal/lib/roken/strpool.c [new file with mode: 0644]
source4/heimdal/lib/roken/strsep_copy.c [new file with mode: 0644]
source4/heimdal/lib/roken/strupr.c [new file with mode: 0644]
source4/heimdal/lib/roken/vis.c [new file with mode: 0644]
source4/heimdal/lib/roken/vis.hin [new file with mode: 0644]

diff --git a/source4/heimdal/kdc/524.c b/source4/heimdal/kdc/524.c
new file mode 100644 (file)
index 0000000..497539b
--- /dev/null
@@ -0,0 +1,395 @@
+/*
+ * 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 "kdc_locl.h"
+
+RCSID("$Id: 524.c,v 1.34 2005/06/30 01:47:35 lha Exp $");
+
+#include <krb5-v4compat.h>
+
+/*
+ * fetch the server from `t', returning the name in malloced memory in
+ * `spn' and the entry itself in `server'
+ */
+
+static krb5_error_code
+fetch_server (krb5_context context, 
+             krb5_kdc_configuration *config,
+             const Ticket *t,
+             char **spn,
+             hdb_entry **server,
+             const char *from)
+{
+    krb5_error_code ret;
+    krb5_principal sprinc;
+
+    ret = _krb5_principalname2krb5_principal(&sprinc, t->sname, t->realm);
+    if (ret) {
+       kdc_log(context, config, 0, "_krb5_principalname2krb5_principal: %s",
+               krb5_get_err_text(context, ret));
+       return ret;
+    }
+    ret = krb5_unparse_name(context, sprinc, spn);
+    if (ret) {
+       krb5_free_principal(context, sprinc);
+       kdc_log(context, config, 0, "krb5_unparse_name: %s",
+               krb5_get_err_text(context, ret));
+       return ret;
+    }
+    ret = _kdc_db_fetch(context, config, sprinc, HDB_ENT_TYPE_SERVER, server);
+    krb5_free_principal(context, sprinc);
+    if (ret) {
+       kdc_log(context, config, 0,
+       "Request to convert ticket from %s for unknown principal %s: %s",
+               from, *spn, krb5_get_err_text(context, ret));
+       if (ret == HDB_ERR_NOENTRY)
+           ret = KRB5KDC_ERR_S_PRINCIPAL_UNKNOWN;
+       return ret;
+    }
+    return 0;
+}
+
+static krb5_error_code
+log_524 (krb5_context context, 
+        krb5_kdc_configuration *config,
+        const EncTicketPart *et,
+        const char *from,
+        const char *spn)
+{
+    krb5_principal client;
+    char *cpn;
+    krb5_error_code ret;
+
+    ret = _krb5_principalname2krb5_principal(&client, et->cname, et->crealm);
+    if (ret) {
+       kdc_log(context, config, 0, "_krb5_principalname2krb5_principal: %s",
+               krb5_get_err_text (context, ret));
+       return ret;
+    }
+    ret = krb5_unparse_name(context, client, &cpn);
+    if (ret) {
+       krb5_free_principal(context, client);
+       kdc_log(context, config, 0, "krb5_unparse_name: %s",
+               krb5_get_err_text (context, ret));
+       return ret;
+    }
+    kdc_log(context, config, 1, "524-REQ %s from %s for %s", cpn, from, spn);
+    free(cpn);
+    krb5_free_principal(context, client);
+    return 0;
+}
+
+static krb5_error_code
+verify_flags (krb5_context context, 
+             krb5_kdc_configuration *config,
+             const EncTicketPart *et,
+             const char *spn)
+{
+    if(et->endtime < kdc_time){
+       kdc_log(context, config, 0, "Ticket expired (%s)", spn);
+       return KRB5KRB_AP_ERR_TKT_EXPIRED;
+    }
+    if(et->flags.invalid){
+       kdc_log(context, config, 0, "Ticket not valid (%s)", spn);
+       return KRB5KRB_AP_ERR_TKT_NYV;
+    }
+    return 0;
+}
+
+/*
+ * set the `et->caddr' to the most appropriate address to use, where
+ * `addr' is the address the request was received from.
+ */
+
+static krb5_error_code
+set_address (krb5_context context, 
+            krb5_kdc_configuration *config,
+            EncTicketPart *et,
+            struct sockaddr *addr,
+            const char *from)
+{
+    krb5_error_code ret;
+    krb5_address *v4_addr;
+
+    v4_addr = malloc (sizeof(*v4_addr));
+    if (v4_addr == NULL)
+       return ENOMEM;
+
+    ret = krb5_sockaddr2address(context, addr, v4_addr);
+    if(ret) {
+       free (v4_addr);
+       kdc_log(context, config, 0, "Failed to convert address (%s)", from);
+       return ret;
+    }
+           
+    if (et->caddr && !krb5_address_search (context, v4_addr, et->caddr)) {
+       kdc_log(context, config, 0, "Incorrect network address (%s)", from);
+       krb5_free_address(context, v4_addr);
+       free (v4_addr);
+       return KRB5KRB_AP_ERR_BADADDR;
+    }
+    if(v4_addr->addr_type == KRB5_ADDRESS_INET) {
+       /* we need to collapse the addresses in the ticket to a
+          single address; best guess is to use the address the
+          connection came from */
+       
+       if (et->caddr != NULL) {
+           free_HostAddresses(et->caddr);
+       } else {
+           et->caddr = malloc (sizeof (*et->caddr));
+           if (et->caddr == NULL) {
+               krb5_free_address(context, v4_addr);
+               free(v4_addr);
+               return ENOMEM;
+           }
+       }
+       et->caddr->val = v4_addr;
+       et->caddr->len = 1;
+    } else {
+       krb5_free_address(context, v4_addr);
+       free(v4_addr);
+    }
+    return 0;
+}
+
+
+static krb5_error_code
+encrypt_v4_ticket(krb5_context context, 
+                 krb5_kdc_configuration *config,
+                 void *buf, 
+                 size_t len, 
+                 krb5_keyblock *skey, 
+                 EncryptedData *reply)
+{
+    krb5_crypto crypto;
+    krb5_error_code ret;
+    ret = krb5_crypto_init(context, skey, ETYPE_DES_PCBC_NONE, &crypto);
+    if (ret) {
+       free(buf);
+       kdc_log(context, config, 0, "krb5_crypto_init failed: %s",
+               krb5_get_err_text(context, ret));
+       return ret;
+    }
+
+    ret = krb5_encrypt_EncryptedData(context, 
+                                    crypto,
+                                    KRB5_KU_TICKET,
+                                    buf,
+                                    len,
+                                    0,
+                                    reply);
+    krb5_crypto_destroy(context, crypto);
+    if(ret) {
+       kdc_log(context, config, 0, "Failed to encrypt data: %s",
+               krb5_get_err_text(context, ret));
+       return ret;
+    }
+    return 0;
+}
+
+static krb5_error_code
+encode_524_response(krb5_context context, 
+                   krb5_kdc_configuration *config,
+                   const char *spn, const EncTicketPart et,
+                   const Ticket *t, hdb_entry *server, 
+                   EncryptedData *ticket, int *kvno)
+{
+    krb5_error_code ret;
+    int use_2b;
+    size_t len;
+
+    use_2b = krb5_config_get_bool(context, NULL, "kdc", "use_2b", spn, NULL);
+    if(use_2b) {
+       ASN1_MALLOC_ENCODE(EncryptedData, 
+                          ticket->cipher.data, ticket->cipher.length, 
+                          &t->enc_part, &len, ret);
+       
+       if (ret) {
+           kdc_log(context, config, 0, 
+                   "Failed to encode v4 (2b) ticket (%s)", spn);
+           return ret;
+       }
+       
+       ticket->etype = 0;
+       ticket->kvno = NULL;
+       *kvno = 213; /* 2b's use this magic kvno */
+    } else {
+       unsigned char buf[MAX_KTXT_LEN + 4 * 4];
+       Key *skey;
+       
+       if (!config->enable_v4_cross_realm && strcmp (et.crealm, t->realm) != 0) {
+           kdc_log(context, config, 0, "524 cross-realm %s -> %s disabled", et.crealm,
+                   t->realm);
+           return KRB5KDC_ERR_POLICY;
+       }
+
+       ret = _kdc_encode_v4_ticket(context, config, 
+                                   buf + sizeof(buf) - 1, sizeof(buf),
+                                   &et, &t->sname, &len);
+       if(ret){
+           kdc_log(context, config, 0,
+                   "Failed to encode v4 ticket (%s)", spn);
+           return ret;
+       }
+       ret = _kdc_get_des_key(context, server, TRUE, FALSE, &skey);
+       if(ret){
+           kdc_log(context, config, 0,
+                   "no suitable DES key for server (%s)", spn);
+           return ret;
+       }
+       ret = encrypt_v4_ticket(context, config, buf + sizeof(buf) - len, len, 
+                               &skey->key, ticket);
+       if(ret){
+           kdc_log(context, config, 0,
+                   "Failed to encrypt v4 ticket (%s)", spn);
+           return ret;
+       }
+       *kvno = server->kvno;
+    }
+
+    return 0;
+}
+
+/*
+ * process a 5->4 request, based on `t', and received `from, addr',
+ * returning the reply in `reply'
+ */
+
+krb5_error_code
+_kdc_do_524(krb5_context context, 
+           krb5_kdc_configuration *config,
+           const Ticket *t, krb5_data *reply,
+           const char *from, struct sockaddr *addr)
+{
+    krb5_error_code ret = 0;
+    krb5_crypto crypto;
+    hdb_entry *server = NULL;
+    Key *skey;
+    krb5_data et_data;
+    EncTicketPart et;
+    EncryptedData ticket;
+    krb5_storage *sp;
+    char *spn = NULL;
+    unsigned char buf[MAX_KTXT_LEN + 4 * 4];
+    size_t len;
+    int kvno = 0;
+    
+    if(!config->enable_524) {
+       ret = KRB5KDC_ERR_POLICY;
+       kdc_log(context, config, 0,
+               "Rejected ticket conversion request from %s", from);
+       goto out;
+    }
+
+    ret = fetch_server (context, config, t, &spn, &server, from);
+    if (ret) {
+       goto out;
+    }
+
+    ret = hdb_enctype2key(context, server, t->enc_part.etype, &skey);
+    if(ret){
+       kdc_log(context, config, 0,
+               "No suitable key found for server (%s) from %s", spn, from);
+       goto out;
+    }
+    ret = krb5_crypto_init(context, &skey->key, 0, &crypto);
+    if (ret) {
+       kdc_log(context, config, 0, "krb5_crypto_init failed: %s",
+               krb5_get_err_text(context, ret));
+       goto out;
+    }
+    ret = krb5_decrypt_EncryptedData (context,
+                                     crypto,
+                                     KRB5_KU_TICKET,
+                                     &t->enc_part,
+                                     &et_data);
+    krb5_crypto_destroy(context, crypto);
+    if(ret){
+       kdc_log(context, config, 0,
+               "Failed to decrypt ticket from %s for %s", from, spn);
+       goto out;
+    }
+    ret = krb5_decode_EncTicketPart(context, et_data.data, et_data.length, 
+                                   &et, &len);
+    krb5_data_free(&et_data);
+    if(ret){
+       kdc_log(context, config, 0,
+               "Failed to decode ticket from %s for %s", from, spn);
+       goto out;
+    }
+
+    ret = log_524 (context, config, &et, from, spn);
+    if (ret) {
+       free_EncTicketPart(&et);
+       goto out;
+    }
+
+    ret = verify_flags (context, config, &et, spn);
+    if (ret) {
+       free_EncTicketPart(&et);
+       goto out;
+    }
+
+    ret = set_address (context, config, &et, addr, from);
+    if (ret) {
+       free_EncTicketPart(&et);
+       goto out;
+    }
+
+    ret = encode_524_response(context, config, spn, et, t,
+                             server, &ticket, &kvno);
+    free_EncTicketPart(&et);
+
+ out:
+    /* make reply */
+    memset(buf, 0, sizeof(buf));
+    sp = krb5_storage_from_mem(buf, sizeof(buf));
+    krb5_store_int32(sp, ret);
+    if(ret == 0){
+       krb5_store_int32(sp, kvno);
+       krb5_store_data(sp, ticket.cipher);
+       /* Aargh! This is coded as a KTEXT_ST. */
+       krb5_storage_seek(sp, MAX_KTXT_LEN - ticket.cipher.length, SEEK_CUR);
+       krb5_store_int32(sp, 0); /* mbz */
+       free_EncryptedData(&ticket);
+    }
+    ret = krb5_storage_to_data(sp, reply);
+    reply->length = krb5_storage_seek(sp, 0, SEEK_CUR);
+    krb5_storage_free(sp);
+    
+    if(spn)
+       free(spn);
+    if(server)
+       _kdc_free_ent (context, server);
+    return ret;
+}
diff --git a/source4/heimdal/kdc/default_config.c b/source4/heimdal/kdc/default_config.c
new file mode 100644 (file)
index 0000000..5152fe9
--- /dev/null
@@ -0,0 +1,61 @@
+/*
+ * Copyright (c) 2005 Andrew Bartlett <abartlet@samba.org>
+ * 
+ * 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. 
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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 "kdc_locl.h"
+
+/* 
+ * Setup some of the defaults for the KDC configuration.
+ * 
+ * Note: Caller must also fill in:
+ * - db
+ * - num_db
+ * - logf
+ *
+*/
+
+void
+krb5_kdc_default_config(krb5_kdc_configuration *config)
+{
+    config->require_preauth = TRUE;
+    config->kdc_warn_pwexpire = -1;
+    config->encode_as_rep_as_tgs_rep = FALSE; /* bug compatibility */
+    config->check_ticket_addresses = TRUE;
+    config->allow_null_ticket_addresses = TRUE;
+    config->allow_anonymous = FALSE;
+    config->trpolicy = TRPOLICY_ALWAYS_CHECK;
+    config->enable_v4 = FALSE;
+    config->enable_kaserver = FALSE;
+    config->enable_524 = FALSE; /* overriden by enable_v4 in configure()) */
+    config->enable_v4_cross_realm = FALSE;
+    config->enable_pkinit = FALSE;
+    config->enable_pkinit_princ_in_cert = TRUE;
+    config->db = NULL;
+    config->num_db = 0;
+    config->logf = NULL;
+}
diff --git a/source4/heimdal/kdc/headers.h b/source4/heimdal/kdc/headers.h
new file mode 100644 (file)
index 0000000..86f162a
--- /dev/null
@@ -0,0 +1,101 @@
+/*
+ * 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. 
+ */
+
+/* 
+ * $Id: headers.h,v 1.16 2005/04/24 13:49:00 lha Exp $ 
+ */
+
+#ifndef __HEADERS_H__
+#define __HEADERS_H__
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+#include <limits.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <signal.h>
+#include <stdarg.h>
+#ifdef HAVE_SYS_TYPES_H
+#include <sys/types.h>
+#endif
+#ifdef HAVE_FCNTL_H
+#include <fcntl.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_ARPA_INET_H
+#include <arpa/inet.h>
+#endif
+#ifdef HAVE_NETDB_H
+#include <netdb.h>
+#endif
+#ifdef HAVE_UTIL_H
+#include <util.h>
+#endif
+#ifdef HAVE_LIBUTIL_H
+#include <libutil.h>
+#endif
+#include <err.h>
+#include <roken.h>
+#include <getarg.h>
+#include <base64.h>
+#include <parse_units.h>
+#include <krb5.h>
+#include <krb5_locl.h>
+#include <hdb.h>
+#include <hdb_err.h>
+#include <der.h> /* copy_octet_string */
+
+#undef ALLOC
+#define ALLOC(X) ((X) = malloc(sizeof(*(X))))
+#undef ALLOC_SEQ
+#define ALLOC_SEQ(X, N) do { (X)->len = (N); \
+(X)->val = calloc((X)->len, sizeof(*(X)->val)); } while(0)
+
+#endif /* __HEADERS_H__ */
diff --git a/source4/heimdal/kdc/kaserver.c b/source4/heimdal/kdc/kaserver.c
new file mode 100644 (file)
index 0000000..4a9bd87
--- /dev/null
@@ -0,0 +1,908 @@
+/*
+ * 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 "kdc_locl.h"
+
+RCSID("$Id: kaserver.c,v 1.30 2005/06/30 01:49:39 lha Exp $");
+
+#include <krb5-v4compat.h>
+#include <rx.h>
+
+#define KA_AUTHENTICATION_SERVICE 731
+#define KA_TICKET_GRANTING_SERVICE 732
+#define KA_MAINTENANCE_SERVICE 733
+
+#define AUTHENTICATE_OLD        1
+#define CHANGEPASSWORD          2
+#define GETTICKET_OLD           3
+#define SETPASSWORD             4
+#define SETFIELDS               5
+#define CREATEUSER              6
+#define DELETEUSER              7
+#define GETENTRY                8
+#define LISTENTRY               9
+#define GETSTATS               10
+#define DEBUG                  11
+#define GETPASSWORD            12
+#define GETRANDOMKEY           13
+#define AUTHENTICATE           21
+#define AUTHENTICATE_V2                22
+#define GETTICKET              23
+
+/* XXX - Where do we get these? */
+
+#define RXGEN_OPCODE (-455)
+
+#define KADATABASEINCONSISTENT                   (180480L)
+#define KAEXIST                                  (180481L)
+#define KAIO                                     (180482L)
+#define KACREATEFAIL                             (180483L)
+#define KANOENT                                  (180484L)
+#define KAEMPTY                                  (180485L)
+#define KABADNAME                                (180486L)
+#define KABADINDEX                               (180487L)
+#define KANOAUTH                                 (180488L)
+#define KAANSWERTOOLONG                          (180489L)
+#define KABADREQUEST                             (180490L)
+#define KAOLDINTERFACE                           (180491L)
+#define KABADARGUMENT                            (180492L)
+#define KABADCMD                                 (180493L)
+#define KANOKEYS                                 (180494L)
+#define KAREADPW                                 (180495L)
+#define KABADKEY                                 (180496L)
+#define KAUBIKINIT                               (180497L)
+#define KAUBIKCALL                               (180498L)
+#define KABADPROTOCOL                            (180499L)
+#define KANOCELLS                                (180500L)
+#define KANOCELL                                 (180501L)
+#define KATOOMANYUBIKS                           (180502L)
+#define KATOOMANYKEYS                            (180503L)
+#define KABADTICKET                              (180504L)
+#define KAUNKNOWNKEY                             (180505L)
+#define KAKEYCACHEINVALID                        (180506L)
+#define KABADSERVER                              (180507L)
+#define KABADUSER                                (180508L)
+#define KABADCPW                                 (180509L)
+#define KABADCREATE                              (180510L)
+#define KANOTICKET                               (180511L)
+#define KAASSOCUSER                              (180512L)
+#define KANOTSPECIAL                             (180513L)
+#define KACLOCKSKEW                              (180514L)
+#define KANORECURSE                              (180515L)
+#define KARXFAIL                                 (180516L)
+#define KANULLPASSWORD                           (180517L)
+#define KAINTERNALERROR                          (180518L)
+#define KAPWEXPIRED                              (180519L)
+#define KAREUSED                                 (180520L)
+#define KATOOSOON                                (180521L)
+#define KALOCKED                                 (180522L)
+
+static void
+decode_rx_header (krb5_storage *sp,
+                 struct rx_header *h)
+{
+    krb5_ret_int32(sp, &h->epoch);
+    krb5_ret_int32(sp, &h->connid);
+    krb5_ret_int32(sp, &h->callid);
+    krb5_ret_int32(sp, &h->seqno);
+    krb5_ret_int32(sp, &h->serialno);
+    krb5_ret_int8(sp,  &h->type);
+    krb5_ret_int8(sp,  &h->flags);
+    krb5_ret_int8(sp,  &h->status);
+    krb5_ret_int8(sp,  &h->secindex);
+    krb5_ret_int16(sp, &h->reserved);
+    krb5_ret_int16(sp, &h->serviceid);
+}
+
+static void
+encode_rx_header (struct rx_header *h,
+                 krb5_storage *sp)
+{
+    krb5_store_int32(sp, h->epoch);
+    krb5_store_int32(sp, h->connid);
+    krb5_store_int32(sp, h->callid);
+    krb5_store_int32(sp, h->seqno);
+    krb5_store_int32(sp, h->serialno);
+    krb5_store_int8(sp,  h->type);
+    krb5_store_int8(sp,  h->flags);
+    krb5_store_int8(sp,  h->status);
+    krb5_store_int8(sp,  h->secindex);
+    krb5_store_int16(sp, h->reserved);
+    krb5_store_int16(sp, h->serviceid);
+}
+
+static void
+init_reply_header (struct rx_header *hdr,
+                  struct rx_header *reply_hdr,
+                  u_char type,
+                  u_char flags)
+{
+    reply_hdr->epoch     = hdr->epoch;
+    reply_hdr->connid    = hdr->connid;
+    reply_hdr->callid    = hdr->callid;
+    reply_hdr->seqno     = 1;
+    reply_hdr->serialno  = 1;
+    reply_hdr->type      = type;
+    reply_hdr->flags     = flags;
+    reply_hdr->status    = 0;
+    reply_hdr->secindex  = 0;
+    reply_hdr->reserved  = 0;
+    reply_hdr->serviceid = hdr->serviceid;
+}
+
+static void
+make_error_reply (struct rx_header *hdr,
+                 u_int32_t ret,
+                 krb5_data *reply)
+
+{
+    krb5_storage *sp;
+    struct rx_header reply_hdr;
+
+    init_reply_header (hdr, &reply_hdr, HT_ABORT, HF_LAST);
+    sp = krb5_storage_emem();
+    encode_rx_header (&reply_hdr, sp);
+    krb5_store_int32(sp, ret);
+    krb5_storage_to_data (sp, reply);
+    krb5_storage_free (sp);
+}
+
+static krb5_error_code
+krb5_ret_xdr_data(krb5_storage *sp,
+                 krb5_data *data)
+{
+    int ret;
+    int size;
+    ret = krb5_ret_int32(sp, &size);
+    if(ret)
+       return ret;
+    if(size < 0)
+       return ERANGE;
+    data->length = size;
+    if (size) {
+       u_char foo[4];
+       size_t pad = (4 - size % 4) % 4;
+
+       data->data = malloc(size);
+       if (data->data == NULL)
+           return ENOMEM;
+       ret = krb5_storage_read(sp, data->data, size);
+       if(ret != size)
+           return (ret < 0)? errno : KRB5_CC_END;
+       if (pad) {
+           ret = krb5_storage_read(sp, foo, pad);
+           if (ret != pad)
+               return (ret < 0)? errno : KRB5_CC_END;
+       }
+    } else
+       data->data = NULL;
+    return 0;
+}
+
+static krb5_error_code
+krb5_store_xdr_data(krb5_storage *sp,
+                   krb5_data data)
+{
+    u_char zero[4] = {0, 0, 0, 0};
+    int ret;
+    size_t pad;
+
+    ret = krb5_store_int32(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_CC_END;
+    }
+    pad = (4 - data.length % 4) % 4;
+    if (pad) {
+       ret = krb5_storage_write(sp, zero, pad);
+       if (ret != pad) {
+           if (ret < 0)
+               return errno;
+           return KRB5_CC_END;
+       }
+    }
+    return 0;
+}
+
+
+static krb5_error_code
+create_reply_ticket (krb5_context context, 
+                    struct rx_header *hdr,
+                    Key *skey,
+                    char *name, char *instance, char *realm,
+                    struct sockaddr_in *addr,
+                    int life,
+                    int kvno,
+                    int32_t max_seq_len,
+                    const char *sname, const char *sinstance,
+                    u_int32_t challenge,
+                    const char *label,
+                    krb5_keyblock *key,
+                    krb5_data *reply)
+{
+    krb5_data ticket;
+    krb5_keyblock session;
+    krb5_storage *sp;
+    krb5_data enc_data;
+    struct rx_header reply_hdr;
+    char zero[8];
+    size_t pad;
+    unsigned fyrtiosjuelva;
+
+    /* create the ticket */
+
+    krb5_generate_random_keyblock(context, ETYPE_DES_PCBC_NONE, &session);
+
+    _krb5_krb_create_ticket(context,
+                           0,
+                           name,
+                           instance,
+                           realm,
+                           addr->sin_addr.s_addr,
+                           &session,
+                           life,
+                           kdc_time,
+                           sname,
+                           sinstance,
+                           &skey->key,
+                           &ticket);
+
+    /* create the encrypted part of the reply */
+    sp = krb5_storage_emem ();
+    krb5_generate_random_block(&fyrtiosjuelva, sizeof(fyrtiosjuelva));
+    fyrtiosjuelva &= 0xffffffff;
+    krb5_store_int32 (sp, fyrtiosjuelva);
+    krb5_store_int32 (sp, challenge);
+    krb5_storage_write  (sp, session.keyvalue.data, 8);
+    krb5_free_keyblock_contents(context, &session);
+    krb5_store_int32 (sp, kdc_time);
+    krb5_store_int32 (sp, kdc_time + _krb5_krb_life_to_time (0, life));
+    krb5_store_int32 (sp, kvno);
+    krb5_store_int32 (sp, ticket.length);
+    krb5_store_stringz (sp, name);
+    krb5_store_stringz (sp, instance);
+#if 1 /* XXX - Why shouldn't the realm go here? */
+    krb5_store_stringz (sp, "");
+#else
+    krb5_store_stringz (sp, realm);
+#endif
+    krb5_store_stringz (sp, sname);
+    krb5_store_stringz (sp, sinstance);
+    krb5_storage_write (sp, ticket.data, ticket.length);
+    krb5_storage_write (sp, label, strlen(label));
+
+    /* pad to DES block */
+    memset (zero, 0, sizeof(zero));
+    pad = (8 - krb5_storage_seek (sp, 0, SEEK_CUR) % 8) % 8;
+    krb5_storage_write (sp, zero, pad);
+
+    krb5_storage_to_data (sp, &enc_data);
+    krb5_storage_free (sp);
+
+    if (enc_data.length > max_seq_len) {
+       krb5_data_free (&enc_data);
+       make_error_reply (hdr, KAANSWERTOOLONG, reply);
+       return 0;
+    }
+
+    /* encrypt it */
+    {
+        DES_key_schedule schedule;
+       DES_cblock deskey;
+       
+       memcpy (&deskey, key->keyvalue.data, sizeof(deskey));
+       DES_set_key (&deskey, &schedule);
+       DES_pcbc_encrypt (enc_data.data,
+                         enc_data.data,
+                         enc_data.length,
+                         &schedule,
+                         &deskey,
+                         DES_ENCRYPT);
+       memset (&schedule, 0, sizeof(schedule));
+       memset (&deskey, 0, sizeof(deskey));
+    }
+
+    /* create the reply packet */
+    init_reply_header (hdr, &reply_hdr, HT_DATA, HF_LAST);
+    sp = krb5_storage_emem ();
+    encode_rx_header (&reply_hdr, sp);
+    krb5_store_int32 (sp, max_seq_len);
+    krb5_store_xdr_data (sp, enc_data);
+    krb5_data_free (&enc_data);
+    krb5_storage_to_data (sp, reply);
+    krb5_storage_free (sp);
+    return 0;
+}
+
+static krb5_error_code
+unparse_auth_args (krb5_storage *sp,
+                  char **name,
+                  char **instance,
+                  time_t *start_time,
+                  time_t *end_time,
+                  krb5_data *request,
+                  int32_t *max_seq_len)
+{
+    krb5_data data;
+    int32_t tmp;
+
+    krb5_ret_xdr_data (sp, &data);
+    *name = malloc(data.length + 1);
+    if (*name == NULL)
+       return ENOMEM;
+    memcpy (*name, data.data, data.length);
+    (*name)[data.length] = '\0';
+    krb5_data_free (&data);
+
+    krb5_ret_xdr_data (sp, &data);
+    *instance = malloc(data.length + 1);
+    if (*instance == NULL) {
+       free (*name);
+       return ENOMEM;
+    }
+    memcpy (*instance, data.data, data.length);
+    (*instance)[data.length] = '\0';
+    krb5_data_free (&data);
+
+    krb5_ret_int32 (sp, &tmp);
+    *start_time = tmp;
+    krb5_ret_int32 (sp, &tmp);
+    *end_time = tmp;
+    krb5_ret_xdr_data (sp, request);
+    krb5_ret_int32 (sp, max_seq_len);
+    /* ignore the rest */
+    return 0;
+}
+
+static void
+do_authenticate (krb5_context context, 
+                krb5_kdc_configuration *config,
+                struct rx_header *hdr,
+                krb5_storage *sp,
+                struct sockaddr_in *addr,
+                const char *from,
+                krb5_data *reply)
+{
+    krb5_error_code ret;
+    char *name = NULL;
+    char *instance = NULL;
+    time_t start_time;
+    time_t end_time;
+    krb5_data request;
+    int32_t max_seq_len;
+    hdb_entry *client_entry = NULL;
+    hdb_entry *server_entry = NULL;
+    Key *ckey = NULL;
+    Key *skey = NULL;
+    krb5_storage *reply_sp;
+    time_t max_life;
+    u_int8_t life;
+    int32_t chal;
+    char client_name[256];
+    char server_name[256];
+       
+    krb5_data_zero (&request);
+
+    ret = unparse_auth_args (sp, &name, &instance, &start_time, &end_time,
+                            &request, &max_seq_len);
+    if (ret != 0 || request.length < 8) {
+       make_error_reply (hdr, KABADREQUEST, reply);
+       goto out;
+    }
+
+    snprintf (client_name, sizeof(client_name), "%s.%s@%s",
+             name, instance, config->v4_realm);
+    snprintf (server_name, sizeof(server_name), "%s.%s@%s",
+             "krbtgt", config->v4_realm, config->v4_realm);
+
+    kdc_log(context, config, 0, "AS-REQ (kaserver) %s from %s for %s",
+           client_name, from, server_name);
+
+    ret = _kdc_db_fetch4 (context, config, name, instance, 
+                         config->v4_realm, HDB_ENT_TYPE_CLIENT, 
+                         &client_entry);
+    if (ret) {
+       kdc_log(context, config, 0, "Client not found in database: %s: %s",
+               client_name, krb5_get_err_text(context, ret));
+       make_error_reply (hdr, KANOENT, reply);
+       goto out;
+    }
+
+    ret = _kdc_db_fetch4 (context, config, "krbtgt", 
+                         config->v4_realm, config->v4_realm, 
+                         HDB_ENT_TYPE_SERVER, &server_entry);
+    if (ret) {
+       kdc_log(context, config, 0, "Server not found in database: %s: %s",
+               server_name, krb5_get_err_text(context, ret));
+       make_error_reply (hdr, KANOENT, reply);
+       goto out;
+    }
+
+    ret = _kdc_check_flags (context, config,
+                           client_entry, client_name,
+                           server_entry, server_name,
+                           TRUE);
+    if (ret) {
+       make_error_reply (hdr, KAPWEXPIRED, reply);
+       goto out;
+    }
+
+    /* find a DES key */
+    ret = _kdc_get_des_key(context, client_entry, FALSE, TRUE, &ckey);
+    if(ret){
+       kdc_log(context, config, 0, "no suitable DES key for client");
+       make_error_reply (hdr, KANOKEYS, reply);
+       goto out;
+    }
+
+    /* find a DES key */
+    ret = _kdc_get_des_key(context, server_entry, TRUE, TRUE, &skey);
+    if(ret){
+       kdc_log(context, config, 0, "no suitable DES key for server");
+       make_error_reply (hdr, KANOKEYS, reply);
+       goto out;
+    }
+
+    {
+       DES_cblock key;
+       DES_key_schedule schedule;
+       
+       /* try to decode the `request' */
+       memcpy (&key, ckey->key.keyvalue.data, sizeof(key));
+       DES_set_key (&key, &schedule);
+       DES_pcbc_encrypt (request.data,
+                         request.data,
+                         request.length,
+                         &schedule,
+                         &key,
+                         DES_DECRYPT);
+       memset (&schedule, 0, sizeof(schedule));
+       memset (&key, 0, sizeof(key));
+    }
+
+    /* check for the magic label */
+    if (memcmp ((char *)request.data + 4, "gTGS", 4) != 0) {
+       kdc_log(context, config, 0, "preauth failed for %s", client_name);
+       make_error_reply (hdr, KABADREQUEST, reply);
+       goto out;
+    }
+
+    reply_sp = krb5_storage_from_mem (request.data, 4);
+    krb5_ret_int32 (reply_sp, &chal);
+    krb5_storage_free (reply_sp);
+
+    if (abs(chal - kdc_time) > context->max_skew) {
+       make_error_reply (hdr, KACLOCKSKEW, reply);
+       goto out;
+    }
+
+    /* life */
+    max_life = end_time - kdc_time;
+    /* end_time - kdc_time can sometimes be non-positive due to slight
+       time skew between client and server. Let's make sure it is postive */
+    if(max_life < 1)
+       max_life = 1;
+    if (client_entry->max_life)
+       max_life = min(max_life, *client_entry->max_life);
+    if (server_entry->max_life)
+       max_life = min(max_life, *server_entry->max_life);
+
+    life = krb_time_to_life(kdc_time, kdc_time + max_life);
+
+    create_reply_ticket (context, 
+                        hdr, skey,
+                        name, instance, config->v4_realm,
+                        addr, life, server_entry->kvno,
+                        max_seq_len,
+                        "krbtgt", config->v4_realm,
+                        chal + 1, "tgsT",
+                        &ckey->key, reply);
+
+ out:
+    if (request.length) {
+       memset (request.data, 0, request.length);
+       krb5_data_free (&request);
+    }
+    if (name)
+       free (name);
+    if (instance)
+       free (instance);
+    if (client_entry)
+       _kdc_free_ent (context, client_entry);
+    if (server_entry)
+       _kdc_free_ent (context, server_entry);
+}
+
+static krb5_error_code
+unparse_getticket_args (krb5_storage *sp,
+                       int *kvno,
+                       char **auth_domain,
+                       krb5_data *ticket,
+                       char **name,
+                       char **instance,
+                       krb5_data *times,
+                       int32_t *max_seq_len)
+{
+    krb5_data data;
+    int32_t tmp;
+
+    krb5_ret_int32 (sp, &tmp);
+    *kvno = tmp;
+
+    krb5_ret_xdr_data (sp, &data);
+    *auth_domain = malloc(data.length + 1);
+    if (*auth_domain == NULL)
+       return ENOMEM;
+    memcpy (*auth_domain, data.data, data.length);
+    (*auth_domain)[data.length] = '\0';
+    krb5_data_free (&data);
+
+    krb5_ret_xdr_data (sp, ticket);
+
+    krb5_ret_xdr_data (sp, &data);
+    *name = malloc(data.length + 1);
+    if (*name == NULL) {
+       free (*auth_domain);
+       return ENOMEM;
+    }
+    memcpy (*name, data.data, data.length);
+    (*name)[data.length] = '\0';
+    krb5_data_free (&data);
+
+    krb5_ret_xdr_data (sp, &data);
+    *instance = malloc(data.length + 1);
+    if (*instance == NULL) {
+       free (*auth_domain);
+       free (*name);
+       return ENOMEM;
+    }
+    memcpy (*instance, data.data, data.length);
+    (*instance)[data.length] = '\0';
+    krb5_data_free (&data);
+
+    krb5_ret_xdr_data (sp, times);
+
+    krb5_ret_int32 (sp, max_seq_len);
+    /* ignore the rest */
+    return 0;
+}
+
+static void
+do_getticket (krb5_context context, 
+             krb5_kdc_configuration *config,
+             struct rx_header *hdr,
+             krb5_storage *sp,
+             struct sockaddr_in *addr,
+             const char *from,
+             krb5_data *reply)
+{
+    krb5_error_code ret;
+    int kvno;
+    char *auth_domain = NULL;
+    krb5_data aticket;
+    char *name = NULL;
+    char *instance = NULL;
+    krb5_data times;
+    int32_t max_seq_len;
+    hdb_entry *server_entry = NULL;
+    hdb_entry *client_entry = NULL;
+    hdb_entry *krbtgt_entry = NULL;
+    Key *kkey = NULL;
+    Key *skey = NULL;
+    DES_cblock key;
+    DES_key_schedule schedule;
+    DES_cblock session;
+    time_t max_life;
+    int8_t life;
+    time_t start_time, end_time;
+    char server_name[256];
+    char client_name[256];
+    struct _krb5_krb_auth_data ad;
+
+    krb5_data_zero (&aticket);
+    krb5_data_zero (&times);
+
+    memset(&ad, 0, sizeof(ad));
+
+    unparse_getticket_args (sp, &kvno, &auth_domain, &aticket,
+                           &name, &instance, &times, &max_seq_len);
+    if (times.length < 8) {
+       make_error_reply (hdr, KABADREQUEST, reply);
+       goto out;
+       
+    }
+
+    snprintf (server_name, sizeof(server_name),
+             "%s.%s@%s", name, instance, config->v4_realm);
+
+    ret = _kdc_db_fetch4 (context, config, name, instance, 
+                         config->v4_realm, HDB_ENT_TYPE_SERVER, 
+                         &server_entry);
+    if (ret) {
+       kdc_log(context, config, 0, "Server not found in database: %s: %s",
+               server_name, krb5_get_err_text(context, ret));
+       make_error_reply (hdr, KANOENT, reply);
+       goto out;
+    }
+
+    ret = _kdc_db_fetch4 (context, config, "krbtgt", 
+                         config->v4_realm, config->v4_realm, 
+                         HDB_ENT_TYPE_CLIENT, &krbtgt_entry);
+    if (ret) {
+       kdc_log(context, config, 0,
+               "Server not found in database: %s.%s@%s: %s",
+               "krbtgt", config->v4_realm,  config->v4_realm,
+               krb5_get_err_text(context, ret));
+       make_error_reply (hdr, KANOENT, reply);
+       goto out;
+    }
+
+    /* find a DES key */
+    ret = _kdc_get_des_key(context, krbtgt_entry, TRUE, TRUE, &kkey);
+    if(ret){
+       kdc_log(context, config, 0, "no suitable DES key for krbtgt");
+       make_error_reply (hdr, KANOKEYS, reply);
+       goto out;
+    }
+
+    /* find a DES key */
+    ret = _kdc_get_des_key(context, server_entry, TRUE, TRUE, &skey);
+    if(ret){
+       kdc_log(context, config, 0, "no suitable DES key for server");
+       make_error_reply (hdr, KANOKEYS, reply);
+       goto out;
+    }
+
+    /* decrypt the incoming ticket */
+    memcpy (&key, kkey->key.keyvalue.data, sizeof(key));
+
+    /* unpack the ticket */
+    {
+       char *sname = NULL;
+       char *sinstance = NULL;
+
+       ret = _krb5_krb_decomp_ticket(context, &aticket, &kkey->key, 
+                                     config->v4_realm, &sname,
+                                     &sinstance, &ad);
+       if (ret) {
+           kdc_log(context, config, 0,
+                   "kaserver: decomp failed for %s.%s with %d",
+                   sname, sinstance, ret);
+           make_error_reply (hdr, KABADTICKET, reply);
+           goto out;
+       }
+
+       if (strcmp (sname, "krbtgt") != 0
+           || strcmp (sinstance, config->v4_realm) != 0) {
+           kdc_log(context, config, 0, "no TGT: %s.%s for %s.%s@%s",
+                   sname, sinstance,
+                   ad.pname, ad.pinst, ad.prealm);
+           make_error_reply (hdr, KABADTICKET, reply);
+           free(sname);
+           free(sinstance);
+           goto out;
+       }
+       free(sname);
+       free(sinstance);
+
+       if (kdc_time > _krb5_krb_life_to_time(ad.time_sec, ad.life)) {
+           kdc_log(context, config, 0, "TGT expired: %s.%s@%s",
+                   ad.pname, ad.pinst, ad.prealm);
+           make_error_reply (hdr, KABADTICKET, reply);
+           goto out;
+       }
+    }
+
+    snprintf (client_name, sizeof(client_name),
+             "%s.%s@%s", ad.pname, ad.pinst, ad.prealm);
+
+    kdc_log(context, config, 0, "TGS-REQ (kaserver) %s from %s for %s",
+           client_name, from, server_name);
+
+    ret = _kdc_db_fetch4 (context, config, 
+                         ad.pname, ad.pinst, ad.prealm, 
+                         HDB_ENT_TYPE_CLIENT, &client_entry);
+    if(ret && ret != HDB_ERR_NOENTRY) {
+       kdc_log(context, config, 0,
+               "Client not found in database: (krb4) %s: %s",
+               client_name, krb5_get_err_text(context, ret));
+       make_error_reply (hdr, KANOENT, reply);
+       goto out;
+    }
+    if (client_entry == NULL && strcmp(ad.prealm, config->v4_realm) == 0) {
+       kdc_log(context, config, 0, 
+               "Local client not found in database: (krb4) "
+               "%s", client_name);
+       make_error_reply (hdr, KANOENT, reply);
+       goto out;
+    }
+
+    ret = _kdc_check_flags (context, config, 
+                           client_entry, client_name,
+                           server_entry, server_name,
+                           FALSE);
+    if (ret) {
+       make_error_reply (hdr, KAPWEXPIRED, reply);
+       goto out;
+    }
+
+    /* decrypt the times */
+    memcpy(&session, ad.session.keyvalue.data, sizeof(session));
+    DES_set_key (&session, &schedule);
+    DES_ecb_encrypt (times.data,
+                    times.data,
+                    &schedule,
+                    DES_DECRYPT);
+    memset (&schedule, 0, sizeof(schedule));
+    memset (&session, 0, sizeof(session));
+
+    /* and extract them */
+    {
+       krb5_storage *tsp;
+       int32_t tmp;
+
+       tsp = krb5_storage_from_mem (times.data, times.length);
+       krb5_ret_int32 (tsp, &tmp);
+       start_time = tmp;
+       krb5_ret_int32 (tsp, &tmp);
+       end_time = tmp;
+       krb5_storage_free (tsp);
+    }
+
+    /* life */
+    max_life = end_time - kdc_time;
+    /* end_time - kdc_time can sometimes be non-positive due to slight
+       time skew between client and server. Let's make sure it is postive */
+    if(max_life < 1)
+       max_life = 1;
+    if (krbtgt_entry->max_life)
+       max_life = min(max_life, *krbtgt_entry->max_life);
+    if (server_entry->max_life)
+       max_life = min(max_life, *server_entry->max_life);
+    /* if this is a cross realm request, the client_entry will likely
+       be NULL */
+    if (client_entry && client_entry->max_life)
+       max_life = min(max_life, *client_entry->max_life);
+
+    life = _krb5_krb_time_to_life(kdc_time, kdc_time + max_life);
+
+    create_reply_ticket (context, 
+                        hdr, skey,
+                        ad.pname, ad.pinst, ad.prealm,
+                        addr, life, server_entry->kvno,
+                        max_seq_len,
+                        name, instance,
+                        0, "gtkt",
+                        &ad.session, reply);
+    
+ out:
+    _krb5_krb_free_auth_data(context, &ad);
+    if (aticket.length) {
+       memset (aticket.data, 0, aticket.length);
+       krb5_data_free (&aticket);
+    }
+    if (times.length) {
+       memset (times.data, 0, times.length);
+       krb5_data_free (&times);
+    }
+    if (auth_domain)
+       free (auth_domain);
+    if (name)
+       free (name);
+    if (instance)
+       free (instance);
+    if (krbtgt_entry)
+       _kdc_free_ent (context, krbtgt_entry);
+    if (server_entry)
+       _kdc_free_ent (context, server_entry);
+}
+
+krb5_error_code
+_kdc_do_kaserver(krb5_context context, 
+                krb5_kdc_configuration *config,
+                unsigned char *buf,
+                size_t len,
+                krb5_data *reply,
+                const char *from,
+                struct sockaddr_in *addr)
+{
+    krb5_error_code ret = 0;
+    struct rx_header hdr;
+    u_int32_t op;
+    krb5_storage *sp;
+
+    if (len < RX_HEADER_SIZE)
+       return -1;
+    sp = krb5_storage_from_mem (buf, len);
+
+    decode_rx_header (sp, &hdr);
+    buf += RX_HEADER_SIZE;
+    len -= RX_HEADER_SIZE;
+
+    switch (hdr.type) {
+    case HT_DATA :
+       break;
+    case HT_ACK :
+    case HT_BUSY :
+    case HT_ABORT :
+    case HT_ACKALL :
+    case HT_CHAL :
+    case HT_RESP :
+    case HT_DEBUG :
+    default:
+       /* drop */
+       goto out;
+    }
+
+
+    if (hdr.serviceid != KA_AUTHENTICATION_SERVICE
+       && hdr.serviceid != KA_TICKET_GRANTING_SERVICE) {
+       ret = -1;
+       goto out;
+    }
+
+    krb5_ret_int32(sp, &op);
+    switch (op) {
+    case AUTHENTICATE :
+    case AUTHENTICATE_V2 :
+       do_authenticate (context, config, &hdr, sp, addr, from, reply);
+       break;
+    case GETTICKET :
+       do_getticket (context, config, &hdr, sp, addr, from, reply);
+       break;
+    case AUTHENTICATE_OLD :
+    case CHANGEPASSWORD :
+    case GETTICKET_OLD :
+    case SETPASSWORD :
+    case SETFIELDS :
+    case CREATEUSER :
+    case DELETEUSER :
+    case GETENTRY :
+    case LISTENTRY :
+    case GETSTATS :
+    case DEBUG :
+    case GETPASSWORD :
+    case GETRANDOMKEY :
+    default :
+       make_error_reply (&hdr, RXGEN_OPCODE, reply);
+       break;
+    }
+
+out:
+    krb5_storage_free (sp);
+    return ret;
+}
diff --git a/source4/heimdal/kdc/kdc-protos.h b/source4/heimdal/kdc/kdc-protos.h
new file mode 100644 (file)
index 0000000..5967f93
--- /dev/null
@@ -0,0 +1,68 @@
+/* This is a generated file */
+#ifndef __kdc_protos_h__
+#define __kdc_protos_h__
+
+#include <stdarg.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+void
+kdc_log (
+       krb5_context /*context*/,
+       krb5_kdc_configuration */*config*/,
+       int /*level*/,
+       const char */*fmt*/,
+       ...);
+
+char*
+kdc_log_msg (
+       krb5_context /*context*/,
+       krb5_kdc_configuration */*config*/,
+       int /*level*/,
+       const char */*fmt*/,
+       ...);
+
+char*
+kdc_log_msg_va (
+       krb5_context /*context*/,
+       krb5_kdc_configuration */*config*/,
+       int /*level*/,
+       const char */*fmt*/,
+       va_list /*ap*/);
+
+void
+kdc_openlog (
+       krb5_context /*context*/,
+       krb5_kdc_configuration */*config*/);
+
+void
+krb5_kdc_default_config (krb5_kdc_configuration */*config*/);
+
+int
+krb5_kdc_process_generic_request (
+       krb5_context /*context*/,
+       krb5_kdc_configuration */*config*/,
+       unsigned char */*buf*/,
+       size_t /*len*/,
+       krb5_data */*reply*/,
+       krb5_boolean */*prependlength*/,
+       const char */*from*/,
+       struct sockaddr */*addr*/);
+
+int
+krb5_kdc_process_krb5_request (
+       krb5_context /*context*/,
+       krb5_kdc_configuration */*config*/,
+       unsigned char */*buf*/,
+       size_t /*len*/,
+       krb5_data */*reply*/,
+       const char */*from*/,
+       struct sockaddr */*addr*/);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __kdc_protos_h__ */
diff --git a/source4/heimdal/kdc/kdc.h b/source4/heimdal/kdc/kdc.h
new file mode 100644 (file)
index 0000000..f186983
--- /dev/null
@@ -0,0 +1,81 @@
+/*
+ * Copyright (c) 1997-2003 Kungliga Tekniska Högskolan
+ * (Royal Institute of Technology, Stockholm, Sweden). 
+ *
+ * Copyright (c) 2005 Andrew Bartlett <abartlet@samba.org>
+ * 
+ * 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: kdc.h,v 1.4 2005/06/30 01:50:42 lha Exp $ 
+ */
+
+#ifndef __KDC_H__
+#define __KDC_H__
+
+#include <krb5.h>
+
+enum krb5_kdc_trpolicy {
+    TRPOLICY_ALWAYS_CHECK,
+    TRPOLICY_ALLOW_PER_PRINCIPAL, 
+    TRPOLICY_ALWAYS_HONOUR_REQUEST
+};
+
+typedef struct krb5_kdc_configuration {
+    krb5_boolean require_preauth; /* require preauth for all principals */
+    time_t kdc_warn_pwexpire; /* time before expiration to print a warning */
+
+    struct HDB **db;
+    int num_db;
+
+    krb5_boolean encode_as_rep_as_tgs_rep; /* bug compatibility */
+       
+    krb5_boolean check_ticket_addresses;
+    krb5_boolean allow_null_ticket_addresses;
+    krb5_boolean allow_anonymous;
+    enum krb5_kdc_trpolicy trpolicy;
+
+    char *v4_realm;
+    krb5_boolean enable_v4;
+    krb5_boolean enable_kaserver;
+       
+    krb5_boolean enable_524;
+    krb5_boolean enable_v4_cross_realm;
+
+    krb5_boolean enable_pkinit;
+    krb5_boolean enable_pkinit_princ_in_cert;
+
+    krb5_log_facility *logf;
+} krb5_kdc_configuration;
+
+#include <kdc-protos.h>
+
+#endif
diff --git a/source4/heimdal/kdc/kdc_locl.h b/source4/heimdal/kdc/kdc_locl.h
new file mode 100644 (file)
index 0000000..d347c60
--- /dev/null
@@ -0,0 +1,154 @@
+/*
+ * 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. 
+ */
+
+/* 
+ * $Id: kdc_locl.h,v 1.71 2005/07/01 15:36:16 lha Exp $ 
+ */
+
+#ifndef __KDC_LOCL_H__
+#define __KDC_LOCL_H__
+
+#include "headers.h"
+#include "kdc.h"
+
+extern sig_atomic_t exit_flag;
+extern size_t max_request;
+extern const char *port_str;
+extern krb5_addresses explicit_addresses;
+
+extern int enable_http;
+
+#define DETACH_IS_DEFAULT FALSE
+
+extern int detach_from_console;
+
+#define _PATH_KDC_CONF         HDB_DB_DIR "/kdc.conf"
+#define DEFAULT_LOG_DEST       "0-1/FILE:" HDB_DB_DIR "/kdc.log"
+
+extern struct timeval _kdc_now;
+#define kdc_time (_kdc_now.tv_sec)
+
+krb5_error_code
+_kdc_as_rep(krb5_context context, 
+           krb5_kdc_configuration *config,
+           KDC_REQ*, krb5_data*, const char*, struct sockaddr*);
+
+krb5_kdc_configuration *
+configure(krb5_context context, int argc, char **argv);
+
+krb5_error_code
+_kdc_db_fetch(krb5_context, krb5_kdc_configuration *,
+             krb5_principal, enum hdb_ent_type, hdb_entry **);
+
+void
+_kdc_free_ent(krb5_context context, hdb_entry *);
+
+void
+loop(krb5_context context, krb5_kdc_configuration *config);
+
+krb5_error_code
+_kdc_tgs_rep (krb5_context context, 
+             krb5_kdc_configuration *config,
+             KDC_REQ*, krb5_data*, const char*, struct sockaddr *);
+
+krb5_error_code
+_kdc_check_flags(krb5_context context, 
+                krb5_kdc_configuration *config,
+                hdb_entry *client, const char *client_name,
+                hdb_entry *server, const char *server_name,
+                krb5_boolean is_as_req);
+
+krb5_error_code
+_kdc_get_des_key(krb5_context context, hdb_entry*, 
+                krb5_boolean, krb5_boolean, Key**);
+
+krb5_error_code
+_kdc_encode_v4_ticket(krb5_context context, 
+                     krb5_kdc_configuration *config,
+                     void *buf, size_t len, const EncTicketPart *et,
+                     const PrincipalName *service, size_t *size);
+krb5_error_code
+_kdc_do_524(krb5_context context, 
+           krb5_kdc_configuration *config,
+           const Ticket *t, krb5_data *reply,
+           const char *from, struct sockaddr *addr);
+
+
+#ifdef PKINIT
+typedef struct pk_client_params pk_client_params;
+krb5_error_code _kdc_pk_initialize(krb5_context,
+                                  krb5_kdc_configuration *, 
+                                  const char *,
+                                  const char *);
+krb5_error_code _kdc_pk_rd_padata(krb5_context, krb5_kdc_configuration *, 
+                             KDC_REQ *, PA_DATA *, pk_client_params **);
+krb5_error_code        _kdc_pk_mk_pa_reply(krb5_context,
+                                   krb5_kdc_configuration *, 
+                                   pk_client_params *,
+                                   const hdb_entry *,
+                                   const KDC_REQ *,
+                                   krb5_keyblock **,
+                                   METHOD_DATA *);
+krb5_error_code _kdc_pk_check_client(krb5_context, 
+                                    krb5_kdc_configuration *,
+                                    krb5_principal,
+                                    const hdb_entry *, 
+                                    pk_client_params *, char **);
+void _kdc_pk_free_client_param(krb5_context, pk_client_params *);
+#endif
+
+/*
+ * Kerberos 4
+ */
+
+krb5_error_code
+_kdc_db_fetch4 (krb5_context context, 
+               krb5_kdc_configuration *config,
+               const char*, const char*, const char*, enum hdb_ent_type, hdb_entry**);
+
+krb5_error_code
+_kdc_do_version4 (krb5_context context, 
+                 krb5_kdc_configuration *config,
+                 unsigned char*, size_t, krb5_data*, const char*, 
+                 struct sockaddr_in*);
+int
+_kdc_maybe_version4(unsigned char*, int);
+
+krb5_error_code
+_kdc_do_kaserver (krb5_context context, 
+                 krb5_kdc_configuration *config,
+                 unsigned char*, size_t, krb5_data*,
+                 const char*, struct sockaddr_in*);
+
+
+#endif /* __KDC_LOCL_H__ */
diff --git a/source4/heimdal/kdc/kerberos4.c b/source4/heimdal/kdc/kerberos4.c
new file mode 100644 (file)
index 0000000..a81fbb7
--- /dev/null
@@ -0,0 +1,783 @@
+/*
+ * 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 "kdc_locl.h"
+
+#include <krb5-v4compat.h>
+
+RCSID("$Id: kerberos4.c,v 1.54 2005/06/30 01:51:43 lha Exp $");
+
+#ifndef swap32
+static u_int32_t
+swap32(u_int32_t x)
+{
+    return ((x << 24) & 0xff000000) |
+       ((x << 8) & 0xff0000) |
+       ((x >> 8) & 0xff00) |
+       ((x >> 24) & 0xff);
+}
+#endif /* swap32 */
+
+int
+_kdc_maybe_version4(unsigned char *buf, int len)
+{
+    return len > 0 && *buf == 4;
+}
+
+static void
+make_err_reply(krb5_context context, krb5_data *reply,
+              int code, const char *msg)
+{
+    _krb5_krb_cr_err_reply(context, "", "", "", 
+                          kdc_time, code, msg, reply);
+}
+
+static krb5_boolean
+valid_princ(krb5_context context,
+           void *funcctx,
+           krb5_principal princ)
+{
+    krb5_kdc_configuration *config = funcctx;
+    krb5_error_code ret;
+    char *s;
+    hdb_entry *ent;
+
+    ret = krb5_unparse_name(context, princ, &s);
+    if (ret)
+       return FALSE;
+    ret = _kdc_db_fetch(context, config, princ, HDB_ENT_TYPE_ANY, &ent);
+    if (ret) {
+       kdc_log(context, config, 7, "Lookup %s failed: %s", s,
+               krb5_get_err_text (context, ret));
+       free(s);
+       return FALSE;
+    }
+    kdc_log(context, config, 7, "Lookup %s succeeded", s);
+    free(s);
+    _kdc_free_ent(context, ent);
+    return TRUE;
+}
+
+krb5_error_code
+_kdc_db_fetch4(krb5_context context,
+         krb5_kdc_configuration *config,
+         const char *name, const char *instance, const char *realm,
+         enum hdb_ent_type ent_type, 
+         hdb_entry **ent)
+{
+    krb5_principal p;
+    krb5_error_code ret;
+    
+    ret = krb5_425_conv_principal_ext2(context, name, instance, realm, 
+                                      valid_princ, config, 0, &p);
+    if(ret)
+       return ret;
+    ret = _kdc_db_fetch(context, config, p, ent_type, ent);
+    krb5_free_principal(context, p);
+    return ret;
+}
+
+#define RCHECK(X, L) if(X){make_err_reply(context, reply, KFAILURE, "Packet too short"); goto L;}
+
+/*
+ * Process the v4 request in `buf, len' (received from `addr'
+ * (with string `from').
+ * Return an error code and a reply in `reply'.
+ */
+
+krb5_error_code
+_kdc_do_version4(krb5_context context, 
+                krb5_kdc_configuration *config,
+                unsigned char *buf,
+                size_t len,
+                krb5_data *reply,
+                const char *from,
+                struct sockaddr_in *addr)
+{
+    krb5_storage *sp;
+    krb5_error_code ret;
+    hdb_entry *client = NULL, *server = NULL;
+    Key *ckey, *skey;
+    int8_t pvno;
+    int8_t msg_type;
+    int lsb;
+    char *name = NULL, *inst = NULL, *realm = NULL;
+    char *sname = NULL, *sinst = NULL;
+    int32_t req_time;
+    time_t max_life;
+    u_int8_t life;
+    char client_name[256];
+    char server_name[256];
+
+    if(!config->enable_v4) {
+       kdc_log(context, config, 0,
+               "Rejected version 4 request from %s", from);
+       make_err_reply(context, reply, KDC_GEN_ERR, "function not enabled");
+       return 0;
+    }
+
+    sp = krb5_storage_from_mem(buf, len);
+    RCHECK(krb5_ret_int8(sp, &pvno), out);
+    if(pvno != 4){
+       kdc_log(context, config, 0,
+               "Protocol version mismatch (krb4) (%d)", pvno);
+       make_err_reply(context, reply, KDC_PKT_VER, "protocol mismatch");
+       goto out;
+    }
+    RCHECK(krb5_ret_int8(sp, &msg_type), out);
+    lsb = msg_type & 1;
+    msg_type &= ~1;
+    switch(msg_type){
+    case AUTH_MSG_KDC_REQUEST: {
+       krb5_data ticket, cipher;
+       krb5_keyblock session;
+       
+       krb5_data_zero(&ticket);
+       krb5_data_zero(&cipher);
+
+       RCHECK(krb5_ret_stringz(sp, &name), out1);
+       RCHECK(krb5_ret_stringz(sp, &inst), out1);
+       RCHECK(krb5_ret_stringz(sp, &realm), out1);
+       RCHECK(krb5_ret_int32(sp, &req_time), out1);
+       if(lsb)
+           req_time = swap32(req_time);
+       RCHECK(krb5_ret_int8(sp, &life), out1);
+       RCHECK(krb5_ret_stringz(sp, &sname), out1);
+       RCHECK(krb5_ret_stringz(sp, &sinst), out1);
+       snprintf (client_name, sizeof(client_name),
+                 "%s.%s@%s", name, inst, realm);
+       snprintf (server_name, sizeof(server_name),
+                 "%s.%s@%s", sname, sinst, config->v4_realm);
+       
+       kdc_log(context, config, 0, "AS-REQ (krb4) %s from %s for %s",
+               client_name, from, server_name);
+
+       ret = _kdc_db_fetch4(context, config, name, inst, realm, HDB_ENT_TYPE_CLIENT, &client);
+       if(ret) {
+           kdc_log(context, config, 0, "Client not found in database: %s: %s",
+                   client_name, krb5_get_err_text(context, ret));
+           make_err_reply(context, reply, KERB_ERR_PRINCIPAL_UNKNOWN,
+                          "principal unknown");
+           goto out1;
+       }
+       ret = _kdc_db_fetch4(context, config, sname, sinst, 
+                       config->v4_realm, HDB_ENT_TYPE_SERVER, &server);
+       if(ret){
+           kdc_log(context, config, 0, "Server not found in database: %s: %s",
+                   server_name, krb5_get_err_text(context, ret));
+           make_err_reply(context, reply, KERB_ERR_PRINCIPAL_UNKNOWN,
+                          "principal unknown");
+           goto out1;
+       }
+
+       ret = _kdc_check_flags (context, config, 
+                               client, client_name,
+                               server, server_name,
+                               TRUE);
+       if (ret) {
+           /* good error code? */
+           make_err_reply(context, reply, KERB_ERR_NAME_EXP,
+                          "operation not allowed");
+           goto out1;
+       }
+
+       /*
+        * There's no way to do pre-authentication in v4 and thus no
+        * good error code to return if preauthentication is required.
+        */
+
+       if (config->require_preauth
+           || client->flags.require_preauth
+           || server->flags.require_preauth) {
+           kdc_log(context, config, 0,
+                   "Pre-authentication required for v4-request: "
+                   "%s for %s",
+                   client_name, server_name);
+           make_err_reply(context, reply, KERB_ERR_NULL_KEY,
+                          "preauth required");
+           goto out1;
+       }
+
+       ret = _kdc_get_des_key(context, client, FALSE, FALSE, &ckey);
+       if(ret){
+           kdc_log(context, config, 0, "no suitable DES key for client");
+           make_err_reply(context, reply, KDC_NULL_KEY, 
+                          "no suitable DES key for client");
+           goto out1;
+       }
+
+#if 0
+       /* this is not necessary with the new code in libkrb */
+       /* find a properly salted key */
+       while(ckey->salt == NULL || ckey->salt->salt.length != 0)
+           ret = hdb_next_keytype2key(context, client, KEYTYPE_DES, &ckey);
+       if(ret){
+           kdc_log(context, config, 0, "No version-4 salted key in database -- %s.%s@%s", 
+                   name, inst, realm);
+           make_err_reply(context, reply, KDC_NULL_KEY, 
+                          "No version-4 salted key in database");
+           goto out1;
+       }
+#endif
+       
+       ret = _kdc_get_des_key(context, server, TRUE, FALSE, &skey);
+       if(ret){
+           kdc_log(context, config, 0, "no suitable DES key for server");
+           /* XXX */
+           make_err_reply(context, reply, KDC_NULL_KEY, 
+                          "no suitable DES key for server");
+           goto out1;
+       }
+
+       max_life = _krb5_krb_life_to_time(0, life);
+       if(client->max_life)
+           max_life = min(max_life, *client->max_life);
+       if(server->max_life)
+           max_life = min(max_life, *server->max_life);
+
+       life = krb_time_to_life(kdc_time, kdc_time + max_life);
+    
+       ret = krb5_generate_random_keyblock(context,
+                                           ETYPE_DES_PCBC_NONE,
+                                           &session);
+       if (ret) {
+           make_err_reply(context, reply, KFAILURE,
+                          "Not enough random i KDC");
+           goto out1;
+       }
+       
+       ret = _krb5_krb_create_ticket(context,
+                                     0,
+                                     name,
+                                     inst,
+                                     config->v4_realm,
+                                     addr->sin_addr.s_addr,
+                                     &session,
+                                     life,
+                                     kdc_time,
+                                     sname,
+                                     sinst,
+                                     &skey->key,
+                                     &ticket);
+       if (ret) {
+           krb5_free_keyblock_contents(context, &session);
+           make_err_reply(context, reply, KFAILURE,
+                          "failed to create v4 ticket");
+           goto out1;
+       }
+
+       ret = _krb5_krb_create_ciph(context,
+                                   &session,
+                                   sname,
+                                   sinst,
+                                   config->v4_realm,
+                                   life,
+                                   server->kvno % 255,
+                                   &ticket,
+                                   kdc_time,
+                                   &ckey->key,
+                                   &cipher);
+       krb5_free_keyblock_contents(context, &session);
+       krb5_data_free(&ticket);
+       if (ret) {
+           make_err_reply(context, reply, KFAILURE, 
+                          "Failed to create v4 cipher");
+           goto out1;
+       }
+       
+       ret = _krb5_krb_create_auth_reply(context,
+                                         name,
+                                         inst,
+                                         realm,
+                                         req_time,
+                                         0,
+                                         client->pw_end ? *client->pw_end : 0,
+                                         client->kvno % 256,
+                                         &cipher,
+                                         reply);
+       krb5_data_free(&cipher);
+
+    out1:
+       break;
+    }
+    case AUTH_MSG_APPL_REQUEST: {
+       struct _krb5_krb_auth_data ad;
+       int8_t kvno;
+       int8_t ticket_len;
+       int8_t req_len;
+       krb5_data auth;
+       int32_t address;
+       size_t pos;
+       krb5_principal tgt_princ = NULL;
+       hdb_entry *tgt = NULL;
+       Key *tkey;
+       time_t max_end, actual_end, issue_time;
+       
+       memset(&ad, 0, sizeof(ad));
+       krb5_data_zero(&auth);
+
+       RCHECK(krb5_ret_int8(sp, &kvno), out2);
+       RCHECK(krb5_ret_stringz(sp, &realm), out2);
+       
+       ret = krb5_425_conv_principal(context, "krbtgt", realm,
+                                     config->v4_realm,
+                                     &tgt_princ);
+       if(ret){
+           kdc_log(context, config, 0,
+                   "Converting krbtgt principal (krb4): %s", 
+                   krb5_get_err_text(context, ret));
+           make_err_reply(context, reply, KFAILURE, 
+                          "Failed to convert v4 principal (krbtgt)");
+           goto out2;
+       }
+
+       ret = _kdc_db_fetch(context, config, tgt_princ, HDB_ENT_TYPE_SERVER, &tgt);
+       if(ret){
+           char *s;
+           s = kdc_log_msg(context, config, 0, "Ticket-granting ticket not "
+                           "found in database (krb4): krbtgt.%s@%s: %s", 
+                           realm, config->v4_realm,
+                           krb5_get_err_text(context, ret));
+           make_err_reply(context, reply, KFAILURE, s);
+           free(s);
+           goto out2;
+       }
+       
+       if(tgt->kvno % 256 != kvno){
+           kdc_log(context, config, 0,
+                   "tgs-req (krb4) with old kvno %d (current %d) for "
+                   "krbtgt.%s@%s", kvno, tgt->kvno % 256, 
+                   realm, config->v4_realm);
+           make_err_reply(context, reply, KDC_AUTH_EXP,
+                          "old krbtgt kvno used");
+           goto out2;
+       }
+
+       ret = _kdc_get_des_key(context, tgt, TRUE, FALSE, &tkey);
+       if(ret){
+           kdc_log(context, config, 0, 
+                   "no suitable DES key for krbtgt (krb4)");
+           /* XXX */
+           make_err_reply(context, reply, KDC_NULL_KEY, 
+                          "no suitable DES key for krbtgt");
+           goto out2;
+       }
+
+       RCHECK(krb5_ret_int8(sp, &ticket_len), out2);
+       RCHECK(krb5_ret_int8(sp, &req_len), out2);
+       
+       pos = krb5_storage_seek(sp, ticket_len + req_len, SEEK_CUR);
+       
+       auth.data = buf;
+       auth.length = pos;
+
+       if (config->check_ticket_addresses)
+           address = addr->sin_addr.s_addr;
+       else
+           address = 0;
+
+       ret = _krb5_krb_rd_req(context, &auth, "krbtgt", realm, 
+                              config->v4_realm,
+                              address, &tkey->key, &ad);
+       if(ret){
+           kdc_log(context, config, 0, "krb_rd_req: %d", ret);
+           make_err_reply(context, reply, ret, "failed to parse request");
+           goto out2;
+       }
+       
+       RCHECK(krb5_ret_int32(sp, &req_time), out2);
+       if(lsb)
+           req_time = swap32(req_time);
+       RCHECK(krb5_ret_int8(sp, &life), out2);
+       RCHECK(krb5_ret_stringz(sp, &sname), out2);
+       RCHECK(krb5_ret_stringz(sp, &sinst), out2);
+       snprintf (server_name, sizeof(server_name),
+                 "%s.%s@%s",
+                 sname, sinst, config->v4_realm);
+       snprintf (client_name, sizeof(client_name),
+                 "%s.%s@%s",
+                 ad.pname, ad.pinst, ad.prealm);
+
+       kdc_log(context, config, 0, "TGS-REQ (krb4) %s from %s for %s",
+               client_name, from, server_name);
+       
+       if(strcmp(ad.prealm, realm)){
+           kdc_log(context, config, 0, 
+                   "Can't hop realms (krb4) %s -> %s", realm, ad.prealm);
+           make_err_reply(context, reply, KERB_ERR_PRINCIPAL_UNKNOWN, 
+                          "Can't hop realms");
+           goto out2;
+       }
+
+       if (!config->enable_v4_cross_realm && strcmp(realm, config->v4_realm) != 0) {
+           kdc_log(context, config, 0, 
+                   "krb4 Cross-realm %s -> %s disabled",
+                   realm, config->v4_realm);
+           make_err_reply(context, reply, KERB_ERR_PRINCIPAL_UNKNOWN, 
+                          "Can't hop realms");
+           goto out2;
+       }
+
+       if(strcmp(sname, "changepw") == 0){
+           kdc_log(context, config, 0, 
+                   "Bad request for changepw ticket (krb4)");
+           make_err_reply(context, reply, KERB_ERR_PRINCIPAL_UNKNOWN, 
+                          "Can't authorize password change based on TGT");
+           goto out2;
+       }
+       
+       ret = _kdc_db_fetch4(context, config, ad.pname, ad.pinst, ad.prealm, HDB_ENT_TYPE_CLIENT, &client);
+       if(ret && ret != HDB_ERR_NOENTRY) {
+           char *s;
+           s = kdc_log_msg(context, config, 0,
+                           "Client not found in database: (krb4) %s: %s",
+                           client_name, krb5_get_err_text(context, ret));
+           make_err_reply(context, reply, KERB_ERR_PRINCIPAL_UNKNOWN, s);
+           free(s);
+           goto out2;
+       }
+       if (client == NULL && strcmp(ad.prealm, config->v4_realm) == 0) {
+           char *s;
+           s = kdc_log_msg(context, config, 0,
+                           "Local client not found in database: (krb4) "
+                           "%s", client_name);
+           make_err_reply(context, reply, KERB_ERR_PRINCIPAL_UNKNOWN, s);
+           free(s);
+           goto out2;
+       }
+
+       ret = _kdc_db_fetch4(context, config, sname, sinst, config->v4_realm, 
+                            HDB_ENT_TYPE_SERVER, &server);
+       if(ret){
+           char *s;
+           s = kdc_log_msg(context, config, 0,
+                           "Server not found in database (krb4): %s: %s",
+                           server_name, krb5_get_err_text(context, ret));
+           make_err_reply(context, reply, KERB_ERR_PRINCIPAL_UNKNOWN, s);
+           free(s);
+           goto out2;
+       }
+
+       ret = _kdc_check_flags (context, config, 
+                               client, client_name,
+                               server, server_name,
+                               FALSE);
+       if (ret) {
+           /* good error code? */
+           make_err_reply(context, reply, KERB_ERR_NAME_EXP,
+                          "operation not allowed");
+           goto out2;
+       }
+
+       ret = _kdc_get_des_key(context, server, TRUE, FALSE, &skey);
+       if(ret){
+           kdc_log(context, config, 0, 
+                   "no suitable DES key for server (krb4)");
+           /* XXX */
+           make_err_reply(context, reply, KDC_NULL_KEY, 
+                          "no suitable DES key for server");
+           goto out2;
+       }
+
+       max_end = _krb5_krb_life_to_time(ad.time_sec, ad.life);
+       max_end = min(max_end, _krb5_krb_life_to_time(kdc_time, life));
+       if(server->max_life)
+           max_end = min(max_end, kdc_time + *server->max_life);
+       if(client && client->max_life)
+           max_end = min(max_end, kdc_time + *client->max_life);
+       life = min(life, krb_time_to_life(kdc_time, max_end));
+       
+       issue_time = kdc_time;
+       actual_end = _krb5_krb_life_to_time(issue_time, life);
+       while (actual_end > max_end && life > 1) {
+           /* move them into the next earlier lifetime bracket */
+           life--;
+           actual_end = _krb5_krb_life_to_time(issue_time, life);
+       }
+       if (actual_end > max_end) {
+           /* if life <= 1 and it's still too long, backdate the ticket */
+           issue_time -= actual_end - max_end;
+       }
+
+       {
+           krb5_data ticket, cipher;
+           krb5_keyblock session;
+
+           krb5_data_zero(&ticket);
+           krb5_data_zero(&cipher);
+
+           ret = krb5_generate_random_keyblock(context,
+                                               ETYPE_DES_PCBC_NONE,
+                                               &session);
+           if (ret) {
+               make_err_reply(context, reply, KFAILURE,
+                              "Not enough random i KDC");
+               goto out2;
+           }
+       
+           ret = _krb5_krb_create_ticket(context,
+                                         0,
+                                         ad.pname,
+                                         ad.pinst,
+                                         ad.prealm,
+                                         addr->sin_addr.s_addr,
+                                         &session,
+                                         life,
+                                         issue_time,
+                                         sname,
+                                         sinst,
+                                         &skey->key,
+                                         &ticket);
+           if (ret) {
+               krb5_free_keyblock_contents(context, &session);
+               make_err_reply(context, reply, KFAILURE,
+                              "failed to create v4 ticket");
+               goto out2;
+           }
+
+           ret = _krb5_krb_create_ciph(context,
+                                       &session,
+                                       sname,
+                                       sinst,
+                                       config->v4_realm,
+                                       life,
+                                       server->kvno % 255,
+                                       &ticket,
+                                       issue_time,
+                                       &ad.session,
+                                       &cipher);
+           krb5_free_keyblock_contents(context, &session);
+           if (ret) {
+               make_err_reply(context, reply, KFAILURE,
+                              "failed to create v4 cipher");
+               goto out2;
+           }
+           
+           ret = _krb5_krb_create_auth_reply(context,
+                                             ad.pname,
+                                             ad.pinst,
+                                             ad.prealm,
+                                             req_time,
+                                             0,
+                                             0,
+                                             0,
+                                             &cipher,
+                                             reply);
+           krb5_data_free(&cipher);
+       }
+    out2:
+       _krb5_krb_free_auth_data(context, &ad);
+       if(tgt_princ)
+           krb5_free_principal(context, tgt_princ);
+       if(tgt)
+           _kdc_free_ent(context, tgt);
+       break;
+    }
+    case AUTH_MSG_ERR_REPLY:
+       break;
+    default:
+       kdc_log(context, config, 0, "Unknown message type (krb4): %d from %s", 
+               msg_type, from);
+       
+       make_err_reply(context, reply, KFAILURE, "Unknown message type");
+    }
+ out:
+    if(name)
+       free(name);
+    if(inst)
+       free(inst);
+    if(realm)
+       free(realm);
+    if(sname)
+       free(sname);
+    if(sinst)
+       free(sinst);
+    if(client)
+       _kdc_free_ent(context, client);
+    if(server)
+       _kdc_free_ent(context, server);
+    krb5_storage_free(sp);
+    return 0;
+}
+
+krb5_error_code
+_kdc_encode_v4_ticket(krb5_context context, 
+                     krb5_kdc_configuration *config,
+                     void *buf, size_t len, const EncTicketPart *et,
+                     const PrincipalName *service, size_t *size)
+{
+    krb5_storage *sp;
+    krb5_error_code ret;
+    char name[40], inst[40], realm[40];
+    char sname[40], sinst[40];
+
+    {
+       krb5_principal princ;
+       _krb5_principalname2krb5_principal(&princ,
+                                          *service,
+                                          et->crealm);
+       ret = krb5_524_conv_principal(context, 
+                                     princ,
+                                     sname,
+                                     sinst,
+                                     realm);
+       krb5_free_principal(context, princ);
+       if(ret)
+           return ret;
+
+       _krb5_principalname2krb5_principal(&princ,
+                                          et->cname,
+                                          et->crealm);
+                                    
+       ret = krb5_524_conv_principal(context, 
+                                     princ,
+                                     name,
+                                     inst,
+                                     realm);
+       krb5_free_principal(context, princ);
+    }
+    if(ret)
+       return ret;
+
+    sp = krb5_storage_emem();
+    
+    krb5_store_int8(sp, 0); /* flags */
+    krb5_store_stringz(sp, name);
+    krb5_store_stringz(sp, inst);
+    krb5_store_stringz(sp, realm);
+    {
+       unsigned char tmp[4] = { 0, 0, 0, 0 };
+       int i;
+       if(et->caddr){
+           for(i = 0; i < et->caddr->len; i++)
+               if(et->caddr->val[i].addr_type == AF_INET &&
+                  et->caddr->val[i].address.length == 4){
+                   memcpy(tmp, et->caddr->val[i].address.data, 4);
+                   break;
+               }
+       }
+       krb5_storage_write(sp, tmp, sizeof(tmp));
+    }
+
+    if((et->key.keytype != ETYPE_DES_CBC_MD5 &&
+       et->key.keytype != ETYPE_DES_CBC_MD4 &&
+       et->key.keytype != ETYPE_DES_CBC_CRC) || 
+       et->key.keyvalue.length != 8)
+       return -1;
+    krb5_storage_write(sp, et->key.keyvalue.data, 8);
+    
+    {
+       time_t start = et->starttime ? *et->starttime : et->authtime;
+       krb5_store_int8(sp, krb_time_to_life(start, et->endtime));
+       krb5_store_int32(sp, start);
+    }
+
+    krb5_store_stringz(sp, sname);
+    krb5_store_stringz(sp, sinst);
+    
+    {
+       krb5_data data;
+       krb5_storage_to_data(sp, &data);
+       krb5_storage_free(sp);
+       *size = (data.length + 7) & ~7; /* pad to 8 bytes */
+       if(*size > len)
+           return -1;
+       memset((unsigned char*)buf - *size + 1, 0, *size);
+       memcpy((unsigned char*)buf - *size + 1, data.data, data.length);
+       krb5_data_free(&data);
+    }
+    return 0;
+}
+
+krb5_error_code
+_kdc_get_des_key(krb5_context context, 
+                hdb_entry *principal, krb5_boolean is_server, 
+                krb5_boolean prefer_afs_key, Key **ret_key)
+{
+    Key *v5_key = NULL, *v4_key = NULL, *afs_key = NULL, *server_key = NULL;
+    int i;
+    krb5_enctype etypes[] = { ETYPE_DES_CBC_MD5, 
+                             ETYPE_DES_CBC_MD4, 
+                             ETYPE_DES_CBC_CRC };
+
+    for(i = 0;
+       i < sizeof(etypes)/sizeof(etypes[0])
+           && (v5_key == NULL || v4_key == NULL || 
+               afs_key == NULL || server_key == NULL);
+       ++i) {
+       Key *key = NULL;
+       while(hdb_next_enctype2key(context, principal, etypes[i], &key) == 0) {
+           if(key->salt == NULL) {
+               if(v5_key == NULL)
+                   v5_key = key;
+           } else if(key->salt->type == hdb_pw_salt && 
+                     key->salt->salt.length == 0) {
+               if(v4_key == NULL)
+                   v4_key = key;
+           } else if(key->salt->type == hdb_afs3_salt) {
+               if(afs_key == NULL)
+                   afs_key = key;
+           } else if(server_key == NULL)
+               server_key = key;
+       }
+    }
+
+    if(prefer_afs_key) {
+       if(afs_key)
+           *ret_key = afs_key;
+       else if(v4_key)
+           *ret_key = v4_key;
+       else if(v5_key)
+           *ret_key = v5_key;
+       else if(is_server && server_key)
+           *ret_key = server_key;
+       else
+           return KERB_ERR_NULL_KEY;
+    } else {
+       if(v4_key)
+           *ret_key = v4_key;
+       else if(afs_key)
+           *ret_key = afs_key;
+       else  if(v5_key)
+           *ret_key = v5_key;
+       else if(is_server && server_key)
+           *ret_key = server_key;
+       else
+           return KERB_ERR_NULL_KEY;
+    }
+
+    if((*ret_key)->key.keyvalue.length == 0)
+       return KERB_ERR_NULL_KEY;
+    return 0;
+}
+
diff --git a/source4/heimdal/kdc/kerberos5.c b/source4/heimdal/kdc/kerberos5.c
new file mode 100644 (file)
index 0000000..122c9ab
--- /dev/null
@@ -0,0 +1,2422 @@
+/*
+ * 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 "kdc_locl.h"
+#ifdef _SAMBA_BUILD_
+#include "kdc/pac-glue.h"
+#endif
+
+RCSID("$Id: kerberos5.c,v 1.177 2005/06/15 11:34:53 lha Exp $");
+
+#define MAX_TIME ((time_t)((1U << 31) - 1))
+
+static void
+fix_time(time_t **t)
+{
+    if(*t == NULL){
+       ALLOC(*t);
+       **t = MAX_TIME;
+    }
+    if(**t == 0) **t = MAX_TIME; /* fix for old clients */
+}
+
+static int
+realloc_method_data(METHOD_DATA *md)
+{
+    PA_DATA *pa;
+    pa = realloc(md->val, (md->len + 1) * sizeof(*md->val));
+    if(pa == NULL)
+       return ENOMEM;
+    md->val = pa;
+    md->len++;
+    return 0;
+}
+
+static void
+set_salt_padata (METHOD_DATA *md, Salt *salt)
+{
+    if (salt) {
+       realloc_method_data(md);
+       md->val[md->len - 1].padata_type = salt->type;
+       copy_octet_string(&salt->salt,
+                         &md->val[md->len - 1].padata_value);
+    }
+}
+
+static PA_DATA*
+find_padata(KDC_REQ *req, int *start, int type)
+{
+    while(*start < req->padata->len){
+       (*start)++;
+       if(req->padata->val[*start - 1].padata_type == type)
+           return &req->padata->val[*start - 1];
+    }
+    return NULL;
+}
+
+/*
+ * return the first appropriate key of `princ' in `ret_key'.  Look for
+ * all the etypes in (`etypes', `len'), stopping as soon as we find
+ * one, but preferring one that has default salt
+ */
+
+static krb5_error_code
+find_etype(krb5_context context, hdb_entry *princ, 
+          krb5_enctype *etypes, unsigned len, 
+          Key **ret_key, krb5_enctype *ret_etype)
+{
+    int i;
+    krb5_error_code ret = KRB5KDC_ERR_ETYPE_NOSUPP;
+
+    for(i = 0; ret != 0 && i < len ; i++) {
+       Key *key = NULL;
+
+       if (krb5_enctype_valid(context, etypes[i]) != 0)
+           continue;
+
+       while (hdb_next_enctype2key(context, princ, etypes[i], &key) == 0) {
+           if (key->key.keyvalue.length == 0) {
+               ret = KRB5KDC_ERR_NULL_KEY;
+               continue;
+           }
+           *ret_key   = key;
+           *ret_etype = etypes[i];
+           ret = 0;
+           if (key->salt == NULL)
+               return ret;
+       }
+    }
+    return ret;
+}
+
+static krb5_error_code
+find_keys(krb5_context context, 
+         krb5_kdc_configuration *config,
+         hdb_entry *client,
+         hdb_entry *server, 
+         Key **ckey,
+         krb5_enctype *cetype,
+         Key **skey,
+         krb5_enctype *setype, 
+         krb5_enctype *etypes,
+         unsigned num_etypes)
+{
+    char unparse_name[] = "krb5_unparse_name failed";
+    krb5_error_code ret;
+    char *name;
+
+    if(client){
+       /* find client key */
+       ret = find_etype(context, client, etypes, num_etypes, ckey, cetype);
+       if (ret) {
+           if (krb5_unparse_name(context, client->principal, &name) != 0)
+               name = unparse_name;
+           kdc_log(context, config, 0, 
+                   "Client (%s) has no support for etypes", name);
+           if (name != unparse_name)
+               free(name);
+           return ret;
+       }
+    }
+
+    if(server){
+       /* find server key */
+       ret = find_etype(context, server, etypes, num_etypes, skey, setype);
+       if (ret) {
+           if (krb5_unparse_name(context, server->principal, &name) != 0)
+               name = unparse_name;
+           kdc_log(context, config, 0, 
+                   "Server (%s) has no support for etypes", name);
+           if (name != unparse_name)
+               free(name);
+           return ret;
+       }
+    }
+    return 0;
+}
+
+static krb5_error_code
+make_anonymous_principalname (PrincipalName *pn)
+{
+    pn->name_type = KRB5_NT_PRINCIPAL;
+    pn->name_string.len = 1;
+    pn->name_string.val = malloc(sizeof(*pn->name_string.val));
+    if (pn->name_string.val == NULL)
+       return ENOMEM;
+    pn->name_string.val[0] = strdup("anonymous");
+    if (pn->name_string.val[0] == NULL) {
+       free(pn->name_string.val);
+       pn->name_string.val = NULL;
+       return ENOMEM;
+    }
+    return 0;
+}
+
+static void
+log_timestamp(krb5_context context, 
+             krb5_kdc_configuration *config,
+             const char *type,
+             KerberosTime authtime, KerberosTime *starttime, 
+             KerberosTime endtime, KerberosTime *renew_till)
+{
+    char atime[100], stime[100], etime[100], rtime[100];
+    
+    krb5_format_time(context, authtime, atime, sizeof(atime), TRUE); 
+    if (starttime)
+       krb5_format_time(context, *starttime, stime, sizeof(stime), TRUE); 
+    else
+       strlcpy(stime, "unset", sizeof(stime));
+    krb5_format_time(context, endtime, etime, sizeof(etime), TRUE); 
+    if (renew_till)
+       krb5_format_time(context, *renew_till, rtime, sizeof(rtime), TRUE); 
+    else
+       strlcpy(rtime, "unset", sizeof(rtime));
+    
+    kdc_log(context, config, 5,
+           "%s authtime: %s starttime: %s endtype: %s renew till: %s",
+           type, atime, stime, etime, rtime);
+}
+
+static krb5_error_code
+encode_reply(krb5_context context,
+            krb5_kdc_configuration *config,
+            KDC_REP *rep, EncTicketPart *et, EncKDCRepPart *ek, 
+            krb5_enctype etype, 
+            int skvno, EncryptionKey *skey,
+            int ckvno, EncryptionKey *ckey,
+            const char **e_text,
+            krb5_data *reply)
+{
+    unsigned char *buf;
+    size_t buf_size;
+    size_t len;
+    krb5_error_code ret;
+    krb5_crypto crypto;
+
+    ASN1_MALLOC_ENCODE(EncTicketPart, buf, buf_size, et, &len, ret);
+    if(ret) {
+       kdc_log(context, config, 0, "Failed to encode ticket: %s", 
+               krb5_get_err_text(context, ret));
+       return ret;
+    }
+    if(buf_size != len) {
+       free(buf);
+       kdc_log(context, config, 0, "Internal error in ASN.1 encoder");
+       *e_text = "KDC internal error";
+       return KRB5KRB_ERR_GENERIC;
+    }
+
+    ret = krb5_crypto_init(context, skey, etype, &crypto);
+    if (ret) {
+       free(buf);
+       kdc_log(context, config, 0, "krb5_crypto_init failed: %s",
+               krb5_get_err_text(context, ret));
+       return ret;
+    }
+
+    ret = krb5_encrypt_EncryptedData(context, 
+                                    crypto,
+                                    KRB5_KU_TICKET,
+                                    buf,
+                                    len,
+                                    skvno,
+                                    &rep->ticket.enc_part);
+    free(buf);
+    krb5_crypto_destroy(context, crypto);
+    if(ret) {
+       kdc_log(context, config, 0, "Failed to encrypt data: %s",
+               krb5_get_err_text(context, ret));
+       return ret;
+    }
+    
+    if(rep->msg_type == krb_as_rep && !config->encode_as_rep_as_tgs_rep)
+       ASN1_MALLOC_ENCODE(EncASRepPart, buf, buf_size, ek, &len, ret);
+    else
+       ASN1_MALLOC_ENCODE(EncTGSRepPart, buf, buf_size, ek, &len, ret);
+    if(ret) {
+       kdc_log(context, config, 0, "Failed to encode KDC-REP: %s", 
+               krb5_get_err_text(context, ret));
+       return ret;
+    }
+    if(buf_size != len) {
+       free(buf);
+       kdc_log(context, config, 0, "Internal error in ASN.1 encoder");
+       *e_text = "KDC internal error";
+       return KRB5KRB_ERR_GENERIC;
+    }
+    ret = krb5_crypto_init(context, ckey, 0, &crypto);
+    if (ret) {
+       free(buf);
+       kdc_log(context, config, 0, "krb5_crypto_init failed: %s",
+               krb5_get_err_text(context, ret));
+       return ret;
+    }
+    if(rep->msg_type == krb_as_rep) {
+       krb5_encrypt_EncryptedData(context,
+                                  crypto,
+                                  KRB5_KU_AS_REP_ENC_PART,
+                                  buf,
+                                  len,
+                                  ckvno,
+                                  &rep->enc_part);
+       free(buf);
+       ASN1_MALLOC_ENCODE(AS_REP, buf, buf_size, rep, &len, ret);
+    } else {
+       krb5_encrypt_EncryptedData(context,
+                                  crypto,
+                                  KRB5_KU_TGS_REP_ENC_PART_SESSION,
+                                  buf,
+                                  len,
+                                  ckvno,
+                                  &rep->enc_part);
+       free(buf);
+       ASN1_MALLOC_ENCODE(TGS_REP, buf, buf_size, rep, &len, ret);
+    }
+    krb5_crypto_destroy(context, crypto);
+    if(ret) {
+       kdc_log(context, config, 0, "Failed to encode KDC-REP: %s", 
+               krb5_get_err_text(context, ret));
+       return ret;
+    }
+    if(buf_size != len) {
+       free(buf);
+       kdc_log(context, config, 0, "Internal error in ASN.1 encoder");
+       *e_text = "KDC internal error";
+       return KRB5KRB_ERR_GENERIC;
+    }
+    reply->data = buf;
+    reply->length = buf_size;
+    return 0;
+}
+
+static krb5_error_code
+make_etype_info_entry(krb5_context context, ETYPE_INFO_ENTRY *ent, Key *key)
+{
+    ent->etype = key->key.keytype;
+    if(key->salt){
+       ALLOC(ent->salttype);
+#if 0
+       if(key->salt->type == hdb_pw_salt)
+           *ent->salttype = 0; /* or 1? or NULL? */
+       else if(key->salt->type == hdb_afs3_salt)
+           *ent->salttype = 2;
+       else {
+           kdc_log(context, config, 0, "unknown salt-type: %d", 
+                   key->salt->type);
+           return KRB5KRB_ERR_GENERIC;
+       }
+       /* according to `the specs', we can't send a salt if
+          we have AFS3 salted key, but that requires that you
+          *know* what cell you are using (e.g by assuming
+          that the cell is the same as the realm in lower
+          case) */
+#else
+       *ent->salttype = key->salt->type;
+#endif
+       krb5_copy_data(context, &key->salt->salt,
+                      &ent->salt);
+    } else {
+       /* we return no salt type at all, as that should indicate
+        * the default salt type and make everybody happy.  some
+        * systems (like w2k) dislike being told the salt type
+        * here. */
+
+       ent->salttype = NULL;
+       ent->salt = NULL;
+    }
+    return 0;
+}
+
+static krb5_error_code
+get_pa_etype_info(krb5_context context, 
+                 krb5_kdc_configuration *config,
+                 METHOD_DATA *md, hdb_entry *client, 
+                 ENCTYPE *etypes, unsigned int etypes_len)
+{
+    krb5_error_code ret = 0;
+    int i, j;
+    unsigned int n = 0;
+    ETYPE_INFO pa;
+    unsigned char *buf;
+    size_t len;
+    
+
+    pa.len = client->keys.len;
+    if(pa.len > UINT_MAX/sizeof(*pa.val))
+       return ERANGE;
+    pa.val = malloc(pa.len * sizeof(*pa.val));
+    if(pa.val == NULL)
+       return ENOMEM;
+    memset(pa.val, 0, pa.len * sizeof(*pa.val));
+
+    for(j = 0; j < etypes_len; j++) {
+       for (i = 0; i < n; i++)
+           if (pa.val[i].etype == etypes[j])
+               goto skip1;
+       for(i = 0; i < client->keys.len; i++) {
+           if(client->keys.val[i].key.keytype == etypes[j]) {
+               if (krb5_enctype_valid(context, etypes[j]) != 0)
+                   continue;
+               if((ret = make_etype_info_entry(context, 
+                                               &pa.val[n++], 
+                                               &client->keys.val[i])) != 0) {
+                   free_ETYPE_INFO(&pa);
+                   return ret;
+               }
+           }
+       }
+    skip1:;
+    }
+    for(i = 0; i < client->keys.len; i++) {
+       for(j = 0; j < etypes_len; j++) {
+           if(client->keys.val[i].key.keytype == etypes[j])
+               goto skip2;
+       }
+       if (krb5_enctype_valid(context, client->keys.val[i].key.keytype) != 0)
+           continue;
+       if((ret = make_etype_info_entry(context, 
+                                       &pa.val[n++], 
+                                       &client->keys.val[i])) != 0) {
+           free_ETYPE_INFO(&pa);
+           return ret;
+       }
+    skip2:;
+    }
+    
+    if(n != pa.len) {
+       char *name;
+       ret = krb5_unparse_name(context, client->principal, &name);
+       if (ret)
+           name = "<unparse_name failed>";
+       kdc_log(context, config, 0, "internal error in get_pa_etype_info(%s): %d != %d", 
+               name, n, pa.len);
+       if (ret == 0)
+           free(name);
+       pa.len = n;
+    }
+
+    ASN1_MALLOC_ENCODE(ETYPE_INFO, buf, len, &pa, &len, ret);
+    free_ETYPE_INFO(&pa);
+    if(ret)
+       return ret;
+    ret = realloc_method_data(md);
+    if(ret) {
+       free(buf);
+       return ret;
+    }
+    md->val[md->len - 1].padata_type = KRB5_PADATA_ETYPE_INFO;
+    md->val[md->len - 1].padata_value.length = len;
+    md->val[md->len - 1].padata_value.data = buf;
+    return 0;
+}
+
+/*
+ *
+ */
+
+extern int _krb5_AES_string_to_default_iterator;
+
+static krb5_error_code
+make_etype_info2_entry(ETYPE_INFO2_ENTRY *ent, Key *key)
+{
+    ent->etype = key->key.keytype;
+    if(key->salt) {
+       ALLOC(ent->salt);
+       if (ent->salt == NULL)
+           return ENOMEM;
+       *ent->salt = malloc(key->salt->salt.length + 1);
+       if (*ent->salt == NULL) {
+           free(ent->salt);
+           ent->salt = NULL;
+           return ENOMEM;
+       }
+       memcpy(*ent->salt, key->salt->salt.data, key->salt->salt.length);
+       (*ent->salt)[key->salt->salt.length] = '\0';
+    } else
+       ent->salt = NULL;
+
+    ent->s2kparams = NULL;
+
+    switch (key->key.keytype) {
+    case KEYTYPE_AES128:
+    case KEYTYPE_AES256:
+       ALLOC(ent->s2kparams);
+       if (ent->s2kparams == NULL)
+           return ENOMEM;
+       ent->s2kparams->length = 4;
+       ent->s2kparams->data = malloc(ent->s2kparams->length);
+       if (ent->s2kparams->data == NULL) {
+           free(ent->s2kparams);
+           ent->s2kparams = NULL;
+           return ENOMEM;
+       }
+       _krb5_put_int(ent->s2kparams->data, 
+                     _krb5_AES_string_to_default_iterator, 
+                     ent->s2kparams->length);
+       break;
+    default:
+       break;
+    }
+    return 0;
+}
+
+/*
+ * Return 1 if the client have only older enctypes, this is for
+ * determining if the server should send ETYPE_INFO2 or not.
+ */
+
+static int
+only_older_enctype_p(const KDC_REQ *req)
+{
+    int i;
+
+    for(i = 0; i < req->req_body.etype.len; i++) {
+       switch (req->req_body.etype.val[i]) {
+       case ETYPE_DES_CBC_CRC:
+       case ETYPE_DES_CBC_MD4:
+       case ETYPE_DES_CBC_MD5:
+       case ETYPE_DES3_CBC_SHA1:
+       case ETYPE_ARCFOUR_HMAC_MD5:
+       case ETYPE_ARCFOUR_HMAC_MD5_56:
+           break;
+       default:
+           return 0;
+       }
+    }
+    return 1;
+}
+
+/*
+ *
+ */
+
+static krb5_error_code
+get_pa_etype_info2(krb5_context context, 
+                  krb5_kdc_configuration *config,
+                  METHOD_DATA *md, hdb_entry *client, 
+                  ENCTYPE *etypes, unsigned int etypes_len)
+{
+    krb5_error_code ret = 0;
+    int i, j;
+    unsigned int n = 0;
+    ETYPE_INFO2 pa;
+    unsigned char *buf;
+    size_t len;
+
+    pa.len = client->keys.len;
+    if(pa.len > UINT_MAX/sizeof(*pa.val))
+       return ERANGE;
+    pa.val = malloc(pa.len * sizeof(*pa.val));
+    if(pa.val == NULL)
+       return ENOMEM;
+    memset(pa.val, 0, pa.len * sizeof(*pa.val));
+
+    for(j = 0; j < etypes_len; j++) {
+       for (i = 0; i < n; i++)
+           if (pa.val[i].etype == etypes[j])
+               goto skip1;
+       for(i = 0; i < client->keys.len; i++) {
+           if(client->keys.val[i].key.keytype == etypes[j]) {
+               if (krb5_enctype_valid(context, etypes[j]) != 0)
+                   continue;
+               if((ret = make_etype_info2_entry(&pa.val[n++], 
+                                                &client->keys.val[i])) != 0) {
+                   free_ETYPE_INFO2(&pa);
+                   return ret;
+               }
+           }
+       }
+    skip1:;
+    }
+    for(i = 0; i < client->keys.len; i++) {
+       for(j = 0; j < etypes_len; j++) {
+           if(client->keys.val[i].key.keytype == etypes[j])
+               goto skip2;
+       }
+       if (krb5_enctype_valid(context, client->keys.val[i].key.keytype) != 0)
+           continue;
+       if((ret = make_etype_info2_entry(&pa.val[n++],
+                                        &client->keys.val[i])) != 0) {
+           free_ETYPE_INFO2(&pa);
+           return ret;
+       }
+      skip2:;
+    }
+    
+    if(n != pa.len) {
+       char *name;
+       ret = krb5_unparse_name(context, client->principal, &name);
+       if (ret)
+           name = "<unparse_name failed>";
+       kdc_log(context, config, 0, "internal error in get_pa_etype_info2(%s): %d != %d", 
+               name, n, pa.len);
+       if (ret == 0)
+           free(name);
+       pa.len = n;
+    }
+
+    ASN1_MALLOC_ENCODE(ETYPE_INFO2, buf, len, &pa, &len, ret);
+    free_ETYPE_INFO2(&pa);
+    if(ret)
+       return ret;
+    ret = realloc_method_data(md);
+    if(ret) {
+       free(buf);
+       return ret;
+    }
+    md->val[md->len - 1].padata_type = KRB5_PADATA_ETYPE_INFO2;
+    md->val[md->len - 1].padata_value.length = len;
+    md->val[md->len - 1].padata_value.data = buf;
+    return 0;
+}
+
+/*
+ * verify the flags on `client' and `server', returning 0
+ * if they are OK and generating an error messages and returning
+ * and error code otherwise.
+ */
+
+krb5_error_code
+_kdc_check_flags(krb5_context context, 
+                krb5_kdc_configuration *config,
+                hdb_entry *client, const char *client_name,
+                hdb_entry *server, const char *server_name,
+                krb5_boolean is_as_req)
+{
+    if(client != NULL) {
+       /* check client */
+       if (client->flags.invalid) {
+           kdc_log(context, config, 0, 
+                   "Client (%s) has invalid bit set", client_name);
+           return KRB5KDC_ERR_POLICY;
+       }
+       
+       if(!client->flags.client){
+           kdc_log(context, config, 0,
+                   "Principal may not act as client -- %s", 
+                   client_name);
+           return KRB5KDC_ERR_POLICY;
+       }
+       
+       if (client->valid_start && *client->valid_start > kdc_time) {
+           kdc_log(context, config, 0, "Client not yet valid -- %s", client_name);
+           return KRB5KDC_ERR_CLIENT_NOTYET;
+       }
+       
+       if (client->valid_end && *client->valid_end < kdc_time) {
+           kdc_log(context, config, 0, "Client expired -- %s", client_name);
+           return KRB5KDC_ERR_NAME_EXP;
+       }
+       
+       if (client->pw_end && *client->pw_end < kdc_time
+           && !server->flags.change_pw) {
+           kdc_log(context, config, 0, "Client's key has expired -- %s", client_name);
+           return KRB5KDC_ERR_KEY_EXPIRED;
+       }
+    }
+
+    /* check server */
+    
+    if (server != NULL) {
+       if (server->flags.invalid) {
+           kdc_log(context, config, 0, "Server has invalid flag set -- %s", server_name);
+           return KRB5KDC_ERR_POLICY;
+       }
+
+       if(!server->flags.server){
+           kdc_log(context, config, 0, "Principal may not act as server -- %s", 
+                   server_name);
+           return KRB5KDC_ERR_POLICY;
+       }
+
+       if(!is_as_req && server->flags.initial) {
+           kdc_log(context, config, 0, "AS-REQ is required for server -- %s", server_name);
+           return KRB5KDC_ERR_POLICY;
+       }
+
+       if (server->valid_start && *server->valid_start > kdc_time) {
+           kdc_log(context, config, 0, "Server not yet valid -- %s", server_name);
+           return KRB5KDC_ERR_SERVICE_NOTYET;
+       }
+
+       if (server->valid_end && *server->valid_end < kdc_time) {
+           kdc_log(context, config, 0, "Server expired -- %s", server_name);
+           return KRB5KDC_ERR_SERVICE_EXP;
+       }
+
+       if (server->pw_end && *server->pw_end < kdc_time) {
+           kdc_log(context, config, 0, "Server's key has expired -- %s", server_name);
+           return KRB5KDC_ERR_KEY_EXPIRED;
+       }
+    }
+    return 0;
+}
+
+/*
+ * Return TRUE if `from' is part of `addresses' taking into consideration
+ * the configuration variables that tells us how strict we should be about
+ * these checks
+ */
+
+static krb5_boolean
+check_addresses(krb5_context context,        
+               krb5_kdc_configuration *config,
+               HostAddresses *addresses, const struct sockaddr *from)
+{
+    krb5_error_code ret;
+    krb5_address addr;
+    krb5_boolean result;
+    
+    if(config->check_ticket_addresses == 0)
+       return TRUE;
+
+    if(addresses == NULL)
+       return config->allow_null_ticket_addresses;
+    
+    ret = krb5_sockaddr2address (context, from, &addr);
+    if(ret)
+       return FALSE;
+
+    result = krb5_address_search(context, &addr, addresses);
+    krb5_free_address (context, &addr);
+    return result;
+}
+
+krb5_error_code
+_kdc_as_rep(krb5_context context, 
+           krb5_kdc_configuration *config,
+           KDC_REQ *req, 
+           krb5_data *reply,
+           const char *from,
+           struct sockaddr *from_addr)
+{
+    KDC_REQ_BODY *b = &req->req_body;
+    AS_REP rep;
+    KDCOptions f = b->kdc_options;
+    hdb_entry *client = NULL, *server = NULL;
+    krb5_enctype cetype, setype;
+    EncTicketPart et;
+    EncKDCRepPart ek;
+    krb5_principal client_princ = NULL, server_princ = NULL;
+    char *client_name = NULL, *server_name = NULL;
+    krb5_error_code ret = 0;
+    const char *e_text = NULL;
+    krb5_crypto crypto;
+    Key *ckey, *skey;
+    EncryptionKey *reply_key;
+#ifdef PKINIT
+    pk_client_params *pkp = NULL;
+#endif
+
+    memset(&rep, 0, sizeof(rep));
+
+    if(b->sname == NULL){
+       ret = KRB5KRB_ERR_GENERIC;
+       e_text = "No server in request";
+    } else{
+       _krb5_principalname2krb5_principal (&server_princ,
+                                           *(b->sname), b->realm);
+       ret = krb5_unparse_name(context, server_princ, &server_name);
+    }
+    if (ret) {
+       kdc_log(context, config, 0, "AS-REQ malformed server name from %s", from);
+       goto out;
+    }
+    
+    if(b->cname == NULL){
+       ret = KRB5KRB_ERR_GENERIC;
+       e_text = "No client in request";
+    } else {
+       _krb5_principalname2krb5_principal (&client_princ,
+                                           *(b->cname), b->realm);
+       ret = krb5_unparse_name(context, client_princ, &client_name);
+    }
+    if (ret) {
+       kdc_log(context, config, 0, "AS-REQ malformed client name from %s", from);
+       goto out;
+    }
+
+    kdc_log(context, config, 0, "AS-REQ %s from %s for %s", 
+           client_name, from, server_name);
+
+    ret = _kdc_db_fetch(context, config, client_princ, HDB_ENT_TYPE_CLIENT, &client);
+    if(ret){
+       kdc_log(context, config, 0, "UNKNOWN -- %s: %s", client_name,
+               krb5_get_err_text(context, ret));
+       ret = KRB5KDC_ERR_C_PRINCIPAL_UNKNOWN;
+       goto out;
+    }
+
+    ret = _kdc_db_fetch(context, config, server_princ, HDB_ENT_TYPE_SERVER, &server);
+    if(ret){
+       kdc_log(context, config, 0, "UNKNOWN -- %s: %s", server_name,
+               krb5_get_err_text(context, ret));
+       ret = KRB5KDC_ERR_S_PRINCIPAL_UNKNOWN;
+       goto out;
+    }
+
+    ret = _kdc_check_flags(context, config, 
+                          client, client_name,
+                          server, server_name,
+                          TRUE);
+    if(ret)
+       goto out;
+
+    memset(&et, 0, sizeof(et));
+    memset(&ek, 0, sizeof(ek));
+
+    if(req->padata){
+       int i = 0;
+       PA_DATA *pa;
+       int found_pa = 0;
+
+#ifdef PKINIT
+       kdc_log(context, config, 5, 
+               "Looking for PKINIT pa-data -- %s", client_name);
+
+       e_text = "No PKINIT PA found";
+
+       i = 0;
+       if ((pa = find_padata(req, &i, KRB5_PADATA_PK_AS_REQ)))
+           ;
+       if (pa == NULL) {
+           i = 0;
+           if((pa = find_padata(req, &i, KRB5_PADATA_PK_AS_REQ_19)))
+               ;
+       }
+       if (pa == NULL) {
+           i = 0;
+           if((pa = find_padata(req, &i, KRB5_PADATA_PK_AS_REQ_WIN)))
+               ;
+       }
+       if (pa) {
+           char *client_cert = NULL;
+
+           ret = _kdc_pk_rd_padata(context, config, req, pa, &pkp);
+           if (ret) {
+               ret = KRB5KRB_AP_ERR_BAD_INTEGRITY;
+               kdc_log(context, config, 5, 
+                       "Failed to decode PKINIT PA-DATA -- %s", 
+                       client_name);
+               goto ts_enc;
+           }
+           if (ret == 0 && pkp == NULL)
+               goto ts_enc;
+
+           ret = _kdc_pk_check_client(context,
+                                      config,
+                                      client_princ, 
+                                      client,
+                                      pkp,
+                                      &client_cert);
+           if (ret) {
+               e_text = "PKINIT certificate not allowed to "
+                   "impersonate principal";
+               _kdc_pk_free_client_param(context, pkp);
+               pkp = NULL;
+               goto ts_enc;
+           }
+           found_pa = 1;
+           et.flags.pre_authent = 1;
+           kdc_log(context, config, 2,
+                   "PKINIT pre-authentication succeeded -- %s using %s", 
+                   client_name, client_cert);
+           free(client_cert);
+           if (pkp)
+               goto preauth_done;
+       }
+    ts_enc:
+#endif
+       kdc_log(context, config, 5, "Looking for ENC-TS pa-data -- %s", 
+               client_name);
+
+       i = 0;
+       e_text = "No ENC-TS found";
+       while((pa = find_padata(req, &i, KRB5_PADATA_ENC_TIMESTAMP))){
+           krb5_data ts_data;
+           PA_ENC_TS_ENC p;
+           size_t len;
+           EncryptedData enc_data;
+           Key *pa_key;
+           
+           found_pa = 1;
+           
+           ret = decode_EncryptedData(pa->padata_value.data,
+                                      pa->padata_value.length,
+                                      &enc_data,
+                                      &len);
+           if (ret) {
+               ret = KRB5KRB_AP_ERR_BAD_INTEGRITY;
+               kdc_log(context, config, 5, "Failed to decode PA-DATA -- %s", 
+                       client_name);
+               goto out;
+           }
+           
+           ret = hdb_enctype2key(context, client, enc_data.etype, &pa_key);
+           if(ret){
+               char *estr;
+               e_text = "No key matches pa-data";
+               ret = KRB5KDC_ERR_PREAUTH_FAILED;
+               if(krb5_enctype_to_string(context, enc_data.etype, &estr))
+                   estr = NULL;
+               if(estr == NULL)
+                   kdc_log(context, config, 5, 
+                           "No client key matching pa-data (%d) -- %s", 
+                           enc_data.etype, client_name);
+               else
+                   kdc_log(context, config, 5,
+                           "No client key matching pa-data (%s) -- %s", 
+                           estr, client_name);
+               free(estr);
+                   
+               free_EncryptedData(&enc_data);
+               continue;
+           }
+
+       try_next_key:
+           ret = krb5_crypto_init(context, &pa_key->key, 0, &crypto);
+           if (ret) {
+               kdc_log(context, config, 0, "krb5_crypto_init failed: %s",
+                       krb5_get_err_text(context, ret));
+               free_EncryptedData(&enc_data);
+               continue;
+           }
+
+           ret = krb5_decrypt_EncryptedData (context,
+                                             crypto,
+                                             KRB5_KU_PA_ENC_TIMESTAMP,
+                                             &enc_data,
+                                             &ts_data);
+           krb5_crypto_destroy(context, crypto);
+           if(ret){
+               if(hdb_next_enctype2key(context, client, 
+                                       enc_data.etype, &pa_key) == 0)
+                   goto try_next_key;
+               free_EncryptedData(&enc_data);
+               e_text = "Failed to decrypt PA-DATA";
+               kdc_log(context, config, 
+                       5, "Failed to decrypt PA-DATA -- %s",
+                       client_name);
+               ret = KRB5KRB_AP_ERR_BAD_INTEGRITY;
+               continue;
+           }
+           free_EncryptedData(&enc_data);
+           ret = decode_PA_ENC_TS_ENC(ts_data.data,
+                                      ts_data.length,
+                                      &p,
+                                      &len);
+           krb5_data_free(&ts_data);
+           if(ret){
+               e_text = "Failed to decode PA-ENC-TS-ENC";
+               ret = KRB5KRB_AP_ERR_BAD_INTEGRITY;
+               kdc_log(context, config, 
+                       5, "Failed to decode PA-ENC-TS_ENC -- %s",
+                       client_name);
+               continue;
+           }
+           free_PA_ENC_TS_ENC(&p);
+           if (abs(kdc_time - p.patimestamp) > context->max_skew) {
+               ret = KRB5KDC_ERR_PREAUTH_FAILED;
+               e_text = "Too large time skew";
+               kdc_log(context, config, 0,
+                       "Too large time skew -- %s", client_name);
+               goto out;
+           }
+           et.flags.pre_authent = 1;
+           kdc_log(context, config, 2,
+                   "ENC-TS Pre-authentication succeeded -- %s", 
+                   client_name);
+           break;
+       }
+#ifdef PKINIT
+    preauth_done:
+#endif
+       if(found_pa == 0 && config->require_preauth)
+           goto use_pa;
+       /* We come here if we found a pa-enc-timestamp, but if there
+           was some problem with it, other than too large skew */
+       if(found_pa && et.flags.pre_authent == 0){
+           kdc_log(context, config, 0, "%s -- %s", e_text, client_name);
+           e_text = NULL;
+           goto out;
+       }
+    }else if (config->require_preauth
+             || client->flags.require_preauth
+             || server->flags.require_preauth) {
+       METHOD_DATA method_data;
+       PA_DATA *pa;
+       unsigned char *buf;
+       size_t len;
+       krb5_data foo_data;
+
+    use_pa: 
+       method_data.len = 0;
+       method_data.val = NULL;
+
+       ret = realloc_method_data(&method_data);
+       pa = &method_data.val[method_data.len-1];
+       pa->padata_type         = KRB5_PADATA_ENC_TIMESTAMP;
+       pa->padata_value.length = 0;
+       pa->padata_value.data   = NULL;
+
+#ifdef PKINIT
+       ret = realloc_method_data(&method_data);
+       pa = &method_data.val[method_data.len-1];
+       pa->padata_type         = KRB5_PADATA_PK_AS_REQ;
+       pa->padata_value.length = 0;
+       pa->padata_value.data   = NULL;
+
+       ret = realloc_method_data(&method_data);
+       pa = &method_data.val[method_data.len-1];
+       pa->padata_type         = KRB5_PADATA_PK_AS_REQ_19;
+       pa->padata_value.length = 0;
+       pa->padata_value.data   = NULL;
+#endif
+
+       /* XXX check ret */
+       if (only_older_enctype_p(req))
+           ret = get_pa_etype_info(context, config, &method_data, client, 
+                                   b->etype.val, b->etype.len); 
+       /* XXX check ret */
+       ret = get_pa_etype_info2(context, config, &method_data, client, 
+                                b->etype.val, b->etype.len);
+
+       
+       ASN1_MALLOC_ENCODE(METHOD_DATA, buf, len, &method_data, &len, ret);
+       free_METHOD_DATA(&method_data);
+       foo_data.data   = buf;
+       foo_data.length = len;
+       
+       ret = KRB5KDC_ERR_PREAUTH_REQUIRED;
+       krb5_mk_error(context,
+                     ret,
+                     "Need to use PA-ENC-TIMESTAMP/PA-PK-AS-REQ",
+                     &foo_data,
+                     client_princ,
+                     server_princ,
+                     NULL,
+                     NULL,
+                     reply);
+       free(buf);
+       kdc_log(context, config, 0,
+               "No preauth found, returning PREAUTH-REQUIRED -- %s",
+               client_name);
+       ret = 0;
+       goto out2;
+    }
+    
+    ret = find_keys(context, config, 
+                   client, server, &ckey, &cetype, &skey, &setype,
+                   b->etype.val, b->etype.len);
+    if(ret) {
+       kdc_log(context, config, 0, "Server/client has no support for etypes");
+       goto out;
+    }
+       
+    {
+       struct rk_strpool *p = NULL;
+       char *str;
+       int i;
+
+       for (i = 0; i < b->etype.len; i++) {
+           ret = krb5_enctype_to_string(context, b->etype.val[i], &str);
+           if (ret == 0) {
+               p = rk_strpoolprintf(p, "%s", str);
+               free(str);
+           } else
+               p = rk_strpoolprintf(p, "%d", b->etype.val[i]);
+           if (p && i + 1 < b->etype.len)
+               p = rk_strpoolprintf(p, ", ");
+           if (p == NULL) {
+               kdc_log(context, config, 0, "out of meory");
+               goto out;
+           }
+       }
+       str = rk_strpoolcollect(p);
+       kdc_log(context, config, 0, "Client supported enctypes: %s", str);
+       free(str);
+    }
+    {
+       char *cet;
+       char *set;
+
+       ret = krb5_enctype_to_string(context, cetype, &cet);
+       if(ret == 0) {
+           ret = krb5_enctype_to_string(context, setype, &set);
+           if (ret == 0) {
+               kdc_log(context, config, 5, "Using %s/%s", cet, set);
+               free(set);
+           }
+           free(cet);
+       }
+       if (ret != 0)
+           kdc_log(context, config, 5, "Using e-types %d/%d", cetype, setype);
+    }
+    
+    {
+       char str[128];
+       unparse_flags(KDCOptions2int(f), asn1_KDCOptions_units(), 
+                     str, sizeof(str));
+       if(*str)
+           kdc_log(context, config, 2, "Requested flags: %s", str);
+    }
+    
+
+    if(f.renew || f.validate || f.proxy || f.forwarded || f.enc_tkt_in_skey
+       || (f.request_anonymous && !config->allow_anonymous)) {
+       ret = KRB5KDC_ERR_BADOPTION;
+       kdc_log(context, config, 0, "Bad KDC options -- %s", client_name);
+       goto out;
+    }
+    
+    rep.pvno = 5;
+    rep.msg_type = krb_as_rep;
+    copy_Realm(&client->principal->realm, &rep.crealm);
+    if (f.request_anonymous)
+       make_anonymous_principalname (&rep.cname);
+    else
+       _krb5_principal2principalname(&rep.cname, 
+                                     client->principal);
+    rep.ticket.tkt_vno = 5;
+    copy_Realm(&server->principal->realm, &rep.ticket.realm);
+    _krb5_principal2principalname(&rep.ticket.sname, 
+                                 server->principal);
+
+    et.flags.initial = 1;
+    if(client->flags.forwardable && server->flags.forwardable)
+       et.flags.forwardable = f.forwardable;
+    else if (f.forwardable) {
+       ret = KRB5KDC_ERR_POLICY;
+       kdc_log(context, config, 0,
+               "Ticket may not be forwardable -- %s", client_name);
+       goto out;
+    }
+    if(client->flags.proxiable && server->flags.proxiable)
+       et.flags.proxiable = f.proxiable;
+    else if (f.proxiable) {
+       ret = KRB5KDC_ERR_POLICY;
+       kdc_log(context, config, 0, 
+               "Ticket may not be proxiable -- %s", client_name);
+       goto out;
+    }
+    if(client->flags.postdate && server->flags.postdate)
+       et.flags.may_postdate = f.allow_postdate;
+    else if (f.allow_postdate){
+       ret = KRB5KDC_ERR_POLICY;
+       kdc_log(context, config, 0,
+               "Ticket may not be postdatable -- %s", client_name);
+       goto out;
+    }
+
+    /* check for valid set of addresses */
+    if(!check_addresses(context, config, b->addresses, from_addr)) {
+       ret = KRB5KRB_AP_ERR_BADADDR;
+       kdc_log(context, config, 0,
+               "Bad address list requested -- %s", client_name);
+       goto out;
+    }
+
+    krb5_generate_random_keyblock(context, setype, &et.key);
+    copy_PrincipalName(&rep.cname, &et.cname);
+    copy_Realm(&rep.crealm, &et.crealm);
+    
+    {
+       time_t start;
+       time_t t;
+       
+       start = et.authtime = kdc_time;
+    
+       if(f.postdated && req->req_body.from){
+           ALLOC(et.starttime);
+           start = *et.starttime = *req->req_body.from;
+           et.flags.invalid = 1;
+           et.flags.postdated = 1; /* XXX ??? */
+       }
+       fix_time(&b->till);
+       t = *b->till;
+
+       /* be careful not overflowing */
+
+       if(client->max_life)
+           t = start + min(t - start, *client->max_life);
+       if(server->max_life)
+           t = start + min(t - start, *server->max_life);
+#if 0
+       t = min(t, start + realm->max_life);
+#endif
+       et.endtime = t;
+       if(f.renewable_ok && et.endtime < *b->till){
+           f.renewable = 1;
+           if(b->rtime == NULL){
+               ALLOC(b->rtime);
+               *b->rtime = 0;
+           }
+           if(*b->rtime < *b->till)
+               *b->rtime = *b->till;
+       }
+       if(f.renewable && b->rtime){
+           t = *b->rtime;
+           if(t == 0)
+               t = MAX_TIME;
+           if(client->max_renew)
+               t = start + min(t - start, *client->max_renew);
+           if(server->max_renew)
+               t = start + min(t - start, *server->max_renew);
+#if 0
+           t = min(t, start + realm->max_renew);
+#endif
+           ALLOC(et.renew_till);
+           *et.renew_till = t;
+           et.flags.renewable = 1;
+       }
+    }
+
+    if (f.request_anonymous)
+       et.flags.anonymous = 1;
+    
+    if(b->addresses){
+       ALLOC(et.caddr);
+       copy_HostAddresses(b->addresses, et.caddr);
+    }
+    
+    et.transited.tr_type = DOMAIN_X500_COMPRESS;
+    krb5_data_zero(&et.transited.contents); 
+     
+    copy_EncryptionKey(&et.key, &ek.key);
+
+    /* The MIT ASN.1 library (obviously) doesn't tell lengths encoded
+     * as 0 and as 0x80 (meaning indefinite length) apart, and is thus
+     * incapable of correctly decoding SEQUENCE OF's of zero length.
+     *
+     * To fix this, always send at least one no-op last_req
+     *
+     * If there's a pw_end or valid_end we will use that,
+     * otherwise just a dummy lr.
+     */
+    ek.last_req.val = malloc(2 * sizeof(*ek.last_req.val));
+    ek.last_req.len = 0;
+    if (client->pw_end
+       && (config->kdc_warn_pwexpire == 0
+           || kdc_time + config->kdc_warn_pwexpire <= *client->pw_end)) {
+       ek.last_req.val[ek.last_req.len].lr_type  = LR_PW_EXPTIME;
+       ek.last_req.val[ek.last_req.len].lr_value = *client->pw_end;
+       ++ek.last_req.len;
+    }
+    if (client->valid_end) {
+       ek.last_req.val[ek.last_req.len].lr_type  = LR_ACCT_EXPTIME;
+       ek.last_req.val[ek.last_req.len].lr_value = *client->valid_end;
+       ++ek.last_req.len;
+    }
+    if (ek.last_req.len == 0) {
+       ek.last_req.val[ek.last_req.len].lr_type  = LR_NONE;
+       ek.last_req.val[ek.last_req.len].lr_value = 0;
+       ++ek.last_req.len;
+    }
+    ek.nonce = b->nonce;
+    if (client->valid_end || client->pw_end) {
+       ALLOC(ek.key_expiration);
+       if (client->valid_end) {
+           if (client->pw_end)
+               *ek.key_expiration = min(*client->valid_end, *client->pw_end);
+           else
+               *ek.key_expiration = *client->valid_end;
+       } else
+           *ek.key_expiration = *client->pw_end;
+    } else
+       ek.key_expiration = NULL;
+    ek.flags = et.flags;
+    ek.authtime = et.authtime;
+    if (et.starttime) {
+       ALLOC(ek.starttime);
+       *ek.starttime = *et.starttime;
+    }
+    ek.endtime = et.endtime;
+    if (et.renew_till) {
+       ALLOC(ek.renew_till);
+       *ek.renew_till = *et.renew_till;
+    }
+    copy_Realm(&rep.ticket.realm, &ek.srealm);
+    copy_PrincipalName(&rep.ticket.sname, &ek.sname);
+    if(et.caddr){
+       ALLOC(ek.caddr);
+       copy_HostAddresses(et.caddr, ek.caddr);
+    }
+
+    ALLOC(rep.padata);
+    rep.padata->len = 0;
+    rep.padata->val = NULL;
+
+    reply_key = &ckey->key;
+#if PKINIT
+    if (pkp) {
+       ret = _kdc_pk_mk_pa_reply(context, config, pkp, client, req,
+                             &reply_key, rep.padata);
+       if (ret)
+           goto out;
+    }
+#endif
+
+    set_salt_padata (rep.padata, ckey->salt);
+
+    if (rep.padata->len == 0) {
+       free(rep.padata);
+       rep.padata = NULL;
+    }
+
+    log_timestamp(context, config, "AS-REQ", et.authtime, et.starttime, 
+                 et.endtime, et.renew_till);
+
+    ret = encode_reply(context, config, 
+                      &rep, &et, &ek, setype, server->kvno, &skey->key,
+                      client->kvno, reply_key, &e_text, reply);
+    free_EncTicketPart(&et);
+    free_EncKDCRepPart(&ek);
+ out:
+    free_AS_REP(&rep);
+    if(ret){
+       krb5_mk_error(context,
+                     ret,
+                     e_text,
+                     NULL,
+                     client_princ,
+                     server_princ,
+                     NULL,
+                     NULL,
+                     reply);
+       ret = 0;
+    }
+ out2:
+#ifdef PKINIT
+    if (pkp)
+       _kdc_pk_free_client_param(context, pkp);
+#endif
+    if (client_princ)
+       krb5_free_principal(context, client_princ);
+    free(client_name);
+    if (server_princ)
+       krb5_free_principal(context, server_princ);
+    free(server_name);
+    if(client)
+       _kdc_free_ent(context, client);
+    if(server)
+       _kdc_free_ent(context, server);
+    return ret;
+}
+
+
+static krb5_error_code
+check_tgs_flags(krb5_context context,        
+               krb5_kdc_configuration *config,
+               KDC_REQ_BODY *b, EncTicketPart *tgt, EncTicketPart *et)
+{
+    KDCOptions f = b->kdc_options;
+       
+    if(f.validate){
+       if(!tgt->flags.invalid || tgt->starttime == NULL){
+           kdc_log(context, config, 0, "Bad request to validate ticket");
+           return KRB5KDC_ERR_BADOPTION;
+       }
+       if(*tgt->starttime > kdc_time){
+           kdc_log(context, config, 0, "Early request to validate ticket");
+           return KRB5KRB_AP_ERR_TKT_NYV;
+       }
+       /* XXX  tkt = tgt */
+       et->flags.invalid = 0;
+    }else if(tgt->flags.invalid){
+       kdc_log(context, config, 0, "Ticket-granting ticket has INVALID flag set");
+       return KRB5KRB_AP_ERR_TKT_INVALID;
+    }
+
+    if(f.forwardable){
+       if(!tgt->flags.forwardable){
+           kdc_log(context, config, 0, "Bad request for forwardable ticket");
+           return KRB5KDC_ERR_BADOPTION;
+       }
+       et->flags.forwardable = 1;
+    }
+    if(f.forwarded){
+       if(!tgt->flags.forwardable){
+           kdc_log(context, config, 0, "Request to forward non-forwardable ticket");
+           return KRB5KDC_ERR_BADOPTION;
+       }
+       et->flags.forwarded = 1;
+       et->caddr = b->addresses;
+    }
+    if(tgt->flags.forwarded)
+       et->flags.forwarded = 1;
+       
+    if(f.proxiable){
+       if(!tgt->flags.proxiable){
+           kdc_log(context, config, 0,
+                   "Bad request for proxiable ticket");
+           return KRB5KDC_ERR_BADOPTION;
+       }
+       et->flags.proxiable = 1;
+    }
+    if(f.proxy){
+       if(!tgt->flags.proxiable){
+           kdc_log(context, config, 0,
+                   "Request to proxy non-proxiable ticket");
+           return KRB5KDC_ERR_BADOPTION;
+       }
+       et->flags.proxy = 1;
+       et->caddr = b->addresses;
+    }
+    if(tgt->flags.proxy)
+       et->flags.proxy = 1;
+
+    if(f.allow_postdate){
+       if(!tgt->flags.may_postdate){
+           kdc_log(context, config, 0,
+                   "Bad request for post-datable ticket");
+           return KRB5KDC_ERR_BADOPTION;
+       }
+       et->flags.may_postdate = 1;
+    }
+    if(f.postdated){
+       if(!tgt->flags.may_postdate){
+           kdc_log(context, config, 0,
+                   "Bad request for postdated ticket");
+           return KRB5KDC_ERR_BADOPTION;
+       }
+       if(b->from)
+           *et->starttime = *b->from;
+       et->flags.postdated = 1;
+       et->flags.invalid = 1;
+    }else if(b->from && *b->from > kdc_time + context->max_skew){
+       kdc_log(context, config, 0, "Ticket cannot be postdated");
+       return KRB5KDC_ERR_CANNOT_POSTDATE;
+    }
+
+    if(f.renewable){
+       if(!tgt->flags.renewable){
+           kdc_log(context, config, 0,
+                   "Bad request for renewable ticket");
+           return KRB5KDC_ERR_BADOPTION;
+       }
+       et->flags.renewable = 1;
+       ALLOC(et->renew_till);
+       fix_time(&b->rtime);
+       *et->renew_till = *b->rtime;
+    }
+    if(f.renew){
+       time_t old_life;
+       if(!tgt->flags.renewable || tgt->renew_till == NULL){
+           kdc_log(context, config, 0,
+                   "Request to renew non-renewable ticket");
+           return KRB5KDC_ERR_BADOPTION;
+       }
+       old_life = tgt->endtime;
+       if(tgt->starttime)
+           old_life -= *tgt->starttime;
+       else
+           old_life -= tgt->authtime;
+       et->endtime = *et->starttime + old_life;
+       if (et->renew_till != NULL)
+           et->endtime = min(*et->renew_till, et->endtime);
+    }      
+    
+    /* checks for excess flags */
+    if(f.request_anonymous && !config->allow_anonymous){
+       kdc_log(context, config, 0,
+               "Request for anonymous ticket");
+       return KRB5KDC_ERR_BADOPTION;
+    }
+    return 0;
+}
+
+static krb5_error_code
+fix_transited_encoding(krb5_context context, 
+                      krb5_kdc_configuration *config,
+                      krb5_boolean check_policy,
+                      TransitedEncoding *tr, 
+                      EncTicketPart *et, 
+                      const char *client_realm, 
+                      const char *server_realm, 
+                      const char *tgt_realm)
+{
+    krb5_error_code ret = 0;
+    char **realms, **tmp;
+    int num_realms;
+    int i;
+
+    if(tr->tr_type != DOMAIN_X500_COMPRESS) {
+       kdc_log(context, config, 0,
+               "Unknown transited type: %u", tr->tr_type);
+       return KRB5KDC_ERR_TRTYPE_NOSUPP;
+    }
+
+    ret = krb5_domain_x500_decode(context, 
+                                 tr->contents,
+                                 &realms, 
+                                 &num_realms,
+                                 client_realm,
+                                 server_realm);
+    if(ret){
+       krb5_warn(context, ret,
+                 "Decoding transited encoding");
+       return ret;
+    }
+    if(strcmp(client_realm, tgt_realm) && strcmp(server_realm, tgt_realm)) {
+       /* not us, so add the previous realm to transited set */
+       if (num_realms < 0 || num_realms + 1 > UINT_MAX/sizeof(*realms)) {
+           ret = ERANGE;
+           goto free_realms;
+       }
+       tmp = realloc(realms, (num_realms + 1) * sizeof(*realms));
+       if(tmp == NULL){
+           ret = ENOMEM;
+           goto free_realms;
+       }
+       realms = tmp;
+       realms[num_realms] = strdup(tgt_realm);
+       if(realms[num_realms] == NULL){
+           ret = ENOMEM;
+           goto free_realms;
+       }
+       num_realms++;
+    }
+    if(num_realms == 0) {
+       if(strcmp(client_realm, server_realm)) 
+           kdc_log(context, config, 0,
+                   "cross-realm %s -> %s", client_realm, server_realm);
+    } else {
+       size_t l = 0;
+       char *rs;
+       for(i = 0; i < num_realms; i++)
+           l += strlen(realms[i]) + 2;
+       rs = malloc(l);
+       if(rs != NULL) {
+           *rs = '\0';
+           for(i = 0; i < num_realms; i++) {
+               if(i > 0)
+                   strlcat(rs, ", ", l);
+               strlcat(rs, realms[i], l);
+           }
+           kdc_log(context, config, 0,
+                   "cross-realm %s -> %s via [%s]",
+                   client_realm, server_realm, rs);
+           free(rs);
+       }
+    }
+    if(check_policy) {
+       ret = krb5_check_transited(context, client_realm, 
+                                  server_realm, 
+                                  realms, num_realms, NULL);
+       if(ret) {
+           krb5_warn(context, ret, "cross-realm %s -> %s", 
+                     client_realm, server_realm);
+           goto free_realms;
+       }
+       et->flags.transited_policy_checked = 1;
+    }
+    et->transited.tr_type = DOMAIN_X500_COMPRESS;
+    ret = krb5_domain_x500_encode(realms, num_realms, &et->transited.contents);
+    if(ret)
+       krb5_warn(context, ret, "Encoding transited encoding");
+  free_realms:
+    for(i = 0; i < num_realms; i++)
+       free(realms[i]);
+    free(realms);
+    return ret;
+}
+
+
+static krb5_error_code
+tgs_make_reply(krb5_context context, 
+              krb5_kdc_configuration *config,
+              KDC_REQ_BODY *b, 
+              EncTicketPart *tgt, 
+              EncTicketPart *adtkt, 
+              AuthorizationData *auth_data,
+              hdb_entry *server, 
+              hdb_entry *client, 
+              krb5_principal client_principal, 
+              hdb_entry *krbtgt,
+              EncryptionKey *tgtkey,
+              krb5_enctype cetype,
+              const char **e_text,
+              krb5_data *reply)
+{
+    KDC_REP rep;
+    EncKDCRepPart ek;
+    EncTicketPart et;
+    KDCOptions f = b->kdc_options;
+    krb5_error_code ret;
+    krb5_enctype etype;
+    Key *skey;
+    EncryptionKey *ekey;
+    
+    if(adtkt) {
+       int i;
+       krb5_keytype kt;
+       ekey = &adtkt->key;
+       for(i = 0; i < b->etype.len; i++){
+           ret = krb5_enctype_to_keytype(context, b->etype.val[i], &kt);
+           if(ret)
+               continue;
+           if(adtkt->key.keytype == kt)
+               break;
+       }
+       if(i == b->etype.len)
+           return KRB5KDC_ERR_ETYPE_NOSUPP;
+       etype = b->etype.val[i];
+    }else{
+       ret = find_keys(context, config, 
+                       NULL, server, NULL, NULL, &skey, &etype, 
+                       b->etype.val, b->etype.len);
+       if(ret) {
+           kdc_log(context, config, 0, "Server has no support for etypes");
+           return ret;
+       }
+       ekey = &skey->key;
+    }
+    
+    memset(&rep, 0, sizeof(rep));
+    memset(&et, 0, sizeof(et));
+    memset(&ek, 0, sizeof(ek));
+    
+    rep.pvno = 5;
+    rep.msg_type = krb_tgs_rep;
+
+    et.authtime = tgt->authtime;
+    fix_time(&b->till);
+    et.endtime = min(tgt->endtime, *b->till);
+    ALLOC(et.starttime);
+    *et.starttime = kdc_time;
+    
+    ret = check_tgs_flags(context, config, b, tgt, &et);
+    if(ret)
+       goto out;
+
+    /* We should check the transited encoding if:
+       1) the request doesn't ask not to be checked
+       2) globally enforcing a check
+       3) principal requires checking
+       4) we allow non-check per-principal, but principal isn't marked as allowing this
+       5) we don't globally allow this
+    */
+
+#define GLOBAL_FORCE_TRANSITED_CHECK           \
+       (config->trpolicy == TRPOLICY_ALWAYS_CHECK)
+#define GLOBAL_ALLOW_PER_PRINCIPAL             \
+       (config->trpolicy == TRPOLICY_ALLOW_PER_PRINCIPAL)
+#define GLOBAL_ALLOW_DISABLE_TRANSITED_CHECK   \
+       (config->trpolicy == TRPOLICY_ALWAYS_HONOUR_REQUEST)
+
+/* these will consult the database in future release */
+#define PRINCIPAL_FORCE_TRANSITED_CHECK(P)             0
+#define PRINCIPAL_ALLOW_DISABLE_TRANSITED_CHECK(P)     0
+
+    ret = fix_transited_encoding(context, config, 
+                                !f.disable_transited_check ||
+                                GLOBAL_FORCE_TRANSITED_CHECK ||
+                                PRINCIPAL_FORCE_TRANSITED_CHECK(server) ||
+                                !((GLOBAL_ALLOW_PER_PRINCIPAL && 
+                                   PRINCIPAL_ALLOW_DISABLE_TRANSITED_CHECK(server)) ||
+                                  GLOBAL_ALLOW_DISABLE_TRANSITED_CHECK),
+                                &tgt->transited, &et,
+                                *krb5_princ_realm(context, client_principal),
+                                *krb5_princ_realm(context, server->principal),
+                                *krb5_princ_realm(context, krbtgt->principal));
+    if(ret)
+       goto out;
+
+    copy_Realm(krb5_princ_realm(context, server->principal), 
+              &rep.ticket.realm);
+    _krb5_principal2principalname(&rep.ticket.sname, server->principal);
+    copy_Realm(&tgt->crealm, &rep.crealm);
+    if (f.request_anonymous)
+       make_anonymous_principalname (&tgt->cname);
+    else
+       copy_PrincipalName(&tgt->cname, &rep.cname);
+    rep.ticket.tkt_vno = 5;
+
+    ek.caddr = et.caddr;
+    if(et.caddr == NULL)
+       et.caddr = tgt->caddr;
+
+    {
+       time_t life;
+       life = et.endtime - *et.starttime;
+       if(client && client->max_life)
+           life = min(life, *client->max_life);
+       if(server->max_life)
+           life = min(life, *server->max_life);
+       et.endtime = *et.starttime + life;
+    }
+    if(f.renewable_ok && tgt->flags.renewable && 
+       et.renew_till == NULL && et.endtime < *b->till){
+       et.flags.renewable = 1;
+       ALLOC(et.renew_till);
+       *et.renew_till = *b->till;
+    }
+    if(et.renew_till){
+       time_t renew;
+       renew = *et.renew_till - et.authtime;
+       if(client && client->max_renew)
+           renew = min(renew, *client->max_renew);
+       if(server->max_renew)
+           renew = min(renew, *server->max_renew);
+       *et.renew_till = et.authtime + renew;
+    }
+           
+    if(et.renew_till){
+       *et.renew_till = min(*et.renew_till, *tgt->renew_till);
+       *et.starttime = min(*et.starttime, *et.renew_till);
+       et.endtime = min(et.endtime, *et.renew_till);
+    }
+    
+    *et.starttime = min(*et.starttime, et.endtime);
+
+    if(*et.starttime == et.endtime){
+       ret = KRB5KDC_ERR_NEVER_VALID;
+       goto out;
+    }
+    if(et.renew_till && et.endtime == *et.renew_till){
+       free(et.renew_till);
+       et.renew_till = NULL;
+       et.flags.renewable = 0;
+    }
+    
+    et.flags.pre_authent = tgt->flags.pre_authent;
+    et.flags.hw_authent  = tgt->flags.hw_authent;
+    et.flags.anonymous   = tgt->flags.anonymous;
+    et.flags.ok_as_delegate = server->flags.ok_as_delegate;
+           
+#ifdef _SAMBA_BUILD_
+    {
+
+           unsigned char *buf;
+           size_t buf_size;
+           size_t len;
+
+           krb5_data pac;
+           AD_IF_RELEVANT *if_relevant;
+           ALLOC(if_relevant);
+           if_relevant->len = 1;
+           if_relevant->val = malloc(sizeof(*if_relevant->val));
+           if_relevant->val[0].ad_type = KRB5_AUTHDATA_WIN2K_PAC;
+           if_relevant->val[0].ad_data.data = NULL;
+           if_relevant->val[0].ad_data.length = 0;
+
+           /* Get PAC from Samba */
+           ret = samba_get_pac(context, config, 
+                               client->principal,
+                               tgtkey,
+                               ekey,
+                               &pac);
+           if (ret) {
+                   free_AuthorizationData(if_relevant);
+                   goto out;
+           }
+
+           /* pac.data will be freed with this */
+           if_relevant->val[0].ad_data.data = pac.data;
+           if_relevant->val[0].ad_data.length = pac.length;
+
+           ASN1_MALLOC_ENCODE(AuthorizationData, buf, buf_size, if_relevant, &len, ret);
+           
+           auth_data = NULL;
+           ALLOC(auth_data);
+           auth_data->len = 1;
+           auth_data->val = malloc(sizeof(*auth_data->val));
+           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;
+           if (ret) {
+                   goto out;
+           }
+    }
+
+#endif
+    /* XXX Check enc-authorization-data */
+    et.authorization_data = auth_data;
+
+    krb5_generate_random_keyblock(context, etype, &et.key);
+    et.crealm = tgt->crealm;
+    et.cname = tgt->cname;
+           
+    ek.key = et.key;
+    /* MIT must have at least one last_req */
+    ek.last_req.len = 1;
+    ek.last_req.val = calloc(1, sizeof(*ek.last_req.val));
+    ek.nonce = b->nonce;
+    ek.flags = et.flags;
+    ek.authtime = et.authtime;
+    ek.starttime = et.starttime;
+    ek.endtime = et.endtime;
+    ek.renew_till = et.renew_till;
+    ek.srealm = rep.ticket.realm;
+    ek.sname = rep.ticket.sname;
+    
+    log_timestamp(context, config, "TGS-REQ", et.authtime, et.starttime, 
+                 et.endtime, et.renew_till);
+
+    /* It is somewhat unclear where the etype in the following
+       encryption should come from. What we have is a session
+       key in the passed tgt, and a list of preferred etypes
+       *for the new ticket*. Should we pick the best possible
+       etype, given the keytype in the tgt, or should we look
+       at the etype list here as well?  What if the tgt
+       session key is DES3 and we want a ticket with a (say)
+       CAST session key. Should the DES3 etype be added to the
+       etype list, even if we don't want a session key with
+       DES3? */
+    ret = encode_reply(context, config, 
+                      &rep, &et, &ek, etype, adtkt ? 0 : server->kvno, ekey,
+                      0, &tgt->key, e_text, reply);
+  out:
+    free_TGS_REP(&rep);
+    free_TransitedEncoding(&et.transited);
+    if(et.starttime)
+       free(et.starttime);
+    if(et.renew_till)
+       free(et.renew_till);
+    free_LastReq(&ek.last_req);
+    memset(et.key.keyvalue.data, 0, et.key.keyvalue.length);
+    free_EncryptionKey(&et.key);
+    return ret;
+}
+
+static krb5_error_code
+tgs_check_authenticator(krb5_context context, 
+                       krb5_kdc_configuration *config,
+                       krb5_auth_context ac,
+                       KDC_REQ_BODY *b, 
+                       const char **e_text,
+                       krb5_keyblock *key)
+{
+    krb5_authenticator auth;
+    size_t len;
+    unsigned char *buf;
+    size_t buf_size;
+    krb5_error_code ret;
+    krb5_crypto crypto;
+    
+    krb5_auth_con_getauthenticator(context, ac, &auth);
+    if(auth->cksum == NULL){
+       kdc_log(context, config, 0, "No authenticator in request");
+       ret = KRB5KRB_AP_ERR_INAPP_CKSUM;
+       goto out;
+    }
+    /*
+     * according to RFC1510 it doesn't need to be keyed,
+     * but according to the latest draft it needs to.
+     */
+    if (
+#if 0
+!krb5_checksum_is_keyed(context, auth->cksum->cksumtype)
+       ||
+#endif
+ !krb5_checksum_is_collision_proof(context, auth->cksum->cksumtype)) {
+       kdc_log(context, config, 0, "Bad checksum type in authenticator: %d", 
+               auth->cksum->cksumtype);
+       ret =  KRB5KRB_AP_ERR_INAPP_CKSUM;
+       goto out;
+    }
+               
+    /* XXX should not re-encode this */
+    ASN1_MALLOC_ENCODE(KDC_REQ_BODY, buf, buf_size, b, &len, ret);
+    if(ret){
+       kdc_log(context, config, 0, "Failed to encode KDC-REQ-BODY: %s", 
+               krb5_get_err_text(context, ret));
+       goto out;
+    }
+    if(buf_size != len) {
+       free(buf);
+       kdc_log(context, config, 0, "Internal error in ASN.1 encoder");
+       *e_text = "KDC internal error";
+       ret = KRB5KRB_ERR_GENERIC;
+       goto out;
+    }
+    ret = krb5_crypto_init(context, key, 0, &crypto);
+    if (ret) {
+       free(buf);
+       kdc_log(context, config, 0, "krb5_crypto_init failed: %s",
+               krb5_get_err_text(context, ret));
+       goto out;
+    }
+    ret = krb5_verify_checksum(context,
+                              crypto,
+                              KRB5_KU_TGS_REQ_AUTH_CKSUM,
+                              buf, 
+                              len,
+                              auth->cksum);
+    free(buf);
+    krb5_crypto_destroy(context, crypto);
+    if(ret){
+       kdc_log(context, config, 0, "Failed to verify checksum: %s", 
+               krb5_get_err_text(context, ret));
+    }
+out:
+    free_Authenticator(auth);
+    free(auth);
+    return ret;
+}
+
+/*
+ * return the realm of a krbtgt-ticket or NULL
+ */
+
+static Realm 
+get_krbtgt_realm(const PrincipalName *p)
+{
+    if(p->name_string.len == 2
+       && strcmp(p->name_string.val[0], KRB5_TGS_NAME) == 0)
+       return p->name_string.val[1];
+    else
+       return NULL;
+}
+
+static const char *
+find_rpath(krb5_context context, Realm crealm, Realm srealm)
+{
+    const char *new_realm = krb5_config_get_string(context,
+                                                  NULL,
+                                                  "capaths", 
+                                                  crealm,
+                                                  srealm,
+                                                  NULL);
+    return new_realm;
+}
+           
+
+static krb5_boolean
+need_referral(krb5_context context, krb5_principal server, krb5_realm **realms)
+{
+    if(server->name.name_type != KRB5_NT_SRV_INST ||
+       server->name.name_string.len != 2)
+       return FALSE;
+    return _krb5_get_host_realm_int(context, server->name.name_string.val[1],
+                                   FALSE, realms) == 0;
+}
+
+static krb5_error_code
+tgs_rep2(krb5_context context, 
+        krb5_kdc_configuration *config,
+        KDC_REQ_BODY *b,
+        PA_DATA *tgs_req,
+        krb5_data *reply,
+        const char *from,
+        const struct sockaddr *from_addr,
+        time_t **csec,
+        int **cusec)
+{
+    krb5_ap_req ap_req;
+    krb5_error_code ret;
+    krb5_principal princ;
+    krb5_auth_context ac = NULL;
+    krb5_ticket *ticket = NULL;
+    krb5_flags ap_req_options;
+    krb5_flags verify_ap_req_flags;
+    const char *e_text = NULL;
+    krb5_crypto crypto;
+
+    hdb_entry *krbtgt = NULL;
+    EncTicketPart *tgt;
+    Key *tkey;
+    krb5_enctype cetype;
+    krb5_principal cp = NULL;
+    krb5_principal sp = NULL;
+    AuthorizationData *auth_data = NULL;
+
+    *csec  = NULL;
+    *cusec = NULL;
+
+    memset(&ap_req, 0, sizeof(ap_req));
+    ret = krb5_decode_ap_req(context, &tgs_req->padata_value, &ap_req);
+    if(ret){
+       kdc_log(context, config, 0, "Failed to decode AP-REQ: %s", 
+               krb5_get_err_text(context, ret));
+       goto out2;
+    }
+    
+    if(!get_krbtgt_realm(&ap_req.ticket.sname)){
+       /* XXX check for ticket.sname == req.sname */
+       kdc_log(context, config, 0, "PA-DATA is not a ticket-granting ticket");
+       ret = KRB5KDC_ERR_POLICY; /* ? */
+       goto out2;
+    }
+    
+    _krb5_principalname2krb5_principal(&princ,
+                                      ap_req.ticket.sname,
+                                      ap_req.ticket.realm);
+    
+    ret = _kdc_db_fetch(context, config, princ, HDB_ENT_TYPE_SERVER, &krbtgt);
+
+    if(ret) {
+       char *p;
+       ret = krb5_unparse_name(context, princ, &p);
+       if (ret != 0)
+           p = "<unparse_name failed>";
+       krb5_free_principal(context, princ);
+       kdc_log(context, config, 0,
+               "Ticket-granting ticket not found in database: %s: %s",
+               p, krb5_get_err_text(context, ret));
+       if (ret == 0)
+           free(p);
+       ret = KRB5KRB_AP_ERR_NOT_US;
+       goto out2;
+    }
+    
+    if(ap_req.ticket.enc_part.kvno && 
+       *ap_req.ticket.enc_part.kvno != krbtgt->kvno){
+       char *p;
+
+       ret = krb5_unparse_name (context, princ, &p);
+       krb5_free_principal(context, princ);
+       if (ret != 0)
+           p = "<unparse_name failed>";
+       kdc_log(context, config, 0,
+               "Ticket kvno = %d, DB kvno = %d (%s)", 
+               *ap_req.ticket.enc_part.kvno,
+               krbtgt->kvno,
+               p);
+       if (ret == 0)
+           free (p);
+       ret = KRB5KRB_AP_ERR_BADKEYVER;
+       goto out2;
+    }
+
+    ret = hdb_enctype2key(context, krbtgt, ap_req.ticket.enc_part.etype, &tkey);
+    if(ret){
+       char *str;
+       krb5_enctype_to_string(context, ap_req.ticket.enc_part.etype, &str);
+       kdc_log(context, config, 0,
+               "No server key found for %s", str);
+       free(str);
+       ret = KRB5KRB_AP_ERR_BADKEYVER;
+       goto out2;
+    }
+    
+    if (b->kdc_options.validate)
+       verify_ap_req_flags = KRB5_VERIFY_AP_REQ_IGNORE_INVALID;
+    else
+       verify_ap_req_flags = 0;
+
+    ret = krb5_verify_ap_req2(context,
+                             &ac,
+                             &ap_req,
+                             princ,
+                             &tkey->key,
+                             verify_ap_req_flags,
+                             &ap_req_options,
+                             &ticket,
+                             KRB5_KU_TGS_REQ_AUTH);
+                            
+    krb5_free_principal(context, princ);
+    if(ret) {
+       kdc_log(context, config, 0, "Failed to verify AP-REQ: %s", 
+               krb5_get_err_text(context, ret));
+       goto out2;
+    }
+
+    {
+       krb5_authenticator auth;
+
+       ret = krb5_auth_con_getauthenticator(context, ac, &auth);
+       if (ret == 0) {
+           *csec   = malloc(sizeof(**csec));
+           if (*csec == NULL) {
+               krb5_free_authenticator(context, &auth);
+               kdc_log(context, config, 0, "malloc failed");
+               goto out2;
+           }
+           **csec  = auth->ctime;
+           *cusec  = malloc(sizeof(**cusec));
+           if (*cusec == NULL) {
+               krb5_free_authenticator(context, &auth);
+               kdc_log(context, config, 0, "malloc failed");
+               goto out2;
+           }
+           **csec  = auth->cusec;
+           krb5_free_authenticator(context, &auth);
+       }
+    }
+
+    cetype = ap_req.authenticator.etype;
+
+    tgt = &ticket->ticket;
+
+    ret = tgs_check_authenticator(context, config, 
+                                 ac, b, &e_text, &tgt->key);
+
+    if (b->enc_authorization_data) {
+       krb5_keyblock *subkey;
+       krb5_data ad;
+       ret = krb5_auth_con_getremotesubkey(context,
+                                           ac,
+                                           &subkey);
+       if(ret){
+           krb5_auth_con_free(context, ac);
+           kdc_log(context, config, 0, "Failed to get remote subkey: %s", 
+                   krb5_get_err_text(context, ret));
+           goto out2;
+       }
+       if(subkey == NULL){
+           ret = krb5_auth_con_getkey(context, ac, &subkey);
+           if(ret) {
+               krb5_auth_con_free(context, ac);
+               kdc_log(context, config, 0, "Failed to get session key: %s", 
+                       krb5_get_err_text(context, ret));
+               goto out2;
+           }
+       }
+       if(subkey == NULL){
+           krb5_auth_con_free(context, ac);
+           kdc_log(context, config, 0,
+                   "Failed to get key for enc-authorization-data");
+           ret = KRB5KRB_AP_ERR_BAD_INTEGRITY; /* ? */
+           goto out2;
+       }
+       ret = krb5_crypto_init(context, subkey, 0, &crypto);
+       if (ret) {
+           krb5_auth_con_free(context, ac);
+           kdc_log(context, config, 0, "krb5_crypto_init failed: %s",
+                   krb5_get_err_text(context, ret));
+           goto out2;
+       }
+       ret = krb5_decrypt_EncryptedData (context,
+                                         crypto,
+                                         KRB5_KU_TGS_REQ_AUTH_DAT_SUBKEY,
+                                         b->enc_authorization_data,
+                                         &ad);
+       krb5_crypto_destroy(context, crypto);
+       if(ret){
+           krb5_auth_con_free(context, ac);
+           kdc_log(context, config, 0, "Failed to decrypt enc-authorization-data");
+           ret = KRB5KRB_AP_ERR_BAD_INTEGRITY; /* ? */
+           goto out2;
+       }
+       krb5_free_keyblock(context, subkey);
+       ALLOC(auth_data);
+       ret = decode_AuthorizationData(ad.data, ad.length, auth_data, NULL);
+       if(ret){
+           krb5_auth_con_free(context, ac);
+           free(auth_data);
+           auth_data = NULL;
+           kdc_log(context, config, 0, "Failed to decode authorization data");
+           ret = KRB5KRB_AP_ERR_BAD_INTEGRITY; /* ? */
+           goto out2;
+       }
+    }
+
+    krb5_auth_con_free(context, ac);
+
+    if(ret){
+       kdc_log(context, config, 0, "Failed to verify authenticator: %s", 
+               krb5_get_err_text(context, ret));
+       goto out2;
+    }
+    
+    {
+       PrincipalName *s;
+       Realm r;
+       char *spn = NULL, *cpn = NULL;
+       hdb_entry *server = NULL, *client = NULL;
+       int nloop = 0;
+       EncTicketPart adtkt;
+       char opt_str[128];
+
+       s = b->sname;
+       r = b->realm;
+       if(b->kdc_options.enc_tkt_in_skey){
+           Ticket *t;
+           hdb_entry *uu;
+           krb5_principal p;
+           Key *uukey;
+           
+           if(b->additional_tickets == NULL || 
+              b->additional_tickets->len == 0){
+               ret = KRB5KDC_ERR_BADOPTION; /* ? */
+               kdc_log(context, config, 0,
+                       "No second ticket present in request");
+               goto out;
+           }
+           t = &b->additional_tickets->val[0];
+           if(!get_krbtgt_realm(&t->sname)){
+               kdc_log(context, config, 0,
+                       "Additional ticket is not a ticket-granting ticket");
+               ret = KRB5KDC_ERR_POLICY;
+               goto out2;
+           }
+           _krb5_principalname2krb5_principal(&p, t->sname, t->realm);
+           ret = _kdc_db_fetch(context, config, p, HDB_ENT_TYPE_SERVER, &uu);
+           krb5_free_principal(context, p);
+           if(ret){
+               if (ret == HDB_ERR_NOENTRY)
+                   ret = KRB5KDC_ERR_S_PRINCIPAL_UNKNOWN;
+               goto out;
+           }
+           ret = hdb_enctype2key(context, uu, t->enc_part.etype, &uukey);
+           if(ret){
+               ret = KRB5KDC_ERR_ETYPE_NOSUPP; /* XXX */
+               goto out;
+           }
+           ret = krb5_decrypt_ticket(context, t, &uukey->key, &adtkt, 0);
+
+           if(ret)
+               goto out;
+           s = &adtkt.cname;
+           r = adtkt.crealm;
+       }
+
+       _krb5_principalname2krb5_principal(&sp, *s, r);
+       ret = krb5_unparse_name(context, sp, &spn);     
+       if (ret)
+           goto out;
+       _krb5_principalname2krb5_principal(&cp, tgt->cname, tgt->crealm);
+       ret = krb5_unparse_name(context, cp, &cpn);
+       if (ret)
+           goto out;
+       unparse_flags (KDCOptions2int(b->kdc_options),
+                      asn1_KDCOptions_units(),
+                      opt_str, sizeof(opt_str));
+       if(*opt_str)
+           kdc_log(context, config, 0,
+                   "TGS-REQ %s from %s for %s [%s]", 
+                   cpn, from, spn, opt_str);
+       else
+           kdc_log(context, config, 0,
+                   "TGS-REQ %s from %s for %s", cpn, from, spn);
+    server_lookup:
+       ret = _kdc_db_fetch(context, config, sp, HDB_ENT_TYPE_SERVER, &server);
+
+       if(ret){
+           const char *new_rlm;
+           Realm req_rlm;
+           krb5_realm *realms;
+
+           if ((req_rlm = get_krbtgt_realm(&sp->name)) != NULL) {
+               if(nloop++ < 2) {
+                   new_rlm = find_rpath(context, tgt->crealm, req_rlm);
+                   if(new_rlm) {
+                       kdc_log(context, config, 5, "krbtgt for realm %s not found, trying %s", 
+                               req_rlm, new_rlm);
+                       krb5_free_principal(context, sp);
+                       free(spn);
+                       krb5_make_principal(context, &sp, r, 
+                                           KRB5_TGS_NAME, new_rlm, NULL);
+                       ret = krb5_unparse_name(context, sp, &spn);     
+                       if (ret)
+                           goto out;
+                       goto server_lookup;
+                   }
+               }
+           } else if(need_referral(context, sp, &realms)) {
+               if (strcmp(realms[0], sp->realm) != 0) {
+                   kdc_log(context, config, 5,
+                           "Returning a referral to realm %s for "
+                           "server %s that was not found",
+                           realms[0], spn);
+                   krb5_free_principal(context, sp);
+                   free(spn);
+                   krb5_make_principal(context, &sp, r, KRB5_TGS_NAME,
+                                       realms[0], NULL);
+                   ret = krb5_unparse_name(context, sp, &spn);
+                   if (ret)
+                       goto out;
+                   krb5_free_host_realm(context, realms);
+                   goto server_lookup;
+               }
+               krb5_free_host_realm(context, realms);
+           }
+           kdc_log(context, config, 0,
+                   "Server not found in database: %s: %s", spn,
+                   krb5_get_err_text(context, ret));
+           if (ret == HDB_ERR_NOENTRY)
+               ret = KRB5KDC_ERR_S_PRINCIPAL_UNKNOWN;
+           goto out;
+       }
+
+       ret = _kdc_db_fetch(context, config, cp, HDB_ENT_TYPE_CLIENT, &client);
+       if(ret)
+           kdc_log(context, config, 1, "Client not found in database: %s: %s",
+                   cpn, krb5_get_err_text(context, ret));
+#if 0
+       /* XXX check client only if same realm as krbtgt-instance */
+       if(ret){
+           kdc_log(context, config, 0,
+                   "Client not found in database: %s: %s",
+                   cpn, krb5_get_err_text(context, ret));
+           if (ret == HDB_ERR_NOENTRY)
+               ret = KRB5KDC_ERR_C_PRINCIPAL_UNKNOWN;
+           goto out;
+       }
+#endif
+
+       if(strcmp(krb5_principal_get_realm(context, sp),
+                 krb5_principal_get_comp_string(context, krbtgt->principal, 1)) != 0) {
+           char *tpn;
+           ret = krb5_unparse_name(context, krbtgt->principal, &tpn);
+           kdc_log(context, config, 0,
+                   "Request with wrong krbtgt: %s",
+                   (ret == 0) ? tpn : "<unknown>");
+           if(ret == 0)
+               free(tpn);
+           ret = KRB5KRB_AP_ERR_NOT_US;
+           goto out;
+           
+       }
+
+       ret = _kdc_check_flags(context, config, 
+                              client, cpn,
+                              server, spn,
+                              FALSE);
+       if(ret)
+           goto out;
+
+       if((b->kdc_options.validate || b->kdc_options.renew) && 
+          !krb5_principal_compare(context, 
+                                  krbtgt->principal,
+                                  server->principal)){
+           kdc_log(context, config, 0, "Inconsistent request.");
+           ret = KRB5KDC_ERR_SERVER_NOMATCH;
+           goto out;
+       }
+
+       /* check for valid set of addresses */
+       if(!check_addresses(context, config, tgt->caddr, from_addr)) {
+           ret = KRB5KRB_AP_ERR_BADADDR;
+           kdc_log(context, config, 0, "Request from wrong address");
+           goto out;
+       }
+       
+       ret = tgs_make_reply(context, config, 
+                            b, 
+                            tgt, 
+                            b->kdc_options.enc_tkt_in_skey ? &adtkt : NULL, 
+                            auth_data,
+                            server, 
+                            client, 
+                            cp, 
+                            krbtgt, 
+                            &tkey->key,
+                            cetype, 
+                            &e_text,
+                            reply);
+       
+    out:
+       free(spn);
+       free(cpn);
+           
+       if(server)
+           _kdc_free_ent(context, server);
+       if(client)
+           _kdc_free_ent(context, client);
+    }
+ out2:
+    if(ret) {
+       krb5_mk_error(context,
+                     ret,
+                     e_text,
+                     NULL,
+                     cp,
+                     sp,
+                     NULL,
+                     NULL,
+                     reply);
+       free(*csec);
+       free(*cusec);
+       *csec  = NULL;
+       *cusec = NULL;
+    }
+    krb5_free_principal(context, cp);
+    krb5_free_principal(context, sp);
+    if (ticket)
+       krb5_free_ticket(context, ticket);
+    free_AP_REQ(&ap_req);
+    if(auth_data){
+       free_AuthorizationData(auth_data);
+       free(auth_data);
+    }
+
+    if(krbtgt)
+       _kdc_free_ent(context, krbtgt);
+
+    return ret;
+}
+
+
+krb5_error_code
+_kdc_tgs_rep(krb5_context context, 
+            krb5_kdc_configuration *config,
+            KDC_REQ *req, 
+            krb5_data *data,
+            const char *from,
+            struct sockaddr *from_addr)
+{
+    krb5_error_code ret;
+    int i = 0;
+    PA_DATA *tgs_req = NULL;
+    time_t *csec = NULL;
+    int *cusec = NULL;
+
+    if(req->padata == NULL){
+       ret = KRB5KDC_ERR_PREAUTH_REQUIRED; /* XXX ??? */
+       kdc_log(context, config, 0,
+               "TGS-REQ from %s without PA-DATA", from);
+       goto out;
+    }
+    
+    tgs_req = find_padata(req, &i, KRB5_PADATA_TGS_REQ);
+
+    if(tgs_req == NULL){
+       ret = KRB5KDC_ERR_PADATA_TYPE_NOSUPP;
+       
+       kdc_log(context, config, 0, 
+               "TGS-REQ from %s without PA-TGS-REQ", from);
+       goto out;
+    }
+    ret = tgs_rep2(context, config, 
+                  &req->req_body, tgs_req, data, from, from_addr,
+                  &csec, &cusec);
+out:
+    if(ret && data->data == NULL){
+       krb5_mk_error(context,
+                     ret,
+                     NULL,
+                     NULL,
+                     NULL,
+                     NULL,
+                     csec,
+                     cusec,
+                     data);
+    }
+    free(csec);
+    free(cusec);
+    return 0;
+}
diff --git a/source4/heimdal/kdc/log.c b/source4/heimdal/kdc/log.c
new file mode 100644 (file)
index 0000000..c316b0c
--- /dev/null
@@ -0,0 +1,89 @@
+/*
+ * Copyright (c) 1997, 1998, 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 "kdc_locl.h"
+RCSID("$Id: log.c,v 1.16 2005/06/30 01:52:48 lha Exp $");
+
+void
+kdc_openlog(krb5_context context, 
+           krb5_kdc_configuration *config)
+{
+    char **s = NULL, **p;
+    krb5_initlog(context, "kdc", &config->logf);
+    s = krb5_config_get_strings(context, NULL, "kdc", "logging", NULL);
+    if(s == NULL)
+       s = krb5_config_get_strings(context, NULL, "logging", "kdc", NULL);
+    if(s){
+       for(p = s; *p; p++)
+           krb5_addlog_dest(context, config->logf, *p);
+       krb5_config_free_strings(s);
+    }else
+       krb5_addlog_dest(context, config->logf, DEFAULT_LOG_DEST);
+    krb5_set_warn_dest(context, config->logf);
+}
+
+char*
+kdc_log_msg_va(krb5_context context, 
+              krb5_kdc_configuration *config,
+              int level, const char *fmt, va_list ap)
+{
+    char *msg;
+    krb5_vlog_msg(context, config->logf, &msg, level, fmt, ap);
+    return msg;
+}
+
+char*
+kdc_log_msg(krb5_context context, 
+           krb5_kdc_configuration *config,
+           int level, const char *fmt, ...)
+{
+    va_list ap;
+    char *s;
+    va_start(ap, fmt);
+    s = kdc_log_msg_va(context, config, level, fmt, ap);
+    va_end(ap);
+    return s;
+}
+
+void
+kdc_log(krb5_context context, 
+       krb5_kdc_configuration *config,
+       int level, const char *fmt, ...)
+{
+    va_list ap;
+    char *s;
+    va_start(ap, fmt);
+    s = kdc_log_msg_va(context, config, level, fmt, ap);
+    if(s) free(s);
+    va_end(ap);
+}
diff --git a/source4/heimdal/kdc/misc.c b/source4/heimdal/kdc/misc.c
new file mode 100644 (file)
index 0000000..5a25160
--- /dev/null
@@ -0,0 +1,84 @@
+/*
+ * 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 "kdc_locl.h"
+
+RCSID("$Id: misc.c,v 1.25 2005/06/30 01:53:48 lha Exp $");
+
+struct timeval _kdc_now;
+
+krb5_error_code
+_kdc_db_fetch(krb5_context context,
+             krb5_kdc_configuration *config,
+             krb5_principal principal, enum hdb_ent_type ent_type, 
+             hdb_entry **h)
+{
+    hdb_entry *ent;
+    krb5_error_code ret = HDB_ERR_NOENTRY;
+    int i;
+
+    ent = malloc (sizeof (*ent));
+    if (ent == NULL)
+       return ENOMEM;
+    ent->principal = principal;
+
+    for(i = 0; i < config->num_db; i++) {
+       ret = config->db[i]->hdb_open(context, config->db[i], O_RDONLY, 0);
+       if (ret) {
+           kdc_log(context, config, 0, "Failed to open database: %s", 
+                   krb5_get_err_text(context, ret));
+           continue;
+       }
+       ret = config->db[i]->hdb_fetch(context, 
+                                      config->db[i],
+                                      HDB_F_DECRYPT, 
+                                      principal, 
+                                      ent_type,
+                                      ent);
+       config->db[i]->hdb_close(context, config->db[i]);
+       if(ret == 0) {
+           *h = ent;
+           return 0;
+       }
+    }
+    free(ent);
+    return ret;
+}
+
+void
+_kdc_free_ent(krb5_context context, hdb_entry *ent)
+{
+    hdb_free_entry (context, ent);
+    free (ent);
+}
+
diff --git a/source4/heimdal/kdc/pkinit.c b/source4/heimdal/kdc/pkinit.c
new file mode 100755 (executable)
index 0000000..d83e1d3
--- /dev/null
@@ -0,0 +1,1607 @@
+/*
+ * 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 "kdc_locl.h"
+
+RCSID("$Id: pkinit.c,v 1.36 2005/07/01 15:37:24 lha Exp $");
+
+#ifdef PKINIT
+
+#include <heim_asn1.h>
+#include <rfc2459_asn1.h>
+#include <cms_asn1.h>
+#include <pkinit_asn1.h>
+
+#include <openssl/evp.h>
+#include <openssl/x509.h>
+#include <openssl/x509v3.h>
+#include <openssl/bn.h>
+#include <openssl/asn1.h>
+#include <openssl/err.h>
+
+/* XXX copied from lib/krb5/pkinit.c */
+struct krb5_pk_identity {
+    EVP_PKEY *private_key;
+    STACK_OF(X509) *cert;
+    STACK_OF(X509) *trusted_certs;
+    STACK_OF(X509_CRL) *crls;
+    ENGINE *engine;
+};
+
+/* XXX copied from lib/krb5/pkinit.c */
+struct krb5_pk_cert {
+    X509 *cert;
+};
+
+enum pkinit_type {
+    PKINIT_COMPAT_WIN2K = 1,
+    PKINIT_COMPAT_19 = 2,
+    PKINIT_COMPAT_25 = 3
+};
+
+struct pk_client_params {
+    enum pkinit_type type;
+    BIGNUM *dh_public_key;
+    struct krb5_pk_cert *certificate;
+    unsigned nonce;
+    DH *dh;
+    EncryptionKey reply_key;
+};
+
+struct pk_principal_mapping {
+    unsigned int len;
+    struct pk_allowed_princ {
+       krb5_principal principal;
+       char *subject;
+    } *val;
+};
+
+/* XXX copied from lib/krb5/pkinit.c */
+#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;                                         \
+        }                                                              \
+    }                                                                  \
+  }                                                                    \
+}
+
+static struct krb5_pk_identity *kdc_identity;
+static struct pk_principal_mapping principal_mappings;
+
+/*
+ *
+ */
+
+static krb5_error_code
+pk_check_pkauthenticator_win2k(krb5_context context,
+                              PKAuthenticator_Win2k *a,
+                              KDC_REQ *req)
+{
+    krb5_timestamp now;
+
+    krb5_timeofday (context, &now);
+
+    /* XXX cusec */
+    if (a->ctime == 0 || abs(a->ctime - now) > context->max_skew) {
+       krb5_clear_error_string(context);
+       return KRB5KRB_AP_ERR_SKEW;
+    }
+    return 0;
+}
+
+static krb5_error_code
+pk_check_pkauthenticator_19(krb5_context context,
+                           PKAuthenticator_19 *a,
+                           KDC_REQ *req)
+{
+    u_char *buf = NULL;
+    size_t buf_size;
+    krb5_error_code ret;
+    size_t len;
+    krb5_timestamp now;
+
+    krb5_timeofday (context, &now);
+
+    /* XXX cusec */
+    if (a->ctime == 0 || abs(a->ctime - now) > context->max_skew) {
+       krb5_clear_error_string(context);
+       return KRB5KRB_AP_ERR_SKEW;
+    }
+
+    if (a->paChecksum.cksumtype != CKSUMTYPE_RSA_MD5 &&
+       a->paChecksum.cksumtype != CKSUMTYPE_SHA1)
+    {
+       krb5_clear_error_string(context);
+       ret = KRB5KRB_ERR_GENERIC;
+    }
+
+    ASN1_MALLOC_ENCODE(KDC_REQ_BODY, buf, buf_size, &req->req_body, &len, ret);
+    if (ret) {
+       krb5_clear_error_string(context);
+       return ret;
+    }
+    if (buf_size != len)
+       krb5_abortx(context, "Internal error in ASN.1 encoder");
+
+    ret = krb5_verify_checksum(context, NULL, 0, buf, len,
+                              &a->paChecksum);
+    if (ret)
+       krb5_clear_error_string(context);
+
+    free(buf);
+    return ret;
+}
+
+static krb5_error_code
+pk_check_pkauthenticator(krb5_context context,
+                        PKAuthenticator *a,
+                        KDC_REQ *req)
+{
+    u_char *buf = NULL;
+    size_t buf_size;
+    krb5_error_code ret;
+    size_t len;
+    krb5_timestamp now;
+    Checksum checksum;
+
+    krb5_timeofday (context, &now);
+
+    /* XXX cusec */
+    if (a->ctime == 0 || abs(a->ctime - now) > context->max_skew) {
+       krb5_clear_error_string(context);
+       return KRB5KRB_AP_ERR_SKEW;
+    }
+
+    ASN1_MALLOC_ENCODE(KDC_REQ_BODY, buf, buf_size, &req->req_body, &len, ret);
+    if (ret) {
+       krb5_clear_error_string(context);
+       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) {
+       krb5_clear_error_string(context);
+       return ret;
+    }
+       
+    if (a->paChecksum.length != checksum.checksum.length ||
+       memcmp(a->paChecksum.data, checksum.checksum.data, 
+              checksum.checksum.length) != 0)
+    {
+       krb5_clear_error_string(context);
+       ret = KRB5KRB_ERR_GENERIC;
+    }
+    free_Checksum(&checksum);
+
+    return ret;
+}
+
+static krb5_error_code
+pk_encrypt_key(krb5_context context,
+              krb5_keyblock *key,
+               EVP_PKEY *public_key,
+              krb5_data *encrypted_key,
+              const heim_oid **oid)
+{
+    krb5_error_code ret;
+
+    encrypted_key->length = EVP_PKEY_size(public_key);
+
+    if (encrypted_key->length < key->keyvalue.length + 11) { /* XXX */
+       krb5_set_error_string(context, "pkinit: encrypted key too long");
+       return KRB5KRB_ERR_GENERIC;
+    }
+
+    encrypted_key->data = malloc(encrypted_key->length);
+    if (encrypted_key->data == NULL) {
+       krb5_set_error_string(context, "malloc: out of memory");
+       return ENOMEM;
+    }
+
+    ret = EVP_PKEY_encrypt(encrypted_key->data, 
+                          key->keyvalue.data,
+                          key->keyvalue.length,
+                          public_key);
+    if (ret < 0) {
+       free(encrypted_key->data);
+       krb5_set_error_string(context, "Can't encrypt key: %s",
+                             ERR_error_string(ERR_get_error(), NULL));
+       return KRB5KRB_ERR_GENERIC;
+    }
+    if (encrypted_key->length != ret)
+       krb5_abortx(context, "size of EVP_PKEY_size is not the "
+                   "size of the output");
+
+    *oid = oid_id_pkcs1_rsaEncryption();
+
+    return 0;
+}
+
+void
+_kdc_pk_free_client_param(krb5_context context, 
+                         pk_client_params *client_params)
+{
+    if (client_params->certificate)
+       _krb5_pk_cert_free(client_params->certificate);
+    if (client_params->dh)
+       DH_free(client_params->dh);
+    if (client_params->dh_public_key)
+       BN_free(client_params->dh_public_key);
+    krb5_free_keyblock_contents(context, &client_params->reply_key);
+    memset(client_params, 0, sizeof(*client_params));
+    free(client_params);
+}
+
+static krb5_error_code
+check_dh_params(DH *dh)
+{
+    /* XXX check the DH parameters come from 1st or 2nd Oeakley Group */
+    return 0;
+}
+
+static krb5_error_code
+generate_dh_keyblock(krb5_context context, pk_client_params *client_params,
+                     krb5_enctype enctype, krb5_keyblock *reply_key)
+{
+    unsigned char *dh_gen_key = NULL;
+    krb5_keyblock key;
+    int dh_gen_keylen;
+    krb5_error_code ret;
+
+    memset(&key, 0, sizeof(key));
+
+    dh_gen_key = malloc(DH_size(client_params->dh));
+    if (dh_gen_key == NULL) {
+       krb5_set_error_string(context, "malloc: out of memory");
+       ret = ENOMEM;
+       goto out;
+    }
+
+    if (!DH_generate_key(client_params->dh)) {
+       krb5_set_error_string(context, "Can't generate Diffie-Hellman "
+                             "keys (%s)",
+                             ERR_error_string(ERR_get_error(), NULL));
+       ret = KRB5KRB_ERR_GENERIC;
+       goto out;
+    }
+    if (client_params->dh_public_key == NULL) {
+       krb5_set_error_string(context, "dh_public_key");
+       ret = KRB5KRB_ERR_GENERIC;
+       goto out;
+    }
+
+    dh_gen_keylen = DH_compute_key(dh_gen_key, 
+                                  client_params->dh_public_key,
+                                  client_params->dh);
+    if (dh_gen_keylen == -1) {
+       krb5_set_error_string(context, "Can't compute Diffie-Hellman key (%s)",
+                             ERR_error_string(ERR_get_error(), NULL));
+       ret = KRB5KRB_ERR_GENERIC;
+       goto out;
+    }
+
+    ret = krb5_random_to_key(context, enctype, 
+                            dh_gen_key, dh_gen_keylen, &key);
+
+    if (ret) {
+       krb5_set_error_string(context, 
+                             "pkinit - can't create key from DH key");
+       ret = KRB5KRB_ERR_GENERIC;
+       goto out;
+    }
+    ret = krb5_copy_keyblock_contents(context, &key, reply_key);
+
+ out:
+    if (dh_gen_key)
+       free(dh_gen_key);
+    if (key.keyvalue.data)
+       krb5_free_keyblock_contents(context, &key);
+
+    return ret;
+}
+
+static BIGNUM *
+integer_to_BN(krb5_context context, const char *field, heim_integer *f)
+{
+    BIGNUM *bn;
+
+    bn = BN_bin2bn((const unsigned char *)f->data, f->length, NULL);
+    if (bn == NULL) {
+       krb5_set_error_string(context, "PKINIT: parsing BN failed %s", field);
+       return NULL;
+    }
+    bn->neg = f->negative;
+    return bn;
+}
+
+static krb5_error_code
+get_dh_param(krb5_context context, SubjectPublicKeyInfo *dh_key_info,
+            pk_client_params *client_params)
+{
+    DomainParameters dhparam;
+    DH *dh = NULL;
+    krb5_error_code ret;
+    int dhret;
+
+    memset(&dhparam, 0, sizeof(dhparam));
+
+    if (heim_oid_cmp(&dh_key_info->algorithm.algorithm, oid_id_dhpublicnumber())) {
+       krb5_set_error_string(context,
+                             "PKINIT invalid oid in clientPublicValue");
+       return KRB5_BADMSGTYPE;
+    }
+
+    if (dh_key_info->algorithm.parameters == NULL) {
+       krb5_set_error_string(context, "PKINIT missing algorithm parameter "
+                             "in clientPublicValue");
+       return KRB5_BADMSGTYPE;
+    }
+
+    ret = decode_DomainParameters(dh_key_info->algorithm.parameters->data,
+                                 dh_key_info->algorithm.parameters->length,
+                                 &dhparam,
+                                 NULL);
+    if (ret) {
+       krb5_set_error_string(context, "Can't decode algorithm "
+                             "parameters in clientPublicValue");
+       goto out;
+    }
+
+    dh = DH_new();
+    if (dh == NULL) {
+       krb5_set_error_string(context, "Cannot create DH structure (%s)",
+                             ERR_error_string(ERR_get_error(), NULL));
+       ret = ENOMEM;
+       goto out;
+    }
+    ret = KRB5_BADMSGTYPE;
+    dh->p = integer_to_BN(context, "DH prime", &dhparam.p);
+    if (dh->p == NULL)
+       goto out;
+    dh->g = integer_to_BN(context, "DH base", &dhparam.g);
+    if (dh->g == NULL)
+       goto out;
+    dh->q = integer_to_BN(context, "DH p-1 factor", &dhparam.q);
+    if (dh->g == NULL)
+       goto out;
+
+    {
+       heim_integer glue;
+       glue.data = dh_key_info->subjectPublicKey.data;
+       glue.length = dh_key_info->subjectPublicKey.length;
+
+       client_params->dh_public_key = integer_to_BN(context,
+                                                    "subjectPublicKey",
+                                                    &glue);
+       if (client_params->dh_public_key == NULL) {
+           krb5_clear_error_string(context);
+           goto out;
+       }
+    }
+
+    if (DH_check(dh, &dhret) != 1) {
+       krb5_set_error_string(context, "PKINIT DH data not ok: %s",
+                             ERR_error_string(ERR_get_error(), NULL));
+       ret = KRB5_KDC_ERR_KEY_SIZE;
+       goto out;
+    }
+
+    client_params->dh = dh;
+    dh = NULL;
+    ret = 0;
+    
+ out:
+    if (dh)
+       DH_free(dh);
+    free_DomainParameters(&dhparam);
+    return ret;
+}
+
+#if 0
+/* 
+ * XXX We only need this function if there are several certs for the
+ * KDC to choose from, and right now, we can't handle that so punt for
+ * now.
+ *
+ * If client has sent a list of CA's trusted by him, make sure our
+ * CA is in the list.
+ *
+ */
+
+static void
+verify_trusted_ca(PA_PK_AS_REQ_19 *r)
+{
+
+    if (r.trustedCertifiers != NULL) {
+       X509_NAME *kdc_issuer;
+       X509 *kdc_cert;
+
+       kdc_cert = sk_X509_value(kdc_identity->cert, 0);
+       kdc_issuer = X509_get_issuer_name(kdc_cert);
+     
+       /* XXX will work for heirarchical CA's ? */
+       /* XXX also serial_number should be compared */
+
+       ret = KRB5_KDC_ERR_KDC_NOT_TRUSTED;
+       for (i = 0; i < r.trustedCertifiers->len; i++) {
+           TrustedCA_19 *ca = &r.trustedCertifiers->val[i];
+
+           switch (ca->element) {
+           case choice_TrustedCA_19_caName: {
+               X509_NAME *name;
+               unsigned char *p;
+
+               p = ca->u.caName.data;
+               name = d2i_X509_NAME(NULL, &p, ca->u.caName.length);
+               if (name == NULL) /* XXX should this be a failure instead ? */
+                   break;
+               if (X509_NAME_cmp(name, kdc_issuer) == 0)
+                   ret = 0;
+               X509_NAME_free(name);
+               break;
+           }
+           case choice_TrustedCA_19_issuerAndSerial:
+               /* IssuerAndSerialNumber issuerAndSerial */
+               break;
+           default:
+               break;
+           }
+           if (ret == 0)
+               break;
+       }
+       if (ret)
+           goto out;
+    }
+}
+#endif /* 0 */
+
+krb5_error_code
+_kdc_pk_rd_padata(krb5_context context,
+                 krb5_kdc_configuration *config,
+                 KDC_REQ *req,
+                 PA_DATA *pa,
+                 pk_client_params **ret_params)
+{
+    pk_client_params *client_params;
+    krb5_error_code ret;
+    heim_oid eContentType = { 0, NULL };
+    krb5_data eContent = { 0, NULL };
+    krb5_data signed_content = { 0, NULL };
+    const char *type = "unknown type";
+    const heim_oid *pa_contentType;
+
+    *ret_params = NULL;
+    
+    if (!config->enable_pkinit) {
+       krb5_clear_error_string(context);
+       return 0;
+    }
+
+    client_params = malloc(sizeof(*client_params));
+    if (client_params == NULL) {
+       krb5_clear_error_string(context);
+       ret = ENOMEM;
+       goto out;
+    }
+    memset(client_params, 0, sizeof(*client_params));
+
+    if (pa->padata_type == KRB5_PADATA_PK_AS_REQ_WIN) {
+       PA_PK_AS_REQ_Win2k r;
+       ContentInfo info;
+
+       type = "PK-INIT-Win2k";
+       pa_contentType = oid_id_pkcs7_data();
+
+       ret = decode_PA_PK_AS_REQ_Win2k(pa->padata_value.data,
+                                       pa->padata_value.length,
+                                       &r,
+                                       NULL);
+       if (ret) {
+           krb5_set_error_string(context, "Can't decode "
+                                 "PK-AS-REQ-Win2k: %d", ret);
+           goto out;
+       }
+       
+       ret = decode_ContentInfo(r.signed_auth_pack.data,
+                                r.signed_auth_pack.length, &info, NULL);
+       free_PA_PK_AS_REQ_Win2k(&r);
+       if (ret) {
+           krb5_set_error_string(context, "Can't decode PK-AS-REQ: %d", ret);
+           goto out;
+       }
+
+       if (heim_oid_cmp(&info.contentType, oid_id_pkcs7_signedData())) {
+           krb5_set_error_string(context, "PK-AS-REQ-Win2k invalid content "
+                                 "type oid");
+           free_ContentInfo(&info);
+           ret = KRB5KRB_ERR_GENERIC;
+           goto out;
+       }
+       
+       if (info.content == NULL) {
+           krb5_set_error_string(context,
+                                 "PK-AS-REQ-Win2k no signed auth pack");
+           free_ContentInfo(&info);
+           ret = KRB5KRB_ERR_GENERIC;
+           goto out;
+       }
+
+       signed_content.data = malloc(info.content->length);
+       if (signed_content.data == NULL) {
+           ret = ENOMEM;
+           free_ContentInfo(&info);
+           krb5_set_error_string(context, "PK-AS-REQ-Win2k out of memory");
+           goto out;
+       }
+       signed_content.length = info.content->length;
+       memcpy(signed_content.data, info.content->data, signed_content.length);
+
+       free_ContentInfo(&info);
+
+    } else if (pa->padata_type == KRB5_PADATA_PK_AS_REQ_19) {
+       PA_PK_AS_REQ_19 r;
+
+       type = "PK-INIT-19";
+       pa_contentType = oid_id_pkauthdata();
+
+       ret = decode_PA_PK_AS_REQ_19(pa->padata_value.data,
+                                    pa->padata_value.length,
+                                    &r,
+                                    NULL);
+       if (ret) {
+           krb5_set_error_string(context, "Can't decode "
+                                 "PK-AS-REQ-19: %d", ret);
+           goto out;
+       }
+       
+       if (heim_oid_cmp(&r.signedAuthPack.contentType, 
+                        oid_id_pkcs7_signedData()))
+       {
+           krb5_set_error_string(context, "PK-AS-REQ-19 invalid content "
+                                 "type oid");
+           free_PA_PK_AS_REQ_19(&r);
+           ret = KRB5KRB_ERR_GENERIC;
+           goto out;
+       }
+       
+       if (r.signedAuthPack.content == NULL) {
+           krb5_set_error_string(context, "PK-AS-REQ-19 no signed auth pack");
+           free_PA_PK_AS_REQ_19(&r);
+           ret = KRB5KRB_ERR_GENERIC;
+           goto out;
+       }
+
+       signed_content.data = malloc(r.signedAuthPack.content->length);
+       if (signed_content.data == NULL) {
+           ret = ENOMEM;
+           free_PA_PK_AS_REQ_19(&r);
+           krb5_set_error_string(context, "PK-AS-REQ-19 out of memory");
+           goto out;
+       }
+       signed_content.length = r.signedAuthPack.content->length;
+       memcpy(signed_content.data, r.signedAuthPack.content->data,
+              signed_content.length);
+
+       free_PA_PK_AS_REQ_19(&r);
+    } else if (pa->padata_type == KRB5_PADATA_PK_AS_REQ) {
+       PA_PK_AS_REQ r;
+       ContentInfo info;
+
+       type = "PK-INIT-25";
+       pa_contentType = oid_id_pkauthdata();
+
+       ret = decode_PA_PK_AS_REQ(pa->padata_value.data,
+                                 pa->padata_value.length,
+                                 &r,
+                                 NULL);
+       if (ret) {
+           krb5_set_error_string(context, "Can't decode PK-AS-REQ: %d", ret);
+           goto out;
+       }
+       
+       ret = decode_ContentInfo(r.signedAuthPack.data,
+                                r.signedAuthPack.length, &info, NULL);
+       if (ret) {
+           krb5_set_error_string(context, "Can't decode PK-AS-REQ: %d", ret);
+           goto out;
+       }
+
+       if (heim_oid_cmp(&info.contentType, oid_id_pkcs7_signedData())) {
+           krb5_set_error_string(context, "PK-AS-REQ invalid content "
+                                 "type oid");
+           free_ContentInfo(&info);
+           free_PA_PK_AS_REQ(&r);
+           ret = KRB5KRB_ERR_GENERIC;
+           goto out;
+       }
+       
+       if (info.content == NULL) {
+           krb5_set_error_string(context, "PK-AS-REQ no signed auth pack");
+           free_PA_PK_AS_REQ(&r);
+           free_ContentInfo(&info);
+           ret = KRB5KRB_ERR_GENERIC;
+           goto out;
+       }
+
+       signed_content.data = malloc(info.content->length);
+       if (signed_content.data == NULL) {
+           ret = ENOMEM;
+           free_ContentInfo(&info);
+           free_PA_PK_AS_REQ(&r);
+           krb5_set_error_string(context, "PK-AS-REQ out of memory");
+           goto out;
+       }
+       signed_content.length = info.content->length;
+       memcpy(signed_content.data, info.content->data, signed_content.length);
+
+       free_ContentInfo(&info);
+       free_PA_PK_AS_REQ(&r);
+
+    } else { 
+       krb5_clear_error_string(context);
+       ret = KRB5KDC_ERR_PADATA_TYPE_NOSUPP;
+       goto out;
+    }
+
+    ret = _krb5_pk_verify_sign(context,
+                              signed_content.data,
+                              signed_content.length,
+                              kdc_identity,
+                              &eContentType,
+                              &eContent,
+                              &client_params->certificate);
+    if (ret)
+       goto out;
+
+    /* Signature is correct, now verify the signed message */
+    if (heim_oid_cmp(&eContentType, pa_contentType)) {
+       krb5_set_error_string(context, "got wrong oid for pkauthdata");
+       ret = KRB5_BADMSGTYPE;
+       goto out;
+    }
+
+    if (pa->padata_type == KRB5_PADATA_PK_AS_REQ_WIN) {
+       AuthPack_Win2k ap;
+
+       ret = decode_AuthPack_Win2k(eContent.data,
+                                   eContent.length,
+                                   &ap,
+                                   NULL);
+       if (ret) {
+           krb5_set_error_string(context, "can't decode AuthPack: %d", ret);
+           goto out;
+       }
+  
+       ret = pk_check_pkauthenticator_win2k(context, 
+                                            &ap.pkAuthenticator,
+                                            req);
+       if (ret) {
+           free_AuthPack_Win2k(&ap);
+           goto out;
+       }
+
+       client_params->type = PKINIT_COMPAT_WIN2K;
+       client_params->nonce = ap.pkAuthenticator.nonce;
+
+       if (ap.clientPublicValue) {
+           krb5_set_error_string(context, "DH not supported for windows");
+           ret = KRB5KRB_ERR_GENERIC;
+           goto out;
+       }
+       free_AuthPack_Win2k(&ap);
+
+    } else if (pa->padata_type == KRB5_PADATA_PK_AS_REQ_19) {
+       AuthPack_19 ap;
+
+       ret = decode_AuthPack_19(eContent.data,
+                                eContent.length,
+                                &ap,
+                                NULL);
+       if (ret) {
+           krb5_set_error_string(context, "can't decode AuthPack: %d", ret);
+           free_AuthPack_19(&ap);
+           goto out;
+       }
+  
+       ret = pk_check_pkauthenticator_19(context, 
+                                         &ap.pkAuthenticator,
+                                         req);
+       if (ret) {
+           free_AuthPack_19(&ap);
+           goto out;
+       }
+
+       client_params->type = PKINIT_COMPAT_19;
+       client_params->nonce = ap.pkAuthenticator.nonce;
+
+       if (ap.clientPublicValue) {
+           ret = get_dh_param(context, ap.clientPublicValue, client_params);
+           if (ret) {
+               free_AuthPack_19(&ap);
+               goto out;
+           }
+       }
+       free_AuthPack_19(&ap);
+    } else if (pa->padata_type == KRB5_PADATA_PK_AS_REQ) {
+       AuthPack ap;
+
+       ret = decode_AuthPack(eContent.data,
+                             eContent.length,
+                             &ap,
+                             NULL);
+       if (ret) {
+           krb5_set_error_string(context, "can't decode AuthPack: %d", ret);
+           free_AuthPack(&ap);
+           goto out;
+       }
+  
+       ret = pk_check_pkauthenticator(context, 
+                                      &ap.pkAuthenticator,
+                                      req);
+       if (ret) {
+           free_AuthPack(&ap);
+           goto out;
+       }
+
+       client_params->type = PKINIT_COMPAT_25;
+       client_params->nonce = ap.pkAuthenticator.nonce;
+
+       if (ap.clientPublicValue) {
+           krb5_set_error_string(context, "PK-INIT, no support for DH");
+           ret = KRB5KDC_ERR_PADATA_TYPE_NOSUPP;
+           free_AuthPack(&ap);
+           goto out;
+       }
+       free_AuthPack(&ap);
+    } else
+       krb5_abortx(context, "internal pkinit error");
+
+    /* 
+     * Remaining fields (ie kdcCert and encryptionCert) in the request
+     * are ignored for now.
+     */
+
+    kdc_log(context, config, 0, "PK-INIT request of type %s", type);
+
+ out:
+
+    if (signed_content.data)
+       free(signed_content.data);
+    krb5_data_free(&eContent);
+    free_oid(&eContentType);
+    if (ret)
+       _kdc_pk_free_client_param(context, client_params);
+    else
+       *ret_params = client_params;
+    return ret;
+}
+
+/*
+ *
+ */
+
+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;
+}
+
+static krb5_error_code
+pk_mk_pa_reply_enckey(krb5_context context,
+                     pk_client_params *client_params,
+                     const KDC_REQ *req,
+                     krb5_keyblock *reply_key,
+                     ContentInfo *content_info)
+{
+    KeyTransRecipientInfo *ri;
+    EnvelopedData ed;
+    krb5_error_code ret;
+    krb5_crypto crypto = NULL;
+    krb5_data buf, sd_data, enc_sd_data, iv, params;
+    krb5_keyblock tmp_key;
+    krb5_enctype enveloped_enctype;
+    X509_NAME *issuer_name;
+    heim_integer *serial;
+    size_t size;
+    AlgorithmIdentifier *enc_alg;
+    int i;
+
+    krb5_data_zero(&enc_sd_data);
+    krb5_data_zero(&sd_data);
+    krb5_data_zero(&iv);
+
+    memset(&tmp_key, 0, sizeof(tmp_key));
+    memset(&ed, 0, sizeof(ed));
+
+    /* default to DES3 if client doesn't tell us */
+    enveloped_enctype = ETYPE_DES3_CBC_NONE_CMS;
+
+    for (i = 0; i < req->req_body.etype.len; i++) {
+       switch(req->req_body.etype.val[i]) {
+       case 15: /* des-ede3-cbc-Env-OID */
+           enveloped_enctype = ETYPE_DES3_CBC_NONE_CMS;
+           break;
+       default:
+           break;
+       }
+    }
+
+    ret = krb5_generate_random_keyblock(context, enveloped_enctype, &tmp_key);
+    if (ret)
+       goto out;
+
+    ret = krb5_crypto_init(context, &tmp_key, 0, &crypto);
+    if (ret)
+       goto out;
+
+
+    ret = krb5_crypto_getblocksize(context, crypto, &iv.length);
+    if (ret)
+       goto out;
+
+    ret = krb5_data_alloc(&iv, iv.length);
+    if (ret) {
+       krb5_set_error_string(context, "malloc out of memory");
+       goto out;
+    }
+
+    krb5_generate_random_block(iv.data, iv.length);
+
+    enc_alg = &ed.encryptedContentInfo.contentEncryptionAlgorithm;
+
+    ret = krb5_enctype_to_oid(context, enveloped_enctype, &enc_alg->algorithm);
+    if (ret)
+       goto out;
+
+    ret = krb5_crypto_set_params(context, crypto, &iv, &params);
+    if (ret)
+       goto out;
+
+    ALLOC(enc_alg->parameters);
+    if (enc_alg->parameters == NULL) {
+       krb5_data_free(&params);
+       krb5_set_error_string(context, "malloc out of memory");
+       return ENOMEM;
+    }
+    enc_alg->parameters->data = params.data;
+    enc_alg->parameters->length = params.length;
+
+    if (client_params->type == PKINIT_COMPAT_WIN2K || client_params->type == PKINIT_COMPAT_19 || client_params->type == PKINIT_COMPAT_25) {
+       ReplyKeyPack kp;
+       memset(&kp, 0, sizeof(kp));
+
+       ret = copy_EncryptionKey(reply_key, &kp.replyKey);
+       if (ret) {
+           krb5_clear_error_string(context);
+           goto out;
+       }
+       kp.nonce = client_params->nonce;
+       
+       ASN1_MALLOC_ENCODE(ReplyKeyPack, buf.data, buf.length, &kp, &size,ret);
+       free_ReplyKeyPack(&kp);
+    } else {
+       krb5_abortx(context, "internal pkinit error");
+    }
+    if (ret) {
+       krb5_set_error_string(context, "ASN.1 encoding of ReplyKeyPack "
+                             "failed (%d)", ret);
+       goto out;
+    }
+    if (buf.length != size)
+       krb5_abortx(context, "Internal ASN.1 encoder error");
+
+    /* 
+     * CRL's are not transfered -- should be ?
+     */
+
+    ret = _krb5_pk_create_sign(context,
+                              oid_id_pkrkeydata(),
+                              &buf,
+                              kdc_identity,
+                              &sd_data);
+    krb5_data_free(&buf);
+    if (ret) 
+       goto out;
+
+    ret = krb5_encrypt_ivec(context, crypto, 0, 
+                           sd_data.data, sd_data.length,
+                           &enc_sd_data,
+                           iv.data);
+
+    ALLOC_SEQ(&ed.recipientInfos, 1);
+    if (ed.recipientInfos.val == NULL) {
+       krb5_clear_error_string(context);
+       ret = ENOMEM;
+       goto out;
+    }
+
+    ri = &ed.recipientInfos.val[0];
+
+    ri->version = 0;
+    ri->rid.element = choice_CMSIdentifier_issuerAndSerialNumber;
+       
+    issuer_name = X509_get_issuer_name(client_params->certificate->cert);
+    OPENSSL_ASN1_MALLOC_ENCODE(X509_NAME, buf.data, buf.length,
+                              issuer_name, ret);
+    if (ret) {
+       krb5_clear_error_string(context);
+       goto out;
+    }
+    ret = decode_Name(buf.data, buf.length,
+                     &ri->rid.u.issuerAndSerialNumber.issuer,
+                     NULL);
+    free(buf.data);
+    if (ret) {
+       krb5_set_error_string(context, "pkinit: failed to parse Name");
+       goto out;
+    }
+
+    serial = &ri->rid.u.issuerAndSerialNumber.serialNumber;
+    {
+       ASN1_INTEGER *isn;
+       BIGNUM *bn;
+
+       isn = X509_get_serialNumber(client_params->certificate->cert);
+       bn = ASN1_INTEGER_to_BN(isn, NULL);
+       if (bn == NULL) {
+           ret = ENOMEM;
+           krb5_clear_error_string(context);
+           goto out;
+       }
+       ret = BN_to_integer(context, bn, serial);
+       BN_free(bn);
+       if (ret) {
+           krb5_clear_error_string(context);
+           goto out;
+       }
+    }
+
+    {
+       const heim_oid *pk_enc_key_oid;
+       krb5_data enc_tmp_key;
+
+       ret = pk_encrypt_key(context, &tmp_key,
+                            X509_get_pubkey(client_params->certificate->cert),
+                            &enc_tmp_key,
+                            &pk_enc_key_oid);
+       if (ret)
+           goto out;
+
+       ri->encryptedKey.length = enc_tmp_key.length;
+       ri->encryptedKey.data = enc_tmp_key.data;
+
+       ret = copy_oid(pk_enc_key_oid, &ri->keyEncryptionAlgorithm.algorithm);
+       if (ret)
+           goto out;
+    }
+
+    /*
+     *
+     */
+
+    ed.version = 0;
+    ed.originatorInfo = NULL;
+
+    ret = copy_oid(oid_id_pkcs7_signedData(), &ed.encryptedContentInfo.contentType);
+    if (ret) {
+       krb5_clear_error_string(context);
+       goto out;
+    }
+
+    ALLOC(ed.encryptedContentInfo.encryptedContent);
+    if (ed.encryptedContentInfo.encryptedContent == NULL) {
+       krb5_clear_error_string(context);
+       ret = ENOMEM;
+       goto out;
+    }
+
+    ed.encryptedContentInfo.encryptedContent->data = enc_sd_data.data;
+    ed.encryptedContentInfo.encryptedContent->length = enc_sd_data.length;
+    krb5_data_zero(&enc_sd_data);
+
+    ed.unprotectedAttrs = NULL;
+
+    ASN1_MALLOC_ENCODE(EnvelopedData, buf.data, buf.length, &ed, &size, ret);
+    if (ret) {
+       krb5_set_error_string(context, 
+                             "ASN.1 encoding of EnvelopedData failed (%d)",
+                             ret);
+       goto out;
+    }
+  
+    ret = _krb5_pk_mk_ContentInfo(context,
+                                 &buf,
+                                 oid_id_pkcs7_envelopedData(),
+                                 content_info);
+    krb5_data_free(&buf);
+
+ out:
+    if (crypto)
+       krb5_crypto_destroy(context, crypto);
+    krb5_free_keyblock_contents(context, &tmp_key);
+    krb5_data_free(&enc_sd_data);
+    krb5_data_free(&iv);
+    free_EnvelopedData(&ed);
+
+    return ret;
+}
+
+/*
+ *
+ */
+
+static krb5_error_code
+pk_mk_pa_reply_dh(krb5_context context,
+                  DH *kdc_dh,
+                 pk_client_params *client_params,
+                  krb5_keyblock *reply_key,
+                 ContentInfo *content_info)
+{
+    ASN1_INTEGER *dh_pub_key = NULL;
+    KDCDHKeyInfo dh_info;
+    krb5_error_code ret;
+    SignedData sd;
+    krb5_data buf, sd_buf;
+    size_t size;
+
+    memset(&dh_info, 0, sizeof(dh_info));
+    memset(&sd, 0, sizeof(sd));
+    krb5_data_zero(&buf);
+    krb5_data_zero(&sd_buf);
+
+    dh_pub_key = BN_to_ASN1_INTEGER(kdc_dh->pub_key, NULL);
+    if (dh_pub_key == NULL) {
+       krb5_set_error_string(context, "BN_to_ASN1_INTEGER() failed (%s)",
+                             ERR_error_string(ERR_get_error(), NULL));
+       ret = ENOMEM;
+       goto out;
+    }
+
+    OPENSSL_ASN1_MALLOC_ENCODE(ASN1_INTEGER, buf.data, buf.length, dh_pub_key,
+                              ret);
+    ASN1_INTEGER_free(dh_pub_key);
+    if (ret) {
+       krb5_set_error_string(context, "Encoding of ASN1_INTEGER failed (%s)",
+                             ERR_error_string(ERR_get_error(), NULL));
+       goto out;
+    }
+   
+    dh_info.subjectPublicKey.length = buf.length * 8;
+    dh_info.subjectPublicKey.data = buf.data;
+    
+    dh_info.nonce = client_params->nonce;
+
+    ASN1_MALLOC_ENCODE(KDCDHKeyInfo, buf.data, buf.length, &dh_info, &size, 
+                      ret);
+    if (ret) {
+       krb5_set_error_string(context, "ASN.1 encoding of "
+                             "KdcDHKeyInfo failed (%d)", ret);
+       goto out;
+    }
+    if (buf.length != size)
+       krb5_abortx(context, "Internal ASN.1 encoder error");
+
+    /* 
+     * Create the SignedData structure and sign the KdcDHKeyInfo
+     * filled in above
+     */
+
+    ret = _krb5_pk_create_sign(context, 
+                              oid_id_pkdhkeydata(),
+                              &buf,
+                              kdc_identity, 
+                              &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);
+
+ out:
+    free_KDCDHKeyInfo(&dh_info);
+
+    return ret;
+}
+
+/*
+ *
+ */
+
+krb5_error_code
+_kdc_pk_mk_pa_reply(krb5_context context,
+                   krb5_kdc_configuration *config,
+                   pk_client_params *client_params,
+                   const hdb_entry *client,
+                   const KDC_REQ *req,
+                   krb5_keyblock **reply_key,
+                   METHOD_DATA *md)
+{
+    krb5_error_code ret;
+    void *buf;
+    size_t len, size;
+    krb5_enctype enctype;
+    int pa_type;
+    int i;
+
+    if (!config->enable_pkinit) {
+       krb5_clear_error_string(context);
+       return 0;
+    }
+
+    if (req->req_body.etype.len > 0) {
+       for (i = 0; i < req->req_body.etype.len; i++)
+           if (krb5_enctype_valid(context, req->req_body.etype.val[i]) == 0)
+               break;
+       if (req->req_body.etype.len <= i) {
+           ret = KRB5KRB_ERR_GENERIC;
+           krb5_set_error_string(context,
+                                 "No valid enctype available from client");
+           goto out;
+       }       
+       enctype = req->req_body.etype.val[i];
+    } else
+       enctype = ETYPE_DES3_CBC_SHA1;
+
+    if (client_params->type == PKINIT_COMPAT_25) {
+       PA_PK_AS_REP rep;
+
+       pa_type = KRB5_PADATA_PK_AS_REP;
+
+       memset(&rep, 0, sizeof(rep));
+
+       if (client_params->dh == NULL) {
+           rep.element = choice_PA_PK_AS_REP_encKeyPack;
+           ContentInfo info;
+
+           krb5_generate_random_keyblock(context, enctype, 
+                                         &client_params->reply_key);
+           ret = pk_mk_pa_reply_enckey(context,
+                                       client_params,
+                                       req,
+                                       &client_params->reply_key,
+                                       &info);
+           if (ret) {
+               free_PA_PK_AS_REP(&rep);
+               goto out;
+           }
+           ASN1_MALLOC_ENCODE(ContentInfo, rep.u.encKeyPack.data, 
+                              rep.u.encKeyPack.length, &info, &size, 
+                              ret);
+           free_ContentInfo(&info);
+           if (ret) {
+               krb5_set_error_string(context, "encoding of Key ContentInfo "
+                                     "failed %d", ret);
+               free_PA_PK_AS_REP(&rep);
+               goto out;
+           }
+           if (rep.u.encKeyPack.length != size)
+               krb5_abortx(context, "Internal ASN.1 encoder error");
+
+       } else {
+           krb5_set_error_string(context, "DH -25 not implemented");
+           ret = KRB5KRB_ERR_GENERIC;
+       }
+       if (ret) {
+           free_PA_PK_AS_REP(&rep);
+           goto out;
+       }
+
+       ASN1_MALLOC_ENCODE(PA_PK_AS_REP, buf, len, &rep, &size, ret);
+       free_PA_PK_AS_REP(&rep);
+       if (ret) {
+           krb5_set_error_string(context, "encode PA-PK-AS-REP failed %d",
+                                 ret);
+           goto out;
+       }
+       if (len != size)
+           krb5_abortx(context, "Internal ASN.1 encoder error");
+
+    } else if (client_params->type == PKINIT_COMPAT_19) {
+       PA_PK_AS_REP_19 rep;
+
+       pa_type = KRB5_PADATA_PK_AS_REP_19;
+
+       memset(&rep, 0, sizeof(rep));
+
+       if (client_params->dh == NULL) {
+           rep.element = choice_PA_PK_AS_REP_19_encKeyPack;
+           krb5_generate_random_keyblock(context, enctype, 
+                                         &client_params->reply_key);
+           ret = pk_mk_pa_reply_enckey(context,
+                                       client_params,
+                                       req,
+                                       &client_params->reply_key,
+                                       &rep.u.encKeyPack);
+       } else {
+           rep.element = choice_PA_PK_AS_REP_19_dhSignedData;
+
+           ret = check_dh_params(client_params->dh);
+           if (ret)
+               return ret;
+
+           ret = generate_dh_keyblock(context, client_params, enctype,
+                                      &client_params->reply_key);
+           if (ret)
+               return ret;
+
+           ret = pk_mk_pa_reply_dh(context, client_params->dh,
+                                   client_params, 
+                                   &client_params->reply_key,
+                                   &rep.u.dhSignedData);
+       }
+       if (ret) {
+           free_PA_PK_AS_REP_19(&rep);
+           goto out;
+       }
+
+       ASN1_MALLOC_ENCODE(PA_PK_AS_REP_19, buf, len, &rep, &size, ret);
+       free_PA_PK_AS_REP_19(&rep);
+       if (ret) {
+           krb5_set_error_string(context, 
+                                 "encode PA-PK-AS-REP-19 failed %d", ret);
+           goto out;
+       }
+       if (len != size)
+           krb5_abortx(context, "Internal ASN.1 encoder error");
+    } else if (client_params->type == PKINIT_COMPAT_WIN2K) {
+       PA_PK_AS_REP_Win2k rep;
+
+       pa_type = KRB5_PADATA_PK_AS_REP_19;
+
+       memset(&rep, 0, sizeof(rep));
+
+       if (client_params->dh) {
+           krb5_set_error_string(context, "DH -25 not implemented");
+           ret = KRB5KRB_ERR_GENERIC;
+       } else {
+           rep.element = choice_PA_PK_AS_REP_encKeyPack;
+           ContentInfo info;
+
+           krb5_generate_random_keyblock(context, enctype, 
+                                         &client_params->reply_key);
+           ret = pk_mk_pa_reply_enckey(context,
+                                       client_params,
+                                       req,
+                                       &client_params->reply_key,
+                                       &info);
+           if (ret) {
+               free_PA_PK_AS_REP_Win2k(&rep);
+               goto out;
+           }
+           ASN1_MALLOC_ENCODE(ContentInfo, rep.u.encKeyPack.data, 
+                              rep.u.encKeyPack.length, &info, &size, 
+                              ret);
+           free_ContentInfo(&info);
+           if (ret) {
+               krb5_set_error_string(context, "encoding of Key ContentInfo "
+                                     "failed %d", ret);
+               free_PA_PK_AS_REP_Win2k(&rep);
+               goto out;
+           }
+           if (rep.u.encKeyPack.length != size)
+               krb5_abortx(context, "Internal ASN.1 encoder error");
+
+       }
+       if (ret) {
+           free_PA_PK_AS_REP_Win2k(&rep);
+           goto out;
+       }
+
+       ASN1_MALLOC_ENCODE(PA_PK_AS_REP_Win2k, buf, len, &rep, &size, ret);
+       free_PA_PK_AS_REP_Win2k(&rep);
+       if (ret) {
+           krb5_set_error_string(context, 
+                                 "encode PA-PK-AS-REP-Win2k failed %d", ret);
+           goto out;
+       }
+       if (len != size)
+           krb5_abortx(context, "Internal ASN.1 encoder error");
+
+    } else
+       krb5_abortx(context, "PK-INIT internal error");
+
+
+    ret = krb5_padata_add(context, md, pa_type, buf, len);
+    if (ret) {
+       krb5_set_error_string(context, "failed adding "
+                             "PA-PK-AS-REP-19 %d", ret);
+       free(buf);
+    }
+ out:
+    if (ret == 0)
+       *reply_key = &client_params->reply_key;
+    return ret;
+}
+
+static int
+pk_principal_from_X509(krb5_context context, 
+                      krb5_kdc_configuration *config,
+                      struct krb5_pk_cert *client_cert, 
+                      krb5_principal *principal)
+{
+    krb5_error_code ret;
+    GENERAL_NAMES *gens;
+    GENERAL_NAME *gen;
+    ASN1_OBJECT *obj;
+    int i;
+
+    *principal = NULL;
+
+    obj = OBJ_txt2obj("1.3.6.1.5.2.2",1);
+       
+    gens = X509_get_ext_d2i(client_cert->cert, NID_subject_alt_name, 
+                           NULL, NULL);
+    if (gens == NULL)
+       return 1;
+
+    for (i = 0; i < sk_GENERAL_NAME_num(gens); i++) {
+       KRB5PrincipalName kn;
+       size_t len, size;
+       void *p;
+
+       gen = sk_GENERAL_NAME_value(gens, i);
+       if (gen->type != GEN_OTHERNAME)
+           continue;
+
+       if(OBJ_cmp(obj, gen->d.otherName->type_id) != 0) 
+           continue;
+       
+       p = ASN1_STRING_data(gen->d.otherName->value->value.sequence);
+       len = ASN1_STRING_length(gen->d.otherName->value->value.sequence);
+
+       ret = decode_KRB5PrincipalName(p, len, &kn, &size);
+       if (ret) {
+           kdc_log(context, config, 0,
+                   "Decoding kerberos name in certificate failed: %s",
+                   krb5_get_err_text(context, ret));
+           continue;
+       }
+
+       *principal = malloc(sizeof(**principal));
+       if (*principal == NULL) {
+           free_KRB5PrincipalName(&kn);
+           return 1;
+       }
+
+       (*principal)->name = kn.principalName;
+       (*principal)->realm = kn.realm;
+       return 0;
+    }
+    return 1;
+}
+
+
+/* XXX match with issuer too ? */
+
+krb5_error_code
+_kdc_pk_check_client(krb5_context context,
+                    krb5_kdc_configuration *config,
+                    krb5_principal client_princ,
+                    const hdb_entry *client,
+                    pk_client_params *client_params,
+                    char **subject_name)
+{
+    struct krb5_pk_cert *client_cert = client_params->certificate;
+    krb5_principal cert_princ;
+    X509_NAME *name;
+    char *subject = NULL;
+    krb5_error_code ret;
+    krb5_boolean b;
+    int i;
+
+    *subject_name = NULL;
+
+    name = X509_get_subject_name(client_cert->cert);
+    if (name == NULL) {
+       krb5_set_error_string(context, "PKINIT can't get subject name");
+       return ENOMEM;
+    }
+    subject = X509_NAME_oneline(name, NULL, 0);
+    if (subject == NULL) {
+       krb5_set_error_string(context, "PKINIT can't get subject name");
+       return ENOMEM;
+    }
+    *subject_name = strdup(subject);
+    if (*subject_name == NULL) {
+       krb5_set_error_string(context, "out of memory");
+       return ENOMEM;
+    }
+    OPENSSL_free(subject);
+
+    if (config->enable_pkinit_princ_in_cert) {
+       ret = pk_principal_from_X509(context, config, 
+                                    client_cert, &cert_princ);
+       if (ret == 0) {
+           b = krb5_principal_compare(context, client_princ, cert_princ);
+           krb5_free_principal(context, cert_princ);
+           if (b == TRUE)
+               return 0;
+       }
+    }
+
+    for (i = 0; i < principal_mappings.len; i++) {
+       b = krb5_principal_compare(context,
+                                  client_princ,
+                                  principal_mappings.val[i].principal);
+       if (b == FALSE)
+           continue;
+       if (strcmp(principal_mappings.val[i].subject, *subject_name) != 0)
+           continue;
+       return 0;
+    }
+    free(*subject_name);
+    *subject_name = NULL;
+    krb5_set_error_string(context, "PKINIT no matching principals");
+    return KRB5_KDC_ERROR_CLIENT_NAME_MISMATCH;
+}
+
+static krb5_error_code
+add_principal_mapping(krb5_context context, 
+                     const char *principal_name,
+                     const char * subject)
+{
+   struct pk_allowed_princ *tmp;
+   krb5_principal principal;
+   krb5_error_code ret;
+
+   tmp = realloc(principal_mappings.val,
+                (principal_mappings.len + 1) * sizeof(*tmp));
+   if (tmp == NULL)
+       return ENOMEM;
+   principal_mappings.val = tmp;
+
+   ret = krb5_parse_name(context, principal_name, &principal);
+   if (ret)
+       return ret;
+
+   principal_mappings.val[principal_mappings.len].principal = principal;
+
+   principal_mappings.val[principal_mappings.len].subject = strdup(subject);
+   if (principal_mappings.val[principal_mappings.len].subject == NULL) {
+       krb5_free_principal(context, principal);
+       return ENOMEM;
+   }
+   principal_mappings.len++;
+
+   return 0;
+}
+
+
+krb5_error_code
+_kdc_pk_initialize(krb5_context context,
+                  krb5_kdc_configuration *config,
+                  const char *user_id,
+                  const char *x509_anchors)
+{
+    const char *mapping_file; 
+    krb5_error_code ret;
+    char buf[1024];
+    unsigned long lineno = 0;
+    FILE *f;
+
+    principal_mappings.len = 0;
+    principal_mappings.val = NULL;
+
+    ret = _krb5_pk_load_openssl_id(context,
+                                  &kdc_identity,
+                                  user_id,
+                                  x509_anchors,
+                                  NULL,
+                                  NULL,
+                                  NULL);
+    if (ret) {
+       krb5_warn(context, ret, "PKINIT: failed to load");
+       config->enable_pkinit = 0;
+       return ret;
+    }
+
+    mapping_file = krb5_config_get_string_default(context, 
+                                                 NULL,
+                                                 HDB_DB_DIR "/pki-mapping",
+                                                 "kdc",
+                                                 "pki-mappings-file",
+                                                 NULL);
+    f = fopen(mapping_file, "r");
+    if (f == NULL) {
+       krb5_warnx(context, "PKINIT: failed to load mappings file %s",
+                  mapping_file);
+       return 0;
+    }
+
+    while (fgets(buf, sizeof(buf), f) != NULL) {
+       char *subject_name, *p;
+    
+       buf[strcspn(buf, "\n")] = '\0';
+       lineno++;
+
+       p = buf + strspn(buf, " \t");
+
+       if (*p == '#' || *p == '\0')
+           continue;
+
+       subject_name = strchr(p, ':');
+       if (subject_name == NULL) {
+           krb5_warnx(context, "pkinit mapping file line %lu "
+                      "missing \":\" :%s",
+                      lineno, buf);
+           continue;
+       }
+       *subject_name++ = '\0';
+
+       ret = add_principal_mapping(context, p, subject_name);
+       if (ret) {
+           krb5_warn(context, ret, "failed to add line %lu \":\" :%s\n",
+                     lineno, buf);
+           continue;
+       }
+    } 
+
+    fclose(f);
+
+    return 0;
+}
+
+#endif /* PKINIT */
diff --git a/source4/heimdal/kdc/process.c b/source4/heimdal/kdc/process.c
new file mode 100644 (file)
index 0000000..22cf23c
--- /dev/null
@@ -0,0 +1,117 @@
+/*
+ * 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 "kdc_locl.h"
+
+RCSID("$Id: process.c,v 1.2 2005/06/30 01:54:49 lha Exp $");
+
+/*
+ * handle the request in `buf, len', from `addr' (or `from' as a string),
+ * sending a reply in `reply'.
+ */
+
+int
+krb5_kdc_process_generic_request(krb5_context context, 
+                                krb5_kdc_configuration *config,
+                                unsigned char *buf, 
+                                size_t len, 
+                                krb5_data *reply,
+                                krb5_boolean *prependlength,
+                                const char *from,
+                                struct sockaddr *addr)
+{
+    KDC_REQ req;
+    Ticket ticket;
+    krb5_error_code ret;
+    size_t i;
+
+    gettimeofday(&_kdc_now, NULL);
+    if(decode_AS_REQ(buf, len, &req, &i) == 0){
+       ret = _kdc_as_rep(context, config, &req, reply, from, addr);
+       free_AS_REQ(&req);
+       return ret;
+    }else if(decode_TGS_REQ(buf, len, &req, &i) == 0){
+       ret = _kdc_tgs_rep(context, config, &req, reply, from, addr);
+       free_TGS_REQ(&req);
+       return ret;
+    }else if(decode_Ticket(buf, len, &ticket, &i) == 0){
+       ret = _kdc_do_524(context, config, &ticket, reply, from, addr);
+       free_Ticket(&ticket);
+       return ret;
+    } else if(_kdc_maybe_version4(buf, len)){
+       *prependlength = FALSE; /* elbitapmoc sdrawkcab XXX */
+       _kdc_do_version4(context, config, buf, len, reply, from, 
+                        (struct sockaddr_in*)addr);
+       return 0;
+    } else if (config->enable_kaserver) {
+       ret = _kdc_do_kaserver(context, config, buf, len, reply, from,
+                              (struct sockaddr_in*)addr);
+       return ret;
+    }
+                         
+    return -1;
+}
+
+/*
+ * handle the request in `buf, len', from `addr' (or `from' as a string),
+ * sending a reply in `reply'.
+ *
+ * This only processes krb5 requests
+ */
+
+int
+krb5_kdc_process_krb5_request(krb5_context context, 
+                             krb5_kdc_configuration *config,
+                             unsigned char *buf, 
+                             size_t len, 
+                             krb5_data *reply,
+                             const char *from,
+                             struct sockaddr *addr)
+{
+    KDC_REQ req;
+    krb5_error_code ret;
+    size_t i;
+
+    gettimeofday(&_kdc_now, NULL);
+    if(decode_AS_REQ(buf, len, &req, &i) == 0){
+       ret = _kdc_as_rep(context, config, &req, reply, from, addr);
+       free_AS_REQ(&req);
+       return ret;
+    }else if(decode_TGS_REQ(buf, len, &req, &i) == 0){
+       ret = _kdc_tgs_rep(context, config, &req, reply, from, addr);
+       free_TGS_REQ(&req);
+       return ret;
+    }
+    return -1;
+}
diff --git a/source4/heimdal/kdc/rx.h b/source4/heimdal/kdc/rx.h
new file mode 100644 (file)
index 0000000..ab8ec80
--- /dev/null
@@ -0,0 +1,79 @@
+/*
+ * 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. 
+ */
+
+/* $Id: rx.h,v 1.4 1999/12/02 17:05:00 joda Exp $ */
+
+#ifndef __RX_H__
+#define __RX_H__
+
+/* header of a RPC packet */
+
+enum rx_header_type {
+     HT_DATA = 1,
+     HT_ACK = 2,
+     HT_BUSY = 3,
+     HT_ABORT = 4,
+     HT_ACKALL = 5,
+     HT_CHAL = 6,
+     HT_RESP = 7,
+     HT_DEBUG = 8
+};
+
+/* For flags in header */
+
+enum rx_header_flag {
+     HF_CLIENT_INITIATED = 1,
+     HF_REQ_ACK = 2,
+     HF_LAST = 4,
+     HF_MORE = 8
+};
+
+struct rx_header {
+     u_int32_t epoch;
+     u_int32_t connid;         /* And channel ID */
+     u_int32_t callid;
+     u_int32_t seqno;
+     u_int32_t serialno;
+     u_char type;
+     u_char flags;
+     u_char status;
+     u_char secindex;
+     u_int16_t reserved;       /* ??? verifier? */
+     u_int16_t serviceid;
+/* This should be the other way around according to everything but */
+/* tcpdump */
+};
+
+#define RX_HEADER_SIZE 28
+
+#endif /* __RX_H__ */
diff --git a/source4/heimdal/lib/asn1/asn1-common.h b/source4/heimdal/lib/asn1/asn1-common.h
new file mode 100644 (file)
index 0000000..4560b1b
--- /dev/null
@@ -0,0 +1,22 @@
+/* $Id: asn1-common.h,v 1.4 2003/07/15 13:57:31 lha Exp $ */
+
+#include <stddef.h>
+#include <time.h>
+
+#ifndef __asn1_common_definitions__
+#define __asn1_common_definitions__
+
+typedef struct heim_octet_string {
+    size_t length;
+    void *data;
+} heim_octet_string;
+
+typedef char *heim_general_string;
+typedef char *heim_utf8_string;
+
+typedef struct heim_oid {
+    size_t length;
+    unsigned *components;
+} heim_oid;
+
+#endif
diff --git a/source4/heimdal/lib/asn1/asn1_err.et b/source4/heimdal/lib/asn1/asn1_err.et
new file mode 100644 (file)
index 0000000..8f1f272
--- /dev/null
@@ -0,0 +1,20 @@
+#
+# Error messages for the asn.1 library
+#
+# This might look like a com_err file, but is not
+#
+id "$Id: asn1_err.et,v 1.5 1998/02/16 16:17:17 joda Exp $"
+
+error_table asn1
+prefix ASN1
+error_code BAD_TIMEFORMAT,     "ASN.1 failed call to system time library"
+error_code MISSING_FIELD,      "ASN.1 structure is missing a required field"
+error_code MISPLACED_FIELD,    "ASN.1 unexpected field number"
+error_code TYPE_MISMATCH,      "ASN.1 type numbers are inconsistent"
+error_code OVERFLOW,           "ASN.1 value too large"
+error_code OVERRUN,            "ASN.1 encoding ended unexpectedly"
+error_code BAD_ID,             "ASN.1 identifier doesn't match expected value"
+error_code BAD_LENGTH,         "ASN.1 length doesn't match expected value"
+error_code BAD_FORMAT,         "ASN.1 badly-formatted encoding"
+error_code PARSE_ERROR,                "ASN.1 parse error"
+end
diff --git a/source4/heimdal/lib/asn1/der.h b/source4/heimdal/lib/asn1/der.h
new file mode 100644 (file)
index 0000000..6c80842
--- /dev/null
@@ -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. 
+ */
+
+/* $Id: der.h,v 1.28 2005/05/29 14:23:00 lha Exp $ */
+
+#ifndef __DER_H__
+#define __DER_H__
+
+#include <time.h>
+
+typedef enum {
+    ASN1_C_UNIV = 0,
+    ASN1_C_APPL = 1,
+    ASN1_C_CONTEXT = 2 ,
+    ASN1_C_PRIVATE = 3
+} Der_class;
+
+typedef enum {PRIM = 0, CONS = 1} Der_type;
+
+/* Universal tags */
+
+enum {
+     UT_Boolean                = 1,
+     UT_Integer                = 2,
+     UT_BitString      = 3,
+     UT_OctetString    = 4,
+     UT_Null           = 5,
+     UT_OID            = 6,
+     UT_Enumerated     = 10,
+     UT_UTF8String     = 12,
+     UT_Sequence       = 16,
+     UT_Set            = 17,
+     UT_PrintableString        = 19,
+     UT_IA5String      = 22,
+     UT_UTCTime                = 23,
+     UT_GeneralizedTime        = 24,
+     UT_VisibleString  = 26,
+     UT_GeneralString  = 27
+};
+
+#define ASN1_INDEFINITE 0xdce0deed
+
+#ifndef HAVE_TIMEGM
+time_t timegm (struct tm *);
+#endif
+
+int time2generalizedtime (time_t t, heim_octet_string *s);
+
+int der_get_int (const unsigned char *p, size_t len, int *ret, size_t *size);
+int der_get_length (const unsigned char *p, size_t len,
+                   size_t *val, size_t *size);
+int der_get_boolean (const unsigned char *p, size_t len,
+                    int *data, size_t *size);
+int der_get_general_string (const unsigned char *p, size_t len, 
+                           heim_general_string *str, size_t *size);
+int der_get_octet_string (const unsigned char *p, size_t len, 
+                         heim_octet_string *data, size_t *size);
+int der_get_oid (const unsigned char *p, size_t len,
+                heim_oid *data, size_t *size);
+int der_get_tag (const unsigned char *p, size_t len, 
+                Der_class *class, Der_type *type,
+                int *tag, size_t *size);
+
+int der_match_tag (const unsigned char *p, size_t len, 
+                  Der_class class, Der_type type,
+                  int tag, size_t *size);
+int der_match_tag_and_length (const unsigned char *p, size_t len,
+                             Der_class class, Der_type type, int tag,
+                             size_t *length_ret, size_t *size);
+
+int decode_boolean (const unsigned char*, size_t, int*, size_t*);
+int decode_integer (const unsigned char*, size_t, int*, size_t*);
+int decode_unsigned (const unsigned char*, size_t, unsigned*, size_t*);
+int decode_enumerated (const unsigned char*, size_t, unsigned*, size_t*);
+int decode_general_string (const unsigned char*, size_t,
+                          heim_general_string*, size_t*);
+int decode_oid (const unsigned char *p, size_t len, 
+               heim_oid *k, size_t *size);
+int decode_octet_string (const unsigned char*, size_t, 
+                        heim_octet_string*, size_t*);
+int decode_generalized_time (const unsigned char*, size_t, time_t*, size_t*);
+int decode_nulltype (const unsigned char*, size_t, size_t*);
+int decode_utf8string (const unsigned char*, size_t, 
+                      heim_utf8_string*, size_t*);
+
+int der_put_int (unsigned char *p, size_t len, int val, size_t*);
+int der_put_length (unsigned char *p, size_t len, size_t val, size_t*);
+int der_put_boolean (unsigned char *p, size_t len, const int *data, size_t*);
+int der_put_general_string (unsigned char *p, size_t len,
+                           const heim_general_string *str, size_t*);
+int der_put_octet_string (unsigned char *p, size_t len,
+                         const heim_octet_string *data, size_t*);
+int der_put_oid (unsigned char *p, size_t len,
+                const heim_oid *data, size_t *size);
+int der_put_tag (unsigned char *p, size_t len, Der_class class, Der_type type,
+                int tag, size_t*);
+int der_put_length_and_tag (unsigned char*, size_t, size_t, 
+                           Der_class, Der_type, int, size_t*);
+
+int encode_boolean (unsigned char *p, size_t len,
+                   const int *data, size_t*);
+int encode_integer (unsigned char *p, size_t len,
+                   const int *data, size_t*);
+int encode_unsigned (unsigned char *p, size_t len,
+                    const unsigned *data, size_t*);
+int encode_enumerated (unsigned char *p, size_t len,
+                      const unsigned *data, size_t*);
+int encode_general_string (unsigned char *p, size_t len, 
+                          const heim_general_string *data, size_t*);
+int encode_octet_string (unsigned char *p, size_t len,
+                        const heim_octet_string *k, size_t*);
+int encode_oid (unsigned char *p, size_t len,
+               const heim_oid *k, size_t*);
+int encode_generalized_time (unsigned char *p, size_t len,
+                            const time_t *t, size_t*);
+int encode_nulltype (unsigned char*, size_t, size_t*);
+int encode_utf8string (unsigned char*, size_t, 
+                      const heim_utf8_string*, size_t*);
+
+void free_integer (int *num);
+void free_general_string (heim_general_string *str);
+void free_octet_string (heim_octet_string *k);
+void free_oid (heim_oid *k);
+void free_generalized_time (time_t *t);
+void free_utf8string (heim_utf8_string*);
+
+size_t length_len (size_t len);
+size_t length_boolean (const int *data);
+size_t length_integer (const int *data);
+size_t length_unsigned (const unsigned *data);
+size_t length_enumerated (const unsigned *data);
+size_t length_general_string (const heim_general_string *data);
+size_t length_octet_string (const heim_octet_string *k);
+size_t length_oid (const heim_oid *k);
+size_t length_generalized_time (const time_t *t);
+size_t length_nulltype (void);
+size_t length_utf8string (const heim_utf8_string*);
+
+int copy_general_string (const heim_general_string *, heim_general_string *);
+int copy_octet_string (const heim_octet_string *, heim_octet_string *);
+int copy_oid (const heim_oid *from, heim_oid *to);
+int copy_nulltype (void *, void *);
+int copy_utf8string (const heim_utf8_string*, heim_utf8_string*);
+
+int heim_oid_cmp(const heim_oid *, const heim_oid *);
+int heim_octet_string_cmp(const heim_octet_string *,const heim_octet_string *);
+
+int fix_dce(size_t reallen, size_t *len);
+
+#endif /* __DER_H__ */
diff --git a/source4/heimdal/lib/asn1/der_cmp.c b/source4/heimdal/lib/asn1/der_cmp.c
new file mode 100755 (executable)
index 0000000..a5ed7ff
--- /dev/null
@@ -0,0 +1,54 @@
+/*
+ * Copyright (c) 2003 - 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 "der_locl.h"
+
+RCSID("$Id: der_cmp.c,v 1.2 2004/04/26 20:54:02 lha Exp $");
+
+int
+heim_oid_cmp(const heim_oid *p, const heim_oid *q)
+{
+    if (p->length != q->length)
+       return p->length - q->length;
+    return memcmp(p->components, 
+                 q->components,
+                 p->length * sizeof(*p->components));
+}
+
+int
+heim_octet_string_cmp(const heim_octet_string *p, const heim_octet_string *q)
+{
+    if (p->length != q->length)
+       return p->length - q->length;
+    return memcmp(p->data, q->data, p->length);
+}
diff --git a/source4/heimdal/lib/asn1/der_copy.c b/source4/heimdal/lib/asn1/der_copy.c
new file mode 100644 (file)
index 0000000..9366911
--- /dev/null
@@ -0,0 +1,68 @@
+/*
+ * 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 "der_locl.h"
+
+RCSID("$Id: der_copy.c,v 1.12 2003/11/07 07:39:43 lha Exp $");
+
+int
+copy_general_string (const heim_general_string *from, heim_general_string *to)
+{
+    *to = strdup(*from);
+    if(*to == NULL)
+       return ENOMEM;
+    return 0;
+}
+
+int
+copy_octet_string (const heim_octet_string *from, heim_octet_string *to)
+{
+    to->length = from->length;
+    to->data   = malloc(to->length);
+    if(to->length != 0 && to->data == NULL)
+       return ENOMEM;
+    memcpy(to->data, from->data, to->length);
+    return 0;
+}
+
+int
+copy_oid (const heim_oid *from, heim_oid *to)
+{
+    to->length     = from->length;
+    to->components = malloc(to->length * sizeof(*to->components));
+    if (to->length != 0 && to->components == NULL)
+       return ENOMEM;
+    memcpy(to->components, from->components,
+          to->length * sizeof(*to->components));
+    return 0;
+}
diff --git a/source4/heimdal/lib/asn1/der_free.c b/source4/heimdal/lib/asn1/der_free.c
new file mode 100644 (file)
index 0000000..bec41b1
--- /dev/null
@@ -0,0 +1,57 @@
+/*
+ * 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 "der_locl.h"
+
+RCSID("$Id: der_free.c,v 1.10 2003/08/20 16:18:49 joda Exp $");
+
+void
+free_general_string (heim_general_string *str)
+{
+    free(*str);
+    *str = NULL;
+}
+
+void
+free_octet_string (heim_octet_string *k)
+{
+    free(k->data);
+    k->data = NULL;
+}
+
+void
+free_oid (heim_oid *k)
+{
+    free(k->components);
+    k->components = NULL;
+}
diff --git a/source4/heimdal/lib/asn1/der_get.c b/source4/heimdal/lib/asn1/der_get.c
new file mode 100644 (file)
index 0000000..d33d3ca
--- /dev/null
@@ -0,0 +1,533 @@
+/*
+ * 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 "der_locl.h"
+
+RCSID("$Id: der_get.c,v 1.39 2005/05/29 14:23:00 lha Exp $");
+
+#include <version.h>
+
+/* 
+ * All decoding functions take a pointer `p' to first position in
+ * which to read, from the left, `len' which means the maximum number
+ * of characters we are able to read, `ret' were the value will be
+ * returned and `size' where the number of used bytes is stored.
+ * Either 0 or an error code is returned.
+ */
+
+static int
+der_get_unsigned (const unsigned char *p, size_t len,
+                 unsigned *ret, size_t *size)
+{
+    unsigned val = 0;
+    size_t oldlen = len;
+
+    while (len--)
+       val = val * 256 + *p++;
+    *ret = val;
+    if(size) *size = oldlen;
+    return 0;
+}
+
+int
+der_get_int (const unsigned char *p, size_t len,
+            int *ret, size_t *size)
+{
+    int val = 0;
+    size_t oldlen = len;
+
+    if (len > 0) {
+       val = (signed char)*p++;
+       while (--len)
+           val = val * 256 + *p++;
+    }
+    *ret = val;
+    if(size) *size = oldlen;
+    return 0;
+}
+
+int
+der_get_boolean(const unsigned char *p, size_t len, int *data, size_t *size)
+{
+    if(len < 1)
+       return ASN1_OVERRUN;
+    if(*p != 0)
+       *data = 1;
+    else
+       *data = 0;
+    *size = 1;
+    return 0;
+}
+
+int
+der_get_length (const unsigned char *p, size_t len,
+               size_t *val, size_t *size)
+{
+    size_t v;
+
+    if (len <= 0)
+       return ASN1_OVERRUN;
+    --len;
+    v = *p++;
+    if (v < 128) {
+       *val = v;
+       if(size) *size = 1;
+    } else {
+       int e;
+       size_t l;
+       unsigned tmp;
+
+       if(v == 0x80){
+           *val = ASN1_INDEFINITE;
+           if(size) *size = 1;
+           return 0;
+       }
+       v &= 0x7F;
+       if (len < v)
+           return ASN1_OVERRUN;
+       e = der_get_unsigned (p, v, &tmp, &l);
+       if(e) return e;
+       *val = tmp;
+       if(size) *size = l + 1;
+    }
+    return 0;
+}
+
+int
+der_get_general_string (const unsigned char *p, size_t len, 
+                       heim_general_string *str, size_t *size)
+{
+    char *s;
+
+    s = malloc (len + 1);
+    if (s == NULL)
+       return ENOMEM;
+    memcpy (s, p, len);
+    s[len] = '\0';
+    *str = s;
+    if(size) *size = len;
+    return 0;
+}
+
+int
+der_get_octet_string (const unsigned char *p, size_t len, 
+                     heim_octet_string *data, size_t *size)
+{
+    data->length = len;
+    data->data = malloc(len);
+    if (data->data == NULL && data->length != 0)
+       return ENOMEM;
+    memcpy (data->data, p, len);
+    if(size) *size = len;
+    return 0;
+}
+
+int
+der_get_oid (const unsigned char *p, size_t len,
+            heim_oid *data, size_t *size)
+{
+    int n;
+    size_t oldlen = len;
+
+    if (len < 1)
+       return ASN1_OVERRUN;
+
+    data->components = malloc((len + 1) * sizeof(*data->components));
+    if (data->components == NULL)
+       return ENOMEM;
+    data->components[0] = (*p) / 40;
+    data->components[1] = (*p) % 40;
+    --len;
+    ++p;
+    for (n = 2; len > 0; ++n) {
+       unsigned u = 0;
+
+       do {
+           --len;
+           u = u * 128 + (*p++ % 128);
+       } while (len > 0 && p[-1] & 0x80);
+       data->components[n] = u;
+    }
+    if (len > 0 && p[-1] & 0x80) {
+       free_oid (data);
+       return ASN1_OVERRUN;
+    }
+    data->length = n;
+    if (size)
+       *size = oldlen;
+    return 0;
+}
+
+int
+der_get_tag (const unsigned char *p, size_t len,
+            Der_class *class, Der_type *type,
+            int *tag, size_t *size)
+{
+    if (len < 1)
+       return ASN1_OVERRUN;
+    *class = (Der_class)(((*p) >> 6) & 0x03);
+    *type = (Der_type)(((*p) >> 5) & 0x01);
+    *tag = (*p) & 0x1F;
+    if(size) *size = 1;
+    return 0;
+}
+
+int
+der_match_tag (const unsigned char *p, size_t len,
+              Der_class class, Der_type type,
+              int tag, size_t *size)
+{
+    size_t l;
+    Der_class thisclass;
+    Der_type thistype;
+    int thistag;
+    int e;
+
+    e = der_get_tag (p, len, &thisclass, &thistype, &thistag, &l);
+    if (e) return e;
+    if (class != thisclass || type != thistype)
+       return ASN1_BAD_ID;
+    if(tag > thistag)
+       return ASN1_MISPLACED_FIELD;
+    if(tag < thistag)
+       return ASN1_MISSING_FIELD;
+    if(size) *size = l;
+    return 0;
+}
+
+int
+der_match_tag_and_length (const unsigned char *p, size_t len,
+                         Der_class class, Der_type type, int tag,
+                         size_t *length_ret, size_t *size)
+{
+    size_t l, ret = 0;
+    int e;
+
+    e = der_match_tag (p, len, class, type, tag, &l);
+    if (e) return e;
+    p += l;
+    len -= l;
+    ret += l;
+
+    e = der_get_length (p, len, length_ret, &l);
+    if (e) return e;
+    p += l;
+    len -= l;
+    ret += l;
+    if(size) *size = ret;
+    return 0;
+}
+
+int
+decode_boolean (const unsigned char *p, size_t len,
+               int *num, size_t *size)
+{
+    size_t ret = 0;
+    size_t l, reallen;
+    int e;
+
+    e = der_match_tag (p, len, ASN1_C_UNIV, PRIM, UT_Boolean, &l);
+    if (e) return e;
+    p += l;
+    len -= l;
+    ret += l;
+
+    e = der_get_length (p, len, &reallen, &l);
+    if (e) return e;
+    p += l;
+    len -= l;
+    ret += l;
+    if (reallen > len)
+       return ASN1_OVERRUN;
+
+    e = der_get_boolean (p, reallen, num, &l);
+    if (e) return e;
+    p += l;
+    len -= l;
+    ret += l;
+    if(size) *size = ret;
+    return 0;
+}
+
+int
+decode_integer (const unsigned char *p, size_t len,
+               int *num, size_t *size)
+{
+    size_t ret = 0;
+    size_t l, reallen;
+    int e;
+
+    e = der_match_tag (p, len, ASN1_C_UNIV, PRIM, UT_Integer, &l);
+    if (e) return e;
+    p += l;
+    len -= l;
+    ret += l;
+
+    e = der_get_length (p, len, &reallen, &l);
+    if (e) return e;
+    p += l;
+    len -= l;
+    ret += l;
+    if (reallen > len)
+       return ASN1_OVERRUN;
+
+    e = der_get_int (p, reallen, num, &l);
+    if (e) return e;
+    p += l;
+    len -= l;
+    ret += l;
+    if(size) *size = ret;
+    return 0;
+}
+
+int
+decode_unsigned (const unsigned char *p, size_t len,
+                unsigned *num, size_t *size)
+{
+    size_t ret = 0;
+    size_t l, reallen;
+    int e;
+
+    e = der_match_tag (p, len, ASN1_C_UNIV, PRIM, UT_Integer, &l);
+    if (e) return e;
+    p += l;
+    len -= l;
+    ret += l;
+
+    e = der_get_length (p, len, &reallen, &l);
+    if (e) return e;
+    p += l;
+    len -= l;
+    ret += l;
+    if (reallen > len)
+       return ASN1_OVERRUN;
+
+    e = der_get_unsigned (p, reallen, num, &l);
+    if (e) return e;
+    p += l;
+    len -= l;
+    ret += l;
+    if(size) *size = ret;
+    return 0;
+}
+
+int
+decode_enumerated (const unsigned char *p, size_t len,
+                  unsigned *num, size_t *size)
+{
+    size_t ret = 0;
+    size_t l, reallen;
+    int e;
+
+    e = der_match_tag (p, len, ASN1_C_UNIV, PRIM, UT_Enumerated, &l);
+    if (e) return e;
+    p += l;
+    len -= l;
+    ret += l;
+
+    e = der_get_length (p, len, &reallen, &l);
+    if (e) return e;
+    p += l;
+    len -= l;
+    ret += l;
+    if (reallen > len)
+       return ASN1_OVERRUN;
+
+    e = der_get_int (p, reallen, num, &l);
+    if (e) return e;
+    p += l;
+    len -= l;
+    ret += l;
+    if(size) *size = ret;
+    return 0;
+}
+
+int
+decode_general_string (const unsigned char *p, size_t len, 
+                      heim_general_string *str, size_t *size)
+{
+    size_t ret = 0;
+    size_t l, reallen;
+    int e;
+
+    e = der_match_tag (p, len, ASN1_C_UNIV, PRIM, UT_GeneralString, &l);
+    if (e) return e;
+    p += l;
+    len -= l;
+    ret += l;
+
+    e = der_get_length (p, len, &reallen, &l);
+    if (e) return e;
+    p += l;
+    len -= l;
+    ret += l;
+    if (len < reallen)
+       return ASN1_OVERRUN;
+
+    e = der_get_general_string (p, reallen, str, &l);
+    if (e) return e;
+    p += l;
+    len -= l;
+    ret += l;
+    if(size) *size = ret;
+    return 0;
+}
+
+int
+decode_octet_string (const unsigned char *p, size_t len, 
+                    heim_octet_string *k, size_t *size)
+{
+    size_t ret = 0;
+    size_t l, reallen;
+    int e;
+
+    e = der_match_tag (p, len, ASN1_C_UNIV, PRIM, UT_OctetString, &l);
+    if (e) return e;
+    p += l;
+    len -= l;
+    ret += l;
+
+    e = der_get_length (p, len, &reallen, &l);
+    if (e) return e;
+    p += l;
+    len -= l;
+    ret += l;
+    if (len < reallen)
+       return ASN1_OVERRUN;
+
+    e = der_get_octet_string (p, reallen, k, &l);
+    if (e) return e;
+    p += l;
+    len -= l;
+    ret += l;
+    if(size) *size = ret;
+    return 0;
+}
+
+int
+decode_oid (const unsigned char *p, size_t len, 
+           heim_oid *k, size_t *size)
+{
+    size_t ret = 0;
+    size_t l, reallen;
+    int e;
+
+    e = der_match_tag (p, len, ASN1_C_UNIV, PRIM, UT_OID, &l);
+    if (e) return e;
+    p += l;
+    len -= l;
+    ret += l;
+
+    e = der_get_length (p, len, &reallen, &l);
+    if (e) return e;
+    p += l;
+    len -= l;
+    ret += l;
+    if (len < reallen)
+       return ASN1_OVERRUN;
+
+    e = der_get_oid (p, reallen, k, &l);
+    if (e) return e;
+    p += l;
+    len -= l;
+    ret += l;
+    if(size) *size = ret;
+    return 0;
+}
+
+static void
+generalizedtime2time (const char *s, time_t *t)
+{
+    struct tm tm;
+
+    memset(&tm, 0, sizeof(tm));
+    sscanf (s, "%04d%02d%02d%02d%02d%02dZ",
+           &tm.tm_year, &tm.tm_mon, &tm.tm_mday, &tm.tm_hour,
+           &tm.tm_min, &tm.tm_sec);
+    tm.tm_year -= 1900;
+    tm.tm_mon -= 1;
+    *t = timegm (&tm);
+}
+
+int
+decode_generalized_time (const unsigned char *p, size_t len,
+                        time_t *t, size_t *size)
+{
+    heim_octet_string k;
+    char *times;
+    size_t ret = 0;
+    size_t l, reallen;
+    int e;
+
+    e = der_match_tag (p, len, ASN1_C_UNIV, PRIM, UT_GeneralizedTime, &l);
+    if (e) return e;
+    p += l;
+    len -= l;
+    ret += l;
+
+    e = der_get_length (p, len, &reallen, &l);
+    if (e) return e;
+    p += l;
+    len -= l;
+    ret += l;
+    if (len < reallen)
+       return ASN1_OVERRUN;
+
+    e = der_get_octet_string (p, reallen, &k, &l);
+    if (e) return e;
+    p += l;
+    len -= l;
+    ret += l;
+    times = realloc(k.data, k.length + 1);
+    if (times == NULL){
+       free(k.data);
+       return ENOMEM;
+    }
+    times[k.length] = 0;
+    generalizedtime2time (times, t);
+    free (times);
+    if(size) *size = ret;
+    return 0;
+}
+
+
+int
+fix_dce(size_t reallen, size_t *len)
+{
+    if(reallen == ASN1_INDEFINITE)
+       return 1;
+    if(*len < reallen)
+       return -1;
+    *len = reallen;
+    return 0;
+}
diff --git a/source4/heimdal/lib/asn1/der_length.c b/source4/heimdal/lib/asn1/der_length.c
new file mode 100644 (file)
index 0000000..cb07254
--- /dev/null
@@ -0,0 +1,175 @@
+/*
+ * 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 "der_locl.h"
+
+RCSID("$Id: der_length.c,v 1.16 2004/02/07 14:27:59 lha Exp $");
+
+size_t
+_heim_len_unsigned (unsigned val)
+{
+    size_t ret = 0;
+
+    do {
+       ++ret;
+       val /= 256;
+    } while (val);
+    return ret;
+}
+
+size_t
+_heim_len_int (int val)
+{
+    unsigned char q;
+    size_t ret = 0;
+
+    if (val >= 0) {
+       do {
+           q = val % 256;
+           ret++;
+           val /= 256;
+       } while(val);
+       if(q >= 128)
+           ret++;
+    } else {
+       val = ~val;
+       do {
+           q = ~(val % 256);
+           ret++;
+           val /= 256;
+       } while(val);
+       if(q < 128)
+           ret++;
+    }
+    return ret;
+}
+
+static size_t
+len_oid (const heim_oid *oid)
+{
+    size_t ret = 1;
+    int n;
+
+    for (n = 2; n < oid->length; ++n) {
+       unsigned u = oid->components[n];
+
+       ++ret;
+       u /= 128;
+       while (u > 0) {
+           ++ret;
+           u /= 128;
+       }
+    }
+    return ret;
+}
+
+size_t
+length_len (size_t len)
+{
+    if (len < 128)
+       return 1;
+    else
+       return _heim_len_unsigned (len) + 1;
+}
+
+size_t
+length_boolean (const int *data)
+{
+  return 1 + length_len(1) + 1;
+}
+
+size_t
+length_integer (const int *data)
+{
+    size_t len = _heim_len_int (*data);
+
+    return 1 + length_len(len) + len;
+}
+
+size_t
+length_unsigned (const unsigned *data)
+{
+    unsigned val = *data;
+    size_t len = 0;
+    while (val > 255) {
+       ++len;
+       val /= 256;
+    }
+    len++;
+    if (val >= 128)
+       len++;
+    return 1 + length_len(len) + len;
+}
+
+size_t
+length_enumerated (const unsigned *data)
+{
+    size_t len = _heim_len_int (*data);
+
+    return 1 + length_len(len) + len;
+}
+
+size_t
+length_general_string (const heim_general_string *data)
+{
+    char *str = *data;
+    size_t len = strlen(str);
+    return 1 + length_len(len) + len;
+}
+
+size_t
+length_octet_string (const heim_octet_string *k)
+{
+    return 1 + length_len(k->length) + k->length;
+}
+
+size_t
+length_oid (const heim_oid *k)
+{
+    size_t len = len_oid (k);
+
+    return 1 + length_len(len) + len;
+}
+
+size_t
+length_generalized_time (const time_t *t)
+{
+    heim_octet_string k;
+    size_t ret;
+
+    time2generalizedtime (*t, &k);
+    ret = 1 + length_len(k.length) + k.length;
+    free (k.data);
+    return ret;
+}
diff --git a/source4/heimdal/lib/asn1/der_locl.h b/source4/heimdal/lib/asn1/der_locl.h
new file mode 100644 (file)
index 0000000..67e1e87
--- /dev/null
@@ -0,0 +1,59 @@
+/*
+ * 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. 
+ */
+
+/* $Id: der_locl.h,v 1.5 2004/02/07 14:16:53 lha Exp $ */
+
+#ifndef __DER_LOCL_H__
+#define __DER_LOCL_H__
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+#include <assert.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <limits.h>
+#include <ctype.h>
+#include <time.h>
+#include <errno.h>
+#include <roken.h>
+
+#include <asn1-common.h>
+#include <asn1_err.h>
+#include <der.h>
+
+size_t _heim_len_unsigned (unsigned);
+size_t _heim_len_int (int);
+
+#endif /* __DER_LOCL_H__ */
diff --git a/source4/heimdal/lib/asn1/der_put.c b/source4/heimdal/lib/asn1/der_put.c
new file mode 100644 (file)
index 0000000..687dedd
--- /dev/null
@@ -0,0 +1,467 @@
+/*
+ * 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 "der_locl.h"
+
+RCSID("$Id: der_put.c,v 1.32 2005/05/29 14:23:01 lha Exp $");
+
+/*
+ * All encoding functions take a pointer `p' to first position in
+ * which to write, from the right, `len' which means the maximum
+ * number of characters we are able to write.  The function returns
+ * the number of characters written in `size' (if non-NULL).
+ * The return value is 0 or an error.
+ */
+
+static int
+der_put_unsigned (unsigned char *p, size_t len, unsigned val, size_t *size)
+{
+    unsigned char *base = p;
+
+    if (val) {
+       while (len > 0 && val) {
+           *p-- = val % 256;
+           val /= 256;
+           --len;
+       }
+       if (val != 0)
+           return ASN1_OVERFLOW;
+       else {
+           *size = base - p;
+           return 0;
+       }
+    } else if (len < 1)
+       return ASN1_OVERFLOW;
+    else {
+       *p    = 0;
+       *size = 1;
+       return 0;
+    }
+}
+
+int
+der_put_int (unsigned char *p, size_t len, int val, size_t *size)
+{
+    unsigned char *base = p;
+
+    if(val >= 0) {
+       do {
+           if(len < 1)
+               return ASN1_OVERFLOW;
+           *p-- = val % 256;
+           len--;
+           val /= 256;
+       } while(val);
+       if(p[1] >= 128) {
+           if(len < 1)
+               return ASN1_OVERFLOW;
+           *p-- = 0;
+           len--;
+       }
+    } else {
+       val = ~val;
+       do {
+           if(len < 1)
+               return ASN1_OVERFLOW;
+           *p-- = ~(val % 256);
+           len--;
+           val /= 256;
+       } while(val);
+       if(p[1] < 128) {
+           if(len < 1)
+               return ASN1_OVERFLOW;
+           *p-- = 0xff;
+           len--;
+       }
+    }
+    *size = base - p;
+    return 0;
+}
+
+
+int
+der_put_length (unsigned char *p, size_t len, size_t val, size_t *size)
+{
+    if (len < 1)
+       return ASN1_OVERFLOW;
+    if (val < 128) {
+       *p = val;
+       *size = 1;
+       return 0;
+    } else {
+       size_t l;
+       int e;
+
+       e = der_put_unsigned (p, len - 1, val, &l);
+       if (e)
+           return e;
+       p -= l;
+       *p = 0x80 | l;
+       *size = l + 1;
+       return 0;
+    }
+}
+
+int
+der_put_boolean(unsigned char *p, size_t len, const int *data, size_t *size)
+{
+    if(len < 1)
+       return ASN1_OVERFLOW;
+    if(*data != 0)
+       *p = 0xff;
+    else
+       *p = 0;
+    *size = 1;
+    return 0;
+}
+
+int
+der_put_general_string (unsigned char *p, size_t len, 
+                       const heim_general_string *str, size_t *size)
+{
+    size_t slen = strlen(*str);
+
+    if (len < slen)
+       return ASN1_OVERFLOW;
+    p -= slen;
+    len -= slen;
+    memcpy (p+1, *str, slen);
+    *size = slen;
+    return 0;
+}
+
+int
+der_put_octet_string (unsigned char *p, size_t len, 
+                     const heim_octet_string *data, size_t *size)
+{
+    if (len < data->length)
+       return ASN1_OVERFLOW;
+    p -= data->length;
+    len -= data->length;
+    memcpy (p+1, data->data, data->length);
+    *size = data->length;
+    return 0;
+}
+
+int
+der_put_oid (unsigned char *p, size_t len,
+            const heim_oid *data, size_t *size)
+{
+    unsigned char *base = p;
+    int n;
+
+    for (n = data->length - 1; n >= 2; --n) {
+       unsigned u = data->components[n];
+
+       if (len < 1)
+           return ASN1_OVERFLOW;
+       *p-- = u % 128;
+       u /= 128;
+       --len;
+       while (u > 0) {
+           if (len < 1)
+               return ASN1_OVERFLOW;
+           *p-- = 128 + u % 128;
+           u /= 128;
+           --len;
+       }
+    }
+    if (len < 1)
+       return ASN1_OVERFLOW;
+    *p-- = 40 * data->components[0] + data->components[1];
+    *size = base - p;
+    return 0;
+}
+
+int
+der_put_tag (unsigned char *p, size_t len, Der_class class, Der_type type,
+            int tag, size_t *size)
+{
+    if (len < 1)
+       return ASN1_OVERFLOW;
+    *p = (class << 6) | (type << 5) | tag; /* XXX */
+    *size = 1;
+    return 0;
+}
+
+int
+der_put_length_and_tag (unsigned char *p, size_t len, size_t len_val,
+                       Der_class class, Der_type type, int tag, size_t *size)
+{
+    size_t ret = 0;
+    size_t l;
+    int e;
+
+    e = der_put_length (p, len, len_val, &l);
+    if(e)
+       return e;
+    p -= l;
+    len -= l;
+    ret += l;
+    e = der_put_tag (p, len, class, type, tag, &l);
+    if(e)
+       return e;
+    p -= l;
+    len -= l;
+    ret += l;
+    *size = ret;
+    return 0;
+}
+
+int
+encode_boolean (unsigned char *p, size_t len, const int *data,
+               size_t *size)
+{
+    size_t ret = 0;
+    size_t l;
+    int e;
+    
+    e = der_put_boolean (p, len, data, &l);
+    if(e)
+       return e;
+    p -= l;
+    len -= l;
+    ret += l;
+    e = der_put_length_and_tag (p, len, l, ASN1_C_UNIV, PRIM, UT_Boolean, &l);
+    if (e)
+       return e;
+    p -= l;
+    len -= l;
+    ret += l;
+    *size = ret;
+    return 0;
+}
+
+int
+encode_integer (unsigned char *p, size_t len, const int *data, size_t *size)
+{
+    int num = *data;
+    size_t ret = 0;
+    size_t l;
+    int e;
+    
+    e = der_put_int (p, len, num, &l);
+    if(e)
+       return e;
+    p -= l;
+    len -= l;
+    ret += l;
+    e = der_put_length_and_tag (p, len, l, ASN1_C_UNIV, PRIM, UT_Integer, &l);
+    if (e)
+       return e;
+    p -= l;
+    len -= l;
+    ret += l;
+    *size = ret;
+    return 0;
+}
+
+int
+encode_unsigned (unsigned char *p, size_t len, const unsigned *data,
+                size_t *size)
+{
+    unsigned num = *data;
+    size_t ret = 0;
+    size_t l;
+    int e;
+    
+    e = der_put_unsigned (p, len, num, &l);
+    if(e)
+       return e;
+    p -= l;
+    len -= l;
+    ret += l;
+    /* if first octet has msb set, we need to pad with a zero byte */
+    if(p[1] >= 128) {
+       if(len == 0)
+           return ASN1_OVERFLOW;
+       *p-- = 0;
+       len--;
+       ret++;
+       l++;
+    }
+    e = der_put_length_and_tag (p, len, l, ASN1_C_UNIV, PRIM, UT_Integer, &l);
+    if (e)
+       return e;
+    p -= l;
+    len -= l;
+    ret += l;
+    *size = ret;
+    return 0;
+}
+
+int
+encode_enumerated (unsigned char *p, size_t len, const unsigned *data,
+                  size_t *size)
+{
+    unsigned num = *data;
+    size_t ret = 0;
+    size_t l;
+    int e;
+    
+    e = der_put_int (p, len, num, &l);
+    if(e)
+       return e;
+    p -= l;
+    len -= l;
+    ret += l;
+    e = der_put_length_and_tag (p, len, l, ASN1_C_UNIV, PRIM, UT_Enumerated, &l);
+    if (e)
+       return e;
+    p -= l;
+    len -= l;
+    ret += l;
+    *size = ret;
+    return 0;
+}
+
+int
+encode_general_string (unsigned char *p, size_t len, 
+                      const heim_general_string *data, size_t *size)
+{
+    size_t ret = 0;
+    size_t l;
+    int e;
+
+    e = der_put_general_string (p, len, data, &l);
+    if (e)
+       return e;
+    p -= l;
+    len -= l;
+    ret += l;
+    e = der_put_length_and_tag (p, len, l, ASN1_C_UNIV, PRIM, UT_GeneralString, &l);
+    if (e)
+       return e;
+    p -= l;
+    len -= l;
+    ret += l;
+    *size = ret;
+    return 0;
+}
+
+int
+encode_octet_string (unsigned char *p, size_t len, 
+                    const heim_octet_string *k, size_t *size)
+{
+    size_t ret = 0;
+    size_t l;
+    int e;
+
+    e = der_put_octet_string (p, len, k, &l);
+    if (e)
+       return e;
+    p -= l;
+    len -= l;
+    ret += l;
+    e = der_put_length_and_tag (p, len, l, ASN1_C_UNIV, PRIM, UT_OctetString, &l);
+    if (e)
+       return e;
+    p -= l;
+    len -= l;
+    ret += l;
+    *size = ret;
+    return 0;
+}
+
+int
+encode_oid(unsigned char *p, size_t len,
+          const heim_oid *k, size_t *size)
+{
+    size_t ret = 0;
+    size_t l;
+    int e;
+
+    e = der_put_oid (p, len, k, &l);
+    if (e)
+       return e;
+    p -= l;
+    len -= l;
+    ret += l;
+    e = der_put_length_and_tag (p, len, l, ASN1_C_UNIV, PRIM, UT_OID, &l);
+    if (e)
+       return e;
+    p -= l;
+    len -= l;
+    ret += l;
+    *size = ret;
+    return 0;
+}
+
+int
+time2generalizedtime (time_t t, heim_octet_string *s)
+{
+     struct tm *tm;
+     size_t len;
+
+     len = 15;
+
+     s->data = malloc(len + 1);
+     if (s->data == NULL)
+        return ENOMEM;
+     s->length = len;
+     tm = gmtime (&t);
+     snprintf (s->data, len + 1, "%04d%02d%02d%02d%02d%02dZ", 
+              tm->tm_year + 1900, tm->tm_mon + 1, tm->tm_mday, 
+              tm->tm_hour, tm->tm_min, tm->tm_sec);
+     return 0;
+}
+
+int
+encode_generalized_time (unsigned char *p, size_t len,
+                        const time_t *t, size_t *size)
+{
+    size_t ret = 0;
+    size_t l;
+    heim_octet_string k;
+    int e;
+
+    e = time2generalizedtime (*t, &k);
+    if (e)
+       return e;
+    e = der_put_octet_string (p, len, &k, &l);
+    free (k.data);
+    if (e)
+       return e;
+    p -= l;
+    len -= l;
+    ret += l;
+    e = der_put_length_and_tag (p, len, k.length, ASN1_C_UNIV, PRIM, 
+                               UT_GeneralizedTime, &l);
+    if (e)
+       return e;
+    p -= l;
+    len -= l;
+    ret += l;
+    *size = ret;
+    return 0;
+}
diff --git a/source4/heimdal/lib/asn1/gen.c b/source4/heimdal/lib/asn1/gen.c
new file mode 100644 (file)
index 0000000..67cc5ce
--- /dev/null
@@ -0,0 +1,510 @@
+/*
+ * 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 "gen_locl.h"
+
+RCSID("$Id: gen.c,v 1.59 2005/06/16 19:58:15 lha Exp $");
+
+FILE *headerfile, *codefile, *logfile;
+
+#define STEM "asn1"
+
+static const char *orig_filename;
+static char *header;
+static char *headerbase;
+
+/*
+ * list of all IMPORTs
+ */
+
+struct import {
+    const char *module;
+    struct import *next;
+};
+
+static struct import *imports = NULL;
+
+void
+add_import (const char *module)
+{
+    struct import *tmp = emalloc (sizeof(*tmp));
+
+    tmp->module = module;
+    tmp->next   = imports;
+    imports     = tmp;
+}
+
+const char *
+get_filename (void)
+{
+    return orig_filename;
+}
+
+static int unique_number;
+
+void
+unique_reset(void)
+{
+    unique_number = 0;
+}
+
+int
+unique_get_next(void)
+{
+    return unique_number++;
+}
+
+void
+init_generate (const char *filename, const char *base)
+{
+    orig_filename = filename;
+    if(base)
+       asprintf(&headerbase, "%s", base);
+    else
+       headerbase = strdup(STEM);
+    asprintf(&header, "%s.h", headerbase);
+    headerfile = fopen (header, "w");
+    if (headerfile == NULL)
+       err (1, "open %s", header);
+    fprintf (headerfile,
+            "/* Generated from %s */\n"
+            "/* Do not edit */\n\n",
+            filename);
+    fprintf (headerfile, 
+            "#ifndef __%s_h__\n"
+            "#define __%s_h__\n\n", headerbase, headerbase);
+    fprintf (headerfile, 
+            "#include <stddef.h>\n"
+            "#include <time.h>\n\n");
+#ifndef HAVE_TIMEGM
+    fprintf (headerfile, "time_t timegm (struct tm*);\n\n");
+#endif
+    fprintf (headerfile,
+            "#ifndef __asn1_common_definitions__\n"
+            "#define __asn1_common_definitions__\n\n");
+    fprintf (headerfile,
+            "typedef struct heim_octet_string {\n"
+            "  size_t length;\n"
+            "  void *data;\n"
+            "} heim_octet_string;\n\n");
+    fprintf (headerfile,
+            "typedef char *heim_general_string;\n\n"
+            );
+    fprintf (headerfile,
+            "typedef char *heim_utf8_string;\n\n"
+            );
+    fprintf (headerfile,
+            "typedef struct heim_oid {\n"
+            "  size_t length;\n"
+            "  unsigned *components;\n"
+            "} heim_oid;\n\n");
+    fputs("#define ASN1_MALLOC_ENCODE(T, B, BL, S, L, R)                  \\\n"
+         "  do {                                                         \\\n"
+         "    (BL) = length_##T((S));                                    \\\n"
+         "    (B) = malloc((BL));                                        \\\n"
+         "    if((B) == NULL) {                                          \\\n"
+         "      (R) = ENOMEM;                                            \\\n"
+         "    } else {                                                   \\\n"
+         "      (R) = encode_##T(((unsigned char*)(B)) + (BL) - 1, (BL), \\\n"
+         "                       (S), (L));                              \\\n"
+         "      if((R) != 0) {                                           \\\n"
+         "        free((B));                                             \\\n"
+         "        (B) = NULL;                                            \\\n"
+         "      }                                                        \\\n"
+         "    }                                                          \\\n"
+         "  } while (0)\n\n",
+         headerfile);
+    fprintf (headerfile, "#endif\n\n");
+    logfile = fopen(STEM "_files", "w");
+    if (logfile == NULL)
+       err (1, "open " STEM "_files");
+}
+
+void
+close_generate (void)
+{
+    fprintf (headerfile, "#endif /* __%s_h__ */\n", headerbase);
+
+    fclose (headerfile);
+    fprintf (logfile, "\n");
+    fclose (logfile);
+}
+
+void
+generate_constant (const Symbol *s)
+{
+  fprintf (headerfile, "enum { %s = %d };\n\n",
+          s->gen_name, s->constant);
+}
+
+static void
+space(int level)
+{
+    while(level-- > 0)
+       fprintf(headerfile, "  ");
+}
+
+static void
+define_asn1 (int level, Type *t)
+{
+    switch (t->type) {
+    case TType:
+       space(level);
+       fprintf (headerfile, "%s", t->symbol->name);
+       break;
+    case TInteger:
+       space(level);
+       fprintf (headerfile, "INTEGER");
+       break;
+    case TUInteger:
+       space(level);
+       fprintf (headerfile, "UNSIGNED INTEGER");
+       break;
+    case TOctetString:
+       space(level);
+       fprintf (headerfile, "OCTET STRING");
+       break;
+    case TOID :
+       space(level);
+       fprintf(headerfile, "OBJECT IDENTIFIER");
+       break;
+    case TBitString: {
+       Member *m;
+       int tag = -1;
+
+       space(level);
+       fprintf (headerfile, "BIT STRING {\n");
+       for (m = t->members; m && m->val != tag; m = m->next) {
+           if (tag == -1)
+               tag = m->val;
+           space(level + 1);
+           fprintf (headerfile, "%s(%d)%s\n", m->name, m->val, 
+                    m->next->val == tag?"":",");
+
+       }
+       space(level);
+       fprintf (headerfile, "}");
+       break;
+    }
+    case TEnumerated : {
+       Member *m;
+       int tag = -1;
+
+       space(level);
+       fprintf (headerfile, "ENUMERATED {\n");
+       for (m = t->members; m && m->val != tag; m = m->next) {
+           if (tag == -1)
+               tag = m->val;
+           space(level + 1);
+           fprintf (headerfile, "%s(%d)%s\n", m->name, m->val, 
+                    m->next->val == tag?"":",");
+
+       }
+       space(level);
+       fprintf (headerfile, "}");
+       break;
+    }
+    case TSequence: {
+       Member *m;
+       int tag;
+       int max_width = 0;
+
+       space(level);
+       fprintf (headerfile, "SEQUENCE {\n");
+       for (m = t->members, tag = -1; m && m->val != tag; m = m->next) {
+           if (tag == -1)
+               tag = m->val;
+           if(strlen(m->name) + (m->val > 9) > max_width)
+               max_width = strlen(m->name) + (m->val > 9);
+       }
+       max_width += 3 + 2;
+       if(max_width < 16) max_width = 16;
+       for (m = t->members, tag = -1 ; m && m->val != tag; m = m->next) {
+           int width;
+           if (tag == -1)
+               tag = m->val;
+           space(level + 1);
+           fprintf(headerfile, "%s[%d]", m->name, m->val);
+           width = max_width - strlen(m->name) - 3 - (m->val > 9) - 2;
+           fprintf(headerfile, "%*s", width, "");
+           define_asn1(level + 1, m->type);
+           if(m->optional)
+               fprintf(headerfile, " OPTIONAL");
+           if(m->next->val != tag)
+               fprintf (headerfile, ",");
+           fprintf (headerfile, "\n");
+       }
+       space(level);
+       fprintf (headerfile, "}");
+       break;
+    }
+    case TSequenceOf: {
+       space(level);
+       fprintf (headerfile, "SEQUENCE OF ");
+       define_asn1 (0, t->subtype);
+       break;
+    }
+    case TGeneralizedTime:
+       space(level);
+       fprintf (headerfile, "GeneralizedTime");
+       break;
+    case TGeneralString:
+       space(level);
+       fprintf (headerfile, "GeneralString");
+       break;
+    case TApplication:
+       fprintf (headerfile, "[APPLICATION %d] ", t->application);
+       define_asn1 (level, t->subtype);
+       break;
+    case TBoolean:
+       space(level);
+       fprintf (headerfile, "BOOLEAN");
+       break;
+    case TUTF8String:
+       space(level);
+       fprintf (headerfile, "UTF8String");
+       break;
+    case TNull:
+       space(level);
+       fprintf (headerfile, "NULL");
+       break;
+    default:
+       abort ();
+    }
+}
+
+static void
+define_type (int level, const char *name, Type *t, int typedefp)
+{
+    switch (t->type) {
+    case TType:
+       space(level);
+       fprintf (headerfile, "%s %s;\n", t->symbol->gen_name, name);
+       break;
+    case TInteger:
+       space(level);
+        if(t->members == NULL) {
+            fprintf (headerfile, "int %s;\n", name);
+        } else {
+            Member *m;
+            int tag = -1;
+            fprintf (headerfile, "enum %s {\n", typedefp ? name : "");
+           for (m = t->members; m && m->val != tag; m = m->next) {
+                if(tag == -1)
+                    tag = m->val;
+                space (level + 1);
+                fprintf(headerfile, "%s = %d%s\n", m->gen_name, m->val, 
+                        m->next->val == tag ? "" : ",");
+            }
+            fprintf (headerfile, "} %s;\n", name);
+        }
+       break;
+    case TUInteger:
+       space(level);
+       fprintf (headerfile, "unsigned int %s;\n", name);
+       break;
+    case TOctetString:
+       space(level);
+       fprintf (headerfile, "heim_octet_string %s;\n", name);
+       break;
+    case TOID :
+       space(level);
+       fprintf (headerfile, "heim_oid %s;\n", name);
+       break;
+    case TBitString: {
+       Member *m;
+       Type i;
+       int tag = -1;
+
+       i.type = TUInteger;
+       space(level);
+       fprintf (headerfile, "struct %s {\n", typedefp ? name : "");
+       for (m = t->members; m && m->val != tag; m = m->next) {
+           char *n;
+
+           asprintf (&n, "%s:1", m->gen_name);
+           define_type (level + 1, n, &i, FALSE);
+           free (n);
+           if (tag == -1)
+               tag = m->val;
+       }
+       space(level);
+       fprintf (headerfile, "} %s;\n\n", name);
+       break;
+    }
+    case TEnumerated: {
+       Member *m;
+       int tag = -1;
+
+       space(level);
+       fprintf (headerfile, "enum %s {\n", typedefp ? name : "");
+       for (m = t->members; m && m->val != tag; m = m->next) {
+           if (tag == -1)
+               tag = m->val;
+           space(level + 1);
+           fprintf (headerfile, "%s = %d%s\n", m->gen_name, m->val,
+                        m->next->val == tag ? "" : ",");
+       }
+       space(level);
+       fprintf (headerfile, "} %s;\n\n", name);
+       break;
+    }
+    case TSequence: {
+       Member *m;
+       int tag = -1;
+
+       space(level);
+       fprintf (headerfile, "struct %s {\n", typedefp ? name : "");
+       for (m = t->members; m && m->val != tag; m = m->next) {
+           if (m->optional) {
+               char *n;
+
+               asprintf (&n, "*%s", m->gen_name);
+               define_type (level + 1, n, m->type, FALSE);
+               free (n);
+           } else
+               define_type (level + 1, m->gen_name, m->type, FALSE);
+           if (tag == -1)
+               tag = m->val;
+       }
+       space(level);
+       fprintf (headerfile, "} %s;\n", name);
+       break;
+    }
+    case TSequenceOf: {
+       Type i;
+
+       i.type = TUInteger;
+       i.application = 0;
+
+       space(level);
+       fprintf (headerfile, "struct %s {\n", typedefp ? name : "");
+       define_type (level + 1, "len", &i, FALSE);
+       define_type (level + 1, "*val", t->subtype, FALSE);
+       space(level);
+       fprintf (headerfile, "} %s;\n", name);
+       break;
+    }
+    case TGeneralizedTime:
+       space(level);
+       fprintf (headerfile, "time_t %s;\n", name);
+       break;
+    case TGeneralString:
+       space(level);
+       fprintf (headerfile, "heim_general_string %s;\n", name);
+       break;
+    case TUTF8String:
+       space(level);
+       fprintf (headerfile, "heim_utf8_string %s;\n", name);
+       break;
+    case TBoolean:
+       space(level);
+       fprintf (headerfile, "int %s;\n", name);
+       break;
+    case TNull:
+       space(level);
+       fprintf (headerfile, "NULL %s;\n", name);
+       break;
+    case TApplication:
+       define_type (level, name, t->subtype, FALSE);
+       break;
+    default:
+       abort ();
+    }
+}
+
+static void
+generate_type_header (const Symbol *s)
+{
+    fprintf (headerfile, "/*\n");
+    fprintf (headerfile, "%s ::= ", s->name);
+    define_asn1 (0, s->type);
+    fprintf (headerfile, "\n*/\n\n");
+
+    fprintf (headerfile, "typedef ");
+    define_type (0, s->gen_name, s->type, TRUE);
+
+    fprintf (headerfile, "\n");
+}
+
+
+void
+generate_type (const Symbol *s)
+{
+    struct import *i;
+    char *filename;
+
+    asprintf (&filename, "%s_%s.x", STEM, s->gen_name);
+    codefile = fopen (filename, "w");
+    if (codefile == NULL)
+       err (1, "fopen %s", filename);
+    fprintf(logfile, "%s ", filename);
+    free(filename);
+    fprintf (codefile, 
+            "/* Generated from %s */\n"
+            "/* Do not edit */\n\n"
+            "#include <stdio.h>\n"
+            "#include <stdlib.h>\n"
+            "#include <time.h>\n"
+            "#include <string.h>\n"
+            "#include <errno.h>\n",
+            orig_filename);
+
+    for (i = imports; i != NULL; i = i->next)
+       fprintf (codefile,
+                "#include <%s_asn1.h>\n",
+                i->module);
+    fprintf (codefile,
+            "#include <%s.h>\n",
+            headerbase);
+    fprintf (codefile,
+            "#include <asn1_err.h>\n"
+            "#include <der.h>\n"
+            "#include <parse_units.h>\n\n");
+
+    if (s->stype == Stype && s->type->type == TChoice) {
+       fprintf(codefile,
+               "/* CHOICE */\n"
+               "int asn1_%s_dummy_holder = 1;\n", s->gen_name);
+    } else {
+       generate_type_header (s);
+       generate_type_encode (s);
+       generate_type_decode (s);
+       generate_type_free (s);
+       generate_type_length (s);
+       generate_type_copy (s);
+       generate_glue (s);
+    }
+    fprintf(headerfile, "\n\n");
+    fclose(codefile);
+}
diff --git a/source4/heimdal/lib/asn1/gen_copy.c b/source4/heimdal/lib/asn1/gen_copy.c
new file mode 100644 (file)
index 0000000..a8421fe
--- /dev/null
@@ -0,0 +1,157 @@
+/*
+ * 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 "gen_locl.h"
+
+RCSID("$Id: gen_copy.c,v 1.15 2005/06/16 20:03:38 lha Exp $");
+
+static void
+copy_primitive (const char *typename, const char *from, const char *to)
+{
+    fprintf (codefile, "if(copy_%s(%s, %s)) return ENOMEM;\n", 
+            typename, from, to);
+}
+
+static void
+copy_type (const char *from, const char *to, const Type *t)
+{
+  switch (t->type) {
+  case TType:
+#if 0
+      copy_type (from, to, t->symbol->type);
+#endif
+      fprintf (codefile, "if(copy_%s(%s, %s)) return ENOMEM;\n", 
+              t->symbol->gen_name, from, to);
+      break;
+  case TInteger:
+  case TUInteger:
+  case TBoolean:
+  case TEnumerated :
+      fprintf(codefile, "*(%s) = *(%s);\n", to, from);
+      break;
+  case TOctetString:
+      copy_primitive ("octet_string", from, to);
+      break;
+  case TOID:
+      copy_primitive ("oid", from, to);
+      break;
+  case TBitString: {
+      fprintf(codefile, "*(%s) = *(%s);\n", to, from);
+      break;
+  }
+  case TSequence: {
+      Member *m;
+      int tag = -1;
+
+      if (t->members == NULL)
+         break;
+      
+      for (m = t->members; m && tag != m->val; m = m->next) {
+         char *fn;
+         char *tn;
+
+         asprintf (&fn, "%s(%s)->%s",
+                   m->optional ? "" : "&", from, m->gen_name);
+         asprintf (&tn, "%s(%s)->%s",
+                   m->optional ? "" : "&", to, m->gen_name);
+         if(m->optional){
+             fprintf(codefile, "if(%s) {\n", fn);
+             fprintf(codefile, "%s = malloc(sizeof(*%s));\n", tn, tn);
+             fprintf(codefile, "if(%s == NULL) return ENOMEM;\n", tn);
+         }
+         copy_type (fn, tn, m->type);
+         if(m->optional){
+             fprintf(codefile, "}else\n");
+             fprintf(codefile, "%s = NULL;\n", tn);
+         }
+         if (tag == -1)
+             tag = m->val;
+         free (fn);
+         free (tn);
+      }
+      break;
+  }
+  case TSequenceOf: {
+      char *f;
+      char *T;
+
+      fprintf (codefile, "if(((%s)->val = "
+              "malloc((%s)->len * sizeof(*(%s)->val))) == NULL && (%s)->len != 0)\n", 
+              to, from, to, from);
+      fprintf (codefile, "return ENOMEM;\n");
+      fprintf(codefile,
+             "for((%s)->len = 0; (%s)->len < (%s)->len; (%s)->len++){\n",
+             to, to, from, to);
+      asprintf(&f, "&(%s)->val[(%s)->len]", from, to);
+      asprintf(&T, "&(%s)->val[(%s)->len]", to, to);
+      copy_type(f, T, t->subtype);
+      fprintf(codefile, "}\n");
+      free(f);
+      free(T);
+      break;
+  }
+  case TGeneralizedTime:
+      fprintf(codefile, "*(%s) = *(%s);\n", to, from);
+      break;
+  case TGeneralString:
+      copy_primitive ("general_string", from, to);
+      break;
+  case TUTF8String:
+      copy_primitive ("utf8string", from, to);
+      break;
+  case TNull:
+      break;
+  case TApplication:
+      copy_type (from, to, t->subtype);
+      break;
+  default :
+      abort ();
+  }
+}
+
+void
+generate_type_copy (const Symbol *s)
+{
+  fprintf (headerfile,
+          "int    copy_%s  (const %s *, %s *);\n",
+          s->gen_name, s->gen_name, s->gen_name);
+
+  fprintf (codefile, "int\n"
+          "copy_%s(const %s *from, %s *to)\n"
+          "{\n",
+          s->gen_name, s->gen_name, s->gen_name);
+
+  copy_type ("from", "to", s->type);
+  fprintf (codefile, "return 0;\n}\n\n");
+}
+
diff --git a/source4/heimdal/lib/asn1/gen_decode.c b/source4/heimdal/lib/asn1/gen_decode.c
new file mode 100644 (file)
index 0000000..f49593d
--- /dev/null
@@ -0,0 +1,419 @@
+/*
+ * 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 "gen_locl.h"
+
+RCSID("$Id: gen_decode.c,v 1.21 2005/05/29 14:23:01 lha Exp $");
+
+static void
+decode_primitive (const char *typename, const char *name)
+{
+    fprintf (codefile,
+            "e = decode_%s(p, len, %s, &l);\n"
+            "FORW;\n",
+            typename,
+            name);
+}
+
+static void
+decode_type (const char *name, const Type *t)
+{
+    switch (t->type) {
+    case TType:
+#if 0
+       decode_type (name, t->symbol->type);
+#endif
+       fprintf (codefile,
+                "e = decode_%s(p, len, %s, &l);\n"
+                "FORW;\n",
+                t->symbol->gen_name, name);
+       break;
+    case TInteger:
+       if(t->members == NULL)
+           decode_primitive ("integer", name);
+       else {
+           char *s;
+           asprintf(&s, "(int*)%s", name);
+           if(s == NULL)
+               errx (1, "out of memory");
+           decode_primitive ("integer", s);
+           free(s);
+       }
+       break;
+    case TUInteger:
+       decode_primitive ("unsigned", name);
+       break;
+    case TEnumerated:
+       decode_primitive ("enumerated", name);
+       break;
+    case TOctetString:
+       decode_primitive ("octet_string", name);
+       break;
+    case TOID :
+       decode_primitive ("oid", name);
+       break;
+    case TBitString: {
+       Member *m;
+       int tag = -1;
+       int pos;
+
+       fprintf (codefile,
+                "e = der_match_tag_and_length (p, len, ASN1_C_UNIV, PRIM, UT_BitString,"
+                "&reallen, &l);\n"
+                "FORW;\n"
+                "if(len < reallen)\n"
+                "return ASN1_OVERRUN;\n"
+                "p++;\n"
+                "len--;\n"
+                "reallen--;\n"
+                "ret++;\n");
+       pos = 0;
+       for (m = t->members; m && tag != m->val; m = m->next) {
+           while (m->val / 8 > pos / 8) {
+               fprintf (codefile,
+                        "p++; len--; reallen--; ret++;\n");
+               pos += 8;
+           }
+           fprintf (codefile,
+                    "%s->%s = (*p >> %d) & 1;\n",
+                    name, m->gen_name, 7 - m->val % 8);
+           if (tag == -1)
+               tag = m->val;
+       }
+       fprintf (codefile,
+                "p += reallen; len -= reallen; ret += reallen;\n");
+       break;
+    }
+    case TSequence: {
+       Member *m;
+       int tag = -1;
+       int fd_counter = unique_get_next();
+       int fd_counter_inner = unique_get_next();
+
+       if (t->members == NULL)
+           break;
+
+       fprintf (codefile,
+                "e = der_match_tag_and_length (p, len, ASN1_C_UNIV, CONS, UT_Sequence,"
+                "&reallen, &l);\n"
+                "FORW;\n"
+                "{\n"
+                "int dce_fix%d;\n"
+                "if((dce_fix%d = fix_dce(reallen, &len)) < 0)\n"
+                "return ASN1_BAD_FORMAT;\n",
+                fd_counter, fd_counter);
+
+       for (m = t->members; m && tag != m->val; m = m->next) {
+           char *s;
+
+           asprintf (&s, "%s(%s)->%s", m->optional ? "" : "&", name, m->gen_name);
+           if (0 && m->type->type == TType){
+               if(m->optional)
+                   fprintf (codefile,
+                            "%s = malloc(sizeof(*%s));\n"
+                            "if(%s == NULL) return ENOMEM;\n", s, s, s);
+               fprintf (codefile, 
+                        "e = decode_seq_%s(p, len, %d, %d, %s, &l);\n",
+                        m->type->symbol->gen_name,
+                        m->val, 
+                        m->optional,
+                        s);
+               if(m->optional)
+                   fprintf (codefile, 
+                            "if (e == ASN1_MISSING_FIELD) {\n"
+                            "free(%s);\n"
+                            "%s = NULL;\n"
+                            "e = l = 0;\n"
+                            "}\n",
+                            s, s);
+         
+               fprintf (codefile, "FORW;\n");
+         
+           }else{
+               fprintf (codefile, "{\n"
+                        "size_t newlen, oldlen;\n\n"
+                        "e = der_match_tag (p, len, ASN1_C_CONTEXT, CONS, %d, &l);\n",
+                        m->val);
+               fprintf (codefile,
+                        "if (e)\n");
+               if(m->optional)
+                   /* XXX should look at e */
+                   fprintf (codefile,
+                            "%s = NULL;\n", s);
+               else
+                   fprintf (codefile,
+                            "return e;\n");
+               fprintf (codefile, 
+                        "else {\n");
+               fprintf (codefile,
+                        "p += l;\n"
+                        "len -= l;\n"
+                        "ret += l;\n"
+                        "e = der_get_length (p, len, &newlen, &l);\n"
+                        "FORW;\n"
+                        "{\n"
+              
+                        "int dce_fix%d;\n"
+                        "oldlen = len;\n"
+                        "if((dce_fix%d = fix_dce(newlen, &len)) < 0)"
+                        "return ASN1_BAD_FORMAT;\n",
+                        fd_counter_inner,
+                        fd_counter_inner);
+               if (m->optional)
+                   fprintf (codefile,
+                            "%s = malloc(sizeof(*%s));\n"
+                            "if(%s == NULL) return ENOMEM;\n", s, s, s);
+               decode_type (s, m->type);
+               fprintf (codefile,
+                        "if(dce_fix%d){\n"
+                        "e = der_match_tag_and_length (p, len, "
+                        "(Der_class)0, (Der_type)0, 0, &reallen, &l);\n"
+                        "FORW;\n"
+                        "}else \n"
+                        "len = oldlen - newlen;\n"
+                        "}\n"
+                        "}\n",
+                        fd_counter_inner);
+               fprintf (codefile,
+                        "}\n");
+           }
+           if (tag == -1)
+               tag = m->val;
+           free (s);
+       }
+       fprintf(codefile,
+               "if(dce_fix%d){\n"
+               "e = der_match_tag_and_length (p, len, "
+               "(Der_class)0, (Der_type)0, 0, &reallen, &l);\n"
+               "FORW;\n"
+               "}\n"
+               "}\n",
+               fd_counter);
+
+       break;
+    }
+    case TSequenceOf: {
+       char *n;
+       int oldret_counter = unique_get_next();
+
+       fprintf (codefile,
+                "e = der_match_tag_and_length (p, len, ASN1_C_UNIV, CONS, UT_Sequence,"
+                "&reallen, &l);\n"
+                "FORW;\n"
+                "if(len < reallen)\n"
+                "return ASN1_OVERRUN;\n"
+                "len = reallen;\n");
+
+       fprintf (codefile,
+                "{\n"
+                "size_t origlen = len;\n"
+                "int oldret%d = ret;\n"
+                "ret = 0;\n"
+                "(%s)->len = 0;\n"
+                "(%s)->val = NULL;\n"
+                "while(ret < origlen) {\n"
+                "(%s)->len++;\n"
+                "(%s)->val = realloc((%s)->val, sizeof(*((%s)->val)) * (%s)->len);\n",
+                oldret_counter, name, name, name, name, name, name, name);
+       asprintf (&n, "&(%s)->val[(%s)->len-1]", name, name);
+       decode_type (n, t->subtype);
+       fprintf (codefile, 
+                "len = origlen - ret;\n"
+                "}\n"
+                "ret += oldret%d;\n"
+                "}\n",
+                oldret_counter);
+       free (n);
+       break;
+    }
+    case TGeneralizedTime:
+       decode_primitive ("generalized_time", name);
+       break;
+    case TGeneralString:
+       decode_primitive ("general_string", name);
+       break;
+    case TUTF8String:
+       decode_primitive ("utf8string", name);
+       break;
+    case TNull:
+       fprintf (codefile,
+                "e = decode_nulltype(p, len, &l);\n"
+                "FORW;\n");
+       break;
+    case TApplication:
+       fprintf (codefile,
+                "e = der_match_tag_and_length (p, len, ASN1_C_APPL, CONS, %d, "
+                "&reallen, &l);\n"
+                "FORW;\n"
+                "{\n"
+                "int dce_fix;\n"
+                "if((dce_fix = fix_dce(reallen, &len)) < 0)\n"
+                "return ASN1_BAD_FORMAT;\n", 
+                t->application);
+       decode_type (name, t->subtype);
+       fprintf(codefile,
+               "if(dce_fix){\n"
+               "e = der_match_tag_and_length (p, len, "
+               "(Der_class)0, (Der_type)0, 0, &reallen, &l);\n"
+               "FORW;\n"
+               "}\n"
+               "}\n");
+
+       break;
+    case TBoolean:
+       decode_primitive ("boolean", name);
+       break;
+    default :
+       abort ();
+    }
+}
+
+void
+generate_type_decode (const Symbol *s)
+{
+  unique_reset();
+  fprintf (headerfile,
+          "int    "
+          "decode_%s(const unsigned char *, size_t, %s *, size_t *);\n",
+          s->gen_name, s->gen_name);
+
+  fprintf (codefile, "#define FORW "
+          "if(e) goto fail; "
+          "p += l; "
+          "len -= l; "
+          "ret += l\n\n");
+
+
+  fprintf (codefile, "int\n"
+          "decode_%s(const unsigned char *p,"
+          " size_t len, %s *data, size_t *size)\n"
+          "{\n",
+          s->gen_name, s->gen_name);
+
+  switch (s->type->type) {
+  case TInteger:
+  case TUInteger:
+  case TBoolean:
+  case TOctetString:
+  case TOID:
+  case TGeneralizedTime:
+  case TGeneralString:
+  case TUTF8String:
+  case TNull:
+  case TEnumerated:
+  case TBitString:
+  case TSequence:
+  case TSequenceOf:
+  case TApplication:
+  case TType:
+    fprintf (codefile,
+            "size_t ret = 0, reallen;\n"
+            "size_t l;\n"
+            "int e;\n\n");
+    fprintf (codefile, "memset(data, 0, sizeof(*data));\n");
+    fprintf (codefile, "reallen = 0;\n"); /* hack to avoid `unused variable' */
+
+    decode_type ("data", s->type);
+    fprintf (codefile, 
+            "if(size) *size = ret;\n"
+            "return 0;\n");
+    fprintf (codefile,
+            "fail:\n"
+            "free_%s(data);\n"
+            "return e;\n",
+            s->gen_name);
+    break;
+  default:
+    abort ();
+  }
+  fprintf (codefile, "}\n\n");
+}
+
+void
+generate_seq_type_decode (const Symbol *s)
+{
+    fprintf (headerfile,
+            "int decode_seq_%s(const unsigned char *, size_t, int, int, "
+            "%s *, size_t *);\n",
+            s->gen_name, s->gen_name);
+
+    fprintf (codefile, "int\n"
+            "decode_seq_%s(const unsigned char *p, size_t len, int tag, "
+            "int optional, %s *data, size_t *size)\n"
+            "{\n",
+            s->gen_name, s->gen_name);
+
+    fprintf (codefile,
+            "size_t newlen, oldlen;\n"
+            "size_t l, ret = 0;\n"
+            "int e;\n"
+            "int dce_fix;\n");
+    
+    fprintf (codefile,
+            "e = der_match_tag(p, len, ASN1_C_CONTEXT, CONS, tag, &l);\n"
+            "if (e)\n"
+            "return e;\n");
+    fprintf (codefile, 
+            "p += l;\n"
+            "len -= l;\n"
+            "ret += l;\n"
+            "e = der_get_length(p, len, &newlen, &l);\n"
+            "if (e)\n"
+            "return e;\n"
+            "p += l;\n"
+            "len -= l;\n"
+            "ret += l;\n"
+            "oldlen = len;\n"
+            "if ((dce_fix = fix_dce(newlen, &len)) < 0)\n"
+            "return ASN1_BAD_FORMAT;\n"
+            "e = decode_%s(p, len, data, &l);\n"
+            "if (e)\n"
+            "return e;\n"
+            "p += l;\n"
+            "len -= l;\n"
+            "ret += l;\n"
+            "if (dce_fix) {\n"
+            "size_t reallen;\n\n"
+            "e = der_match_tag_and_length(p, len, "
+            "(Der_class)0, (Der_type)0, 0, &reallen, &l);\n"
+            "if (e)\n"
+            "return e;\n"
+            "ret += l;\n"
+            "}\n",
+            s->gen_name);
+    fprintf (codefile, 
+            "if(size) *size = ret;\n"
+            "return 0;\n");
+
+    fprintf (codefile, "}\n\n");
+}
diff --git a/source4/heimdal/lib/asn1/gen_encode.c b/source4/heimdal/lib/asn1/gen_encode.c
new file mode 100644 (file)
index 0000000..e77bcc5
--- /dev/null
@@ -0,0 +1,287 @@
+/*
+ * 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 "gen_locl.h"
+
+RCSID("$Id: gen_encode.c,v 1.15 2005/05/29 14:23:01 lha Exp $");
+
+static void
+encode_primitive (const char *typename, const char *name)
+{
+    fprintf (codefile,
+            "e = encode_%s(p, len, %s, &l);\n"
+            "BACK;\n",
+            typename,
+            name);
+}
+
+static void
+encode_type (const char *name, const Type *t)
+{
+    switch (t->type) {
+    case TType:
+#if 0
+       encode_type (name, t->symbol->type);
+#endif
+       fprintf (codefile,
+                "e = encode_%s(p, len, %s, &l);\n"
+                "BACK;\n",
+                t->symbol->gen_name, name);
+       break;
+    case TInteger:
+       if(t->members == NULL)
+           encode_primitive ("integer", name);
+       else {
+           char *s;
+           asprintf(&s, "(const int*)%s", name);
+           if(s == NULL)
+               errx(1, "out of memory");
+           encode_primitive ("integer", s);
+           free(s);
+       }
+       break;
+    case TUInteger:
+       encode_primitive ("unsigned", name);
+       break;
+    case TOctetString:
+       encode_primitive ("octet_string", name);
+       break;
+    case TOID :
+       encode_primitive ("oid", name);
+       break;
+    case TBitString: {
+       Member *m;
+       int pos;
+       int rest;
+       int tag = -1;
+
+       if (t->members == NULL)
+           break;
+
+       fprintf (codefile, "{\n"
+                "unsigned char c = 0;\n");
+       pos = t->members->prev->val;
+       /* fix for buggy MIT (and OSF?) code */
+       if (pos > 31)
+           abort ();
+       /*
+        * It seems that if we do not always set pos to 31 here, the MIT
+        * code will do the wrong thing.
+        *
+        * I hate ASN.1 (and DER), but I hate it even more when everybody
+        * has to screw it up differently.
+        */
+       pos = 31;
+       rest = 7 - (pos % 8);
+
+       for (m = t->members->prev; m && tag != m->val; m = m->prev) {
+           while (m->val / 8 < pos / 8) {
+               fprintf (codefile,
+                        "*p-- = c; len--; ret++;\n"
+                        "c = 0;\n");
+               pos -= 8;
+           }
+           fprintf (codefile,
+                    "if(%s->%s) c |= 1<<%d;\n", name, m->gen_name,
+                    7 - m->val % 8);
+
+           if (tag == -1)
+               tag = m->val;
+       }
+
+       fprintf (codefile, 
+                "*p-- = c;\n"
+                "*p-- = %d;\n"
+                "len -= 2;\n"
+                "ret += 2;\n"
+                "}\n\n"
+                "e = der_put_length_and_tag (p, len, ret, ASN1_C_UNIV, PRIM,"
+                "UT_BitString, &l);\n"
+                "BACK;\n",
+                rest);
+       break;
+    }
+    case TEnumerated : {
+       encode_primitive ("enumerated", name);
+       break;
+    }
+    case TSequence: {
+       Member *m;
+       int tag = -1;
+       int oldret_counter = unique_get_next();
+
+       if (t->members == NULL)
+           break;
+
+       for (m = t->members->prev; m && tag != m->val; m = m->prev) {
+           char *s;
+
+           asprintf (&s, "%s(%s)->%s", m->optional ? "" : "&", name, m->gen_name);
+           if (m->optional)
+               fprintf (codefile,
+                        "if(%s)\n",
+                        s);
+#if 1
+           fprintf (codefile, "{\n"
+                    "int oldret%d = ret;\n"
+                    "ret = 0;\n",
+                    oldret_counter);
+#endif
+           encode_type (s, m->type);
+           fprintf (codefile,
+                    "e = der_put_length_and_tag (p, len, ret, ASN1_C_CONTEXT, CONS, "
+                    "%d, &l);\n"
+                    "BACK;\n",
+                    m->val);
+#if 1
+           fprintf (codefile,
+                    "ret += oldret%d;\n"
+                    "}\n",
+                    oldret_counter);
+#endif
+           if (tag == -1)
+               tag = m->val;
+           free (s);
+       }
+       fprintf (codefile,
+                "e = der_put_length_and_tag (p, len, ret, ASN1_C_UNIV, CONS, UT_Sequence, &l);\n"
+                "BACK;\n");
+       break;
+    }
+    case TSequenceOf: {
+       int oldret_counter = unique_get_next();
+       char *n;
+
+       fprintf (codefile,
+                "for(i = (%s)->len - 1; i >= 0; --i) {\n"
+#if 1
+                "int oldret%d = ret;\n"
+                "ret = 0;\n",
+#else
+                ,
+#endif
+                name, oldret_counter);
+       asprintf (&n, "&(%s)->val[i]", name);
+       encode_type (n, t->subtype);
+       fprintf (codefile,
+#if 1
+                "ret += oldret%d;\n"
+#endif
+                "}\n"
+                "e = der_put_length_and_tag (p, len, ret, ASN1_C_UNIV, CONS, UT_Sequence, &l);\n"
+                "BACK;\n"
+#if 1
+                , oldret_counter
+#endif
+           );
+       free (n);
+       break;
+    }
+    case TGeneralizedTime:
+       encode_primitive ("generalized_time", name);
+       break;
+    case TGeneralString:
+       encode_primitive ("general_string", name);
+       break;
+    case TUTF8String:
+       encode_primitive ("utf8string", name);
+       break;
+    case TNull:
+       fprintf (codefile,
+                "e = encode_nulltype(p, len, &l);\n"
+                "BACK;\n");
+       break;
+    case TApplication:
+       encode_type (name, t->subtype);
+       fprintf (codefile,
+                "e = der_put_length_and_tag (p, len, ret, ASN1_C_APPL, CONS, %d, &l);\n"
+                "BACK;\n",
+                t->application);
+       break;
+    case TBoolean:
+       encode_primitive ("boolean", name);
+       break;
+    default:
+       abort ();
+    }
+}
+
+void
+generate_type_encode (const Symbol *s)
+{
+  fprintf (headerfile,
+          "int    "
+          "encode_%s(unsigned char *, size_t, const %s *, size_t *);\n",
+          s->gen_name, s->gen_name);
+
+  fprintf (codefile, "#define BACK if (e) return e; p -= l; len -= l; ret += l\n\n");
+
+
+  fprintf (codefile, "int\n"
+          "encode_%s(unsigned char *p, size_t len,"
+          " const %s *data, size_t *size)\n"
+          "{\n",
+          s->gen_name, s->gen_name);
+
+  switch (s->type->type) {
+  case TInteger:
+  case TUInteger:
+  case TBoolean:
+  case TOctetString:
+  case TGeneralizedTime:
+  case TGeneralString:
+  case TUTF8String:
+  case TNull:
+  case TBitString:
+  case TEnumerated:
+  case TOID:
+  case TSequence:
+  case TSequenceOf:
+  case TApplication:
+  case TType:
+    fprintf (codefile,
+            "size_t ret = 0;\n"
+            "size_t l;\n"
+            "int i, e;\n\n");
+    fprintf(codefile, "i = 0;\n"); /* hack to avoid `unused variable' */
+    
+      encode_type("data", s->type);
+
+    fprintf (codefile, "*size = ret;\n"
+            "return 0;\n");
+    break;
+  default:
+    abort ();
+  }
+  fprintf (codefile, "}\n\n");
+}
diff --git a/source4/heimdal/lib/asn1/gen_free.c b/source4/heimdal/lib/asn1/gen_free.c
new file mode 100644 (file)
index 0000000..9665d07
--- /dev/null
@@ -0,0 +1,143 @@
+/*
+ * 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 "gen_locl.h"
+
+RCSID("$Id: gen_free.c,v 1.12 2003/10/03 00:28:08 lha Exp $");
+
+static void
+free_primitive (const char *typename, const char *name)
+{
+    fprintf (codefile, "free_%s(%s);\n", typename, name);
+}
+
+static void
+free_type (const char *name, const Type *t)
+{
+  switch (t->type) {
+  case TType:
+#if 0
+      free_type (name, t->symbol->type);
+#endif
+      fprintf (codefile, "free_%s(%s);\n", t->symbol->gen_name, name);
+      break;
+  case TInteger:
+  case TUInteger:
+  case TBoolean:
+  case TEnumerated :
+      break;
+  case TOctetString:
+      free_primitive ("octet_string", name);
+      break;
+  case TOID :
+      free_primitive ("oid", name);
+      break;
+  case TBitString: {
+      break;
+  }
+  case TSequence: {
+      Member *m;
+      int tag = -1;
+
+      if (t->members == NULL)
+         break;
+      
+      for (m = t->members; m && tag != m->val; m = m->next) {
+         char *s;
+
+         asprintf (&s, "%s(%s)->%s",
+                   m->optional ? "" : "&", name, m->gen_name);
+         if(m->optional)
+             fprintf(codefile, "if(%s) {\n", s);
+         free_type (s, m->type);
+         if(m->optional)
+             fprintf(codefile, 
+                     "free(%s);\n"
+                     "%s = NULL;\n"
+                     "}\n", s, s);
+         if (tag == -1)
+             tag = m->val;
+         free (s);
+      }
+      break;
+  }
+  case TSequenceOf: {
+      char *n;
+
+      fprintf (codefile, "while((%s)->len){\n", name);
+      asprintf (&n, "&(%s)->val[(%s)->len-1]", name, name);
+      free_type(n, t->subtype);
+      fprintf(codefile, 
+             "(%s)->len--;\n"
+             "}\n",
+             name);
+      fprintf(codefile,
+             "free((%s)->val);\n"
+             "(%s)->val = NULL;\n", name, name);
+      free(n);
+      break;
+  }
+  case TGeneralizedTime:
+      break;
+  case TGeneralString:
+      free_primitive ("general_string", name);
+      break;
+  case TUTF8String:
+      free_primitive ("utf8string", name);
+      break;
+  case TNull:
+      break;
+  case TApplication:
+      free_type (name, t->subtype);
+      break;
+  default :
+      abort ();
+  }
+}
+
+void
+generate_type_free (const Symbol *s)
+{
+  fprintf (headerfile,
+          "void   free_%s  (%s *);\n",
+          s->gen_name, s->gen_name);
+
+  fprintf (codefile, "void\n"
+          "free_%s(%s *data)\n"
+          "{\n",
+          s->gen_name, s->gen_name);
+
+  free_type ("data", s->type);
+  fprintf (codefile, "}\n\n");
+}
+
diff --git a/source4/heimdal/lib/asn1/gen_glue.c b/source4/heimdal/lib/asn1/gen_glue.c
new file mode 100644 (file)
index 0000000..6ab4725
--- /dev/null
@@ -0,0 +1,147 @@
+/*
+ * 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 "gen_locl.h"
+
+RCSID("$Id: gen_glue.c,v 1.8 2005/04/25 18:07:07 lha Exp $");
+
+static void
+generate_2int (const Symbol *s)
+{
+    Type *t = s->type;
+    Member *m;
+    int tag = -1;
+
+    fprintf (headerfile,
+            "unsigned %s2int(%s);\n",
+            s->gen_name, s->gen_name);
+
+    fprintf (codefile,
+            "unsigned %s2int(%s f)\n"
+            "{\n"
+            "unsigned r = 0;\n",
+            s->gen_name, s->gen_name);
+
+    for (m = t->members; m && m->val != tag; m = m->next) {
+       fprintf (codefile, "if(f.%s) r |= (1U << %d);\n",
+                m->gen_name, m->val);
+       
+       if (tag == -1)
+           tag = m->val;
+    }
+    fprintf (codefile, "return r;\n"
+            "}\n\n");
+}
+
+static void
+generate_int2 (const Symbol *s)
+{
+    Type *t = s->type;
+    Member *m;
+    int tag = -1;
+
+    fprintf (headerfile,
+            "%s int2%s(unsigned);\n",
+            s->gen_name, s->gen_name);
+
+    fprintf (codefile,
+            "%s int2%s(unsigned n)\n"
+            "{\n"
+            "\t%s flags;\n\n",
+            s->gen_name, s->gen_name, s->gen_name);
+
+    for (m = t->members; m && m->val != tag; m = m->next) {
+       fprintf (codefile, "\tflags.%s = (n >> %d) & 1;\n",
+                m->gen_name, m->val);
+       
+       if (tag == -1)
+           tag = m->val;
+    }
+    fprintf (codefile, "\treturn flags;\n"
+            "}\n\n");
+}
+
+/*
+ * This depends on the bit string being declared in increasing order
+ */
+
+static void
+generate_units (const Symbol *s)
+{
+    Type *t = s->type;
+    Member *m;
+    int tag = -1;
+
+    fprintf (headerfile,
+            "const struct units * asn1_%s_units(void);",
+            s->gen_name);
+
+    fprintf (codefile,
+            "static struct units %s_units[] = {\n",
+            s->gen_name);
+
+    if(t->members)
+       for (m = t->members->prev; m && m->val != tag; m = m->prev) {
+           fprintf (codefile,
+                    "\t{\"%s\",\t1U << %d},\n", m->gen_name, m->val);
+           
+           if (tag == -1)
+               tag = m->val;
+       }
+
+    fprintf (codefile,
+            "\t{NULL,\t0}\n"
+            "};\n\n");
+
+    fprintf (codefile,
+            "const struct units * asn1_%s_units(void){\n"
+            "return %s_units;\n"
+            "}\n\n",
+            s->gen_name, s->gen_name);
+
+
+}
+
+void
+generate_glue (const Symbol *s)
+{
+    switch(s->type->type) {
+    case TBitString :
+       generate_2int (s);
+       generate_int2 (s);
+       generate_units (s);
+       break;
+    default :
+       break;
+    }
+}
diff --git a/source4/heimdal/lib/asn1/gen_length.c b/source4/heimdal/lib/asn1/gen_length.c
new file mode 100644 (file)
index 0000000..c6ea0f7
--- /dev/null
@@ -0,0 +1,188 @@
+/*
+ * 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 "gen_locl.h"
+
+RCSID("$Id: gen_length.c,v 1.14 2004/01/19 17:54:33 lha Exp $");
+
+static void
+length_primitive (const char *typename,
+                 const char *name,
+                 const char *variable)
+{
+    fprintf (codefile, "%s += length_%s(%s);\n", variable, typename, name);
+}
+
+static void
+length_type (const char *name, const Type *t, const char *variable)
+{
+    switch (t->type) {
+    case TType:
+#if 0
+       length_type (name, t->symbol->type);
+#endif
+       fprintf (codefile, "%s += length_%s(%s);\n",
+                variable, t->symbol->gen_name, name);
+       break;
+    case TInteger:
+        if(t->members == NULL)
+            length_primitive ("integer", name, variable);
+        else {
+            char *s;
+            asprintf(&s, "(const int*)%s", name);
+            if(s == NULL)
+               errx (1, "out of memory");
+            length_primitive ("integer", s, variable);
+            free(s);
+        }
+       break;
+    case TUInteger:
+       length_primitive ("unsigned", name, variable);
+       break;
+    case TEnumerated :
+       length_primitive ("enumerated", name, variable);
+       break;
+    case TOctetString:
+       length_primitive ("octet_string", name, variable);
+       break;
+    case TOID :
+       length_primitive ("oid", name, variable);
+       break;
+    case TBitString: {
+       /*
+        * XXX - Hope this is correct
+        * look at TBitString case in `encode_type'
+        */
+       fprintf (codefile, "%s += 7;\n", variable);
+       break;
+    }
+    case TSequence: {
+       Member *m;
+       int tag = -1;
+       int oldret_counter = unique_get_next();
+
+       if (t->members == NULL)
+           break;
+      
+       for (m = t->members; m && tag != m->val; m = m->next) {
+           char *s;
+
+           asprintf (&s, "%s(%s)->%s",
+                     m->optional ? "" : "&", name, m->gen_name);
+           if (m->optional)
+               fprintf (codefile, "if(%s)", s);
+           fprintf (codefile, "{\n"
+                    "int oldret%d = %s;\n"
+                    "%s = 0;\n", oldret_counter, variable, variable);
+           length_type (s, m->type, "ret");
+           fprintf (codefile, "%s += 1 + length_len(%s) + oldret%d;\n",
+                    variable, variable, oldret_counter);
+           fprintf (codefile, "}\n");
+           if (tag == -1)
+               tag = m->val;
+           free (s);
+       }
+       fprintf (codefile,
+                "%s += 1 + length_len(%s);\n", variable, variable);
+       break;
+    }
+    case TSequenceOf: {
+       char *n;
+       int oldret_counter = unique_get_next();
+       int oldret_counter_inner = unique_get_next();
+
+       fprintf (codefile,
+                "{\n"
+                "int oldret%d = %s;\n"
+                "int i;\n"
+                "%s = 0;\n",
+                oldret_counter, variable, variable);
+
+       fprintf (codefile, "for(i = (%s)->len - 1; i >= 0; --i){\n", name);
+       fprintf (codefile, "int oldret%d = %s;\n"
+                "%s = 0;\n", oldret_counter_inner, variable, variable);
+       asprintf (&n, "&(%s)->val[i]", name);
+       length_type(n, t->subtype, variable);
+       fprintf (codefile, "%s += oldret%d;\n",
+                variable, oldret_counter_inner);
+       fprintf (codefile, "}\n");
+
+       fprintf (codefile,
+                "%s += 1 + length_len(%s) + oldret%d;\n"
+                "}\n", variable, variable, oldret_counter);
+       free(n);
+       break;
+    }
+    case TGeneralizedTime:
+       length_primitive ("generalized_time", name, variable);
+       break;
+    case TGeneralString:
+       length_primitive ("general_string", name, variable);
+       break;
+    case TUTF8String:
+       length_primitive ("utf8string", name, variable);
+       break;
+    case TNull:
+       fprintf (codefile, "%s += length_nulltype();\n", variable);
+       break;
+    case TApplication:
+       length_type (name, t->subtype, variable);
+       fprintf (codefile, "ret += 1 + length_len (ret);\n");
+       break;
+    case TBoolean:
+       length_primitive ("boolean", name, variable);
+       break;
+    default :
+       abort ();
+    }
+}
+
+void
+generate_type_length (const Symbol *s)
+{
+  unique_reset();
+  fprintf (headerfile,
+          "size_t length_%s(const %s *);\n",
+          s->gen_name, s->gen_name);
+
+  fprintf (codefile,
+          "size_t\n"
+          "length_%s(const %s *data)\n"
+          "{\n"
+          "size_t ret = 0;\n",
+          s->gen_name, s->gen_name);
+
+  length_type ("data", s->type, "ret");
+  fprintf (codefile, "return ret;\n}\n\n");
+}
+
diff --git a/source4/heimdal/lib/asn1/gen_locl.h b/source4/heimdal/lib/asn1/gen_locl.h
new file mode 100644 (file)
index 0000000..adaf853
--- /dev/null
@@ -0,0 +1,77 @@
+/*
+ * 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. 
+ */
+
+/* $Id: gen_locl.h,v 1.10 2005/06/16 19:58:58 lha Exp $ */
+
+#ifndef __GEN_LOCL_H__
+#define __GEN_LOCL_H__
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+#include <assert.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <limits.h>
+#include <ctype.h>
+#include <time.h>
+#include <errno.h>
+#include <err.h>
+#include <roken.h>
+#include "hash.h"
+#include "symbol.h"
+
+void generate_type (const Symbol *);
+void generate_constant (const Symbol *);
+void generate_type_encode (const Symbol *s);
+void generate_type_decode (const Symbol *s);
+void generate_seq_type_decode (const Symbol *s);
+void generate_type_free (const Symbol *s);
+void generate_type_length (const Symbol *s);
+void generate_type_copy (const Symbol *s);
+void generate_type_maybe (const Symbol *s);
+void generate_glue (const Symbol *s);
+
+void unique_reset(void);
+int unique_get_next(void);
+
+void init_generate (const char *filename, const char *basename);
+const char *get_filename (void);
+void close_generate(void);
+void add_import(const char *module);
+int yyparse(void);
+
+extern FILE *headerfile, *codefile, *logfile;
+
+#endif /* __GEN_LOCL_H__ */
diff --git a/source4/heimdal/lib/asn1/hash.c b/source4/heimdal/lib/asn1/hash.c
new file mode 100644 (file)
index 0000000..54be897
--- /dev/null
@@ -0,0 +1,207 @@
+/*
+ * 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. 
+ */
+
+/*
+ * Hash table functions
+ */
+
+#include "gen_locl.h"
+
+RCSID("$Id: hash.c,v 1.9 2005/01/08 22:55:26 lha Exp $");
+
+static Hashentry *_search(Hashtab * htab,      /* The hash table */
+                         void *ptr);   /* And key */
+
+Hashtab *
+hashtabnew(int sz,
+          int (*cmp) (void *, void *),
+          unsigned (*hash) (void *))
+{
+    Hashtab *htab;
+    int i;
+
+    assert(sz > 0);
+
+    htab = (Hashtab *) malloc(sizeof(Hashtab) + (sz - 1) * sizeof(Hashentry *));
+    for (i = 0; i < sz; ++i)
+       htab->tab[i] = NULL;
+
+    if (htab == NULL) {
+       return NULL;
+    } else {
+       htab->cmp = cmp;
+       htab->hash = hash;
+       htab->sz = sz;
+       return htab;
+    }
+}
+
+/* Intern search function */
+
+static Hashentry *
+_search(Hashtab * htab, void *ptr)
+{
+    Hashentry *hptr;
+
+    assert(htab && ptr);
+
+    for (hptr = htab->tab[(*htab->hash) (ptr) % htab->sz];
+        hptr;
+        hptr = hptr->next)
+       if ((*htab->cmp) (ptr, hptr->ptr) == 0)
+           break;
+    return hptr;
+}
+
+/* Search for element in hash table */
+
+void *
+hashtabsearch(Hashtab * htab, void *ptr)
+{
+    Hashentry *tmp;
+
+    tmp = _search(htab, ptr);
+    return tmp ? tmp->ptr : tmp;
+}
+
+/* add element to hash table */
+/* if already there, set new value */
+/* !NULL if succesful */
+
+void *
+hashtabadd(Hashtab * htab, void *ptr)
+{
+    Hashentry *h = _search(htab, ptr);
+    Hashentry **tabptr;
+
+    assert(htab && ptr);
+
+    if (h)
+       free((void *) h->ptr);
+    else {
+       h = (Hashentry *) malloc(sizeof(Hashentry));
+       if (h == NULL) {
+           return NULL;
+       }
+       tabptr = &htab->tab[(*htab->hash) (ptr) % htab->sz];
+       h->next = *tabptr;
+       *tabptr = h;
+       h->prev = tabptr;
+       if (h->next)
+           h->next->prev = &h->next;
+    }
+    h->ptr = ptr;
+    return h;
+}
+
+/* delete element with key key. Iff freep, free Hashentry->ptr */
+
+int
+_hashtabdel(Hashtab * htab, void *ptr, int freep)
+{
+    Hashentry *h;
+
+    assert(htab && ptr);
+
+    h = _search(htab, ptr);
+    if (h) {
+       if (freep)
+           free(h->ptr);
+       if ((*(h->prev) = h->next))
+           h->next->prev = h->prev;
+       free(h);
+       return 0;
+    } else
+       return -1;
+}
+
+/* Do something for each element */
+
+void
+hashtabforeach(Hashtab * htab, int (*func) (void *ptr, void *arg),
+              void *arg)
+{
+    Hashentry **h, *g;
+
+    assert(htab);
+
+    for (h = htab->tab; h < &htab->tab[htab->sz]; ++h)
+       for (g = *h; g; g = g->next)
+           if ((*func) (g->ptr, arg))
+               return;
+}
+
+/* standard hash-functions for strings */
+
+unsigned
+hashadd(const char *s)
+{                              /* Standard hash function */
+    unsigned i;
+
+    assert(s);
+
+    for (i = 0; *s; ++s)
+       i += *s;
+    return i;
+}
+
+unsigned
+hashcaseadd(const char *s)
+{                              /* Standard hash function */
+    unsigned i;
+
+    assert(s);
+
+    for (i = 0; *s; ++s)
+       i += toupper((unsigned char)*s);
+    return i;
+}
+
+#define TWELVE (sizeof(unsigned))
+#define SEVENTYFIVE (6*sizeof(unsigned))
+#define HIGH_BITS (~((unsigned)(~0) >> TWELVE))
+
+unsigned
+hashjpw(const char *ss)
+{                              /* another hash function */
+    unsigned h = 0;
+    unsigned g;
+    const unsigned char *s = (const unsigned char *)ss;
+
+    for (; *s; ++s) {
+       h = (h << TWELVE) + *s;
+       if ((g = h & HIGH_BITS))
+           h = (h ^ (g >> SEVENTYFIVE)) & ~HIGH_BITS;
+    }
+    return h;
+}
diff --git a/source4/heimdal/lib/asn1/hash.h b/source4/heimdal/lib/asn1/hash.h
new file mode 100644 (file)
index 0000000..b54e102
--- /dev/null
@@ -0,0 +1,87 @@
+/*
+ * 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. 
+ */
+
+/*
+ * hash.h. Header file for hash table functions
+ */
+
+/* $Id: hash.h,v 1.3 1999/12/02 17:05:02 joda Exp $ */
+
+struct hashentry {             /* Entry in bucket */
+     struct hashentry **prev;
+     struct hashentry *next;
+     void *ptr;
+};
+
+typedef struct hashentry Hashentry;
+
+struct hashtab {               /* Hash table */
+     int (*cmp)(void *, void *); /* Compare function */
+     unsigned (*hash)(void *); /* hash function */
+     int sz;                   /* Size */
+     Hashentry *tab[1];                /* The table */
+};
+
+typedef struct hashtab Hashtab;
+
+/* prototypes */
+
+Hashtab *hashtabnew(int sz, 
+                   int (*cmp)(void *, void *),
+                   unsigned (*hash)(void *));  /* Make new hash table */
+
+void *hashtabsearch(Hashtab *htab, /* The hash table */
+                   void *ptr); /*  The key */
+
+
+void *hashtabadd(Hashtab *htab,        /* The hash table */
+              void *ptr);      /* The element */
+
+int _hashtabdel(Hashtab *htab, /* The table */
+               void *ptr,      /* Key */
+               int freep);     /* Free data part? */
+
+void hashtabforeach(Hashtab *htab,
+                   int (*func)(void *ptr, void *arg),
+                   void *arg);
+
+unsigned hashadd(const char *s);               /* Standard hash function */
+unsigned hashcaseadd(const char *s);           /* Standard hash function */
+unsigned hashjpw(const char *s);               /* another hash function */
+
+/* macros */
+
+ /* Don't free space */
+#define hashtabdel(htab,key)  _hashtabdel(htab,key,FALSE)
+
+#define hashtabfree(htab,key) _hashtabdel(htab,key,TRUE) /* Do! */
diff --git a/source4/heimdal/lib/asn1/k5.asn1 b/source4/heimdal/lib/asn1/k5.asn1
new file mode 100644 (file)
index 0000000..802c0a4
--- /dev/null
@@ -0,0 +1,590 @@
+-- $Id: k5.asn1,v 1.43 2005/06/17 04:58:59 lha Exp $
+
+KERBEROS5 DEFINITIONS ::=
+BEGIN
+
+NAME-TYPE ::= INTEGER {
+       KRB5_NT_UNKNOWN(0),     -- Name type not known
+       KRB5_NT_PRINCIPAL(1),   -- Just the name of the principal as in
+       KRB5_NT_SRV_INST(2),    -- Service and other unique instance (krbtgt)
+       KRB5_NT_SRV_HST(3),     -- Service with host name as instance
+       KRB5_NT_SRV_XHST(4),    -- Service with host as remaining components
+       KRB5_NT_UID(5),         -- Unique ID
+       KRB5_NT_X500_PRINCIPAL(6), -- PKINIT
+       KRB5_NT_ENTERPRISE(10)  -- May be mapped to principal name
+}
+
+-- message types
+
+MESSAGE-TYPE ::= INTEGER {
+       krb-as-req(10), -- Request for initial authentication
+       krb-as-rep(11), -- Response to KRB_AS_REQ request
+       krb-tgs-req(12), -- Request for authentication based on TGT
+       krb-tgs-rep(13), -- Response to KRB_TGS_REQ request
+       krb-ap-req(14), -- application request to server
+       krb-ap-rep(15), -- Response to KRB_AP_REQ_MUTUAL
+       krb-safe(20), -- Safe (checksummed) application message
+       krb-priv(21), -- Private (encrypted) application message
+       krb-cred(22), -- Private (encrypted) message to forward credentials
+       krb-error(30) -- Error response
+}
+
+
+-- pa-data types
+
+PADATA-TYPE ::= INTEGER {
+       KRB5-PADATA-NONE(0),
+       KRB5-PADATA-TGS-REQ(1),
+       KRB5-PADATA-AP-REQ(1),
+       KRB5-PADATA-ENC-TIMESTAMP(2),
+       KRB5-PADATA-PW-SALT(3),
+       KRB5-PADATA-ENC-UNIX-TIME(5),
+       KRB5-PADATA-SANDIA-SECUREID(6),
+       KRB5-PADATA-SESAME(7),
+       KRB5-PADATA-OSF-DCE(8),
+       KRB5-PADATA-CYBERSAFE-SECUREID(9),
+       KRB5-PADATA-AFS3-SALT(10),
+       KRB5-PADATA-ETYPE-INFO(11),
+       KRB5-PADATA-SAM-CHALLENGE(12), -- (sam/otp)
+       KRB5-PADATA-SAM-RESPONSE(13), -- (sam/otp)
+       KRB5-PADATA-PK-AS-REQ-19(14), -- (PKINIT-19)
+       KRB5-PADATA-PK-AS-REP-19(15), -- (PKINIT-19)
+       KRB5-PADATA-PK-AS-REQ(16), -- (PKINIT-25)
+       KRB5-PADATA-PK-AS-REP(17), -- (PKINIT-25)
+       KRB5-PADATA-ETYPE-INFO2(19),
+       KRB5-PADATA-USE-SPECIFIED-KVNO(20),
+       KRB5-PADATA-SAM-REDIRECT(21), -- (sam/otp)
+       KRB5-PADATA-GET-FROM-TYPED-DATA(22),
+       KRB5-PADATA-SAM-ETYPE-INFO(23),
+       KRB5-PADATA-SERVER-REFERRAL(25),
+       KRB5-PADATA-TD-KRB-PRINCIPAL(102),      -- PrincipalName
+       KRB5-PADATA-TD-KRB-REALM(103),          -- Realm
+       KRB5-PADATA-PK-TD-TRUSTED-CERTIFIERS(104), -- PKINIT
+       KRB5-PADATA-PK-TD-CERTIFICATE-INDEX(105), -- PKINIT
+       KRB5-PADATA-TD-APP-DEFINED-ERROR(106),  -- application specific
+       KRB5-PADATA-TD-REQ-NONCE(107),          -- INTEGER
+       KRB5-PADATA-TD-REQ-SEQ(108),            -- INTEGER
+       KRB5-PADATA-PA-PAC-REQUEST(128)         -- jbrezak@exchange.microsoft.com
+}
+
+AUTHDATA-TYPE ::= INTEGER {
+       KRB5-AUTHDATA-IF-RELEVANT(1),
+       KRB5-AUTHDATA-INTENDED-FOR_SERVER(2),
+       KRB5-AUTHDATA-INTENDED-FOR-APPLICATION-CLASS(3),
+       KRB5-AUTHDATA-KDC-ISSUED(4),
+       KRB5-AUTHDATA-AND-OR(5),
+       KRB5-AUTHDATA-MANDATORY-TICKET-EXTENSIONS(6),
+       KRB5-AUTHDATA-IN-TICKET-EXTENSIONS(7),
+       KRB5-AUTHDATA-MANDATORY-FOR-KDC(8),
+       KRB5-AUTHDATA-OSF-DCE(64),
+       KRB5-AUTHDATA-SESAME(65),
+       KRB5-AUTHDATA-OSF-DCE-PKI-CERTID(66),
+       KRB5-AUTHDATA-WIN2K-PAC(128),
+       KRB5-AUTHDATA-GSS-API-ETYPE-NEGOTIATION(129) -- Authenticator only
+}
+
+-- checksumtypes
+
+CKSUMTYPE ::= INTEGER {
+       CKSUMTYPE_NONE(0),
+       CKSUMTYPE_CRC32(1),
+       CKSUMTYPE_RSA_MD4(2),
+       CKSUMTYPE_RSA_MD4_DES(3),
+       CKSUMTYPE_DES_MAC(4),
+       CKSUMTYPE_DES_MAC_K(5),
+       CKSUMTYPE_RSA_MD4_DES_K(6),
+       CKSUMTYPE_RSA_MD5(7),
+       CKSUMTYPE_RSA_MD5_DES(8),
+       CKSUMTYPE_RSA_MD5_DES3(9),
+       CKSUMTYPE_SHA1_OTHER(10),
+       CKSUMTYPE_HMAC_SHA1_DES3(12),
+       CKSUMTYPE_SHA1(14),
+       CKSUMTYPE_HMAC_SHA1_96_AES_128(15),
+       CKSUMTYPE_HMAC_SHA1_96_AES_256(16),
+       CKSUMTYPE_GSSAPI(0x8003),
+       CKSUMTYPE_HMAC_MD5(-138),       -- unofficial microsoft number
+       CKSUMTYPE_HMAC_MD5_ENC(-1138)   -- even more unofficial
+}
+
+--enctypes
+ENCTYPE ::= INTEGER {
+       ETYPE_NULL(0),
+       ETYPE_DES_CBC_CRC(1),
+       ETYPE_DES_CBC_MD4(2),
+       ETYPE_DES_CBC_MD5(3),
+       ETYPE_DES3_CBC_MD5(5),
+       ETYPE_OLD_DES3_CBC_SHA1(7),
+       ETYPE_SIGN_DSA_GENERATE(8),
+       ETYPE_ENCRYPT_RSA_PRIV(9),
+       ETYPE_ENCRYPT_RSA_PUB(10),
+       ETYPE_DES3_CBC_SHA1(16),        -- with key derivation
+       ETYPE_AES128_CTS_HMAC_SHA1_96(17),
+       ETYPE_AES256_CTS_HMAC_SHA1_96(18),
+       ETYPE_ARCFOUR_HMAC_MD5(23),
+       ETYPE_ARCFOUR_HMAC_MD5_56(24),
+       ETYPE_ENCTYPE_PK_CROSS(48),
+-- these are for Heimdal internal use
+       ETYPE_DES_CBC_NONE(-0x1000),
+       ETYPE_DES3_CBC_NONE(-0x1001),
+       ETYPE_DES_CFB64_NONE(-0x1002),
+       ETYPE_DES_PCBC_NONE(-0x1003),
+       ETYPE_DIGEST_MD5_NONE(-0x1004),         -- private use, lukeh@padl.com
+       ETYPE_CRAM_MD5_NONE(-0x1005),           -- private use, lukeh@padl.com
+       ETYPE_RC2_CBC_NONE(-0x1006),
+       ETYPE_AES128_CBC_NONE(-0x1007),
+       ETYPE_AES192_CBC_NONE(-0x1008),
+       ETYPE_AES256_CBC_NONE(-0x1009),
+       ETYPE_DES3_CBC_NONE_CMS(-0x100a)
+}
+
+-- this is sugar to make something ASN1 does not have: unsigned
+
+UNSIGNED ::= INTEGER (0..4294967295)
+
+KerberosString  ::= GeneralString
+
+Realm ::= GeneralString
+PrincipalName ::= SEQUENCE {
+       name-type[0]            NAME-TYPE,
+       name-string[1]          SEQUENCE OF GeneralString
+}
+
+-- this is not part of RFC1510
+Principal ::= SEQUENCE {
+       name[0]                 PrincipalName,
+       realm[1]                Realm
+}
+
+HostAddress ::= SEQUENCE  {
+       addr-type[0]            INTEGER,
+       address[1]              OCTET STRING
+}
+
+-- This is from RFC1510.
+--
+-- HostAddresses ::= SEQUENCE OF SEQUENCE {
+--     addr-type[0]            INTEGER,
+--     address[1]              OCTET STRING
+-- }
+
+-- This seems much better.
+HostAddresses ::= SEQUENCE OF HostAddress
+
+
+KerberosTime ::= GeneralizedTime -- Specifying UTC time zone (Z)
+
+AuthorizationData ::= SEQUENCE OF SEQUENCE {
+       ad-type[0]              INTEGER,
+       ad-data[1]              OCTET STRING
+}
+
+APOptions ::= BIT STRING {
+       reserved(0),
+       use-session-key(1),
+       mutual-required(2)
+}
+
+TicketFlags ::= BIT STRING {
+       reserved(0),
+       forwardable(1),
+       forwarded(2),
+       proxiable(3),
+       proxy(4),
+       may-postdate(5),
+       postdated(6),
+       invalid(7),
+       renewable(8),
+       initial(9),
+       pre-authent(10),
+       hw-authent(11),
+       transited-policy-checked(12),
+       ok-as-delegate(13),
+       anonymous(14)
+}
+
+KDCOptions ::= BIT STRING {
+       reserved(0),
+       forwardable(1),
+       forwarded(2),
+       proxiable(3),
+       proxy(4),
+       allow-postdate(5),
+       postdated(6),
+       unused7(7),
+       renewable(8),
+       unused9(9),
+       unused10(10),
+       unused11(11),
+       request-anonymous(14),
+       canonicalize(15),
+       disable-transited-check(26),
+       renewable-ok(27),
+       enc-tkt-in-skey(28),
+       renew(30),
+       validate(31)
+}
+
+LR-TYPE ::= INTEGER {
+       LR_NONE(0),             -- no information
+       LR_INITIAL_TGT(1),      -- last initial TGT request
+       LR_INITIAL(2),          -- last initial request
+       LR_ISSUE_USE_TGT(3),    -- time of newest TGT used
+       LR_RENEWAL(4),          -- time of last renewal
+       LR_REQUEST(5),          -- time of last request (of any type)
+       LR_PW_EXPTIME(6),       -- expiration time of password
+       LR_ACCT_EXPTIME(7)      -- expiration time of account
+}
+
+LastReq ::= SEQUENCE OF SEQUENCE {
+       lr-type[0]              LR-TYPE,
+       lr-value[1]             KerberosTime
+}
+
+
+EncryptedData ::= SEQUENCE {
+       etype[0]                ENCTYPE, -- EncryptionType
+       kvno[1]                 INTEGER OPTIONAL,
+       cipher[2]               OCTET STRING -- ciphertext
+}
+
+EncryptionKey ::= SEQUENCE {
+       keytype[0]              INTEGER,
+       keyvalue[1]             OCTET STRING
+}
+
+-- encoded Transited field
+TransitedEncoding ::= SEQUENCE {
+       tr-type[0]              INTEGER, -- must be registered
+       contents[1]             OCTET STRING
+}
+
+Ticket ::= [APPLICATION 1] SEQUENCE {
+       tkt-vno[0]              INTEGER,
+       realm[1]                Realm,
+       sname[2]                PrincipalName,
+       enc-part[3]             EncryptedData
+}
+-- Encrypted part of ticket
+EncTicketPart ::= [APPLICATION 3] SEQUENCE {
+       flags[0]                TicketFlags,
+       key[1]                  EncryptionKey,
+       crealm[2]               Realm,
+       cname[3]                PrincipalName,
+       transited[4]            TransitedEncoding,
+       authtime[5]             KerberosTime,
+       starttime[6]            KerberosTime OPTIONAL,
+       endtime[7]              KerberosTime,
+       renew-till[8]           KerberosTime OPTIONAL,
+       caddr[9]                HostAddresses OPTIONAL,
+       authorization-data[10]  AuthorizationData OPTIONAL
+}
+
+Checksum ::= SEQUENCE {
+       cksumtype[0]            CKSUMTYPE,
+       checksum[1]             OCTET STRING
+}
+
+Authenticator ::= [APPLICATION 2] SEQUENCE    {
+       authenticator-vno[0]    INTEGER,
+       crealm[1]               Realm,
+       cname[2]                PrincipalName,
+       cksum[3]                Checksum OPTIONAL,
+       cusec[4]                INTEGER,
+       ctime[5]                KerberosTime,
+       subkey[6]               EncryptionKey OPTIONAL,
+       seq-number[7]           UNSIGNED OPTIONAL,
+       authorization-data[8]   AuthorizationData OPTIONAL
+       }
+
+PA-DATA ::= SEQUENCE {
+       -- might be encoded AP-REQ
+       padata-type[1]          PADATA-TYPE,
+       padata-value[2]         OCTET STRING
+}
+
+ETYPE-INFO-ENTRY ::= SEQUENCE {
+       etype[0]                ENCTYPE,
+       salt[1]                 OCTET STRING OPTIONAL,
+       salttype[2]             INTEGER OPTIONAL
+}
+
+ETYPE-INFO ::= SEQUENCE OF ETYPE-INFO-ENTRY
+
+ETYPE-INFO2-ENTRY ::= SEQUENCE {
+       etype[0]                ENCTYPE,
+       salt[1]                 KerberosString OPTIONAL,
+       s2kparams[2]            OCTET STRING OPTIONAL
+}
+
+ETYPE-INFO2 ::= SEQUENCE OF ETYPE-INFO2-ENTRY
+
+METHOD-DATA ::= SEQUENCE OF PA-DATA
+
+KDC-REQ-BODY ::= SEQUENCE {
+       kdc-options[0]          KDCOptions,
+       cname[1]                PrincipalName OPTIONAL, -- Used only in AS-REQ
+       realm[2]                Realm,  -- Server's realm
+                                       -- Also client's in AS-REQ
+       sname[3]                PrincipalName OPTIONAL,
+       from[4]                 KerberosTime OPTIONAL,
+       till[5]                 KerberosTime OPTIONAL,
+       rtime[6]                KerberosTime OPTIONAL,
+       nonce[7]                INTEGER,
+       etype[8]                SEQUENCE OF ENCTYPE, -- EncryptionType,
+                                       -- in preference order
+       addresses[9]            HostAddresses OPTIONAL,
+       enc-authorization-data[10] EncryptedData OPTIONAL,
+                                       -- Encrypted AuthorizationData encoding
+       additional-tickets[11]  SEQUENCE OF Ticket OPTIONAL
+}
+
+KDC-REQ ::= SEQUENCE {
+       pvno[1]                 INTEGER,
+       msg-type[2]             MESSAGE-TYPE,
+       padata[3]               METHOD-DATA OPTIONAL,
+       req-body[4]             KDC-REQ-BODY
+}
+
+AS-REQ ::= [APPLICATION 10] KDC-REQ
+TGS-REQ ::= [APPLICATION 12] KDC-REQ
+
+-- padata-type ::= PA-ENC-TIMESTAMP
+-- padata-value ::= EncryptedData - PA-ENC-TS-ENC
+
+PA-ENC-TS-ENC ::= SEQUENCE {
+       patimestamp[0]          KerberosTime, -- client's time
+       pausec[1]               INTEGER OPTIONAL
+}
+
+-- draft-brezak-win2k-krb-authz-01
+PA-PAC-REQUEST ::= SEQUENCE {
+       include-pac[0]          BOOLEAN -- Indicates whether a PAC 
+                                       -- should be included or not
+}
+
+KDC-REP ::= SEQUENCE {
+       pvno[0]                 INTEGER,
+       msg-type[1]             MESSAGE-TYPE,
+       padata[2]               METHOD-DATA OPTIONAL,
+       crealm[3]               Realm,
+       cname[4]                PrincipalName,
+       ticket[5]               Ticket,
+       enc-part[6]             EncryptedData
+}
+
+AS-REP ::= [APPLICATION 11] KDC-REP
+TGS-REP ::= [APPLICATION 13] KDC-REP
+
+EncKDCRepPart ::= SEQUENCE {
+       key[0]                  EncryptionKey,
+       last-req[1]             LastReq,
+       nonce[2]                INTEGER,
+       key-expiration[3]       KerberosTime OPTIONAL,
+       flags[4]                TicketFlags,
+       authtime[5]             KerberosTime,
+       starttime[6]            KerberosTime OPTIONAL,
+       endtime[7]              KerberosTime,
+       renew-till[8]           KerberosTime OPTIONAL,
+       srealm[9]               Realm,
+       sname[10]               PrincipalName,
+       caddr[11]               HostAddresses OPTIONAL
+}
+
+EncASRepPart ::= [APPLICATION 25] EncKDCRepPart
+EncTGSRepPart ::= [APPLICATION 26] EncKDCRepPart
+
+AP-REQ ::= [APPLICATION 14] SEQUENCE {
+       pvno[0]                 INTEGER,
+       msg-type[1]             MESSAGE-TYPE,
+       ap-options[2]           APOptions,
+       ticket[3]               Ticket,
+       authenticator[4]        EncryptedData
+}
+
+AP-REP ::= [APPLICATION 15] SEQUENCE {
+       pvno[0]                 INTEGER,
+       msg-type[1]             MESSAGE-TYPE,
+       enc-part[2]             EncryptedData
+}
+
+EncAPRepPart ::= [APPLICATION 27]     SEQUENCE {
+       ctime[0]                KerberosTime,
+       cusec[1]                INTEGER,
+       subkey[2]               EncryptionKey OPTIONAL,
+       seq-number[3]           UNSIGNED OPTIONAL
+}
+
+KRB-SAFE-BODY ::= SEQUENCE {
+       user-data[0]            OCTET STRING,
+       timestamp[1]            KerberosTime OPTIONAL,
+       usec[2]                 INTEGER OPTIONAL,
+       seq-number[3]           UNSIGNED OPTIONAL,
+       s-address[4]            HostAddress OPTIONAL,
+       r-address[5]            HostAddress OPTIONAL
+}
+
+KRB-SAFE ::= [APPLICATION 20] SEQUENCE {
+       pvno[0]                 INTEGER,
+       msg-type[1]             MESSAGE-TYPE,
+       safe-body[2]            KRB-SAFE-BODY,
+       cksum[3]                Checksum
+}
+
+KRB-PRIV ::= [APPLICATION 21] SEQUENCE {
+       pvno[0]                 INTEGER,
+       msg-type[1]             MESSAGE-TYPE,
+       enc-part[3]             EncryptedData
+}
+EncKrbPrivPart ::= [APPLICATION 28] SEQUENCE {
+       user-data[0]            OCTET STRING,
+       timestamp[1]            KerberosTime OPTIONAL,
+       usec[2]                 INTEGER OPTIONAL,
+       seq-number[3]           UNSIGNED OPTIONAL,
+       s-address[4]            HostAddress OPTIONAL, -- sender's addr
+       r-address[5]            HostAddress OPTIONAL  -- recip's addr
+}
+
+KRB-CRED ::= [APPLICATION 22]   SEQUENCE {
+       pvno[0]                 INTEGER,
+       msg-type[1]             MESSAGE-TYPE, -- KRB_CRED
+       tickets[2]              SEQUENCE OF Ticket,
+       enc-part[3]             EncryptedData
+}
+
+KrbCredInfo ::= SEQUENCE {
+       key[0]                  EncryptionKey,
+       prealm[1]               Realm OPTIONAL,
+       pname[2]                PrincipalName OPTIONAL,
+       flags[3]                TicketFlags OPTIONAL,
+       authtime[4]             KerberosTime OPTIONAL,
+       starttime[5]            KerberosTime OPTIONAL,
+       endtime[6]              KerberosTime OPTIONAL,
+       renew-till[7]           KerberosTime OPTIONAL,
+       srealm[8]               Realm OPTIONAL,
+       sname[9]                PrincipalName OPTIONAL,
+       caddr[10]               HostAddresses OPTIONAL
+}
+
+EncKrbCredPart ::= [APPLICATION 29]   SEQUENCE {
+       ticket-info[0]          SEQUENCE OF KrbCredInfo,
+       nonce[1]                INTEGER OPTIONAL,
+       timestamp[2]            KerberosTime OPTIONAL,
+       usec[3]                 INTEGER OPTIONAL,
+       s-address[4]            HostAddress OPTIONAL,
+       r-address[5]            HostAddress OPTIONAL
+}
+
+KRB-ERROR ::= [APPLICATION 30] SEQUENCE {
+       pvno[0]                 INTEGER,
+       msg-type[1]             MESSAGE-TYPE,
+       ctime[2]                KerberosTime OPTIONAL,
+       cusec[3]                INTEGER OPTIONAL,
+       stime[4]                KerberosTime,
+       susec[5]                INTEGER,
+       error-code[6]           INTEGER,
+       crealm[7]               Realm OPTIONAL,
+       cname[8]                PrincipalName OPTIONAL,
+       realm[9]                Realm, -- Correct realm
+       sname[10]               PrincipalName, -- Correct name
+       e-text[11]              GeneralString OPTIONAL,
+       e-data[12]              OCTET STRING OPTIONAL
+}
+
+ChangePasswdDataMS ::= SEQUENCE {
+       newpasswd[0]            OCTET STRING,
+       targname[1]             PrincipalName OPTIONAL,
+       targrealm[2]            Realm OPTIONAL
+}
+
+EtypeList ::= SEQUENCE OF INTEGER
+       -- the client's proposed enctype list in
+       -- decreasing preference order, favorite choice first
+
+krb5-pvno INTEGER ::= 5 -- current Kerberos protocol version number
+
+-- transited encodings
+
+DOMAIN-X500-COMPRESS   INTEGER ::= 1
+
+-- authorization data primitives
+
+AD-IF-RELEVANT ::= AuthorizationData
+
+AD-KDCIssued ::= SEQUENCE {
+       ad-checksum[0]          Checksum,
+       i-realm[1]              Realm OPTIONAL,
+       i-sname[2]              PrincipalName OPTIONAL,
+       elements[3]             AuthorizationData
+}
+
+AD-AND-OR ::= SEQUENCE {
+       condition-count[0]      INTEGER,
+       elements[1]             AuthorizationData
+}
+
+AD-MANDATORY-FOR-KDC ::= AuthorizationData
+
+-- PA-SAM-RESPONSE-2/PA-SAM-RESPONSE-2
+
+PA-SAM-TYPE ::= INTEGER {
+       PA_SAM_TYPE_ENIGMA(1),          -- Enigma Logic
+       PA_SAM_TYPE_DIGI_PATH(2),       -- Digital Pathways
+       PA_SAM_TYPE_SKEY_K0(3),         -- S/key where  KDC has key 0
+       PA_SAM_TYPE_SKEY(4),            -- Traditional S/Key
+       PA_SAM_TYPE_SECURID(5),         -- Security Dynamics
+       PA_SAM_TYPE_CRYPTOCARD(6)       -- CRYPTOCard
+}
+
+PA-SAM-REDIRECT ::= HostAddresses
+
+SAMFlags ::= BIT STRING {
+       use-sad-as-key(0),
+       send-encrypted-sad(1),
+       must-pk-encrypt-sad(2)
+}
+
+PA-SAM-CHALLENGE-2-BODY ::= SEQUENCE {
+       sam-type[0]             INTEGER,
+       sam-flags[1]            SAMFlags,
+       sam-type-name[2]        GeneralString OPTIONAL,
+       sam-track-id[3]         GeneralString OPTIONAL,
+       sam-challenge-label[4]  GeneralString OPTIONAL,
+       sam-challenge[5]        GeneralString OPTIONAL,
+       sam-response-prompt[6]  GeneralString OPTIONAL,
+       sam-pk-for-sad[7]       EncryptionKey OPTIONAL,
+       sam-nonce[8]            INTEGER,
+       sam-etype[9]            INTEGER,
+       ...
+}
+
+PA-SAM-CHALLENGE-2 ::= SEQUENCE {
+       sam-body[0]             PA-SAM-CHALLENGE-2-BODY,
+       sam-cksum[1]            SEQUENCE OF Checksum, -- (1..MAX)
+       ...
+}
+
+PA-SAM-RESPONSE-2 ::= SEQUENCE {
+       sam-type[0]             INTEGER,
+       sam-flags[1]            SAMFlags,
+       sam-track-id[2]         GeneralString OPTIONAL,
+       sam-enc-nonce-or-sad[3] EncryptedData, -- PA-ENC-SAM-RESPONSE-ENC
+       sam-nonce[4]            INTEGER,
+       ...
+}
+
+PA-ENC-SAM-RESPONSE-ENC ::= SEQUENCE {
+       sam-nonce[0]            INTEGER,
+       sam-sad[1]              GeneralString OPTIONAL,
+       ...
+}
+
+RC2CBCParameter ::= SEQUENCE {
+       rc2ParameterVersion     [0] INTEGER,
+       iv                      [1] OCTET STRING -- exactly 8 octets
+}
+
+CBCParameter ::= OCTET STRING
+
+END
+
+-- etags -r '/\([A-Za-z][-A-Za-z0-9]*\).*::=/\1/' k5.asn1
diff --git a/source4/heimdal/lib/asn1/lex.h b/source4/heimdal/lib/asn1/lex.h
new file mode 100644 (file)
index 0000000..9f5cadf
--- /dev/null
@@ -0,0 +1,41 @@
+/*
+ * 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. 
+ */
+
+/* $Id: lex.h,v 1.5 2000/07/01 20:21:34 assar Exp $ */
+
+#include <roken.h>
+
+void error_message (const char *, ...)
+__attribute__ ((format (printf, 1, 2)));
+
+int yylex(void);
diff --git a/source4/heimdal/lib/asn1/lex.l b/source4/heimdal/lib/asn1/lex.l
new file mode 100644 (file)
index 0000000..f0c1234
--- /dev/null
@@ -0,0 +1,186 @@
+%{
+/*
+ * 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: lex.l,v 1.25 2005/06/16 19:58:35 lha Exp $ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+#include <stdio.h>
+#include <stdarg.h>
+#include <stdlib.h>
+#include <string.h>
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+#undef ECHO
+#include "symbol.h"
+#include "parse.h"
+#include "lex.h"
+#include "gen_locl.h"
+
+static unsigned lineno = 1;
+
+#define YY_NO_UNPUT
+
+#undef ECHO
+
+static void handle_comment(int type);
+
+%}
+
+
+%%
+INTEGER                        { return INTEGER; }
+BOOLEAN                        { return BOOLEAN; }
+IMPORTS                        { return IMPORTS; }
+FROM                   { return FROM; }
+SEQUENCE               { return SEQUENCE; }
+CHOICE                 { return CHOICE; }
+OF                     { return OF; }
+OCTET                  { return OCTET; }
+STRING                 { return STRING; }
+GeneralizedTime                { return GeneralizedTime; }
+GeneralString          { return GeneralString; }
+UTF8String             { return UTF8String; }
+NULL                   { return NULLTYPE; }
+BIT                    { return BIT; }
+APPLICATION            { return APPLICATION; }
+OPTIONAL               { return OPTIONAL; }
+BEGIN                  { return TBEGIN; }
+END                    { return END; }
+DEFAULT                        { return DEFAULT; }
+DEFINITIONS            { return DEFINITIONS; }
+ENUMERATED             { return ENUMERATED; }
+EXTERNAL               { return EXTERNAL; }
+OBJECT                 { return OBJECT; }
+IDENTIFIER             { return IDENTIFIER; }
+[-,;{}()|\"]           { return *yytext; }
+"["                    { return *yytext; }
+"]"                    { return *yytext; }
+::=                    { return EEQUAL; }
+--                     { handle_comment(0); }
+\/\*                   { handle_comment(1); }
+0x[0-9A-Fa-f]+|[0-9]+  { char *e, *y = yytext;
+                         yylval.constant = strtol((const char *)yytext,
+                                                  &e, 0);
+                         if(e == y) 
+                           error_message("malformed constant (%s)", yytext); 
+                         else
+                           return CONSTANT;
+                       }
+[A-Za-z][-A-Za-z0-9_]* {
+                         yylval.name =  strdup ((const char *)yytext);
+                         return IDENT;
+                       }
+[ \t]                  ;
+\n                     { ++lineno; }
+\.\.\.                 { return DOTDOTDOT; }
+\.\.                   { return DOTDOT; }
+.                      { error_message("Ignoring char(%c)\n", *yytext); }
+%%
+
+#ifndef yywrap /* XXX */
+int
+yywrap () 
+{
+     return 1;
+}
+#endif
+
+void
+error_message (const char *format, ...)
+{
+     va_list args;
+
+     va_start (args, format);
+     fprintf (stderr, "%s:%d: ", get_filename(), lineno);
+     vfprintf (stderr, format, args);
+     va_end (args);
+}
+
+static void
+handle_comment(int type)
+{
+    int c;
+    int start_lineno = lineno;
+    if(type == 0) {
+       int f = 0;
+       while((c = input()) != EOF) {
+           if(f && c == '-')
+               return;
+           if(c == '-') {
+               f = 1;
+               continue;
+           }
+           if(c == '\n') {
+               lineno++;
+               return;
+           }
+           f = 0;
+       }
+    } else {
+       int level = 1;
+       int seen_star = 0;
+       int seen_slash = 0;
+       while((c = input()) != EOF) {
+           if(c == '/') {
+               if(seen_star) {
+                   if(--level == 0)
+                       return;
+                   seen_star = 0;
+                   continue;
+               }
+               seen_slash = 1;
+               continue;
+           }
+           if(c == '*') {
+               if(seen_slash) {
+                   level++;
+                   seen_star = seen_slash = 0;
+                   continue;
+               } 
+               seen_star = 1;
+               continue;
+           }
+           seen_star = seen_slash = 0;
+           if(c == '\n') {
+               lineno++;
+               continue;
+           }
+       }
+    }
+    if(c == EOF)
+       error_message("unterminated comment, possibly started on line %d\n", start_lineno);
+}
diff --git a/source4/heimdal/lib/asn1/main.c b/source4/heimdal/lib/asn1/main.c
new file mode 100644 (file)
index 0000000..afa164e
--- /dev/null
@@ -0,0 +1,90 @@
+/*
+ * Copyright (c) 1997, 1998, 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 "gen_locl.h"
+#include <getarg.h>
+
+RCSID("$Id: main.c,v 1.13 2005/06/16 20:05:31 lha Exp $");
+
+extern FILE *yyin;
+
+int version_flag;
+int help_flag;
+struct getargs args[] = {
+    { "version", 0, arg_flag, &version_flag },
+    { "help", 0, arg_flag, &help_flag }
+};
+int num_args = sizeof(args) / sizeof(args[0]);
+
+static void
+usage(int code)
+{
+    arg_printusage(args, num_args, NULL, "[asn1-file [name]]");
+    exit(code);
+}
+
+int
+main(int argc, char **argv)
+{
+    int ret;
+    const char *file;
+    const char *name = NULL;
+    int optidx = 0;
+
+    setprogname(argv[0]);
+    if(getarg(args, num_args, argc, argv, &optidx))
+       usage(1);
+    if(help_flag)
+       usage(0);
+    if(version_flag) {
+       print_version(NULL);
+       exit(0);
+    }
+    if (argc == optidx) {
+       file = "stdin";
+       name = "stdin";
+       yyin = stdin;
+    } else {
+       file = argv[optidx];
+       yyin = fopen (file, "r");
+       if (yyin == NULL)
+           err (1, "open %s", file);
+       name = argv[optidx + 1];
+    }
+
+    init_generate (file, name);
+    initsym ();
+    ret = yyparse ();
+    close_generate ();
+    return ret;
+}
diff --git a/source4/heimdal/lib/asn1/parse.y b/source4/heimdal/lib/asn1/parse.y
new file mode 100644 (file)
index 0000000..ab83d45
--- /dev/null
@@ -0,0 +1,295 @@
+/*
+ * 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. 
+ */
+
+/* $Id: parse.y,v 1.23 2004/10/13 17:41:48 lha Exp $ */
+
+%{
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include "symbol.h"
+#include "lex.h"
+#include "gen_locl.h"
+
+RCSID("$Id: parse.y,v 1.23 2004/10/13 17:41:48 lha Exp $");
+
+static Type *new_type (Typetype t);
+void yyerror (char *);
+
+static void append (Member *l, Member *r);
+
+%}
+
+%union {
+  int constant;
+  char *name;
+  Type *type;
+  Member *member;
+  char *defval;
+}
+
+%token INTEGER SEQUENCE CHOICE OF OCTET STRING GeneralizedTime GeneralString 
+%token BIT APPLICATION OPTIONAL EEQUAL TBEGIN END DEFINITIONS ENUMERATED
+%token UTF8String NULLTYPE
+%token EXTERNAL DEFAULT
+%token DOTDOT DOTDOTDOT
+%token BOOLEAN
+%token IMPORTS FROM
+%token OBJECT IDENTIFIER
+%token <name> IDENT 
+%token <constant> CONSTANT
+
+%type <constant> constant optional2
+%type <type> type
+%type <member> memberdecls memberdecl memberdeclstart bitdecls bitdecl
+
+%type <defval> defvalue
+
+%start envelope
+
+%%
+
+envelope       : IDENT DEFINITIONS EEQUAL TBEGIN specification END {}
+               ;
+
+specification  :
+               | specification declaration
+               ;
+
+declaration    : imports_decl
+               | type_decl
+               | constant_decl
+               ;
+
+referencenames : IDENT ',' referencenames
+               {
+                       Symbol *s = addsym($1);
+                       s->stype = Stype;
+               }
+               | IDENT
+               {
+                       Symbol *s = addsym($1);
+                       s->stype = Stype;
+               }
+               ;
+
+imports_decl   : IMPORTS referencenames FROM IDENT ';'
+               { add_import($4); }
+               ;
+
+type_decl      : IDENT EEQUAL type
+               {
+                 Symbol *s = addsym ($1);
+                 s->stype = Stype;
+                 s->type = $3;
+                 generate_type (s);
+               }
+               ;
+
+constant_decl  : IDENT type EEQUAL constant
+               {
+                 Symbol *s = addsym ($1);
+                 s->stype = SConstant;
+                 s->constant = $4;
+                 generate_constant (s);
+               }
+               ;
+
+type           : INTEGER     { $$ = new_type(TInteger); }
+               | INTEGER '(' constant DOTDOT constant ')' {
+                   if($3 != 0)
+                       error_message("Only 0 supported as low range");
+                   if($5 != INT_MIN && $5 != UINT_MAX && $5 != INT_MAX)
+                       error_message("Only %u supported as high range",
+                                     UINT_MAX);
+                   $$ = new_type(TUInteger);
+               }
+                | INTEGER '{' bitdecls '}'
+                {
+                       $$ = new_type(TInteger);
+                       $$->members = $3;
+                }
+               | OBJECT IDENTIFIER { $$ = new_type(TOID); }
+               | ENUMERATED '{' bitdecls '}'
+               {
+                       $$ = new_type(TEnumerated);
+                       $$->members = $3;
+               }
+               | OCTET STRING { $$ = new_type(TOctetString); }
+               | GeneralString { $$ = new_type(TGeneralString); }
+               | UTF8String { $$ = new_type(TUTF8String); }
+                | NULLTYPE { $$ = new_type(TNull); }
+               | GeneralizedTime { $$ = new_type(TGeneralizedTime); }
+               | SEQUENCE OF type
+               {
+                 $$ = new_type(TSequenceOf);
+                 $$->subtype = $3;
+               }
+               | SEQUENCE '{' memberdecls '}'
+               {
+                 $$ = new_type(TSequence);
+                 $$->members = $3;
+               }
+               | CHOICE '{' memberdecls '}'
+               {
+                 $$ = new_type(TChoice);
+                 $$->members = $3;
+               }
+               | BIT STRING '{' bitdecls '}'
+               {
+                 $$ = new_type(TBitString);
+                 $$->members = $4;
+               }
+               | IDENT
+               {
+                 Symbol *s = addsym($1);
+                 $$ = new_type(TType);
+                 if(s->stype != Stype)
+                   error_message ("%s is not a type\n", $1);
+                 else
+                   $$->symbol = s;
+               }
+               | '[' APPLICATION constant ']' type
+               {
+                 $$ = new_type(TApplication);
+                 $$->subtype = $5;
+                 $$->application = $3;
+               }
+               | BOOLEAN     { $$ = new_type(TBoolean); }
+               ;
+
+memberdecls    : { $$ = NULL; }
+               | memberdecl    { $$ = $1; }
+               | memberdecls  ',' DOTDOTDOT { $$ = $1; }
+               | memberdecls ',' memberdecl { $$ = $1; append($$, $3); }
+               ;
+
+memberdeclstart : IDENT '[' constant ']' type
+               {
+                 $$ = malloc(sizeof(*$$));
+                 $$->name = $1;
+                 $$->gen_name = strdup($1);
+                 output_name ($$->gen_name);
+                 $$->val = $3;
+                 $$->optional = 0;
+                 $$->defval = NULL;
+                 $$->type = $5;
+                 $$->next = $$->prev = $$;
+               }
+               ;
+
+
+memberdecl     : memberdeclstart optional2
+               { $1->optional = $2 ; $$ = $1; }
+               | memberdeclstart defvalue
+               { $1->defval = $2 ; $$ = $1; }
+               | memberdeclstart
+               { $$ = $1; }
+               ;
+
+
+optional2      : OPTIONAL { $$ = 1; }
+               ;
+
+defvalue       : DEFAULT constant
+               { asprintf(&$$, "%d", $2); }
+               | DEFAULT '"' IDENT '"'
+               { $$ = strdup ($3); }
+               ;
+
+bitdecls       : { $$ = NULL; }
+               | bitdecl { $$ = $1; }
+               | bitdecls ',' DOTDOTDOT { $$ = $1; }
+               | bitdecls ',' bitdecl { $$ = $1; append($$, $3); }
+               ;
+
+bitdecl                : IDENT '(' constant ')'
+               {
+                 $$ = malloc(sizeof(*$$));
+                 $$->name = $1;
+                 $$->gen_name = strdup($1);
+                 output_name ($$->gen_name);
+                 $$->val = $3;
+                 $$->optional = 0;
+                 $$->type = NULL;
+                 $$->prev = $$->next = $$;
+               }
+               ;
+
+constant       : CONSTANT      { $$ = $1; }
+               | '-' CONSTANT  { $$ = -$2; }
+               | IDENT {
+                                 Symbol *s = addsym($1);
+                                 if(s->stype != SConstant)
+                                   error_message ("%s is not a constant\n",
+                                                  s->name);
+                                 else
+                                   $$ = s->constant;
+                               }
+               ;
+%%
+
+void
+yyerror (char *s)
+{
+     error_message ("%s\n", s);
+}
+
+static Type *
+new_type (Typetype tt)
+{
+  Type *t = malloc(sizeof(*t));
+  if (t == NULL) {
+      error_message ("out of memory in malloc(%lu)", 
+                    (unsigned long)sizeof(*t));
+      exit (1);
+  }
+  t->type = tt;
+  t->application = 0;
+  t->members = NULL;
+  t->subtype = NULL;
+  t->symbol  = NULL;
+  return t;
+}
+
+static void
+append (Member *l, Member *r)
+{
+  l->prev->next = r;
+  r->prev = l->prev;
+  l->prev = r;
+  r->next = l;
+}
diff --git a/source4/heimdal/lib/asn1/symbol.c b/source4/heimdal/lib/asn1/symbol.c
new file mode 100644 (file)
index 0000000..5f69c10
--- /dev/null
@@ -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 "gen_locl.h"
+
+RCSID("$Id: symbol.c,v 1.9 2001/09/25 13:39:27 assar Exp $");
+
+static Hashtab *htab;
+
+static int
+cmp (void *a, void *b)
+{
+  Symbol *s1 = (Symbol *)a;
+  Symbol *s2 = (Symbol *)b;
+
+  return strcmp (s1->name, s2->name);
+}
+
+static unsigned
+hash (void *a)
+{
+  Symbol *s = (Symbol *)a;
+
+  return hashjpw (s->name);
+}
+
+void
+initsym (void)
+{
+  htab = hashtabnew (101, cmp, hash);
+}
+
+
+void
+output_name (char *s)
+{
+  char *p;
+
+  for (p = s; *p; ++p)
+    if (*p == '-')
+      *p = '_';
+}
+
+Symbol*
+addsym (char *name)
+{
+  Symbol key, *s;
+
+  key.name = name;
+  s = (Symbol *)hashtabsearch (htab, (void *)&key);
+  if (s == NULL) {
+    s = (Symbol *)malloc (sizeof (*s));
+    s->name = name;
+    s->gen_name = strdup(name);
+    output_name (s->gen_name);
+    s->stype = SUndefined;
+    hashtabadd (htab, s);
+  }
+  return s;
+}
diff --git a/source4/heimdal/lib/asn1/symbol.h b/source4/heimdal/lib/asn1/symbol.h
new file mode 100644 (file)
index 0000000..443935c
--- /dev/null
@@ -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. 
+ */
+
+/* $Id: symbol.h,v 1.11 2003/10/03 00:28:29 lha Exp $ */
+
+#ifndef _SYMBOL_H
+#define _SYMBOL_H
+
+enum typetype { 
+    TApplication,
+    TBitString,
+    TBoolean,
+    TChoice,
+    TEnumerated,
+    TGeneralString,
+    TGeneralizedTime,
+    TInteger, 
+    TNull,
+    TOID,
+    TOctetString,
+    TSequence,
+    TSequenceOf,
+    TType, 
+    TUInteger,
+    TUTF8String
+};
+
+typedef enum typetype Typetype;
+
+struct type;
+
+struct member {
+  char *name;
+  char *gen_name;
+  int val;
+  int optional;
+  struct type *type;
+  struct member *next, *prev;
+  char *defval;
+};
+
+typedef struct member Member;
+
+struct symbol;
+
+struct type {
+  Typetype type;
+  int application;
+  Member *members;
+  struct type *subtype;
+  struct symbol *symbol;
+};
+
+typedef struct type Type;
+
+struct symbol {
+  char *name;
+  char *gen_name;
+  enum { SUndefined, SConstant, Stype } stype;
+  int constant;
+  Type *type;
+};
+
+typedef struct symbol Symbol;
+
+void initsym (void);
+Symbol *addsym (char *);
+void output_name (char *);
+#endif
diff --git a/source4/heimdal/lib/asn1/timegm.c b/source4/heimdal/lib/asn1/timegm.c
new file mode 100644 (file)
index 0000000..bdc997f
--- /dev/null
@@ -0,0 +1,71 @@
+/*
+ * 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 "der_locl.h"
+
+RCSID("$Id: timegm.c,v 1.7 1999/12/02 17:05:02 joda Exp $");
+
+#ifndef HAVE_TIMEGM
+
+static int
+is_leap(unsigned y)
+{
+    y += 1900;
+    return (y % 4) == 0 && ((y % 100) != 0 || (y % 400) == 0);
+}
+
+time_t
+timegm (struct tm *tm)
+{
+  static const unsigned ndays[2][12] ={
+    {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31},
+    {31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}};
+  time_t res = 0;
+  unsigned i;
+
+  for (i = 70; i < tm->tm_year; ++i)
+    res += is_leap(i) ? 366 : 365;
+
+  for (i = 0; i < tm->tm_mon; ++i)
+    res += ndays[is_leap(tm->tm_year)][i];
+  res += tm->tm_mday - 1;
+  res *= 24;
+  res += tm->tm_hour;
+  res *= 60;
+  res += tm->tm_min;
+  res *= 60;
+  res += tm->tm_sec;
+  return res;
+}
+
+#endif /* HAVE_TIMEGM */
diff --git a/source4/heimdal/lib/com_err/com_err.c b/source4/heimdal/lib/com_err/com_err.c
new file mode 100644 (file)
index 0000000..0462fdc
--- /dev/null
@@ -0,0 +1,172 @@
+/*
+ * 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. 
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+RCSID("$Id: com_err.c,v 1.19 2005/04/24 19:42:39 lha Exp $");
+#endif
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <roken.h>
+#include "com_err.h"
+
+struct et_list *_et_list = NULL;
+
+
+const char *
+error_message (long code)
+{
+    static char msg[128];
+    const char *p = com_right(_et_list, code);
+    if (p == NULL) {
+       if (code < 0)
+           snprintf(msg, sizeof(msg), "Unknown error %ld", code);
+       else
+           p = strerror(code);
+    }
+    if (p != NULL && *p != '\0') {
+       strlcpy(msg, p, sizeof(msg));
+    } else 
+       snprintf(msg, sizeof(msg), "Unknown error %ld", code);
+    return msg;
+}
+
+int
+init_error_table(const char **msgs, long base, int count)
+{
+    initialize_error_table_r(&_et_list, msgs, count, base);
+    return 0;
+}
+
+static void
+default_proc (const char *whoami, long code, const char *fmt, va_list args)
+    __attribute__((__format__(__printf__, 3, 0)));
+static void
+default_proc (const char *whoami, long code, const char *fmt, va_list args)
+{
+    if (whoami)
+      fprintf(stderr, "%s: ", whoami);
+    if (code)
+      fprintf(stderr, "%s ", error_message(code));
+    if (fmt)
+      vfprintf(stderr, fmt, args);
+    fprintf(stderr, "\r\n");   /* ??? */
+}
+
+static errf com_err_hook = default_proc;
+
+void 
+com_err_va (const char *whoami, 
+           long code, 
+           const char *fmt, 
+           va_list args)
+{
+    (*com_err_hook) (whoami, code, fmt, args);
+}
+
+void
+com_err (const char *whoami,
+        long code,
+        const char *fmt, 
+        ...)
+{
+    va_list ap;
+    va_start(ap, fmt);
+    com_err_va (whoami, code, fmt, ap);
+    va_end(ap);
+}
+
+errf
+set_com_err_hook (errf new)
+{
+    errf old = com_err_hook;
+
+    if (new)
+       com_err_hook = new;
+    else
+       com_err_hook = default_proc;
+    
+    return old;
+}
+
+errf
+reset_com_err_hook (void) 
+{
+    return set_com_err_hook(NULL);
+}
+
+#define ERRCODE_RANGE   8       /* # of bits to shift table number */
+#define BITS_PER_CHAR   6       /* # bits to shift per character in name */
+
+static const char char_set[] =
+        "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789_";
+
+static char buf[6];
+
+const char *
+error_table_name(int num)
+{
+    int ch;
+    int i;
+    char *p;
+
+    /* num = aa aaa abb bbb bcc ccc cdd ddd d?? ??? ??? */
+    p = buf;
+    num >>= ERRCODE_RANGE;
+    /* num = ?? ??? ??? aaa aaa bbb bbb ccc ccc ddd ddd */
+    num &= 077777777;
+    /* num = 00 000 000 aaa aaa bbb bbb ccc ccc ddd ddd */
+    for (i = 4; i >= 0; i--) {
+        ch = (num >> BITS_PER_CHAR * i) & ((1 << BITS_PER_CHAR) - 1);
+        if (ch != 0)
+            *p++ = char_set[ch-1];
+    }
+    *p = '\0';
+    return(buf);
+}
+
+void
+add_to_error_table(struct et_list *new_table)
+{
+    struct et_list *et;
+
+    for (et = _et_list; et; et = et->next) {
+       if (et->table->base == new_table->table->base)
+           return;
+    }
+
+    new_table->next = _et_list;
+    _et_list = new_table;
+}
diff --git a/source4/heimdal/lib/com_err/com_err.h b/source4/heimdal/lib/com_err/com_err.h
new file mode 100644 (file)
index 0000000..fe74411
--- /dev/null
@@ -0,0 +1,66 @@
+/*
+ * 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. 
+ */
+
+/* $Id: com_err.h,v 1.11 2005/07/07 14:58:07 lha Exp $ */
+
+/* MIT compatible com_err library */
+
+#ifndef __COM_ERR_H__
+#define __COM_ERR_H__
+
+#include <com_right.h>
+#include <stdarg.h>
+
+#if !defined(__GNUC__) && !defined(__attribute__)
+#define __attribute__(X)
+#endif
+
+typedef void (*errf) (const char *, long, const char *, va_list);
+
+const char * error_message (long);
+int init_error_table (const char**, long, int);
+
+void com_err_va (const char *, long, const char *, va_list)
+    __attribute__((format(printf, 3, 0)));
+
+void com_err (const char *, long, const char *, ...)
+    __attribute__((format(printf, 3, 4)));
+
+errf set_com_err_hook (errf);
+errf reset_com_err_hook (void);
+
+const char *error_table_name  (int num);
+
+void add_to_error_table (struct et_list *new_table);
+
+#endif /* __COM_ERR_H__ */
diff --git a/source4/heimdal/lib/com_err/com_right.h b/source4/heimdal/lib/com_err/com_right.h
new file mode 100644 (file)
index 0000000..7e7d342
--- /dev/null
@@ -0,0 +1,58 @@
+/*
+ * 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. 
+ */
+
+/* $Id: com_right.h,v 1.12 2005/02/03 08:43:01 lha Exp $ */
+
+#ifndef __COM_RIGHT_H__
+#define __COM_RIGHT_H__
+
+#ifdef __STDC__
+#include <stdarg.h>
+#endif
+
+struct error_table {
+    char const * const * msgs;
+    long base;
+    int n_msgs;
+};
+struct et_list {
+    struct et_list *next;
+    struct error_table *table;
+};
+extern struct et_list *_et_list;
+
+const char *com_right (struct et_list *list, long code);
+void initialize_error_table_r (struct et_list **, const char **, int, long);
+void free_error_table (struct et_list *);
+
+#endif /* __COM_RIGHT_H__ */
diff --git a/source4/heimdal/lib/com_err/compile_et.c b/source4/heimdal/lib/com_err/compile_et.c
new file mode 100644 (file)
index 0000000..1b472d8
--- /dev/null
@@ -0,0 +1,236 @@
+/*
+ * Copyright (c) 1998-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. 
+ */
+
+#undef ROKEN_RENAME
+#include "compile_et.h"
+#include <getarg.h>
+
+RCSID("$Id: compile_et.c,v 1.19 2005/06/16 19:21:00 lha Exp $");
+
+#include <roken.h>
+#include <err.h>
+#include "parse.h"
+
+int numerror;
+extern FILE *yyin;
+
+extern void yyparse(void);
+
+long base_id;
+int number;
+char *prefix;
+char *id_str;
+
+char name[128];
+char Basename[128];
+
+#ifdef YYDEBUG
+extern int yydebug = 1;
+#endif
+
+char *filename;
+char hfn[128];
+char cfn[128];
+
+struct error_code *codes = NULL;
+
+static int
+generate_c(void)
+{
+    int n;
+    struct error_code *ec;
+
+    FILE *c_file = fopen(cfn, "w");
+    if(c_file == NULL)
+       return 1;
+
+    fprintf(c_file, "/* Generated from %s */\n", filename);
+    if(id_str) 
+       fprintf(c_file, "/* %s */\n", id_str);
+    fprintf(c_file, "\n");
+    fprintf(c_file, "#include <stddef.h>\n");
+    fprintf(c_file, "#include <com_err.h>\n");
+    fprintf(c_file, "#include \"%s\"\n", hfn);
+    fprintf(c_file, "\n");
+
+    fprintf(c_file, "static const char *%s_error_strings[] = {\n", name);
+
+    for(ec = codes, n = 0; ec; ec = ec->next, n++) {
+       while(n < ec->number) {
+           fprintf(c_file, "\t/* %03d */ \"Reserved %s error (%d)\",\n",
+                   n, name, n);
+           n++;
+           
+       }
+       fprintf(c_file, "\t/* %03d */ \"%s\",\n", ec->number, ec->string);
+    }
+
+    fprintf(c_file, "\tNULL\n");
+    fprintf(c_file, "};\n");
+    fprintf(c_file, "\n");
+    fprintf(c_file, "#define num_errors %d\n", number);
+    fprintf(c_file, "\n");
+    fprintf(c_file, 
+           "void initialize_%s_error_table_r(struct et_list **list)\n", 
+           name);
+    fprintf(c_file, "{\n");
+    fprintf(c_file, 
+           "    initialize_error_table_r(list, %s_error_strings, "
+           "num_errors, ERROR_TABLE_BASE_%s);\n", name, name);
+    fprintf(c_file, "}\n");
+    fprintf(c_file, "\n");
+    fprintf(c_file, "void initialize_%s_error_table(void)\n", name);
+    fprintf(c_file, "{\n");
+    fprintf(c_file,
+           "    init_error_table(%s_error_strings, ERROR_TABLE_BASE_%s, "
+           "num_errors);\n", name, name);
+    fprintf(c_file, "}\n");
+
+    fclose(c_file);
+    return 0;
+}
+
+static int
+generate_h(void)
+{
+    struct error_code *ec;
+    char fn[128];
+    FILE *h_file = fopen(hfn, "w");
+    char *p;
+
+    if(h_file == NULL)
+       return 1;
+
+    snprintf(fn, sizeof(fn), "__%s__", hfn);
+    for(p = fn; *p; p++)
+       if(!isalnum((unsigned char)*p))
+           *p = '_';
+    
+    fprintf(h_file, "/* Generated from %s */\n", filename);
+    if(id_str) 
+       fprintf(h_file, "/* %s */\n", id_str);
+    fprintf(h_file, "\n");
+    fprintf(h_file, "#ifndef %s\n", fn);
+    fprintf(h_file, "#define %s\n", fn);
+    fprintf(h_file, "\n");
+    fprintf(h_file, "struct et_list;\n");
+    fprintf(h_file, "\n");
+    fprintf(h_file, 
+           "void initialize_%s_error_table_r(struct et_list **);\n",
+           name);
+    fprintf(h_file, "\n");
+    fprintf(h_file, "void initialize_%s_error_table(void);\n", name);
+    fprintf(h_file, "#define init_%s_err_tbl initialize_%s_error_table\n", 
+           name, name);
+    fprintf(h_file, "\n");
+    fprintf(h_file, "typedef enum %s_error_number{\n", name);
+
+    for(ec = codes; ec; ec = ec->next) {
+       fprintf(h_file, "\t%s = %ld%s\n", ec->name, base_id + ec->number, 
+               (ec->next != NULL) ? "," : "");
+    }
+
+    fprintf(h_file, "} %s_error_number;\n", name);
+    fprintf(h_file, "\n");
+    fprintf(h_file, "#define ERROR_TABLE_BASE_%s %ld\n", name, base_id);
+    fprintf(h_file, "\n");
+    fprintf(h_file, "#endif /* %s */\n", fn);
+
+
+    fclose(h_file);
+    return 0;
+}
+
+static int
+generate(void)
+{
+    return generate_c() || generate_h();
+}
+
+int version_flag;
+int help_flag;
+struct getargs args[] = {
+    { "version", 0, arg_flag, &version_flag },
+    { "help", 0, arg_flag, &help_flag }
+};
+int num_args = sizeof(args) / sizeof(args[0]);
+
+static void
+usage(int code)
+{
+    arg_printusage(args, num_args, NULL, "error-table");
+    exit(code);
+}
+
+int
+main(int argc, char **argv)
+{
+    char *p;
+    int optidx = 0;
+
+    setprogname(argv[0]);
+    if(getarg(args, num_args, argc, argv, &optidx))
+       usage(1);
+    if(help_flag)
+       usage(0);
+    if(version_flag) {
+       print_version(NULL);
+       exit(0);
+    }
+
+    if(optidx == argc) 
+       usage(1);
+    filename = argv[optidx];
+    yyin = fopen(filename, "r");
+    if(yyin == NULL)
+       err(1, "%s", filename);
+       
+    
+    p = strrchr(filename, '/');
+    if(p)
+       p++;
+    else
+       p = filename;
+    strlcpy(Basename, p, sizeof(Basename));
+    
+    Basename[strcspn(Basename, ".")] = '\0';
+    
+    snprintf(hfn, sizeof(hfn), "%s.h", Basename);
+    snprintf(cfn, sizeof(cfn), "%s.c", Basename);
+    
+    yyparse();
+    if(numerror)
+       return 1;
+
+    return generate();
+}
diff --git a/source4/heimdal/lib/com_err/compile_et.h b/source4/heimdal/lib/com_err/compile_et.h
new file mode 100644 (file)
index 0000000..6da8c59
--- /dev/null
@@ -0,0 +1,80 @@
+/*
+ * Copyright (c) 1998 - 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. 
+ */
+
+/* $Id: compile_et.h,v 1.8 2005/06/16 19:21:26 lha Exp $ */
+
+#ifndef __COMPILE_ET_H__
+#define __COMPILE_ET_H__
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <err.h>
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#include <ctype.h>
+#include <roken.h>
+
+extern long base_id;
+extern int number;
+extern char *prefix;
+extern char name[128];
+extern char *id_str;
+extern char *filename;
+extern int numerror;
+
+struct error_code {
+    unsigned number;
+    char *name;
+    char *string;
+    struct error_code *next, **tail;
+};
+
+extern struct error_code *codes;
+
+#define APPEND(L, V)                           \
+do {                                           \
+    if((L) == NULL) {                          \
+       (L) = (V);                              \
+       (L)->tail = &(V)->next;                 \
+       (L)->next = NULL;                       \
+    }else{                                     \
+       *(L)->tail = (V);                       \
+       (L)->tail = &(V)->next;                 \
+    }                                          \
+}while(0)
+
+#endif /* __COMPILE_ET_H__ */
diff --git a/source4/heimdal/lib/com_err/error.c b/source4/heimdal/lib/com_err/error.c
new file mode 100644 (file)
index 0000000..b22f25b
--- /dev/null
@@ -0,0 +1,91 @@
+/*
+ * Copyright (c) 1997, 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. 
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+RCSID("$Id: error.c,v 1.15 2001/02/28 20:00:13 joda Exp $");
+#endif
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <com_right.h>
+
+const char *
+com_right(struct et_list *list, long code)
+{
+    struct et_list *p;
+    for (p = list; p; p = p->next) {
+       if (code >= p->table->base && code < p->table->base + p->table->n_msgs)
+           return p->table->msgs[code - p->table->base];
+    }
+    return NULL;
+}
+
+struct foobar {
+    struct et_list etl;
+    struct error_table et;
+};
+
+void
+initialize_error_table_r(struct et_list **list, 
+                        const char **messages, 
+                        int num_errors,
+                        long base)
+{
+    struct et_list *et, **end;
+    struct foobar *f;
+    for (end = list, et = *list; et; end = &et->next, et = et->next)
+        if (et->table->msgs == messages)
+            return;
+    f = malloc(sizeof(*f));
+    if (f == NULL)
+        return;
+    et = &f->etl;
+    et->table = &f->et;
+    et->table->msgs = messages;
+    et->table->n_msgs = num_errors;
+    et->table->base = base;
+    et->next = NULL;
+    *end = et;
+}
+                       
+
+void
+free_error_table(struct et_list *et)
+{
+    while(et){
+       struct et_list *p = et;
+       et = et->next;
+       free(p);
+    }
+}
diff --git a/source4/heimdal/lib/com_err/lex.h b/source4/heimdal/lib/com_err/lex.h
new file mode 100644 (file)
index 0000000..9912bf4
--- /dev/null
@@ -0,0 +1,39 @@
+/*
+ * 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. 
+ */
+
+/* $Id: lex.h,v 1.1 2000/06/22 00:42:52 assar Exp $ */
+
+void error_message (const char *, ...)
+__attribute__ ((format (printf, 1, 2)));
+
+int yylex(void);
diff --git a/source4/heimdal/lib/com_err/lex.l b/source4/heimdal/lib/com_err/lex.l
new file mode 100644 (file)
index 0000000..d60e67c
--- /dev/null
@@ -0,0 +1,128 @@
+%{
+/*
+ * Copyright (c) 1998 - 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. 
+ */
+
+/*
+ * This is to handle the definition of this symbol in some AIX
+ * headers, which will conflict with the definition that lex will
+ * generate for it.  It's only a problem for AIX lex.
+ */
+
+#undef ECHO
+
+#include "compile_et.h"
+#include "parse.h"
+#include "lex.h"
+
+RCSID("$Id: lex.l,v 1.8 2005/05/16 08:52:54 lha Exp $");
+
+static unsigned lineno = 1;
+static int getstring(void);
+
+#define YY_NO_UNPUT
+
+#undef ECHO
+
+%}
+
+
+%%
+et                     { return ET; }
+error_table            { return ET; }
+ec                     { return EC; }
+error_code             { return EC; }
+prefix                 { return PREFIX; }
+index                  { return INDEX; }
+id                     { return ID; }
+end                    { return END; }
+[0-9]+                 { yylval.number = atoi(yytext); return NUMBER; }
+#[^\n]*                        ;
+[ \t]                  ;
+\n                     { lineno++; }
+\"                     { return getstring(); }
+[a-zA-Z0-9_]+          { yylval.string = strdup(yytext); return STRING; }
+.                      { return *yytext; }
+%%
+
+#ifndef yywrap /* XXX */
+int
+yywrap () 
+{
+     return 1;
+}
+#endif
+
+static int
+getstring(void)
+{
+    char x[128];
+    int i = 0;
+    int c;
+    int quote = 0;
+    while(i < sizeof(x) - 1 && (c = input()) != EOF){
+       if(quote) {
+           x[i++] = c;
+           quote = 0;
+           continue;
+       }
+       if(c == '\n'){
+           error_message("unterminated string");
+           lineno++;
+           break;
+       }
+       if(c == '\\'){
+           quote++;
+           continue;
+       }
+       if(c == '\"')
+           break;
+       x[i++] = c;
+    }
+    x[i] = '\0';
+    yylval.string = strdup(x);
+    if (yylval.string == NULL)
+        err(1, "malloc");
+    return STRING;
+}
+
+void
+error_message (const char *format, ...)
+{
+     va_list args;
+
+     va_start (args, format);
+     fprintf (stderr, "%s:%d:", filename, lineno);
+     vfprintf (stderr, format, args);
+     va_end (args);
+     numerror++;
+}
diff --git a/source4/heimdal/lib/com_err/parse.y b/source4/heimdal/lib/com_err/parse.y
new file mode 100644 (file)
index 0000000..6174d6a
--- /dev/null
@@ -0,0 +1,173 @@
+%{
+/*
+ * Copyright (c) 1998 - 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 "compile_et.h"
+#include "lex.h"
+
+RCSID("$Id: parse.y,v 1.15 2005/06/16 19:21:42 lha Exp $");
+
+void yyerror (char *s);
+static long name2number(const char *str);
+
+extern char *yytext;
+
+/* This is for bison */
+
+#if !defined(alloca) && !defined(HAVE_ALLOCA)
+#define alloca(x) malloc(x)
+#endif
+
+%}
+
+%union {
+  char *string;
+  int number;
+}
+
+%token ET INDEX PREFIX EC ID END
+%token <string> STRING
+%token <number> NUMBER
+
+%%
+
+file           : /* */ 
+               | header statements
+               ;
+
+header         : id et
+               | et
+               ;
+
+id             : ID STRING
+               {
+                   id_str = $2;
+               }
+               ;
+
+et             : ET STRING
+               {
+                   base_id = name2number($2);
+                   strlcpy(name, $2, sizeof(name));
+                   free($2);
+               }
+               | ET STRING STRING
+               {
+                   base_id = name2number($2);
+                   strlcpy(name, $3, sizeof(name));
+                   free($2);
+                   free($3);
+               }
+               ;
+
+statements     : statement
+               | statements statement
+               ;
+
+statement      : INDEX NUMBER 
+               {
+                       number = $2;
+               }
+               | PREFIX STRING
+               {
+                   free(prefix);
+                   asprintf (&prefix, "%s_", $2);
+                   if (prefix == NULL)
+                       errx(1, "malloc");
+                   free($2);
+               }
+               | PREFIX
+               {
+                   prefix = realloc(prefix, 1);
+                   if (prefix == NULL)
+                       errx(1, "malloc");
+                   *prefix = '\0';
+               }
+               | EC STRING ',' STRING
+               {
+                   struct error_code *ec = malloc(sizeof(*ec));
+                   
+                   if (ec == NULL)
+                       errx(1, "malloc");
+
+                   ec->next = NULL;
+                   ec->number = number;
+                   if(prefix && *prefix != '\0') {
+                       asprintf (&ec->name, "%s%s", prefix, $2);
+                       if (ec->name == NULL)
+                           errx(1, "malloc");
+                       free($2);
+                   } else
+                       ec->name = $2;
+                   ec->string = $4;
+                   APPEND(codes, ec);
+                   number++;
+               }
+               | END
+               {
+                       YYACCEPT;
+               }
+               ;
+
+%%
+
+static long
+name2number(const char *str)
+{
+    const char *p;
+    long num = 0;
+    const char *x = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
+       "abcdefghijklmnopqrstuvwxyz0123456789_";
+    if(strlen(str) > 4) {
+       yyerror("table name too long");
+       return 0;
+    }
+    for(p = str; *p; p++){
+       char *q = strchr(x, *p);
+       if(q == NULL) {
+           yyerror("invalid character in table name");
+           return 0;
+       }
+       num = (num << 6) + (q - x) + 1;
+    }
+    num <<= 8;
+    if(num > 0x7fffffff)
+       num = -(0xffffffff - num + 1);
+    return num;
+}
+
+void
+yyerror (char *s)
+{
+     error_message ("%s\n", s);
+}
diff --git a/source4/heimdal/lib/des/aes.c b/source4/heimdal/lib/des/aes.c
new file mode 100755 (executable)
index 0000000..5e0069d
--- /dev/null
@@ -0,0 +1,124 @@
+/*
+ * 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.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+
+RCSID("$Id: aes.c,v 1.5 2005/06/18 22:46:35 lha Exp $");
+#endif
+
+#ifdef KRB5
+#include <krb5-types.h>
+#endif
+
+#include <string.h>
+
+#include "rijndael-alg-fst.h"
+#include "aes.h"
+
+int
+AES_set_encrypt_key(const unsigned char *userkey, const int bits, AES_KEY *key)
+{
+    key->rounds = rijndaelKeySetupEnc(key->key, userkey, bits);
+    if (key->rounds == 0)
+       return -1;
+    return 0;
+}
+
+int
+AES_set_decrypt_key(const unsigned char *userkey, const int bits, AES_KEY *key)
+{
+    key->rounds = rijndaelKeySetupDec(key->key, userkey, bits);
+    if (key->rounds == 0)
+       return -1;
+    return 0;
+}
+
+void
+AES_encrypt(const unsigned char *in, unsigned char *out, const AES_KEY *key)
+{
+    rijndaelEncrypt(key->key, key->rounds, in, out);
+}
+
+void
+AES_decrypt(const unsigned char *in, unsigned char *out, const AES_KEY *key)
+{
+    rijndaelDecrypt(key->key, key->rounds, in, out);
+}
+
+void
+AES_cbc_encrypt(const unsigned char *in, unsigned char *out,
+               unsigned long size, const AES_KEY *key,
+               unsigned char *iv, int forward_encrypt)
+{
+    unsigned char tmp[AES_BLOCK_SIZE];
+    int i;
+
+    if (forward_encrypt) {
+       while (size >= AES_BLOCK_SIZE) {
+           for (i = 0; i < AES_BLOCK_SIZE; i++)
+               tmp[i] = in[i] ^ iv[i];
+           AES_encrypt(tmp, out, key);
+           memcpy(iv, out, AES_BLOCK_SIZE);
+           size -= AES_BLOCK_SIZE;
+           in += AES_BLOCK_SIZE;
+           out += AES_BLOCK_SIZE;
+       }
+       if (size) {
+           for (i = 0; i < size; i++)
+               tmp[i] = in[i] ^ iv[i];
+           for (i = size; i < AES_BLOCK_SIZE; i++)
+               tmp[i] = iv[i];
+           AES_encrypt(tmp, out, key);
+           memcpy(iv, out, AES_BLOCK_SIZE);
+       }
+    } else {
+       while (size >= AES_BLOCK_SIZE) {
+           memcpy(tmp, in, AES_BLOCK_SIZE);
+           AES_decrypt(tmp, out, key);
+           for (i = 0; i < AES_BLOCK_SIZE; i++)
+               out[i] ^= iv[i];
+           memcpy(iv, tmp, AES_BLOCK_SIZE);
+           size -= AES_BLOCK_SIZE;
+           in += AES_BLOCK_SIZE;
+           out += AES_BLOCK_SIZE;
+       }
+       if (size) {
+           memcpy(tmp, in, AES_BLOCK_SIZE);
+           AES_decrypt(tmp, out, key);
+           for (i = 0; i < size; i++)
+               out[i] ^= iv[i];
+           memcpy(iv, tmp, AES_BLOCK_SIZE);
+       }
+    }
+}
diff --git a/source4/heimdal/lib/des/aes.h b/source4/heimdal/lib/des/aes.h
new file mode 100755 (executable)
index 0000000..ef72b0a
--- /dev/null
@@ -0,0 +1,60 @@
+/*
+ * Copyright (c) 2003-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: aes.h,v 1.4 2005/04/10 19:09:47 lha Exp $ */
+
+#ifndef HEIM_AES_H
+#define HEIM_AES_H 1
+
+#define AES_BLOCK_SIZE 16
+#define AES_MAXNR 14
+
+#define AES_ENCRYPT 1
+#define AES_DECRYPT 0
+
+typedef struct aes_key {
+    u_int32_t key[(AES_MAXNR+1)*4];
+    int rounds;
+} AES_KEY;
+
+int AES_set_encrypt_key(const unsigned char *, const int, AES_KEY *);
+int AES_set_decrypt_key(const unsigned char *, const int, AES_KEY *);
+
+void AES_encrypt(const unsigned char *, unsigned char *, const AES_KEY *);
+void AES_decrypt(const unsigned char *, unsigned char *, const AES_KEY *);
+
+void AES_cbc_encrypt(const unsigned char *, unsigned char *,
+                    const unsigned long, const AES_KEY *,
+                    unsigned char *, int);
+
+#endif /* HEIM_AES_H */
diff --git a/source4/heimdal/lib/des/des-tables.h b/source4/heimdal/lib/des/des-tables.h
new file mode 100644 (file)
index 0000000..03854ec
--- /dev/null
@@ -0,0 +1,196 @@
+/* GENERATE FILE from gen-des.pl, do not edit */
+
+/* pc1_c_3 bit pattern 5 13 21 */
+static int pc1_c_3[8] = {
+    0x00000000, 0x00000010, 0x00001000, 0x00001010, 
+    0x00100000, 0x00100010, 0x00101000, 0x00101010
+};
+/* pc1_c_4 bit pattern 1 9 17 25 */
+static int pc1_c_4[16] = {
+    0x00000000, 0x00000001, 0x00000100, 0x00000101, 
+    0x00010000, 0x00010001, 0x00010100, 0x00010101, 
+    0x01000000, 0x01000001, 0x01000100, 0x01000101, 
+    0x01010000, 0x01010001, 0x01010100, 0x01010101
+};
+/* pc1_d_3 bit pattern 49 41 33 */
+static int pc1_d_3[8] = {
+    0x00000000, 0x01000000, 0x00010000, 0x01010000, 
+    0x00000100, 0x01000100, 0x00010100, 0x01010100
+};
+/* pc1_d_4 bit pattern 57 53 45 37 */
+static int pc1_d_4[16] = {
+    0x00000000, 0x00100000, 0x00001000, 0x00101000, 
+    0x00000010, 0x00100010, 0x00001010, 0x00101010, 
+    0x00000001, 0x00100001, 0x00001001, 0x00101001, 
+    0x00000011, 0x00100011, 0x00001011, 0x00101011
+};
+/* pc2_c_1 bit pattern 5 24 7 16 6 10 */
+static int pc2_c_1[64] = {
+    0x00000000, 0x00004000, 0x00040000, 0x00044000, 
+    0x00000100, 0x00004100, 0x00040100, 0x00044100, 
+    0x00020000, 0x00024000, 0x00060000, 0x00064000, 
+    0x00020100, 0x00024100, 0x00060100, 0x00064100, 
+    0x00000001, 0x00004001, 0x00040001, 0x00044001, 
+    0x00000101, 0x00004101, 0x00040101, 0x00044101, 
+    0x00020001, 0x00024001, 0x00060001, 0x00064001, 
+    0x00020101, 0x00024101, 0x00060101, 0x00064101, 
+    0x00080000, 0x00084000, 0x000c0000, 0x000c4000, 
+    0x00080100, 0x00084100, 0x000c0100, 0x000c4100, 
+    0x000a0000, 0x000a4000, 0x000e0000, 0x000e4000, 
+    0x000a0100, 0x000a4100, 0x000e0100, 0x000e4100, 
+    0x00080001, 0x00084001, 0x000c0001, 0x000c4001, 
+    0x00080101, 0x00084101, 0x000c0101, 0x000c4101, 
+    0x000a0001, 0x000a4001, 0x000e0001, 0x000e4001, 
+    0x000a0101, 0x000a4101, 0x000e0101, 0x000e4101
+};
+/* pc2_c_2 bit pattern 20 18 12 3 15 23 */
+static int pc2_c_2[64] = {
+    0x00000000, 0x00000002, 0x00000200, 0x00000202, 
+    0x00200000, 0x00200002, 0x00200200, 0x00200202, 
+    0x00001000, 0x00001002, 0x00001200, 0x00001202, 
+    0x00201000, 0x00201002, 0x00201200, 0x00201202, 
+    0x00000040, 0x00000042, 0x00000240, 0x00000242, 
+    0x00200040, 0x00200042, 0x00200240, 0x00200242, 
+    0x00001040, 0x00001042, 0x00001240, 0x00001242, 
+    0x00201040, 0x00201042, 0x00201240, 0x00201242, 
+    0x00000010, 0x00000012, 0x00000210, 0x00000212, 
+    0x00200010, 0x00200012, 0x00200210, 0x00200212, 
+    0x00001010, 0x00001012, 0x00001210, 0x00001212, 
+    0x00201010, 0x00201012, 0x00201210, 0x00201212, 
+    0x00000050, 0x00000052, 0x00000250, 0x00000252, 
+    0x00200050, 0x00200052, 0x00200250, 0x00200252, 
+    0x00001050, 0x00001052, 0x00001250, 0x00001252, 
+    0x00201050, 0x00201052, 0x00201250, 0x00201252
+};
+/* pc2_c_3 bit pattern 1 9 19 2 14 22 */
+static int pc2_c_3[64] = {
+    0x00000000, 0x00000004, 0x00000400, 0x00000404, 
+    0x00400000, 0x00400004, 0x00400400, 0x00400404, 
+    0x00000020, 0x00000024, 0x00000420, 0x00000424, 
+    0x00400020, 0x00400024, 0x00400420, 0x00400424, 
+    0x00008000, 0x00008004, 0x00008400, 0x00008404, 
+    0x00408000, 0x00408004, 0x00408400, 0x00408404, 
+    0x00008020, 0x00008024, 0x00008420, 0x00008424, 
+    0x00408020, 0x00408024, 0x00408420, 0x00408424, 
+    0x00800000, 0x00800004, 0x00800400, 0x00800404, 
+    0x00c00000, 0x00c00004, 0x00c00400, 0x00c00404, 
+    0x00800020, 0x00800024, 0x00800420, 0x00800424, 
+    0x00c00020, 0x00c00024, 0x00c00420, 0x00c00424, 
+    0x00808000, 0x00808004, 0x00808400, 0x00808404, 
+    0x00c08000, 0x00c08004, 0x00c08400, 0x00c08404, 
+    0x00808020, 0x00808024, 0x00808420, 0x00808424, 
+    0x00c08020, 0x00c08024, 0x00c08420, 0x00c08424
+};
+/* pc2_c_4 bit pattern 11 13 4 17 21 8 */
+static int pc2_c_4[64] = {
+    0x00000000, 0x00010000, 0x00000008, 0x00010008, 
+    0x00000080, 0x00010080, 0x00000088, 0x00010088, 
+    0x00100000, 0x00110000, 0x00100008, 0x00110008, 
+    0x00100080, 0x00110080, 0x00100088, 0x00110088, 
+    0x00000800, 0x00010800, 0x00000808, 0x00010808, 
+    0x00000880, 0x00010880, 0x00000888, 0x00010888, 
+    0x00100800, 0x00110800, 0x00100808, 0x00110808, 
+    0x00100880, 0x00110880, 0x00100888, 0x00110888, 
+    0x00002000, 0x00012000, 0x00002008, 0x00012008, 
+    0x00002080, 0x00012080, 0x00002088, 0x00012088, 
+    0x00102000, 0x00112000, 0x00102008, 0x00112008, 
+    0x00102080, 0x00112080, 0x00102088, 0x00112088, 
+    0x00002800, 0x00012800, 0x00002808, 0x00012808, 
+    0x00002880, 0x00012880, 0x00002888, 0x00012888, 
+    0x00102800, 0x00112800, 0x00102808, 0x00112808, 
+    0x00102880, 0x00112880, 0x00102888, 0x00112888
+};
+/* pc2_d_1 bit pattern 51 35 31 52 39 45 */
+static int pc2_d_1[64] = {
+    0x00000000, 0x00000080, 0x00002000, 0x00002080, 
+    0x00000001, 0x00000081, 0x00002001, 0x00002081, 
+    0x00200000, 0x00200080, 0x00202000, 0x00202080, 
+    0x00200001, 0x00200081, 0x00202001, 0x00202081, 
+    0x00020000, 0x00020080, 0x00022000, 0x00022080, 
+    0x00020001, 0x00020081, 0x00022001, 0x00022081, 
+    0x00220000, 0x00220080, 0x00222000, 0x00222080, 
+    0x00220001, 0x00220081, 0x00222001, 0x00222081, 
+    0x00000002, 0x00000082, 0x00002002, 0x00002082, 
+    0x00000003, 0x00000083, 0x00002003, 0x00002083, 
+    0x00200002, 0x00200082, 0x00202002, 0x00202082, 
+    0x00200003, 0x00200083, 0x00202003, 0x00202083, 
+    0x00020002, 0x00020082, 0x00022002, 0x00022082, 
+    0x00020003, 0x00020083, 0x00022003, 0x00022083, 
+    0x00220002, 0x00220082, 0x00222002, 0x00222082, 
+    0x00220003, 0x00220083, 0x00222003, 0x00222083
+};
+/* pc2_d_2 bit pattern 50 32 43 36 29 48 */
+static int pc2_d_2[64] = {
+    0x00000000, 0x00000010, 0x00800000, 0x00800010, 
+    0x00010000, 0x00010010, 0x00810000, 0x00810010, 
+    0x00000200, 0x00000210, 0x00800200, 0x00800210, 
+    0x00010200, 0x00010210, 0x00810200, 0x00810210, 
+    0x00100000, 0x00100010, 0x00900000, 0x00900010, 
+    0x00110000, 0x00110010, 0x00910000, 0x00910010, 
+    0x00100200, 0x00100210, 0x00900200, 0x00900210, 
+    0x00110200, 0x00110210, 0x00910200, 0x00910210, 
+    0x00000004, 0x00000014, 0x00800004, 0x00800014, 
+    0x00010004, 0x00010014, 0x00810004, 0x00810014, 
+    0x00000204, 0x00000214, 0x00800204, 0x00800214, 
+    0x00010204, 0x00010214, 0x00810204, 0x00810214, 
+    0x00100004, 0x00100014, 0x00900004, 0x00900014, 
+    0x00110004, 0x00110014, 0x00910004, 0x00910014, 
+    0x00100204, 0x00100214, 0x00900204, 0x00900214, 
+    0x00110204, 0x00110214, 0x00910204, 0x00910214
+};
+/* pc2_d_3 bit pattern 41 38 47 33 40 42 */
+static int pc2_d_3[64] = {
+    0x00000000, 0x00000400, 0x00001000, 0x00001400, 
+    0x00080000, 0x00080400, 0x00081000, 0x00081400, 
+    0x00000020, 0x00000420, 0x00001020, 0x00001420, 
+    0x00080020, 0x00080420, 0x00081020, 0x00081420, 
+    0x00004000, 0x00004400, 0x00005000, 0x00005400, 
+    0x00084000, 0x00084400, 0x00085000, 0x00085400, 
+    0x00004020, 0x00004420, 0x00005020, 0x00005420, 
+    0x00084020, 0x00084420, 0x00085020, 0x00085420, 
+    0x00000800, 0x00000c00, 0x00001800, 0x00001c00, 
+    0x00080800, 0x00080c00, 0x00081800, 0x00081c00, 
+    0x00000820, 0x00000c20, 0x00001820, 0x00001c20, 
+    0x00080820, 0x00080c20, 0x00081820, 0x00081c20, 
+    0x00004800, 0x00004c00, 0x00005800, 0x00005c00, 
+    0x00084800, 0x00084c00, 0x00085800, 0x00085c00, 
+    0x00004820, 0x00004c20, 0x00005820, 0x00005c20, 
+    0x00084820, 0x00084c20, 0x00085820, 0x00085c20
+};
+/* pc2_d_4 bit pattern 49 37 30 46 34 44 */
+static int pc2_d_4[64] = {
+    0x00000000, 0x00000100, 0x00040000, 0x00040100, 
+    0x00000040, 0x00000140, 0x00040040, 0x00040140, 
+    0x00400000, 0x00400100, 0x00440000, 0x00440100, 
+    0x00400040, 0x00400140, 0x00440040, 0x00440140, 
+    0x00008000, 0x00008100, 0x00048000, 0x00048100, 
+    0x00008040, 0x00008140, 0x00048040, 0x00048140, 
+    0x00408000, 0x00408100, 0x00448000, 0x00448100, 
+    0x00408040, 0x00408140, 0x00448040, 0x00448140, 
+    0x00000008, 0x00000108, 0x00040008, 0x00040108, 
+    0x00000048, 0x00000148, 0x00040048, 0x00040148, 
+    0x00400008, 0x00400108, 0x00440008, 0x00440108, 
+    0x00400048, 0x00400148, 0x00440048, 0x00440148, 
+    0x00008008, 0x00008108, 0x00048008, 0x00048108, 
+    0x00008048, 0x00008148, 0x00048048, 0x00048148, 
+    0x00408008, 0x00408108, 0x00448008, 0x00448108, 
+    0x00408048, 0x00408148, 0x00448048, 0x00448148
+};
+static unsigned char odd_parity[256] = { 
+  1,  1,  2,  2,  4,  4,  7,  7,  8,  8, 11, 11, 13, 13, 14, 14,
+ 16, 16, 19, 19, 21, 21, 22, 22, 25, 25, 26, 26, 28, 28, 31, 31,
+ 32, 32, 35, 35, 37, 37, 38, 38, 41, 41, 42, 42, 44, 44, 47, 47,
+ 49, 49, 50, 50, 52, 52, 55, 55, 56, 56, 59, 59, 61, 61, 62, 62,
+ 64, 64, 67, 67, 69, 69, 70, 70, 73, 73, 74, 74, 76, 76, 79, 79,
+ 81, 81, 82, 82, 84, 84, 87, 87, 88, 88, 91, 91, 93, 93, 94, 94,
+ 97, 97, 98, 98,100,100,103,103,104,104,107,107,109,109,110,110,
+112,112,115,115,117,117,118,118,121,121,122,122,124,124,127,127,
+128,128,131,131,133,133,134,134,137,137,138,138,140,140,143,143,
+145,145,146,146,148,148,151,151,152,152,155,155,157,157,158,158,
+161,161,162,162,164,164,167,167,168,168,171,171,173,173,174,174,
+176,176,179,179,181,181,182,182,185,185,186,186,188,188,191,191,
+193,193,194,194,196,196,199,199,200,200,203,203,205,205,206,206,
+208,208,211,211,213,213,214,214,217,217,218,218,220,220,223,223,
+224,224,227,227,229,229,230,230,233,233,234,234,236,236,239,239,
+241,241,242,242,244,244,247,247,248,248,251,251,253,253,254,254,
+ };
diff --git a/source4/heimdal/lib/des/des.c b/source4/heimdal/lib/des/des.c
new file mode 100644 (file)
index 0000000..66d2bf4
--- /dev/null
@@ -0,0 +1,954 @@
+/*
+ * Copyright (c) 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.
+ */
+
+/*
+ * The document that got me started for real was "Efficient
+ * Implementation of the Data Encryption Standard" by Dag Arne Osvik.
+ * I never got to the PC1 transformation was working, instead I used
+ * table-lookup was used for all key schedule setup. The document was
+ * very useful since it de-mystified other implementations for me.
+ *
+ * The core DES function (SBOX + P transformation) is from Richard
+ * Outerbridge public domain DES implementation. My sanity is saved
+ * thanks to his work. Thank you Richard.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+RCSID("$Id: des.c,v 1.14 2005/06/18 22:47:17 lha Exp $");
+#endif
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <krb5-types.h>
+
+#include "des.h"
+
+static void desx(uint32_t [2], DES_key_schedule *, int);
+static void IP(uint32_t [2]);
+static void FP(uint32_t [2]);
+
+#include "des-tables.h"
+
+#define ROTATE_LEFT28(x,one)                           \
+    if (one) {                                         \
+       x = ( ((x)<<(1)) & 0xffffffe) | ((x) >> 27);    \
+    } else {                                           \
+       x = ( ((x)<<(2)) & 0xffffffc) | ((x) >> 26);    \
+    }
+
+/*
+ *
+ */
+
+int
+DES_set_odd_parity(DES_cblock *key)
+{
+    int i;
+    for (i = 0; i < DES_CBLOCK_LEN; i++)
+       (*key)[i] = odd_parity[(*key)[i]];
+    return 0;
+}
+
+/*
+ *
+ */
+
+/* FIPS 74 */
+static DES_cblock weak_keys[] = {
+    {0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01}, /* weak keys */
+    {0xFE,0xFE,0xFE,0xFE,0xFE,0xFE,0xFE,0xFE},
+    {0x1F,0x1F,0x1F,0x1F,0x0E,0x0E,0x0E,0x0E},
+    {0xE0,0xE0,0xE0,0xE0,0xF1,0xF1,0xF1,0xF1},
+    {0x01,0xFE,0x01,0xFE,0x01,0xFE,0x01,0xFE}, /* semi-weak keys */
+    {0xFE,0x01,0xFE,0x01,0xFE,0x01,0xFE,0x01},
+    {0x1F,0xE0,0x1F,0xE0,0x0E,0xF1,0x0E,0xF1},
+    {0xE0,0x1F,0xE0,0x1F,0xF1,0x0E,0xF1,0x0E},
+    {0x01,0xE0,0x01,0xE0,0x01,0xF1,0x01,0xF1},
+    {0xE0,0x01,0xE0,0x01,0xF1,0x01,0xF1,0x01},
+    {0x1F,0xFE,0x1F,0xFE,0x0E,0xFE,0x0E,0xFE},
+    {0xFE,0x1F,0xFE,0x1F,0xFE,0x0E,0xFE,0x0E},
+    {0x01,0x1F,0x01,0x1F,0x01,0x0E,0x01,0x0E},
+    {0x1F,0x01,0x1F,0x01,0x0E,0x01,0x0E,0x01},
+    {0xE0,0xFE,0xE0,0xFE,0xF1,0xFE,0xF1,0xFE},
+    {0xFE,0xE0,0xFE,0xE0,0xFE,0xF1,0xFE,0xF1}
+};
+
+int
+DES_is_weak_key(DES_cblock *key)
+{
+    int i;
+
+    for (i = 0; i < sizeof(weak_keys)/sizeof(weak_keys[0]); i++) {
+       if (memcmp(weak_keys[i], key, DES_CBLOCK_LEN) == 0)
+           return 1;
+    }
+    return 0;
+}
+
+
+/*
+ *
+ */
+
+int
+DES_set_key(DES_cblock *key, DES_key_schedule *ks)
+{
+    uint32_t t1, t2;
+    uint32_t c, d;
+    int shifts[16] = { 1, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1 };
+    uint32_t *k = &ks->ks[0];
+    int i;
+
+    t1 = (*key)[0] << 24 | (*key)[1] << 16 | (*key)[2] << 8 | (*key)[3];
+    t2 = (*key)[4] << 24 | (*key)[5] << 16 | (*key)[6] << 8 | (*key)[7];
+
+    c =   (pc1_c_3[(t1 >> (5            )) & 0x7] << 3)
+       | (pc1_c_3[(t1 >> (5 + 8        )) & 0x7] << 2)
+       | (pc1_c_3[(t1 >> (5 + 8 + 8    )) & 0x7] << 1)
+       | (pc1_c_3[(t1 >> (5 + 8 + 8 + 8)) & 0x7] << 0)
+       | (pc1_c_4[(t2 >> (4            )) & 0xf] << 3)
+       | (pc1_c_4[(t2 >> (4 + 8        )) & 0xf] << 2)
+       | (pc1_c_4[(t2 >> (4 + 8 + 8    )) & 0xf] << 1)
+       | (pc1_c_4[(t2 >> (4 + 8 + 8 + 8)) & 0xf] << 0);
+
+    
+    d =   (pc1_d_3[(t2 >> (1            )) & 0x7] << 3)
+       | (pc1_d_3[(t2 >> (1 + 8        )) & 0x7] << 2)
+       | (pc1_d_3[(t2 >> (1 + 8 + 8    )) & 0x7] << 1)
+       | (pc1_d_3[(t2 >> (1 + 8 + 8 + 8)) & 0x7] << 0)
+       | (pc1_d_4[(t1 >> (1            )) & 0xf] << 3)
+       | (pc1_d_4[(t1 >> (1 + 8        )) & 0xf] << 2)
+       | (pc1_d_4[(t1 >> (1 + 8 + 8    )) & 0xf] << 1)
+       | (pc1_d_4[(t1 >> (1 + 8 + 8 + 8)) & 0xf] << 0);
+
+    for (i = 0; i < 16; i++) {
+       uint32_t kc, kd;
+       
+       ROTATE_LEFT28(c, shifts[i]);
+       ROTATE_LEFT28(d, shifts[i]);
+       
+       kc = pc2_c_1[(c >> 22) & 0x3f] |
+           pc2_c_2[((c >> 16) & 0x30) | ((c >> 15) & 0xf)] |
+           pc2_c_3[((c >> 9 ) & 0x3c) | ((c >> 8 ) & 0x3)] |
+           pc2_c_4[((c >> 2 ) & 0x20) | ((c >> 1) & 0x18) | (c & 0x7)];
+       kd = pc2_d_1[(d >> 22) & 0x3f] |
+           pc2_d_2[((d >> 15) & 0x30) | ((d >> 14) & 0xf)] |
+           pc2_d_3[ (d >> 7 ) & 0x3f] |
+           pc2_d_4[((d >> 1 ) & 0x3c) | ((d      ) & 0x3)];
+
+       /* Change to byte order used by the S boxes */
+       *k  =    (kc & 0x00fc0000L) << 6;
+       *k |=    (kc & 0x00000fc0L) << 10;
+       *k |=    (kd & 0x00fc0000L) >> 10;
+       *k++  |= (kd & 0x00000fc0L) >> 6;
+       *k  =    (kc & 0x0003f000L) << 12;
+       *k |=    (kc & 0x0000003fL) << 16;
+       *k |=    (kd & 0x0003f000L) >> 4;
+       *k++  |= (kd & 0x0000003fL);
+    }
+
+    return 0;
+}
+
+/*
+ *
+ */
+
+int
+DES_set_key_checked(DES_cblock *key, DES_key_schedule *ks)
+{
+    if (DES_is_weak_key(key)) {
+       memset(ks, 0, sizeof(*ks));
+       return 1;
+    }
+    return DES_set_key(key, ks);
+}
+
+/*
+ * Compatibility function for eay libdes
+ */
+
+int
+DES_key_sched(DES_cblock *key, DES_key_schedule *ks)
+{
+    return DES_set_key(key, ks);
+}
+
+/*
+ *
+ */
+
+static void
+load(const unsigned char *b, uint32_t v[2])
+{
+    v[0] =  b[0] << 24;
+    v[0] |= b[1] << 16;
+    v[0] |= b[2] << 8;
+    v[0] |= b[3] << 0;
+    v[1] =  b[4] << 24;
+    v[1] |= b[5] << 16;
+    v[1] |= b[6] << 8;
+    v[1] |= b[7] << 0;
+}
+
+static void
+store(const uint32_t v[2], unsigned char *b)
+{
+    b[0] = (v[0] >> 24) & 0xff;
+    b[1] = (v[0] >> 16) & 0xff;
+    b[2] = (v[0] >>  8) & 0xff;
+    b[3] = (v[0] >>  0) & 0xff;
+    b[4] = (v[1] >> 24) & 0xff;
+    b[5] = (v[1] >> 16) & 0xff;
+    b[6] = (v[1] >>  8) & 0xff;
+    b[7] = (v[1] >>  0) & 0xff;
+}
+
+/*
+ *
+ */
+
+void
+DES_encrypt(uint32_t u[2], DES_key_schedule *ks, int forward_encrypt)
+{
+    IP(u);
+    desx(u, ks, forward_encrypt);
+    FP(u);
+}
+
+/*
+ *
+ */
+
+void
+DES_ecb_encrypt(DES_cblock *input, DES_cblock *output,
+               DES_key_schedule *ks, int forward_encrypt)
+{
+    uint32_t u[2];
+    load(*input, u);
+    DES_encrypt(u, ks, forward_encrypt);
+    store(u, *output);
+}
+
+/*
+ *
+ */
+
+void
+DES_cbc_encrypt(unsigned char *input, unsigned char *output, long length,
+               DES_key_schedule *ks, DES_cblock *iv, int forward_encrypt)
+{
+    uint32_t u[2];
+    uint32_t uiv[2];
+
+    load(*iv, uiv);
+
+    if (forward_encrypt) {
+       while (length >= DES_CBLOCK_LEN) {
+           load(input, u);
+           u[0] ^= uiv[0]; u[1] ^= uiv[1];
+           DES_encrypt(u, ks, 1);
+           uiv[0] = u[0]; uiv[1] = u[1];
+           store(u, output);
+
+           length -= DES_CBLOCK_LEN;
+           input += DES_CBLOCK_LEN;
+           output += DES_CBLOCK_LEN;
+       }
+       if (length) {
+           unsigned char tmp[DES_CBLOCK_LEN];
+           memcpy(tmp, input, length);
+           memset(tmp + length, 0, DES_CBLOCK_LEN - length);
+           load(tmp, u);
+           u[0] ^= uiv[0]; u[1] ^= uiv[1];
+           DES_encrypt(u, ks, 1);
+           store(u, output);
+       }
+    } else {
+       uint32_t t[2];
+       while (length >= DES_CBLOCK_LEN) {
+           load(input, u);
+           t[0] = u[0]; t[1] = u[1];
+           DES_encrypt(u, ks, 0);
+           u[0] ^= uiv[0]; u[1] ^= uiv[1];
+           store(u, output);
+           uiv[0] = t[0]; uiv[1] = t[1];
+
+           length -= DES_CBLOCK_LEN;
+           input += DES_CBLOCK_LEN;
+           output += DES_CBLOCK_LEN;
+       }
+       if (length) {
+           unsigned char tmp[DES_CBLOCK_LEN];
+           memcpy(tmp, input, length);
+           memset(tmp + length, 0, DES_CBLOCK_LEN - length);
+           load(tmp, u);
+           DES_encrypt(u, ks, 0);
+           u[0] ^= uiv[0]; u[1] ^= uiv[1];
+           store(u, output);
+       }
+    }
+    uiv[0] = 0; u[0] = 0; uiv[1] = 0; u[1] = 0;
+}
+
+/*
+ *
+ */
+
+void
+DES_pcbc_encrypt(unsigned char *input, unsigned char *output, long length,
+                DES_key_schedule *ks, DES_cblock *iv, int forward_encrypt)
+{
+    uint32_t u[2];
+    uint32_t uiv[2];
+
+    load(*iv, uiv);
+
+    if (forward_encrypt) {
+       uint32_t t[2];
+       while (length >= DES_CBLOCK_LEN) {
+           load(input, u);
+           t[0] = u[0]; t[1] = u[1];
+           u[0] ^= uiv[0]; u[1] ^= uiv[1];
+           DES_encrypt(u, ks, 1);
+           uiv[0] = u[0] ^ t[0]; uiv[1] = u[1] ^ t[1];
+           store(u, output);
+
+           length -= DES_CBLOCK_LEN;
+           input += DES_CBLOCK_LEN;
+           output += DES_CBLOCK_LEN;
+       }
+       if (length) {
+           unsigned char tmp[DES_CBLOCK_LEN];
+           memcpy(tmp, input, length);
+           memset(tmp + length, 0, DES_CBLOCK_LEN - length);
+           load(tmp, u);
+           u[0] ^= uiv[0]; u[1] ^= uiv[1];
+           DES_encrypt(u, ks, 1);
+           store(u, output);
+       }
+    } else {
+       uint32_t t[2];
+       while (length >= DES_CBLOCK_LEN) {
+           load(input, u);
+           t[0] = u[0]; t[1] = u[1];
+           DES_encrypt(u, ks, 0);
+           u[0] ^= uiv[0]; u[1] ^= uiv[1];
+           store(u, output);
+           uiv[0] = t[0] ^ u[0]; uiv[1] = t[1] ^ u[1];
+
+           length -= DES_CBLOCK_LEN;
+           input += DES_CBLOCK_LEN;
+           output += DES_CBLOCK_LEN;
+       }
+       if (length) {
+           unsigned char tmp[DES_CBLOCK_LEN];
+           memcpy(tmp, input, length);
+           memset(tmp + length, 0, DES_CBLOCK_LEN - length);
+           load(tmp, u);
+           DES_encrypt(u, ks, 0);
+           u[0] ^= uiv[0]; u[1] ^= uiv[1];
+       }
+    }
+    uiv[0] = 0; u[0] = 0; uiv[1] = 0; u[1] = 0;
+}
+
+/*
+ *
+ */
+
+static void
+_des3_encrypt(uint32_t u[2], DES_key_schedule *ks1, DES_key_schedule *ks2, 
+             DES_key_schedule *ks3, int forward_encrypt)
+{
+    IP(u);
+    if (forward_encrypt) {
+       desx(u, ks1, 1); /* IP + FP cancel out each other */
+       desx(u, ks2, 0);
+       desx(u, ks3, 1);
+    } else {
+       desx(u, ks3, 0);
+       desx(u, ks2, 1);
+       desx(u, ks1, 0);
+    }
+    FP(u);
+}
+
+/*
+ *
+ */
+
+void
+DES_ecb3_encrypt(DES_cblock *input,
+                DES_cblock *output,
+                DES_key_schedule *ks1,
+                DES_key_schedule *ks2,
+                DES_key_schedule *ks3,
+                int forward_encrypt)
+{
+    uint32_t u[2];
+    load(*input, u);
+    _des3_encrypt(u, ks1, ks2, ks3, forward_encrypt);
+    store(u, *output);
+    return;
+}
+
+/*
+ *
+ */
+
+void
+DES_ede3_cbc_encrypt(const unsigned char *input, unsigned char *output,
+                    long length, DES_key_schedule *ks1, 
+                    DES_key_schedule *ks2, DES_key_schedule *ks3,
+                    DES_cblock *iv, int forward_encrypt)
+{
+    uint32_t u[2];
+    uint32_t uiv[2];
+
+    load(*iv, uiv);
+
+    if (forward_encrypt) {
+       while (length >= DES_CBLOCK_LEN) {
+           load(input, u);
+           u[0] ^= uiv[0]; u[1] ^= uiv[1];
+           _des3_encrypt(u, ks1, ks2, ks3, 1);
+           uiv[0] = u[0]; uiv[1] = u[1];
+           store(u, output);
+
+           length -= DES_CBLOCK_LEN;
+           input += DES_CBLOCK_LEN;
+           output += DES_CBLOCK_LEN;
+       }
+       if (length) {
+           unsigned char tmp[DES_CBLOCK_LEN];
+           memcpy(tmp, input, length);
+           memset(tmp + length, 0, DES_CBLOCK_LEN - length);
+           load(tmp, u);
+           u[0] ^= uiv[0]; u[1] ^= uiv[1];
+           _des3_encrypt(u, ks1, ks2, ks3, 1);
+           store(u, output);
+       }
+    } else {
+       uint32_t t[2];
+       while (length >= DES_CBLOCK_LEN) {
+           load(input, u);
+           t[0] = u[0]; t[1] = u[1];
+           _des3_encrypt(u, ks1, ks2, ks3, 0);
+           u[0] ^= uiv[0]; u[1] ^= uiv[1];
+           store(u, output);
+           uiv[0] = t[0]; uiv[1] = t[1];
+
+           length -= DES_CBLOCK_LEN;
+           input += DES_CBLOCK_LEN;
+           output += DES_CBLOCK_LEN;
+       }
+       if (length) {
+           unsigned char tmp[DES_CBLOCK_LEN];
+           memcpy(tmp, input, length);
+           memset(tmp + length, 0, DES_CBLOCK_LEN - length);
+           load(tmp, u);
+           _des3_encrypt(u, ks1, ks2, ks3, 0);
+           u[0] ^= uiv[0]; u[1] ^= uiv[1];
+           store(u, output);
+       }
+    }
+    store(uiv, *iv);
+    uiv[0] = 0; u[0] = 0; uiv[1] = 0; u[1] = 0;
+}
+
+/*
+ *
+ */
+
+void
+DES_cfb64_encrypt(unsigned char *input, unsigned char *output, 
+                 long length, DES_key_schedule *ks, DES_cblock *iv,
+                 int *num, int forward_encrypt)
+{
+    unsigned char tmp[DES_CBLOCK_LEN];
+    uint32_t uiv[2];
+
+    load(*iv, uiv);
+
+    if (forward_encrypt) {
+       int i = *num;
+
+       while (length > 0) {
+           if (i == 0)
+               DES_encrypt(uiv, ks, 1);
+           store(uiv, tmp);
+           for (; i < DES_CBLOCK_LEN && i < length; i++) {
+               output[i] = tmp[i] ^ input[i];
+           }
+           if (i == DES_CBLOCK_LEN)
+               load(output, uiv);
+           output += i;
+           input += i;
+           length -= i;
+           if (i == DES_CBLOCK_LEN)
+               i = 0;
+       }
+       store(uiv, *iv);
+       *num = i;
+    } else {
+       int i = *num;
+       unsigned char c;
+
+       while (length > 0) {
+           if (i == 0) {
+               DES_encrypt(uiv, ks, 1);
+               store(uiv, tmp);
+           }
+           for (; i < DES_CBLOCK_LEN && i < length; i++) {
+               c = input[i];
+               output[i] = tmp[i] ^ input[i];
+               (*iv)[i] = c;
+           }
+           output += i;
+           input += i;
+           length -= i;
+           if (i == DES_CBLOCK_LEN) {
+               i = 0;
+               load(*iv, uiv);
+           }
+       }
+       store(uiv, *iv);
+       *num = i;
+    }
+}
+
+/*
+ *
+ */
+
+uint32_t
+DES_cbc_cksum(const unsigned char *input, DES_cblock *output,
+             long length, DES_key_schedule *ks, DES_cblock *iv)
+{
+    uint32_t uiv[2];
+    uint32_t u[2] = { 0, 0 };
+
+    load(*iv, uiv);
+
+    while (length >= DES_CBLOCK_LEN) {
+       load(input, u);
+       u[0] ^= uiv[0]; u[1] ^= uiv[1];
+       DES_encrypt(u, ks, 1);
+       uiv[0] = u[0]; uiv[1] = u[1];
+       
+       length -= DES_CBLOCK_LEN;
+       input += DES_CBLOCK_LEN;
+    }
+    if (length) {
+       unsigned char tmp[DES_CBLOCK_LEN];
+       memcpy(tmp, input, length);
+       memset(tmp + length, 0, DES_CBLOCK_LEN - length);
+       load(tmp, u);
+       u[0] ^= uiv[0]; u[1] ^= uiv[1];
+       DES_encrypt(u, ks, 1);
+    }
+    if (output)
+       store(u, *output);
+
+    uiv[0] = 0; u[0] = 0; uiv[1] = 0;
+    return u[1];
+}
+
+/*
+ *
+ */
+
+static unsigned char
+bitswap8(unsigned char b)
+{
+    unsigned char r = 0;
+    int i;
+    for (i = 0; i < 8; i++) {
+       r = r << 1 | (b & 1);
+       b = b >> 1;
+    }
+    return r;
+}
+
+void
+DES_string_to_key(const char *str, DES_cblock *key)
+{
+    const unsigned char *s;
+    unsigned char *k;
+    DES_key_schedule ks;
+    size_t i, len;
+
+    memset(key, 0, sizeof(*key));
+    k = *key;
+    s = (const unsigned char *)str;
+
+    len = strlen(str);
+    for (i = 0; i < len; i++) {
+       if ((i % 16) < 8)
+           k[i % 8] ^= s[i] << 1;
+       else
+           k[7 - (i % 8)] ^= bitswap8(s[i]);
+    }
+    DES_set_odd_parity(key);
+    if (DES_is_weak_key(key))
+       k[7] ^= 0xF0;
+    DES_set_key(key, &ks);
+    DES_cbc_cksum(s, key, len, &ks, key);
+    memset(&ks, 0, sizeof(ks));
+    DES_set_odd_parity(key);
+    if (DES_is_weak_key(key))
+       k[7] ^= 0xF0;
+}
+
+/*
+ *
+ */
+
+int
+DES_read_password(DES_cblock *key, char *prompt, int verify)
+{
+    char buf[512];
+    int ret;
+
+    ret = UI_UTIL_read_pw_string(buf, sizeof(buf) - 1, prompt, verify);
+    if (ret == 0)
+       DES_string_to_key(buf, key);
+    return ret;
+}
+
+/*
+ *
+ */
+
+
+void
+_DES_ipfp_test(void)
+{
+    DES_cblock k = "\x01\x02\x04\x08\x10\x20\x40\x80", k2;
+    uint32_t u[2] = { 1, 0 };
+    IP(u);
+    FP(u);
+    IP(u);
+    FP(u);
+    if (u[0] != 1 || u[1] != 0)
+       abort();
+
+    load(k, u);
+    store(u, k2);
+    if (memcmp(k, k2, 8) != 0)
+       abort();
+}    
+
+/* D3DES (V5.09) - 
+ *
+ * A portable, public domain, version of the Data Encryption Standard.
+ *
+ * Written with Symantec's THINK (Lightspeed) C by Richard Outerbridge.
+ * Thanks to: Dan Hoey for his excellent Initial and Inverse permutation
+ * code;  Jim Gillogly & Phil Karn for the DES key schedule code; Dennis
+ * Ferguson, Eric Young and Dana How for comparing notes; and Ray Lau,
+ * for humouring me on. 
+ *
+ * Copyright (c) 1988,1989,1990,1991,1992 by Richard Outerbridge.
+ * (GEnie : OUTER; CIS : [71755,204]) Graven Imagery, 1992.
+ */
+
+static uint32_t SP1[64] = {
+    0x01010400L, 0x00000000L, 0x00010000L, 0x01010404L,
+    0x01010004L, 0x00010404L, 0x00000004L, 0x00010000L,
+    0x00000400L, 0x01010400L, 0x01010404L, 0x00000400L,
+    0x01000404L, 0x01010004L, 0x01000000L, 0x00000004L,
+    0x00000404L, 0x01000400L, 0x01000400L, 0x00010400L,
+    0x00010400L, 0x01010000L, 0x01010000L, 0x01000404L,
+    0x00010004L, 0x01000004L, 0x01000004L, 0x00010004L,
+    0x00000000L, 0x00000404L, 0x00010404L, 0x01000000L,
+    0x00010000L, 0x01010404L, 0x00000004L, 0x01010000L,
+    0x01010400L, 0x01000000L, 0x01000000L, 0x00000400L,
+    0x01010004L, 0x00010000L, 0x00010400L, 0x01000004L,
+    0x00000400L, 0x00000004L, 0x01000404L, 0x00010404L,
+    0x01010404L, 0x00010004L, 0x01010000L, 0x01000404L,
+    0x01000004L, 0x00000404L, 0x00010404L, 0x01010400L,
+    0x00000404L, 0x01000400L, 0x01000400L, 0x00000000L,
+    0x00010004L, 0x00010400L, 0x00000000L, 0x01010004L };
+
+static uint32_t SP2[64] = {
+    0x80108020L, 0x80008000L, 0x00008000L, 0x00108020L,
+    0x00100000L, 0x00000020L, 0x80100020L, 0x80008020L,
+    0x80000020L, 0x80108020L, 0x80108000L, 0x80000000L,
+    0x80008000L, 0x00100000L, 0x00000020L, 0x80100020L,
+    0x00108000L, 0x00100020L, 0x80008020L, 0x00000000L,
+    0x80000000L, 0x00008000L, 0x00108020L, 0x80100000L,
+    0x00100020L, 0x80000020L, 0x00000000L, 0x00108000L,
+    0x00008020L, 0x80108000L, 0x80100000L, 0x00008020L,
+    0x00000000L, 0x00108020L, 0x80100020L, 0x00100000L,
+    0x80008020L, 0x80100000L, 0x80108000L, 0x00008000L,
+    0x80100000L, 0x80008000L, 0x00000020L, 0x80108020L,
+    0x00108020L, 0x00000020L, 0x00008000L, 0x80000000L,
+    0x00008020L, 0x80108000L, 0x00100000L, 0x80000020L,
+    0x00100020L, 0x80008020L, 0x80000020L, 0x00100020L,
+    0x00108000L, 0x00000000L, 0x80008000L, 0x00008020L,
+    0x80000000L, 0x80100020L, 0x80108020L, 0x00108000L };
+
+static uint32_t SP3[64] = {
+    0x00000208L, 0x08020200L, 0x00000000L, 0x08020008L,
+    0x08000200L, 0x00000000L, 0x00020208L, 0x08000200L,
+    0x00020008L, 0x08000008L, 0x08000008L, 0x00020000L,
+    0x08020208L, 0x00020008L, 0x08020000L, 0x00000208L,
+    0x08000000L, 0x00000008L, 0x08020200L, 0x00000200L,
+    0x00020200L, 0x08020000L, 0x08020008L, 0x00020208L,
+    0x08000208L, 0x00020200L, 0x00020000L, 0x08000208L,
+    0x00000008L, 0x08020208L, 0x00000200L, 0x08000000L,
+    0x08020200L, 0x08000000L, 0x00020008L, 0x00000208L,
+    0x00020000L, 0x08020200L, 0x08000200L, 0x00000000L,
+    0x00000200L, 0x00020008L, 0x08020208L, 0x08000200L,
+    0x08000008L, 0x00000200L, 0x00000000L, 0x08020008L,
+    0x08000208L, 0x00020000L, 0x08000000L, 0x08020208L,
+    0x00000008L, 0x00020208L, 0x00020200L, 0x08000008L,
+    0x08020000L, 0x08000208L, 0x00000208L, 0x08020000L,
+    0x00020208L, 0x00000008L, 0x08020008L, 0x00020200L };
+
+static uint32_t SP4[64] = {
+    0x00802001L, 0x00002081L, 0x00002081L, 0x00000080L,
+    0x00802080L, 0x00800081L, 0x00800001L, 0x00002001L,
+    0x00000000L, 0x00802000L, 0x00802000L, 0x00802081L,
+    0x00000081L, 0x00000000L, 0x00800080L, 0x00800001L,
+    0x00000001L, 0x00002000L, 0x00800000L, 0x00802001L,
+    0x00000080L, 0x00800000L, 0x00002001L, 0x00002080L,
+    0x00800081L, 0x00000001L, 0x00002080L, 0x00800080L,
+    0x00002000L, 0x00802080L, 0x00802081L, 0x00000081L,
+    0x00800080L, 0x00800001L, 0x00802000L, 0x00802081L,
+    0x00000081L, 0x00000000L, 0x00000000L, 0x00802000L,
+    0x00002080L, 0x00800080L, 0x00800081L, 0x00000001L,
+    0x00802001L, 0x00002081L, 0x00002081L, 0x00000080L,
+    0x00802081L, 0x00000081L, 0x00000001L, 0x00002000L,
+    0x00800001L, 0x00002001L, 0x00802080L, 0x00800081L,
+    0x00002001L, 0x00002080L, 0x00800000L, 0x00802001L,
+    0x00000080L, 0x00800000L, 0x00002000L, 0x00802080L };
+
+static uint32_t SP5[64] = {
+    0x00000100L, 0x02080100L, 0x02080000L, 0x42000100L,
+    0x00080000L, 0x00000100L, 0x40000000L, 0x02080000L,
+    0x40080100L, 0x00080000L, 0x02000100L, 0x40080100L,
+    0x42000100L, 0x42080000L, 0x00080100L, 0x40000000L,
+    0x02000000L, 0x40080000L, 0x40080000L, 0x00000000L,
+    0x40000100L, 0x42080100L, 0x42080100L, 0x02000100L,
+    0x42080000L, 0x40000100L, 0x00000000L, 0x42000000L,
+    0x02080100L, 0x02000000L, 0x42000000L, 0x00080100L,
+    0x00080000L, 0x42000100L, 0x00000100L, 0x02000000L,
+    0x40000000L, 0x02080000L, 0x42000100L, 0x40080100L,
+    0x02000100L, 0x40000000L, 0x42080000L, 0x02080100L,
+    0x40080100L, 0x00000100L, 0x02000000L, 0x42080000L,
+    0x42080100L, 0x00080100L, 0x42000000L, 0x42080100L,
+    0x02080000L, 0x00000000L, 0x40080000L, 0x42000000L,
+    0x00080100L, 0x02000100L, 0x40000100L, 0x00080000L,
+    0x00000000L, 0x40080000L, 0x02080100L, 0x40000100L };
+
+static uint32_t SP6[64] = {
+    0x20000010L, 0x20400000L, 0x00004000L, 0x20404010L,
+    0x20400000L, 0x00000010L, 0x20404010L, 0x00400000L,
+    0x20004000L, 0x00404010L, 0x00400000L, 0x20000010L,
+    0x00400010L, 0x20004000L, 0x20000000L, 0x00004010L,
+    0x00000000L, 0x00400010L, 0x20004010L, 0x00004000L,
+    0x00404000L, 0x20004010L, 0x00000010L, 0x20400010L,
+    0x20400010L, 0x00000000L, 0x00404010L, 0x20404000L,
+    0x00004010L, 0x00404000L, 0x20404000L, 0x20000000L,
+    0x20004000L, 0x00000010L, 0x20400010L, 0x00404000L,
+    0x20404010L, 0x00400000L, 0x00004010L, 0x20000010L,
+    0x00400000L, 0x20004000L, 0x20000000L, 0x00004010L,
+    0x20000010L, 0x20404010L, 0x00404000L, 0x20400000L,
+    0x00404010L, 0x20404000L, 0x00000000L, 0x20400010L,
+    0x00000010L, 0x00004000L, 0x20400000L, 0x00404010L,
+    0x00004000L, 0x00400010L, 0x20004010L, 0x00000000L,
+    0x20404000L, 0x20000000L, 0x00400010L, 0x20004010L };
+
+static uint32_t SP7[64] = {
+    0x00200000L, 0x04200002L, 0x04000802L, 0x00000000L,
+    0x00000800L, 0x04000802L, 0x00200802L, 0x04200800L,
+    0x04200802L, 0x00200000L, 0x00000000L, 0x04000002L,
+    0x00000002L, 0x04000000L, 0x04200002L, 0x00000802L,
+    0x04000800L, 0x00200802L, 0x00200002L, 0x04000800L,
+    0x04000002L, 0x04200000L, 0x04200800L, 0x00200002L,
+    0x04200000L, 0x00000800L, 0x00000802L, 0x04200802L,
+    0x00200800L, 0x00000002L, 0x04000000L, 0x00200800L,
+    0x04000000L, 0x00200800L, 0x00200000L, 0x04000802L,
+    0x04000802L, 0x04200002L, 0x04200002L, 0x00000002L,
+    0x00200002L, 0x04000000L, 0x04000800L, 0x00200000L,
+    0x04200800L, 0x00000802L, 0x00200802L, 0x04200800L,
+    0x00000802L, 0x04000002L, 0x04200802L, 0x04200000L,
+    0x00200800L, 0x00000000L, 0x00000002L, 0x04200802L,
+    0x00000000L, 0x00200802L, 0x04200000L, 0x00000800L,
+    0x04000002L, 0x04000800L, 0x00000800L, 0x00200002L };
+
+static uint32_t SP8[64] = {
+    0x10001040L, 0x00001000L, 0x00040000L, 0x10041040L,
+    0x10000000L, 0x10001040L, 0x00000040L, 0x10000000L,
+    0x00040040L, 0x10040000L, 0x10041040L, 0x00041000L,
+    0x10041000L, 0x00041040L, 0x00001000L, 0x00000040L,
+    0x10040000L, 0x10000040L, 0x10001000L, 0x00001040L,
+    0x00041000L, 0x00040040L, 0x10040040L, 0x10041000L,
+    0x00001040L, 0x00000000L, 0x00000000L, 0x10040040L,
+    0x10000040L, 0x10001000L, 0x00041040L, 0x00040000L,
+    0x00041040L, 0x00040000L, 0x10041000L, 0x00001000L,
+    0x00000040L, 0x10040040L, 0x00001000L, 0x00041040L,
+    0x10001000L, 0x00000040L, 0x10000040L, 0x10040000L,
+    0x10040040L, 0x10000000L, 0x00040000L, 0x10001040L,
+    0x00000000L, 0x10041040L, 0x00040040L, 0x10000040L,
+    0x10040000L, 0x10001000L, 0x10001040L, 0x00000000L,
+    0x10041040L, 0x00041000L, 0x00041000L, 0x00001040L,
+    0x00001040L, 0x00040040L, 0x10000000L, 0x10041000L };
+
+static void
+IP(uint32_t v[2])
+{
+    uint32_t work;
+
+    work = ((v[0] >> 4) ^ v[1]) & 0x0f0f0f0fL;
+    v[1] ^= work;
+    v[0] ^= (work << 4);
+    work = ((v[0] >> 16) ^ v[1]) & 0x0000ffffL;
+    v[1] ^= work;
+    v[0] ^= (work << 16);
+    work = ((v[1] >> 2) ^ v[0]) & 0x33333333L;
+    v[0] ^= work;
+    v[1] ^= (work << 2);
+    work = ((v[1] >> 8) ^ v[0]) & 0x00ff00ffL;
+    v[0] ^= work;
+    v[1] ^= (work << 8);
+    v[1] = ((v[1] << 1) | ((v[1] >> 31) & 1L)) & 0xffffffffL;
+    work = (v[0] ^ v[1]) & 0xaaaaaaaaL;
+    v[0] ^= work;
+    v[1] ^= work;
+    v[0] = ((v[0] << 1) | ((v[0] >> 31) & 1L)) & 0xffffffffL;
+}
+
+static void
+FP(uint32_t v[2])
+{
+    uint32_t work;
+
+    v[0] = (v[0] << 31) | (v[0] >> 1);
+    work = (v[1] ^ v[0]) & 0xaaaaaaaaL;
+    v[1] ^= work;
+    v[0] ^= work;
+    v[1] = (v[1] << 31) | (v[1] >> 1);
+    work = ((v[1] >> 8) ^ v[0]) & 0x00ff00ffL;
+    v[0] ^= work;
+    v[1] ^= (work << 8);
+    work = ((v[1] >> 2) ^ v[0]) & 0x33333333L;
+    v[0] ^= work;
+    v[1] ^= (work << 2);
+    work = ((v[0] >> 16) ^ v[1]) & 0x0000ffffL;
+    v[1] ^= work;
+    v[0] ^= (work << 16);
+    work = ((v[0] >> 4) ^ v[1]) & 0x0f0f0f0fL;
+    v[1] ^= work;
+    v[0] ^= (work << 4);
+}
+
+static void
+desx(uint32_t block[2], DES_key_schedule *ks, int forward_encrypt)
+{
+    uint32_t *keys;
+    uint32_t fval, work, right, left;
+    int round;
+
+    left = block[0];
+    right = block[1];
+
+    if (forward_encrypt) {
+       keys = &ks->ks[0];
+
+       for( round = 0; round < 8; round++ ) {
+           work  = (right << 28) | (right >> 4);
+           work ^= *keys++;
+           fval  = SP7[ work     & 0x3fL];
+           fval |= SP5[(work >>  8) & 0x3fL];
+           fval |= SP3[(work >> 16) & 0x3fL];
+           fval |= SP1[(work >> 24) & 0x3fL];
+           work  = right ^ *keys++;
+           fval |= SP8[ work     & 0x3fL];
+           fval |= SP6[(work >>  8) & 0x3fL];
+           fval |= SP4[(work >> 16) & 0x3fL];
+           fval |= SP2[(work >> 24) & 0x3fL];
+           left ^= fval;
+           work  = (left << 28) | (left >> 4);
+           work ^= *keys++;
+           fval  = SP7[ work     & 0x3fL];
+           fval |= SP5[(work >>  8) & 0x3fL];
+           fval |= SP3[(work >> 16) & 0x3fL];
+           fval |= SP1[(work >> 24) & 0x3fL];
+           work  = left ^ *keys++;
+           fval |= SP8[ work     & 0x3fL];
+           fval |= SP6[(work >>  8) & 0x3fL];
+           fval |= SP4[(work >> 16) & 0x3fL];
+           fval |= SP2[(work >> 24) & 0x3fL];
+           right ^= fval;
+       }
+    } else {
+       keys = &ks->ks[30];
+
+       for( round = 0; round < 8; round++ ) {
+           work  = (right << 28) | (right >> 4);
+           work ^= *keys++;
+           fval  = SP7[ work     & 0x3fL];
+           fval |= SP5[(work >>  8) & 0x3fL];
+           fval |= SP3[(work >> 16) & 0x3fL];
+           fval |= SP1[(work >> 24) & 0x3fL];
+           work  = right ^ *keys++;
+           fval |= SP8[ work     & 0x3fL];
+           fval |= SP6[(work >>  8) & 0x3fL];
+           fval |= SP4[(work >> 16) & 0x3fL];
+           fval |= SP2[(work >> 24) & 0x3fL];
+           left ^= fval;
+           work  = (left << 28) | (left >> 4);
+           keys -= 4;
+           work ^= *keys++;
+           fval  = SP7[ work     & 0x3fL];
+           fval |= SP5[(work >>  8) & 0x3fL];
+           fval |= SP3[(work >> 16) & 0x3fL];
+           fval |= SP1[(work >> 24) & 0x3fL];
+           work  = left ^ *keys++;
+           fval |= SP8[ work     & 0x3fL];
+           fval |= SP6[(work >>  8) & 0x3fL];
+           fval |= SP4[(work >> 16) & 0x3fL];
+           fval |= SP2[(work >> 24) & 0x3fL];
+           right ^= fval;
+           keys -= 4;
+       }
+    }
+    block[0] = right;
+    block[1] = left;
+}
diff --git a/source4/heimdal/lib/des/des.h b/source4/heimdal/lib/des/des.h
new file mode 100644 (file)
index 0000000..378c775
--- /dev/null
@@ -0,0 +1,92 @@
+/*
+ * Copyright (c) 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.
+ */
+
+/* $Id: des.h,v 1.23 2005/04/30 14:09:50 lha Exp $ */
+
+#ifndef _DESperate_H
+#define _DESperate_H 1
+
+#define DES_CBLOCK_LEN 8
+#define DES_KEY_SZ 8
+
+#define DES_ENCRYPT 1
+#define DES_DECRYPT 0
+
+typedef unsigned char DES_cblock[DES_CBLOCK_LEN];
+typedef struct DES_key_schedule
+{
+       uint32_t ks[32];
+} DES_key_schedule;
+
+int    DES_set_odd_parity(DES_cblock *);
+int    DES_is_weak_key(DES_cblock *);
+int    DES_set_key(DES_cblock *, DES_key_schedule *);
+int    DES_set_key_checked(DES_cblock *, DES_key_schedule *);
+int    DES_key_sched(DES_cblock *, DES_key_schedule *);
+int    DES_new_random_key(DES_cblock *);
+void   DES_string_to_key(const char *, DES_cblock *);
+int    DES_read_password(DES_cblock *, char *, int);
+
+int    UI_UTIL_read_pw_string(char *, int, const char *, int); /* XXX */
+
+void   DES_rand_data(unsigned char *, int);
+void   DES_set_random_generator_seed(DES_cblock *);
+void   DES_generate_random_block(DES_cblock *);
+void   DES_set_sequence_number(unsigned char *);
+void   DES_init_random_number_generator(DES_cblock *);
+void   DES_random_key(DES_cblock *);
+
+
+void   DES_encrypt(uint32_t [2], DES_key_schedule *, int);
+void   DES_ecb_encrypt(DES_cblock *, DES_cblock *, DES_key_schedule *, int);
+void   DES_ecb3_encrypt(DES_cblock *,DES_cblock *, DES_key_schedule *,
+                        DES_key_schedule *, DES_key_schedule *, int);
+void   DES_pcbc_encrypt(unsigned char *, unsigned char *, long,
+                        DES_key_schedule *, DES_cblock *, int);
+void   DES_cbc_encrypt(unsigned char *, unsigned char *, long,
+                       DES_key_schedule *, DES_cblock *, int);
+void   DES_ede3_cbc_encrypt(const unsigned char *, unsigned char *, long, 
+                            DES_key_schedule *, DES_key_schedule *, 
+                            DES_key_schedule *, DES_cblock *, int);
+void DES_cfb64_encrypt(unsigned char *, unsigned char *, long,
+                      DES_key_schedule *, DES_cblock *, int *, int);
+
+
+uint32_t DES_cbc_cksum(const unsigned char *, DES_cblock *,
+                     long, DES_key_schedule *, DES_cblock *);
+
+
+void   _DES_ipfp_test(void);
+
+
+#endif /* _DESperate_H */
diff --git a/source4/heimdal/lib/des/hash.h b/source4/heimdal/lib/des/hash.h
new file mode 100644 (file)
index 0000000..24217a2
--- /dev/null
@@ -0,0 +1,71 @@
+/*
+ * 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. */
+
+/* $Id: hash.h,v 1.3 2005/04/27 11:53:48 lha Exp $ */
+
+/* stuff in common between md4, md5, and sha1 */
+
+#ifndef __hash_h__
+#define __hash_h__
+
+#include <stdlib.h>
+#include <string.h>
+#include <stddef.h>
+#ifdef KRB5
+#include <krb5-types.h>
+#endif
+
+#ifndef min
+#define min(a,b) (((a)>(b))?(b):(a))
+#endif
+
+/* Vector Crays doesn't have a good 32-bit type, or more precisely,
+   int32_t as defined by <bind/bitypes.h> isn't 32 bits, and we don't
+   want to depend in being able to redefine this type.  To cope with
+   this we have to clamp the result in some places to [0,2^32); no
+   need to do this on other machines.  Did I say this was a mess?
+   */
+
+#ifdef _CRAY
+#define CRAYFIX(X) ((X) & 0xffffffff)
+#else
+#define CRAYFIX(X) (X)
+#endif
+
+static inline u_int32_t
+cshift (u_int32_t x, unsigned int n)
+{
+    x = CRAYFIX(x);
+    return CRAYFIX((x << n) | (x >> (32 - n)));
+}
+
+#endif /* __hash_h__ */
diff --git a/source4/heimdal/lib/des/md4.c b/source4/heimdal/lib/des/md4.c
new file mode 100644 (file)
index 0000000..693b8f5
--- /dev/null
@@ -0,0 +1,250 @@
+/*
+ * Copyright (c) 1995 - 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.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+
+RCSID("$Id: md4.c,v 1.17 2005/04/27 11:54:56 lha Exp $");
+#endif
+
+#include "hash.h"
+#include "md4.h"
+
+#define A m->counter[0]
+#define B m->counter[1]
+#define C m->counter[2]
+#define D m->counter[3]
+#define X data
+
+void
+MD4_Init (struct md4 *m)
+{
+  m->sz[0] = 0;
+  m->sz[1] = 0;
+  D = 0x10325476;
+  C = 0x98badcfe;
+  B = 0xefcdab89;
+  A = 0x67452301;
+}
+
+#define F(x,y,z) CRAYFIX((x & y) | (~x & z))
+#define G(x,y,z) ((x & y) | (x & z) | (y & z))
+#define H(x,y,z) (x ^ y ^ z)
+
+#define DOIT(a,b,c,d,k,s,i,OP) \
+a = cshift(a + OP(b,c,d) + X[k] + i, s)
+
+#define DO1(a,b,c,d,k,s,i) DOIT(a,b,c,d,k,s,i,F)
+#define DO2(a,b,c,d,k,s,i) DOIT(a,b,c,d,k,s,i,G)
+#define DO3(a,b,c,d,k,s,i) DOIT(a,b,c,d,k,s,i,H)
+
+static inline void
+calc (struct md4 *m, u_int32_t *data)
+{
+  u_int32_t AA, BB, CC, DD;
+
+  AA = A;
+  BB = B;
+  CC = C;
+  DD = D;
+
+  /* Round 1 */
+
+  DO1(A,B,C,D,0,3,0);
+  DO1(D,A,B,C,1,7,0);
+  DO1(C,D,A,B,2,11,0);
+  DO1(B,C,D,A,3,19,0);
+
+  DO1(A,B,C,D,4,3,0);
+  DO1(D,A,B,C,5,7,0);
+  DO1(C,D,A,B,6,11,0);
+  DO1(B,C,D,A,7,19,0);
+
+  DO1(A,B,C,D,8,3,0);
+  DO1(D,A,B,C,9,7,0);
+  DO1(C,D,A,B,10,11,0);
+  DO1(B,C,D,A,11,19,0);
+
+  DO1(A,B,C,D,12,3,0);
+  DO1(D,A,B,C,13,7,0);
+  DO1(C,D,A,B,14,11,0);
+  DO1(B,C,D,A,15,19,0);
+
+  /* Round 2 */
+
+  DO2(A,B,C,D,0,3,0x5A827999);
+  DO2(D,A,B,C,4,5,0x5A827999);
+  DO2(C,D,A,B,8,9,0x5A827999);
+  DO2(B,C,D,A,12,13,0x5A827999);
+
+  DO2(A,B,C,D,1,3,0x5A827999);
+  DO2(D,A,B,C,5,5,0x5A827999);
+  DO2(C,D,A,B,9,9,0x5A827999);
+  DO2(B,C,D,A,13,13,0x5A827999);
+
+  DO2(A,B,C,D,2,3,0x5A827999);
+  DO2(D,A,B,C,6,5,0x5A827999);
+  DO2(C,D,A,B,10,9,0x5A827999);
+  DO2(B,C,D,A,14,13,0x5A827999);
+
+  DO2(A,B,C,D,3,3,0x5A827999);
+  DO2(D,A,B,C,7,5,0x5A827999);
+  DO2(C,D,A,B,11,9,0x5A827999);
+  DO2(B,C,D,A,15,13,0x5A827999);
+
+  /* Round 3 */
+
+  DO3(A,B,C,D,0,3,0x6ED9EBA1);
+  DO3(D,A,B,C,8,9,0x6ED9EBA1);
+  DO3(C,D,A,B,4,11,0x6ED9EBA1);
+  DO3(B,C,D,A,12,15,0x6ED9EBA1);
+
+  DO3(A,B,C,D,2,3,0x6ED9EBA1);
+  DO3(D,A,B,C,10,9,0x6ED9EBA1);
+  DO3(C,D,A,B,6,11,0x6ED9EBA1);
+  DO3(B,C,D,A,14,15,0x6ED9EBA1);
+
+  DO3(A,B,C,D,1,3,0x6ED9EBA1);
+  DO3(D,A,B,C,9,9,0x6ED9EBA1);
+  DO3(C,D,A,B,5,11,0x6ED9EBA1);
+  DO3(B,C,D,A,13,15,0x6ED9EBA1);
+
+  DO3(A,B,C,D,3,3,0x6ED9EBA1);
+  DO3(D,A,B,C,11,9,0x6ED9EBA1);
+  DO3(C,D,A,B,7,11,0x6ED9EBA1);
+  DO3(B,C,D,A,15,15,0x6ED9EBA1);
+
+  A += AA;
+  B += BB;
+  C += CC;
+  D += DD;
+}
+
+/*
+ * From `Performance analysis of MD5' by Joseph D. Touch <touch@isi.edu>
+ */
+
+#if defined(WORDS_BIGENDIAN)
+static inline u_int32_t
+swap_u_int32_t (u_int32_t t)
+{
+  u_int32_t temp1, temp2;
+
+  temp1   = cshift(t, 16);
+  temp2   = temp1 >> 8;
+  temp1  &= 0x00ff00ff;
+  temp2  &= 0x00ff00ff;
+  temp1 <<= 8;
+  return temp1 | temp2;
+}
+#endif
+
+struct x32{
+  unsigned int a:32;
+  unsigned int b:32;
+};
+
+void
+MD4_Update (struct md4 *m, const void *v, size_t len)
+{
+    const unsigned char *p = v;
+    size_t old_sz = m->sz[0];
+    size_t offset;
+
+    m->sz[0] += len * 8;
+    if (m->sz[0] < old_sz)
+       ++m->sz[1];
+    offset = (old_sz / 8)  % 64;
+    while(len > 0) {
+       size_t l = min(len, 64 - offset);
+       memcpy(m->save + offset, p, l);
+       offset += l;
+       p += l;
+       len -= l;
+       if(offset == 64) {
+#if defined(WORDS_BIGENDIAN)
+           int i;
+           u_int32_t current[16];
+           struct x32 *u = (struct x32*)m->save;
+           for(i = 0; i < 8; i++){
+               current[2*i+0] = swap_u_int32_t(u[i].a);
+               current[2*i+1] = swap_u_int32_t(u[i].b);
+           }
+           calc(m, current);
+#else
+           calc(m, (u_int32_t*)m->save);
+#endif
+           offset = 0;
+       }
+    }
+}
+
+void
+MD4_Final (void *res, struct md4 *m)
+{
+  unsigned char zeros[72];
+  unsigned offset = (m->sz[0] / 8) % 64;
+  unsigned int dstart = (120 - offset - 1) % 64 + 1;
+
+  *zeros = 0x80;
+  memset (zeros + 1, 0, sizeof(zeros) - 1);
+  zeros[dstart+0] = (m->sz[0] >> 0) & 0xff;
+  zeros[dstart+1] = (m->sz[0] >> 8) & 0xff;
+  zeros[dstart+2] = (m->sz[0] >> 16) & 0xff;
+  zeros[dstart+3] = (m->sz[0] >> 24) & 0xff;
+  zeros[dstart+4] = (m->sz[1] >> 0) & 0xff;
+  zeros[dstart+5] = (m->sz[1] >> 8) & 0xff;
+  zeros[dstart+6] = (m->sz[1] >> 16) & 0xff;
+  zeros[dstart+7] = (m->sz[1] >> 24) & 0xff;
+  MD4_Update (m, zeros, dstart + 8);
+  {
+      int i;
+      unsigned char *r = (unsigned char *)res;
+
+      for (i = 0; i < 4; ++i) {
+         r[4*i]   = m->counter[i] & 0xFF;
+         r[4*i+1] = (m->counter[i] >> 8) & 0xFF;
+         r[4*i+2] = (m->counter[i] >> 16) & 0xFF;
+         r[4*i+3] = (m->counter[i] >> 24) & 0xFF;
+      }
+  }
+#if 0
+  {
+    int i;
+    u_int32_t *r = (u_int32_t *)res;
+
+    for (i = 0; i < 4; ++i)
+      r[i] = swap_u_int32_t (m->counter[i]);
+  }
+#endif
+}
diff --git a/source4/heimdal/lib/des/md4.h b/source4/heimdal/lib/des/md4.h
new file mode 100644 (file)
index 0000000..92147c8
--- /dev/null
@@ -0,0 +1,51 @@
+/*
+ * Copyright (c) 1995 - 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.
+ */
+
+/* $Id: md4.h,v 1.9 2005/04/10 19:12:38 lha Exp $ */
+
+#ifndef HEIM_MD4_H
+#define HEIM_MD4_H 1
+
+struct md4 {
+  unsigned int sz[2];
+  u_int32_t counter[4];
+  unsigned char save[64];
+};
+
+typedef struct md4 MD4_CTX;
+
+void MD4_Init (struct md4 *m);
+void MD4_Update (struct md4 *m, const void *p, size_t len);
+void MD4_Final (void *res, struct md4 *m);
+
+#endif /* HEIM_MD4_H */
diff --git a/source4/heimdal/lib/des/md5.c b/source4/heimdal/lib/des/md5.c
new file mode 100644 (file)
index 0000000..d5b7c24
--- /dev/null
@@ -0,0 +1,274 @@
+/*
+ * Copyright (c) 1995 - 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.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+
+RCSID("$Id: md5.c,v 1.17 2005/04/27 11:54:35 lha Exp $");
+#endif
+
+#include "hash.h"
+#include "md5.h"
+
+#define A m->counter[0]
+#define B m->counter[1]
+#define C m->counter[2]
+#define D m->counter[3]
+#define X data
+
+void
+MD5_Init (struct md5 *m)
+{
+  m->sz[0] = 0;
+  m->sz[1] = 0;
+  D = 0x10325476;
+  C = 0x98badcfe;
+  B = 0xefcdab89;
+  A = 0x67452301;
+}
+
+#define F(x,y,z) CRAYFIX((x & y) | (~x & z))
+#define G(x,y,z) CRAYFIX((x & z) | (y & ~z))
+#define H(x,y,z) (x ^ y ^ z)
+#define I(x,y,z) CRAYFIX(y ^ (x | ~z))
+
+#define DOIT(a,b,c,d,k,s,i,OP) \
+a = b + cshift(a + OP(b,c,d) + X[k] + (i), s)
+
+#define DO1(a,b,c,d,k,s,i) DOIT(a,b,c,d,k,s,i,F)
+#define DO2(a,b,c,d,k,s,i) DOIT(a,b,c,d,k,s,i,G)
+#define DO3(a,b,c,d,k,s,i) DOIT(a,b,c,d,k,s,i,H)
+#define DO4(a,b,c,d,k,s,i) DOIT(a,b,c,d,k,s,i,I)
+
+static inline void
+calc (struct md5 *m, u_int32_t *data)
+{
+  u_int32_t AA, BB, CC, DD;
+
+  AA = A;
+  BB = B;
+  CC = C;
+  DD = D;
+
+  /* Round 1 */
+
+  DO1(A,B,C,D,0,7,0xd76aa478);
+  DO1(D,A,B,C,1,12,0xe8c7b756);
+  DO1(C,D,A,B,2,17,0x242070db);
+  DO1(B,C,D,A,3,22,0xc1bdceee);
+
+  DO1(A,B,C,D,4,7,0xf57c0faf);
+  DO1(D,A,B,C,5,12,0x4787c62a);
+  DO1(C,D,A,B,6,17,0xa8304613);
+  DO1(B,C,D,A,7,22,0xfd469501);
+
+  DO1(A,B,C,D,8,7,0x698098d8);
+  DO1(D,A,B,C,9,12,0x8b44f7af);
+  DO1(C,D,A,B,10,17,0xffff5bb1);
+  DO1(B,C,D,A,11,22,0x895cd7be);
+
+  DO1(A,B,C,D,12,7,0x6b901122);
+  DO1(D,A,B,C,13,12,0xfd987193);
+  DO1(C,D,A,B,14,17,0xa679438e);
+  DO1(B,C,D,A,15,22,0x49b40821);
+
+  /* Round 2 */
+
+  DO2(A,B,C,D,1,5,0xf61e2562);
+  DO2(D,A,B,C,6,9,0xc040b340);
+  DO2(C,D,A,B,11,14,0x265e5a51);
+  DO2(B,C,D,A,0,20,0xe9b6c7aa);
+
+  DO2(A,B,C,D,5,5,0xd62f105d);
+  DO2(D,A,B,C,10,9,0x2441453);
+  DO2(C,D,A,B,15,14,0xd8a1e681);
+  DO2(B,C,D,A,4,20,0xe7d3fbc8);
+
+  DO2(A,B,C,D,9,5,0x21e1cde6);
+  DO2(D,A,B,C,14,9,0xc33707d6);
+  DO2(C,D,A,B,3,14,0xf4d50d87);
+  DO2(B,C,D,A,8,20,0x455a14ed);
+
+  DO2(A,B,C,D,13,5,0xa9e3e905);
+  DO2(D,A,B,C,2,9,0xfcefa3f8);
+  DO2(C,D,A,B,7,14,0x676f02d9);
+  DO2(B,C,D,A,12,20,0x8d2a4c8a);
+
+  /* Round 3 */
+
+  DO3(A,B,C,D,5,4,0xfffa3942);
+  DO3(D,A,B,C,8,11,0x8771f681);
+  DO3(C,D,A,B,11,16,0x6d9d6122);
+  DO3(B,C,D,A,14,23,0xfde5380c);
+
+  DO3(A,B,C,D,1,4,0xa4beea44);
+  DO3(D,A,B,C,4,11,0x4bdecfa9);
+  DO3(C,D,A,B,7,16,0xf6bb4b60);
+  DO3(B,C,D,A,10,23,0xbebfbc70);
+
+  DO3(A,B,C,D,13,4,0x289b7ec6);
+  DO3(D,A,B,C,0,11,0xeaa127fa);
+  DO3(C,D,A,B,3,16,0xd4ef3085);
+  DO3(B,C,D,A,6,23,0x4881d05);
+
+  DO3(A,B,C,D,9,4,0xd9d4d039);
+  DO3(D,A,B,C,12,11,0xe6db99e5);
+  DO3(C,D,A,B,15,16,0x1fa27cf8);
+  DO3(B,C,D,A,2,23,0xc4ac5665);
+
+  /* Round 4 */
+
+  DO4(A,B,C,D,0,6,0xf4292244);
+  DO4(D,A,B,C,7,10,0x432aff97);
+  DO4(C,D,A,B,14,15,0xab9423a7);
+  DO4(B,C,D,A,5,21,0xfc93a039);
+
+  DO4(A,B,C,D,12,6,0x655b59c3);
+  DO4(D,A,B,C,3,10,0x8f0ccc92);
+  DO4(C,D,A,B,10,15,0xffeff47d);
+  DO4(B,C,D,A,1,21,0x85845dd1);
+
+  DO4(A,B,C,D,8,6,0x6fa87e4f);
+  DO4(D,A,B,C,15,10,0xfe2ce6e0);
+  DO4(C,D,A,B,6,15,0xa3014314);
+  DO4(B,C,D,A,13,21,0x4e0811a1);
+
+  DO4(A,B,C,D,4,6,0xf7537e82);
+  DO4(D,A,B,C,11,10,0xbd3af235);
+  DO4(C,D,A,B,2,15,0x2ad7d2bb);
+  DO4(B,C,D,A,9,21,0xeb86d391);
+
+  A += AA;
+  B += BB;
+  C += CC;
+  D += DD;
+}
+
+/*
+ * From `Performance analysis of MD5' by Joseph D. Touch <touch@isi.edu>
+ */
+
+#if defined(WORDS_BIGENDIAN)
+static inline u_int32_t
+swap_u_int32_t (u_int32_t t)
+{
+  u_int32_t temp1, temp2;
+
+  temp1   = cshift(t, 16);
+  temp2   = temp1 >> 8;
+  temp1  &= 0x00ff00ff;
+  temp2  &= 0x00ff00ff;
+  temp1 <<= 8;
+  return temp1 | temp2;
+}
+#endif
+
+struct x32{
+  unsigned int a:32;
+  unsigned int b:32;
+};
+
+void
+MD5_Update (struct md5 *m, const void *v, size_t len)
+{
+  const unsigned char *p = v;
+  size_t old_sz = m->sz[0];
+  size_t offset;
+
+  m->sz[0] += len * 8;
+  if (m->sz[0] < old_sz)
+      ++m->sz[1];
+  offset = (old_sz / 8)  % 64;
+  while(len > 0){
+    size_t l = min(len, 64 - offset);
+    memcpy(m->save + offset, p, l);
+    offset += l;
+    p += l;
+    len -= l;
+    if(offset == 64){
+#if defined(WORDS_BIGENDIAN)
+      int i;
+      u_int32_t current[16];
+      struct x32 *u = (struct x32*)m->save;
+      for(i = 0; i < 8; i++){
+       current[2*i+0] = swap_u_int32_t(u[i].a);
+       current[2*i+1] = swap_u_int32_t(u[i].b);
+      }
+      calc(m, current);
+#else
+      calc(m, (u_int32_t*)m->save);
+#endif
+      offset = 0;
+    }
+  }
+}
+
+void
+MD5_Final (void *res, struct md5 *m)
+{
+  unsigned char zeros[72];
+  unsigned offset = (m->sz[0] / 8) % 64;
+  unsigned int dstart = (120 - offset - 1) % 64 + 1;
+
+  *zeros = 0x80;
+  memset (zeros + 1, 0, sizeof(zeros) - 1);
+  zeros[dstart+0] = (m->sz[0] >> 0) & 0xff;
+  zeros[dstart+1] = (m->sz[0] >> 8) & 0xff;
+  zeros[dstart+2] = (m->sz[0] >> 16) & 0xff;
+  zeros[dstart+3] = (m->sz[0] >> 24) & 0xff;
+  zeros[dstart+4] = (m->sz[1] >> 0) & 0xff;
+  zeros[dstart+5] = (m->sz[1] >> 8) & 0xff;
+  zeros[dstart+6] = (m->sz[1] >> 16) & 0xff;
+  zeros[dstart+7] = (m->sz[1] >> 24) & 0xff;
+  MD5_Update (m, zeros, dstart + 8);
+  {
+      int i;
+      unsigned char *r = (unsigned char *)res;
+
+      for (i = 0; i < 4; ++i) {
+         r[4*i]   = m->counter[i] & 0xFF;
+         r[4*i+1] = (m->counter[i] >> 8) & 0xFF;
+         r[4*i+2] = (m->counter[i] >> 16) & 0xFF;
+         r[4*i+3] = (m->counter[i] >> 24) & 0xFF;
+      }
+  }
+#if 0
+  {
+    int i;
+    u_int32_t *r = (u_int32_t *)res;
+
+    for (i = 0; i < 4; ++i)
+      r[i] = swap_u_int32_t (m->counter[i]);
+  }
+#endif
+}
diff --git a/source4/heimdal/lib/des/md5.h b/source4/heimdal/lib/des/md5.h
new file mode 100644 (file)
index 0000000..c0463e0
--- /dev/null
@@ -0,0 +1,51 @@
+/*
+ * Copyright (c) 1995 - 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.
+ */
+
+/* $Id: md5.h,v 1.9 2005/04/10 19:14:34 lha Exp $ */
+
+#ifndef HEIM_MD5_H
+#define HEIM_MD5_H 1
+
+struct md5 {
+  unsigned int sz[2];
+  u_int32_t counter[4];
+  unsigned char save[64];
+};
+
+typedef struct md5 MD5_CTX;
+
+void MD5_Init (struct md5 *m);
+void MD5_Update (struct md5 *m, const void *p, size_t len);
+void MD5_Final (void *res, struct md5 *m); /* u_int32_t res[4] */
+
+#endif /* HEIM_MD5_H */
diff --git a/source4/heimdal/lib/des/rc2.c b/source4/heimdal/lib/des/rc2.c
new file mode 100755 (executable)
index 0000000..4b4b53d
--- /dev/null
@@ -0,0 +1,243 @@
+/*
+ * 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.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+RCSID("$Id: rc2.c,v 1.6 2005/06/18 22:47:33 lha Exp $");
+#endif
+
+#include "rc2.h"
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+/*
+ * Implemented from Peter Gutmann's "Specification for Ron Rivests Cipher No.2"
+ * rfc2268 and "On the Design and Security of RC2" was also useful.
+ */
+
+static unsigned int Sbox[256] = {
+    0xd9, 0x78, 0xf9, 0xc4, 0x19, 0xdd, 0xb5, 0xed, 
+    0x28, 0xe9, 0xfd, 0x79, 0x4a, 0xa0, 0xd8, 0x9d, 
+    0xc6, 0x7e, 0x37, 0x83, 0x2b, 0x76, 0x53, 0x8e, 
+    0x62, 0x4c, 0x64, 0x88, 0x44, 0x8b, 0xfb, 0xa2, 
+    0x17, 0x9a, 0x59, 0xf5, 0x87, 0xb3, 0x4f, 0x13, 
+    0x61, 0x45, 0x6d, 0x8d, 0x09, 0x81, 0x7d, 0x32, 
+    0xbd, 0x8f, 0x40, 0xeb, 0x86, 0xb7, 0x7b, 0x0b, 
+    0xf0, 0x95, 0x21, 0x22, 0x5c, 0x6b, 0x4e, 0x82, 
+    0x54, 0xd6, 0x65, 0x93, 0xce, 0x60, 0xb2, 0x1c, 
+    0x73, 0x56, 0xc0, 0x14, 0xa7, 0x8c, 0xf1, 0xdc, 
+    0x12, 0x75, 0xca, 0x1f, 0x3b, 0xbe, 0xe4, 0xd1, 
+    0x42, 0x3d, 0xd4, 0x30, 0xa3, 0x3c, 0xb6, 0x26, 
+    0x6f, 0xbf, 0x0e, 0xda, 0x46, 0x69, 0x07, 0x57, 
+    0x27, 0xf2, 0x1d, 0x9b, 0xbc, 0x94, 0x43, 0x03, 
+    0xf8, 0x11, 0xc7, 0xf6, 0x90, 0xef, 0x3e, 0xe7, 
+    0x06, 0xc3, 0xd5, 0x2f, 0xc8, 0x66, 0x1e, 0xd7, 
+    0x08, 0xe8, 0xea, 0xde, 0x80, 0x52, 0xee, 0xf7, 
+    0x84, 0xaa, 0x72, 0xac, 0x35, 0x4d, 0x6a, 0x2a, 
+    0x96, 0x1a, 0xd2, 0x71, 0x5a, 0x15, 0x49, 0x74, 
+    0x4b, 0x9f, 0xd0, 0x5e, 0x04, 0x18, 0xa4, 0xec, 
+    0xc2, 0xe0, 0x41, 0x6e, 0x0f, 0x51, 0xcb, 0xcc, 
+    0x24, 0x91, 0xaf, 0x50, 0xa1, 0xf4, 0x70, 0x39, 
+    0x99, 0x7c, 0x3a, 0x85, 0x23, 0xb8, 0xb4, 0x7a, 
+    0xfc, 0x02, 0x36, 0x5b, 0x25, 0x55, 0x97, 0x31, 
+    0x2d, 0x5d, 0xfa, 0x98, 0xe3, 0x8a, 0x92, 0xae, 
+    0x05, 0xdf, 0x29, 0x10, 0x67, 0x6c, 0xba, 0xc9, 
+    0xd3, 0x00, 0xe6, 0xcf, 0xe1, 0x9e, 0xa8, 0x2c, 
+    0x63, 0x16, 0x01, 0x3f, 0x58, 0xe2, 0x89, 0xa9, 
+    0x0d, 0x38, 0x34, 0x1b, 0xab, 0x33, 0xff, 0xb0, 
+    0xbb, 0x48, 0x0c, 0x5f, 0xb9, 0xb1, 0xcd, 0x2e, 
+    0xc5, 0xf3, 0xdb, 0x47, 0xe5, 0xa5, 0x9c, 0x77, 
+    0x0a, 0xa6, 0x20, 0x68, 0xfe, 0x7f, 0xc1, 0xad
+};
+
+void
+RC2_set_key(RC2_KEY *key, int len, const unsigned char *data, int bits)
+{
+    unsigned char k[128];
+    int j, T8, TM;
+
+    if (len > 128)
+       len = 128;
+    if (bits <= 0 || bits > 1024)
+       bits = 1024;
+
+    for (j = 0; j < len; j++)
+       k[j] = data[j];
+    for (; j < 128; j++)
+       k[j] = Sbox[(k[j - len] + k[j - 1]) & 0xff];
+
+    T8 = (bits + 7) / 8;
+    j = (8*T8 - bits);
+    TM = 0xff >> j;
+
+    k[128 - T8] = Sbox[k[128 - T8] & TM];
+
+    for (j = 127 - T8; j >= 0; j--)
+       k[j] = Sbox[k[j + 1] ^ k[j + T8]];
+
+    for (j = 0; j < 64; j++)
+       key->data[j] = k[(j * 2) + 0] | (k[(j * 2) + 1] << 8);  
+    memset(k, 0, sizeof(k));
+}
+
+#define ROT16L(w,n)  ((w<<n)|(w>>(16-n)))
+#define ROT16R(w,n)  ((w>>n)|(w<<(16-n)))
+
+void
+RC2_encryptc(unsigned char *in, unsigned char *out, const RC2_KEY *key)
+{
+    int i, j;
+    int w0, w1, w2, w3;
+    int t0, t1, t2, t3;
+
+    w0 = in[0] | (in[1] << 8);
+    w1 = in[2] | (in[3] << 8);
+    w2 = in[4] | (in[5] << 8);
+    w3 = in[6] | (in[7] << 8);
+
+    for (i = 0; i < 16; i++) {
+       j = i * 4;
+       t0 = (w0 + (w1 & ~w3) + (w2 & w3) + key->data[j + 0]) & 0xffff;
+       w0 = ROT16L(t0, 1);
+       t1 = (w1 + (w2 & ~w0) + (w3 & w0) + key->data[j + 1]) & 0xffff;
+       w1 = ROT16L(t1, 2);
+       t2 = (w2 + (w3 & ~w1) + (w0 & w1) + key->data[j + 2]) & 0xffff;
+       w2 = ROT16L(t2, 3);
+       t3 = (w3 + (w0 & ~w2) + (w1 & w2) + key->data[j + 3]) & 0xffff;
+       w3 = ROT16L(t3, 5);
+       if(i == 4 || i == 10) {
+           w0 += key->data[w3 & 63];
+           w1 += key->data[w0 & 63];
+           w2 += key->data[w1 & 63];
+           w3 += key->data[w2 & 63];
+       }
+    }
+
+    out[0] = w0 & 0xff;
+    out[1] = (w0 >> 8) & 0xff;
+    out[2] = w1 & 0xff;
+    out[3] = (w1 >> 8) & 0xff;
+    out[4] = w2 & 0xff;
+    out[5] = (w2 >> 8) & 0xff;
+    out[6] = w3 & 0xff;
+    out[7] = (w3 >> 8) & 0xff;
+}
+
+void
+RC2_decryptc(unsigned char *in, unsigned char *out, const RC2_KEY *key)
+{
+    int i, j;
+    int w0, w1, w2, w3;
+    int t0, t1, t2, t3;
+
+    w0 = in[0] | (in[1] << 8);
+    w1 = in[2] | (in[3] << 8);
+    w2 = in[4] | (in[5] << 8);
+    w3 = in[6] | (in[7] << 8);
+
+    for (i = 15; i >= 0; i--) {
+       j = i * 4;
+
+       if(i == 4 || i == 10) {
+           w3 = (w3 - key->data[w2 & 63]) & 0xffff;
+           w2 = (w2 - key->data[w1 & 63]) & 0xffff;
+           w1 = (w1 - key->data[w0 & 63]) & 0xffff;
+           w0 = (w0 - key->data[w3 & 63]) & 0xffff;
+       }
+
+       t3 = ROT16R(w3, 5);
+       w3 = (t3 - (w0 & ~w2) - (w1 & w2) - key->data[j + 3]) & 0xffff;
+       t2 = ROT16R(w2, 3);
+       w2 = (t2 - (w3 & ~w1) - (w0 & w1) - key->data[j + 2]) & 0xffff;
+       t1 = ROT16R(w1, 2);
+       w1 = (t1 - (w2 & ~w0) - (w3 & w0) - key->data[j + 1]) & 0xffff;
+       t0 = ROT16R(w0, 1);
+       w0 = (t0 - (w1 & ~w3) - (w2 & w3) - key->data[j + 0]) & 0xffff;
+
+    }
+    out[0] = w0 & 0xff;
+    out[1] = (w0 >> 8) & 0xff;
+    out[2] = w1 & 0xff;
+    out[3] = (w1 >> 8) & 0xff;
+    out[4] = w2 & 0xff;
+    out[5] = (w2 >> 8) & 0xff;
+    out[6] = w3 & 0xff;
+    out[7] = (w3 >> 8) & 0xff;
+}
+
+void
+RC2_cbc_encrypt(const unsigned char *in, unsigned char *out, long size,
+               RC2_KEY *key, unsigned char *iv, int forward_encrypt)
+{
+    unsigned char tmp[RC2_BLOCK_SIZE];
+    int i;
+
+    if (forward_encrypt) {
+       while (size >= RC2_BLOCK_SIZE) {
+           for (i = 0; i < RC2_BLOCK_SIZE; i++)
+               tmp[i] = in[i] ^ iv[i];
+           RC2_encryptc(tmp, out, key);
+           memcpy(iv, out, RC2_BLOCK_SIZE);
+           size -= RC2_BLOCK_SIZE;
+           in += RC2_BLOCK_SIZE;
+           out += RC2_BLOCK_SIZE;
+       }
+       if (size) {
+           for (i = 0; i < size; i++)
+               tmp[i] = in[i] ^ iv[i];
+           for (i = size; i < RC2_BLOCK_SIZE; i++)
+               tmp[i] = iv[i];
+           RC2_encryptc(tmp, out, key);
+           memcpy(iv, out, RC2_BLOCK_SIZE);
+       }
+    } else {
+       while (size >= RC2_BLOCK_SIZE) {
+           memcpy(tmp, in, RC2_BLOCK_SIZE);
+           RC2_decryptc(tmp, out, key);
+           for (i = 0; i < RC2_BLOCK_SIZE; i++)
+               out[i] ^= iv[i];
+           memcpy(iv, tmp, RC2_BLOCK_SIZE);
+           size -= RC2_BLOCK_SIZE;
+           in += RC2_BLOCK_SIZE;
+           out += RC2_BLOCK_SIZE;
+       }
+       if (size) {
+           memcpy(tmp, in, RC2_BLOCK_SIZE);
+           RC2_decryptc(tmp, out, key);
+           for (i = 0; i < size; i++)
+               out[i] ^= iv[i];
+           memcpy(iv, tmp, RC2_BLOCK_SIZE);
+       }
+    }
+}
diff --git a/source4/heimdal/lib/des/rc2.h b/source4/heimdal/lib/des/rc2.h
new file mode 100755 (executable)
index 0000000..3ff44dc
--- /dev/null
@@ -0,0 +1,61 @@
+/*
+ * 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: rc2.h,v 1.1 2004/04/23 19:23:00 lha Exp $ */
+
+#define RC2_ENCRYPT    1
+#define RC2_DECRYPT    0
+
+#define RC2_BLOCK_SIZE 8
+#define RC2_BLOCK      RC2_BLOCK_SIZE
+#define RC2_KEY_LENGTH 16
+
+typedef struct rc2_key {
+    unsigned int data[64];
+} RC2_KEY;
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+void RC2_set_key(RC2_KEY *, int, const unsigned char *,int);
+
+void RC2_encryptc(unsigned char *, unsigned char *, const RC2_KEY *);
+void RC2_decryptc(unsigned char *, unsigned char *, const RC2_KEY *);
+
+void RC2_cbc_encrypt(const unsigned char *, unsigned char *, long,
+                    RC2_KEY *, unsigned char *, int);
+
+#ifdef  __cplusplus
+}
+#endif
diff --git a/source4/heimdal/lib/des/rc4.c b/source4/heimdal/lib/des/rc4.c
new file mode 100755 (executable)
index 0000000..17d4b02
--- /dev/null
@@ -0,0 +1,82 @@
+/*
+ * 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.
+ */
+
+/* implemented from description in draft-kaukonen-cipher-arcfour-03.txt */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+
+RCSID("$Id: rc4.c,v 1.1 2004/03/25 16:40:59 lha Exp $");
+#endif
+
+#include <rc4.h>
+
+#define SWAP(k,x,y)                            \
+{ unsigned int _t;                             \
+  _t = k->state[x];                            \
+  k->state[x] = k->state[y];                   \
+  k->state[y] = _t;                            \
+}
+
+void
+RC4_set_key(RC4_KEY *key, const int len, unsigned char *data)
+{
+    int i, j;
+
+    for (i = 0; i < 256; i++)
+       key->state[i] = i;
+    for (i = 0, j = 0; i < 256; i++) {
+       j = (j + key->state[i] + data[i % len]) % 256;
+       SWAP(key, i, j);
+    }
+    key->x = key->y = 0;
+}
+
+void
+RC4(RC4_KEY *key, const int len, const unsigned char *in, unsigned char *out)
+{
+    int i, t;
+    unsigned x, y;
+
+    x = key->x;
+    y = key->y;
+    for (i = 0; i < len; i++) {
+       x = (x + 1) % 256;
+       y = (y + key->state[x]) % 256;
+       SWAP(key, x, y);
+       t = (key->state[x] + key->state[y]) % 256;
+       *out++ = key->state[t] ^ *in++;
+    }
+    key->x = x;
+    key->y = y;
+}
diff --git a/source4/heimdal/lib/des/rc4.h b/source4/heimdal/lib/des/rc4.h
new file mode 100644 (file)
index 0000000..a39e79f
--- /dev/null
@@ -0,0 +1,42 @@
+/*
+ * 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: rc4.h,v 1.3 2004/03/25 16:39:58 lha Exp $ */
+
+typedef struct rc4_key {
+    unsigned int x, y;
+    unsigned int state[256];
+} RC4_KEY;
+
+void RC4_set_key(RC4_KEY *, const int, unsigned char *);
+void RC4(RC4_KEY *, const int, const unsigned char *, unsigned char *);
diff --git a/source4/heimdal/lib/des/rijndael-alg-fst.c b/source4/heimdal/lib/des/rijndael-alg-fst.c
new file mode 100755 (executable)
index 0000000..65b36ab
--- /dev/null
@@ -0,0 +1,1231 @@
+/*     $NetBSD: rijndael-alg-fst.c,v 1.5 2001/11/13 01:40:10 lukem Exp $       */
+/*     $KAME: rijndael-alg-fst.c,v 1.10 2003/07/15 10:47:16 itojun Exp $       */
+/**
+ * rijndael-alg-fst.c
+ *
+ * @version 3.0 (December 2000)
+ *
+ * Optimised ANSI C code for the Rijndael cipher (now AES)
+ *
+ * @author Vincent Rijmen <vincent.rijmen@esat.kuleuven.ac.be>
+ * @author Antoon Bosselaers <antoon.bosselaers@esat.kuleuven.ac.be>
+ * @author Paulo Barreto <paulo.barreto@terra.com.br>
+ *
+ * This code is hereby placed in the public domain.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHORS ''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 AUTHORS 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.
+ */
+
+/* "$NetBSD: rijndael-alg-fst.c,v 1.5 2001/11/13 01:40:10 lukem Exp $" */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+
+RCSID("$Id: rijndael-alg-fst.c,v 1.2 2004/06/02 20:09:48 lha Exp $");
+#endif
+
+#ifdef KRB5
+#include <krb5-types.h>
+#endif
+
+#include <rijndael-alg-fst.h>
+
+/* the file should not be used from outside */
+typedef u_int8_t               u8;
+typedef u_int16_t              u16;    
+typedef u_int32_t              u32;
+
+/*
+Te0[x] = S [x].[02, 01, 01, 03];
+Te1[x] = S [x].[03, 02, 01, 01];
+Te2[x] = S [x].[01, 03, 02, 01];
+Te3[x] = S [x].[01, 01, 03, 02];
+Te4[x] = S [x].[01, 01, 01, 01];
+
+Td0[x] = Si[x].[0e, 09, 0d, 0b];
+Td1[x] = Si[x].[0b, 0e, 09, 0d];
+Td2[x] = Si[x].[0d, 0b, 0e, 09];
+Td3[x] = Si[x].[09, 0d, 0b, 0e];
+Td4[x] = Si[x].[01, 01, 01, 01];
+*/
+
+static const u32 Te0[256] = {
+    0xc66363a5U, 0xf87c7c84U, 0xee777799U, 0xf67b7b8dU,
+    0xfff2f20dU, 0xd66b6bbdU, 0xde6f6fb1U, 0x91c5c554U,
+    0x60303050U, 0x02010103U, 0xce6767a9U, 0x562b2b7dU,
+    0xe7fefe19U, 0xb5d7d762U, 0x4dababe6U, 0xec76769aU,
+    0x8fcaca45U, 0x1f82829dU, 0x89c9c940U, 0xfa7d7d87U,
+    0xeffafa15U, 0xb25959ebU, 0x8e4747c9U, 0xfbf0f00bU,
+    0x41adadecU, 0xb3d4d467U, 0x5fa2a2fdU, 0x45afafeaU,
+    0x239c9cbfU, 0x53a4a4f7U, 0xe4727296U, 0x9bc0c05bU,
+    0x75b7b7c2U, 0xe1fdfd1cU, 0x3d9393aeU, 0x4c26266aU,
+    0x6c36365aU, 0x7e3f3f41U, 0xf5f7f702U, 0x83cccc4fU,
+    0x6834345cU, 0x51a5a5f4U, 0xd1e5e534U, 0xf9f1f108U,
+    0xe2717193U, 0xabd8d873U, 0x62313153U, 0x2a15153fU,
+    0x0804040cU, 0x95c7c752U, 0x46232365U, 0x9dc3c35eU,
+    0x30181828U, 0x379696a1U, 0x0a05050fU, 0x2f9a9ab5U,
+    0x0e070709U, 0x24121236U, 0x1b80809bU, 0xdfe2e23dU,
+    0xcdebeb26U, 0x4e272769U, 0x7fb2b2cdU, 0xea75759fU,
+    0x1209091bU, 0x1d83839eU, 0x582c2c74U, 0x341a1a2eU,
+    0x361b1b2dU, 0xdc6e6eb2U, 0xb45a5aeeU, 0x5ba0a0fbU,
+    0xa45252f6U, 0x763b3b4dU, 0xb7d6d661U, 0x7db3b3ceU,
+    0x5229297bU, 0xdde3e33eU, 0x5e2f2f71U, 0x13848497U,
+    0xa65353f5U, 0xb9d1d168U, 0x00000000U, 0xc1eded2cU,
+    0x40202060U, 0xe3fcfc1fU, 0x79b1b1c8U, 0xb65b5bedU,
+    0xd46a6abeU, 0x8dcbcb46U, 0x67bebed9U, 0x7239394bU,
+    0x944a4adeU, 0x984c4cd4U, 0xb05858e8U, 0x85cfcf4aU,
+    0xbbd0d06bU, 0xc5efef2aU, 0x4faaaae5U, 0xedfbfb16U,
+    0x864343c5U, 0x9a4d4dd7U, 0x66333355U, 0x11858594U,
+    0x8a4545cfU, 0xe9f9f910U, 0x04020206U, 0xfe7f7f81U,
+    0xa05050f0U, 0x783c3c44U, 0x259f9fbaU, 0x4ba8a8e3U,
+    0xa25151f3U, 0x5da3a3feU, 0x804040c0U, 0x058f8f8aU,
+    0x3f9292adU, 0x219d9dbcU, 0x70383848U, 0xf1f5f504U,
+    0x63bcbcdfU, 0x77b6b6c1U, 0xafdada75U, 0x42212163U,
+    0x20101030U, 0xe5ffff1aU, 0xfdf3f30eU, 0xbfd2d26dU,
+    0x81cdcd4cU, 0x180c0c14U, 0x26131335U, 0xc3ecec2fU,
+    0xbe5f5fe1U, 0x359797a2U, 0x884444ccU, 0x2e171739U,
+    0x93c4c457U, 0x55a7a7f2U, 0xfc7e7e82U, 0x7a3d3d47U,
+    0xc86464acU, 0xba5d5de7U, 0x3219192bU, 0xe6737395U,
+    0xc06060a0U, 0x19818198U, 0x9e4f4fd1U, 0xa3dcdc7fU,
+    0x44222266U, 0x542a2a7eU, 0x3b9090abU, 0x0b888883U,
+    0x8c4646caU, 0xc7eeee29U, 0x6bb8b8d3U, 0x2814143cU,
+    0xa7dede79U, 0xbc5e5ee2U, 0x160b0b1dU, 0xaddbdb76U,
+    0xdbe0e03bU, 0x64323256U, 0x743a3a4eU, 0x140a0a1eU,
+    0x924949dbU, 0x0c06060aU, 0x4824246cU, 0xb85c5ce4U,
+    0x9fc2c25dU, 0xbdd3d36eU, 0x43acacefU, 0xc46262a6U,
+    0x399191a8U, 0x319595a4U, 0xd3e4e437U, 0xf279798bU,
+    0xd5e7e732U, 0x8bc8c843U, 0x6e373759U, 0xda6d6db7U,
+    0x018d8d8cU, 0xb1d5d564U, 0x9c4e4ed2U, 0x49a9a9e0U,
+    0xd86c6cb4U, 0xac5656faU, 0xf3f4f407U, 0xcfeaea25U,
+    0xca6565afU, 0xf47a7a8eU, 0x47aeaee9U, 0x10080818U,
+    0x6fbabad5U, 0xf0787888U, 0x4a25256fU, 0x5c2e2e72U,
+    0x381c1c24U, 0x57a6a6f1U, 0x73b4b4c7U, 0x97c6c651U,
+    0xcbe8e823U, 0xa1dddd7cU, 0xe874749cU, 0x3e1f1f21U,
+    0x964b4bddU, 0x61bdbddcU, 0x0d8b8b86U, 0x0f8a8a85U,
+    0xe0707090U, 0x7c3e3e42U, 0x71b5b5c4U, 0xcc6666aaU,
+    0x904848d8U, 0x06030305U, 0xf7f6f601U, 0x1c0e0e12U,
+    0xc26161a3U, 0x6a35355fU, 0xae5757f9U, 0x69b9b9d0U,
+    0x17868691U, 0x99c1c158U, 0x3a1d1d27U, 0x279e9eb9U,
+    0xd9e1e138U, 0xebf8f813U, 0x2b9898b3U, 0x22111133U,
+    0xd26969bbU, 0xa9d9d970U, 0x078e8e89U, 0x339494a7U,
+    0x2d9b9bb6U, 0x3c1e1e22U, 0x15878792U, 0xc9e9e920U,
+    0x87cece49U, 0xaa5555ffU, 0x50282878U, 0xa5dfdf7aU,
+    0x038c8c8fU, 0x59a1a1f8U, 0x09898980U, 0x1a0d0d17U,
+    0x65bfbfdaU, 0xd7e6e631U, 0x844242c6U, 0xd06868b8U,
+    0x824141c3U, 0x299999b0U, 0x5a2d2d77U, 0x1e0f0f11U,
+    0x7bb0b0cbU, 0xa85454fcU, 0x6dbbbbd6U, 0x2c16163aU,
+};
+static const u32 Te1[256] = {
+    0xa5c66363U, 0x84f87c7cU, 0x99ee7777U, 0x8df67b7bU,
+    0x0dfff2f2U, 0xbdd66b6bU, 0xb1de6f6fU, 0x5491c5c5U,
+    0x50603030U, 0x03020101U, 0xa9ce6767U, 0x7d562b2bU,
+    0x19e7fefeU, 0x62b5d7d7U, 0xe64dababU, 0x9aec7676U,
+    0x458fcacaU, 0x9d1f8282U, 0x4089c9c9U, 0x87fa7d7dU,
+    0x15effafaU, 0xebb25959U, 0xc98e4747U, 0x0bfbf0f0U,
+    0xec41adadU, 0x67b3d4d4U, 0xfd5fa2a2U, 0xea45afafU,
+    0xbf239c9cU, 0xf753a4a4U, 0x96e47272U, 0x5b9bc0c0U,
+    0xc275b7b7U, 0x1ce1fdfdU, 0xae3d9393U, 0x6a4c2626U,
+    0x5a6c3636U, 0x417e3f3fU, 0x02f5f7f7U, 0x4f83ccccU,
+    0x5c683434U, 0xf451a5a5U, 0x34d1e5e5U, 0x08f9f1f1U,
+    0x93e27171U, 0x73abd8d8U, 0x53623131U, 0x3f2a1515U,
+    0x0c080404U, 0x5295c7c7U, 0x65462323U, 0x5e9dc3c3U,
+    0x28301818U, 0xa1379696U, 0x0f0a0505U, 0xb52f9a9aU,
+    0x090e0707U, 0x36241212U, 0x9b1b8080U, 0x3ddfe2e2U,
+    0x26cdebebU, 0x694e2727U, 0xcd7fb2b2U, 0x9fea7575U,
+    0x1b120909U, 0x9e1d8383U, 0x74582c2cU, 0x2e341a1aU,
+    0x2d361b1bU, 0xb2dc6e6eU, 0xeeb45a5aU, 0xfb5ba0a0U,
+    0xf6a45252U, 0x4d763b3bU, 0x61b7d6d6U, 0xce7db3b3U,
+    0x7b522929U, 0x3edde3e3U, 0x715e2f2fU, 0x97138484U,
+    0xf5a65353U, 0x68b9d1d1U, 0x00000000U, 0x2cc1ededU,
+    0x60402020U, 0x1fe3fcfcU, 0xc879b1b1U, 0xedb65b5bU,
+    0xbed46a6aU, 0x468dcbcbU, 0xd967bebeU, 0x4b723939U,
+    0xde944a4aU, 0xd4984c4cU, 0xe8b05858U, 0x4a85cfcfU,
+    0x6bbbd0d0U, 0x2ac5efefU, 0xe54faaaaU, 0x16edfbfbU,
+    0xc5864343U, 0xd79a4d4dU, 0x55663333U, 0x94118585U,
+    0xcf8a4545U, 0x10e9f9f9U, 0x06040202U, 0x81fe7f7fU,
+    0xf0a05050U, 0x44783c3cU, 0xba259f9fU, 0xe34ba8a8U,
+    0xf3a25151U, 0xfe5da3a3U, 0xc0804040U, 0x8a058f8fU,
+    0xad3f9292U, 0xbc219d9dU, 0x48703838U, 0x04f1f5f5U,
+    0xdf63bcbcU, 0xc177b6b6U, 0x75afdadaU, 0x63422121U,
+    0x30201010U, 0x1ae5ffffU, 0x0efdf3f3U, 0x6dbfd2d2U,
+    0x4c81cdcdU, 0x14180c0cU, 0x35261313U, 0x2fc3ececU,
+    0xe1be5f5fU, 0xa2359797U, 0xcc884444U, 0x392e1717U,
+    0x5793c4c4U, 0xf255a7a7U, 0x82fc7e7eU, 0x477a3d3dU,
+    0xacc86464U, 0xe7ba5d5dU, 0x2b321919U, 0x95e67373U,
+    0xa0c06060U, 0x98198181U, 0xd19e4f4fU, 0x7fa3dcdcU,
+    0x66442222U, 0x7e542a2aU, 0xab3b9090U, 0x830b8888U,
+    0xca8c4646U, 0x29c7eeeeU, 0xd36bb8b8U, 0x3c281414U,
+    0x79a7dedeU, 0xe2bc5e5eU, 0x1d160b0bU, 0x76addbdbU,
+    0x3bdbe0e0U, 0x56643232U, 0x4e743a3aU, 0x1e140a0aU,
+    0xdb924949U, 0x0a0c0606U, 0x6c482424U, 0xe4b85c5cU,
+    0x5d9fc2c2U, 0x6ebdd3d3U, 0xef43acacU, 0xa6c46262U,
+    0xa8399191U, 0xa4319595U, 0x37d3e4e4U, 0x8bf27979U,
+    0x32d5e7e7U, 0x438bc8c8U, 0x596e3737U, 0xb7da6d6dU,
+    0x8c018d8dU, 0x64b1d5d5U, 0xd29c4e4eU, 0xe049a9a9U,
+    0xb4d86c6cU, 0xfaac5656U, 0x07f3f4f4U, 0x25cfeaeaU,
+    0xafca6565U, 0x8ef47a7aU, 0xe947aeaeU, 0x18100808U,
+    0xd56fbabaU, 0x88f07878U, 0x6f4a2525U, 0x725c2e2eU,
+    0x24381c1cU, 0xf157a6a6U, 0xc773b4b4U, 0x5197c6c6U,
+    0x23cbe8e8U, 0x7ca1ddddU, 0x9ce87474U, 0x213e1f1fU,
+    0xdd964b4bU, 0xdc61bdbdU, 0x860d8b8bU, 0x850f8a8aU,
+    0x90e07070U, 0x427c3e3eU, 0xc471b5b5U, 0xaacc6666U,
+    0xd8904848U, 0x05060303U, 0x01f7f6f6U, 0x121c0e0eU,
+    0xa3c26161U, 0x5f6a3535U, 0xf9ae5757U, 0xd069b9b9U,
+    0x91178686U, 0x5899c1c1U, 0x273a1d1dU, 0xb9279e9eU,
+    0x38d9e1e1U, 0x13ebf8f8U, 0xb32b9898U, 0x33221111U,
+    0xbbd26969U, 0x70a9d9d9U, 0x89078e8eU, 0xa7339494U,
+    0xb62d9b9bU, 0x223c1e1eU, 0x92158787U, 0x20c9e9e9U,
+    0x4987ceceU, 0xffaa5555U, 0x78502828U, 0x7aa5dfdfU,
+    0x8f038c8cU, 0xf859a1a1U, 0x80098989U, 0x171a0d0dU,
+    0xda65bfbfU, 0x31d7e6e6U, 0xc6844242U, 0xb8d06868U,
+    0xc3824141U, 0xb0299999U, 0x775a2d2dU, 0x111e0f0fU,
+    0xcb7bb0b0U, 0xfca85454U, 0xd66dbbbbU, 0x3a2c1616U,
+};
+static const u32 Te2[256] = {
+    0x63a5c663U, 0x7c84f87cU, 0x7799ee77U, 0x7b8df67bU,
+    0xf20dfff2U, 0x6bbdd66bU, 0x6fb1de6fU, 0xc55491c5U,
+    0x30506030U, 0x01030201U, 0x67a9ce67U, 0x2b7d562bU,
+    0xfe19e7feU, 0xd762b5d7U, 0xabe64dabU, 0x769aec76U,
+    0xca458fcaU, 0x829d1f82U, 0xc94089c9U, 0x7d87fa7dU,
+    0xfa15effaU, 0x59ebb259U, 0x47c98e47U, 0xf00bfbf0U,
+    0xadec41adU, 0xd467b3d4U, 0xa2fd5fa2U, 0xafea45afU,
+    0x9cbf239cU, 0xa4f753a4U, 0x7296e472U, 0xc05b9bc0U,
+    0xb7c275b7U, 0xfd1ce1fdU, 0x93ae3d93U, 0x266a4c26U,
+    0x365a6c36U, 0x3f417e3fU, 0xf702f5f7U, 0xcc4f83ccU,
+    0x345c6834U, 0xa5f451a5U, 0xe534d1e5U, 0xf108f9f1U,
+    0x7193e271U, 0xd873abd8U, 0x31536231U, 0x153f2a15U,
+    0x040c0804U, 0xc75295c7U, 0x23654623U, 0xc35e9dc3U,
+    0x18283018U, 0x96a13796U, 0x050f0a05U, 0x9ab52f9aU,
+    0x07090e07U, 0x12362412U, 0x809b1b80U, 0xe23ddfe2U,
+    0xeb26cdebU, 0x27694e27U, 0xb2cd7fb2U, 0x759fea75U,
+    0x091b1209U, 0x839e1d83U, 0x2c74582cU, 0x1a2e341aU,
+    0x1b2d361bU, 0x6eb2dc6eU, 0x5aeeb45aU, 0xa0fb5ba0U,
+    0x52f6a452U, 0x3b4d763bU, 0xd661b7d6U, 0xb3ce7db3U,
+    0x297b5229U, 0xe33edde3U, 0x2f715e2fU, 0x84971384U,
+    0x53f5a653U, 0xd168b9d1U, 0x00000000U, 0xed2cc1edU,
+    0x20604020U, 0xfc1fe3fcU, 0xb1c879b1U, 0x5bedb65bU,
+    0x6abed46aU, 0xcb468dcbU, 0xbed967beU, 0x394b7239U,
+    0x4ade944aU, 0x4cd4984cU, 0x58e8b058U, 0xcf4a85cfU,
+    0xd06bbbd0U, 0xef2ac5efU, 0xaae54faaU, 0xfb16edfbU,
+    0x43c58643U, 0x4dd79a4dU, 0x33556633U, 0x85941185U,
+    0x45cf8a45U, 0xf910e9f9U, 0x02060402U, 0x7f81fe7fU,
+    0x50f0a050U, 0x3c44783cU, 0x9fba259fU, 0xa8e34ba8U,
+    0x51f3a251U, 0xa3fe5da3U, 0x40c08040U, 0x8f8a058fU,
+    0x92ad3f92U, 0x9dbc219dU, 0x38487038U, 0xf504f1f5U,
+    0xbcdf63bcU, 0xb6c177b6U, 0xda75afdaU, 0x21634221U,
+    0x10302010U, 0xff1ae5ffU, 0xf30efdf3U, 0xd26dbfd2U,
+    0xcd4c81cdU, 0x0c14180cU, 0x13352613U, 0xec2fc3ecU,
+    0x5fe1be5fU, 0x97a23597U, 0x44cc8844U, 0x17392e17U,
+    0xc45793c4U, 0xa7f255a7U, 0x7e82fc7eU, 0x3d477a3dU,
+    0x64acc864U, 0x5de7ba5dU, 0x192b3219U, 0x7395e673U,
+    0x60a0c060U, 0x81981981U, 0x4fd19e4fU, 0xdc7fa3dcU,
+    0x22664422U, 0x2a7e542aU, 0x90ab3b90U, 0x88830b88U,
+    0x46ca8c46U, 0xee29c7eeU, 0xb8d36bb8U, 0x143c2814U,
+    0xde79a7deU, 0x5ee2bc5eU, 0x0b1d160bU, 0xdb76addbU,
+    0xe03bdbe0U, 0x32566432U, 0x3a4e743aU, 0x0a1e140aU,
+    0x49db9249U, 0x060a0c06U, 0x246c4824U, 0x5ce4b85cU,
+    0xc25d9fc2U, 0xd36ebdd3U, 0xacef43acU, 0x62a6c462U,
+    0x91a83991U, 0x95a43195U, 0xe437d3e4U, 0x798bf279U,
+    0xe732d5e7U, 0xc8438bc8U, 0x37596e37U, 0x6db7da6dU,
+    0x8d8c018dU, 0xd564b1d5U, 0x4ed29c4eU, 0xa9e049a9U,
+    0x6cb4d86cU, 0x56faac56U, 0xf407f3f4U, 0xea25cfeaU,
+    0x65afca65U, 0x7a8ef47aU, 0xaee947aeU, 0x08181008U,
+    0xbad56fbaU, 0x7888f078U, 0x256f4a25U, 0x2e725c2eU,
+    0x1c24381cU, 0xa6f157a6U, 0xb4c773b4U, 0xc65197c6U,
+    0xe823cbe8U, 0xdd7ca1ddU, 0x749ce874U, 0x1f213e1fU,
+    0x4bdd964bU, 0xbddc61bdU, 0x8b860d8bU, 0x8a850f8aU,
+    0x7090e070U, 0x3e427c3eU, 0xb5c471b5U, 0x66aacc66U,
+    0x48d89048U, 0x03050603U, 0xf601f7f6U, 0x0e121c0eU,
+    0x61a3c261U, 0x355f6a35U, 0x57f9ae57U, 0xb9d069b9U,
+    0x86911786U, 0xc15899c1U, 0x1d273a1dU, 0x9eb9279eU,
+    0xe138d9e1U, 0xf813ebf8U, 0x98b32b98U, 0x11332211U,
+    0x69bbd269U, 0xd970a9d9U, 0x8e89078eU, 0x94a73394U,
+    0x9bb62d9bU, 0x1e223c1eU, 0x87921587U, 0xe920c9e9U,
+    0xce4987ceU, 0x55ffaa55U, 0x28785028U, 0xdf7aa5dfU,
+    0x8c8f038cU, 0xa1f859a1U, 0x89800989U, 0x0d171a0dU,
+    0xbfda65bfU, 0xe631d7e6U, 0x42c68442U, 0x68b8d068U,
+    0x41c38241U, 0x99b02999U, 0x2d775a2dU, 0x0f111e0fU,
+    0xb0cb7bb0U, 0x54fca854U, 0xbbd66dbbU, 0x163a2c16U,
+};
+static const u32 Te3[256] = {
+
+    0x6363a5c6U, 0x7c7c84f8U, 0x777799eeU, 0x7b7b8df6U,
+    0xf2f20dffU, 0x6b6bbdd6U, 0x6f6fb1deU, 0xc5c55491U,
+    0x30305060U, 0x01010302U, 0x6767a9ceU, 0x2b2b7d56U,
+    0xfefe19e7U, 0xd7d762b5U, 0xababe64dU, 0x76769aecU,
+    0xcaca458fU, 0x82829d1fU, 0xc9c94089U, 0x7d7d87faU,
+    0xfafa15efU, 0x5959ebb2U, 0x4747c98eU, 0xf0f00bfbU,
+    0xadadec41U, 0xd4d467b3U, 0xa2a2fd5fU, 0xafafea45U,
+    0x9c9cbf23U, 0xa4a4f753U, 0x727296e4U, 0xc0c05b9bU,
+    0xb7b7c275U, 0xfdfd1ce1U, 0x9393ae3dU, 0x26266a4cU,
+    0x36365a6cU, 0x3f3f417eU, 0xf7f702f5U, 0xcccc4f83U,
+    0x34345c68U, 0xa5a5f451U, 0xe5e534d1U, 0xf1f108f9U,
+    0x717193e2U, 0xd8d873abU, 0x31315362U, 0x15153f2aU,
+    0x04040c08U, 0xc7c75295U, 0x23236546U, 0xc3c35e9dU,
+    0x18182830U, 0x9696a137U, 0x05050f0aU, 0x9a9ab52fU,
+    0x0707090eU, 0x12123624U, 0x80809b1bU, 0xe2e23ddfU,
+    0xebeb26cdU, 0x2727694eU, 0xb2b2cd7fU, 0x75759feaU,
+    0x09091b12U, 0x83839e1dU, 0x2c2c7458U, 0x1a1a2e34U,
+    0x1b1b2d36U, 0x6e6eb2dcU, 0x5a5aeeb4U, 0xa0a0fb5bU,
+    0x5252f6a4U, 0x3b3b4d76U, 0xd6d661b7U, 0xb3b3ce7dU,
+    0x29297b52U, 0xe3e33eddU, 0x2f2f715eU, 0x84849713U,
+    0x5353f5a6U, 0xd1d168b9U, 0x00000000U, 0xeded2cc1U,
+    0x20206040U, 0xfcfc1fe3U, 0xb1b1c879U, 0x5b5bedb6U,
+    0x6a6abed4U, 0xcbcb468dU, 0xbebed967U, 0x39394b72U,
+    0x4a4ade94U, 0x4c4cd498U, 0x5858e8b0U, 0xcfcf4a85U,
+    0xd0d06bbbU, 0xefef2ac5U, 0xaaaae54fU, 0xfbfb16edU,
+    0x4343c586U, 0x4d4dd79aU, 0x33335566U, 0x85859411U,
+    0x4545cf8aU, 0xf9f910e9U, 0x02020604U, 0x7f7f81feU,
+    0x5050f0a0U, 0x3c3c4478U, 0x9f9fba25U, 0xa8a8e34bU,
+    0x5151f3a2U, 0xa3a3fe5dU, 0x4040c080U, 0x8f8f8a05U,
+    0x9292ad3fU, 0x9d9dbc21U, 0x38384870U, 0xf5f504f1U,
+    0xbcbcdf63U, 0xb6b6c177U, 0xdada75afU, 0x21216342U,
+    0x10103020U, 0xffff1ae5U, 0xf3f30efdU, 0xd2d26dbfU,
+    0xcdcd4c81U, 0x0c0c1418U, 0x13133526U, 0xecec2fc3U,
+    0x5f5fe1beU, 0x9797a235U, 0x4444cc88U, 0x1717392eU,
+    0xc4c45793U, 0xa7a7f255U, 0x7e7e82fcU, 0x3d3d477aU,
+    0x6464acc8U, 0x5d5de7baU, 0x19192b32U, 0x737395e6U,
+    0x6060a0c0U, 0x81819819U, 0x4f4fd19eU, 0xdcdc7fa3U,
+    0x22226644U, 0x2a2a7e54U, 0x9090ab3bU, 0x8888830bU,
+    0x4646ca8cU, 0xeeee29c7U, 0xb8b8d36bU, 0x14143c28U,
+    0xdede79a7U, 0x5e5ee2bcU, 0x0b0b1d16U, 0xdbdb76adU,
+    0xe0e03bdbU, 0x32325664U, 0x3a3a4e74U, 0x0a0a1e14U,
+    0x4949db92U, 0x06060a0cU, 0x24246c48U, 0x5c5ce4b8U,
+    0xc2c25d9fU, 0xd3d36ebdU, 0xacacef43U, 0x6262a6c4U,
+    0x9191a839U, 0x9595a431U, 0xe4e437d3U, 0x79798bf2U,
+    0xe7e732d5U, 0xc8c8438bU, 0x3737596eU, 0x6d6db7daU,
+    0x8d8d8c01U, 0xd5d564b1U, 0x4e4ed29cU, 0xa9a9e049U,
+    0x6c6cb4d8U, 0x5656faacU, 0xf4f407f3U, 0xeaea25cfU,
+    0x6565afcaU, 0x7a7a8ef4U, 0xaeaee947U, 0x08081810U,
+    0xbabad56fU, 0x787888f0U, 0x25256f4aU, 0x2e2e725cU,
+    0x1c1c2438U, 0xa6a6f157U, 0xb4b4c773U, 0xc6c65197U,
+    0xe8e823cbU, 0xdddd7ca1U, 0x74749ce8U, 0x1f1f213eU,
+    0x4b4bdd96U, 0xbdbddc61U, 0x8b8b860dU, 0x8a8a850fU,
+    0x707090e0U, 0x3e3e427cU, 0xb5b5c471U, 0x6666aaccU,
+    0x4848d890U, 0x03030506U, 0xf6f601f7U, 0x0e0e121cU,
+    0x6161a3c2U, 0x35355f6aU, 0x5757f9aeU, 0xb9b9d069U,
+    0x86869117U, 0xc1c15899U, 0x1d1d273aU, 0x9e9eb927U,
+    0xe1e138d9U, 0xf8f813ebU, 0x9898b32bU, 0x11113322U,
+    0x6969bbd2U, 0xd9d970a9U, 0x8e8e8907U, 0x9494a733U,
+    0x9b9bb62dU, 0x1e1e223cU, 0x87879215U, 0xe9e920c9U,
+    0xcece4987U, 0x5555ffaaU, 0x28287850U, 0xdfdf7aa5U,
+    0x8c8c8f03U, 0xa1a1f859U, 0x89898009U, 0x0d0d171aU,
+    0xbfbfda65U, 0xe6e631d7U, 0x4242c684U, 0x6868b8d0U,
+    0x4141c382U, 0x9999b029U, 0x2d2d775aU, 0x0f0f111eU,
+    0xb0b0cb7bU, 0x5454fca8U, 0xbbbbd66dU, 0x16163a2cU,
+};
+static const u32 Te4[256] = {
+    0x63636363U, 0x7c7c7c7cU, 0x77777777U, 0x7b7b7b7bU,
+    0xf2f2f2f2U, 0x6b6b6b6bU, 0x6f6f6f6fU, 0xc5c5c5c5U,
+    0x30303030U, 0x01010101U, 0x67676767U, 0x2b2b2b2bU,
+    0xfefefefeU, 0xd7d7d7d7U, 0xababababU, 0x76767676U,
+    0xcacacacaU, 0x82828282U, 0xc9c9c9c9U, 0x7d7d7d7dU,
+    0xfafafafaU, 0x59595959U, 0x47474747U, 0xf0f0f0f0U,
+    0xadadadadU, 0xd4d4d4d4U, 0xa2a2a2a2U, 0xafafafafU,
+    0x9c9c9c9cU, 0xa4a4a4a4U, 0x72727272U, 0xc0c0c0c0U,
+    0xb7b7b7b7U, 0xfdfdfdfdU, 0x93939393U, 0x26262626U,
+    0x36363636U, 0x3f3f3f3fU, 0xf7f7f7f7U, 0xccccccccU,
+    0x34343434U, 0xa5a5a5a5U, 0xe5e5e5e5U, 0xf1f1f1f1U,
+    0x71717171U, 0xd8d8d8d8U, 0x31313131U, 0x15151515U,
+    0x04040404U, 0xc7c7c7c7U, 0x23232323U, 0xc3c3c3c3U,
+    0x18181818U, 0x96969696U, 0x05050505U, 0x9a9a9a9aU,
+    0x07070707U, 0x12121212U, 0x80808080U, 0xe2e2e2e2U,
+    0xebebebebU, 0x27272727U, 0xb2b2b2b2U, 0x75757575U,
+    0x09090909U, 0x83838383U, 0x2c2c2c2cU, 0x1a1a1a1aU,
+    0x1b1b1b1bU, 0x6e6e6e6eU, 0x5a5a5a5aU, 0xa0a0a0a0U,
+    0x52525252U, 0x3b3b3b3bU, 0xd6d6d6d6U, 0xb3b3b3b3U,
+    0x29292929U, 0xe3e3e3e3U, 0x2f2f2f2fU, 0x84848484U,
+    0x53535353U, 0xd1d1d1d1U, 0x00000000U, 0xededededU,
+    0x20202020U, 0xfcfcfcfcU, 0xb1b1b1b1U, 0x5b5b5b5bU,
+    0x6a6a6a6aU, 0xcbcbcbcbU, 0xbebebebeU, 0x39393939U,
+    0x4a4a4a4aU, 0x4c4c4c4cU, 0x58585858U, 0xcfcfcfcfU,
+    0xd0d0d0d0U, 0xefefefefU, 0xaaaaaaaaU, 0xfbfbfbfbU,
+    0x43434343U, 0x4d4d4d4dU, 0x33333333U, 0x85858585U,
+    0x45454545U, 0xf9f9f9f9U, 0x02020202U, 0x7f7f7f7fU,
+    0x50505050U, 0x3c3c3c3cU, 0x9f9f9f9fU, 0xa8a8a8a8U,
+    0x51515151U, 0xa3a3a3a3U, 0x40404040U, 0x8f8f8f8fU,
+    0x92929292U, 0x9d9d9d9dU, 0x38383838U, 0xf5f5f5f5U,
+    0xbcbcbcbcU, 0xb6b6b6b6U, 0xdadadadaU, 0x21212121U,
+    0x10101010U, 0xffffffffU, 0xf3f3f3f3U, 0xd2d2d2d2U,
+    0xcdcdcdcdU, 0x0c0c0c0cU, 0x13131313U, 0xececececU,
+    0x5f5f5f5fU, 0x97979797U, 0x44444444U, 0x17171717U,
+    0xc4c4c4c4U, 0xa7a7a7a7U, 0x7e7e7e7eU, 0x3d3d3d3dU,
+    0x64646464U, 0x5d5d5d5dU, 0x19191919U, 0x73737373U,
+    0x60606060U, 0x81818181U, 0x4f4f4f4fU, 0xdcdcdcdcU,
+    0x22222222U, 0x2a2a2a2aU, 0x90909090U, 0x88888888U,
+    0x46464646U, 0xeeeeeeeeU, 0xb8b8b8b8U, 0x14141414U,
+    0xdedededeU, 0x5e5e5e5eU, 0x0b0b0b0bU, 0xdbdbdbdbU,
+    0xe0e0e0e0U, 0x32323232U, 0x3a3a3a3aU, 0x0a0a0a0aU,
+    0x49494949U, 0x06060606U, 0x24242424U, 0x5c5c5c5cU,
+    0xc2c2c2c2U, 0xd3d3d3d3U, 0xacacacacU, 0x62626262U,
+    0x91919191U, 0x95959595U, 0xe4e4e4e4U, 0x79797979U,
+    0xe7e7e7e7U, 0xc8c8c8c8U, 0x37373737U, 0x6d6d6d6dU,
+    0x8d8d8d8dU, 0xd5d5d5d5U, 0x4e4e4e4eU, 0xa9a9a9a9U,
+    0x6c6c6c6cU, 0x56565656U, 0xf4f4f4f4U, 0xeaeaeaeaU,
+    0x65656565U, 0x7a7a7a7aU, 0xaeaeaeaeU, 0x08080808U,
+    0xbabababaU, 0x78787878U, 0x25252525U, 0x2e2e2e2eU,
+    0x1c1c1c1cU, 0xa6a6a6a6U, 0xb4b4b4b4U, 0xc6c6c6c6U,
+    0xe8e8e8e8U, 0xddddddddU, 0x74747474U, 0x1f1f1f1fU,
+    0x4b4b4b4bU, 0xbdbdbdbdU, 0x8b8b8b8bU, 0x8a8a8a8aU,
+    0x70707070U, 0x3e3e3e3eU, 0xb5b5b5b5U, 0x66666666U,
+    0x48484848U, 0x03030303U, 0xf6f6f6f6U, 0x0e0e0e0eU,
+    0x61616161U, 0x35353535U, 0x57575757U, 0xb9b9b9b9U,
+    0x86868686U, 0xc1c1c1c1U, 0x1d1d1d1dU, 0x9e9e9e9eU,
+    0xe1e1e1e1U, 0xf8f8f8f8U, 0x98989898U, 0x11111111U,
+    0x69696969U, 0xd9d9d9d9U, 0x8e8e8e8eU, 0x94949494U,
+    0x9b9b9b9bU, 0x1e1e1e1eU, 0x87878787U, 0xe9e9e9e9U,
+    0xcecececeU, 0x55555555U, 0x28282828U, 0xdfdfdfdfU,
+    0x8c8c8c8cU, 0xa1a1a1a1U, 0x89898989U, 0x0d0d0d0dU,
+    0xbfbfbfbfU, 0xe6e6e6e6U, 0x42424242U, 0x68686868U,
+    0x41414141U, 0x99999999U, 0x2d2d2d2dU, 0x0f0f0f0fU,
+    0xb0b0b0b0U, 0x54545454U, 0xbbbbbbbbU, 0x16161616U,
+};
+static const u32 Td0[256] = {
+    0x51f4a750U, 0x7e416553U, 0x1a17a4c3U, 0x3a275e96U,
+    0x3bab6bcbU, 0x1f9d45f1U, 0xacfa58abU, 0x4be30393U,
+    0x2030fa55U, 0xad766df6U, 0x88cc7691U, 0xf5024c25U,
+    0x4fe5d7fcU, 0xc52acbd7U, 0x26354480U, 0xb562a38fU,
+    0xdeb15a49U, 0x25ba1b67U, 0x45ea0e98U, 0x5dfec0e1U,
+    0xc32f7502U, 0x814cf012U, 0x8d4697a3U, 0x6bd3f9c6U,
+    0x038f5fe7U, 0x15929c95U, 0xbf6d7aebU, 0x955259daU,
+    0xd4be832dU, 0x587421d3U, 0x49e06929U, 0x8ec9c844U,
+    0x75c2896aU, 0xf48e7978U, 0x99583e6bU, 0x27b971ddU,
+    0xbee14fb6U, 0xf088ad17U, 0xc920ac66U, 0x7dce3ab4U,
+    0x63df4a18U, 0xe51a3182U, 0x97513360U, 0x62537f45U,
+    0xb16477e0U, 0xbb6bae84U, 0xfe81a01cU, 0xf9082b94U,
+    0x70486858U, 0x8f45fd19U, 0x94de6c87U, 0x527bf8b7U,
+    0xab73d323U, 0x724b02e2U, 0xe31f8f57U, 0x6655ab2aU,
+    0xb2eb2807U, 0x2fb5c203U, 0x86c57b9aU, 0xd33708a5U,
+    0x302887f2U, 0x23bfa5b2U, 0x02036abaU, 0xed16825cU,
+    0x8acf1c2bU, 0xa779b492U, 0xf307f2f0U, 0x4e69e2a1U,
+    0x65daf4cdU, 0x0605bed5U, 0xd134621fU, 0xc4a6fe8aU,
+    0x342e539dU, 0xa2f355a0U, 0x058ae132U, 0xa4f6eb75U,
+    0x0b83ec39U, 0x4060efaaU, 0x5e719f06U, 0xbd6e1051U,
+    0x3e218af9U, 0x96dd063dU, 0xdd3e05aeU, 0x4de6bd46U,
+    0x91548db5U, 0x71c45d05U, 0x0406d46fU, 0x605015ffU,
+    0x1998fb24U, 0xd6bde997U, 0x894043ccU, 0x67d99e77U,
+    0xb0e842bdU, 0x07898b88U, 0xe7195b38U, 0x79c8eedbU,
+    0xa17c0a47U, 0x7c420fe9U, 0xf8841ec9U, 0x00000000U,
+    0x09808683U, 0x322bed48U, 0x1e1170acU, 0x6c5a724eU,
+    0xfd0efffbU, 0x0f853856U, 0x3daed51eU, 0x362d3927U,
+    0x0a0fd964U, 0x685ca621U, 0x9b5b54d1U, 0x24362e3aU,
+    0x0c0a67b1U, 0x9357e70fU, 0xb4ee96d2U, 0x1b9b919eU,
+    0x80c0c54fU, 0x61dc20a2U, 0x5a774b69U, 0x1c121a16U,
+    0xe293ba0aU, 0xc0a02ae5U, 0x3c22e043U, 0x121b171dU,
+    0x0e090d0bU, 0xf28bc7adU, 0x2db6a8b9U, 0x141ea9c8U,
+    0x57f11985U, 0xaf75074cU, 0xee99ddbbU, 0xa37f60fdU,
+    0xf701269fU, 0x5c72f5bcU, 0x44663bc5U, 0x5bfb7e34U,
+    0x8b432976U, 0xcb23c6dcU, 0xb6edfc68U, 0xb8e4f163U,
+    0xd731dccaU, 0x42638510U, 0x13972240U, 0x84c61120U,
+    0x854a247dU, 0xd2bb3df8U, 0xaef93211U, 0xc729a16dU,
+    0x1d9e2f4bU, 0xdcb230f3U, 0x0d8652ecU, 0x77c1e3d0U,
+    0x2bb3166cU, 0xa970b999U, 0x119448faU, 0x47e96422U,
+    0xa8fc8cc4U, 0xa0f03f1aU, 0x567d2cd8U, 0x223390efU,
+    0x87494ec7U, 0xd938d1c1U, 0x8ccaa2feU, 0x98d40b36U,
+    0xa6f581cfU, 0xa57ade28U, 0xdab78e26U, 0x3fadbfa4U,
+    0x2c3a9de4U, 0x5078920dU, 0x6a5fcc9bU, 0x547e4662U,
+    0xf68d13c2U, 0x90d8b8e8U, 0x2e39f75eU, 0x82c3aff5U,
+    0x9f5d80beU, 0x69d0937cU, 0x6fd52da9U, 0xcf2512b3U,
+    0xc8ac993bU, 0x10187da7U, 0xe89c636eU, 0xdb3bbb7bU,
+    0xcd267809U, 0x6e5918f4U, 0xec9ab701U, 0x834f9aa8U,
+    0xe6956e65U, 0xaaffe67eU, 0x21bccf08U, 0xef15e8e6U,
+    0xbae79bd9U, 0x4a6f36ceU, 0xea9f09d4U, 0x29b07cd6U,
+    0x31a4b2afU, 0x2a3f2331U, 0xc6a59430U, 0x35a266c0U,
+    0x744ebc37U, 0xfc82caa6U, 0xe090d0b0U, 0x33a7d815U,
+    0xf104984aU, 0x41ecdaf7U, 0x7fcd500eU, 0x1791f62fU,
+    0x764dd68dU, 0x43efb04dU, 0xccaa4d54U, 0xe49604dfU,
+    0x9ed1b5e3U, 0x4c6a881bU, 0xc12c1fb8U, 0x4665517fU,
+    0x9d5eea04U, 0x018c355dU, 0xfa877473U, 0xfb0b412eU,
+    0xb3671d5aU, 0x92dbd252U, 0xe9105633U, 0x6dd64713U,
+    0x9ad7618cU, 0x37a10c7aU, 0x59f8148eU, 0xeb133c89U,
+    0xcea927eeU, 0xb761c935U, 0xe11ce5edU, 0x7a47b13cU,
+    0x9cd2df59U, 0x55f2733fU, 0x1814ce79U, 0x73c737bfU,
+    0x53f7cdeaU, 0x5ffdaa5bU, 0xdf3d6f14U, 0x7844db86U,
+    0xcaaff381U, 0xb968c43eU, 0x3824342cU, 0xc2a3405fU,
+    0x161dc372U, 0xbce2250cU, 0x283c498bU, 0xff0d9541U,
+    0x39a80171U, 0x080cb3deU, 0xd8b4e49cU, 0x6456c190U,
+    0x7bcb8461U, 0xd532b670U, 0x486c5c74U, 0xd0b85742U,
+};
+static const u32 Td1[256] = {
+    0x5051f4a7U, 0x537e4165U, 0xc31a17a4U, 0x963a275eU,
+    0xcb3bab6bU, 0xf11f9d45U, 0xabacfa58U, 0x934be303U,
+    0x552030faU, 0xf6ad766dU, 0x9188cc76U, 0x25f5024cU,
+    0xfc4fe5d7U, 0xd7c52acbU, 0x80263544U, 0x8fb562a3U,
+    0x49deb15aU, 0x6725ba1bU, 0x9845ea0eU, 0xe15dfec0U,
+    0x02c32f75U, 0x12814cf0U, 0xa38d4697U, 0xc66bd3f9U,
+    0xe7038f5fU, 0x9515929cU, 0xebbf6d7aU, 0xda955259U,
+    0x2dd4be83U, 0xd3587421U, 0x2949e069U, 0x448ec9c8U,
+    0x6a75c289U, 0x78f48e79U, 0x6b99583eU, 0xdd27b971U,
+    0xb6bee14fU, 0x17f088adU, 0x66c920acU, 0xb47dce3aU,
+    0x1863df4aU, 0x82e51a31U, 0x60975133U, 0x4562537fU,
+    0xe0b16477U, 0x84bb6baeU, 0x1cfe81a0U, 0x94f9082bU,
+    0x58704868U, 0x198f45fdU, 0x8794de6cU, 0xb7527bf8U,
+    0x23ab73d3U, 0xe2724b02U, 0x57e31f8fU, 0x2a6655abU,
+    0x07b2eb28U, 0x032fb5c2U, 0x9a86c57bU, 0xa5d33708U,
+    0xf2302887U, 0xb223bfa5U, 0xba02036aU, 0x5ced1682U,
+    0x2b8acf1cU, 0x92a779b4U, 0xf0f307f2U, 0xa14e69e2U,
+    0xcd65daf4U, 0xd50605beU, 0x1fd13462U, 0x8ac4a6feU,
+    0x9d342e53U, 0xa0a2f355U, 0x32058ae1U, 0x75a4f6ebU,
+    0x390b83ecU, 0xaa4060efU, 0x065e719fU, 0x51bd6e10U,
+    0xf93e218aU, 0x3d96dd06U, 0xaedd3e05U, 0x464de6bdU,
+    0xb591548dU, 0x0571c45dU, 0x6f0406d4U, 0xff605015U,
+    0x241998fbU, 0x97d6bde9U, 0xcc894043U, 0x7767d99eU,
+    0xbdb0e842U, 0x8807898bU, 0x38e7195bU, 0xdb79c8eeU,
+    0x47a17c0aU, 0xe97c420fU, 0xc9f8841eU, 0x00000000U,
+    0x83098086U, 0x48322bedU, 0xac1e1170U, 0x4e6c5a72U,
+    0xfbfd0effU, 0x560f8538U, 0x1e3daed5U, 0x27362d39U,
+    0x640a0fd9U, 0x21685ca6U, 0xd19b5b54U, 0x3a24362eU,
+    0xb10c0a67U, 0x0f9357e7U, 0xd2b4ee96U, 0x9e1b9b91U,
+    0x4f80c0c5U, 0xa261dc20U, 0x695a774bU, 0x161c121aU,
+    0x0ae293baU, 0xe5c0a02aU, 0x433c22e0U, 0x1d121b17U,
+    0x0b0e090dU, 0xadf28bc7U, 0xb92db6a8U, 0xc8141ea9U,
+    0x8557f119U, 0x4caf7507U, 0xbbee99ddU, 0xfda37f60U,
+    0x9ff70126U, 0xbc5c72f5U, 0xc544663bU, 0x345bfb7eU,
+    0x768b4329U, 0xdccb23c6U, 0x68b6edfcU, 0x63b8e4f1U,
+    0xcad731dcU, 0x10426385U, 0x40139722U, 0x2084c611U,
+    0x7d854a24U, 0xf8d2bb3dU, 0x11aef932U, 0x6dc729a1U,
+    0x4b1d9e2fU, 0xf3dcb230U, 0xec0d8652U, 0xd077c1e3U,
+    0x6c2bb316U, 0x99a970b9U, 0xfa119448U, 0x2247e964U,
+    0xc4a8fc8cU, 0x1aa0f03fU, 0xd8567d2cU, 0xef223390U,
+    0xc787494eU, 0xc1d938d1U, 0xfe8ccaa2U, 0x3698d40bU,
+    0xcfa6f581U, 0x28a57adeU, 0x26dab78eU, 0xa43fadbfU,
+    0xe42c3a9dU, 0x0d507892U, 0x9b6a5fccU, 0x62547e46U,
+    0xc2f68d13U, 0xe890d8b8U, 0x5e2e39f7U, 0xf582c3afU,
+    0xbe9f5d80U, 0x7c69d093U, 0xa96fd52dU, 0xb3cf2512U,
+    0x3bc8ac99U, 0xa710187dU, 0x6ee89c63U, 0x7bdb3bbbU,
+    0x09cd2678U, 0xf46e5918U, 0x01ec9ab7U, 0xa8834f9aU,
+    0x65e6956eU, 0x7eaaffe6U, 0x0821bccfU, 0xe6ef15e8U,
+    0xd9bae79bU, 0xce4a6f36U, 0xd4ea9f09U, 0xd629b07cU,
+    0xaf31a4b2U, 0x312a3f23U, 0x30c6a594U, 0xc035a266U,
+    0x37744ebcU, 0xa6fc82caU, 0xb0e090d0U, 0x1533a7d8U,
+    0x4af10498U, 0xf741ecdaU, 0x0e7fcd50U, 0x2f1791f6U,
+    0x8d764dd6U, 0x4d43efb0U, 0x54ccaa4dU, 0xdfe49604U,
+    0xe39ed1b5U, 0x1b4c6a88U, 0xb8c12c1fU, 0x7f466551U,
+    0x049d5eeaU, 0x5d018c35U, 0x73fa8774U, 0x2efb0b41U,
+    0x5ab3671dU, 0x5292dbd2U, 0x33e91056U, 0x136dd647U,
+    0x8c9ad761U, 0x7a37a10cU, 0x8e59f814U, 0x89eb133cU,
+    0xeecea927U, 0x35b761c9U, 0xede11ce5U, 0x3c7a47b1U,
+    0x599cd2dfU, 0x3f55f273U, 0x791814ceU, 0xbf73c737U,
+    0xea53f7cdU, 0x5b5ffdaaU, 0x14df3d6fU, 0x867844dbU,
+    0x81caaff3U, 0x3eb968c4U, 0x2c382434U, 0x5fc2a340U,
+    0x72161dc3U, 0x0cbce225U, 0x8b283c49U, 0x41ff0d95U,
+    0x7139a801U, 0xde080cb3U, 0x9cd8b4e4U, 0x906456c1U,
+    0x617bcb84U, 0x70d532b6U, 0x74486c5cU, 0x42d0b857U,
+};
+static const u32 Td2[256] = {
+    0xa75051f4U, 0x65537e41U, 0xa4c31a17U, 0x5e963a27U,
+    0x6bcb3babU, 0x45f11f9dU, 0x58abacfaU, 0x03934be3U,
+    0xfa552030U, 0x6df6ad76U, 0x769188ccU, 0x4c25f502U,
+    0xd7fc4fe5U, 0xcbd7c52aU, 0x44802635U, 0xa38fb562U,
+    0x5a49deb1U, 0x1b6725baU, 0x0e9845eaU, 0xc0e15dfeU,
+    0x7502c32fU, 0xf012814cU, 0x97a38d46U, 0xf9c66bd3U,
+    0x5fe7038fU, 0x9c951592U, 0x7aebbf6dU, 0x59da9552U,
+    0x832dd4beU, 0x21d35874U, 0x692949e0U, 0xc8448ec9U,
+    0x896a75c2U, 0x7978f48eU, 0x3e6b9958U, 0x71dd27b9U,
+    0x4fb6bee1U, 0xad17f088U, 0xac66c920U, 0x3ab47dceU,
+    0x4a1863dfU, 0x3182e51aU, 0x33609751U, 0x7f456253U,
+    0x77e0b164U, 0xae84bb6bU, 0xa01cfe81U, 0x2b94f908U,
+    0x68587048U, 0xfd198f45U, 0x6c8794deU, 0xf8b7527bU,
+    0xd323ab73U, 0x02e2724bU, 0x8f57e31fU, 0xab2a6655U,
+    0x2807b2ebU, 0xc2032fb5U, 0x7b9a86c5U, 0x08a5d337U,
+    0x87f23028U, 0xa5b223bfU, 0x6aba0203U, 0x825ced16U,
+    0x1c2b8acfU, 0xb492a779U, 0xf2f0f307U, 0xe2a14e69U,
+    0xf4cd65daU, 0xbed50605U, 0x621fd134U, 0xfe8ac4a6U,
+    0x539d342eU, 0x55a0a2f3U, 0xe132058aU, 0xeb75a4f6U,
+    0xec390b83U, 0xefaa4060U, 0x9f065e71U, 0x1051bd6eU,
+
+    0x8af93e21U, 0x063d96ddU, 0x05aedd3eU, 0xbd464de6U,
+    0x8db59154U, 0x5d0571c4U, 0xd46f0406U, 0x15ff6050U,
+    0xfb241998U, 0xe997d6bdU, 0x43cc8940U, 0x9e7767d9U,
+    0x42bdb0e8U, 0x8b880789U, 0x5b38e719U, 0xeedb79c8U,
+    0x0a47a17cU, 0x0fe97c42U, 0x1ec9f884U, 0x00000000U,
+    0x86830980U, 0xed48322bU, 0x70ac1e11U, 0x724e6c5aU,
+    0xfffbfd0eU, 0x38560f85U, 0xd51e3daeU, 0x3927362dU,
+    0xd9640a0fU, 0xa621685cU, 0x54d19b5bU, 0x2e3a2436U,
+    0x67b10c0aU, 0xe70f9357U, 0x96d2b4eeU, 0x919e1b9bU,
+    0xc54f80c0U, 0x20a261dcU, 0x4b695a77U, 0x1a161c12U,
+    0xba0ae293U, 0x2ae5c0a0U, 0xe0433c22U, 0x171d121bU,
+    0x0d0b0e09U, 0xc7adf28bU, 0xa8b92db6U, 0xa9c8141eU,
+    0x198557f1U, 0x074caf75U, 0xddbbee99U, 0x60fda37fU,
+    0x269ff701U, 0xf5bc5c72U, 0x3bc54466U, 0x7e345bfbU,
+    0x29768b43U, 0xc6dccb23U, 0xfc68b6edU, 0xf163b8e4U,
+    0xdccad731U, 0x85104263U, 0x22401397U, 0x112084c6U,
+    0x247d854aU, 0x3df8d2bbU, 0x3211aef9U, 0xa16dc729U,
+    0x2f4b1d9eU, 0x30f3dcb2U, 0x52ec0d86U, 0xe3d077c1U,
+    0x166c2bb3U, 0xb999a970U, 0x48fa1194U, 0x642247e9U,
+    0x8cc4a8fcU, 0x3f1aa0f0U, 0x2cd8567dU, 0x90ef2233U,
+    0x4ec78749U, 0xd1c1d938U, 0xa2fe8ccaU, 0x0b3698d4U,
+    0x81cfa6f5U, 0xde28a57aU, 0x8e26dab7U, 0xbfa43fadU,
+    0x9de42c3aU, 0x920d5078U, 0xcc9b6a5fU, 0x4662547eU,
+    0x13c2f68dU, 0xb8e890d8U, 0xf75e2e39U, 0xaff582c3U,
+    0x80be9f5dU, 0x937c69d0U, 0x2da96fd5U, 0x12b3cf25U,
+    0x993bc8acU, 0x7da71018U, 0x636ee89cU, 0xbb7bdb3bU,
+    0x7809cd26U, 0x18f46e59U, 0xb701ec9aU, 0x9aa8834fU,
+    0x6e65e695U, 0xe67eaaffU, 0xcf0821bcU, 0xe8e6ef15U,
+    0x9bd9bae7U, 0x36ce4a6fU, 0x09d4ea9fU, 0x7cd629b0U,
+    0xb2af31a4U, 0x23312a3fU, 0x9430c6a5U, 0x66c035a2U,
+    0xbc37744eU, 0xcaa6fc82U, 0xd0b0e090U, 0xd81533a7U,
+    0x984af104U, 0xdaf741ecU, 0x500e7fcdU, 0xf62f1791U,
+    0xd68d764dU, 0xb04d43efU, 0x4d54ccaaU, 0x04dfe496U,
+    0xb5e39ed1U, 0x881b4c6aU, 0x1fb8c12cU, 0x517f4665U,
+    0xea049d5eU, 0x355d018cU, 0x7473fa87U, 0x412efb0bU,
+    0x1d5ab367U, 0xd25292dbU, 0x5633e910U, 0x47136dd6U,
+    0x618c9ad7U, 0x0c7a37a1U, 0x148e59f8U, 0x3c89eb13U,
+    0x27eecea9U, 0xc935b761U, 0xe5ede11cU, 0xb13c7a47U,
+    0xdf599cd2U, 0x733f55f2U, 0xce791814U, 0x37bf73c7U,
+    0xcdea53f7U, 0xaa5b5ffdU, 0x6f14df3dU, 0xdb867844U,
+    0xf381caafU, 0xc43eb968U, 0x342c3824U, 0x405fc2a3U,
+    0xc372161dU, 0x250cbce2U, 0x498b283cU, 0x9541ff0dU,
+    0x017139a8U, 0xb3de080cU, 0xe49cd8b4U, 0xc1906456U,
+    0x84617bcbU, 0xb670d532U, 0x5c74486cU, 0x5742d0b8U,
+};
+static const u32 Td3[256] = {
+    0xf4a75051U, 0x4165537eU, 0x17a4c31aU, 0x275e963aU,
+    0xab6bcb3bU, 0x9d45f11fU, 0xfa58abacU, 0xe303934bU,
+    0x30fa5520U, 0x766df6adU, 0xcc769188U, 0x024c25f5U,
+    0xe5d7fc4fU, 0x2acbd7c5U, 0x35448026U, 0x62a38fb5U,
+    0xb15a49deU, 0xba1b6725U, 0xea0e9845U, 0xfec0e15dU,
+    0x2f7502c3U, 0x4cf01281U, 0x4697a38dU, 0xd3f9c66bU,
+    0x8f5fe703U, 0x929c9515U, 0x6d7aebbfU, 0x5259da95U,
+    0xbe832dd4U, 0x7421d358U, 0xe0692949U, 0xc9c8448eU,
+    0xc2896a75U, 0x8e7978f4U, 0x583e6b99U, 0xb971dd27U,
+    0xe14fb6beU, 0x88ad17f0U, 0x20ac66c9U, 0xce3ab47dU,
+    0xdf4a1863U, 0x1a3182e5U, 0x51336097U, 0x537f4562U,
+    0x6477e0b1U, 0x6bae84bbU, 0x81a01cfeU, 0x082b94f9U,
+    0x48685870U, 0x45fd198fU, 0xde6c8794U, 0x7bf8b752U,
+    0x73d323abU, 0x4b02e272U, 0x1f8f57e3U, 0x55ab2a66U,
+    0xeb2807b2U, 0xb5c2032fU, 0xc57b9a86U, 0x3708a5d3U,
+    0x2887f230U, 0xbfa5b223U, 0x036aba02U, 0x16825cedU,
+    0xcf1c2b8aU, 0x79b492a7U, 0x07f2f0f3U, 0x69e2a14eU,
+    0xdaf4cd65U, 0x05bed506U, 0x34621fd1U, 0xa6fe8ac4U,
+    0x2e539d34U, 0xf355a0a2U, 0x8ae13205U, 0xf6eb75a4U,
+    0x83ec390bU, 0x60efaa40U, 0x719f065eU, 0x6e1051bdU,
+    0x218af93eU, 0xdd063d96U, 0x3e05aeddU, 0xe6bd464dU,
+    0x548db591U, 0xc45d0571U, 0x06d46f04U, 0x5015ff60U,
+    0x98fb2419U, 0xbde997d6U, 0x4043cc89U, 0xd99e7767U,
+    0xe842bdb0U, 0x898b8807U, 0x195b38e7U, 0xc8eedb79U,
+    0x7c0a47a1U, 0x420fe97cU, 0x841ec9f8U, 0x00000000U,
+    0x80868309U, 0x2bed4832U, 0x1170ac1eU, 0x5a724e6cU,
+    0x0efffbfdU, 0x8538560fU, 0xaed51e3dU, 0x2d392736U,
+    0x0fd9640aU, 0x5ca62168U, 0x5b54d19bU, 0x362e3a24U,
+    0x0a67b10cU, 0x57e70f93U, 0xee96d2b4U, 0x9b919e1bU,
+    0xc0c54f80U, 0xdc20a261U, 0x774b695aU, 0x121a161cU,
+    0x93ba0ae2U, 0xa02ae5c0U, 0x22e0433cU, 0x1b171d12U,
+    0x090d0b0eU, 0x8bc7adf2U, 0xb6a8b92dU, 0x1ea9c814U,
+    0xf1198557U, 0x75074cafU, 0x99ddbbeeU, 0x7f60fda3U,
+    0x01269ff7U, 0x72f5bc5cU, 0x663bc544U, 0xfb7e345bU,
+    0x4329768bU, 0x23c6dccbU, 0xedfc68b6U, 0xe4f163b8U,
+    0x31dccad7U, 0x63851042U, 0x97224013U, 0xc6112084U,
+    0x4a247d85U, 0xbb3df8d2U, 0xf93211aeU, 0x29a16dc7U,
+    0x9e2f4b1dU, 0xb230f3dcU, 0x8652ec0dU, 0xc1e3d077U,
+    0xb3166c2bU, 0x70b999a9U, 0x9448fa11U, 0xe9642247U,
+    0xfc8cc4a8U, 0xf03f1aa0U, 0x7d2cd856U, 0x3390ef22U,
+    0x494ec787U, 0x38d1c1d9U, 0xcaa2fe8cU, 0xd40b3698U,
+    0xf581cfa6U, 0x7ade28a5U, 0xb78e26daU, 0xadbfa43fU,
+    0x3a9de42cU, 0x78920d50U, 0x5fcc9b6aU, 0x7e466254U,
+    0x8d13c2f6U, 0xd8b8e890U, 0x39f75e2eU, 0xc3aff582U,
+    0x5d80be9fU, 0xd0937c69U, 0xd52da96fU, 0x2512b3cfU,
+    0xac993bc8U, 0x187da710U, 0x9c636ee8U, 0x3bbb7bdbU,
+    0x267809cdU, 0x5918f46eU, 0x9ab701ecU, 0x4f9aa883U,
+    0x956e65e6U, 0xffe67eaaU, 0xbccf0821U, 0x15e8e6efU,
+    0xe79bd9baU, 0x6f36ce4aU, 0x9f09d4eaU, 0xb07cd629U,
+    0xa4b2af31U, 0x3f23312aU, 0xa59430c6U, 0xa266c035U,
+    0x4ebc3774U, 0x82caa6fcU, 0x90d0b0e0U, 0xa7d81533U,
+    0x04984af1U, 0xecdaf741U, 0xcd500e7fU, 0x91f62f17U,
+    0x4dd68d76U, 0xefb04d43U, 0xaa4d54ccU, 0x9604dfe4U,
+    0xd1b5e39eU, 0x6a881b4cU, 0x2c1fb8c1U, 0x65517f46U,
+    0x5eea049dU, 0x8c355d01U, 0x877473faU, 0x0b412efbU,
+    0x671d5ab3U, 0xdbd25292U, 0x105633e9U, 0xd647136dU,
+    0xd7618c9aU, 0xa10c7a37U, 0xf8148e59U, 0x133c89ebU,
+    0xa927eeceU, 0x61c935b7U, 0x1ce5ede1U, 0x47b13c7aU,
+    0xd2df599cU, 0xf2733f55U, 0x14ce7918U, 0xc737bf73U,
+    0xf7cdea53U, 0xfdaa5b5fU, 0x3d6f14dfU, 0x44db8678U,
+    0xaff381caU, 0x68c43eb9U, 0x24342c38U, 0xa3405fc2U,
+    0x1dc37216U, 0xe2250cbcU, 0x3c498b28U, 0x0d9541ffU,
+    0xa8017139U, 0x0cb3de08U, 0xb4e49cd8U, 0x56c19064U,
+    0xcb84617bU, 0x32b670d5U, 0x6c5c7448U, 0xb85742d0U,
+};
+static const u32 Td4[256] = {
+    0x52525252U, 0x09090909U, 0x6a6a6a6aU, 0xd5d5d5d5U,
+    0x30303030U, 0x36363636U, 0xa5a5a5a5U, 0x38383838U,
+    0xbfbfbfbfU, 0x40404040U, 0xa3a3a3a3U, 0x9e9e9e9eU,
+    0x81818181U, 0xf3f3f3f3U, 0xd7d7d7d7U, 0xfbfbfbfbU,
+    0x7c7c7c7cU, 0xe3e3e3e3U, 0x39393939U, 0x82828282U,
+    0x9b9b9b9bU, 0x2f2f2f2fU, 0xffffffffU, 0x87878787U,
+    0x34343434U, 0x8e8e8e8eU, 0x43434343U, 0x44444444U,
+    0xc4c4c4c4U, 0xdedededeU, 0xe9e9e9e9U, 0xcbcbcbcbU,
+    0x54545454U, 0x7b7b7b7bU, 0x94949494U, 0x32323232U,
+    0xa6a6a6a6U, 0xc2c2c2c2U, 0x23232323U, 0x3d3d3d3dU,
+    0xeeeeeeeeU, 0x4c4c4c4cU, 0x95959595U, 0x0b0b0b0bU,
+    0x42424242U, 0xfafafafaU, 0xc3c3c3c3U, 0x4e4e4e4eU,
+    0x08080808U, 0x2e2e2e2eU, 0xa1a1a1a1U, 0x66666666U,
+    0x28282828U, 0xd9d9d9d9U, 0x24242424U, 0xb2b2b2b2U,
+    0x76767676U, 0x5b5b5b5bU, 0xa2a2a2a2U, 0x49494949U,
+    0x6d6d6d6dU, 0x8b8b8b8bU, 0xd1d1d1d1U, 0x25252525U,
+    0x72727272U, 0xf8f8f8f8U, 0xf6f6f6f6U, 0x64646464U,
+    0x86868686U, 0x68686868U, 0x98989898U, 0x16161616U,
+    0xd4d4d4d4U, 0xa4a4a4a4U, 0x5c5c5c5cU, 0xccccccccU,
+    0x5d5d5d5dU, 0x65656565U, 0xb6b6b6b6U, 0x92929292U,
+    0x6c6c6c6cU, 0x70707070U, 0x48484848U, 0x50505050U,
+    0xfdfdfdfdU, 0xededededU, 0xb9b9b9b9U, 0xdadadadaU,
+    0x5e5e5e5eU, 0x15151515U, 0x46464646U, 0x57575757U,
+    0xa7a7a7a7U, 0x8d8d8d8dU, 0x9d9d9d9dU, 0x84848484U,
+    0x90909090U, 0xd8d8d8d8U, 0xababababU, 0x00000000U,
+    0x8c8c8c8cU, 0xbcbcbcbcU, 0xd3d3d3d3U, 0x0a0a0a0aU,
+    0xf7f7f7f7U, 0xe4e4e4e4U, 0x58585858U, 0x05050505U,
+    0xb8b8b8b8U, 0xb3b3b3b3U, 0x45454545U, 0x06060606U,
+    0xd0d0d0d0U, 0x2c2c2c2cU, 0x1e1e1e1eU, 0x8f8f8f8fU,
+    0xcacacacaU, 0x3f3f3f3fU, 0x0f0f0f0fU, 0x02020202U,
+    0xc1c1c1c1U, 0xafafafafU, 0xbdbdbdbdU, 0x03030303U,
+    0x01010101U, 0x13131313U, 0x8a8a8a8aU, 0x6b6b6b6bU,
+    0x3a3a3a3aU, 0x91919191U, 0x11111111U, 0x41414141U,
+    0x4f4f4f4fU, 0x67676767U, 0xdcdcdcdcU, 0xeaeaeaeaU,
+    0x97979797U, 0xf2f2f2f2U, 0xcfcfcfcfU, 0xcecececeU,
+    0xf0f0f0f0U, 0xb4b4b4b4U, 0xe6e6e6e6U, 0x73737373U,
+    0x96969696U, 0xacacacacU, 0x74747474U, 0x22222222U,
+    0xe7e7e7e7U, 0xadadadadU, 0x35353535U, 0x85858585U,
+    0xe2e2e2e2U, 0xf9f9f9f9U, 0x37373737U, 0xe8e8e8e8U,
+    0x1c1c1c1cU, 0x75757575U, 0xdfdfdfdfU, 0x6e6e6e6eU,
+    0x47474747U, 0xf1f1f1f1U, 0x1a1a1a1aU, 0x71717171U,
+    0x1d1d1d1dU, 0x29292929U, 0xc5c5c5c5U, 0x89898989U,
+    0x6f6f6f6fU, 0xb7b7b7b7U, 0x62626262U, 0x0e0e0e0eU,
+    0xaaaaaaaaU, 0x18181818U, 0xbebebebeU, 0x1b1b1b1bU,
+    0xfcfcfcfcU, 0x56565656U, 0x3e3e3e3eU, 0x4b4b4b4bU,
+    0xc6c6c6c6U, 0xd2d2d2d2U, 0x79797979U, 0x20202020U,
+    0x9a9a9a9aU, 0xdbdbdbdbU, 0xc0c0c0c0U, 0xfefefefeU,
+    0x78787878U, 0xcdcdcdcdU, 0x5a5a5a5aU, 0xf4f4f4f4U,
+    0x1f1f1f1fU, 0xddddddddU, 0xa8a8a8a8U, 0x33333333U,
+    0x88888888U, 0x07070707U, 0xc7c7c7c7U, 0x31313131U,
+    0xb1b1b1b1U, 0x12121212U, 0x10101010U, 0x59595959U,
+    0x27272727U, 0x80808080U, 0xececececU, 0x5f5f5f5fU,
+    0x60606060U, 0x51515151U, 0x7f7f7f7fU, 0xa9a9a9a9U,
+    0x19191919U, 0xb5b5b5b5U, 0x4a4a4a4aU, 0x0d0d0d0dU,
+    0x2d2d2d2dU, 0xe5e5e5e5U, 0x7a7a7a7aU, 0x9f9f9f9fU,
+    0x93939393U, 0xc9c9c9c9U, 0x9c9c9c9cU, 0xefefefefU,
+    0xa0a0a0a0U, 0xe0e0e0e0U, 0x3b3b3b3bU, 0x4d4d4d4dU,
+    0xaeaeaeaeU, 0x2a2a2a2aU, 0xf5f5f5f5U, 0xb0b0b0b0U,
+    0xc8c8c8c8U, 0xebebebebU, 0xbbbbbbbbU, 0x3c3c3c3cU,
+    0x83838383U, 0x53535353U, 0x99999999U, 0x61616161U,
+    0x17171717U, 0x2b2b2b2bU, 0x04040404U, 0x7e7e7e7eU,
+    0xbabababaU, 0x77777777U, 0xd6d6d6d6U, 0x26262626U,
+    0xe1e1e1e1U, 0x69696969U, 0x14141414U, 0x63636363U,
+    0x55555555U, 0x21212121U, 0x0c0c0c0cU, 0x7d7d7d7dU,
+};
+static const u32 rcon[] = {
+       0x01000000, 0x02000000, 0x04000000, 0x08000000,
+       0x10000000, 0x20000000, 0x40000000, 0x80000000,
+       0x1B000000, 0x36000000, /* for 128-bit blocks, Rijndael never uses more than 10 rcon values */
+};
+
+#define SWAP(x) (_lrotl(x, 8) & 0x00ff00ff | _lrotr(x, 8) & 0xff00ff00)
+
+#ifdef _MSC_VER
+#define GETU32(p) SWAP(*((u32 *)(p)))
+#define PUTU32(ct, st) { *((u32 *)(ct)) = SWAP((st)); }
+#else
+#define GETU32(pt) (((u32)(pt)[0] << 24) ^ ((u32)(pt)[1] << 16) ^ ((u32)(pt)[2] <<  8) ^ ((u32)(pt)[3]))
+#define PUTU32(ct, st) { (ct)[0] = (u8)((st) >> 24); (ct)[1] = (u8)((st) >> 16); (ct)[2] = (u8)((st) >>  8); (ct)[3] = (u8)(st); }
+#endif
+
+/**
+ * Expand the cipher key into the encryption key schedule.
+ *
+ * @return     the number of rounds for the given cipher key size.
+ */
+int rijndaelKeySetupEnc(u32 rk[/*4*(Nr + 1)*/], const u8 cipherKey[], int keyBits) {
+       int i = 0;
+       u32 temp;
+
+       rk[0] = GETU32(cipherKey     );
+       rk[1] = GETU32(cipherKey +  4);
+       rk[2] = GETU32(cipherKey +  8);
+       rk[3] = GETU32(cipherKey + 12);
+       if (keyBits == 128) {
+               for (;;) {
+                       temp  = rk[3];
+                       rk[4] = rk[0] ^
+                               (Te4[(temp >> 16) & 0xff] & 0xff000000) ^
+                               (Te4[(temp >>  8) & 0xff] & 0x00ff0000) ^
+                               (Te4[(temp      ) & 0xff] & 0x0000ff00) ^
+                               (Te4[(temp >> 24)       ] & 0x000000ff) ^
+                               rcon[i];
+                       rk[5] = rk[1] ^ rk[4];
+                       rk[6] = rk[2] ^ rk[5];
+                       rk[7] = rk[3] ^ rk[6];
+                       if (++i == 10) {
+                               return 10;
+                       }
+                       rk += 4;
+               }
+       }
+       rk[4] = GETU32(cipherKey + 16);
+       rk[5] = GETU32(cipherKey + 20);
+       if (keyBits == 192) {
+               for (;;) {
+                       temp = rk[ 5];
+                       rk[ 6] = rk[ 0] ^
+                               (Te4[(temp >> 16) & 0xff] & 0xff000000) ^
+                               (Te4[(temp >>  8) & 0xff] & 0x00ff0000) ^
+                               (Te4[(temp      ) & 0xff] & 0x0000ff00) ^
+                               (Te4[(temp >> 24)       ] & 0x000000ff) ^
+                               rcon[i];
+                       rk[ 7] = rk[ 1] ^ rk[ 6];
+                       rk[ 8] = rk[ 2] ^ rk[ 7];
+                       rk[ 9] = rk[ 3] ^ rk[ 8];
+                       if (++i == 8) {
+                               return 12;
+                       }
+                       rk[10] = rk[ 4] ^ rk[ 9];
+                       rk[11] = rk[ 5] ^ rk[10];
+                       rk += 6;
+               }
+       }
+       rk[6] = GETU32(cipherKey + 24);
+       rk[7] = GETU32(cipherKey + 28);
+       if (keyBits == 256) {
+        for (;;) {
+               temp = rk[ 7];
+               rk[ 8] = rk[ 0] ^
+                       (Te4[(temp >> 16) & 0xff] & 0xff000000) ^
+                       (Te4[(temp >>  8) & 0xff] & 0x00ff0000) ^
+                       (Te4[(temp      ) & 0xff] & 0x0000ff00) ^
+                       (Te4[(temp >> 24)       ] & 0x000000ff) ^
+                       rcon[i];
+               rk[ 9] = rk[ 1] ^ rk[ 8];
+               rk[10] = rk[ 2] ^ rk[ 9];
+               rk[11] = rk[ 3] ^ rk[10];
+                       if (++i == 7) {
+                               return 14;
+                       }
+               temp = rk[11];
+               rk[12] = rk[ 4] ^
+                       (Te4[(temp >> 24)       ] & 0xff000000) ^
+                       (Te4[(temp >> 16) & 0xff] & 0x00ff0000) ^
+                       (Te4[(temp >>  8) & 0xff] & 0x0000ff00) ^
+                       (Te4[(temp      ) & 0xff] & 0x000000ff);
+               rk[13] = rk[ 5] ^ rk[12];
+               rk[14] = rk[ 6] ^ rk[13];
+               rk[15] = rk[ 7] ^ rk[14];
+
+                       rk += 8;
+        }
+       }
+       return 0;
+}
+
+/**
+ * Expand the cipher key into the decryption key schedule.
+ *
+ * @return     the number of rounds for the given cipher key size.
+ */
+int rijndaelKeySetupDec(u32 rk[/*4*(Nr + 1)*/], const u8 cipherKey[], int keyBits) {
+       int Nr, i, j;
+       u32 temp;
+
+       /* expand the cipher key: */
+       Nr = rijndaelKeySetupEnc(rk, cipherKey, keyBits);
+       /* invert the order of the round keys: */
+       for (i = 0, j = 4*Nr; i < j; i += 4, j -= 4) {
+               temp = rk[i    ]; rk[i    ] = rk[j    ]; rk[j    ] = temp;
+               temp = rk[i + 1]; rk[i + 1] = rk[j + 1]; rk[j + 1] = temp;
+               temp = rk[i + 2]; rk[i + 2] = rk[j + 2]; rk[j + 2] = temp;
+               temp = rk[i + 3]; rk[i + 3] = rk[j + 3]; rk[j + 3] = temp;
+       }
+       /* apply the inverse MixColumn transform to all round keys but the first and the last: */
+       for (i = 1; i < Nr; i++) {
+               rk += 4;
+               rk[0] =
+                       Td0[Te4[(rk[0] >> 24)       ] & 0xff] ^
+                       Td1[Te4[(rk[0] >> 16) & 0xff] & 0xff] ^
+                       Td2[Te4[(rk[0] >>  8) & 0xff] & 0xff] ^
+                       Td3[Te4[(rk[0]      ) & 0xff] & 0xff];
+               rk[1] =
+                       Td0[Te4[(rk[1] >> 24)       ] & 0xff] ^
+                       Td1[Te4[(rk[1] >> 16) & 0xff] & 0xff] ^
+                       Td2[Te4[(rk[1] >>  8) & 0xff] & 0xff] ^
+                       Td3[Te4[(rk[1]      ) & 0xff] & 0xff];
+               rk[2] =
+                       Td0[Te4[(rk[2] >> 24)       ] & 0xff] ^
+                       Td1[Te4[(rk[2] >> 16) & 0xff] & 0xff] ^
+                       Td2[Te4[(rk[2] >>  8) & 0xff] & 0xff] ^
+                       Td3[Te4[(rk[2]      ) & 0xff] & 0xff];
+               rk[3] =
+                       Td0[Te4[(rk[3] >> 24)       ] & 0xff] ^
+                       Td1[Te4[(rk[3] >> 16) & 0xff] & 0xff] ^
+                       Td2[Te4[(rk[3] >>  8) & 0xff] & 0xff] ^
+                       Td3[Te4[(rk[3]      ) & 0xff] & 0xff];
+       }
+       return Nr;
+}
+
+void rijndaelEncrypt(const u32 rk[/*4*(Nr + 1)*/], int Nr, const u8 pt[16], u8 ct[16]) {
+       u32 s0, s1, s2, s3, t0, t1, t2, t3;
+#ifndef FULL_UNROLL
+    int r;
+#endif /* ?FULL_UNROLL */
+
+    /*
+        * map byte array block to cipher state
+        * and add initial round key:
+        */
+       s0 = GETU32(pt     ) ^ rk[0];
+       s1 = GETU32(pt +  4) ^ rk[1];
+       s2 = GETU32(pt +  8) ^ rk[2];
+       s3 = GETU32(pt + 12) ^ rk[3];
+#ifdef FULL_UNROLL
+    /* round 1: */
+       t0 = Te0[s0 >> 24] ^ Te1[(s1 >> 16) & 0xff] ^ Te2[(s2 >>  8) & 0xff] ^ Te3[s3 & 0xff] ^ rk[ 4];
+       t1 = Te0[s1 >> 24] ^ Te1[(s2 >> 16) & 0xff] ^ Te2[(s3 >>  8) & 0xff] ^ Te3[s0 & 0xff] ^ rk[ 5];
+       t2 = Te0[s2 >> 24] ^ Te1[(s3 >> 16) & 0xff] ^ Te2[(s0 >>  8) & 0xff] ^ Te3[s1 & 0xff] ^ rk[ 6];
+       t3 = Te0[s3 >> 24] ^ Te1[(s0 >> 16) & 0xff] ^ Te2[(s1 >>  8) & 0xff] ^ Te3[s2 & 0xff] ^ rk[ 7];
+       /* round 2: */
+       s0 = Te0[t0 >> 24] ^ Te1[(t1 >> 16) & 0xff] ^ Te2[(t2 >>  8) & 0xff] ^ Te3[t3 & 0xff] ^ rk[ 8];
+       s1 = Te0[t1 >> 24] ^ Te1[(t2 >> 16) & 0xff] ^ Te2[(t3 >>  8) & 0xff] ^ Te3[t0 & 0xff] ^ rk[ 9];
+       s2 = Te0[t2 >> 24] ^ Te1[(t3 >> 16) & 0xff] ^ Te2[(t0 >>  8) & 0xff] ^ Te3[t1 & 0xff] ^ rk[10];
+       s3 = Te0[t3 >> 24] ^ Te1[(t0 >> 16) & 0xff] ^ Te2[(t1 >>  8) & 0xff] ^ Te3[t2 & 0xff] ^ rk[11];
+    /* round 3: */
+       t0 = Te0[s0 >> 24] ^ Te1[(s1 >> 16) & 0xff] ^ Te2[(s2 >>  8) & 0xff] ^ Te3[s3 & 0xff] ^ rk[12];
+       t1 = Te0[s1 >> 24] ^ Te1[(s2 >> 16) & 0xff] ^ Te2[(s3 >>  8) & 0xff] ^ Te3[s0 & 0xff] ^ rk[13];
+       t2 = Te0[s2 >> 24] ^ Te1[(s3 >> 16) & 0xff] ^ Te2[(s0 >>  8) & 0xff] ^ Te3[s1 & 0xff] ^ rk[14];
+       t3 = Te0[s3 >> 24] ^ Te1[(s0 >> 16) & 0xff] ^ Te2[(s1 >>  8) & 0xff] ^ Te3[s2 & 0xff] ^ rk[15];
+       /* round 4: */
+       s0 = Te0[t0 >> 24] ^ Te1[(t1 >> 16) & 0xff] ^ Te2[(t2 >>  8) & 0xff] ^ Te3[t3 & 0xff] ^ rk[16];
+       s1 = Te0[t1 >> 24] ^ Te1[(t2 >> 16) & 0xff] ^ Te2[(t3 >>  8) & 0xff] ^ Te3[t0 & 0xff] ^ rk[17];
+       s2 = Te0[t2 >> 24] ^ Te1[(t3 >> 16) & 0xff] ^ Te2[(t0 >>  8) & 0xff] ^ Te3[t1 & 0xff] ^ rk[18];
+       s3 = Te0[t3 >> 24] ^ Te1[(t0 >> 16) & 0xff] ^ Te2[(t1 >>  8) & 0xff] ^ Te3[t2 & 0xff] ^ rk[19];
+    /* round 5: */
+       t0 = Te0[s0 >> 24] ^ Te1[(s1 >> 16) & 0xff] ^ Te2[(s2 >>  8) & 0xff] ^ Te3[s3 & 0xff] ^ rk[20];
+       t1 = Te0[s1 >> 24] ^ Te1[(s2 >> 16) & 0xff] ^ Te2[(s3 >>  8) & 0xff] ^ Te3[s0 & 0xff] ^ rk[21];
+       t2 = Te0[s2 >> 24] ^ Te1[(s3 >> 16) & 0xff] ^ Te2[(s0 >>  8) & 0xff] ^ Te3[s1 & 0xff] ^ rk[22];
+       t3 = Te0[s3 >> 24] ^ Te1[(s0 >> 16) & 0xff] ^ Te2[(s1 >>  8) & 0xff] ^ Te3[s2 & 0xff] ^ rk[23];
+       /* round 6: */
+       s0 = Te0[t0 >> 24] ^ Te1[(t1 >> 16) & 0xff] ^ Te2[(t2 >>  8) & 0xff] ^ Te3[t3 & 0xff] ^ rk[24];
+       s1 = Te0[t1 >> 24] ^ Te1[(t2 >> 16) & 0xff] ^ Te2[(t3 >>  8) & 0xff] ^ Te3[t0 & 0xff] ^ rk[25];
+       s2 = Te0[t2 >> 24] ^ Te1[(t3 >> 16) & 0xff] ^ Te2[(t0 >>  8) & 0xff] ^ Te3[t1 & 0xff] ^ rk[26];
+       s3 = Te0[t3 >> 24] ^ Te1[(t0 >> 16) & 0xff] ^ Te2[(t1 >>  8) & 0xff] ^ Te3[t2 & 0xff] ^ rk[27];
+    /* round 7: */
+       t0 = Te0[s0 >> 24] ^ Te1[(s1 >> 16) & 0xff] ^ Te2[(s2 >>  8) & 0xff] ^ Te3[s3 & 0xff] ^ rk[28];
+       t1 = Te0[s1 >> 24] ^ Te1[(s2 >> 16) & 0xff] ^ Te2[(s3 >>  8) & 0xff] ^ Te3[s0 & 0xff] ^ rk[29];
+       t2 = Te0[s2 >> 24] ^ Te1[(s3 >> 16) & 0xff] ^ Te2[(s0 >>  8) & 0xff] ^ Te3[s1 & 0xff] ^ rk[30];
+       t3 = Te0[s3 >> 24] ^ Te1[(s0 >> 16) & 0xff] ^ Te2[(s1 >>  8) & 0xff] ^ Te3[s2 & 0xff] ^ rk[31];
+       /* round 8: */
+       s0 = Te0[t0 >> 24] ^ Te1[(t1 >> 16) & 0xff] ^ Te2[(t2 >>  8) & 0xff] ^ Te3[t3 & 0xff] ^ rk[32];
+       s1 = Te0[t1 >> 24] ^ Te1[(t2 >> 16) & 0xff] ^ Te2[(t3 >>  8) & 0xff] ^ Te3[t0 & 0xff] ^ rk[33];
+       s2 = Te0[t2 >> 24] ^ Te1[(t3 >> 16) & 0xff] ^ Te2[(t0 >>  8) & 0xff] ^ Te3[t1 & 0xff] ^ rk[34];
+       s3 = Te0[t3 >> 24] ^ Te1[(t0 >> 16) & 0xff] ^ Te2[(t1 >>  8) & 0xff] ^ Te3[t2 & 0xff] ^ rk[35];
+    /* round 9: */
+       t0 = Te0[s0 >> 24] ^ Te1[(s1 >> 16) & 0xff] ^ Te2[(s2 >>  8) & 0xff] ^ Te3[s3 & 0xff] ^ rk[36];
+       t1 = Te0[s1 >> 24] ^ Te1[(s2 >> 16) & 0xff] ^ Te2[(s3 >>  8) & 0xff] ^ Te3[s0 & 0xff] ^ rk[37];
+       t2 = Te0[s2 >> 24] ^ Te1[(s3 >> 16) & 0xff] ^ Te2[(s0 >>  8) & 0xff] ^ Te3[s1 & 0xff] ^ rk[38];
+       t3 = Te0[s3 >> 24] ^ Te1[(s0 >> 16) & 0xff] ^ Te2[(s1 >>  8) & 0xff] ^ Te3[s2 & 0xff] ^ rk[39];
+    if (Nr > 10) {
+        /* round 10: */
+        s0 = Te0[t0 >> 24] ^ Te1[(t1 >> 16) & 0xff] ^ Te2[(t2 >>  8) & 0xff] ^ Te3[t3 & 0xff] ^ rk[40];
+        s1 = Te0[t1 >> 24] ^ Te1[(t2 >> 16) & 0xff] ^ Te2[(t3 >>  8) & 0xff] ^ Te3[t0 & 0xff] ^ rk[41];
+        s2 = Te0[t2 >> 24] ^ Te1[(t3 >> 16) & 0xff] ^ Te2[(t0 >>  8) & 0xff] ^ Te3[t1 & 0xff] ^ rk[42];
+        s3 = Te0[t3 >> 24] ^ Te1[(t0 >> 16) & 0xff] ^ Te2[(t1 >>  8) & 0xff] ^ Te3[t2 & 0xff] ^ rk[43];
+        /* round 11: */
+        t0 = Te0[s0 >> 24] ^ Te1[(s1 >> 16) & 0xff] ^ Te2[(s2 >>  8) & 0xff] ^ Te3[s3 & 0xff] ^ rk[44];
+        t1 = Te0[s1 >> 24] ^ Te1[(s2 >> 16) & 0xff] ^ Te2[(s3 >>  8) & 0xff] ^ Te3[s0 & 0xff] ^ rk[45];
+        t2 = Te0[s2 >> 24] ^ Te1[(s3 >> 16) & 0xff] ^ Te2[(s0 >>  8) & 0xff] ^ Te3[s1 & 0xff] ^ rk[46];
+        t3 = Te0[s3 >> 24] ^ Te1[(s0 >> 16) & 0xff] ^ Te2[(s1 >>  8) & 0xff] ^ Te3[s2 & 0xff] ^ rk[47];
+        if (Nr > 12) {
+            /* round 12: */
+            s0 = Te0[t0 >> 24] ^ Te1[(t1 >> 16) & 0xff] ^ Te2[(t2 >>  8) & 0xff] ^ Te3[t3 & 0xff] ^ rk[48];
+            s1 = Te0[t1 >> 24] ^ Te1[(t2 >> 16) & 0xff] ^ Te2[(t3 >>  8) & 0xff] ^ Te3[t0 & 0xff] ^ rk[49];
+            s2 = Te0[t2 >> 24] ^ Te1[(t3 >> 16) & 0xff] ^ Te2[(t0 >>  8) & 0xff] ^ Te3[t1 & 0xff] ^ rk[50];
+            s3 = Te0[t3 >> 24] ^ Te1[(t0 >> 16) & 0xff] ^ Te2[(t1 >>  8) & 0xff] ^ Te3[t2 & 0xff] ^ rk[51];
+            /* round 13: */
+            t0 = Te0[s0 >> 24] ^ Te1[(s1 >> 16) & 0xff] ^ Te2[(s2 >>  8) & 0xff] ^ Te3[s3 & 0xff] ^ rk[52];
+            t1 = Te0[s1 >> 24] ^ Te1[(s2 >> 16) & 0xff] ^ Te2[(s3 >>  8) & 0xff] ^ Te3[s0 & 0xff] ^ rk[53];
+            t2 = Te0[s2 >> 24] ^ Te1[(s3 >> 16) & 0xff] ^ Te2[(s0 >>  8) & 0xff] ^ Te3[s1 & 0xff] ^ rk[54];
+            t3 = Te0[s3 >> 24] ^ Te1[(s0 >> 16) & 0xff] ^ Te2[(s1 >>  8) & 0xff] ^ Te3[s2 & 0xff] ^ rk[55];
+        }
+    }
+    rk += Nr << 2;
+#else  /* !FULL_UNROLL */
+    /*
+        * Nr - 1 full rounds:
+        */
+    r = Nr >> 1;
+    for (;;) {
+        t0 =
+            Te0[(s0 >> 24)       ] ^
+            Te1[(s1 >> 16) & 0xff] ^
+            Te2[(s2 >>  8) & 0xff] ^
+            Te3[(s3      ) & 0xff] ^
+            rk[4];
+        t1 =
+            Te0[(s1 >> 24)       ] ^
+            Te1[(s2 >> 16) & 0xff] ^
+            Te2[(s3 >>  8) & 0xff] ^
+            Te3[(s0      ) & 0xff] ^
+            rk[5];
+        t2 =
+            Te0[(s2 >> 24)       ] ^
+            Te1[(s3 >> 16) & 0xff] ^
+            Te2[(s0 >>  8) & 0xff] ^
+            Te3[(s1      ) & 0xff] ^
+            rk[6];
+        t3 =
+            Te0[(s3 >> 24)       ] ^
+            Te1[(s0 >> 16) & 0xff] ^
+            Te2[(s1 >>  8) & 0xff] ^
+            Te3[(s2      ) & 0xff] ^
+            rk[7];
+
+        rk += 8;
+        if (--r == 0) {
+            break;
+        }
+
+        s0 =
+            Te0[(t0 >> 24)       ] ^
+            Te1[(t1 >> 16) & 0xff] ^
+            Te2[(t2 >>  8) & 0xff] ^
+            Te3[(t3      ) & 0xff] ^
+            rk[0];
+        s1 =
+            Te0[(t1 >> 24)       ] ^
+            Te1[(t2 >> 16) & 0xff] ^
+            Te2[(t3 >>  8) & 0xff] ^
+            Te3[(t0      ) & 0xff] ^
+            rk[1];
+        s2 =
+            Te0[(t2 >> 24)       ] ^
+            Te1[(t3 >> 16) & 0xff] ^
+            Te2[(t0 >>  8) & 0xff] ^
+            Te3[(t1      ) & 0xff] ^
+            rk[2];
+        s3 =
+            Te0[(t3 >> 24)       ] ^
+            Te1[(t0 >> 16) & 0xff] ^
+            Te2[(t1 >>  8) & 0xff] ^
+            Te3[(t2      ) & 0xff] ^
+            rk[3];
+    }
+#endif /* ?FULL_UNROLL */
+    /*
+        * apply last round and
+        * map cipher state to byte array block:
+        */
+       s0 =
+               (Te4[(t0 >> 24)       ] & 0xff000000) ^
+               (Te4[(t1 >> 16) & 0xff] & 0x00ff0000) ^
+               (Te4[(t2 >>  8) & 0xff] & 0x0000ff00) ^
+               (Te4[(t3      ) & 0xff] & 0x000000ff) ^
+               rk[0];
+       PUTU32(ct     , s0);
+       s1 =
+               (Te4[(t1 >> 24)       ] & 0xff000000) ^
+               (Te4[(t2 >> 16) & 0xff] & 0x00ff0000) ^
+               (Te4[(t3 >>  8) & 0xff] & 0x0000ff00) ^
+               (Te4[(t0      ) & 0xff] & 0x000000ff) ^
+               rk[1];
+       PUTU32(ct +  4, s1);
+       s2 =
+               (Te4[(t2 >> 24)       ] & 0xff000000) ^
+               (Te4[(t3 >> 16) & 0xff] & 0x00ff0000) ^
+               (Te4[(t0 >>  8) & 0xff] & 0x0000ff00) ^
+               (Te4[(t1      ) & 0xff] & 0x000000ff) ^
+               rk[2];
+       PUTU32(ct +  8, s2);
+       s3 =
+               (Te4[(t3 >> 24)       ] & 0xff000000) ^
+               (Te4[(t0 >> 16) & 0xff] & 0x00ff0000) ^
+               (Te4[(t1 >>  8) & 0xff] & 0x0000ff00) ^
+               (Te4[(t2      ) & 0xff] & 0x000000ff) ^
+               rk[3];
+       PUTU32(ct + 12, s3);
+}
+
+void rijndaelDecrypt(const u32 rk[/*4*(Nr + 1)*/], int Nr, const u8 ct[16], u8 pt[16]) {
+       u32 s0, s1, s2, s3, t0, t1, t2, t3;
+#ifndef FULL_UNROLL
+    int r;
+#endif /* ?FULL_UNROLL */
+
+    /*
+        * map byte array block to cipher state
+        * and add initial round key:
+        */
+    s0 = GETU32(ct     ) ^ rk[0];
+    s1 = GETU32(ct +  4) ^ rk[1];
+    s2 = GETU32(ct +  8) ^ rk[2];
+    s3 = GETU32(ct + 12) ^ rk[3];
+#ifdef FULL_UNROLL
+    /* round 1: */
+    t0 = Td0[s0 >> 24] ^ Td1[(s3 >> 16) & 0xff] ^ Td2[(s2 >>  8) & 0xff] ^ Td3[s1 & 0xff] ^ rk[ 4];
+    t1 = Td0[s1 >> 24] ^ Td1[(s0 >> 16) & 0xff] ^ Td2[(s3 >>  8) & 0xff] ^ Td3[s2 & 0xff] ^ rk[ 5];
+    t2 = Td0[s2 >> 24] ^ Td1[(s1 >> 16) & 0xff] ^ Td2[(s0 >>  8) & 0xff] ^ Td3[s3 & 0xff] ^ rk[ 6];
+    t3 = Td0[s3 >> 24] ^ Td1[(s2 >> 16) & 0xff] ^ Td2[(s1 >>  8) & 0xff] ^ Td3[s0 & 0xff] ^ rk[ 7];
+    /* round 2: */
+    s0 = Td0[t0 >> 24] ^ Td1[(t3 >> 16) & 0xff] ^ Td2[(t2 >>  8) & 0xff] ^ Td3[t1 & 0xff] ^ rk[ 8];
+    s1 = Td0[t1 >> 24] ^ Td1[(t0 >> 16) & 0xff] ^ Td2[(t3 >>  8) & 0xff] ^ Td3[t2 & 0xff] ^ rk[ 9];
+    s2 = Td0[t2 >> 24] ^ Td1[(t1 >> 16) & 0xff] ^ Td2[(t0 >>  8) & 0xff] ^ Td3[t3 & 0xff] ^ rk[10];
+    s3 = Td0[t3 >> 24] ^ Td1[(t2 >> 16) & 0xff] ^ Td2[(t1 >>  8) & 0xff] ^ Td3[t0 & 0xff] ^ rk[11];
+    /* round 3: */
+    t0 = Td0[s0 >> 24] ^ Td1[(s3 >> 16) & 0xff] ^ Td2[(s2 >>  8) & 0xff] ^ Td3[s1 & 0xff] ^ rk[12];
+    t1 = Td0[s1 >> 24] ^ Td1[(s0 >> 16) & 0xff] ^ Td2[(s3 >>  8) & 0xff] ^ Td3[s2 & 0xff] ^ rk[13];
+    t2 = Td0[s2 >> 24] ^ Td1[(s1 >> 16) & 0xff] ^ Td2[(s0 >>  8) & 0xff] ^ Td3[s3 & 0xff] ^ rk[14];
+    t3 = Td0[s3 >> 24] ^ Td1[(s2 >> 16) & 0xff] ^ Td2[(s1 >>  8) & 0xff] ^ Td3[s0 & 0xff] ^ rk[15];
+    /* round 4: */
+    s0 = Td0[t0 >> 24] ^ Td1[(t3 >> 16) & 0xff] ^ Td2[(t2 >>  8) & 0xff] ^ Td3[t1 & 0xff] ^ rk[16];
+    s1 = Td0[t1 >> 24] ^ Td1[(t0 >> 16) & 0xff] ^ Td2[(t3 >>  8) & 0xff] ^ Td3[t2 & 0xff] ^ rk[17];
+    s2 = Td0[t2 >> 24] ^ Td1[(t1 >> 16) & 0xff] ^ Td2[(t0 >>  8) & 0xff] ^ Td3[t3 & 0xff] ^ rk[18];
+    s3 = Td0[t3 >> 24] ^ Td1[(t2 >> 16) & 0xff] ^ Td2[(t1 >>  8) & 0xff] ^ Td3[t0 & 0xff] ^ rk[19];
+    /* round 5: */
+    t0 = Td0[s0 >> 24] ^ Td1[(s3 >> 16) & 0xff] ^ Td2[(s2 >>  8) & 0xff] ^ Td3[s1 & 0xff] ^ rk[20];
+    t1 = Td0[s1 >> 24] ^ Td1[(s0 >> 16) & 0xff] ^ Td2[(s3 >>  8) & 0xff] ^ Td3[s2 & 0xff] ^ rk[21];
+    t2 = Td0[s2 >> 24] ^ Td1[(s1 >> 16) & 0xff] ^ Td2[(s0 >>  8) & 0xff] ^ Td3[s3 & 0xff] ^ rk[22];
+    t3 = Td0[s3 >> 24] ^ Td1[(s2 >> 16) & 0xff] ^ Td2[(s1 >>  8) & 0xff] ^ Td3[s0 & 0xff] ^ rk[23];
+    /* round 6: */
+    s0 = Td0[t0 >> 24] ^ Td1[(t3 >> 16) & 0xff] ^ Td2[(t2 >>  8) & 0xff] ^ Td3[t1 & 0xff] ^ rk[24];
+    s1 = Td0[t1 >> 24] ^ Td1[(t0 >> 16) & 0xff] ^ Td2[(t3 >>  8) & 0xff] ^ Td3[t2 & 0xff] ^ rk[25];
+    s2 = Td0[t2 >> 24] ^ Td1[(t1 >> 16) & 0xff] ^ Td2[(t0 >>  8) & 0xff] ^ Td3[t3 & 0xff] ^ rk[26];
+    s3 = Td0[t3 >> 24] ^ Td1[(t2 >> 16) & 0xff] ^ Td2[(t1 >>  8) & 0xff] ^ Td3[t0 & 0xff] ^ rk[27];
+    /* round 7: */
+    t0 = Td0[s0 >> 24] ^ Td1[(s3 >> 16) & 0xff] ^ Td2[(s2 >>  8) & 0xff] ^ Td3[s1 & 0xff] ^ rk[28];
+    t1 = Td0[s1 >> 24] ^ Td1[(s0 >> 16) & 0xff] ^ Td2[(s3 >>  8) & 0xff] ^ Td3[s2 & 0xff] ^ rk[29];
+    t2 = Td0[s2 >> 24] ^ Td1[(s1 >> 16) & 0xff] ^ Td2[(s0 >>  8) & 0xff] ^ Td3[s3 & 0xff] ^ rk[30];
+    t3 = Td0[s3 >> 24] ^ Td1[(s2 >> 16) & 0xff] ^ Td2[(s1 >>  8) & 0xff] ^ Td3[s0 & 0xff] ^ rk[31];
+    /* round 8: */
+    s0 = Td0[t0 >> 24] ^ Td1[(t3 >> 16) & 0xff] ^ Td2[(t2 >>  8) & 0xff] ^ Td3[t1 & 0xff] ^ rk[32];
+    s1 = Td0[t1 >> 24] ^ Td1[(t0 >> 16) & 0xff] ^ Td2[(t3 >>  8) & 0xff] ^ Td3[t2 & 0xff] ^ rk[33];
+    s2 = Td0[t2 >> 24] ^ Td1[(t1 >> 16) & 0xff] ^ Td2[(t0 >>  8) & 0xff] ^ Td3[t3 & 0xff] ^ rk[34];
+    s3 = Td0[t3 >> 24] ^ Td1[(t2 >> 16) & 0xff] ^ Td2[(t1 >>  8) & 0xff] ^ Td3[t0 & 0xff] ^ rk[35];
+    /* round 9: */
+    t0 = Td0[s0 >> 24] ^ Td1[(s3 >> 16) & 0xff] ^ Td2[(s2 >>  8) & 0xff] ^ Td3[s1 & 0xff] ^ rk[36];
+    t1 = Td0[s1 >> 24] ^ Td1[(s0 >> 16) & 0xff] ^ Td2[(s3 >>  8) & 0xff] ^ Td3[s2 & 0xff] ^ rk[37];
+    t2 = Td0[s2 >> 24] ^ Td1[(s1 >> 16) & 0xff] ^ Td2[(s0 >>  8) & 0xff] ^ Td3[s3 & 0xff] ^ rk[38];
+    t3 = Td0[s3 >> 24] ^ Td1[(s2 >> 16) & 0xff] ^ Td2[(s1 >>  8) & 0xff] ^ Td3[s0 & 0xff] ^ rk[39];
+    if (Nr > 10) {
+        /* round 10: */
+        s0 = Td0[t0 >> 24] ^ Td1[(t3 >> 16) & 0xff] ^ Td2[(t2 >>  8) & 0xff] ^ Td3[t1 & 0xff] ^ rk[40];
+        s1 = Td0[t1 >> 24] ^ Td1[(t0 >> 16) & 0xff] ^ Td2[(t3 >>  8) & 0xff] ^ Td3[t2 & 0xff] ^ rk[41];
+        s2 = Td0[t2 >> 24] ^ Td1[(t1 >> 16) & 0xff] ^ Td2[(t0 >>  8) & 0xff] ^ Td3[t3 & 0xff] ^ rk[42];
+        s3 = Td0[t3 >> 24] ^ Td1[(t2 >> 16) & 0xff] ^ Td2[(t1 >>  8) & 0xff] ^ Td3[t0 & 0xff] ^ rk[43];
+        /* round 11: */
+        t0 = Td0[s0 >> 24] ^ Td1[(s3 >> 16) & 0xff] ^ Td2[(s2 >>  8) & 0xff] ^ Td3[s1 & 0xff] ^ rk[44];
+        t1 = Td0[s1 >> 24] ^ Td1[(s0 >> 16) & 0xff] ^ Td2[(s3 >>  8) & 0xff] ^ Td3[s2 & 0xff] ^ rk[45];
+        t2 = Td0[s2 >> 24] ^ Td1[(s1 >> 16) & 0xff] ^ Td2[(s0 >>  8) & 0xff] ^ Td3[s3 & 0xff] ^ rk[46];
+        t3 = Td0[s3 >> 24] ^ Td1[(s2 >> 16) & 0xff] ^ Td2[(s1 >>  8) & 0xff] ^ Td3[s0 & 0xff] ^ rk[47];
+        if (Nr > 12) {
+            /* round 12: */
+            s0 = Td0[t0 >> 24] ^ Td1[(t3 >> 16) & 0xff] ^ Td2[(t2 >>  8) & 0xff] ^ Td3[t1 & 0xff] ^ rk[48];
+            s1 = Td0[t1 >> 24] ^ Td1[(t0 >> 16) & 0xff] ^ Td2[(t3 >>  8) & 0xff] ^ Td3[t2 & 0xff] ^ rk[49];
+            s2 = Td0[t2 >> 24] ^ Td1[(t1 >> 16) & 0xff] ^ Td2[(t0 >>  8) & 0xff] ^ Td3[t3 & 0xff] ^ rk[50];
+            s3 = Td0[t3 >> 24] ^ Td1[(t2 >> 16) & 0xff] ^ Td2[(t1 >>  8) & 0xff] ^ Td3[t0 & 0xff] ^ rk[51];
+            /* round 13: */
+            t0 = Td0[s0 >> 24] ^ Td1[(s3 >> 16) & 0xff] ^ Td2[(s2 >>  8) & 0xff] ^ Td3[s1 & 0xff] ^ rk[52];
+            t1 = Td0[s1 >> 24] ^ Td1[(s0 >> 16) & 0xff] ^ Td2[(s3 >>  8) & 0xff] ^ Td3[s2 & 0xff] ^ rk[53];
+            t2 = Td0[s2 >> 24] ^ Td1[(s1 >> 16) & 0xff] ^ Td2[(s0 >>  8) & 0xff] ^ Td3[s3 & 0xff] ^ rk[54];
+            t3 = Td0[s3 >> 24] ^ Td1[(s2 >> 16) & 0xff] ^ Td2[(s1 >>  8) & 0xff] ^ Td3[s0 & 0xff] ^ rk[55];
+        }
+    }
+       rk += Nr << 2;
+#else  /* !FULL_UNROLL */
+    /*
+     * Nr - 1 full rounds:
+     */
+    r = Nr >> 1;
+    for (;;) {
+        t0 =
+            Td0[(s0 >> 24)       ] ^
+            Td1[(s3 >> 16) & 0xff] ^
+            Td2[(s2 >>  8) & 0xff] ^
+            Td3[(s1      ) & 0xff] ^
+            rk[4];
+        t1 =
+            Td0[(s1 >> 24)       ] ^
+            Td1[(s0 >> 16) & 0xff] ^
+            Td2[(s3 >>  8) & 0xff] ^
+            Td3[(s2      ) & 0xff] ^
+            rk[5];
+        t2 =
+            Td0[(s2 >> 24)       ] ^
+            Td1[(s1 >> 16) & 0xff] ^
+            Td2[(s0 >>  8) & 0xff] ^
+            Td3[(s3      ) & 0xff] ^
+            rk[6];
+        t3 =
+            Td0[(s3 >> 24)       ] ^
+            Td1[(s2 >> 16) & 0xff] ^
+            Td2[(s1 >>  8) & 0xff] ^
+            Td3[(s0      ) & 0xff] ^
+            rk[7];
+
+        rk += 8;
+        if (--r == 0) {
+            break;
+        }
+
+        s0 =
+            Td0[(t0 >> 24)       ] ^
+            Td1[(t3 >> 16) & 0xff] ^
+            Td2[(t2 >>  8) & 0xff] ^
+            Td3[(t1      ) & 0xff] ^
+            rk[0];
+        s1 =
+            Td0[(t1 >> 24)       ] ^
+            Td1[(t0 >> 16) & 0xff] ^
+            Td2[(t3 >>  8) & 0xff] ^
+            Td3[(t2      ) & 0xff] ^
+            rk[1];
+        s2 =
+            Td0[(t2 >> 24)       ] ^
+            Td1[(t1 >> 16) & 0xff] ^
+            Td2[(t0 >>  8) & 0xff] ^
+            Td3[(t3      ) & 0xff] ^
+            rk[2];
+        s3 =
+            Td0[(t3 >> 24)       ] ^
+            Td1[(t2 >> 16) & 0xff] ^
+            Td2[(t1 >>  8) & 0xff] ^
+            Td3[(t0      ) & 0xff] ^
+            rk[3];
+    }
+#endif /* ?FULL_UNROLL */
+    /*
+        * apply last round and
+        * map cipher state to byte array block:
+        */
+       s0 =
+               (Td4[(t0 >> 24)       ] & 0xff000000) ^
+               (Td4[(t3 >> 16) & 0xff] & 0x00ff0000) ^
+               (Td4[(t2 >>  8) & 0xff] & 0x0000ff00) ^
+               (Td4[(t1      ) & 0xff] & 0x000000ff) ^
+               rk[0];
+       PUTU32(pt     , s0);
+       s1 =
+               (Td4[(t1 >> 24)       ] & 0xff000000) ^
+               (Td4[(t0 >> 16) & 0xff] & 0x00ff0000) ^
+               (Td4[(t3 >>  8) & 0xff] & 0x0000ff00) ^
+               (Td4[(t2      ) & 0xff] & 0x000000ff) ^
+               rk[1];
+       PUTU32(pt +  4, s1);
+       s2 =
+               (Td4[(t2 >> 24)       ] & 0xff000000) ^
+               (Td4[(t1 >> 16) & 0xff] & 0x00ff0000) ^
+               (Td4[(t0 >>  8) & 0xff] & 0x0000ff00) ^
+               (Td4[(t3      ) & 0xff] & 0x000000ff) ^
+               rk[2];
+       PUTU32(pt +  8, s2);
+       s3 =
+               (Td4[(t3 >> 24)       ] & 0xff000000) ^
+               (Td4[(t2 >> 16) & 0xff] & 0x00ff0000) ^
+               (Td4[(t1 >>  8) & 0xff] & 0x0000ff00) ^
+               (Td4[(t0      ) & 0xff] & 0x000000ff) ^
+               rk[3];
+       PUTU32(pt + 12, s3);
+}
diff --git a/source4/heimdal/lib/des/rijndael-alg-fst.h b/source4/heimdal/lib/des/rijndael-alg-fst.h
new file mode 100755 (executable)
index 0000000..0281110
--- /dev/null
@@ -0,0 +1,40 @@
+/*     $NetBSD: rijndael-alg-fst.h,v 1.2 2000/10/02 17:19:15 itojun Exp $      */
+/*     $KAME: rijndael-alg-fst.h,v 1.5 2003/07/15 10:47:16 itojun Exp $        */
+/**
+ * rijndael-alg-fst.h
+ *
+ * @version 3.0 (December 2000)
+ *
+ * Optimised ANSI C code for the Rijndael cipher (now AES)
+ *
+ * @author Vincent Rijmen <vincent.rijmen@esat.kuleuven.ac.be>
+ * @author Antoon Bosselaers <antoon.bosselaers@esat.kuleuven.ac.be>
+ * @author Paulo Barreto <paulo.barreto@terra.com.br>
+ *
+ * This code is hereby placed in the public domain.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHORS ''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 AUTHORS 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 __RIJNDAEL_ALG_FST_H
+#define __RIJNDAEL_ALG_FST_H
+
+#define RIJNDAEL_MAXKC (256/32)
+#define RIJNDAEL_MAXKB (256/8)
+#define RIJNDAEL_MAXNR 14
+
+int rijndaelKeySetupEnc(u_int32_t rk[/*4*(Nr + 1)*/], const u_int8_t cipherKey[], int keyBits);
+int rijndaelKeySetupDec(u_int32_t rk[/*4*(Nr + 1)*/], const u_int8_t cipherKey[], int keyBits);
+void rijndaelEncrypt(const u_int32_t rk[/*4*(Nr + 1)*/], int Nr, const u_int8_t pt[16], u_int8_t ct[16]);
+void rijndaelDecrypt(const u_int32_t rk[/*4*(Nr + 1)*/], int Nr, const u_int8_t ct[16], u_int8_t pt[16]);
+
+#endif /* __RIJNDAEL_ALG_FST_H */
diff --git a/source4/heimdal/lib/des/rnd_keys.c b/source4/heimdal/lib/des/rnd_keys.c
new file mode 100644 (file)
index 0000000..49d8838
--- /dev/null
@@ -0,0 +1,503 @@
+/*
+ * Copyright (c) 1995, 1996, 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.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+
+RCSID("$Id: rnd_keys.c,v 1.68 2005/06/29 22:28:10 lha Exp $");
+#endif
+
+#ifdef KRB5
+#include <krb5-types.h>
+#endif
+#include <des.h>
+
+#include <stdlib.h>
+#include <string.h>
+
+#ifdef TIME_WITH_SYS_TIME
+#include <sys/time.h>
+#include <time.h>
+#elif defined(HAVE_SYS_TIME_H)
+#include <sys/time.h>
+#else
+#include <time.h>
+#endif
+
+#ifdef HAVE_SYS_TYPES_H
+#include <sys/types.h>
+#endif
+
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+#ifdef HAVE_IO_H
+#include <io.h>
+#endif
+
+#ifdef HAVE_SIGNAL_H
+#include <signal.h>
+#endif
+#ifdef HAVE_FCNTL_H
+#include <fcntl.h>
+#endif
+
+/*
+ * Generate "random" data by checksumming a file.
+ *
+ * Returns -1 if there were any problems with permissions or I/O
+ * errors.
+ */
+static
+int
+sumFile (const char *name, int len, void *res)
+{
+  u_int32_t sum[2] = { 0, 0 };
+  u_int32_t buf[1024*2];
+  int fd, i;
+
+  fd = open (name, 0);
+  if (fd < 0)
+    return -1;
+
+  while (len > 0)
+    {
+      int n = read(fd, buf, sizeof(buf));
+      if (n < 0)
+       {
+         close(fd);
+         return n;
+       }
+      for (i = 0; i < (n/sizeof(buf[0])); i++)
+       {
+         sum[0] += buf[i];
+         i++;
+         sum[1] += buf[i];
+       }
+      len -= n;
+    }
+  close (fd);
+  memcpy (res, &sum, sizeof(sum));
+  return 0;
+}
+
+#if 0
+static
+int
+md5sumFile (const char *name, int len, int32_t sum[4])
+{
+  int32_t buf[1024*2];
+  int fd, cnt;
+  struct md5 md5;
+
+  fd = open (name, 0);
+  if (fd < 0)
+    return -1;
+
+  md5_init(&md5);
+  while (len > 0)
+    {
+      int n = read(fd, buf, sizeof(buf));
+      if (n < 0)
+       {
+         close(fd);
+         return n;
+       }
+      md5_update(&md5, buf, n);
+      len -= n;
+    }
+  md5_finito(&md5, (unsigned char *)sum);
+  close (fd);
+  return 0;
+}
+#endif
+
+/*
+ * Create a sequence of random 64 bit blocks.
+ * The sequence is indexed with a long long and 
+ * based on an initial des key used as a seed.
+ */
+static DES_key_schedule sequence_seed;
+static u_int32_t sequence_index[2];
+
+/* 
+ * Random number generator based on ideas from truerand in cryptolib
+ * as described on page 424 in Applied Cryptography 2 ed. by Bruce
+ * Schneier.
+ */
+
+static volatile int counter;
+static volatile unsigned char *gdata; /* Global data */
+static volatile int igdata;    /* Index into global data */
+static int gsize;
+
+#if !defined(WIN32) && !defined(__EMX__) && !defined(__OS2__) && !defined(__CYGWIN32__)
+/* Visual C++ 4.0 (Windows95/NT) */
+
+static
+RETSIGTYPE
+sigALRM(int sig)
+{
+    if (igdata < gsize)
+       gdata[igdata++] ^= counter & 0xff;
+
+#ifndef HAVE_SIGACTION
+    signal(SIGALRM, sigALRM); /* Reinstall SysV signal handler */
+#endif
+    SIGRETURN(0);
+}
+
+#endif
+
+#if !defined(HAVE_RANDOM) && defined(HAVE_RAND)
+#ifndef srandom
+#define srandom srand
+#endif
+#ifndef random
+#define random rand
+#endif
+#endif
+
+#if !defined(HAVE_SETITIMER) || defined(WIN32) || defined(__EMX__) || defined(__OS2__) || defined(__CYGWIN32__)
+static void
+des_not_rand_data(unsigned char *data, int size)
+{
+  int i;
+
+  srandom (time (NULL));
+
+  for(i = 0; i < size; ++i)
+    data[i] ^= random() % 0x100;
+}
+#endif
+
+#if !defined(WIN32) && !defined(__EMX__) && !defined(__OS2__) && !defined(__CYGWIN32__)
+
+#ifndef HAVE_SETITIMER
+static void
+pacemaker(struct timeval *tv)
+{
+    fd_set fds;
+    pid_t pid;
+    pid = getppid();
+    while(1){
+       FD_ZERO(&fds);
+       FD_SET(0, &fds);
+       select(1, &fds, NULL, NULL, tv);
+       kill(pid, SIGALRM);
+    }
+}
+#endif
+
+#ifdef HAVE_SIGACTION
+/* XXX ugly hack, should perhaps use function from roken */
+static RETSIGTYPE 
+(*fake_signal(int sig, RETSIGTYPE (*f)(int)))(int)
+{
+    struct sigaction sa, osa;
+    sa.sa_handler = f;
+    sa.sa_flags = 0;
+    sigemptyset(&sa.sa_mask);
+    sigaction(sig, &sa, &osa);
+    return osa.sa_handler;
+}
+#define signal(S, F) fake_signal((S), (F))
+#endif
+
+/*
+ * Generate size bytes of "random" data using timed interrupts.
+ * It takes about 40ms/byte random data.
+ * It's not neccessary to be root to run it.
+ */
+void
+DES_rand_data(unsigned char *data, int size)
+{
+    struct itimerval tv, otv;
+    RETSIGTYPE (*osa)(int);
+    int i, j;
+#ifndef HAVE_SETITIMER 
+    RETSIGTYPE (*ochld)(int);
+    pid_t pid;
+#endif
+    const char *rnd_devices[] = {"/dev/random",
+                          "/dev/srandom",
+                          "/dev/urandom",
+                          "/dev/arandom",
+                          NULL};
+    const char **p;
+
+    for(p = rnd_devices; *p; p++) {
+      int fd = open(*p, O_RDONLY | O_NDELAY);
+      
+      if(fd >= 0 && read(fd, data, size) == size) {
+       close(fd);
+       return;
+      }
+      close(fd);
+    }
+
+    /* Paranoia? Initialize data from /dev/mem if we can read it. */
+    if (size >= 8)
+      sumFile("/dev/mem", (1024*1024*2), data);
+
+    gdata = data;
+    gsize = size;
+    igdata = 0;
+
+    osa = signal(SIGALRM, sigALRM);
+  
+    /* Start timer */
+    tv.it_value.tv_sec = 0;
+    tv.it_value.tv_usec = 10 * 1000; /* 10 ms */
+    tv.it_interval = tv.it_value;
+#ifdef HAVE_SETITIMER
+    setitimer(ITIMER_REAL, &tv, &otv);
+#else
+    ochld = signal(SIGCHLD, SIG_IGN);
+    pid = fork();
+    if(pid == -1){
+       signal(SIGCHLD, ochld != SIG_ERR ? ochld : SIG_DFL);
+       des_not_rand_data(data, size);
+       return;
+    }
+    if(pid == 0)
+       pacemaker(&tv.it_interval);
+#endif
+
+    for(i = 0; i < 4; i++) {
+       for (igdata = 0; igdata < size;) /* igdata++ in sigALRM */
+           counter++;
+       for (j = 0; j < size; j++) /* Only use 2 bits each lap */
+           gdata[j] = (gdata[j]>>2) | (gdata[j]<<6);
+    }
+#ifdef HAVE_SETITIMER
+    setitimer(ITIMER_REAL, &otv, 0);
+#else
+    kill(pid, SIGKILL);
+    while(waitpid(pid, NULL, 0) != pid);
+    signal(SIGCHLD, ochld != SIG_ERR ? ochld : SIG_DFL);
+#endif
+    signal(SIGALRM, osa != SIG_ERR ? osa : SIG_DFL);
+}
+#else
+void
+DES_rand_data(unsigned char *p, int s)
+{
+  des_not_rand_data (p, s);
+}
+#endif
+
+void
+DES_generate_random_block(DES_cblock *block)
+{
+  DES_rand_data((unsigned char *)block, sizeof(*block));
+}
+
+void
+DES_rand_data_key(DES_cblock *key);
+
+/*
+ * Generate a "random" DES key.
+ */
+void
+DES_rand_data_key(DES_cblock *key)
+{
+    unsigned char data[8];
+    DES_key_schedule sched;
+    do {
+       DES_rand_data(data, sizeof(data));
+       DES_rand_data((unsigned char*)key, sizeof(DES_cblock));
+       DES_set_odd_parity(key);
+       DES_set_key(key, &sched);
+       DES_ecb_encrypt(&data, key, &sched, DES_ENCRYPT);
+       memset(&data, 0, sizeof(data));
+       memset(&sched, 0, sizeof(sched));
+       DES_set_odd_parity(key);
+    } while(DES_is_weak_key(key));
+}
+
+/*
+ * Generate "random" data by checksumming /dev/mem
+ *
+ * It's neccessary to be root to run it. Returns -1 if there were any
+ * problems with permissions.
+ */
+int
+DES_mem_rand8(unsigned char *data);
+
+int
+DES_mem_rand8(unsigned char *data)
+{
+  return 1;
+}
+
+/*
+ * In case the generator does not get initialized use this as fallback.
+ */
+static int initialized;
+
+static void
+do_initialize(void)
+{
+    DES_cblock default_seed;
+    do {
+       DES_generate_random_block(&default_seed);
+       DES_set_odd_parity(&default_seed);
+    } while (DES_is_weak_key(&default_seed));
+    DES_init_random_number_generator(&default_seed);
+}
+
+#define zero_long_long(ll) do { ll[0] = ll[1] = 0; } while (0)
+
+#define incr_long_long(ll) do { if (++ll[0] == 0) ++ll[1]; } while (0)
+
+#define set_sequence_number(ll) \
+memcpy((char *)sequence_index, (ll), sizeof(sequence_index));
+
+/*
+ * Set the sequnce number to this value (a long long).
+ */
+void
+DES_set_sequence_number(unsigned char *ll)
+{
+    set_sequence_number(ll);
+}
+
+/*
+ * Set the generator seed and reset the sequence number to 0.
+ */
+void
+DES_set_random_generator_seed(DES_cblock *seed)
+{
+    DES_set_key(seed, &sequence_seed);
+    zero_long_long(sequence_index);
+    initialized = 1;
+}
+
+/*
+ * Generate a sequence of random des keys
+ * using the random block sequence, fixup
+ * parity and skip weak keys.
+ */
+int
+DES_new_random_key(DES_cblock *key)
+{
+    if (!initialized)
+       do_initialize();
+
+    do {
+       DES_ecb_encrypt((DES_cblock *) sequence_index,
+                       key,
+                       &sequence_seed,
+                       DES_ENCRYPT);
+       incr_long_long(sequence_index);
+       /* random key must have odd parity and not be weak */
+       DES_set_odd_parity(key);
+    } while (DES_is_weak_key(key));
+    return(0);
+}
+
+/*
+ * des_init_random_number_generator:
+ *
+ * Initialize the sequence of random 64 bit blocks.  The input seed
+ * can be a secret key since it should be well hidden and is also not
+ * kept.
+ *
+ */
+void 
+DES_init_random_number_generator(DES_cblock *seed)
+{
+    struct timeval now;
+    DES_cblock uniq;
+    DES_cblock new_key;
+
+    gettimeofday(&now, (struct timezone *)0);
+    DES_generate_random_block(&uniq);
+
+    /* Pick a unique random key from the shared sequence. */
+    DES_set_random_generator_seed(seed);
+    set_sequence_number((unsigned char *)&uniq);
+    DES_new_random_key(&new_key);
+
+    /* Select a new nonshared sequence, */
+    DES_set_random_generator_seed(&new_key);
+
+    /* and use the current time to pick a key for the new sequence. */
+    set_sequence_number((unsigned char *)&now);
+    DES_new_random_key(&new_key);
+    DES_set_random_generator_seed(&new_key);
+}
+
+/* This is for backwards compatibility. */
+void
+DES_random_key(DES_cblock *ret)
+{
+    DES_new_random_key(ret);
+}
+
+#ifdef TESTRUN
+int
+main()
+{
+    unsigned char data[8];
+    int i;
+
+    while (1)
+        {
+           if (sumFile("/dev/mem", (1024*1024*8), data) != 0)
+             { perror("sumFile"); exit(1); }
+            for (i = 0; i < 8; i++)
+                printf("%02x", data[i]);
+            printf("\n");
+        }
+}
+#endif
+
+#ifdef TESTRUN2
+int
+main()
+{
+    DES_cblock data;
+    int i;
+
+    while (1)
+        {
+           do_initialize();
+            DES_random_key(data);
+            for (i = 0; i < 8; i++)
+                printf("%02x", data[i]);
+            printf("\n");
+        }
+}
+#endif
diff --git a/source4/heimdal/lib/des/sha.c b/source4/heimdal/lib/des/sha.c
new file mode 100644 (file)
index 0000000..ca6c1c1
--- /dev/null
@@ -0,0 +1,300 @@
+/*
+ * Copyright (c) 1995 - 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.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+
+RCSID("$Id: sha.c,v 1.18 2005/04/27 11:55:05 lha Exp $");
+#endif
+
+#include "hash.h"
+#include "sha.h"
+
+#define A m->counter[0]
+#define B m->counter[1]
+#define C m->counter[2]
+#define D m->counter[3]
+#define E m->counter[4]
+#define X data
+
+void
+SHA1_Init (struct sha *m)
+{
+  m->sz[0] = 0;
+  m->sz[1] = 0;
+  A = 0x67452301;
+  B = 0xefcdab89;
+  C = 0x98badcfe;
+  D = 0x10325476;
+  E = 0xc3d2e1f0;
+}
+
+
+#define F0(x,y,z) CRAYFIX((x & y) | (~x & z))
+#define F1(x,y,z) (x ^ y ^ z)
+#define F2(x,y,z) ((x & y) | (x & z) | (y & z))
+#define F3(x,y,z) F1(x,y,z)
+
+#define K0 0x5a827999
+#define K1 0x6ed9eba1
+#define K2 0x8f1bbcdc
+#define K3 0xca62c1d6
+
+#define DO(t,f,k) \
+do { \
+  u_int32_t temp; \
+ \
+  temp = cshift(AA, 5) + f(BB,CC,DD) + EE + data[t] + k; \
+  EE = DD; \
+  DD = CC; \
+  CC = cshift(BB, 30); \
+  BB = AA; \
+  AA = temp; \
+} while(0)
+
+static inline void
+calc (struct sha *m, u_int32_t *in)
+{
+  u_int32_t AA, BB, CC, DD, EE;
+  u_int32_t data[80];
+  int i;
+
+  AA = A;
+  BB = B;
+  CC = C;
+  DD = D;
+  EE = E;
+
+  for (i = 0; i < 16; ++i)
+    data[i] = in[i];
+  for (i = 16; i < 80; ++i)
+    data[i] = cshift(data[i-3] ^ data[i-8] ^ data[i-14] ^ data[i-16], 1);
+
+  /* t=[0,19] */
+
+  DO(0,F0,K0);
+  DO(1,F0,K0);
+  DO(2,F0,K0);
+  DO(3,F0,K0);
+  DO(4,F0,K0);
+  DO(5,F0,K0);
+  DO(6,F0,K0);
+  DO(7,F0,K0);
+  DO(8,F0,K0);
+  DO(9,F0,K0);
+  DO(10,F0,K0);
+  DO(11,F0,K0);
+  DO(12,F0,K0);
+  DO(13,F0,K0);
+  DO(14,F0,K0);
+  DO(15,F0,K0);
+  DO(16,F0,K0);
+  DO(17,F0,K0);
+  DO(18,F0,K0);
+  DO(19,F0,K0);
+
+  /* t=[20,39] */
+
+  DO(20,F1,K1);
+  DO(21,F1,K1);
+  DO(22,F1,K1);
+  DO(23,F1,K1);
+  DO(24,F1,K1);
+  DO(25,F1,K1);
+  DO(26,F1,K1);
+  DO(27,F1,K1);
+  DO(28,F1,K1);
+  DO(29,F1,K1);
+  DO(30,F1,K1);
+  DO(31,F1,K1);
+  DO(32,F1,K1);
+  DO(33,F1,K1);
+  DO(34,F1,K1);
+  DO(35,F1,K1);
+  DO(36,F1,K1);
+  DO(37,F1,K1);
+  DO(38,F1,K1);
+  DO(39,F1,K1);
+
+  /* t=[40,59] */
+
+  DO(40,F2,K2);
+  DO(41,F2,K2);
+  DO(42,F2,K2);
+  DO(43,F2,K2);
+  DO(44,F2,K2);
+  DO(45,F2,K2);
+  DO(46,F2,K2);
+  DO(47,F2,K2);
+  DO(48,F2,K2);
+  DO(49,F2,K2);
+  DO(50,F2,K2);
+  DO(51,F2,K2);
+  DO(52,F2,K2);
+  DO(53,F2,K2);
+  DO(54,F2,K2);
+  DO(55,F2,K2);
+  DO(56,F2,K2);
+  DO(57,F2,K2);
+  DO(58,F2,K2);
+  DO(59,F2,K2);
+
+  /* t=[60,79] */
+
+  DO(60,F3,K3);
+  DO(61,F3,K3);
+  DO(62,F3,K3);
+  DO(63,F3,K3);
+  DO(64,F3,K3);
+  DO(65,F3,K3);
+  DO(66,F3,K3);
+  DO(67,F3,K3);
+  DO(68,F3,K3);
+  DO(69,F3,K3);
+  DO(70,F3,K3);
+  DO(71,F3,K3);
+  DO(72,F3,K3);
+  DO(73,F3,K3);
+  DO(74,F3,K3);
+  DO(75,F3,K3);
+  DO(76,F3,K3);
+  DO(77,F3,K3);
+  DO(78,F3,K3);
+  DO(79,F3,K3);
+
+  A += AA;
+  B += BB;
+  C += CC;
+  D += DD;
+  E += EE;
+}
+
+/*
+ * From `Performance analysis of MD5' by Joseph D. Touch <touch@isi.edu>
+ */
+
+#if !defined(WORDS_BIGENDIAN) || defined(_CRAY)
+static inline u_int32_t
+swap_u_int32_t (u_int32_t t)
+{
+#define ROL(x,n) ((x)<<(n))|((x)>>(32-(n)))
+  u_int32_t temp1, temp2;
+
+  temp1   = cshift(t, 16);
+  temp2   = temp1 >> 8;
+  temp1  &= 0x00ff00ff;
+  temp2  &= 0x00ff00ff;
+  temp1 <<= 8;
+  return temp1 | temp2;
+}
+#endif
+
+struct x32{
+  unsigned int a:32;
+  unsigned int b:32;
+};
+
+void
+SHA1_Update (struct sha *m, const void *v, size_t len)
+{
+  const unsigned char *p = v;
+  size_t old_sz = m->sz[0];
+  size_t offset;
+
+  m->sz[0] += len * 8;
+  if (m->sz[0] < old_sz)
+      ++m->sz[1];
+  offset = (old_sz / 8)  % 64;
+  while(len > 0){
+    size_t l = min(len, 64 - offset);
+    memcpy(m->save + offset, p, l);
+    offset += l;
+    p += l;
+    len -= l;
+    if(offset == 64){
+#if !defined(WORDS_BIGENDIAN) || defined(_CRAY)
+      int i;
+      u_int32_t current[16];
+      struct x32 *u = (struct x32*)m->save;
+      for(i = 0; i < 8; i++){
+       current[2*i+0] = swap_u_int32_t(u[i].a);
+       current[2*i+1] = swap_u_int32_t(u[i].b);
+      }
+      calc(m, current);
+#else
+      calc(m, (u_int32_t*)m->save);
+#endif
+      offset = 0;
+    }
+  }
+}
+
+void
+SHA1_Final (void *res, struct sha *m)
+{
+  unsigned char zeros[72];
+  unsigned offset = (m->sz[0] / 8) % 64;
+  unsigned int dstart = (120 - offset - 1) % 64 + 1;
+
+  *zeros = 0x80;
+  memset (zeros + 1, 0, sizeof(zeros) - 1);
+  zeros[dstart+7] = (m->sz[0] >> 0) & 0xff;
+  zeros[dstart+6] = (m->sz[0] >> 8) & 0xff;
+  zeros[dstart+5] = (m->sz[0] >> 16) & 0xff;
+  zeros[dstart+4] = (m->sz[0] >> 24) & 0xff;
+  zeros[dstart+3] = (m->sz[1] >> 0) & 0xff;
+  zeros[dstart+2] = (m->sz[1] >> 8) & 0xff;
+  zeros[dstart+1] = (m->sz[1] >> 16) & 0xff;
+  zeros[dstart+0] = (m->sz[1] >> 24) & 0xff;
+  SHA1_Update (m, zeros, dstart + 8);
+  {
+      int i;
+      unsigned char *r = (unsigned char*)res;
+
+      for (i = 0; i < 5; ++i) {
+         r[4*i+3] = m->counter[i] & 0xFF;
+         r[4*i+2] = (m->counter[i] >> 8) & 0xFF;
+         r[4*i+1] = (m->counter[i] >> 16) & 0xFF;
+         r[4*i]   = (m->counter[i] >> 24) & 0xFF;
+      }
+  }
+#if 0
+  {
+    int i;
+    u_int32_t *r = (u_int32_t *)res;
+
+    for (i = 0; i < 5; ++i)
+      r[i] = swap_u_int32_t (m->counter[i]);
+  }
+#endif
+}
diff --git a/source4/heimdal/lib/des/sha.h b/source4/heimdal/lib/des/sha.h
new file mode 100644 (file)
index 0000000..77d84fb
--- /dev/null
@@ -0,0 +1,51 @@
+/*
+ * Copyright (c) 1995 - 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.
+ */
+
+/* $Id: sha.h,v 1.8 2005/04/10 19:18:13 lha Exp $ */
+
+#ifndef HEIM_SHA_H
+#define HEIM_SHA_H 1
+
+struct sha {
+  unsigned int sz[2];
+  u_int32_t counter[5];
+  unsigned char save[64];
+};
+
+typedef struct sha SHA_CTX;
+
+void SHA1_Init (struct sha *m);
+void SHA1_Update (struct sha *m, const void *v, size_t len);
+void SHA1_Final (void *res, struct sha *m);
+
+#endif /* HEIM_SHA_H */
diff --git a/source4/heimdal/lib/des/ui.c b/source4/heimdal/lib/des/ui.c
new file mode 100644 (file)
index 0000000..9253873
--- /dev/null
@@ -0,0 +1,154 @@
+/*
+ * Copyright (c) 1997 - 2000, 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. 
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+RCSID("$Id: ui.c,v 1.4 2005/04/30 14:10:18 lha Exp $");
+#endif
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <signal.h>
+#include <termios.h>
+#include <roken.h>
+
+#include <des.h>
+
+static sig_atomic_t intr_flag;
+
+static void
+intr(int sig)
+{
+    intr_flag++;
+}
+
+static int
+read_string(const char *preprompt, const char *prompt, 
+           char *buf, size_t len, int echo)
+{
+    struct sigaction sigs[47];
+    struct sigaction sa;
+    FILE *tty;
+    int ret = 0;
+    int of = 0;
+    int i;
+    int c;
+    char *p;
+
+    struct termios t_new, t_old;
+
+    memset(&sa, 0, sizeof(sa));
+    sa.sa_handler = intr;
+    sigemptyset(&sa.sa_mask);
+    sa.sa_flags = 0;
+    for(i = 0; i < sizeof(sigs) / sizeof(sigs[0]); i++)
+       if (i != SIGALRM) sigaction(i, &sa, &sigs[i]);
+
+    if((tty = fopen("/dev/tty", "r")) == NULL)
+       tty = stdin;
+       
+    fprintf(stderr, "%s%s", preprompt, prompt);
+    fflush(stderr);
+
+    if(echo == 0){
+       tcgetattr(fileno(tty), &t_old);
+       memcpy(&t_new, &t_old, sizeof(t_new));
+       t_new.c_lflag &= ~ECHO;
+       tcsetattr(fileno(tty), TCSANOW, &t_new);
+    }
+    intr_flag = 0;
+    p = buf;
+    while(intr_flag == 0){
+       c = getc(tty);
+       if(c == EOF){
+           if(!ferror(tty))
+               ret = 1;
+           break;
+       }
+       if(c == '\n')
+           break;
+       if(of == 0)
+           *p++ = c;
+       of = (p == buf + len);
+    }
+    if(of)
+       p--;
+    *p = 0;
+    
+    if(echo == 0){
+       printf("\n");
+       tcsetattr(fileno(tty), TCSANOW, &t_old);
+    }
+    
+    if(tty != stdin)
+       fclose(tty);
+
+    for(i = 0; i < sizeof(sigs) / sizeof(sigs[0]); i++)
+       if (i != SIGALRM) sigaction(i, &sigs[i], NULL);
+    
+    if(ret)
+       return -3;
+    if(intr_flag)
+       return -2;
+    if(of)
+       return -1;
+    return 0;
+}
+
+int
+UI_UTIL_read_pw_string(char *buf, int length, const char *prompt, int verify)
+{
+    int ret;
+
+    ret = read_string("", prompt, buf, length, 0);
+    if (ret)
+       return ret;
+
+    if (verify) {
+       char *buf2;
+       buf2 = malloc(length);
+       if (buf2 == NULL)
+           return 1;
+
+       ret = read_string("Verify password - ", prompt, buf2, length, 0);
+       if (ret) {
+           free(buf2);
+           return ret;
+       }
+       if (strcmp(buf2, buf) != 0)
+           ret = 1;
+       free(buf2);
+    }
+    return ret;
+}
diff --git a/source4/heimdal/lib/gssapi/8003.c b/source4/heimdal/lib/gssapi/8003.c
new file mode 100644 (file)
index 0000000..b60d260
--- /dev/null
@@ -0,0 +1,246 @@
+/*
+ * 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 "gssapi_locl.h"
+
+RCSID("$Id: 8003.c,v 1.17 2005/04/01 08:55:36 lha Exp $");
+
+krb5_error_code
+gssapi_encode_om_uint32(OM_uint32 n, u_char *p)
+{
+  p[0] = (n >> 0)  & 0xFF;
+  p[1] = (n >> 8)  & 0xFF;
+  p[2] = (n >> 16) & 0xFF;
+  p[3] = (n >> 24) & 0xFF;
+  return 0;
+}
+
+krb5_error_code
+gssapi_encode_be_om_uint32(OM_uint32 n, u_char *p)
+{
+  p[0] = (n >> 24) & 0xFF;
+  p[1] = (n >> 16) & 0xFF;
+  p[2] = (n >> 8)  & 0xFF;
+  p[3] = (n >> 0)  & 0xFF;
+  return 0;
+}
+
+krb5_error_code
+gssapi_decode_om_uint32(u_char *p, OM_uint32 *n)
+{
+    *n = (p[0] << 0) | (p[1] << 8) | (p[2] << 16) | (p[3] << 24);
+    return 0;
+}
+
+krb5_error_code
+gssapi_decode_be_om_uint32(u_char *p, OM_uint32 *n)
+{
+    *n = (p[0] <<24) | (p[1] << 16) | (p[2] << 8) | (p[3] << 0);
+    return 0;
+}
+
+static krb5_error_code
+hash_input_chan_bindings (const gss_channel_bindings_t b,
+                         u_char *p)
+{
+  u_char num[4];
+  MD5_CTX md5;
+
+  MD5_Init(&md5);
+  gssapi_encode_om_uint32 (b->initiator_addrtype, num);
+  MD5_Update (&md5, num, sizeof(num));
+  gssapi_encode_om_uint32 (b->initiator_address.length, num);
+  MD5_Update (&md5, num, sizeof(num));
+  if (b->initiator_address.length)
+    MD5_Update (&md5,
+               b->initiator_address.value,
+               b->initiator_address.length);
+  gssapi_encode_om_uint32 (b->acceptor_addrtype, num);
+  MD5_Update (&md5, num, sizeof(num));
+  gssapi_encode_om_uint32 (b->acceptor_address.length, num);
+  MD5_Update (&md5, num, sizeof(num));
+  if (b->acceptor_address.length)
+    MD5_Update (&md5,
+               b->acceptor_address.value,
+               b->acceptor_address.length);
+  gssapi_encode_om_uint32 (b->application_data.length, num);
+  MD5_Update (&md5, num, sizeof(num));
+  if (b->application_data.length)
+    MD5_Update (&md5,
+               b->application_data.value,
+               b->application_data.length);
+  MD5_Final (p, &md5);
+  return 0;
+}
+
+/*
+ * create a checksum over the chanel bindings in
+ * `input_chan_bindings', `flags' and `fwd_data' and return it in
+ * `result'
+ */
+
+OM_uint32
+gssapi_krb5_create_8003_checksum (
+                     OM_uint32 *minor_status,    
+                     const gss_channel_bindings_t input_chan_bindings,
+                     OM_uint32 flags,
+                     const krb5_data *fwd_data,
+                     Checksum *result)
+{
+    u_char *p;
+
+    /* 
+     * see rfc1964 (section 1.1.1 (Initial Token), and the checksum value 
+     * field's format) */
+    result->cksumtype = CKSUMTYPE_GSSAPI;
+    if (fwd_data->length > 0 && (flags & GSS_C_DELEG_FLAG))
+       result->checksum.length = 24 + 4 + fwd_data->length;
+    else 
+       result->checksum.length = 24;
+    result->checksum.data   = malloc (result->checksum.length);
+    if (result->checksum.data == NULL) {
+       *minor_status = ENOMEM;
+       return GSS_S_FAILURE;
+    }
+  
+    p = result->checksum.data;
+    gssapi_encode_om_uint32 (16, p);
+    p += 4;
+    if (input_chan_bindings == GSS_C_NO_CHANNEL_BINDINGS) {
+       memset (p, 0, 16);
+    } else {
+       hash_input_chan_bindings (input_chan_bindings, p);
+    }
+    p += 16;
+    gssapi_encode_om_uint32 (flags, p);
+    p += 4;
+
+    if (fwd_data->length > 0 && (flags & GSS_C_DELEG_FLAG)) {
+
+       *p++ = (1 >> 0) & 0xFF;                   /* DlgOpt */ /* == 1 */
+       *p++ = (1 >> 8) & 0xFF;                   /* DlgOpt */ /* == 0 */
+       *p++ = (fwd_data->length >> 0) & 0xFF;    /* Dlgth  */
+       *p++ = (fwd_data->length >> 8) & 0xFF;    /* Dlgth  */
+       memcpy(p, (unsigned char *) fwd_data->data, fwd_data->length);
+
+       p += fwd_data->length;
+    }
+     
+    return GSS_S_COMPLETE;
+}
+
+/*
+ * verify the checksum in `cksum' over `input_chan_bindings'
+ * returning  `flags' and `fwd_data'
+ */
+
+OM_uint32
+gssapi_krb5_verify_8003_checksum(
+                     OM_uint32 *minor_status,    
+                     const gss_channel_bindings_t input_chan_bindings,
+                     const Checksum *cksum,
+                     OM_uint32 *flags,
+                     krb5_data *fwd_data)
+{
+    unsigned char hash[16];
+    unsigned char *p;
+    OM_uint32 length;
+    int DlgOpt;
+    static unsigned char zeros[16];
+
+    if (cksum == NULL) {
+       *minor_status = 0;
+       return GSS_S_BAD_BINDINGS;
+    }
+
+    /* XXX should handle checksums > 24 bytes */
+    if(cksum->cksumtype != CKSUMTYPE_GSSAPI || cksum->checksum.length < 24) {
+       *minor_status = 0;
+       return GSS_S_BAD_BINDINGS;
+    }
+    
+    p = cksum->checksum.data;
+    gssapi_decode_om_uint32(p, &length);
+    if(length != sizeof(hash)) {
+       *minor_status = 0;
+       return GSS_S_BAD_BINDINGS;
+    }
+    
+    p += 4;
+    
+    if (input_chan_bindings != GSS_C_NO_CHANNEL_BINDINGS
+       && memcmp(p, zeros, sizeof(zeros)) != 0) {
+       if(hash_input_chan_bindings(input_chan_bindings, hash) != 0) {
+           *minor_status = 0;
+           return GSS_S_BAD_BINDINGS;
+       }
+       if(memcmp(hash, p, sizeof(hash)) != 0) {
+           *minor_status = 0;
+           return GSS_S_BAD_BINDINGS;
+       }
+    }
+    
+    p += sizeof(hash);
+    
+    gssapi_decode_om_uint32(p, flags);
+    p += 4;
+
+    if (cksum->checksum.length > 24 && (*flags & GSS_C_DELEG_FLAG)) {
+       if(cksum->checksum.length < 28) {
+           *minor_status = 0;
+           return GSS_S_BAD_BINDINGS;
+       }
+    
+       DlgOpt = (p[0] << 0) | (p[1] << 8);
+       p += 2;
+       if (DlgOpt != 1) {
+           *minor_status = 0;
+           return GSS_S_BAD_BINDINGS;
+       }
+
+       fwd_data->length = (p[0] << 0) | (p[1] << 8);
+       p += 2;
+       if(cksum->checksum.length < 28 + fwd_data->length) {
+           *minor_status = 0;
+           return GSS_S_BAD_BINDINGS;
+       }
+       fwd_data->data = malloc(fwd_data->length);
+       if (fwd_data->data == NULL) {
+           *minor_status = ENOMEM;
+           return GSS_S_FAILURE;
+       }
+       memcpy(fwd_data->data, p, fwd_data->length);
+    }
+    
+    return GSS_S_COMPLETE;
+}
diff --git a/source4/heimdal/lib/gssapi/accept_sec_context.c b/source4/heimdal/lib/gssapi/accept_sec_context.c
new file mode 100644 (file)
index 0000000..6672f3f
--- /dev/null
@@ -0,0 +1,1118 @@
+/*
+ * 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 "gssapi_locl.h"
+
+RCSID("$Id: accept_sec_context.c,v 1.53 2005/05/29 15:12:41 lha Exp $");
+
+HEIMDAL_MUTEX gssapi_keytab_mutex = HEIMDAL_MUTEX_INITIALIZER;
+krb5_keytab gssapi_krb5_keytab;
+
+OM_uint32
+gsskrb5_register_acceptor_identity (const char *identity)
+{
+    krb5_error_code ret;
+
+    ret = gssapi_krb5_init();
+    if(ret)
+       return GSS_S_FAILURE;
+    
+    HEIMDAL_MUTEX_lock(&gssapi_keytab_mutex);
+
+    if(gssapi_krb5_keytab != NULL) {
+       krb5_kt_close(gssapi_krb5_context, gssapi_krb5_keytab);
+       gssapi_krb5_keytab = NULL;
+    }
+    if (identity == NULL) {
+       ret = krb5_kt_default(gssapi_krb5_context, &gssapi_krb5_keytab);
+    } else {
+       char *p;
+
+       asprintf(&p, "FILE:%s", identity);
+       if(p == NULL) {
+           HEIMDAL_MUTEX_unlock(&gssapi_keytab_mutex);
+           return GSS_S_FAILURE;
+       }
+       ret = krb5_kt_resolve(gssapi_krb5_context, p, &gssapi_krb5_keytab);
+       free(p);
+    }
+    HEIMDAL_MUTEX_unlock(&gssapi_keytab_mutex);
+    if(ret)
+       return GSS_S_FAILURE;
+    return GSS_S_COMPLETE;
+}
+
+void
+gsskrb5_is_cfx(gss_ctx_id_t context_handle, int *is_cfx)
+{
+    krb5_keyblock *key;
+    int acceptor = (context_handle->more_flags & LOCAL) == 0;
+
+    if (acceptor) {
+       if (context_handle->auth_context->local_subkey)
+           key = context_handle->auth_context->local_subkey;
+       else
+           key = context_handle->auth_context->remote_subkey;
+    } else {
+       if (context_handle->auth_context->remote_subkey)
+           key = context_handle->auth_context->remote_subkey;
+       else
+           key = context_handle->auth_context->local_subkey;
+    }
+    if (key == NULL)
+       key = context_handle->auth_context->keyblock;
+
+    if (key == NULL)
+       return;
+           
+    switch (key->keytype) {
+    case ETYPE_DES_CBC_CRC:
+    case ETYPE_DES_CBC_MD4:
+    case ETYPE_DES_CBC_MD5:
+    case ETYPE_DES3_CBC_MD5:
+    case ETYPE_DES3_CBC_SHA1:
+    case ETYPE_ARCFOUR_HMAC_MD5:
+    case ETYPE_ARCFOUR_HMAC_MD5_56:
+       break;
+    default :
+       *is_cfx = 1;
+       if ((acceptor && context_handle->auth_context->local_subkey) ||
+           (!acceptor && context_handle->auth_context->remote_subkey))
+           context_handle->more_flags |= ACCEPTOR_SUBKEY;
+       break;
+    }
+}
+
+
+static OM_uint32
+gsskrb5_accept_delegated_token
+           (OM_uint32 * minor_status,
+            gss_ctx_id_t * context_handle,
+            gss_cred_id_t * delegated_cred_handle)
+{
+    krb5_data *fwd_data = &(*context_handle)->fwd_data;
+    OM_uint32 *flags = &(*context_handle)->flags;
+    krb5_principal principal = (*context_handle)->source;
+    krb5_ccache ccache = NULL;
+    krb5_error_code kret;
+    int32_t ac_flags, ret;
+    gss_cred_id_t handle = NULL;
+      
+    if (delegated_cred_handle == NULL) {
+       /* XXX Create a new delegated_cred_handle? */
+
+       ret = 0;
+
+       kret = krb5_cc_default (gssapi_krb5_context, &ccache);
+       if (kret) {
+           *flags &= ~GSS_C_DELEG_FLAG;
+           goto end_fwd;
+       }
+    } else {
+
+       *delegated_cred_handle = NULL;
+       
+       handle = calloc(1, sizeof(*handle));
+       if (handle == NULL) {
+           ret = GSS_S_FAILURE;
+           *minor_status = ENOMEM;
+           krb5_set_error_string(gssapi_krb5_context, "out of memory");
+           gssapi_krb5_set_error_string();
+           *flags &= ~GSS_C_DELEG_FLAG;
+           goto end_fwd;
+       }
+       if ((ret = gss_duplicate_name(minor_status, principal,
+                                     &handle->principal)) != 0) {
+           *flags &= ~GSS_C_DELEG_FLAG;
+           ret = 0;
+           goto end_fwd;
+       }
+       kret = krb5_cc_gen_new (gssapi_krb5_context,
+                               &krb5_mcc_ops,
+                               &handle->ccache);
+       if (kret) {
+           *flags &= ~GSS_C_DELEG_FLAG;
+           ret = 0;
+           goto end_fwd;
+       }
+       ccache = handle->ccache;
+
+       ret = gss_create_empty_oid_set(minor_status, &handle->mechanisms);
+       if (ret) {
+           *flags &= ~GSS_C_DELEG_FLAG;
+           goto end_fwd;
+       }
+       ret = gss_add_oid_set_member(minor_status, GSS_KRB5_MECHANISM,
+                                    &handle->mechanisms);
+       if (ret) {
+           *flags &= ~GSS_C_DELEG_FLAG;
+           goto end_fwd;
+       }
+    }
+
+    kret = krb5_cc_initialize(gssapi_krb5_context, ccache, principal);
+    if (kret) {
+       *flags &= ~GSS_C_DELEG_FLAG;
+       ret = 0;
+       goto end_fwd;
+    }
+      
+    krb5_auth_con_removeflags(gssapi_krb5_context,
+                             (*context_handle)->auth_context,
+                             KRB5_AUTH_CONTEXT_DO_TIME,
+                             &ac_flags);
+    kret = krb5_rd_cred2(gssapi_krb5_context,
+                        (*context_handle)->auth_context,
+                        ccache,
+                        fwd_data);
+    if (kret)
+       gssapi_krb5_set_error_string();
+    krb5_auth_con_setflags(gssapi_krb5_context,
+                          (*context_handle)->auth_context,
+                          ac_flags);
+    if (kret) {
+       *flags &= ~GSS_C_DELEG_FLAG;
+       ret = GSS_S_FAILURE;
+       *minor_status = kret;
+       goto end_fwd;
+    }
+ end_fwd:
+    /* if there was some kind of failure, clean up internal structures */
+    if ((*flags & GSS_C_DELEG_FLAG) == 0) {
+       if (handle) {
+           if (handle->principal)
+               gss_release_name(minor_status, &handle->principal);
+           if (handle->mechanisms)
+               gss_release_oid_set(NULL, &handle->mechanisms);
+           if (handle->ccache)
+               krb5_cc_destroy(gssapi_krb5_context, handle->ccache);
+           free(handle);
+           handle = NULL;
+       }
+    }
+    if (delegated_cred_handle == NULL) {
+       if (ccache)
+           krb5_cc_close(gssapi_krb5_context, ccache);
+    }
+    if (handle)
+       *delegated_cred_handle = handle;
+
+    return ret;
+}
+
+static OM_uint32
+gsskrb5_acceptor_ready(
+       OM_uint32 * minor_status,
+       gss_ctx_id_t * context_handle,
+       gss_cred_id_t * delegated_cred_handle)
+{
+       OM_uint32 ret;
+       int32_t seq_number;
+       int is_cfx = 0;
+       u_int32_t flags = (*context_handle)->flags;
+
+       krb5_auth_getremoteseqnumber (gssapi_krb5_context,
+                                     (*context_handle)->auth_context,
+                                     &seq_number);
+
+       gsskrb5_is_cfx(*context_handle, &is_cfx);
+
+       ret = _gssapi_msg_order_create(minor_status,
+                                      &(*context_handle)->order,
+                                      _gssapi_msg_order_f(flags),
+                                      seq_number, 0, is_cfx);
+       if (ret) return ret;
+
+       if (!(flags & GSS_C_MUTUAL_FLAG) && _gssapi_msg_order_f(flags)) {
+               krb5_auth_con_setlocalseqnumber(gssapi_krb5_context,
+                                               (*context_handle)->auth_context,
+                                               seq_number);
+       }
+
+       /*
+        * We should handle the delegation ticket, in case it's there
+        */
+       if ((*context_handle)->fwd_data.length > 0 && (flags & GSS_C_DELEG_FLAG)) {
+               ret = gsskrb5_accept_delegated_token(minor_status,
+                                                    context_handle,
+                                                    delegated_cred_handle);
+               if (ret) return ret;
+       }
+
+       (*context_handle)->state        = ACCEPTOR_READY;
+       (*context_handle)->more_flags   |= OPEN;
+
+       return GSS_S_COMPLETE;
+}
+
+static OM_uint32
+gsskrb5_acceptor_start(
+       OM_uint32 * minor_status,
+       gss_ctx_id_t * context_handle,
+       const gss_cred_id_t acceptor_cred_handle,
+       const gss_buffer_t input_token,
+       const gss_channel_bindings_t input_chan_bindings,
+       gss_name_t * src_name,
+       gss_OID * mech_type,
+       gss_buffer_t output_token,
+       OM_uint32 * ret_flags,
+       OM_uint32 * time_rec,
+       gss_cred_id_t * delegated_cred_handle)
+{
+       krb5_error_code kret;
+       OM_uint32 ret = GSS_S_COMPLETE;
+       krb5_data indata;
+       krb5_flags ap_options;
+       OM_uint32 flags;
+       krb5_ticket *ticket = NULL;
+       krb5_keytab keytab = NULL;
+       krb5_keyblock *keyblock = NULL;
+       int no_wrap = 0;
+
+       /*
+        * TODO: check the channel_bindings
+        */
+
+       /*
+        * We need a sequence number
+        */
+       krb5_auth_con_addflags(gssapi_krb5_context,
+                              (*context_handle)->auth_context,
+                              KRB5_AUTH_CONTEXT_DO_SEQUENCE,
+                              NULL);
+
+       /*
+        * We need remove the decapsulate only when GSS_C_DCE_STYLE isn't in use
+        */
+       ret = gssapi_krb5_decapsulate(minor_status,
+                                     input_token,&indata,
+                                     "\x01\x00",
+                                     GSS_KRB5_MECHANISM);
+       if (ret) {
+               /* No OID wrapping apparently available. */
+               no_wrap         = 1;
+               indata.length   = input_token->length;
+               indata.data     = input_token->value;
+       }
+
+       /*
+        * We need to get our keytab
+        */
+       if (acceptor_cred_handle == GSS_C_NO_CREDENTIAL) {
+               if (gssapi_krb5_keytab != NULL) {
+                       keytab = gssapi_krb5_keytab;
+               }
+       } else {
+               keytab = acceptor_cred_handle->keytab;
+       }
+
+       /*
+        * We need to check the ticket and create the AP-REP packet
+        */
+       kret = krb5_rd_req_return_keyblock(gssapi_krb5_context,
+                                          &(*context_handle)->auth_context,
+                                          &indata,
+                                          (acceptor_cred_handle == GSS_C_NO_CREDENTIAL) ? NULL : acceptor_cred_handle->principal,
+                                          keytab,
+                                          &ap_options,
+                                          &ticket,
+                                          &keyblock);
+       if (kret) {
+               *minor_status = kret;
+               gssapi_krb5_set_error_string ();
+               return GSS_S_FAILURE;
+       }
+
+       /*
+        * We need to remember some data on the context_handle
+        */
+       (*context_handle)->ticket = ticket;
+       (*context_handle)->service_keyblock = keyblock;
+       (*context_handle)->lifetime = ticket->ticket.endtime;
+
+       /*
+        * We need to copy the principal names to the context and the calling layer
+        */
+       kret = krb5_copy_principal(gssapi_krb5_context,
+                                  ticket->client,
+                                  &(*context_handle)->source);
+       if (kret) {
+               *minor_status = kret;
+               gssapi_krb5_set_error_string ();
+               return GSS_S_FAILURE;
+       }
+
+       kret = krb5_copy_principal(gssapi_krb5_context,
+                                  ticket->server,
+                                  &(*context_handle)->target);
+       if (kret) {
+               *minor_status = kret;
+               gssapi_krb5_set_error_string ();
+               return GSS_S_FAILURE;
+       }
+
+       /*
+        * We need to setup some compat stuff, this assumes that context_handle->target is already set
+        */
+       ret = _gss_DES3_get_mic_compat(minor_status, *context_handle);
+       if (ret) return ret;
+
+       /*
+        * We need to get the flags out of the 8003 checksum
+        */
+       {
+               krb5_authenticator authenticator;
+
+               kret = krb5_auth_con_getauthenticator(gssapi_krb5_context,
+                                             (*context_handle)->auth_context,
+                                             &authenticator);
+               if (kret) {
+                       *minor_status = kret;
+                       gssapi_krb5_set_error_string ();
+                       return GSS_S_FAILURE;
+               }
+
+               ret = gssapi_krb5_verify_8003_checksum(minor_status,
+                                                      input_chan_bindings,
+                                                      authenticator->cksum,
+                                                      &flags,
+                                                      &(*context_handle)->fwd_data);
+               krb5_free_authenticator(gssapi_krb5_context, &authenticator);
+               if (ret) return ret;
+       }
+
+       /* And remember them for later */
+       (*context_handle)->flags = flags;
+
+       if(flags & GSS_C_MUTUAL_FLAG) {
+               int is_cfx = 0;
+               krb5_data outbuf;
+
+               gsskrb5_is_cfx(*context_handle, &is_cfx);
+
+               if (is_cfx || (ap_options & AP_OPTS_USE_SUBKEY)) {
+                       kret = krb5_auth_con_addflags(gssapi_krb5_context,
+                                             (*context_handle)->auth_context,
+                                             KRB5_AUTH_CONTEXT_USE_SUBKEY,
+                                             NULL);
+                       (*context_handle)->more_flags |= ACCEPTOR_SUBKEY;
+               }
+
+               kret = krb5_mk_rep(gssapi_krb5_context,
+                                  (*context_handle)->auth_context,
+                                  &outbuf);
+               if (kret) {
+                       *minor_status = kret;
+                       gssapi_krb5_set_error_string ();
+                       return GSS_S_FAILURE;
+               }
+
+               if (!(flags & GSS_C_DCE_STYLE)) {
+                       ret = gssapi_krb5_encapsulate(minor_status,
+                                                     &outbuf,
+                                                     output_token,
+                                                     "\x02\x00",
+                                                     GSS_KRB5_MECHANISM);
+                       krb5_data_free (&outbuf);
+                       if (ret) return ret;
+               } else {
+                       output_token->length    = outbuf.length;
+                       output_token->value     = outbuf.data;
+               }
+       }
+
+       /*
+        * We need to set the return value for the calling layer
+        */
+       if (ret_flags) *ret_flags = flags;
+
+       if (time_rec) {
+               ret = gssapi_lifetime_left(minor_status,
+                                          (*context_handle)->lifetime,
+                                          time_rec);
+               if (ret) return ret;
+       }
+
+       if (src_name) {
+               kret = krb5_copy_principal(gssapi_krb5_context,
+                                          (*context_handle)->source,
+                                          src_name);
+               if (kret) {
+                       *minor_status = kret;
+                       gssapi_krb5_set_error_string ();
+                       return GSS_S_FAILURE;
+               }
+       }
+
+       /*
+        * When GSS_C_DCE_STYLE is in use, we need ask for a AP-REP from the client
+        */
+       if (flags & GSS_C_DCE_STYLE) {
+               (*context_handle)->state = ACCEPTOR_WAIT_FOR_DCESTYLE;
+               return GSS_S_CONTINUE_NEEDED;
+       }
+
+       return gsskrb5_acceptor_ready(minor_status, context_handle, delegated_cred_handle);
+}
+
+static OM_uint32
+gsskrb5_acceptor_wait_for_dcestyle(
+       OM_uint32 * minor_status,
+       gss_ctx_id_t * context_handle,
+       const gss_cred_id_t acceptor_cred_handle,
+       const gss_buffer_t input_token,
+       const gss_channel_bindings_t input_chan_bindings,
+       gss_name_t * src_name,
+       gss_OID * mech_type,
+       gss_buffer_t output_token,
+       OM_uint32 * ret_flags,
+       OM_uint32 * time_rec,
+       gss_cred_id_t * delegated_cred_handle)
+{
+       OM_uint32 ret;
+       krb5_error_code kret;
+       krb5_data inbuf;
+       OM_uint32 r_seq_number;
+       OM_uint32 l_seq_number;
+       
+       /* We know it's GSS_C_DCE_STYLE so we don't need to decapsulate the AP_REP */
+       inbuf.length    = input_token->length;
+       inbuf.data      = input_token->value;
+
+       /* 
+        * We need to remeber the old remote seq_number, then check if the client has replied with our local seq_number,
+        * and then reset the remote seq_number to the old value 
+        */
+       {
+               kret = krb5_auth_con_getlocalseqnumber(gssapi_krb5_context,
+                                                   (*context_handle)->auth_context,
+                                                   &l_seq_number);
+               if (kret) {
+                       gssapi_krb5_set_error_string ();
+                       *minor_status = kret;
+                       return GSS_S_FAILURE;
+               }
+
+               kret = krb5_auth_getremoteseqnumber(gssapi_krb5_context,
+                                                   (*context_handle)->auth_context,
+                                                   &r_seq_number);
+               if (kret) {
+                       gssapi_krb5_set_error_string ();
+                       *minor_status = kret;
+                       return GSS_S_FAILURE;
+               }
+
+               kret = krb5_auth_con_setremoteseqnumber(gssapi_krb5_context,
+                                                   (*context_handle)->auth_context,
+                                                   l_seq_number);
+               if (kret) {
+                       gssapi_krb5_set_error_string ();
+                       *minor_status = kret;
+                       return GSS_S_FAILURE;
+               }
+       }
+
+       /* We need to verify the AP_REP, but we need to flag that this
+          is DCE_STYLE, so don't check the timestamps this time 
+       */ 
+       {
+               krb5_ap_rep_enc_part *repl;
+
+               kret = _krb5_rd_rep_type(gssapi_krb5_context,
+                                        (*context_handle)->auth_context,
+                                        &inbuf,
+                                        &repl,
+                                        TRUE);
+               if (kret) {
+                       gssapi_krb5_set_error_string ();
+                       *minor_status = kret;
+                       return GSS_S_FAILURE;
+               }
+               krb5_free_ap_rep_enc_part(gssapi_krb5_context, repl);
+       }
+
+       /* We need to check the liftime */
+       {
+               OM_uint32 lifetime_rec;
+
+               ret = gssapi_lifetime_left(minor_status,
+                                          (*context_handle)->lifetime,
+                                          &lifetime_rec);
+               if (ret) return ret;
+
+               if (lifetime_rec == 0) {
+                       return GSS_S_CONTEXT_EXPIRED;
+               }
+       
+               if (time_rec) *time_rec = lifetime_rec;
+       }
+
+       /* We need to give the caller the flags which are in use */
+       if (ret_flags) *ret_flags = (*context_handle)->flags;
+
+       if (src_name) {
+               kret = krb5_copy_principal(gssapi_krb5_context,
+                                          (*context_handle)->source,
+                                          src_name);
+               if (kret) {
+                       *minor_status = kret;
+                       gssapi_krb5_set_error_string ();
+                       return GSS_S_FAILURE;
+               }
+       }
+
+       /*
+        * After the krb5_rd_rep() the remote and local seq_number should be the same,
+        * because the client just replies the seq_number from our AP-REP in its AP-REP,
+        * but then the client uses the seq_number from its AP-REQ for GSS_wrap()
+        */
+       {
+               OM_uint32 tmp_r_seq_number;
+               OM_uint32 l_seq_number;
+
+               kret = krb5_auth_getremoteseqnumber(gssapi_krb5_context,
+                                                   (*context_handle)->auth_context,
+                                                   &tmp_r_seq_number);
+               if (kret) {
+                       gssapi_krb5_set_error_string ();
+                       *minor_status = kret;
+                       return GSS_S_FAILURE;
+               }
+
+               kret = krb5_auth_con_getlocalseqnumber(gssapi_krb5_context,
+                                                   (*context_handle)->auth_context,
+                                                   &l_seq_number);
+               if (kret) {
+                       gssapi_krb5_set_error_string ();
+                       *minor_status = kret;
+                       return GSS_S_FAILURE;
+               }
+
+               /*
+                * Here we check if the client has responsed with our local seq_number,
+                */
+               if (tmp_r_seq_number != l_seq_number) {
+                       return GSS_S_UNSEQ_TOKEN;
+               }
+       }
+
+       /*
+        * We need to reset the remote seq_number, because the client will use,
+        * the old one for the GSS_wrap() calls
+        */
+       {
+               kret = krb5_auth_con_setremoteseqnumber(gssapi_krb5_context,
+                                                      (*context_handle)->auth_context,
+                                                      r_seq_number);   
+               if (kret) {
+                       gssapi_krb5_set_error_string ();
+                       *minor_status = kret;
+                       return GSS_S_FAILURE;
+               }
+       }
+
+       return gsskrb5_acceptor_ready(minor_status, context_handle, delegated_cred_handle);
+}
+
+static OM_uint32
+gsskrb5_accept_sec_context(
+       OM_uint32 * minor_status,
+       gss_ctx_id_t * context_handle,
+       const gss_cred_id_t acceptor_cred_handle,
+       const gss_buffer_t input_token,
+       const gss_channel_bindings_t input_chan_bindings,
+       gss_name_t * src_name,
+       gss_OID * actual_mech_type,
+       gss_buffer_t output_token,
+       OM_uint32 * ret_flags,
+       OM_uint32 * time_rec,
+       gss_cred_id_t * delegated_cred_handle)
+{
+       OM_uint32 ret;
+
+       if (*context_handle == GSS_C_NO_CONTEXT) {
+               ret = _gsskrb5_create_ctx(minor_status,
+                                         context_handle,
+                                         input_chan_bindings,
+                                         ACCEPTOR_START);
+               if (ret) return ret;
+       }
+
+       if (actual_mech_type) *actual_mech_type = GSS_KRB5_MECHANISM;
+
+       HEIMDAL_MUTEX_lock(&(*context_handle)->ctx_id_mutex);
+
+       switch ((*context_handle)->state) {
+       case ACCEPTOR_START:
+               ret = gsskrb5_acceptor_start(minor_status,
+                                            context_handle,
+                                            acceptor_cred_handle,
+                                            input_token,
+                                            input_chan_bindings,
+                                            src_name,
+                                            actual_mech_type,
+                                            output_token,
+                                            ret_flags,
+                                            time_rec,
+                                            delegated_cred_handle);
+               break;
+       case ACCEPTOR_WAIT_FOR_DCESTYLE:
+               ret = gsskrb5_acceptor_wait_for_dcestyle(minor_status,
+                                                        context_handle,
+                                                        acceptor_cred_handle,
+                                                        input_token,
+                                                        input_chan_bindings,
+                                                        src_name,
+                                                        actual_mech_type,
+                                                        output_token,
+                                                        ret_flags,
+                                                        time_rec,
+                                                        delegated_cred_handle);
+               break;
+       case ACCEPTOR_READY:
+               /* this function should not be called after it has returned GSS_S_COMPLETE */
+               ret =  GSS_S_BAD_STATUS;
+               break;
+       default:
+               /* TODO: is this correct here? --metze */
+               ret =  GSS_S_BAD_STATUS;
+               break;
+       }
+
+       HEIMDAL_MUTEX_unlock(&(*context_handle)->ctx_id_mutex);
+
+       return ret;
+}
+
+static OM_uint32
+code_NegTokenArg(OM_uint32 *minor_status,
+                const NegTokenTarg *targ,
+                krb5_data *data,
+                u_char **ret_buf)
+{
+    OM_uint32 ret;
+    u_char *buf;
+    size_t buf_size, buf_len;
+
+    buf_size = 1024;
+    buf = malloc(buf_size);
+    if (buf == NULL) {
+       *minor_status = ENOMEM;
+       return GSS_S_FAILURE;
+    }
+
+    do {
+       ret = encode_NegTokenTarg(buf + buf_size - 1,
+                                 buf_size,
+                                 targ, &buf_len);
+       if (ret == 0) {
+           size_t tmp;
+
+           ret = der_put_length_and_tag(buf + buf_size - buf_len - 1,
+                                        buf_size - buf_len,
+                                        buf_len,
+                                        ASN1_C_CONTEXT,
+                                        CONS,
+                                        1,
+                                        &tmp);
+           if (ret == 0)
+               buf_len += tmp;
+       }
+       if (ret) {
+           if (ret == ASN1_OVERFLOW) {
+               u_char *tmp;
+
+               buf_size *= 2;
+               tmp = realloc (buf, buf_size);
+               if (tmp == NULL) {
+                   *minor_status = ENOMEM;
+                   free(buf);
+                   return GSS_S_FAILURE;
+               }
+               buf = tmp;
+           } else {
+               *minor_status = ret;
+               free(buf);
+               return GSS_S_FAILURE;
+           }
+       }
+    } while (ret == ASN1_OVERFLOW);
+
+    data->data   = buf + buf_size - buf_len;
+    data->length = buf_len;
+    *ret_buf     = buf;
+    return GSS_S_COMPLETE;
+}
+
+static OM_uint32
+send_reject (OM_uint32 *minor_status,
+            gss_buffer_t output_token)
+{
+    NegTokenTarg targ;
+    krb5_data data;
+    u_char *buf;
+    OM_uint32 ret;
+
+    ALLOC(targ.negResult, 1);
+    if (targ.negResult == NULL) {
+       *minor_status = ENOMEM;
+       return GSS_S_FAILURE;
+    }
+    *(targ.negResult) = reject;
+    targ.supportedMech = NULL;
+    targ.responseToken = NULL;
+    targ.mechListMIC   = NULL;
+    
+    ret = code_NegTokenArg (minor_status, &targ, &data, &buf);
+    free_NegTokenTarg(&targ);
+    if (ret)
+       return ret;
+
+#if 0
+    ret = _gssapi_encapsulate(minor_status,
+                             &data,
+                             output_token,
+                             GSS_SPNEGO_MECHANISM);
+#else
+    output_token->value = malloc(data.length);
+    if (output_token->value == NULL) {
+       *minor_status = ENOMEM;
+       ret = GSS_S_FAILURE;
+    } else {
+       output_token->length = data.length;
+       memcpy(output_token->value, data.data, output_token->length);
+    }
+#endif
+    free(buf);
+    if (ret)
+       return ret;
+    return GSS_S_BAD_MECH;
+}
+
+static OM_uint32
+send_accept (OM_uint32 *minor_status,
+            OM_uint32 major_status,
+            gss_buffer_t output_token,
+            gss_buffer_t mech_token,
+            gss_ctx_id_t context_handle,
+            const MechTypeList *mechtypelist)
+{
+    NegTokenTarg targ;
+    krb5_data data;
+    u_char *buf;
+    OM_uint32 ret;
+    gss_buffer_desc mech_buf, mech_mic_buf;
+    krb5_boolean require_mic;
+
+    memset(&targ, 0, sizeof(targ));
+    ALLOC(targ.negResult, 1);
+    if (targ.negResult == NULL) {
+       *minor_status = ENOMEM;
+       return GSS_S_FAILURE;
+    }
+    *(targ.negResult) = accept_completed;
+
+    ALLOC(targ.supportedMech, 1);
+    if (targ.supportedMech == NULL) {
+       free_NegTokenTarg(&targ);
+       *minor_status = ENOMEM;
+       return GSS_S_FAILURE;
+    }
+
+    ret = der_get_oid(GSS_KRB5_MECHANISM->elements,
+                     GSS_KRB5_MECHANISM->length,
+                     targ.supportedMech,
+                     NULL);
+    if (ret) {
+       free_NegTokenTarg(&targ);
+       *minor_status = ENOMEM;
+       return GSS_S_FAILURE;
+    }
+
+    if (mech_token != NULL && mech_token->length != 0) {
+       ALLOC(targ.responseToken, 1);
+       if (targ.responseToken == NULL) {
+           free_NegTokenTarg(&targ);
+           *minor_status = ENOMEM;
+           return GSS_S_FAILURE;
+       }
+       targ.responseToken->length = mech_token->length;
+       targ.responseToken->data   = mech_token->value;
+       mech_token->length = 0;
+       mech_token->value  = NULL;
+    } else {
+       targ.responseToken = NULL;
+    }
+
+    ret = _gss_spnego_require_mechlist_mic(minor_status, context_handle,
+                                          &require_mic);
+    if (ret) {
+       free_NegTokenTarg(&targ);
+       return ret;
+    }
+
+    if (major_status == GSS_S_COMPLETE && require_mic) {
+       size_t buf_len;
+
+       ALLOC(targ.mechListMIC, 1);
+       if (targ.mechListMIC == NULL) {
+           free_NegTokenTarg(&targ);
+           *minor_status = ENOMEM;
+           return GSS_S_FAILURE;
+       }
+       
+       ASN1_MALLOC_ENCODE(MechTypeList, mech_buf.value, mech_buf.length,
+                          mechtypelist, &buf_len, ret);
+       if (ret) {
+           free_NegTokenTarg(&targ);
+           return ret;
+       }
+       if (mech_buf.length != buf_len)
+           abort();
+
+       ret = gss_get_mic(minor_status, context_handle, 0, &mech_buf,
+                         &mech_mic_buf);
+       free (mech_buf.value);
+       if (ret) {
+           free_NegTokenTarg(&targ);
+           return ret;
+       }
+
+       targ.mechListMIC->length = mech_mic_buf.length;
+       targ.mechListMIC->data   = mech_mic_buf.value;
+    } else
+       targ.mechListMIC = NULL;
+
+    ret = code_NegTokenArg (minor_status, &targ, &data, &buf);
+    free_NegTokenTarg(&targ);
+    if (ret)
+       return ret;
+
+#if 0
+    ret = _gssapi_encapsulate(minor_status,
+                             &data,
+                             output_token,
+                             GSS_SPNEGO_MECHANISM);
+#else
+    output_token->value = malloc(data.length);
+    if (output_token->value == NULL) {
+       *minor_status = ENOMEM;
+       ret = GSS_S_FAILURE;
+    } else {
+       output_token->length = data.length;
+       memcpy(output_token->value, data.data, output_token->length);
+    }
+#endif
+    free(buf);
+    if (ret)
+       return ret;
+    return GSS_S_COMPLETE;
+}
+
+static OM_uint32
+spnego_accept_sec_context
+           (OM_uint32 * minor_status,
+            gss_ctx_id_t * context_handle,
+            const gss_cred_id_t acceptor_cred_handle,
+            const gss_buffer_t input_token_buffer,
+            const gss_channel_bindings_t input_chan_bindings,
+            gss_name_t * src_name,
+            gss_OID * mech_type,
+            gss_buffer_t output_token,
+            OM_uint32 * ret_flags,
+            OM_uint32 * time_rec,
+            gss_cred_id_t * delegated_cred_handle
+           )
+{
+    OM_uint32 ret, ret2;
+    NegTokenInit ni;
+    size_t ni_len;
+    int i;
+    int found = 0;
+    krb5_data data;
+    size_t len, taglen;
+
+    output_token->length = 0;
+    output_token->value  = NULL;
+
+    ret = _gssapi_decapsulate (minor_status,
+                              input_token_buffer,
+                              &data,
+                              GSS_SPNEGO_MECHANISM);
+    if (ret)
+       return ret;
+
+    ret = der_match_tag_and_length(data.data, data.length,
+                                  ASN1_C_CONTEXT, CONS, 0, &len, &taglen);
+    if (ret)
+       return ret;
+
+    if(len > data.length - taglen)
+       return ASN1_OVERRUN;
+
+    ret = decode_NegTokenInit((const char *)data.data + taglen, len,
+                             &ni, &ni_len);
+    if (ret)
+       return GSS_S_DEFECTIVE_TOKEN;
+
+    if (ni.mechTypes == NULL) {
+       free_NegTokenInit(&ni);
+       return send_reject (minor_status, output_token);
+    }
+
+    for (i = 0; !found && i < ni.mechTypes->len; ++i) {
+       char mechbuf[17];
+       size_t mech_len;
+
+       ret = der_put_oid (mechbuf + sizeof(mechbuf) - 1,
+                          sizeof(mechbuf),
+                          &ni.mechTypes->val[i],
+                          &mech_len);
+       if (ret) {
+           free_NegTokenInit(&ni);
+           return GSS_S_DEFECTIVE_TOKEN;
+       }
+       if (mech_len == GSS_KRB5_MECHANISM->length
+           && memcmp(GSS_KRB5_MECHANISM->elements,
+                     mechbuf + sizeof(mechbuf) - mech_len,
+                     mech_len) == 0)
+           found = 1;
+    }
+    if (found) {
+       gss_buffer_desc ibuf, obuf;
+       gss_buffer_t ot = NULL;
+       OM_uint32 minor;
+
+       if (ni.mechToken != NULL) {
+           ibuf.length = ni.mechToken->length;
+           ibuf.value  = ni.mechToken->data;
+
+           ret = gsskrb5_accept_sec_context(&minor,
+                                            context_handle,
+                                            acceptor_cred_handle,
+                                            &ibuf,
+                                            input_chan_bindings,
+                                            src_name,
+                                            mech_type,
+                                            &obuf,
+                                            ret_flags,
+                                            time_rec,
+                                            delegated_cred_handle);
+           if (ret == GSS_S_COMPLETE || ret == GSS_S_CONTINUE_NEEDED) {
+               ot = &obuf;
+           } else {
+               free_NegTokenInit(&ni);
+               send_reject (minor_status, output_token);
+               return ret;
+           }
+       }
+       ret2 = send_accept (minor_status, ret, output_token, ot,
+                          *context_handle, ni.mechTypes);
+       if (ret2 != GSS_S_COMPLETE)
+           ret = ret2;
+       if (ot != NULL)
+           gss_release_buffer(&minor, ot);
+       free_NegTokenInit(&ni);
+       return ret;
+    } else {
+       free_NegTokenInit(&ni);
+       return send_reject (minor_status, output_token);
+    }
+}
+
+OM_uint32
+gss_accept_sec_context(
+       OM_uint32 * minor_status,
+       gss_ctx_id_t * context_handle,
+       const gss_cred_id_t acceptor_cred_handle,
+       const gss_buffer_t input_token,
+       const gss_channel_bindings_t input_chan_bindings,
+       gss_name_t * src_name,
+       gss_OID * actual_mech_type,
+       gss_buffer_t output_token,
+       OM_uint32 * ret_flags,
+       OM_uint32 * time_rec,
+       gss_cred_id_t * delegated_cred_handle)
+{
+       ssize_t mech_len;
+       const u_char *p;
+
+       GSSAPI_KRB5_INIT ();
+
+       *minor_status = 0;
+
+       if (src_name)                   *src_name               = GSS_C_NO_NAME;
+       if (actual_mech_type)           *actual_mech_type       = GSS_C_NO_OID;
+
+       output_token->length = 0;
+       output_token->value  = NULL;
+
+       if (ret_flags)                  *ret_flags              = 0;
+       if (time_rec)                   *time_rec               = 0;
+       if (delegated_cred_handle)      *delegated_cred_handle  = NULL;
+
+       mech_len = gssapi_krb5_get_mech(input_token->value,
+                                       input_token->length,
+                                       &p);
+
+       /* This could be 'dce style' kerberos, where the OID is missing :-( */
+       if ((mech_len < 0) || (mech_len == GSS_KRB5_MECHANISM->length 
+                              && memcmp(p, GSS_KRB5_MECHANISM->elements, mech_len) == 0)) {
+               return gsskrb5_accept_sec_context(minor_status,
+                                                 context_handle,
+                                                 acceptor_cred_handle,
+                                                 input_token,
+                                                 input_chan_bindings,
+                                                 src_name,
+                                                 actual_mech_type,
+                                                 output_token,
+                                                 ret_flags,
+                                                 time_rec,
+                                                 delegated_cred_handle);
+       } else if (mech_len == GSS_SPNEGO_MECHANISM->length
+            && memcmp(p, GSS_SPNEGO_MECHANISM->elements, mech_len) == 0) {
+               return spnego_accept_sec_context(minor_status,
+                                                context_handle,
+                                                acceptor_cred_handle,
+                                                input_token,
+                                                input_chan_bindings,
+                                                src_name,
+                                                actual_mech_type,
+                                                output_token,
+                                                ret_flags,
+                                                time_rec,
+                                                delegated_cred_handle);
+       }
+
+       return GSS_S_BAD_MECH;
+}
diff --git a/source4/heimdal/lib/gssapi/acquire_cred.c b/source4/heimdal/lib/gssapi/acquire_cred.c
new file mode 100644 (file)
index 0000000..6ded413
--- /dev/null
@@ -0,0 +1,376 @@
+/*
+ * 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 "gssapi_locl.h"
+
+RCSID("$Id: acquire_cred.c,v 1.22 2005/01/05 02:32:26 lukeh Exp $");
+
+static krb5_error_code
+get_keytab(krb5_context context, krb5_keytab *keytab)
+{
+    char kt_name[256];
+    krb5_error_code kret;
+
+    HEIMDAL_MUTEX_lock(&gssapi_keytab_mutex);
+
+    if (gssapi_krb5_keytab != NULL) {
+       kret = krb5_kt_get_name(context,
+                               gssapi_krb5_keytab,
+                               kt_name, sizeof(kt_name));
+       if (kret == 0)
+           kret = krb5_kt_resolve(context, kt_name, keytab);
+    } else
+       kret = krb5_kt_default(context, keytab);
+
+    HEIMDAL_MUTEX_unlock(&gssapi_keytab_mutex);
+
+    return (kret);
+}
+
+static OM_uint32 acquire_initiator_cred
+                 (OM_uint32 * minor_status,
+                  krb5_context context,
+                  krb5_keytab keytab,
+                  krb5_ccache ccache,
+                  const gss_name_t desired_name,
+                  OM_uint32 time_req,
+                  const gss_OID_set desired_mechs,
+                  gss_cred_usage_t cred_usage,
+                  gss_cred_id_t handle,
+                  gss_OID_set * actual_mechs,
+                  OM_uint32 * time_rec
+                 )
+{
+    OM_uint32 ret;
+    krb5_creds cred;
+    krb5_principal def_princ;
+    krb5_get_init_creds_opt *opt;
+    krb5_error_code kret;
+    krb5_boolean made_ccache = FALSE;
+    krb5_boolean made_keytab = FALSE;
+
+    def_princ = NULL;
+    ret = GSS_S_FAILURE;
+    memset(&cred, 0, sizeof(cred));
+
+    if (ccache == NULL) {
+       kret = krb5_cc_default(context, &ccache);
+        if (kret)
+           goto end;
+        made_ccache = TRUE;
+    }
+    kret = krb5_cc_get_principal(context, ccache,
+       &def_princ);
+    if (kret != 0) {
+       /* we'll try to use a keytab below */
+       krb5_cc_destroy(context, ccache);
+       made_ccache = FALSE;
+       ccache = NULL;
+       kret = 0;
+    } else if (handle->principal == NULL)  {
+       kret = krb5_copy_principal(context, def_princ,
+           &handle->principal);
+       if (kret)
+           goto end;
+    } else if (handle->principal != NULL &&
+       krb5_principal_compare(context, handle->principal,
+       def_princ) == FALSE) {
+       /* Before failing, lets check the keytab */
+       krb5_free_principal(context, def_princ);
+       def_princ = NULL;
+    }
+    if (def_princ == NULL) {
+       /* We have no existing credentials cache,
+        * so attempt to get a TGT using a keytab.
+        */
+       if (handle->principal == NULL) {
+           kret = krb5_get_default_principal(context,
+               &handle->principal);
+           if (kret)
+               goto end;
+       }
+       if (keytab != NULL) {
+           kret = get_keytab(context, &keytab);
+           if (kret)
+               goto end;
+            made_keytab = TRUE;
+       }
+       kret = krb5_get_init_creds_opt_alloc(context, &opt);
+       if (kret)
+           goto end;
+       kret = krb5_get_init_creds_keytab(context, &cred,
+           handle->principal, keytab, 0, NULL, opt);
+       krb5_get_init_creds_opt_free(opt);
+       if (kret)
+           goto end;
+       if (ccache == NULL) {
+           kret = krb5_cc_gen_new(context, &krb5_mcc_ops,
+                                  &ccache);
+           if (kret)
+               goto end;
+            made_ccache = TRUE;
+       }
+       kret = krb5_cc_initialize(context, ccache, cred.client);
+       if (kret)
+           goto end;
+       kret = krb5_cc_store_cred(context, ccache, &cred);
+       if (kret)
+           goto end;
+       handle->lifetime = cred.times.endtime;
+    } else {
+       krb5_creds in_cred, *out_cred;
+       krb5_const_realm realm;
+
+       memset(&in_cred, 0, sizeof(in_cred));
+       in_cred.client = handle->principal;
+       
+       realm = krb5_principal_get_realm(context, 
+                                        handle->principal);
+       if (realm == NULL) {
+           kret = KRB5_PRINC_NOMATCH; /* XXX */
+           goto end;
+       }
+
+       kret = krb5_make_principal(context, &in_cred.server, 
+                                  realm, KRB5_TGS_NAME, realm, NULL);
+       if (kret)
+           goto end;
+
+       kret = krb5_get_credentials(context, 0, 
+                                   ccache, &in_cred, &out_cred);
+       krb5_free_principal(context, in_cred.server);
+       if (kret)
+           goto end;
+
+       handle->lifetime = out_cred->times.endtime;
+       krb5_free_creds(context, out_cred);
+    }
+
+    handle->ccache = ccache;
+    handle->made_ccache = made_ccache;
+    ret = GSS_S_COMPLETE;
+
+end:
+    if (cred.client != NULL)
+       krb5_free_cred_contents(context, &cred);
+    if (def_princ != NULL)
+       krb5_free_principal(context, def_princ);
+    if (made_keytab)
+       krb5_kt_close(context, keytab);
+    if (ret != GSS_S_COMPLETE) {
+       if (made_ccache)
+           krb5_cc_close(context, ccache);
+       if (kret != 0) {
+           *minor_status = kret;
+           gssapi_krb5_set_error_string ();
+       }
+    }
+    return (ret);
+}
+
+static OM_uint32 acquire_acceptor_cred
+                 (OM_uint32 * minor_status,
+                  krb5_context context,
+                  krb5_keytab keytab,
+                  OM_uint32 time_req,
+                  const gss_OID_set desired_mechs,
+                  gss_cred_usage_t cred_usage,
+                  gss_cred_id_t handle,
+                  gss_OID_set * actual_mechs,
+                  OM_uint32 * time_rec
+                 )
+{
+    OM_uint32 ret;
+    krb5_error_code kret;
+
+    kret = 0;
+    ret = GSS_S_FAILURE;
+    if (keytab == NULL) {
+        kret = get_keytab(context, &handle->keytab);
+       if (kret)
+               goto end;
+       handle->made_keytab = TRUE;
+    } else {
+       handle->keytab = keytab;
+       handle->made_keytab = FALSE;
+    }
+    ret = GSS_S_COMPLETE;
+end:
+    if (ret != GSS_S_COMPLETE) {
+       if (handle->made_keytab)
+           krb5_kt_close(context, handle->keytab);
+       if (kret != 0) {
+           *minor_status = kret;
+           gssapi_krb5_set_error_string ();
+       }
+    }
+    return (ret);
+}
+
+OM_uint32 gsskrb5_acquire_cred
+           (OM_uint32 * minor_status,
+           struct krb5_keytab_data *keytab,
+           struct krb5_ccache_data *ccache,
+            const gss_name_t desired_name,
+            OM_uint32 time_req,
+            const gss_OID_set desired_mechs,
+            gss_cred_usage_t cred_usage,
+            gss_cred_id_t * output_cred_handle,
+            gss_OID_set * actual_mechs,
+            OM_uint32 * time_rec
+           )
+{
+    gss_cred_id_t handle;
+    OM_uint32 ret;
+
+    if (cred_usage != GSS_C_ACCEPT && cred_usage != GSS_C_INITIATE && cred_usage != GSS_C_BOTH) {
+       *minor_status = GSS_KRB5_S_G_BAD_USAGE;
+       return GSS_S_FAILURE;
+    }
+
+    GSSAPI_KRB5_INIT ();
+
+    *output_cred_handle = NULL;
+    if (time_rec)
+       *time_rec = 0;
+    if (actual_mechs)
+       *actual_mechs = GSS_C_NO_OID_SET;
+
+    if (desired_mechs) {
+       int present = 0;
+
+       ret = gss_test_oid_set_member(minor_status, GSS_KRB5_MECHANISM,
+                                     desired_mechs, &present); 
+       if (ret)
+           return ret;
+       if (!present) {
+           *minor_status = 0;
+           return GSS_S_BAD_MECH;
+       }
+    }
+
+    handle = (gss_cred_id_t)malloc(sizeof(*handle));
+    if (handle == GSS_C_NO_CREDENTIAL) {
+       *minor_status = ENOMEM;
+        return (GSS_S_FAILURE);
+    }
+
+    memset(handle, 0, sizeof (*handle));
+    HEIMDAL_MUTEX_init(&handle->cred_id_mutex);
+
+    if (desired_name != GSS_C_NO_NAME) {
+       ret = gss_duplicate_name(minor_status, desired_name,
+           &handle->principal);
+       if (ret != GSS_S_COMPLETE) {
+           HEIMDAL_MUTEX_destroy(&handle->cred_id_mutex);
+           free(handle);
+           return (ret);
+       }
+    }
+    if (cred_usage == GSS_C_INITIATE || cred_usage == GSS_C_BOTH) {
+       ret = acquire_initiator_cred(minor_status, gssapi_krb5_context, 
+                                    keytab, ccache, 
+                                    desired_name, time_req,
+                                    desired_mechs, cred_usage, 
+                                    handle, actual_mechs, time_rec);
+       if (ret != GSS_S_COMPLETE) {
+           HEIMDAL_MUTEX_destroy(&handle->cred_id_mutex);
+           krb5_free_principal(gssapi_krb5_context, handle->principal);
+           free(handle);
+           return (ret);
+       }
+    }
+    if (cred_usage == GSS_C_ACCEPT || cred_usage == GSS_C_BOTH) {
+       ret = acquire_acceptor_cred(minor_status, gssapi_krb5_context, 
+                                   keytab, time_req,
+                                   desired_mechs, cred_usage, 
+                                   handle, actual_mechs, time_rec);
+       if (ret != GSS_S_COMPLETE) {
+           HEIMDAL_MUTEX_destroy(&handle->cred_id_mutex);
+           krb5_free_principal(gssapi_krb5_context, handle->principal);
+           free(handle);
+           return (ret);
+       }
+    }
+    ret = gss_create_empty_oid_set(minor_status, &handle->mechanisms);
+    if (ret == GSS_S_COMPLETE)
+       ret = gss_add_oid_set_member(minor_status, GSS_KRB5_MECHANISM,
+                                &handle->mechanisms);
+    if (ret == GSS_S_COMPLETE)
+       ret = gss_inquire_cred(minor_status, handle, NULL, time_rec, NULL,
+                          actual_mechs);
+    if (ret != GSS_S_COMPLETE) {
+       if (handle->mechanisms != NULL)
+           gss_release_oid_set(NULL, &handle->mechanisms);
+       HEIMDAL_MUTEX_destroy(&handle->cred_id_mutex);
+       krb5_free_principal(gssapi_krb5_context, handle->principal);
+       free(handle);
+       return (ret);
+    } 
+    *minor_status = 0;
+    if (time_rec) {
+       ret = gssapi_lifetime_left(minor_status,
+                                  handle->lifetime,
+                                  time_rec);
+
+       if (ret)
+           return ret;
+    }
+    handle->usage = cred_usage;
+
+    *output_cred_handle = handle;
+    return (GSS_S_COMPLETE);
+}
+
+OM_uint32 gss_acquire_cred
+           (OM_uint32 * minor_status,
+            const gss_name_t desired_name,
+            OM_uint32 time_req,
+            const gss_OID_set desired_mechs,
+            gss_cred_usage_t cred_usage,
+            gss_cred_id_t * output_cred_handle,
+            gss_OID_set * actual_mechs,
+            OM_uint32 * time_rec
+           )
+{
+       return gsskrb5_acquire_cred(minor_status,
+                                   NULL, NULL,
+                                   desired_name,
+                                   time_req,
+                                   desired_mechs,
+                                   cred_usage,
+                                   output_cred_handle,
+                                   actual_mechs,
+                                   time_rec);
+}
diff --git a/source4/heimdal/lib/gssapi/add_oid_set_member.c b/source4/heimdal/lib/gssapi/add_oid_set_member.c
new file mode 100644 (file)
index 0000000..ed654fc
--- /dev/null
@@ -0,0 +1,69 @@
+/*
+ * 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 "gssapi_locl.h"
+
+RCSID("$Id: add_oid_set_member.c,v 1.8 2003/03/16 17:50:49 lha Exp $");
+
+OM_uint32 gss_add_oid_set_member (
+            OM_uint32 * minor_status,
+            const gss_OID member_oid,
+            gss_OID_set * oid_set
+           )
+{
+  gss_OID tmp;
+  size_t n;
+  OM_uint32 res;
+  int present;
+
+  res = gss_test_oid_set_member(minor_status, member_oid, *oid_set, &present);
+  if (res != GSS_S_COMPLETE)
+    return res;
+
+  if (present) {
+    *minor_status = 0;
+    return GSS_S_COMPLETE;
+  }
+
+  n = (*oid_set)->count + 1;
+  tmp = realloc ((*oid_set)->elements, n * sizeof(gss_OID_desc));
+  if (tmp == NULL) {
+    *minor_status = ENOMEM;
+    return GSS_S_FAILURE;
+  }
+  (*oid_set)->elements = tmp;
+  (*oid_set)->count = n;
+  (*oid_set)->elements[n-1] = *member_oid;
+  *minor_status = 0;
+  return GSS_S_COMPLETE;
+}
diff --git a/source4/heimdal/lib/gssapi/address_to_krb5addr.c b/source4/heimdal/lib/gssapi/address_to_krb5addr.c
new file mode 100644 (file)
index 0000000..13a6825
--- /dev/null
@@ -0,0 +1,76 @@
+/*
+ * 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 "gssapi_locl.h"
+
+#include <roken.h>
+
+krb5_error_code
+gss_address_to_krb5addr(OM_uint32 gss_addr_type,
+                        gss_buffer_desc *gss_addr,
+                        int16_t port,
+                        krb5_address *address)
+{
+   int addr_type;
+   struct sockaddr sa;
+   krb5_socklen_t sa_size = sizeof(sa);
+   krb5_error_code problem;
+   
+   if (gss_addr == NULL)
+      return GSS_S_FAILURE; 
+   
+   switch (gss_addr_type) {
+#ifdef HAVE_IPV6
+      case GSS_C_AF_INET6: addr_type = AF_INET6;
+                           break;
+#endif /* HAVE_IPV6 */
+                           
+      case GSS_C_AF_INET:  addr_type = AF_INET;
+                           break;
+      default:
+                           return GSS_S_FAILURE;
+   }
+                      
+   problem = krb5_h_addr2sockaddr (gssapi_krb5_context,
+                                  addr_type,
+                                   gss_addr->value, 
+                                   &sa, 
+                                   &sa_size, 
+                                   port);
+   if (problem)
+      return GSS_S_FAILURE;
+
+   problem = krb5_sockaddr2address (gssapi_krb5_context, &sa, address);
+
+   return problem;  
+}
diff --git a/source4/heimdal/lib/gssapi/arcfour.c b/source4/heimdal/lib/gssapi/arcfour.c
new file mode 100644 (file)
index 0000000..5edcee0
--- /dev/null
@@ -0,0 +1,660 @@
+/*
+ * Copyright (c) 2003 - 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 "gssapi_locl.h"
+
+RCSID("$Id: arcfour.c,v 1.17 2005/05/06 07:13:32 lha Exp $");
+
+/*
+ * Implements draft-brezak-win2k-krb-rc4-hmac-04.txt
+ *
+ * The arcfour message have the following formats:
+ *
+ * MIC token
+ *     TOK_ID[2] = 01 01
+ *     SGN_ALG[2] = 11 00
+ *     Filler[4]
+ *     SND_SEQ[8]
+ *     SGN_CKSUM[8]
+ *
+ * WRAP token
+ *     TOK_ID[2] = 02 01
+ *     SGN_ALG[2];
+ *     SEAL_ALG[2]
+ *     Filler[2]
+ *     SND_SEQ[2]
+ *     SGN_CKSUM[8]
+ *     Confounder[8]
+ */
+
+
+static krb5_error_code
+arcfour_mic_key(krb5_context context, krb5_keyblock *key,
+               void *cksum_data, size_t cksum_size,
+               void *key6_data, size_t key6_size)
+{
+    krb5_error_code ret;
+    
+    Checksum cksum_k5;
+    krb5_keyblock key5;
+    char k5_data[16];
+    
+    Checksum cksum_k6;
+    
+    char T[4];
+
+    memset(T, 0, 4);
+    cksum_k5.checksum.data = k5_data;
+    cksum_k5.checksum.length = sizeof(k5_data);
+
+    if (key->keytype == KEYTYPE_ARCFOUR_56) {
+       char L40[14] = "fortybits";
+
+       memcpy(L40 + 10, T, sizeof(T));
+       ret = krb5_hmac(context, CKSUMTYPE_RSA_MD5,
+                       L40, 14, 0, key, &cksum_k5);
+       memset(&k5_data[7], 0xAB, 9);
+    } else {
+       ret = krb5_hmac(context, CKSUMTYPE_RSA_MD5,
+                       T, 4, 0, key, &cksum_k5);
+    }
+    if (ret)
+       return ret;
+
+    key5.keytype = KEYTYPE_ARCFOUR;
+    key5.keyvalue = cksum_k5.checksum;
+
+    cksum_k6.checksum.data = key6_data;
+    cksum_k6.checksum.length = key6_size;
+
+    return krb5_hmac(context, CKSUMTYPE_RSA_MD5,
+                    cksum_data, cksum_size, 0, &key5, &cksum_k6);
+}
+
+
+static krb5_error_code
+arcfour_mic_cksum(krb5_keyblock *key, unsigned usage,
+                 u_char *sgn_cksum, size_t sgn_cksum_sz,
+                 const char *v1, size_t l1,
+                 const void *v2, size_t l2,
+                 const void *v3, size_t l3)
+{
+    Checksum CKSUM;
+    u_char *ptr;
+    size_t len;
+    krb5_crypto crypto;
+    krb5_error_code ret;
+    
+    assert(sgn_cksum_sz == 8);
+
+    len = l1 + l2 + l3;
+
+    ptr = malloc(len);
+    if (ptr == NULL)
+       return ENOMEM;
+
+    memcpy(ptr, v1, l1);
+    memcpy(ptr + l1, v2, l2);
+    memcpy(ptr + l1 + l2, v3, l3);
+    
+    ret = krb5_crypto_init(gssapi_krb5_context, key, 0, &crypto);
+    if (ret) {
+       free(ptr);
+       return ret;
+    }
+    
+    ret = krb5_create_checksum(gssapi_krb5_context,
+                              crypto,
+                              usage,
+                              0,
+                              ptr, len,
+                              &CKSUM);
+    free(ptr);
+    if (ret == 0) {
+       memcpy(sgn_cksum, CKSUM.checksum.data, sgn_cksum_sz);
+       free_Checksum(&CKSUM);
+    }
+    krb5_crypto_destroy(gssapi_krb5_context, crypto);
+
+    return ret;
+}
+
+
+OM_uint32
+_gssapi_get_mic_arcfour(OM_uint32 * minor_status,
+                       const gss_ctx_id_t context_handle,
+                       gss_qop_t qop_req,
+                       const gss_buffer_t message_buffer,
+                       gss_buffer_t message_token,
+                       krb5_keyblock *key)
+{
+    krb5_error_code ret;
+    int32_t seq_number;
+    size_t len, total_len;
+    u_char k6_data[16], *p0, *p;
+    RC4_KEY rc4_key;
+    
+    gssapi_krb5_encap_length (22, &len, &total_len, GSS_KRB5_MECHANISM);
+    
+    message_token->length = total_len;
+    message_token->value  = malloc (total_len);
+    if (message_token->value == NULL) {
+       *minor_status = ENOMEM;
+       return GSS_S_FAILURE;
+    }
+    
+    p0 = _gssapi_make_mech_header(message_token->value,
+                                 len,
+                                 GSS_KRB5_MECHANISM);
+    p = p0;
+    
+    *p++ = 0x01; /* TOK_ID */
+    *p++ = 0x01;
+    *p++ = 0x11; /* SGN_ALG */
+    *p++ = 0x00;
+    *p++ = 0xff; /* Filler */
+    *p++ = 0xff;
+    *p++ = 0xff;
+    *p++ = 0xff;
+
+    p = NULL;
+
+    ret = arcfour_mic_cksum(key, KRB5_KU_USAGE_SIGN,
+                           p0 + 16, 8,  /* SGN_CKSUM */
+                           p0, 8, /* TOK_ID, SGN_ALG, Filer */
+                           message_buffer->value, message_buffer->length,
+                           NULL, 0);
+    if (ret) {
+       gss_release_buffer(minor_status, message_token);
+       *minor_status = ret;
+       return GSS_S_FAILURE;
+    }
+
+    ret = arcfour_mic_key(gssapi_krb5_context, key,
+                         p0 + 16, 8, /* SGN_CKSUM */
+                         k6_data, sizeof(k6_data));
+    if (ret) {
+       gss_release_buffer(minor_status, message_token);
+       *minor_status = ret;
+       return GSS_S_FAILURE;
+    }
+
+    HEIMDAL_MUTEX_lock(&context_handle->ctx_id_mutex);
+    krb5_auth_con_getlocalseqnumber (gssapi_krb5_context,
+                                    context_handle->auth_context,
+                                    &seq_number);
+    p = p0 + 8; /* SND_SEQ */
+    gssapi_encode_be_om_uint32(seq_number, p);
+    
+    krb5_auth_con_setlocalseqnumber (gssapi_krb5_context,
+                                    context_handle->auth_context,
+                                    ++seq_number);
+    HEIMDAL_MUTEX_unlock(&context_handle->ctx_id_mutex);
+    
+    memset (p + 4, (context_handle->more_flags & LOCAL) ? 0 : 0xff, 4);
+
+    RC4_set_key (&rc4_key, sizeof(k6_data), k6_data);
+    RC4 (&rc4_key, 8, p, p);
+       
+    memset(&rc4_key, 0, sizeof(rc4_key));
+    memset(k6_data, 0, sizeof(k6_data));
+    
+    *minor_status = 0;
+    return GSS_S_COMPLETE;
+}
+
+
+OM_uint32
+_gssapi_verify_mic_arcfour(OM_uint32 * minor_status,
+                          const gss_ctx_id_t context_handle,
+                          const gss_buffer_t message_buffer,
+                          const gss_buffer_t token_buffer,
+                          gss_qop_t * qop_state,
+                          krb5_keyblock *key,
+                          char *type)
+{
+    krb5_error_code ret;
+    int32_t seq_number;
+    OM_uint32 omret;
+    char cksum_data[8], k6_data[16], SND_SEQ[8];
+    u_char *p;
+    int cmp;
+    
+    if (qop_state)
+       *qop_state = 0;
+
+    p = token_buffer->value;
+    omret = gssapi_krb5_verify_header (&p,
+                                      token_buffer->length,
+                                      type,
+                                      GSS_KRB5_MECHANISM);
+    if (omret)
+       return omret;
+    
+    if (memcmp(p, "\x11\x00", 2) != 0) /* SGN_ALG = HMAC MD5 ARCFOUR */
+       return GSS_S_BAD_SIG;
+    p += 2;
+    if (memcmp (p, "\xff\xff\xff\xff", 4) != 0)
+       return GSS_S_BAD_MIC;
+    p += 4;
+
+    ret = arcfour_mic_cksum(key, KRB5_KU_USAGE_SIGN,
+                           cksum_data, sizeof(cksum_data),
+                           p - 8, 8,
+                           message_buffer->value, message_buffer->length,
+                           NULL, 0);
+    if (ret) {
+       *minor_status = ret;
+       return GSS_S_FAILURE;
+    }
+
+    ret = arcfour_mic_key(gssapi_krb5_context, key,
+                         cksum_data, sizeof(cksum_data),
+                         k6_data, sizeof(k6_data));
+    if (ret) {
+       *minor_status = ret;
+       return GSS_S_FAILURE;
+    }
+
+    cmp = memcmp(cksum_data, p + 8, 8);
+    if (cmp) {
+       *minor_status = 0;
+       return GSS_S_BAD_MIC;
+    }
+
+    {
+       RC4_KEY rc4_key;
+       
+       RC4_set_key (&rc4_key, sizeof(k6_data), k6_data);
+       RC4 (&rc4_key, 8, p, SND_SEQ);
+       
+       memset(&rc4_key, 0, sizeof(rc4_key));
+       memset(k6_data, 0, sizeof(k6_data));
+    }
+
+    gssapi_decode_be_om_uint32(SND_SEQ, &seq_number);
+
+    if (context_handle->more_flags & LOCAL)
+       cmp = memcmp(&SND_SEQ[4], "\xff\xff\xff\xff", 4);
+    else
+       cmp = memcmp(&SND_SEQ[4], "\x00\x00\x00\x00", 4);
+
+    memset(SND_SEQ, 0, sizeof(SND_SEQ));
+    if (cmp != 0) {
+       *minor_status = 0;
+       return GSS_S_BAD_MIC;
+    }
+    
+    HEIMDAL_MUTEX_lock(&context_handle->ctx_id_mutex);
+    omret = _gssapi_msg_order_check(context_handle->order, seq_number);
+    HEIMDAL_MUTEX_unlock(&context_handle->ctx_id_mutex);
+    if (omret)
+       return omret;
+
+    *minor_status = 0;
+    return GSS_S_COMPLETE;
+}
+
+OM_uint32
+_gssapi_wrap_arcfour(OM_uint32 * minor_status,
+                    const gss_ctx_id_t context_handle,
+                    int conf_req_flag,
+                    gss_qop_t qop_req,
+                    const gss_buffer_t input_message_buffer,
+                    int * conf_state,
+                    gss_buffer_t output_message_buffer,
+                    krb5_keyblock *key)
+{
+    u_char Klocaldata[16], k6_data[16], *p, *p0;
+    size_t len, total_len, datalen;
+    krb5_keyblock Klocal;
+    krb5_error_code ret;
+    int32_t seq_number;
+
+    if (conf_state)
+       *conf_state = 0;
+
+    datalen = input_message_buffer->length;
+    len = GSS_ARCFOUR_WRAP_TOKEN_SIZE;
+    /* if GSS_C_DCE_STYLE is in use:
+     *  - we only need to encapsulate the WRAP token
+     *  - we should not add padding
+     */
+    if (!(context_handle->flags & GSS_C_DCE_STYLE)) {
+       datalen += 1 /* padding */;
+       len += datalen;
+    }
+    _gssapi_encap_length(len, &len, &total_len, GSS_KRB5_MECHANISM);
+    if (context_handle->flags & GSS_C_DCE_STYLE) {
+       total_len += datalen;
+    }
+
+    output_message_buffer->length = total_len;
+    output_message_buffer->value  = malloc (total_len);
+    if (output_message_buffer->value == NULL) {
+       *minor_status = ENOMEM;
+       return GSS_S_FAILURE;
+    }
+    
+    p0 = _gssapi_make_mech_header(output_message_buffer->value,
+                                 len,
+                                 GSS_KRB5_MECHANISM);
+    p = p0;
+
+    *p++ = 0x02; /* TOK_ID */
+    *p++ = 0x01;
+    *p++ = 0x11; /* SGN_ALG */
+    *p++ = 0x00;
+    if (conf_req_flag) {
+       *p++ = 0x10; /* SEAL_ALG */
+       *p++ = 0x00;
+    } else {
+       *p++ = 0xff; /* SEAL_ALG */
+       *p++ = 0xff;
+    }
+    *p++ = 0xff; /* Filler */
+    *p++ = 0xff;
+
+    p = NULL;
+
+    HEIMDAL_MUTEX_lock(&context_handle->ctx_id_mutex);
+    krb5_auth_con_getlocalseqnumber (gssapi_krb5_context,
+                                    context_handle->auth_context,
+                                    &seq_number);
+
+    gssapi_encode_be_om_uint32(seq_number, p0 + 8);
+
+    krb5_auth_con_setlocalseqnumber (gssapi_krb5_context,
+                                    context_handle->auth_context,
+                                    ++seq_number);
+    HEIMDAL_MUTEX_unlock(&context_handle->ctx_id_mutex);
+
+    memset (p0 + 8 + 4,
+           (context_handle->more_flags & LOCAL) ? 0 : 0xff,
+           4);
+
+    krb5_generate_random_block(p0 + 24, 8); /* fill in Confounder */
+    
+    /* p points to data */
+    p = p0 + GSS_ARCFOUR_WRAP_TOKEN_SIZE;
+    memcpy(p, input_message_buffer->value, input_message_buffer->length);
+    /* only add padding when GSS_C_DCE_STYLE is not in use */
+    if (!(context_handle->flags & GSS_C_DCE_STYLE)) {
+       p[input_message_buffer->length] = 1; /* PADDING */
+    }
+
+    ret = arcfour_mic_cksum(key, KRB5_KU_USAGE_SEAL,
+                           p0 + 16, 8, /* SGN_CKSUM */ 
+                           p0, 8, /* TOK_ID, SGN_ALG, SEAL_ALG, Filler */
+                           p0 + 24, 8, /* Confounder */
+                           p0 + GSS_ARCFOUR_WRAP_TOKEN_SIZE, 
+                           datalen);
+    if (ret) {
+       *minor_status = ret;
+       gss_release_buffer(minor_status, output_message_buffer);
+       return GSS_S_FAILURE;
+    }
+
+    {
+       int i;
+
+       Klocal.keytype = key->keytype;
+       Klocal.keyvalue.data = Klocaldata;
+       Klocal.keyvalue.length = sizeof(Klocaldata);
+
+       for (i = 0; i < 16; i++)
+           Klocaldata[i] = ((u_char *)key->keyvalue.data)[i] ^ 0xF0;
+    }
+    ret = arcfour_mic_key(gssapi_krb5_context, &Klocal,
+                         p0 + 8, 4, /* SND_SEQ */
+                         k6_data, sizeof(k6_data));
+    memset(Klocaldata, 0, sizeof(Klocaldata));
+    if (ret) {
+       gss_release_buffer(minor_status, output_message_buffer);
+       *minor_status = ret;
+       return GSS_S_FAILURE;
+    }
+
+
+    if(conf_req_flag) {
+       RC4_KEY rc4_key;
+
+       RC4_set_key (&rc4_key, sizeof(k6_data), k6_data);
+       /* XXX ? */
+       RC4 (&rc4_key, 8 + datalen, p0 + 24, p0 + 24); /* Confounder + data */
+       memset(&rc4_key, 0, sizeof(rc4_key));
+    }
+    memset(k6_data, 0, sizeof(k6_data));
+
+    ret = arcfour_mic_key(gssapi_krb5_context, key,
+                         p0 + 16, 8, /* SGN_CKSUM */
+                         k6_data, sizeof(k6_data));
+    if (ret) {
+       gss_release_buffer(minor_status, output_message_buffer);
+       *minor_status = ret;
+       return GSS_S_FAILURE;
+    }
+
+    {
+       RC4_KEY rc4_key;
+       
+       RC4_set_key (&rc4_key, sizeof(k6_data), k6_data);
+       RC4 (&rc4_key, 8, p0 + 8, p0 + 8); /* SND_SEQ */
+       memset(&rc4_key, 0, sizeof(rc4_key));
+       memset(k6_data, 0, sizeof(k6_data));
+    }
+
+    if (conf_state)
+       *conf_state = conf_req_flag;
+
+    *minor_status = 0;
+    return GSS_S_COMPLETE;
+}
+
+OM_uint32 _gssapi_unwrap_arcfour(OM_uint32 *minor_status,
+                                const gss_ctx_id_t context_handle,
+                                const gss_buffer_t input_message_buffer,
+                                gss_buffer_t output_message_buffer,
+                                int *conf_state,
+                                gss_qop_t *qop_state,
+                                krb5_keyblock *key)
+{
+    u_char Klocaldata[16];
+    krb5_keyblock Klocal;
+    krb5_error_code ret;
+    int32_t seq_number;
+    size_t len, datalen;
+    OM_uint32 omret;
+    char k6_data[16], SND_SEQ[8], Confounder[8];
+    char cksum_data[8];
+    u_char *p, *p0;
+    int cmp;
+    int conf_flag;
+    size_t padlen = 0;
+    
+    if (conf_state)
+       *conf_state = 0;
+    if (qop_state)
+       *qop_state = 0;
+
+    p0 = input_message_buffer->value;
+    len = input_message_buffer->length;
+    /* if we have GSS_C_DCE_STYLE in use, we only need to decapsulate the WRAP token */
+    if (context_handle->flags & GSS_C_DCE_STYLE) {
+       if (input_message_buffer->length < (GSS_ARCFOUR_WRAP_TOKEN_OFFSET+GSS_ARCFOUR_WRAP_TOKEN_SIZE)) {
+           return GSS_S_BAD_MECH;
+       }
+       len = GSS_ARCFOUR_WRAP_TOKEN_OFFSET+GSS_ARCFOUR_WRAP_TOKEN_SIZE;
+    }
+    omret = _gssapi_verify_mech_header(&p0,
+                                      len,
+                                      GSS_KRB5_MECHANISM);
+    if (omret)
+       return omret;
+    p = p0;
+
+    datalen = input_message_buffer->length -
+       (p - ((u_char *)input_message_buffer->value)) - 
+       GSS_ARCFOUR_WRAP_TOKEN_SIZE;
+
+    if (memcmp(p, "\x02\x01", 2) != 0)
+       return GSS_S_BAD_SIG;
+    p += 2;
+    if (memcmp(p, "\x11\x00", 2) != 0) /* SGN_ALG = HMAC MD5 ARCFOUR */
+       return GSS_S_BAD_SIG;
+    p += 2;
+
+    if (memcmp (p, "\x10\x00", 2) == 0)
+       conf_flag = 1;
+    else if (memcmp (p, "\xff\xff", 2) == 0)
+       conf_flag = 0;
+    else
+       return GSS_S_BAD_SIG;
+
+    p += 2;
+    if (memcmp (p, "\xff\xff", 2) != 0)
+       return GSS_S_BAD_MIC;
+    p = NULL;
+
+    ret = arcfour_mic_key(gssapi_krb5_context, key,
+                         p0 + 16, 8, /* SGN_CKSUM */
+                         k6_data, sizeof(k6_data));
+    if (ret) {
+       *minor_status = ret;
+       return GSS_S_FAILURE;
+    }
+
+    {
+       RC4_KEY rc4_key;
+       
+       RC4_set_key (&rc4_key, sizeof(k6_data), k6_data);
+       RC4 (&rc4_key, 8, p0 + 8, SND_SEQ); /* SND_SEQ */
+       memset(&rc4_key, 0, sizeof(rc4_key));
+       memset(k6_data, 0, sizeof(k6_data));
+    }
+
+    gssapi_decode_be_om_uint32(SND_SEQ, &seq_number);
+
+    if (context_handle->more_flags & LOCAL)
+       cmp = memcmp(&SND_SEQ[4], "\xff\xff\xff\xff", 4);
+    else
+       cmp = memcmp(&SND_SEQ[4], "\x00\x00\x00\x00", 4);
+
+    if (cmp != 0) {
+       *minor_status = 0;
+       return GSS_S_BAD_MIC;
+    }
+
+    {
+       int i;
+
+       Klocal.keytype = key->keytype;
+       Klocal.keyvalue.data = Klocaldata;
+       Klocal.keyvalue.length = sizeof(Klocaldata);
+
+       for (i = 0; i < 16; i++)
+           Klocaldata[i] = ((u_char *)key->keyvalue.data)[i] ^ 0xF0;
+    }
+    ret = arcfour_mic_key(gssapi_krb5_context, &Klocal,
+                         SND_SEQ, 4,
+                         k6_data, sizeof(k6_data));
+    memset(Klocaldata, 0, sizeof(Klocaldata));
+    if (ret) {
+       *minor_status = ret;
+       return GSS_S_FAILURE;
+    }
+
+    output_message_buffer->value = malloc(datalen);
+    if (output_message_buffer->value == NULL) {
+       *minor_status = ENOMEM;
+       return GSS_S_FAILURE;
+    }
+    output_message_buffer->length = datalen;
+
+    if(conf_flag) {
+       RC4_KEY rc4_key;
+
+       RC4_set_key (&rc4_key, sizeof(k6_data), k6_data);
+       RC4 (&rc4_key, 8, p0 + 24, Confounder); /* Confounder */
+       RC4 (&rc4_key, datalen, p0 + GSS_ARCFOUR_WRAP_TOKEN_SIZE,
+            output_message_buffer->value);
+       memset(&rc4_key, 0, sizeof(rc4_key));
+    } else {
+       memcpy(Confounder, p0 + 24, 8); /* Confounder */
+       memcpy(output_message_buffer->value, 
+              p0 + GSS_ARCFOUR_WRAP_TOKEN_SIZE,
+              datalen);
+    }
+    memset(k6_data, 0, sizeof(k6_data));
+
+    if (!(context_handle->flags & GSS_C_DCE_STYLE)) {
+        ret = _gssapi_verify_pad(output_message_buffer, datalen, &padlen);
+        if (ret) {
+           gss_release_buffer(minor_status, output_message_buffer);
+           *minor_status = 0;
+           return ret;
+        }
+        output_message_buffer->length -= padlen;
+    }
+
+    ret = arcfour_mic_cksum(key, KRB5_KU_USAGE_SEAL,
+                           cksum_data, sizeof(cksum_data),
+                           p0, 8, 
+                           Confounder, sizeof(Confounder),
+                           output_message_buffer->value, 
+                           output_message_buffer->length + padlen);
+    if (ret) {
+       gss_release_buffer(minor_status, output_message_buffer);
+       *minor_status = ret;
+       return GSS_S_FAILURE;
+    }
+
+    cmp = memcmp(cksum_data, p0 + 16, 8); /* SGN_CKSUM */
+    if (cmp) {
+       gss_release_buffer(minor_status, output_message_buffer);
+       *minor_status = 0;
+       return GSS_S_BAD_MIC;
+    }
+
+    HEIMDAL_MUTEX_lock(&context_handle->ctx_id_mutex);
+    omret = _gssapi_msg_order_check(context_handle->order, seq_number);
+    HEIMDAL_MUTEX_unlock(&context_handle->ctx_id_mutex);
+    if (omret)
+       return omret;
+
+    if (conf_state)
+       *conf_state = conf_flag;
+
+    *minor_status = 0;
+    return GSS_S_COMPLETE;
+}
diff --git a/source4/heimdal/lib/gssapi/arcfour.h b/source4/heimdal/lib/gssapi/arcfour.h
new file mode 100644 (file)
index 0000000..5acfcad
--- /dev/null
@@ -0,0 +1,74 @@
+/*
+ * 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: arcfour.h,v 1.5 2004/03/07 22:30:57 lha Exp $ */
+
+#ifndef GSSAPI_ARCFOUR_H_
+#define GSSAPI_ARCFOUR_H_ 1
+
+#define GSS_ARCFOUR_WRAP_TOKEN_SIZE 32
+#define GSS_ARCFOUR_WRAP_TOKEN_OFFSET 13
+
+OM_uint32 _gssapi_wrap_arcfour(OM_uint32 *minor_status,
+                              const gss_ctx_id_t context_handle,
+                              int conf_req_flag,
+                              gss_qop_t qop_req,
+                              const gss_buffer_t input_message_buffer,
+                              int *conf_state,
+                              gss_buffer_t output_message_buffer,
+                              krb5_keyblock *key);
+
+OM_uint32 _gssapi_unwrap_arcfour(OM_uint32 *minor_status,
+                                const gss_ctx_id_t context_handle,
+                                const gss_buffer_t input_message_buffer,
+                                gss_buffer_t output_message_buffer,
+                                int *conf_state,
+                                gss_qop_t *qop_state,
+                                krb5_keyblock *key);
+
+OM_uint32 _gssapi_get_mic_arcfour(OM_uint32 *minor_status,
+                                 const gss_ctx_id_t context_handle,
+                                 gss_qop_t qop_req,
+                                 const gss_buffer_t message_buffer,
+                                 gss_buffer_t message_token,
+                                 krb5_keyblock *key);
+
+OM_uint32 _gssapi_verify_mic_arcfour(OM_uint32 *minor_status,
+                                    const gss_ctx_id_t context_handle,
+                                    const gss_buffer_t message_buffer,
+                                    const gss_buffer_t token_buffer,
+                                    gss_qop_t *qop_state,
+                                    krb5_keyblock *key,
+                                    char *type);
+
+#endif /* GSSAPI_ARCFOUR_H_ */
diff --git a/source4/heimdal/lib/gssapi/ccache_name.c b/source4/heimdal/lib/gssapi/ccache_name.c
new file mode 100755 (executable)
index 0000000..3bebb83
--- /dev/null
@@ -0,0 +1,80 @@
+/*
+ * 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. 
+ */
+
+#include "gssapi_locl.h"
+
+RCSID("$Id: ccache_name.c,v 1.2 2005/06/16 20:38:49 lha Exp $");
+
+char *last_out_name;
+
+OM_uint32
+gss_krb5_ccache_name(OM_uint32 *minor_status, 
+                    const char *name,
+                    const char **out_name)
+{
+    krb5_error_code kret;
+
+    *minor_status = 0;
+
+    GSSAPI_KRB5_INIT();
+
+    if (out_name) {
+       const char *n;
+
+       if (last_out_name) {
+           free(last_out_name);
+           last_out_name = NULL;
+       }
+
+       n = krb5_cc_default_name(gssapi_krb5_context);
+       if (n == NULL) {
+           *minor_status = ENOMEM;
+           gssapi_krb5_set_error_string ();
+           return GSS_S_FAILURE;
+       }
+       last_out_name = strdup(n);
+       if (last_out_name == NULL) {
+           *minor_status = ENOMEM;
+           return GSS_S_FAILURE;
+       }
+       *out_name = last_out_name;
+    }
+
+    kret = krb5_cc_set_default_name(gssapi_krb5_context, name);
+    if (kret) {
+       *minor_status = kret;
+       gssapi_krb5_set_error_string ();
+       return GSS_S_FAILURE;
+    }
+    return GSS_S_COMPLETE;
+}
diff --git a/source4/heimdal/lib/gssapi/cfx.c b/source4/heimdal/lib/gssapi/cfx.c
new file mode 100755 (executable)
index 0000000..75b6a8b
--- /dev/null
@@ -0,0 +1,841 @@
+/*
+ * Copyright (c) 2003, 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 "gssapi_locl.h"
+
+RCSID("$Id: cfx.c,v 1.17 2005/04/27 17:47:32 lha Exp $");
+
+/*
+ * Implementation of draft-ietf-krb-wg-gssapi-cfx-06.txt
+ */
+
+#define CFXSentByAcceptor      (1 << 0)
+#define CFXSealed              (1 << 1)
+#define CFXAcceptorSubkey      (1 << 2)
+
+static krb5_error_code
+wrap_length_cfx(krb5_crypto crypto,
+               int conf_req_flag,
+               size_t input_length,
+               size_t *output_length,
+               size_t *cksumsize,
+               u_int16_t *padlength)
+{
+    krb5_error_code ret;
+    krb5_cksumtype type;
+
+    /* 16-byte header is always first */
+    *output_length = sizeof(gss_cfx_wrap_token_desc);
+    *padlength = 0;
+
+    ret = krb5_crypto_get_checksum_type(gssapi_krb5_context, crypto, &type);
+    if (ret) {
+       return ret;
+    }
+
+    ret = krb5_checksumsize(gssapi_krb5_context, type, cksumsize);
+    if (ret) {
+       return ret;
+    }
+
+    if (conf_req_flag) {
+       size_t padsize;
+
+       /* Header is concatenated with data before encryption */
+       input_length += sizeof(gss_cfx_wrap_token_desc);
+
+       ret = krb5_crypto_getpadsize(gssapi_krb5_context, crypto, &padsize);
+       if (ret) {
+           return ret;
+       }
+       if (padsize > 1) {
+           /* XXX check this */
+           *padlength = padsize - (input_length % padsize);
+       }
+
+       /* We add the pad ourselves (noted here for completeness only) */
+       input_length += *padlength;
+
+       *output_length += krb5_get_wrapped_length(gssapi_krb5_context,
+                                                 crypto, input_length);
+    } else {
+       /* Checksum is concatenated with data */
+       *output_length += input_length + *cksumsize;
+    }
+
+    assert(*output_length > input_length);
+
+    return 0;
+}
+
+OM_uint32 _gssapi_wrap_size_cfx(OM_uint32 *minor_status,
+                               const gss_ctx_id_t context_handle,
+                               int conf_req_flag,
+                               gss_qop_t qop_req,
+                               OM_uint32 req_output_size,
+                               OM_uint32 *max_input_size,
+                               krb5_keyblock *key)
+{
+    krb5_error_code ret;
+    krb5_crypto crypto;
+    u_int16_t padlength;
+    size_t output_length, cksumsize;
+
+    ret = krb5_crypto_init(gssapi_krb5_context, key, 0, &crypto);
+    if (ret != 0) {
+       gssapi_krb5_set_error_string();
+       *minor_status = ret;
+       return GSS_S_FAILURE;
+    }
+
+    ret = wrap_length_cfx(crypto, conf_req_flag, 
+                         req_output_size,
+                         &output_length, &cksumsize, &padlength);
+    if (ret != 0) {
+       gssapi_krb5_set_error_string();
+       *minor_status = ret;
+       krb5_crypto_destroy(gssapi_krb5_context, crypto);
+       return GSS_S_FAILURE;
+    }
+
+    if (output_length < req_output_size) {
+       *max_input_size = (req_output_size - output_length);
+       *max_input_size -= padlength;
+    } else {
+       /* Should this return an error? */
+       *max_input_size = 0;
+    }
+
+    krb5_crypto_destroy(gssapi_krb5_context, crypto);
+
+    return GSS_S_COMPLETE;
+}
+
+/*
+ * Rotate "rrc" bytes to the front or back
+ */
+
+static krb5_error_code
+rrc_rotate(void *data, size_t len, u_int16_t rrc, krb5_boolean unrotate)
+{
+    u_char *tmp;
+    size_t left;
+    char buf[256];
+
+    if (len == 0)
+       return 0;
+
+    rrc %= len;
+
+    if (rrc == 0)
+       return 0;
+
+    left = len - rrc;
+
+    if (rrc <= sizeof(buf)) {
+       tmp = buf;
+    } else {
+       tmp = malloc(rrc);
+       if (tmp == NULL) 
+           return ENOMEM;
+    }
+    if (unrotate) {
+       memcpy(tmp, data, rrc);
+       memmove(data, (u_char *)data + rrc, left);
+       memcpy((u_char *)data + left, tmp, rrc);
+    } else {
+       memcpy(tmp, (u_char *)data + left, rrc);
+       memmove((u_char *)data + rrc, data, left);
+       memcpy(data, tmp, rrc);
+    }
+
+    if (rrc > sizeof(buf)) 
+       free(tmp);
+
+    return 0;
+}
+
+OM_uint32 _gssapi_wrap_cfx(OM_uint32 *minor_status,
+                          const gss_ctx_id_t context_handle,
+                          int conf_req_flag,
+                          gss_qop_t qop_req,
+                          const gss_buffer_t input_message_buffer,
+                          int *conf_state,
+                          gss_buffer_t output_message_buffer,
+                          krb5_keyblock *key)
+{
+    krb5_crypto crypto;
+    gss_cfx_wrap_token token;
+    krb5_error_code ret;
+    unsigned usage;
+    krb5_data cipher;
+    size_t wrapped_len, cksumsize;
+    u_int16_t padlength, rrc = 0;
+    OM_uint32 seq_number;
+    u_char *p;
+
+    ret = krb5_crypto_init(gssapi_krb5_context, key, 0, &crypto);
+    if (ret != 0) {
+       gssapi_krb5_set_error_string();
+       *minor_status = ret;
+       return GSS_S_FAILURE;
+    }
+
+    ret = wrap_length_cfx(crypto, conf_req_flag, 
+                         input_message_buffer->length,
+                         &wrapped_len, &cksumsize, &padlength);
+    if (ret != 0) {
+       gssapi_krb5_set_error_string();
+       *minor_status = ret;
+       krb5_crypto_destroy(gssapi_krb5_context, crypto);
+       return GSS_S_FAILURE;
+    }
+
+    /* Always rotate encrypted token (if any) and checksum to header */
+    rrc = (conf_req_flag ? sizeof(*token) : 0) + (u_int16_t)cksumsize;
+
+    output_message_buffer->length = wrapped_len;
+    output_message_buffer->value = malloc(output_message_buffer->length);
+    if (output_message_buffer->value == NULL) {
+       *minor_status = ENOMEM;
+       krb5_crypto_destroy(gssapi_krb5_context, crypto);
+       return GSS_S_FAILURE;
+    }
+
+    p = output_message_buffer->value;
+    token = (gss_cfx_wrap_token)p;
+    token->TOK_ID[0] = 0x05;
+    token->TOK_ID[1] = 0x04;
+    token->Flags     = 0;
+    token->Filler    = 0xFF;
+    if ((context_handle->more_flags & LOCAL) == 0)
+       token->Flags |= CFXSentByAcceptor;
+    if (context_handle->more_flags & ACCEPTOR_SUBKEY)
+       token->Flags |= CFXAcceptorSubkey;
+    if (conf_req_flag) {
+       /*
+        * In Wrap tokens with confidentiality, the EC field is
+        * used to encode the size (in bytes) of the random filler.
+        */
+       token->Flags |= CFXSealed;
+       token->EC[0] = (padlength >> 8) & 0xFF;
+       token->EC[1] = (padlength >> 0) & 0xFF;
+    } else {
+       /*
+        * In Wrap tokens without confidentiality, the EC field is
+        * used to encode the size (in bytes) of the trailing
+        * checksum.
+        *
+        * This is not used in the checksum calcuation itself,
+        * because the checksum length could potentially vary
+        * depending on the data length.
+        */
+       token->EC[0] = 0;
+       token->EC[1] = 0;
+    }
+
+    /*
+     * In Wrap tokens that provide for confidentiality, the RRC
+     * field in the header contains the hex value 00 00 before
+     * encryption.
+     *
+     * In Wrap tokens that do not provide for confidentiality,
+     * both the EC and RRC fields in the appended checksum
+     * contain the hex value 00 00 for the purpose of calculating
+     * the checksum.
+     */
+    token->RRC[0] = 0;
+    token->RRC[1] = 0;
+
+    HEIMDAL_MUTEX_lock(&context_handle->ctx_id_mutex);
+    krb5_auth_con_getlocalseqnumber(gssapi_krb5_context,
+                                   context_handle->auth_context,
+                                   &seq_number);
+    gssapi_encode_be_om_uint32(0,          &token->SND_SEQ[0]);
+    gssapi_encode_be_om_uint32(seq_number, &token->SND_SEQ[4]);
+    krb5_auth_con_setlocalseqnumber(gssapi_krb5_context,
+                                   context_handle->auth_context,
+                                   ++seq_number);
+    HEIMDAL_MUTEX_unlock(&context_handle->ctx_id_mutex);
+
+    /*
+     * If confidentiality is requested, the token header is
+     * appended to the plaintext before encryption; the resulting
+     * token is {"header" | encrypt(plaintext | pad | "header")}.
+     *
+     * If no confidentiality is requested, the checksum is
+     * calculated over the plaintext concatenated with the
+     * token header.
+     */
+    if (context_handle->more_flags & LOCAL) {
+       usage = KRB5_KU_USAGE_INITIATOR_SEAL;
+    } else {
+       usage = KRB5_KU_USAGE_ACCEPTOR_SEAL;
+    }
+
+    if (conf_req_flag) {
+       /*
+        * Any necessary padding is added here to ensure that the
+        * encrypted token header is always at the end of the
+        * ciphertext.
+        *
+        * The specification does not require that the padding
+        * bytes are initialized.
+        */
+       p += sizeof(*token);
+       memcpy(p, input_message_buffer->value, input_message_buffer->length);
+       memset(p + input_message_buffer->length, 0xFF, padlength);
+       memcpy(p + input_message_buffer->length + padlength,
+              token, sizeof(*token));
+
+       ret = krb5_encrypt(gssapi_krb5_context, crypto,
+                          usage, p,
+                          input_message_buffer->length + padlength +
+                               sizeof(*token),
+                          &cipher);
+       if (ret != 0) {
+           gssapi_krb5_set_error_string();
+           *minor_status = ret;
+           krb5_crypto_destroy(gssapi_krb5_context, crypto);
+           gss_release_buffer(minor_status, output_message_buffer);
+           return GSS_S_FAILURE;
+       }
+       assert(sizeof(*token) + cipher.length == wrapped_len);
+       token->RRC[0] = (rrc >> 8) & 0xFF;  
+       token->RRC[1] = (rrc >> 0) & 0xFF;
+
+       ret = rrc_rotate(cipher.data, cipher.length, rrc, FALSE);
+       if (ret != 0) {
+           gssapi_krb5_set_error_string();
+           *minor_status = ret;
+           krb5_crypto_destroy(gssapi_krb5_context, crypto);
+           gss_release_buffer(minor_status, output_message_buffer);
+           return GSS_S_FAILURE;
+       }
+       memcpy(p, cipher.data, cipher.length);
+       krb5_data_free(&cipher);
+    } else {
+       char *buf;
+       Checksum cksum;
+
+       buf = malloc(input_message_buffer->length + sizeof(*token));
+       if (buf == NULL) {
+           *minor_status = ENOMEM;
+           krb5_crypto_destroy(gssapi_krb5_context, crypto);
+           gss_release_buffer(minor_status, output_message_buffer);
+           return GSS_S_FAILURE;
+       }
+       memcpy(buf, input_message_buffer->value, input_message_buffer->length);
+       memcpy(buf + input_message_buffer->length, token, sizeof(*token));
+
+       ret = krb5_create_checksum(gssapi_krb5_context, crypto,
+                                  usage, 0, buf, 
+                                  input_message_buffer->length +
+                                       sizeof(*token), 
+                                  &cksum);
+       if (ret != 0) {
+           gssapi_krb5_set_error_string();
+           *minor_status = ret;
+           krb5_crypto_destroy(gssapi_krb5_context, crypto);
+           gss_release_buffer(minor_status, output_message_buffer);
+           free(buf);
+           return GSS_S_FAILURE;
+       }
+
+       free(buf);
+
+       assert(cksum.checksum.length == cksumsize);
+       token->EC[0] =  (cksum.checksum.length >> 8) & 0xFF;
+       token->EC[1] =  (cksum.checksum.length >> 0) & 0xFF;
+       token->RRC[0] = (rrc >> 8) & 0xFF;  
+       token->RRC[1] = (rrc >> 0) & 0xFF;
+
+       p += sizeof(*token);
+       memcpy(p, input_message_buffer->value, input_message_buffer->length);
+       memcpy(p + input_message_buffer->length,
+              cksum.checksum.data, cksum.checksum.length);
+
+       ret = rrc_rotate(p,
+           input_message_buffer->length + cksum.checksum.length, rrc, FALSE);
+       if (ret != 0) {
+           gssapi_krb5_set_error_string();
+           *minor_status = ret;
+           krb5_crypto_destroy(gssapi_krb5_context, crypto);
+           gss_release_buffer(minor_status, output_message_buffer);
+           free_Checksum(&cksum);
+           return GSS_S_FAILURE;
+       }
+       free_Checksum(&cksum);
+    }
+
+    krb5_crypto_destroy(gssapi_krb5_context, crypto);
+
+    if (conf_state != NULL) {
+       *conf_state = conf_req_flag;
+    }
+
+    *minor_status = 0;
+    return GSS_S_COMPLETE;
+}
+
+OM_uint32 _gssapi_unwrap_cfx(OM_uint32 *minor_status,
+                            const gss_ctx_id_t context_handle,
+                            const gss_buffer_t input_message_buffer,
+                            gss_buffer_t output_message_buffer,
+                            int *conf_state,
+                            gss_qop_t *qop_state,
+                            krb5_keyblock *key)
+{
+    krb5_crypto crypto;
+    gss_cfx_wrap_token token;
+    u_char token_flags;
+    krb5_error_code ret;
+    unsigned usage;
+    krb5_data data;
+    u_int16_t ec, rrc;
+    OM_uint32 seq_number_lo, seq_number_hi;
+    size_t len;
+    u_char *p;
+
+    *minor_status = 0;
+
+    if (input_message_buffer->length < sizeof(*token)) {
+       return GSS_S_DEFECTIVE_TOKEN;
+    }
+
+    p = input_message_buffer->value;
+
+    token = (gss_cfx_wrap_token)p;
+
+    if (token->TOK_ID[0] != 0x05 || token->TOK_ID[1] != 0x04) {
+       return GSS_S_DEFECTIVE_TOKEN;
+    }
+
+    /* Ignore unknown flags */
+    token_flags = token->Flags &
+       (CFXSentByAcceptor | CFXSealed | CFXAcceptorSubkey);
+
+    if (token_flags & CFXSentByAcceptor) {
+       if ((context_handle->more_flags & LOCAL) == 0)
+           return GSS_S_DEFECTIVE_TOKEN;
+    }
+
+    if (context_handle->more_flags & ACCEPTOR_SUBKEY) {
+       if ((token_flags & CFXAcceptorSubkey) == 0)
+           return GSS_S_DEFECTIVE_TOKEN;
+    } else {
+       if (token_flags & CFXAcceptorSubkey)
+           return GSS_S_DEFECTIVE_TOKEN;
+    }
+
+    if (token->Filler != 0xFF) {
+       return GSS_S_DEFECTIVE_TOKEN;
+    }
+
+    if (conf_state != NULL) {
+       *conf_state = (token_flags & CFXSealed) ? 1 : 0;
+    }
+
+    ec  = (token->EC[0]  << 8) | token->EC[1];
+    rrc = (token->RRC[0] << 8) | token->RRC[1];
+
+    /*
+     * Check sequence number
+     */
+    gssapi_decode_be_om_uint32(&token->SND_SEQ[0], &seq_number_hi);
+    gssapi_decode_be_om_uint32(&token->SND_SEQ[4], &seq_number_lo);
+    if (seq_number_hi) {
+       /* no support for 64-bit sequence numbers */
+       *minor_status = ERANGE;
+       return GSS_S_UNSEQ_TOKEN;
+    }
+
+    HEIMDAL_MUTEX_lock(&context_handle->ctx_id_mutex);
+    ret = _gssapi_msg_order_check(context_handle->order, seq_number_lo);
+    if (ret != 0) {
+       *minor_status = 0;
+       HEIMDAL_MUTEX_unlock(&context_handle->ctx_id_mutex);
+       gss_release_buffer(minor_status, output_message_buffer);
+       return ret;
+    }
+    HEIMDAL_MUTEX_unlock(&context_handle->ctx_id_mutex);
+
+    /*
+     * Decrypt and/or verify checksum
+     */
+    ret = krb5_crypto_init(gssapi_krb5_context, key, 0, &crypto);
+    if (ret != 0) {
+       gssapi_krb5_set_error_string();
+       *minor_status = ret;
+       return GSS_S_FAILURE;
+    }
+
+    if (context_handle->more_flags & LOCAL) {
+       usage = KRB5_KU_USAGE_ACCEPTOR_SEAL;
+    } else {
+       usage = KRB5_KU_USAGE_INITIATOR_SEAL;
+    }
+
+    p += sizeof(*token);
+    len = input_message_buffer->length;
+    len -= (p - (u_char *)input_message_buffer->value);
+
+    /* Rotate by RRC; bogus to do this in-place XXX */
+    *minor_status = rrc_rotate(p, len, rrc, TRUE);
+    if (*minor_status != 0) {
+       krb5_crypto_destroy(gssapi_krb5_context, crypto);
+       return GSS_S_FAILURE;
+    }
+
+    if (token_flags & CFXSealed) {
+       ret = krb5_decrypt(gssapi_krb5_context, crypto, usage,
+           p, len, &data);
+       if (ret != 0) {
+           gssapi_krb5_set_error_string();
+           *minor_status = ret;
+           krb5_crypto_destroy(gssapi_krb5_context, crypto);
+           return GSS_S_BAD_MIC;
+       }
+
+       /* Check that there is room for the pad and token header */
+       if (data.length < ec + sizeof(*token)) {
+           krb5_crypto_destroy(gssapi_krb5_context, crypto);
+           krb5_data_free(&data);
+           return GSS_S_DEFECTIVE_TOKEN;
+       }
+       p = data.data;
+       p += data.length - sizeof(*token);
+
+       /* RRC is unprotected; don't modify input buffer */
+       ((gss_cfx_wrap_token)p)->RRC[0] = token->RRC[0];
+       ((gss_cfx_wrap_token)p)->RRC[1] = token->RRC[1];
+
+       /* Check the integrity of the header */
+       if (memcmp(p, token, sizeof(*token)) != 0) {
+           krb5_crypto_destroy(gssapi_krb5_context, crypto);
+           krb5_data_free(&data);
+           return GSS_S_BAD_MIC;
+       }
+
+       output_message_buffer->value = data.data;
+       output_message_buffer->length = data.length - ec - sizeof(*token);
+    } else {
+       Checksum cksum;
+
+       /* Determine checksum type */
+       ret = krb5_crypto_get_checksum_type(gssapi_krb5_context,
+                                           crypto, &cksum.cksumtype);
+       if (ret != 0) {
+           gssapi_krb5_set_error_string();
+           *minor_status = ret;
+           krb5_crypto_destroy(gssapi_krb5_context, crypto);
+           return GSS_S_FAILURE;
+       }
+
+       cksum.checksum.length = ec;
+
+       /* Check we have at least as much data as the checksum */
+       if (len < cksum.checksum.length) {
+           *minor_status = ERANGE;
+           krb5_crypto_destroy(gssapi_krb5_context, crypto);
+           return GSS_S_BAD_MIC;
+       }
+
+       /* Length now is of the plaintext only, no checksum */
+       len -= cksum.checksum.length;
+       cksum.checksum.data = p + len;
+
+       output_message_buffer->length = len; /* for later */
+       output_message_buffer->value = malloc(len + sizeof(*token));
+       if (output_message_buffer->value == NULL) {
+           *minor_status = ENOMEM;
+           krb5_crypto_destroy(gssapi_krb5_context, crypto);
+           return GSS_S_FAILURE;
+       }
+
+       /* Checksum is over (plaintext-data | "header") */
+       memcpy(output_message_buffer->value, p, len);
+       memcpy((u_char *)output_message_buffer->value + len, 
+              token, sizeof(*token));
+
+       /* EC is not included in checksum calculation */
+       token = (gss_cfx_wrap_token)((u_char *)output_message_buffer->value +
+                                    len);
+       token->EC[0]  = 0;
+       token->EC[1]  = 0;
+       token->RRC[0] = 0;
+       token->RRC[1] = 0;
+
+       ret = krb5_verify_checksum(gssapi_krb5_context, crypto,
+                                  usage,
+                                  output_message_buffer->value,
+                                  len + sizeof(*token),
+                                  &cksum);
+       if (ret != 0) {
+           gssapi_krb5_set_error_string();
+           *minor_status = ret;
+           krb5_crypto_destroy(gssapi_krb5_context, crypto);
+           gss_release_buffer(minor_status, output_message_buffer);
+           return GSS_S_BAD_MIC;
+       }
+    }
+
+    krb5_crypto_destroy(gssapi_krb5_context, crypto);
+
+    if (qop_state != NULL) {
+       *qop_state = GSS_C_QOP_DEFAULT;
+    }
+
+    *minor_status = 0;
+    return GSS_S_COMPLETE;
+}
+
+OM_uint32 _gssapi_mic_cfx(OM_uint32 *minor_status,
+                         const gss_ctx_id_t context_handle,
+                         gss_qop_t qop_req,
+                         const gss_buffer_t message_buffer,
+                         gss_buffer_t message_token,
+                         krb5_keyblock *key)
+{
+    krb5_crypto crypto;
+    gss_cfx_mic_token token;
+    krb5_error_code ret;
+    unsigned usage;
+    Checksum cksum;
+    u_char *buf;
+    size_t len;
+    OM_uint32 seq_number;
+
+    ret = krb5_crypto_init(gssapi_krb5_context, key, 0, &crypto);
+    if (ret != 0) {
+       gssapi_krb5_set_error_string();
+       *minor_status = ret;
+       return GSS_S_FAILURE;
+    }
+
+    len = message_buffer->length + sizeof(*token);
+    buf = malloc(len);
+    if (buf == NULL) {
+       *minor_status = ENOMEM;
+       krb5_crypto_destroy(gssapi_krb5_context, crypto);
+       return GSS_S_FAILURE;
+    }
+
+    memcpy(buf, message_buffer->value, message_buffer->length);
+
+    token = (gss_cfx_mic_token)(buf + message_buffer->length);
+    token->TOK_ID[0] = 0x04;
+    token->TOK_ID[1] = 0x04;
+    token->Flags = 0;
+    if ((context_handle->more_flags & LOCAL) == 0)
+       token->Flags |= CFXSentByAcceptor;
+    if (context_handle->more_flags & ACCEPTOR_SUBKEY)
+       token->Flags |= CFXAcceptorSubkey;
+    memset(token->Filler, 0xFF, 5);
+
+    HEIMDAL_MUTEX_lock(&context_handle->ctx_id_mutex);
+    krb5_auth_con_getlocalseqnumber(gssapi_krb5_context,
+                                   context_handle->auth_context,
+                                   &seq_number);
+    gssapi_encode_be_om_uint32(0,          &token->SND_SEQ[0]);
+    gssapi_encode_be_om_uint32(seq_number, &token->SND_SEQ[4]);
+    krb5_auth_con_setlocalseqnumber(gssapi_krb5_context,
+                                   context_handle->auth_context,
+                                   ++seq_number);
+    HEIMDAL_MUTEX_unlock(&context_handle->ctx_id_mutex);
+
+    if (context_handle->more_flags & LOCAL) {
+       usage = KRB5_KU_USAGE_INITIATOR_SIGN;
+    } else {
+       usage = KRB5_KU_USAGE_ACCEPTOR_SIGN;
+    }
+
+    ret = krb5_create_checksum(gssapi_krb5_context, crypto,
+       usage, 0, buf, len, &cksum);
+    if (ret != 0) {
+       gssapi_krb5_set_error_string();
+       *minor_status = ret;
+       krb5_crypto_destroy(gssapi_krb5_context, crypto);
+       free(buf);
+       return GSS_S_FAILURE;
+    }
+    krb5_crypto_destroy(gssapi_krb5_context, crypto);
+
+    /* Determine MIC length */
+    message_token->length = sizeof(*token) + cksum.checksum.length;
+    message_token->value = malloc(message_token->length);
+    if (message_token->value == NULL) {
+       *minor_status = ENOMEM;
+       free_Checksum(&cksum);
+       free(buf);
+       return GSS_S_FAILURE;
+    }
+
+    /* Token is { "header" | get_mic("header" | plaintext-data) } */
+    memcpy(message_token->value, token, sizeof(*token));
+    memcpy((u_char *)message_token->value + sizeof(*token),
+          cksum.checksum.data, cksum.checksum.length);
+
+    free_Checksum(&cksum);
+    free(buf);
+
+    *minor_status = 0;
+    return GSS_S_COMPLETE;
+}
+
+OM_uint32 _gssapi_verify_mic_cfx(OM_uint32 *minor_status,
+                                const gss_ctx_id_t context_handle,
+                                const gss_buffer_t message_buffer,
+                                const gss_buffer_t token_buffer,
+                                gss_qop_t *qop_state,
+                                krb5_keyblock *key)
+{
+    krb5_crypto crypto;
+    gss_cfx_mic_token token;
+    u_char token_flags;
+    krb5_error_code ret;
+    unsigned usage;
+    OM_uint32 seq_number_lo, seq_number_hi;
+    u_char *buf, *p;
+    Checksum cksum;
+
+    *minor_status = 0;
+
+    if (token_buffer->length < sizeof(*token)) {
+       return GSS_S_DEFECTIVE_TOKEN;
+    }
+
+    p = token_buffer->value;
+
+    token = (gss_cfx_mic_token)p;
+
+    if (token->TOK_ID[0] != 0x04 || token->TOK_ID[1] != 0x04) {
+       return GSS_S_DEFECTIVE_TOKEN;
+    }
+
+    /* Ignore unknown flags */
+    token_flags = token->Flags & (CFXSentByAcceptor | CFXAcceptorSubkey);
+
+    if (token_flags & CFXSentByAcceptor) {
+       if ((context_handle->more_flags & LOCAL) == 0)
+           return GSS_S_DEFECTIVE_TOKEN;
+    }
+    if (context_handle->more_flags & ACCEPTOR_SUBKEY) {
+       if ((token_flags & CFXAcceptorSubkey) == 0)
+           return GSS_S_DEFECTIVE_TOKEN;
+    } else {
+       if (token_flags & CFXAcceptorSubkey)
+           return GSS_S_DEFECTIVE_TOKEN;
+    }
+
+    if (memcmp(token->Filler, "\xff\xff\xff\xff\xff", 5) != 0) {
+       return GSS_S_DEFECTIVE_TOKEN;
+    }
+
+    /*
+     * Check sequence number
+     */
+    gssapi_decode_be_om_uint32(&token->SND_SEQ[0], &seq_number_hi);
+    gssapi_decode_be_om_uint32(&token->SND_SEQ[4], &seq_number_lo);
+    if (seq_number_hi) {
+       *minor_status = ERANGE;
+       return GSS_S_UNSEQ_TOKEN;
+    }
+
+    HEIMDAL_MUTEX_lock(&context_handle->ctx_id_mutex);
+    ret = _gssapi_msg_order_check(context_handle->order, seq_number_lo);
+    if (ret != 0) {
+       *minor_status = 0;
+       HEIMDAL_MUTEX_unlock(&context_handle->ctx_id_mutex);
+       return ret;
+    }
+    HEIMDAL_MUTEX_unlock(&context_handle->ctx_id_mutex);
+
+    /*
+     * Verify checksum
+     */
+    ret = krb5_crypto_init(gssapi_krb5_context, key, 0, &crypto);
+    if (ret != 0) {
+       gssapi_krb5_set_error_string();
+       *minor_status = ret;
+       return GSS_S_FAILURE;
+    }
+
+    ret = krb5_crypto_get_checksum_type(gssapi_krb5_context, crypto,
+                                       &cksum.cksumtype);
+    if (ret != 0) {
+       gssapi_krb5_set_error_string();
+       *minor_status = ret;
+       krb5_crypto_destroy(gssapi_krb5_context, crypto);
+       return GSS_S_FAILURE;
+    }
+
+    cksum.checksum.data = p + sizeof(*token);
+    cksum.checksum.length = token_buffer->length - sizeof(*token);
+
+    if (context_handle->more_flags & LOCAL) {
+       usage = KRB5_KU_USAGE_ACCEPTOR_SIGN;
+    } else {
+       usage = KRB5_KU_USAGE_INITIATOR_SIGN;
+    }
+
+    buf = malloc(message_buffer->length + sizeof(*token));
+    if (buf == NULL) {
+       *minor_status = ENOMEM;
+       krb5_crypto_destroy(gssapi_krb5_context, crypto);
+       return GSS_S_FAILURE;
+    }
+    memcpy(buf, message_buffer->value, message_buffer->length);
+    memcpy(buf + message_buffer->length, token, sizeof(*token));
+
+    ret = krb5_verify_checksum(gssapi_krb5_context, crypto,
+                              usage,
+                              buf,
+                              sizeof(*token) + message_buffer->length,
+                              &cksum);
+    if (ret != 0) {
+       gssapi_krb5_set_error_string();
+       *minor_status = ret;
+       krb5_crypto_destroy(gssapi_krb5_context, crypto);
+       free(buf);
+       return GSS_S_BAD_MIC;
+    }
+
+    free(buf);
+
+    if (qop_state != NULL) {
+       *qop_state = GSS_C_QOP_DEFAULT;
+    }
+
+    return GSS_S_COMPLETE;
+}
diff --git a/source4/heimdal/lib/gssapi/cfx.h b/source4/heimdal/lib/gssapi/cfx.h
new file mode 100755 (executable)
index 0000000..a587cb9
--- /dev/null
@@ -0,0 +1,104 @@
+/*
+ * Copyright (c) 2003, 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.
+ */
+
+/* $Id: cfx.h,v 1.5 2003/09/22 21:48:35 lha Exp $ */
+
+#ifndef GSSAPI_CFX_H_
+#define GSSAPI_CFX_H_ 1
+
+/*
+ * Implementation of draft-ietf-krb-wg-gssapi-cfx-01.txt
+ */
+
+typedef struct gss_cfx_mic_token_desc_struct {
+       u_char TOK_ID[2]; /* 04 04 */
+       u_char Flags;
+       u_char Filler[5];
+       u_char SND_SEQ[8];
+} gss_cfx_mic_token_desc, *gss_cfx_mic_token;
+
+typedef struct gss_cfx_wrap_token_desc_struct {
+       u_char TOK_ID[2]; /* 04 05 */
+       u_char Flags;
+       u_char Filler;
+       u_char EC[2];
+       u_char RRC[2];
+       u_char SND_SEQ[8];
+} gss_cfx_wrap_token_desc, *gss_cfx_wrap_token;
+
+typedef struct gss_cfx_delete_token_desc_struct {
+       u_char TOK_ID[2]; /* 05 04 */
+       u_char Flags;
+       u_char Filler[5];
+       u_char SND_SEQ[8];
+} gss_cfx_delete_token_desc, *gss_cfx_delete_token;
+
+OM_uint32 _gssapi_wrap_size_cfx(OM_uint32 *minor_status,
+                               const gss_ctx_id_t context_handle,
+                               int conf_req_flag,
+                               gss_qop_t qop_req,
+                               OM_uint32 req_output_size,
+                               OM_uint32 *max_input_size,
+                               krb5_keyblock *key);
+
+OM_uint32 _gssapi_wrap_cfx(OM_uint32 *minor_status,
+                          const gss_ctx_id_t context_handle,
+                          int conf_req_flag,
+                          gss_qop_t qop_req,
+                          const gss_buffer_t input_message_buffer,
+                          int *conf_state,
+                          gss_buffer_t output_message_buffer,
+                          krb5_keyblock *key);
+
+OM_uint32 _gssapi_unwrap_cfx(OM_uint32 *minor_status,
+                            const gss_ctx_id_t context_handle,
+                            const gss_buffer_t input_message_buffer,
+                            gss_buffer_t output_message_buffer,
+                            int *conf_state,
+                            gss_qop_t *qop_state,
+                            krb5_keyblock *key);
+
+OM_uint32 _gssapi_mic_cfx(OM_uint32 *minor_status,
+                         const gss_ctx_id_t context_handle,
+                         gss_qop_t qop_req,
+                         const gss_buffer_t message_buffer,
+                         gss_buffer_t message_token,
+                         krb5_keyblock *key);
+
+OM_uint32 _gssapi_verify_mic_cfx(OM_uint32 *minor_status,
+                                const gss_ctx_id_t context_handle,
+                                const gss_buffer_t message_buffer,
+                                const gss_buffer_t token_buffer,
+                                gss_qop_t *qop_state,
+                                krb5_keyblock *key);
+
+#endif /* GSSAPI_CFX_H_ */
diff --git a/source4/heimdal/lib/gssapi/compat.c b/source4/heimdal/lib/gssapi/compat.c
new file mode 100644 (file)
index 0000000..5605c48
--- /dev/null
@@ -0,0 +1,154 @@
+/*
+ * 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 "gssapi_locl.h"
+
+RCSID("$Id: compat.c,v 1.10 2005/05/30 20:51:51 lha Exp $");
+
+
+krb5_error_code
+_gss_check_compat(OM_uint32 *minor_status, gss_name_t name, 
+                 const char *option, krb5_boolean *compat, 
+                 krb5_boolean match_val)
+{
+    krb5_error_code ret = 0;
+    char **p, **q;
+    krb5_principal match;
+
+
+    p = krb5_config_get_strings(gssapi_krb5_context, NULL, "gssapi",
+                               option, NULL);
+    if(p == NULL)
+       return 0;
+
+    match = NULL;
+    for(q = p; *q; q++) {
+       ret = krb5_parse_name(gssapi_krb5_context, *q, &match);
+       if (ret)
+           break;
+
+       if (krb5_principal_match(gssapi_krb5_context, name, match)) {
+           *compat = match_val;
+           break;
+       }
+       
+       krb5_free_principal(gssapi_krb5_context, match);
+       match = NULL;
+    }
+    if (match)
+       krb5_free_principal(gssapi_krb5_context, match);
+    krb5_config_free_strings(p);
+
+    if (ret) {
+       if (minor_status)
+           *minor_status = ret;
+       return GSS_S_FAILURE;
+    }
+
+    return 0;
+}
+
+/*
+ * ctx->ctx_id_mutex is assumed to be locked
+ */
+
+OM_uint32
+_gss_DES3_get_mic_compat(OM_uint32 *minor_status, gss_ctx_id_t ctx)
+{
+    krb5_boolean use_compat = FALSE;
+    OM_uint32 ret;
+
+    if ((ctx->more_flags & COMPAT_OLD_DES3_SELECTED) == 0) {
+       ret = _gss_check_compat(minor_status, ctx->target, 
+                               "broken_des3_mic", &use_compat, TRUE);
+       if (ret)
+           return ret;
+       ret = _gss_check_compat(minor_status, ctx->target, 
+                               "correct_des3_mic", &use_compat, FALSE);
+       if (ret)
+           return ret;
+
+       if (use_compat)
+           ctx->more_flags |= COMPAT_OLD_DES3;
+       ctx->more_flags |= COMPAT_OLD_DES3_SELECTED;
+    }
+    return 0;
+}
+
+OM_uint32
+gss_krb5_compat_des3_mic(OM_uint32 *minor_status, gss_ctx_id_t ctx, int on)
+{
+    *minor_status = 0;
+
+    HEIMDAL_MUTEX_lock(&ctx->ctx_id_mutex);
+    if (on) {
+       ctx->more_flags |= COMPAT_OLD_DES3;
+    } else {
+       ctx->more_flags &= ~COMPAT_OLD_DES3;
+    }
+    ctx->more_flags |= COMPAT_OLD_DES3_SELECTED;
+    HEIMDAL_MUTEX_unlock(&ctx->ctx_id_mutex);
+
+    return 0;
+}
+
+/*
+ * For compatability with the Windows SPNEGO implementation, the
+ * default is to ignore the mechListMIC unless the initiator specified
+ * CFX or configured in krb5.conf with the option
+ *     [gssapi]require_mechlist_mic=target-principal-pattern.
+ * The option is valid for both initiator and acceptor.
+ */
+OM_uint32
+_gss_spnego_require_mechlist_mic(OM_uint32 *minor_status,
+                                gss_ctx_id_t ctx,
+                                krb5_boolean *require_mic)
+{
+    OM_uint32 ret;
+    int is_cfx = 0;
+
+    gsskrb5_is_cfx(ctx, &is_cfx);
+    if (is_cfx) {
+       /* CFX session key was used */
+       *require_mic = TRUE;
+    } else {
+       *require_mic = FALSE;
+       ret = _gss_check_compat(minor_status, ctx->target, 
+                               "require_mechlist_mic",
+                               require_mic, TRUE);
+       if (ret)
+           return ret;
+    }
+    *minor_status = 0;
+    return GSS_S_COMPLETE;
+}
diff --git a/source4/heimdal/lib/gssapi/context_time.c b/source4/heimdal/lib/gssapi/context_time.c
new file mode 100644 (file)
index 0000000..e13480c
--- /dev/null
@@ -0,0 +1,87 @@
+/*
+ * 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 "gssapi_locl.h"
+
+RCSID("$Id: context_time.c,v 1.10 2003/06/03 15:08:00 lha Exp $");
+
+OM_uint32
+gssapi_lifetime_left(OM_uint32 *minor_status, 
+                    OM_uint32 lifetime,
+                    OM_uint32 *lifetime_rec)
+{
+    krb5_timestamp timeret;
+    krb5_error_code kret;
+
+    kret = krb5_timeofday(gssapi_krb5_context, &timeret);
+    if (kret) {
+       *minor_status = kret;
+       gssapi_krb5_set_error_string ();
+       return GSS_S_FAILURE;
+    }
+
+    if (lifetime < timeret) 
+       *lifetime_rec = 0;
+    else
+       *lifetime_rec = lifetime - timeret;
+
+    return GSS_S_COMPLETE;
+}
+
+
+OM_uint32 gss_context_time
+           (OM_uint32 * minor_status,
+            const gss_ctx_id_t context_handle,
+            OM_uint32 * time_rec
+           )
+{
+    OM_uint32 lifetime;
+    OM_uint32 major_status;
+
+    GSSAPI_KRB5_INIT ();
+
+    HEIMDAL_MUTEX_lock(&context_handle->ctx_id_mutex);
+    lifetime = context_handle->lifetime;
+    HEIMDAL_MUTEX_unlock(&context_handle->ctx_id_mutex);
+
+    major_status = gssapi_lifetime_left(minor_status, lifetime, time_rec);
+    if (major_status != GSS_S_COMPLETE)
+       return major_status;
+
+    *minor_status = 0;
+
+    if (*time_rec == 0)
+       return GSS_S_CONTEXT_EXPIRED;
+       
+    return GSS_S_COMPLETE;
+}
diff --git a/source4/heimdal/lib/gssapi/copy_ccache.c b/source4/heimdal/lib/gssapi/copy_ccache.c
new file mode 100644 (file)
index 0000000..4f2b3f4
--- /dev/null
@@ -0,0 +1,134 @@
+/*
+ * Copyright (c) 2000 - 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 "gssapi_locl.h"
+
+RCSID("$Id: copy_ccache.c,v 1.7 2003/09/01 15:11:09 lha Exp $");
+
+OM_uint32
+gss_krb5_copy_ccache(OM_uint32 *minor_status,
+                    gss_cred_id_t cred,
+                    krb5_ccache out)
+{
+    krb5_error_code kret;
+
+    HEIMDAL_MUTEX_lock(&cred->cred_id_mutex);
+
+    if (cred->ccache == NULL) {
+       HEIMDAL_MUTEX_unlock(&cred->cred_id_mutex);
+       *minor_status = EINVAL;
+       return GSS_S_FAILURE;
+    }
+
+    kret = krb5_cc_copy_cache(gssapi_krb5_context, cred->ccache, out);
+    HEIMDAL_MUTEX_unlock(&cred->cred_id_mutex);
+    if (kret) {
+       *minor_status = kret;
+       gssapi_krb5_set_error_string ();
+       return GSS_S_FAILURE;
+    }
+    *minor_status = 0;
+    return GSS_S_COMPLETE;
+}
+
+OM_uint32
+gsskrb5_extract_authz_data_from_sec_context(OM_uint32 *minor_status,
+                                           gss_ctx_id_t context_handle,
+                                           int ad_type,
+                                           gss_buffer_t ad_data)
+{
+    krb5_error_code ret;
+    krb5_data data;
+    
+    ad_data->value = NULL;
+    ad_data->length = 0;
+    
+    HEIMDAL_MUTEX_lock(&context_handle->ctx_id_mutex);
+    if (context_handle->ticket == NULL) {
+       HEIMDAL_MUTEX_unlock(&context_handle->ctx_id_mutex);
+       *minor_status = EINVAL;
+       return GSS_S_FAILURE;
+    }
+
+    ret = krb5_ticket_get_authorization_data_type(gssapi_krb5_context,
+                                                 context_handle->ticket,
+                                                 ad_type,
+                                                 &data);
+    HEIMDAL_MUTEX_unlock(&context_handle->ctx_id_mutex);
+    if (ret) {
+       *minor_status = ret;
+       return GSS_S_FAILURE;
+    }
+    
+    ad_data->value = malloc(data.length);
+    if (ad_data->value == NULL) {
+       krb5_data_free(&data);
+       *minor_status = ENOMEM;
+       return GSS_S_FAILURE;
+    }
+
+    ad_data->length = data.length;
+    memcpy(ad_data->value, data.data, ad_data->length);
+    krb5_data_free(&data);
+           
+    *minor_status = 0;
+    return GSS_S_COMPLETE;
+}
+
+OM_uint32 gss_krb5_copy_service_keyblock
+        (OM_uint32 *minor_status,
+        gss_ctx_id_t context_handle,
+        struct EncryptionKey **out)
+{
+    krb5_error_code ret;
+    
+    HEIMDAL_MUTEX_lock(&context_handle->ctx_id_mutex);
+    if (context_handle->service_keyblock == NULL) {
+       HEIMDAL_MUTEX_unlock(&context_handle->ctx_id_mutex);
+       *minor_status = EINVAL;
+       return GSS_S_FAILURE;
+    }
+
+    ret = krb5_copy_keyblock(gssapi_krb5_context,
+                            context_handle->service_keyblock, 
+                            out);
+
+    HEIMDAL_MUTEX_unlock(&context_handle->ctx_id_mutex);
+    if (ret) {
+       *minor_status = ret;
+       return GSS_S_FAILURE;
+    }
+    
+    *minor_status = 0;
+    return GSS_S_COMPLETE;
+}
diff --git a/source4/heimdal/lib/gssapi/create_emtpy_oid_set.c b/source4/heimdal/lib/gssapi/create_emtpy_oid_set.c
new file mode 100644 (file)
index 0000000..1a25e0d
--- /dev/null
@@ -0,0 +1,52 @@
+/*
+ * 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 "gssapi_locl.h"
+
+RCSID("$Id: create_emtpy_oid_set.c,v 1.5 2003/03/16 17:47:07 lha Exp $");
+
+OM_uint32 gss_create_empty_oid_set (
+            OM_uint32 * minor_status,
+            gss_OID_set * oid_set
+           )
+{
+  *oid_set = malloc(sizeof(**oid_set));
+  if (*oid_set == NULL) {
+    *minor_status = ENOMEM;
+    return GSS_S_FAILURE;
+  }
+  (*oid_set)->count = 0;
+  (*oid_set)->elements = NULL;
+  *minor_status = 0;
+  return GSS_S_COMPLETE;
+}
diff --git a/source4/heimdal/lib/gssapi/decapsulate.c b/source4/heimdal/lib/gssapi/decapsulate.c
new file mode 100644 (file)
index 0000000..90e037f
--- /dev/null
@@ -0,0 +1,209 @@
+/*
+ * 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 "gssapi_locl.h"
+
+RCSID("$Id: decapsulate.c,v 1.12 2005/06/16 20:40:49 lha Exp $");
+
+/*
+ * return the length of the mechanism in token or -1
+ * (which implies that the token was bad - GSS_S_DEFECTIVE_TOKEN
+ */
+
+ssize_t
+gssapi_krb5_get_mech (const u_char *ptr,
+                     size_t total_len,
+                     const u_char **mech_ret)
+{
+    size_t len, len_len, mech_len, foo;
+    const u_char *p = ptr;
+    int e;
+
+    if (total_len < 1)
+       return -1;
+    if (*p++ != 0x60)
+       return -1;
+    e = der_get_length (p, total_len - 1, &len, &len_len);
+    if (e || 1 + len_len + len != total_len)
+       return -1;
+    p += len_len;
+    if (*p++ != 0x06)
+       return -1;
+    e = der_get_length (p, total_len - 1 - len_len - 1,
+                       &mech_len, &foo);
+    if (e)
+       return -1;
+    p += foo;
+    *mech_ret = p;
+    return mech_len;
+}
+
+OM_uint32
+_gssapi_verify_mech_header(u_char **str,
+                          size_t total_len,
+                          gss_OID mech)
+{
+    const u_char *p;
+    ssize_t mech_len;
+
+    mech_len = gssapi_krb5_get_mech (*str, total_len, &p);
+    if (mech_len < 0)
+       return GSS_S_DEFECTIVE_TOKEN;
+
+    if (mech_len != mech->length)
+       return GSS_S_BAD_MECH;
+    if (memcmp(p,
+              mech->elements,
+              mech->length) != 0)
+       return GSS_S_BAD_MECH;
+    p += mech_len;
+    *str = rk_UNCONST(p);
+    return GSS_S_COMPLETE;
+}
+
+OM_uint32
+gssapi_krb5_verify_header(u_char **str,
+                         size_t total_len,
+                         const u_char *type,
+                         gss_OID oid)
+{
+    OM_uint32 ret;
+    size_t len;
+    u_char *p = *str;
+
+    ret = _gssapi_verify_mech_header(str, total_len, oid);
+    if (ret)
+       return ret;
+
+    len = total_len - (*str - p);
+
+    if (len < 2)
+       return GSS_S_DEFECTIVE_TOKEN;
+
+    if (memcmp (*str, type, 2) != 0)
+       return GSS_S_DEFECTIVE_TOKEN;
+    *str += 2;
+
+    return 0;
+}
+
+/*
+ * Remove the GSS-API wrapping from `in_token' giving `out_data.
+ * Does not copy data, so just free `in_token'.
+ */
+
+OM_uint32
+_gssapi_decapsulate(
+    OM_uint32 *minor_status,
+    gss_buffer_t input_token_buffer,
+    krb5_data *out_data,
+    const gss_OID mech
+)
+{
+    u_char *p;
+    OM_uint32 ret;
+
+    p = input_token_buffer->value;
+    ret = _gssapi_verify_mech_header(&p,
+                                   input_token_buffer->length,
+                                   mech);
+    if (ret) {
+       *minor_status = 0;
+       return ret;
+    }
+
+    out_data->length = input_token_buffer->length -
+       (p - (u_char *)input_token_buffer->value);
+    out_data->data   = p;
+    return GSS_S_COMPLETE;
+}
+
+/*
+ * Remove the GSS-API wrapping from `in_token' giving `out_data.
+ * Does not copy data, so just free `in_token'.
+ */
+
+OM_uint32
+gssapi_krb5_decapsulate(OM_uint32 *minor_status,    
+                       gss_buffer_t input_token_buffer,
+                       krb5_data *out_data,
+                       const char *type,
+                       gss_OID oid)
+{
+    u_char *p;
+    OM_uint32 ret;
+
+    p = input_token_buffer->value;
+    ret = gssapi_krb5_verify_header(&p,
+                                   input_token_buffer->length,
+                                   type,
+                                   oid);
+    if (ret) {
+       *minor_status = 0;
+       return ret;
+    }
+
+    out_data->length = input_token_buffer->length -
+       (p - (u_char *)input_token_buffer->value);
+    out_data->data   = p;
+    return GSS_S_COMPLETE;
+}
+
+/*
+ * Verify padding of a gss wrapped message and return its length.
+ */
+
+OM_uint32
+_gssapi_verify_pad(gss_buffer_t wrapped_token, 
+                  size_t datalen,
+                  size_t *padlen)
+{
+    u_char *pad;
+    size_t padlength;
+    int i;
+
+    pad = (u_char *)wrapped_token->value + wrapped_token->length - 1;
+    padlength = *pad;
+
+    if (padlength > datalen)
+       return GSS_S_BAD_MECH;
+
+    for (i = padlength; i > 0 && *pad == padlength; i--, pad--)
+       ;
+    if (i != 0)
+       return GSS_S_BAD_MIC;
+
+    *padlen = padlength;
+
+    return 0;
+}
diff --git a/source4/heimdal/lib/gssapi/delete_sec_context.c b/source4/heimdal/lib/gssapi/delete_sec_context.c
new file mode 100644 (file)
index 0000000..83658fa
--- /dev/null
@@ -0,0 +1,77 @@
+/*
+ * 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 "gssapi_locl.h"
+
+RCSID("$Id: delete_sec_context.c,v 1.15 2005/04/27 17:48:17 lha Exp $");
+
+OM_uint32 gss_delete_sec_context
+           (OM_uint32 * minor_status,
+            gss_ctx_id_t * context_handle,
+            gss_buffer_t output_token
+           )
+{
+    GSSAPI_KRB5_INIT ();
+
+    if (output_token) {
+       output_token->length = 0;
+       output_token->value  = NULL;
+    }
+
+    HEIMDAL_MUTEX_lock(&(*context_handle)->ctx_id_mutex);
+
+    krb5_auth_con_free (gssapi_krb5_context,
+                       (*context_handle)->auth_context);
+    if((*context_handle)->source)
+       krb5_free_principal (gssapi_krb5_context,
+                            (*context_handle)->source);
+    if((*context_handle)->target)
+       krb5_free_principal (gssapi_krb5_context,
+                            (*context_handle)->target);
+    if ((*context_handle)->ticket)
+       krb5_free_ticket (gssapi_krb5_context,
+                         (*context_handle)->ticket);
+    if ((*context_handle)->service_keyblock)
+       krb5_free_keyblock (gssapi_krb5_context,
+                         (*context_handle)->service_keyblock);
+    if((*context_handle)->order)
+       _gssapi_msg_order_destroy(&(*context_handle)->order);
+
+    HEIMDAL_MUTEX_unlock(&(*context_handle)->ctx_id_mutex);
+    HEIMDAL_MUTEX_destroy(&(*context_handle)->ctx_id_mutex);
+    memset(*context_handle, 0, sizeof(**context_handle));
+    free (*context_handle);
+    *context_handle = GSS_C_NO_CONTEXT;
+    *minor_status = 0;
+    return GSS_S_COMPLETE;
+}
diff --git a/source4/heimdal/lib/gssapi/display_name.c b/source4/heimdal/lib/gssapi/display_name.c
new file mode 100644 (file)
index 0000000..27a232f
--- /dev/null
@@ -0,0 +1,73 @@
+/*
+ * 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 "gssapi_locl.h"
+
+RCSID("$Id: display_name.c,v 1.9 2003/03/16 17:46:11 lha Exp $");
+
+OM_uint32 gss_display_name
+           (OM_uint32 * minor_status,
+            const gss_name_t input_name,
+            gss_buffer_t output_name_buffer,
+            gss_OID * output_name_type
+           )
+{
+    krb5_error_code kret;
+    char *buf;
+    size_t len;
+
+    GSSAPI_KRB5_INIT ();
+    kret = krb5_unparse_name (gssapi_krb5_context,
+                             input_name,
+                             &buf);
+    if (kret) {
+       *minor_status = kret;
+       gssapi_krb5_set_error_string ();
+       return GSS_S_FAILURE;
+    }
+    len = strlen (buf);
+    output_name_buffer->length = len;
+    output_name_buffer->value  = malloc(len + 1);
+    if (output_name_buffer->value == NULL) {
+       free (buf);
+       *minor_status = ENOMEM;
+       return GSS_S_FAILURE;
+    }
+    memcpy (output_name_buffer->value, buf, len);
+    ((char *)output_name_buffer->value)[len] = '\0';
+    free (buf);
+    if (output_name_type)
+       *output_name_type = GSS_KRB5_NT_PRINCIPAL_NAME;
+    *minor_status = 0;
+    return GSS_S_COMPLETE;
+}
diff --git a/source4/heimdal/lib/gssapi/display_status.c b/source4/heimdal/lib/gssapi/display_status.c
new file mode 100644 (file)
index 0000000..2c84628
--- /dev/null
@@ -0,0 +1,208 @@
+/*
+ * Copyright (c) 1998 - 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 "gssapi_locl.h"
+
+RCSID("$Id: display_status.c,v 1.12 2005/03/16 13:15:03 lha Exp $");
+
+static char *
+calling_error(OM_uint32 v)
+{
+    static char *msgs[] = {
+       NULL,                   /* 0 */
+       "A required input parameter could not be read.", /*  */
+       "A required output parameter could not be written.", /*  */
+       "A parameter was malformed"
+    };
+
+    v >>= GSS_C_CALLING_ERROR_OFFSET;
+
+    if (v == 0)
+       return "";
+    else if (v >= sizeof(msgs)/sizeof(*msgs))
+       return "unknown calling error";
+    else
+       return msgs[v];
+}
+
+static char *
+routine_error(OM_uint32 v)
+{
+    static char *msgs[] = {
+       NULL,                   /* 0 */
+       "An unsupported mechanism was requested",
+       "An invalid name was supplied",
+       "A supplied name was of an unsupported type",
+       "Incorrect channel bindings were supplied",
+       "An invalid status code was supplied",
+       "A token had an invalid MIC",
+       "No credentials were supplied, "
+       "or the credentials were unavailable or inaccessible.",
+       "No context has been established",
+       "A token was invalid",
+       "A credential was invalid",
+       "The referenced credentials have expired",
+       "The context has expired",
+       "Miscellaneous failure (see text)",
+       "The quality-of-protection requested could not be provide",
+       "The operation is forbidden by local security policy",
+       "The operation or option is not available",
+       "The requested credential element already exists",
+       "The provided name was not a mechanism name.",
+    };
+
+    v >>= GSS_C_ROUTINE_ERROR_OFFSET;
+
+    if (v == 0)
+       return "";
+    else if (v >= sizeof(msgs)/sizeof(*msgs))
+       return "unknown routine error";
+    else
+       return msgs[v];
+}
+
+static char *
+supplementary_error(OM_uint32 v)
+{
+    static char *msgs[] = {
+       "normal completion",
+       "continuation call to routine required",
+       "duplicate per-message token detected",
+       "timed-out per-message token detected",
+       "reordered (early) per-message token detected",
+       "skipped predecessor token(s) detected"
+    };
+
+    v >>= GSS_C_SUPPLEMENTARY_OFFSET;
+
+    if (v >= sizeof(msgs)/sizeof(*msgs))
+       return "unknown routine error";
+    else
+       return msgs[v];
+}
+
+void
+gssapi_krb5_set_error_string (void)
+{
+    struct gssapi_thr_context *ctx = gssapi_get_thread_context(1);
+    char *e;
+
+    if (ctx == NULL)
+       return;
+    HEIMDAL_MUTEX_lock(&ctx->mutex);
+    if (ctx->error_string)
+       free(ctx->error_string);
+    e = krb5_get_error_string(gssapi_krb5_context);
+    if (e == NULL)
+       ctx->error_string = NULL;
+    else {
+       /* ignore failures, will use status code instead */
+       ctx->error_string = strdup(e); 
+       krb5_free_error_string(gssapi_krb5_context, e);
+    }
+    HEIMDAL_MUTEX_unlock(&ctx->mutex);
+}
+
+char *
+gssapi_krb5_get_error_string (void)
+{
+    struct gssapi_thr_context *ctx = gssapi_get_thread_context(0);
+    char *ret;
+
+    if (ctx == NULL)
+       return NULL;
+    HEIMDAL_MUTEX_lock(&ctx->mutex);
+    ret = ctx->error_string;
+    ctx->error_string = NULL;
+    HEIMDAL_MUTEX_unlock(&ctx->mutex);
+    return ret;
+}
+
+OM_uint32 gss_display_status
+           (OM_uint32          *minor_status,
+           OM_uint32            status_value,
+           int                  status_type,
+           const gss_OID        mech_type,
+           OM_uint32           *message_context,
+           gss_buffer_t         status_string)
+{
+  char *buf;
+
+  GSSAPI_KRB5_INIT ();
+
+  status_string->length = 0;
+  status_string->value = NULL;
+
+  if (gss_oid_equal(mech_type, GSS_C_NO_OID) == 0 &&
+      gss_oid_equal(mech_type, GSS_KRB5_MECHANISM) == 0) {
+      *minor_status = 0;
+      return GSS_C_GSS_CODE;
+  }
+
+  if (status_type == GSS_C_GSS_CODE) {
+      if (GSS_SUPPLEMENTARY_INFO(status_value))
+         asprintf(&buf, "%s", 
+                  supplementary_error(GSS_SUPPLEMENTARY_INFO(status_value)));
+      else
+         asprintf (&buf, "%s %s",
+                   calling_error(GSS_CALLING_ERROR(status_value)),
+                   routine_error(GSS_ROUTINE_ERROR(status_value)));
+  } else if (status_type == GSS_C_MECH_CODE) {
+      buf = gssapi_krb5_get_error_string ();
+      if (buf == NULL) {
+         const char *tmp = krb5_get_err_text (gssapi_krb5_context,
+                                              status_value);
+         if (tmp == NULL)
+             asprintf(&buf, "unknown mech error-code %u",
+                      (unsigned)status_value);
+         else
+             buf = strdup(tmp);
+      }
+  } else {
+      *minor_status = EINVAL;
+      return GSS_S_BAD_STATUS;
+  }
+
+  if (buf == NULL) {
+      *minor_status = ENOMEM;
+      return GSS_S_FAILURE;
+  }
+
+  *message_context = 0;
+  *minor_status = 0;
+
+  status_string->length = strlen(buf);
+  status_string->value  = buf;
+  
+  return GSS_S_COMPLETE;
+}
diff --git a/source4/heimdal/lib/gssapi/duplicate_name.c b/source4/heimdal/lib/gssapi/duplicate_name.c
new file mode 100644 (file)
index 0000000..2b54e90
--- /dev/null
@@ -0,0 +1,59 @@
+/*
+ * 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 "gssapi_locl.h"
+
+RCSID("$Id: duplicate_name.c,v 1.7 2003/03/16 17:44:26 lha Exp $");
+
+OM_uint32 gss_duplicate_name (
+            OM_uint32 * minor_status,
+            const gss_name_t src_name,
+            gss_name_t * dest_name
+           )
+{
+    krb5_error_code kret;
+
+    GSSAPI_KRB5_INIT ();
+
+    kret = krb5_copy_principal (gssapi_krb5_context,
+                               src_name,
+                               dest_name);
+    if (kret) {
+       *minor_status = kret;
+       gssapi_krb5_set_error_string ();
+       return GSS_S_FAILURE;
+    } else {
+       *minor_status = 0;
+       return GSS_S_COMPLETE;
+    }
+}
diff --git a/source4/heimdal/lib/gssapi/encapsulate.c b/source4/heimdal/lib/gssapi/encapsulate.c
new file mode 100644 (file)
index 0000000..4d488a6
--- /dev/null
@@ -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 "gssapi_locl.h"
+
+RCSID("$Id: encapsulate.c,v 1.8 2003/09/04 18:08:55 lha Exp $");
+
+void
+_gssapi_encap_length (size_t data_len,
+                     size_t *len,
+                     size_t *total_len,
+                     const gss_OID mech)
+{
+    size_t len_len;
+
+    *len = 1 + 1 + mech->length + data_len;
+
+    len_len = length_len(*len);
+
+    *total_len = 1 + len_len + *len;
+}
+
+void
+gssapi_krb5_encap_length (size_t data_len,
+                         size_t *len,
+                         size_t *total_len,
+                         const gss_OID mech)
+{
+    _gssapi_encap_length(data_len + 2, len, total_len, mech);
+}
+
+u_char *
+gssapi_krb5_make_header (u_char *p,
+                        size_t len,
+                        const u_char *type,
+                        const gss_OID mech)
+{
+    p = _gssapi_make_mech_header(p, len, mech);
+    memcpy (p, type, 2);
+    p += 2;
+    return p;
+}
+
+u_char *
+_gssapi_make_mech_header(u_char *p,
+                        size_t len,
+                        const gss_OID mech)
+{
+    int e;
+    size_t len_len, foo;
+
+    *p++ = 0x60;
+    len_len = length_len(len);
+    e = der_put_length (p + len_len - 1, len_len, len, &foo);
+    if(e || foo != len_len)
+       abort ();
+    p += len_len;
+    *p++ = 0x06;
+    *p++ = mech->length;
+    memcpy (p, mech->elements, mech->length);
+    p += mech->length;
+    return p;
+}
+
+/*
+ * Give it a krb5_data and it will encapsulate with extra GSS-API wrappings.
+ */
+
+OM_uint32
+_gssapi_encapsulate(
+    OM_uint32 *minor_status,
+    const krb5_data *in_data,
+    gss_buffer_t output_token,
+    const gss_OID mech
+)
+{
+    size_t len, outer_len;
+    u_char *p;
+
+    _gssapi_encap_length (in_data->length, &len, &outer_len, mech);
+    
+    output_token->length = outer_len;
+    output_token->value  = malloc (outer_len);
+    if (output_token->value == NULL) {
+       *minor_status = ENOMEM;
+       return GSS_S_FAILURE;
+    }  
+
+    p = _gssapi_make_mech_header (output_token->value, len, mech);
+    memcpy (p, in_data->data, in_data->length);
+    return GSS_S_COMPLETE;
+}
+
+/*
+ * Give it a krb5_data and it will encapsulate with extra GSS-API krb5
+ * wrappings.
+ */
+
+OM_uint32
+gssapi_krb5_encapsulate(
+                       OM_uint32 *minor_status,    
+                       const krb5_data *in_data,
+                       gss_buffer_t output_token,
+                       const u_char *type,
+                       const gss_OID mech
+)
+{
+    size_t len, outer_len;
+    u_char *p;
+
+    gssapi_krb5_encap_length (in_data->length, &len, &outer_len, mech);
+    
+    output_token->length = outer_len;
+    output_token->value  = malloc (outer_len);
+    if (output_token->value == NULL) {
+       *minor_status = ENOMEM;
+       return GSS_S_FAILURE;
+    }  
+
+    p = gssapi_krb5_make_header (output_token->value, len, type, mech);
+    memcpy (p, in_data->data, in_data->length);
+    return GSS_S_COMPLETE;
+}
diff --git a/source4/heimdal/lib/gssapi/external.c b/source4/heimdal/lib/gssapi/external.c
new file mode 100644 (file)
index 0000000..f3e9718
--- /dev/null
@@ -0,0 +1,270 @@
+/*
+ * 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 "gssapi_locl.h"
+
+RCSID("$Id: external.c,v 1.6 2003/09/08 15:34:19 lha Exp $");
+
+/*
+ * The implementation must reserve static storage for a
+ * gss_OID_desc object containing the value
+ * {10, (void *)"\x2a\x86\x48\x86\xf7\x12"
+ *              "\x01\x02\x01\x01"},
+ * corresponding to an object-identifier value of
+ * {iso(1) member-body(2) United States(840) mit(113554)
+ *  infosys(1) gssapi(2) generic(1) user_name(1)}.  The constant
+ * GSS_C_NT_USER_NAME should be initialized to point
+ * to that gss_OID_desc.
+ */
+
+static gss_OID_desc gss_c_nt_user_name_oid_desc =
+{10, (void *)"\x2a\x86\x48\x86\xf7\x12"
+ "\x01\x02\x01\x01"};
+
+gss_OID GSS_C_NT_USER_NAME = &gss_c_nt_user_name_oid_desc;
+
+/*
+ * The implementation must reserve static storage for a
+ * gss_OID_desc object containing the value
+ * {10, (void *)"\x2a\x86\x48\x86\xf7\x12"
+ *              "\x01\x02\x01\x02"},
+ * corresponding to an object-identifier value of
+ * {iso(1) member-body(2) United States(840) mit(113554)
+ *  infosys(1) gssapi(2) generic(1) machine_uid_name(2)}.
+ * The constant GSS_C_NT_MACHINE_UID_NAME should be
+ * initialized to point to that gss_OID_desc.
+ */
+
+static gss_OID_desc gss_c_nt_machine_uid_name_oid_desc =
+{10, (void *)"\x2a\x86\x48\x86\xf7\x12"
+ "\x01\x02\x01\x02"};
+
+gss_OID GSS_C_NT_MACHINE_UID_NAME = &gss_c_nt_machine_uid_name_oid_desc;
+
+/*
+ * The implementation must reserve static storage for a
+ * gss_OID_desc object containing the value
+ * {10, (void *)"\x2a\x86\x48\x86\xf7\x12"
+ *              "\x01\x02\x01\x03"},
+ * corresponding to an object-identifier value of
+ * {iso(1) member-body(2) United States(840) mit(113554)
+ *  infosys(1) gssapi(2) generic(1) string_uid_name(3)}.
+ * The constant GSS_C_NT_STRING_UID_NAME should be
+ * initialized to point to that gss_OID_desc.
+ */
+
+static gss_OID_desc gss_c_nt_string_uid_name_oid_desc =
+{10, (void *)"\x2a\x86\x48\x86\xf7\x12"
+ "\x01\x02\x01\x03"};
+
+gss_OID GSS_C_NT_STRING_UID_NAME = &gss_c_nt_string_uid_name_oid_desc;
+
+/*
+ * The implementation must reserve static storage for a
+ * gss_OID_desc object containing the value
+ * {6, (void *)"\x2b\x06\x01\x05\x06\x02"},
+ * corresponding to an object-identifier value of
+ * {iso(1) org(3) dod(6) internet(1) security(5)
+ * nametypes(6) gss-host-based-services(2)).  The constant
+ * GSS_C_NT_HOSTBASED_SERVICE_X should be initialized to point
+ * to that gss_OID_desc.  This is a deprecated OID value, and
+ * implementations wishing to support hostbased-service names
+ * should instead use the GSS_C_NT_HOSTBASED_SERVICE OID,
+ * defined below, to identify such names;
+ * GSS_C_NT_HOSTBASED_SERVICE_X should be accepted a synonym
+ * for GSS_C_NT_HOSTBASED_SERVICE when presented as an input
+ * parameter, but should not be emitted by GSS-API
+ * implementations
+ */
+
+static gss_OID_desc gss_c_nt_hostbased_service_x_oid_desc =
+{6, (void *)"\x2b\x06\x01\x05\x06\x02"};
+
+gss_OID GSS_C_NT_HOSTBASED_SERVICE_X = &gss_c_nt_hostbased_service_x_oid_desc;
+
+/*
+ * The implementation must reserve static storage for a
+ * gss_OID_desc object containing the value
+ * {10, (void *)"\x2a\x86\x48\x86\xf7\x12"
+ *              "\x01\x02\x01\x04"}, corresponding to an
+ * object-identifier value of {iso(1) member-body(2)
+ * Unites States(840) mit(113554) infosys(1) gssapi(2)
+ * generic(1) service_name(4)}.  The constant
+ * GSS_C_NT_HOSTBASED_SERVICE should be initialized
+ * to point to that gss_OID_desc.
+ */
+static gss_OID_desc gss_c_nt_hostbased_service_oid_desc =
+{10, (void *)"\x2a\x86\x48\x86\xf7\x12" "\x01\x02\x01\x04"};
+
+gss_OID GSS_C_NT_HOSTBASED_SERVICE = &gss_c_nt_hostbased_service_oid_desc;
+
+/*
+ * The implementation must reserve static storage for a
+ * gss_OID_desc object containing the value
+ * {6, (void *)"\x2b\x06\01\x05\x06\x03"},
+ * corresponding to an object identifier value of
+ * {1(iso), 3(org), 6(dod), 1(internet), 5(security),
+ * 6(nametypes), 3(gss-anonymous-name)}.  The constant
+ * and GSS_C_NT_ANONYMOUS should be initialized to point
+ * to that gss_OID_desc.
+ */
+
+static gss_OID_desc gss_c_nt_anonymous_oid_desc =
+{6, (void *)"\x2b\x06\01\x05\x06\x03"};
+
+gss_OID GSS_C_NT_ANONYMOUS = &gss_c_nt_anonymous_oid_desc;
+
+/*
+ * The implementation must reserve static storage for a
+ * gss_OID_desc object containing the value
+ * {6, (void *)"\x2b\x06\x01\x05\x06\x04"},
+ * corresponding to an object-identifier value of
+ * {1(iso), 3(org), 6(dod), 1(internet), 5(security),
+ * 6(nametypes), 4(gss-api-exported-name)}.  The constant
+ * GSS_C_NT_EXPORT_NAME should be initialized to point
+ * to that gss_OID_desc.
+ */
+
+static gss_OID_desc gss_c_nt_export_name_oid_desc =
+{6, (void *)"\x2b\x06\x01\x05\x06\x04"};
+
+gss_OID GSS_C_NT_EXPORT_NAME = &gss_c_nt_export_name_oid_desc;
+
+/*
+ *   This name form shall be represented by the Object Identifier {iso(1)
+ *   member-body(2) United States(840) mit(113554) infosys(1) gssapi(2)
+ *   krb5(2) krb5_name(1)}.  The recommended symbolic name for this type
+ *   is "GSS_KRB5_NT_PRINCIPAL_NAME".
+ */
+
+static gss_OID_desc gss_krb5_nt_principal_name_oid_desc =
+{10, (void *)"\x2a\x86\x48\x86\xf7\x12\x01\x02\x02\x01"};
+
+gss_OID GSS_KRB5_NT_PRINCIPAL_NAME = &gss_krb5_nt_principal_name_oid_desc;
+
+/*
+ *   This name form shall be represented by the Object Identifier {iso(1)
+ *   member-body(2) United States(840) mit(113554) infosys(1) gssapi(2)
+ *   generic(1) user_name(1)}.  The recommended symbolic name for this
+ *   type is "GSS_KRB5_NT_USER_NAME".
+ */
+
+gss_OID GSS_KRB5_NT_USER_NAME = &gss_c_nt_user_name_oid_desc;
+
+/*
+ *   This name form shall be represented by the Object Identifier {iso(1)
+ *   member-body(2) United States(840) mit(113554) infosys(1) gssapi(2)
+ *   generic(1) machine_uid_name(2)}.  The recommended symbolic name for
+ *   this type is "GSS_KRB5_NT_MACHINE_UID_NAME".
+ */
+
+gss_OID GSS_KRB5_NT_MACHINE_UID_NAME = &gss_c_nt_machine_uid_name_oid_desc;
+
+/*
+ *   This name form shall be represented by the Object Identifier {iso(1)
+ *   member-body(2) United States(840) mit(113554) infosys(1) gssapi(2)
+ *   generic(1) string_uid_name(3)}.  The recommended symbolic name for
+ *   this type is "GSS_KRB5_NT_STRING_UID_NAME".
+ */
+
+gss_OID GSS_KRB5_NT_STRING_UID_NAME = &gss_c_nt_string_uid_name_oid_desc;
+
+/*
+ *   To support ongoing experimentation, testing, and evolution of the
+ *   specification, the Kerberos V5 GSS-API mechanism as defined in this
+ *   and any successor memos will be identified with the following Object
+ *   Identifier, as defined in RFC-1510, until the specification is
+ *   advanced to the level of Proposed Standard RFC:
+ *
+ *   {iso(1), org(3), dod(5), internet(1), security(5), kerberosv5(2)}
+ *
+ *   Upon advancement to the level of Proposed Standard RFC, the Kerberos
+ *   V5 GSS-API mechanism will be identified by an Object Identifier
+ *   having the value:
+ *
+ *   {iso(1) member-body(2) United States(840) mit(113554) infosys(1)
+ *   gssapi(2) krb5(2)}
+ */
+
+#if 0 /* This is the old OID */
+
+static gss_OID_desc gss_krb5_mechanism_oid_desc =
+{5, (void *)"\x2b\x05\x01\x05\x02"};
+
+#endif
+
+static gss_OID_desc gss_krb5_mechanism_oid_desc =
+{9, (void *)"\x2a\x86\x48\x86\xf7\x12\x01\x02\x02"};
+
+gss_OID GSS_KRB5_MECHANISM = &gss_krb5_mechanism_oid_desc;
+
+/*
+ * RFC2478, SPNEGO:
+ *  The security mechanism of the initial
+ *  negotiation token is identified by the Object Identifier
+ *  iso.org.dod.internet.security.mechanism.snego (1.3.6.1.5.5.2).
+ */
+
+static gss_OID_desc gss_spnego_mechanism_oid_desc =
+{6, (void *)"\x2b\x06\x01\x05\x05\x02"};
+
+gss_OID GSS_SPNEGO_MECHANISM = &gss_spnego_mechanism_oid_desc;
+
+/*
+ * draft-ietf-cat-iakerb-09, IAKERB:
+ *   The mechanism ID for IAKERB proxy GSS-API Kerberos, in accordance
+ *   with the mechanism proposed by SPNEGO [7] for negotiating protocol
+ *   variations, is:  {iso(1) org(3) dod(6) internet(1) security(5)
+ *   mechanisms(5) iakerb(10) iakerbProxyProtocol(1)}.  The proposed
+ *   mechanism ID for IAKERB minimum messages GSS-API Kerberos, in
+ *   accordance with the mechanism proposed by SPNEGO for negotiating
+ *   protocol variations, is: {iso(1) org(3) dod(6) internet(1)
+ *   security(5) mechanisms(5) iakerb(10)
+ *   iakerbMinimumMessagesProtocol(2)}.
+ */
+
+static gss_OID_desc gss_iakerb_proxy_mechanism_oid_desc =
+{7, (void *)"\x2b\x06\x01\x05\x05\x0a\x01"};
+
+gss_OID GSS_IAKERB_PROXY_MECHANISM = &gss_iakerb_proxy_mechanism_oid_desc;
+
+static gss_OID_desc gss_iakerb_min_msg_mechanism_oid_desc =
+{7, (void *)"\x2b\x06\x01\x05\x05\x0a\x02"};
+
+gss_OID GSS_IAKERB_MIN_MSG_MECHANISM = &gss_iakerb_min_msg_mechanism_oid_desc;
+
+/*
+ * Context for krb5 calls.
+ */
+
+krb5_context gssapi_krb5_context;
diff --git a/source4/heimdal/lib/gssapi/get_mic.c b/source4/heimdal/lib/gssapi/get_mic.c
new file mode 100644 (file)
index 0000000..1c950e9
--- /dev/null
@@ -0,0 +1,302 @@
+/*
+ * 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 "gssapi_locl.h"
+
+RCSID("$Id: get_mic.c,v 1.29 2005/01/05 02:52:12 lukeh Exp $");
+
+static OM_uint32
+mic_des
+           (OM_uint32 * minor_status,
+            const gss_ctx_id_t context_handle,
+            gss_qop_t qop_req,
+            const gss_buffer_t message_buffer,
+            gss_buffer_t message_token,
+           krb5_keyblock *key
+           )
+{
+  u_char *p;
+  MD5_CTX md5;
+  u_char hash[16];
+  DES_key_schedule schedule;
+  DES_cblock deskey;
+  DES_cblock zero;
+  int32_t seq_number;
+  size_t len, total_len;
+
+  gssapi_krb5_encap_length (22, &len, &total_len, GSS_KRB5_MECHANISM);
+
+  message_token->length = total_len;
+  message_token->value  = malloc (total_len);
+  if (message_token->value == NULL) {
+    *minor_status = ENOMEM;
+    return GSS_S_FAILURE;
+  }
+
+  p = gssapi_krb5_make_header(message_token->value,
+                             len,
+                             "\x01\x01", /* TOK_ID */
+                             GSS_KRB5_MECHANISM); 
+
+  memcpy (p, "\x00\x00", 2);   /* SGN_ALG = DES MAC MD5 */
+  p += 2;
+
+  memcpy (p, "\xff\xff\xff\xff", 4); /* Filler */
+  p += 4;
+
+  /* Fill in later (SND-SEQ) */
+  memset (p, 0, 16);
+  p += 16;
+
+  /* checksum */
+  MD5_Init (&md5);
+  MD5_Update (&md5, p - 24, 8);
+  MD5_Update (&md5, message_buffer->value, message_buffer->length);
+  MD5_Final (hash, &md5);
+
+  memset (&zero, 0, sizeof(zero));
+  memcpy (&deskey, key->keyvalue.data, sizeof(deskey));
+  DES_set_key (&deskey, &schedule);
+  DES_cbc_cksum ((void *)hash, (void *)hash, sizeof(hash),
+                &schedule, &zero);
+  memcpy (p - 8, hash, 8);     /* SGN_CKSUM */
+
+  HEIMDAL_MUTEX_lock(&context_handle->ctx_id_mutex);
+  /* sequence number */
+  krb5_auth_con_getlocalseqnumber (gssapi_krb5_context,
+                              context_handle->auth_context,
+                              &seq_number);
+
+  p -= 16;                     /* SND_SEQ */
+  p[0] = (seq_number >> 0)  & 0xFF;
+  p[1] = (seq_number >> 8)  & 0xFF;
+  p[2] = (seq_number >> 16) & 0xFF;
+  p[3] = (seq_number >> 24) & 0xFF;
+  memset (p + 4,
+         (context_handle->more_flags & LOCAL) ? 0 : 0xFF,
+         4);
+
+  DES_set_key (&deskey, &schedule);
+  DES_cbc_encrypt ((void *)p, (void *)p, 8,
+                  &schedule, (DES_cblock *)(p + 8), DES_ENCRYPT);
+
+  krb5_auth_con_setlocalseqnumber (gssapi_krb5_context,
+                              context_handle->auth_context,
+                              ++seq_number);
+  HEIMDAL_MUTEX_unlock(&context_handle->ctx_id_mutex);
+  
+  memset (deskey, 0, sizeof(deskey));
+  memset (&schedule, 0, sizeof(schedule));
+  
+  *minor_status = 0;
+  return GSS_S_COMPLETE;
+}
+
+static OM_uint32
+mic_des3
+           (OM_uint32 * minor_status,
+            const gss_ctx_id_t context_handle,
+            gss_qop_t qop_req,
+            const gss_buffer_t message_buffer,
+            gss_buffer_t message_token,
+           krb5_keyblock *key
+           )
+{
+  u_char *p;
+  Checksum cksum;
+  u_char seq[8];
+
+  int32_t seq_number;
+  size_t len, total_len;
+
+  krb5_crypto crypto;
+  krb5_error_code kret;
+  krb5_data encdata;
+  char *tmp;
+  char ivec[8];
+
+  gssapi_krb5_encap_length (36, &len, &total_len, GSS_KRB5_MECHANISM);
+
+  message_token->length = total_len;
+  message_token->value  = malloc (total_len);
+  if (message_token->value == NULL) {
+      *minor_status = ENOMEM;
+      return GSS_S_FAILURE;
+  }
+
+  p = gssapi_krb5_make_header(message_token->value,
+                             len,
+                             "\x01\x01", /* TOK-ID */
+                             GSS_KRB5_MECHANISM);
+
+  memcpy (p, "\x04\x00", 2);   /* SGN_ALG = HMAC SHA1 DES3-KD */
+  p += 2;
+
+  memcpy (p, "\xff\xff\xff\xff", 4); /* filler */
+  p += 4;
+
+  /* this should be done in parts */
+
+  tmp = malloc (message_buffer->length + 8);
+  if (tmp == NULL) {
+      free (message_token->value);
+      *minor_status = ENOMEM;
+      return GSS_S_FAILURE;
+  }
+  memcpy (tmp, p - 8, 8);
+  memcpy (tmp + 8, message_buffer->value, message_buffer->length);
+
+  kret = krb5_crypto_init(gssapi_krb5_context, key, 0, &crypto);
+  if (kret) {
+      free (message_token->value);
+      free (tmp);
+      gssapi_krb5_set_error_string ();
+      *minor_status = kret;
+      return GSS_S_FAILURE;
+  }
+
+  kret = krb5_create_checksum (gssapi_krb5_context,
+                              crypto,
+                              KRB5_KU_USAGE_SIGN,
+                              0,
+                              tmp,
+                              message_buffer->length + 8,
+                              &cksum);
+  free (tmp);
+  krb5_crypto_destroy (gssapi_krb5_context, crypto);
+  if (kret) {
+      free (message_token->value);
+      gssapi_krb5_set_error_string ();
+      *minor_status = kret;
+      return GSS_S_FAILURE;
+  }
+
+  memcpy (p + 8, cksum.checksum.data, cksum.checksum.length);
+
+  HEIMDAL_MUTEX_lock(&context_handle->ctx_id_mutex);
+  /* sequence number */
+  krb5_auth_con_getlocalseqnumber (gssapi_krb5_context,
+                              context_handle->auth_context,
+                              &seq_number);
+
+  seq[0] = (seq_number >> 0)  & 0xFF;
+  seq[1] = (seq_number >> 8)  & 0xFF;
+  seq[2] = (seq_number >> 16) & 0xFF;
+  seq[3] = (seq_number >> 24) & 0xFF;
+  memset (seq + 4,
+         (context_handle->more_flags & LOCAL) ? 0 : 0xFF,
+         4);
+
+  kret = krb5_crypto_init(gssapi_krb5_context, key,
+                         ETYPE_DES3_CBC_NONE, &crypto);
+  if (kret) {
+      free (message_token->value);
+      gssapi_krb5_set_error_string ();
+      *minor_status = kret;
+      return GSS_S_FAILURE;
+  }
+
+  if (context_handle->more_flags & COMPAT_OLD_DES3)
+      memset(ivec, 0, 8);
+  else
+      memcpy(ivec, p + 8, 8);
+
+  kret = krb5_encrypt_ivec (gssapi_krb5_context,
+                           crypto,
+                           KRB5_KU_USAGE_SEQ,
+                           seq, 8, &encdata, ivec);
+  krb5_crypto_destroy (gssapi_krb5_context, crypto);
+  if (kret) {
+      free (message_token->value);
+      gssapi_krb5_set_error_string ();
+      *minor_status = kret;
+      return GSS_S_FAILURE;
+  }
+  
+  assert (encdata.length == 8);
+
+  memcpy (p, encdata.data, encdata.length);
+  krb5_data_free (&encdata);
+
+  krb5_auth_con_setlocalseqnumber (gssapi_krb5_context,
+                              context_handle->auth_context,
+                              ++seq_number);
+  HEIMDAL_MUTEX_unlock(&context_handle->ctx_id_mutex);
+  
+  free_Checksum (&cksum);
+  *minor_status = 0;
+  return GSS_S_COMPLETE;
+}
+
+OM_uint32 gss_get_mic
+           (OM_uint32 * minor_status,
+            const gss_ctx_id_t context_handle,
+            gss_qop_t qop_req,
+            const gss_buffer_t message_buffer,
+            gss_buffer_t message_token
+           )
+{
+  krb5_keyblock *key;
+  OM_uint32 ret;
+  krb5_keytype keytype;
+
+  ret = gss_krb5_get_subkey(context_handle, &key);
+  if (ret) {
+      gssapi_krb5_set_error_string ();
+      *minor_status = ret;
+      return GSS_S_FAILURE;
+  }
+  krb5_enctype_to_keytype (gssapi_krb5_context, key->keytype, &keytype);
+
+  switch (keytype) {
+  case KEYTYPE_DES :
+      ret = mic_des (minor_status, context_handle, qop_req,
+                    message_buffer, message_token, key);
+      break;
+  case KEYTYPE_DES3 :
+      ret = mic_des3 (minor_status, context_handle, qop_req,
+                     message_buffer, message_token, key);
+      break;
+  case KEYTYPE_ARCFOUR:
+  case KEYTYPE_ARCFOUR_56:
+      ret = _gssapi_get_mic_arcfour (minor_status, context_handle, qop_req,
+                                    message_buffer, message_token, key);
+      break;
+  default :
+      ret = _gssapi_mic_cfx (minor_status, context_handle, qop_req,
+                            message_buffer, message_token, key);
+      break;
+  }
+  krb5_free_keyblock (gssapi_krb5_context, key);
+  return ret;
+}
diff --git a/source4/heimdal/lib/gssapi/gssapi.h b/source4/heimdal/lib/gssapi/gssapi.h
new file mode 100644 (file)
index 0000000..5712581
--- /dev/null
@@ -0,0 +1,826 @@
+/*
+ * 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: gssapi.h,v 1.37 2005/02/21 08:48:15 lukeh Exp $ */
+
+#ifndef GSSAPI_H_
+#define GSSAPI_H_
+
+/*
+ * First, include stddef.h to get size_t defined.
+ */
+#include <stddef.h>
+
+#include <krb5-types.h>
+
+/*
+ * Now define the three implementation-dependent types.
+ */
+
+typedef u_int32_t OM_uint32;
+
+typedef u_int32_t gss_uint32;
+
+/*
+ * This is to avoid having to include <krb5.h>
+ */
+
+struct krb5_auth_context_data;
+
+struct Principal;
+
+/* typedef void *gss_name_t; */
+
+typedef struct Principal *gss_name_t;
+
+struct gss_ctx_id_t_desc_struct;
+typedef struct gss_ctx_id_t_desc_struct *gss_ctx_id_t;
+
+typedef struct gss_OID_desc_struct {
+      OM_uint32 length;
+      void      *elements;
+} gss_OID_desc, *gss_OID;
+
+typedef struct gss_OID_set_desc_struct  {
+      size_t     count;
+      gss_OID    elements;
+} gss_OID_set_desc, *gss_OID_set;
+
+struct krb5_keytab_data;
+
+struct krb5_ccache_data;
+
+typedef int gss_cred_usage_t;
+
+struct gss_cred_id_t_desc_struct;
+typedef struct gss_cred_id_t_desc_struct *gss_cred_id_t;
+
+typedef struct gss_buffer_desc_struct {
+      size_t length;
+      void *value;
+} gss_buffer_desc, *gss_buffer_t;
+
+typedef struct gss_channel_bindings_struct {
+      OM_uint32 initiator_addrtype;
+      gss_buffer_desc initiator_address;
+      OM_uint32 acceptor_addrtype;
+      gss_buffer_desc acceptor_address;
+      gss_buffer_desc application_data;
+} *gss_channel_bindings_t;
+
+/*
+ * For now, define a QOP-type as an OM_uint32
+ */
+typedef OM_uint32 gss_qop_t;
+
+/*
+ * Flag bits for context-level services.
+ */
+#define GSS_C_DELEG_FLAG 1             /* 0x00000001 */
+#define GSS_C_MUTUAL_FLAG 2            /* 0x00000002 */
+#define GSS_C_REPLAY_FLAG 4            /* 0x00000004 */
+#define GSS_C_SEQUENCE_FLAG 8          /* 0x00000008 */
+#define GSS_C_CONF_FLAG 16             /* 0x00000010 */
+#define GSS_C_INTEG_FLAG 32            /* 0x00000020 */
+#define GSS_C_ANON_FLAG 64             /* 0x00000040 */
+#define GSS_C_PROT_READY_FLAG 128      /* 0x00000080 */
+#define GSS_C_TRANS_FLAG 256           /* 0x00000100 */
+
+/* these are from draft-brezak-win2k-krb-rc4-hmac-04.txt */
+#define GSS_C_DCE_STYLE 4096           /* 0x00001000 */
+#define GSS_C_IDENTIFY_FLAG 8192       /* 0x00002000 */
+#define GSS_C_EXTENDED_ERROR_FLAG 16384 /* 0x00004000 */
+
+/*
+ * Credential usage options
+ */
+#define GSS_C_BOTH 0
+#define GSS_C_INITIATE 1
+#define GSS_C_ACCEPT 2
+
+/*
+ * Status code types for gss_display_status
+ */
+#define GSS_C_GSS_CODE 1
+#define GSS_C_MECH_CODE 2
+
+/*
+ * The constant definitions for channel-bindings address families
+ */
+#define GSS_C_AF_UNSPEC     0
+#define GSS_C_AF_LOCAL      1
+#define GSS_C_AF_INET       2
+#define GSS_C_AF_IMPLINK    3
+#define GSS_C_AF_PUP        4
+#define GSS_C_AF_CHAOS      5
+#define GSS_C_AF_NS         6
+#define GSS_C_AF_NBS        7
+#define GSS_C_AF_ECMA       8
+#define GSS_C_AF_DATAKIT    9
+#define GSS_C_AF_CCITT      10
+#define GSS_C_AF_SNA        11
+#define GSS_C_AF_DECnet     12
+#define GSS_C_AF_DLI        13
+#define GSS_C_AF_LAT        14
+#define GSS_C_AF_HYLINK     15
+#define GSS_C_AF_APPLETALK  16
+#define GSS_C_AF_BSC        17
+#define GSS_C_AF_DSS        18
+#define GSS_C_AF_OSI        19
+#define GSS_C_AF_X25        21
+#define GSS_C_AF_INET6     24
+
+#define GSS_C_AF_NULLADDR   255
+
+/*
+ * Various Null values
+ */
+#define GSS_C_NO_NAME ((gss_name_t) 0)
+#define GSS_C_NO_BUFFER ((gss_buffer_t) 0)
+#define GSS_C_NO_OID ((gss_OID) 0)
+#define GSS_C_NO_OID_SET ((gss_OID_set) 0)
+#define GSS_C_NO_CONTEXT ((gss_ctx_id_t) 0)
+#define GSS_C_NO_CREDENTIAL ((gss_cred_id_t) 0)
+#define GSS_C_NO_CHANNEL_BINDINGS ((gss_channel_bindings_t) 0)
+#define GSS_C_EMPTY_BUFFER {0, NULL}
+
+/*
+ * Some alternate names for a couple of the above
+ * values.  These are defined for V1 compatibility.
+ */
+#define GSS_C_NULL_OID GSS_C_NO_OID
+#define GSS_C_NULL_OID_SET GSS_C_NO_OID_SET
+
+/*
+ * Define the default Quality of Protection for per-message
+ * services.  Note that an implementation that offers multiple
+ * levels of QOP may define GSS_C_QOP_DEFAULT to be either zero
+ * (as done here) to mean "default protection", or to a specific
+ * explicit QOP value.  However, a value of 0 should always be
+ * interpreted by a GSSAPI implementation as a request for the
+ * default protection level.
+ */
+#define GSS_C_QOP_DEFAULT 0
+
+#define GSS_KRB5_CONF_C_QOP_DES                0x0100
+#define GSS_KRB5_CONF_C_QOP_DES3_KD    0x0200
+
+/*
+ * Expiration time of 2^32-1 seconds means infinite lifetime for a
+ * credential or security context
+ */
+#define GSS_C_INDEFINITE 0xfffffffful
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*
+ * The implementation must reserve static storage for a
+ * gss_OID_desc object containing the value
+ * {10, (void *)"\x2a\x86\x48\x86\xf7\x12"
+ *              "\x01\x02\x01\x01"},
+ * corresponding to an object-identifier value of
+ * {iso(1) member-body(2) United States(840) mit(113554)
+ *  infosys(1) gssapi(2) generic(1) user_name(1)}.  The constant
+ * GSS_C_NT_USER_NAME should be initialized to point
+ * to that gss_OID_desc.
+ */
+extern gss_OID GSS_C_NT_USER_NAME;
+
+/*
+ * The implementation must reserve static storage for a
+ * gss_OID_desc object containing the value
+ * {10, (void *)"\x2a\x86\x48\x86\xf7\x12"
+ *              "\x01\x02\x01\x02"},
+ * corresponding to an object-identifier value of
+ * {iso(1) member-body(2) United States(840) mit(113554)
+ *  infosys(1) gssapi(2) generic(1) machine_uid_name(2)}.
+ * The constant GSS_C_NT_MACHINE_UID_NAME should be
+ * initialized to point to that gss_OID_desc.
+ */
+extern gss_OID GSS_C_NT_MACHINE_UID_NAME;
+
+/*
+ * The implementation must reserve static storage for a
+ * gss_OID_desc object containing the value
+ * {10, (void *)"\x2a\x86\x48\x86\xf7\x12"
+ *              "\x01\x02\x01\x03"},
+ * corresponding to an object-identifier value of
+ * {iso(1) member-body(2) United States(840) mit(113554)
+ *  infosys(1) gssapi(2) generic(1) string_uid_name(3)}.
+ * The constant GSS_C_NT_STRING_UID_NAME should be
+ * initialized to point to that gss_OID_desc.
+ */
+extern gss_OID GSS_C_NT_STRING_UID_NAME;
+
+/*
+ * The implementation must reserve static storage for a
+ * gss_OID_desc object containing the value
+ * {6, (void *)"\x2b\x06\x01\x05\x06\x02"},
+ * corresponding to an object-identifier value of
+ * {iso(1) org(3) dod(6) internet(1) security(5)
+ * nametypes(6) gss-host-based-services(2)).  The constant
+ * GSS_C_NT_HOSTBASED_SERVICE_X should be initialized to point
+ * to that gss_OID_desc.  This is a deprecated OID value, and
+ * implementations wishing to support hostbased-service names
+ * should instead use the GSS_C_NT_HOSTBASED_SERVICE OID,
+ * defined below, to identify such names;
+ * GSS_C_NT_HOSTBASED_SERVICE_X should be accepted a synonym
+ * for GSS_C_NT_HOSTBASED_SERVICE when presented as an input
+ * parameter, but should not be emitted by GSS-API
+ * implementations
+ */
+extern gss_OID GSS_C_NT_HOSTBASED_SERVICE_X;
+
+/*
+ * The implementation must reserve static storage for a
+ * gss_OID_desc object containing the value
+ * {10, (void *)"\x2a\x86\x48\x86\xf7\x12"
+ *              "\x01\x02\x01\x04"}, corresponding to an
+ * object-identifier value of {iso(1) member-body(2)
+ * Unites States(840) mit(113554) infosys(1) gssapi(2)
+ * generic(1) service_name(4)}.  The constant
+ * GSS_C_NT_HOSTBASED_SERVICE should be initialized
+ * to point to that gss_OID_desc.
+ */
+extern gss_OID GSS_C_NT_HOSTBASED_SERVICE;
+
+/*
+ * The implementation must reserve static storage for a
+ * gss_OID_desc object containing the value
+ * {6, (void *)"\x2b\x06\01\x05\x06\x03"},
+ * corresponding to an object identifier value of
+ * {1(iso), 3(org), 6(dod), 1(internet), 5(security),
+ * 6(nametypes), 3(gss-anonymous-name)}.  The constant
+ * and GSS_C_NT_ANONYMOUS should be initialized to point
+ * to that gss_OID_desc.
+ */
+extern gss_OID GSS_C_NT_ANONYMOUS;
+
+/*
+ * The implementation must reserve static storage for a
+ * gss_OID_desc object containing the value
+ * {6, (void *)"\x2b\x06\x01\x05\x06\x04"},
+ * corresponding to an object-identifier value of
+ * {1(iso), 3(org), 6(dod), 1(internet), 5(security),
+ * 6(nametypes), 4(gss-api-exported-name)}.  The constant
+ * GSS_C_NT_EXPORT_NAME should be initialized to point
+ * to that gss_OID_desc.
+ */
+extern gss_OID GSS_C_NT_EXPORT_NAME;
+
+/*
+ * RFC2478, SPNEGO:
+ *  The security mechanism of the initial
+ *  negotiation token is identified by the Object Identifier
+ *  iso.org.dod.internet.security.mechanism.snego (1.3.6.1.5.5.2).
+ */
+extern gss_OID GSS_SPNEGO_MECHANISM;
+
+/*
+ * This if for kerberos5 names.
+ */
+
+extern gss_OID GSS_KRB5_NT_PRINCIPAL_NAME;
+extern gss_OID GSS_KRB5_NT_USER_NAME;
+extern gss_OID GSS_KRB5_NT_MACHINE_UID_NAME;
+extern gss_OID GSS_KRB5_NT_STRING_UID_NAME;
+
+extern gss_OID GSS_KRB5_MECHANISM;
+
+/* for compatibility with MIT api */
+
+#define gss_mech_krb5 GSS_KRB5_MECHANISM
+#define gss_krb5_nt_general_name GSS_KRB5_NT_PRINCIPAL_NAME
+
+/* Major status codes */
+
+#define GSS_S_COMPLETE 0
+
+/*
+ * Some "helper" definitions to make the status code macros obvious.
+ */
+#define GSS_C_CALLING_ERROR_OFFSET 24
+#define GSS_C_ROUTINE_ERROR_OFFSET 16
+#define GSS_C_SUPPLEMENTARY_OFFSET 0
+#define GSS_C_CALLING_ERROR_MASK 0377ul
+#define GSS_C_ROUTINE_ERROR_MASK 0377ul
+#define GSS_C_SUPPLEMENTARY_MASK 0177777ul
+
+/*
+ * The macros that test status codes for error conditions.
+ * Note that the GSS_ERROR() macro has changed slightly from
+ * the V1 GSSAPI so that it now evaluates its argument
+ * only once.
+ */
+#define GSS_CALLING_ERROR(x) \
+  (x & (GSS_C_CALLING_ERROR_MASK << GSS_C_CALLING_ERROR_OFFSET))
+#define GSS_ROUTINE_ERROR(x) \
+  (x & (GSS_C_ROUTINE_ERROR_MASK << GSS_C_ROUTINE_ERROR_OFFSET))
+#define GSS_SUPPLEMENTARY_INFO(x) \
+  (x & (GSS_C_SUPPLEMENTARY_MASK << GSS_C_SUPPLEMENTARY_OFFSET))
+#define GSS_ERROR(x) \
+  (x & ((GSS_C_CALLING_ERROR_MASK << GSS_C_CALLING_ERROR_OFFSET) | \
+        (GSS_C_ROUTINE_ERROR_MASK << GSS_C_ROUTINE_ERROR_OFFSET)))
+
+/*
+ * Now the actual status code definitions
+ */
+
+/*
+ * Calling errors:
+ */
+#define GSS_S_CALL_INACCESSIBLE_READ \
+                             (1ul << GSS_C_CALLING_ERROR_OFFSET)
+#define GSS_S_CALL_INACCESSIBLE_WRITE \
+                             (2ul << GSS_C_CALLING_ERROR_OFFSET)
+#define GSS_S_CALL_BAD_STRUCTURE \
+                             (3ul << GSS_C_CALLING_ERROR_OFFSET)
+
+/*
+ * Routine errors:
+ */
+#define GSS_S_BAD_MECH (1ul << GSS_C_ROUTINE_ERROR_OFFSET)
+#define GSS_S_BAD_NAME (2ul << GSS_C_ROUTINE_ERROR_OFFSET)
+#define GSS_S_BAD_NAMETYPE (3ul << GSS_C_ROUTINE_ERROR_OFFSET)
+
+#define GSS_S_BAD_BINDINGS (4ul << GSS_C_ROUTINE_ERROR_OFFSET)
+#define GSS_S_BAD_STATUS (5ul << GSS_C_ROUTINE_ERROR_OFFSET)
+#define GSS_S_BAD_SIG (6ul << GSS_C_ROUTINE_ERROR_OFFSET)
+#define GSS_S_BAD_MIC GSS_S_BAD_SIG
+#define GSS_S_NO_CRED (7ul << GSS_C_ROUTINE_ERROR_OFFSET)
+#define GSS_S_NO_CONTEXT (8ul << GSS_C_ROUTINE_ERROR_OFFSET)
+#define GSS_S_DEFECTIVE_TOKEN (9ul << GSS_C_ROUTINE_ERROR_OFFSET)
+#define GSS_S_DEFECTIVE_CREDENTIAL (10ul << GSS_C_ROUTINE_ERROR_OFFSET)
+#define GSS_S_CREDENTIALS_EXPIRED (11ul << GSS_C_ROUTINE_ERROR_OFFSET)
+#define GSS_S_CONTEXT_EXPIRED (12ul << GSS_C_ROUTINE_ERROR_OFFSET)
+#define GSS_S_FAILURE (13ul << GSS_C_ROUTINE_ERROR_OFFSET)
+#define GSS_S_BAD_QOP (14ul << GSS_C_ROUTINE_ERROR_OFFSET)
+#define GSS_S_UNAUTHORIZED (15ul << GSS_C_ROUTINE_ERROR_OFFSET)
+#define GSS_S_UNAVAILABLE (16ul << GSS_C_ROUTINE_ERROR_OFFSET)
+#define GSS_S_DUPLICATE_ELEMENT (17ul << GSS_C_ROUTINE_ERROR_OFFSET)
+#define GSS_S_NAME_NOT_MN (18ul << GSS_C_ROUTINE_ERROR_OFFSET)
+
+/*
+ * Supplementary info bits:
+ */
+#define GSS_S_CONTINUE_NEEDED (1ul << (GSS_C_SUPPLEMENTARY_OFFSET + 0))
+#define GSS_S_DUPLICATE_TOKEN (1ul << (GSS_C_SUPPLEMENTARY_OFFSET + 1))
+#define GSS_S_OLD_TOKEN (1ul << (GSS_C_SUPPLEMENTARY_OFFSET + 2))
+#define GSS_S_UNSEQ_TOKEN (1ul << (GSS_C_SUPPLEMENTARY_OFFSET + 3))
+#define GSS_S_GAP_TOKEN (1ul << (GSS_C_SUPPLEMENTARY_OFFSET + 4))
+
+/*
+ * From RFC1964:
+ *
+ * 4.1.1. Non-Kerberos-specific codes
+ */
+
+#define GSS_KRB5_S_G_BAD_SERVICE_NAME 1
+           /* "No @ in SERVICE-NAME name string" */
+#define GSS_KRB5_S_G_BAD_STRING_UID 2
+           /* "STRING-UID-NAME contains nondigits" */
+#define GSS_KRB5_S_G_NOUSER 3
+           /* "UID does not resolve to username" */
+#define GSS_KRB5_S_G_VALIDATE_FAILED 4
+           /* "Validation error" */
+#define GSS_KRB5_S_G_BUFFER_ALLOC 5
+           /* "Couldn't allocate gss_buffer_t data" */
+#define GSS_KRB5_S_G_BAD_MSG_CTX 6
+           /* "Message context invalid" */
+#define GSS_KRB5_S_G_WRONG_SIZE 7
+           /* "Buffer is the wrong size" */
+#define GSS_KRB5_S_G_BAD_USAGE 8
+           /* "Credential usage type is unknown" */
+#define GSS_KRB5_S_G_UNKNOWN_QOP 9
+           /* "Unknown quality of protection specified" */
+
+  /*
+   * 4.1.2. Kerberos-specific-codes
+   */
+
+#define GSS_KRB5_S_KG_CCACHE_NOMATCH 10
+           /* "Principal in credential cache does not match desired name" */
+#define GSS_KRB5_S_KG_KEYTAB_NOMATCH 11
+           /* "No principal in keytab matches desired name" */
+#define GSS_KRB5_S_KG_TGT_MISSING 12
+           /* "Credential cache has no TGT" */
+#define GSS_KRB5_S_KG_NO_SUBKEY 13
+           /* "Authenticator has no subkey" */
+#define GSS_KRB5_S_KG_CONTEXT_ESTABLISHED 14
+           /* "Context is already fully established" */
+#define GSS_KRB5_S_KG_BAD_SIGN_TYPE 15
+           /* "Unknown signature type in token" */
+#define GSS_KRB5_S_KG_BAD_LENGTH 16
+           /* "Invalid field length in token" */
+#define GSS_KRB5_S_KG_CTX_INCOMPLETE 17
+           /* "Attempt to use incomplete security context" */
+
+/*
+ * Finally, function prototypes for the GSS-API routines.
+ */
+
+
+OM_uint32 gss_acquire_cred
+           (OM_uint32 * /*minor_status*/,
+            const gss_name_t /*desired_name*/,
+            OM_uint32 /*time_req*/,
+            const gss_OID_set /*desired_mechs*/,
+            gss_cred_usage_t /*cred_usage*/,
+            gss_cred_id_t * /*output_cred_handle*/,
+            gss_OID_set * /*actual_mechs*/,
+            OM_uint32 * /*time_rec*/
+           );
+
+OM_uint32 gss_release_cred
+           (OM_uint32 * /*minor_status*/,
+            gss_cred_id_t * /*cred_handle*/
+           );
+
+OM_uint32 gss_init_sec_context
+           (OM_uint32 * /*minor_status*/,
+            const gss_cred_id_t /*initiator_cred_handle*/,
+            gss_ctx_id_t * /*context_handle*/,
+            const gss_name_t /*target_name*/,
+            const gss_OID /*mech_type*/,
+            OM_uint32 /*req_flags*/,
+            OM_uint32 /*time_req*/,
+            const gss_channel_bindings_t /*input_chan_bindings*/,
+            const gss_buffer_t /*input_token*/,
+            gss_OID * /*actual_mech_type*/,
+            gss_buffer_t /*output_token*/,
+            OM_uint32 * /*ret_flags*/,
+            OM_uint32 * /*time_rec*/
+           );
+
+OM_uint32 gss_accept_sec_context
+           (OM_uint32 * /*minor_status*/,
+            gss_ctx_id_t * /*context_handle*/,
+            const gss_cred_id_t /*acceptor_cred_handle*/,
+            const gss_buffer_t /*input_token_buffer*/,
+            const gss_channel_bindings_t /*input_chan_bindings*/,
+            gss_name_t * /*src_name*/,
+            gss_OID * /*mech_type*/,
+            gss_buffer_t /*output_token*/,
+            OM_uint32 * /*ret_flags*/,
+            OM_uint32 * /*time_rec*/,
+            gss_cred_id_t * /*delegated_cred_handle*/
+           );
+
+OM_uint32 gss_process_context_token
+           (OM_uint32 * /*minor_status*/,
+            const gss_ctx_id_t /*context_handle*/,
+            const gss_buffer_t /*token_buffer*/
+           );
+
+OM_uint32 gss_delete_sec_context
+           (OM_uint32 * /*minor_status*/,
+            gss_ctx_id_t * /*context_handle*/,
+            gss_buffer_t /*output_token*/
+           );
+
+OM_uint32 gss_context_time
+           (OM_uint32 * /*minor_status*/,
+            const gss_ctx_id_t /*context_handle*/,
+            OM_uint32 * /*time_rec*/
+           );
+
+OM_uint32 gss_get_mic
+           (OM_uint32 * /*minor_status*/,
+            const gss_ctx_id_t /*context_handle*/,
+            gss_qop_t /*qop_req*/,
+            const gss_buffer_t /*message_buffer*/,
+            gss_buffer_t /*message_token*/
+           );
+
+OM_uint32 gss_verify_mic
+           (OM_uint32 * /*minor_status*/,
+            const gss_ctx_id_t /*context_handle*/,
+            const gss_buffer_t /*message_buffer*/,
+            const gss_buffer_t /*token_buffer*/,
+            gss_qop_t * /*qop_state*/
+           );
+
+OM_uint32 gss_wrap
+           (OM_uint32 * /*minor_status*/,
+            const gss_ctx_id_t /*context_handle*/,
+            int /*conf_req_flag*/,
+            gss_qop_t /*qop_req*/,
+            const gss_buffer_t /*input_message_buffer*/,
+            int * /*conf_state*/,
+            gss_buffer_t /*output_message_buffer*/
+           );
+
+OM_uint32 gss_unwrap
+           (OM_uint32 * /*minor_status*/,
+            const gss_ctx_id_t /*context_handle*/,
+            const gss_buffer_t /*input_message_buffer*/,
+            gss_buffer_t /*output_message_buffer*/,
+            int * /*conf_state*/,
+            gss_qop_t * /*qop_state*/
+           );
+
+OM_uint32 gss_display_status
+           (OM_uint32 * /*minor_status*/,
+            OM_uint32 /*status_value*/,
+            int /*status_type*/,
+            const gss_OID /*mech_type*/,
+            OM_uint32 * /*message_context*/,
+            gss_buffer_t /*status_string*/
+           );
+
+OM_uint32 gss_indicate_mechs
+           (OM_uint32 * /*minor_status*/,
+            gss_OID_set * /*mech_set*/
+           );
+
+OM_uint32 gss_compare_name
+           (OM_uint32 * /*minor_status*/,
+            const gss_name_t /*name1*/,
+            const gss_name_t /*name2*/,
+            int * /*name_equal*/
+           );
+
+OM_uint32 gss_display_name
+           (OM_uint32 * /*minor_status*/,
+            const gss_name_t /*input_name*/,
+            gss_buffer_t /*output_name_buffer*/,
+            gss_OID * /*output_name_type*/
+           );
+
+OM_uint32 gss_import_name
+           (OM_uint32 * /*minor_status*/,
+            const gss_buffer_t /*input_name_buffer*/,
+            const gss_OID /*input_name_type*/,
+            gss_name_t * /*output_name*/
+           );
+
+OM_uint32 gss_export_name
+           (OM_uint32  * /*minor_status*/,
+            const gss_name_t /*input_name*/,
+            gss_buffer_t /*exported_name*/
+           );
+
+OM_uint32 gss_release_name
+           (OM_uint32 * /*minor_status*/,
+            gss_name_t * /*input_name*/
+           );
+
+OM_uint32 gss_release_buffer
+           (OM_uint32 * /*minor_status*/,
+            gss_buffer_t /*buffer*/
+           );
+
+OM_uint32 gss_release_oid_set
+           (OM_uint32 * /*minor_status*/,
+            gss_OID_set * /*set*/
+           );
+
+OM_uint32 gss_inquire_cred
+           (OM_uint32 * /*minor_status*/,
+            const gss_cred_id_t /*cred_handle*/,
+            gss_name_t * /*name*/,
+            OM_uint32 * /*lifetime*/,
+            gss_cred_usage_t * /*cred_usage*/,
+            gss_OID_set * /*mechanisms*/
+           );
+
+OM_uint32 gss_inquire_context (
+            OM_uint32 * /*minor_status*/,
+            const gss_ctx_id_t /*context_handle*/,
+            gss_name_t * /*src_name*/,
+            gss_name_t * /*targ_name*/,
+            OM_uint32 * /*lifetime_rec*/,
+            gss_OID * /*mech_type*/,
+            OM_uint32 * /*ctx_flags*/,
+            int * /*locally_initiated*/,
+            int * /*open_context*/
+           );
+
+OM_uint32 gss_wrap_size_limit (
+            OM_uint32 * /*minor_status*/,
+            const gss_ctx_id_t /*context_handle*/,
+            int /*conf_req_flag*/,
+            gss_qop_t /*qop_req*/,
+            OM_uint32 /*req_output_size*/,
+            OM_uint32 * /*max_input_size*/
+           );
+
+OM_uint32 gss_add_cred (
+            OM_uint32 * /*minor_status*/,
+            const gss_cred_id_t /*input_cred_handle*/,
+            const gss_name_t /*desired_name*/,
+            const gss_OID /*desired_mech*/,
+            gss_cred_usage_t /*cred_usage*/,
+            OM_uint32 /*initiator_time_req*/,
+            OM_uint32 /*acceptor_time_req*/,
+            gss_cred_id_t * /*output_cred_handle*/,
+            gss_OID_set * /*actual_mechs*/,
+            OM_uint32 * /*initiator_time_rec*/,
+            OM_uint32 * /*acceptor_time_rec*/
+           );
+
+OM_uint32 gss_inquire_cred_by_mech (
+            OM_uint32 * /*minor_status*/,
+            const gss_cred_id_t /*cred_handle*/,
+            const gss_OID /*mech_type*/,
+            gss_name_t * /*name*/,
+            OM_uint32 * /*initiator_lifetime*/,
+            OM_uint32 * /*acceptor_lifetime*/,
+            gss_cred_usage_t * /*cred_usage*/
+           );
+
+OM_uint32 gss_export_sec_context (
+            OM_uint32 * /*minor_status*/,
+            gss_ctx_id_t * /*context_handle*/,
+            gss_buffer_t /*interprocess_token*/
+           );
+
+OM_uint32 gss_import_sec_context (
+            OM_uint32 * /*minor_status*/,
+            const gss_buffer_t /*interprocess_token*/,
+            gss_ctx_id_t * /*context_handle*/
+           );
+
+OM_uint32 gss_create_empty_oid_set (
+            OM_uint32 * /*minor_status*/,
+            gss_OID_set * /*oid_set*/
+           );
+
+OM_uint32 gss_add_oid_set_member (
+            OM_uint32 * /*minor_status*/,
+            const gss_OID /*member_oid*/,
+            gss_OID_set * /*oid_set*/
+           );
+
+OM_uint32 gss_test_oid_set_member (
+            OM_uint32 * /*minor_status*/,
+            const gss_OID /*member*/,
+            const gss_OID_set /*set*/,
+            int * /*present*/
+           );
+
+OM_uint32 gss_inquire_names_for_mech (
+            OM_uint32 * /*minor_status*/,
+            const gss_OID /*mechanism*/,
+            gss_OID_set * /*name_types*/
+           );
+
+OM_uint32 gss_inquire_mechs_for_name (
+            OM_uint32 * /*minor_status*/,
+            const gss_name_t /*input_name*/,
+            gss_OID_set * /*mech_types*/
+           );
+
+OM_uint32 gss_canonicalize_name (
+            OM_uint32 * /*minor_status*/,
+            const gss_name_t /*input_name*/,
+            const gss_OID /*mech_type*/,
+            gss_name_t * /*output_name*/
+           );
+
+OM_uint32 gss_duplicate_name (
+            OM_uint32 * /*minor_status*/,
+            const gss_name_t /*src_name*/,
+            gss_name_t * /*dest_name*/
+           );
+
+/*
+ * The following routines are obsolete variants of gss_get_mic,
+ * gss_verify_mic, gss_wrap and gss_unwrap.  They should be
+ * provided by GSSAPI V2 implementations for backwards
+ * compatibility with V1 applications.  Distinct entrypoints
+ * (as opposed to #defines) should be provided, both to allow
+ * GSSAPI V1 applications to link against GSSAPI V2 implementations,
+ * and to retain the slight parameter type differences between the
+ * obsolete versions of these routines and their current forms.
+ */
+
+OM_uint32 gss_sign
+           (OM_uint32 * /*minor_status*/,
+            gss_ctx_id_t /*context_handle*/,
+            int /*qop_req*/,
+            gss_buffer_t /*message_buffer*/,
+            gss_buffer_t /*message_token*/
+           );
+
+OM_uint32 gss_verify
+           (OM_uint32 * /*minor_status*/,
+            gss_ctx_id_t /*context_handle*/,
+            gss_buffer_t /*message_buffer*/,
+            gss_buffer_t /*token_buffer*/,
+            int * /*qop_state*/
+           );
+
+OM_uint32 gss_seal
+           (OM_uint32 * /*minor_status*/,
+            gss_ctx_id_t /*context_handle*/,
+            int /*conf_req_flag*/,
+            int /*qop_req*/,
+            gss_buffer_t /*input_message_buffer*/,
+            int * /*conf_state*/,
+            gss_buffer_t /*output_message_buffer*/
+           );
+
+OM_uint32 gss_unseal
+           (OM_uint32 * /*minor_status*/,
+            gss_ctx_id_t /*context_handle*/,
+            gss_buffer_t /*input_message_buffer*/,
+            gss_buffer_t /*output_message_buffer*/,
+            int * /*conf_state*/,
+            int * /*qop_state*/
+           );
+
+/*
+ * kerberos mechanism specific functions
+ */
+
+OM_uint32 gsskrb5_acquire_cred
+           (OM_uint32 * minor_status,
+           struct krb5_keytab_data *keytab,
+           struct krb5_ccache_data *ccache,
+            const gss_name_t desired_name,
+            OM_uint32 time_req,
+            const gss_OID_set desired_mechs,
+            gss_cred_usage_t cred_usage,
+            gss_cred_id_t * output_cred_handle,
+            gss_OID_set * actual_mechs,
+            OM_uint32 * time_rec
+                  );
+
+OM_uint32
+gss_krb5_ccache_name(OM_uint32 * /*minor_status*/, 
+                    const char * /*name */,
+                    const char ** /*out_name */);
+
+OM_uint32 gsskrb5_register_acceptor_identity
+        (const char */*identity*/);
+
+OM_uint32 gss_krb5_copy_ccache
+       (OM_uint32 */*minor*/,
+        gss_cred_id_t /*cred*/,
+        struct krb5_ccache_data */*out*/);
+
+OM_uint32 gss_krb5_copy_service_keyblock
+        (OM_uint32 *minor_status,
+        gss_ctx_id_t context_handle,
+        struct EncryptionKey **out);
+
+OM_uint32 gss_krb5_get_tkt_flags
+       (OM_uint32 */*minor*/,
+        gss_ctx_id_t /*context_handle*/,
+        OM_uint32 */*tkt_flags*/);
+
+OM_uint32
+gsskrb5_extract_authz_data_from_sec_context
+       (OM_uint32 * /*minor_status*/,
+        gss_ctx_id_t /*context_handle*/,
+        int /*ad_type*/,
+        gss_buffer_t /*ad_data*/);
+OM_uint32
+gsskrb5_get_initiator_subkey
+        (OM_uint32 * /*minor_status*/,
+        const gss_ctx_id_t context_handle,
+        gss_buffer_t /* subkey */);
+
+#define GSS_C_KRB5_COMPAT_DES3_MIC 1
+
+OM_uint32
+gss_krb5_compat_des3_mic(OM_uint32 *, gss_ctx_id_t, int);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* GSSAPI_H_ */
diff --git a/source4/heimdal/lib/gssapi/gssapi_locl.h b/source4/heimdal/lib/gssapi/gssapi_locl.h
new file mode 100644 (file)
index 0000000..47a37e4
--- /dev/null
@@ -0,0 +1,295 @@
+/*
+ * 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: gssapi_locl.h,v 1.40 2005/06/16 20:34:03 lha Exp $ */
+
+#ifndef GSSAPI_LOCL_H
+#define GSSAPI_LOCL_H
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <krb5_locl.h>
+#include <gssapi.h>
+#include <assert.h>
+
+#include "cfx.h"
+#include "arcfour.h"
+
+#include "spnego_asn1.h"
+
+/*
+ *
+ */
+
+struct gss_msg_order;
+
+typedef struct gss_ctx_id_t_desc_struct {
+  struct krb5_auth_context_data *auth_context;
+  gss_name_t source, target;
+  enum gss_ctx_id_t_state {
+       INITIATOR_START = 1, INITIATOR_WAIT_FOR_MUTAL = 2, INITIATOR_READY= 3,
+       ACCEPTOR_START = 11, ACCEPTOR_WAIT_FOR_DCESTYLE = 12, ACCEPTOR_READY = 13
+  } state;
+  OM_uint32 flags;
+  enum {LOCAL = 1,
+       OPEN = 2,
+       COMPAT_OLD_DES3 = 4,
+       COMPAT_OLD_DES3_SELECTED = 8,
+       ACCEPTOR_SUBKEY = 16
+  } more_flags;
+  struct krb5_ticket *ticket;
+  krb5_keyblock *service_keyblock;
+  krb5_data fwd_data;
+  OM_uint32 lifetime;
+  HEIMDAL_MUTEX ctx_id_mutex;
+  struct gss_msg_order *order;
+} gss_ctx_id_t_desc;
+
+typedef struct gss_cred_id_t_desc_struct {
+  gss_name_t principal;
+  krb5_boolean made_keytab;
+  struct krb5_keytab_data *keytab;
+  OM_uint32 lifetime;
+  gss_cred_usage_t usage;
+  gss_OID_set mechanisms;
+  krb5_boolean made_ccache;
+  struct krb5_ccache_data *ccache;
+  HEIMDAL_MUTEX cred_id_mutex;
+} gss_cred_id_t_desc;
+
+/*
+ *
+ */
+
+extern krb5_context gssapi_krb5_context;
+
+extern krb5_keytab gssapi_krb5_keytab;
+extern HEIMDAL_MUTEX gssapi_keytab_mutex;
+
+struct gssapi_thr_context {
+    HEIMDAL_MUTEX mutex;
+    char *error_string;
+};
+
+/*
+ * Prototypes
+ */
+
+krb5_error_code gssapi_krb5_init (void);
+
+#define GSSAPI_KRB5_INIT() do {                                        \
+    krb5_error_code kret_gss_init;                             \
+    if((kret_gss_init = gssapi_krb5_init ()) != 0) {           \
+       *minor_status = kret_gss_init;                          \
+       return GSS_S_FAILURE;                                   \
+    }                                                          \
+} while (0)
+
+struct gssapi_thr_context *
+gssapi_get_thread_context(int);
+
+OM_uint32
+_gsskrb5_create_ctx(
+       OM_uint32 * minor_status,
+       gss_ctx_id_t * context_handle,
+       const gss_channel_bindings_t input_chan_bindings,
+       enum gss_ctx_id_t_state state);
+
+void
+gsskrb5_is_cfx(gss_ctx_id_t, int *);
+
+OM_uint32
+gssapi_krb5_create_8003_checksum (
+                     OM_uint32 *minor_status,
+                     const gss_channel_bindings_t input_chan_bindings,
+                     OM_uint32 flags,
+                      const krb5_data *fwd_data,
+                     Checksum *result);
+
+OM_uint32
+gssapi_krb5_verify_8003_checksum (
+                     OM_uint32 *minor_status,
+                     const gss_channel_bindings_t input_chan_bindings,
+                     const Checksum *cksum,
+                     OM_uint32 *flags,
+                      krb5_data *fwd_data);
+
+void
+_gssapi_encap_length (size_t data_len,
+                     size_t *len,
+                     size_t *total_len,
+                     const gss_OID mech);
+
+void
+gssapi_krb5_encap_length (size_t data_len,
+                         size_t *len,
+                         size_t *total_len,
+                         const gss_OID mech);
+
+
+
+OM_uint32
+_gssapi_encapsulate(OM_uint32 *minor_status,
+                   const krb5_data *in_data,
+                   gss_buffer_t output_token,
+                   const gss_OID mech);
+
+
+OM_uint32
+gssapi_krb5_encapsulate(OM_uint32 *minor_status,    
+                       const krb5_data *in_data,
+                       gss_buffer_t output_token,
+                       const u_char *type,
+                       const gss_OID mech);
+
+OM_uint32
+gssapi_krb5_decapsulate(OM_uint32 *minor_status,
+                       gss_buffer_t input_token_buffer,
+                       krb5_data *out_data,
+                       const char *type,
+                       gss_OID oid);
+
+u_char *
+gssapi_krb5_make_header (u_char *p,
+                        size_t len,
+                        const u_char *type,
+                        const gss_OID mech);
+
+u_char *
+_gssapi_make_mech_header(u_char *p,
+                        size_t len,
+                        const gss_OID mech);
+
+OM_uint32
+_gssapi_verify_mech_header(u_char **str,
+                          size_t total_len,
+                          gss_OID oid);
+
+OM_uint32
+gssapi_krb5_verify_header(u_char **str,
+                         size_t total_len,
+                         const u_char *type,
+                         gss_OID oid);
+
+OM_uint32
+_gssapi_decapsulate(OM_uint32 *minor_status,
+                   gss_buffer_t input_token_buffer,
+                   krb5_data *out_data,
+                   const gss_OID mech);
+
+
+ssize_t
+gssapi_krb5_get_mech (const u_char *, size_t, const u_char **);
+
+OM_uint32
+_gssapi_verify_pad(gss_buffer_t, size_t, size_t *);
+
+OM_uint32
+gss_verify_mic_internal(OM_uint32 * minor_status,
+                       const gss_ctx_id_t context_handle,
+                       const gss_buffer_t message_buffer,
+                       const gss_buffer_t token_buffer,
+                       gss_qop_t * qop_state,
+                       char * type);
+
+OM_uint32
+gss_krb5_get_subkey(const gss_ctx_id_t context_handle,
+                   krb5_keyblock **key);
+
+krb5_error_code
+gss_address_to_krb5addr(OM_uint32 gss_addr_type,
+                        gss_buffer_desc *gss_addr,
+                        int16_t port,
+                        krb5_address *address);
+
+/* sec_context flags */
+
+#define SC_LOCAL_ADDRESS  0x01
+#define SC_REMOTE_ADDRESS 0x02
+#define SC_KEYBLOCK      0x04
+#define SC_LOCAL_SUBKEY          0x08
+#define SC_REMOTE_SUBKEY  0x10
+
+int
+gss_oid_equal(const gss_OID a, const gss_OID b);
+
+void
+gssapi_krb5_set_error_string (void);
+
+char *
+gssapi_krb5_get_error_string (void);
+
+OM_uint32
+_gss_DES3_get_mic_compat(OM_uint32 *, gss_ctx_id_t);
+
+OM_uint32
+_gss_spnego_require_mechlist_mic(OM_uint32 *, gss_ctx_id_t, krb5_boolean *);
+
+krb5_error_code
+_gss_check_compat(OM_uint32 *, gss_name_t, const char *,
+                 krb5_boolean *, krb5_boolean);
+
+OM_uint32
+gssapi_lifetime_left(OM_uint32 *, OM_uint32, OM_uint32 *);
+
+/* sequence */
+
+OM_uint32
+_gssapi_msg_order_create(OM_uint32 *, struct gss_msg_order **, 
+                        OM_uint32, OM_uint32, OM_uint32, int);
+OM_uint32
+_gssapi_msg_order_destroy(struct gss_msg_order **);
+
+OM_uint32
+_gssapi_msg_order_check(struct gss_msg_order *, OM_uint32);
+
+OM_uint32
+_gssapi_msg_order_f(OM_uint32);
+
+/* 8003 */
+
+krb5_error_code
+gssapi_encode_om_uint32(OM_uint32, u_char *);
+
+krb5_error_code
+gssapi_encode_be_om_uint32(OM_uint32, u_char *);
+
+krb5_error_code
+gssapi_decode_om_uint32(u_char *, OM_uint32 *);
+
+krb5_error_code
+gssapi_decode_be_om_uint32(u_char *, OM_uint32 *);
+
+#endif
diff --git a/source4/heimdal/lib/gssapi/import_name.c b/source4/heimdal/lib/gssapi/import_name.c
new file mode 100644 (file)
index 0000000..423e757
--- /dev/null
@@ -0,0 +1,229 @@
+/*
+ * 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 "gssapi_locl.h"
+
+RCSID("$Id: import_name.c,v 1.13 2003/03/16 17:33:31 lha Exp $");
+
+static OM_uint32
+parse_krb5_name (OM_uint32 *minor_status,
+                const char *name,
+                gss_name_t *output_name)
+{
+    krb5_error_code kerr;
+
+    kerr = krb5_parse_name (gssapi_krb5_context, name, output_name);
+
+    if (kerr == 0)
+       return GSS_S_COMPLETE;
+    else if (kerr == KRB5_PARSE_ILLCHAR || kerr == KRB5_PARSE_MALFORMED) {
+       gssapi_krb5_set_error_string ();
+       *minor_status = kerr;
+       return GSS_S_BAD_NAME;
+    } else {
+       gssapi_krb5_set_error_string ();
+       *minor_status = kerr;
+       return GSS_S_FAILURE;
+    }
+}
+
+static OM_uint32
+import_krb5_name (OM_uint32 *minor_status,
+                 const gss_buffer_t input_name_buffer,
+                 gss_name_t *output_name)
+{
+    OM_uint32 ret;
+    char *tmp;
+
+    tmp = malloc (input_name_buffer->length + 1);
+    if (tmp == NULL) {
+       *minor_status = ENOMEM;
+       return GSS_S_FAILURE;
+    }
+    memcpy (tmp,
+           input_name_buffer->value,
+           input_name_buffer->length);
+    tmp[input_name_buffer->length] = '\0';
+
+    ret = parse_krb5_name(minor_status, tmp, output_name);
+    free(tmp);
+
+    return ret;
+}
+
+static OM_uint32
+import_hostbased_name (OM_uint32 *minor_status,
+                      const gss_buffer_t input_name_buffer,
+                      gss_name_t *output_name)
+{
+    krb5_error_code kerr;
+    char *tmp;
+    char *p;
+    char *host;
+    char local_hostname[MAXHOSTNAMELEN];
+
+    *output_name = NULL;
+
+    tmp = malloc (input_name_buffer->length + 1);
+    if (tmp == NULL) {
+       *minor_status = ENOMEM;
+       return GSS_S_FAILURE;
+    }
+    memcpy (tmp,
+           input_name_buffer->value,
+           input_name_buffer->length);
+    tmp[input_name_buffer->length] = '\0';
+
+    p = strchr (tmp, '@');
+    if (p != NULL) {
+       *p = '\0';
+       host = p + 1;
+    } else {
+       if (gethostname(local_hostname, sizeof(local_hostname)) < 0) {
+           *minor_status = errno;
+           free (tmp);
+           return GSS_S_FAILURE;
+       }
+       host = local_hostname;
+    }
+
+    kerr = krb5_sname_to_principal (gssapi_krb5_context,
+                                   host,
+                                   tmp,
+                                   KRB5_NT_SRV_HST,
+                                   output_name);
+    free (tmp);
+    *minor_status = kerr;
+    if (kerr == 0)
+       return GSS_S_COMPLETE;
+    else if (kerr == KRB5_PARSE_ILLCHAR || kerr == KRB5_PARSE_MALFORMED) {
+       gssapi_krb5_set_error_string ();
+       *minor_status = kerr;
+       return GSS_S_BAD_NAME;
+    } else {
+       gssapi_krb5_set_error_string ();
+       *minor_status = kerr;
+       return GSS_S_FAILURE;
+    }
+}
+
+static OM_uint32
+import_export_name (OM_uint32 *minor_status,
+                   const gss_buffer_t input_name_buffer,
+                   gss_name_t *output_name)
+{
+    unsigned char *p;
+    uint32_t length;
+    OM_uint32 ret;
+    char *name;
+
+    if (input_name_buffer->length < 10 + GSS_KRB5_MECHANISM->length)
+       return GSS_S_BAD_NAME;
+
+    /* TOK, MECH_OID_LEN, DER(MECH_OID), NAME_LEN, NAME */
+
+    p = input_name_buffer->value;
+
+    if (memcmp(&p[0], "\x04\x01\x00", 3) != 0 ||
+       p[3] != GSS_KRB5_MECHANISM->length + 2 ||
+       p[4] != 0x06 ||
+       p[5] != GSS_KRB5_MECHANISM->length ||
+       memcmp(&p[6], GSS_KRB5_MECHANISM->elements, 
+              GSS_KRB5_MECHANISM->length) != 0)
+       return GSS_S_BAD_NAME;
+
+    p += 6 + GSS_KRB5_MECHANISM->length;
+
+    length = p[0] << 24 | p[1] << 16 | p[2] << 8 | p[3];
+    p += 4;
+
+    if (length > input_name_buffer->length - 10 - GSS_KRB5_MECHANISM->length)
+       return GSS_S_BAD_NAME;
+
+    name = malloc(length + 1);
+    if (name == NULL) {
+       *minor_status = ENOMEM;
+       return GSS_S_FAILURE;
+    }
+    memcpy(name, p, length);
+    name[length] = '\0';
+
+    ret = parse_krb5_name(minor_status, name, output_name);
+    free(name);
+
+    return ret;
+}
+
+int
+gss_oid_equal(const gss_OID a, const gss_OID b)
+{
+       if (a == b)
+               return 1;
+       else if (a == GSS_C_NO_OID || b == GSS_C_NO_OID || a->length != b->length)
+               return 0;
+       else
+               return memcmp(a->elements, b->elements, a->length) == 0;
+}
+
+OM_uint32 gss_import_name
+           (OM_uint32 * minor_status,
+            const gss_buffer_t input_name_buffer,
+            const gss_OID input_name_type,
+            gss_name_t * output_name
+           )
+{
+    GSSAPI_KRB5_INIT ();
+
+    *minor_status = 0;
+    *output_name = GSS_C_NO_NAME;
+    
+    if (gss_oid_equal(input_name_type, GSS_C_NT_HOSTBASED_SERVICE))
+       return import_hostbased_name (minor_status,
+                                     input_name_buffer,
+                                     output_name);
+    else if (gss_oid_equal(input_name_type, GSS_C_NO_OID)
+            || gss_oid_equal(input_name_type, GSS_C_NT_USER_NAME)
+            || gss_oid_equal(input_name_type, GSS_KRB5_NT_PRINCIPAL_NAME))
+       /* default printable syntax */
+       return import_krb5_name (minor_status,
+                                input_name_buffer,
+                                output_name);
+    else if (gss_oid_equal(input_name_type, GSS_C_NT_EXPORT_NAME)) {
+       return import_export_name(minor_status,
+                                 input_name_buffer, 
+                                 output_name);
+    } else {
+       *minor_status = 0;
+       return GSS_S_BAD_NAMETYPE;
+    }
+}
diff --git a/source4/heimdal/lib/gssapi/init.c b/source4/heimdal/lib/gssapi/init.c
new file mode 100644 (file)
index 0000000..37f4662
--- /dev/null
@@ -0,0 +1,111 @@
+/*
+ * 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 "gssapi_locl.h"
+
+RCSID("$Id: init.c,v 1.7 2003/07/22 19:50:11 lha Exp $");
+
+static HEIMDAL_MUTEX gssapi_krb5_context_mutex = HEIMDAL_MUTEX_INITIALIZER;
+static int created_key;
+static HEIMDAL_thread_key gssapi_context_key;
+
+static void
+gssapi_destroy_thread_context(void *ptr)
+{
+    struct gssapi_thr_context *ctx = ptr;
+
+    if (ctx == NULL)
+       return;
+    if (ctx->error_string)
+       free(ctx->error_string);
+    HEIMDAL_MUTEX_destroy(&ctx->mutex);
+    free(ctx);
+}
+
+
+struct gssapi_thr_context *
+gssapi_get_thread_context(int createp)
+{
+    struct gssapi_thr_context *ctx;
+    int ret;
+
+    HEIMDAL_MUTEX_lock(&gssapi_krb5_context_mutex);
+
+    if (!created_key)
+       abort();
+    ctx = HEIMDAL_getspecific(gssapi_context_key);
+    if (ctx == NULL) {
+       if (!createp)
+           goto fail;
+       ctx = malloc(sizeof(*ctx));
+       if (ctx == NULL)
+           goto fail;
+       ctx->error_string = NULL;
+       HEIMDAL_MUTEX_init(&ctx->mutex);
+       HEIMDAL_setspecific(gssapi_context_key, ctx, ret);
+       if (ret)
+           goto fail;
+    }
+    HEIMDAL_MUTEX_unlock(&gssapi_krb5_context_mutex);
+    return ctx;
+ fail:
+    HEIMDAL_MUTEX_unlock(&gssapi_krb5_context_mutex);
+    if (ctx)
+       free(ctx);
+    return NULL;
+}
+
+krb5_error_code
+gssapi_krb5_init (void)
+{
+    krb5_error_code ret = 0;
+
+    HEIMDAL_MUTEX_lock(&gssapi_krb5_context_mutex);
+
+    if(gssapi_krb5_context == NULL)
+       ret = krb5_init_context (&gssapi_krb5_context);
+    if (ret == 0 && !created_key) {
+       HEIMDAL_key_create(&gssapi_context_key, 
+                          gssapi_destroy_thread_context,
+                          ret);
+       if (ret) {
+           krb5_free_context(gssapi_krb5_context);
+           gssapi_krb5_context = NULL;
+       } else
+           created_key = 1;
+    }
+
+    HEIMDAL_MUTEX_unlock(&gssapi_krb5_context_mutex);
+
+    return ret;
+}
diff --git a/source4/heimdal/lib/gssapi/init_sec_context.c b/source4/heimdal/lib/gssapi/init_sec_context.c
new file mode 100644 (file)
index 0000000..c7e4aa5
--- /dev/null
@@ -0,0 +1,1261 @@
+/*
+ * 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 "gssapi_locl.h"
+
+RCSID("$Id: init_sec_context.c,v 1.57 2005/05/30 20:58:29 lha Exp $");
+
+/*
+ * copy the addresses from `input_chan_bindings' (if any) to
+ * the auth context `ac'
+ */
+
+static OM_uint32
+gsskrb5_set_addresses(
+       krb5_auth_context ac,
+       const gss_channel_bindings_t input_chan_bindings)              
+{
+    /* Port numbers are expected to be in application_data.value, 
+     * initator's port first */ 
+
+    krb5_address initiator_addr, acceptor_addr;
+    krb5_error_code kret;
+       
+    if (input_chan_bindings == GSS_C_NO_CHANNEL_BINDINGS
+       || input_chan_bindings->application_data.length !=
+       2 * sizeof(ac->local_port))
+       return 0;
+
+    memset(&initiator_addr, 0, sizeof(initiator_addr));
+    memset(&acceptor_addr, 0, sizeof(acceptor_addr));
+       
+    ac->local_port =
+       *(int16_t *) input_chan_bindings->application_data.value;
+       
+    ac->remote_port =
+       *((int16_t *) input_chan_bindings->application_data.value + 1);
+       
+    kret = gss_address_to_krb5addr(input_chan_bindings->acceptor_addrtype,
+                                  &input_chan_bindings->acceptor_address,
+                                  ac->remote_port,
+                                  &acceptor_addr);
+    if (kret)
+       return kret;
+           
+    kret = gss_address_to_krb5addr(input_chan_bindings->initiator_addrtype,
+                                  &input_chan_bindings->initiator_address,
+                                  ac->local_port,
+                                  &initiator_addr);
+    if (kret) {
+       krb5_free_address (gssapi_krb5_context, &acceptor_addr);
+       return kret;
+    }
+       
+    kret = krb5_auth_con_setaddrs(gssapi_krb5_context,
+                                 ac,
+                                 &initiator_addr,  /* local address */
+                                 &acceptor_addr);  /* remote address */
+       
+    krb5_free_address (gssapi_krb5_context, &initiator_addr);
+    krb5_free_address (gssapi_krb5_context, &acceptor_addr);
+       
+#if 0
+    free(input_chan_bindings->application_data.value);
+    input_chan_bindings->application_data.value = NULL;
+    input_chan_bindings->application_data.length = 0;
+#endif
+
+    return kret;
+}
+
+OM_uint32
+_gsskrb5_create_ctx(
+       OM_uint32 * minor_status,
+       gss_ctx_id_t * context_handle,
+       const gss_channel_bindings_t input_chan_bindings,
+       enum gss_ctx_id_t_state state)
+{
+       krb5_error_code kret;
+
+       *context_handle = malloc(sizeof(**context_handle));
+       if (*context_handle == NULL) {
+               *minor_status = ENOMEM;
+               return GSS_S_FAILURE;
+       }
+       (*context_handle)->auth_context = NULL;
+       (*context_handle)->source       = NULL;
+       (*context_handle)->target       = NULL;
+       (*context_handle)->state        = state;
+       (*context_handle)->flags        = 0;
+       (*context_handle)->more_flags   = 0;
+       (*context_handle)->service_keyblock     = NULL;
+       (*context_handle)->ticket       = NULL;
+       krb5_data_zero(&(*context_handle)->fwd_data);
+       (*context_handle)->lifetime     = GSS_C_INDEFINITE;
+       (*context_handle)->order        = NULL;
+       HEIMDAL_MUTEX_init(&(*context_handle)->ctx_id_mutex);
+
+       kret = krb5_auth_con_init (gssapi_krb5_context,
+                                  &(*context_handle)->auth_context);
+       if (kret) {
+               *minor_status = kret;
+               gssapi_krb5_set_error_string ();
+
+               HEIMDAL_MUTEX_destroy(&(*context_handle)->ctx_id_mutex);
+               
+               return GSS_S_FAILURE;
+       }
+
+       kret = gsskrb5_set_addresses((*context_handle)->auth_context,
+                                    input_chan_bindings);
+       if (kret) {
+               *minor_status = kret;
+
+               HEIMDAL_MUTEX_destroy(&(*context_handle)->ctx_id_mutex);
+
+               krb5_auth_con_free(gssapi_krb5_context, (*context_handle)->auth_context);
+
+               return GSS_S_BAD_BINDINGS;
+       }
+
+       return GSS_S_COMPLETE;
+}
+
+static OM_uint32
+gsskrb5_get_creds(
+       OM_uint32 * minor_status,
+       const gss_cred_id_t initiator_cred_handle,
+       gss_ctx_id_t * context_handle,
+       const gss_name_t target_name,
+       OM_uint32 time_req,
+       OM_uint32 * time_rec,
+       krb5_creds ** cred)
+{
+       OM_uint32 ret;
+       krb5_error_code kret;
+       krb5_creds this_cred;
+       krb5_ccache ccache = NULL;
+       OM_uint32 lifetime_rec;
+
+       *cred = NULL;
+
+       if (initiator_cred_handle == GSS_C_NO_CREDENTIAL) {
+               kret = krb5_cc_default (gssapi_krb5_context, &ccache);
+               if (kret) {
+                       gssapi_krb5_set_error_string ();
+                       *minor_status = kret;
+                       return GSS_S_FAILURE;
+               }
+       } else {
+               ccache = initiator_cred_handle->ccache;
+       }
+
+       kret = krb5_cc_get_principal(gssapi_krb5_context,
+                                    ccache,
+                                    &(*context_handle)->source);
+       if (kret) {
+               gssapi_krb5_set_error_string ();
+               *minor_status = kret;
+               return GSS_S_FAILURE;
+       }
+
+       kret = krb5_copy_principal(gssapi_krb5_context,
+                                  target_name,
+                                  &(*context_handle)->target);
+       if (kret) {
+               gssapi_krb5_set_error_string ();
+               *minor_status = kret;
+               return GSS_S_FAILURE;
+       }
+
+       memset(&this_cred, 0, sizeof(this_cred));
+       this_cred.client = (*context_handle)->source;
+       this_cred.server = (*context_handle)->target;
+
+       if (time_req && time_req != GSS_C_INDEFINITE) {
+               krb5_timestamp ts;
+
+               krb5_timeofday (gssapi_krb5_context, &ts);
+               this_cred.times.endtime = ts + time_req;
+       } else {
+               this_cred.times.endtime   = 0;
+       }
+
+       this_cred.session.keytype = KEYTYPE_NULL;
+
+       kret = krb5_get_credentials(gssapi_krb5_context,
+                                   0,
+                                   ccache,
+                                   &this_cred,
+                                   cred);
+       if (kret) {
+               gssapi_krb5_set_error_string ();
+               *minor_status = kret;
+               return GSS_S_FAILURE;
+       }
+
+       (*context_handle)->lifetime = (*cred)->times.endtime;
+
+       ret = gssapi_lifetime_left(minor_status,
+                                  (*context_handle)->lifetime,
+                                  &lifetime_rec);
+       if (ret) return ret;
+
+       if (lifetime_rec == 0) {
+               *minor_status = 0;
+               return GSS_S_CONTEXT_EXPIRED;
+       }
+
+       if (time_rec) *time_rec = lifetime_rec;
+
+       if (initiator_cred_handle == GSS_C_NO_CREDENTIAL) {
+               krb5_cc_close(gssapi_krb5_context, ccache);
+       }
+
+       return GSS_S_COMPLETE;
+}
+
+static OM_uint32
+gsskrb5_initiator_ready(
+       OM_uint32 * minor_status,
+       gss_ctx_id_t * context_handle)
+{
+       OM_uint32 ret;
+       int32_t seq_number;
+       int is_cfx = 0;
+       u_int32_t flags = (*context_handle)->flags;
+
+       krb5_auth_getremoteseqnumber (gssapi_krb5_context,
+                                     (*context_handle)->auth_context,
+                                     &seq_number);
+
+       gsskrb5_is_cfx(*context_handle, &is_cfx);
+
+       ret = _gssapi_msg_order_create(minor_status,
+                                      &(*context_handle)->order,
+                                      _gssapi_msg_order_f(flags),
+                                      seq_number, 0, is_cfx);
+       if (ret) return ret;
+
+       (*context_handle)->state        = INITIATOR_READY;
+       (*context_handle)->more_flags   |= OPEN;
+
+       return GSS_S_COMPLETE;
+}
+
+/*
+ * handle delegated creds in init-sec-context
+ */
+
+static void
+gsskrb5_do_delegation(
+       krb5_auth_context ac,
+       krb5_ccache ccache,
+       krb5_creds *cred,
+       const gss_name_t target_name,
+       krb5_data *fwd_data,
+       int *flags)
+{
+    krb5_creds creds;
+    krb5_kdc_flags fwd_flags;
+    krb5_error_code kret;
+       
+    memset (&creds, 0, sizeof(creds));
+    krb5_data_zero (fwd_data);
+
+    kret = krb5_cc_get_principal(gssapi_krb5_context, ccache, &creds.client);
+    if (kret) 
+       goto out;
+       
+    kret = krb5_build_principal(gssapi_krb5_context,
+                               &creds.server,
+                               strlen(creds.client->realm),
+                               creds.client->realm,
+                               KRB5_TGS_NAME,
+                               creds.client->realm,
+                               NULL);
+    if (kret)
+       goto out; 
+       
+    creds.times.endtime = 0;
+       
+    fwd_flags.i = 0;
+    fwd_flags.b.forwarded = 1;
+    fwd_flags.b.forwardable = 1;
+       
+    if ( /*target_name->name.name_type != KRB5_NT_SRV_HST ||*/
+       target_name->name.name_string.len < 2) 
+       goto out;
+       
+    kret = krb5_get_forwarded_creds(gssapi_krb5_context,
+                                   ac,
+                                   ccache,
+                                   fwd_flags.i,
+                                   target_name->name.name_string.val[1],
+                                   &creds,
+                                   fwd_data);
+       
+ out:
+    if (kret)
+       *flags &= ~GSS_C_DELEG_FLAG;
+    else
+       *flags |= GSS_C_DELEG_FLAG;
+       
+    if (creds.client)
+       krb5_free_principal(gssapi_krb5_context, creds.client);
+    if (creds.server)
+       krb5_free_principal(gssapi_krb5_context, creds.server);
+}
+
+/*
+ * first stage of init-sec-context
+ */
+
+static OM_uint32
+gsskrb5_initiator_start(
+       OM_uint32 * minor_status,
+       const gss_cred_id_t initiator_cred_handle,
+       gss_ctx_id_t * context_handle,
+       const gss_name_t target_name,
+       const gss_OID mech_type,
+       OM_uint32 req_flags,
+       OM_uint32 time_req,
+       const gss_channel_bindings_t input_chan_bindings,
+       const gss_buffer_t input_token,
+       gss_buffer_t output_token,
+       OM_uint32 * ret_flags,
+       OM_uint32 * time_rec)
+{
+       OM_uint32 ret = GSS_S_FAILURE;
+       krb5_error_code kret;
+       krb5_flags ap_options;
+       krb5_creds *cred = NULL;
+       krb5_data outbuf;
+       krb5_ccache ccache = NULL;
+       u_int32_t flags;
+       krb5_data authenticator;
+       Checksum cksum;
+       krb5_enctype enctype;
+       krb5_data fwd_data;
+
+       krb5_data_zero(&outbuf);
+       krb5_data_zero(&fwd_data);
+
+       (*context_handle)->more_flags |= LOCAL;
+
+       /* We need to get the credentials for the requested target */
+       ret = gsskrb5_get_creds(minor_status,
+                               initiator_cred_handle,
+                               context_handle,
+                               target_name,
+                               time_req,
+                               time_rec,
+                               &cred);
+       if (ret) return ret;
+
+       /*
+        * We need to setup some compat stuff, this assumes that context_handle->target is already set
+        */
+       ret = _gss_DES3_get_mic_compat(minor_status, *context_handle);
+       if (ret) return ret;
+
+       /*
+        * We need a sequence number
+        */
+
+       krb5_auth_con_addflags(gssapi_krb5_context,
+                              (*context_handle)->auth_context,
+                              KRB5_AUTH_CONTEXT_DO_SEQUENCE,
+                              NULL);
+
+       /* We need the key and a random local subkey */
+       {
+               kret = krb5_auth_con_setkey(gssapi_krb5_context, 
+                            (*context_handle)->auth_context, 
+                            &cred->session);
+               if (kret) {
+                       gssapi_krb5_set_error_string ();
+                       *minor_status = kret;
+                       return GSS_S_FAILURE;
+               }
+
+               kret = krb5_auth_con_generatelocalsubkey(gssapi_krb5_context, 
+                                                        (*context_handle)->auth_context,
+                                                        &cred->session);
+               if (kret) {
+                       gssapi_krb5_set_error_string ();
+                       *minor_status = kret;
+                       return GSS_S_FAILURE;
+               }
+       }
+
+       /* We need to prepare the flags used for this context */
+       {
+               flags = 0;
+               ap_options = 0;
+
+               if (req_flags & GSS_C_DELEG_FLAG) {
+                       gsskrb5_do_delegation((*context_handle)->auth_context,
+                                             ccache, cred, target_name, &fwd_data, &flags);
+               }
+
+               if (req_flags & GSS_C_MUTUAL_FLAG) {
+                       flags |= GSS_C_MUTUAL_FLAG;
+                       ap_options |= AP_OPTS_MUTUAL_REQUIRED;
+               }
+    
+               if (req_flags & GSS_C_REPLAY_FLAG) {
+                       flags |= GSS_C_REPLAY_FLAG;
+               }
+
+               if (req_flags & GSS_C_SEQUENCE_FLAG) {
+                       flags |= GSS_C_SEQUENCE_FLAG;
+               }
+
+               if (req_flags & GSS_C_ANON_FLAG) {
+                       ;/* XXX */
+               }
+
+               if (req_flags & GSS_C_DCE_STYLE) {
+                       flags |= GSS_C_DCE_STYLE;
+                       /* GSS_C_DCE_STYLE implies GSS_C_MUTUAL_FLAG */
+                       flags |= GSS_C_MUTUAL_FLAG;
+                       ap_options |= AP_OPTS_MUTUAL_REQUIRED;
+               }
+
+               if (req_flags & GSS_C_IDENTIFY_FLAG) {
+                       flags |= GSS_C_IDENTIFY_FLAG;
+               }
+
+               if (req_flags & GSS_C_EXTENDED_ERROR_FLAG) {
+                       flags |= GSS_C_EXTENDED_ERROR_FLAG;
+               }
+
+               /* TODO: why are this always there? --metze */
+               flags |= GSS_C_CONF_FLAG;
+               flags |= GSS_C_INTEG_FLAG;
+               flags |= GSS_C_TRANS_FLAG;
+
+               if (ret_flags) *ret_flags = flags;
+               (*context_handle)->flags = flags;
+       }
+
+       /* We need to generate the 8003 checksum */
+       {
+               ret = gssapi_krb5_create_8003_checksum(minor_status,
+                                                      input_chan_bindings,
+                                                      flags,
+                                                      &fwd_data,
+                                                      &cksum);
+               krb5_data_free (&fwd_data);
+               if (ret) return ret;
+       }
+
+       enctype = (*context_handle)->auth_context->keyblock->keytype;
+
+       /* We need to create an Authenticator */
+       {
+               kret = krb5_build_authenticator (gssapi_krb5_context,
+                                    (*context_handle)->auth_context,
+                                    enctype,
+                                    cred,
+                                    &cksum,
+                                    NULL,
+                                    &authenticator,
+                                    KRB5_KU_AP_REQ_AUTH);
+               free_Checksum(&cksum);
+               if (kret) {
+                       gssapi_krb5_set_error_string ();
+                       *minor_status = kret;
+                       return GSS_S_FAILURE;
+               }
+       }
+
+       /* We need to create the AP_REQ */
+       {
+               kret = krb5_build_ap_req(gssapi_krb5_context,
+                                        enctype,
+                                        cred,
+                                        ap_options,
+                                        authenticator,
+                                        &outbuf);
+               if (kret) {
+                       gssapi_krb5_set_error_string ();
+                       *minor_status = kret;
+                       return GSS_S_FAILURE;
+               }
+       }
+
+       /* We need to encapsulate the AP_REQ if GSS_C_DCE_STYLE isn't in use */
+       {
+               if (!(flags & GSS_C_DCE_STYLE)) {
+                       ret = gssapi_krb5_encapsulate(minor_status, &outbuf, output_token,
+                                                     "\x01\x00", GSS_KRB5_MECHANISM);
+                       krb5_data_free (&outbuf);
+                       if (ret) return ret;
+               } else {
+                       output_token->length = outbuf.length;
+                       output_token->value  = outbuf.data;
+               }
+       }
+
+       /* We no longer need the creds */
+       krb5_free_creds(gssapi_krb5_context, cred);
+
+       /* We are done if GSS_C_MUTUAL_FLAG is in use */
+       if (flags & GSS_C_MUTUAL_FLAG) {
+               (*context_handle)->state = INITIATOR_WAIT_FOR_MUTAL;
+               return GSS_S_CONTINUE_NEEDED;
+       }
+
+       return gsskrb5_initiator_ready(minor_status, context_handle);
+}
+
+static OM_uint32
+gsskrb5_initiator_wait_for_mutual(
+       OM_uint32 * minor_status,
+       const gss_cred_id_t initiator_cred_handle,
+       gss_ctx_id_t * context_handle,
+       const gss_name_t target_name,
+       const gss_OID mech_type,
+       OM_uint32 req_flags,
+       OM_uint32 time_req,
+       const gss_channel_bindings_t input_chan_bindings,
+       const gss_buffer_t input_token,
+       gss_buffer_t output_token,
+       OM_uint32 * ret_flags,
+       OM_uint32 * time_rec)
+{
+       OM_uint32 ret;
+       krb5_error_code kret;
+       krb5_data inbuf;
+       u_int32_t flags = (*context_handle)->flags;
+       OM_uint32 l_seq_number;
+       OM_uint32 r_seq_number;
+       
+       /* We need to decapsulate the AP_REP if GSS_C_DCE_STYLE isn't in use */
+       {
+               if (!(flags & GSS_C_DCE_STYLE)) {
+                       ret = gssapi_krb5_decapsulate(minor_status, input_token, &inbuf,
+                                                     "\x02\x00", GSS_KRB5_MECHANISM);
+                       if (ret) return ret;
+               } else {
+                       inbuf.length    = input_token->length;
+                       inbuf.data      = input_token->value;
+               }
+       }
+
+       /* We need to verify the AP_REP */ 
+       {
+               krb5_ap_rep_enc_part *repl;
+
+               kret = krb5_rd_rep(gssapi_krb5_context,
+                                  (*context_handle)->auth_context,
+                                  &inbuf,
+                                  &repl);
+               if (kret) {
+                       gssapi_krb5_set_error_string ();
+                       *minor_status = kret;
+                       return GSS_S_FAILURE;
+               }
+               krb5_free_ap_rep_enc_part(gssapi_krb5_context, repl);
+       }
+
+       /* We need to check the liftime */
+       {
+               OM_uint32 lifetime_rec;
+
+               ret = gssapi_lifetime_left(minor_status,
+                                          (*context_handle)->lifetime,
+                                          &lifetime_rec);
+               if (ret) return ret;
+
+               if (lifetime_rec == 0) {
+                       return GSS_S_CONTEXT_EXPIRED;
+               }
+       
+               if (time_rec) *time_rec = lifetime_rec;
+       }
+
+       /* We need to give the caller the flags which are in use */
+       if (ret_flags) *ret_flags = (*context_handle)->flags;
+
+       /* We are done here if GSS_C_DCE_STYLE isn't in use */
+       if (!(flags & GSS_C_DCE_STYLE)) {
+               return gsskrb5_initiator_ready(minor_status, context_handle);
+       }
+
+       /* 
+        * We need to set the local seq_number to the remote one just for the krb5_mk_rep(),
+        * and then we need to use the old local seq_number again for the GSS_Wrap() messages
+        */
+       {
+               kret = krb5_auth_getremoteseqnumber(gssapi_krb5_context,
+                                                   (*context_handle)->auth_context,
+                                                   &r_seq_number);
+               if (kret) {
+                       gssapi_krb5_set_error_string ();
+                       *minor_status = kret;
+                       return GSS_S_FAILURE;
+               }
+
+               kret = krb5_auth_con_getlocalseqnumber(gssapi_krb5_context,
+                                                   (*context_handle)->auth_context,
+                                                   &l_seq_number);
+               if (kret) {
+                       gssapi_krb5_set_error_string ();
+                       *minor_status = kret;
+                       return GSS_S_FAILURE;
+               }
+
+               kret = krb5_auth_con_setlocalseqnumber(gssapi_krb5_context,
+                                                      (*context_handle)->auth_context,
+                                                      r_seq_number);   
+               if (kret) {
+                       gssapi_krb5_set_error_string ();
+                       *minor_status = kret;
+                       return GSS_S_FAILURE;
+               }
+       }
+
+       /* We need to create an AP_REP */ 
+       {
+               krb5_data outbuf;
+
+               kret = krb5_mk_rep(gssapi_krb5_context,
+                                  (*context_handle)->auth_context,
+                                  &outbuf);
+               if (kret) {
+                       gssapi_krb5_set_error_string ();
+                       *minor_status = kret;
+                       return GSS_S_FAILURE;
+               }
+
+               output_token->length = outbuf.length;
+               output_token->value  = outbuf.data;
+       }
+
+       /* We need to reset the local seq_number */
+       {
+               kret = krb5_auth_con_setlocalseqnumber(gssapi_krb5_context,
+                                                      (*context_handle)->auth_context,
+                                                      l_seq_number);   
+               if (kret) {
+                       gssapi_krb5_set_error_string ();
+                       *minor_status = kret;
+                       return GSS_S_FAILURE;
+               }       
+       }
+
+       return gsskrb5_initiator_ready(minor_status, context_handle);
+}
+
+static OM_uint32
+gsskrb5_init_sec_context(
+       OM_uint32 * minor_status,
+       const gss_cred_id_t initiator_cred_handle,
+       gss_ctx_id_t * context_handle,
+       const gss_name_t target_name,
+       const gss_OID mech_type,
+       OM_uint32 req_flags,
+       OM_uint32 time_req,
+       const gss_channel_bindings_t input_chan_bindings,
+       const gss_buffer_t input_token,
+       gss_OID * actual_mech_type,
+       gss_buffer_t output_token,
+       OM_uint32 * ret_flags,
+       OM_uint32 * time_rec)
+{
+       OM_uint32 ret;
+
+       if (*context_handle == GSS_C_NO_CONTEXT) {
+               ret = _gsskrb5_create_ctx(minor_status,
+                                         context_handle,
+                                         input_chan_bindings,
+                                         INITIATOR_START);
+               if (ret) return ret;
+       }
+
+       if (actual_mech_type) *actual_mech_type = GSS_KRB5_MECHANISM;
+
+       HEIMDAL_MUTEX_lock(&(*context_handle)->ctx_id_mutex);
+
+       switch ((*context_handle)->state) {
+       case INITIATOR_START:
+               ret = gsskrb5_initiator_start(minor_status,
+                                             initiator_cred_handle,
+                                             context_handle,
+                                             target_name,
+                                             mech_type,
+                                             req_flags,
+                                             time_req,
+                                             input_chan_bindings,
+                                             input_token,
+                                             output_token,
+                                             ret_flags,
+                                             time_rec);
+               break;
+       case INITIATOR_WAIT_FOR_MUTAL:
+               ret = gsskrb5_initiator_wait_for_mutual(minor_status,
+                                                       initiator_cred_handle,
+                                                       context_handle,
+                                                       target_name,
+                                                       mech_type,
+                                                       req_flags,
+                                                       time_req,
+                                                       input_chan_bindings,
+                                                       input_token,
+                                                       output_token,
+                                                       ret_flags,
+                                                       time_rec);
+               break;
+       case INITIATOR_READY:
+               /* should this be GSS_S_BAD_STATUS ? --metze */
+
+               /* We need to check the liftime */
+               {
+                       OM_uint32 lifetime_rec;
+
+                       ret = gssapi_lifetime_left(minor_status,
+                                                  (*context_handle)->lifetime,
+                                                  &lifetime_rec);
+                       if (ret) break;
+
+                       if (lifetime_rec == 0) {
+                               *minor_status = 0;
+                               ret = GSS_S_CONTEXT_EXPIRED;
+                               break;
+                       }
+
+                       if (time_rec) *time_rec = lifetime_rec;
+               }
+
+               /* We need to give the caller the flags which are in use */
+               if (ret_flags) *ret_flags = (*context_handle)->flags;
+
+               ret = GSS_S_COMPLETE;
+               break;
+       default:
+               /* TODO: is this correct here? --metze */
+               ret =  GSS_S_BAD_STATUS;
+               break;
+       }
+
+       HEIMDAL_MUTEX_unlock(&(*context_handle)->ctx_id_mutex);
+
+       return ret;
+}
+
+static OM_uint32
+spnego_reply
+           (OM_uint32 * minor_status,
+            const gss_cred_id_t initiator_cred_handle,
+            gss_ctx_id_t * context_handle,
+            const gss_name_t target_name,
+            const gss_OID mech_type,
+            OM_uint32 req_flags,
+            OM_uint32 time_req,
+            const gss_channel_bindings_t input_chan_bindings,
+            const gss_buffer_t input_token,
+            gss_OID * actual_mech_type,
+            gss_buffer_t output_token,
+            OM_uint32 * ret_flags,
+            OM_uint32 * time_rec
+    )
+{
+    OM_uint32 ret;
+    krb5_data indata;
+    NegTokenTarg targ;
+    u_char oidbuf[17];
+    size_t oidlen;
+    gss_buffer_desc sub_token;
+    ssize_t mech_len;
+    const u_char *p;
+    size_t len, taglen;
+    krb5_boolean require_mic;
+
+    output_token->length = 0;
+    output_token->value  = NULL;
+
+    /*
+     * SPNEGO doesn't include gss wrapping on SubsequentContextToken
+     * like the Kerberos 5 mech does. But lets check for it anyway.
+     */
+    
+    mech_len = gssapi_krb5_get_mech (input_token->value,
+                                    input_token->length,
+                                    &p);
+
+    if (mech_len < 0) {
+       indata.data = input_token->value;
+       indata.length = input_token->length;
+    } else if (mech_len == GSS_KRB5_MECHANISM->length
+       && memcmp(GSS_KRB5_MECHANISM->elements, p, mech_len) == 0)
+       return gsskrb5_init_sec_context (minor_status,
+                                        initiator_cred_handle,
+                                        context_handle,
+                                        target_name,
+                                        GSS_KRB5_MECHANISM,
+                                        req_flags,
+                                        time_req,
+                                        input_chan_bindings,
+                                        input_token,
+                                        actual_mech_type,
+                                        output_token,
+                                        ret_flags,
+                                        time_rec);
+    else if (mech_len == GSS_SPNEGO_MECHANISM->length
+            && memcmp(GSS_SPNEGO_MECHANISM->elements, p, mech_len) == 0){
+       ret = _gssapi_decapsulate (minor_status,
+                                  input_token,
+                                  &indata,
+                                  GSS_SPNEGO_MECHANISM);
+       if (ret)
+           return ret;
+    } else
+       return GSS_S_BAD_MECH;
+
+    ret = der_match_tag_and_length((const char *)indata.data,
+                                  indata.length,
+                                  ASN1_C_CONTEXT, CONS, 1, &len, &taglen);
+    if (ret)
+       return ret;
+
+    if(len > indata.length - taglen)
+       return ASN1_OVERRUN;
+
+    ret = decode_NegTokenTarg((const char *)indata.data + taglen, 
+                             len, &targ, NULL);
+    if (ret) {
+       *minor_status = ENOMEM;
+       return GSS_S_FAILURE;
+    }
+
+    if (targ.negResult == NULL
+       || *(targ.negResult) == reject
+       || targ.supportedMech == NULL) {
+       free_NegTokenTarg(&targ);
+       return GSS_S_BAD_MECH;
+    }
+    
+    ret = der_put_oid(oidbuf + sizeof(oidbuf) - 1,
+                     sizeof(oidbuf),
+                     targ.supportedMech,
+                     &oidlen);
+    if (ret || oidlen != GSS_KRB5_MECHANISM->length
+       || memcmp(oidbuf + sizeof(oidbuf) - oidlen,
+                 GSS_KRB5_MECHANISM->elements,
+                 oidlen) != 0) {
+       free_NegTokenTarg(&targ);
+       return GSS_S_BAD_MECH;
+    }
+
+    if (targ.responseToken != NULL) {
+       sub_token.length = targ.responseToken->length;
+       sub_token.value  = targ.responseToken->data;
+    } else {
+       sub_token.length = 0;
+       sub_token.value  = NULL;
+    }
+
+    ret = gsskrb5_init_sec_context(minor_status,
+                                  initiator_cred_handle,
+                                  context_handle,
+                                  target_name,
+                                  GSS_KRB5_MECHANISM,
+                                  req_flags,
+                                  time_req,
+                                  input_chan_bindings,
+                                  &sub_token,
+                                  actual_mech_type,
+                                  output_token,
+                                  ret_flags,
+                                  time_rec);
+    if (ret) {
+       free_NegTokenTarg(&targ);
+       return ret;
+    }
+
+    /*
+     * Verify the mechListMIC if CFX was used; or if local policy
+     * dictated so.
+     */
+    ret = _gss_spnego_require_mechlist_mic(minor_status, *context_handle,
+                                          &require_mic);
+    if (ret) {
+       free_NegTokenTarg(&targ);
+       return ret;
+    }
+
+    if (require_mic) {
+       MechTypeList mechlist;
+       MechType m0;
+       size_t buf_len;
+       gss_buffer_desc mic_buf, mech_buf;
+
+       if (targ.mechListMIC == NULL) {
+           free_NegTokenTarg(&targ);
+           *minor_status = 0;
+           return GSS_S_BAD_MIC;
+       }
+
+       mechlist.len = 1;
+       mechlist.val = &m0;
+
+       ret = der_get_oid(GSS_KRB5_MECHANISM->elements,
+                         GSS_KRB5_MECHANISM->length,
+                         &m0,
+                         NULL);
+       if (ret) {
+           free_NegTokenTarg(&targ);
+           *minor_status = ENOMEM;
+           return GSS_S_FAILURE;
+       }
+
+       ASN1_MALLOC_ENCODE(MechTypeList, mech_buf.value, mech_buf.length,
+                          &mechlist, &buf_len, ret);
+       if (ret) {
+           free_NegTokenTarg(&targ);
+           free_oid(&m0);
+           *minor_status = ENOMEM;
+           return GSS_S_FAILURE;
+       }
+       if (mech_buf.length != buf_len)
+           abort();
+
+       mic_buf.length = targ.mechListMIC->length;
+       mic_buf.value  = targ.mechListMIC->data;
+
+       ret = gss_verify_mic(minor_status, *context_handle,
+                            &mech_buf, &mic_buf, NULL);
+       free(mech_buf.value);
+       free_oid(&m0);
+    }
+    free_NegTokenTarg(&targ);
+    return ret;
+}
+
+static OM_uint32
+spnego_initial
+           (OM_uint32 * minor_status,
+            const gss_cred_id_t initiator_cred_handle,
+            gss_ctx_id_t * context_handle,
+            const gss_name_t target_name,
+            const gss_OID mech_type,
+            OM_uint32 req_flags,
+            OM_uint32 time_req,
+            const gss_channel_bindings_t input_chan_bindings,
+            const gss_buffer_t input_token,
+            gss_OID * actual_mech_type,
+            gss_buffer_t output_token,
+            OM_uint32 * ret_flags,
+            OM_uint32 * time_rec
+          )
+{
+    NegTokenInit ni;
+    int ret;
+    OM_uint32 sub, minor;
+    gss_buffer_desc mech_token;
+    u_char *buf;
+    size_t buf_size, buf_len;
+    krb5_data data;
+#if 1
+    size_t ni_len;
+#endif
+
+    memset (&ni, 0, sizeof(ni));
+
+    ALLOC(ni.mechTypes, 1);
+    if (ni.mechTypes == NULL) {
+       *minor_status = ENOMEM;
+       return GSS_S_FAILURE;
+    }
+    ALLOC_SEQ(ni.mechTypes, 1);
+    if (ni.mechTypes->val == NULL) {
+       free_NegTokenInit(&ni);
+       *minor_status = ENOMEM;
+       return GSS_S_FAILURE;
+    }
+    ret = der_get_oid(GSS_KRB5_MECHANISM->elements,
+                     GSS_KRB5_MECHANISM->length,
+                     &ni.mechTypes->val[0],
+                     NULL);
+    if (ret) {
+       free_NegTokenInit(&ni);
+       *minor_status = ENOMEM;
+       return GSS_S_FAILURE;
+    }
+
+#if 0
+    ALLOC(ni.reqFlags, 1);
+    if (ni.reqFlags == NULL) {
+       free_NegTokenInit(&ni);
+       *minor_status = ENOMEM;
+       return GSS_S_FAILURE;
+    }
+    ni.reqFlags->delegFlag    = req_flags & GSS_C_DELEG_FLAG;
+    ni.reqFlags->mutualFlag   = req_flags & GSS_C_MUTUAL_FLAG;
+    ni.reqFlags->replayFlag   = req_flags & GSS_C_REPLAY_FLAG;
+    ni.reqFlags->sequenceFlag = req_flags & GSS_C_SEQUENCE_FLAG;
+    ni.reqFlags->anonFlag     = req_flags & GSS_C_ANON_FLAG;
+    ni.reqFlags->confFlag     = req_flags & GSS_C_CONF_FLAG;
+    ni.reqFlags->integFlag    = req_flags & GSS_C_INTEG_FLAG;
+#else
+    ni.reqFlags = NULL;
+#endif
+
+    sub = gsskrb5_init_sec_context(&minor,
+                                  initiator_cred_handle,
+                                  context_handle,
+                                  target_name,
+                                  GSS_KRB5_MECHANISM,
+                                  req_flags,
+                                  time_req,
+                                  input_chan_bindings,
+                                  GSS_C_NO_BUFFER,
+                                  actual_mech_type,
+                                  &mech_token,
+                                  ret_flags,
+                                  time_rec);
+    if (GSS_ERROR(sub)) {
+       free_NegTokenInit(&ni);
+       return sub;
+    }
+    if (mech_token.length != 0) {
+       ALLOC(ni.mechToken, 1);
+       if (ni.mechToken == NULL) {
+           free_NegTokenInit(&ni);
+           gss_release_buffer(&minor, &mech_token);
+           *minor_status = ENOMEM;
+           return GSS_S_FAILURE;
+       }
+       ni.mechToken->length = mech_token.length;
+       ni.mechToken->data = malloc(mech_token.length);
+       if (ni.mechToken->data == NULL && mech_token.length != 0) {
+           free_NegTokenInit(&ni);
+           gss_release_buffer(&minor, &mech_token);
+           *minor_status = ENOMEM;
+           return GSS_S_FAILURE;
+       }
+       memcpy(ni.mechToken->data, mech_token.value, mech_token.length);
+       gss_release_buffer(&minor, &mech_token);
+    } else
+       ni.mechToken = NULL;
+
+    /* XXX ignore mech list mic for now */
+    ni.mechListMIC = NULL;
+
+
+#if 0
+    {
+       int ret;
+       NegotiationToken nt;
+
+       nt.element = choice_NegotiationToken_negTokenInit;
+       nt.u.negTokenInit = ni;
+
+       ASN1_MALLOC_ENCODE(NegotiationToken, buf, buf_size,
+                          &nt, &buf_len, ret);
+       if (buf_size != buf_len)
+           abort();
+    }
+#else
+    ni_len = length_NegTokenInit(&ni);
+    buf_size = 1 + length_len(ni_len) + ni_len;
+
+    buf = malloc(buf_size);
+    if (buf == NULL) {
+       free_NegTokenInit(&ni);
+       *minor_status = ENOMEM;
+       return GSS_S_FAILURE;
+    }
+
+    ret = encode_NegTokenInit(buf + buf_size - 1,
+                             ni_len,
+                             &ni, &buf_len);
+    if (ret == 0 && ni_len != buf_len)
+       abort();
+
+    if (ret == 0) {
+       size_t tmp;
+
+       ret = der_put_length_and_tag(buf + buf_size - buf_len - 1,
+                                    buf_size - buf_len,
+                                    buf_len,
+                                    ASN1_C_CONTEXT,
+                                    CONS,
+                                    0,
+                                    &tmp);
+       if (ret == 0 && tmp + buf_len != buf_size)
+           abort();
+    }
+    if (ret) {
+       *minor_status = ret;
+       free(buf);
+       free_NegTokenInit(&ni);
+       return GSS_S_FAILURE;
+    }
+
+#endif
+    data.data   = buf;
+    data.length = buf_size;
+
+    free_NegTokenInit(&ni);
+    if (ret)
+       return ret;
+
+    sub = _gssapi_encapsulate(minor_status,
+                             &data,
+                             output_token,
+                             GSS_SPNEGO_MECHANISM);
+    free (buf);
+
+    if (sub)
+       return sub;
+
+    return GSS_S_CONTINUE_NEEDED;
+}
+
+static OM_uint32
+spnego_init_sec_context
+           (OM_uint32 * minor_status,
+            const gss_cred_id_t initiator_cred_handle,
+            gss_ctx_id_t * context_handle,
+            const gss_name_t target_name,
+            const gss_OID mech_type,
+            OM_uint32 req_flags,
+            OM_uint32 time_req,
+            const gss_channel_bindings_t input_chan_bindings,
+            const gss_buffer_t input_token,
+            gss_OID * actual_mech_type,
+            gss_buffer_t output_token,
+            OM_uint32 * ret_flags,
+            OM_uint32 * time_rec
+           )
+{
+    if (input_token == GSS_C_NO_BUFFER || input_token->length == 0)
+       return spnego_initial (minor_status,
+                              initiator_cred_handle,
+                              context_handle,
+                              target_name,
+                              mech_type,
+                              req_flags,
+                              time_req,
+                              input_chan_bindings,
+                              input_token,
+                              actual_mech_type,
+                              output_token,
+                              ret_flags,
+                              time_rec);
+    else
+       return spnego_reply (minor_status,
+                            initiator_cred_handle,
+                            context_handle,
+                            target_name,
+                            mech_type,
+                            req_flags,
+                            time_req,
+                            input_chan_bindings,
+                            input_token,
+                            actual_mech_type,
+                            output_token,
+                            ret_flags,
+                            time_rec);
+}
+
+/*
+ * gss_init_sec_context
+ */
+
+OM_uint32 gss_init_sec_context(
+       OM_uint32 * minor_status,
+       const gss_cred_id_t initiator_cred_handle,
+       gss_ctx_id_t * context_handle,
+       const gss_name_t target_name,
+       const gss_OID mech_type,
+       OM_uint32 req_flags,
+       OM_uint32 time_req,
+       const gss_channel_bindings_t input_chan_bindings,
+       const gss_buffer_t input_token,
+       gss_OID * actual_mech_type,
+       gss_buffer_t output_token,
+       OM_uint32 * ret_flags,
+       OM_uint32 * time_rec)
+{
+       GSSAPI_KRB5_INIT ();
+
+       *minor_status = 0;
+
+       if (actual_mech_type)   *actual_mech_type       = GSS_C_NO_OID;
+
+       output_token->length = 0;
+       output_token->value  = NULL;
+
+       if (ret_flags)          *ret_flags              = 0;
+       if (time_rec)           *time_rec               = 0;
+
+       if (target_name == GSS_C_NO_NAME) return GSS_S_BAD_NAME;
+
+       if (mech_type == GSS_C_NO_OID ||
+           gss_oid_equal(mech_type, GSS_KRB5_MECHANISM)) {
+               return gsskrb5_init_sec_context(minor_status,
+                                               initiator_cred_handle,
+                                               context_handle,
+                                               target_name,
+                                               mech_type,
+                                               req_flags,
+                                               time_req,
+                                               input_chan_bindings,
+                                               input_token,
+                                               actual_mech_type,
+                                               output_token,
+                                               ret_flags,
+                                               time_rec);
+       } else if (gss_oid_equal(mech_type, GSS_SPNEGO_MECHANISM)) {
+               return spnego_init_sec_context (minor_status,
+                                               initiator_cred_handle,
+                                               context_handle,
+                                               target_name,
+                                               mech_type,
+                                               req_flags,
+                                               time_req,
+                                               input_chan_bindings,
+                                               input_token,
+                                               actual_mech_type,
+                                               output_token,
+                                               ret_flags,
+                                               time_rec);
+       }
+
+       return GSS_S_BAD_MECH;
+}
diff --git a/source4/heimdal/lib/gssapi/inquire_cred.c b/source4/heimdal/lib/gssapi/inquire_cred.c
new file mode 100644 (file)
index 0000000..9ed1ff4
--- /dev/null
@@ -0,0 +1,123 @@
+/*
+ * 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 "gssapi_locl.h"
+
+RCSID("$Id: inquire_cred.c,v 1.7 2004/11/30 19:27:11 lha Exp $");
+
+OM_uint32 gss_inquire_cred
+           (OM_uint32 * minor_status,
+            const gss_cred_id_t cred_handle,
+            gss_name_t * name,
+            OM_uint32 * lifetime,
+            gss_cred_usage_t * cred_usage,
+            gss_OID_set * mechanisms
+           )
+{
+    gss_cred_id_t cred;
+    OM_uint32 ret;
+
+    *minor_status = 0;
+
+    if (name)
+       *name = NULL;
+    if (mechanisms)
+       *mechanisms = GSS_C_NO_OID_SET;
+
+    if (cred_handle == GSS_C_NO_CREDENTIAL) {
+       ret = gss_acquire_cred(minor_status, 
+                              GSS_C_NO_NAME,
+                              GSS_C_INDEFINITE,
+                              GSS_C_NO_OID_SET,
+                              GSS_C_BOTH,
+                              &cred,
+                              NULL,
+                              NULL);
+       if (ret)
+           return ret;
+    } else
+       cred = (gss_cred_id_t)cred_handle;
+
+    HEIMDAL_MUTEX_lock(&cred->cred_id_mutex);
+
+    if (name != NULL) {
+       if (cred->principal != NULL) {
+            ret = gss_duplicate_name(minor_status, cred->principal,
+               name);
+            if (ret)
+               goto out;
+       } else if (cred->usage == GSS_C_ACCEPT) {
+           *minor_status = krb5_sname_to_principal(gssapi_krb5_context, NULL,
+               NULL, KRB5_NT_SRV_HST, name);
+           if (*minor_status) {
+               ret = GSS_S_FAILURE;
+               goto out;
+           }
+       } else {
+           *minor_status = krb5_get_default_principal(gssapi_krb5_context,
+               name);
+           if (*minor_status) {
+               ret = GSS_S_FAILURE;
+               goto out;
+           }
+       }
+    }
+    if (lifetime != NULL) {
+       ret = gssapi_lifetime_left(minor_status, 
+                                  cred->lifetime,
+                                  lifetime);
+       if (ret)
+           goto out;
+    }
+    if (cred_usage != NULL)
+        *cred_usage = cred->usage;
+
+    if (mechanisms != NULL) {
+        ret = gss_create_empty_oid_set(minor_status, mechanisms);
+        if (ret)
+           goto out;
+        ret = gss_add_oid_set_member(minor_status,
+                                    &cred->mechanisms->elements[0],
+                                    mechanisms);
+        if (ret)
+           goto out;
+    }
+    ret = GSS_S_COMPLETE;
+ out:
+    HEIMDAL_MUTEX_unlock(&cred->cred_id_mutex);
+
+    if (cred_handle == GSS_C_NO_CREDENTIAL)
+       ret = gss_release_cred(minor_status, &cred);
+
+    return ret;
+}
diff --git a/source4/heimdal/lib/gssapi/release_buffer.c b/source4/heimdal/lib/gssapi/release_buffer.c
new file mode 100644 (file)
index 0000000..258b76f
--- /dev/null
@@ -0,0 +1,48 @@
+/*
+ * Copyright (c) 1997 - 2000, 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 "gssapi_locl.h"
+
+RCSID("$Id: release_buffer.c,v 1.5 2003/03/16 17:58:20 lha Exp $");
+
+OM_uint32 gss_release_buffer
+           (OM_uint32 * minor_status,
+            gss_buffer_t buffer
+           )
+{
+  *minor_status = 0;
+  free (buffer->value);
+  buffer->value  = NULL;
+  buffer->length = 0;
+  return GSS_S_COMPLETE;
+}
diff --git a/source4/heimdal/lib/gssapi/release_cred.c b/source4/heimdal/lib/gssapi/release_cred.c
new file mode 100644 (file)
index 0000000..8ae65dd
--- /dev/null
@@ -0,0 +1,73 @@
+/*
+ * 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 "gssapi_locl.h"
+
+RCSID("$Id: release_cred.c,v 1.10 2003/10/07 00:51:46 lha Exp $");
+
+OM_uint32 gss_release_cred
+           (OM_uint32 * minor_status,
+            gss_cred_id_t * cred_handle
+           )
+{
+    *minor_status = 0;
+
+    if (*cred_handle == GSS_C_NO_CREDENTIAL) {
+        return GSS_S_COMPLETE;
+    }
+
+    GSSAPI_KRB5_INIT ();
+
+    HEIMDAL_MUTEX_lock(&(*cred_handle)->cred_id_mutex);
+
+    if ((*cred_handle)->principal != NULL)
+        krb5_free_principal(gssapi_krb5_context, (*cred_handle)->principal);
+    if ((*cred_handle)->made_keytab)
+       krb5_kt_close(gssapi_krb5_context, (*cred_handle)->keytab);
+    if ((*cred_handle)->made_ccache) {
+       const krb5_cc_ops *ops;
+       ops = krb5_cc_get_ops(gssapi_krb5_context, (*cred_handle)->ccache);
+       if (ops == &krb5_mcc_ops)
+           krb5_cc_destroy(gssapi_krb5_context, (*cred_handle)->ccache);
+       else 
+           krb5_cc_close(gssapi_krb5_context, (*cred_handle)->ccache);
+    }
+    gss_release_oid_set(NULL, &(*cred_handle)->mechanisms);
+    HEIMDAL_MUTEX_unlock(&(*cred_handle)->cred_id_mutex);
+    HEIMDAL_MUTEX_destroy(&(*cred_handle)->cred_id_mutex);
+    memset(*cred_handle, 0, sizeof(**cred_handle));
+    free(*cred_handle);
+    *cred_handle = GSS_C_NO_CREDENTIAL;
+    return GSS_S_COMPLETE;
+}
+
diff --git a/source4/heimdal/lib/gssapi/release_name.c b/source4/heimdal/lib/gssapi/release_name.c
new file mode 100644 (file)
index 0000000..6894ffa
--- /dev/null
@@ -0,0 +1,50 @@
+/*
+ * 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 "gssapi_locl.h"
+
+RCSID("$Id: release_name.c,v 1.7 2003/03/16 17:52:48 lha Exp $");
+
+OM_uint32 gss_release_name
+           (OM_uint32 * minor_status,
+            gss_name_t * input_name
+           )
+{
+    GSSAPI_KRB5_INIT ();
+    if (minor_status)
+      *minor_status = 0;
+    krb5_free_principal(gssapi_krb5_context,
+                       *input_name);
+    *input_name = GSS_C_NO_NAME;
+    return GSS_S_COMPLETE;
+}
diff --git a/source4/heimdal/lib/gssapi/release_oid_set.c b/source4/heimdal/lib/gssapi/release_oid_set.c
new file mode 100644 (file)
index 0000000..04eb015
--- /dev/null
@@ -0,0 +1,49 @@
+/*
+ * Copyright (c) 1997 - 2000, 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 "gssapi_locl.h"
+
+RCSID("$Id: release_oid_set.c,v 1.5 2003/03/16 17:53:25 lha Exp $");
+
+OM_uint32 gss_release_oid_set
+           (OM_uint32 * minor_status,
+            gss_OID_set * set
+           )
+{
+  if (minor_status)
+      *minor_status = 0;
+  free ((*set)->elements);
+  free (*set);
+  *set = GSS_C_NO_OID_SET;
+  return GSS_S_COMPLETE;
+}
diff --git a/source4/heimdal/lib/gssapi/sequence.c b/source4/heimdal/lib/gssapi/sequence.c
new file mode 100755 (executable)
index 0000000..973fc6a
--- /dev/null
@@ -0,0 +1,189 @@
+/*
+ * 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 "gssapi_locl.h"
+
+RCSID("$Id: sequence.c,v 1.5 2005/04/27 17:49:43 lha Exp $");
+
+#define DEFAULT_JITTER_WINDOW 20
+
+struct gss_msg_order {
+    OM_uint32 flags;
+    OM_uint32 start;
+    OM_uint32 length;
+    OM_uint32 jitter_window;
+    OM_uint32 first_seq;
+    OM_uint32 elem[1];
+};
+
+/*
+ *
+ */
+
+OM_uint32
+_gssapi_msg_order_create(OM_uint32 *minor_status,
+                        struct gss_msg_order **o, 
+                        OM_uint32 flags, 
+                        OM_uint32 seq_num, 
+                        OM_uint32 jitter_window,
+                        int use_64)
+{
+    size_t len;
+
+    if (jitter_window == 0)
+       jitter_window = DEFAULT_JITTER_WINDOW;
+
+    len = jitter_window * sizeof((*o)->elem[0]);
+    len += sizeof(**o);
+    len -= sizeof((*o)->elem[0]);
+    
+    *o = malloc(len);
+    if (*o == NULL) {
+       *minor_status = ENOMEM;
+       return GSS_S_FAILURE;
+    }  
+    memset(*o, 0, len);
+    (*o)->flags = flags;
+    (*o)->length = 0;
+    (*o)->first_seq = seq_num;
+    (*o)->jitter_window = jitter_window;
+    (*o)->elem[0] = seq_num - 1;
+
+    *minor_status = 0;
+    return GSS_S_COMPLETE;
+}
+
+OM_uint32
+_gssapi_msg_order_destroy(struct gss_msg_order **m)
+{
+    free(*m);
+    *m = NULL;
+    return GSS_S_COMPLETE;
+}
+
+static void
+elem_set(struct gss_msg_order *o, unsigned int slot, OM_uint32 val)
+{
+    o->elem[slot % o->jitter_window] = val;
+}
+
+static void
+elem_insert(struct gss_msg_order *o, 
+           unsigned int after_slot,
+           OM_uint32 seq_num)
+{
+    assert(o->jitter_window > after_slot);
+
+    if (o->length > after_slot)
+       memmove(&o->elem[after_slot + 1], &o->elem[after_slot],
+               (o->length - after_slot - 1) * sizeof(o->elem[0]));
+
+    elem_set(o, after_slot, seq_num);
+
+    if (o->length < o->jitter_window)
+       o->length++;
+}
+
+/* rule 1: expected sequence number */
+/* rule 2: > expected sequence number */
+/* rule 3: seqnum < seqnum(first) */
+/* rule 4+5: seqnum in [seqnum(first),seqnum(last)]  */
+
+OM_uint32
+_gssapi_msg_order_check(struct gss_msg_order *o, OM_uint32 seq_num)
+{
+    OM_uint32 r;
+    int i;
+
+    if (o == NULL)
+       return GSS_S_COMPLETE;
+
+    if ((o->flags & (GSS_C_REPLAY_FLAG|GSS_C_SEQUENCE_FLAG)) == 0)
+       return GSS_S_COMPLETE;
+
+    /* check if the packet is the next in order */
+    if (o->elem[0] == seq_num - 1) {
+       elem_insert(o, 0, seq_num);
+       return GSS_S_COMPLETE;
+    }
+
+    r = (o->flags & (GSS_C_REPLAY_FLAG|GSS_C_SEQUENCE_FLAG))==GSS_C_REPLAY_FLAG;
+
+    /* sequence number larger then largest sequence number 
+     * or smaller then the first sequence number */
+    if (seq_num > o->elem[0]
+       || seq_num < o->first_seq
+       || o->length == 0) 
+    {
+       elem_insert(o, 0, seq_num);
+       if (r) {
+           return GSS_S_COMPLETE;
+       } else {
+           return GSS_S_GAP_TOKEN;
+       }
+    }
+
+    assert(o->length > 0);
+
+    /* sequence number smaller the first sequence number */
+    if (seq_num < o->elem[o->length - 1]) {
+       if (r)
+           return(GSS_S_OLD_TOKEN);
+       else
+           return(GSS_S_UNSEQ_TOKEN);
+    }
+
+    if (seq_num == o->elem[o->length - 1]) {
+       return GSS_S_DUPLICATE_TOKEN;
+    }
+
+    for (i = 0; i < o->length - 1; i++) {
+       if (o->elem[i] == seq_num)
+           return GSS_S_DUPLICATE_TOKEN;
+       if (o->elem[i + 1] < seq_num && o->elem[i] < seq_num) {
+           elem_insert(o, i, seq_num);
+           if (r)
+               return GSS_S_COMPLETE;
+           else
+               return GSS_S_UNSEQ_TOKEN;
+       }
+    }
+
+    return GSS_S_FAILURE;
+}
+
+OM_uint32
+_gssapi_msg_order_f(OM_uint32 flags)
+{
+    return flags & (GSS_C_SEQUENCE_FLAG|GSS_C_REPLAY_FLAG);
+}
diff --git a/source4/heimdal/lib/gssapi/spnego.asn1 b/source4/heimdal/lib/gssapi/spnego.asn1
new file mode 100755 (executable)
index 0000000..5dc767c
--- /dev/null
@@ -0,0 +1,42 @@
+-- $Id: spnego.asn1,v 1.4 2004/03/07 13:38:08 lha Exp $
+
+SPNEGO DEFINITIONS ::=
+BEGIN
+
+MechType::= OBJECT IDENTIFIER
+
+MechTypeList ::= SEQUENCE OF MechType
+
+ContextFlags ::= BIT STRING {
+        delegFlag       (0),
+        mutualFlag      (1),
+        replayFlag      (2),
+        sequenceFlag    (3),
+        anonFlag        (4),
+        confFlag        (5),
+        integFlag       (6)
+}
+
+NegTokenInit ::= SEQUENCE {
+                            mechTypes       [0] MechTypeList  OPTIONAL,
+                            reqFlags        [1] ContextFlags  OPTIONAL,
+                            mechToken       [2] OCTET STRING  OPTIONAL,
+                            mechListMIC     [3] OCTET STRING  OPTIONAL
+                         }
+
+NegTokenTarg ::= SEQUENCE {
+    negResult      [0] ENUMERATED {
+                            accept_completed    (0),
+                            accept_incomplete   (1),
+                            reject              (2) }          OPTIONAL,
+    supportedMech  [1] MechType                                OPTIONAL,
+    responseToken  [2] OCTET STRING                            OPTIONAL,
+    mechListMIC    [3] OCTET STRING                            OPTIONAL
+}
+
+NegotiationToken ::= CHOICE {
+       negTokenInit[0]         NegTokenInit,
+       negTokenTarg[1]         NegTokenTarg
+}
+
+END
diff --git a/source4/heimdal/lib/gssapi/test_oid_set_member.c b/source4/heimdal/lib/gssapi/test_oid_set_member.c
new file mode 100644 (file)
index 0000000..e747c5a
--- /dev/null
@@ -0,0 +1,55 @@
+/*
+ * 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 "gssapi_locl.h"
+
+RCSID("$Id: test_oid_set_member.c,v 1.5 2003/03/16 17:54:06 lha Exp $");
+
+OM_uint32 gss_test_oid_set_member (
+            OM_uint32 * minor_status,
+            const gss_OID member,
+            const gss_OID_set set,
+            int * present
+           )
+{
+  size_t i;
+
+  *minor_status = 0;
+  *present = 0;
+  for (i = 0; i < set->count; ++i)
+      if (gss_oid_equal(member, &set->elements[i]) != 0) {
+         *present = 1;
+         break;
+      }
+  return GSS_S_COMPLETE;
+}
diff --git a/source4/heimdal/lib/gssapi/unwrap.c b/source4/heimdal/lib/gssapi/unwrap.c
new file mode 100644 (file)
index 0000000..c358c1a
--- /dev/null
@@ -0,0 +1,413 @@
+/*
+ * 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 "gssapi_locl.h"
+
+RCSID("$Id: unwrap.c,v 1.34 2005/04/27 17:50:40 lha Exp $");
+
+static OM_uint32
+unwrap_des
+           (OM_uint32 * minor_status,
+            const gss_ctx_id_t context_handle,
+            const gss_buffer_t input_message_buffer,
+            gss_buffer_t output_message_buffer,
+            int * conf_state,
+            gss_qop_t * qop_state,
+           krb5_keyblock *key
+           )
+{
+  u_char *p, *seq;
+  size_t len;
+  MD5_CTX md5;
+  u_char hash[16];
+  DES_key_schedule schedule;
+  DES_cblock deskey;
+  DES_cblock zero;
+  int i;
+  int32_t seq_number;
+  size_t padlength;
+  OM_uint32 ret;
+  int cstate;
+  int cmp;
+
+  p = input_message_buffer->value;
+  ret = gssapi_krb5_verify_header (&p,
+                                  input_message_buffer->length,
+                                  "\x02\x01",
+                                  GSS_KRB5_MECHANISM);
+  if (ret)
+      return ret;
+
+  if (memcmp (p, "\x00\x00", 2) != 0)
+    return GSS_S_BAD_SIG;
+  p += 2;
+  if (memcmp (p, "\x00\x00", 2) == 0) {
+      cstate = 1;
+  } else if (memcmp (p, "\xFF\xFF", 2) == 0) {
+      cstate = 0;
+  } else
+      return GSS_S_BAD_MIC;
+  p += 2;
+  if(conf_state != NULL)
+      *conf_state = cstate;
+  if (memcmp (p, "\xff\xff", 2) != 0)
+    return GSS_S_DEFECTIVE_TOKEN;
+  p += 2;
+  p += 16;
+
+  len = p - (u_char *)input_message_buffer->value;
+
+  if(cstate) {
+      /* decrypt data */
+      memcpy (&deskey, key->keyvalue.data, sizeof(deskey));
+
+      for (i = 0; i < sizeof(deskey); ++i)
+         deskey[i] ^= 0xf0;
+      DES_set_key (&deskey, &schedule);
+      memset (&zero, 0, sizeof(zero));
+      DES_cbc_encrypt ((void *)p,
+                      (void *)p,
+                      input_message_buffer->length - len,
+                      &schedule,
+                      &zero,
+                      DES_DECRYPT);
+      
+      memset (deskey, 0, sizeof(deskey));
+      memset (&schedule, 0, sizeof(schedule));
+  }
+  /* check pad */
+  ret = _gssapi_verify_pad(input_message_buffer, 
+                          input_message_buffer->length - len,
+                          &padlength);
+  if (ret)
+      return ret;
+
+  MD5_Init (&md5);
+  MD5_Update (&md5, p - 24, 8);
+  MD5_Update (&md5, p, input_message_buffer->length - len);
+  MD5_Final (hash, &md5);
+
+  memset (&zero, 0, sizeof(zero));
+  memcpy (&deskey, key->keyvalue.data, sizeof(deskey));
+  DES_set_key (&deskey, &schedule);
+  DES_cbc_cksum ((void *)hash, (void *)hash, sizeof(hash),
+                &schedule, &zero);
+  if (memcmp (p - 8, hash, 8) != 0)
+    return GSS_S_BAD_MIC;
+
+  /* verify sequence number */
+  
+  HEIMDAL_MUTEX_lock(&context_handle->ctx_id_mutex);
+
+  p -= 16;
+  DES_set_key (&deskey, &schedule);
+  DES_cbc_encrypt ((void *)p, (void *)p, 8,
+                  &schedule, (DES_cblock *)hash, DES_DECRYPT);
+
+  memset (deskey, 0, sizeof(deskey));
+  memset (&schedule, 0, sizeof(schedule));
+
+  seq = p;
+  gssapi_decode_om_uint32(seq, &seq_number);
+
+  if (context_handle->more_flags & LOCAL)
+      cmp = memcmp(&seq[4], "\xff\xff\xff\xff", 4);
+  else
+      cmp = memcmp(&seq[4], "\x00\x00\x00\x00", 4);
+
+  if (cmp != 0) {
+    HEIMDAL_MUTEX_unlock(&context_handle->ctx_id_mutex);
+    return GSS_S_BAD_MIC;
+  }
+
+  ret = _gssapi_msg_order_check(context_handle->order, seq_number);
+  if (ret) {
+    HEIMDAL_MUTEX_unlock(&context_handle->ctx_id_mutex);
+    return ret;
+  }
+
+  HEIMDAL_MUTEX_unlock(&context_handle->ctx_id_mutex);
+
+  /* copy out data */
+
+  output_message_buffer->length = input_message_buffer->length
+    - len - padlength - 8;
+  output_message_buffer->value  = malloc(output_message_buffer->length);
+  if(output_message_buffer->length != 0 && output_message_buffer->value == NULL)
+      return GSS_S_FAILURE;
+  memcpy (output_message_buffer->value,
+         p + 24,
+         output_message_buffer->length);
+  return GSS_S_COMPLETE;
+}
+
+static OM_uint32
+unwrap_des3
+           (OM_uint32 * minor_status,
+            const gss_ctx_id_t context_handle,
+            const gss_buffer_t input_message_buffer,
+            gss_buffer_t output_message_buffer,
+            int * conf_state,
+            gss_qop_t * qop_state,
+           krb5_keyblock *key
+           )
+{
+  u_char *p;
+  size_t len;
+  u_char *seq;
+  krb5_data seq_data;
+  u_char cksum[20];
+  int32_t seq_number;
+  size_t padlength;
+  OM_uint32 ret;
+  int cstate;
+  krb5_crypto crypto;
+  Checksum csum;
+  int cmp;
+
+  p = input_message_buffer->value;
+  ret = gssapi_krb5_verify_header (&p,
+                                  input_message_buffer->length,
+                                  "\x02\x01",
+                                  GSS_KRB5_MECHANISM);
+  if (ret)
+      return ret;
+
+  if (memcmp (p, "\x04\x00", 2) != 0) /* HMAC SHA1 DES3_KD */
+    return GSS_S_BAD_SIG;
+  p += 2;
+  if (memcmp (p, "\x02\x00", 2) == 0) {
+    cstate = 1;
+  } else if (memcmp (p, "\xff\xff", 2) == 0) {
+    cstate = 0;
+  } else
+    return GSS_S_BAD_MIC;
+  p += 2;
+  if(conf_state != NULL)
+    *conf_state = cstate;
+  if (memcmp (p, "\xff\xff", 2) != 0)
+    return GSS_S_DEFECTIVE_TOKEN;
+  p += 2;
+  p += 28;
+
+  len = p - (u_char *)input_message_buffer->value;
+
+  if(cstate) {
+      /* decrypt data */
+      krb5_data tmp;
+
+      ret = krb5_crypto_init(gssapi_krb5_context, key,
+                            ETYPE_DES3_CBC_NONE, &crypto);
+      if (ret) {
+         gssapi_krb5_set_error_string ();
+         *minor_status = ret;
+         return GSS_S_FAILURE;
+      }
+      ret = krb5_decrypt(gssapi_krb5_context, crypto, KRB5_KU_USAGE_SEAL,
+                        p, input_message_buffer->length - len, &tmp);
+      krb5_crypto_destroy(gssapi_krb5_context, crypto);
+      if (ret) {
+         gssapi_krb5_set_error_string ();
+         *minor_status = ret;
+         return GSS_S_FAILURE;
+      }
+      assert (tmp.length == input_message_buffer->length - len);
+
+      memcpy (p, tmp.data, tmp.length);
+      krb5_data_free(&tmp);
+  }
+  /* check pad */
+  ret = _gssapi_verify_pad(input_message_buffer, 
+                          input_message_buffer->length - len,
+                          &padlength);
+  if (ret)
+      return ret;
+
+  /* verify sequence number */
+  
+  HEIMDAL_MUTEX_lock(&context_handle->ctx_id_mutex);
+
+  p -= 28;
+
+  ret = krb5_crypto_init(gssapi_krb5_context, key,
+                        ETYPE_DES3_CBC_NONE, &crypto);
+  if (ret) {
+      gssapi_krb5_set_error_string ();
+      *minor_status = ret;
+      HEIMDAL_MUTEX_unlock(&context_handle->ctx_id_mutex);
+      return GSS_S_FAILURE;
+  }
+  {
+      DES_cblock ivec;
+
+      memcpy(&ivec, p + 8, 8);
+      ret = krb5_decrypt_ivec (gssapi_krb5_context,
+                              crypto,
+                              KRB5_KU_USAGE_SEQ,
+                              p, 8, &seq_data,
+                              &ivec);
+  }
+  krb5_crypto_destroy (gssapi_krb5_context, crypto);
+  if (ret) {
+      gssapi_krb5_set_error_string ();
+      *minor_status = ret;
+      HEIMDAL_MUTEX_unlock(&context_handle->ctx_id_mutex);
+      return GSS_S_FAILURE;
+  }
+  if (seq_data.length != 8) {
+      krb5_data_free (&seq_data);
+      *minor_status = 0;
+      HEIMDAL_MUTEX_unlock(&context_handle->ctx_id_mutex);
+      return GSS_S_BAD_MIC;
+  }
+
+  seq = seq_data.data;
+  gssapi_decode_om_uint32(seq, &seq_number);
+
+  if (context_handle->more_flags & LOCAL)
+      cmp = memcmp(&seq[4], "\xff\xff\xff\xff", 4);
+  else
+      cmp = memcmp(&seq[4], "\x00\x00\x00\x00", 4);
+  
+  krb5_data_free (&seq_data);
+  if (cmp != 0) {
+      *minor_status = 0;
+      HEIMDAL_MUTEX_unlock(&context_handle->ctx_id_mutex);
+      return GSS_S_BAD_MIC;
+  }
+
+  ret = _gssapi_msg_order_check(context_handle->order, seq_number);
+  if (ret) {
+      *minor_status = 0;
+      HEIMDAL_MUTEX_unlock(&context_handle->ctx_id_mutex);
+      return ret;
+  }
+
+  HEIMDAL_MUTEX_unlock(&context_handle->ctx_id_mutex);
+
+  /* verify checksum */
+
+  memcpy (cksum, p + 8, 20);
+
+  memcpy (p + 20, p - 8, 8);
+
+  csum.cksumtype = CKSUMTYPE_HMAC_SHA1_DES3;
+  csum.checksum.length = 20;
+  csum.checksum.data   = cksum;
+
+  ret = krb5_crypto_init(gssapi_krb5_context, key, 0, &crypto);
+  if (ret) {
+      gssapi_krb5_set_error_string ();
+      *minor_status = ret;
+      return GSS_S_FAILURE;
+  }
+
+  ret = krb5_verify_checksum (gssapi_krb5_context, crypto,
+                             KRB5_KU_USAGE_SIGN,
+                             p + 20,
+                             input_message_buffer->length - len + 8,
+                             &csum);
+  krb5_crypto_destroy (gssapi_krb5_context, crypto);
+  if (ret) {
+      gssapi_krb5_set_error_string ();
+      *minor_status = ret;
+      return GSS_S_FAILURE;
+  }
+
+  /* copy out data */
+
+  output_message_buffer->length = input_message_buffer->length
+    - len - padlength - 8;
+  output_message_buffer->value  = malloc(output_message_buffer->length);
+  if(output_message_buffer->length != 0 && output_message_buffer->value == NULL)
+      return GSS_S_FAILURE;
+  memcpy (output_message_buffer->value,
+         p + 36,
+         output_message_buffer->length);
+  return GSS_S_COMPLETE;
+}
+
+OM_uint32 gss_unwrap
+           (OM_uint32 * minor_status,
+            const gss_ctx_id_t context_handle,
+            const gss_buffer_t input_message_buffer,
+            gss_buffer_t output_message_buffer,
+            int * conf_state,
+            gss_qop_t * qop_state
+           )
+{
+  krb5_keyblock *key;
+  OM_uint32 ret;
+  krb5_keytype keytype;
+
+  output_message_buffer->value = NULL;
+  output_message_buffer->length = 0;
+
+  if (qop_state != NULL)
+      *qop_state = GSS_C_QOP_DEFAULT;
+  ret = gss_krb5_get_subkey(context_handle, &key);
+  if (ret) {
+      gssapi_krb5_set_error_string ();
+      *minor_status = ret;
+      return GSS_S_FAILURE;
+  }
+  krb5_enctype_to_keytype (gssapi_krb5_context, key->keytype, &keytype);
+
+  *minor_status = 0;
+
+  switch (keytype) {
+  case KEYTYPE_DES :
+      ret = unwrap_des (minor_status, context_handle,
+                       input_message_buffer, output_message_buffer,
+                       conf_state, qop_state, key);
+      break;
+  case KEYTYPE_DES3 :
+      ret = unwrap_des3 (minor_status, context_handle,
+                        input_message_buffer, output_message_buffer,
+                        conf_state, qop_state, key);
+      break;
+  case KEYTYPE_ARCFOUR:
+  case KEYTYPE_ARCFOUR_56:
+      ret = _gssapi_unwrap_arcfour (minor_status, context_handle,
+                                   input_message_buffer, output_message_buffer,
+                                   conf_state, qop_state, key);
+      break;
+  default :
+      ret = _gssapi_unwrap_cfx (minor_status, context_handle,
+                               input_message_buffer, output_message_buffer,
+                               conf_state, qop_state, key);
+      break;
+  }
+  krb5_free_keyblock (gssapi_krb5_context, key);
+  return ret;
+}
diff --git a/source4/heimdal/lib/gssapi/verify_mic.c b/source4/heimdal/lib/gssapi/verify_mic.c
new file mode 100644 (file)
index 0000000..7b7d437
--- /dev/null
@@ -0,0 +1,336 @@
+/*
+ * 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 "gssapi_locl.h"
+
+RCSID("$Id: verify_mic.c,v 1.32 2005/04/27 17:51:04 lha Exp $");
+
+static OM_uint32
+verify_mic_des
+           (OM_uint32 * minor_status,
+            const gss_ctx_id_t context_handle,
+            const gss_buffer_t message_buffer,
+            const gss_buffer_t token_buffer,
+            gss_qop_t * qop_state,
+           krb5_keyblock *key,
+           char *type
+           )
+{
+  u_char *p;
+  MD5_CTX md5;
+  u_char hash[16], *seq;
+  DES_key_schedule schedule;
+  DES_cblock zero;
+  DES_cblock deskey;
+  int32_t seq_number;
+  OM_uint32 ret;
+  int cmp;
+
+  p = token_buffer->value;
+  ret = gssapi_krb5_verify_header (&p,
+                                  token_buffer->length,
+                                  type,
+                                  GSS_KRB5_MECHANISM);
+  if (ret)
+      return ret;
+
+  if (memcmp(p, "\x00\x00", 2) != 0)
+      return GSS_S_BAD_SIG;
+  p += 2;
+  if (memcmp (p, "\xff\xff\xff\xff", 4) != 0)
+    return GSS_S_BAD_MIC;
+  p += 4;
+  p += 16;
+
+  /* verify checksum */
+  MD5_Init (&md5);
+  MD5_Update (&md5, p - 24, 8);
+  MD5_Update (&md5, message_buffer->value,
+            message_buffer->length);
+  MD5_Final (hash, &md5);
+
+  memset (&zero, 0, sizeof(zero));
+  memcpy (&deskey, key->keyvalue.data, sizeof(deskey));
+
+  DES_set_key (&deskey, &schedule);
+  DES_cbc_cksum ((void *)hash, (void *)hash, sizeof(hash),
+                &schedule, &zero);
+  if (memcmp (p - 8, hash, 8) != 0) {
+    memset (deskey, 0, sizeof(deskey));
+    memset (&schedule, 0, sizeof(schedule));
+    return GSS_S_BAD_MIC;
+  }
+
+  /* verify sequence number */
+  
+  HEIMDAL_MUTEX_lock(&context_handle->ctx_id_mutex);
+
+  p -= 16;
+  DES_set_key (&deskey, &schedule);
+  DES_cbc_encrypt ((void *)p, (void *)p, 8,
+                  &schedule, (DES_cblock *)hash, DES_DECRYPT);
+
+  memset (deskey, 0, sizeof(deskey));
+  memset (&schedule, 0, sizeof(schedule));
+
+  seq = p;
+  gssapi_decode_om_uint32(seq, &seq_number);
+
+  if (context_handle->more_flags & LOCAL)
+      cmp = memcmp(&seq[4], "\xff\xff\xff\xff", 4);
+  else
+      cmp = memcmp(&seq[4], "\x00\x00\x00\x00", 4);
+
+  if (cmp != 0) {
+    HEIMDAL_MUTEX_unlock(&context_handle->ctx_id_mutex);
+    return GSS_S_BAD_MIC;
+  }
+
+  ret = _gssapi_msg_order_check(context_handle->order, seq_number);
+  if (ret) {
+      HEIMDAL_MUTEX_unlock(&context_handle->ctx_id_mutex);
+      return ret;
+  }
+
+  HEIMDAL_MUTEX_unlock(&context_handle->ctx_id_mutex);
+
+  return GSS_S_COMPLETE;
+}
+
+static OM_uint32
+verify_mic_des3
+           (OM_uint32 * minor_status,
+            const gss_ctx_id_t context_handle,
+            const gss_buffer_t message_buffer,
+            const gss_buffer_t token_buffer,
+            gss_qop_t * qop_state,
+           krb5_keyblock *key,
+           char *type
+           )
+{
+  u_char *p;
+  u_char *seq;
+  int32_t seq_number;
+  OM_uint32 ret;
+  krb5_crypto crypto;
+  krb5_data seq_data;
+  int cmp, docompat;
+  Checksum csum;
+  char *tmp;
+  char ivec[8];
+  
+  p = token_buffer->value;
+  ret = gssapi_krb5_verify_header (&p,
+                                  token_buffer->length,
+                                  type,
+                                  GSS_KRB5_MECHANISM);
+  if (ret)
+      return ret;
+
+  if (memcmp(p, "\x04\x00", 2) != 0) /* SGN_ALG = HMAC SHA1 DES3-KD */
+      return GSS_S_BAD_SIG;
+  p += 2;
+  if (memcmp (p, "\xff\xff\xff\xff", 4) != 0)
+    return GSS_S_BAD_MIC;
+  p += 4;
+
+  ret = krb5_crypto_init(gssapi_krb5_context, key,
+                        ETYPE_DES3_CBC_NONE, &crypto);
+  if (ret){
+      gssapi_krb5_set_error_string ();
+      *minor_status = ret;
+      return GSS_S_FAILURE;
+  }
+
+  /* verify sequence number */
+  docompat = 0;
+retry:
+  if (docompat)
+      memset(ivec, 0, 8);
+  else
+      memcpy(ivec, p + 8, 8);
+
+  ret = krb5_decrypt_ivec (gssapi_krb5_context,
+                          crypto,
+                          KRB5_KU_USAGE_SEQ,
+                          p, 8, &seq_data, ivec);
+  if (ret) {
+      if (docompat++) {
+         gssapi_krb5_set_error_string ();
+         krb5_crypto_destroy (gssapi_krb5_context, crypto);
+         *minor_status = ret;
+         return GSS_S_FAILURE;
+      } else
+         goto retry;
+  }
+
+  if (seq_data.length != 8) {
+      krb5_data_free (&seq_data);
+      if (docompat++) {
+         krb5_crypto_destroy (gssapi_krb5_context, crypto);
+         return GSS_S_BAD_MIC;
+      } else
+         goto retry;
+  }
+
+  HEIMDAL_MUTEX_lock(&context_handle->ctx_id_mutex);
+
+  seq = seq_data.data;
+  gssapi_decode_om_uint32(seq, &seq_number);
+
+  if (context_handle->more_flags & LOCAL)
+      cmp = memcmp(&seq[4], "\xff\xff\xff\xff", 4);
+  else
+      cmp = memcmp(&seq[4], "\x00\x00\x00\x00", 4);
+
+  krb5_data_free (&seq_data);
+  if (cmp != 0) {
+      krb5_crypto_destroy (gssapi_krb5_context, crypto);
+      *minor_status = 0;
+      HEIMDAL_MUTEX_unlock(&context_handle->ctx_id_mutex);
+      return GSS_S_BAD_MIC;
+  }
+
+  ret = _gssapi_msg_order_check(context_handle->order, seq_number);
+  if (ret) {
+      krb5_crypto_destroy (gssapi_krb5_context, crypto);
+      *minor_status = 0;
+      HEIMDAL_MUTEX_unlock(&context_handle->ctx_id_mutex);
+      return ret;
+  }
+
+  /* verify checksum */
+
+  tmp = malloc (message_buffer->length + 8);
+  if (tmp == NULL) {
+      krb5_crypto_destroy (gssapi_krb5_context, crypto);
+      HEIMDAL_MUTEX_unlock(&context_handle->ctx_id_mutex);
+      *minor_status = ENOMEM;
+      return GSS_S_FAILURE;
+  }
+
+  memcpy (tmp, p - 8, 8);
+  memcpy (tmp + 8, message_buffer->value, message_buffer->length);
+
+  csum.cksumtype = CKSUMTYPE_HMAC_SHA1_DES3;
+  csum.checksum.length = 20;
+  csum.checksum.data   = p + 8;
+
+  ret = krb5_verify_checksum (gssapi_krb5_context, crypto,
+                             KRB5_KU_USAGE_SIGN,
+                             tmp, message_buffer->length + 8,
+                             &csum);
+  free (tmp);
+  if (ret) {
+      gssapi_krb5_set_error_string ();
+      krb5_crypto_destroy (gssapi_krb5_context, crypto);
+      *minor_status = ret;
+      HEIMDAL_MUTEX_unlock(&context_handle->ctx_id_mutex);
+      return GSS_S_BAD_MIC;
+  }
+  HEIMDAL_MUTEX_unlock(&context_handle->ctx_id_mutex);
+
+  krb5_crypto_destroy (gssapi_krb5_context, crypto);
+  return GSS_S_COMPLETE;
+}
+
+OM_uint32
+gss_verify_mic_internal
+           (OM_uint32 * minor_status,
+            const gss_ctx_id_t context_handle,
+            const gss_buffer_t message_buffer,
+            const gss_buffer_t token_buffer,
+            gss_qop_t * qop_state,
+           char * type
+           )
+{
+    krb5_keyblock *key;
+    OM_uint32 ret;
+    krb5_keytype keytype;
+
+    ret = gss_krb5_get_subkey(context_handle, &key);
+    if (ret) {
+       gssapi_krb5_set_error_string ();
+       *minor_status = ret;
+       return GSS_S_FAILURE;
+    }
+    *minor_status = 0;
+    krb5_enctype_to_keytype (gssapi_krb5_context, key->keytype, &keytype);
+    switch (keytype) {
+    case KEYTYPE_DES :
+       ret = verify_mic_des (minor_status, context_handle,
+                             message_buffer, token_buffer, qop_state, key,
+                             type);
+       break;
+    case KEYTYPE_DES3 :
+       ret = verify_mic_des3 (minor_status, context_handle,
+                              message_buffer, token_buffer, qop_state, key,
+                              type);
+       break;
+    case KEYTYPE_ARCFOUR :
+    case KEYTYPE_ARCFOUR_56 :
+       ret = _gssapi_verify_mic_arcfour (minor_status, context_handle,
+                                         message_buffer, token_buffer,
+                                         qop_state, key, type);
+       break;
+    default :
+       ret = _gssapi_verify_mic_cfx (minor_status, context_handle,
+                                     message_buffer, token_buffer, qop_state,
+                                     key);
+       break;
+    }
+    krb5_free_keyblock (gssapi_krb5_context, key);
+    
+    return ret;
+}
+
+OM_uint32
+gss_verify_mic
+           (OM_uint32 * minor_status,
+            const gss_ctx_id_t context_handle,
+            const gss_buffer_t message_buffer,
+            const gss_buffer_t token_buffer,
+            gss_qop_t * qop_state
+           )
+{
+    OM_uint32 ret;
+
+    if (qop_state != NULL)
+       *qop_state = GSS_C_QOP_DEFAULT;
+
+    ret = gss_verify_mic_internal(minor_status, context_handle, 
+                                 message_buffer, token_buffer,
+                                 qop_state, "\x01\x01");
+
+    return ret;
+}
diff --git a/source4/heimdal/lib/gssapi/wrap.c b/source4/heimdal/lib/gssapi/wrap.c
new file mode 100644 (file)
index 0000000..bdb09e6
--- /dev/null
@@ -0,0 +1,533 @@
+/*
+ * 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 "gssapi_locl.h"
+
+RCSID("$Id: wrap.c,v 1.31 2005/01/05 02:52:12 lukeh Exp $");
+
+OM_uint32
+gsskrb5_get_initiator_subkey(OM_uint32 *minor_status,
+                            gss_ctx_id_t context_handle,
+                            gss_buffer_t key)
+{
+    krb5_error_code ret;
+    krb5_keyblock *skey = NULL;
+
+    HEIMDAL_MUTEX_lock(&context_handle->ctx_id_mutex);
+    if (context_handle->more_flags & LOCAL) {
+       ret = krb5_auth_con_getlocalsubkey(gssapi_krb5_context,
+                                          context_handle->auth_context, 
+                                          &skey);
+       if (ret) {
+               *minor_status = ret;
+               return GSS_KRB5_S_KG_NO_SUBKEY; /* XXX */
+       }
+       
+    } else {
+       ret = krb5_auth_con_getremotesubkey(gssapi_krb5_context,
+                                           context_handle->auth_context, 
+                                           &skey);
+       if (ret) {
+               *minor_status = ret;
+               return GSS_KRB5_S_KG_NO_SUBKEY; /* XXX */
+       }
+    
+    }
+    HEIMDAL_MUTEX_unlock(&context_handle->ctx_id_mutex);
+    key->length = skey->keyvalue.length;
+    key->value  = malloc (key->length);
+    if (!key->value) {
+           krb5_free_keyblock(gssapi_krb5_context, skey);
+           *minor_status = ENOMEM;
+           return GSS_S_FAILURE;
+    }
+    memcpy(key->value, skey->keyvalue.data, key->length);
+    krb5_free_keyblock(gssapi_krb5_context, skey);
+    return 0;
+}
+
+OM_uint32
+gss_krb5_get_subkey(const gss_ctx_id_t context_handle,
+                   krb5_keyblock **key)
+{
+    krb5_keyblock *skey = NULL;
+
+    HEIMDAL_MUTEX_lock(&context_handle->ctx_id_mutex);
+    if (context_handle->more_flags & LOCAL) {
+       krb5_auth_con_getremotesubkey(gssapi_krb5_context,
+                                     context_handle->auth_context, 
+                                     &skey);
+    } else {
+       krb5_auth_con_getlocalsubkey(gssapi_krb5_context,
+                                    context_handle->auth_context, 
+                                    &skey);
+    }
+    /*
+     * Only use the initiator subkey or ticket session key if
+     * an acceptor subkey was not required.
+     */
+    if (skey == NULL &&
+       (context_handle->more_flags & ACCEPTOR_SUBKEY) == 0) {
+       if (context_handle->more_flags & LOCAL) {
+           krb5_auth_con_getlocalsubkey(gssapi_krb5_context,
+                                        context_handle->auth_context,
+                                        &skey);
+       } else {
+           krb5_auth_con_getremotesubkey(gssapi_krb5_context,
+                                         context_handle->auth_context,
+                                         &skey);
+       }
+       if(skey == NULL)
+           krb5_auth_con_getkey(gssapi_krb5_context,
+                                context_handle->auth_context, 
+                                &skey);
+    }
+    HEIMDAL_MUTEX_unlock(&context_handle->ctx_id_mutex);
+    if(skey == NULL)
+       return GSS_KRB5_S_KG_NO_SUBKEY; /* XXX */
+    *key = skey;
+    return 0;
+}
+
+static OM_uint32
+sub_wrap_size (
+            OM_uint32 req_output_size,
+            OM_uint32 * max_input_size,
+           int blocksize,
+           int extrasize
+           )
+{
+    size_t len, total_len; 
+
+    len = 8 + req_output_size + blocksize + extrasize;
+
+    gssapi_krb5_encap_length(len, &len, &total_len, GSS_KRB5_MECHANISM);
+
+    total_len -= req_output_size; /* token length */
+    if (total_len < req_output_size) {
+        *max_input_size = (req_output_size - total_len);
+        (*max_input_size) &= (~(OM_uint32)(blocksize - 1));
+    } else {
+        *max_input_size = 0;
+    }
+    return GSS_S_COMPLETE;
+}
+
+OM_uint32
+gss_wrap_size_limit (
+            OM_uint32 * minor_status,
+            const gss_ctx_id_t context_handle,
+            int conf_req_flag,
+            gss_qop_t qop_req,
+            OM_uint32 req_output_size,
+            OM_uint32 * max_input_size
+           )
+{
+  krb5_keyblock *key;
+  OM_uint32 ret;
+  krb5_keytype keytype;
+
+  ret = gss_krb5_get_subkey(context_handle, &key);
+  if (ret) {
+      gssapi_krb5_set_error_string ();
+      *minor_status = ret;
+      return GSS_S_FAILURE;
+  }
+  krb5_enctype_to_keytype (gssapi_krb5_context, key->keytype, &keytype);
+
+  switch (keytype) {
+  case KEYTYPE_DES :
+  case KEYTYPE_ARCFOUR:
+  case KEYTYPE_ARCFOUR_56:
+      ret = sub_wrap_size(req_output_size, max_input_size, 8, 22);
+      break;
+  case KEYTYPE_DES3 :
+      ret = sub_wrap_size(req_output_size, max_input_size, 8, 34);
+      break;
+  default :
+      ret = _gssapi_wrap_size_cfx(minor_status, context_handle, 
+                                 conf_req_flag, qop_req, 
+                                 req_output_size, max_input_size, key);
+      break;
+  }
+  krb5_free_keyblock (gssapi_krb5_context, key);
+  *minor_status = 0;
+  return ret;
+}
+
+static OM_uint32
+wrap_des
+           (OM_uint32 * minor_status,
+            const gss_ctx_id_t context_handle,
+            int conf_req_flag,
+            gss_qop_t qop_req,
+            const gss_buffer_t input_message_buffer,
+            int * conf_state,
+            gss_buffer_t output_message_buffer,
+           krb5_keyblock *key
+           )
+{
+  u_char *p;
+  MD5_CTX md5;
+  u_char hash[16];
+  DES_key_schedule schedule;
+  DES_cblock deskey;
+  DES_cblock zero;
+  int i;
+  int32_t seq_number;
+  size_t len, total_len, padlength, datalen;
+
+  padlength = 8 - (input_message_buffer->length % 8);
+  datalen = input_message_buffer->length + padlength + 8;
+  len = datalen + 22;
+  gssapi_krb5_encap_length (len, &len, &total_len, GSS_KRB5_MECHANISM);
+
+  output_message_buffer->length = total_len;
+  output_message_buffer->value  = malloc (total_len);
+  if (output_message_buffer->value == NULL) {
+    *minor_status = ENOMEM;
+    return GSS_S_FAILURE;
+  }
+
+  p = gssapi_krb5_make_header(output_message_buffer->value,
+                             len,
+                             "\x02\x01", /* TOK_ID */
+                             GSS_KRB5_MECHANISM);
+
+  /* SGN_ALG */
+  memcpy (p, "\x00\x00", 2);
+  p += 2;
+  /* SEAL_ALG */
+  if(conf_req_flag)
+      memcpy (p, "\x00\x00", 2);
+  else
+      memcpy (p, "\xff\xff", 2);
+  p += 2;
+  /* Filler */
+  memcpy (p, "\xff\xff", 2);
+  p += 2;
+
+  /* fill in later */
+  memset (p, 0, 16);
+  p += 16;
+
+  /* confounder + data + pad */
+  krb5_generate_random_block(p, 8);
+  memcpy (p + 8, input_message_buffer->value,
+         input_message_buffer->length);
+  memset (p + 8 + input_message_buffer->length, padlength, padlength);
+
+  /* checksum */
+  MD5_Init (&md5);
+  MD5_Update (&md5, p - 24, 8);
+  MD5_Update (&md5, p, datalen);
+  MD5_Final (hash, &md5);
+
+  memset (&zero, 0, sizeof(zero));
+  memcpy (&deskey, key->keyvalue.data, sizeof(deskey));
+  DES_set_key (&deskey, &schedule);
+  DES_cbc_cksum ((void *)hash, (void *)hash, sizeof(hash),
+                &schedule, &zero);
+  memcpy (p - 8, hash, 8);
+
+  /* sequence number */
+  HEIMDAL_MUTEX_lock(&context_handle->ctx_id_mutex);
+  krb5_auth_con_getlocalseqnumber (gssapi_krb5_context,
+                              context_handle->auth_context,
+                              &seq_number);
+
+  p -= 16;
+  p[0] = (seq_number >> 0)  & 0xFF;
+  p[1] = (seq_number >> 8)  & 0xFF;
+  p[2] = (seq_number >> 16) & 0xFF;
+  p[3] = (seq_number >> 24) & 0xFF;
+  memset (p + 4,
+         (context_handle->more_flags & LOCAL) ? 0 : 0xFF,
+         4);
+
+  DES_set_key (&deskey, &schedule);
+  DES_cbc_encrypt ((void *)p, (void *)p, 8,
+                  &schedule, (DES_cblock *)(p + 8), DES_ENCRYPT);
+
+  krb5_auth_con_setlocalseqnumber (gssapi_krb5_context,
+                              context_handle->auth_context,
+                              ++seq_number);
+  HEIMDAL_MUTEX_unlock(&context_handle->ctx_id_mutex);
+
+  /* encrypt the data */
+  p += 16;
+
+  if(conf_req_flag) {
+      memcpy (&deskey, key->keyvalue.data, sizeof(deskey));
+
+      for (i = 0; i < sizeof(deskey); ++i)
+         deskey[i] ^= 0xf0;
+      DES_set_key (&deskey, &schedule);
+      memset (&zero, 0, sizeof(zero));
+      DES_cbc_encrypt ((void *)p,
+                      (void *)p,
+                      datalen,
+                      &schedule,
+                      &zero,
+                      DES_ENCRYPT);
+  }
+  memset (deskey, 0, sizeof(deskey));
+  memset (&schedule, 0, sizeof(schedule));
+
+  if(conf_state != NULL)
+      *conf_state = conf_req_flag;
+  *minor_status = 0;
+  return GSS_S_COMPLETE;
+}
+
+static OM_uint32
+wrap_des3
+           (OM_uint32 * minor_status,
+            const gss_ctx_id_t context_handle,
+            int conf_req_flag,
+            gss_qop_t qop_req,
+            const gss_buffer_t input_message_buffer,
+            int * conf_state,
+            gss_buffer_t output_message_buffer,
+           krb5_keyblock *key
+           )
+{
+  u_char *p;
+  u_char seq[8];
+  int32_t seq_number;
+  size_t len, total_len, padlength, datalen;
+  u_int32_t ret;
+  krb5_crypto crypto;
+  Checksum cksum;
+  krb5_data encdata;
+
+  padlength = 8 - (input_message_buffer->length % 8);
+  datalen = input_message_buffer->length + padlength + 8;
+  len = datalen + 34;
+  gssapi_krb5_encap_length (len, &len, &total_len, GSS_KRB5_MECHANISM);
+
+  output_message_buffer->length = total_len;
+  output_message_buffer->value  = malloc (total_len);
+  if (output_message_buffer->value == NULL) {
+    *minor_status = ENOMEM;
+    return GSS_S_FAILURE;
+  }
+
+  p = gssapi_krb5_make_header(output_message_buffer->value,
+                             len,
+                             "\x02\x01", /* TOK_ID */
+                             GSS_KRB5_MECHANISM); 
+
+  /* SGN_ALG */
+  memcpy (p, "\x04\x00", 2);   /* HMAC SHA1 DES3-KD */
+  p += 2;
+  /* SEAL_ALG */
+  if(conf_req_flag)
+      memcpy (p, "\x02\x00", 2); /* DES3-KD */
+  else
+      memcpy (p, "\xff\xff", 2);
+  p += 2;
+  /* Filler */
+  memcpy (p, "\xff\xff", 2);
+  p += 2;
+
+  /* calculate checksum (the above + confounder + data + pad) */
+
+  memcpy (p + 20, p - 8, 8);
+  krb5_generate_random_block(p + 28, 8);
+  memcpy (p + 28 + 8, input_message_buffer->value,
+         input_message_buffer->length);
+  memset (p + 28 + 8 + input_message_buffer->length, padlength, padlength);
+
+  ret = krb5_crypto_init(gssapi_krb5_context, key, 0, &crypto);
+  if (ret) {
+      gssapi_krb5_set_error_string ();
+      free (output_message_buffer->value);
+      *minor_status = ret;
+      return GSS_S_FAILURE;
+  }
+
+  ret = krb5_create_checksum (gssapi_krb5_context,
+                             crypto,
+                             KRB5_KU_USAGE_SIGN,
+                             0,
+                             p + 20,
+                             datalen + 8,
+                             &cksum);
+  krb5_crypto_destroy (gssapi_krb5_context, crypto);
+  if (ret) {
+      gssapi_krb5_set_error_string ();
+      free (output_message_buffer->value);
+      *minor_status = ret;
+      return GSS_S_FAILURE;
+  }
+
+  /* zero out SND_SEQ + SGN_CKSUM in case */
+  memset (p, 0, 28);
+
+  memcpy (p + 8, cksum.checksum.data, cksum.checksum.length);
+  free_Checksum (&cksum);
+
+  HEIMDAL_MUTEX_lock(&context_handle->ctx_id_mutex);
+  /* sequence number */
+  krb5_auth_con_getlocalseqnumber (gssapi_krb5_context,
+                              context_handle->auth_context,
+                              &seq_number);
+
+  seq[0] = (seq_number >> 0)  & 0xFF;
+  seq[1] = (seq_number >> 8)  & 0xFF;
+  seq[2] = (seq_number >> 16) & 0xFF;
+  seq[3] = (seq_number >> 24) & 0xFF;
+  memset (seq + 4,
+         (context_handle->more_flags & LOCAL) ? 0 : 0xFF,
+         4);
+
+
+  ret = krb5_crypto_init(gssapi_krb5_context, key, ETYPE_DES3_CBC_NONE,
+                        &crypto);
+  if (ret) {
+      free (output_message_buffer->value);
+      *minor_status = ret;
+      return GSS_S_FAILURE;
+  }
+
+  {
+      DES_cblock ivec;
+
+      memcpy (&ivec, p + 8, 8);
+      ret = krb5_encrypt_ivec (gssapi_krb5_context,
+                              crypto,
+                              KRB5_KU_USAGE_SEQ,
+                              seq, 8, &encdata,
+                              &ivec);
+  }
+  krb5_crypto_destroy (gssapi_krb5_context, crypto);
+  if (ret) {
+      gssapi_krb5_set_error_string ();
+      free (output_message_buffer->value);
+      *minor_status = ret;
+      return GSS_S_FAILURE;
+  }
+  
+  assert (encdata.length == 8);
+
+  memcpy (p, encdata.data, encdata.length);
+  krb5_data_free (&encdata);
+
+  krb5_auth_con_setlocalseqnumber (gssapi_krb5_context,
+                              context_handle->auth_context,
+                              ++seq_number);
+  HEIMDAL_MUTEX_unlock(&context_handle->ctx_id_mutex);
+
+  /* encrypt the data */
+  p += 28;
+
+  if(conf_req_flag) {
+      krb5_data tmp;
+
+      ret = krb5_crypto_init(gssapi_krb5_context, key,
+                            ETYPE_DES3_CBC_NONE, &crypto);
+      if (ret) {
+         gssapi_krb5_set_error_string ();
+         free (output_message_buffer->value);
+         *minor_status = ret;
+         return GSS_S_FAILURE;
+      }
+      ret = krb5_encrypt(gssapi_krb5_context, crypto, KRB5_KU_USAGE_SEAL,
+                        p, datalen, &tmp);
+      krb5_crypto_destroy(gssapi_krb5_context, crypto);
+      if (ret) {
+         gssapi_krb5_set_error_string ();
+         free (output_message_buffer->value);
+         *minor_status = ret;
+         return GSS_S_FAILURE;
+      }
+      assert (tmp.length == datalen);
+
+      memcpy (p, tmp.data, datalen);
+      krb5_data_free(&tmp);
+  }
+  if(conf_state != NULL)
+      *conf_state = conf_req_flag;
+  *minor_status = 0;
+  return GSS_S_COMPLETE;
+}
+
+OM_uint32 gss_wrap
+           (OM_uint32 * minor_status,
+            const gss_ctx_id_t context_handle,
+            int conf_req_flag,
+            gss_qop_t qop_req,
+            const gss_buffer_t input_message_buffer,
+            int * conf_state,
+            gss_buffer_t output_message_buffer
+           )
+{
+  krb5_keyblock *key;
+  OM_uint32 ret;
+  krb5_keytype keytype;
+
+  ret = gss_krb5_get_subkey(context_handle, &key);
+  if (ret) {
+      gssapi_krb5_set_error_string ();
+      *minor_status = ret;
+      return GSS_S_FAILURE;
+  }
+  krb5_enctype_to_keytype (gssapi_krb5_context, key->keytype, &keytype);
+
+  switch (keytype) {
+  case KEYTYPE_DES :
+      ret = wrap_des (minor_status, context_handle, conf_req_flag,
+                     qop_req, input_message_buffer, conf_state,
+                     output_message_buffer, key);
+      break;
+  case KEYTYPE_DES3 :
+      ret = wrap_des3 (minor_status, context_handle, conf_req_flag,
+                      qop_req, input_message_buffer, conf_state,
+                      output_message_buffer, key);
+      break;
+  case KEYTYPE_ARCFOUR:
+  case KEYTYPE_ARCFOUR_56:
+      ret = _gssapi_wrap_arcfour (minor_status, context_handle, conf_req_flag,
+                                 qop_req, input_message_buffer, conf_state,
+                                 output_message_buffer, key);
+      break;
+  default :
+      ret = _gssapi_wrap_cfx (minor_status, context_handle, conf_req_flag,
+                             qop_req, input_message_buffer, conf_state,
+                             output_message_buffer, key);
+      break;
+  }
+  krb5_free_keyblock (gssapi_krb5_context, key);
+  return ret;
+}
diff --git a/source4/heimdal/lib/hdb/db.c b/source4/heimdal/lib/hdb/db.c
new file mode 100644 (file)
index 0000000..d7a4cf3
--- /dev/null
@@ -0,0 +1,306 @@
+/*
+ * 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 "hdb_locl.h"
+
+RCSID("$Id: db.c,v 1.32 2005/06/23 13:34:17 lha Exp $");
+
+#if HAVE_DB1
+
+#if defined(HAVE_DB_185_H)
+#include <db_185.h>
+#elif defined(HAVE_DB_H)
+#include <db.h>
+#endif
+
+static krb5_error_code
+DB_close(krb5_context context, HDB *db)
+{
+    DB *d = (DB*)db->hdb_db;
+    d->close(d);
+    return 0;
+}
+
+static krb5_error_code
+DB_destroy(krb5_context context, HDB *db)
+{
+    krb5_error_code ret;
+
+    ret = hdb_clear_master_key (context, db);
+    free(db->hdb_name);
+    free(db);
+    return ret;
+}
+
+static krb5_error_code
+DB_lock(krb5_context context, HDB *db, int operation)
+{
+    DB *d = (DB*)db->hdb_db;
+    int fd = (*d->fd)(d);
+    if(fd < 0)
+       return HDB_ERR_CANT_LOCK_DB;
+    return hdb_lock(fd, operation);
+}
+
+static krb5_error_code
+DB_unlock(krb5_context context, HDB *db)
+{
+    DB *d = (DB*)db->hdb_db;
+    int fd = (*d->fd)(d);
+    if(fd < 0)
+       return HDB_ERR_CANT_LOCK_DB;
+    return hdb_unlock(fd);
+}
+
+
+static krb5_error_code
+DB_seq(krb5_context context, HDB *db,
+       unsigned flags, hdb_entry *entry, int flag)
+{
+    DB *d = (DB*)db->hdb_db;
+    DBT key, value;
+    krb5_data key_data, data;
+    int code;
+
+    code = db->hdb_lock(context, db, HDB_RLOCK);
+    if(code == -1)
+       return HDB_ERR_DB_INUSE;
+    code = d->seq(d, &key, &value, flag);
+    db->hdb_unlock(context, db); /* XXX check value */
+    if(code == -1)
+       return errno;
+    if(code == 1)
+       return HDB_ERR_NOENTRY;
+
+    key_data.data = key.data;
+    key_data.length = key.size;
+    data.data = value.data;
+    data.length = value.size;
+    if (hdb_value2entry(context, &data, entry))
+       return DB_seq(context, db, flags, entry, R_NEXT);
+    if (db->hdb_master_key_set && (flags & HDB_F_DECRYPT)) {
+       code = hdb_unseal_keys (context, db, entry);
+       if (code)
+           hdb_free_entry (context, entry);
+    }
+    if (code == 0 && entry->principal == NULL) {
+       entry->principal = malloc(sizeof(*entry->principal));
+       if (entry->principal == NULL) {
+           krb5_set_error_string(context, "malloc: out of memory");
+           code = ENOMEM;
+           hdb_free_entry (context, entry);
+       } else {
+           hdb_key2principal(context, &key_data, entry->principal);
+       }
+    }
+    return code;
+}
+
+
+static krb5_error_code
+DB_firstkey(krb5_context context, HDB *db, unsigned flags, hdb_entry *entry)
+{
+    return DB_seq(context, db, flags, entry, R_FIRST);
+}
+
+
+static krb5_error_code
+DB_nextkey(krb5_context context, HDB *db, unsigned flags, hdb_entry *entry)
+{
+    return DB_seq(context, db, flags, entry, R_NEXT);
+}
+
+static krb5_error_code
+DB_rename(krb5_context context, HDB *db, const char *new_name)
+{
+    int ret;
+    char *old, *new;
+
+    asprintf(&old, "%s.db", db->hdb_name);
+    asprintf(&new, "%s.db", new_name);
+    ret = rename(old, new);
+    free(old);
+    free(new);
+    if(ret)
+       return errno;
+    
+    free(db->hdb_name);
+    db->hdb_name = strdup(new_name);
+    return 0;
+}
+
+static krb5_error_code
+DB__get(krb5_context context, HDB *db, krb5_data key, krb5_data *reply)
+{
+    DB *d = (DB*)db->hdb_db;
+    DBT k, v;
+    int code;
+
+    k.data = key.data;
+    k.size = key.length;
+    code = db->hdb_lock(context, db, HDB_RLOCK);
+    if(code)
+       return code;
+    code = d->get(d, &k, &v, 0);
+    db->hdb_unlock(context, db);
+    if(code < 0)
+       return errno;
+    if(code == 1)
+       return HDB_ERR_NOENTRY;
+    
+    krb5_data_copy(reply, v.data, v.size);
+    return 0;
+}
+
+static krb5_error_code
+DB__put(krb5_context context, HDB *db, int replace, 
+       krb5_data key, krb5_data value)
+{
+    DB *d = (DB*)db->hdb_db;
+    DBT k, v;
+    int code;
+
+    k.data = key.data;
+    k.size = key.length;
+    v.data = value.data;
+    v.size = value.length;
+    code = db->hdb_lock(context, db, HDB_WLOCK);
+    if(code)
+       return code;
+    code = d->put(d, &k, &v, replace ? 0 : R_NOOVERWRITE);
+    db->hdb_unlock(context, db);
+    if(code < 0)
+       return errno;
+    if(code == 1)
+       return HDB_ERR_EXISTS;
+    return 0;
+}
+
+static krb5_error_code
+DB__del(krb5_context context, HDB *db, krb5_data key)
+{
+    DB *d = (DB*)db->hdb_db;
+    DBT k;
+    krb5_error_code code;
+    k.data = key.data;
+    k.size = key.length;
+    code = db->hdb_lock(context, db, HDB_WLOCK);
+    if(code)
+       return code;
+    code = d->del(d, &k, 0);
+    db->hdb_unlock(context, db);
+    if(code == 1)
+       return HDB_ERR_NOENTRY;
+    if(code < 0)
+       return errno;
+    return 0;
+}
+
+static krb5_error_code
+DB_open(krb5_context context, HDB *db, int flags, mode_t mode)
+{
+    char *fn;
+    krb5_error_code ret;
+
+    asprintf(&fn, "%s.db", db->hdb_name);
+    if (fn == NULL) {
+       krb5_set_error_string(context, "malloc: out of memory");
+       return ENOMEM;
+    }
+    db->hdb_db = dbopen(fn, flags, mode, DB_BTREE, NULL);
+    free(fn);
+    /* try to open without .db extension */
+    if(db->hdb_db == NULL && errno == ENOENT)
+       db->hdb_db = dbopen(db->hdb_name, flags, mode, DB_BTREE, NULL);
+    if(db->hdb_db == NULL) {
+       ret = errno;
+       krb5_set_error_string(context, "dbopen (%s): %s",
+                             db->hdb_name, strerror(ret));
+       return ret;
+    }
+    if((flags & O_ACCMODE) == O_RDONLY)
+       ret = hdb_check_db_format(context, db);
+    else
+       ret = hdb_init_db(context, db);
+    if(ret == HDB_ERR_NOENTRY) {
+       krb5_clear_error_string(context);
+       return 0;
+    }
+    if (ret) {
+       DB_close(context, db);
+       krb5_set_error_string(context, "hdb_open: failed %s database %s",
+                             (flags & O_ACCMODE) == O_RDONLY ? 
+                             "checking format of" : "initialize", 
+                             db->hdb_name);
+    }
+    return ret;
+}
+
+krb5_error_code
+hdb_db_create(krb5_context context, HDB **db, 
+             const char *filename)
+{
+    *db = malloc(sizeof(**db));
+    if (*db == NULL) {
+       krb5_set_error_string(context, "malloc: out of memory");
+       return ENOMEM;
+    }
+
+    (*db)->hdb_db = NULL;
+    (*db)->hdb_name = strdup(filename);
+    if ((*db)->hdb_name == NULL) {
+       krb5_set_error_string(context, "malloc: out of memory");
+       free(*db);
+       *db = NULL;
+       return ENOMEM;
+    }
+    (*db)->hdb_master_key_set = 0;
+    (*db)->hdb_openp = 0;
+    (*db)->hdb_open = DB_open;
+    (*db)->hdb_close = DB_close;
+    (*db)->hdb_fetch = _hdb_fetch;
+    (*db)->hdb_store = _hdb_store;
+    (*db)->hdb_remove = _hdb_remove;
+    (*db)->hdb_firstkey = DB_firstkey;
+    (*db)->hdb_nextkey= DB_nextkey;
+    (*db)->hdb_lock = DB_lock;
+    (*db)->hdb_unlock = DB_unlock;
+    (*db)->hdb_rename = DB_rename;
+    (*db)->hdb__get = DB__get;
+    (*db)->hdb__put = DB__put;
+    (*db)->hdb__del = DB__del;
+    (*db)->hdb_destroy = DB_destroy;
+    return 0;
+}
+
+#endif /* HAVE_DB1 */
diff --git a/source4/heimdal/lib/hdb/hdb-private.h b/source4/heimdal/lib/hdb/hdb-private.h
new file mode 100644 (file)
index 0000000..653df8c
--- /dev/null
@@ -0,0 +1,25 @@
+/* This is a generated file */
+#ifndef __hdb_private_h__
+#define __hdb_private_h__
+
+#include <stdarg.h>
+
+krb5_error_code
+_hdb_fetch(krb5_context context, HDB *db, unsigned flags,         
+          krb5_principal principal,
+          enum hdb_ent_type ent_type,
+          hdb_entry *entry);
+krb5_error_code
+_hdb_remove (
+       krb5_context /*context*/,
+       HDB */*db*/,
+       hdb_entry */*entry*/);
+
+krb5_error_code
+_hdb_store (
+       krb5_context /*context*/,
+       HDB */*db*/,
+       unsigned /*flags*/,
+       hdb_entry */*entry*/);
+
+#endif /* __hdb_private_h__ */
diff --git a/source4/heimdal/lib/hdb/hdb-protos.h b/source4/heimdal/lib/hdb/hdb-protos.h
new file mode 100644 (file)
index 0000000..886d48e
--- /dev/null
@@ -0,0 +1,247 @@
+/* This is a generated file */
+#ifndef __hdb_protos_h__
+#define __hdb_protos_h__
+
+#include <stdarg.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+krb5_error_code
+hdb_add_master_key (
+       krb5_context /*context*/,
+       krb5_keyblock */*key*/,
+       hdb_master_key */*inout*/);
+
+krb5_error_code
+hdb_check_db_format (
+       krb5_context /*context*/,
+       HDB */*db*/);
+
+krb5_error_code
+hdb_clear_master_key (
+       krb5_context /*context*/,
+       HDB */*db*/);
+
+krb5_error_code
+hdb_create (
+       krb5_context /*context*/,
+       HDB **/*db*/,
+       const char */*filename*/);
+
+krb5_error_code
+hdb_db_create (
+       krb5_context /*context*/,
+       HDB **/*db*/,
+       const char */*filename*/);
+
+krb5_error_code
+hdb_enctype2key (
+       krb5_context /*context*/,
+       hdb_entry */*e*/,
+       krb5_enctype /*enctype*/,
+       Key **/*key*/);
+
+krb5_error_code
+hdb_entry2string (
+       krb5_context /*context*/,
+       hdb_entry */*ent*/,
+       char **/*str*/);
+
+int
+hdb_entry2value (
+       krb5_context /*context*/,
+       hdb_entry */*ent*/,
+       krb5_data */*value*/);
+
+krb5_error_code
+hdb_foreach (
+       krb5_context /*context*/,
+       HDB */*db*/,
+       unsigned /*flags*/,
+       hdb_foreach_func_t /*func*/,
+       void */*data*/);
+
+void
+hdb_free_entry (
+       krb5_context /*context*/,
+       hdb_entry */*ent*/);
+
+void
+hdb_free_key (Key */*key*/);
+
+void
+hdb_free_keys (
+       krb5_context /*context*/,
+       int /*len*/,
+       Key */*keys*/);
+
+void
+hdb_free_master_key (
+       krb5_context /*context*/,
+       hdb_master_key /*mkey*/);
+
+krb5_error_code
+hdb_generate_key_set (
+       krb5_context /*context*/,
+       krb5_principal /*principal*/,
+       Key **/*ret_key_set*/,
+       size_t */*nkeyset*/,
+       int /*no_salt*/);
+
+krb5_error_code
+hdb_generate_key_set_password (
+       krb5_context /*context*/,
+       krb5_principal /*principal*/,
+       const char */*password*/,
+       Key **/*keys*/,
+       size_t */*num_keys*/);
+
+krb5_error_code
+hdb_init_db (
+       krb5_context /*context*/,
+       HDB */*db*/);
+
+int
+hdb_key2principal (
+       krb5_context /*context*/,
+       krb5_data */*key*/,
+       krb5_principal /*p*/);
+
+krb5_error_code
+hdb_ldap_create (
+       krb5_context /*context*/,
+       HDB ** /*db*/,
+       const char */*arg*/);
+
+krb5_error_code
+hdb_list_builtin (
+       krb5_context /*context*/,
+       char **/*list*/);
+
+krb5_error_code
+hdb_lock (
+       int /*fd*/,
+       int /*operation*/);
+
+krb5_error_code
+hdb_ndbm_create (
+       krb5_context /*context*/,
+       HDB **/*db*/,
+       const char */*filename*/);
+
+krb5_error_code
+hdb_next_enctype2key (
+       krb5_context /*context*/,
+       const hdb_entry */*e*/,
+       krb5_enctype /*enctype*/,
+       Key **/*key*/);
+
+int
+hdb_principal2key (
+       krb5_context /*context*/,
+       krb5_principal /*p*/,
+       krb5_data */*key*/);
+
+krb5_error_code
+hdb_print_entry (
+       krb5_context /*context*/,
+       HDB */*db*/,
+       hdb_entry */*entry*/,
+       void */*data*/);
+
+krb5_error_code
+hdb_process_master_key (
+       krb5_context /*context*/,
+       int /*kvno*/,
+       krb5_keyblock */*key*/,
+       krb5_enctype /*etype*/,
+       hdb_master_key */*mkey*/);
+
+krb5_error_code
+hdb_read_master_key (
+       krb5_context /*context*/,
+       const char */*filename*/,
+       hdb_master_key */*mkey*/);
+
+krb5_error_code
+hdb_seal_key (
+       krb5_context /*context*/,
+       HDB */*db*/,
+       Key */*k*/);
+
+krb5_error_code
+hdb_seal_key_mkey (
+       krb5_context /*context*/,
+       Key */*k*/,
+       hdb_master_key /*mkey*/);
+
+krb5_error_code
+hdb_seal_keys (
+       krb5_context /*context*/,
+       HDB */*db*/,
+       hdb_entry */*ent*/);
+
+krb5_error_code
+hdb_seal_keys_mkey (
+       krb5_context /*context*/,
+       hdb_entry */*ent*/,
+       hdb_master_key /*mkey*/);
+
+krb5_error_code
+hdb_set_master_key (
+       krb5_context /*context*/,
+       HDB */*db*/,
+       krb5_keyblock */*key*/);
+
+krb5_error_code
+hdb_set_master_keyfile (
+       krb5_context /*context*/,
+       HDB */*db*/,
+       const char */*keyfile*/);
+
+krb5_error_code
+hdb_unlock (int /*fd*/);
+
+krb5_error_code
+hdb_unseal_key (
+       krb5_context /*context*/,
+       HDB */*db*/,
+       Key */*k*/);
+
+krb5_error_code
+hdb_unseal_key_mkey (
+       krb5_context /*context*/,
+       Key */*k*/,
+       hdb_master_key /*mkey*/);
+
+krb5_error_code
+hdb_unseal_keys (
+       krb5_context /*context*/,
+       HDB */*db*/,
+       hdb_entry */*ent*/);
+
+krb5_error_code
+hdb_unseal_keys_mkey (
+       krb5_context /*context*/,
+       hdb_entry */*ent*/,
+       hdb_master_key /*mkey*/);
+
+int
+hdb_value2entry (
+       krb5_context /*context*/,
+       krb5_data */*value*/,
+       hdb_entry */*ent*/);
+
+krb5_error_code
+hdb_write_master_key (
+       krb5_context /*context*/,
+       const char */*filename*/,
+       hdb_master_key /*mkey*/);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __hdb_protos_h__ */
diff --git a/source4/heimdal/lib/hdb/hdb.asn1 b/source4/heimdal/lib/hdb/hdb.asn1
new file mode 100644 (file)
index 0000000..770acf4
--- /dev/null
@@ -0,0 +1,70 @@
+-- $Id: hdb.asn1,v 1.12 2004/11/10 18:50:27 lha Exp $
+HDB DEFINITIONS ::=
+BEGIN
+
+IMPORTS EncryptionKey, KerberosTime, Principal FROM krb5;
+
+HDB_DB_FORMAT INTEGER ::= 2    -- format of database, 
+                               -- update when making changes
+
+-- these must have the same value as the pa-* counterparts
+hdb-pw-salt    INTEGER ::= 3
+hdb-afs3-salt  INTEGER ::= 10
+
+Salt ::= SEQUENCE {
+       type[0]         INTEGER (0..4294967295),
+       salt[1]         OCTET STRING
+}
+
+Key ::= SEQUENCE {
+       mkvno[0]        INTEGER (0..4294967295) OPTIONAL, -- master key version number
+       key[1]          EncryptionKey,
+       salt[2]         Salt OPTIONAL
+}
+
+Event ::= SEQUENCE {
+       time[0]         KerberosTime,
+       principal[1]    Principal OPTIONAL
+}
+
+HDBFlags ::= BIT STRING {
+       initial(0),                     -- require as-req
+       forwardable(1),                 -- may issue forwardable
+       proxiable(2),                   -- may issue proxiable
+       renewable(3),                   -- may issue renewable
+       postdate(4),                    -- may issue postdatable
+       server(5),                      -- may be server
+       client(6),                      -- may be client
+       invalid(7),                     -- entry is invalid
+       require-preauth(8),             -- must use preauth
+       change-pw(9),                   -- change password service
+       require-hwauth(10),             -- must use hwauth
+       ok-as-delegate(11),             -- as in TicketFlags
+       user-to-user(12),               -- may use user-to-user auth
+       immutable(13)                   -- may not be deleted
+}
+
+GENERATION ::= SEQUENCE {
+       time[0]         KerberosTime,                   -- timestamp
+       usec[1]         INTEGER (0..4294967295),        -- microseconds
+       gen[2]          INTEGER (0..4294967295)         -- generation number
+}
+
+hdb_entry ::= SEQUENCE {
+       principal[0]    Principal  OPTIONAL, -- this is optional only 
+                                            -- for compatibility with libkrb5
+       kvno[1]         INTEGER (0..4294967295),
+       keys[2]         SEQUENCE OF Key,
+       created-by[3]   Event,
+       modified-by[4]  Event OPTIONAL,
+       valid-start[5]  KerberosTime OPTIONAL,
+       valid-end[6]    KerberosTime OPTIONAL,
+       pw-end[7]       KerberosTime OPTIONAL,
+       max-life[8]     INTEGER (0..4294967295) OPTIONAL,
+       max-renew[9]    INTEGER (0..4294967295) OPTIONAL,
+       flags[10]       HDBFlags,
+       etypes[11]      SEQUENCE OF INTEGER (0..4294967295) OPTIONAL,
+       generation[12]  GENERATION OPTIONAL
+}
+
+END
diff --git a/source4/heimdal/lib/hdb/hdb.c b/source4/heimdal/lib/hdb/hdb.c
new file mode 100644 (file)
index 0000000..53c9529
--- /dev/null
@@ -0,0 +1,373 @@
+/*
+ * 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 "hdb_locl.h"
+
+RCSID("$Id: hdb.c,v 1.54 2005/05/29 18:12:28 lha Exp $");
+
+#ifdef HAVE_DLFCN_H
+#include <dlfcn.h>
+#endif
+
+struct hdb_method {
+    const char *prefix;
+    krb5_error_code (*create)(krb5_context, HDB **, const char *filename);
+};
+
+static struct hdb_method methods[] = {
+#if HAVE_DB1 || HAVE_DB3
+    {"db:",    hdb_db_create},
+#endif
+#if HAVE_NDBM
+    {"ndbm:",  hdb_ndbm_create},
+#endif
+#if defined(OPENLDAP) && !defined(OPENLDAP_MODULE)
+    {"ldap:",  hdb_ldap_create},
+#endif
+#if HAVE_DB1 || HAVE_DB3
+    {"",       hdb_db_create},
+#elif defined(HAVE_NDBM)
+    {"",       hdb_ndbm_create},
+#elif defined(OPENLDAP) && !defined(OPENLDAP_MODULE)
+    {"",       hdb_ldap_create},
+#endif
+    {NULL,     NULL}
+};
+
+krb5_error_code
+hdb_next_enctype2key(krb5_context context,
+                    const hdb_entry *e,
+                    krb5_enctype enctype,
+                    Key **key)
+{
+    Key *k;
+    
+    for (k = *key ? (*key) + 1 : e->keys.val;
+        k < e->keys.val + e->keys.len; 
+        k++)
+       if(k->key.keytype == enctype){
+           *key = k;
+           return 0;
+       }
+    return KRB5_PROG_ETYPE_NOSUPP; /* XXX */
+}
+
+krb5_error_code
+hdb_enctype2key(krb5_context context, 
+               hdb_entry *e, 
+               krb5_enctype enctype, 
+               Key **key)
+{
+    *key = NULL;
+    return hdb_next_enctype2key(context, e, enctype, key);
+}
+
+void
+hdb_free_key(Key *key)
+{
+    memset(key->key.keyvalue.data, 
+          0,
+          key->key.keyvalue.length);
+    free_Key(key);
+    free(key);
+}
+
+
+krb5_error_code
+hdb_lock(int fd, int operation)
+{
+    int i, code = 0;
+
+    for(i = 0; i < 3; i++){
+       code = flock(fd, (operation == HDB_RLOCK ? LOCK_SH : LOCK_EX) | LOCK_NB);
+       if(code == 0 || errno != EWOULDBLOCK)
+           break;
+       sleep(1);
+    }
+    if(code == 0)
+       return 0;
+    if(errno == EWOULDBLOCK)
+       return HDB_ERR_DB_INUSE;
+    return HDB_ERR_CANT_LOCK_DB;
+}
+
+krb5_error_code
+hdb_unlock(int fd)
+{
+    int code;
+    code = flock(fd, LOCK_UN);
+    if(code)
+       return 4711 /* XXX */;
+    return 0;
+}
+
+void
+hdb_free_entry(krb5_context context, hdb_entry *ent)
+{
+    int i;
+
+    for(i = 0; i < ent->keys.len; ++i) {
+       Key *k = &ent->keys.val[i];
+
+       memset (k->key.keyvalue.data, 0, k->key.keyvalue.length);
+    }
+    free_hdb_entry(ent);
+}
+
+krb5_error_code
+hdb_foreach(krb5_context context,
+           HDB *db,
+           unsigned flags,
+           hdb_foreach_func_t func,
+           void *data)
+{
+    krb5_error_code ret;
+    hdb_entry entry;
+    ret = db->hdb_firstkey(context, db, flags, &entry);
+    while(ret == 0){
+       ret = (*func)(context, db, &entry, data);
+       hdb_free_entry(context, &entry);
+       if(ret == 0)
+           ret = db->hdb_nextkey(context, db, flags, &entry);
+    }
+    if(ret == HDB_ERR_NOENTRY)
+       ret = 0;
+    return ret;
+}
+
+krb5_error_code
+hdb_check_db_format(krb5_context context, HDB *db)
+{
+    krb5_data tag;
+    krb5_data version;
+    krb5_error_code ret;
+    unsigned ver;
+    int foo;
+
+    tag.data = HDB_DB_FORMAT_ENTRY;
+    tag.length = strlen(tag.data);
+    ret = (*db->hdb__get)(context, db, tag, &version);
+    if(ret)
+       return ret;
+    foo = sscanf(version.data, "%u", &ver);
+    krb5_data_free (&version);
+    if (foo != 1)
+       return HDB_ERR_BADVERSION;
+    if(ver != HDB_DB_FORMAT)
+       return HDB_ERR_BADVERSION;
+    return 0;
+}
+
+krb5_error_code
+hdb_init_db(krb5_context context, HDB *db)
+{
+    krb5_error_code ret;
+    krb5_data tag;
+    krb5_data version;
+    char ver[32];
+    
+    ret = hdb_check_db_format(context, db);
+    if(ret != HDB_ERR_NOENTRY)
+       return ret;
+    
+    tag.data = HDB_DB_FORMAT_ENTRY;
+    tag.length = strlen(tag.data);
+    snprintf(ver, sizeof(ver), "%u", HDB_DB_FORMAT);
+    version.data = ver;
+    version.length = strlen(version.data) + 1; /* zero terminated */
+    ret = (*db->hdb__put)(context, db, 0, tag, version);
+    return ret;
+}
+
+#ifdef HAVE_DLOPEN
+
+ /*
+ * Load a dynamic backend from /usr/heimdal/lib/hdb_NAME.so,
+ * looking for the hdb_NAME_create symbol.
+ */
+
+static const struct hdb_method *
+find_dynamic_method (krb5_context context,
+                    const char *filename, 
+                    const char **rest)
+{
+    static struct hdb_method method;
+    struct hdb_so_method *mso;
+    char *prefix, *path, *symbol;
+    const char *p;
+    void *dl;
+    size_t len;
+    
+    p = strchr(filename, ':');
+
+    /* if no prefix, don't know what module to load, just ignore it */
+    if (p == NULL)
+       return NULL;
+
+    len = p - filename;
+    *rest = filename + len + 1;
+    
+    prefix = strndup(filename, len);
+    if (prefix == NULL)
+       krb5_errx(context, 1, "out of memory");
+    
+    if (asprintf(&path, LIBDIR "/hdb_%s.so", prefix) == -1)
+       krb5_errx(context, 1, "out of memory");
+
+#ifndef RTLD_NOW
+#define RTLD_NOW 0
+#endif
+#ifndef RTLD_GLOBAL
+#define RTLD_GLOBAL 0
+#endif
+
+    dl = dlopen(path, RTLD_NOW | RTLD_GLOBAL);
+    if (dl == NULL) {
+       krb5_warnx(context, "error trying to load dynamic module %s: %s\n",
+                  path, dlerror());
+       free(prefix);
+       free(path);
+       return NULL;
+    }
+    
+    if (asprintf(&symbol, "hdb_%s_interface", prefix) == -1)
+       krb5_errx(context, 1, "out of memory");
+       
+    mso = dlsym(dl, symbol);
+    if (mso == NULL) {
+       krb5_warnx(context, "error finding symbol %s in %s: %s\n", 
+                  symbol, path, dlerror());
+       dlclose(dl);
+       free(symbol);
+       free(prefix);
+       free(path);
+       return NULL;
+    }
+    free(path);
+    free(symbol);
+
+    if (mso->version != HDB_INTERFACE_VERSION) {
+       krb5_warnx(context, 
+                  "error wrong version in shared module %s "
+                  "version: %d should have been %d\n", 
+                  prefix, mso->version, HDB_INTERFACE_VERSION);
+       dlclose(dl);
+       free(prefix);
+       return NULL;
+    }
+
+    if (mso->create == NULL) {
+       krb5_errx(context, 1,
+                 "no entry point function in shared mod %s ",
+                  prefix);
+       dlclose(dl);
+       free(prefix);
+       return NULL;
+    }
+
+    method.create = mso->create;
+    method.prefix = prefix;
+
+    return &method;
+}
+#endif /* HAVE_DLOPEN */
+
+/*
+ * find the relevant method for `filename', returning a pointer to the
+ * rest in `rest'.
+ * return NULL if there's no such method.
+ */
+
+static const struct hdb_method *
+find_method (const char *filename, const char **rest)
+{
+    const struct hdb_method *h;
+
+    for (h = methods; h->prefix != NULL; ++h)
+       if (strncmp (filename, h->prefix, strlen(h->prefix)) == 0) {
+           *rest = filename + strlen(h->prefix);
+           return h;
+       }
+    return NULL;
+}
+
+krb5_error_code
+hdb_list_builtin(krb5_context context, char **list)
+{
+    const struct hdb_method *h;
+    size_t len = 0;
+    char *buf = NULL;
+
+    for (h = methods; h->prefix != NULL; ++h) {
+       if (h->prefix[0] == '\0')
+           continue;
+       len += strlen(h->prefix) + 2;
+    }
+
+    len += 1;
+    buf = malloc(len);
+    if (buf == NULL) {
+       krb5_set_error_string(context, "malloc: out of memory");
+       return ENOMEM;
+    }
+    buf[0] = '\0';
+
+    for (h = methods; h->prefix != NULL; ++h) {
+       if (h->prefix[0] == '\0')
+           continue;
+       if (h != methods)
+           strlcat(buf, ", ", len);
+       strlcat(buf, h->prefix, len);
+    }
+    *list = buf;
+    return 0;
+}
+
+krb5_error_code
+hdb_create(krb5_context context, HDB **db, const char *filename)
+{
+    const struct hdb_method *h;
+    const char *residual;
+
+    if(filename == NULL)
+       filename = HDB_DEFAULT_DB;
+    krb5_add_et_list(context, initialize_hdb_error_table_r);
+    h = find_method (filename, &residual);
+#ifdef HAVE_DLOPEN
+    if (h == NULL)
+       h = find_dynamic_method (context, filename, &residual);
+#endif
+    if (h == NULL)
+       krb5_errx(context, 1, "No database support! (hdb_create)");
+    return (*h->create)(context, db, residual);
+}
diff --git a/source4/heimdal/lib/hdb/hdb.h b/source4/heimdal/lib/hdb/hdb.h
new file mode 100644 (file)
index 0000000..481d4ea
--- /dev/null
@@ -0,0 +1,102 @@
+/*
+ * 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. 
+ */
+
+/* $Id: hdb.h,v 1.33 2003/09/19 00:19:36 lha Exp $ */
+
+#ifndef __HDB_H__
+#define __HDB_H__
+
+#include <hdb_err.h>
+
+#include <hdb_asn1.h>
+
+enum hdb_lockop{ HDB_RLOCK, HDB_WLOCK };
+
+/* flags for various functions */
+#define HDB_F_DECRYPT  1 /* decrypt keys */
+#define HDB_F_REPLACE  2 /* replace entry */
+
+/* key usage for master key */
+#define HDB_KU_MKEY    0x484442
+
+enum hdb_ent_type{ HDB_ENT_TYPE_CLIENT, HDB_ENT_TYPE_SERVER, HDB_ENT_TYPE_ANY };
+
+typedef struct hdb_master_key_data *hdb_master_key;
+
+typedef struct HDB{
+    void *hdb_db;
+    void *hdb_dbc;
+    char *hdb_name;
+    int hdb_master_key_set;
+    hdb_master_key hdb_master_key;
+    void *hdb_openp;
+
+    krb5_error_code (*hdb_open)(krb5_context, struct HDB*, int, mode_t);
+    krb5_error_code (*hdb_close)(krb5_context, struct HDB*);
+    krb5_error_code (*hdb_fetch)(krb5_context,struct HDB*,unsigned hdb_flags, krb5_const_principal principal,
+                                enum hdb_ent_type ent_type, hdb_entry*);
+    krb5_error_code (*hdb_store)(krb5_context,struct HDB*,unsigned,hdb_entry*);
+    krb5_error_code (*hdb_remove)(krb5_context, struct HDB*, hdb_entry*);
+    krb5_error_code (*hdb_firstkey)(krb5_context, struct HDB*, 
+                               unsigned, hdb_entry*);
+    krb5_error_code (*hdb_nextkey)(krb5_context, struct HDB*, 
+                              unsigned, hdb_entry*);
+    krb5_error_code (*hdb_lock)(krb5_context, struct HDB*, int operation);
+    krb5_error_code (*hdb_unlock)(krb5_context, struct HDB*);
+    krb5_error_code (*hdb_rename)(krb5_context, struct HDB*, const char*);
+    krb5_error_code (*hdb__get)(krb5_context,struct HDB*,krb5_data,krb5_data*);
+    krb5_error_code (*hdb__put)(krb5_context, struct HDB*, int, 
+                           krb5_data, krb5_data);
+    krb5_error_code (*hdb__del)(krb5_context, struct HDB*, krb5_data);
+    krb5_error_code (*hdb_destroy)(krb5_context, struct HDB*);
+}HDB;
+
+#define HDB_INTERFACE_VERSION  1
+
+struct hdb_so_method {
+    int version;
+    const char *prefix;
+    krb5_error_code (*create)(krb5_context, HDB **, const char *filename);
+};
+
+#define HDB_DB_DIR "/var/heimdal"
+#define HDB_DEFAULT_DB HDB_DB_DIR "/heimdal"
+#define HDB_DB_FORMAT_ENTRY "hdb/db-format"
+
+typedef krb5_error_code (*hdb_foreach_func_t)(krb5_context, HDB*,
+                                             hdb_entry*, void*);
+extern krb5_kt_ops hdb_kt_ops;
+
+#include <hdb-protos.h>
+
+#endif /* __HDB_H__ */
diff --git a/source4/heimdal/lib/hdb/hdb_err.et b/source4/heimdal/lib/hdb/hdb_err.et
new file mode 100644 (file)
index 0000000..9929a56
--- /dev/null
@@ -0,0 +1,27 @@
+#
+# Error messages for the hdb library
+#
+# This might look like a com_err file, but is not
+#
+id "$Id: hdb_err.et,v 1.5 2001/01/28 23:05:52 assar Exp $"
+
+error_table hdb
+
+prefix HDB_ERR
+
+index 1
+#error_code INUSE,             "Entry already exists in database"
+error_code UK_SERROR,          "Database store error"
+error_code UK_RERROR,          "Database read error"
+error_code NOENTRY,            "No such entry in the database"
+error_code DB_INUSE,           "Database is locked or in use--try again later"
+error_code DB_CHANGED,         "Database was modified during read"
+error_code RECURSIVELOCK,      "Attempt to lock database twice"
+error_code NOTLOCKED,          "Attempt to unlock database when not locked"
+error_code BADLOCKMODE,                "Invalid kdb lock mode"
+error_code CANT_LOCK_DB,       "Insufficient access to lock database"
+error_code EXISTS,             "Entry already exists in database"
+error_code BADVERSION,         "Wrong database version"
+error_code NO_MKEY,            "No correct master key"
+
+end
diff --git a/source4/heimdal/lib/hdb/hdb_locl.h b/source4/heimdal/lib/hdb/hdb_locl.h
new file mode 100644 (file)
index 0000000..0d07164
--- /dev/null
@@ -0,0 +1,67 @@
+/*
+ * 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. 
+ */
+
+/* $Id: hdb_locl.h,v 1.19 2003/09/10 21:54:58 lha Exp $ */
+
+#ifndef __HDB_LOCL_H__
+#define __HDB_LOCL_H__
+
+#include <config.h>
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <errno.h>
+#ifdef HAVE_SYS_TYPES_H
+#include <sys/types.h>
+#endif
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+#ifdef HAVE_FCNTL_H
+#include <fcntl.h>
+#endif
+#ifdef HAVE_SYS_FILE_H
+#include <sys/file.h>
+#endif
+#ifdef HAVE_LIMITS_H
+#include <limits.h>
+#endif
+#include <roken.h>
+
+#include "crypto-headers.h"
+#include <krb5.h>
+#include <hdb.h>
+#include <hdb-private.h>
+
+#endif /* __HDB_LOCL_H__ */
diff --git a/source4/heimdal/lib/hdb/keys.c b/source4/heimdal/lib/hdb/keys.c
new file mode 100644 (file)
index 0000000..c5a2efd
--- /dev/null
@@ -0,0 +1,393 @@
+/*
+ * Copyright (c) 1997 - 2001, 2003 - 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 "hdb_locl.h"
+
+RCSID("$Id: keys.c,v 1.3 2005/03/17 00:42:05 lha Exp $");
+
+/*
+ * free all the memory used by (len, keys)
+ */
+
+void
+hdb_free_keys (krb5_context context, int len, Key *keys)
+{
+    int i;
+
+    for (i = 0; i < len; i++) {
+       free(keys[i].mkvno);
+       keys[i].mkvno = NULL;
+       if (keys[i].salt != NULL) {
+           free_Salt(keys[i].salt);
+           free(keys[i].salt);
+           keys[i].salt = NULL;
+       }
+       krb5_free_keyblock_contents(context, &keys[i].key);
+    }
+    free (keys);
+}
+
+/* 
+ * for each entry in `default_keys' try to parse it as a sequence
+ * of etype:salttype:salt, syntax of this if something like:
+ * [(des|des3|etype):](pw-salt|afs3)[:string], if etype is omitted it
+ *      means all etypes, and if string is omitted is means the default
+ * string (for that principal). Additional special values:
+ *     v5 == pw-salt, and
+ *     v4 == des:pw-salt:
+ *     afs or afs3 == des:afs3-salt
+ */
+
+/* the 3 DES types must be first */
+static const krb5_enctype all_etypes[] = { 
+    ETYPE_DES_CBC_MD5,
+    ETYPE_DES_CBC_MD4,
+    ETYPE_DES_CBC_CRC,
+    ETYPE_AES256_CTS_HMAC_SHA1_96,
+    ETYPE_ARCFOUR_HMAC_MD5,
+    ETYPE_DES3_CBC_SHA1
+};
+
+static krb5_error_code
+parse_key_set(krb5_context context, const char *key, 
+             krb5_enctype **ret_enctypes, size_t *ret_num_enctypes, 
+             krb5_salt *salt, krb5_principal principal)
+{
+    const char *p;
+    char buf[3][256];
+    int num_buf = 0;
+    int i, num_enctypes = 0;
+    krb5_enctype e;
+    const krb5_enctype *enctypes = NULL;
+    krb5_error_code ret;
+    
+    p = key;
+
+    *ret_enctypes = NULL;
+    *ret_num_enctypes = 0;
+
+    /* split p in a list of :-separated strings */
+    for(num_buf = 0; num_buf < 3; num_buf++)
+       if(strsep_copy(&p, ":", buf[num_buf], sizeof(buf[num_buf])) == -1)
+           break;
+
+    salt->saltvalue.data = NULL;
+    salt->saltvalue.length = 0;
+
+    for(i = 0; i < num_buf; i++) {
+       if(enctypes == NULL) {
+           /* this might be a etype specifier */
+           /* XXX there should be a string_to_etypes handling
+              special cases like `des' and `all' */
+           if(strcmp(buf[i], "des") == 0) {
+               enctypes = all_etypes;
+               num_enctypes = 3;
+               continue;
+           } else if(strcmp(buf[i], "des3") == 0) {
+               e = ETYPE_DES3_CBC_SHA1;
+               enctypes = &e;
+               num_enctypes = 1;
+               continue;
+           } else {
+               ret = krb5_string_to_enctype(context, buf[i], &e);
+               if (ret == 0) {
+                   enctypes = &e;
+                   num_enctypes = 1;
+                   continue;
+               }
+           }
+       }
+
+       if(salt->salttype == 0) {
+           /* interpret string as a salt specifier, if no etype
+              is set, this sets default values */
+           /* XXX should perhaps use string_to_salttype, but that
+              interface sucks */
+           if(strcmp(buf[i], "pw-salt") == 0) {
+               if(enctypes == NULL) {
+                   enctypes = all_etypes;
+                   num_enctypes = sizeof(all_etypes)/sizeof(all_etypes[0]);
+               }
+               salt->salttype = KRB5_PW_SALT;
+           } else if(strcmp(buf[i], "afs3-salt") == 0) {
+               if(enctypes == NULL) {
+                   enctypes = all_etypes;
+                   num_enctypes = 3;
+               }
+               salt->salttype = KRB5_AFS3_SALT;
+           }
+       } else {
+           /* if there is a final string, use it as the string to
+              salt with, this is mostly useful with null salt for
+              v4 compat, and a cell name for afs compat */
+           salt->saltvalue.data = strdup(buf[i]);
+           if (salt->saltvalue.data == NULL) {
+               krb5_set_error_string(context, "malloc out of memory");
+               return ENOMEM;
+           }
+           salt->saltvalue.length = strlen(buf[i]);
+       }
+    }
+    
+    if(enctypes == NULL || salt->salttype == 0) {
+       krb5_set_error_string(context, "bad value for default_keys `%s'", key);
+       return EINVAL;
+    }
+    
+    /* if no salt was specified make up default salt */
+    if(salt->saltvalue.data == NULL) {
+       if(salt->salttype == KRB5_PW_SALT)
+           ret = krb5_get_pw_salt(context, principal, salt);
+       else if(salt->salttype == KRB5_AFS3_SALT) {
+           krb5_realm *realm = krb5_princ_realm(context, principal);
+           salt->saltvalue.data = strdup(*realm);
+           if(salt->saltvalue.data == NULL) {
+               krb5_set_error_string(context, "out of memory while "
+                                     "parsing salt specifiers");
+               return ENOMEM;
+           }
+           strlwr(salt->saltvalue.data);
+           salt->saltvalue.length = strlen(*realm);
+       }
+    }
+
+    *ret_enctypes = malloc(sizeof(enctypes[0]) * num_enctypes);
+    if (*ret_enctypes == NULL) {
+       krb5_free_salt(context, *salt);
+       krb5_set_error_string(context, "out of memory");
+       return ENOMEM;
+    }
+    memcpy(*ret_enctypes, enctypes, sizeof(enctypes[0]) * num_enctypes);
+    *ret_num_enctypes = num_enctypes;
+
+    return 0;
+}
+
+static krb5_error_code
+add_enctype_to_key_set(Key **key_set, size_t *nkeyset, 
+                      krb5_enctype enctype, krb5_salt *salt)
+{
+    krb5_error_code ret;
+    Key key, *tmp;
+
+    memset(&key, 0, sizeof(key));
+
+    tmp = realloc(*key_set, (*nkeyset + 1) * sizeof((*key_set)[0]));
+    if (tmp == NULL)
+       return ENOMEM;
+    
+    *key_set = tmp;
+
+    key.key.keytype = enctype;
+    key.key.keyvalue.length = 0;
+    key.key.keyvalue.data = NULL;
+    
+    if (salt) {
+       key.salt = malloc(sizeof(*key.salt));
+       if (key.salt == NULL) {
+           free_Key(&key);
+           return ENOMEM;
+       }
+       
+       key.salt->type = salt->salttype;
+       krb5_data_zero (&key.salt->salt);
+       
+       ret = krb5_data_copy(&key.salt->salt, 
+                            salt->saltvalue.data, 
+                            salt->saltvalue.length);
+       if (ret) {
+           free_Key(&key);
+           return ret;
+       }
+    } else
+       key.salt = NULL;
+    
+    (*key_set)[*nkeyset] = key;
+    
+    *nkeyset += 1;
+
+    return 0;
+}
+
+
+/*
+ * Generate the `key_set' from the [kadmin]default_keys statement. If
+ * `no_salt' is set, salt is not important (and will not be set) since
+ * its random keys that is going to be created.
+ */
+
+krb5_error_code
+hdb_generate_key_set(krb5_context context, krb5_principal principal,
+                    Key **ret_key_set, size_t *nkeyset, int no_salt)
+{
+    char **ktypes, **kp;
+    krb5_error_code ret;
+    Key *k, *key_set;
+    int i, j;
+    char *default_keytypes[] = {
+       "des:pw-salt",
+       "aes256-cts-hmac-sha1-96:pw-salt",
+       "des3-cbc-sha1:pw-salt",
+       "arcfour-hmac-md5:pw-salt",
+       NULL
+    };
+    
+    ktypes = krb5_config_get_strings(context, NULL, "kadmin",
+                                    "default_keys", NULL);
+    if (ktypes == NULL)
+       ktypes = default_keytypes;
+
+    if (ktypes == NULL)
+       abort();
+
+    *ret_key_set = key_set = NULL;
+    *nkeyset = 0;
+
+    ret = 0;
+    for(kp = ktypes; kp && *kp; kp++) {
+       const char *p;
+       krb5_salt salt;
+       krb5_enctype *enctypes;
+       size_t num_enctypes;
+
+       p = *kp;
+       /* check alias */
+       if(strcmp(p, "v5") == 0)
+           p = "pw-salt";
+       else if(strcmp(p, "v4") == 0)
+           p = "des:pw-salt:";
+       else if(strcmp(p, "afs") == 0 || strcmp(p, "afs3") == 0)
+           p = "des:afs3-salt";
+       else if (strcmp(p, "arcfour-hmac-md5") == 0)
+           p = "arcfour-hmac-md5:pw-salt";
+           
+       memset(&salt, 0, sizeof(salt));
+
+       ret = parse_key_set(context, p,
+                           &enctypes, &num_enctypes, &salt, principal);
+       if (ret) {
+           krb5_warnx(context, "bad value for default_keys `%s'", *kp);
+           continue;
+       }
+
+       for (i = 0; i < num_enctypes; i++) {
+           /* find duplicates */
+           for (j = 0; j < *nkeyset; j++) {
+
+               k = &key_set[j];
+
+               if (k->key.keytype == enctypes[i]) {
+                   if (no_salt)
+                       break;
+                   if (k->salt == NULL && salt.salttype == KRB5_PW_SALT)
+                       break;
+                   if (k->salt->type == salt.salttype &&
+                       k->salt->salt.length == salt.saltvalue.length &&
+                       memcmp(k->salt->salt.data, salt.saltvalue.data, 
+                              salt.saltvalue.length) == 0)
+                       break;
+               }
+           }
+           /* not a duplicate, lets add it */
+           if (j == *nkeyset) {
+               ret = add_enctype_to_key_set(&key_set, nkeyset, enctypes[i], 
+                                            no_salt ? NULL : &salt);
+               if (ret) {
+                   free(enctypes);
+                   krb5_free_salt(context, salt);
+                   goto out;
+               }
+           }
+       }
+       free(enctypes);
+       krb5_free_salt(context, salt);
+    }
+    
+ out:
+    if (ret) {
+       krb5_warn(context, ret, 
+                 "failed to parse the [kadmin]default_keys values");
+
+       for (i = 0; i < *nkeyset; i++)
+           free_Key(&key_set[i]);
+       free(key_set);
+    } else if (*nkeyset == 0) {
+       krb5_warnx(context, 
+                  "failed to parse any of the [kadmin]default_keys values");
+       ret = EINVAL; /* XXX */
+    }
+
+    *ret_key_set = key_set;
+
+    return ret;
+}
+
+
+krb5_error_code
+hdb_generate_key_set_password(krb5_context context, 
+                             krb5_principal principal, 
+                             const char *password, 
+                             Key **keys, size_t *num_keys) 
+{
+    krb5_error_code ret;
+    int i;
+
+    ret = hdb_generate_key_set(context, principal,
+                               keys, num_keys, 0);
+    if (ret)
+       return ret;
+
+    for (i = 0; i < (*num_keys); i++) {
+       krb5_salt salt;
+
+       salt.salttype = (*keys)[i].salt->type;
+       salt.saltvalue.length = (*keys)[i].salt->salt.length;
+       salt.saltvalue.data = (*keys)[i].salt->salt.data;
+
+       ret = krb5_string_to_key_salt (context,
+                                      (*keys)[i].key.keytype,
+                                      password,
+                                      salt,
+                                      &(*keys)[i].key);
+
+       if(ret)
+           break;
+    }
+
+    if(ret) {
+       hdb_free_keys (context, *num_keys, *keys);
+       return ret;
+    }
+    return ret;
+}
diff --git a/source4/heimdal/lib/hdb/ndbm.c b/source4/heimdal/lib/hdb/ndbm.c
new file mode 100644 (file)
index 0000000..588ff80
--- /dev/null
@@ -0,0 +1,369 @@
+/*
+ * 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 "hdb_locl.h"
+
+RCSID("$Id: ndbm.c,v 1.35 2005/06/23 13:37:57 lha Exp $");
+
+#if HAVE_NDBM
+
+#if defined(HAVE_GDBM_NDBM_H)
+#include <gdbm/ndbm.h>
+#elif defined(HAVE_NDBM_H)
+#include <ndbm.h>
+#elif defined(HAVE_DBM_H)
+#include <dbm.h>
+#endif
+
+struct ndbm_db {
+    DBM *db;
+    int lock_fd;
+};
+
+static krb5_error_code
+NDBM_destroy(krb5_context context, HDB *db)
+{
+    krb5_error_code ret;
+
+    ret = hdb_clear_master_key (context, db);
+    free(db->hdb_name);
+    free(db);
+    return 0;
+}
+
+static krb5_error_code
+NDBM_lock(krb5_context context, HDB *db, int operation)
+{
+    struct ndbm_db *d = db->hdb_db;
+    return hdb_lock(d->lock_fd, operation);
+}
+
+static krb5_error_code
+NDBM_unlock(krb5_context context, HDB *db)
+{
+    struct ndbm_db *d = db->hdb_db;
+    return hdb_unlock(d->lock_fd);
+}
+
+static krb5_error_code
+NDBM_seq(krb5_context context, HDB *db, 
+        unsigned flags, hdb_entry *entry, int first)
+
+{
+    struct ndbm_db *d = (struct ndbm_db *)db->hdb_db;
+    datum key, value;
+    krb5_data key_data, data;
+    krb5_error_code ret = 0;
+
+    if(first)
+       key = dbm_firstkey(d->db);
+    else
+       key = dbm_nextkey(d->db);
+    if(key.dptr == NULL)
+       return HDB_ERR_NOENTRY;
+    key_data.data = key.dptr;
+    key_data.length = key.dsize;
+    ret = db->hdb_lock(context, db, HDB_RLOCK);
+    if(ret) return ret;
+    value = dbm_fetch(d->db, key);
+    db->hdb_unlock(context, db);
+    data.data = value.dptr;
+    data.length = value.dsize;
+    if(hdb_value2entry(context, &data, entry))
+       return NDBM_seq(context, db, flags, entry, 0);
+    if (db->hdb_master_key_set && (flags & HDB_F_DECRYPT)) {
+       ret = hdb_unseal_keys (context, db, entry);
+       if (ret)
+           hdb_free_entry (context, entry);
+    }
+    if (entry->principal == NULL) {
+       entry->principal = malloc (sizeof(*entry->principal));
+       if (entry->principal == NULL) {
+           ret = ENOMEM;
+           hdb_free_entry (context, entry);
+           krb5_set_error_string(context, "malloc: out of memory");
+       } else {
+           hdb_key2principal (context, &key_data, entry->principal);
+       }
+    }
+    return ret;
+}
+
+
+static krb5_error_code
+NDBM_firstkey(krb5_context context, HDB *db, unsigned flags, hdb_entry *entry)
+{
+    return NDBM_seq(context, db, flags, entry, 1);
+}
+
+
+static krb5_error_code
+NDBM_nextkey(krb5_context context, HDB *db, unsigned flags, hdb_entry *entry)
+{
+    return NDBM_seq(context, db, flags, entry, 0);
+}
+
+static krb5_error_code
+NDBM_rename(krb5_context context, HDB *db, const char *new_name)
+{
+    /* XXX this function will break */
+    struct ndbm_db *d = db->hdb_db;
+
+    int ret;
+    char *old_dir, *old_pag, *new_dir, *new_pag;
+    char *new_lock;
+    int lock_fd;
+
+    /* lock old and new databases */
+    ret = db->hdb_lock(context, db, HDB_WLOCK);
+    if(ret)
+       return ret;
+    asprintf(&new_lock, "%s.lock", new_name);
+    if(new_lock == NULL) {
+       db->hdb_unlock(context, db);
+       krb5_set_error_string(context, "malloc: out of memory");
+       return ENOMEM;
+    }
+    lock_fd = open(new_lock, O_RDWR | O_CREAT, 0600);
+    if(lock_fd < 0) {
+       ret = errno;
+       db->hdb_unlock(context, db);
+       krb5_set_error_string(context, "open(%s): %s", new_lock,
+                             strerror(ret));
+       free(new_lock);
+       return ret;
+    }
+    free(new_lock);
+    ret = hdb_lock(lock_fd, HDB_WLOCK);
+    if(ret) {
+       db->hdb_unlock(context, db);
+       close(lock_fd);
+       return ret;
+    }
+
+    asprintf(&old_dir, "%s.dir", db->hdb_name);
+    asprintf(&old_pag, "%s.pag", db->hdb_name);
+    asprintf(&new_dir, "%s.dir", new_name);
+    asprintf(&new_pag, "%s.pag", new_name);
+
+    ret = rename(old_dir, new_dir) || rename(old_pag, new_pag);
+    free(old_dir);
+    free(old_pag);
+    free(new_dir);
+    free(new_pag);
+    hdb_unlock(lock_fd);
+    db->hdb_unlock(context, db);
+
+    if(ret) {
+       ret = errno;
+       close(lock_fd);
+       krb5_set_error_string(context, "rename: %s", strerror(ret));
+       return ret;
+    }
+
+    close(d->lock_fd);
+    d->lock_fd = lock_fd;
+    
+    free(db->hdb_name);
+    db->hdb_name = strdup(new_name);
+    return 0;
+}
+
+static krb5_error_code
+NDBM__get(krb5_context context, HDB *db, krb5_data key, krb5_data *reply)
+{
+    struct ndbm_db *d = (struct ndbm_db *)db->hdb_db;
+    datum k, v;
+    int code;
+
+    k.dptr  = key.data;
+    k.dsize = key.length;
+    code = db->hdb_lock(context, db, HDB_RLOCK);
+    if(code)
+       return code;
+    v = dbm_fetch(d->db, k);
+    db->hdb_unlock(context, db);
+    if(v.dptr == NULL)
+       return HDB_ERR_NOENTRY;
+
+    krb5_data_copy(reply, v.dptr, v.dsize);
+    return 0;
+}
+
+static krb5_error_code
+NDBM__put(krb5_context context, HDB *db, int replace, 
+       krb5_data key, krb5_data value)
+{
+    struct ndbm_db *d = (struct ndbm_db *)db->hdb_db;
+    datum k, v;
+    int code;
+
+    k.dptr  = key.data;
+    k.dsize = key.length;
+    v.dptr  = value.data;
+    v.dsize = value.length;
+
+    code = db->hdb_lock(context, db, HDB_WLOCK);
+    if(code)
+       return code;
+    code = dbm_store(d->db, k, v, replace ? DBM_REPLACE : DBM_INSERT);
+    db->hdb_unlock(context, db);
+    if(code == 1)
+       return HDB_ERR_EXISTS;
+    if (code < 0)
+       return code;
+    return 0;
+}
+
+static krb5_error_code
+NDBM__del(krb5_context context, HDB *db, krb5_data key)
+{
+    struct ndbm_db *d = (struct ndbm_db *)db->hdb_db;
+    datum k;
+    int code;
+    krb5_error_code ret;
+
+    k.dptr = key.data;
+    k.dsize = key.length;
+    ret = db->hdb_lock(context, db, HDB_WLOCK);
+    if(ret) return ret;
+    code = dbm_delete(d->db, k);
+    db->hdb_unlock(context, db);
+    if(code < 0)
+       return errno;
+    return 0;
+}
+
+
+static krb5_error_code
+NDBM_close(krb5_context context, HDB *db)
+{
+    struct ndbm_db *d = db->hdb_db;
+    dbm_close(d->db);
+    close(d->lock_fd);
+    free(d);
+    return 0;
+}
+
+static krb5_error_code
+NDBM_open(krb5_context context, HDB *db, int flags, mode_t mode)
+{
+    krb5_error_code ret;
+    struct ndbm_db *d = malloc(sizeof(*d));
+    char *lock_file;
+
+    if(d == NULL) {
+       krb5_set_error_string(context, "malloc: out of memory");
+       return ENOMEM;
+    }
+    asprintf(&lock_file, "%s.lock", (char*)db->hdb_name);
+    if(lock_file == NULL) {
+       free(d);
+       krb5_set_error_string(context, "malloc: out of memory");
+       return ENOMEM;
+    }
+    d->db = dbm_open((char*)db->hdb_name, flags, mode);
+    if(d->db == NULL){
+       ret = errno;
+       free(d);
+       free(lock_file);
+       krb5_set_error_string(context, "dbm_open(%s): %s", db->hdb_name,
+                             strerror(ret));
+       return ret;
+    }
+    d->lock_fd = open(lock_file, O_RDWR | O_CREAT, 0600);
+    if(d->lock_fd < 0){
+       ret = errno;
+       dbm_close(d->db);
+       free(d);
+       krb5_set_error_string(context, "open(%s): %s", lock_file,
+                             strerror(ret));
+       free(lock_file);
+       return ret;
+    }
+    free(lock_file);
+    db->hdb_db = d;
+    if((flags & O_ACCMODE) == O_RDONLY)
+       ret = hdb_check_db_format(context, db);
+    else
+       ret = hdb_init_db(context, db);
+    if(ret == HDB_ERR_NOENTRY)
+       return 0;
+    if (ret) {
+       NDBM_close(context, db);
+       krb5_set_error_string(context, "hdb_open: failed %s database %s",
+                             (flags & O_ACCMODE) == O_RDONLY ? 
+                             "checking format of" : "initialize", 
+                             db->hdb_name);
+    }
+    return ret;
+}
+
+krb5_error_code
+hdb_ndbm_create(krb5_context context, HDB **db, 
+               const char *filename)
+{
+    *db = malloc(sizeof(**db));
+    if (*db == NULL) {
+       krb5_set_error_string(context, "malloc: out of memory");
+       return ENOMEM;
+    }
+
+    (*db)->hdb_db = NULL;
+    (*db)->hdb_name = strdup(filename);
+    if ((*db)->hdb_name == NULL) {
+       krb5_set_error_string(context, "malloc: out of memory");
+       free(*db);
+       *db = NULL;
+       return ENOMEM;
+    }
+    (*db)->hdb_master_key_set = 0;
+    (*db)->hdb_openp = 0;
+    (*db)->hdb_open = NDBM_open;
+    (*db)->hdb_close = NDBM_close;
+    (*db)->hdb_fetch = _hdb_fetch;
+    (*db)->hdb_store = _hdb_store;
+    (*db)->hdb_remove = _hdb_remove;
+    (*db)->hdb_firstkey = NDBM_firstkey;
+    (*db)->hdb_nextkey= NDBM_nextkey;
+    (*db)->hdb_lock = NDBM_lock;
+    (*db)->hdb_unlock = NDBM_unlock;
+    (*db)->hdb_rename = NDBM_rename;
+    (*db)->hdb__get = NDBM__get;
+    (*db)->hdb__put = NDBM__put;
+    (*db)->hdb__del = NDBM__del;
+    (*db)->hdb_destroy = NDBM_destroy;
+    return 0;
+}
+
+#endif /* HAVE_NDBM */
diff --git a/source4/heimdal/lib/krb5/acache.c b/source4/heimdal/lib/krb5/acache.c
new file mode 100644 (file)
index 0000000..75f5315
--- /dev/null
@@ -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 (file)
index 0000000..3b9773b
--- /dev/null
@@ -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 (file)
index 0000000..ccc97f4
--- /dev/null
@@ -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 (file)
index 0000000..03fa933
--- /dev/null
@@ -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 (file)
index 0000000..01b5d3e
--- /dev/null
@@ -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 (file)
index 0000000..b8ce65d
--- /dev/null
@@ -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 (file)
index 0000000..e11744c
--- /dev/null
@@ -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 (file)
index 0000000..1c38721
--- /dev/null
@@ -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 (file)
index 0000000..f293a96
--- /dev/null
@@ -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 (file)
index 0000000..e6ef1d9
--- /dev/null
@@ -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 (file)
index 0000000..080e8a6
--- /dev/null
@@ -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 (file)
index 0000000..86e286c
--- /dev/null
@@ -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 (file)
index 0000000..6e72509
--- /dev/null
@@ -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 (file)
index 0000000..89ebc34
--- /dev/null
@@ -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 (file)
index 0000000..62fb92d
--- /dev/null
@@ -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 (file)
index 0000000..eb77fba
--- /dev/null
@@ -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 (file)
index 0000000..c7cedd8
--- /dev/null
@@ -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 (file)
index 0000000..2afd072
--- /dev/null
@@ -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 (file)
index 0000000..2b1ac3a
--- /dev/null
@@ -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 (file)
index 0000000..9cf1410
--- /dev/null
@@ -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 (file)
index 0000000..f0d1f51
--- /dev/null
@@ -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 (file)
index 0000000..649bdd2
--- /dev/null
@@ -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 (file)
index 0000000..8488119
--- /dev/null
@@ -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 (file)
index 0000000..03848ab
--- /dev/null
@@ -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 (file)
index 0000000..84aa6f8
--- /dev/null
@@ -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 (file)
index 0000000..27afcdb
--- /dev/null
@@ -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 (file)
index 0000000..f9e9cde
--- /dev/null
@@ -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 (file)
index 0000000..df4828d
--- /dev/null
@@ -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 (file)
index 0000000..034516d
--- /dev/null
@@ -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 (file)
index 0000000..63fb556
--- /dev/null
@@ -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 (file)
index 0000000..03e8f0a
--- /dev/null
@@ -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 (file)
index 0000000..bb72daf
--- /dev/null
@@ -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 (file)
index 0000000..ea0bc4a
--- /dev/null
@@ -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 (file)
index 0000000..d9c5bd5
--- /dev/null
@@ -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 (file)
index 0000000..24d6c29
--- /dev/null
@@ -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 (file)
index 0000000..69da6c5
--- /dev/null
@@ -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 (file)
index 0000000..ba76466
--- /dev/null
@@ -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 (file)
index 0000000..3c4f06e
--- /dev/null
@@ -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 (executable)
index 0000000..3ebe66b
--- /dev/null
@@ -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 (file)
index 0000000..95c980d
--- /dev/null
@@ -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 (file)
index 0000000..8b3975f
--- /dev/null
@@ -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 (file)
index 0000000..2dc60f4
--- /dev/null
@@ -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 (file)
index 0000000..b7873f3
--- /dev/null
@@ -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 (file)
index 0000000..314d979
--- /dev/null
@@ -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 (file)
index 0000000..a405664
--- /dev/null
@@ -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 (file)
index 0000000..667788c
--- /dev/null
@@ -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 (file)
index 0000000..dca09ff
--- /dev/null
@@ -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 (file)
index 0000000..b53fa36
--- /dev/null
@@ -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 (file)
index 0000000..1a83fac
--- /dev/null
@@ -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 (file)
index 0000000..3dca515
--- /dev/null
@@ -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 (file)
index 0000000..e59cab8
--- /dev/null
@@ -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 (file)
index 0000000..cee8a02
--- /dev/null
@@ -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 (file)
index 0000000..1d092dc
--- /dev/null
@@ -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 (file)
index 0000000..890a500
--- /dev/null
@@ -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 (file)
index 0000000..00c30d7
--- /dev/null
@@ -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 (file)
index 0000000..1257b07
--- /dev/null
@@ -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 (file)
index 0000000..a64ccc5
--- /dev/null
@@ -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 (file)
index 0000000..49eee08
--- /dev/null
@@ -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 (file)
index 0000000..4f6381c
--- /dev/null
@@ -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 (file)
index 0000000..0a65d53
--- /dev/null
@@ -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 (file)
index 0000000..baf63f6
--- /dev/null
@@ -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 (executable)
index 0000000..b7f06c1
--- /dev/null
@@ -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 (file)
index 0000000..7a8b1ba
--- /dev/null
@@ -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 (file)
index 0000000..56112ee
--- /dev/null
@@ -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 (file)
index 0000000..90823f9
--- /dev/null
@@ -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 (file)
index 0000000..adc077e
--- /dev/null
@@ -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 (file)
index 0000000..ab83d91
--- /dev/null
@@ -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 (file)
index 0000000..691e95e
--- /dev/null
@@ -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 (file)
index 0000000..d5c3f42
--- /dev/null
@@ -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 (executable)
index 0000000..84db4fe
--- /dev/null
@@ -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 (file)
index 0000000..b7194b4
--- /dev/null
@@ -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 (file)
index 0000000..9129ece
--- /dev/null
@@ -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 (file)
index 0000000..93e70c4
--- /dev/null
@@ -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 (file)
index 0000000..bafd23e
--- /dev/null
@@ -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 (file)
index 0000000..a92eea5
--- /dev/null
@@ -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 (file)
index 0000000..30ad08b
--- /dev/null
@@ -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 (file)
index 0000000..ec99f86
--- /dev/null
@@ -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 (file)
index 0000000..d55f8dc
--- /dev/null
@@ -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 (file)
index 0000000..9658833
--- /dev/null
@@ -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 (file)
index 0000000..42e695a
--- /dev/null
@@ -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 (file)
index 0000000..4266776
--- /dev/null
@@ -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 (file)
index 0000000..b9f9372
--- /dev/null
@@ -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 (file)
index 0000000..46043a6
--- /dev/null
@@ -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 (file)
index 0000000..decf74a
--- /dev/null
@@ -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 (file)
index 0000000..734cd4d
--- /dev/null
@@ -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 (file)
index 0000000..4a120ab
--- /dev/null
@@ -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 (file)
index 0000000..9e24db0
--- /dev/null
@@ -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 (file)
index 0000000..c66b06c
--- /dev/null
@@ -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 (file)
index 0000000..5f0fd66
--- /dev/null
@@ -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 (file)
index 0000000..f982591
--- /dev/null
@@ -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;
+}
diff --git a/source4/heimdal/lib/roken/base64.c b/source4/heimdal/lib/roken/base64.c
new file mode 100644 (file)
index 0000000..78dbe9c
--- /dev/null
@@ -0,0 +1,136 @@
+/*
+ * Copyright (c) 1995-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.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+RCSID("$Id: base64.c,v 1.6 2005/04/12 11:28:34 lha Exp $");
+#endif
+#include <stdlib.h>
+#include <string.h>
+#include "base64.h"
+
+static const char base64_chars[] = 
+    "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
+
+static int 
+pos(char c)
+{
+    const char *p;
+    for (p = base64_chars; *p; p++)
+       if (*p == c)
+           return p - base64_chars;
+    return -1;
+}
+
+int ROKEN_LIB_FUNCTION
+base64_encode(const void *data, int size, char **str)
+{
+    char *s, *p;
+    int i;
+    int c;
+    const unsigned char *q;
+
+    p = s = (char *) malloc(size * 4 / 3 + 4);
+    if (p == NULL)
+       return -1;
+    q = (const unsigned char *) data;
+    i = 0;
+    for (i = 0; i < size;) {
+       c = q[i++];
+       c *= 256;
+       if (i < size)
+           c += q[i];
+       i++;
+       c *= 256;
+       if (i < size)
+           c += q[i];
+       i++;
+       p[0] = base64_chars[(c & 0x00fc0000) >> 18];
+       p[1] = base64_chars[(c & 0x0003f000) >> 12];
+       p[2] = base64_chars[(c & 0x00000fc0) >> 6];
+       p[3] = base64_chars[(c & 0x0000003f) >> 0];
+       if (i > size)
+           p[3] = '=';
+       if (i > size + 1)
+           p[2] = '=';
+       p += 4;
+    }
+    *p = 0;
+    *str = s;
+    return strlen(s);
+}
+
+#define DECODE_ERROR 0xffffffff
+
+static unsigned int
+token_decode(const char *token)
+{
+    int i;
+    unsigned int val = 0;
+    int marker = 0;
+    if (strlen(token) < 4)
+       return DECODE_ERROR;
+    for (i = 0; i < 4; i++) {
+       val *= 64;
+       if (token[i] == '=')
+           marker++;
+       else if (marker > 0)
+           return DECODE_ERROR;
+       else
+           val += pos(token[i]);
+    }
+    if (marker > 2)
+       return DECODE_ERROR;
+    return (marker << 24) | val;
+}
+
+int ROKEN_LIB_FUNCTION
+base64_decode(const char *str, void *data)
+{
+    const char *p;
+    unsigned char *q;
+
+    q = data;
+    for (p = str; *p && (*p == '=' || strchr(base64_chars, *p)); p += 4) {
+       unsigned int val = token_decode(p);
+       unsigned int marker = (val >> 24) & 0xff;
+       if (val == DECODE_ERROR)
+           return -1;
+       *q++ = (val >> 16) & 0xff;
+       if (marker < 2)
+           *q++ = (val >> 8) & 0xff;
+       if (marker < 1)
+           *q++ = val & 0xff;
+    }
+    return q - (unsigned char *) data;
+}
diff --git a/source4/heimdal/lib/roken/base64.h b/source4/heimdal/lib/roken/base64.h
new file mode 100644 (file)
index 0000000..95992f9
--- /dev/null
@@ -0,0 +1,53 @@
+/*
+ * Copyright (c) 1995, 1996, 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.
+ */
+
+/* $Id: base64.h,v 1.4 2005/06/30 07:13:33 lha Exp $ */
+
+#ifndef _BASE64_H_
+#define _BASE64_H_
+
+#ifndef ROKEN_LIB_FUNCTION
+#ifdef _WIN32
+#define ROKEN_LIB_FUNCTION _stdcall
+#else
+#define ROKEN_LIB_FUNCTION
+#endif
+#endif
+
+int ROKEN_LIB_FUNCTION
+base64_encode(const void *, int, char **);
+
+int ROKEN_LIB_FUNCTION
+base64_decode(const char *, void *);
+
+#endif
diff --git a/source4/heimdal/lib/roken/bswap.c b/source4/heimdal/lib/roken/bswap.c
new file mode 100644 (file)
index 0000000..48b587d
--- /dev/null
@@ -0,0 +1,61 @@
+/*
+ * 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.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+#include "roken.h"
+
+RCSID("$Id: bswap.c,v 1.4 2005/04/12 11:28:35 lha Exp $");
+
+#ifndef HAVE_BSWAP32
+
+unsigned int ROKEN_LIB_FUNCTION
+bswap32 (unsigned int val)
+{
+    return (val & 0xff) << 24 |
+       (val & 0xff00) << 8 |
+       (val & 0xff0000) >> 8 |
+       (val & 0xff000000) >> 24;
+}
+#endif
+
+#ifndef HAVE_BSWAP16
+
+unsigned short ROKEN_LIB_FUNCTION
+bswap16 (unsigned short val)
+{
+    return (val & 0xff) << 8 |
+       (val & 0xff00) >> 8;
+}
+#endif
diff --git a/source4/heimdal/lib/roken/emalloc.c b/source4/heimdal/lib/roken/emalloc.c
new file mode 100644 (file)
index 0000000..91af6b5
--- /dev/null
@@ -0,0 +1,56 @@
+/*
+ * 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.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+RCSID("$Id: emalloc.c,v 1.6 2005/04/12 11:28:37 lha Exp $");
+#endif
+
+#include <stdlib.h>
+#include <err.h>
+
+#include <roken.h>
+
+/*
+ * Like malloc but never fails.
+ */
+
+void * ROKEN_LIB_FUNCTION
+emalloc (size_t sz)
+{
+    void *tmp = malloc (sz);
+
+    if (tmp == NULL && sz != 0)
+       errx (1, "malloc %lu failed", (unsigned long)sz);
+    return tmp;
+}
diff --git a/source4/heimdal/lib/roken/get_window_size.c b/source4/heimdal/lib/roken/get_window_size.c
new file mode 100644 (file)
index 0000000..6743e15
--- /dev/null
@@ -0,0 +1,102 @@
+/*
+ * Copyright (c) 1995, 1996, 1997, 1998 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.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+RCSID("$Id: get_window_size.c,v 1.10 2005/04/12 11:28:42 lha Exp $");
+#endif
+
+#include <stdlib.h>
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+#ifdef HAVE_SYS_TYPES_H
+#include <sys/types.h>
+#endif
+
+#if 0 /* Where were those needed? /confused */
+#ifdef HAVE_SYS_PROC_H
+#include <sys/proc.h>
+#endif
+
+#ifdef HAVE_SYS_TTY_H
+#include <sys/tty.h>
+#endif
+#endif
+
+#ifdef HAVE_TERMIOS_H
+#include <termios.h>
+#endif
+
+#include <roken.h>
+
+int ROKEN_LIB_FUNCTION
+get_window_size(int fd, struct winsize *wp)
+{
+    int ret = -1;
+    
+    memset(wp, 0, sizeof(*wp));
+
+#if defined(TIOCGWINSZ)
+    ret = ioctl(fd, TIOCGWINSZ, wp);
+#elif defined(TIOCGSIZE)
+    {
+       struct ttysize ts;
+       
+       ret = ioctl(fd, TIOCGSIZE, &ts);
+       if(ret == 0) {
+           wp->ws_row = ts.ts_lines;
+           wp->ws_col = ts.ts_cols;
+       }
+    }
+#elif defined(HAVE__SCRSIZE)
+    {
+       int dst[2];
+       
+       _scrsize(dst);
+       wp->ws_row = dst[1];
+       wp->ws_col = dst[0];
+       ret = 0;
+    }
+#endif
+    if (ret != 0) {
+        char *s;
+        if((s = getenv("COLUMNS")))
+           wp->ws_col = atoi(s);
+       if((s = getenv("LINES")))
+           wp->ws_row = atoi(s);
+       if(wp->ws_col > 0 && wp->ws_row > 0)
+           ret = 0;
+    }
+    return ret;
+}
diff --git a/source4/heimdal/lib/roken/getarg.c b/source4/heimdal/lib/roken/getarg.c
new file mode 100644 (file)
index 0000000..e4e0556
--- /dev/null
@@ -0,0 +1,595 @@
+/*
+ * 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. 
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+RCSID("$Id: getarg.c,v 1.48 2005/04/12 11:28:43 lha Exp $");
+#endif
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <roken.h>
+#include "getarg.h"
+
+#define ISFLAG(X) ((X).type == arg_flag || (X).type == arg_negative_flag)
+
+static size_t
+print_arg (char *string, size_t len, int mdoc, int longp, struct getargs *arg)
+{
+    const char *s;
+
+    *string = '\0';
+
+    if (ISFLAG(*arg) || (!longp && arg->type == arg_counter))
+       return 0;
+
+    if(mdoc){
+       if(longp)
+           strlcat(string, "= Ns", len);
+       strlcat(string, " Ar ", len);
+    } else {
+       if (longp)
+           strlcat (string, "=", len);
+       else
+           strlcat (string, " ", len);
+    }
+
+    if (arg->arg_help)
+       s = arg->arg_help;
+    else if (arg->type == arg_integer || arg->type == arg_counter)
+       s = "integer";
+    else if (arg->type == arg_string)
+       s = "string";
+    else if (arg->type == arg_strings)
+       s = "strings";
+    else if (arg->type == arg_double)
+       s = "float";
+    else
+       s = "<undefined>";
+
+    strlcat(string, s, len);
+    return 1 + strlen(s);
+}
+
+static void
+mandoc_template(struct getargs *args,
+               size_t num_args,
+               const char *progname,
+               const char *extra_string)
+{
+    int i;
+    char timestr[64], cmd[64];
+    char buf[128];
+    const char *p;
+    time_t t;
+
+    printf(".\\\" Things to fix:\n");
+    printf(".\\\"   * correct section, and operating system\n");
+    printf(".\\\"   * remove Op from mandatory flags\n");
+    printf(".\\\"   * use better macros for arguments (like .Pa for files)\n");
+    printf(".\\\"\n");
+    t = time(NULL);
+    strftime(timestr, sizeof(timestr), "%B %e, %Y", localtime(&t));
+    printf(".Dd %s\n", timestr);
+    p = strrchr(progname, '/');
+    if(p) p++; else p = progname;
+    strlcpy(cmd, p, sizeof(cmd));
+    strupr(cmd);
+       
+    printf(".Dt %s SECTION\n", cmd);
+    printf(".Os OPERATING_SYSTEM\n");
+    printf(".Sh NAME\n");
+    printf(".Nm %s\n", p);
+    printf(".Nd\n");
+    printf("in search of a description\n");
+    printf(".Sh SYNOPSIS\n");
+    printf(".Nm\n");
+    for(i = 0; i < num_args; i++){
+       /* we seem to hit a limit on number of arguments if doing
+           short and long flags with arguments -- split on two lines */
+       if(ISFLAG(args[i]) || 
+          args[i].short_name == 0 || args[i].long_name == NULL) {
+           printf(".Op ");
+
+           if(args[i].short_name) {
+               print_arg(buf, sizeof(buf), 1, 0, args + i);
+               printf("Fl %c%s", args[i].short_name, buf);
+               if(args[i].long_name)
+                   printf(" | ");
+           }
+           if(args[i].long_name) {
+               print_arg(buf, sizeof(buf), 1, 1, args + i);
+               printf("Fl -%s%s%s",
+                      args[i].type == arg_negative_flag ? "no-" : "",
+                      args[i].long_name, buf);
+           }
+           printf("\n");
+       } else {
+           print_arg(buf, sizeof(buf), 1, 0, args + i);
+           printf(".Oo Fl %c%s \\*(Ba Xo\n", args[i].short_name, buf);
+           print_arg(buf, sizeof(buf), 1, 1, args + i);
+           printf(".Fl -%s%s\n.Xc\n.Oc\n", args[i].long_name, buf);
+       }
+    /*
+           if(args[i].type == arg_strings)
+               fprintf (stderr, "...");
+               */
+    }
+    if (extra_string && *extra_string)
+       printf (".Ar %s\n", extra_string);
+    printf(".Sh DESCRIPTION\n");
+    printf("Supported options:\n");
+    printf(".Bl -tag -width Ds\n");
+    for(i = 0; i < num_args; i++){
+       printf(".It Xo\n");
+       if(args[i].short_name){
+           printf(".Fl %c", args[i].short_name);
+           print_arg(buf, sizeof(buf), 1, 0, args + i);
+           printf("%s", buf);
+           if(args[i].long_name)
+               printf(" ,");
+           printf("\n");
+       }
+       if(args[i].long_name){
+           printf(".Fl -%s%s",
+                  args[i].type == arg_negative_flag ? "no-" : "",
+                  args[i].long_name);
+           print_arg(buf, sizeof(buf), 1, 1, args + i);
+           printf("%s\n", buf);
+       }
+       printf(".Xc\n");
+       if(args[i].help)
+           printf("%s\n", args[i].help);
+    /*
+           if(args[i].type == arg_strings)
+               fprintf (stderr, "...");
+               */
+    }
+    printf(".El\n");
+    printf(".\\\".Sh ENVIRONMENT\n");
+    printf(".\\\".Sh FILES\n");
+    printf(".\\\".Sh EXAMPLES\n");
+    printf(".\\\".Sh DIAGNOSTICS\n");
+    printf(".\\\".Sh SEE ALSO\n");
+    printf(".\\\".Sh STANDARDS\n");
+    printf(".\\\".Sh HISTORY\n");
+    printf(".\\\".Sh AUTHORS\n");
+    printf(".\\\".Sh BUGS\n");
+}
+
+static int
+check_column(FILE *f, int col, int len, int columns)
+{
+    if(col + len > columns) {
+       fprintf(f, "\n");
+       col = fprintf(f, "  ");
+    }
+    return col;
+}
+
+void ROKEN_LIB_FUNCTION
+arg_printusage (struct getargs *args,
+               size_t num_args,
+               const char *progname,
+               const char *extra_string)
+{
+    int i;
+    size_t max_len = 0;
+    char buf[128];
+    int col = 0, columns;
+    struct winsize ws;
+
+    if (progname == NULL)
+       progname = getprogname();
+
+    if(getenv("GETARGMANDOC")){
+       mandoc_template(args, num_args, progname, extra_string);
+       return;
+    }
+    if(get_window_size(2, &ws) == 0)
+       columns = ws.ws_col;
+    else
+       columns = 80;
+    col = 0;
+    col += fprintf (stderr, "Usage: %s", progname);
+    buf[0] = '\0';
+    for (i = 0; i < num_args; ++i) {
+       if(args[i].short_name && ISFLAG(args[i])) {
+           char s[2];
+           if(buf[0] == '\0')
+               strlcpy(buf, "[-", sizeof(buf));
+           s[0] = args[i].short_name;
+           s[1] = '\0';
+           strlcat(buf, s, sizeof(buf));
+       }
+    }
+    if(buf[0] != '\0') {
+       strlcat(buf, "]", sizeof(buf));
+       col = check_column(stderr, col, strlen(buf) + 1, columns);
+       col += fprintf(stderr, " %s", buf);
+    }
+
+    for (i = 0; i < num_args; ++i) {
+       size_t len = 0;
+
+       if (args[i].long_name) {
+           buf[0] = '\0';
+           strlcat(buf, "[--", sizeof(buf));
+           len += 2;
+           if(args[i].type == arg_negative_flag) {
+               strlcat(buf, "no-", sizeof(buf));
+               len += 3;
+           }
+           strlcat(buf, args[i].long_name, sizeof(buf));
+           len += strlen(args[i].long_name);
+           len += print_arg(buf + strlen(buf), sizeof(buf) - strlen(buf), 
+                            0, 1, &args[i]);
+           strlcat(buf, "]", sizeof(buf));
+           if(args[i].type == arg_strings)
+               strlcat(buf, "...", sizeof(buf));
+           col = check_column(stderr, col, strlen(buf) + 1, columns);
+           col += fprintf(stderr, " %s", buf);
+       }
+       if (args[i].short_name && !ISFLAG(args[i])) {
+           snprintf(buf, sizeof(buf), "[-%c", args[i].short_name);
+           len += 2;
+           len += print_arg(buf + strlen(buf), sizeof(buf) - strlen(buf), 
+                            0, 0, &args[i]);
+           strlcat(buf, "]", sizeof(buf));
+           if(args[i].type == arg_strings)
+               strlcat(buf, "...", sizeof(buf));
+           col = check_column(stderr, col, strlen(buf) + 1, columns);
+           col += fprintf(stderr, " %s", buf);
+       }
+       if (args[i].long_name && args[i].short_name)
+           len += 2; /* ", " */
+       max_len = max(max_len, len);
+    }
+    if (extra_string) {
+       col = check_column(stderr, col, strlen(extra_string) + 1, columns);
+       fprintf (stderr, " %s\n", extra_string);
+    } else
+       fprintf (stderr, "\n");
+    for (i = 0; i < num_args; ++i) {
+       if (args[i].help) {
+           size_t count = 0;
+
+           if (args[i].short_name) {
+               count += fprintf (stderr, "-%c", args[i].short_name);
+               print_arg (buf, sizeof(buf), 0, 0, &args[i]);
+               count += fprintf(stderr, "%s", buf);
+           }
+           if (args[i].short_name && args[i].long_name)
+               count += fprintf (stderr, ", ");
+           if (args[i].long_name) {
+               count += fprintf (stderr, "--");
+               if (args[i].type == arg_negative_flag)
+                   count += fprintf (stderr, "no-");
+               count += fprintf (stderr, "%s", args[i].long_name);
+               print_arg (buf, sizeof(buf), 0, 1, &args[i]);
+               count += fprintf(stderr, "%s", buf);
+           }
+           while(count++ <= max_len)
+               putc (' ', stderr);
+           fprintf (stderr, "%s\n", args[i].help);
+       }
+    }
+}
+
+static int
+add_string(getarg_strings *s, char *value)
+{
+    char **strings;
+
+    strings = realloc(s->strings, (s->num_strings + 1) * sizeof(*s->strings));
+    if (strings == NULL) {
+       free(s->strings);
+       s->strings = NULL;
+       s->num_strings = 0;
+       return ENOMEM;
+    }
+    s->strings = strings;
+    s->strings[s->num_strings] = value;
+    s->num_strings++;
+    return 0;
+}
+
+static int
+arg_match_long(struct getargs *args, size_t num_args,
+              char *argv, int argc, char **rargv, int *goptind)
+{
+    int i;
+    char *goptarg = NULL;
+    int negate = 0;
+    int partial_match = 0;
+    struct getargs *partial = NULL;
+    struct getargs *current = NULL;
+    int argv_len;
+    char *p;
+    int p_len;
+
+    argv_len = strlen(argv);
+    p = strchr (argv, '=');
+    if (p != NULL)
+       argv_len = p - argv;
+
+    for (i = 0; i < num_args; ++i) {
+       if(args[i].long_name) {
+           int len = strlen(args[i].long_name);
+           p = argv;
+           p_len = argv_len;
+           negate = 0;
+
+           for (;;) {
+               if (strncmp (args[i].long_name, p, p_len) == 0) {
+                   if(p_len == len)
+                       current = &args[i];
+                   else {
+                       ++partial_match;
+                       partial = &args[i];
+                   }
+                   goptarg  = p + p_len;
+               } else if (ISFLAG(args[i]) && strncmp (p, "no-", 3) == 0) {
+                   negate = !negate;
+                   p += 3;
+                   p_len -= 3;
+                   continue;
+               }
+               break;
+           }
+           if (current)
+               break;
+       }
+    }
+    if (current == NULL) {
+       if (partial_match == 1)
+           current = partial;
+       else
+           return ARG_ERR_NO_MATCH;
+    }
+    
+    if(*goptarg == '\0'
+       && !ISFLAG(*current)
+       && current->type != arg_collect
+       && current->type != arg_counter)
+       return ARG_ERR_NO_MATCH;
+    switch(current->type){
+    case arg_integer:
+    {
+       int tmp;
+       if(sscanf(goptarg + 1, "%d", &tmp) != 1)
+           return ARG_ERR_BAD_ARG;
+       *(int*)current->value = tmp;
+       return 0;
+    }
+    case arg_string:
+    {
+       *(char**)current->value = goptarg + 1;
+       return 0;
+    }
+    case arg_strings:
+    {
+       return add_string((getarg_strings*)current->value, goptarg + 1);
+    }
+    case arg_flag:
+    case arg_negative_flag:
+    {
+       int *flag = current->value;
+       if(*goptarg == '\0' ||
+          strcmp(goptarg + 1, "yes") == 0 || 
+          strcmp(goptarg + 1, "true") == 0){
+           *flag = !negate;
+           return 0;
+       } else if (*goptarg && strcmp(goptarg + 1, "maybe") == 0) {
+#ifdef HAVE_RANDOM
+           *flag = random() & 1;
+#else
+           *flag = rand() & 1;
+#endif
+       } else {
+           *flag = negate;
+           return 0;
+       }
+       return ARG_ERR_BAD_ARG;
+    }
+    case arg_counter :
+    {
+       int val;
+
+       if (*goptarg == '\0')
+           val = 1;
+       else if(sscanf(goptarg + 1, "%d", &val) != 1)
+           return ARG_ERR_BAD_ARG;
+       *(int *)current->value += val;
+       return 0;
+    }
+    case arg_double:
+    {
+       double tmp;
+       if(sscanf(goptarg + 1, "%lf", &tmp) != 1)
+           return ARG_ERR_BAD_ARG;
+       *(double*)current->value = tmp;
+       return 0;
+    }
+    case arg_collect:{
+       struct getarg_collect_info *c = current->value;
+       int o = argv - rargv[*goptind];
+       return (*c->func)(FALSE, argc, rargv, goptind, &o, c->data);
+    }
+
+    default:
+       abort ();
+    }
+}
+
+static int
+arg_match_short (struct getargs *args, size_t num_args,
+                char *argv, int argc, char **rargv, int *goptind)
+{
+    int j, k;
+
+    for(j = 1; j > 0 && j < strlen(rargv[*goptind]); j++) {
+       for(k = 0; k < num_args; k++) {
+           char *goptarg;
+
+           if(args[k].short_name == 0)
+               continue;
+           if(argv[j] == args[k].short_name) {
+               if(args[k].type == arg_flag) {
+                   *(int*)args[k].value = 1;
+                   break;
+               }
+               if(args[k].type == arg_negative_flag) {
+                   *(int*)args[k].value = 0;
+                   break;
+               } 
+               if(args[k].type == arg_counter) {
+                   ++*(int *)args[k].value;
+                   break;
+               }
+               if(args[k].type == arg_collect) {
+                   struct getarg_collect_info *c = args[k].value;
+
+                   if((*c->func)(TRUE, argc, rargv, goptind, &j, c->data))
+                       return ARG_ERR_BAD_ARG;
+                   break;
+               }
+
+               if(argv[j + 1])
+                   goptarg = &argv[j + 1];
+               else {
+                   ++*goptind;
+                   goptarg = rargv[*goptind];
+               }
+               if(goptarg == NULL) {
+                   --*goptind;
+                   return ARG_ERR_NO_ARG;
+               }
+               if(args[k].type == arg_integer) {
+                   int tmp;
+                   if(sscanf(goptarg, "%d", &tmp) != 1)
+                       return ARG_ERR_BAD_ARG;
+                   *(int*)args[k].value = tmp;
+                   return 0;
+               } else if(args[k].type == arg_string) {
+                   *(char**)args[k].value = goptarg;
+                   return 0;
+               } else if(args[k].type == arg_strings) {
+                   return add_string((getarg_strings*)args[k].value, goptarg);
+               } else if(args[k].type == arg_double) {
+                   double tmp;
+                   if(sscanf(goptarg, "%lf", &tmp) != 1)
+                       return ARG_ERR_BAD_ARG;
+                   *(double*)args[k].value = tmp;
+                   return 0;
+               }
+               return ARG_ERR_BAD_ARG;
+           }
+       }
+       if (k == num_args)
+           return ARG_ERR_NO_MATCH;
+    }
+    return 0;
+}
+
+int ROKEN_LIB_FUNCTION
+getarg(struct getargs *args, size_t num_args, 
+       int argc, char **argv, int *goptind)
+{
+    int i;
+    int ret = 0;
+
+#if defined(HAVE_SRANDOMDEV)
+    srandomdev();
+#elif defined(HAVE_RANDOM)
+    srandom(time(NULL));
+#else
+    srand (time(NULL));
+#endif
+    (*goptind)++;
+    for(i = *goptind; i < argc; i++) {
+       if(argv[i][0] != '-')
+           break;
+       if(argv[i][1] == '-'){
+           if(argv[i][2] == 0){
+               i++;
+               break;
+           }
+           ret = arg_match_long (args, num_args, argv[i] + 2, 
+                                 argc, argv, &i);
+       } else {
+           ret = arg_match_short (args, num_args, argv[i],
+                                  argc, argv, &i);
+       }
+       if(ret)
+           break;
+    }
+    *goptind = i;
+    return ret;
+}
+
+void ROKEN_LIB_FUNCTION
+free_getarg_strings (getarg_strings *s)
+{
+    free (s->strings);
+}
+
+#if TEST
+int foo_flag = 2;
+int flag1 = 0;
+int flag2 = 0;
+int bar_int;
+char *baz_string;
+
+struct getargs args[] = {
+    { NULL, '1', arg_flag, &flag1, "one", NULL },
+    { NULL, '2', arg_flag, &flag2, "two", NULL },
+    { "foo", 'f', arg_negative_flag, &foo_flag, "foo", NULL },
+    { "bar", 'b', arg_integer, &bar_int, "bar", "seconds"},
+    { "baz", 'x', arg_string, &baz_string, "baz", "name" },
+};
+
+int main(int argc, char **argv)
+{
+    int goptind = 0;
+    while(getarg(args, 5, argc, argv, &goptind))
+       printf("Bad arg: %s\n", argv[goptind]);
+    printf("flag1 = %d\n", flag1);  
+    printf("flag2 = %d\n", flag2);  
+    printf("foo_flag = %d\n", foo_flag);  
+    printf("bar_int = %d\n", bar_int);
+    printf("baz_flag = %s\n", baz_string);
+    arg_printusage (args, 5, argv[0], "nothing here");
+}
+#endif
diff --git a/source4/heimdal/lib/roken/getarg.h b/source4/heimdal/lib/roken/getarg.h
new file mode 100644 (file)
index 0000000..bffa044
--- /dev/null
@@ -0,0 +1,102 @@
+/*
+ * 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: getarg.h,v 1.14 2005/04/13 05:52:27 lha Exp $ */
+
+#ifndef __GETARG_H__
+#define __GETARG_H__
+
+#include <stddef.h>
+
+#ifndef ROKEN_LIB_FUNCTION
+#ifdef _WIN32
+#define ROKEN_LIB_FUNCTION _stdcall
+#else
+#define ROKEN_LIB_FUNCTION
+#endif
+#endif
+
+struct getargs{
+    const char *long_name;
+    char short_name;
+    enum { arg_integer, 
+          arg_string, 
+          arg_flag, 
+          arg_negative_flag, 
+          arg_strings,
+          arg_double,
+          arg_collect,
+          arg_counter
+    } type;
+    void *value;
+    const char *help;
+    const char *arg_help;
+};
+
+enum {
+    ARG_ERR_NO_MATCH  = 1,
+    ARG_ERR_BAD_ARG,
+    ARG_ERR_NO_ARG
+};
+
+typedef struct getarg_strings {
+    int num_strings;
+    char **strings;
+} getarg_strings;
+
+typedef int (*getarg_collect_func)(int short_opt,
+                                  int argc,
+                                  char **argv,
+                                  int *goptind,
+                                  int *goptarg,
+                                  void *data);
+
+typedef struct getarg_collect_info {
+    getarg_collect_func func;
+    void *data;
+} getarg_collect_info;
+
+int ROKEN_LIB_FUNCTION
+getarg(struct getargs *args, size_t num_args, 
+       int argc, char **argv, int *goptind);
+
+void ROKEN_LIB_FUNCTION
+arg_printusage (struct getargs *args,
+               size_t num_args,
+               const char *progname,
+               const char *extra_string);
+
+void ROKEN_LIB_FUNCTION
+free_getarg_strings (getarg_strings *);
+
+#endif /* __GETARG_H__ */
diff --git a/source4/heimdal/lib/roken/getifaddrs.c b/source4/heimdal/lib/roken/getifaddrs.c
new file mode 100644 (file)
index 0000000..3c97e89
--- /dev/null
@@ -0,0 +1,1186 @@
+/*
+ * Copyright (c) 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.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+RCSID("$Id: getifaddrs.c,v 1.11 2005/04/30 15:45:47 lha Exp $");
+#endif
+#include "roken.h"
+
+#ifdef __osf__
+/* hate */
+struct rtentry;
+struct mbuf;
+#endif
+#ifdef HAVE_NET_IF_H
+#include <net/if.h>
+#endif
+
+#ifdef HAVE_SYS_SOCKIO_H
+#include <sys/sockio.h>
+#endif /* HAVE_SYS_SOCKIO_H */
+
+#ifdef HAVE_NETINET_IN6_VAR_H
+#include <netinet/in6_var.h>
+#endif /* HAVE_NETINET_IN6_VAR_H */
+
+#include <ifaddrs.h>
+
+#ifdef AF_NETLINK
+
+/*
+ * The linux - AF_NETLINK version of getifaddrs - from Usagi.
+ * Linux does not return v6 addresses from SIOCGIFCONF.
+ */
+
+/* $USAGI: ifaddrs.c,v 1.18 2002/03/06 01:50:46 yoshfuji Exp $ */
+
+/**************************************************************************
+ * ifaddrs.c
+ * Copyright (C)2000 Hideaki YOSHIFUJI, 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 author 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 AUTHOR 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 AUTHOR 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 "config.h"
+
+#include <string.h>
+#include <time.h>
+#include <malloc.h>
+#include <errno.h>
+#include <unistd.h>
+
+#include <sys/socket.h>
+#include <asm/types.h>
+#include <linux/netlink.h>
+#include <linux/rtnetlink.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netpacket/packet.h>
+#include <net/ethernet.h>     /* the L2 protocols */
+#include <sys/uio.h>
+#include <net/if.h>
+#include <net/if_arp.h>
+#include <ifaddrs.h>
+#include <netinet/in.h>
+
+#define __set_errno(e) (errno = (e))
+#define __close(fd) (close(fd))
+#undef ifa_broadaddr
+#define ifa_broadaddr ifa_dstaddr
+#define IFA_NETMASK
+
+/* ====================================================================== */
+struct nlmsg_list{
+    struct nlmsg_list *nlm_next;
+    struct nlmsghdr *nlh;
+    int size;
+    time_t seq;
+};
+
+struct rtmaddr_ifamap {
+  void *address;
+  void *local;
+#ifdef IFA_NETMASK
+  void *netmask;
+#endif
+  void *broadcast;
+#ifdef HAVE_IFADDRS_IFA_ANYCAST
+  void *anycast;
+#endif
+  int address_len;
+  int local_len;
+#ifdef IFA_NETMASK
+  int netmask_len;
+#endif
+  int broadcast_len;
+#ifdef HAVE_IFADDRS_IFA_ANYCAST
+  int anycast_len;
+#endif
+};
+
+/* ====================================================================== */
+static size_t
+ifa_sa_len(sa_family_t family, int len)
+{
+  size_t size;
+  switch(family){
+  case AF_INET:
+    size = sizeof(struct sockaddr_in);
+    break;
+  case AF_INET6:
+    size = sizeof(struct sockaddr_in6);
+    break;
+  case AF_PACKET:
+    size = (size_t)(((struct sockaddr_ll *)NULL)->sll_addr) + len;
+    if (size < sizeof(struct sockaddr_ll))
+      size = sizeof(struct sockaddr_ll);
+    break;
+  default:
+    size = (size_t)(((struct sockaddr *)NULL)->sa_data) + len;
+    if (size < sizeof(struct sockaddr))
+      size = sizeof(struct sockaddr);
+    break;
+  }
+  return size;
+}
+
+static void 
+ifa_make_sockaddr(sa_family_t family, 
+                 struct sockaddr *sa, 
+                 void *p, size_t len,
+                 uint32_t scope, uint32_t scopeid)
+{
+  if (sa == NULL) return;
+  switch(family){
+  case AF_INET:
+    memcpy(&((struct sockaddr_in*)sa)->sin_addr, (char *)p, len);
+    break;
+  case AF_INET6:
+    memcpy(&((struct sockaddr_in6*)sa)->sin6_addr, (char *)p, len);
+    if (IN6_IS_ADDR_LINKLOCAL(p) ||
+       IN6_IS_ADDR_MC_LINKLOCAL(p)){
+      ((struct sockaddr_in6*)sa)->sin6_scope_id = scopeid;
+    }
+    break;
+  case AF_PACKET:
+    memcpy(((struct sockaddr_ll*)sa)->sll_addr, (char *)p, len);
+    ((struct sockaddr_ll*)sa)->sll_halen = len;
+    break;
+  default:
+    memcpy(sa->sa_data, p, len);       /*XXX*/
+    break;
+  }
+  sa->sa_family = family;
+#ifdef HAVE_SOCKADDR_SA_LEN
+  sa->sa_len = ifa_sa_len(family, len);
+#endif
+}
+
+#ifndef IFA_NETMASK
+static struct sockaddr *
+ifa_make_sockaddr_mask(sa_family_t family, 
+                      struct sockaddr *sa, 
+                      uint32_t prefixlen)
+{
+  int i;
+  char *p = NULL, c;
+  uint32_t max_prefixlen = 0;
+
+  if (sa == NULL) return NULL;
+  switch(family){
+  case AF_INET:
+    memset(&((struct sockaddr_in*)sa)->sin_addr, 0, sizeof(((struct sockaddr_in*)sa)->sin_addr));
+    p = (char *)&((struct sockaddr_in*)sa)->sin_addr;
+    max_prefixlen = 32;
+    break;
+  case AF_INET6:
+    memset(&((struct sockaddr_in6*)sa)->sin6_addr, 0, sizeof(((struct sockaddr_in6*)sa)->sin6_addr));
+    p = (char *)&((struct sockaddr_in6*)sa)->sin6_addr;
+#if 0  /* XXX: fill scope-id? */
+    if (IN6_IS_ADDR_LINKLOCAL(p) ||
+       IN6_IS_ADDR_MC_LINKLOCAL(p)){
+      ((struct sockaddr_in6*)sa)->sin6_scope_id = scopeid;
+    }
+#endif
+    max_prefixlen = 128;
+    break;
+  default:
+    return NULL;
+  }
+  sa->sa_family = family;
+#ifdef HAVE_SOCKADDR_SA_LEN
+  sa->sa_len = ifa_sa_len(family, len);
+#endif
+  if (p){
+    if (prefixlen > max_prefixlen)
+      prefixlen = max_prefixlen;
+    for (i=0; i<(prefixlen / 8); i++)
+      *p++ = 0xff;
+    c = 0xff;
+    c <<= (8 - (prefixlen % 8));
+    *p = c;
+  }
+  return sa;
+}
+#endif
+
+/* ====================================================================== */
+static int 
+nl_sendreq(int sd, int request, int flags, int *seq)
+{
+  char reqbuf[NLMSG_ALIGN(sizeof(struct nlmsghdr)) +
+             NLMSG_ALIGN(sizeof(struct rtgenmsg))];
+  struct sockaddr_nl nladdr;
+  struct nlmsghdr *req_hdr;
+  struct rtgenmsg *req_msg;
+  time_t t = time(NULL);
+
+  if (seq) *seq = t;
+  memset(&reqbuf, 0, sizeof(reqbuf));
+  req_hdr = (struct nlmsghdr *)reqbuf;
+  req_msg = (struct rtgenmsg *)NLMSG_DATA(req_hdr);
+  req_hdr->nlmsg_len = NLMSG_LENGTH(sizeof(*req_msg));
+  req_hdr->nlmsg_type = request;
+  req_hdr->nlmsg_flags = flags | NLM_F_REQUEST;
+  req_hdr->nlmsg_pid = 0;
+  req_hdr->nlmsg_seq = t;
+  req_msg->rtgen_family = AF_UNSPEC;
+  memset(&nladdr, 0, sizeof(nladdr));
+  nladdr.nl_family = AF_NETLINK;
+  return (sendto(sd, (void *)req_hdr, req_hdr->nlmsg_len, 0,
+                (struct sockaddr *)&nladdr, sizeof(nladdr)));
+}
+
+static int 
+nl_recvmsg(int sd, int request, int seq, 
+          void *buf, size_t buflen, 
+          int *flags)
+{
+  struct msghdr msg;
+  struct iovec iov = { buf, buflen };
+  struct sockaddr_nl nladdr;
+  int read_len;
+
+  for (;;){
+    msg.msg_name = (void *)&nladdr;
+    msg.msg_namelen = sizeof(nladdr);
+    msg.msg_iov = &iov;
+    msg.msg_iovlen = 1;
+    msg.msg_control = NULL;
+    msg.msg_controllen = 0;
+    msg.msg_flags = 0;
+    read_len = recvmsg(sd, &msg, 0);
+    if ((read_len < 0 && errno == EINTR) || (msg.msg_flags & MSG_TRUNC))
+      continue;
+    if (flags) *flags = msg.msg_flags;
+    break;
+  }
+  return read_len;
+}
+
+static int 
+nl_getmsg(int sd, int request, int seq, 
+         struct nlmsghdr **nlhp,
+         int *done)
+{
+  struct nlmsghdr *nh;
+  size_t bufsize = 65536, lastbufsize = 0;
+  void *buff = NULL;
+  int result = 0, read_size;
+  int msg_flags;
+  pid_t pid = getpid();
+  for (;;){
+    void *newbuff = realloc(buff, bufsize);
+    if (newbuff == NULL || bufsize < lastbufsize) {
+      result = -1;
+      break;
+    }
+    buff = newbuff;
+    result = read_size = nl_recvmsg(sd, request, seq, buff, bufsize, &msg_flags);
+    if (read_size < 0 || (msg_flags & MSG_TRUNC)){
+      lastbufsize = bufsize;
+      bufsize *= 2;
+      continue;
+    }
+    if (read_size == 0) break;
+    nh = (struct nlmsghdr *)buff;
+    for (nh = (struct nlmsghdr *)buff;
+        NLMSG_OK(nh, read_size);
+        nh = (struct nlmsghdr *)NLMSG_NEXT(nh, read_size)){
+      if (nh->nlmsg_pid != pid ||
+         nh->nlmsg_seq != seq)
+       continue;
+      if (nh->nlmsg_type == NLMSG_DONE){
+       (*done)++;
+       break; /* ok */
+      }
+      if (nh->nlmsg_type == NLMSG_ERROR){
+       struct nlmsgerr *nlerr = (struct nlmsgerr *)NLMSG_DATA(nh);
+       result = -1;
+       if (nh->nlmsg_len < NLMSG_LENGTH(sizeof(struct nlmsgerr)))
+         __set_errno(EIO);
+       else
+         __set_errno(-nlerr->error);
+       break;
+      }
+    }
+    break;
+  }
+  if (result < 0)
+    if (buff){
+      int saved_errno = errno;
+      free(buff);
+      __set_errno(saved_errno);
+    }
+  *nlhp = (struct nlmsghdr *)buff;
+  return result;
+}
+
+static int
+nl_getlist(int sd, int seq,
+          int request,
+          struct nlmsg_list **nlm_list,
+          struct nlmsg_list **nlm_end)
+{
+  struct nlmsghdr *nlh = NULL;
+  int status;
+  int done = 0;
+
+  status = nl_sendreq(sd, request, NLM_F_ROOT|NLM_F_MATCH, &seq);
+  if (status < 0)
+    return status;
+  if (seq == 0)
+    seq = (int)time(NULL);
+  while(!done){
+    status = nl_getmsg(sd, request, seq, &nlh, &done);
+    if (status < 0)
+      return status;
+    if (nlh){
+      struct nlmsg_list *nlm_next = (struct nlmsg_list *)malloc(sizeof(struct nlmsg_list));
+      if (nlm_next == NULL){
+       int saved_errno = errno;
+       free(nlh);
+       __set_errno(saved_errno);
+       status = -1;
+      } else {
+       nlm_next->nlm_next = NULL;
+       nlm_next->nlh = (struct nlmsghdr *)nlh;
+       nlm_next->size = status;
+       nlm_next->seq = seq;
+       if (*nlm_list == NULL){
+         *nlm_list = nlm_next;
+         *nlm_end = nlm_next;
+       } else {
+         (*nlm_end)->nlm_next = nlm_next;
+         *nlm_end = nlm_next;
+       }
+      }
+    }
+  }
+  return status >= 0 ? seq : status;
+}
+
+/* ---------------------------------------------------------------------- */
+static void 
+free_nlmsglist(struct nlmsg_list *nlm0)
+{
+  struct nlmsg_list *nlm;
+  int saved_errno;
+  if (!nlm0)
+    return;
+  saved_errno = errno;
+  for (nlm=nlm0; nlm; nlm=nlm->nlm_next){
+    if (nlm->nlh)
+      free(nlm->nlh);
+  }
+  free(nlm0);
+  __set_errno(saved_errno);
+}
+
+static void 
+free_data(void *data, void *ifdata)
+{
+  int saved_errno = errno;
+  if (data != NULL) free(data);
+  if (ifdata != NULL) free(ifdata);
+  __set_errno(saved_errno);
+}
+
+/* ---------------------------------------------------------------------- */
+static void 
+nl_close(int sd)
+{
+  int saved_errno = errno;
+  if (sd >= 0) __close(sd);
+  __set_errno(saved_errno);
+}
+
+/* ---------------------------------------------------------------------- */
+static int 
+nl_open(void)
+{
+  struct sockaddr_nl nladdr;
+  int sd;
+
+  sd = socket(PF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
+  if (sd < 0) return -1;
+  memset(&nladdr, 0, sizeof(nladdr));
+  nladdr.nl_family = AF_NETLINK;
+  if (bind(sd, (struct sockaddr*)&nladdr, sizeof(nladdr)) < 0){
+    nl_close(sd);
+    return -1;
+  }
+  return sd;
+}
+
+/* ====================================================================== */
+int ROKEN_LIB_FUNCTION
+getifaddrs(struct ifaddrs **ifap)
+{
+  int sd;
+  struct nlmsg_list *nlmsg_list, *nlmsg_end, *nlm;
+  /* - - - - - - - - - - - - - - - */
+  int icnt;
+  size_t dlen, xlen, nlen;
+  uint32_t max_ifindex = 0;
+
+  pid_t pid = getpid();
+  int seq;
+  int result;
+  int build     ; /* 0 or 1 */
+
+/* ---------------------------------- */
+  /* initialize */
+  icnt = dlen = xlen = nlen = 0;
+  nlmsg_list = nlmsg_end = NULL;
+
+  if (ifap)
+    *ifap = NULL;
+
+/* ---------------------------------- */
+  /* open socket and bind */
+  sd = nl_open();
+  if (sd < 0)
+    return -1;
+
+/* ---------------------------------- */
+   /* gather info */
+  if ((seq = nl_getlist(sd, 0, RTM_GETLINK,
+                       &nlmsg_list, &nlmsg_end)) < 0){
+    free_nlmsglist(nlmsg_list);
+    nl_close(sd);
+    return -1;
+  }
+  if ((seq = nl_getlist(sd, seq+1, RTM_GETADDR,
+                       &nlmsg_list, &nlmsg_end)) < 0){
+    free_nlmsglist(nlmsg_list);
+    nl_close(sd);
+    return -1;
+  }
+
+/* ---------------------------------- */
+  /* Estimate size of result buffer and fill it */
+  for (build=0; build<=1; build++){
+    struct ifaddrs *ifl = NULL, *ifa = NULL;
+    struct nlmsghdr *nlh, *nlh0;
+    char *data = NULL, *xdata = NULL;
+    void *ifdata = NULL;
+    char *ifname = NULL, **iflist = NULL;
+    uint16_t *ifflist = NULL;
+    struct rtmaddr_ifamap ifamap;
+
+    if (build){
+      data = calloc(1,
+                   NLMSG_ALIGN(sizeof(struct ifaddrs[icnt]))
+                   + dlen + xlen + nlen);
+      ifa = (struct ifaddrs *)data;
+      ifdata = calloc(1, 
+                     NLMSG_ALIGN(sizeof(char *[max_ifindex+1]))
+                     + NLMSG_ALIGN(sizeof(uint16_t [max_ifindex+1])));
+      if (ifap != NULL)
+       *ifap = (ifdata != NULL) ? ifa : NULL;
+      else{
+       free_data(data, ifdata);
+       result = 0;
+       break;
+      }
+      if (data == NULL || ifdata == NULL){
+       free_data(data, ifdata);
+       result = -1;
+       break;
+      }
+      ifl = NULL;
+      data += NLMSG_ALIGN(sizeof(struct ifaddrs)) * icnt;
+      xdata = data + dlen;
+      ifname = xdata + xlen;
+      iflist = ifdata;
+      ifflist = (uint16_t *)(((char *)iflist) + NLMSG_ALIGN(sizeof(char *[max_ifindex+1])));
+    }
+
+    for (nlm=nlmsg_list; nlm; nlm=nlm->nlm_next){
+      int nlmlen = nlm->size;
+      if (!(nlh0 = nlm->nlh))
+       continue;
+      for (nlh = nlh0; 
+          NLMSG_OK(nlh, nlmlen); 
+          nlh=NLMSG_NEXT(nlh,nlmlen)){
+       struct ifinfomsg *ifim = NULL;
+       struct ifaddrmsg *ifam = NULL;
+       struct rtattr *rta;
+
+       size_t nlm_struct_size = 0;
+       sa_family_t nlm_family = 0;
+       uint32_t nlm_scope = 0, nlm_index = 0;
+       size_t sockaddr_size = 0;
+       uint32_t nlm_prefixlen = 0;
+       size_t rtasize;
+
+       memset(&ifamap, 0, sizeof(ifamap));
+
+       /* check if the message is what we want */
+       if (nlh->nlmsg_pid != pid ||
+           nlh->nlmsg_seq != nlm->seq)
+         continue;
+       if (nlh->nlmsg_type == NLMSG_DONE){
+         break; /* ok */
+       }
+       switch (nlh->nlmsg_type){
+       case RTM_NEWLINK:
+         ifim = (struct ifinfomsg *)NLMSG_DATA(nlh);
+         nlm_struct_size = sizeof(*ifim);
+         nlm_family = ifim->ifi_family;
+         nlm_scope = 0;
+         nlm_index = ifim->ifi_index;
+         nlm_prefixlen = 0;
+         if (build)
+           ifflist[nlm_index] = ifa->ifa_flags = ifim->ifi_flags;
+         break;
+       case RTM_NEWADDR:
+         ifam = (struct ifaddrmsg *)NLMSG_DATA(nlh);
+         nlm_struct_size = sizeof(*ifam);
+         nlm_family = ifam->ifa_family;
+         nlm_scope = ifam->ifa_scope;
+         nlm_index = ifam->ifa_index;
+         nlm_prefixlen = ifam->ifa_prefixlen;
+         if (build)
+           ifa->ifa_flags = ifflist[nlm_index];
+         break;
+       default:
+         continue;
+       }
+       
+       if (!build){
+         if (max_ifindex < nlm_index)
+           max_ifindex = nlm_index;
+       } else {
+         if (ifl != NULL)
+           ifl->ifa_next = ifa;
+       }
+
+       rtasize = NLMSG_PAYLOAD(nlh, nlmlen) - NLMSG_ALIGN(nlm_struct_size);
+       for (rta = (struct rtattr *)(((char *)NLMSG_DATA(nlh)) + NLMSG_ALIGN(nlm_struct_size));
+            RTA_OK(rta, rtasize);
+            rta = RTA_NEXT(rta, rtasize)){
+         struct sockaddr **sap = NULL;
+         void *rtadata = RTA_DATA(rta);
+         size_t rtapayload = RTA_PAYLOAD(rta);
+         socklen_t sa_len;
+
+         switch(nlh->nlmsg_type){
+         case RTM_NEWLINK:
+           switch(rta->rta_type){
+           case IFLA_ADDRESS:
+           case IFLA_BROADCAST:
+             if (build){
+               sap = (rta->rta_type == IFLA_ADDRESS) ? &ifa->ifa_addr : &ifa->ifa_broadaddr;
+               *sap = (struct sockaddr *)data;
+             }
+             sa_len = ifa_sa_len(AF_PACKET, rtapayload);
+             if (rta->rta_type == IFLA_ADDRESS)
+               sockaddr_size = NLMSG_ALIGN(sa_len);
+             if (!build){
+               dlen += NLMSG_ALIGN(sa_len);
+             } else {
+               memset(*sap, 0, sa_len);
+               ifa_make_sockaddr(AF_PACKET, *sap, rtadata,rtapayload, 0,0);
+               ((struct sockaddr_ll *)*sap)->sll_ifindex = nlm_index;
+               ((struct sockaddr_ll *)*sap)->sll_hatype = ifim->ifi_type;
+               data += NLMSG_ALIGN(sa_len);
+             }
+             break;
+           case IFLA_IFNAME:/* Name of Interface */
+             if (!build)
+               nlen += NLMSG_ALIGN(rtapayload + 1);
+             else{
+               ifa->ifa_name = ifname;
+               if (iflist[nlm_index] == NULL)
+                 iflist[nlm_index] = ifa->ifa_name;
+               strncpy(ifa->ifa_name, rtadata, rtapayload);
+               ifa->ifa_name[rtapayload] = '\0';
+               ifname += NLMSG_ALIGN(rtapayload + 1);
+             }
+             break;
+           case IFLA_STATS:/* Statistics of Interface */
+             if (!build)
+               xlen += NLMSG_ALIGN(rtapayload);
+             else{
+               ifa->ifa_data = xdata;
+               memcpy(ifa->ifa_data, rtadata, rtapayload);
+               xdata += NLMSG_ALIGN(rtapayload);
+             }
+             break;
+           case IFLA_UNSPEC:
+             break;
+           case IFLA_MTU:
+             break;
+           case IFLA_LINK:
+             break;
+           case IFLA_QDISC:
+             break;
+           default:
+             break;
+           }
+           break;
+         case RTM_NEWADDR:
+           if (nlm_family == AF_PACKET) break;
+           switch(rta->rta_type){
+           case IFA_ADDRESS:
+               ifamap.address = rtadata;
+               ifamap.address_len = rtapayload;
+               break;
+           case IFA_LOCAL:
+               ifamap.local = rtadata;
+               ifamap.local_len = rtapayload;
+               break;
+           case IFA_BROADCAST:
+               ifamap.broadcast = rtadata;
+               ifamap.broadcast_len = rtapayload;
+               break;
+#ifdef HAVE_IFADDRS_IFA_ANYCAST
+           case IFA_ANYCAST:
+               ifamap.anycast = rtadata;
+               ifamap.anycast_len = rtapayload;
+               break;
+#endif
+           case IFA_LABEL:
+             if (!build)
+               nlen += NLMSG_ALIGN(rtapayload + 1);
+             else{
+               ifa->ifa_name = ifname;
+               if (iflist[nlm_index] == NULL)
+                 iflist[nlm_index] = ifname;
+               strncpy(ifa->ifa_name, rtadata, rtapayload);
+               ifa->ifa_name[rtapayload] = '\0';
+               ifname += NLMSG_ALIGN(rtapayload + 1);
+             }
+             break;
+           case IFA_UNSPEC:
+             break;
+           case IFA_CACHEINFO:
+             break;
+           default:
+             break;
+           }
+         }
+       }
+       if (nlh->nlmsg_type == RTM_NEWADDR &&
+           nlm_family != AF_PACKET) {
+         if (!ifamap.local) {
+           ifamap.local = ifamap.address;
+           ifamap.local_len = ifamap.address_len;
+         }
+         if (!ifamap.address) {
+           ifamap.address = ifamap.local;
+           ifamap.address_len = ifamap.local_len;
+         }
+         if (ifamap.address_len != ifamap.local_len ||
+             (ifamap.address != NULL &&
+              memcmp(ifamap.address, ifamap.local, ifamap.address_len))) {
+           /* p2p; address is peer and local is ours */
+           ifamap.broadcast = ifamap.address;
+           ifamap.broadcast_len = ifamap.address_len;
+           ifamap.address = ifamap.local;
+           ifamap.address_len = ifamap.local_len;
+         }
+         if (ifamap.address) {
+#ifndef IFA_NETMASK
+           sockaddr_size = NLMSG_ALIGN(ifa_sa_len(nlm_family,ifamap.address_len));
+#endif
+           if (!build)
+             dlen += NLMSG_ALIGN(ifa_sa_len(nlm_family,ifamap.address_len));
+           else {
+             ifa->ifa_addr = (struct sockaddr *)data;
+             ifa_make_sockaddr(nlm_family, ifa->ifa_addr, ifamap.address, ifamap.address_len,
+                               nlm_scope, nlm_index);
+             data += NLMSG_ALIGN(ifa_sa_len(nlm_family, ifamap.address_len));
+           }
+         }
+#ifdef IFA_NETMASK
+         if (ifamap.netmask) {
+           if (!build)
+             dlen += NLMSG_ALIGN(ifa_sa_len(nlm_family,ifamap.netmask_len));
+           else {
+             ifa->ifa_netmask = (struct sockaddr *)data;
+             ifa_make_sockaddr(nlm_family, ifa->ifa_netmask, ifamap.netmask, ifamap.netmask_len,
+                               nlm_scope, nlm_index);
+             data += NLMSG_ALIGN(ifa_sa_len(nlm_family, ifamap.netmask_len));
+           }
+         }
+#endif
+         if (ifamap.broadcast) {
+           if (!build)
+             dlen += NLMSG_ALIGN(ifa_sa_len(nlm_family,ifamap.broadcast_len));
+           else {
+             ifa->ifa_broadaddr = (struct sockaddr *)data;
+             ifa_make_sockaddr(nlm_family, ifa->ifa_broadaddr, ifamap.broadcast, ifamap.broadcast_len,
+                               nlm_scope, nlm_index);
+             data += NLMSG_ALIGN(ifa_sa_len(nlm_family, ifamap.broadcast_len));
+           }
+         }
+#ifdef HAVE_IFADDRS_IFA_ANYCAST
+         if (ifamap.anycast) {
+           if (!build)
+             dlen += NLMSG_ALIGN(ifa_sa_len(nlm_family,ifamap.anycast_len));
+           else {
+             ifa->ifa_anycast = (struct sockaddr *)data;
+             ifa_make_sockaddr(nlm_family, ifa->ifa_anyaddr, ifamap.anycast, ifamap.anycast_len,
+                               nlm_scope, nlm_index);
+             data += NLMSG_ALIGN(ifa_sa_len(nlm_family, ifamap.anycast_len));
+           }
+         }
+#endif
+       }
+       if (!build){
+#ifndef IFA_NETMASK
+         dlen += sockaddr_size;
+#endif
+         icnt++;
+       } else {
+         if (ifa->ifa_name == NULL)
+           ifa->ifa_name = iflist[nlm_index];
+#ifndef IFA_NETMASK
+         if (ifa->ifa_addr && 
+             ifa->ifa_addr->sa_family != AF_UNSPEC && 
+             ifa->ifa_addr->sa_family != AF_PACKET){
+           ifa->ifa_netmask = (struct sockaddr *)data;
+           ifa_make_sockaddr_mask(ifa->ifa_addr->sa_family, ifa->ifa_netmask, nlm_prefixlen);
+         }
+         data += sockaddr_size;
+#endif
+         ifl = ifa++;
+       }
+      }
+    }
+    if (!build){
+      if (icnt == 0 && (dlen + nlen + xlen == 0)){
+       if (ifap != NULL)
+         *ifap = NULL;
+       break; /* cannot found any addresses */
+      }
+    }
+    else
+      free_data(NULL, ifdata);
+  }
+
+/* ---------------------------------- */
+  /* Finalize */
+  free_nlmsglist(nlmsg_list);
+  nl_close(sd);
+  return 0;
+}
+
+/* ---------------------------------------------------------------------- */
+void ROKEN_LIB_FUNCTION
+freeifaddrs(struct ifaddrs *ifa)
+{
+  free(ifa);
+}
+
+
+#else /* !AF_NETLINK */
+
+/*
+ * The generic SIOCGIFCONF version.
+ */
+
+static int
+getifaddrs2(struct ifaddrs **ifap, 
+           int af, int siocgifconf, int siocgifflags,
+           size_t ifreq_sz)
+{
+    int ret;
+    int fd;
+    size_t buf_size;
+    char *buf;
+    struct ifconf ifconf;
+    char *p;
+    size_t sz;
+    struct sockaddr sa_zero;
+    struct ifreq *ifr;
+    struct ifaddrs *start = NULL, **end = &start;
+
+    buf = NULL;
+
+    memset (&sa_zero, 0, sizeof(sa_zero));
+    fd = socket(af, SOCK_DGRAM, 0);
+    if (fd < 0)
+       return -1;
+
+    buf_size = 8192;
+    for (;;) {
+       buf = calloc(1, buf_size);
+       if (buf == NULL) {
+           ret = ENOMEM;
+           goto error_out;
+       }
+       ifconf.ifc_len = buf_size;
+       ifconf.ifc_buf = buf;
+
+       /*
+        * Solaris returns EINVAL when the buffer is too small.
+        */
+       if (ioctl (fd, siocgifconf, &ifconf) < 0 && errno != EINVAL) {
+           ret = errno;
+           goto error_out;
+       }
+       /*
+        * Can the difference between a full and a overfull buf
+        * be determined?
+        */
+
+       if (ifconf.ifc_len < buf_size)
+           break;
+       free (buf);
+       buf_size *= 2;
+    }
+
+    for (p = ifconf.ifc_buf;
+        p < ifconf.ifc_buf + ifconf.ifc_len;
+        p += sz) {
+       struct ifreq ifreq;
+       struct sockaddr *sa;
+       size_t salen;
+
+       ifr = (struct ifreq *)p;
+       sa  = &ifr->ifr_addr;
+
+       sz = ifreq_sz;
+       salen = sizeof(struct sockaddr);
+#ifdef HAVE_STRUCT_SOCKADDR_SA_LEN
+       salen = sa->sa_len;
+       sz = max(sz, sizeof(ifr->ifr_name) + sa->sa_len);
+#endif
+#ifdef SA_LEN
+       salen = SA_LEN(sa);
+       sz = max(sz, sizeof(ifr->ifr_name) + SA_LEN(sa));
+#endif
+       memset (&ifreq, 0, sizeof(ifreq));
+       memcpy (ifreq.ifr_name, ifr->ifr_name, sizeof(ifr->ifr_name));
+
+       if (ioctl(fd, siocgifflags, &ifreq) < 0) {
+           ret = errno;
+           goto error_out;
+       }
+
+       *end = malloc(sizeof(**end));
+       if (*end == NULL) {
+           ret = ENOMEM;
+           goto error_out;
+       }
+
+       (*end)->ifa_next = NULL;
+       (*end)->ifa_name = strdup(ifr->ifr_name);
+       (*end)->ifa_flags = ifreq.ifr_flags;
+       (*end)->ifa_addr = malloc(salen);
+       memcpy((*end)->ifa_addr, sa, salen);
+       (*end)->ifa_netmask = NULL;
+
+#if 0
+       /* fix these when we actually need them */
+       if(ifreq.ifr_flags & IFF_BROADCAST) {
+           (*end)->ifa_broadaddr = malloc(sizeof(ifr->ifr_broadaddr));
+           memcpy((*end)->ifa_broadaddr, &ifr->ifr_broadaddr, 
+                  sizeof(ifr->ifr_broadaddr));
+       } else if(ifreq.ifr_flags & IFF_POINTOPOINT) {
+           (*end)->ifa_dstaddr = malloc(sizeof(ifr->ifr_dstaddr));
+           memcpy((*end)->ifa_dstaddr, &ifr->ifr_dstaddr, 
+                  sizeof(ifr->ifr_dstaddr));
+       } else
+           (*end)->ifa_dstaddr = NULL;
+#else
+           (*end)->ifa_dstaddr = NULL;
+#endif
+
+       (*end)->ifa_data = NULL;
+
+       end = &(*end)->ifa_next;
+       
+    }
+    *ifap = start;
+    close(fd);
+    free(buf);
+    return 0;
+  error_out:
+    freeifaddrs(start);
+    close(fd);
+    free(buf);
+    errno = ret;
+    return -1;
+}
+
+#if defined(HAVE_IPV6) && defined(SIOCGLIFCONF) && defined(SIOCGLIFFLAGS)
+static int
+getlifaddrs2(struct ifaddrs **ifap, 
+            int af, int siocgifconf, int siocgifflags,
+            size_t ifreq_sz)
+{
+    int ret;
+    int fd;
+    size_t buf_size;
+    char *buf;
+    struct lifconf ifconf;
+    char *p;
+    size_t sz;
+    struct sockaddr sa_zero;
+    struct lifreq *ifr;
+    struct ifaddrs *start = NULL, **end = &start;
+
+    buf = NULL;
+
+    memset (&sa_zero, 0, sizeof(sa_zero));
+    fd = socket(af, SOCK_DGRAM, 0);
+    if (fd < 0)
+       return -1;
+
+    buf_size = 8192;
+    for (;;) {
+       buf = calloc(1, buf_size);
+       if (buf == NULL) {
+           ret = ENOMEM;
+           goto error_out;
+       }
+       ifconf.lifc_family = AF_UNSPEC;
+       ifconf.lifc_flags  = 0;
+       ifconf.lifc_len    = buf_size;
+       ifconf.lifc_buf    = buf;
+
+       /*
+        * Solaris returns EINVAL when the buffer is too small.
+        */
+       if (ioctl (fd, siocgifconf, &ifconf) < 0 && errno != EINVAL) {
+           ret = errno;
+           goto error_out;
+       }
+       /*
+        * Can the difference between a full and a overfull buf
+        * be determined?
+        */
+
+       if (ifconf.lifc_len < buf_size)
+           break;
+       free (buf);
+       buf_size *= 2;
+    }
+
+    for (p = ifconf.lifc_buf;
+        p < ifconf.lifc_buf + ifconf.lifc_len;
+        p += sz) {
+       struct lifreq ifreq;
+       struct sockaddr_storage *sa;
+       size_t salen;
+
+       ifr = (struct lifreq *)p;
+       sa  = &ifr->lifr_addr;
+
+       sz = ifreq_sz;
+       salen = sizeof(struct sockaddr_storage);
+#ifdef HAVE_STRUCT_SOCKADDR_SA_LEN
+       salen = sa->sa_len;
+       sz = max(sz, sizeof(ifr->ifr_name) + sa->sa_len);
+#endif
+#ifdef SA_LEN
+       salen = SA_LEN(sa);
+       sz = max(sz, sizeof(ifr->ifr_name) + SA_LEN(sa));
+#endif
+       memset (&ifreq, 0, sizeof(ifreq));
+       memcpy (ifreq.lifr_name, ifr->lifr_name, sizeof(ifr->lifr_name));
+
+       if (ioctl(fd, siocgifflags, &ifreq) < 0) {
+           ret = errno;
+           goto error_out;
+       }
+
+       *end = malloc(sizeof(**end));
+
+       (*end)->ifa_next = NULL;
+       (*end)->ifa_name = strdup(ifr->lifr_name);
+       (*end)->ifa_flags = ifreq.lifr_flags;
+       (*end)->ifa_addr = malloc(salen);
+       memcpy((*end)->ifa_addr, sa, salen);
+       (*end)->ifa_netmask = NULL;
+
+#if 0
+       /* fix these when we actually need them */
+       if(ifreq.ifr_flags & IFF_BROADCAST) {
+           (*end)->ifa_broadaddr = malloc(sizeof(ifr->ifr_broadaddr));
+           memcpy((*end)->ifa_broadaddr, &ifr->ifr_broadaddr, 
+                  sizeof(ifr->ifr_broadaddr));
+       } else if(ifreq.ifr_flags & IFF_POINTOPOINT) {
+           (*end)->ifa_dstaddr = malloc(sizeof(ifr->ifr_dstaddr));
+           memcpy((*end)->ifa_dstaddr, &ifr->ifr_dstaddr, 
+                  sizeof(ifr->ifr_dstaddr));
+       } else
+           (*end)->ifa_dstaddr = NULL;
+#else
+           (*end)->ifa_dstaddr = NULL;
+#endif
+
+       (*end)->ifa_data = NULL;
+
+       end = &(*end)->ifa_next;
+       
+    }
+    *ifap = start;
+    close(fd);
+    free(buf);
+    return 0;
+  error_out:
+    freeifaddrs(start);
+    close(fd);
+    free(buf);
+    errno = ret;
+    return -1;
+}
+#endif /* defined(HAVE_IPV6) && defined(SIOCGLIFCONF) && defined(SIOCGLIFFLAGS) */
+
+int ROKEN_LIB_FUNCTION
+getifaddrs(struct ifaddrs **ifap) 
+{
+    int ret = -1;
+    errno = ENXIO;
+#if defined(AF_INET6) && defined(SIOCGIF6CONF) && defined(SIOCGIF6FLAGS)
+    if (ret)
+       ret = getifaddrs2 (ifap, AF_INET6, SIOCGIF6CONF, SIOCGIF6FLAGS,
+                          sizeof(struct in6_ifreq));
+#endif
+#if defined(HAVE_IPV6) && defined(SIOCGLIFCONF) && defined(SIOCGLIFFLAGS)
+    if (ret)
+       ret = getlifaddrs2 (ifap, AF_INET6, SIOCGLIFCONF, SIOCGLIFFLAGS,
+                           sizeof(struct lifreq));
+#endif
+#if defined(HAVE_IPV6) && defined(SIOCGIFCONF)
+    if (ret)
+       ret = getifaddrs2 (ifap, AF_INET6, SIOCGIFCONF, SIOCGIFFLAGS,
+                          sizeof(struct ifreq));
+#endif
+#if defined(AF_INET) && defined(SIOCGIFCONF) && defined(SIOCGIFFLAGS)
+    if (ret)
+       ret = getifaddrs2 (ifap, AF_INET, SIOCGIFCONF, SIOCGIFFLAGS,
+                          sizeof(struct ifreq));
+#endif
+    return ret;
+}
+
+void ROKEN_LIB_FUNCTION
+freeifaddrs(struct ifaddrs *ifp)
+{
+    struct ifaddrs *p, *q;
+    
+    for(p = ifp; p; ) {
+       free(p->ifa_name);
+       if(p->ifa_addr)
+           free(p->ifa_addr);
+       if(p->ifa_dstaddr) 
+           free(p->ifa_dstaddr);
+       if(p->ifa_netmask) 
+           free(p->ifa_netmask);
+       if(p->ifa_data)
+           free(p->ifa_data);
+       q = p;
+       p = p->ifa_next;
+       free(q);
+    }
+}
+
+#endif /* !AF_NETLINK */
+
+#ifdef TEST
+
+void
+print_addr(const char *s, struct sockaddr *sa)
+{
+    int i;
+    printf("  %s=%d/", s, sa->sa_family);
+#ifdef HAVE_STRUCT_SOCKADDR_SA_LEN
+    for(i = 0; i < sa->sa_len - ((long)sa->sa_data - (long)&sa->sa_family); i++)
+       printf("%02x", ((unsigned char*)sa->sa_data)[i]);
+#else
+    for(i = 0; i < sizeof(sa->sa_data); i++) 
+       printf("%02x", ((unsigned char*)sa->sa_data)[i]);
+#endif
+    printf("\n");
+}
+
+void 
+print_ifaddrs(struct ifaddrs *x)
+{
+    struct ifaddrs *p;
+    
+    for(p = x; p; p = p->ifa_next) {
+       printf("%s\n", p->ifa_name);
+       printf("  flags=%x\n", p->ifa_flags);
+       if(p->ifa_addr)
+           print_addr("addr", p->ifa_addr);
+       if(p->ifa_dstaddr) 
+           print_addr("dstaddr", p->ifa_dstaddr);
+       if(p->ifa_netmask) 
+           print_addr("netmask", p->ifa_netmask);
+       printf("  %p\n", p->ifa_data);
+    }
+}
+
+int
+main()
+{
+    struct ifaddrs *a = NULL, *b;
+    getifaddrs2(&a, AF_INET, SIOCGIFCONF, SIOCGIFFLAGS, sizeof(struct ifreq));
+    print_ifaddrs(a);
+    printf("---\n");
+    getifaddrs(&b);
+    print_ifaddrs(b);
+    return 0;
+}
+#endif
diff --git a/source4/heimdal/lib/roken/getprogname.c b/source4/heimdal/lib/roken/getprogname.c
new file mode 100644 (file)
index 0000000..f8f1e9d
--- /dev/null
@@ -0,0 +1,51 @@
+/*
+ * Copyright (c) 1995-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.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+RCSID("$Id: getprogname.c,v 1.3 2005/04/12 11:28:48 lha Exp $");
+#endif
+
+#include "roken.h"
+
+#ifndef HAVE___PROGNAME
+const char *__progname;
+#endif
+
+#ifndef HAVE_GETPROGNAME
+const char * ROKEN_LIB_FUNCTION
+getprogname(void)
+{
+    return __progname;
+}
+#endif /* HAVE_GETPROGNAME */
diff --git a/source4/heimdal/lib/roken/h_errno.c b/source4/heimdal/lib/roken/h_errno.c
new file mode 100644 (file)
index 0000000..c2d4452
--- /dev/null
@@ -0,0 +1,41 @@
+/*
+ * 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.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+RCSID("$Id: h_errno.c,v 1.1 2001/08/08 03:47:23 assar Exp $");
+#endif
+
+#ifndef HAVE_H_ERRNO
+int h_errno = -17; /* Some magic number */
+#endif
diff --git a/source4/heimdal/lib/roken/issuid.c b/source4/heimdal/lib/roken/issuid.c
new file mode 100644 (file)
index 0000000..7ccf615
--- /dev/null
@@ -0,0 +1,59 @@
+/*
+ * 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. 
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+RCSID("$Id: issuid.c,v 1.6 2005/05/13 07:42:03 lha Exp $");
+#endif
+
+#include "roken.h"
+
+int ROKEN_LIB_FUNCTION
+issuid(void)
+{
+#if defined(HAVE_ISSETUGID)
+    return issetugid();
+#else /* !HAVE_ISSETUGID */
+
+#if defined(HAVE_GETUID) && defined(HAVE_GETEUID)
+    if(getuid() != geteuid())
+       return 1;
+#endif
+#if defined(HAVE_GETGID) && defined(HAVE_GETEGID)
+    if(getgid() != getegid())
+       return 2;
+#endif
+
+    return 0;
+#endif /* HAVE_ISSETUGID */
+}
diff --git a/source4/heimdal/lib/roken/net_read.c b/source4/heimdal/lib/roken/net_read.c
new file mode 100644 (file)
index 0000000..f8d4dd1
--- /dev/null
@@ -0,0 +1,74 @@
+/*
+ * Copyright (c) 1995, 1996, 1997, 1998 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.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+RCSID("$Id: net_read.c,v 1.4 2005/04/12 11:28:57 lha Exp $");
+#endif
+
+#include <sys/types.h>
+#include <unistd.h>
+#include <errno.h>
+
+#include <roken.h>
+
+/*
+ * Like read but never return partial data.
+ */
+
+ssize_t ROKEN_LIB_FUNCTION
+net_read (int fd, void *buf, size_t nbytes)
+{
+    char *cbuf = (char *)buf;
+    ssize_t count;
+    size_t rem = nbytes;
+
+    while (rem > 0) {
+#ifdef WIN32
+       count = recv (fd, cbuf, rem, 0);
+#else
+       count = read (fd, cbuf, rem);
+#endif
+       if (count < 0) {
+           if (errno == EINTR)
+               continue;
+           else
+               return count;
+       } else if (count == 0) {
+           return count;
+       }
+       cbuf += count;
+       rem -= count;
+    }
+    return nbytes;
+}
diff --git a/source4/heimdal/lib/roken/net_write.c b/source4/heimdal/lib/roken/net_write.c
new file mode 100644 (file)
index 0000000..83d14f4
--- /dev/null
@@ -0,0 +1,72 @@
+/*
+ * Copyright (c) 1995, 1996, 1997, 1998 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.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+RCSID("$Id: net_write.c,v 1.5 2005/04/12 11:28:58 lha Exp $");
+#endif
+
+#include <sys/types.h>
+#include <unistd.h>
+#include <errno.h>
+
+#include <roken.h>
+
+/*
+ * Like write but never return partial data.
+ */
+
+ssize_t ROKEN_LIB_FUNCTION
+net_write (int fd, const void *buf, size_t nbytes)
+{
+    const char *cbuf = (const char *)buf;
+    ssize_t count;
+    size_t rem = nbytes;
+
+    while (rem > 0) {
+#ifdef WIN32
+       count = send (fd, cbuf, rem, 0);
+#else
+       count = write (fd, cbuf, rem);
+#endif
+       if (count < 0) {
+           if (errno == EINTR)
+               continue;
+           else
+               return count;
+       }
+       cbuf += count;
+       rem -= count;
+    }
+    return nbytes;
+}
diff --git a/source4/heimdal/lib/roken/parse_time.c b/source4/heimdal/lib/roken/parse_time.c
new file mode 100644 (file)
index 0000000..551bee3
--- /dev/null
@@ -0,0 +1,78 @@
+/*
+ * Copyright (c) 1997, 1998 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. 
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+RCSID("$Id: parse_time.c,v 1.7 2005/04/12 11:28:58 lha Exp $");
+#endif
+
+#include <parse_units.h>
+#include "parse_time.h"
+
+static struct units time_units[] = {
+    {"year",   365 * 24 * 60 * 60},
+    {"month",  30 * 24 * 60 * 60},
+    {"week",   7 * 24 * 60 * 60},
+    {"day",    24 * 60 * 60},
+    {"hour",   60 * 60},
+    {"h",      60 * 60},
+    {"minute", 60},
+    {"m",      60},
+    {"second", 1},
+    {"s",      1},
+    {NULL, 0},
+};
+
+int ROKEN_LIB_FUNCTION
+parse_time (const char *s, const char *def_unit)
+{
+    return parse_units (s, time_units, def_unit);
+}
+
+size_t ROKEN_LIB_FUNCTION
+unparse_time (int t, char *s, size_t len)
+{
+    return unparse_units (t, time_units, s, len);
+}
+
+size_t ROKEN_LIB_FUNCTION
+unparse_time_approx (int t, char *s, size_t len)
+{
+    return unparse_units_approx (t, time_units, s, len);
+}
+
+void ROKEN_LIB_FUNCTION
+print_time_table (FILE *f)
+{
+    print_units_table (time_units, f);
+}
diff --git a/source4/heimdal/lib/roken/parse_time.h b/source4/heimdal/lib/roken/parse_time.h
new file mode 100644 (file)
index 0000000..5c9de87
--- /dev/null
@@ -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. 
+ */
+
+/* $Id: parse_time.h,v 1.5 2005/04/12 11:28:59 lha Exp $ */
+
+#ifndef __PARSE_TIME_H__
+#define __PARSE_TIME_H__
+
+#ifndef ROKEN_LIB_FUNCTION
+#ifdef _WIN32
+#define ROKEN_LIB_FUNCTION _stdcall
+#else
+#define ROKEN_LIB_FUNCTION
+#endif
+#endif
+
+int
+parse_time (const char *s, const char *def_unit);
+
+size_t
+unparse_time (int t, char *s, size_t len);
+
+size_t
+unparse_time_approx (int t, char *s, size_t len);
+
+void
+print_time_table (FILE *f);
+
+#endif /* __PARSE_TIME_H__ */
diff --git a/source4/heimdal/lib/roken/parse_units.c b/source4/heimdal/lib/roken/parse_units.c
new file mode 100644 (file)
index 0000000..5b01937
--- /dev/null
@@ -0,0 +1,330 @@
+/*
+ * 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. 
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+RCSID("$Id: parse_units.c,v 1.18 2005/04/12 11:28:59 lha Exp $");
+#endif
+
+#include <stdio.h>
+#include <ctype.h>
+#include <string.h>
+#include <roken.h>
+#include "parse_units.h"
+
+/*
+ * Parse string in `s' according to `units' and return value.
+ * def_unit defines the default unit.
+ */
+
+static int
+parse_something (const char *s, const struct units *units,
+                const char *def_unit,
+                int (*func)(int res, int val, unsigned mult),
+                int init,
+                int accept_no_val_p)
+{
+    const char *p;
+    int res = init;
+    unsigned def_mult = 1;
+
+    if (def_unit != NULL) {
+       const struct units *u;
+
+       for (u = units; u->name; ++u) {
+           if (strcasecmp (u->name, def_unit) == 0) {
+               def_mult = u->mult;
+               break;
+           }
+       }
+       if (u->name == NULL)
+           return -1;
+    }
+
+    p = s;
+    while (*p) {
+       double val;
+       char *next;
+       const struct units *u, *partial_unit;
+       size_t u_len;
+       unsigned partial;
+       int no_val_p = 0;
+
+       while(isspace((unsigned char)*p) || *p == ',')
+           ++p;
+
+       val = strtod (p, &next); /* strtol(p, &next, 0); */
+       if (p == next) {
+           val = 0;
+           if(!accept_no_val_p)
+               return -1;
+           no_val_p = 1;
+       }
+       p = next;
+       while (isspace((unsigned char)*p))
+           ++p;
+       if (*p == '\0') {
+           res = (*func)(res, val, def_mult);
+           if (res < 0)
+               return res;
+           break;
+       } else if (*p == '+') {
+           ++p;
+           val = 1;
+       } else if (*p == '-') {
+           ++p;
+           val = -1;
+       }
+       if (no_val_p && val == 0)
+           val = 1;
+       u_len = strcspn (p, ", \t");
+       partial = 0;
+       partial_unit = NULL;
+       if (u_len > 1 && p[u_len - 1] == 's')
+           --u_len;
+       for (u = units; u->name; ++u) {
+           if (strncasecmp (p, u->name, u_len) == 0) {
+               if (u_len == strlen (u->name)) {
+                   p += u_len;
+                   res = (*func)(res, val, u->mult);
+                   if (res < 0)
+                       return res;
+                   break;
+               } else {
+                   ++partial;
+                   partial_unit = u;
+               }
+           }
+       }
+       if (u->name == NULL) {
+           if (partial == 1) {
+               p += u_len;
+               res = (*func)(res, val, partial_unit->mult);
+               if (res < 0)
+                   return res;
+           } else {
+               return -1;
+           }
+       }
+       if (*p == 's')
+           ++p;
+    }
+    return res;
+}
+
+/*
+ * The string consists of a sequence of `n unit'
+ */
+
+static int
+acc_units(int res, int val, unsigned mult)
+{
+    return res + val * mult;
+}
+
+int ROKEN_LIB_FUNCTION
+parse_units (const char *s, const struct units *units,
+            const char *def_unit)
+{
+    return parse_something (s, units, def_unit, acc_units, 0, 0);
+}
+
+/*
+ * The string consists of a sequence of `[+-]flag'.  `orig' consists
+ * the original set of flags, those are then modified and returned as
+ * the function value.
+ */
+
+static int
+acc_flags(int res, int val, unsigned mult)
+{
+    if(val == 1)
+       return res | mult;
+    else if(val == -1)
+       return res & ~mult;
+    else if (val == 0)
+       return mult;
+    else
+       return -1;
+}
+
+int ROKEN_LIB_FUNCTION
+parse_flags (const char *s, const struct units *units,
+            int orig)
+{
+    return parse_something (s, units, NULL, acc_flags, orig, 1);
+}
+
+/*
+ * Return a string representation according to `units' of `num' in `s'
+ * with maximum length `len'.  The actual length is the function value.
+ */
+
+static int
+unparse_something (int num, const struct units *units, char *s, size_t len,
+                  int (*print) (char *, size_t, int, const char *, int),
+                  int (*update) (int, unsigned),
+                  const char *zero_string)
+{
+    const struct units *u;
+    int ret = 0, tmp;
+
+    if (num == 0)
+       return snprintf (s, len, "%s", zero_string);
+
+    for (u = units; num > 0 && u->name; ++u) {
+       int divisor;
+
+       divisor = num / u->mult;
+       if (divisor) {
+           num = (*update) (num, u->mult);
+           tmp = (*print) (s, len, divisor, u->name, num);
+           if (tmp < 0)
+               return tmp;
+           if (tmp > len) {
+               len = 0;
+               s = NULL;
+           } else {
+               len -= tmp;
+               s += tmp;
+           }
+           ret += tmp;
+       }
+    }
+    return ret;
+}
+
+static int
+print_unit (char *s, size_t len, int divisor, const char *name, int rem)
+{
+    return snprintf (s, len, "%u %s%s%s",
+                    divisor, name,
+                    divisor == 1 ? "" : "s",
+                    rem > 0 ? " " : "");
+}
+
+static int
+update_unit (int in, unsigned mult)
+{
+    return in % mult;
+}
+
+static int
+update_unit_approx (int in, unsigned mult)
+{
+    if (in / mult > 0)
+       return 0;
+    else
+       return update_unit (in, mult);
+}
+
+int ROKEN_LIB_FUNCTION
+unparse_units (int num, const struct units *units, char *s, size_t len)
+{
+    return unparse_something (num, units, s, len,
+                             print_unit,
+                             update_unit,
+                             "0");
+}
+
+int ROKEN_LIB_FUNCTION
+unparse_units_approx (int num, const struct units *units, char *s, size_t len)
+{
+    return unparse_something (num, units, s, len,
+                             print_unit,
+                             update_unit_approx,
+                             "0");
+}
+
+void ROKEN_LIB_FUNCTION
+print_units_table (const struct units *units, FILE *f)
+{
+    const struct units *u, *u2;
+    unsigned max_sz = 0;
+
+    for (u = units; u->name; ++u) {
+       max_sz = max(max_sz, strlen(u->name));
+    }
+
+    for (u = units; u->name;) {
+       char buf[1024];
+       const struct units *next;
+
+       for (next = u + 1; next->name && next->mult == u->mult; ++next)
+           ;
+
+       if (next->name) {
+           for (u2 = next;
+                u2->name && u->mult % u2->mult != 0;
+                ++u2)
+               ;
+           if (u2->name == NULL)
+               --u2;
+           unparse_units (u->mult, u2, buf, sizeof(buf));
+           fprintf (f, "1 %*s = %s\n", max_sz, u->name, buf);
+       } else {
+           fprintf (f, "1 %s\n", u->name);
+       }
+       u = next;
+    }
+}
+
+static int
+print_flag (char *s, size_t len, int divisor, const char *name, int rem)
+{
+    return snprintf (s, len, "%s%s", name, rem > 0 ? ", " : "");
+}
+
+static int
+update_flag (int in, unsigned mult)
+{
+    return in - mult;
+}
+
+int ROKEN_LIB_FUNCTION
+unparse_flags (int num, const struct units *units, char *s, size_t len)
+{
+    return unparse_something (num, units, s, len,
+                             print_flag,
+                             update_flag,
+                             "");
+}
+
+void ROKEN_LIB_FUNCTION
+print_flags_table (const struct units *units, FILE *f)
+{
+    const struct units *u;
+
+    for(u = units; u->name; ++u)
+       fprintf(f, "%s%s", u->name, (u+1)->name ? ", " : "\n");
+}
diff --git a/source4/heimdal/lib/roken/parse_units.h b/source4/heimdal/lib/roken/parse_units.h
new file mode 100644 (file)
index 0000000..9d01926
--- /dev/null
@@ -0,0 +1,79 @@
+/*
+ * 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. 
+ */
+
+/* $Id: parse_units.h,v 1.9 2005/04/12 11:28:59 lha Exp $ */
+
+#ifndef __PARSE_UNITS_H__
+#define __PARSE_UNITS_H__
+
+#include <stdio.h>
+#include <stddef.h>
+
+#ifndef ROKEN_LIB_FUNCTION
+#ifdef _WIN32
+#define ROKEN_LIB_FUNCTION _stdcall
+#else
+#define ROKEN_LIB_FUNCTION
+#endif
+#endif
+
+struct units {
+    const char *name;
+    unsigned mult;
+};
+
+int ROKEN_LIB_FUNCTION
+parse_units (const char *s, const struct units *units,
+            const char *def_unit);
+
+void ROKEN_LIB_FUNCTION
+print_units_table (const struct units *units, FILE *f);
+
+int ROKEN_LIB_FUNCTION
+parse_flags (const char *s, const struct units *units,
+            int orig);
+
+int ROKEN_LIB_FUNCTION
+unparse_units (int num, const struct units *units, char *s, size_t len);
+
+int ROKEN_LIB_FUNCTION
+unparse_units_approx (int num, const struct units *units, char *s,
+                     size_t len);
+
+int ROKEN_LIB_FUNCTION
+unparse_flags (int num, const struct units *units, char *s, size_t len);
+
+void ROKEN_LIB_FUNCTION
+print_flags_table (const struct units *units, FILE *f);
+
+#endif /* __PARSE_UNITS_H__ */
diff --git a/source4/heimdal/lib/roken/print_version.c b/source4/heimdal/lib/roken/print_version.c
new file mode 100644 (file)
index 0000000..9d67805
--- /dev/null
@@ -0,0 +1,78 @@
+/*
+ * 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. 
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+RCSID("$Id: print_version.c,v 1.9 2005/04/12 11:29:00 lha Exp $");
+#endif
+#include "roken.h"
+
+#include "print_version.h"
+
+void ROKEN_LIB_FUNCTION
+print_version(const char *progname)
+{
+    const char *arg[] = VERSIONLIST;
+    const int num_args = sizeof(arg) / sizeof(arg[0]);
+    char *msg;
+    size_t len = 0;
+    int i;
+    
+    if(progname == NULL)
+       progname = getprogname();
+    
+    if(num_args == 0)
+       msg = "no version information";
+    else {
+       for(i = 0; i < num_args; i++) {
+           if(i > 0)
+               len += 2;
+           len += strlen(arg[i]);
+       }
+       msg = malloc(len + 1);
+       if(msg == NULL) {
+           fprintf(stderr, "%s: out of memory\n", progname);
+           return;
+       }
+       msg[0] = '\0';
+       for(i = 0; i < num_args; i++) {
+           if(i > 0)
+               strcat(msg, ", ");
+           strcat(msg, arg[i]);
+       }
+    }
+    fprintf(stderr, "%s (%s)\n", progname, msg);
+    fprintf(stderr, "Copyright (c) 1999 - 2001 Kungliga Tekniska Högskolan\n");
+    if(num_args != 0)
+       free(msg);
+}
diff --git a/source4/heimdal/lib/roken/resolve.c b/source4/heimdal/lib/roken/resolve.c
new file mode 100644 (file)
index 0000000..46a1e4d
--- /dev/null
@@ -0,0 +1,690 @@
+/*
+ * Copyright (c) 1995 - 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.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+#include "roken.h"
+#ifdef HAVE_ARPA_NAMESER_H
+#include <arpa/nameser.h>
+#endif
+#ifdef HAVE_RESOLV_H
+#include <resolv.h>
+#endif
+#include "resolve.h"
+
+#include <assert.h>
+
+RCSID("$Id: resolve.c,v 1.51 2005/06/16 16:46:16 lha Exp $");
+
+#ifdef _AIX /* AIX have broken res_nsearch() in 5.1 (5.0 also ?) */
+#undef HAVE_RES_NSEARCH
+#endif
+
+#define DECL(X) {#X, rk_ns_t_##X}
+
+static struct stot{
+    const char *name;
+    int type;
+}stot[] = {
+    DECL(a),
+    DECL(aaaa),
+    DECL(ns),
+    DECL(cname),
+    DECL(soa),
+    DECL(ptr),
+    DECL(mx),
+    DECL(txt),
+    DECL(afsdb),
+    DECL(sig),
+    DECL(key),
+    DECL(srv),
+    DECL(naptr),
+    DECL(sshfp),
+    DECL(ds),
+    {NULL,     0}
+};
+
+int _resolve_debug = 0;
+
+int ROKEN_LIB_FUNCTION
+dns_string_to_type(const char *name)
+{
+    struct stot *p = stot;
+    for(p = stot; p->name; p++)
+       if(strcasecmp(name, p->name) == 0)
+           return p->type;
+    return -1;
+}
+
+const char * ROKEN_LIB_FUNCTION
+dns_type_to_string(int type)
+{
+    struct stot *p = stot;
+    for(p = stot; p->name; p++)
+       if(type == p->type)
+           return p->name;
+    return NULL;
+}
+
+#if (defined(HAVE_RES_SEARCH) || defined(HAVE_RES_NSEARCH)) && defined(HAVE_DN_EXPAND)
+
+void ROKEN_LIB_FUNCTION
+dns_free_data(struct dns_reply *r)
+{
+    struct resource_record *rr;
+    if(r->q.domain)
+       free(r->q.domain);
+    for(rr = r->head; rr;){
+       struct resource_record *tmp = rr;
+       if(rr->domain)
+           free(rr->domain);
+       if(rr->u.data)
+           free(rr->u.data);
+       rr = rr->next;
+       free(tmp);
+    }
+    free (r);
+}
+
+static int
+parse_record(const unsigned char *data, const unsigned char *end_data, 
+            const unsigned char **pp, struct resource_record **rr)
+{
+    int type, class, ttl, size;
+    int status;
+    char host[MAXDNAME];
+    const unsigned char *p = *pp;
+    status = dn_expand(data, end_data, p, host, sizeof(host));
+    if(status < 0) 
+       return -1;
+    if (p + status + 10 > end_data)
+       return -1;
+    p += status;
+    type = (p[0] << 8) | p[1];
+    p += 2;
+    class = (p[0] << 8) | p[1];
+    p += 2;
+    ttl = (p[0] << 24) | (p[1] << 16) | (p[2] << 8) | p[3];
+    p += 4;
+    size = (p[0] << 8) | p[1];
+    p += 2;
+
+    if (p + size > end_data)
+       return -1;
+
+    *rr = calloc(1, sizeof(**rr));
+    if(*rr == NULL) 
+       return -1;
+    (*rr)->domain = strdup(host);
+    if((*rr)->domain == NULL) {
+       free(*rr);
+       return -1;
+    }
+    (*rr)->type = type;
+    (*rr)->class = class;
+    (*rr)->ttl = ttl;
+    (*rr)->size = size;
+    switch(type){
+    case rk_ns_t_ns:
+    case rk_ns_t_cname:
+    case rk_ns_t_ptr:
+       status = dn_expand(data, end_data, p, host, sizeof(host));
+       if(status < 0) {
+           free(*rr);
+           return -1;
+       }
+       (*rr)->u.txt = strdup(host);
+       if((*rr)->u.txt == NULL) {
+           free(*rr);
+           return -1;
+       }
+       break;
+    case rk_ns_t_mx:
+    case rk_ns_t_afsdb:{
+       size_t hostlen;
+
+       status = dn_expand(data, end_data, p + 2, host, sizeof(host));
+       if(status < 0){
+           free(*rr);
+           return -1;
+       }
+       if (status + 2 > size) {
+           free(*rr);
+           return -1;
+       }
+
+       hostlen = strlen(host);
+       (*rr)->u.mx = (struct mx_record*)malloc(sizeof(struct mx_record) + 
+                                               hostlen);
+       if((*rr)->u.mx == NULL) {
+           free(*rr);
+           return -1;
+       }
+       (*rr)->u.mx->preference = (p[0] << 8) | p[1];
+       strlcpy((*rr)->u.mx->domain, host, hostlen + 1);
+       break;
+    }
+    case rk_ns_t_srv:{
+       size_t hostlen;
+       status = dn_expand(data, end_data, p + 6, host, sizeof(host));
+       if(status < 0){
+           free(*rr);
+           return -1;
+       }
+       if (status + 6 > size) {
+           free(*rr);
+           return -1;
+       }
+
+       hostlen = strlen(host);
+       (*rr)->u.srv = 
+           (struct srv_record*)malloc(sizeof(struct srv_record) + 
+                                      hostlen);
+       if((*rr)->u.srv == NULL) {
+           free(*rr);
+           return -1;
+       }
+       (*rr)->u.srv->priority = (p[0] << 8) | p[1];
+       (*rr)->u.srv->weight = (p[2] << 8) | p[3];
+       (*rr)->u.srv->port = (p[4] << 8) | p[5];
+       strlcpy((*rr)->u.srv->target, host, hostlen + 1);
+       break;
+    }
+    case rk_ns_t_txt:{
+       if(size == 0 || size < *p + 1) {
+           free(*rr);
+           return -1;
+       }
+       (*rr)->u.txt = (char*)malloc(*p + 1);
+       if((*rr)->u.txt == NULL) {
+           free(*rr);
+           return -1;
+       }
+       strncpy((*rr)->u.txt, (const char*)(p + 1), *p);
+       (*rr)->u.txt[*p] = '\0';
+       break;
+    }
+    case rk_ns_t_key : {
+       size_t key_len;
+
+       if (size < 4) {
+           free(*rr);
+           return -1;
+       }
+
+       key_len = size - 4;
+       (*rr)->u.key = malloc (sizeof(*(*rr)->u.key) + key_len - 1);
+       if ((*rr)->u.key == NULL) {
+           free(*rr);
+           return -1;
+       }
+
+       (*rr)->u.key->flags     = (p[0] << 8) | p[1];
+       (*rr)->u.key->protocol  = p[2];
+       (*rr)->u.key->algorithm = p[3];
+       (*rr)->u.key->key_len   = key_len;
+       memcpy ((*rr)->u.key->key_data, p + 4, key_len);
+       break;
+    }
+    case rk_ns_t_sig : {
+       size_t sig_len, hostlen;
+
+       if(size <= 18) {
+           free(*rr);
+           return -1;
+       }
+       status = dn_expand (data, end_data, p + 18, host, sizeof(host));
+       if (status < 0) {
+           free(*rr);
+           return -1;
+       }
+       if (status + 18 > size) {
+           free(*rr);
+           return -1;
+       }
+
+       /* the signer name is placed after the sig_data, to make it
+           easy to free this struture; the size calculation below
+           includes the zero-termination if the structure itself.
+          don't you just love C?
+       */
+       sig_len = size - 18 - status;
+       hostlen = strlen(host);
+       (*rr)->u.sig = malloc(sizeof(*(*rr)->u.sig)
+                             + hostlen + sig_len);
+       if ((*rr)->u.sig == NULL) {
+           free(*rr);
+           return -1;
+       }
+       (*rr)->u.sig->type           = (p[0] << 8) | p[1];
+       (*rr)->u.sig->algorithm      = p[2];
+       (*rr)->u.sig->labels         = p[3];
+       (*rr)->u.sig->orig_ttl       = (p[4] << 24) | (p[5] << 16)
+           | (p[6] << 8) | p[7];
+       (*rr)->u.sig->sig_expiration = (p[8] << 24) | (p[9] << 16)
+           | (p[10] << 8) | p[11];
+       (*rr)->u.sig->sig_inception  = (p[12] << 24) | (p[13] << 16)
+           | (p[14] << 8) | p[15];
+       (*rr)->u.sig->key_tag        = (p[16] << 8) | p[17];
+       (*rr)->u.sig->sig_len        = sig_len;
+       memcpy ((*rr)->u.sig->sig_data, p + 18 + status, sig_len);
+       (*rr)->u.sig->signer         = &(*rr)->u.sig->sig_data[sig_len];
+       strlcpy((*rr)->u.sig->signer, host, hostlen + 1);
+       break;
+    }
+
+    case rk_ns_t_cert : {
+       size_t cert_len;
+
+       if (size < 5) {
+           free(*rr);
+           return -1;
+       }
+
+       cert_len = size - 5;
+       (*rr)->u.cert = malloc (sizeof(*(*rr)->u.cert) + cert_len - 1);
+       if ((*rr)->u.cert == NULL) {
+           free(*rr);
+           return -1;
+       }
+
+       (*rr)->u.cert->type      = (p[0] << 8) | p[1];
+       (*rr)->u.cert->tag       = (p[2] << 8) | p[3];
+       (*rr)->u.cert->algorithm = p[4];
+       (*rr)->u.cert->cert_len  = cert_len;
+       memcpy ((*rr)->u.cert->cert_data, p + 5, cert_len);
+       break;
+    }
+    case rk_ns_t_sshfp : {
+       size_t sshfp_len;
+
+       if (size < 2) {
+           free(*rr);
+           return -1;
+       }
+
+       sshfp_len = size - 2;
+
+       (*rr)->u.sshfp = malloc (sizeof(*(*rr)->u.sshfp) + sshfp_len - 1);
+       if ((*rr)->u.sshfp == NULL) {
+           free(*rr);
+           return -1;
+       }
+
+       (*rr)->u.sshfp->algorithm = p[0];
+       (*rr)->u.sshfp->type      = p[1];
+       (*rr)->u.sshfp->sshfp_len  = sshfp_len;
+       memcpy ((*rr)->u.sshfp->sshfp_data, p + 2, sshfp_len);
+       break;
+    }
+    case rk_ns_t_ds: {
+       size_t digest_len;
+
+       if (size < 4) {
+           free(*rr);
+           return -1;
+       }
+
+       digest_len = size - 4;
+
+       (*rr)->u.ds = malloc (sizeof(*(*rr)->u.ds) + digest_len - 1);
+       if ((*rr)->u.ds == NULL) {
+           free(*rr);
+           return -1;
+       }
+
+       (*rr)->u.ds->key_tag     = (p[0] << 8) | p[1];
+       (*rr)->u.ds->algorithm   = p[2];
+       (*rr)->u.ds->digest_type = p[3];
+       (*rr)->u.ds->digest_len  = digest_len;
+       memcpy ((*rr)->u.ds->digest_data, p + 4, digest_len);
+       break;
+    }
+    default:
+       (*rr)->u.data = (unsigned char*)malloc(size);
+       if(size != 0 && (*rr)->u.data == NULL) {
+           free(*rr);
+           return -1;
+       }
+       memcpy((*rr)->u.data, p, size);
+    }
+    *pp = p + size;
+    return 0;
+}
+
+#ifndef TEST_RESOLVE
+static
+#endif
+struct dns_reply*
+parse_reply(const unsigned char *data, size_t len)
+{
+    const unsigned char *p;
+    int status;
+    int i;
+    char host[MAXDNAME];
+    const unsigned char *end_data = data + len;
+    struct dns_reply *r;
+    struct resource_record **rr;
+    
+    r = calloc(1, sizeof(*r));
+    if (r == NULL)
+       return NULL;
+
+    p = data;
+
+    r->h.id = (p[0] << 8) | p[1];
+    r->h.flags = 0;
+    if (p[2] & 0x01)
+       r->h.flags |= rk_DNS_HEADER_RESPONSE_FLAG;
+    r->h.opcode = (p[2] >> 1) & 0xf;
+    if (p[2] & 0x20)
+       r->h.flags |= rk_DNS_HEADER_AUTHORITIVE_ANSWER;
+    if (p[2] & 0x40)
+       r->h.flags |= rk_DNS_HEADER_TRUNCATED_MESSAGE;
+    if (p[2] & 0x80)
+       r->h.flags |= rk_DNS_HEADER_RECURSION_DESIRED;
+    if (p[3] & 0x01)
+       r->h.flags |= rk_DNS_HEADER_RECURSION_AVAILABLE;
+    if (p[3] & 0x04)
+       r->h.flags |= rk_DNS_HEADER_AUTHORITIVE_ANSWER;
+    if (p[3] & 0x08)
+       r->h.flags |= rk_DNS_HEADER_CHECKING_DISABLED;
+    r->h.response_code = (p[3] >> 4) & 0xf;
+    r->h.qdcount = (p[4] << 8) | p[5];
+    r->h.ancount = (p[6] << 8) | p[7];
+    r->h.nscount = (p[8] << 8) | p[9];
+    r->h.arcount = (p[10] << 8) | p[11];
+
+    p += 12;
+
+    if(r->h.qdcount != 1) {
+       free(r);
+       return NULL;
+    }
+    status = dn_expand(data, end_data, p, host, sizeof(host));
+    if(status < 0){
+       dns_free_data(r);
+       return NULL;
+    }
+    r->q.domain = strdup(host);
+    if(r->q.domain == NULL) {
+       dns_free_data(r);
+       return NULL;
+    }
+    if (p + status + 4 > end_data) {
+       dns_free_data(r);
+       return NULL;
+    }
+    p += status;
+    r->q.type = (p[0] << 8 | p[1]);
+    p += 2;
+    r->q.class = (p[0] << 8 | p[1]);
+    p += 2;
+    
+    rr = &r->head;
+    for(i = 0; i < r->h.ancount; i++) {
+       if(parse_record(data, end_data, &p, rr) != 0) {
+           dns_free_data(r);
+           return NULL;
+       }
+       rr = &(*rr)->next;
+    }
+    for(i = 0; i < r->h.nscount; i++) {
+       if(parse_record(data, end_data, &p, rr) != 0) {
+           dns_free_data(r);
+           return NULL;
+       }
+       rr = &(*rr)->next;
+    }
+    for(i = 0; i < r->h.arcount; i++) {
+       if(parse_record(data, end_data, &p, rr) != 0) {
+           dns_free_data(r);
+           return NULL;
+       }
+       rr = &(*rr)->next;
+    }
+    *rr = NULL;
+    return r;
+}
+
+static struct dns_reply *
+dns_lookup_int(const char *domain, int rr_class, int rr_type)
+{
+    struct dns_reply *r;
+    unsigned char *reply = NULL;
+    int size;
+    int len;
+#ifdef HAVE_RES_NSEARCH
+    struct __res_state state;
+    memset(&state, 0, sizeof(state));
+    if(res_ninit(&state))
+       return NULL; /* is this the best we can do? */
+#elif defined(HAVE__RES)
+    u_long old_options = 0;
+#endif
+    
+    size = 0;
+    len = 1000;
+    do {
+       if (reply) {
+           free(reply);
+           reply = NULL;
+       }
+       if (size <= len)
+           size = len;
+       if (_resolve_debug) {
+#ifdef HAVE_RES_NSEARCH
+           state.options |= RES_DEBUG;
+#elif defined(HAVE__RES)
+           old_options = _res.options;
+           _res.options |= RES_DEBUG;
+#endif
+           fprintf(stderr, "dns_lookup(%s, %d, %s), buffer size %d\n", domain,
+                   rr_class, dns_type_to_string(rr_type), size);
+       }
+       reply = malloc(size);
+       if (reply == NULL) {
+#ifdef HAVE_RES_NSEARCH
+           res_nclose(&state);
+#endif
+           return NULL;
+       }
+#ifdef HAVE_RES_NSEARCH
+       len = res_nsearch(&state, domain, rr_class, rr_type, reply, size);
+#else
+       len = res_search(domain, rr_class, rr_type, reply, size);
+#endif
+       if (_resolve_debug) {
+#if defined(HAVE__RES) && !defined(HAVE_RES_NSEARCH)
+           _res.options = old_options;
+#endif
+           fprintf(stderr, "dns_lookup(%s, %d, %s) --> %d\n",
+                   domain, rr_class, dns_type_to_string(rr_type), len);
+       }
+       if (len < 0) {
+#ifdef HAVE_RES_NSEARCH
+           res_nclose(&state);
+#endif
+           free(reply);
+           return NULL;
+       }
+    } while (size < len && len < rk_DNS_MAX_PACKET_SIZE);
+#ifdef HAVE_RES_NSEARCH
+    res_nclose(&state);
+#endif
+
+    len = min(len, size);
+    r = parse_reply(reply, len);
+    free(reply);
+    return r;
+}
+
+struct dns_reply * ROKEN_LIB_FUNCTION
+dns_lookup(const char *domain, const char *type_name)
+{
+    int type;
+    
+    type = dns_string_to_type(type_name);
+    if(type == -1) {
+       if(_resolve_debug)
+           fprintf(stderr, "dns_lookup: unknown resource type: `%s'\n", 
+                   type_name);
+       return NULL;
+    }
+    return dns_lookup_int(domain, C_IN, type);
+}
+
+static int
+compare_srv(const void *a, const void *b)
+{
+    const struct resource_record *const* aa = a, *const* bb = b;
+
+    if((*aa)->u.srv->priority == (*bb)->u.srv->priority)
+       return ((*aa)->u.srv->weight - (*bb)->u.srv->weight);
+    return ((*aa)->u.srv->priority - (*bb)->u.srv->priority);
+}
+
+#ifndef HAVE_RANDOM
+#define random() rand()
+#endif
+
+/* try to rearrange the srv-records by the algorithm in RFC2782 */
+void ROKEN_LIB_FUNCTION
+dns_srv_order(struct dns_reply *r)
+{
+    struct resource_record **srvs, **ss, **headp;
+    struct resource_record *rr;
+    int num_srv = 0;
+
+#if defined(HAVE_INITSTATE) && defined(HAVE_SETSTATE)
+    int state[256 / sizeof(int)];
+    char *oldstate;
+#endif
+
+    for(rr = r->head; rr; rr = rr->next) 
+       if(rr->type == rk_ns_t_srv)
+           num_srv++;
+
+    if(num_srv == 0)
+       return;
+
+    srvs = malloc(num_srv * sizeof(*srvs));
+    if(srvs == NULL)
+       return; /* XXX not much to do here */
+    
+    /* unlink all srv-records from the linked list and put them in
+       a vector */
+    for(ss = srvs, headp = &r->head; *headp; )
+       if((*headp)->type == rk_ns_t_srv) {
+           *ss = *headp;
+           *headp = (*headp)->next;
+           (*ss)->next = NULL;
+           ss++;
+       } else
+           headp = &(*headp)->next;
+    
+    /* sort them by priority and weight */
+    qsort(srvs, num_srv, sizeof(*srvs), compare_srv);
+
+#if defined(HAVE_INITSTATE) && defined(HAVE_SETSTATE)
+    oldstate = initstate(time(NULL), (char*)state, sizeof(state));
+#endif
+
+    headp = &r->head;
+    
+    for(ss = srvs; ss < srvs + num_srv; ) {
+       int sum, rnd, count;
+       struct resource_record **ee, **tt;
+       /* find the last record with the same priority and count the
+           sum of all weights */
+       for(sum = 0, tt = ss; tt < srvs + num_srv; tt++) {
+           if(*tt == NULL)
+               continue;
+           if((*tt)->u.srv->priority != (*ss)->u.srv->priority)
+               break;
+           sum += (*tt)->u.srv->weight;
+       }
+       ee = tt;
+       /* ss is now the first record of this priority and ee is the
+           first of the next */
+       while(ss < ee) {
+           rnd = random() % (sum + 1);
+           for(count = 0, tt = ss; ; tt++) {
+               if(*tt == NULL)
+                   continue;
+               count += (*tt)->u.srv->weight;
+               if(count >= rnd)
+                   break;
+           }
+
+           assert(tt < ee);
+
+           /* insert the selected record at the tail (of the head) of
+               the list */
+           (*tt)->next = *headp;
+           *headp = *tt;
+           headp = &(*tt)->next;
+           sum -= (*tt)->u.srv->weight;
+           *tt = NULL;
+           while(ss < ee && *ss == NULL)
+               ss++;
+       }
+    }
+    
+#if defined(HAVE_INITSTATE) && defined(HAVE_SETSTATE)
+    setstate(oldstate);
+#endif
+    free(srvs);
+    return;
+}
+
+#else /* NOT defined(HAVE_RES_SEARCH) && defined(HAVE_DN_EXPAND) */
+
+struct dns_reply * ROKEN_LIB_FUNCTION
+dns_lookup(const char *domain, const char *type_name)
+{
+    return NULL;
+}
+
+void ROKEN_LIB_FUNCTION
+dns_free_data(struct dns_reply *r)
+{
+}
+
+void ROKEN_LIB_FUNCTION
+dns_srv_order(struct dns_reply *r)
+{
+}
+
+#endif
diff --git a/source4/heimdal/lib/roken/resolve.h b/source4/heimdal/lib/roken/resolve.h
new file mode 100644 (file)
index 0000000..2106c11
--- /dev/null
@@ -0,0 +1,298 @@
+/*
+ * Copyright (c) 1995 - 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: resolve.h,v 1.24 2005/04/12 11:29:02 lha Exp $ */
+
+#ifndef __RESOLVE_H__
+#define __RESOLVE_H__
+
+#ifndef ROKEN_LIB_FUNCTION
+#ifdef _WIN32
+#define ROKEN_LIB_FUNCTION _stdcall
+#else
+#define ROKEN_LIB_FUNCTION
+#endif
+#endif
+
+typedef enum {
+       rk_ns_t_invalid = 0,    /* Cookie. */
+       rk_ns_t_a = 1,          /* Host address. */
+       rk_ns_t_ns = 2,         /* Authoritative server. */
+       rk_ns_t_md = 3,         /* Mail destination. */
+       rk_ns_t_mf = 4,         /* Mail forwarder. */
+       rk_ns_t_cname = 5,      /* Canonical name. */
+       rk_ns_t_soa = 6,        /* Start of authority zone. */
+       rk_ns_t_mb = 7,         /* Mailbox domain name. */
+       rk_ns_t_mg = 8,         /* Mail group member. */
+       rk_ns_t_mr = 9,         /* Mail rename name. */
+       rk_ns_t_null = 10,      /* Null resource record. */
+       rk_ns_t_wks = 11,       /* Well known service. */
+       rk_ns_t_ptr = 12,       /* Domain name pointer. */
+       rk_ns_t_hinfo = 13,     /* Host information. */
+       rk_ns_t_minfo = 14,     /* Mailbox information. */
+       rk_ns_t_mx = 15,        /* Mail routing information. */
+       rk_ns_t_txt = 16,       /* Text strings. */
+       rk_ns_t_rp = 17,        /* Responsible person. */
+       rk_ns_t_afsdb = 18,     /* AFS cell database. */
+       rk_ns_t_x25 = 19,       /* X_25 calling address. */
+       rk_ns_t_isdn = 20,      /* ISDN calling address. */
+       rk_ns_t_rt = 21,        /* Router. */
+       rk_ns_t_nsap = 22,      /* NSAP address. */
+       rk_ns_t_nsap_ptr = 23,  /* Reverse NSAP lookup (deprecated). */
+       rk_ns_t_sig = 24,       /* Security signature. */
+       rk_ns_t_key = 25,       /* Security key. */
+       rk_ns_t_px = 26,        /* X.400 mail mapping. */
+       rk_ns_t_gpos = 27,      /* Geographical position (withdrawn). */
+       rk_ns_t_aaaa = 28,      /* Ip6 Address. */
+       rk_ns_t_loc = 29,       /* Location Information. */
+       rk_ns_t_nxt = 30,       /* Next domain (security). */
+       rk_ns_t_eid = 31,       /* Endpoint identifier. */
+       rk_ns_t_nimloc = 32,    /* Nimrod Locator. */
+       rk_ns_t_srv = 33,       /* Server Selection. */
+       rk_ns_t_atma = 34,      /* ATM Address */
+       rk_ns_t_naptr = 35,     /* Naming Authority PoinTeR */
+       rk_ns_t_kx = 36,        /* Key Exchange */
+       rk_ns_t_cert = 37,      /* Certification record */
+       rk_ns_t_a6 = 38,        /* IPv6 address (deprecates AAAA) */
+       rk_ns_t_dname = 39,     /* Non-terminal DNAME (for IPv6) */
+       rk_ns_t_sink = 40,      /* Kitchen sink (experimentatl) */
+       rk_ns_t_opt = 41,       /* EDNS0 option (meta-RR) */
+       rk_ns_t_apl = 42,       /* Address prefix list (RFC 3123) */
+       rk_ns_t_ds = 43,        /* Delegation Signer (RFC 3658) */
+       rk_ns_t_sshfp = 44,     /* SSH fingerprint */
+       rk_ns_t_tkey = 249,     /* Transaction key */
+       rk_ns_t_tsig = 250,     /* Transaction signature. */
+       rk_ns_t_ixfr = 251,     /* Incremental zone transfer. */
+       rk_ns_t_axfr = 252,     /* Transfer zone of authority. */
+       rk_ns_t_mailb = 253,    /* Transfer mailbox records. */
+       rk_ns_t_maila = 254,    /* Transfer mail agent records. */
+       rk_ns_t_any = 255,      /* Wildcard match. */
+       rk_ns_t_zxfr = 256,     /* BIND-specific, nonstandard. */
+       rk_ns_t_max = 65536
+} rk_ns_type;
+
+/* We use these, but they are not always present in <arpa/nameser.h> */
+
+#ifndef C_IN
+#define C_IN           1
+#endif
+
+#ifndef T_A
+#define T_A            1
+#endif
+#ifndef T_NS
+#define T_NS           2
+#endif
+#ifndef T_CNAME
+#define T_CNAME                5
+#endif
+#ifndef T_SOA
+#define T_SOA          5
+#endif
+#ifndef T_PTR
+#define T_PTR          12
+#endif
+#ifndef T_MX
+#define T_MX           15
+#endif
+#ifndef T_TXT
+#define T_TXT          16
+#endif
+#ifndef T_AFSDB
+#define T_AFSDB                18
+#endif
+#ifndef T_SIG
+#define T_SIG          24
+#endif
+#ifndef T_KEY
+#define T_KEY          25
+#endif
+#ifndef T_AAAA
+#define T_AAAA         28
+#endif
+#ifndef T_SRV
+#define T_SRV          33
+#endif
+#ifndef T_NAPTR
+#define T_NAPTR                35
+#endif
+#ifndef T_CERT
+#define T_CERT         37
+#endif
+#ifndef T_SSHFP
+#define T_SSHFP                44
+#endif
+
+#ifndef MAXDNAME
+#define MAXDNAME       1025
+#endif
+
+#define dns_query              rk_dns_query
+#define mx_record              rk_mx_record
+#define srv_record             rk_srv_record
+#define key_record             rk_key_record
+#define sig_record             rk_sig_record
+#define cert_record            rk_cert_record
+#define sshfp_record           rk_sshfp_record
+#define resource_record                rk_resource_record
+#define dns_reply              rk_dns_reply
+
+#define dns_lookup             rk_dns_lookup
+#define dns_free_data          rk_dns_free_data
+#define dns_string_to_type     rk_dns_string_to_type
+#define dns_type_to_string     rk_dns_type_to_string
+#define dns_srv_order          rk_dns_srv_order
+
+struct dns_query{
+    char *domain;
+    unsigned type;
+    unsigned class;
+};
+
+struct mx_record{
+    unsigned  preference;
+    char domain[1];
+};
+
+struct srv_record{
+    unsigned priority;
+    unsigned weight;
+    unsigned port;
+    char target[1];
+};
+
+struct key_record {
+    unsigned flags;
+    unsigned protocol;
+    unsigned algorithm;
+    size_t   key_len;
+    u_char   key_data[1];
+};
+
+struct sig_record {
+    unsigned type;
+    unsigned algorithm;
+    unsigned labels;
+    unsigned orig_ttl;
+    unsigned sig_expiration;
+    unsigned sig_inception;
+    unsigned key_tag;
+    char     *signer;
+    unsigned sig_len;
+    char     sig_data[1];      /* also includes signer */
+};
+
+struct cert_record {
+    unsigned type;
+    unsigned tag;
+    unsigned algorithm;
+    size_t   cert_len;
+    u_char   cert_data[1];
+};
+
+struct sshfp_record {
+    unsigned algorithm;
+    unsigned type;
+    size_t   sshfp_len;
+    u_char   sshfp_data[1];
+};
+
+struct ds_record {
+    unsigned key_tag;
+    unsigned algorithm;
+    unsigned digest_type;
+    unsigned digest_len;
+    u_char digest_data[1];
+};
+
+struct resource_record{
+    char *domain;
+    unsigned type;
+    unsigned class;
+    unsigned ttl;
+    unsigned size;
+    union {
+       void *data;
+       struct mx_record *mx;
+       struct mx_record *afsdb; /* mx and afsdb are identical */
+       struct srv_record *srv;
+       struct in_addr *a;
+       char *txt;
+       struct key_record *key;
+       struct cert_record *cert;
+       struct sig_record *sig;
+       struct sshfp_record *sshfp;
+       struct ds_record *ds;
+    }u;
+    struct resource_record *next;
+};
+
+#define rk_DNS_MAX_PACKET_SIZE         0xffff
+
+struct dns_header {
+    unsigned id;
+    unsigned flags;
+#define rk_DNS_HEADER_RESPONSE_FLAG            1
+#define rk_DNS_HEADER_AUTHORITIVE_ANSWER       2
+#define rk_DNS_HEADER_TRUNCATED_MESSAGE                4
+#define rk_DNS_HEADER_RECURSION_DESIRED                8
+#define rk_DNS_HEADER_RECURSION_AVAILABLE      16
+#define rk_DNS_HEADER_AUTHENTIC_DATA           32
+#define rk_DNS_HEADER_CHECKING_DISABLED                64
+    unsigned opcode;
+    unsigned response_code;
+    unsigned qdcount;
+    unsigned ancount;
+    unsigned nscount;
+    unsigned arcount;
+};
+
+struct dns_reply{
+    struct dns_header h;
+    struct dns_query q;
+    struct resource_record *head;
+};
+
+
+struct dns_reply* ROKEN_LIB_FUNCTION
+       dns_lookup(const char *, const char *);
+void ROKEN_LIB_FUNCTION
+       dns_free_data(struct dns_reply *);
+int ROKEN_LIB_FUNCTION
+       dns_string_to_type(const char *name);
+const char *ROKEN_LIB_FUNCTION
+       dns_type_to_string(int type);
+void ROKEN_LIB_FUNCTION
+       dns_srv_order(struct dns_reply*);
+
+#endif /* __RESOLVE_H__ */
diff --git a/source4/heimdal/lib/roken/roken-common.h b/source4/heimdal/lib/roken/roken-common.h
new file mode 100644 (file)
index 0000000..d85d55f
--- /dev/null
@@ -0,0 +1,399 @@
+/*
+ * Copyright (c) 1995 - 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.
+ */
+
+/* $Id: roken-common.h,v 1.61 2005/07/07 05:03:30 lha Exp $ */
+
+#ifndef __ROKEN_COMMON_H__
+#define __ROKEN_COMMON_H__
+
+#ifndef ROKEN_LIB_FUNCTION
+#ifdef _WIN32
+#define ROKEN_LIB_FUNCTION _stdcall
+#else
+#define ROKEN_LIB_FUNCTION
+#endif
+#endif
+
+#ifdef __cplusplus
+#define ROKEN_CPP_START        extern "C" {
+#define ROKEN_CPP_END  }
+#else
+#define ROKEN_CPP_START
+#define ROKEN_CPP_END
+#endif
+
+#ifndef INADDR_NONE
+#define INADDR_NONE 0xffffffff
+#endif
+
+#ifndef INADDR_LOOPBACK
+#define INADDR_LOOPBACK 0x7f000001
+#endif
+
+#ifndef SOMAXCONN
+#define SOMAXCONN 5
+#endif
+
+#ifndef STDIN_FILENO
+#define STDIN_FILENO 0
+#endif
+
+#ifndef STDOUT_FILENO
+#define STDOUT_FILENO 1
+#endif
+
+#ifndef STDERR_FILENO
+#define STDERR_FILENO 2
+#endif
+
+#ifndef max
+#define max(a,b) (((a)>(b))?(a):(b))
+#endif
+
+#ifndef min
+#define min(a,b) (((a)<(b))?(a):(b))
+#endif
+
+#ifndef TRUE
+#define TRUE 1
+#endif
+
+#ifndef FALSE
+#define FALSE 0
+#endif
+
+#ifndef LOG_DAEMON
+#define openlog(id,option,facility) openlog((id),(option))
+#define        LOG_DAEMON      0
+#endif
+#ifndef LOG_ODELAY
+#define LOG_ODELAY 0
+#endif
+#ifndef LOG_NDELAY
+#define LOG_NDELAY 0x08
+#endif
+#ifndef LOG_CONS
+#define LOG_CONS 0
+#endif
+#ifndef LOG_AUTH
+#define LOG_AUTH 0
+#endif
+#ifndef LOG_AUTHPRIV
+#define LOG_AUTHPRIV LOG_AUTH
+#endif
+
+#ifndef F_OK
+#define F_OK 0
+#endif
+
+#ifndef O_ACCMODE
+#define O_ACCMODE      003
+#endif
+
+#ifndef _PATH_DEV
+#define _PATH_DEV "/dev/"
+#endif
+
+#ifndef _PATH_DEVNULL
+#define _PATH_DEVNULL "/dev/null"
+#endif
+
+#ifndef _PATH_HEQUIV
+#define _PATH_HEQUIV "/etc/hosts.equiv"
+#endif
+
+#ifndef _PATH_VARRUN
+#define _PATH_VARRUN "/var/run/"
+#endif
+
+#ifndef _PATH_BSHELL
+#define _PATH_BSHELL "/bin/sh"
+#endif
+
+#ifndef MAXPATHLEN
+#define MAXPATHLEN (1024+4)
+#endif
+
+#ifndef SIG_ERR
+#define SIG_ERR ((RETSIGTYPE (*)(int))-1)
+#endif
+
+/*
+ * error code for getipnodeby{name,addr}
+ */
+
+#ifndef HOST_NOT_FOUND
+#define HOST_NOT_FOUND 1
+#endif
+
+#ifndef TRY_AGAIN
+#define TRY_AGAIN 2
+#endif
+
+#ifndef NO_RECOVERY
+#define NO_RECOVERY 3
+#endif
+
+#ifndef NO_DATA
+#define NO_DATA 4
+#endif
+
+#ifndef NO_ADDRESS
+#define NO_ADDRESS NO_DATA
+#endif
+
+/*
+ * error code for getaddrinfo
+ */
+
+#ifndef EAI_NOERROR
+#define EAI_NOERROR    0       /* no error */
+#endif
+
+#ifndef EAI_NONAME
+
+#define EAI_ADDRFAMILY 1       /* address family for nodename not supported */
+#define EAI_AGAIN      2       /* temporary failure in name resolution */
+#define EAI_BADFLAGS   3       /* invalid value for ai_flags */
+#define EAI_FAIL       4       /* non-recoverable failure in name resolution */
+#define EAI_FAMILY     5       /* ai_family not supported */
+#define EAI_MEMORY     6       /* memory allocation failure */
+#define EAI_NODATA     7       /* no address associated with nodename */
+#define EAI_NONAME     8       /* nodename nor servname provided, or not known */
+#define EAI_SERVICE    9       /* servname not supported for ai_socktype */
+#define EAI_SOCKTYPE   10      /* ai_socktype not supported */
+#define EAI_SYSTEM     11      /* system error returned in errno */
+
+#endif /* EAI_NONAME */
+
+/* flags for getaddrinfo() */
+
+#ifndef AI_PASSIVE
+#define AI_PASSIVE     0x01
+#define AI_CANONNAME   0x02
+#endif /* AI_PASSIVE */
+
+#ifndef AI_NUMERICHOST
+#define AI_NUMERICHOST 0x04
+#endif
+
+/* flags for getnameinfo() */
+
+#ifndef NI_DGRAM
+#define NI_DGRAM       0x01
+#define NI_NAMEREQD    0x02
+#define NI_NOFQDN      0x04
+#define NI_NUMERICHOST 0x08
+#define NI_NUMERICSERV 0x10
+#endif
+
+/*
+ * constants for getnameinfo
+ */
+
+#ifndef NI_MAXHOST
+#define NI_MAXHOST  1025
+#define NI_MAXSERV    32
+#endif
+
+/*
+ * constants for inet_ntop
+ */
+
+#ifndef INET_ADDRSTRLEN
+#define INET_ADDRSTRLEN    16
+#endif
+
+#ifndef INET6_ADDRSTRLEN
+#define INET6_ADDRSTRLEN   46
+#endif
+
+/*
+ * for shutdown(2)
+ */
+
+#ifndef SHUT_RD
+#define SHUT_RD 0
+#endif
+
+#ifndef SHUT_WR
+#define SHUT_WR 1
+#endif
+
+#ifndef SHUT_RDWR
+#define SHUT_RDWR 2
+#endif
+
+#ifndef HAVE___ATTRIBUTE__
+#define __attribute__(x)
+#endif
+
+#define rk_UNCONST(x) ((void *)(unsigned long)(const void *)(x))
+
+ROKEN_CPP_START
+
+#ifndef IRIX4 /* fix for compiler bug */
+#ifdef RETSIGTYPE
+typedef RETSIGTYPE (*SigAction)(int);
+SigAction signal(int iSig, SigAction pAction); /* BSD compatible */
+#endif
+#endif
+
+int ROKEN_LIB_FUNCTION
+simple_execve(const char*, char*const[], char*const[]);
+
+int ROKEN_LIB_FUNCTION
+simple_execve_timed(const char *, char *const[], 
+                   char *const [], time_t (*)(void *), 
+                   void *, time_t);
+int ROKEN_LIB_FUNCTION
+simple_execvp(const char*, char *const[]);
+
+int ROKEN_LIB_FUNCTION
+simple_execvp_timed(const char *, char *const[], 
+                   time_t (*)(void *), void *, time_t);
+int ROKEN_LIB_FUNCTION
+simple_execlp(const char*, ...);
+
+int ROKEN_LIB_FUNCTION
+simple_execle(const char*, ...);
+
+int ROKEN_LIB_FUNCTION
+simple_execl(const char *file, ...);
+
+int ROKEN_LIB_FUNCTION
+wait_for_process(pid_t);
+
+int ROKEN_LIB_FUNCTION
+wait_for_process_timed(pid_t, time_t (*)(void *), 
+                                             void *, time_t);
+int ROKEN_LIB_FUNCTION
+pipe_execv(FILE**, FILE**, FILE**, const char*, ...);
+
+void ROKEN_LIB_FUNCTION
+print_version(const char *);
+
+ssize_t ROKEN_LIB_FUNCTION
+eread (int fd, void *buf, size_t nbytes);
+
+ssize_t ROKEN_LIB_FUNCTION
+ewrite (int fd, const void *buf, size_t nbytes);
+
+struct hostent;
+
+const char * ROKEN_LIB_FUNCTION
+hostent_find_fqdn (const struct hostent *he);
+
+void ROKEN_LIB_FUNCTION
+esetenv(const char *var, const char *val, int rewrite);
+
+void ROKEN_LIB_FUNCTION
+socket_set_address_and_port (struct sockaddr *sa, const void *ptr, int port);
+
+size_t ROKEN_LIB_FUNCTION
+socket_addr_size (const struct sockaddr *sa);
+
+void ROKEN_LIB_FUNCTION
+socket_set_any (struct sockaddr *sa, int af);
+
+size_t ROKEN_LIB_FUNCTION
+socket_sockaddr_size (const struct sockaddr *sa);
+
+void * ROKEN_LIB_FUNCTION
+socket_get_address (struct sockaddr *sa);
+
+int ROKEN_LIB_FUNCTION
+socket_get_port (const struct sockaddr *sa);
+
+void ROKEN_LIB_FUNCTION
+socket_set_port (struct sockaddr *sa, int port);
+
+void ROKEN_LIB_FUNCTION
+socket_set_portrange (int sock, int restr, int af);
+
+void ROKEN_LIB_FUNCTION
+socket_set_debug (int sock);
+
+void ROKEN_LIB_FUNCTION
+socket_set_tos (int sock, int tos);
+
+void ROKEN_LIB_FUNCTION
+socket_set_reuseaddr (int sock, int val);
+
+char ** ROKEN_LIB_FUNCTION
+vstrcollect(va_list *ap);
+
+char ** ROKEN_LIB_FUNCTION
+strcollect(char *first, ...);
+
+void ROKEN_LIB_FUNCTION
+timevalfix(struct timeval *t1);
+
+void ROKEN_LIB_FUNCTION
+timevaladd(struct timeval *t1, const struct timeval *t2);
+
+void ROKEN_LIB_FUNCTION
+timevalsub(struct timeval *t1, const struct timeval *t2);
+
+char *ROKEN_LIB_FUNCTION
+pid_file_write (const char *progname);
+
+void ROKEN_LIB_FUNCTION
+pid_file_delete (char **);
+
+int ROKEN_LIB_FUNCTION
+read_environment(const char *file, char ***env);
+
+void ROKEN_LIB_FUNCTION
+warnerr(int doerrno, const char *fmt, va_list ap)
+    __attribute__ ((format (printf, 2, 0)));
+
+void * ROKEN_LIB_FUNCTION
+rk_realloc(void *, size_t);
+
+struct rk_strpool;
+
+char * ROKEN_LIB_FUNCTION
+rk_strpoolcollect(struct rk_strpool *);
+
+struct rk_strpool * ROKEN_LIB_FUNCTION
+rk_strpoolprintf(struct rk_strpool *, const char *, ...)
+    __attribute__ ((format (printf, 2, 3)));
+
+void ROKEN_LIB_FUNCTION
+rk_strpoolfree(struct rk_strpool *);
+
+
+ROKEN_CPP_END
+
+#endif /* __ROKEN_COMMON_H__ */
diff --git a/source4/heimdal/lib/roken/roken.h b/source4/heimdal/lib/roken/roken.h
new file mode 100644 (file)
index 0000000..545f43c
--- /dev/null
@@ -0,0 +1,688 @@
+/* -*- C -*- */
+/*
+ * Copyright (c) 1995-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.
+ */
+
+/* $Id: roken.h.in,v 1.175 2005/07/07 19:16:17 lha Exp $ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#include <string.h>
+#include <signal.h>
+
+#ifdef _AIX
+struct ether_addr;
+struct sockaddr_dl;
+#endif
+#ifdef HAVE_SYS_PARAM_H
+#include <sys/param.h>
+#endif
+#ifdef HAVE_INTTYPES_H
+#include <inttypes.h>
+#endif
+#ifdef HAVE_SYS_TYPES_H
+#include <sys/types.h>
+#endif
+#ifdef HAVE_SYS_BITYPES_H
+#include <sys/bitypes.h>
+#endif
+#ifdef HAVE_BIND_BITYPES_H
+#include <bind/bitypes.h>
+#endif
+#ifdef HAVE_NETINET_IN6_MACHTYPES_H
+#include <netinet/in6_machtypes.h>
+#endif
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+#ifdef HAVE_SYS_SOCKET_H
+#include <sys/socket.h>
+#endif
+#ifdef HAVE_SYS_UIO_H
+#include <sys/uio.h>
+#endif
+#ifdef HAVE_GRP_H
+#include <grp.h>
+#endif
+#ifdef HAVE_SYS_STAT_H
+#include <sys/stat.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_ARPA_INET_H
+#include <arpa/inet.h>
+#endif
+#ifdef HAVE_NETDB_H
+#include <netdb.h>
+#endif
+#ifdef HAVE_ARPA_NAMESER_H
+#include <arpa/nameser.h>
+#endif
+#ifdef HAVE_RESOLV_H
+#include <resolv.h>
+#endif
+#ifdef HAVE_SYSLOG_H
+#include <syslog.h>
+#endif
+#ifdef HAVE_FCNTL_H
+#include <fcntl.h>
+#endif
+#ifdef HAVE_ERRNO_H
+#include <errno.h>
+#endif
+#include <err.h>
+#ifdef HAVE_TERMIOS_H
+#include <termios.h>
+#endif
+#if defined(HAVE_SYS_IOCTL_H) && SunOS != 40
+#include <sys/ioctl.h>
+#endif
+#ifdef TIME_WITH_SYS_TIME
+#include <sys/time.h>
+#include <time.h>
+#elif defined(HAVE_SYS_TIME_H)
+#include <sys/time.h>
+#else
+#include <time.h>
+#endif
+#ifdef HAVE_STRINGS_H
+#include <strings.h>
+#endif
+
+#ifdef HAVE_PATHS_H
+#include <paths.h>
+#endif
+
+#ifndef HAVE_SSIZE_T
+typedef int ssize_t;
+#endif
+
+#include <roken-common.h>
+
+ROKEN_CPP_START
+
+#if !defined(HAVE_SETSID) && defined(HAVE__SETSID)
+#define setsid _setsid
+#endif
+
+#ifndef HAVE_PUTENV
+int ROKEN_LIB_FUNCTION putenv(const char *string);
+#endif
+
+#if !defined(HAVE_SETENV) || defined(NEED_SETENV_PROTO)
+int ROKEN_LIB_FUNCTION setenv(const char *var, const char *val, int rewrite);
+#endif
+
+#if !defined(HAVE_UNSETENV) || defined(NEED_UNSETENV_PROTO)
+void ROKEN_LIB_FUNCTION unsetenv(const char *name);
+#endif
+
+#if !defined(HAVE_GETUSERSHELL) || defined(NEED_GETUSERSHELL_PROTO)
+char * ROKEN_LIB_FUNCTION getusershell(void);
+void ROKEN_LIB_FUNCTION endusershell(void);
+#endif
+
+#if !defined(HAVE_SNPRINTF) || defined(NEED_SNPRINTF_PROTO)
+int ROKEN_LIB_FUNCTION snprintf (char *str, size_t sz, const char *format, ...)
+     __attribute__ ((format (printf, 3, 4)));
+#endif
+
+#if !defined(HAVE_VSNPRINTF) || defined(NEED_VSNPRINTF_PROTO)
+int ROKEN_LIB_FUNCTION 
+     vsnprintf (char *str, size_t sz, const char *format, va_list ap)
+     __attribute__((format (printf, 3, 0)));
+#endif
+
+#if !defined(HAVE_ASPRINTF) || defined(NEED_ASPRINTF_PROTO)
+int ROKEN_LIB_FUNCTION
+     asprintf (char **ret, const char *format, ...)
+     __attribute__ ((format (printf, 2, 3)));
+#endif
+
+#if !defined(HAVE_VASPRINTF) || defined(NEED_VASPRINTF_PROTO)
+int ROKEN_LIB_FUNCTION
+    vasprintf (char **ret, const char *format, va_list ap)
+     __attribute__((format (printf, 2, 0)));
+#endif
+
+#if !defined(HAVE_ASNPRINTF) || defined(NEED_ASNPRINTF_PROTO)
+int ROKEN_LIB_FUNCTION
+    asnprintf (char **ret, size_t max_sz, const char *format, ...)
+     __attribute__ ((format (printf, 3, 4)));
+#endif
+
+#if !defined(HAVE_VASNPRINTF) || defined(NEED_VASNPRINTF_PROTO)
+int ROKEN_LIB_FUNCTION
+    vasnprintf (char **ret, size_t max_sz, const char *format, va_list ap)
+     __attribute__((format (printf, 3, 0)));
+#endif
+
+#ifndef HAVE_STRDUP
+char * ROKEN_LIB_FUNCTION strdup(const char *old);
+#endif
+
+#if !defined(HAVE_STRNDUP) || defined(NEED_STRNDUP_PROTO)
+char * ROKEN_LIB_FUNCTION strndup(const char *old, size_t sz);
+#endif
+
+#ifndef HAVE_STRLWR
+char * ROKEN_LIB_FUNCTION strlwr(char *);
+#endif
+
+#ifndef HAVE_STRNLEN
+size_t ROKEN_LIB_FUNCTION strnlen(const char*, size_t);
+#endif
+
+#if !defined(HAVE_STRSEP) || defined(NEED_STRSEP_PROTO)
+char * ROKEN_LIB_FUNCTION strsep(char**, const char*);
+#endif
+
+#if !defined(HAVE_STRSEP_COPY) || defined(NEED_STRSEP_COPY_PROTO)
+ssize_t ROKEN_LIB_FUNCTION strsep_copy(const char**, const char*, char*, size_t);
+#endif
+
+#ifndef HAVE_STRCASECMP
+int ROKEN_LIB_FUNCTION strcasecmp(const char *s1, const char *s2);
+#endif
+
+#ifdef NEED_FCLOSE_PROTO
+int ROKEN_LIB_FUNCTION fclose(FILE *);
+#endif
+
+#ifdef NEED_STRTOK_R_PROTO
+char * ROKEN_LIB_FUNCTION strtok_r(char *s1, const char *s2, char **lasts);
+#endif
+
+#ifndef HAVE_STRUPR
+char * ROKEN_LIB_FUNCTION strupr(char *);
+#endif
+
+#ifndef HAVE_STRLCPY
+size_t ROKEN_LIB_FUNCTION strlcpy (char *dst, const char *src, size_t dst_sz);
+#endif
+
+#ifndef HAVE_STRLCAT
+size_t ROKEN_LIB_FUNCTION strlcat (char *dst, const char *src, size_t dst_sz);
+#endif
+
+#ifndef HAVE_GETDTABLESIZE
+int ROKEN_LIB_FUNCTION getdtablesize(void);
+#endif
+
+#if !defined(HAVE_STRERROR) && !defined(strerror)
+char * ROKEN_LIB_FUNCTION strerror(int eno);
+#endif
+
+#if !defined(HAVE_HSTRERROR) || defined(NEED_HSTRERROR_PROTO)
+/* This causes a fatal error under Psoriasis */
+#if !(defined(SunOS) && (SunOS >= 50))
+const char * ROKEN_LIB_FUNCTION hstrerror(int herr);
+#endif
+#endif
+
+#if !HAVE_DECL_H_ERRNO
+extern int h_errno;
+#endif
+
+#if !defined(HAVE_INET_ATON) || defined(NEED_INET_ATON_PROTO)
+int ROKEN_LIB_FUNCTION inet_aton(const char *cp, struct in_addr *adr);
+#endif
+
+#ifndef HAVE_INET_NTOP
+const char * ROKEN_LIB_FUNCTION
+inet_ntop(int af, const void *src, char *dst, size_t size);
+#endif
+
+#ifndef HAVE_INET_PTON
+int ROKEN_LIB_FUNCTION
+inet_pton(int af, const char *src, void *dst);
+#endif
+
+#if !defined(HAVE_GETCWD)
+char* ROKEN_LIB_FUNCTION getcwd(char *path, size_t size);
+#endif
+
+#ifdef HAVE_PWD_H
+#include <pwd.h>
+struct passwd * ROKEN_LIB_FUNCTION k_getpwnam (const char *user);
+struct passwd * ROKEN_LIB_FUNCTION k_getpwuid (uid_t uid);
+#endif
+
+const char * ROKEN_LIB_FUNCTION get_default_username (void);
+
+#ifndef HAVE_SETEUID
+int ROKEN_LIB_FUNCTION seteuid(uid_t euid);
+#endif
+
+#ifndef HAVE_SETEGID
+int ROKEN_LIB_FUNCTION setegid(gid_t egid);
+#endif
+
+#ifndef HAVE_LSTAT
+int ROKEN_LIB_FUNCTION lstat(const char *path, struct stat *buf);
+#endif
+
+#if !defined(HAVE_MKSTEMP) || defined(NEED_MKSTEMP_PROTO)
+int ROKEN_LIB_FUNCTION mkstemp(char *);
+#endif
+
+#ifndef HAVE_CGETENT
+int ROKEN_LIB_FUNCTION cgetent(char **buf, char **db_array, const char *name);
+int ROKEN_LIB_FUNCTION cgetstr(char *buf, const char *cap, char **str);
+#endif
+
+#ifndef HAVE_INITGROUPS
+int ROKEN_LIB_FUNCTION initgroups(const char *name, gid_t basegid);
+#endif
+
+#ifndef HAVE_FCHOWN
+int ROKEN_LIB_FUNCTION fchown(int fd, uid_t owner, gid_t group);
+#endif
+
+#if !defined(HAVE_DAEMON) || defined(NEED_DAEMON_PROTO)
+int ROKEN_LIB_FUNCTION daemon(int nochdir, int noclose);
+#endif
+
+#ifndef HAVE_INNETGR
+int ROKEN_LIB_FUNCTION innetgr(const char *netgroup, const char *machine, 
+           const char *user, const char *domain);
+#endif
+
+#ifndef HAVE_CHOWN
+int ROKEN_LIB_FUNCTION chown(const char *path, uid_t owner, gid_t group);
+#endif
+
+#ifndef HAVE_RCMD
+int ROKEN_LIB_FUNCTION
+    rcmd(char **ahost, unsigned short inport, const char *locuser,
+        const char *remuser, const char *cmd, int *fd2p);
+#endif
+
+#if !defined(HAVE_INNETGR) || defined(NEED_INNETGR_PROTO)
+int ROKEN_LIB_FUNCTION innetgr(const char*, const char*,
+    const char*, const char*);
+#endif
+
+#ifndef HAVE_IRUSEROK
+int ROKEN_LIB_FUNCTION iruserok(unsigned raddr, int superuser, 
+    const char *ruser, const char *luser);
+#endif
+
+#if !defined(HAVE_GETHOSTNAME) || defined(NEED_GETHOSTNAME_PROTO)
+int ROKEN_LIB_FUNCTION gethostname(char *name, int namelen);
+#endif
+
+#ifndef HAVE_WRITEV
+ssize_t ROKEN_LIB_FUNCTION
+writev(int d, const struct iovec *iov, int iovcnt);
+#endif
+
+#ifndef HAVE_READV
+ssize_t ROKEN_LIB_FUNCTION
+readv(int d, const struct iovec *iov, int iovcnt);
+#endif
+
+#ifndef HAVE_MKSTEMP
+int ROKEN_LIB_FUNCTION
+mkstemp(char *template);
+#endif
+
+#ifndef HAVE_PIDFILE
+void ROKEN_LIB_FUNCTION pidfile (const char*);
+#endif
+
+#ifndef HAVE_BSWAP32
+unsigned int ROKEN_LIB_FUNCTION bswap32(unsigned int);
+#endif
+
+#ifndef HAVE_BSWAP16
+unsigned short ROKEN_LIB_FUNCTION bswap16(unsigned short);
+#endif
+
+#ifndef HAVE_FLOCK
+#ifndef LOCK_SH
+#define LOCK_SH   1            /* Shared lock */
+#endif
+#ifndef        LOCK_EX
+#define LOCK_EX   2            /* Exclusive lock */
+#endif
+#ifndef LOCK_NB
+#define LOCK_NB   4            /* Don't block when locking */
+#endif
+#ifndef LOCK_UN
+#define LOCK_UN   8            /* Unlock */
+#endif
+
+int flock(int fd, int operation);
+#endif /* HAVE_FLOCK */
+
+time_t ROKEN_LIB_FUNCTION tm2time (struct tm tm, int local);
+
+int ROKEN_LIB_FUNCTION unix_verify_user(char *user, char *password);
+
+int ROKEN_LIB_FUNCTION roken_concat (char *s, size_t len, ...);
+
+size_t ROKEN_LIB_FUNCTION roken_mconcat (char **s, size_t max_len, ...);
+
+int ROKEN_LIB_FUNCTION roken_vconcat (char *s, size_t len, va_list args);
+
+size_t ROKEN_LIB_FUNCTION
+    roken_vmconcat (char **s, size_t max_len, va_list args);
+
+ssize_t ROKEN_LIB_FUNCTION net_write (int fd, const void *buf, size_t nbytes);
+
+ssize_t ROKEN_LIB_FUNCTION net_read (int fd, void *buf, size_t nbytes);
+
+int ROKEN_LIB_FUNCTION issuid(void);
+
+#ifndef HAVE_STRUCT_WINSIZE
+struct winsize {
+       unsigned short ws_row, ws_col;
+       unsigned short ws_xpixel, ws_ypixel;
+};
+#endif
+
+int ROKEN_LIB_FUNCTION get_window_size(int fd, struct winsize *);
+
+#ifndef HAVE_VSYSLOG
+void ROKEN_LIB_FUNCTION vsyslog(int pri, const char *fmt, va_list ap);
+#endif
+
+#if !HAVE_DECL_OPTARG
+extern char *optarg;
+#endif
+#if !HAVE_DECL_OPTIND
+extern int optind;
+#endif
+#if !HAVE_DECL_OPTERR
+extern int opterr;
+#endif
+
+#if !HAVE_DECL_ENVIRON
+extern char **environ;
+#endif
+
+#ifndef HAVE_GETIPNODEBYNAME
+struct hostent * ROKEN_LIB_FUNCTION
+getipnodebyname (const char *name, int af, int flags, int *error_num);
+#endif
+
+#ifndef HAVE_GETIPNODEBYADDR
+struct hostent * ROKEN_LIB_FUNCTION
+getipnodebyaddr (const void *src, size_t len, int af, int *error_num);
+#endif
+
+#ifndef HAVE_FREEHOSTENT
+void ROKEN_LIB_FUNCTION
+freehostent (struct hostent *h);
+#endif
+
+#ifndef HAVE_COPYHOSTENT
+struct hostent * ROKEN_LIB_FUNCTION
+copyhostent (const struct hostent *h);
+#endif
+
+#ifndef HAVE_SOCKLEN_T
+typedef int socklen_t;
+#endif
+
+#ifndef HAVE_STRUCT_SOCKADDR_STORAGE
+
+#ifndef HAVE_SA_FAMILY_T
+typedef unsigned short sa_family_t;
+#endif
+
+#ifdef HAVE_IPV6
+#define _SS_MAXSIZE sizeof(struct sockaddr_in6)
+#else
+#define _SS_MAXSIZE sizeof(struct sockaddr_in)
+#endif
+
+#define _SS_ALIGNSIZE  sizeof(unsigned long)
+
+#if HAVE_STRUCT_SOCKADDR_SA_LEN
+
+typedef unsigned char roken_sa_family_t;
+
+#define _SS_PAD1SIZE   ((2 * _SS_ALIGNSIZE - sizeof (roken_sa_family_t) - sizeof(unsigned char)) % _SS_ALIGNSIZE)
+#define _SS_PAD2SIZE   (_SS_MAXSIZE - (sizeof (roken_sa_family_t) + sizeof(unsigned char) + _SS_PAD1SIZE + _SS_ALIGNSIZE))
+
+struct sockaddr_storage {
+    unsigned char      ss_len;
+    roken_sa_family_t  ss_family;
+    char               __ss_pad1[_SS_PAD1SIZE];
+    unsigned long      __ss_align[_SS_PAD2SIZE / sizeof(unsigned long) + 1];
+};
+
+#else /* !HAVE_STRUCT_SOCKADDR_SA_LEN */
+
+typedef unsigned short roken_sa_family_t;
+
+#define _SS_PAD1SIZE   ((2 * _SS_ALIGNSIZE - sizeof (roken_sa_family_t)) % _SS_ALIGNSIZE)
+#define _SS_PAD2SIZE   (_SS_MAXSIZE - (sizeof (roken_sa_family_t) + _SS_PAD1SIZE + _SS_ALIGNSIZE))
+
+struct sockaddr_storage {
+    roken_sa_family_t  ss_family;
+    char               __ss_pad1[_SS_PAD1SIZE];
+    unsigned long      __ss_align[_SS_PAD2SIZE / sizeof(unsigned long) + 1];
+};
+
+#endif /* HAVE_STRUCT_SOCKADDR_SA_LEN */
+
+#endif /* HAVE_STRUCT_SOCKADDR_STORAGE */
+
+#ifndef HAVE_STRUCT_ADDRINFO
+struct addrinfo {
+    int    ai_flags;
+    int    ai_family;
+    int    ai_socktype;
+    int    ai_protocol;
+    size_t ai_addrlen;
+    char  *ai_canonname;
+    struct sockaddr *ai_addr;
+    struct addrinfo *ai_next;
+};
+#endif
+
+#ifndef HAVE_GETADDRINFO
+int ROKEN_LIB_FUNCTION
+getaddrinfo(const char *nodename,
+           const char *servname,
+           const struct addrinfo *hints,
+           struct addrinfo **res);
+#endif
+
+#ifndef HAVE_GETNAMEINFO
+int ROKEN_LIB_FUNCTION
+getnameinfo(const struct sockaddr *sa, socklen_t salen,
+               char *host, size_t hostlen,
+               char *serv, size_t servlen,
+               int flags);
+#endif
+
+#ifndef HAVE_FREEADDRINFO
+void ROKEN_LIB_FUNCTION
+freeaddrinfo(struct addrinfo *ai);
+#endif
+
+#ifndef HAVE_GAI_STRERROR
+char * ROKEN_LIB_FUNCTION
+gai_strerror(int ecode);
+#endif
+
+int ROKEN_LIB_FUNCTION
+getnameinfo_verified(const struct sockaddr *sa, socklen_t salen,
+                    char *host, size_t hostlen,
+                    char *serv, size_t servlen,
+                    int flags);
+
+int ROKEN_LIB_FUNCTION
+roken_getaddrinfo_hostspec(const char *, int, struct addrinfo **); 
+int ROKEN_LIB_FUNCTION
+roken_getaddrinfo_hostspec2(const char *, int, int, struct addrinfo **);
+
+#ifndef HAVE_STRFTIME
+size_t ROKEN_LIB_FUNCTION
+strftime (char *buf, size_t maxsize, const char *format,
+         const struct tm *tm);
+#endif
+
+#ifndef HAVE_STRPTIME
+char * ROKEN_LIB_FUNCTION
+strptime (const char *buf, const char *format, struct tm *timeptr);
+#endif
+
+#ifndef HAVE_EMALLOC
+void * ROKEN_LIB_FUNCTION emalloc (size_t);
+#endif
+#ifndef HAVE_ECALLOC
+void * ROKEN_LIB_FUNCTION ecalloc(size_t num, size_t sz);
+#endif
+#ifndef HAVE_EREALLOC
+void * ROKEN_LIB_FUNCTION erealloc (void *, size_t);
+#endif
+#ifndef HAVE_ESTRDUP
+char * ROKEN_LIB_FUNCTION estrdup (const char *);
+#endif
+
+/*
+ * kludges and such
+ */
+
+#if 1
+int ROKEN_LIB_FUNCTION
+roken_gethostby_setup(const char*, const char*);
+struct hostent* ROKEN_LIB_FUNCTION
+roken_gethostbyname(const char*);
+struct hostent* ROKEN_LIB_FUNCTION 
+roken_gethostbyaddr(const void*, size_t, int);
+#else
+#ifdef GETHOSTBYNAME_PROTO_COMPATIBLE
+#define roken_gethostbyname(x) gethostbyname(x)
+#else
+#define roken_gethostbyname(x) gethostbyname((char *)x)
+#endif
+
+#ifdef GETHOSTBYADDR_PROTO_COMPATIBLE
+#define roken_gethostbyaddr(a, l, t) gethostbyaddr(a, l, t)
+#else
+#define roken_gethostbyaddr(a, l, t) gethostbyaddr((char *)a, l, t)
+#endif
+#endif
+
+#ifdef GETSERVBYNAME_PROTO_COMPATIBLE
+#define roken_getservbyname(x,y) getservbyname(x,y)
+#else
+#define roken_getservbyname(x,y) getservbyname((char *)x, (char *)y)
+#endif
+
+#ifdef OPENLOG_PROTO_COMPATIBLE
+#define roken_openlog(a,b,c) openlog(a,b,c)
+#else
+#define roken_openlog(a,b,c) openlog((char *)a,b,c)
+#endif
+
+#ifdef GETSOCKNAME_PROTO_COMPATIBLE
+#define roken_getsockname(a,b,c) getsockname(a,b,c)
+#else
+#define roken_getsockname(a,b,c) getsockname(a, b, (void*)c)
+#endif
+
+#ifndef HAVE_SETPROGNAME
+void ROKEN_LIB_FUNCTION setprogname(const char *argv0);
+#endif
+
+#ifndef HAVE_GETPROGNAME
+const char * ROKEN_LIB_FUNCTION getprogname(void);
+#endif
+
+#if !defined(HAVE_SETPROGNAME) && !defined(HAVE_GETPROGNAME) && !HAVE_DECL___PROGNAME
+extern const char *__progname;
+#endif
+
+void ROKEN_LIB_FUNCTION mini_inetd_addrinfo (struct addrinfo*);
+void ROKEN_LIB_FUNCTION mini_inetd (int port);
+
+#ifndef HAVE_LOCALTIME_R
+struct tm * ROKEN_LIB_FUNCTION
+localtime_r(const time_t *timer, struct tm *result);
+#endif
+
+#if !defined(HAVE_STRSVIS) || defined(NEED_STRSVIS_PROTO)
+int ROKEN_LIB_FUNCTION
+strsvis(char *dst, const char *src, int flag, const char *extra);
+#endif
+
+#if !defined(HAVE_STRUNVIS) || defined(NEED_STRUNVIS_PROTO)
+int ROKEN_LIB_FUNCTION
+strunvis(char *dst, const char *src);
+#endif
+
+#if !defined(HAVE_STRVIS) || defined(NEED_STRVIS_PROTO)
+int ROKEN_LIB_FUNCTION
+strvis(char *dst, const char *src, int flag);
+#endif
+
+#if !defined(HAVE_STRVISX) || defined(NEED_STRVISX_PROTO)
+int ROKEN_LIB_FUNCTION
+strvisx(char *dst, const char *src, size_t len, int flag);
+#endif
+
+#if !defined(HAVE_SVIS) || defined(NEED_SVIS_PROTO)
+char * ROKEN_LIB_FUNCTION
+svis(char *dst, int c, int flag, int nextc, const char *extra);
+#endif
+
+#if !defined(HAVE_UNVIS) || defined(NEED_UNVIS_PROTO)
+int ROKEN_LIB_FUNCTION
+unvis(char *cp, int c, int *astate, int flag);
+#endif
+
+#if !defined(HAVE_VIS) || defined(NEED_VIS_PROTO)
+char * ROKEN_LIB_FUNCTION
+vis(char *dst, int c, int flag, int nextc);
+#endif
+
+#if !defined(HAVE_CLOSEFROM)
+int ROKEN_LIB_FUNCTION
+closefrom(int);
+#endif
+
+ROKEN_CPP_END
diff --git a/source4/heimdal/lib/roken/roken_gethostby.c b/source4/heimdal/lib/roken/roken_gethostby.c
new file mode 100644 (file)
index 0000000..2df3f83
--- /dev/null
@@ -0,0 +1,274 @@
+/*
+ * Copyright (c) 1998 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. 
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+RCSID("$Id: roken_gethostby.c,v 1.7 2005/04/12 11:29:03 lha Exp $");
+#endif
+
+#include <roken.h>
+
+#undef roken_gethostbyname
+#undef roken_gethostbyaddr
+
+static struct sockaddr_in dns_addr;
+static char *dns_req;
+
+static int
+make_address(const char *address, struct in_addr *ip)
+{
+    if(inet_aton(address, ip) == 0){
+       /* try to resolve as hostname, it might work if the address we
+           are trying to lookup is local, for instance a web proxy */
+       struct hostent *he = gethostbyname(address);
+       if(he) {
+           unsigned char *p = (unsigned char*)he->h_addr;
+           ip->s_addr = (p[0] << 24) | (p[1] << 16) | (p[2] << 8) | p[3];
+       } else {
+           return -1;
+       }
+    }
+    return 0;
+}
+
+static int
+setup_int(const char *proxy_host, short proxy_port,
+         const char *dns_host, short dns_port,
+         const char *dns_path)
+{
+    memset(&dns_addr, 0, sizeof(dns_addr));
+    if(dns_req)
+       free(dns_req);
+    if(proxy_host) {
+       if(make_address(proxy_host, &dns_addr.sin_addr) != 0)
+           return -1;
+       dns_addr.sin_port = htons(proxy_port);
+       asprintf(&dns_req, "http://%s:%d%s", dns_host, dns_port, dns_path);
+    } else {
+       if(make_address(dns_host, &dns_addr.sin_addr) != 0)
+           return -1;
+       dns_addr.sin_port = htons(dns_port);
+       asprintf(&dns_req, "%s", dns_path);
+    }
+    dns_addr.sin_family = AF_INET;
+    return 0;
+}
+
+static void
+split_spec(const char *spec, char **host, int *port, char **path, int def_port)
+{
+    char *p;
+    *host = strdup(spec);
+    p = strchr(*host, ':');
+    if(p) {
+       *p++ = '\0';
+       if(sscanf(p, "%d", port) != 1)
+           *port = def_port;
+    } else
+       *port = def_port;
+    p = strchr(p ? p : *host, '/');
+    if(p) {
+       if(path) 
+           *path = strdup(p);
+       *p = '\0';
+    }else
+       if(path) 
+           *path = NULL;
+}
+
+
+int ROKEN_LIB_FUNCTION
+roken_gethostby_setup(const char *proxy_spec, const char *dns_spec)
+{
+    char *proxy_host = NULL;
+    int proxy_port;
+    char *dns_host, *dns_path;
+    int dns_port;
+    
+    int ret = -1;
+    
+    split_spec(dns_spec, &dns_host, &dns_port, &dns_path, 80);
+    if(dns_path == NULL)
+       goto out;
+    if(proxy_spec)
+       split_spec(proxy_spec, &proxy_host, &proxy_port, NULL, 80);
+    ret = setup_int(proxy_host, proxy_port, dns_host, dns_port, dns_path);
+out:
+    free(proxy_host);
+    free(dns_host);
+    free(dns_path);
+    return ret;
+}
+    
+
+/* Try to lookup a name or an ip-address using http as transport
+   mechanism. See the end of this file for an example program. */
+static struct hostent*
+roken_gethostby(const char *hostname)
+{
+    int s;
+    struct sockaddr_in addr;
+    char *request;
+    char buf[1024];
+    int offset = 0;
+    int n;
+    char *p, *foo;
+    
+    if(dns_addr.sin_family == 0)
+       return NULL; /* no configured host */
+    addr = dns_addr;
+    asprintf(&request, "GET %s?%s HTTP/1.0\r\n\r\n", dns_req, hostname);
+    if(request == NULL)
+       return NULL;
+    s  = socket(AF_INET, SOCK_STREAM, 0);
+    if(s < 0) {
+       free(request);
+       return NULL;
+    }
+    if(connect(s, (struct sockaddr*)&addr, sizeof(addr)) < 0) {
+       close(s);
+       free(request);
+       return NULL;
+    }
+    if(write(s, request, strlen(request)) != strlen(request)) {
+       close(s);
+       free(request);
+       return NULL;
+    }
+    free(request);
+    while(1) {
+       n = read(s, buf + offset, sizeof(buf) - offset);
+       if(n <= 0)
+           break;
+       offset += n;
+    }
+    buf[offset] = '\0';
+    close(s);
+    p = strstr(buf, "\r\n\r\n"); /* find end of header */
+    if(p) p += 4;
+    else return NULL;
+    foo = NULL;
+    p = strtok_r(p, " \t\r\n", &foo);
+    if(p == NULL)
+       return NULL;
+    {
+       /* make a hostent to return */
+#define MAX_ADDRS 16
+       static struct hostent he;
+       static char addrs[4 * MAX_ADDRS];
+       static char *addr_list[MAX_ADDRS];
+       int num_addrs = 0;
+       
+       he.h_name = p;
+       he.h_aliases = NULL;
+       he.h_addrtype = AF_INET;
+       he.h_length = 4;
+       
+       while((p = strtok_r(NULL, " \t\r\n", &foo)) && num_addrs < MAX_ADDRS) {
+           struct in_addr ip;
+           inet_aton(p, &ip);
+           ip.s_addr = ntohl(ip.s_addr);
+           addr_list[num_addrs] = &addrs[num_addrs * 4];
+           addrs[num_addrs * 4 + 0] = (ip.s_addr >> 24) & 0xff;
+           addrs[num_addrs * 4 + 1] = (ip.s_addr >> 16) & 0xff;
+           addrs[num_addrs * 4 + 2] = (ip.s_addr >> 8) & 0xff;
+           addrs[num_addrs * 4 + 3] = (ip.s_addr >> 0) & 0xff;
+           addr_list[++num_addrs] = NULL;
+       }
+       he.h_addr_list = addr_list;
+       return &he;
+    }
+}
+
+struct hostent*
+roken_gethostbyname(const char *hostname)
+{
+    struct hostent *he;
+    he = gethostbyname(hostname);
+    if(he)
+       return he;
+    return roken_gethostby(hostname);
+}
+
+struct hostent* ROKEN_LIB_FUNCTION
+roken_gethostbyaddr(const void *addr, size_t len, int type)
+{
+    struct in_addr a;
+    const char *p;
+    struct hostent *he;
+    he = gethostbyaddr(addr, len, type);
+    if(he)
+       return he;
+    if(type != AF_INET || len != 4)
+       return NULL;
+    p = addr;
+    a.s_addr = htonl((p[0] << 24) | (p[1] << 16) | (p[2] << 8) | p[3]);
+    return roken_gethostby(inet_ntoa(a));
+}
+
+#if 0
+
+/* this program can be used as a cgi `script' to lookup names and
+   ip-addresses */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <netdb.h>
+#include <sys/param.h>
+
+int
+main(int argc, char **argv)
+{
+    char *query = getenv("QUERY_STRING");
+    char host[MAXHOSTNAMELEN];
+    int i;
+    struct hostent *he;
+    
+    printf("Content-type: text/plain\n\n");
+    if(query == NULL)
+       exit(0);
+    he = gethostbyname(query);
+    strncpy(host, he->h_name, sizeof(host));
+    host[sizeof(host) - 1] = '\0';
+    he = gethostbyaddr(he->h_addr, he->h_length, AF_INET);
+    printf("%s\n", he->h_name);
+    for(i = 0; he->h_addr_list[i]; i++) {
+       struct in_addr ip;
+       unsigned char *p = (unsigned char*)he->h_addr_list[i];
+       ip.s_addr = htonl((p[0] << 24) | (p[1] << 16) | (p[2] << 8) | p[3]);
+       printf("%s\n", inet_ntoa(ip));
+    }
+    exit(0);
+}
+
+#endif
diff --git a/source4/heimdal/lib/roken/setprogname.c b/source4/heimdal/lib/roken/setprogname.c
new file mode 100644 (file)
index 0000000..9c4210d
--- /dev/null
@@ -0,0 +1,61 @@
+/*
+ * Copyright (c) 1995-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.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+RCSID("$Id: setprogname.c,v 1.3 2005/04/12 11:29:05 lha Exp $");
+#endif
+
+#include "roken.h"
+
+#ifndef HAVE___PROGNAME
+extern const char *__progname;
+#endif
+
+#ifndef HAVE_SETPROGNAME
+void ROKEN_LIB_FUNCTION
+setprogname(const char *argv0)
+{
+#ifndef HAVE___PROGNAME
+    char *p;
+    if(argv0 == NULL)
+       return;
+    p = strrchr(argv0, '/');
+    if(p == NULL)
+       p = (char *)argv0;
+    else
+       p++;
+    __progname = p;
+#endif
+}
+#endif /* HAVE_SETPROGNAME */
diff --git a/source4/heimdal/lib/roken/signal.c b/source4/heimdal/lib/roken/signal.c
new file mode 100644 (file)
index 0000000..d92742d
--- /dev/null
@@ -0,0 +1,80 @@
+/*
+ * Copyright (c) 1995 - 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.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+RCSID("$Id: signal.c,v 1.13 2005/04/12 11:29:05 lha Exp $");
+#endif
+
+#include <signal.h>
+#include "roken.h"
+
+/*
+ * We would like to always use this signal but there is a link error
+ * on NEXTSTEP
+ */
+#if !defined(NeXT) && !defined(__APPLE__)
+/*
+ * Bugs:
+ *
+ * Do we need any extra hacks for SIGCLD and/or SIGCHLD?
+ */
+
+SigAction ROKEN_LIB_FUNCTION
+signal(int iSig, SigAction pAction)
+{
+    struct sigaction saNew, saOld;
+
+    saNew.sa_handler = pAction;
+    sigemptyset(&saNew.sa_mask);
+    saNew.sa_flags = 0;
+
+    if (iSig == SIGALRM)
+       {
+#ifdef SA_INTERRUPT
+           saNew.sa_flags |= SA_INTERRUPT;
+#endif
+       }
+    else
+       {
+#ifdef SA_RESTART
+           saNew.sa_flags |= SA_RESTART;
+#endif
+       }
+
+    if (sigaction(iSig, &saNew, &saOld) < 0)
+       return(SIG_ERR);
+
+    return(saOld.sa_handler);
+}
+#endif
diff --git a/source4/heimdal/lib/roken/strlwr.c b/source4/heimdal/lib/roken/strlwr.c
new file mode 100644 (file)
index 0000000..c0ef46d
--- /dev/null
@@ -0,0 +1,53 @@
+/*
+ * Copyright (c) 1995, 1996, 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.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+RCSID("$Id: strlwr.c,v 1.6 2005/04/12 11:29:09 lha Exp $");
+#endif
+#include <string.h>
+#include <ctype.h>
+
+#include <roken.h>
+
+#ifndef HAVE_STRLWR
+char * ROKEN_LIB_FUNCTION
+strlwr(char *str)
+{
+  char *s;
+
+  for(s = str; *s; s++)
+    *s = tolower((unsigned char)*s);
+  return str;
+}
+#endif
diff --git a/source4/heimdal/lib/roken/strpool.c b/source4/heimdal/lib/roken/strpool.c
new file mode 100644 (file)
index 0000000..8ee9565
--- /dev/null
@@ -0,0 +1,111 @@
+/*
+ * Copyright (c) 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. 
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+RCSID("$Id: strpool.c,v 1.1 2005/06/28 22:46:57 lha Exp $");
+#endif
+
+#include <stdarg.h>
+#include <stdlib.h>
+#include <roken.h>
+
+struct rk_strpool {
+    char *str;
+    size_t len;
+};
+
+/*
+ *
+ */
+
+void ROKEN_LIB_FUNCTION
+rk_strpoolfree(struct rk_strpool *p)
+{
+    if (p->str) {
+       free(p->str);
+       p->str = NULL;
+    }
+    free(p);
+}
+
+/*
+ *
+ */
+
+struct rk_strpool * ROKEN_LIB_FUNCTION
+rk_strpoolprintf(struct rk_strpool *p, const char *fmt, ...)
+{
+    va_list ap;
+    char *str, *str2;
+    int len;
+
+    if (p == NULL) {
+       p = malloc(sizeof(*p));
+       if (p == NULL)
+           return NULL;
+       p->str = NULL;
+       p->len = 0;
+    }
+    va_start(ap, fmt);
+    len = vasprintf(&str, fmt, ap);
+    va_end(ap);
+    if (str == NULL) {
+       printf("vasprintf");
+       rk_strpoolfree(p);
+       return NULL;
+    }
+    str2 = realloc(p->str, len + p->len + 1);
+    if (str2 == NULL) {
+       printf("realloc");
+       rk_strpoolfree(p);
+       return NULL;
+    }
+    p->str = str2;
+    memcpy(p->str + p->len, str, len + 1);
+    p->len += len;
+    return p;
+}
+
+/*
+ *
+ */
+
+char * ROKEN_LIB_FUNCTION
+rk_strpoolcollect(struct rk_strpool *p)
+{
+    char *str = p->str;
+    p->str = NULL;
+    free(p);
+    return str;
+}
diff --git a/source4/heimdal/lib/roken/strsep_copy.c b/source4/heimdal/lib/roken/strsep_copy.c
new file mode 100644 (file)
index 0000000..5149838
--- /dev/null
@@ -0,0 +1,69 @@
+/*
+ * Copyright (c) 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. 
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+RCSID("$Id: strsep_copy.c,v 1.5 2005/04/12 11:29:11 lha Exp $");
+#endif
+
+#include <string.h>
+
+#include "roken.h"
+
+#ifndef HAVE_STRSEP_COPY
+
+/* strsep, but with const stringp, so return string in buf */
+
+ssize_t ROKEN_LIB_FUNCTION
+strsep_copy(const char **stringp, const char *delim, char *buf, size_t len)
+{
+    const char *save = *stringp;
+    size_t l;
+    if(save == NULL)
+       return -1;
+    *stringp = *stringp + strcspn(*stringp, delim);
+    l = min(len, *stringp - save);
+    if(len > 0) {
+       memcpy(buf, save, l);
+       buf[l] = '\0';
+    }
+
+    l = *stringp - save;
+    if(**stringp == '\0')
+       *stringp = NULL;
+    else
+       (*stringp)++;
+    return l;
+}
+
+#endif
diff --git a/source4/heimdal/lib/roken/strupr.c b/source4/heimdal/lib/roken/strupr.c
new file mode 100644 (file)
index 0000000..4763a1a
--- /dev/null
@@ -0,0 +1,53 @@
+/*
+ * Copyright (c) 1995, 1996, 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.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+RCSID("$Id: strupr.c,v 1.6 2005/04/12 11:29:11 lha Exp $");
+#endif
+#include <string.h>
+#include <ctype.h>
+
+#include <roken.h>
+
+#ifndef HAVE_STRUPR
+char * ROKEN_LIB_FUNCTION
+strupr(char *str)
+{
+  char *s;
+
+  for(s = str; *s; s++)
+    *s = toupper((unsigned char)*s);
+  return str;
+}
+#endif
diff --git a/source4/heimdal/lib/roken/vis.c b/source4/heimdal/lib/roken/vis.c
new file mode 100644 (file)
index 0000000..a4bde71
--- /dev/null
@@ -0,0 +1,330 @@
+/*     $NetBSD: vis.c,v 1.4 2003/08/07 09:15:32 agc Exp $      */
+
+/*-
+ * Copyright (c) 1989, 1993
+ *     The Regents of the University of California.  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 University 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 REGENTS 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 REGENTS 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.
+ */
+
+/*-
+ * Copyright (c) 1999 The NetBSD Foundation, Inc.
+ *
+ * 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. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *     This product includes software developed by the University of
+ *     California, Berkeley and its contributors.
+ * 4. Neither the name of the University 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 REGENTS 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 REGENTS 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.
+ */
+
+
+#if 1
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+RCSID("$Id: vis.c,v 1.9 2005/04/12 11:29:15 lha Exp $");
+#endif
+#include <roken.h>
+#ifndef _DIAGASSERT
+#define _DIAGASSERT(X)
+#endif
+#else
+#include <sys/cdefs.h>
+#if !defined(lint)
+__RCSID("$NetBSD: vis.c,v 1.4 2003/08/07 09:15:32 agc Exp $");
+#endif /* not lint */
+#endif
+
+#if 0
+#include "namespace.h"
+#endif
+#include <sys/types.h>
+
+#include <assert.h>
+#include <ctype.h>
+#include <limits.h>
+#include <stdio.h>
+#include <string.h>
+#include <vis.h>
+
+#if 0
+#ifdef __weak_alias
+__weak_alias(strsvis,_strsvis)
+__weak_alias(strsvisx,_strsvisx)
+__weak_alias(strvis,_strvis)
+__weak_alias(strvisx,_strvisx)
+__weak_alias(svis,_svis)
+__weak_alias(vis,_vis)
+#endif
+#endif
+
+#undef BELL
+#if defined(__STDC__)
+#define BELL '\a'
+#else
+#define BELL '\007'
+#endif
+
+#define isoctal(c)     (((u_char)(c)) >= '0' && ((u_char)(c)) <= '7')
+#define iswhite(c)     (c == ' ' || c == '\t' || c == '\n')
+#define issafe(c)      (c == '\b' || c == BELL || c == '\r')
+
+#define MAXEXTRAS       5
+
+
+#define MAKEEXTRALIST(flag, extra)                                           \
+do {                                                                         \
+       char *pextra = extra;                                                 \
+       if (flag & VIS_SP) *pextra++ = ' ';                                   \
+       if (flag & VIS_TAB) *pextra++ = '\t';                                 \
+       if (flag & VIS_NL) *pextra++ = '\n';                                  \
+       if ((flag & VIS_NOSLASH) == 0) *pextra++ = '\\';                      \
+       *pextra = '\0';                                                       \
+} while (/*CONSTCOND*/0)
+
+/*
+ * This is SVIS, the central macro of vis.
+ * dst:              Pointer to the destination buffer
+ * c:        Character to encode
+ * flag:      Flag word
+ * nextc:     The character following 'c'
+ * extra:     Pointer to the list of extra characters to be
+ *           backslash-protected.
+ */
+#define SVIS(dst, c, flag, nextc, extra)                                  \
+do {                                                                      \
+       int isextra, isc;                                                  \
+       isextra = strchr(extra, c) != NULL;                                \
+       if (!isextra &&                                                    \
+           isascii((unsigned char)c) &&                                   \
+           (isgraph((unsigned char)c) || iswhite(c) ||                    \
+           ((flag & VIS_SAFE) && issafe(c)))) {                           \
+               *dst++ = c;                                                \
+               break;                                                     \
+       }                                                                  \
+       isc = 0;                                                           \
+       if (flag & VIS_CSTYLE) {                                           \
+               switch (c) {                                               \
+               case '\n':                                                 \
+                       isc = 1; *dst++ = '\\'; *dst++ = 'n';              \
+                       break;                                             \
+               case '\r':                                                 \
+                       isc = 1; *dst++ = '\\'; *dst++ = 'r';              \
+                       break;                                             \
+               case '\b':                                                 \
+                       isc = 1; *dst++ = '\\'; *dst++ = 'b';              \
+                       break;                                             \
+               case BELL:                                                 \
+                       isc = 1; *dst++ = '\\'; *dst++ = 'a';              \
+                       break;                                             \
+               case '\v':                                                 \
+                       isc = 1; *dst++ = '\\'; *dst++ = 'v';              \
+                       break;                                             \
+               case '\t':                                                 \
+                       isc = 1; *dst++ = '\\'; *dst++ = 't';              \
+                       break;                                             \
+               case '\f':                                                 \
+                       isc = 1; *dst++ = '\\'; *dst++ = 'f';              \
+                       break;                                             \
+               case ' ':                                                  \
+                       isc = 1; *dst++ = '\\'; *dst++ = 's';              \
+                       break;                                             \
+               case '\0':                                                 \
+                       isc = 1; *dst++ = '\\'; *dst++ = '0';              \
+                       if (isoctal(nextc)) {                              \
+                               *dst++ = '0';                              \
+                               *dst++ = '0';                              \
+                       }                                                  \
+               }                                                          \
+       }                                                                  \
+       if (isc) break;                                                    \
+       if (isextra || ((c & 0177) == ' ') || (flag & VIS_OCTAL)) {        \
+               *dst++ = '\\';                                             \
+               *dst++ = (u_char)(((unsigned)(u_char)c >> 6) & 03) + '0';  \
+               *dst++ = (u_char)(((unsigned)(u_char)c >> 3) & 07) + '0';  \
+               *dst++ =                             (c       & 07) + '0'; \
+       } else {                                                           \
+               if ((flag & VIS_NOSLASH) == 0) *dst++ = '\\';              \
+               if (c & 0200) {                                            \
+                       c &= 0177; *dst++ = 'M';                           \
+               }                                                          \
+               if (iscntrl((unsigned char)c)) {                           \
+                       *dst++ = '^';                                      \
+                       if (c == 0177)                                     \
+                               *dst++ = '?';                              \
+                       else                                               \
+                               *dst++ = c + '@';                          \
+               } else {                                                   \
+                       *dst++ = '-'; *dst++ = c;                          \
+               }                                                          \
+       }                                                                  \
+} while (/*CONSTCOND*/0)
+
+
+/*
+ * svis - visually encode characters, also encoding the characters
+ *       pointed to by `extra'
+ */
+#ifndef HAVE_SVIS
+char * ROKEN_LIB_FUNCTION
+svis(char *dst, int c, int flag, int nextc, const char *extra)
+{
+       _DIAGASSERT(dst != NULL);
+       _DIAGASSERT(extra != NULL);
+
+       SVIS(dst, c, flag, nextc, extra);
+       *dst = '\0';
+       return(dst);
+}
+#endif
+
+
+/*
+ * strsvis, strsvisx - visually encode characters from src into dst
+ *
+ *     Extra is a pointer to a \0-terminated list of characters to
+ *     be encoded, too. These functions are useful e. g. to
+ *     encode strings in such a way so that they are not interpreted
+ *     by a shell.
+ *     
+ *     Dst must be 4 times the size of src to account for possible
+ *     expansion.  The length of dst, not including the trailing NULL,
+ *     is returned. 
+ *
+ *     Strsvisx encodes exactly len bytes from src into dst.
+ *     This is useful for encoding a block of data.
+ */
+#ifndef HAVE_STRSVIS
+int ROKEN_LIB_FUNCTION
+strsvis(char *dst, const char *src, int flag, const char *extra)
+{
+       char c;
+       char *start;
+
+       _DIAGASSERT(dst != NULL);
+       _DIAGASSERT(src != NULL);
+       _DIAGASSERT(extra != NULL);
+
+       for (start = dst; (c = *src++) != '\0'; /* empty */)
+           SVIS(dst, c, flag, *src, extra);
+       *dst = '\0';
+       return (dst - start);
+}
+#endif
+
+
+#ifndef HAVE_STRVISX
+int ROKEN_LIB_FUNCTION
+strsvisx(char *dst, const char *src, size_t len, int flag, const char *extra)
+{
+       char c;
+       char *start;
+
+       _DIAGASSERT(dst != NULL);
+       _DIAGASSERT(src != NULL);
+       _DIAGASSERT(extra != NULL);
+
+       for (start = dst; len > 0; len--) {
+               c = *src++;
+               SVIS(dst, c, flag, len ? *src : '\0', extra);
+       }
+       *dst = '\0';
+       return (dst - start);
+}
+#endif
+
+
+/*
+ * vis - visually encode characters
+ */
+#ifndef HAVE_VIS
+char * ROKEN_LIB_FUNCTION
+vis(char *dst, int c, int flag, int nextc)
+{
+       char extra[MAXEXTRAS];
+
+       _DIAGASSERT(dst != NULL);
+
+       MAKEEXTRALIST(flag, extra);
+       SVIS(dst, c, flag, nextc, extra);
+       *dst = '\0';
+       return (dst);
+}
+#endif
+
+
+/*
+ * strvis, strvisx - visually encode characters from src into dst
+ *     
+ *     Dst must be 4 times the size of src to account for possible
+ *     expansion.  The length of dst, not including the trailing NULL,
+ *     is returned. 
+ *
+ *     Strvisx encodes exactly len bytes from src into dst.
+ *     This is useful for encoding a block of data.
+ */
+#ifndef HAVE_STRVIS
+int ROKEN_LIB_FUNCTION
+strvis(char *dst, const char *src, int flag)
+{
+       char extra[MAXEXTRAS];
+
+       MAKEEXTRALIST(flag, extra);
+       return (strsvis(dst, src, flag, extra));
+}
+#endif
+
+
+#ifndef HAVE_STRVISX
+int ROKEN_LIB_FUNCTION
+strvisx(char *dst, const char *src, size_t len, int flag)
+{
+       char extra[MAXEXTRAS];
+
+       MAKEEXTRALIST(flag, extra);
+       return (strsvisx(dst, src, len, flag, extra));
+}
+#endif
diff --git a/source4/heimdal/lib/roken/vis.hin b/source4/heimdal/lib/roken/vis.hin
new file mode 100644 (file)
index 0000000..5b45c94
--- /dev/null
@@ -0,0 +1,98 @@
+/*     $NetBSD: vis.h,v 1.11 1999/11/25 16:55:50 wennmach Exp $        */
+/*     $Id: vis.hin,v 1.3 2005/04/12 11:29:15 lha Exp $        */
+
+/*-
+ * Copyright (c) 1990, 1993
+ *     The Regents of the University of California.  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 University 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 REGENTS 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 REGENTS 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.
+ *
+ *     @(#)vis.h       8.1 (Berkeley) 6/2/93
+ */
+
+#ifndef _VIS_H_
+#define        _VIS_H_
+
+#ifndef ROKEN_LIB_FUNCTION
+#ifdef _WIN32
+#define ROKEN_LIB_FUNCTION _stdcall
+#else
+#define ROKEN_LIB_FUNCTION
+#endif
+#endif
+
+/*
+ * to select alternate encoding format
+ */
+#define        VIS_OCTAL       0x01    /* use octal \ddd format */
+#define        VIS_CSTYLE      0x02    /* use \[nrft0..] where appropiate */
+
+/*
+ * to alter set of characters encoded (default is to encode all
+ * non-graphic except space, tab, and newline).
+ */
+#define        VIS_SP          0x04    /* also encode space */
+#define        VIS_TAB         0x08    /* also encode tab */
+#define        VIS_NL          0x10    /* also encode newline */
+#define        VIS_WHITE       (VIS_SP | VIS_TAB | VIS_NL)
+#define        VIS_SAFE        0x20    /* only encode "unsafe" characters */
+
+/*
+ * other
+ */
+#define        VIS_NOSLASH     0x40    /* inhibit printing '\' */
+
+/*
+ * unvis return codes
+ */
+#define        UNVIS_VALID      1      /* character valid */
+#define        UNVIS_VALIDPUSH  2      /* character valid, push back passed char */
+#define        UNVIS_NOCHAR     3      /* valid sequence, no character produced */
+#define        UNVIS_SYNBAD    -1      /* unrecognized escape sequence */
+#define        UNVIS_ERROR     -2      /* decoder in unknown state (unrecoverable) */
+
+/*
+ * unvis flags
+ */
+#define        UNVIS_END       1       /* no more characters */
+
+char ROKEN_LIB_FUNCTION
+       *vis (char *, int, int, int);
+char ROKEN_LIB_FUNCTION
+       *svis (char *, int, int, int, const char *);
+int ROKEN_LIB_FUNCTION
+       strvis (char *, const char *, int);
+int ROKEN_LIB_FUNCTION
+       strsvis (char *, const char *, int, const char *);
+int ROKEN_LIB_FUNCTION
+       strvisx (char *, const char *, size_t, int);
+int ROKEN_LIB_FUNCTION
+       strsvisx (char *, const char *, size_t, int, const char *);
+int ROKEN_LIB_FUNCTION
+       strunvis (char *, const char *);
+int ROKEN_LIB_FUNCTION
+       unvis (char *, int, int *, int);
+
+#endif /* !_VIS_H_ */