r19604: This is a massive commit, and I appologise in advance for it's size.
authorAndrew Bartlett <abartlet@samba.org>
Tue, 7 Nov 2006 06:59:56 +0000 (06:59 +0000)
committerGerald (Jerry) Carter <jerry@samba.org>
Wed, 10 Oct 2007 19:25:03 +0000 (14:25 -0500)
This merges Samba4 with lorikeet-heimdal, which itself has been
tracking Heimdal CVS for the past couple of weeks.

This is such a big change because Heimdal reorganised it's internal
structures, with the mechglue merge, and because many of our 'wishes' have been granted:  we now have DCE_STYLE GSSAPI, send_to_kdc hooks and many other features merged into the mainline code.  We have adapted to upstream's choice of API in these cases.

In gensec_gssapi and gensec_krb5, we either expect a valid PAC, or NO
PAC.  This matches windows behavour.  We also have an option to
require the PAC to be present (which allows us to automate the testing
of this code).

This also includes a restructure of how the kerberos dependencies are
handled, due to the fallout of the merge.

Andrew Bartlett
(This used to be commit 4826f1735197c2a471d771495e6d4c1051b4c471)

265 files changed:
source4/auth/credentials/credentials_krb5.h
source4/auth/gensec/gensec_gssapi.c
source4/auth/gensec/gensec_krb5.c
source4/auth/kerberos/kerberos.c
source4/auth/kerberos/kerberos_pac.c
source4/auth/kerberos/krb5_init_context.c
source4/auth/kerberos/krb5_init_context.h
source4/dsdb/samdb/cracknames.c
source4/heimdal/kdc/524.c
source4/heimdal/kdc/default_config.c
source4/heimdal/kdc/digest.c [new file with mode: 0644]
source4/heimdal/kdc/headers.h
source4/heimdal/kdc/kaserver.c
source4/heimdal/kdc/kdc-private.h
source4/heimdal/kdc/kdc-protos.h
source4/heimdal/kdc/kdc.h
source4/heimdal/kdc/kerberos4.c
source4/heimdal/kdc/kerberos5.c
source4/heimdal/kdc/krb5tgs.c [new file with mode: 0644]
source4/heimdal/kdc/misc.c
source4/heimdal/kdc/pkinit.c
source4/heimdal/kdc/process.c
source4/heimdal/lib/asn1/CMS.asn1
source4/heimdal/lib/asn1/asn1-common.h
source4/heimdal/lib/asn1/der-protos.h [new file with mode: 0644]
source4/heimdal/lib/asn1/der.h
source4/heimdal/lib/asn1/der_cmp.c
source4/heimdal/lib/asn1/der_copy.c
source4/heimdal/lib/asn1/der_format.c
source4/heimdal/lib/asn1/der_free.c
source4/heimdal/lib/asn1/der_get.c
source4/heimdal/lib/asn1/der_length.c
source4/heimdal/lib/asn1/der_locl.h
source4/heimdal/lib/asn1/der_put.c
source4/heimdal/lib/asn1/digest.asn1 [new file with mode: 0644]
source4/heimdal/lib/asn1/gen.c
source4/heimdal/lib/asn1/gen_copy.c
source4/heimdal/lib/asn1/gen_decode.c
source4/heimdal/lib/asn1/gen_free.c
source4/heimdal/lib/asn1/gen_length.c
source4/heimdal/lib/asn1/gen_locl.h
source4/heimdal/lib/asn1/gen_seq.c [new file with mode: 0644]
source4/heimdal/lib/asn1/heim_asn1.h
source4/heimdal/lib/asn1/k5.asn1
source4/heimdal/lib/asn1/lex.c
source4/heimdal/lib/asn1/main.c
source4/heimdal/lib/asn1/parse.c
source4/heimdal/lib/asn1/parse.h
source4/heimdal/lib/asn1/pkinit.asn1 [new file with mode: 0644]
source4/heimdal/lib/asn1/rfc2459.asn1 [new file with mode: 0644]
source4/heimdal/lib/asn1/test.asn1
source4/heimdal/lib/asn1/timegm.c [new file with mode: 0644]
source4/heimdal/lib/com_err/lex.c
source4/heimdal/lib/com_err/parse.c
source4/heimdal/lib/com_err/parse.h
source4/heimdal/lib/des/evp.c
source4/heimdal/lib/des/evp.h
source4/heimdal/lib/des/hmac.c
source4/heimdal/lib/des/rand-unix.c [new file with mode: 0644]
source4/heimdal/lib/des/rand.c [new file with mode: 0644]
source4/heimdal/lib/des/ui.c
source4/heimdal/lib/gssapi/accept_sec_context.c [deleted file]
source4/heimdal/lib/gssapi/arcfour.h [deleted file]
source4/heimdal/lib/gssapi/gssapi.h
source4/heimdal/lib/gssapi/gssapi/gssapi.h [new file with mode: 0644]
source4/heimdal/lib/gssapi/gssapi/gssapi_krb5.h [new file with mode: 0644]
source4/heimdal/lib/gssapi/gssapi/gssapi_spnego.h [new file with mode: 0644]
source4/heimdal/lib/gssapi/gssapi_locl.h [deleted file]
source4/heimdal/lib/gssapi/gssapi_mech.h [new file with mode: 0644]
source4/heimdal/lib/gssapi/init_sec_context.c [deleted file]
source4/heimdal/lib/gssapi/inquire_cred.c [deleted file]
source4/heimdal/lib/gssapi/krb5/8003.c [moved from source4/heimdal/lib/gssapi/8003.c with 88% similarity]
source4/heimdal/lib/gssapi/krb5/accept_sec_context.c [new file with mode: 0644]
source4/heimdal/lib/gssapi/krb5/acquire_cred.c [moved from source4/heimdal/lib/gssapi/acquire_cred.c with 63% similarity]
source4/heimdal/lib/gssapi/krb5/add_cred.c [new file with mode: 0644]
source4/heimdal/lib/gssapi/krb5/add_oid_set_member.c [moved from source4/heimdal/lib/gssapi/add_oid_set_member.c with 90% similarity]
source4/heimdal/lib/gssapi/krb5/address_to_krb5addr.c [moved from source4/heimdal/lib/gssapi/address_to_krb5addr.c with 88% similarity]
source4/heimdal/lib/gssapi/krb5/arcfour.c [moved from source4/heimdal/lib/gssapi/arcfour.c with 73% similarity]
source4/heimdal/lib/gssapi/krb5/canonicalize_name.c [new file with mode: 0644]
source4/heimdal/lib/gssapi/krb5/cfx.c [moved from source4/heimdal/lib/gssapi/cfx.c with 74% similarity]
source4/heimdal/lib/gssapi/krb5/cfx.h [moved from source4/heimdal/lib/gssapi/cfx.h with 64% similarity]
source4/heimdal/lib/gssapi/krb5/compare_name.c [new file with mode: 0644]
source4/heimdal/lib/gssapi/krb5/compat.c [moved from source4/heimdal/lib/gssapi/compat.c with 63% similarity]
source4/heimdal/lib/gssapi/krb5/context_time.c [moved from source4/heimdal/lib/gssapi/context_time.c with 82% similarity]
source4/heimdal/lib/gssapi/krb5/copy_ccache.c [moved from source4/heimdal/lib/gssapi/copy_ccache.c with 50% similarity]
source4/heimdal/lib/gssapi/krb5/create_emtpy_oid_set.c [moved from source4/heimdal/lib/gssapi/create_emtpy_oid_set.c with 93% similarity]
source4/heimdal/lib/gssapi/krb5/decapsulate.c [moved from source4/heimdal/lib/gssapi/decapsulate.c with 91% similarity]
source4/heimdal/lib/gssapi/krb5/delete_sec_context.c [moved from source4/heimdal/lib/gssapi/delete_sec_context.c with 61% similarity]
source4/heimdal/lib/gssapi/krb5/display_name.c [moved from source4/heimdal/lib/gssapi/display_name.c with 89% similarity]
source4/heimdal/lib/gssapi/krb5/display_status.c [moved from source4/heimdal/lib/gssapi/display_status.c with 88% similarity]
source4/heimdal/lib/gssapi/krb5/duplicate_name.c [moved from source4/heimdal/lib/gssapi/duplicate_name.c with 85% similarity]
source4/heimdal/lib/gssapi/krb5/encapsulate.c [moved from source4/heimdal/lib/gssapi/encapsulate.c with 87% similarity]
source4/heimdal/lib/gssapi/krb5/export_name.c [new file with mode: 0644]
source4/heimdal/lib/gssapi/krb5/export_sec_context.c [new file with mode: 0644]
source4/heimdal/lib/gssapi/krb5/external.c [moved from source4/heimdal/lib/gssapi/external.c with 67% similarity]
source4/heimdal/lib/gssapi/krb5/get_mic.c [moved from source4/heimdal/lib/gssapi/get_mic.c with 76% similarity]
source4/heimdal/lib/gssapi/krb5/gsskrb5-private.h [new file with mode: 0644]
source4/heimdal/lib/gssapi/krb5/gsskrb5_locl.h [new file with mode: 0644]
source4/heimdal/lib/gssapi/krb5/import_name.c [moved from source4/heimdal/lib/gssapi/import_name.c with 84% similarity]
source4/heimdal/lib/gssapi/krb5/import_sec_context.c [new file with mode: 0644]
source4/heimdal/lib/gssapi/krb5/indicate_mechs.c [new file with mode: 0644]
source4/heimdal/lib/gssapi/krb5/init.c [moved from source4/heimdal/lib/gssapi/init.c with 62% similarity]
source4/heimdal/lib/gssapi/krb5/init_sec_context.c [new file with mode: 0644]
source4/heimdal/lib/gssapi/krb5/inquire_context.c [new file with mode: 0644]
source4/heimdal/lib/gssapi/krb5/inquire_cred.c [new file with mode: 0644]
source4/heimdal/lib/gssapi/krb5/inquire_cred_by_mech.c [new file with mode: 0644]
source4/heimdal/lib/gssapi/krb5/inquire_cred_by_oid.c [new file with mode: 0644]
source4/heimdal/lib/gssapi/krb5/inquire_mechs_for_name.c [new file with mode: 0644]
source4/heimdal/lib/gssapi/krb5/inquire_names_for_mech.c [new file with mode: 0644]
source4/heimdal/lib/gssapi/krb5/inquire_sec_context_by_oid.c [new file with mode: 0644]
source4/heimdal/lib/gssapi/krb5/process_context_token.c [new file with mode: 0644]
source4/heimdal/lib/gssapi/krb5/release_buffer.c [moved from source4/heimdal/lib/gssapi/release_buffer.c with 93% similarity]
source4/heimdal/lib/gssapi/krb5/release_cred.c [moved from source4/heimdal/lib/gssapi/release_cred.c with 66% similarity]
source4/heimdal/lib/gssapi/krb5/release_name.c [moved from source4/heimdal/lib/gssapi/release_name.c with 88% similarity]
source4/heimdal/lib/gssapi/krb5/release_oid_set.c [moved from source4/heimdal/lib/gssapi/release_oid_set.c with 93% similarity]
source4/heimdal/lib/gssapi/krb5/sequence.c [moved from source4/heimdal/lib/gssapi/sequence.c with 97% similarity]
source4/heimdal/lib/gssapi/krb5/set_cred_option.c [new file with mode: 0644]
source4/heimdal/lib/gssapi/krb5/set_sec_context_option.c [new file with mode: 0644]
source4/heimdal/lib/gssapi/krb5/test_oid_set_member.c [moved from source4/heimdal/lib/gssapi/test_oid_set_member.c with 82% similarity]
source4/heimdal/lib/gssapi/krb5/unwrap.c [moved from source4/heimdal/lib/gssapi/unwrap.c with 85% similarity]
source4/heimdal/lib/gssapi/krb5/verify_mic.c [moved from source4/heimdal/lib/gssapi/verify_mic.c with 82% similarity]
source4/heimdal/lib/gssapi/krb5/wrap.c [moved from source4/heimdal/lib/gssapi/wrap.c with 57% similarity]
source4/heimdal/lib/gssapi/mech/context.h [new file with mode: 0644]
source4/heimdal/lib/gssapi/mech/cred.h [new file with mode: 0644]
source4/heimdal/lib/gssapi/mech/gss_accept_sec_context.c [new file with mode: 0644]
source4/heimdal/lib/gssapi/mech/gss_acquire_cred.c [new file with mode: 0644]
source4/heimdal/lib/gssapi/mech/gss_add_cred.c [new file with mode: 0644]
source4/heimdal/lib/gssapi/mech/gss_add_oid_set_member.c [moved from source4/heimdal/lib/gssapi/ccache_name.c with 66% similarity, mode: 0644]
source4/heimdal/lib/gssapi/mech/gss_buffer_set.c [new file with mode: 0644]
source4/heimdal/lib/gssapi/mech/gss_canonicalize_name.c [new file with mode: 0644]
source4/heimdal/lib/gssapi/mech/gss_compare_name.c [new file with mode: 0644]
source4/heimdal/lib/gssapi/mech/gss_context_time.c [new file with mode: 0644]
source4/heimdal/lib/gssapi/mech/gss_create_empty_oid_set.c [new file with mode: 0644]
source4/heimdal/lib/gssapi/mech/gss_decapsulate_token.c [new file with mode: 0644]
source4/heimdal/lib/gssapi/mech/gss_delete_sec_context.c [new file with mode: 0644]
source4/heimdal/lib/gssapi/mech/gss_display_name.c [new file with mode: 0644]
source4/heimdal/lib/gssapi/mech/gss_display_status.c [new file with mode: 0644]
source4/heimdal/lib/gssapi/mech/gss_duplicate_name.c [new file with mode: 0644]
source4/heimdal/lib/gssapi/mech/gss_duplicate_oid.c [new file with mode: 0644]
source4/heimdal/lib/gssapi/mech/gss_encapsulate_token.c [new file with mode: 0644]
source4/heimdal/lib/gssapi/mech/gss_export_name.c [new file with mode: 0644]
source4/heimdal/lib/gssapi/mech/gss_export_sec_context.c [new file with mode: 0644]
source4/heimdal/lib/gssapi/mech/gss_get_mic.c [new file with mode: 0644]
source4/heimdal/lib/gssapi/mech/gss_import_name.c [new file with mode: 0644]
source4/heimdal/lib/gssapi/mech/gss_import_sec_context.c [new file with mode: 0644]
source4/heimdal/lib/gssapi/mech/gss_indicate_mechs.c [new file with mode: 0644]
source4/heimdal/lib/gssapi/mech/gss_init_sec_context.c [new file with mode: 0644]
source4/heimdal/lib/gssapi/mech/gss_inquire_context.c [new file with mode: 0644]
source4/heimdal/lib/gssapi/mech/gss_inquire_cred.c [new file with mode: 0644]
source4/heimdal/lib/gssapi/mech/gss_inquire_cred_by_mech.c [new file with mode: 0644]
source4/heimdal/lib/gssapi/mech/gss_inquire_cred_by_oid.c [new file with mode: 0644]
source4/heimdal/lib/gssapi/mech/gss_inquire_mechs_for_name.c [new file with mode: 0644]
source4/heimdal/lib/gssapi/mech/gss_inquire_names_for_mech.c [new file with mode: 0644]
source4/heimdal/lib/gssapi/mech/gss_inquire_sec_context_by_oid.c [new file with mode: 0644]
source4/heimdal/lib/gssapi/mech/gss_krb5.c [new file with mode: 0644]
source4/heimdal/lib/gssapi/mech/gss_mech_switch.c [new file with mode: 0644]
source4/heimdal/lib/gssapi/mech/gss_names.c [new file with mode: 0644]
source4/heimdal/lib/gssapi/mech/gss_oid_equal.c [new file with mode: 0644]
source4/heimdal/lib/gssapi/mech/gss_process_context_token.c [new file with mode: 0644]
source4/heimdal/lib/gssapi/mech/gss_release_buffer.c [new file with mode: 0644]
source4/heimdal/lib/gssapi/mech/gss_release_cred.c [new file with mode: 0644]
source4/heimdal/lib/gssapi/mech/gss_release_name.c [new file with mode: 0644]
source4/heimdal/lib/gssapi/mech/gss_release_oid.c [new file with mode: 0644]
source4/heimdal/lib/gssapi/mech/gss_release_oid_set.c [new file with mode: 0644]
source4/heimdal/lib/gssapi/mech/gss_seal.c [new file with mode: 0644]
source4/heimdal/lib/gssapi/mech/gss_set_cred_option.c [new file with mode: 0644]
source4/heimdal/lib/gssapi/mech/gss_set_sec_context_option.c [new file with mode: 0644]
source4/heimdal/lib/gssapi/mech/gss_sign.c [new file with mode: 0644]
source4/heimdal/lib/gssapi/mech/gss_test_oid_set_member.c [new file with mode: 0644]
source4/heimdal/lib/gssapi/mech/gss_unseal.c [new file with mode: 0644]
source4/heimdal/lib/gssapi/mech/gss_unwrap.c [new file with mode: 0644]
source4/heimdal/lib/gssapi/mech/gss_utils.c [new file with mode: 0644]
source4/heimdal/lib/gssapi/mech/gss_verify.c [new file with mode: 0644]
source4/heimdal/lib/gssapi/mech/gss_verify_mic.c [new file with mode: 0644]
source4/heimdal/lib/gssapi/mech/gss_wrap.c [new file with mode: 0644]
source4/heimdal/lib/gssapi/mech/gss_wrap_size_limit.c [new file with mode: 0644]
source4/heimdal/lib/gssapi/mech/gssapi.asn1 [new file with mode: 0644]
source4/heimdal/lib/gssapi/mech/mech_locl.h [new file with mode: 0644]
source4/heimdal/lib/gssapi/mech/mech_switch.h [new file with mode: 0644]
source4/heimdal/lib/gssapi/mech/mechqueue.h [new file with mode: 0644]
source4/heimdal/lib/gssapi/mech/name.h [new file with mode: 0644]
source4/heimdal/lib/gssapi/mech/utils.h [new file with mode: 0644]
source4/heimdal/lib/gssapi/spnego.asn1 [deleted file]
source4/heimdal/lib/gssapi/spnego/accept_sec_context.c [new file with mode: 0644]
source4/heimdal/lib/gssapi/spnego/compat.c [new file with mode: 0644]
source4/heimdal/lib/gssapi/spnego/context_stubs.c [new file with mode: 0644]
source4/heimdal/lib/gssapi/spnego/cred_stubs.c [new file with mode: 0644]
source4/heimdal/lib/gssapi/spnego/external.c [new file with mode: 0644]
source4/heimdal/lib/gssapi/spnego/init_sec_context.c [new file with mode: 0644]
source4/heimdal/lib/gssapi/spnego/spnego-private.h [new file with mode: 0644]
source4/heimdal/lib/gssapi/spnego/spnego.asn1 [new file with mode: 0644]
source4/heimdal/lib/gssapi/spnego/spnego_locl.h [new file with mode: 0644]
source4/heimdal/lib/hdb/db.c
source4/heimdal/lib/hdb/ext.c
source4/heimdal/lib/hdb/hdb-protos.h
source4/heimdal/lib/hdb/hdb.asn1
source4/heimdal/lib/hdb/hdb.c
source4/heimdal/lib/hdb/hdb.h
source4/heimdal/lib/hdb/keys.c
source4/heimdal/lib/hdb/keytab.c
source4/heimdal/lib/krb5/acache.c
source4/heimdal/lib/krb5/addr_families.c
source4/heimdal/lib/krb5/asn1_glue.c
source4/heimdal/lib/krb5/cache.c
source4/heimdal/lib/krb5/context.c
source4/heimdal/lib/krb5/crypto.c
source4/heimdal/lib/krb5/data.c
source4/heimdal/lib/krb5/expand_hostname.c
source4/heimdal/lib/krb5/get_cred.c
source4/heimdal/lib/krb5/get_for_creds.c
source4/heimdal/lib/krb5/get_host_realm.c
source4/heimdal/lib/krb5/get_in_tkt.c
source4/heimdal/lib/krb5/heim_err.c [new file with mode: 0644]
source4/heimdal/lib/krb5/heim_threads.h
source4/heimdal/lib/krb5/init_creds.c
source4/heimdal/lib/krb5/init_creds_pw.c
source4/heimdal/lib/krb5/k524_err.c [new file with mode: 0644]
source4/heimdal/lib/krb5/krb5-private.h
source4/heimdal/lib/krb5/krb5-protos.h
source4/heimdal/lib/krb5/krb5.h
source4/heimdal/lib/krb5/krb5_err.c [new file with mode: 0644]
source4/heimdal/lib/krb5/krb5_locl.h
source4/heimdal/lib/krb5/krbhst.c
source4/heimdal/lib/krb5/misc.c
source4/heimdal/lib/krb5/mit_glue.c
source4/heimdal/lib/krb5/pkinit.c
source4/heimdal/lib/krb5/principal.c
source4/heimdal/lib/krb5/rd_cred.c
source4/heimdal/lib/krb5/rd_rep.c
source4/heimdal/lib/krb5/rd_req.c
source4/heimdal/lib/krb5/send_to_kdc.c
source4/heimdal/lib/krb5/set_default_realm.c
source4/heimdal/lib/krb5/store.c
source4/heimdal/lib/krb5/store_fd.c
source4/heimdal/lib/krb5/ticket.c
source4/heimdal/lib/roken/bswap.c
source4/heimdal/lib/roken/copyhostent.c
source4/heimdal/lib/roken/freeaddrinfo.c
source4/heimdal/lib/roken/freehostent.c
source4/heimdal/lib/roken/gai_strerror.c
source4/heimdal/lib/roken/getaddrinfo.c
source4/heimdal/lib/roken/getipnodebyaddr.c
source4/heimdal/lib/roken/getipnodebyname.c
source4/heimdal/lib/roken/getprogname.c
source4/heimdal/lib/roken/hex.c
source4/heimdal/lib/roken/hostent_find_fqdn.c
source4/heimdal/lib/roken/inet_aton.c
source4/heimdal/lib/roken/issuid.c
source4/heimdal/lib/roken/resolve.c
source4/heimdal/lib/roken/roken.h
source4/heimdal/lib/roken/setprogname.c
source4/heimdal/lib/roken/signal.c
source4/heimdal/lib/roken/strsep.c
source4/heimdal/lib/roken/strsep_copy.c
source4/heimdal_build/asn1_deps.pl
source4/heimdal_build/config.mk
source4/kdc/hdb-ldb.c
source4/kdc/kdc.c
source4/kdc/kdc.h
source4/kdc/kpasswdd.c
source4/kdc/pac-glue.c
source4/smbd/process_single.c
source4/smbd/process_standard.c
source4/static_deps.mk
source4/torture/auth/pac.c

index 2bd38af5c78a70fe04e782273a649d6711df1b7f..22c0f5abfeae8be28038e5860e10d8497854ba20 100644 (file)
@@ -21,9 +21,7 @@
    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 */
 
-struct EncryptionKey;
-
-#include "heimdal/lib/gssapi/gssapi.h"
+#include "heimdal/lib/gssapi/gssapi/gssapi.h"
 
 struct ccache_container;
 
index ed407b623bb47e5b8e2ea29687456c681dbe6072..136962d89237129538f1da5865767de643d91fad 100644 (file)
@@ -24,7 +24,7 @@
 
 #include "includes.h"
 #include "system/kerberos.h"
-#include "heimdal/lib/gssapi/gssapi.h"
+#include "heimdal/lib/gssapi/gssapi/gssapi.h"
 #include "auth/kerberos/kerberos.h"
 #include "librpc/gen_ndr/krb5pac.h"
 #include "auth/auth.h"
@@ -73,6 +73,7 @@ struct gensec_gssapi_state {
                                  * layer... */
 
        size_t max_wrap_buf_size;
+       int gss_exchange_count;
 };
 
 static size_t gensec_gssapi_max_input_size(struct gensec_security *gensec_security);
@@ -133,12 +134,14 @@ static NTSTATUS gensec_gssapi_start(struct gensec_security *gensec_security)
 {
        struct gensec_gssapi_state *gensec_gssapi_state;
        krb5_error_code ret;
-       
+       struct gsskrb5_send_to_kdc send_to_kdc;
+
        gensec_gssapi_state = talloc(gensec_security, struct gensec_gssapi_state);
        if (!gensec_gssapi_state) {
                return NT_STATUS_NO_MEMORY;
        }
        
+       gensec_gssapi_state->gss_exchange_count = 0;
        gensec_gssapi_state->max_wrap_buf_size
                = lp_parm_int(-1, "gensec_gssapi", "max wrap buf size", 65536);
                
@@ -186,10 +189,18 @@ static NTSTATUS gensec_gssapi_start(struct gensec_security *gensec_security)
 
        gensec_gssapi_state->gss_oid = gss_mech_krb5;
        
+       send_to_kdc.func = smb_krb5_send_and_recv_func;
+       send_to_kdc.ptr = gensec_security->event_ctx;
+
+       ret = gsskrb5_set_send_to_kdc(&send_to_kdc);
+       if (ret) {
+               DEBUG(1,("gensec_krb5_start: gsskrb5_set_send_to_kdc failed\n"));
+               return NT_STATUS_INTERNAL_ERROR;
+       }
        ret = smb_krb5_init_context(gensec_gssapi_state, 
                                    &gensec_gssapi_state->smb_krb5_context);
        if (ret) {
-               DEBUG(1,("gensec_krb5_start: krb5_init_context failed (%s)\n",                                  
+               DEBUG(1,("gensec_krb5_start: krb5_init_context failed (%s)\n",
                         error_message(ret)));
                return NT_STATUS_INTERNAL_ERROR;
        }
@@ -431,6 +442,8 @@ static NTSTATUS gensec_gssapi_update(struct gensec_security *gensec_security,
                        
                }
 
+               gensec_gssapi_state->gss_exchange_count++;
+
                if (maj_stat == GSS_S_COMPLETE) {
                        *out = data_blob_talloc(out_mem_ctx, output_token.value, output_token.length);
                        gss_release_buffer(&min_stat2, &output_token);
@@ -493,12 +506,14 @@ static NTSTATUS gensec_gssapi_update(struct gensec_security *gensec_security,
                                /* garbage input, possibly from the auto-mech detection */
                                return NT_STATUS_INVALID_PARAMETER;
                        default:
-                               DEBUG(1, ("GSS(krb5) Update failed: %s\n", 
+                               DEBUG(1, ("GSS Update(krb5)(%d) Update failed: %s\n", 
+                                         gensec_gssapi_state->gss_exchange_count,
                                          gssapi_error_string(out_mem_ctx, maj_stat, min_stat, gensec_gssapi_state->gss_oid)));
                                return nt_status;
                        }
                } else {
-                       DEBUG(1, ("GSS Update failed: %s\n", 
+                       DEBUG(1, ("GSS Update(%d) failed: %s\n", 
+                                 gensec_gssapi_state->gss_exchange_count,
                                  gssapi_error_string(out_mem_ctx, maj_stat, min_stat, gensec_gssapi_state->gss_oid)));
                        return nt_status;
                }
@@ -583,7 +598,7 @@ static NTSTATUS gensec_gssapi_update(struct gensec_security *gensec_security,
                                            &conf_state,
                                            &output_token);
                        if (GSS_ERROR(maj_stat)) {
-                               DEBUG(1, ("gensec_gssapi_wrap: GSS Wrap failed: %s\n", 
+                               DEBUG(1, ("GSS Update(SSF_NEG): GSS Wrap failed: %s\n", 
                                          gssapi_error_string(out_mem_ctx, maj_stat, min_stat, gensec_gssapi_state->gss_oid)));
                                return NT_STATUS_ACCESS_DENIED;
                        }
@@ -648,7 +663,7 @@ static NTSTATUS gensec_gssapi_update(struct gensec_security *gensec_security,
                                            &conf_state,
                                            &output_token);
                        if (GSS_ERROR(maj_stat)) {
-                               DEBUG(1, ("gensec_gssapi_wrap: GSS Wrap failed: %s\n", 
+                               DEBUG(1, ("GSS Update(SSF_NEG): GSS Wrap failed: %s\n", 
                                          gssapi_error_string(out_mem_ctx, maj_stat, min_stat, gensec_gssapi_state->gss_oid)));
                                return NT_STATUS_ACCESS_DENIED;
                        }
@@ -1185,38 +1200,57 @@ static NTSTATUS gensec_gssapi_session_info(struct gensec_security *gensec_securi
                return NT_STATUS_NO_MEMORY;
        }
 
-       maj_stat = gss_krb5_copy_service_keyblock(&min_stat, 
-                                                 gensec_gssapi_state->gssapi_context, 
-                                                 &keyblock);
-
-       if (maj_stat == 0) {
-               maj_stat = gsskrb5_extract_authtime_from_sec_context(&min_stat,
-                                                                    gensec_gssapi_state->gssapi_context, 
-                                                                    &authtime);
-       }
-
-       if (maj_stat == 0) {
-               maj_stat = gsskrb5_extract_authz_data_from_sec_context(&min_stat, 
-                                                                      gensec_gssapi_state->gssapi_context, 
-                                                                      KRB5_AUTHDATA_WIN2K_PAC,
-                                                                      &pac);
-       }
-
+       maj_stat = gsskrb5_extract_authz_data_from_sec_context(&min_stat, 
+                                                              gensec_gssapi_state->gssapi_context, 
+                                                              KRB5_AUTHDATA_WIN2K_PAC,
+                                                              &pac);
+       
+       
        if (maj_stat == 0) {
                pac_blob = data_blob_talloc(mem_ctx, pac.value, pac.length);
                gss_release_buffer(&min_stat, &pac);
+
+       } else {
+               pac_blob = data_blob(NULL, 0);
        }
        
        /* IF we have the PAC - otherwise we need to get this
         * data from elsewere - local ldb, or (TODO) lookup of some
         * kind... 
         */
-       if (maj_stat == 0) {
+       if (pac_blob.length) {
                krb5_error_code ret;
+               union netr_Validation validation;
 
-               ret = krb5_parse_name(gensec_gssapi_state->smb_krb5_context->krb5_context,
-                                     principal_string, &principal);
+               maj_stat = gsskrb5_extract_authtime_from_sec_context(&min_stat,
+                                                                    gensec_gssapi_state->gssapi_context, 
+                                                                    &authtime);
+               
+               if (GSS_ERROR(maj_stat)) {
+                       DEBUG(1, ("gsskrb5_extract_authtime_from_sec_context: %s\n", 
+                                 gssapi_error_string(mem_ctx, maj_stat, min_stat, gensec_gssapi_state->gss_oid)));
+                       talloc_free(mem_ctx);
+                       return NT_STATUS_FOOBAR;
+               }
+
+               maj_stat = gsskrb5_extract_service_keyblock(&min_stat, 
+                                                           gensec_gssapi_state->gssapi_context, 
+                                                           &keyblock);
+               
+               if (GSS_ERROR(maj_stat)) {
+                       DEBUG(1, ("gsskrb5_copy_service_keyblock failed: %s\n", 
+                                 gssapi_error_string(mem_ctx, maj_stat, min_stat, gensec_gssapi_state->gss_oid)));
+                       talloc_free(mem_ctx);
+                       return NT_STATUS_FOOBAR;
+               } 
+
+               ret = krb5_parse_name_flags(gensec_gssapi_state->smb_krb5_context->krb5_context,
+                                           principal_string, 
+                                           KRB5_PRINCIPAL_PARSE_MUST_REALM,
+                                           &principal);
                if (ret) {
+                       krb5_free_keyblock(gensec_gssapi_state->smb_krb5_context->krb5_context,
+                                          keyblock);
                        talloc_free(mem_ctx);
                        return NT_STATUS_INVALID_PARAMETER;
                }
@@ -1226,25 +1260,25 @@ static NTSTATUS gensec_gssapi_session_info(struct gensec_security *gensec_securi
                                                    gensec_gssapi_state->smb_krb5_context->krb5_context,
                                                    NULL, keyblock, principal, authtime, NULL);
                krb5_free_principal(gensec_gssapi_state->smb_krb5_context->krb5_context, principal);
+               krb5_free_keyblock(gensec_gssapi_state->smb_krb5_context->krb5_context,
+                                  keyblock);
 
-               if (NT_STATUS_IS_OK(nt_status)) {
-                       union netr_Validation validation;
-                       validation.sam3 = &logon_info->info3;
-                       nt_status = make_server_info_netlogon_validation(gensec_gssapi_state, 
-                                                                        NULL,
-                                                                        3, &validation,
-                                                                        &server_info); 
-                       if (!NT_STATUS_IS_OK(nt_status)) {
-                               talloc_free(mem_ctx);
-                               return nt_status;
-                       }
-               } else {
-                       maj_stat = 1;
+               if (!NT_STATUS_IS_OK(nt_status)) {
+                       talloc_free(mem_ctx);
+                       return nt_status;
                }
-       }
-       
-       if (maj_stat) {
-               DEBUG(1, ("Unable to use PAC, resorting to local user lookup!\n"));
+               validation.sam3 = &logon_info->info3;
+               nt_status = make_server_info_netlogon_validation(gensec_gssapi_state, 
+                                                                NULL,
+                                                                3, &validation,
+                                                                &server_info); 
+               if (!NT_STATUS_IS_OK(nt_status)) {
+                       talloc_free(mem_ctx);
+                       return nt_status;
+               }
+       } else if (!lp_parm_bool(-1, "gensec", "require_pac", False)) {
+               DEBUG(1, ("Unable to find PAC, resorting to local user lookup: %s\n",
+                         gssapi_error_string(mem_ctx, maj_stat, min_stat, gensec_gssapi_state->gss_oid)));
                nt_status = sam_get_server_info_principal(mem_ctx, principal_string,
                                                          &server_info);
 
@@ -1252,6 +1286,11 @@ static NTSTATUS gensec_gssapi_session_info(struct gensec_security *gensec_securi
                        talloc_free(mem_ctx);
                        return nt_status;
                }
+       } else {
+               DEBUG(1, ("Unable to find PAC in ticket from %s, failing to allow access: %s\n",
+                         principal_string,
+                         gssapi_error_string(mem_ctx, maj_stat, min_stat, gensec_gssapi_state->gss_oid)));
+               return NT_STATUS_ACCESS_DENIED;
        }
 
        /* references the server_info into the session_info */
index d84f3dedf579d5027a8da662792966a09d81dac0..66d280152012c5afd102b5151f102447e5b07b46 100644 (file)
@@ -527,6 +527,7 @@ static NTSTATUS gensec_krb5_session_info(struct gensec_security *gensec_security
        struct PAC_LOGON_INFO *logon_info;
 
        krb5_principal client_principal;
+       char *principal_string;
        
        DATA_BLOB pac;
        krb5_data pac_data;
@@ -538,30 +539,63 @@ static NTSTATUS gensec_krb5_session_info(struct gensec_security *gensec_security
                return NT_STATUS_NO_MEMORY;
        }
        
+       ret = krb5_ticket_get_client(context, gensec_krb5_state->ticket, &client_principal);
+       if (ret) {
+               DEBUG(5, ("krb5_ticket_get_client failed to get cleint principal: %s\n", 
+                         smb_get_krb5_error_message(context, 
+                                                    ret, mem_ctx)));
+               talloc_free(mem_ctx);
+               return NT_STATUS_NO_MEMORY;
+       }
+       
+       ret = krb5_unparse_name(gensec_krb5_state->smb_krb5_context->krb5_context, 
+                               client_principal, &principal_string);
+       if (ret) {
+               DEBUG(1, ("Unable to parse client principal: %s\n",
+                         smb_get_krb5_error_message(context, 
+                                                    ret, mem_ctx)));
+               talloc_free(mem_ctx);
+               return NT_STATUS_NO_MEMORY;
+       }
+
        ret = krb5_ticket_get_authorization_data_type(context, gensec_krb5_state->ticket, 
                                                      KRB5_AUTHDATA_WIN2K_PAC, 
                                                      &pac_data);
        
-       if (ret) {
+       if (ret && lp_parm_bool(-1, "gensec", "require_pac", False)) {
+               DEBUG(1, ("Unable to find PAC in ticket from %s, failing to allow access: %s \n",
+                         principal_string,
+                         smb_get_krb5_error_message(context, 
+                                                    ret, mem_ctx)));
+               krb5_free_principal(context, client_principal);
+               free(principal_string);
+               return NT_STATUS_ACCESS_DENIED;
+       } else if (ret) {
+               /* NO pac */
                DEBUG(5, ("krb5_ticket_get_authorization_data_type failed to find PAC: %s\n", 
                          smb_get_krb5_error_message(context, 
                                                     ret, mem_ctx)));
+               nt_status = sam_get_server_info_principal(mem_ctx, principal_string,
+                                                         &server_info);
+               krb5_free_principal(context, client_principal);
+               free(principal_string);
+               
+               if (!NT_STATUS_IS_OK(nt_status)) {
+                       talloc_free(mem_ctx);
+                       return nt_status;
+               }
        } else {
+               /* Found pac */
+               union netr_Validation validation;
+               free(principal_string);
+
                pac = data_blob_talloc(mem_ctx, pac_data.data, pac_data.length);
                if (!pac.data) {
+                       krb5_free_principal(context, client_principal);
                        talloc_free(mem_ctx);
                        return NT_STATUS_NO_MEMORY;
                }
 
-               ret = krb5_ticket_get_client(context, gensec_krb5_state->ticket, &client_principal);
-               if (ret) {
-                       DEBUG(5, ("krb5_ticket_get_client failed to get cleint principal: %s\n", 
-                                 smb_get_krb5_error_message(context, 
-                                                            ret, mem_ctx)));
-                       talloc_free(mem_ctx);
-                       return NT_STATUS_NO_MEMORY;
-               }
-               
                /* decode and verify the pac */
                nt_status = kerberos_pac_logon_info(gensec_krb5_state, &logon_info, pac,
                                                    gensec_krb5_state->smb_krb5_context->krb5_context,
@@ -570,46 +604,16 @@ static NTSTATUS gensec_krb5_session_info(struct gensec_security *gensec_security
                                                    gensec_krb5_state->ticket->ticket.authtime, NULL);
                krb5_free_principal(context, client_principal);
 
-               if (NT_STATUS_IS_OK(nt_status)) {
-                       union netr_Validation validation;
-                       validation.sam3 = &logon_info->info3;
-                       nt_status = make_server_info_netlogon_validation(mem_ctx, 
-                                                                        NULL,
-                                                                        3, &validation,
-                                                                        &server_info); 
-               }
-       }
-
-               
-               
-       /* IF we have the PAC - otherwise we need to get this
-        * data from elsewere - local ldb, or (TODO) lookup of some
-        * kind... 
-        */
-       if (!NT_STATUS_IS_OK(nt_status)) {
-               /* NO pac, or can't parse or verify it */
-               char *principal_string;
-               ret = krb5_ticket_get_client(context, gensec_krb5_state->ticket, &client_principal);
-               if (ret) {
-                       DEBUG(5, ("krb5_ticket_get_client failed to get cleint principal: %s\n", 
-                                 smb_get_krb5_error_message(context, 
-                                                            ret, mem_ctx)));
-                       talloc_free(mem_ctx);
-                       return NT_STATUS_NO_MEMORY;
-               }
-               
-               ret = krb5_unparse_name(gensec_krb5_state->smb_krb5_context->krb5_context, 
-                                       client_principal, &principal_string);
-               krb5_free_principal(context, client_principal);
-               if (ret) {
+               if (!NT_STATUS_IS_OK(nt_status)) {
                        talloc_free(mem_ctx);
-                       return NT_STATUS_NO_MEMORY;
+                       return nt_status;
                }
 
-               nt_status = sam_get_server_info_principal(mem_ctx, principal_string,
-                                                         &server_info);
-               free(principal_string);
-               
+               validation.sam3 = &logon_info->info3;
+               nt_status = make_server_info_netlogon_validation(mem_ctx, 
+                                                                NULL,
+                                                                3, &validation,
+                                                                &server_info); 
                if (!NT_STATUS_IS_OK(nt_status)) {
                        talloc_free(mem_ctx);
                        return nt_status;
index 06f0c186a37925a5b68399b1ccd78530bee6b876..2b4c5d4cb0e9958b0b6c0653304f95830baa85c0 100644 (file)
@@ -45,6 +45,8 @@
 
        krb5_get_init_creds_opt_init(&options);
 
+       krb5_get_init_creds_opt_set_default_flags(ctx, NULL, NULL, &options);
+
        if ((code = krb5_get_init_creds_keyblock(ctx, &my_creds, principal, keyblock,
                                                 0, NULL, &options))) {
                return code;
@@ -87,6 +89,8 @@
 
        krb5_get_init_creds_opt_init(&options);
 
+       krb5_get_init_creds_opt_set_default_flags(ctx, NULL, NULL, &options);
+
        if ((code = krb5_get_init_creds_password(ctx, &my_creds, principal, password, 
                                                 NULL, 
                                                 NULL, 0, NULL, &options))) {
index dcfe16c8965d38fe5457be451fa494c6c26b6959..8e1801f745c1ec648fb8531da7f81206ae9f34a4 100644 (file)
@@ -280,7 +280,8 @@ static krb5_error_code check_pac_checksum(TALLOC_CTX *mem_ctx,
                return NT_STATUS_ACCESS_DENIED;
        }
 
-       ret = krb5_parse_name_norealm(context, logon_name->account_name, &client_principal_pac);
+       ret = krb5_parse_name_flags(context, logon_name->account_name, KRB5_PRINCIPAL_PARSE_NO_REALM, 
+                                   &client_principal_pac);
        if (ret) {
                DEBUG(2, ("Could not parse name from incoming PAC: [%s]: %s\n", 
                          logon_name->account_name, 
@@ -591,7 +592,8 @@ static krb5_error_code make_pac_checksum(TALLOC_CTX *mem_ctx,
        u_LOGON_INFO->logon_info.info           = LOGON_INFO;
        LOGON_INFO->info3 = *sam3;
 
-       ret = krb5_unparse_name_norealm(context, client_principal, &name);
+       ret = krb5_unparse_name_flags(context, client_principal, 
+                                     KRB5_PRINCIPAL_UNPARSE_NO_REALM, &name);
        if (ret) {
                return ret;
        }
index d895d7a3369767a4773401353298de4a041111d8..a3ef895b162ff4c486f3559d2ac3346f6e11a5f2 100644 (file)
@@ -23,6 +23,7 @@
 
 #include "includes.h"
 #include "system/kerberos.h"
+#include "heimdal/lib/krb5/krb5_locl.h"
 #include "auth/kerberos/kerberos.h"
 #include "lib/socket/socket.h"
 #include "system/network.h"
@@ -69,7 +70,7 @@ static void smb_krb5_debug_close(void *private) {
 
 static void smb_krb5_debug_wrapper(const char *timestr, const char *msg, void *private) 
 {
-       DEBUG(3, ("Kerberos: %s\n", msg));
+       DEBUG(2, ("Kerberos: %s\n", msg));
 }
 
 /*
@@ -224,11 +225,11 @@ static void smb_krb5_socket_handler(struct event_context *ev, struct fd_event *f
 }
 
 
-static krb5_error_code smb_krb5_send_and_recv_func(krb5_context context,
-                                                  void *data,
-                                                  krb5_krbhst_info *hi,
-                                                  const krb5_data *send_buf,
-                                                  krb5_data *recv_buf)
+krb5_error_code smb_krb5_send_and_recv_func(krb5_context context,
+                                           void *data,
+                                           krb5_krbhst_info *hi,
+                                           const krb5_data *send_buf,
+                                           krb5_data *recv_buf)
 {
        krb5_error_code ret;
        NTSTATUS status;
@@ -363,13 +364,6 @@ static krb5_error_code smb_krb5_send_and_recv_func(krb5_context context,
        return KRB5_KDC_UNREACH;
 }
 
-/* NO internal data, so nothing to free */
-static void smb_krb5_send_and_recv_close_func(krb5_context context, void *data) 
-{
-       return;
-}
-
-
 krb5_error_code smb_krb5_init_context(void *parent_ctx, 
                                       struct smb_krb5_context **smb_krb5_context) 
 {
@@ -437,9 +431,9 @@ krb5_error_code smb_krb5_init_context(void *parent_ctx,
 
        ev = event_context_find(*smb_krb5_context);
        /* Set use of our socket lib */
-       ret = krb5_set_send_recv_func((*smb_krb5_context)->krb5_context, 
-                                     smb_krb5_send_and_recv_func, 
-                                     smb_krb5_send_and_recv_close_func, ev);
+       ret = krb5_set_send_to_kdc_func((*smb_krb5_context)->krb5_context, 
+                                       smb_krb5_send_and_recv_func, 
+                                       ev);
        if (ret) {
                DEBUG(1,("krb5_set_send_recv_func failed (%s)\n", 
                         smb_get_krb5_error_message((*smb_krb5_context)->krb5_context, ret, tmp_ctx)));
@@ -454,12 +448,8 @@ krb5_error_code smb_krb5_init_context(void *parent_ctx,
 
        /* Set options in kerberos */
 
-       (*smb_krb5_context)->krb5_context->fdns = FALSE;
+       krb5_set_dns_canonicalize_hostname((*smb_krb5_context)->krb5_context, FALSE);
 
        return 0;
 }
 
- void smb_krb5_free_context(struct smb_krb5_context *smb_krb5_context) 
-{
-       talloc_free(smb_krb5_context);
-}
index f3ffc067faa9bf4b521d1ce160dc11a72bc85c09..7aad97e2ca58c9885f4222eb4b6048ac3eeef24c 100644 (file)
@@ -27,3 +27,8 @@ krb5_error_code smb_krb5_init_context(void *parent_ctx,
                                      struct smb_krb5_context **smb_krb5_context); 
 void smb_krb5_free_context(struct smb_krb5_context *smb_krb5_context);
 
+krb5_error_code smb_krb5_send_and_recv_func(krb5_context context,
+                                           void *data,
+                                           krb5_krbhst_info *hi,
+                                           const krb5_data *send_buf,
+                                           krb5_data *recv_buf);
index f92cf949b145e2538c2553f4daa94099bf426f15..eb051a0fb2deb56b290ff813bc37a7ff3569d427 100644 (file)
@@ -154,8 +154,8 @@ static WERROR DsCrackNameSPNAlias(struct ldb_context *sam_ctx, TALLOC_CTX *mem_c
        enum drsuapi_DsNameStatus namestatus;
        
        /* parse principal */
-       ret = krb5_parse_name_norealm(smb_krb5_context->krb5_context, 
-                                     name, &principal);
+       ret = krb5_parse_name_flags(smb_krb5_context->krb5_context, 
+                                   name, KRB5_PRINCIPAL_PARSE_NO_REALM, &principal);
        if (ret) {
                DEBUG(2, ("Could not parse principal: %s: %s",
                          name, smb_get_krb5_error_message(smb_krb5_context->krb5_context, 
@@ -196,7 +196,8 @@ static WERROR DsCrackNameSPNAlias(struct ldb_context *sam_ctx, TALLOC_CTX *mem_c
        }
        
        /* reform principal */
-       ret = krb5_unparse_name_norealm(smb_krb5_context->krb5_context, principal, &new_princ);
+       ret = krb5_unparse_name_flags(smb_krb5_context->krb5_context, principal, 
+                                     KRB5_PRINCIPAL_UNPARSE_NO_REALM, &new_princ);
 
        krb5_free_principal(smb_krb5_context->krb5_context, principal);
        
@@ -231,7 +232,8 @@ static WERROR DsCrackNameUPN(struct ldb_context *sam_ctx, TALLOC_CTX *mem_ctx,
                return WERR_OK;
        }
 
-       ret = krb5_parse_name_mustrealm(smb_krb5_context->krb5_context, name, &principal);
+       ret = krb5_parse_name_flags(smb_krb5_context->krb5_context, name, 
+                                   KRB5_PRINCIPAL_PARSE_MUST_REALM, &principal);
        if (ret) {
                info1->status = DRSUAPI_DS_NAME_STATUS_NOT_FOUND;
                return WERR_OK;
@@ -243,7 +245,8 @@ static WERROR DsCrackNameUPN(struct ldb_context *sam_ctx, TALLOC_CTX *mem_ctx,
                                        "(&(&(|(&(dnsRoot=%s)(nETBIOSName=*))(nETBIOSName=%s))(objectclass=crossRef))(ncName=*))",
                                        ldb_binary_encode_string(mem_ctx, *realm), 
                                        ldb_binary_encode_string(mem_ctx, *realm));
-       ret = krb5_unparse_name_norealm(smb_krb5_context->krb5_context, principal, &unparsed_name_short);
+       ret = krb5_unparse_name_flags(smb_krb5_context->krb5_context, principal, 
+                                     KRB5_PRINCIPAL_UNPARSE_NO_REALM, &unparsed_name_short);
        krb5_free_principal(smb_krb5_context->krb5_context, principal);
                
        if (ret) {
@@ -445,11 +448,13 @@ WERROR DsCrackNameOneName(struct ldb_context *sam_ctx, TALLOC_CTX *mem_ctx,
                krb5_principal principal;
                char *unparsed_name_short;
                char *service;
-               ret = krb5_parse_name_norealm(smb_krb5_context->krb5_context, name, &principal);
+               ret = krb5_parse_name_flags(smb_krb5_context->krb5_context, name, 
+                                           KRB5_PRINCIPAL_PARSE_NO_REALM, &principal);
                if (ret) {
                        /* perhaps it's a principal with a realm, so return the right 'domain only' response */
                        char **realm;
-                       ret = krb5_parse_name_mustrealm(smb_krb5_context->krb5_context, name, &principal);
+                       ret = krb5_parse_name_flags(smb_krb5_context->krb5_context, name, 
+                                                   KRB5_PRINCIPAL_PARSE_MUST_REALM, &principal);
                        if (ret) {
                                info1->status = DRSUAPI_DS_NAME_STATUS_NOT_FOUND;
                                return WERR_OK;
@@ -473,7 +478,8 @@ WERROR DsCrackNameOneName(struct ldb_context *sam_ctx, TALLOC_CTX *mem_ctx,
 
                domain_filter = NULL;
                
-               ret = krb5_unparse_name_norealm(smb_krb5_context->krb5_context, principal, &unparsed_name_short);
+               ret = krb5_unparse_name_flags(smb_krb5_context->krb5_context, principal, 
+                                             KRB5_PRINCIPAL_UNPARSE_NO_REALM, &unparsed_name_short);
                if (ret) {
                        krb5_free_principal(smb_krb5_context->krb5_context, principal);
                        return WERR_NOMEM;
index d61b78d9b6c592416388457319f685330afc048b..56c12efd6003641f06548da559169c27673e0cc6 100644 (file)
@@ -33,7 +33,7 @@
 
 #include "kdc_locl.h"
 
-RCSID("$Id: 524.c,v 1.37 2006/04/27 11:33:20 lha Exp $");
+RCSID("$Id: 524.c,v 1.40 2006/10/06 17:06:30 lha Exp $");
 
 #include <krb5-v4compat.h>
 
@@ -53,7 +53,8 @@ fetch_server (krb5_context context,
     krb5_error_code ret;
     krb5_principal sprinc;
 
-    ret = _krb5_principalname2krb5_principal(context, &sprinc, t->sname, t->realm);
+    ret = _krb5_principalname2krb5_principal(context, &sprinc,
+                                            t->sname, t->realm);
     if (ret) {
        kdc_log(context, config, 0, "_krb5_principalname2krb5_principal: %s",
                krb5_get_err_text(context, ret));
@@ -66,7 +67,8 @@ fetch_server (krb5_context context,
                krb5_get_err_text(context, ret));
        return ret;
     }
-    ret = _kdc_db_fetch(context, config, sprinc, HDB_F_GET_SERVER, server);
+    ret = _kdc_db_fetch(context, config, sprinc, HDB_F_GET_SERVER, 
+                       NULL, server);
     krb5_free_principal(context, sprinc);
     if (ret) {
        kdc_log(context, config, 0,
@@ -90,7 +92,8 @@ log_524 (krb5_context context,
     char *cpn;
     krb5_error_code ret;
 
-    ret = _krb5_principalname2krb5_principal(context, &client, et->cname, et->crealm);
+    ret = _krb5_principalname2krb5_principal(context, &client, 
+                                            et->cname, et->crealm);
     if (ret) {
        kdc_log(context, config, 0, "_krb5_principalname2krb5_principal: %s",
                krb5_get_err_text (context, ret));
index 5152fe9ab1c026c8ad7a42592a79a279d46cec5f..c4d9f51fd0b2b690ea919a65eb99cabc36ba8a9a 100644 (file)
@@ -42,8 +42,9 @@
 void
 krb5_kdc_default_config(krb5_kdc_configuration *config)
 {
+    memset(config, 0, sizeof(*config));
     config->require_preauth = TRUE;
-    config->kdc_warn_pwexpire = -1;
+    config->kdc_warn_pwexpire = 0;
     config->encode_as_rep_as_tgs_rep = FALSE; /* bug compatibility */
     config->check_ticket_addresses = TRUE;
     config->allow_null_ticket_addresses = TRUE;
diff --git a/source4/heimdal/kdc/digest.c b/source4/heimdal/kdc/digest.c
new file mode 100644 (file)
index 0000000..a5517fb
--- /dev/null
@@ -0,0 +1,712 @@
+/*
+ * Copyright (c) 2006 Kungliga Tekniska Högskolan
+ * (Royal Institute of Technology, Stockholm, Sweden). 
+ * All rights reserved. 
+ *
+ * Redistribution and use in source and binary forms, with or without 
+ * modification, are permitted provided that the following conditions 
+ * are met: 
+ *
+ * 1. Redistributions of source code must retain the above copyright 
+ *    notice, this list of conditions and the following disclaimer. 
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright 
+ *    notice, this list of conditions and the following disclaimer in the 
+ *    documentation and/or other materials provided with the distribution. 
+ *
+ * 3. Neither the name of the Institute nor the names of its contributors 
+ *    may be used to endorse or promote products derived from this software 
+ *    without specific prior written permission. 
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND 
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE 
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 
+ * LIABILITY, OR TORT (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 <digest_asn1.h>
+#include <hex.h>
+
+RCSID("$Id: digest.c,v 1.7 2006/10/22 20:11:44 lha Exp $");
+
+krb5_error_code
+_kdc_do_digest(krb5_context context, 
+              krb5_kdc_configuration *config,
+              const DigestREQ *req, krb5_data *reply,
+              const char *from, struct sockaddr *addr)
+{
+    krb5_error_code ret = 0;
+    krb5_ticket *ticket = NULL;
+    krb5_auth_context ac = NULL;
+    krb5_keytab id = NULL;
+    krb5_crypto crypto = NULL;
+    DigestReqInner ireq;
+    DigestRepInner r;
+    DigestREP rep;
+    krb5_flags ap_req_options;
+    krb5_data buf;
+    size_t size;
+    krb5_storage *sp = NULL;
+    Checksum res;
+    hdb_entry_ex *server = NULL, *user = NULL;
+    char *password = NULL;
+    krb5_data serverNonce;
+
+    if(!config->enable_digest) {
+       kdc_log(context, config, 0, "Rejected digest request from %s", from);
+       return KRB5KDC_ERR_POLICY;
+    }
+
+    krb5_data_zero(&buf);
+    krb5_data_zero(reply);
+    krb5_data_zero(&serverNonce);
+    memset(&ireq, 0, sizeof(ireq));
+    memset(&r, 0, sizeof(r));
+    memset(&rep, 0, sizeof(rep));
+
+    kdc_log(context, config, 0, "Digest request from %s", from);
+
+    ret = krb5_kt_resolve(context, "HDB:", &id);
+    if (ret) {
+       kdc_log(context, config, 0, "Can't open database for digest");
+       goto out;
+    }
+
+    ret = krb5_rd_req(context, 
+                     &ac,
+                     &req->apReq,
+                     NULL,
+                     id,
+                     &ap_req_options,
+                     &ticket);
+    if (ret)
+       goto out;
+
+    /* check the server principal in the ticket matches digest/R@R */
+    {
+       krb5_principal principal = NULL;
+       const char *p, *r;
+
+       ret = krb5_ticket_get_server(context, ticket, &principal);
+       if (ret)
+           goto out;
+
+       ret = EINVAL;
+       krb5_set_error_string(context, "Wrong digest server principal used");
+       p = krb5_principal_get_comp_string(context, principal, 0);
+       if (p == NULL) {
+           krb5_free_principal(context, principal);
+           goto out;
+       }
+       if (strcmp(p, KRB5_DIGEST_NAME) != 0) {
+           krb5_free_principal(context, principal);
+           goto out;
+       }
+
+       p = krb5_principal_get_comp_string(context, principal, 1);
+       if (p == NULL) {
+           krb5_free_principal(context, principal);
+           goto out;
+       }
+       r = krb5_principal_get_realm(context, principal);
+       if (r == NULL) {
+           krb5_free_principal(context, principal);
+           goto out;
+       }
+       if (strcmp(p, r) != 0) {
+           krb5_free_principal(context, principal);
+           goto out;
+       }
+
+       ret = _kdc_db_fetch(context, config, principal,
+                           HDB_F_GET_SERVER, NULL, &server);
+       if (ret)
+           goto out;
+
+       krb5_free_principal(context, principal);
+    }
+
+    /* check the client is allowed to do digest auth */
+    {
+       krb5_principal principal = NULL;
+       hdb_entry_ex *client;
+
+       ret = krb5_ticket_get_client(context, ticket, &principal);
+       if (ret)
+           goto out;
+
+       ret = _kdc_db_fetch(context, config, principal,
+                           HDB_F_GET_CLIENT, NULL, &client);
+       krb5_free_principal(context, principal);
+       if (ret)
+           goto out;
+
+       if (client->entry.flags.allow_digest == 0) {
+           krb5_set_error_string(context, 
+                                 "Client is not permitted to use digest");
+           ret = KRB5KDC_ERR_POLICY;
+           _kdc_free_ent (context, client);
+           goto out;
+       }
+       _kdc_free_ent (context, client);
+    }
+
+    /* unpack request */
+    {
+       krb5_keyblock *key;
+
+       ret = krb5_auth_con_getremotesubkey(context, ac, &key);
+       if (ret)
+           goto out;
+       if (key == NULL) {
+           krb5_set_error_string(context, "digest: remote subkey not found");
+           ret = EINVAL;
+           goto out;
+       }
+
+       ret = krb5_crypto_init(context, key, 0, &crypto);
+       krb5_free_keyblock (context, key);
+       if (ret)
+           goto out;
+    }
+
+    ret = krb5_decrypt_EncryptedData(context, crypto, KRB5_KU_DIGEST_ENCRYPT,
+                                    &req->innerReq, &buf);
+    krb5_crypto_destroy(context, crypto);
+    crypto = NULL;
+    if (ret)
+       goto out;
+          
+    ret = decode_DigestReqInner(buf.data, buf.length, &ireq, NULL);
+    krb5_data_free(&buf);
+    if (ret) {
+       krb5_set_error_string(context, "Failed to decode digest inner request");
+       goto out;
+    }
+
+    /*
+     * Process the inner request
+     */
+
+    switch (ireq.element) {
+    case choice_DigestReqInner_init: {
+       unsigned char server_nonce[16], identifier;
+
+       RAND_pseudo_bytes(&identifier, sizeof(identifier));
+       RAND_pseudo_bytes(server_nonce, sizeof(server_nonce));
+
+       server_nonce[0] = kdc_time & 0xff;
+       server_nonce[1] = (kdc_time >> 8) & 0xff;
+       server_nonce[2] = (kdc_time >> 16) & 0xff;
+       server_nonce[3] = (kdc_time >> 24) & 0xff;
+
+       r.element = choice_DigestRepInner_initReply;
+
+       hex_encode(server_nonce, sizeof(server_nonce), &r.u.initReply.nonce);
+       if (r.u.initReply.nonce == NULL) {
+           krb5_set_error_string(context, "Failed to decode server nonce");
+           ret = ENOMEM;
+           goto out;
+       }
+
+       sp = krb5_storage_emem();
+       if (sp == NULL) {
+           ret = ENOMEM;
+           krb5_set_error_string(context, "out of memory");
+           goto out;
+       }
+       ret = krb5_store_stringz(sp, ireq.u.init.type);
+       if (ret) {
+           krb5_clear_error_string(context);
+           goto out;
+       }
+
+       if (ireq.u.init.channel) {
+           char *s;
+
+           asprintf(&s, "%s-%s:%s", r.u.initReply.nonce,
+                    ireq.u.init.channel->cb_type,
+                    ireq.u.init.channel->cb_binding);
+           if (s == NULL) {
+               krb5_set_error_string(context, "Failed to allocate "
+                                     "channel binding");
+               ret = ENOMEM;
+               goto out;
+           }
+           free(r.u.initReply.nonce);
+           r.u.initReply.nonce = s;
+       }
+       
+       ret = krb5_store_stringz(sp, r.u.initReply.nonce);
+       if (ret) {
+           krb5_clear_error_string(context);
+           goto out;
+       }
+
+       if (strcasecmp(ireq.u.init.type, "CHAP") == 0) {
+           r.u.initReply.identifier = 
+               malloc(sizeof(*r.u.initReply.identifier));
+           if (r.u.initReply.identifier == NULL) {
+               krb5_set_error_string(context, "out of memory");
+               ret = ENOMEM;
+               goto out;
+           }
+
+           asprintf(r.u.initReply.identifier, "%02X", identifier & 0xff);
+           if (*r.u.initReply.identifier == NULL) {
+               krb5_set_error_string(context, "out of memory");
+               ret = ENOMEM;
+               goto out;
+           }
+
+           ret = krb5_store_stringz(sp, *r.u.initReply.identifier);
+           if (ret) {
+               krb5_clear_error_string(context);
+               goto out;
+           }
+       } else
+           r.u.initReply.identifier = NULL;
+
+       if (ireq.u.init.hostname) {
+           ret = krb5_store_stringz(sp, *ireq.u.init.hostname);
+           if (ret) {
+               krb5_clear_error_string(context);
+               goto out;
+           }
+       }
+
+       ret = krb5_storage_to_data(sp, &buf);
+       if (ret) {
+           krb5_clear_error_string(context);
+           goto out;
+       }
+
+       {
+           Key *key;
+           krb5_enctype enctype;
+
+           ret = _kdc_get_preferred_key(context,
+                                        config,
+                                        server,
+                                        "digest-service",
+                                        &enctype,
+                                        &key);
+           if (ret)
+               goto out;
+           ret = krb5_crypto_init(context, &key->key, 0, &crypto);
+           if (ret)
+               goto out;
+       }
+
+       ret = krb5_create_checksum(context,
+                                  crypto,
+                                  KRB5_KU_DIGEST_OPAQUE,
+                                  0,
+                                  buf.data,
+                                  buf.length,
+                                  &res);
+       krb5_crypto_destroy(context, crypto);
+       crypto = NULL;
+       krb5_data_free(&buf);
+       if (ret)
+           goto out;
+       
+       ASN1_MALLOC_ENCODE(Checksum, buf.data, buf.length, &res, &size, ret);
+       free_Checksum(&res);
+       if (ret) {
+           krb5_set_error_string(context, "Failed to encode "
+                                 "checksum in digest request");
+           goto out;
+       }
+       if (size != buf.length)
+           krb5_abortx(context, "ASN1 internal error");
+
+       hex_encode(buf.data, buf.length, &r.u.initReply.opaque);
+       free(buf.data);
+       if (r.u.initReply.opaque == NULL) {
+           krb5_clear_error_string(context);
+           ret = ENOMEM;
+           goto out;
+       }
+
+       break;
+    }
+    case choice_DigestReqInner_digestRequest: {
+       krb5_principal clientprincipal;
+       HDB *db;
+
+       sp = krb5_storage_emem();
+       if (sp == NULL) {
+           ret = ENOMEM;
+           krb5_set_error_string(context, "out of memory");
+           goto out;
+       }
+       krb5_store_stringz(sp, ireq.u.digestRequest.type);
+
+       krb5_store_stringz(sp, ireq.u.digestRequest.serverNonce);
+       if (ireq.u.digestRequest.identifier) {
+           ret = krb5_store_stringz(sp, *ireq.u.digestRequest.identifier);
+           if (ret) {
+               krb5_clear_error_string(context);
+               goto out;
+           }
+       }
+       if (ireq.u.digestRequest.hostname) {
+           ret = krb5_store_stringz(sp, *ireq.u.digestRequest.hostname);
+           if (ret) {
+               krb5_clear_error_string(context);
+               goto out;
+           }
+       }
+
+       buf.length = strlen(ireq.u.digestRequest.opaque);
+       buf.data = malloc(buf.length);
+       if (buf.data == NULL) {
+           krb5_set_error_string(context, "out of memory");
+           ret = ENOMEM;
+           goto out;
+       }
+
+       ret = hex_decode(ireq.u.digestRequest.opaque, buf.data, buf.length);
+       if (ret <= 0) {
+           krb5_set_error_string(context, "Failed to decode opaque");
+           ret = ENOMEM;
+           goto out;
+       }
+       buf.length = ret;
+
+       ret = decode_Checksum(buf.data, buf.length, &res, NULL);
+       free(buf.data);
+       if (ret) {
+           krb5_set_error_string(context, "Failed to decode digest Checksum");
+           goto out;
+       }
+       
+       ret = krb5_storage_to_data(sp, &buf);
+       if (ret) {
+           krb5_clear_error_string(context);
+           goto out;
+       }
+
+       serverNonce.length = strlen(ireq.u.digestRequest.serverNonce);
+       serverNonce.data = malloc(serverNonce.length);
+       if (serverNonce.data == NULL) {
+           krb5_set_error_string(context, "out of memory");
+           ret = ENOMEM;
+           goto out;
+       }
+           
+       /*
+        * CHAP does the checksum of the raw nonce, but do it for all
+        * types, since we need to check the timestamp.
+        */
+       {
+           ssize_t ssize;
+           
+           ssize = hex_decode(ireq.u.digestRequest.serverNonce, 
+                              serverNonce.data, serverNonce.length);
+           if (ssize <= 0) {
+               krb5_set_error_string(context, "Failed to decode serverNonce");
+               ret = ENOMEM;
+               goto out;
+           }
+           serverNonce.length = ssize;
+       }
+
+       {
+           Key *key;
+           krb5_enctype enctype;
+
+           ret = _kdc_get_preferred_key(context,
+                                        config,
+                                        server,
+                                        "digest-service",
+                                        &enctype,
+                                        &key);
+           if (ret)
+               goto out;
+           ret = krb5_crypto_init(context, &key->key, 0, &crypto);
+           if (ret)
+               goto out;
+       }
+
+       ret = krb5_verify_checksum(context, crypto, 
+                                  KRB5_KU_DIGEST_OPAQUE,
+                                  buf.data, buf.length, &res);
+       krb5_crypto_destroy(context, crypto);
+       crypto = NULL;
+       if (ret)
+           goto out;
+
+       /* verify time */
+       {
+           unsigned char *p = serverNonce.data;
+           uint32_t t;
+           
+           if (serverNonce.length < 4) {
+               krb5_set_error_string(context, "server nonce too short");
+               ret = EINVAL;
+               goto out;
+           }
+           t = p[0] | (p[1] << 8) | (p[2] << 16) | (p[3] << 24);
+
+           if (abs((kdc_time & 0xffffffff) - t) > context->max_skew) {
+               krb5_set_error_string(context, "time screw in server nonce ");
+               ret = EINVAL;
+               goto out;
+           }
+       }
+
+       /* get username */
+       ret = krb5_parse_name(context,
+                             ireq.u.digestRequest.username,
+                             &clientprincipal);
+       if (ret)
+           goto out;
+
+       ret = _kdc_db_fetch(context, config, clientprincipal,
+                           HDB_F_GET_CLIENT, &db, &user);
+
+       krb5_free_principal(context, clientprincipal);
+       if (ret)
+           goto out;
+
+       ret = hdb_entry_get_password(context, db, &user->entry, &password);
+       if (ret || password == NULL) {
+           if (ret == 0) {
+               ret = EINVAL;
+               krb5_set_error_string(context, "password missing");
+           }
+           goto out;
+       }
+
+       if (strcasecmp(ireq.u.digestRequest.type, "CHAP") == 0) {
+           MD5_CTX ctx;
+           unsigned char md[MD5_DIGEST_LENGTH];
+           char id;
+
+           if (ireq.u.digestRequest.identifier == NULL) {
+               krb5_set_error_string(context, "Identifier missing "
+                                     "from CHAP request");
+               ret = EINVAL;
+               goto out;
+           }
+           
+           if (hex_decode(*ireq.u.digestRequest.identifier, &id, 1) != 1) {
+               krb5_set_error_string(context, "failed to decode identifier");
+               ret = EINVAL;
+               goto out;
+           }
+           
+           MD5_Init(&ctx);
+           MD5_Update(&ctx, &id, 1);
+           MD5_Update(&ctx, password, strlen(password));
+           MD5_Update(&ctx, serverNonce.data, serverNonce.length);
+           MD5_Final(md, &ctx);
+
+           r.element = choice_DigestRepInner_response;
+           hex_encode(md, sizeof(md), &r.u.response.responseData);
+           if (r.u.response.responseData == NULL) {
+               krb5_clear_error_string(context);
+               ret = ENOMEM;
+               goto out;
+           }
+       } else if (strcasecmp(ireq.u.digestRequest.type, "SASL-DIGEST-MD5") == 0) {
+           MD5_CTX ctx;
+           unsigned char md[MD5_DIGEST_LENGTH];
+           char *A1, *A2;
+
+           if (ireq.u.digestRequest.nonceCount == NULL) 
+               goto out;
+           if (ireq.u.digestRequest.clientNonce == NULL) 
+               goto out;
+           if (ireq.u.digestRequest.qop == NULL) 
+               goto out;
+           if (ireq.u.digestRequest.realm == NULL) 
+               goto out;
+           
+           MD5_Init(&ctx);
+           MD5_Update(&ctx, ireq.u.digestRequest.username,
+                      strlen(ireq.u.digestRequest.username));
+           MD5_Update(&ctx, ":", 1);
+           MD5_Update(&ctx, *ireq.u.digestRequest.realm,
+                      strlen(*ireq.u.digestRequest.realm));
+           MD5_Update(&ctx, ":", 1);
+           MD5_Update(&ctx, password, strlen(password));
+           MD5_Final(md, &ctx);
+           
+           MD5_Init(&ctx);
+           MD5_Update(&ctx, md, sizeof(md));
+           MD5_Update(&ctx, ":", 1);
+           MD5_Update(&ctx, ireq.u.digestRequest.serverNonce,
+                      strlen(ireq.u.digestRequest.serverNonce));
+           MD5_Update(&ctx, ":", 1);
+           MD5_Update(&ctx, *ireq.u.digestRequest.nonceCount,
+                      strlen(*ireq.u.digestRequest.nonceCount));
+           if (ireq.u.digestRequest.authid) {
+               MD5_Update(&ctx, ":", 1);
+               MD5_Update(&ctx, *ireq.u.digestRequest.authid,
+                          strlen(*ireq.u.digestRequest.authid));
+           }
+           MD5_Final(md, &ctx);
+           hex_encode(md, sizeof(md), &A1);
+           if (A1 == NULL) {
+               krb5_set_error_string(context, "out of memory");
+               ret = ENOMEM;
+               goto out;
+           }
+           
+           MD5_Init(&ctx);
+           MD5_Update(&ctx, "AUTHENTICATE:", sizeof("AUTHENTICATE:") - 1);
+           MD5_Update(&ctx, *ireq.u.digestRequest.uri,
+                      strlen(*ireq.u.digestRequest.uri));
+       
+           /* conf|int */
+           if (strcmp(ireq.u.digestRequest.digest, "clear") != 0) {
+               static char conf_zeros[] = ":00000000000000000000000000000000";
+               MD5_Update(&ctx, conf_zeros, sizeof(conf_zeros) - 1);
+           }
+           
+           MD5_Final(md, &ctx);
+           hex_encode(md, sizeof(md), &A2);
+           if (A2 == NULL) {
+               krb5_set_error_string(context, "out of memory");
+               ret = ENOMEM;
+               free(A1);
+               goto out;
+           }
+
+           MD5_Init(&ctx);
+           MD5_Update(&ctx, A1, strlen(A2));
+           MD5_Update(&ctx, ":", 1);
+           MD5_Update(&ctx, ireq.u.digestRequest.serverNonce,
+                      strlen(ireq.u.digestRequest.serverNonce));
+           MD5_Update(&ctx, ":", 1);
+           MD5_Update(&ctx, *ireq.u.digestRequest.nonceCount,
+                      strlen(*ireq.u.digestRequest.nonceCount));
+           MD5_Update(&ctx, ":", 1);
+           MD5_Update(&ctx, *ireq.u.digestRequest.clientNonce,
+                      strlen(*ireq.u.digestRequest.clientNonce));
+           MD5_Update(&ctx, ":", 1);
+           MD5_Update(&ctx, *ireq.u.digestRequest.qop,
+                      strlen(*ireq.u.digestRequest.qop));
+           MD5_Update(&ctx, ":", 1);
+           MD5_Update(&ctx, A2, strlen(A2));
+
+           MD5_Final(md, &ctx);
+
+           r.element = choice_DigestRepInner_response;
+           hex_encode(md, sizeof(md), &r.u.response.responseData);
+
+           free(A1);
+           free(A2);
+
+           if (r.u.response.responseData == NULL) {
+               krb5_set_error_string(context, "out of memory");
+               ret = ENOMEM;
+               goto out;
+           }
+
+       } else {
+           r.element = choice_DigestRepInner_error;
+           asprintf(&r.u.error.reason, "unsupported digest type %s", 
+                    ireq.u.digestRequest.type);
+           if (r.u.error.reason == NULL) {
+               krb5_set_error_string(context, "out of memory");
+               ret = ENOMEM;
+               goto out;
+           }
+           r.u.error.code = EINVAL;
+       }
+
+       break;
+    }
+    default:
+       r.element = choice_DigestRepInner_error;
+       r.u.error.reason = strdup("unknown operation");
+       if (r.u.error.reason == NULL) {
+           krb5_set_error_string(context, "out of memory");
+           ret = ENOMEM;
+           goto out;
+       }
+       r.u.error.code = EINVAL;
+       break;
+    }
+
+    ASN1_MALLOC_ENCODE(DigestRepInner, buf.data, buf.length, &r, &size, ret);
+    if (ret) {
+       krb5_set_error_string(context, "Failed to encode inner digest reply");
+       goto out;
+    }
+    if (size != buf.length)
+       krb5_abortx(context, "ASN1 internal error");
+
+    krb5_auth_con_addflags(context, ac, KRB5_AUTH_CONTEXT_USE_SUBKEY, NULL);
+
+    ret = krb5_mk_rep (context, ac, &rep.apRep);
+    if (ret)
+       goto out;
+
+    {
+       krb5_keyblock *key;
+
+       ret = krb5_auth_con_getlocalsubkey(context, ac, &key);
+       if (ret)
+           goto out;
+
+       ret = krb5_crypto_init(context, key, 0, &crypto);
+       krb5_free_keyblock (context, key);
+       if (ret)
+           goto out;
+    }
+
+    ret = krb5_encrypt_EncryptedData(context, crypto, KRB5_KU_DIGEST_ENCRYPT, 
+                                    buf.data, buf.length, 0,
+                                    &rep.innerRep);
+    
+    ASN1_MALLOC_ENCODE(DigestREP, reply->data, reply->length, &rep, &size, ret);
+    if (ret) {
+       krb5_set_error_string(context, "Failed to encode digest reply");
+       goto out;
+    }
+    if (size != reply->length)
+       krb5_abortx(context, "ASN1 internal error");
+
+    
+out:
+    if (ac)
+       krb5_auth_con_free(context, ac);
+    if (ret)
+       krb5_warn(context, ret, "Digest request from %s failed", from);
+    if (ticket)
+       krb5_free_ticket(context, ticket);
+    if (id)
+       krb5_kt_close(context, id);
+    if (crypto)
+       krb5_crypto_destroy(context, crypto);
+    if (sp)
+       krb5_storage_free(sp);
+    if (user)
+       _kdc_free_ent (context, user);
+    if (server)
+       _kdc_free_ent (context, server);
+    if (password) {
+       memset(password, 0, strlen(password));
+       free (password);
+    }
+    krb5_data_free(&buf);
+    krb5_data_free(&serverNonce);
+    free_DigestREP(&rep);
+    free_DigestRepInner(&r);
+    free_DigestReqInner(&ireq);
+
+    return ret;
+}
index 86f162aa94b2b8204fd8644100d340b9346417e6..87d713b076f0c0a18a8374a1f84bc0381659f130 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1997 - 2001 Kungliga Tekniska Högskolan
+ * Copyright (c) 1997 - 2006 Kungliga Tekniska Högskolan
  * (Royal Institute of Technology, Stockholm, Sweden). 
  * All rights reserved. 
  *
@@ -32,7 +32,7 @@
  */
 
 /* 
- * $Id: headers.h,v 1.16 2005/04/24 13:49:00 lha Exp $ 
+ * $Id: headers.h,v 1.18 2006/10/17 02:22:17 lha Exp $ 
  */
 
 #ifndef __HEADERS_H__
 #include <parse_units.h>
 #include <krb5.h>
 #include <krb5_locl.h>
+#include <digest_asn1.h>
 #include <hdb.h>
 #include <hdb_err.h>
-#include <der.h> /* copy_octet_string */
+#include <der.h>
 
 #undef ALLOC
 #define ALLOC(X) ((X) = malloc(sizeof(*(X))))
index c08a51b9cc4073cbbb8ce7e8cf056738d91fe76a..ac282717ed0c3988e0da5010abb9a6a2ffb4b884 100644 (file)
@@ -33,7 +33,7 @@
 
 #include "kdc_locl.h"
 
-RCSID("$Id: kaserver.c,v 1.35 2006/05/05 10:49:50 lha Exp $");
+RCSID("$Id: kaserver.c,v 1.36 2006/08/23 11:43:44 lha Exp $");
 
 #include <krb5-v4compat.h>
 #include <rx.h>
@@ -465,7 +465,8 @@ do_authenticate (krb5_context context,
            client_name, from, server_name);
 
     ret = _kdc_db_fetch4 (context, config, name, instance, 
-                         config->v4_realm, HDB_F_GET_CLIENT, &client_entry);
+                         config->v4_realm, HDB_F_GET_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));
index 251e06b14aa6a39cd947da647bb53ecefd4f5544..8c2f56002d042ba4dc4c684295c4b9f5a388a4fa 100644 (file)
@@ -4,6 +4,16 @@
 
 #include <stdarg.h>
 
+krb5_error_code
+_kdc_add_KRB5SignedPath (
+       krb5_context /*context*/,
+       krb5_kdc_configuration */*config*/,
+       hdb_entry_ex */*krbtgt*/,
+       krb5_enctype /*enctype*/,
+       krb5_const_principal /*server*/,
+       KRB5SignedPathPrincipals */*principals*/,
+       EncTicketPart */*tkt*/);
+
 krb5_error_code
 _kdc_as_rep (
        krb5_context /*context*/,
@@ -12,7 +22,15 @@ _kdc_as_rep (
        const krb5_data */*req_buffer*/,
        krb5_data */*reply*/,
        const char */*from*/,
-       struct sockaddr */*from_addr*/);
+       struct sockaddr */*from_addr*/,
+       int /*datagram_reply*/);
+
+krb5_boolean
+_kdc_check_addresses (
+       krb5_context /*context*/,
+       krb5_kdc_configuration */*config*/,
+       HostAddresses */*addresses*/,
+       const struct sockaddr */*from*/);
 
 krb5_error_code
 _kdc_check_flags (
@@ -30,6 +48,7 @@ _kdc_db_fetch (
        krb5_kdc_configuration */*config*/,
        krb5_const_principal /*principal*/,
        unsigned /*flags*/,
+       HDB **/*db*/,
        hdb_entry_ex **/*h*/);
 
 krb5_error_code
@@ -51,6 +70,15 @@ _kdc_do_524 (
        const char */*from*/,
        struct sockaddr */*addr*/);
 
+krb5_error_code
+_kdc_do_digest (
+       krb5_context /*context*/,
+       krb5_kdc_configuration */*config*/,
+       const DigestREQ */*req*/,
+       krb5_data */*reply*/,
+       const char */*from*/,
+       struct sockaddr */*addr*/);
+
 krb5_error_code
 _kdc_do_kaserver (
        krb5_context /*context*/,
@@ -71,6 +99,21 @@ _kdc_do_version4 (
        const char */*from*/,
        struct sockaddr_in */*addr*/);
 
+krb5_error_code
+_kdc_encode_reply (
+       krb5_context /*context*/,
+       krb5_kdc_configuration */*config*/,
+       KDC_REP */*rep*/,
+       const EncTicketPart */*et*/,
+       EncKDCRepPart */*ek*/,
+       krb5_enctype /*etype*/,
+       int /*skvno*/,
+       const EncryptionKey */*skey*/,
+       int /*ckvno*/,
+       const EncryptionKey */*ckey*/,
+       const char **/*e_text*/,
+       krb5_data */*reply*/);
+
 krb5_error_code
 _kdc_encode_v4_ticket (
        krb5_context /*context*/,
@@ -81,6 +124,24 @@ _kdc_encode_v4_ticket (
        const PrincipalName */*service*/,
        size_t */*size*/);
 
+krb5_error_code
+_kdc_find_etype (
+       krb5_context /*context*/,
+       const hdb_entry_ex */*princ*/,
+       krb5_enctype */*etypes*/,
+       unsigned /*len*/,
+       Key **/*ret_key*/,
+       krb5_enctype */*ret_etype*/);
+
+PA_DATA*
+_kdc_find_padata (
+       KDC_REQ */*req*/,
+       int */*start*/,
+       int /*type*/);
+
+void
+_kdc_fix_time (time_t **/*t*/);
+
 void
 _kdc_free_ent (
        krb5_context /*context*/,
@@ -94,6 +155,28 @@ _kdc_get_des_key (
        krb5_boolean /*prefer_afs_key*/,
        Key **/*ret_key*/);
 
+krb5_error_code
+_kdc_get_preferred_key (
+       krb5_context /*context*/,
+       krb5_kdc_configuration */*config*/,
+       hdb_entry_ex */*h*/,
+       const char */*name*/,
+       krb5_enctype */*enctype*/,
+       Key **/*key*/);
+
+void
+_kdc_log_timestamp (
+       krb5_context /*context*/,
+       krb5_kdc_configuration */*config*/,
+       const char */*type*/,
+       KerberosTime /*authtime*/,
+       KerberosTime */*starttime*/,
+       KerberosTime /*endtime*/,
+       KerberosTime */*renew_till*/);
+
+krb5_error_code
+_kdc_make_anonymous_principalname (PrincipalName */*pn*/);
+
 int
 _kdc_maybe_version4 (
        unsigned char */*buf*/,
@@ -120,7 +203,7 @@ _kdc_pk_initialize (
        const char */*user_id*/,
        const char */*anchors*/,
        char **/*pool*/,
-       char **/*revoke*/);
+       char **/*revoke_list*/);
 
 krb5_error_code
 _kdc_pk_mk_pa_reply (
index 5967f933f39ddeeda04ac317699087274804515c..69bc871b01dd30ebacdd5443edfeb340a6f1d290 100644 (file)
@@ -41,25 +41,27 @@ void
 krb5_kdc_default_config (krb5_kdc_configuration */*config*/);
 
 int
-krb5_kdc_process_generic_request (
+krb5_kdc_process_krb5_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*/);
+       struct sockaddr */*addr*/,
+       int /*datagram_reply*/);
 
 int
-krb5_kdc_process_krb5_request (
+krb5_kdc_process_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*/);
+       struct sockaddr */*addr*/,
+       int /*datagram_reply*/);
 
 #ifdef __cplusplus
 }
index 2948570e3a1f2f9906aed45834afbdb9381111bb..043b6de47d2269d96cf10eacbab32904bcb77cf3 100644 (file)
@@ -35,7 +35,7 @@
  */
 
 /* 
- * $Id: kdc.h,v 1.6 2006/05/03 12:03:29 lha Exp $ 
+ * $Id: kdc.h,v 1.9 2006/10/09 15:34:07 lha Exp $ 
  */
 
 #ifndef __KDC_H__
@@ -65,10 +65,12 @@ typedef struct krb5_kdc_configuration {
 
     char *v4_realm;
     krb5_boolean enable_v4;
+    krb5_boolean enable_v4_cross_realm;
+    krb5_boolean enable_v4_per_principal;
+
     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;
@@ -78,6 +80,9 @@ typedef struct krb5_kdc_configuration {
 
     int pkinit_dh_min_bits;
 
+    int enable_digest;
+    size_t max_datagram_reply_length;
+
 } krb5_kdc_configuration;
 
 #include <kdc-protos.h>
index d7a3a9cb69ac3c55332e807bf7df5dc0247cde62..97e98d86ad3ae931b7a4da7f56e66e05a4618a3a 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1997 - 2005 Kungliga Tekniska Högskolan
+ * Copyright (c) 1997 - 2006 Kungliga Tekniska Högskolan
  * (Royal Institute of Technology, Stockholm, Sweden). 
  * All rights reserved. 
  *
@@ -35,7 +35,7 @@
 
 #include <krb5-v4compat.h>
 
-RCSID("$Id: kerberos4.c,v 1.60 2006/05/05 10:50:44 lha Exp $");
+RCSID("$Id: kerberos4.c,v 1.63 2006/10/08 13:43:27 lha Exp $");
 
 #ifndef swap32
 static uint32_t
@@ -80,7 +80,7 @@ valid_princ(krb5_context context,
     ret = krb5_unparse_name(context, princ, &s);
     if (ret)
        return FALSE;
-    ret = _kdc_db_fetch(context, ctx->config, princ, ctx->flags, &ent);
+    ret = _kdc_db_fetch(context, ctx->config, princ, ctx->flags, NULL, &ent);
     if (ret) {
        kdc_log(context, ctx->config, 7, "Lookup %s failed: %s", s,
                krb5_get_err_text (context, ret));
@@ -111,7 +111,7 @@ _kdc_db_fetch4(krb5_context context,
                                       valid_princ, &ctx, 0, &p);
     if(ret)
        return ret;
-    ret = _kdc_db_fetch(context, config, p, flags, ent);
+    ret = _kdc_db_fetch(context, config, p, flags, NULL, ent);
     krb5_free_principal(context, p);
     return ret;
 }
@@ -221,6 +221,17 @@ _kdc_do_version4(krb5_context context,
            goto out1;
        }
 
+       if (config->enable_v4_per_principal &&
+           client->entry.flags.allow_kerberos4 == 0)
+       {
+           kdc_log(context, config, 0,
+                   "Per principal Kerberos 4 flag not turned on for %s",
+                   client_name);
+           make_err_reply(context, reply, KERB_ERR_NULL_KEY,
+                          "allow kerberos4 flag required");
+           goto out1;
+       }
+
        /*
         * There's no way to do pre-authentication in v4 and thus no
         * good error code to return if preauthentication is required.
@@ -372,7 +383,7 @@ _kdc_do_version4(krb5_context context,
        }
 
        ret = _kdc_db_fetch(context, config, tgt_princ,
-                           HDB_F_GET_KRBTGT, &tgt);
+                           HDB_F_GET_KRBTGT, NULL, &tgt);
        if(ret){
            char *s;
            s = kdc_log_msg(context, config, 0, "Ticket-granting ticket not "
@@ -668,7 +679,7 @@ _kdc_encode_v4_ticket(krb5_context context,
        if(ret)
            return ret;
 
-       _krb5_principalname2krb5_principal(context, 
+       _krb5_principalname2krb5_principal(context,
                                           &princ,
                                           et->cname,
                                           et->crealm);
index a73c2c10b3b6c6fb5c56d4ead157304dbd70a2ad..19287b31ccc4f7d44c533fb8d4daed7e05926485 100644 (file)
 
 #include "kdc_locl.h"
 
-RCSID("$Id: kerberos5.c,v 1.211 2006/04/27 12:01:09 lha Exp $");
+RCSID("$Id: kerberos5.c,v 1.223 2006/10/17 02:16:29 lha Exp $");
 
 #define MAX_TIME ((time_t)((1U << 31) - 1))
 
-static void
-fix_time(time_t **t)
+void
+_kdc_fix_time(time_t **t)
 {
     if(*t == NULL){
        ALLOC(*t);
@@ -65,13 +65,13 @@ 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);
+       der_copy_octet_string(&salt->salt,
+                             &md->val[md->len - 1].padata_value);
     }
 }
 
-static PA_DATA*
-find_padata(KDC_REQ *req, int *start, int type)
+PA_DATA*
+_kdc_find_padata(KDC_REQ *req, int *start, int type)
 {
     while(*start < req->padata->len){
        (*start)++;
@@ -87,10 +87,10 @@ find_padata(KDC_REQ *req, int *start, int type)
  * one, but preferring one that has default salt
  */
 
-static krb5_error_code
-find_etype(krb5_context context, const hdb_entry_ex *princ,
-          krb5_enctype *etypes, unsigned len, 
-          Key **ret_key, krb5_enctype *ret_etype)
+krb5_error_code
+_kdc_find_etype(krb5_context context, const hdb_entry_ex *princ,
+               krb5_enctype *etypes, unsigned len, 
+               Key **ret_key, krb5_enctype *ret_etype)
 {
     int i;
     krb5_error_code ret = KRB5KDC_ERR_ETYPE_NOSUPP;
@@ -116,46 +116,8 @@ find_etype(krb5_context context, const hdb_entry_ex *princ,
     return ret;
 }
 
-static krb5_error_code
-find_keys(krb5_context context, 
-         krb5_kdc_configuration *config,
-         const hdb_entry_ex *client,
-         const char *client_name,
-         const hdb_entry_ex *server,
-         const char *server_name,
-         Key **ckey,
-         krb5_enctype *cetype,
-         Key **skey,
-         krb5_enctype *setype, 
-         krb5_enctype *etypes,
-         unsigned num_etypes)
-{
-    krb5_error_code ret;
-
-    if(client){
-       /* find client key */
-       ret = find_etype(context, client, etypes, num_etypes, ckey, cetype);
-       if (ret) {
-           kdc_log(context, config, 0, 
-                   "Client (%s) has no support for etypes", client_name);
-           return ret;
-       }
-    }
-
-    if(server){
-       /* find server key */
-       ret = find_etype(context, server, etypes, num_etypes, skey, setype);
-       if (ret) {
-           kdc_log(context, config, 0, 
-                   "Server (%s) has no support for etypes", server_name);
-           return ret;
-       }
-    }
-    return 0;
-}
-
-static krb5_error_code
-make_anonymous_principalname (PrincipalName *pn)
+krb5_error_code
+_kdc_make_anonymous_principalname (PrincipalName *pn)
 {
     pn->name_type = KRB5_NT_PRINCIPAL;
     pn->name_string.len = 1;
@@ -171,12 +133,12 @@ make_anonymous_principalname (PrincipalName *pn)
     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)
+void
+_kdc_log_timestamp(krb5_context context, 
+                  krb5_kdc_configuration *config,
+                  const char *type,
+                  KerberosTime authtime, KerberosTime *starttime, 
+                  KerberosTime endtime, KerberosTime *renew_till)
 {
     char authtime_str[100], starttime_str[100], 
        endtime_str[100], renewtime_str[100];
@@ -248,15 +210,15 @@ log_patypes(krb5_context context,
  */
 
 
-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)
+krb5_error_code
+_kdc_encode_reply(krb5_context context,
+                 krb5_kdc_configuration *config,
+                 KDC_REP *rep, const EncTicketPart *et, EncKDCRepPart *ek, 
+                 krb5_enctype etype, 
+                 int skvno, const EncryptionKey *skey,
+                 int ckvno, const EncryptionKey *ckey,
+                 const char **e_text,
+                 krb5_data *reply)
 {
     unsigned char *buf;
     size_t buf_size;
@@ -795,10 +757,10 @@ _kdc_check_flags(krb5_context context,
  * these checks
  */
 
-static krb5_boolean
-check_addresses(krb5_context context,        
-               krb5_kdc_configuration *config,
-               HostAddresses *addresses, const struct sockaddr *from)
+krb5_boolean
+_kdc_check_addresses(krb5_context context,        
+                    krb5_kdc_configuration *config,
+                    HostAddresses *addresses, const struct sockaddr *from)
 {
     krb5_error_code ret;
     krb5_address addr;
@@ -843,13 +805,14 @@ _kdc_as_rep(krb5_context context,
            const krb5_data *req_buffer, 
            krb5_data *reply,
            const char *from,
-           struct sockaddr *from_addr)
+           struct sockaddr *from_addr,
+           int datagram_reply)
 {
     KDC_REQ_BODY *b = &req->req_body;
     AS_REP rep;
     KDCOptions f = b->kdc_options;
     hdb_entry_ex *client = NULL, *server = NULL;
-    krb5_enctype cetype, setype;
+    krb5_enctype cetype, setype, sessionetype;
     EncTicketPart et;
     EncKDCRepPart ek;
     krb5_principal client_princ = NULL, server_princ = NULL;
@@ -869,12 +832,15 @@ _kdc_as_rep(krb5_context context,
        ret = KRB5KRB_ERR_GENERIC;
        e_text = "No server in request";
     } else{
-           _krb5_principalname2krb5_principal (context, &server_princ,
-                                           *(b->sname), b->realm);
+       _krb5_principalname2krb5_principal (context,
+                                           &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);
+       kdc_log(context, config, 0, 
+               "AS-REQ malformed server name from %s", from);
        goto out;
     }
     
@@ -882,12 +848,15 @@ _kdc_as_rep(krb5_context context,
        ret = KRB5KRB_ERR_GENERIC;
        e_text = "No client in request";
     } else {
-           _krb5_principalname2krb5_principal (context, &client_princ,
-                                           *(b->cname), b->realm);
+       _krb5_principalname2krb5_principal (context,
+                                           &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);
+       kdc_log(context, config, 0,
+               "AS-REQ malformed client name from %s", from);
        goto out;
     }
 
@@ -895,7 +864,7 @@ _kdc_as_rep(krb5_context context,
            client_name, from, server_name);
 
     ret = _kdc_db_fetch(context, config, client_princ, 
-                       HDB_F_GET_CLIENT, &client);
+                       HDB_F_GET_CLIENT, NULL, &client);
     if(ret){
        kdc_log(context, config, 0, "UNKNOWN -- %s: %s", client_name,
                krb5_get_err_text(context, ret));
@@ -904,7 +873,8 @@ _kdc_as_rep(krb5_context context,
     }
 
     ret = _kdc_db_fetch(context, config, server_princ,
-                       HDB_F_GET_SERVER|HDB_F_GET_KRBTGT, &server);
+                       HDB_F_GET_SERVER|HDB_F_GET_KRBTGT,
+                       NULL, &server);
     if(ret){
        kdc_log(context, config, 0, "UNKNOWN -- %s: %s", server_name,
                krb5_get_err_text(context, ret));
@@ -943,11 +913,11 @@ _kdc_as_rep(krb5_context context,
        e_text = "No PKINIT PA found";
 
        i = 0;
-       if ((pa = find_padata(req, &i, KRB5_PADATA_PK_AS_REQ)))
+       if ((pa = _kdc_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_WIN)))
+           if((pa = _kdc_find_padata(req, &i, KRB5_PADATA_PK_AS_REQ_WIN)))
                ;
        }
        if (pa) {
@@ -995,7 +965,7 @@ _kdc_as_rep(krb5_context context,
 
        i = 0;
        e_text = "No ENC-TS found";
-       while((pa = find_padata(req, &i, KRB5_PADATA_ENC_TIMESTAMP))){
+       while((pa = _kdc_find_padata(req, &i, KRB5_PADATA_ENC_TIMESTAMP))){
            krb5_data ts_data;
            PA_ENC_TS_ENC p;
            size_t len;
@@ -1056,7 +1026,7 @@ _kdc_as_rep(krb5_context context,
            if(ret){
                krb5_error_code ret2;
                ret2 = krb5_enctype_to_string(context, 
-                                            pa_key->key.keytype, &str);
+                                             pa_key->key.keytype, &str);
                if (ret2)
                    str = NULL;
                kdc_log(context, config, 5, 
@@ -1092,9 +1062,18 @@ _kdc_as_rep(krb5_context context,
            }
            free_PA_ENC_TS_ENC(&p);
            if (abs(kdc_time - p.patimestamp) > context->max_skew) {
+               char client_time[100];
+
+               krb5_format_time(context, p.patimestamp, 
+                                client_time, sizeof(client_time), TRUE); 
+
                ret = KRB5KRB_AP_ERR_SKEW;
                kdc_log(context, config, 0,
-                       "Too large time skew -- %s", client_name);
+                       "Too large time skew, client time %s is out by %u > %u seconds -- %s", 
+                       client_time, 
+                       (unsigned)abs(kdc_time - p.patimestamp), 
+                       context->max_skew,
+                       client_name);
                /* 
                 * the following is needed to make windows clients
                 * to retry using the timestamp in the error message
@@ -1162,7 +1141,7 @@ _kdc_as_rep(krb5_context context,
         *   both info replies (we send 'info' first in the list).
         * - If the client is 'modern', because it knows about 'new'
         *   enctype types, then only send the 'info2' reply.
-       */
+        */
 
        /* XXX check ret */
        if (only_older_enctype_p(req))
@@ -1197,14 +1176,54 @@ _kdc_as_rep(krb5_context context,
        goto out2;
     }
     
-    ret = find_keys(context, config, 
-                   client, client_name, 
-                   server, server_name, 
-                   &ckey, &cetype, &skey, &setype,
-                   b->etype.val, b->etype.len);
-    if(ret)
+    /*
+     * Find the client key (for preauth ENC-TS verification and reply
+     * encryption).  Then the best encryption type for the KDC and
+     * last the best session key that shared between the client and
+     * KDC runtime enctypes.
+     */
+
+    ret = _kdc_find_etype(context, client, b->etype.val, b->etype.len,
+                         &ckey, &cetype);
+    if (ret) {
+       kdc_log(context, config, 0, 
+               "Client (%s) has no support for etypes", client_name);
        goto out;
+    }
        
+    ret = _kdc_get_preferred_key(context, config,
+                                server, server_name,
+                                &setype, &skey);
+    if(ret)
+       goto out;
+
+    {
+       const krb5_enctype *p;
+       int i, j;
+
+       p = krb5_kerberos_enctypes(context);
+
+       sessionetype = ETYPE_NULL;
+
+       for (i = 0; p[i] != ETYPE_NULL && sessionetype == ETYPE_NULL; i++) {
+           if (krb5_enctype_valid(context, p[i]) != 0)
+               continue;
+           for (j = 0; j < b->etype.len; j++) {
+               if (p[i] == b->etype.val[j]) {
+                   sessionetype = p[i];
+                   break;
+               }
+           }
+       }
+       if (sessionetype == ETYPE_NULL) {
+           kdc_log(context, config, 0, 
+                   "Client (%s) from %s has no common enctypes with KDC"
+                   "to use for the session key",
+                   client_name, from);
+           goto out;
+       }
+    }
+
     {
        struct rk_strpool *p = NULL;
        char *str;
@@ -1268,9 +1287,9 @@ _kdc_as_rep(krb5_context context,
     rep.msg_type = krb_as_rep;
     copy_Realm(&client->entry.principal->realm, &rep.crealm);
     if (f.request_anonymous)
-       make_anonymous_principalname (&rep.cname);
+       _kdc_make_anonymous_principalname (&rep.cname);
     else
-           _krb5_principal2principalname(&rep.cname, 
+       _krb5_principal2principalname(&rep.cname, 
                                      client->entry.principal);
     rep.ticket.tkt_vno = 5;
     copy_Realm(&server->entry.principal->realm, &rep.ticket.realm);
@@ -1304,14 +1323,14 @@ _kdc_as_rep(krb5_context context,
     }
 
     /* check for valid set of addresses */
-    if(!check_addresses(context, config, b->addresses, from_addr)) {
+    if(!_kdc_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);
+    krb5_generate_random_keyblock(context, sessionetype, &et.key);
     copy_PrincipalName(&rep.cname, &et.cname);
     copy_Realm(&rep.crealm, &et.crealm);
     
@@ -1327,7 +1346,7 @@ _kdc_as_rep(krb5_context context,
            et.flags.invalid = 1;
            et.flags.postdated = 1; /* XXX ??? */
        }
-       fix_time(&b->till);
+       _kdc_fix_time(&b->till);
        t = *b->till;
 
        /* be careful not overflowing */
@@ -1392,7 +1411,7 @@ _kdc_as_rep(krb5_context context,
     ek.last_req.len = 0;
     if (client->entry.pw_end
        && (config->kdc_warn_pwexpire == 0
-           || kdc_time + config->kdc_warn_pwexpire <= *client->entry.pw_end)) {
+           || kdc_time + config->kdc_warn_pwexpire >= *client->entry.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->entry.pw_end;
        ++ek.last_req.len;
@@ -1472,15 +1491,37 @@ _kdc_as_rep(krb5_context context,
                    goto out;
     }
 
-    log_timestamp(context, config, "AS-REQ", et.authtime, et.starttime, 
-                 et.endtime, et.renew_till);
+    _kdc_log_timestamp(context, config, "AS-REQ", et.authtime, et.starttime, 
+                      et.endtime, et.renew_till);
+
+    /* do this as the last thing since this signs the EncTicketPart */
+    ret = _kdc_add_KRB5SignedPath(context,
+                                 config,
+                                 server,
+                                 setype,
+                                 NULL,
+                                 NULL,
+                                 &et);
+    if (ret)
+       goto out;
 
-    ret = encode_reply(context, config, 
-                      &rep, &et, &ek, setype, server->entry.kvno, &skey->key,
-                      client->entry.kvno, reply_key, &e_text, reply);
+    ret = _kdc_encode_reply(context, config, 
+                           &rep, &et, &ek, setype, server->entry.kvno, 
+                           &skey->key, client->entry.kvno, 
+                           reply_key, &e_text, reply);
     free_EncTicketPart(&et);
     free_EncKDCRepPart(&ek);
- out:
+    if (ret)
+       goto out;
+
+    /* */
+    if (datagram_reply && reply->length > config->max_datagram_reply_length) {
+       krb5_data_free(reply);
+       ret = KRB5KRB_ERR_RESPONSE_TOO_BIG;
+       e_text = "Reply packet too large";
+    }
+
+out:
     free_AS_REP(&rep);
     if(ret){
        krb5_mk_error(context,
@@ -1494,7 +1535,7 @@ _kdc_as_rep(krb5_context context,
                      reply);
        ret = 0;
     }
- out2:
+out2:
 #ifdef PKINIT
     if (pkp)
        _kdc_pk_free_client_param(context, pkp);
@@ -1511,1089 +1552,3 @@ _kdc_as_rep(krb5_context context,
        _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;
-
-    switch (tr->tr_type) {
-    case DOMAIN_X500_COMPRESS:
-       break;
-    case 0:
-       /*
-        * Allow empty content of type 0 because that is was Microsoft
-        * generates in their TGT.
-        */
-       if (tr->contents.length == 0)
-           break;
-       kdc_log(context, config, 0,
-               "Transited type 0 with non empty content");
-       return KRB5KDC_ERR_TRTYPE_NOSUPP;
-    default:
-       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,
-              krb5_ticket *tgs_ticket,
-              hdb_entry_ex *server, 
-              const char *server_name, 
-              hdb_entry_ex *client, 
-              krb5_principal client_principal, 
-              hdb_entry_ex *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;
-    AuthorizationData *new_auth_data = NULL;
-    
-    if(adtkt) {
-       int i;
-       ekey = &adtkt->key;
-       for(i = 0; i < b->etype.len; i++)
-           if (b->etype.val[i] == adtkt->key.keytype)
-               break;
-       if(i == b->etype.len) {
-           krb5_clear_error_string(context);
-           return KRB5KDC_ERR_ETYPE_NOSUPP;
-       }
-       etype = b->etype.val[i];
-    }else{
-       ret = find_keys(context, config, 
-                       NULL, NULL, server, server_name,
-                       NULL, NULL, &skey, &etype, 
-                       b->etype.val, b->etype.len);
-       if(ret)
-           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->entry.principal),
-                                *krb5_princ_realm(context, krbtgt->entry.principal));
-    if(ret)
-       goto out;
-
-    copy_Realm(krb5_princ_realm(context, server->entry.principal), 
-              &rep.ticket.realm);
-    _krb5_principal2principalname(&rep.ticket.sname, server->entry.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->entry.max_life)
-           life = min(life, *client->entry.max_life);
-       if(server->entry.max_life)
-           life = min(life, *server->entry.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->entry.max_renew)
-           renew = min(renew, *client->entry.max_renew);
-       if(server->entry.max_renew)
-           renew = min(renew, *server->entry.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->entry.flags.ok_as_delegate;
-           
-    
-    krb5_generate_random_keyblock(context, etype, &et.key);
-
-    if (server->authz_data_tgs_req) {
-           ret = server->authz_data_tgs_req(context, server,
-                                            client_principal, 
-                                            tgs_ticket->ticket.authorization_data,
-                                            tgs_ticket->ticket.authtime,
-                                            tgtkey,
-                                            ekey, 
-                                            &et.key, 
-                                            &new_auth_data);
-           if (ret) {
-                   new_auth_data = NULL;
-           }
-    }
-
-    /* XXX Check enc-authorization-data */
-    et.authorization_data = new_auth_data;
-
-    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->entry.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 authenticator 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_ex *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(context, &princ,
-                                      ap_req.ticket.sname,
-                                      ap_req.ticket.realm);
-    
-    ret = _kdc_db_fetch(context, config, princ, HDB_F_GET_KRBTGT, &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->entry.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->entry.kvno,
-               p);
-       if (ret == 0)
-           free (p);
-       ret = KRB5KRB_AP_ERR_BADKEYVER;
-       goto out2;
-    }
-
-    ret = hdb_enctype2key(context, &krbtgt->entry, 
-                         ap_req.ticket.enc_part.etype, &tkey);
-    if(ret){
-       char *str, *p;
-       krb5_enctype_to_string(context, ap_req.ticket.enc_part.etype, &str);
-       krb5_unparse_name(context, princ, &p);
-       kdc_log(context, config, 0,
-               "No server key with enctype %s found for %s", str, p);
-       free(str);
-       free(p);
-       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 (ret) {
-       krb5_auth_con_free(context, ac);
-       goto out2;
-    }
-
-    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);
-
-    {
-       PrincipalName *s;
-       Realm r;
-       char *spn = NULL, *cpn = NULL;
-       hdb_entry_ex *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_ex *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(context, &p, t->sname, t->realm);
-           ret = _kdc_db_fetch(context, config, p, 
-                               HDB_F_GET_CLIENT|HDB_F_GET_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->entry, 
-                                 t->enc_part.etype, &uukey);
-           if(ret){
-               _kdc_free_ent(context, uu);
-               ret = KRB5KDC_ERR_ETYPE_NOSUPP; /* XXX */
-               goto out;
-           }
-           ret = krb5_decrypt_ticket(context, t, &uukey->key, &adtkt, 0);
-           _kdc_free_ent(context, uu);
-           if(ret)
-               goto out;
-           s = &adtkt.cname;
-           r = adtkt.crealm;
-       }
-
-       _krb5_principalname2krb5_principal(context, &sp, *s, r);
-       ret = krb5_unparse_name(context, sp, &spn);     
-       if (ret)
-           goto out;
-       _krb5_principalname2krb5_principal(context, &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_F_GET_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_F_GET_CLIENT, &client);
-       if(ret)
-           kdc_log(context, config, 1, "Client not found in database: %s: %s",
-                   cpn, krb5_get_err_text(context, ret));
-
-       /*
-        * If the client belongs to the same realm as our krbtgt, it
-        * should exist in the local database.
-        *
-        * If its not the same, check the "direction" on the krbtgt,
-        * so its not a backward uni-directional trust.
-        */
-
-       if(strcmp(krb5_principal_get_realm(context, sp),
-                 krb5_principal_get_comp_string(context, 
-                                                krbtgt->entry.principal, 1)) == 0) {
-           if(ret) {
-               if (ret == HDB_ERR_NOENTRY)
-                   ret = KRB5KDC_ERR_C_PRINCIPAL_UNKNOWN;
-               goto out;
-           }
-       } else {
-           char *tpn;
-           ret = krb5_unparse_name(context, krbtgt->entry.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->entry.principal,
-                                  server->entry.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,
-                            ticket,
-                            server, 
-                            spn,
-                            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/krb5tgs.c b/source4/heimdal/kdc/krb5tgs.c
new file mode 100644 (file)
index 0000000..dcf29eb
--- /dev/null
@@ -0,0 +1,1781 @@
+/*
+ * Copyright (c) 1997-2006 Kungliga Tekniska Högskolan
+ * (Royal Institute of Technology, Stockholm, Sweden). 
+ * All rights reserved. 
+ *
+ * Redistribution and use in source and binary forms, with or without 
+ * modification, are permitted provided that the following conditions 
+ * are met: 
+ *
+ * 1. Redistributions of source code must retain the above copyright 
+ *    notice, this list of conditions and the following disclaimer. 
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright 
+ *    notice, this list of conditions and the following disclaimer in the 
+ *    documentation and/or other materials provided with the distribution. 
+ *
+ * 3. Neither the name of the Institute nor the names of its contributors 
+ *    may be used to endorse or promote products derived from this software 
+ *    without specific prior written permission. 
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND 
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE 
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 
+ * LIABILITY, OR TORT (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: krb5tgs.c,v 1.16 2006/10/22 15:54:37 lha Exp $");
+
+/*
+ * 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;
+}
+
+/*
+ * The KDC might add a signed path to the ticket authorization data
+ * field. This is to avoid server impersonating clients and the
+ * request constrained delegation.
+ *
+ * This is done by storing a KRB5_AUTHDATA_IF_RELEVANT with a single
+ * entry of type KRB5SignedPath.
+ */
+
+static krb5_error_code
+find_KRB5SignedPath(krb5_context context,
+                   const AuthorizationData *ad,
+                   krb5_data *data)
+{
+    AuthorizationData child;
+    krb5_error_code ret;
+    int pos;
+       
+    if (ad == NULL || ad->len == 0)
+       return KRB5KDC_ERR_PADATA_TYPE_NOSUPP;
+
+    pos = ad->len - 1;
+
+    if (ad->val[pos].ad_type != KRB5_AUTHDATA_IF_RELEVANT)
+       return KRB5KDC_ERR_PADATA_TYPE_NOSUPP;
+
+    ret = decode_AuthorizationData(ad->val[pos].ad_data.data,
+                                  ad->val[pos].ad_data.length,
+                                  &child,
+                                  NULL);
+    if (ret) {
+       krb5_set_error_string(context, "Failed to decode "
+                             "IF_RELEVANT with %d", ret);
+       return ret;
+    }
+
+    if (child.len != 1) {
+       free_AuthorizationData(&child);
+       return KRB5KDC_ERR_PADATA_TYPE_NOSUPP;
+    }
+
+    if (child.val[0].ad_type != KRB5_AUTHDATA_SIGNTICKET) {
+       free_AuthorizationData(&child);
+       return KRB5KDC_ERR_PADATA_TYPE_NOSUPP;
+    }
+
+    if (data)
+       ret = der_copy_octet_string(&child.val[0].ad_data, data);
+    free_AuthorizationData(&child);
+    return ret;
+}
+
+krb5_error_code
+_kdc_add_KRB5SignedPath(krb5_context context,
+                       krb5_kdc_configuration *config,
+                       hdb_entry_ex *krbtgt,
+                       krb5_enctype enctype,
+                       krb5_const_principal server,
+                       KRB5SignedPathPrincipals *principals,
+                       EncTicketPart *tkt)
+{
+    krb5_error_code ret;
+    KRB5SignedPath sp;
+    krb5_data data;
+    krb5_crypto crypto = NULL;
+    size_t size;
+
+    if (server && principals) {
+       ret = add_KRB5SignedPathPrincipals(principals, server);
+       if (ret)
+           goto out;
+    }
+
+    {
+       KRB5SignedPathData spd;
+       
+       spd.encticket = *tkt;
+       spd.delegated = principals;
+       
+       ASN1_MALLOC_ENCODE(KRB5SignedPathData, data.data, data.length,
+                          &spd, &size, ret);
+       if (ret)
+           goto out;
+       if (data.length != size)
+           krb5_abortx(context, "internal asn.1 encoder error");
+    }
+
+    {
+       Key *key;
+       ret = hdb_enctype2key(context, &krbtgt->entry, enctype, &key);
+       if (ret == 0)
+           ret = krb5_crypto_init(context, &key->key, 0, &crypto);
+       if (ret) {
+           free(data.data);
+           return ret;
+       }
+    }
+
+    /*
+     * Fill in KRB5SignedPath
+     */
+
+    sp.etype = enctype;
+    sp.delegated = principals;
+
+    ret = krb5_create_checksum(context, crypto, KRB5_KU_KRB5SIGNEDPATH, 0,
+                              data.data, data.length, &sp.cksum);
+    krb5_crypto_destroy(context, crypto);
+    free(data.data);
+    if (ret)
+       goto out;
+
+    ASN1_MALLOC_ENCODE(KRB5SignedPath, data.data, data.length, &sp, &size, ret);
+    free_Checksum(&sp.cksum);
+    if (ret)
+       goto out;
+    if (data.length != size)
+       krb5_abortx(context, "internal asn.1 encoder error");
+
+    
+    /*
+     * Add IF-RELEVANT(KRB5SignedPath) to the last slot in
+     * authorization data field.
+     */
+
+    if (tkt->authorization_data == NULL) {
+       tkt->authorization_data = calloc(1, sizeof(*tkt->authorization_data));
+       if (tkt->authorization_data == NULL) {
+           ret = ENOMEM;
+           goto out;
+       }
+    }
+
+    /* add the entry to the last element */
+    {
+       AuthorizationData ad = { 0, NULL };
+       AuthorizationDataElement ade;
+
+       ade.ad_type = KRB5_AUTHDATA_SIGNTICKET;
+       ade.ad_data = data;
+
+       ret = add_AuthorizationData(&ad, &ade);
+       krb5_data_free(&data);
+       if (ret)
+           return ret;
+
+       ASN1_MALLOC_ENCODE(AuthorizationData, data.data, data.length, 
+                          &ad, &size, ret);
+       free_AuthorizationData(&ad);
+       if (ret)
+           return ret;
+       if (data.length != size)
+           krb5_abortx(context, "internal asn.1 encoder error");
+       
+       ade.ad_type = KRB5_AUTHDATA_IF_RELEVANT;
+       ade.ad_data = data;
+
+       ret = add_AuthorizationData(tkt->authorization_data, &ade);
+       krb5_data_free(&data);
+       if (ret)
+           return ret;
+    }
+
+out:
+    return 0;
+}
+
+static krb5_error_code
+check_KRB5SignedPath(krb5_context context,
+                    krb5_kdc_configuration *config,
+                    hdb_entry_ex *krbtgt,
+                    EncTicketPart *tkt,
+                    KRB5SignedPathPrincipals **delegated,
+                    int require_signedpath)
+{
+    krb5_error_code ret;
+    krb5_data data;
+    krb5_crypto crypto = NULL;
+
+    *delegated = NULL;
+
+    ret = find_KRB5SignedPath(context, tkt->authorization_data, &data);
+    if (ret == 0) {
+       KRB5SignedPathData spd;
+       KRB5SignedPath sp;
+       AuthorizationData *ad;
+       size_t size;
+
+       ret = decode_KRB5SignedPath(data.data, data.length, &sp, NULL);
+       krb5_data_free(&data);
+       if (ret)
+           return ret;
+
+       spd.encticket = *tkt;
+       /* the KRB5SignedPath is the last entry */
+       ad = spd.encticket.authorization_data;
+       if (--ad->len == 0)
+           spd.encticket.authorization_data = NULL;
+       spd.delegated = sp.delegated;
+
+       ASN1_MALLOC_ENCODE(KRB5SignedPathData, data.data, data.length,
+                          &spd, &size, ret);
+       ad->len++;
+       spd.encticket.authorization_data = ad;
+       if (ret) {
+           free_KRB5SignedPath(&sp);
+           return ret;
+       }
+       if (data.length != size)
+           krb5_abortx(context, "internal asn.1 encoder error");
+
+       {
+           Key *key;
+           ret = hdb_enctype2key(context, &krbtgt->entry, sp.etype, &key);
+           if (ret == 0)
+               ret = krb5_crypto_init(context, &key->key, 0, &crypto);
+           if (ret) {
+               free(data.data);
+               free_KRB5SignedPath(&sp);
+               return ret;
+           }
+       }
+       ret = krb5_verify_checksum(context, crypto, KRB5_KU_KRB5SIGNEDPATH, 
+                                  data.data, data.length, 
+                                  &sp.cksum);
+       krb5_crypto_destroy(context, crypto);
+       free(data.data);
+       if (ret) {
+           free_KRB5SignedPath(&sp);
+           return ret;
+       }
+
+       if (sp.delegated) {
+
+           *delegated = malloc(sizeof(*sp.delegated));
+           if (*delegated == NULL) {
+               free_KRB5SignedPath(&sp);
+               return ENOMEM;
+           }
+
+           ret = copy_KRB5SignedPathPrincipals(*delegated, sp.delegated);
+           if (ret) {
+               free_KRB5SignedPath(&sp);
+               free(*delegated);
+               *delegated = NULL;
+               return ret;
+           }
+       }
+       free_KRB5SignedPath(&sp);
+       
+    } else {
+       if (require_signedpath)
+           return KRB5KDC_ERR_BADOPTION;
+    }
+
+    return 0;
+}
+
+
+/*
+ *
+ */
+
+static krb5_error_code
+check_tgs_flags(krb5_context context,        
+               krb5_kdc_configuration *config,
+               KDC_REQ_BODY *b, const 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);
+       _kdc_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
+check_constrained_delegation(krb5_context context, 
+                            krb5_kdc_configuration *config,
+                            hdb_entry_ex *client,
+                            krb5_const_principal server)
+{
+    const HDB_Ext_Constrained_delegation_acl *acl;
+    krb5_error_code ret;
+    int i;
+
+    ret = hdb_entry_get_ConstrainedDelegACL(&client->entry, &acl);
+    if (ret) {
+       krb5_clear_error_string(context);
+       return ret;
+    }
+
+    if (acl) {
+       for (i = 0; i < acl->len; i++) {
+           if (krb5_principal_compare(context, server, &acl->val[i]) == TRUE)
+               return 0;
+       }
+    }
+    kdc_log(context, config, 0,
+           "Bad request for constrained delegation");
+    return KRB5KDC_ERR_BADOPTION;
+}
+
+/*
+ *
+ */
+
+static krb5_error_code
+verify_flags (krb5_context context, 
+             krb5_kdc_configuration *config,
+             const EncTicketPart *et,
+             const char *pstr)
+{
+    if(et->endtime < kdc_time){
+       kdc_log(context, config, 0, "Ticket expired (%s)", pstr);
+       return KRB5KRB_AP_ERR_TKT_EXPIRED;
+    }
+    if(et->flags.invalid){
+       kdc_log(context, config, 0, "Ticket not valid (%s)", pstr);
+       return KRB5KRB_AP_ERR_TKT_NYV;
+    }
+    return 0;
+}
+
+/*
+ *
+ */
+
+static krb5_error_code
+fix_transited_encoding(krb5_context context, 
+                      krb5_kdc_configuration *config,
+                      krb5_boolean check_policy,
+                      const 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;
+
+    switch (tr->tr_type) {
+    case DOMAIN_X500_COMPRESS:
+       break;
+    case 0:
+       /*
+        * Allow empty content of type 0 because that is was Microsoft
+        * generates in their TGT.
+        */
+       if (tr->contents.length == 0)
+           break;
+       kdc_log(context, config, 0,
+               "Transited type 0 with non empty content");
+       return KRB5KDC_ERR_TRTYPE_NOSUPP;
+    default:
+       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, 
+              krb5_const_principal tgt_name,
+              const EncTicketPart *tgt, 
+              const EncTicketPart *adtkt, 
+              AuthorizationData *auth_data,
+              krb5_ticket *tgs_ticket,
+              hdb_entry_ex *server, 
+              const char *server_name, 
+              hdb_entry_ex *client, 
+              krb5_principal client_principal, 
+              hdb_entry_ex *krbtgt,
+              krb5_enctype krbtgt_etype,
+              KRB5SignedPathPrincipals *spp,
+              EncryptionKey *tgtkey,
+              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;
+    const EncryptionKey *ekey;
+    AuthorizationData *new_auth_data = NULL;
+    
+    if(adtkt) {
+       int i;
+       ekey = &adtkt->key;
+       for(i = 0; i < b->etype.len; i++)
+           if (b->etype.val[i] == adtkt->key.keytype)
+               break;
+       if(i == b->etype.len) {
+           krb5_clear_error_string(context);
+           return KRB5KDC_ERR_ETYPE_NOSUPP;
+       }
+       etype = b->etype.val[i];
+    }else{
+       ret = _kdc_find_etype(context, server, b->etype.val, b->etype.len,
+                             &skey, &etype);
+       if(ret) {
+           kdc_log(context, config, 0, 
+                   "Server (%s) has no support for etypes", server_name);
+           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;
+    _kdc_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->entry.principal),
+                                *krb5_princ_realm(context, krbtgt->entry.principal));
+    if(ret)
+       goto out;
+
+    copy_Realm(krb5_princ_realm(context, server->entry.principal), 
+              &rep.ticket.realm);
+    _krb5_principal2principalname(&rep.ticket.sname, server->entry.principal);
+    copy_Realm(&tgt_name->realm, &rep.crealm);
+    if (f.request_anonymous)
+       _kdc_make_anonymous_principalname (&rep.cname);
+    else
+       copy_PrincipalName(&tgt_name->name, &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->entry.max_life)
+           life = min(life, *client->entry.max_life);
+       if(server->entry.max_life)
+           life = min(life, *server->entry.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->entry.max_renew)
+           renew = min(renew, *client->entry.max_renew);
+       if(server->entry.max_renew)
+           renew = min(renew, *server->entry.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->entry.flags.ok_as_delegate;
+           
+    
+    krb5_generate_random_keyblock(context, etype, &et.key);
+
+    if (server->authz_data_tgs_req) {
+           ret = server->authz_data_tgs_req(context, server,
+                                            client_principal, 
+                                            tgs_ticket->ticket.authorization_data,
+                                            tgs_ticket->ticket.authtime,
+                                            tgtkey,
+                                            ekey, 
+                                            &et.key, 
+                                            &new_auth_data);
+           if (ret) {
+                   new_auth_data = NULL;
+           }
+    }
+
+    /* XXX Check enc-authorization-data */
+    et.authorization_data = new_auth_data;
+
+    et.crealm = tgt->crealm;
+    et.cname = tgt_name->name;
+           
+    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;
+    
+    _kdc_log_timestamp(context, config, "TGS-REQ", et.authtime, et.starttime, 
+                      et.endtime, et.renew_till);
+
+    /* Don't sign cross realm tickets, they can't be checked anyway */
+    {
+       char *r = get_krbtgt_realm(&ek.sname);
+
+       if (r == NULL || strcmp(r, ek.srealm) == 0) {
+           ret = _kdc_add_KRB5SignedPath(context,
+                                         config,
+                                         krbtgt,
+                                         krbtgt_etype,
+                                         NULL,
+                                         NULL,
+                                         &et);
+           if (ret)
+               goto out;
+       }
+    }
+
+    /* 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 = _kdc_encode_reply(context, config, 
+                           &rep, &et, &ek, etype,
+                           adtkt ? 0 : server->entry.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);
+    if(et.authorization_data) {
+       free_AuthorizationData(et.authorization_data);
+       free(et.authorization_data);
+    }
+    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 authenticator checksum: %s", 
+               krb5_get_err_text(context, ret));
+    }
+out:
+    free_Authenticator(auth);
+    free(auth);
+    return ret;
+}
+
+/*
+ *
+ */
+
+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_parse_request(krb5_context context, 
+                 krb5_kdc_configuration *config,
+                 KDC_REQ_BODY *b,
+                 PA_DATA *tgs_req,
+                 hdb_entry_ex **krbtgt,
+                 krb5_enctype *krbtgt_etype,
+                 krb5_ticket **ticket,
+                 const char **e_text,
+                 const char *from,
+                 const struct sockaddr *from_addr,
+                 time_t **csec,
+                 int **cusec,
+                 AuthorizationData **auth_data,
+                 EncryptionKey **tgtkey)
+{
+    krb5_ap_req ap_req;
+    krb5_error_code ret;
+    krb5_principal princ;
+    krb5_auth_context ac = NULL;
+    krb5_flags ap_req_options;
+    krb5_flags verify_ap_req_flags;
+    krb5_crypto crypto;
+    Key *tkey;
+
+    *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 out;
+    }
+
+    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 out;
+    }
+    
+    _krb5_principalname2krb5_principal(context,
+                                      &princ,
+                                      ap_req.ticket.sname,
+                                      ap_req.ticket.realm);
+    
+    ret = _kdc_db_fetch(context, config, princ, HDB_F_GET_KRBTGT, NULL, 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 out;
+    }
+    
+    if(ap_req.ticket.enc_part.kvno && 
+       *ap_req.ticket.enc_part.kvno != (*krbtgt)->entry.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)->entry.kvno,
+               p);
+       if (ret == 0)
+           free (p);
+       ret = KRB5KRB_AP_ERR_BADKEYVER;
+       goto out;
+    }
+
+    *krbtgt_etype = ap_req.ticket.enc_part.etype;
+
+    ret = hdb_enctype2key(context, &(*krbtgt)->entry, 
+                         ap_req.ticket.enc_part.etype, &tkey);
+    if(ret){
+       char *str, *p;
+       krb5_enctype_to_string(context, ap_req.ticket.enc_part.etype, &str);
+       krb5_unparse_name(context, princ, &p);
+       kdc_log(context, config, 0,
+               "No server key with enctype %s found for %s", str, p);
+       free(str);
+       free(p);
+       ret = KRB5KRB_AP_ERR_BADKEYVER;
+       goto out;
+    }
+
+    *tgtkey = &tkey->key;
+    
+    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 out;
+    }
+
+    {
+       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 out;
+           }
+           **csec  = auth->ctime;
+           *cusec  = malloc(sizeof(**cusec));
+           if (*cusec == NULL) {
+               krb5_free_authenticator(context, &auth);
+               kdc_log(context, config, 0, "malloc failed");
+               goto out;
+           }
+           **cusec  = auth->cusec;
+           krb5_free_authenticator(context, &auth);
+       }
+    }
+
+    ret = tgs_check_authenticator(context, config, 
+                                 ac, b, e_text, &(*ticket)->ticket.key);
+    if (ret) {
+       krb5_auth_con_free(context, ac);
+       goto out;
+    }
+
+    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 out;
+       }
+       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 out;
+           }
+       }
+       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 out;
+       }
+       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 out;
+       }
+       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 out;
+       }
+       krb5_free_keyblock(context, subkey);
+       ALLOC(*auth_data);
+       if (*auth_data == NULL) {
+           krb5_auth_con_free(context, ac);
+           ret = KRB5KRB_AP_ERR_BAD_INTEGRITY; /* ? */
+           goto out;
+       }
+       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 out;
+       }
+    }
+
+    krb5_auth_con_free(context, ac);
+    
+out:
+    free_AP_REQ(&ap_req);
+    
+    return ret;
+}
+
+static krb5_error_code
+tgs_build_reply(krb5_context context, 
+               krb5_kdc_configuration *config,
+               KDC_REQ *req, 
+               KDC_REQ_BODY *b,
+               hdb_entry_ex *krbtgt,
+               krb5_enctype krbtgt_etype,
+               krb5_ticket *ticket,
+               krb5_data *reply,
+               const char *from,
+               const char **e_text,
+               AuthorizationData *auth_data,
+               EncryptionKey *tgtkey,
+       const struct sockaddr *from_addr)
+{
+    krb5_error_code ret;
+    krb5_principal cp = NULL, sp = NULL;
+    krb5_principal client_principal = NULL;
+    char *spn = NULL, *cpn = NULL;
+    hdb_entry_ex *server = NULL, *client = NULL;
+    EncTicketPart *tgt = &ticket->ticket;
+    KRB5SignedPathPrincipals *spp = NULL;
+
+    PrincipalName *s;
+    Realm r;
+    int nloop = 0;
+    EncTicketPart adtkt;
+    char opt_str[128];
+    int require_signedpath = 0;
+
+    memset(&adtkt, 0, sizeof(adtkt));
+
+    s = b->sname;
+    r = b->realm;
+
+    if(b->kdc_options.enc_tkt_in_skey){
+       Ticket *t;
+       hdb_entry_ex *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 out;
+       }
+       _krb5_principalname2krb5_principal(context, &p, t->sname, t->realm);
+       ret = _kdc_db_fetch(context, config, p, 
+                           HDB_F_GET_CLIENT|HDB_F_GET_SERVER, 
+                           NULL, &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->entry, 
+                             t->enc_part.etype, &uukey);
+       if(ret){
+           _kdc_free_ent(context, uu);
+           ret = KRB5KDC_ERR_ETYPE_NOSUPP; /* XXX */
+           goto out;
+       }
+       ret = krb5_decrypt_ticket(context, t, &uukey->key, &adtkt, 0);
+       _kdc_free_ent(context, uu);
+       if(ret)
+           goto out;
+
+       ret = verify_flags(context, config, &adtkt, spn);
+       if (ret)
+           goto out;
+
+       s = &adtkt.cname;
+       r = adtkt.crealm;
+    }
+
+    _krb5_principalname2krb5_principal(context, &sp, *s, r);
+    ret = krb5_unparse_name(context, sp, &spn);        
+    if (ret)
+       goto out;
+    _krb5_principalname2krb5_principal(context, &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);
+
+    /*
+     * Fetch server
+     */
+
+server_lookup:
+    ret = _kdc_db_fetch(context, config, sp, HDB_F_GET_SERVER, NULL, &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_F_GET_CLIENT, NULL, &client);
+    if(ret) {
+       const char *krbtgt_realm; 
+
+       /*
+        * If the client belongs to the same realm as our krbtgt, it
+        * should exist in the local database.
+        *
+        */
+
+       krbtgt_realm = 
+           krb5_principal_get_comp_string(context, 
+                                          krbtgt->entry.principal, 1);
+
+       if(strcmp(krb5_principal_get_realm(context, cp), krbtgt_realm) == 0) {
+           if (ret == HDB_ERR_NOENTRY)
+               ret = KRB5KDC_ERR_C_PRINCIPAL_UNKNOWN;
+           kdc_log(context, config, 1, "Client no longer in database: %s",
+                   cpn);
+           goto out;
+       }
+       
+       kdc_log(context, config, 1, "Client not found in database: %s: %s",
+               cpn, krb5_get_err_text(context, ret));
+    }
+    
+    /*
+     * Check that service is in the same realm as the krbtgt. If its
+     * not the same, its someone that is using a uni-directional trust
+     * backward.
+     */
+    
+    if (strcmp(krb5_principal_get_realm(context, sp),
+              krb5_principal_get_comp_string(context, 
+                                             krbtgt->entry.principal, 
+                                             1)) != 0) {
+       char *tpn;
+       ret = krb5_unparse_name(context, krbtgt->entry.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;
+    }
+
+    /*
+     *
+     */
+
+    client_principal = cp;
+
+    if (client) {
+       const PA_DATA *sdata;
+       int i = 0;
+
+       sdata = _kdc_find_padata(req, &i, KRB5_PADATA_S4U2SELF);
+       if (sdata) {
+           krb5_crypto crypto;
+           krb5_data datack;
+           PA_S4U2Self self;
+           char *selfcpn = NULL;
+           const char *str;
+
+           ret = decode_PA_S4U2Self(sdata->padata_value.data, 
+                                    sdata->padata_value.length,
+                                    &self, NULL);
+           if (ret) {
+               kdc_log(context, config, 0, "Failed to decode PA-S4U2Self");
+               goto out;
+           }
+
+           ret = _krb5_s4u2self_to_checksumdata(context, &self, &datack);
+           if (ret)
+               goto out;
+
+           ret = krb5_crypto_init(context, &tgt->key, 0, &crypto);
+           if (ret) {
+               free_PA_S4U2Self(&self);
+               krb5_data_free(&datack);
+               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_IMPERSONATE,
+                                      datack.data, 
+                                      datack.length, 
+                                      &self.cksum);
+           krb5_data_free(&datack);
+           krb5_crypto_destroy(context, crypto);
+           if (ret) {
+               free_PA_S4U2Self(&self);
+               kdc_log(context, config, 0, 
+                       "krb5_verify_checksum failed for S4U2Self: %s",
+                       krb5_get_err_text(context, ret));
+               goto out;
+           }
+
+           ret = _krb5_principalname2krb5_principal(context,
+                                                    &client_principal,
+                                                    self.name,
+                                                    self.realm);
+           free_PA_S4U2Self(&self);
+           if (ret)
+               goto out;
+
+           ret = krb5_unparse_name(context, client_principal, &selfcpn);       
+           if (ret)
+               goto out;
+
+           /*
+            * Check that service doing the impersonating is
+            * requesting a ticket to it-self.
+            */
+           if (krb5_principal_compare(context, cp, sp) != TRUE) {
+               kdc_log(context, config, 0, "S4U2Self: %s is not allowed "
+                       "to impersonate some other user "
+                       "(tried for user %s to service %s)",
+                       cpn, selfcpn, spn);
+               free(selfcpn);
+               ret = KRB5KDC_ERR_BADOPTION; /* ? */
+               goto out;
+           }
+
+           /*
+            * If the service isn't trusted for authentication to
+            * delegation, remove the forward flag.
+            */
+
+           if (client->entry.flags.trusted_for_delegation) {
+               str = "[forwardable]";
+           } else {
+               b->kdc_options.forwardable = 0;
+               str = "";
+           }
+           kdc_log(context, config, 0, "s4u2self %s impersonating %s to "
+                   "service %s %s", cpn, selfcpn, spn, str);
+           free(selfcpn);
+       }
+    }
+
+    /*
+     * Constrained delegation
+     */
+
+    if (client != NULL
+       && b->additional_tickets != NULL
+       && b->additional_tickets->len != 0
+       && b->kdc_options.enc_tkt_in_skey == 0)
+    {
+       Key *clientkey;
+       Ticket *t;
+       char *str;
+
+       t = &b->additional_tickets->val[0];
+
+       ret = hdb_enctype2key(context, &client->entry, 
+                             t->enc_part.etype, &clientkey);
+       if(ret){
+           ret = KRB5KDC_ERR_ETYPE_NOSUPP; /* XXX */
+           goto out;
+       }
+
+       ret = krb5_decrypt_ticket(context, t, &clientkey->key, &adtkt, 0);
+       if (ret) {
+           kdc_log(context, config, 0,
+                   "failed to decrypt ticket for "
+                   "constrained delegation from %s to %s ", spn, cpn);
+           goto out;
+       }
+
+       /* check that ticket is valid */
+
+       if (adtkt.flags.forwardable == 0) {
+           kdc_log(context, config, 0,
+                   "Missing forwardable flag on ticket for "
+                   "constrained delegation from %s to %s ", spn, cpn);
+           ret = KRB5KDC_ERR_ETYPE_NOSUPP; /* XXX */
+           goto out;
+       }
+
+       ret = check_constrained_delegation(context, config, client, sp);
+       if (ret) {
+           kdc_log(context, config, 0,
+                   "constrained delegation from %s to %s not allowed", 
+                   spn, cpn);
+           goto out;
+       }
+
+       ret = _krb5_principalname2krb5_principal(context,
+                                                &client_principal,
+                                                adtkt.cname,
+                                                adtkt.crealm);
+       if (ret)
+           goto out;
+
+       ret = krb5_unparse_name(context, client_principal, &str);
+       if (ret)
+           goto out;
+
+       ret = verify_flags(context, config, &adtkt, str);
+       if (ret) {
+           free(str);
+           goto out;
+       }
+
+       /*
+        * Check KRB5SignedPath in authorization data and add new entry to
+        * make sure servers can't fake a ticket to us.
+        */
+
+       ret = check_KRB5SignedPath(context,
+                                  config,
+                                  krbtgt,
+                                  &adtkt,
+                                  &spp,
+                                  1);
+       if (ret) {
+           kdc_log(context, config, 0,
+                   "KRB5SignedPath check from service %s failed "
+                   "for delegation to %s for client %s "
+                   "from %s failed with %s",
+                   spn, str, cpn, from, krb5_get_err_text(context, ret));
+           free(str);
+           goto out;
+       }
+
+       kdc_log(context, config, 0, "constrained delegation for %s "
+               "from %s to %s", str, cpn, spn);
+       free(str);
+
+       /* 
+        * Also require that the KDC have issue the service's krbtgt
+        * used to do the request. 
+        */
+       require_signedpath = 1;
+    }
+
+    /*
+     * Check flags
+     */
+
+    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->entry.principal,
+                              server->entry.principal)){
+       kdc_log(context, config, 0, "Inconsistent request.");
+       ret = KRB5KDC_ERR_SERVER_NOMATCH;
+       goto out;
+    }
+
+    /* check for valid set of addresses */
+    if(!_kdc_check_addresses(context, config, tgt->caddr, from_addr)) {
+       ret = KRB5KRB_AP_ERR_BADADDR;
+       kdc_log(context, config, 0, "Request from wrong address");
+       goto out;
+    }
+       
+    /* also check the krbtgt for signature */
+    ret = check_KRB5SignedPath(context,
+                              config,
+                              krbtgt,
+                              tgt,
+                              &spp,
+                              require_signedpath);
+    if (ret) {
+       kdc_log(context, config, 0,
+               "KRB5SignedPath check failed for %s (%s) from %s with %s",
+               spn, cpn, from, krb5_get_err_text(context, ret));
+       goto out;
+    }
+
+    /*
+     *
+     */
+
+    ret = tgs_make_reply(context,
+                        config, 
+                        b, 
+                        client_principal,
+                        tgt, 
+                        b->kdc_options.enc_tkt_in_skey ? &adtkt : NULL, 
+                        auth_data,
+                        ticket,
+                        server, 
+                        spn,
+                        client, 
+                        cp, 
+                        krbtgt, 
+                        krbtgt_etype,
+                        spp,
+                        tgtkey,
+                        e_text,
+                        reply);
+       
+out:
+    free(spn);
+    free(cpn);
+           
+    if(server)
+       _kdc_free_ent(context, server);
+    if(client)
+       _kdc_free_ent(context, client);
+
+    if (client_principal && client_principal != cp)
+       krb5_free_principal(context, client_principal);
+    if (cp)
+       krb5_free_principal(context, cp);
+    if (sp)
+       krb5_free_principal(context, sp);
+
+    free_EncTicketPart(&adtkt);
+
+    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)
+{
+    AuthorizationData *auth_data = NULL;
+    krb5_error_code ret;
+    int i = 0;
+    PA_DATA *tgs_req = NULL;
+
+    hdb_entry_ex *krbtgt = NULL;
+    krb5_ticket *ticket = NULL;
+    const char *e_text = NULL;
+    krb5_enctype krbtgt_etype = ETYPE_NULL;
+    EncryptionKey *tgtkey = 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 = _kdc_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_parse_request(context, config, 
+                           &req->req_body, tgs_req,
+                           &krbtgt,
+                           &krbtgt_etype,
+                           &ticket,
+                           &e_text,
+                           from, from_addr,
+                           &csec, &cusec,
+                           &auth_data,                           
+                           &tgtkey);
+    if (ret) {
+       kdc_log(context, config, 0, 
+               "Failed parsing TGS-REQ from %s", from);
+       goto out;
+    }
+
+    ret = tgs_build_reply(context,
+                         config,
+                         req,
+                         &req->req_body,
+                         krbtgt,
+                         krbtgt_etype,
+                         ticket,
+                         data,
+                         from,
+                         &e_text,
+                         auth_data,
+                         tgtkey,
+                         from_addr);
+    if (ret) {
+       kdc_log(context, config, 0, 
+               "Failed building TGS-REP to %s", from);
+       goto out;
+    }
+
+out:
+    if(ret && data->data == NULL){
+       krb5_mk_error(context,
+                     ret,
+                     NULL,
+                     NULL,
+                     NULL,
+                     NULL,
+                     csec,
+                     cusec,
+                     data);
+    }
+    free(csec);
+    free(cusec);
+    if (ticket)
+       krb5_free_ticket(context, ticket);
+    if(krbtgt)
+       _kdc_free_ent(context, krbtgt);
+
+    if (auth_data) {
+       free_AuthorizationData(auth_data);
+       free(auth_data);
+    }
+
+    return 0;
+}
index a61c647f719fc956be7b6b7ae75f9f19cc5f26c6..b511e1a7a8d39a575ff8abec7ebad541bb0ae14a 100644 (file)
@@ -33,7 +33,7 @@
 
 #include "kdc_locl.h"
 
-RCSID("$Id: misc.c,v 1.29 2006/04/27 11:33:21 lha Exp $");
+RCSID("$Id: misc.c,v 1.32 2006/08/28 14:41:49 lha Exp $");
 
 struct timeval _kdc_now;
 
@@ -42,6 +42,7 @@ _kdc_db_fetch(krb5_context context,
              krb5_kdc_configuration *config,
              krb5_const_principal principal,
              unsigned flags,
+             HDB **db,
              hdb_entry_ex **h)
 {
     hdb_entry_ex *ent;
@@ -66,6 +67,8 @@ _kdc_db_fetch(krb5_context context,
                                       ent);
        config->db[i]->hdb_close(context, config->db[i]);
        if(ret == 0) {
+           if (db)
+               *db = config->db[i];
            *h = ent;
            return 0;
        }
@@ -81,3 +84,36 @@ _kdc_free_ent(krb5_context context, hdb_entry_ex *ent)
     free (ent);
 }
 
+/*
+ * Use the order list of preferred encryption types and sort the
+ * available keys and return the most preferred key.
+ */
+
+krb5_error_code
+_kdc_get_preferred_key(krb5_context context,
+                      krb5_kdc_configuration *config,
+                      hdb_entry_ex *h,
+                      const char *name,
+                      krb5_enctype *enctype,
+                      Key **key)
+{
+    const krb5_enctype *p;
+    krb5_error_code ret;
+    int i;
+
+    p = krb5_kerberos_enctypes(context);
+
+    for (i = 0; p[i] != ETYPE_NULL; i++) {
+       if (krb5_enctype_valid(context, p[i]) != 0)
+           continue;
+       ret = hdb_enctype2key(context, &h->entry, p[i], key);
+       if (ret == 0) {
+           *enctype = p[i];
+           return 0;
+       }
+    }
+
+    krb5_set_error_string(context, "No valid kerberos key found for %s", name);
+    return EINVAL;
+}
+
index c220e70dddb77ca32605eeddcbb5d3ea231ab5a2..e3d77c06219f76e16668619c4947346d6b54a025 100755 (executable)
@@ -33,7 +33,7 @@
 
 #include "kdc_locl.h"
 
-RCSID("$Id: pkinit.c,v 1.65 2006/05/06 13:22:33 lha Exp $");
+RCSID("$Id: pkinit.c,v 1.72 2006/10/24 17:51:33 lha Exp $");
 
 #ifdef PKINIT
 
@@ -156,7 +156,7 @@ pk_check_pkauthenticator(krb5_context context,
        goto out;
     }
 
-    if (heim_octet_string_cmp(a->paChecksum, &checksum.checksum) != 0) {
+    if (der_heim_octet_string_cmp(a->paChecksum, &checksum.checksum) != 0) {
        krb5_clear_error_string(context);
        ret = KRB5KRB_ERR_GENERIC;
     }
@@ -269,7 +269,7 @@ get_dh_param(krb5_context context,
 
     memset(&dhparam, 0, sizeof(dhparam));
 
-    if (heim_oid_cmp(&dh_key_info->algorithm.algorithm, oid_id_dhpublicnumber())) {
+    if (der_heim_oid_cmp(&dh_key_info->algorithm.algorithm, oid_id_dhpublicnumber())) {
        krb5_set_error_string(context,
                              "PKINIT invalid oid in clientPublicValue");
        return KRB5_BADMSGTYPE;
@@ -338,7 +338,7 @@ get_dh_param(krb5_context context,
        client_params->dh_public_key = integer_to_BN(context,
                                                     "subjectPublicKey",
                                                     &glue);
-       free_heim_integer(&glue);
+       der_free_heim_integer(&glue);
        if (client_params->dh_public_key == NULL)
            goto out;
     }
@@ -426,7 +426,7 @@ _kdc_pk_rd_padata(krb5_context context,
     krb5_data signed_content = { 0, NULL };
     const char *type = "unknown type";
     const heim_oid *pa_contentType;
-    int have_data;
+    int have_data = 0;
 
     *ret_params = NULL;
     
@@ -444,7 +444,6 @@ _kdc_pk_rd_padata(krb5_context context,
 
     if (pa->padata_type == KRB5_PADATA_PK_AS_REQ_WIN) {
        PA_PK_AS_REQ_Win2k r;
-       int have_data;
 
        type = "PK-INIT-Win2k";
        pa_contentType = oid_id_pkcs7_data();
@@ -502,7 +501,7 @@ _kdc_pk_rd_padata(krb5_context context,
        goto out;
     }
 
-    ret = heim_oid_cmp(&contentInfoOid, oid_id_pkcs7_signedData());
+    ret = der_heim_oid_cmp(&contentInfoOid, oid_id_pkcs7_signedData());
     if (ret != 0) {
        krb5_set_error_string(context, "PK-AS-REQ-Win2k invalid content "
                              "type oid");
@@ -542,7 +541,7 @@ _kdc_pk_rd_padata(krb5_context context,
     }
 
     /* Signature is correct, now verify the signed message */
-    if (heim_oid_cmp(&eContentType, pa_contentType)) {
+    if (der_heim_oid_cmp(&eContentType, pa_contentType)) {
        krb5_set_error_string(context, "got wrong oid for pkauthdata");
        ret = KRB5_BADMSGTYPE;
        goto out;
@@ -621,8 +620,8 @@ out:
     if (signed_content.data)
        free(signed_content.data);
     krb5_data_free(&eContent);
-    free_oid(&eContentType);
-    free_oid(&contentInfoOid);
+    der_free_oid(&eContentType);
+    der_free_oid(&contentInfoOid);
     if (ret)
        _kdc_pk_free_client_param(context, client_params);
     else
@@ -657,10 +656,11 @@ pk_mk_pa_reply_enckey(krb5_context context,
                      ContentInfo *content_info)
 {
     krb5_error_code ret;
-    krb5_data buf, o;
+    krb5_data buf, signed_data;
     size_t size;
 
     krb5_data_zero(&buf);
+    krb5_data_zero(&signed_data);
 
     switch (client_params->type) {
     case PKINIT_COMPAT_WIN2K: {
@@ -678,6 +678,7 @@ pk_mk_pa_reply_enckey(krb5_context context,
                           buf.data, buf.length,
                           &kp, &size,ret);
        free_ReplyKeyPack_Win2k(&kp);
+       break;
     }
     case PKINIT_COMPAT_27: {
        krb5_crypto ascrypto;
@@ -724,21 +725,55 @@ pk_mk_pa_reply_enckey(krb5_context context,
     if (buf.length != size)
        krb5_abortx(context, "Internal ASN.1 encoder error");
 
+    {
+       hx509_query *q;
+       hx509_cert cert;
+       
+       ret = hx509_query_alloc(kdc_identity->hx509ctx, &q);
+       if (ret)
+           goto out;
+       
+       hx509_query_match_option(q, HX509_QUERY_OPTION_PRIVATE_KEY);
+       hx509_query_match_option(q, HX509_QUERY_OPTION_KU_DIGITALSIGNATURE);
+       
+       ret = hx509_certs_find(kdc_identity->hx509ctx, 
+                              kdc_identity->certs, 
+                              q, 
+                              &cert);
+       hx509_query_free(kdc_identity->hx509ctx, q);
+       if (ret)
+           goto out;
+       
+       ret = hx509_cms_create_signed_1(kdc_identity->hx509ctx,
+                                       oid_id_pkrkeydata(),
+                                       buf.data,
+                                       buf.length,
+                                       NULL,
+                                       cert,
+                                       kdc_identity->anchors,
+                                       kdc_identity->certpool,
+                                       &signed_data);
+       hx509_cert_free(cert);
+    }
+
+    krb5_data_free(&buf);
+    if (ret) 
+       goto out;
+
     ret = hx509_cms_envelope_1(kdc_identity->hx509ctx,
                               client_params->cert,
-                              buf.data, buf.length, NULL,
-                              oid_id_pkcs7_signedData(), &o);
+                              signed_data.data, signed_data.length, NULL,
+                              oid_id_pkcs7_signedData(), &buf);
     if (ret)
        goto out;
     
     ret = _krb5_pk_mk_ContentInfo(context,
-                                 &o,
+                                 &buf,
                                  oid_id_pkcs7_envelopedData(),
                                  content_info);
-    free_octet_string(&o);
-
- out:
+out:
     krb5_data_free(&buf);
+    krb5_data_free(&signed_data);
     return ret;
 }
 
@@ -1195,6 +1230,7 @@ _kdc_pk_check_client(krb5_context context,
                     pk_client_params *client_params,
                     char **subject_name)
 {
+    const HDB_Ext_PKINIT_acl *acl;
     krb5_error_code ret;
     hx509_name name;
     int i;
@@ -1210,8 +1246,8 @@ _kdc_pk_check_client(krb5_context context,
     if (ret)
        return ret;
 
-    kdc_log(context, config, 5,
-           "Trying to authorize subject DN %s", 
+    kdc_log(context, config, 0,
+           "Trying to authorize PK-INIT subject DN %s", 
            *subject_name);
 
     if (config->enable_pkinit_princ_in_cert) {
@@ -1225,6 +1261,28 @@ _kdc_pk_check_client(krb5_context context,
        }
     }
 
+    ret = hdb_entry_get_pkinit_acl(&client->entry, &acl);
+    if (ret == 0 && acl != NULL) {
+       /*
+        * Cheat here and compare the generated name with the string
+        * and not the reverse.
+        */
+       for (i = 0; i < acl->len; i++) {
+           if (strcmp(*subject_name, acl->val[0].subject) != 0)
+               continue;
+
+           /* Don't support isser and anchor checking right now */
+           if (acl->val[0].issuer)
+               continue;
+           if (acl->val[0].anchor)
+               continue;
+
+           kdc_log(context, config, 5,
+                   "Found matching PK-INIT database ACL");
+           return 0;
+       }
+    }
+
     for (i = 0; i < principal_mappings.len; i++) {
        krb5_boolean b;
 
@@ -1235,11 +1293,14 @@ _kdc_pk_check_client(krb5_context context,
            continue;
        if (strcmp(principal_mappings.val[i].subject, *subject_name) != 0)
            continue;
+       kdc_log(context, config, 5,
+               "Found matching PK-INIT FILE ACL");
        return 0;
     }
-    free(*subject_name);
 
+    free(*subject_name);
     *subject_name = NULL;
+
     krb5_set_error_string(context, "PKINIT no matching principals");
     return KRB5_KDC_ERR_CLIENT_NAME_MISMATCH;
 }
@@ -1282,7 +1343,7 @@ _kdc_pk_initialize(krb5_context context,
                   const char *user_id,
                   const char *anchors,
                   char **pool,
-                  char **revoke)
+                  char **revoke_list)
 {
     const char *file; 
     krb5_error_code ret;
@@ -1305,7 +1366,7 @@ _kdc_pk_initialize(krb5_context context,
                           user_id,
                           anchors,
                           pool,
-                          revoke,
+                          revoke_list,
                           NULL,
                           NULL,
                           NULL);
index d0f8245bf9101a3b02c4c407b72136577821908a..ed5cb3d651330c046fad37e7fb1059260770f247 100644 (file)
@@ -34,7 +34,7 @@
 
 #include "kdc_locl.h"
 
-RCSID("$Id: process.c,v 1.3 2005/08/12 08:25:48 lha Exp $");
+RCSID("$Id: process.c,v 1.5 2006/10/09 15:37:39 lha Exp $");
 
 /*
  * handle the request in `buf, len', from `addr' (or `from' as a string),
@@ -42,17 +42,19 @@ RCSID("$Id: process.c,v 1.3 2005/08/12 08:25:48 lha Exp $");
  */
 
 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)
+krb5_kdc_process_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 datagram_reply)
 {
     KDC_REQ req;
     Ticket ticket;
+    DigestREQ digestreq;
     krb5_error_code ret;
     size_t i;
 
@@ -64,7 +66,7 @@ krb5_kdc_process_generic_request(krb5_context context,
        req_buffer.length = len;
 
        ret = _kdc_as_rep(context, config, &req, &req_buffer, 
-                         reply, from, addr);
+                         reply, from, addr, datagram_reply);
        free_AS_REQ(&req);
        return ret;
     }else if(decode_TGS_REQ(buf, len, &req, &i) == 0){
@@ -75,6 +77,10 @@ krb5_kdc_process_generic_request(krb5_context context,
        ret = _kdc_do_524(context, config, &ticket, reply, from, addr);
        free_Ticket(&ticket);
        return ret;
+    }else if(decode_DigestREQ(buf, len, &digestreq, &i) == 0){
+       ret = _kdc_do_digest(context, config, &digestreq, reply, from, addr);
+       free_DigestREQ(&digestreq);
+       return ret;
     } else if(_kdc_maybe_version4(buf, len)){
        *prependlength = FALSE; /* elbitapmoc sdrawkcab XXX */
        _kdc_do_version4(context, config, buf, len, reply, from, 
@@ -103,7 +109,8 @@ krb5_kdc_process_krb5_request(krb5_context context,
                              size_t len, 
                              krb5_data *reply,
                              const char *from,
-                             struct sockaddr *addr)
+                             struct sockaddr *addr,
+                             int datagram_reply)
 {
     KDC_REQ req;
     krb5_error_code ret;
@@ -117,7 +124,7 @@ krb5_kdc_process_krb5_request(krb5_context context,
        req_buffer.length = len;
 
        ret = _kdc_as_rep(context, config, &req, &req_buffer,
-                         reply, from, addr);
+                         reply, from, addr, datagram_reply);
        free_AS_REQ(&req);
        return ret;
     }else if(decode_TGS_REQ(buf, len, &req, &i) == 0){
index 78873761b6eeb8b26c140315fce9708a84bb3103..ce43c2cd02f944f1941c93e4f4a2c2f5c303276e 100644 (file)
@@ -1,5 +1,5 @@
 -- From RFC 3369 --
--- $Id: CMS.asn1,v 1.4 2006/04/15 10:53:25 lha Exp $ --
+-- $Id: CMS.asn1,v 1.5 2006/09/07 12:20:42 lha Exp $ --
 
 CMS DEFINITIONS ::= BEGIN
 
@@ -17,7 +17,13 @@ id-pkcs7-signedAndEnvelopedData OBJECT IDENTIFIER ::=        { id-pkcs7 4 }
 id-pkcs7-digestedData OBJECT IDENTIFIER ::=            { id-pkcs7 5 }
 id-pkcs7-encryptedData OBJECT IDENTIFIER ::=           { id-pkcs7 6 }
 
-CMSVersion ::= INTEGER { v0(0), v1(1), v2(2), v3(3), v4(4) }
+CMSVersion ::= INTEGER {
+          CMSVersion_v0(0), 
+          CMSVersion_v1(1), 
+          CMSVersion_v2(2),
+          CMSVersion_v3(3),
+          CMSVersion_v4(4)
+}
 
 DigestAlgorithmIdentifier ::= AlgorithmIdentifier
 DigestAlgorithmIdentifiers ::= SET OF DigestAlgorithmIdentifier
index 01411b384a288ddf2c3cf31c13df0b984f62290d..ab06ae79dd630d02670386744f71d584c906fe4b 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: asn1-common.h,v 1.5 2005/07/12 06:27:14 lha Exp $ */
+/* $Id: asn1-common.h,v 1.6 2006/10/14 05:09:47 lha Exp $ */
 
 #include <stddef.h>
 #include <time.h>
@@ -43,6 +43,9 @@ typedef struct heim_bit_string {
     void *data;
 } heim_bit_string;
 
+typedef struct heim_octet_string heim_any;
+typedef struct heim_octet_string heim_any_set;
+
 #define ASN1_MALLOC_ENCODE(T, B, BL, S, L, R)                  \
   do {                                                         \
     (BL) = length_##T((S));                                    \
diff --git a/source4/heimdal/lib/asn1/der-protos.h b/source4/heimdal/lib/asn1/der-protos.h
new file mode 100644 (file)
index 0000000..3aee392
--- /dev/null
@@ -0,0 +1,542 @@
+/* This is a generated file */
+#ifndef __der_protos_h__
+#define __der_protos_h__
+
+#include <stdarg.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+int
+copy_heim_any (
+       const heim_any */*from*/,
+       heim_any */*to*/);
+
+int
+copy_heim_any_set (
+       const heim_any_set */*from*/,
+       heim_any_set */*to*/);
+
+int
+decode_heim_any (
+       const unsigned char */*p*/,
+       size_t /*len*/,
+       heim_any */*data*/,
+       size_t */*size*/);
+
+int
+decode_heim_any_set (
+       const unsigned char */*p*/,
+       size_t /*len*/,
+       heim_any_set */*data*/,
+       size_t */*size*/);
+
+int
+der_copy_bit_string (
+       const heim_bit_string */*from*/,
+       heim_bit_string */*to*/);
+
+int
+der_copy_bmp_string (
+       const heim_bmp_string */*from*/,
+       heim_bmp_string */*to*/);
+
+int
+der_copy_general_string (
+       const heim_general_string */*from*/,
+       heim_general_string */*to*/);
+
+int
+der_copy_heim_integer (
+       const heim_integer */*from*/,
+       heim_integer */*to*/);
+
+int
+der_copy_ia5_string (
+       const heim_printable_string */*from*/,
+       heim_printable_string */*to*/);
+
+int
+der_copy_octet_string (
+       const heim_octet_string */*from*/,
+       heim_octet_string */*to*/);
+
+int
+der_copy_oid (
+       const heim_oid */*from*/,
+       heim_oid */*to*/);
+
+int
+der_copy_printable_string (
+       const heim_printable_string */*from*/,
+       heim_printable_string */*to*/);
+
+int
+der_copy_universal_string (
+       const heim_universal_string */*from*/,
+       heim_universal_string */*to*/);
+
+int
+der_copy_utf8string (
+       const heim_utf8_string */*from*/,
+       heim_utf8_string */*to*/);
+
+void
+der_free_bit_string (heim_bit_string */*k*/);
+
+void
+der_free_bmp_string (heim_bmp_string */*k*/);
+
+void
+der_free_general_string (heim_general_string */*str*/);
+
+void
+der_free_heim_integer (heim_integer */*k*/);
+
+void
+der_free_ia5_string (heim_ia5_string */*str*/);
+
+void
+der_free_octet_string (heim_octet_string */*k*/);
+
+void
+der_free_oid (heim_oid */*k*/);
+
+void
+der_free_printable_string (heim_printable_string */*str*/);
+
+void
+der_free_universal_string (heim_universal_string */*k*/);
+
+void
+der_free_utf8string (heim_utf8_string */*str*/);
+
+int
+der_get_bit_string (
+       const unsigned char */*p*/,
+       size_t /*len*/,
+       heim_bit_string */*data*/,
+       size_t */*size*/);
+
+int
+der_get_bmp_string (
+       const unsigned char */*p*/,
+       size_t /*len*/,
+       heim_bmp_string */*data*/,
+       size_t */*size*/);
+
+int
+der_get_boolean (
+       const unsigned char */*p*/,
+       size_t /*len*/,
+       int */*data*/,
+       size_t */*size*/);
+
+const char *
+der_get_class_name (unsigned /*num*/);
+
+int
+der_get_class_num (const char */*name*/);
+
+int
+der_get_general_string (
+       const unsigned char */*p*/,
+       size_t /*len*/,
+       heim_general_string */*str*/,
+       size_t */*size*/);
+
+int
+der_get_generalized_time (
+       const unsigned char */*p*/,
+       size_t /*len*/,
+       time_t */*data*/,
+       size_t */*size*/);
+
+int
+der_get_heim_integer (
+       const unsigned char */*p*/,
+       size_t /*len*/,
+       heim_integer */*data*/,
+       size_t */*size*/);
+
+int
+der_get_ia5_string (
+       const unsigned char */*p*/,
+       size_t /*len*/,
+       heim_ia5_string */*str*/,
+       size_t */*size*/);
+
+int
+der_get_integer (
+       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_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_printable_string (
+       const unsigned char */*p*/,
+       size_t /*len*/,
+       heim_printable_string */*str*/,
+       size_t */*size*/);
+
+int
+der_get_tag (
+       const unsigned char */*p*/,
+       size_t /*len*/,
+       Der_class */*class*/,
+       Der_type */*type*/,
+       unsigned int */*tag*/,
+       size_t */*size*/);
+
+const char *
+der_get_tag_name (unsigned /*num*/);
+
+int
+der_get_tag_num (const char */*name*/);
+
+const char *
+der_get_type_name (unsigned /*num*/);
+
+int
+der_get_type_num (const char */*name*/);
+
+int
+der_get_universal_string (
+       const unsigned char */*p*/,
+       size_t /*len*/,
+       heim_universal_string */*data*/,
+       size_t */*size*/);
+
+int
+der_get_unsigned (
+       const unsigned char */*p*/,
+       size_t /*len*/,
+       unsigned */*ret*/,
+       size_t */*size*/);
+
+int
+der_get_utctime (
+       const unsigned char */*p*/,
+       size_t /*len*/,
+       time_t */*data*/,
+       size_t */*size*/);
+
+int
+der_get_utf8string (
+       const unsigned char */*p*/,
+       size_t /*len*/,
+       heim_utf8_string */*str*/,
+       size_t */*size*/);
+
+int
+der_heim_bit_string_cmp (
+       const heim_bit_string */*p*/,
+       const heim_bit_string */*q*/);
+
+int
+der_heim_bmp_string_cmp (
+       const heim_bmp_string */*p*/,
+       const heim_bmp_string */*q*/);
+
+int
+der_heim_integer_cmp (
+       const heim_integer */*p*/,
+       const heim_integer */*q*/);
+
+int
+der_heim_octet_string_cmp (
+       const heim_octet_string */*p*/,
+       const heim_octet_string */*q*/);
+
+int
+der_heim_oid_cmp (
+       const heim_oid */*p*/,
+       const heim_oid */*q*/);
+
+int
+der_heim_universal_string_cmp (
+       const heim_universal_string */*p*/,
+       const heim_universal_string */*q*/);
+
+size_t
+der_length_bit_string (const heim_bit_string */*k*/);
+
+size_t
+der_length_bmp_string (const heim_bmp_string */*data*/);
+
+size_t
+der_length_boolean (const int */*k*/);
+
+size_t
+der_length_enumerated (const unsigned */*data*/);
+
+size_t
+der_length_general_string (const heim_general_string */*data*/);
+
+size_t
+der_length_generalized_time (const time_t */*t*/);
+
+size_t
+der_length_heim_integer (const heim_integer */*k*/);
+
+size_t
+der_length_ia5_string (const heim_ia5_string */*data*/);
+
+size_t
+der_length_integer (const int */*data*/);
+
+size_t
+der_length_len (size_t /*len*/);
+
+size_t
+der_length_octet_string (const heim_octet_string */*k*/);
+
+size_t
+der_length_oid (const heim_oid */*k*/);
+
+size_t
+der_length_printable_string (const heim_printable_string */*data*/);
+
+size_t
+der_length_universal_string (const heim_universal_string */*data*/);
+
+size_t
+der_length_unsigned (const unsigned */*data*/);
+
+size_t
+der_length_utctime (const time_t */*t*/);
+
+size_t
+der_length_utf8string (const heim_utf8_string */*data*/);
+
+int
+der_match_tag (
+       const unsigned char */*p*/,
+       size_t /*len*/,
+       Der_class /*class*/,
+       Der_type /*type*/,
+       unsigned int /*tag*/,
+       size_t */*size*/);
+
+int
+der_match_tag_and_length (
+       const unsigned char */*p*/,
+       size_t /*len*/,
+       Der_class /*class*/,
+       Der_type /*type*/,
+       unsigned int /*tag*/,
+       size_t */*length_ret*/,
+       size_t */*size*/);
+
+int
+der_parse_heim_oid (
+       const char */*str*/,
+       const char */*sep*/,
+       heim_oid */*data*/);
+
+int
+der_parse_hex_heim_integer (
+       const char */*p*/,
+       heim_integer */*data*/);
+
+int
+der_print_heim_oid (
+       const heim_oid */*oid*/,
+       char /*delim*/,
+       char **/*str*/);
+
+int
+der_print_hex_heim_integer (
+       const heim_integer */*data*/,
+       char **/*p*/);
+
+int
+der_put_bit_string (
+       unsigned char */*p*/,
+       size_t /*len*/,
+       const heim_bit_string */*data*/,
+       size_t */*size*/);
+
+int
+der_put_bmp_string (
+       unsigned char */*p*/,
+       size_t /*len*/,
+       const heim_bmp_string */*data*/,
+       size_t */*size*/);
+
+int
+der_put_boolean (
+       unsigned char */*p*/,
+       size_t /*len*/,
+       const int */*data*/,
+       size_t */*size*/);
+
+int
+der_put_general_string (
+       unsigned char */*p*/,
+       size_t /*len*/,
+       const heim_general_string */*str*/,
+       size_t */*size*/);
+
+int
+der_put_generalized_time (
+       unsigned char */*p*/,
+       size_t /*len*/,
+       const time_t */*data*/,
+       size_t */*size*/);
+
+int
+der_put_heim_integer (
+       unsigned char */*p*/,
+       size_t /*len*/,
+       const heim_integer */*data*/,
+       size_t */*size*/);
+
+int
+der_put_ia5_string (
+       unsigned char */*p*/,
+       size_t /*len*/,
+       const heim_ia5_string */*str*/,
+       size_t */*size*/);
+
+int
+der_put_integer (
+       unsigned char */*p*/,
+       size_t /*len*/,
+       const int */*v*/,
+       size_t */*size*/);
+
+int
+der_put_length (
+       unsigned char */*p*/,
+       size_t /*len*/,
+       size_t /*val*/,
+       size_t */*size*/);
+
+int
+der_put_length_and_tag (
+       unsigned char */*p*/,
+       size_t /*len*/,
+       size_t /*len_val*/,
+       Der_class /*class*/,
+       Der_type /*type*/,
+       unsigned int /*tag*/,
+       size_t */*size*/);
+
+int
+der_put_octet_string (
+       unsigned char */*p*/,
+       size_t /*len*/,
+       const heim_octet_string */*data*/,
+       size_t */*size*/);
+
+int
+der_put_oid (
+       unsigned char */*p*/,
+       size_t /*len*/,
+       const heim_oid */*data*/,
+       size_t */*size*/);
+
+int
+der_put_printable_string (
+       unsigned char */*p*/,
+       size_t /*len*/,
+       const heim_printable_string */*str*/,
+       size_t */*size*/);
+
+int
+der_put_tag (
+       unsigned char */*p*/,
+       size_t /*len*/,
+       Der_class /*class*/,
+       Der_type /*type*/,
+       unsigned int /*tag*/,
+       size_t */*size*/);
+
+int
+der_put_universal_string (
+       unsigned char */*p*/,
+       size_t /*len*/,
+       const heim_universal_string */*data*/,
+       size_t */*size*/);
+
+int
+der_put_unsigned (
+       unsigned char */*p*/,
+       size_t /*len*/,
+       const unsigned */*v*/,
+       size_t */*size*/);
+
+int
+der_put_utctime (
+       unsigned char */*p*/,
+       size_t /*len*/,
+       const time_t */*data*/,
+       size_t */*size*/);
+
+int
+der_put_utf8string (
+       unsigned char */*p*/,
+       size_t /*len*/,
+       const heim_utf8_string */*str*/,
+       size_t */*size*/);
+
+int
+encode_heim_any (
+       unsigned char */*p*/,
+       size_t /*len*/,
+       const heim_any */*data*/,
+       size_t */*size*/);
+
+int
+encode_heim_any_set (
+       unsigned char */*p*/,
+       size_t /*len*/,
+       const heim_any_set */*data*/,
+       size_t */*size*/);
+
+void
+free_heim_any (heim_any */*data*/);
+
+void
+free_heim_any_set (heim_any_set */*data*/);
+
+int
+heim_any_cmp (
+       const heim_any_set */*p*/,
+       const heim_any_set */*q*/);
+
+size_t
+length_heim_any (const heim_any */*data*/);
+
+size_t
+length_heim_any_set (const heim_any */*data*/);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __der_protos_h__ */
index b9c2b470792d7fbcefe3e2c78884ec9fb0412ddd..b0170e35fe534bc1a5f76ae48c41deb81216e299 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1997 - 2005 Kungliga Tekniska Högskolan
+ * Copyright (c) 1997 - 2006 Kungliga Tekniska Högskolan
  * (Royal Institute of Technology, Stockholm, Sweden). 
  * All rights reserved. 
  *
@@ -31,7 +31,7 @@
  * SUCH DAMAGE. 
  */
 
-/* $Id: der.h,v 1.32 2006/01/30 15:25:25 lha Exp $ */
+/* $Id: der.h,v 1.36 2006/10/14 05:16:08 lha Exp $ */
 
 #ifndef __DER_H__
 #define __DER_H__
@@ -83,164 +83,21 @@ enum {
 
 #define ASN1_INDEFINITE 0xdce0deed
 
-typedef struct asn1_der_time_t {
+typedef struct heim_der_time_t {
     time_t dt_sec;
     unsigned long dt_nsec;
-} asn1_der_time_t;
+} heim_der_time_t;
 
-typedef struct asn1_ber_time_t {
+typedef struct heim_ber_time_t {
     time_t bt_sec;
     unsigned bt_nsec;
     int bt_zone;
-} asn1_ber_time_t;
+} heim_ber_time_t;
 
-int der_get_unsigned (const unsigned char *p, size_t len,
-                     unsigned *ret, size_t *size);
-int der_get_integer (const unsigned char *p, size_t len,
-                    int *ret, size_t *size);
-int der_get_heim_integer (const unsigned char *p, size_t len,
-                         heim_integer *ret, size_t *size);
-int der_get_boolean(const unsigned char *p, size_t len,
-                   int *data, size_t *size);
-int der_get_length (const unsigned char *p, size_t len,
-                   size_t *val, 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_utf8string (const unsigned char *p, size_t len, 
-                           heim_utf8_string *str, size_t *size);
-int der_get_universal_string (const unsigned char *p, size_t len, 
-                            heim_universal_string *str, size_t *size);
-int der_get_bmp_string (const unsigned char *p, size_t len, 
-                       heim_bmp_string *str, size_t *size);
-int der_get_printable_string (const unsigned char *p, size_t len, 
-                           heim_printable_string *str, size_t *size);
-int der_get_ia5_string (const unsigned char *p, size_t len,
-                       heim_ia5_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_generalized_time (const unsigned char *p, size_t len, 
-                             time_t *data, size_t *size);
-int der_get_generalized_time_der (const unsigned char *p, size_t len, 
-                                 asn1_der_time_t *data, size_t *size);
-int der_get_generalized_time_ber (const unsigned char *p, size_t len, 
-                                 asn1_ber_time_t *data, size_t *size);
-int der_get_utctime (const unsigned char *p, size_t len, 
-                    time_t *data, size_t *size);
-int der_get_oid (const unsigned char *p, size_t len,
-                heim_oid *data, size_t *size);
-int der_get_bit_string (const unsigned char *p, size_t len,
-                       heim_bit_string *data, size_t *size);
-int der_get_tag (const unsigned char *p, size_t len, 
-                Der_class *class, Der_type *type,
-                unsigned int *tag, size_t *size);
-
-int der_match_tag (const unsigned char *p, size_t len, 
-                  Der_class class, Der_type type,
-                  unsigned int tag, size_t *size);
-int der_match_tag_and_length (const unsigned char *p, size_t len,
-                             Der_class class, Der_type type, unsigned int tag,
-                             size_t *length_ret, size_t *size);
-
-int der_put_unsigned (unsigned char *p, size_t len, const unsigned *val, size_t*);
-int der_put_integer (unsigned char *p, size_t len, const int *val, size_t*);
-int der_put_heim_integer (unsigned char *p, size_t len, 
-                         const heim_integer *val, size_t*);
-int der_put_boolean (unsigned char *p, size_t len, const int *val, size_t*);
-
-int der_put_length (unsigned char *p, size_t len, size_t val, size_t*);
-int der_put_general_string (unsigned char *p, size_t len,
-                           const heim_general_string *str, size_t*);
-int der_put_utf8string (unsigned char *p, size_t len,
-                       const heim_utf8_string *str, size_t*);
-int der_put_universal_string (unsigned char *p, size_t len,
-                             const heim_universal_string *str, size_t*);
-int der_put_bmp_string (unsigned char *p, size_t len,
-                           const heim_bmp_string *str, size_t*);
-int der_put_printable_string (unsigned char *p, size_t len,
-                           const heim_printable_string *str, size_t*);
-int der_put_ia5_string (unsigned char *p, size_t len,
-                       const heim_ia5_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_generalized_time (unsigned char *p, size_t len, 
-                             const time_t *data, size_t *size);
-int der_put_utctime (unsigned char *p, size_t len, 
-                    const time_t *data, size_t *size);
-int der_put_oid (unsigned char *p, size_t len,
-                const heim_oid *data, size_t *size);
-int der_put_bit_string (unsigned char *p, size_t len,
-                       const heim_bit_string *data, size_t *size);
-int der_put_tag (unsigned char *p, size_t len, Der_class class, Der_type type,
-                unsigned int tag, size_t*);
-int der_put_length_and_tag (unsigned char*, size_t, size_t, 
-                           Der_class, Der_type, unsigned int, size_t*);
-
-void free_integer (int *num);
-void free_heim_integer (heim_integer *num);
-void free_octet_string (heim_octet_string *k);
-void free_general_string (heim_general_string *str);
-void free_octet_string (heim_octet_string *k);
-void free_oid (heim_oid *k);
-void free_bit_string (heim_bit_string *k);
-void free_generalized_time (time_t *t);
-void free_utctime (time_t *t);
-void free_utf8string (heim_utf8_string*);
-void free_printable_string (heim_printable_string*);
-void free_ia5_string (heim_ia5_string*);
-void free_universal_string (heim_universal_string*);
-void free_bmp_string (heim_bmp_string*);
-
-size_t length_len (size_t len);
-size_t length_integer (const int *data);
-size_t length_heim_integer (const heim_integer *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_bit_string (const heim_bit_string *k);
-size_t length_generalized_time (const time_t *t);
-size_t length_utctime (const time_t *t);
-size_t length_utf8string (const heim_utf8_string*);
-size_t length_printable_string (const heim_printable_string*);
-size_t length_ia5_string (const heim_ia5_string*);
-size_t length_bmp_string (const heim_bmp_string*);
-size_t length_universal_string (const heim_universal_string*);
-size_t length_boolean (const int*);
-
-int copy_heim_integer (const heim_integer *, heim_integer *);
-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_bit_string (const heim_bit_string *from, heim_bit_string *to);
-int copy_utf8string (const heim_utf8_string*, heim_utf8_string*);
-int copy_printable_string (const heim_printable_string*,heim_printable_string*);
-int copy_ia5_string (const heim_ia5_string*,heim_ia5_string*);
-int copy_universal_string(const heim_universal_string*,heim_universal_string*);
-int copy_bmp_string (const heim_bmp_string*,heim_bmp_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 heim_bit_string_cmp(const heim_bit_string *, const heim_bit_string *);
-int heim_integer_cmp(const heim_integer *, const heim_integer *);
-int heim_bmp_string_cmp(const heim_bmp_string *, const heim_bmp_string *);
-int heim_universal_string_cmp(const heim_universal_string *, 
-                             const heim_universal_string *);
-
-int der_parse_oid(const char *, heim_oid *);
+#include <der-protos.h>
 
 int _heim_fix_dce(size_t reallen, size_t *len);
 int _heim_der_set_sort(const void *, const void *);
 int _heim_time2generalizedtime (time_t, heim_octet_string *, int);
 
-const char *   der_get_class_name(unsigned);
-int            der_get_class_num(const char *);
-const char *   der_get_type_name(unsigned);
-int            der_get_type_num(const char *);
-const char *   der_get_tag_name(unsigned);
-int            der_get_tag_num(const char *);
-
-int            der_parse_hex_heim_integer(const char *, heim_integer *);
-int            der_print_hex_heim_integer(const heim_integer *, char **);
-
 #endif /* __DER_H__ */
index 2471312ba81a70fd52e367a5d062ae27ae8775be..f27f03c02bd3a0c3ca734fa913ef526f8d5ec459 100755 (executable)
@@ -34,7 +34,7 @@
 #include "der_locl.h"
 
 int
-heim_oid_cmp(const heim_oid *p, const heim_oid *q)
+der_heim_oid_cmp(const heim_oid *p, const heim_oid *q)
 {
     if (p->length != q->length)
        return p->length - q->length;
@@ -44,7 +44,8 @@ heim_oid_cmp(const heim_oid *p, const heim_oid *q)
 }
 
 int
-heim_octet_string_cmp(const heim_octet_string *p, const heim_octet_string *q)
+der_heim_octet_string_cmp(const heim_octet_string *p, 
+                         const heim_octet_string *q)
 {
     if (p->length != q->length)
        return p->length - q->length;
@@ -52,7 +53,8 @@ heim_octet_string_cmp(const heim_octet_string *p, const heim_octet_string *q)
 }
 
 int
-heim_bit_string_cmp(const heim_bit_string *p, const heim_bit_string *q)
+der_heim_bit_string_cmp(const heim_bit_string *p,
+                       const heim_bit_string *q)
 {
     int i, r1, r2;
     if (p->length != q->length)
@@ -72,7 +74,8 @@ heim_bit_string_cmp(const heim_bit_string *p, const heim_bit_string *q)
 }
 
 int
-heim_integer_cmp(const heim_integer *p, const heim_integer *q)
+der_heim_integer_cmp(const heim_integer *p,
+                    const heim_integer *q)
 {
     if (p->negative != q->negative)
        return q->negative - p->negative;
@@ -82,7 +85,7 @@ heim_integer_cmp(const heim_integer *p, const heim_integer *q)
 }
 
 int
-heim_bmp_string_cmp(const heim_bmp_string *p, const heim_bmp_string *q)
+der_heim_bmp_string_cmp(const heim_bmp_string *p, const heim_bmp_string *q)
 {
     if (p->length != q->length)
        return p->length - q->length;
@@ -90,8 +93,8 @@ heim_bmp_string_cmp(const heim_bmp_string *p, const heim_bmp_string *q)
 }
 
 int
-heim_universal_string_cmp(const heim_universal_string *p, 
-                         const heim_universal_string *q)
+der_heim_universal_string_cmp(const heim_universal_string *p, 
+                             const heim_universal_string *q)
 {
     if (p->length != q->length)
        return p->length - q->length;
index e0443eed39cc412c0b93b079af28b9e0d7b62b27..96eea9c6d7c99416346417624b6223c3d04ecdce 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1997 - 2005 Kungliga Tekniska Högskolan
+ * Copyright (c) 1997 - 2006 Kungliga Tekniska Högskolan
  * (Royal Institute of Technology, Stockholm, Sweden). 
  * All rights reserved. 
  *
 
 #include "der_locl.h"
 
-RCSID("$Id: der_copy.c,v 1.14 2006/01/04 23:41:29 lha Exp $");
+RCSID("$Id: der_copy.c,v 1.16 2006/10/14 05:30:02 lha Exp $");
 
 int
-copy_general_string (const heim_general_string *from, heim_general_string *to)
+der_copy_general_string (const heim_general_string *from, 
+                        heim_general_string *to)
 {
     *to = strdup(*from);
     if(*to == NULL)
@@ -45,27 +46,27 @@ copy_general_string (const heim_general_string *from, heim_general_string *to)
 }
 
 int
-copy_utf8string (const heim_utf8_string *from, heim_utf8_string *to)
+der_copy_utf8string (const heim_utf8_string *from, heim_utf8_string *to)
 {
-    return copy_general_string(from, to);
+    return der_copy_general_string(from, to);
 }
 
 int
-copy_printable_string (const heim_printable_string *from, 
+der_copy_printable_string (const heim_printable_string *from, 
                       heim_printable_string *to)
 {
-    return copy_general_string(from, to);
+    return der_copy_general_string(from, to);
 }
 
 int
-copy_ia5_string (const heim_printable_string *from, 
-                      heim_printable_string *to)
+der_copy_ia5_string (const heim_printable_string *from, 
+                    heim_printable_string *to)
 {
-    return copy_general_string(from, to);
+    return der_copy_general_string(from, to);
 }
 
 int
-copy_bmp_string (const heim_bmp_string *from, heim_bmp_string *to)
+der_copy_bmp_string (const heim_bmp_string *from, heim_bmp_string *to)
 {
     to->length = from->length;
     to->data   = malloc(to->length * sizeof(to->data[0]));
@@ -76,8 +77,8 @@ copy_bmp_string (const heim_bmp_string *from, heim_bmp_string *to)
 }
 
 int
-copy_universal_string (const heim_universal_string *from,
-                      heim_universal_string *to)
+der_copy_universal_string (const heim_universal_string *from,
+                          heim_universal_string *to)
 {
     to->length = from->length;
     to->data   = malloc(to->length * sizeof(to->data[0]));
@@ -88,7 +89,7 @@ copy_universal_string (const heim_universal_string *from,
 }
 
 int
-copy_octet_string (const heim_octet_string *from, heim_octet_string *to)
+der_copy_octet_string (const heim_octet_string *from, heim_octet_string *to)
 {
     to->length = from->length;
     to->data   = malloc(to->length);
@@ -99,7 +100,7 @@ copy_octet_string (const heim_octet_string *from, heim_octet_string *to)
 }
 
 int
-copy_heim_integer (const heim_integer *from, heim_integer *to)
+der_copy_heim_integer (const heim_integer *from, heim_integer *to)
 {
     to->length = from->length;
     to->data   = malloc(to->length);
@@ -111,7 +112,7 @@ copy_heim_integer (const heim_integer *from, heim_integer *to)
 }
 
 int
-copy_oid (const heim_oid *from, heim_oid *to)
+der_copy_oid (const heim_oid *from, heim_oid *to)
 {
     to->length     = from->length;
     to->components = malloc(to->length * sizeof(*to->components));
@@ -123,7 +124,7 @@ copy_oid (const heim_oid *from, heim_oid *to)
 }
 
 int
-copy_bit_string (const heim_bit_string *from, heim_bit_string *to)
+der_copy_bit_string (const heim_bit_string *from, heim_bit_string *to)
 {
     size_t len;
 
index 44e39b46c590354b817b7de7c0b2edd4cccfa709..9655269356d6a7716aa9ff21fd2ef97d004906cd 100644 (file)
@@ -34,7 +34,7 @@
 #include "der_locl.h"
 #include <hex.h>
 
-RCSID("$Id: der_format.c,v 1.2 2006/01/16 23:01:11 lha Exp $");
+RCSID("$Id: der_format.c,v 1.6 2006/10/21 18:24:15 lha Exp $");
 
 int
 der_parse_hex_heim_integer (const char *p, heim_integer *data)
@@ -73,13 +73,13 @@ der_parse_hex_heim_integer (const char *p, heim_integer *data)
     }
 
     {
-       unsigned char *p = data->data;
-       while(*p == 0 && len > 0) {
-           p++;
+       unsigned char *q = data->data;
+       while(*q == 0 && len > 0) {
+           q++;
            len--;
        }
        data->length = len;
-       memmove(data->data, p, len);
+       memmove(data->data, q, len);
     }
     return 0;
 }
@@ -103,3 +103,65 @@ der_print_hex_heim_integer (const heim_integer *data, char **p)
     }
     return 0;
 }
+
+int
+der_print_heim_oid (const heim_oid *oid, char delim, char **str)
+{
+    struct rk_strpool *p = NULL;
+    int i;
+
+    for (i = 0; i < oid->length ; i++) {
+       p = rk_strpoolprintf(p, "%d%s", 
+                            oid->components[i],
+                            i < oid->length - 1 ? " " : "");
+       if (p == NULL) {
+           *str = NULL;
+           return ENOMEM;
+       }
+    }
+
+    *str = rk_strpoolcollect(p);
+    if (*str == NULL)
+       return ENOMEM;
+    return 0;
+}
+
+int
+der_parse_heim_oid (const char *str, const char *sep, heim_oid *data)
+{
+    char *s, *w, *brkt, *endptr;
+    unsigned int *c;
+    long l;
+
+    data->length = 0;
+    data->components = NULL;
+
+    if (sep == NULL)
+       sep = ".";
+
+    s = strdup(str);
+
+    for (w = strtok_r(s, sep, &brkt); 
+        w != NULL; 
+        w = strtok_r(NULL, sep, &brkt)) {
+
+       c = realloc(data->components,
+                   (data->length + 1) * sizeof(data->components[0]));
+       if (c == NULL) {
+           der_free_oid(data);
+           free(s);
+           return ENOMEM;
+       }
+       data->components = c;
+
+       l = strtol(w, &endptr, 10);
+       if (*endptr != '\0' || l < 0 || l > INT_MAX) {
+           der_free_oid(data);
+           free(s);
+           return EINVAL;
+       }
+       data->components[data->length++] = l;
+    }
+    free(s);
+    return 0;
+}
index 8959c3b1c3b9521bdb799af3cfe45b118b6122a9..c3a6a17fff730923cee5c3f0d4f34d196ea101b0 100644 (file)
 
 #include "der_locl.h"
 
-RCSID("$Id: der_free.c,v 1.11 2005/07/12 06:27:21 lha Exp $");
+RCSID("$Id: der_free.c,v 1.13 2006/10/14 05:30:47 lha Exp $");
 
 void
-free_general_string (heim_general_string *str)
+der_free_general_string (heim_general_string *str)
 {
     free(*str);
     *str = NULL;
 }
 
 void
-free_utf8string (heim_utf8_string *str)
+der_free_utf8string (heim_utf8_string *str)
 {
     free(*str);
     *str = NULL;
 }
 
 void
-free_printable_string (heim_printable_string *str)
+der_free_printable_string (heim_printable_string *str)
 {
     free(*str);
     *str = NULL;
 }
 
 void
-free_ia5_string (heim_ia5_string *str)
+der_f