From 17ffdd0e93271072369e479f440ddf85e020580a Mon Sep 17 00:00:00 2001 From: Greg Hudson Date: Fri, 9 Oct 2009 18:29:34 +0000 Subject: [PATCH] Implement GSS naming extensions and authdata verification Merge Luke's users/lhoward/authdata branch to trunk. Implements GSS naming extensions and verification of authorization data. ticket: 6572 git-svn-id: svn://anonsvn.mit.edu/krb5/trunk@22875 dc483132-0cff-0310-8789-dd5450dbe970 --- src/clients/klist/klist.c | 27 +- src/configure.in | 2 + src/include/k5-int.h | 124 ++ src/include/kdb_ext.h | 1 + src/include/krb5/authdata_plugin.h | 181 ++- src/include/krb5/krb5.hin | 16 + src/kdc/do_tgs_req.c | 8 +- src/kdc/kdc_authdata.c | 47 +- src/kdc/kdc_util.c | 2 + src/kdc/kdc_util.h | 1 + src/lib/crypto/krb/enc_provider/Makefile.in | 41 + src/lib/crypto/krb/enc_provider/aes.c | 415 ++++++ src/lib/crypto/krb/enc_provider/deps | 49 + src/lib/crypto/krb/enc_provider/des.c | 181 +++ src/lib/crypto/krb/enc_provider/des3.c | 221 +++ .../crypto/krb/enc_provider/enc_provider.h | 36 + src/lib/crypto/krb/enc_provider/rc4.c | 271 ++++ src/lib/crypto/openssl/sha1/shs.c | 2 +- src/lib/crypto/openssl/sha1/shs.h | 2 +- src/lib/gssapi/generic/gssapi_ext.h | 75 +- src/lib/gssapi/krb5/Makefile.in | 3 + src/lib/gssapi/krb5/accept_sec_context.c | 57 +- src/lib/gssapi/krb5/acquire_cred.c | 87 +- src/lib/gssapi/krb5/add_cred.c | 39 +- src/lib/gssapi/krb5/compare_name.c | 5 +- src/lib/gssapi/krb5/delete_sec_context.c | 4 +- src/lib/gssapi/krb5/disp_name.c | 3 +- src/lib/gssapi/krb5/duplicate_name.c | 15 +- src/lib/gssapi/krb5/export_name.c | 2 +- src/lib/gssapi/krb5/gssapiP_krb5.h | 93 +- src/lib/gssapi/krb5/gssapi_krb5.c | 8 + src/lib/gssapi/krb5/import_name.c | 106 +- src/lib/gssapi/krb5/init_sec_context.c | 61 +- src/lib/gssapi/krb5/inq_context.c | 34 +- src/lib/gssapi/krb5/inq_cred.c | 20 +- src/lib/gssapi/krb5/naming_exts.c | 722 ++++++++++ src/lib/gssapi/krb5/rel_cred.c | 4 +- src/lib/gssapi/krb5/rel_name.c | 5 +- src/lib/gssapi/krb5/s4u_gss_glue.c | 46 +- src/lib/gssapi/krb5/ser_sctx.c | 91 +- src/lib/gssapi/krb5/val_cred.c | 2 +- src/lib/gssapi/libgssapi_krb5.exports | 8 + src/lib/gssapi/mechglue/Makefile.in | 24 + src/lib/gssapi/mechglue/g_del_name_attr.c | 70 + src/lib/gssapi/mechglue/g_dsp_name.c | 7 +- src/lib/gssapi/mechglue/g_dsp_name_ext.c | 131 ++ src/lib/gssapi/mechglue/g_export_name_comp.c | 73 + src/lib/gssapi/mechglue/g_get_name_attr.c | 89 ++ src/lib/gssapi/mechglue/g_glue.c | 77 +- src/lib/gssapi/mechglue/g_imp_name.c | 5 +- src/lib/gssapi/mechglue/g_initialize.c | 11 +- src/lib/gssapi/mechglue/g_inq_context_oid.c | 4 +- src/lib/gssapi/mechglue/g_inq_cred_oid.c | 12 +- src/lib/gssapi/mechglue/g_inq_name.c | 101 ++ src/lib/gssapi/mechglue/g_map_name_to_any.c | 80 ++ src/lib/gssapi/mechglue/g_rel_name_mapping.c | 78 ++ .../gssapi/mechglue/g_set_context_option.c | 5 +- src/lib/gssapi/mechglue/g_set_cred_option.c | 12 +- src/lib/gssapi/mechglue/g_set_name_attr.c | 74 + src/lib/gssapi/mechglue/mglueP.h | 69 + src/lib/gssapi/spnego/gssapiP_spnego.h | 77 + src/lib/gssapi/spnego/spnego_mech.c | 131 ++ src/lib/krb5/asn.1/asn1_k_decode.c | 26 +- src/lib/krb5/asn.1/asn1_k_decode.h | 6 + src/lib/krb5/asn.1/asn1_k_encode.c | 19 +- src/lib/krb5/asn.1/krb5_decode.c | 11 + src/lib/krb5/ccache/cc_file.c | 4 +- src/lib/krb5/ccache/ccfns.c | 4 +- src/lib/krb5/error_tables/kv5m_err.et | 1 + src/lib/krb5/krb/Makefile.in | 11 +- src/lib/krb5/krb/auth_con.c | 20 + src/lib/krb5/krb/auth_con.h | 1 + src/lib/krb5/krb/authdata.c | 1245 +++++++++++++++++ src/lib/krb5/krb/authdata.h | 48 + src/lib/krb5/krb/copy_auth.c | 123 ++ src/lib/krb5/krb/gc_frm_kdc.c | 31 +- src/lib/krb5/krb/int-proto.h | 1 + src/lib/krb5/krb/kfree.c | 30 +- src/lib/krb5/krb/mk_req_ext.c | 40 +- src/lib/krb5/krb/pac.c | 730 +++++++++- src/lib/krb5/krb/rd_req.c | 22 +- src/lib/krb5/krb/rd_req_dec.c | 69 +- src/lib/krb5/krb/s4u_creds.c | 2 +- src/lib/krb5/krb/ser_actx.c | 2 + src/lib/krb5/krb/t_authdata.c | 16 +- src/lib/krb5/libkrb5.exports | 20 + src/plugins/authdata/greet_client/Makefile.in | 38 + src/plugins/authdata/greet_client/deps | 6 + src/plugins/authdata/greet_client/greet.c | 379 +++++ .../greet_client/greet_client.exports | 1 + src/plugins/authdata/greet_server/Makefile.in | 38 + src/plugins/authdata/greet_server/deps | 6 + .../authdata/greet_server/greet_auth.c | 191 +++ .../greet_server/greet_server.exports | 1 + src/tests/asn.1/krb5_decode_leak.c | 12 +- src/tests/asn.1/krb5_decode_test.c | 10 + src/tests/asn.1/krb5_encode_test.c | 12 +- src/tests/asn.1/ktest.c | 21 + src/tests/asn.1/ktest.h | 2 + src/tests/asn.1/ktest_equal.c | 14 + src/tests/asn.1/ktest_equal.h | 4 + src/tests/asn.1/reference_encode.out | 1 + src/tests/asn.1/trval_reference.out | 20 + src/tests/gssapi/Makefile.in | 11 +- src/tests/gssapi/t_namingexts.c | 488 +++++++ src/tests/gssapi/t_s4u.c | 135 +- 106 files changed, 7739 insertions(+), 380 deletions(-) create mode 100644 src/lib/crypto/krb/enc_provider/Makefile.in create mode 100644 src/lib/crypto/krb/enc_provider/aes.c create mode 100644 src/lib/crypto/krb/enc_provider/deps create mode 100644 src/lib/crypto/krb/enc_provider/des.c create mode 100644 src/lib/crypto/krb/enc_provider/des3.c create mode 100644 src/lib/crypto/krb/enc_provider/enc_provider.h create mode 100644 src/lib/crypto/krb/enc_provider/rc4.c create mode 100644 src/lib/gssapi/krb5/naming_exts.c create mode 100644 src/lib/gssapi/mechglue/g_del_name_attr.c create mode 100644 src/lib/gssapi/mechglue/g_dsp_name_ext.c create mode 100644 src/lib/gssapi/mechglue/g_export_name_comp.c create mode 100644 src/lib/gssapi/mechglue/g_get_name_attr.c create mode 100644 src/lib/gssapi/mechglue/g_inq_name.c create mode 100644 src/lib/gssapi/mechglue/g_map_name_to_any.c create mode 100644 src/lib/gssapi/mechglue/g_rel_name_mapping.c create mode 100644 src/lib/gssapi/mechglue/g_set_name_attr.c create mode 100644 src/lib/krb5/krb/authdata.c create mode 100644 src/lib/krb5/krb/authdata.h create mode 100644 src/plugins/authdata/greet_client/Makefile.in create mode 100644 src/plugins/authdata/greet_client/deps create mode 100644 src/plugins/authdata/greet_client/greet.c create mode 100644 src/plugins/authdata/greet_client/greet_client.exports create mode 100644 src/plugins/authdata/greet_server/Makefile.in create mode 100644 src/plugins/authdata/greet_server/deps create mode 100644 src/plugins/authdata/greet_server/greet_auth.c create mode 100644 src/plugins/authdata/greet_server/greet_server.exports create mode 100644 src/tests/gssapi/t_namingexts.c diff --git a/src/clients/klist/klist.c b/src/clients/klist/klist.c index c20aa9801..9e93f7b35 100644 --- a/src/clients/klist/klist.c +++ b/src/clients/klist/klist.c @@ -57,6 +57,7 @@ extern int optind; int show_flags = 0, show_time = 0, status_only = 0, show_keys = 0; int show_etype = 0, show_addresses = 0, no_resolve = 0, print_version = 0; +int show_adtype = 0; char *defname; char *progname; krb5_int32 now; @@ -81,7 +82,7 @@ static void usage() { #define KRB_AVAIL_STRING(x) ((x)?"available":"not available") - fprintf(stderr, "Usage: %s [-e] [-V] [[-c] [-f] [-s] [-a [-n]]] %s", + fprintf(stderr, "Usage: %s [-e] [-V] [[-c] [-d] [-f] [-s] [-a [-n]]] %s", progname, "[-k [-t] [-K]] [name]\n"); fprintf(stderr, "\t-c specifies credentials cache\n"); fprintf(stderr, "\t-k specifies keytab\n"); @@ -89,6 +90,7 @@ static void usage() fprintf(stderr, "\t-e shows the encryption type\n"); fprintf(stderr, "\t-V shows the Kerberos version and exits\n"); fprintf(stderr, "\toptions for credential caches:\n"); + fprintf(stderr, "\t\t-d shows the submitted authorization data types\n"); fprintf(stderr, "\t\t-f shows credentials flags\n"); fprintf(stderr, "\t\t-s sets exit status based on valid tgt existence\n"); fprintf(stderr, "\t\t-a displays the address list\n"); @@ -113,8 +115,11 @@ main(argc, argv) name = NULL; mode = DEFAULT; /* V=version so v can be used for verbose later if desired. */ - while ((c = getopt(argc, argv, "fetKsnack45V")) != -1) { + while ((c = getopt(argc, argv, "dfetKsnack45V")) != -1) { switch (c) { + case 'd': + show_adtype = 1; + break; case 'f': show_flags = 1; break; @@ -570,6 +575,24 @@ show_credential(cred) krb5_free_ticket(kcontext, tkt); } + if (show_adtype) { + int i; + + if (cred->authdata != NULL) { + if (!extra_field) + fputs("\t",stdout); + else + fputs(", ",stdout); + printf("AD types: "); + for (i = 0; cred->authdata[i] != NULL; i++) { + if (i) + printf(", "); + printf("%d", cred->authdata[i]->ad_type); + } + extra_field++; + } + } + /* if any additional info was printed, extra_field is non-zero */ if (extra_field) putchar('\n'); diff --git a/src/configure.in b/src/configure.in index 415115172..af98dfbc9 100644 --- a/src/configure.in +++ b/src/configure.in @@ -1098,6 +1098,8 @@ dnl ccapi ccapi/lib ccapi/lib/unix ccapi/server ccapi/server/unix ccapi/test plugins/preauth/cksum_body plugins/preauth/encrypted_challenge plugins/preauth/wpse plugins/authdata/greet + plugins/authdata/greet_client + plugins/authdata/greet_server clients clients/klist clients/kinit clients/kvno clients/kdestroy clients/kpasswd clients/ksu diff --git a/src/include/k5-int.h b/src/include/k5-int.h index 1c8a1c92d..77221724c 100644 --- a/src/include/k5-int.h +++ b/src/include/k5-int.h @@ -1035,6 +1035,11 @@ typedef struct _krb5_fast_response { krb5_int32 nonce; } krb5_fast_response; +typedef struct _krb5_ad_kdcissued { + krb5_checksum ad_checksum; + krb5_principal i_principal; + krb5_authdata **elements; +} krb5_ad_kdcissued; typedef krb5_error_code (*krb5_preauth_obtain_proc) (krb5_context, @@ -1345,11 +1350,111 @@ void KRB5_CALLCONV krb5_free_fast_finished (krb5_context, krb5_fast_finished *); void KRB5_CALLCONV krb5_free_fast_response (krb5_context, krb5_fast_response *); +void KRB5_CALLCONV krb5_free_ad_kdcissued +(krb5_context, krb5_ad_kdcissued *); /* #include "krb5/wordsize.h" -- comes in through base-defs.h. */ #include "com_err.h" #include "k5-plugin.h" +#include + +struct _krb5_authdata_context { + krb5_magic magic; + int n_modules; + struct _krb5_authdata_context_module { + krb5_authdatatype ad_type; + void *plugin_context; + authdata_client_plugin_fini_proc client_fini; + krb5_flags flags; + krb5plugin_authdata_client_ftable_v0 *ftable; + authdata_client_request_init_proc client_req_init; + authdata_client_request_fini_proc client_req_fini; + const char *name; + void *request_context; + void **request_context_pp; + } *modules; + struct plugin_dir_handle plugins; +}; + +typedef struct _krb5_authdata_context *krb5_authdata_context; + +void KRB5_CALLCONV krb5int_free_data_list +(krb5_context context, krb5_data *data); + +krb5_error_code KRB5_CALLCONV krb5_authdata_context_init +(krb5_context kcontext, krb5_authdata_context *pcontext); + +void KRB5_CALLCONV +krb5_authdata_context_free +(krb5_context kcontext, krb5_authdata_context context); + +krb5_error_code KRB5_CALLCONV krb5_authdata_export_authdata +(krb5_context kcontext, + krb5_authdata_context context, + krb5_flags usage, + krb5_authdata ***pauthdata); + +krb5_error_code KRB5_CALLCONV +krb5_authdata_get_attribute_types +(krb5_context kcontext, + krb5_authdata_context context, + krb5_data **attrs); + +krb5_error_code KRB5_CALLCONV krb5_authdata_get_attribute +(krb5_context kcontext, + krb5_authdata_context context, + const krb5_data *attribute, + krb5_boolean *authenticated, + krb5_boolean *complete, + krb5_data *value, + krb5_data *display_value, + int *more); + +krb5_error_code KRB5_CALLCONV krb5_authdata_set_attribute +(krb5_context kcontext, + krb5_authdata_context context, + krb5_boolean complete, + const krb5_data *attribute, + const krb5_data *value); + +krb5_error_code KRB5_CALLCONV +krb5_authdata_delete_attribute +(krb5_context kcontext, + krb5_authdata_context context, + const krb5_data *attribute); + +krb5_error_code KRB5_CALLCONV krb5_authdata_import_attributes +(krb5_context kcontext, + krb5_authdata_context context, + krb5_flags usage, + const krb5_data *attributes); + +krb5_error_code KRB5_CALLCONV krb5_authdata_export_attributes +(krb5_context kcontext, + krb5_authdata_context context, + krb5_flags usage, + krb5_data **pattributes); + +krb5_error_code KRB5_CALLCONV krb5_authdata_export_internal +(krb5_context kcontext, + krb5_authdata_context context, + krb5_boolean restrict_authenticated, + const char *module, + void **ptr); + +krb5_error_code KRB5_CALLCONV krb5_authdata_context_copy +(krb5_context kcontext, + krb5_authdata_context src, + krb5_authdata_context *dst); + +krb5_error_code KRB5_CALLCONV krb5_authdata_free_internal +(krb5_context kcontext, + krb5_authdata_context context, + const char *module, + void *ptr); + + struct _kdb5_dal_handle; /* private, in kdb5.h */ typedef struct _kdb5_dal_handle kdb5_dal_handle; struct _kdb_log_context; @@ -1669,6 +1774,9 @@ krb5_error_code encode_krb5_pa_fx_fast_reply krb5_error_code encode_krb5_fast_response (const krb5_fast_response *, krb5_data **); +krb5_error_code encode_krb5_ad_kdcissued +(const krb5_ad_kdcissued *, krb5_data **); + /************************************************************************* * End of prototypes for krb5_encode.c *************************************************************************/ @@ -1844,6 +1952,9 @@ krb5_error_code decode_krb5_pa_fx_fast_reply krb5_error_code decode_krb5_fast_response (const krb5_data *, krb5_fast_response **); +krb5_error_code decode_krb5_ad_kdcissued +(const krb5_data *, krb5_ad_kdcissued **); + struct _krb5_key_data; /* kdb.h */ struct ldap_seqof_key_data { @@ -2686,6 +2797,7 @@ krb5_error_code krb5_rd_req_decoded_anyflag krb5_keytab, krb5_flags *, krb5_ticket **); + krb5_error_code KRB5_CALLCONV krb5_cc_register (krb5_context, const krb5_cc_ops *, @@ -2730,6 +2842,18 @@ krb5_error_code krb5_auth_con_get_subkey_enctype krb5_auth_context, krb5_enctype *); +krb5_error_code +krb5_auth_con_get_authdata_context + (krb5_context context, + krb5_auth_context auth_context, + krb5_authdata_context *ad_context); + +krb5_error_code +krb5_auth_con_set_authdata_context + (krb5_context context, + krb5_auth_context auth_context, + krb5_authdata_context ad_context); + krb5_error_code KRB5_CALLCONV krb5int_server_decrypt_ticket_keyblock (krb5_context context, diff --git a/src/include/kdb_ext.h b/src/include/kdb_ext.h index 348be5127..384192005 100644 --- a/src/include/kdb_ext.h +++ b/src/include/kdb_ext.h @@ -97,6 +97,7 @@ typedef struct _kdb_sign_auth_data_req { krb5_keyblock *server_key; /* Key used to generate server signature */ krb5_timestamp authtime; /* Authtime of TGT */ krb5_authdata **auth_data; /* Authorization data from TGT */ + krb5_keyblock *session_key; /* Reply session key */ } kdb_sign_auth_data_req; typedef struct _kdb_sign_auth_data_rep { diff --git a/src/include/krb5/authdata_plugin.h b/src/include/krb5/authdata_plugin.h index e8c9fce2d..449b7f890 100644 --- a/src/include/krb5/authdata_plugin.h +++ b/src/include/krb5/authdata_plugin.h @@ -7,7 +7,7 @@ * require a specific license from the United States Government. * It is the responsibility of any person or organization contemplating * export to obtain such a license before exporting. - * + * * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and * distribute this software and its documentation for any purpose and * without fee is hereby granted, provided that the above copyright @@ -21,7 +21,7 @@ * M.I.T. makes no representations about the suitability of * this software for any purpose. It is provided "as is" without express * or implied warranty. - * + * * AuthorizationData plugin definitions for Kerberos 5. */ @@ -68,7 +68,7 @@ struct _krb5_db_entry_new; * functions. */ /* extern krb5plugin_authdata_ftable_v0 authdata_server_0; */ -typedef struct krb5plugin_authdata_ftable_v0 { +typedef struct krb5plugin_authdata_server_ftable_v0 { /* Not-usually-visible name. */ char *name; @@ -107,9 +107,11 @@ typedef struct krb5plugin_authdata_ftable_v0 { krb5_data *req_pkt, krb5_kdc_req *request, krb5_enc_tkt_part *enc_tkt_reply); -} krb5plugin_authdata_ftable_v0; +} krb5plugin_server_authdata_ftable_v0; -typedef struct krb5plugin_authdata_ftable_v1 { +typedef krb5plugin_server_authdata_ftable_v0 krb5plugin_authdata_ftable_v0; + +typedef struct krb5plugin_authdata_server_ftable_v1 { /* Not-usually-visible name. */ char *name; @@ -155,6 +157,173 @@ typedef struct krb5plugin_authdata_ftable_v1 { krb5_const_principal for_user_princ, krb5_enc_tkt_part *enc_tkt_request, krb5_enc_tkt_part *enc_tkt_reply); -} krb5plugin_authdata_ftable_v1; +} krb5plugin_authdata_server_ftable_v1; + +typedef krb5plugin_authdata_server_ftable_v1 krb5plugin_authdata_ftable_v1; + +typedef krb5_error_code +(*authdata_client_plugin_init_proc)(krb5_context context, + void **plugin_context); + +#define AD_USAGE_AS_REQ 0x01 +#define AD_USAGE_TGS_REQ 0x02 +#define AD_USAGE_AP_REQ 0x04 +#define AD_USAGE_KDC_ISSUED 0x08 +#define AD_USAGE_MASK 0x0F +#define AD_INFORMATIONAL 0x10 + +struct _krb5_authdata_context; + +typedef void +(*authdata_client_plugin_flags_proc)(krb5_context kcontext, + void *plugin_context, + krb5_authdatatype ad_type, + krb5_flags *flags); + +typedef void +(*authdata_client_plugin_fini_proc)(krb5_context kcontext, + void *plugin_context); + +typedef krb5_error_code +(*authdata_client_request_init_proc)(krb5_context kcontext, + struct _krb5_authdata_context *context, + void *plugin_context, + void **request_context); + +typedef void +(*authdata_client_request_fini_proc)(krb5_context kcontext, + struct _krb5_authdata_context *context, + void *plugin_context, + void *request_context); + +typedef krb5_error_code +(*authdata_client_import_authdata_proc)(krb5_context kcontext, + struct _krb5_authdata_context *context, + void *plugin_context, + void *request_context, + krb5_authdata **authdata, + krb5_boolean kdc_issued_flag, + krb5_const_principal issuer); + +typedef krb5_error_code +(*authdata_client_export_authdata_proc)(krb5_context kcontext, + struct _krb5_authdata_context *context, + void *plugin_context, + void *request_context, + krb5_flags usage, + krb5_authdata ***authdata); + +typedef krb5_error_code +(*authdata_client_get_attribute_types_proc)(krb5_context kcontext, + struct _krb5_authdata_context *context, + void *plugin_context, + void *request_context, + krb5_data **attrs); + +typedef krb5_error_code +(*authdata_client_get_attribute_proc)(krb5_context kcontext, + struct _krb5_authdata_context *context, + void *plugin_context, + void *request_context, + const krb5_data *attribute, + krb5_boolean *authenticated, + krb5_boolean *complete, + krb5_data *value, + krb5_data *display_value, + int *more); + +typedef krb5_error_code +(*authdata_client_set_attribute_proc)(krb5_context kcontext, + struct _krb5_authdata_context *context, + void *plugin_context, + void *request_context, + krb5_boolean complete, + const krb5_data *attribute, + const krb5_data *value); + +typedef krb5_error_code +(*authdata_client_delete_attribute_proc)(krb5_context kcontext, + struct _krb5_authdata_context *context, + void *plugin_context, + void *request_context, + const krb5_data *attribute); + +typedef krb5_error_code +(*authdata_client_export_internal_proc)(krb5_context kcontext, + struct _krb5_authdata_context *context, + void *plugin_context, + void *request_context, + krb5_boolean restrict_authenticated, + void **ptr); + +typedef void +(*authdata_client_free_internal_proc)(krb5_context kcontext, + struct _krb5_authdata_context *context, + void *plugin_context, + void *request_context, + void *ptr); + +typedef krb5_error_code +(*authdata_client_verify_proc)(krb5_context kcontext, + struct _krb5_authdata_context *context, + void *plugin_context, + void *request_context, + const krb5_auth_context *auth_context, + const krb5_keyblock *key, + const krb5_ap_req *req); + +typedef krb5_error_code +(*authdata_client_size_proc)(krb5_context kcontext, + struct _krb5_authdata_context *context, + void *plugin_context, + void *request_context, + size_t *sizep); + +typedef krb5_error_code +(*authdata_client_externalize_proc)(krb5_context kcontext, + struct _krb5_authdata_context *context, + void *plugin_context, + void *request_context, + krb5_octet **buffer, + size_t *lenremain); + +typedef krb5_error_code +(*authdata_client_internalize_proc)(krb5_context kcontext, + struct _krb5_authdata_context *context, + void *plugin_context, + void *request_context, + krb5_octet **buffer, + size_t *lenremain); + +typedef krb5_error_code +(*authdata_client_copy_proc)(krb5_context kcontext, + struct _krb5_authdata_context *context, + void *plugin_context, + void *request_context, + void *dst_plugin_context, + void *dst_request_context); + +typedef struct krb5plugin_authdata_client_ftable_v0 { + char *name; + krb5_authdatatype *ad_type_list; + authdata_client_plugin_init_proc init; + authdata_client_plugin_fini_proc fini; + authdata_client_plugin_flags_proc flags; + authdata_client_request_init_proc request_init; + authdata_client_request_fini_proc request_fini; + authdata_client_get_attribute_types_proc get_attribute_types; + authdata_client_get_attribute_proc get_attribute; + authdata_client_set_attribute_proc set_attribute; + authdata_client_delete_attribute_proc delete_attribute; + authdata_client_export_authdata_proc export_authdata; + authdata_client_import_authdata_proc import_authdata; + authdata_client_export_internal_proc export_internal; + authdata_client_free_internal_proc free_internal; + authdata_client_verify_proc verify; + authdata_client_size_proc size; + authdata_client_externalize_proc externalize; + authdata_client_internalize_proc internalize; + authdata_client_copy_proc copy; /* optional */ +} krb5plugin_authdata_client_ftable_v0; #endif /* KRB5_AUTHDATA_PLUGIN_H_INCLUDED */ diff --git a/src/include/krb5/krb5.hin b/src/include/krb5/krb5.hin index 8111c5bb6..81bc1cf6e 100644 --- a/src/include/krb5/krb5.hin +++ b/src/include/krb5/krb5.hin @@ -2574,6 +2574,22 @@ krb5_encode_authdata_container(krb5_context context, krb5_authdata * const*authdata, krb5_authdata ***container); +/* + * AD-KDCIssued + */ +krb5_error_code KRB5_CALLCONV +krb5_make_authdata_kdc_issued(krb5_context context, + const krb5_keyblock *key, + krb5_const_principal issuer, + krb5_authdata *const *authdata, + krb5_authdata ***ad_kdcissued); +krb5_error_code KRB5_CALLCONV +krb5_verify_authdata_kdc_issued(krb5_context context, + const krb5_keyblock *key, + const krb5_authdata *ad_kdcissued, + krb5_principal *issuer, + krb5_authdata ***authdata); + /* * Windows PAC */ diff --git a/src/kdc/do_tgs_req.c b/src/kdc/do_tgs_req.c index 2f357574d..7ea3975dc 100644 --- a/src/kdc/do_tgs_req.c +++ b/src/kdc/do_tgs_req.c @@ -699,6 +699,10 @@ tgt_again: else enc_tkt_reply.client = header_enc_tkt->client; + enc_tkt_reply.session = &session_key; + enc_tkt_reply.transited.tr_type = KRB5_DOMAIN_X500_COMPRESS; + enc_tkt_reply.transited.tr_contents = empty_string; /* equivalent of "" */ + errcode = handle_authdata(kdc_context, c_flags, (c_nprincs != 0) ? &client : NULL, @@ -728,10 +732,6 @@ tgt_again: } } - enc_tkt_reply.session = &session_key; - enc_tkt_reply.transited.tr_type = KRB5_DOMAIN_X500_COMPRESS; - enc_tkt_reply.transited.tr_contents = empty_string; /* equivalent of "" */ - /* * Only add the realm of the presented tgt to the transited list if * it is different than the local realm (cross-realm) and it is different diff --git a/src/kdc/kdc_authdata.c b/src/kdc/kdc_authdata.c index 504d3fbdd..82f934f57 100644 --- a/src/kdc/kdc_authdata.c +++ b/src/kdc/kdc_authdata.c @@ -158,11 +158,10 @@ load_authdata_plugins(krb5_context context) } /* Count the valid modules. */ - module_count = sizeof(static_authdata_systems) - / sizeof(static_authdata_systems[0]); + module_count = 0; if (authdata_plugins_ftables_v1 != NULL) { - struct krb5plugin_authdata_ftable_v1 *ftable; + struct krb5plugin_authdata_server_ftable_v1 *ftable; for (i = 0; authdata_plugins_ftables_v1[i] != NULL; i++) { ftable = authdata_plugins_ftables_v1[i]; @@ -172,7 +171,7 @@ load_authdata_plugins(krb5_context context) } if (authdata_plugins_ftables_v0 != NULL) { - struct krb5plugin_authdata_ftable_v0 *ftable; + struct krb5plugin_authdata_server_ftable_v0 *ftable; for (i = 0; authdata_plugins_ftables_v0[i] != NULL; i++) { ftable = authdata_plugins_ftables_v0[i]; @@ -181,6 +180,9 @@ load_authdata_plugins(krb5_context context) } } + module_count += sizeof(static_authdata_systems) + / sizeof(static_authdata_systems[0]); + /* Build the complete list of supported authdata options, and * leave room for a terminator entry. */ authdata_systems = calloc(module_count + 1, sizeof(krb5_authdata_systems)); @@ -189,25 +191,11 @@ load_authdata_plugins(krb5_context context) goto cleanup; } - /* Add the locally-supplied mechanisms to the dynamic list first. */ - for (i = 0, k = 0; - i < sizeof(static_authdata_systems) / sizeof(static_authdata_systems[0]); - i++) { - authdata_systems[k] = static_authdata_systems[i]; - /* Try to initialize the authdata system. If it fails, we'll remove it - * from the list of systems we'll be using. */ - server_init_proc = static_authdata_systems[i].init; - if ((server_init_proc != NULL) && - ((*server_init_proc)(context, &authdata_systems[k].plugin_context) != 0)) { - memset(&authdata_systems[k], 0, sizeof(authdata_systems[k])); - continue; - } - k++; - } + k = 0; /* Add dynamically loaded V1 plugins */ if (authdata_plugins_ftables_v1 != NULL) { - struct krb5plugin_authdata_ftable_v1 *ftable; + struct krb5plugin_authdata_server_ftable_v1 *ftable; for (i = 0; authdata_plugins_ftables_v1[i] != NULL; i++) { krb5_error_code initerr; @@ -245,7 +233,7 @@ load_authdata_plugins(krb5_context context) /* Add dynamically loaded V0 plugins */ if (authdata_plugins_ftables_v0 != NULL) { - struct krb5plugin_authdata_ftable_v0 *ftable; + struct krb5plugin_authdata_server_ftable_v0 *ftable; for (i = 0; authdata_plugins_ftables_v0[i] != NULL; i++) { krb5_error_code initerr; @@ -281,6 +269,22 @@ load_authdata_plugins(krb5_context context) } } + /* Add the locally-supplied mechanisms to the dynamic list first. */ + for (i = 0; + i < sizeof(static_authdata_systems) / sizeof(static_authdata_systems[0]); + i++) { + authdata_systems[k] = static_authdata_systems[i]; + /* Try to initialize the authdata system. If it fails, we'll remove it + * from the list of systems we'll be using. */ + server_init_proc = static_authdata_systems[i].init; + if ((server_init_proc != NULL) && + ((*server_init_proc)(context, &authdata_systems[k].plugin_context) != 0)) { + memset(&authdata_systems[k], 0, sizeof(authdata_systems[k])); + continue; + } + k++; + } + n_authdata_systems = k; /* Add the end-of-list marker. */ authdata_systems[k].name = "[end]"; @@ -526,6 +530,7 @@ handle_tgt_authdata (krb5_context context, server_key, /* U2U or server key */ enc_tkt_reply->times.authtime, tgs_req ? enc_tkt_request->authorization_data : NULL, + enc_tkt_reply->session, &db_authdata, &ad_entry, &ad_nprincs); diff --git a/src/kdc/kdc_util.c b/src/kdc/kdc_util.c index 6ac528953..9aada8132 100644 --- a/src/kdc/kdc_util.c +++ b/src/kdc/kdc_util.c @@ -1739,6 +1739,7 @@ sign_db_authdata (krb5_context context, krb5_keyblock *server_key, krb5_timestamp authtime, krb5_authdata **tgs_authdata, + krb5_keyblock *session_key, krb5_authdata ***ret_authdata, krb5_db_entry *ad_entry, int *ad_nprincs) @@ -1765,6 +1766,7 @@ sign_db_authdata (krb5_context context, req.server_key = server_key; req.authtime = authtime; req.auth_data = tgs_authdata; + req.session_key = session_key; rep.entry = ad_entry; rep.nprincs = 0; diff --git a/src/kdc/kdc_util.h b/src/kdc/kdc_util.h index cb8fb5f7a..26650510d 100644 --- a/src/kdc/kdc_util.h +++ b/src/kdc/kdc_util.h @@ -238,6 +238,7 @@ krb5_error_code sign_db_authdata krb5_keyblock *server_key, krb5_timestamp authtime, krb5_authdata **tgs_authdata, + krb5_keyblock *session_key, krb5_authdata ***ret_authdata, krb5_db_entry *ad_entry, int *ad_nprincs); diff --git a/src/lib/crypto/krb/enc_provider/Makefile.in b/src/lib/crypto/krb/enc_provider/Makefile.in new file mode 100644 index 000000000..2eedf1d9d --- /dev/null +++ b/src/lib/crypto/krb/enc_provider/Makefile.in @@ -0,0 +1,41 @@ +thisconfigdir=../../../.. +myfulldir=lib/crypto/krb/enc_provider +mydir=lib/crypto/krb/enc_provider +BUILDTOP=$(REL)..$(S)..$(S)..$(S).. +LOCALINCLUDES = -I$(srcdir)/../../@CRYPTO_IMPL@/des -I$(srcdir)/../../@CRYPTO_IMPL@/arcfour \ + -I$(srcdir)/../../@CRYPTO_IMPL@/aes -I$(srcdir)/.. -I$(srcdir)/../../@CRYPTO_IMPL@ +DEFS= + +##DOS##BUILDTOP = ..\..\..\.. +##DOS##PREFIXDIR=enc_provider +##DOS##OBJFILE=..\$(OUTPRE)enc_prov.lst + +PROG_LIBPATH=-L$(TOPLIBD) +PROG_RPATH=$(KRB5_LIBDIR) + +STLIBOBJS= des.o des3.o rc4.o aes.o + +OBJS= \ + $(OUTPRE)des.$(OBJEXT) \ + $(OUTPRE)des3.$(OBJEXT) \ + $(OUTPRE)aes.$(OBJEXT) \ + $(OUTPRE)rc4.$(OBJEXT) + +SRCS= \ + $(srcdir)/des.c \ + $(srcdir)/des3.c \ + $(srcdir)/aes.c \ + $(srcdir)/rc4.c + +##DOS##LIBOBJS = $(OBJS) + +all-unix:: all-libobjs + +includes:: depend + +depend:: $(SRCS) + +clean-unix:: clean-libobjs + +@libobj_frag@ + diff --git a/src/lib/crypto/krb/enc_provider/aes.c b/src/lib/crypto/krb/enc_provider/aes.c new file mode 100644 index 000000000..060d119c4 --- /dev/null +++ b/src/lib/crypto/krb/enc_provider/aes.c @@ -0,0 +1,415 @@ +/* + * lib/crypto/enc_provider/aes.c + * + * Copyright (C) 2003, 2007, 2008 by the Massachusetts Institute of Technology. + * All rights reserved. + * + * Export of this software from the United States of America may + * require a specific license from the United States Government. + * It is the responsibility of any person or organization contemplating + * export to obtain such a license before exporting. + * + * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and + * distribute this software and its documentation for any purpose and + * without fee is hereby granted, provided that the above copyright + * notice appear in all copies and that both that copyright notice and + * this permission notice appear in supporting documentation, and that + * the name of M.I.T. not be used in advertising or publicity pertaining + * to distribution of the software without specific, written prior + * permission. Furthermore if you modify this software you must label + * your software as modified software and not distribute it in such a + * fashion that it might be confused with the original M.I.T. software. + * M.I.T. makes no representations about the suitability of + * this software for any purpose. It is provided "as is" without express + * or implied warranty. + */ + +#include "k5-int.h" +#include "enc_provider.h" +#include "aes.h" +#include "../aead.h" + +#if 0 +aes_rval aes_blk_len(unsigned int blen, aes_ctx cx[1]); +aes_rval aes_enc_key(const unsigned char in_key[], unsigned int klen, aes_ctx cx[1]); +aes_rval aes_enc_blk(const unsigned char in_blk[], unsigned char out_blk[], const aes_ctx cx[1]); +aes_rval aes_dec_key(const unsigned char in_key[], unsigned int klen, aes_ctx cx[1]); +aes_rval aes_dec_blk(const unsigned char in_blk[], unsigned char out_blk[], const aes_ctx cx[1]); +#endif + +#define CHECK_SIZES 0 + +#if 0 +static void printd (const char *descr, krb5_data *d) { + int i, j; + const int r = 16; + + printf("%s:", descr); + + for (i = 0; i < d->length; i += r) { + printf("\n %04x: ", i); + for (j = i; j < i + r && j < d->length; j++) + printf(" %02x", 0xff & d->data[j]); +#ifdef SHOW_TEXT + for (; j < i + r; j++) + printf(" "); + printf(" "); + for (j = i; j < i + r && j < d->length; j++) { + int c = 0xff & d->data[j]; + printf("%c", isprint(c) ? c : '.'); + } +#endif + } + printf("\n"); +} +#endif + +static inline void enc(char *out, const char *in, aes_ctx *ctx) +{ + if (aes_enc_blk((const unsigned char *)in, (unsigned char *)out, ctx) + != aes_good) + abort(); +} +static inline void dec(char *out, const char *in, aes_ctx *ctx) +{ + if (aes_dec_blk((const unsigned char *)in, (unsigned char *)out, ctx) + != aes_good) + abort(); +} + +static void xorblock(char *out, const char *in) +{ + int z; + for (z = 0; z < BLOCK_SIZE; z++) + out[z] ^= in[z]; +} + +krb5_error_code +krb5int_aes_encrypt(const krb5_keyblock *key, const krb5_data *ivec, + const krb5_data *input, krb5_data *output) +{ + aes_ctx ctx; + char tmp[BLOCK_SIZE], tmp2[BLOCK_SIZE], tmp3[BLOCK_SIZE]; + int nblocks = 0, blockno; + +/* CHECK_SIZES; */ + + if (aes_enc_key(key->contents, key->length, &ctx) != aes_good) + abort(); + + if (ivec) + memcpy(tmp, ivec->data, BLOCK_SIZE); + else + memset(tmp, 0, BLOCK_SIZE); + + nblocks = (input->length + BLOCK_SIZE - 1) / BLOCK_SIZE; + + if (nblocks == 1) { + /* XXX Used for DK function. */ + enc(output->data, input->data, &ctx); + } else { + unsigned int nleft; + + for (blockno = 0; blockno < nblocks - 2; blockno++) { + xorblock(tmp, input->data + blockno * BLOCK_SIZE); + enc(tmp2, tmp, &ctx); + memcpy(output->data + blockno * BLOCK_SIZE, tmp2, BLOCK_SIZE); + + /* Set up for next block. */ + memcpy(tmp, tmp2, BLOCK_SIZE); + } + /* Do final CTS step for last two blocks (the second of which + may or may not be incomplete). */ + xorblock(tmp, input->data + (nblocks - 2) * BLOCK_SIZE); + enc(tmp2, tmp, &ctx); + nleft = input->length - (nblocks - 1) * BLOCK_SIZE; + memcpy(output->data + (nblocks - 1) * BLOCK_SIZE, tmp2, nleft); + memcpy(tmp, tmp2, BLOCK_SIZE); + + memset(tmp3, 0, sizeof(tmp3)); + memcpy(tmp3, input->data + (nblocks - 1) * BLOCK_SIZE, nleft); + xorblock(tmp, tmp3); + enc(tmp2, tmp, &ctx); + memcpy(output->data + (nblocks - 2) * BLOCK_SIZE, tmp2, BLOCK_SIZE); + if (ivec) + memcpy(ivec->data, tmp2, BLOCK_SIZE); + } + + return 0; +} + +krb5_error_code +krb5int_aes_decrypt(const krb5_keyblock *key, const krb5_data *ivec, + const krb5_data *input, krb5_data *output) +{ + aes_ctx ctx; + char tmp[BLOCK_SIZE], tmp2[BLOCK_SIZE], tmp3[BLOCK_SIZE]; + int nblocks = 0, blockno; + + CHECK_SIZES; + + if (aes_dec_key(key->contents, key->length, &ctx) != aes_good) + abort(); + + if (ivec) + memcpy(tmp, ivec->data, BLOCK_SIZE); + else + memset(tmp, 0, BLOCK_SIZE); + + nblocks = (input->length + BLOCK_SIZE - 1) / BLOCK_SIZE; + + if (nblocks == 1) { + if (input->length < BLOCK_SIZE) + abort(); + dec(output->data, input->data, &ctx); + } else { + + for (blockno = 0; blockno < nblocks - 2; blockno++) { + dec(tmp2, input->data + blockno * BLOCK_SIZE, &ctx); + xorblock(tmp2, tmp); + memcpy(output->data + blockno * BLOCK_SIZE, tmp2, BLOCK_SIZE); + memcpy(tmp, input->data + blockno * BLOCK_SIZE, BLOCK_SIZE); + } + /* Do last two blocks, the second of which (next-to-last block + of plaintext) may be incomplete. */ + dec(tmp2, input->data + (nblocks - 2) * BLOCK_SIZE, &ctx); + /* Set tmp3 to last ciphertext block, padded. */ + memset(tmp3, 0, sizeof(tmp3)); + memcpy(tmp3, input->data + (nblocks - 1) * BLOCK_SIZE, + input->length - (nblocks - 1) * BLOCK_SIZE); + /* Set tmp2 to last (possibly partial) plaintext block, and + save it. */ + xorblock(tmp2, tmp3); + memcpy(output->data + (nblocks - 1) * BLOCK_SIZE, tmp2, + input->length - (nblocks - 1) * BLOCK_SIZE); + /* Maybe keep the trailing part, and copy in the last + ciphertext block. */ + memcpy(tmp2, tmp3, input->length - (nblocks - 1) * BLOCK_SIZE); + /* Decrypt, to get next to last plaintext block xor previous + ciphertext. */ + dec(tmp3, tmp2, &ctx); + xorblock(tmp3, tmp); + memcpy(output->data + (nblocks - 2) * BLOCK_SIZE, tmp3, BLOCK_SIZE); + if (ivec) + memcpy(ivec->data, input->data + (nblocks - 2) * BLOCK_SIZE, + BLOCK_SIZE); + } + + return 0; +} + +static krb5_error_code +krb5int_aes_encrypt_iov(const krb5_keyblock *key, + const krb5_data *ivec, + krb5_crypto_iov *data, + size_t num_data) +{ + aes_ctx ctx; + char tmp[BLOCK_SIZE], tmp2[BLOCK_SIZE]; + int nblocks = 0, blockno; + size_t input_length, i; + + if (aes_enc_key(key->contents, key->length, &ctx) != aes_good) + abort(); + + if (ivec != NULL) + memcpy(tmp, ivec->data, BLOCK_SIZE); + else + memset(tmp, 0, BLOCK_SIZE); + + for (i = 0, input_length = 0; i < num_data; i++) { + krb5_crypto_iov *iov = &data[i]; + + if (ENCRYPT_IOV(iov)) + input_length += iov->data.length; + } + + nblocks = (input_length + BLOCK_SIZE - 1) / BLOCK_SIZE; + + assert(nblocks > 1); + + { + char blockN2[BLOCK_SIZE]; /* second last */ + char blockN1[BLOCK_SIZE]; /* last block */ + struct iov_block_state input_pos, output_pos; + + IOV_BLOCK_STATE_INIT(&input_pos); + IOV_BLOCK_STATE_INIT(&output_pos); + + for (blockno = 0; blockno < nblocks - 2; blockno++) { + char blockN[BLOCK_SIZE]; + + krb5int_c_iov_get_block((unsigned char *)blockN, BLOCK_SIZE, data, num_data, &input_pos); + xorblock(tmp, blockN); + enc(tmp2, tmp, &ctx); + krb5int_c_iov_put_block(data, num_data, (unsigned char *)tmp2, BLOCK_SIZE, &output_pos); + + /* Set up for next block. */ + memcpy(tmp, tmp2, BLOCK_SIZE); + } + + /* Do final CTS step for last two blocks (the second of which + may or may not be incomplete). */ + + /* First, get the last two blocks */ + memset(blockN1, 0, sizeof(blockN1)); /* pad last block with zeros */ + krb5int_c_iov_get_block((unsigned char *)blockN2, BLOCK_SIZE, data, num_data, &input_pos); + krb5int_c_iov_get_block((unsigned char *)blockN1, BLOCK_SIZE, data, num_data, &input_pos); + + /* Encrypt second last block */ + xorblock(tmp, blockN2); + enc(tmp2, tmp, &ctx); + memcpy(blockN2, tmp2, BLOCK_SIZE); /* blockN2 now contains first block */ + memcpy(tmp, tmp2, BLOCK_SIZE); + + /* Encrypt last block */ + xorblock(tmp, blockN1); + enc(tmp2, tmp, &ctx); + memcpy(blockN1, tmp2, BLOCK_SIZE); + + /* Put the last two blocks back into the iovec (reverse order) */ + krb5int_c_iov_put_block(data, num_data, (unsigned char *)blockN1, BLOCK_SIZE, &output_pos); + krb5int_c_iov_put_block(data, num_data, (unsigned char *)blockN2, BLOCK_SIZE, &output_pos); + + if (ivec != NULL) + memcpy(ivec->data, blockN1, BLOCK_SIZE); + } + + return 0; +} + +static krb5_error_code +krb5int_aes_decrypt_iov(const krb5_keyblock *key, + const krb5_data *ivec, + krb5_crypto_iov *data, + size_t num_data) +{ + aes_ctx ctx; + char tmp[BLOCK_SIZE], tmp2[BLOCK_SIZE], tmp3[BLOCK_SIZE]; + int nblocks = 0, blockno; + unsigned int i; + size_t input_length; + + CHECK_SIZES; + + if (aes_dec_key(key->contents, key->length, &ctx) != aes_good) + abort(); + + if (ivec != NULL) + memcpy(tmp, ivec->data, BLOCK_SIZE); + else + memset(tmp, 0, BLOCK_SIZE); + + for (i = 0, input_length = 0; i < num_data; i++) { + krb5_crypto_iov *iov = &data[i]; + + if (ENCRYPT_IOV(iov)) + input_length += iov->data.length; + } + + nblocks = (input_length + BLOCK_SIZE - 1) / BLOCK_SIZE; + + assert(nblocks > 1); + + { + char blockN2[BLOCK_SIZE]; /* second last */ + char blockN1[BLOCK_SIZE]; /* last block */ + struct iov_block_state input_pos, output_pos; + + IOV_BLOCK_STATE_INIT(&input_pos); + IOV_BLOCK_STATE_INIT(&output_pos); + + for (blockno = 0; blockno < nblocks - 2; blockno++) { + char blockN[BLOCK_SIZE]; + + krb5int_c_iov_get_block((unsigned char *)blockN, BLOCK_SIZE, data, num_data, &input_pos); + dec(tmp2, blockN, &ctx); + xorblock(tmp2, tmp); + krb5int_c_iov_put_block(data, num_data, (unsigned char *)tmp2, BLOCK_SIZE, &output_pos); + memcpy(tmp, blockN, BLOCK_SIZE); + } + + /* Do last two blocks, the second of which (next-to-last block + of plaintext) may be incomplete. */ + + /* First, get the last two encrypted blocks */ + memset(blockN1, 0, sizeof(blockN1)); /* pad last block with zeros */ + krb5int_c_iov_get_block((unsigned char *)blockN2, BLOCK_SIZE, data, num_data, &input_pos); + krb5int_c_iov_get_block((unsigned char *)blockN1, BLOCK_SIZE, data, num_data, &input_pos); + + /* Decrypt second last block */ + dec(tmp2, blockN2, &ctx); + /* Set tmp2 to last (possibly partial) plaintext block, and + save it. */ + xorblock(tmp2, blockN1); + memcpy(blockN2, tmp2, BLOCK_SIZE); + + /* Maybe keep the trailing part, and copy in the last + ciphertext block. */ + input_length %= BLOCK_SIZE; + memcpy(tmp2, blockN1, input_length ? input_length : BLOCK_SIZE); + dec(tmp3, tmp2, &ctx); + xorblock(tmp3, tmp); + /* Copy out ivec first before we clobber blockN1 with plaintext */ + if (ivec != NULL) + memcpy(ivec->data, blockN1, BLOCK_SIZE); + memcpy(blockN1, tmp3, BLOCK_SIZE); + + /* Put the last two blocks back into the iovec */ + krb5int_c_iov_put_block(data, num_data, (unsigned char *)blockN1, BLOCK_SIZE, &output_pos); + krb5int_c_iov_put_block(data, num_data, (unsigned char *)blockN2, BLOCK_SIZE, &output_pos); + } + + return 0; +} + +static krb5_error_code +k5_aes_make_key(const krb5_data *randombits, krb5_keyblock *key) +{ + if (key->length != 16 && key->length != 32) + return(KRB5_BAD_KEYSIZE); + if (randombits->length != key->length) + return(KRB5_CRYPTO_INTERNAL); + + key->magic = KV5M_KEYBLOCK; + + memcpy(key->contents, randombits->data, randombits->length); + return(0); +} + +static krb5_error_code +krb5int_aes_init_state (const krb5_keyblock *key, krb5_keyusage usage, + krb5_data *state) +{ + state->length = 16; + state->data = (void *) malloc(16); + if (state->data == NULL) + return ENOMEM; + memset(state->data, 0, state->length); + return 0; +} + +const struct krb5_enc_provider krb5int_enc_aes128 = { + 16, + 16, 16, + krb5int_aes_encrypt, + krb5int_aes_decrypt, + k5_aes_make_key, + krb5int_aes_init_state, + krb5int_default_free_state, + krb5int_aes_encrypt_iov, + krb5int_aes_decrypt_iov +}; + +const struct krb5_enc_provider krb5int_enc_aes256 = { + 16, + 32, 32, + krb5int_aes_encrypt, + krb5int_aes_decrypt, + k5_aes_make_key, + krb5int_aes_init_state, + krb5int_default_free_state, + krb5int_aes_encrypt_iov, + krb5int_aes_decrypt_iov +}; + diff --git a/src/lib/crypto/krb/enc_provider/deps b/src/lib/crypto/krb/enc_provider/deps new file mode 100644 index 000000000..064976279 --- /dev/null +++ b/src/lib/crypto/krb/enc_provider/deps @@ -0,0 +1,49 @@ +# +# Generated makefile dependencies follow. +# +des.so des.po $(OUTPRE)des.$(OBJEXT): $(BUILDTOP)/include/autoconf.h \ + $(BUILDTOP)/include/krb5/krb5.h $(BUILDTOP)/include/osconf.h \ + $(BUILDTOP)/include/profile.h $(COM_ERR_DEPS) $(SRCTOP)/include/k5-buf.h \ + $(SRCTOP)/include/k5-err.h $(SRCTOP)/include/k5-gmt_mktime.h \ + $(SRCTOP)/include/k5-int-pkinit.h $(SRCTOP)/include/k5-int.h \ + $(SRCTOP)/include/k5-platform.h $(SRCTOP)/include/k5-plugin.h \ + $(SRCTOP)/include/k5-thread.h $(SRCTOP)/include/krb5.h \ + $(SRCTOP)/include/krb5/locate_plugin.h $(SRCTOP)/include/krb5/preauth_plugin.h \ + $(SRCTOP)/include/port-sockets.h $(SRCTOP)/include/socket-utils.h \ + $(srcdir)/../../builtin/des/des_int.h $(srcdir)/../aead.h \ + $(srcdir)/../cksumtypes.h des.c enc_provider.h +des3.so des3.po $(OUTPRE)des3.$(OBJEXT): $(BUILDTOP)/include/autoconf.h \ + $(BUILDTOP)/include/krb5/krb5.h $(BUILDTOP)/include/osconf.h \ + $(BUILDTOP)/include/profile.h $(COM_ERR_DEPS) $(SRCTOP)/include/k5-buf.h \ + $(SRCTOP)/include/k5-err.h $(SRCTOP)/include/k5-gmt_mktime.h \ + $(SRCTOP)/include/k5-int-pkinit.h $(SRCTOP)/include/k5-int.h \ + $(SRCTOP)/include/k5-platform.h $(SRCTOP)/include/k5-plugin.h \ + $(SRCTOP)/include/k5-thread.h $(SRCTOP)/include/krb5.h \ + $(SRCTOP)/include/krb5/locate_plugin.h $(SRCTOP)/include/krb5/preauth_plugin.h \ + $(SRCTOP)/include/port-sockets.h $(SRCTOP)/include/socket-utils.h \ + $(srcdir)/../../builtin/des/des_int.h $(srcdir)/../aead.h \ + $(srcdir)/../cksumtypes.h des3.c +aes.so aes.po $(OUTPRE)aes.$(OBJEXT): $(BUILDTOP)/include/autoconf.h \ + $(BUILDTOP)/include/krb5/krb5.h $(BUILDTOP)/include/osconf.h \ + $(BUILDTOP)/include/profile.h $(COM_ERR_DEPS) $(SRCTOP)/include/k5-buf.h \ + $(SRCTOP)/include/k5-err.h $(SRCTOP)/include/k5-gmt_mktime.h \ + $(SRCTOP)/include/k5-int-pkinit.h $(SRCTOP)/include/k5-int.h \ + $(SRCTOP)/include/k5-platform.h $(SRCTOP)/include/k5-plugin.h \ + $(SRCTOP)/include/k5-thread.h $(SRCTOP)/include/krb5.h \ + $(SRCTOP)/include/krb5/locate_plugin.h $(SRCTOP)/include/krb5/preauth_plugin.h \ + $(SRCTOP)/include/port-sockets.h $(SRCTOP)/include/socket-utils.h \ + $(srcdir)/../../builtin/aes/aes.h $(srcdir)/../../builtin/aes/uitypes.h \ + $(srcdir)/../aead.h $(srcdir)/../cksumtypes.h aes.c \ + enc_provider.h +rc4.so rc4.po $(OUTPRE)rc4.$(OBJEXT): $(BUILDTOP)/include/autoconf.h \ + $(BUILDTOP)/include/krb5/krb5.h $(BUILDTOP)/include/osconf.h \ + $(BUILDTOP)/include/profile.h $(COM_ERR_DEPS) $(SRCTOP)/include/k5-buf.h \ + $(SRCTOP)/include/k5-err.h $(SRCTOP)/include/k5-gmt_mktime.h \ + $(SRCTOP)/include/k5-int-pkinit.h $(SRCTOP)/include/k5-int.h \ + $(SRCTOP)/include/k5-platform.h $(SRCTOP)/include/k5-plugin.h \ + $(SRCTOP)/include/k5-thread.h $(SRCTOP)/include/krb5.h \ + $(SRCTOP)/include/krb5/locate_plugin.h $(SRCTOP)/include/krb5/preauth_plugin.h \ + $(SRCTOP)/include/port-sockets.h $(SRCTOP)/include/socket-utils.h \ + $(srcdir)/../../builtin/arcfour/arcfour-int.h $(srcdir)/../../builtin/arcfour/arcfour.h \ + $(srcdir)/../aead.h $(srcdir)/../cksumtypes.h enc_provider.h \ + rc4.c diff --git a/src/lib/crypto/krb/enc_provider/des.c b/src/lib/crypto/krb/enc_provider/des.c new file mode 100644 index 000000000..547f6b976 --- /dev/null +++ b/src/lib/crypto/krb/enc_provider/des.c @@ -0,0 +1,181 @@ +/* + * Copyright (C) 1998 by the FundsXpress, INC. + * + * All rights reserved. + * + * Export of this software from the United States of America may require + * a specific license from the United States Government. It is the + * responsibility of any person or organization contemplating export to + * obtain such a license before exporting. + * + * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and + * distribute this software and its documentation for any purpose and + * without fee is hereby granted, provided that the above copyright + * notice appear in all copies and that both that copyright notice and + * this permission notice appear in supporting documentation, and that + * the name of FundsXpress. not be used in advertising or publicity pertaining + * to distribution of the software without specific, written prior + * permission. FundsXpress makes no representations about the suitability of + * this software for any purpose. It is provided "as is" without express + * or implied warranty. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED + * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. + */ + +#include "k5-int.h" +#include "des_int.h" +#include "enc_provider.h" +#include "aead.h" + +static krb5_error_code +k5_des_docrypt(const krb5_keyblock *key, const krb5_data *ivec, + const krb5_data *input, krb5_data *output, int enc) +{ + mit_des_key_schedule schedule; + + /* key->enctype was checked by the caller */ + + if (key->length != 8) + return(KRB5_BAD_KEYSIZE); + if ((input->length%8) != 0) + return(KRB5_BAD_MSIZE); + if (ivec && (ivec->length != 8)) + return(KRB5_BAD_MSIZE); + if (input->length != output->length) + return(KRB5_BAD_MSIZE); + + switch (mit_des_key_sched(key->contents, schedule)) { + case -1: + return(KRB5DES_BAD_KEYPAR); + case -2: + return(KRB5DES_WEAK_KEY); + } + + /* this has a return value, but the code always returns zero */ + + mit_des_cbc_encrypt((krb5_pointer) input->data, + (krb5_pointer) output->data, input->length, + schedule, + (ivec + ? (const unsigned char *) ivec->data + : (const unsigned char *) mit_des_zeroblock), + enc); + + memset(schedule, 0, sizeof(schedule)); + + return(0); +} + +static krb5_error_code +k5_des_encrypt(const krb5_keyblock *key, const krb5_data *ivec, + const krb5_data *input, krb5_data *output) +{ + return(k5_des_docrypt(key, ivec, input, output, 1)); +} + +static krb5_error_code +k5_des_decrypt(const krb5_keyblock *key, const krb5_data *ivec, + const krb5_data *input, krb5_data *output) +{ + return(k5_des_docrypt(key, ivec, input, output, 0)); +} + +static krb5_error_code +k5_des_make_key(const krb5_data *randombits, krb5_keyblock *key) +{ + if (key->length != 8) + return(KRB5_BAD_KEYSIZE); + if (randombits->length != 7) + return(KRB5_CRYPTO_INTERNAL); + + key->magic = KV5M_KEYBLOCK; + key->length = 8; + + /* take the seven bytes, move them around into the top 7 bits of the + 8 key bytes, then compute the parity bits */ + + memcpy(key->contents, randombits->data, randombits->length); + key->contents[7] = (((key->contents[0]&1)<<1) | ((key->contents[1]&1)<<2) | + ((key->contents[2]&1)<<3) | ((key->contents[3]&1)<<4) | + ((key->contents[4]&1)<<5) | ((key->contents[5]&1)<<6) | + ((key->contents[6]&1)<<7)); + + mit_des_fixup_key_parity(key->contents); + + return(0); +} + +static krb5_error_code +k5_des_docrypt_iov(const krb5_keyblock *key, const krb5_data *ivec, + krb5_crypto_iov *data, size_t num_data, int enc) +{ + mit_des_key_schedule schedule; + size_t input_length = 0; + unsigned int i; + + /* key->enctype was checked by the caller */ + + if (key->length != 8) + return(KRB5_BAD_KEYSIZE); + + for (i = 0; i < num_data; i++) { + const krb5_crypto_iov *iov = &data[i]; + + if (ENCRYPT_DATA_IOV(iov)) + input_length += iov->data.length; + } + + if ((input_length % 8) != 0) + return(KRB5_BAD_MSIZE); + if (ivec && (ivec->length != 8)) + return(KRB5_BAD_MSIZE); + + switch (mit_des_key_sched(key->contents, schedule)) { + case -1: + return(KRB5DES_BAD_KEYPAR); + case -2: + return(KRB5DES_WEAK_KEY); + } + + /* this has a return value, but the code always returns zero */ + if (enc) + krb5int_des_cbc_encrypt_iov(data, num_data, schedule, ivec ? ivec->data : NULL); + else + krb5int_des_cbc_decrypt_iov(data, num_data, schedule, ivec ? ivec->data : NULL); + + memset(schedule, 0, sizeof(schedule)); + + return(0); +} + +static krb5_error_code +k5_des_encrypt_iov(const krb5_keyblock *key, + const krb5_data *ivec, + krb5_crypto_iov *data, + size_t num_data) +{ + return k5_des_docrypt_iov(key, ivec, data, num_data, 1); +} + +static krb5_error_code +k5_des_decrypt_iov(const krb5_keyblock *key, + const krb5_data *ivec, + krb5_crypto_iov *data, + size_t num_data) +{ + return k5_des_docrypt_iov(key, ivec, data, num_data, 0); +} + +const struct krb5_enc_provider krb5int_enc_des = { + 8, + 7, 8, + k5_des_encrypt, + k5_des_decrypt, + k5_des_make_key, + krb5int_des_init_state, + krb5int_default_free_state, + k5_des_encrypt_iov, + k5_des_decrypt_iov +}; diff --git a/src/lib/crypto/krb/enc_provider/des3.c b/src/lib/crypto/krb/enc_provider/des3.c new file mode 100644 index 000000000..412c994a7 --- /dev/null +++ b/src/lib/crypto/krb/enc_provider/des3.c @@ -0,0 +1,221 @@ +/* + * Copyright (C) 1998 by the FundsXpress, INC. + * + * All rights reserved. + * + * Export of this software from the United States of America may require + * a specific license from the United States Government. It is the + * responsibility of any person or organization contemplating export to + * obtain such a license before exporting. + * + * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and + * distribute this software and its documentation for any purpose and + * without fee is hereby granted, provided that the above copyright + * notice appear in all copies and that both that copyright notice and + * this permission notice appear in supporting documentation, and that + * the name of FundsXpress. not be used in advertising or publicity pertaining + * to distribution of the software without specific, written prior + * permission. FundsXpress makes no representations about the suitability of + * this software for any purpose. It is provided "as is" without express + * or implied warranty. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED + * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. + */ + +#include "k5-int.h" +#include "des_int.h" +#include "../aead.h" + +static krb5_error_code +validate_and_schedule(const krb5_keyblock *key, const krb5_data *ivec, + const krb5_data *input, const krb5_data *output, + mit_des3_key_schedule *schedule) +{ + /* key->enctype was checked by the caller */ + + if (key->length != 24) + return(KRB5_BAD_KEYSIZE); + if ((input->length%8) != 0) + return(KRB5_BAD_MSIZE); + if (ivec && (ivec->length != 8)) + return(KRB5_BAD_MSIZE); + if (input->length != output->length) + return(KRB5_BAD_MSIZE); + + switch (mit_des3_key_sched(*(mit_des3_cblock *)key->contents, + *schedule)) { + case -1: + return(KRB5DES_BAD_KEYPAR); + case -2: + return(KRB5DES_WEAK_KEY); + } + return 0; +} + +static krb5_error_code +validate_and_schedule_iov(const krb5_keyblock *key, const krb5_data *ivec, + const krb5_crypto_iov *data, size_t num_data, + mit_des3_key_schedule *schedule) +{ + size_t i, input_length; + + for (i = 0, input_length = 0; i < num_data; i++) { + const krb5_crypto_iov *iov = &data[i]; + + if (ENCRYPT_IOV(iov)) + input_length += iov->data.length; + } + + if (key->length != 24) + return(KRB5_BAD_KEYSIZE); + if ((input_length%8) != 0) + return(KRB5_BAD_MSIZE); + if (ivec && (ivec->length != 8)) + return(KRB5_BAD_MSIZE); + + switch (mit_des3_key_sched(*(mit_des3_cblock *)key->contents, + *schedule)) { + case -1: + return(KRB5DES_BAD_KEYPAR); + case -2: + return(KRB5DES_WEAK_KEY); + } + return 0; +} + +static krb5_error_code +k5_des3_encrypt(const krb5_keyblock *key, const krb5_data *ivec, + const krb5_data *input, krb5_data *output) +{ + mit_des3_key_schedule schedule; + krb5_error_code err; + + err = validate_and_schedule(key, ivec, input, output, &schedule); + if (err) + return err; + + /* this has a return value, but the code always returns zero */ + krb5int_des3_cbc_encrypt((krb5_pointer) input->data, + (krb5_pointer) output->data, input->length, + schedule[0], schedule[1], schedule[2], + ivec?(const unsigned char *) ivec->data:(const unsigned char *)mit_des_zeroblock); + + zap(schedule, sizeof(schedule)); + + return(0); +} + +static krb5_error_code +k5_des3_decrypt(const krb5_keyblock *key, const krb5_data *ivec, + const krb5_data *input, krb5_data *output) +{ + mit_des3_key_schedule schedule; + krb5_error_code err; + + err = validate_and_schedule(key, ivec, input, output, &schedule); + if (err) + return err; + + /* this has a return value, but the code always returns zero */ + krb5int_des3_cbc_decrypt((krb5_pointer) input->data, + (krb5_pointer) output->data, input->length, + schedule[0], schedule[1], schedule[2], + ivec?(const unsigned char *) ivec->data:(const unsigned char *)mit_des_zeroblock); + + zap(schedule, sizeof(schedule)); + + return(0); +} + +static krb5_error_code +k5_des3_make_key(const krb5_data *randombits, krb5_keyblock *key) +{ + int i; + + if (key->length != 24) + return(KRB5_BAD_KEYSIZE); + if (randombits->length != 21) + return(KRB5_CRYPTO_INTERNAL); + + key->magic = KV5M_KEYBLOCK; + key->length = 24; + + /* take the seven bytes, move them around into the top 7 bits of the + 8 key bytes, then compute the parity bits. Do this three times. */ + + for (i=0; i<3; i++) { + memcpy(key->contents+i*8, randombits->data+i*7, 7); + key->contents[i*8+7] = (((key->contents[i*8]&1)<<1) | + ((key->contents[i*8+1]&1)<<2) | + ((key->contents[i*8+2]&1)<<3) | + ((key->contents[i*8+3]&1)<<4) | + ((key->contents[i*8+4]&1)<<5) | + ((key->contents[i*8+5]&1)<<6) | + ((key->contents[i*8+6]&1)<<7)); + + mit_des_fixup_key_parity(key->contents+i*8); + } + + return(0); +} + +static krb5_error_code +k5_des3_encrypt_iov(const krb5_keyblock *key, + const krb5_data *ivec, + krb5_crypto_iov *data, + size_t num_data) +{ + mit_des3_key_schedule schedule; + krb5_error_code err; + + err = validate_and_schedule_iov(key, ivec, data, num_data, &schedule); + if (err) + return err; + + /* this has a return value, but the code always returns zero */ + krb5int_des3_cbc_encrypt_iov(data, num_data, + schedule[0], schedule[1], schedule[2], + ivec != NULL ? (unsigned char *) ivec->data : NULL); + + zap(schedule, sizeof(schedule)); + + return(0); +} + +static krb5_error_code +k5_des3_decrypt_iov(const krb5_keyblock *key, + const krb5_data *ivec, + krb5_crypto_iov *data, + size_t num_data) +{ + mit_des3_key_schedule schedule; + krb5_error_code err; + + err = validate_and_schedule_iov(key, ivec, data, num_data, &schedule); + if (err) + return err; + + /* this has a return value, but the code always returns zero */ + krb5int_des3_cbc_decrypt_iov(data, num_data, + schedule[0], schedule[1], schedule[2], + ivec != NULL ? (unsigned char *) ivec->data : NULL); + + zap(schedule, sizeof(schedule)); + + return(0); +} + +const struct krb5_enc_provider krb5int_enc_des3 = { + 8, + 21, 24, + k5_des3_encrypt, + k5_des3_decrypt, + k5_des3_make_key, + krb5int_des_init_state, + krb5int_default_free_state, + k5_des3_encrypt_iov, + k5_des3_decrypt_iov +}; + diff --git a/src/lib/crypto/krb/enc_provider/enc_provider.h b/src/lib/crypto/krb/enc_provider/enc_provider.h new file mode 100644 index 000000000..92022b3c8 --- /dev/null +++ b/src/lib/crypto/krb/enc_provider/enc_provider.h @@ -0,0 +1,36 @@ +/* + * Copyright (C) 1998 by the FundsXpress, INC. + * + * All rights reserved. + * + * Export of this software from the United States of America may require + * a specific license from the United States Government. It is the + * responsibility of any person or organization contemplating export to + * obtain such a license before exporting. + * + * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and + * distribute this software and its documentation for any purpose and + * without fee is hereby granted, provided that the above copyright + * notice appear in all copies and that both that copyright notice and + * this permission notice appear in supporting documentation, and that + * the name of FundsXpress. not be used in advertising or publicity pertaining + * to distribution of the software without specific, written prior + * permission. FundsXpress makes no representations about the suitability of + * this software for any purpose. It is provided "as is" without express + * or implied warranty. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED + * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. + */ + +#include "k5-int.h" + +extern const struct krb5_enc_provider krb5int_enc_des; +extern const struct krb5_enc_provider krb5int_enc_des3; +extern const struct krb5_enc_provider krb5int_enc_arcfour; +extern const struct krb5_enc_provider krb5int_enc_aes128; +extern const struct krb5_enc_provider krb5int_enc_aes256; +extern const struct krb5_enc_provider krb5int_enc_aes128_ctr; +extern const struct krb5_enc_provider krb5int_enc_aes256_ctr; + diff --git a/src/lib/crypto/krb/enc_provider/rc4.c b/src/lib/crypto/krb/enc_provider/rc4.c new file mode 100644 index 000000000..b950a605b --- /dev/null +++ b/src/lib/crypto/krb/enc_provider/rc4.c @@ -0,0 +1,271 @@ +/* arcfour.c + * + * Copyright (c) 2000 by Computer Science Laboratory, + * Rensselaer Polytechnic Institute + * + * #include STD_DISCLAIMER + */ + +#include "k5-int.h" +#include "arcfour-int.h" +#include "enc_provider.h" +#include "../aead.h" +/* gets the next byte from the PRNG */ +#if ((__GNUC__ >= 2) ) +static __inline__ unsigned int k5_arcfour_byte(ArcfourContext *); +#else +static unsigned int k5_arcfour_byte(ArcfourContext *); +#endif /* gcc inlines*/ + +/* Initializes the context and sets the key. */ +static krb5_error_code k5_arcfour_init(ArcfourContext *ctx, const unsigned char *key, + unsigned int keylen); + +/* Encrypts/decrypts data. */ +static void k5_arcfour_crypt(ArcfourContext *ctx, unsigned char *dest, + const unsigned char *src, unsigned int len); + +/* Interface layer to kerb5 crypto layer */ +static krb5_error_code +k5_arcfour_docrypt(const krb5_keyblock *, const krb5_data *, + const krb5_data *, krb5_data *); + +/* from a random bitstrem, construct a key */ +static krb5_error_code +k5_arcfour_make_key(const krb5_data *, krb5_keyblock *); + +static const unsigned char arcfour_weakkey1[] = {0x00, 0x00, 0xfd}; +static const unsigned char arcfour_weakkey2[] = {0x03, 0xfd, 0xfc}; +static const struct { + size_t length; + const unsigned char *data; +} arcfour_weakkeys[] = { + { sizeof (arcfour_weakkey1), arcfour_weakkey1}, + { sizeof (arcfour_weakkey2), arcfour_weakkey2}, +}; + +static inline unsigned int k5_arcfour_byte(ArcfourContext * ctx) +{ + unsigned int x; + unsigned int y; + unsigned int sx, sy; + unsigned char *state; + + state = ctx->state; + x = (ctx->x + 1) & 0xff; + sx = state[x]; + y = (sx + ctx->y) & 0xff; + sy = state[y]; + ctx->x = x; + ctx->y = y; + state[y] = sx; + state[x] = sy; + return state[(sx + sy) & 0xff]; +} + +static void k5_arcfour_crypt(ArcfourContext *ctx, unsigned char *dest, + const unsigned char *src, unsigned int len) +{ + unsigned int i; + for (i = 0; i < len; i++) + dest[i] = src[i] ^ k5_arcfour_byte(ctx); +} + + +static krb5_error_code +k5_arcfour_init(ArcfourContext *ctx, const unsigned char *key, + unsigned int key_len) +{ + unsigned int t, u; + unsigned int keyindex; + unsigned int stateindex; + unsigned char* state; + unsigned int counter; + + if (key_len != 16) + return KRB5_BAD_MSIZE; /*this is probably not the correct error code + to return */ + for (counter=0; + counter < sizeof(arcfour_weakkeys)/sizeof(arcfour_weakkeys[0]); + counter++) + if (!memcmp(key, arcfour_weakkeys[counter].data, + arcfour_weakkeys[counter].length)) + return KRB5DES_WEAK_KEY; /* most certainly not the correct error */ + + state = &ctx->state[0]; + ctx->x = 0; + ctx->y = 0; + for (counter = 0; counter < 256; counter++) + state[counter] = counter; + keyindex = 0; + stateindex = 0; + for (counter = 0; counter < 256; counter++) + { + t = state[counter]; + stateindex = (stateindex + key[keyindex] + t) & 0xff; + u = state[stateindex]; + state[stateindex] = t; + state[counter] = u; + if (++keyindex >= key_len) + keyindex = 0; + } + return 0; +} + + +/* The workhorse of the arcfour system, this impliments the cipher */ +static krb5_error_code +k5_arcfour_docrypt(const krb5_keyblock *key, const krb5_data *state, + const krb5_data *input, krb5_data *output) +{ + ArcfourContext *arcfour_ctx; + ArcFourCipherState *cipher_state; + int ret; + + if (key->length != 16) + return(KRB5_BAD_KEYSIZE); + if (state && (state->length != sizeof (ArcFourCipherState))) + return(KRB5_BAD_MSIZE); + if (input->length != output->length) + return(KRB5_BAD_MSIZE); + + if (state) { + cipher_state = (ArcFourCipherState *) state->data; + arcfour_ctx=&cipher_state->ctx; + if (cipher_state->initialized == 0) { + if ((ret=k5_arcfour_init(arcfour_ctx, key->contents, key->length))) { + return ret; + } + cipher_state->initialized = 1; + } + k5_arcfour_crypt(arcfour_ctx, (unsigned char *) output->data, (const unsigned char *) input->data, input->length); + } + else { + arcfour_ctx=malloc(sizeof (ArcfourContext)); + if (arcfour_ctx == NULL) + return ENOMEM; + if ((ret=k5_arcfour_init(arcfour_ctx, key->contents, key->length))) { + free(arcfour_ctx); + return (ret); + } + k5_arcfour_crypt(arcfour_ctx, (unsigned char * ) output->data, + (const unsigned char * ) input->data, input->length); + memset(arcfour_ctx, 0, sizeof (ArcfourContext)); + free(arcfour_ctx); + } + + return 0; +} + +/* In-place encryption */ +static krb5_error_code +k5_arcfour_docrypt_iov(const krb5_keyblock *key, + const krb5_data *state, + krb5_crypto_iov *data, + size_t num_data) +{ + ArcfourContext *arcfour_ctx = NULL; + ArcFourCipherState *cipher_state = NULL; + krb5_error_code ret; + size_t i; + + if (key->length != 16) + return KRB5_BAD_KEYSIZE; + if (state != NULL && (state->length != sizeof(ArcFourCipherState))) + return KRB5_BAD_MSIZE; + + if (state != NULL) { + cipher_state = (ArcFourCipherState *)state->data; + arcfour_ctx = &cipher_state->ctx; + if (cipher_state->initialized == 0) { + ret = k5_arcfour_init(arcfour_ctx, key->contents, key->length); + if (ret != 0) + return ret; + + cipher_state->initialized = 1; + } + } else { + arcfour_ctx = (ArcfourContext *)malloc(sizeof(ArcfourContext)); + if (arcfour_ctx == NULL) + return ENOMEM; + + ret = k5_arcfour_init(arcfour_ctx, key->contents, key->length); + if (ret != 0) { + free(arcfour_ctx); + return ret; + } + } + + for (i = 0; i < num_data; i++) { + krb5_crypto_iov *iov = &data[i]; + + if (ENCRYPT_IOV(iov)) + k5_arcfour_crypt(arcfour_ctx, (unsigned char *)iov->data.data, + (const unsigned char *)iov->data.data, iov->data.length); + } + + if (state == NULL) { + memset(arcfour_ctx, 0, sizeof(ArcfourContext)); + free(arcfour_ctx); + } + + return 0; +} + +static krb5_error_code +k5_arcfour_make_key(const krb5_data *randombits, krb5_keyblock *key) +{ + if (key->length != 16) + return(KRB5_BAD_KEYSIZE); + if (randombits->length != 16) + return(KRB5_CRYPTO_INTERNAL); + + key->magic = KV5M_KEYBLOCK; + key->length = 16; + + memcpy(key->contents, randombits->data, randombits->length); + + return(0); +} + +static krb5_error_code +k5_arcfour_init_state (const krb5_keyblock *key, + krb5_keyusage keyusage, krb5_data *new_state) +{ + /* Note that we can't actually set up the state here because the key + * will change between now and when encrypt is called + * because it is data dependent. Yeah, this has strange + * properties. --SDH + */ + new_state->length = sizeof (ArcFourCipherState); + new_state->data = malloc (new_state->length); + if (new_state->data) { + memset (new_state->data, 0 , new_state->length); + /* That will set initialized to zero*/ + }else { + return (ENOMEM); + } + return 0; +} + +/* Since the arcfour cipher is identical going forwards and backwards, + we just call "docrypt" directly +*/ +const struct krb5_enc_provider krb5int_enc_arcfour = { + /* This seems to work... although I am not sure what the + implications are in other places in the kerberos library */ + 1, + /* Keysize is arbitrary in arcfour, but the constraints of the + system, and to attempt to work with the MSFT system forces us + to 16byte/128bit. Since there is no parity in the key, the + byte and length are the same. */ + 16, 16, + k5_arcfour_docrypt, + k5_arcfour_docrypt, + k5_arcfour_make_key, + k5_arcfour_init_state, /*xxx not implemented yet*/ + krb5int_default_free_state, + k5_arcfour_docrypt_iov, + k5_arcfour_docrypt_iov +}; + diff --git a/src/lib/crypto/openssl/sha1/shs.c b/src/lib/crypto/openssl/sha1/shs.c index 7cc864bb8..fadb228b4 100644 --- a/src/lib/crypto/openssl/sha1/shs.c +++ b/src/lib/crypto/openssl/sha1/shs.c @@ -29,7 +29,7 @@ void shsUpdate(SHS_INFO *shsInfo, const SHS_BYTE *buffer, unsigned int count) void shsFinal(SHS_INFO *shsInfo) { - EVP_DigestFinal_ex(&shsInfo->ossl_sha1_ctx ,(unsigned char *)shsInfo->digestBuf , &shsInfo->digestLen); + EVP_DigestFinal_ex(&shsInfo->ossl_sha1_ctx ,(unsigned char *)shsInfo->digestBuf , &shsInfo->digestLen); EVP_MD_CTX_cleanup(&shsInfo->ossl_sha1_ctx ); } diff --git a/src/lib/crypto/openssl/sha1/shs.h b/src/lib/crypto/openssl/sha1/shs.h index 772c72ac6..88ab17287 100644 --- a/src/lib/crypto/openssl/sha1/shs.h +++ b/src/lib/crypto/openssl/sha1/shs.h @@ -22,7 +22,7 @@ typedef krb5_ui_4 SHS_LONG; /* The structure for storing SHS info */ typedef struct { - EVP_MD_CTX ossl_sha1_ctx; + EVP_MD_CTX ossl_sha1_ctx; unsigned char digestBuf[SHS_DIGESTSIZE]; /* output */ unsigned int digestLen; /* output */ } SHS_INFO; diff --git a/src/lib/gssapi/generic/gssapi_ext.h b/src/lib/gssapi/generic/gssapi_ext.h index ce115639b..12216775a 100644 --- a/src/lib/gssapi/generic/gssapi_ext.h +++ b/src/lib/gssapi/generic/gssapi_ext.h @@ -254,7 +254,6 @@ OM_uint32 KRB5_CALLCONV gss_release_iov_buffer gss_iov_buffer_desc *, /* iov */ int); /* iov_count */ - /* * Protocol transition */ @@ -285,6 +284,80 @@ gss_add_cred_impersonate_name( OM_uint32 *, /* initiator_time_rec */ OM_uint32 *); /* acceptor_time_rec */ +/* + * Naming extensions + */ +OM_uint32 KRB5_CALLCONV gss_display_name_ext +( + OM_uint32 *, /* minor_status */ + gss_name_t, /* name */ + gss_OID, /* display_as_name_type */ + gss_buffer_t /* display_name */ +); + +OM_uint32 KRB5_CALLCONV gss_inquire_name +( + OM_uint32 *, /* minor_status */ + gss_name_t, /* name */ + int *, /* name_is_MN */ + gss_OID *, /* MN_mech */ + gss_buffer_set_t * /* attrs */ +); + +OM_uint32 KRB5_CALLCONV gss_get_name_attribute +( + OM_uint32 *, /* minor_status */ + gss_name_t, /* name */ + gss_buffer_t, /* attr */ + int *, /* authenticated */ + int *, /* complete */ + gss_buffer_t, /* value */ + gss_buffer_t, /* display_value */ + int * /* more */ +); + +OM_uint32 KRB5_CALLCONV gss_set_name_attribute +( + OM_uint32 *, /* minor_status */ + gss_name_t, /* name */ + int, /* complete */ + gss_buffer_t, /* attr */ + gss_buffer_t /* value */ +); + +OM_uint32 KRB5_CALLCONV gss_delete_name_attribute +( + OM_uint32 *, /* minor_status */ + gss_name_t, /* name */ + gss_buffer_t /* attr */ +); + +OM_uint32 KRB5_CALLCONV gss_export_name_composite +( + OM_uint32 *, /* minor_status */ + gss_name_t, /* name */ + gss_buffer_t /* exp_composite_name */ +); + +typedef struct gss_any *gss_any_t; + +OM_uint32 KRB5_CALLCONV gss_map_name_to_any +( + OM_uint32 *, /* minor_status */ + gss_name_t, /* name */ + int, /* authenticated */ + gss_buffer_t, /* type_id */ + gss_any_t * /* output */ +); + +OM_uint32 KRB5_CALLCONV gss_release_any_name_mapping +( + OM_uint32 *, /* minor_status */ + gss_name_t, /* name */ + gss_buffer_t, /* type_id */ + gss_any_t * /* input */ +); + #ifdef __cplusplus } #endif diff --git a/src/lib/gssapi/krb5/Makefile.in b/src/lib/gssapi/krb5/Makefile.in index 645b91b11..b84efa176 100644 --- a/src/lib/gssapi/krb5/Makefile.in +++ b/src/lib/gssapi/krb5/Makefile.in @@ -69,6 +69,7 @@ SRCS = \ $(srcdir)/k5unsealiov.c \ $(srcdir)/krb5_gss_glue.c \ $(srcdir)/lucid_context.c \ + $(srcdir)/naming_exts.c \ $(srcdir)/process_context_token.c \ $(srcdir)/rel_cred.c \ $(srcdir)/rel_oid.c \ @@ -120,6 +121,7 @@ OBJS = \ $(OUTPRE)k5unsealiov.$(OBJEXT) \ $(OUTPRE)krb5_gss_glue.$(OBJEXT) \ $(OUTPRE)lucid_context.$(OBJEXT) \ + $(OUTPRE)naming_exts.$(OBJEXT) \ $(OUTPRE)process_context_token.$(OBJEXT) \ $(OUTPRE)rel_cred.$(OBJEXT) \ $(OUTPRE)rel_oid.$(OBJEXT) \ @@ -174,6 +176,7 @@ STLIBOBJS = \ k5unsealiov.o \ krb5_gss_glue.o \ lucid_context.o \ + naming_exts.o \ process_context_token.o \ rel_cred.o \ rel_oid.o \ diff --git a/src/lib/gssapi/krb5/accept_sec_context.c b/src/lib/gssapi/krb5/accept_sec_context.c index d340db7e7..934302cff 100644 --- a/src/lib/gssapi/krb5/accept_sec_context.c +++ b/src/lib/gssapi/krb5/accept_sec_context.c @@ -243,7 +243,7 @@ rd_and_store_for_creds(context, auth_context, inbuf, out_cred) /* copy the client principle into it... */ if ((retval = - krb5_copy_principal(context, creds[0]->client, &(cred->princ)))) { + kg_init_name(context, creds[0]->client, NULL, 0, &cred->name))) { k5_mutex_destroy(&cred->lock); retval = ENOMEM; /* out of memory? */ xfree(cred); /* clean up memory on failure */ @@ -252,7 +252,7 @@ rd_and_store_for_creds(context, auth_context, inbuf, out_cred) } cred->usage = GSS_C_INITIATE; /* we can't accept with this */ - /* cred->princ already set */ + /* cred->name already set */ cred->prerfc_mech = 1; /* this cred will work with all three mechs */ cred->rfc_mech = 1; cred->keytab = NULL; /* no keytab associated with this... */ @@ -307,7 +307,7 @@ kg_accept_dce(minor_status, context_handle, verifier_cred_handle, krb5_error_code code; krb5_gss_ctx_id_rec *ctx = 0; krb5_timestamp now; - krb5_principal name = NULL; + krb5_gss_name_t name = NULL; krb5_ui_4 nonce = 0; krb5_data ap_rep; OM_uint32 major_status = GSS_S_FAILURE; @@ -350,13 +350,8 @@ kg_accept_dce(minor_status, context_handle, verifier_cred_handle, ctx->established = 1; if (src_name) { - if ((code = krb5_copy_principal(ctx->k5_context, ctx->there, &name))) { - major_status = GSS_S_FAILURE; - goto fail; - } - /* intern the src_name */ - if (! kg_save_name((gss_name_t) name)) { - code = G_VALIDATE_FAILED; + if ((code = kg_duplicate_name(ctx->k5_context, ctx->there, + KG_INIT_NAME_INTERN, &name))) { major_status = GSS_S_FAILURE; goto fail; } @@ -420,7 +415,7 @@ kg_accept_krb5(minor_status, context_handle, krb5_address addr, *paddr; krb5_authenticator *authdat = 0; krb5_checksum reqcksum; - krb5_principal name = NULL; + krb5_gss_name_t name = NULL; krb5_ui_4 gss_flags = 0; int decode_req_message = 0; krb5_gss_ctx_id_rec *ctx = NULL; @@ -442,6 +437,7 @@ kg_accept_krb5(minor_status, context_handle, int no_encap = 0; krb5_flags ap_req_options = 0; krb5_enctype negotiated_etype; + krb5_authdata_context ad_context = NULL; code = krb5int_accessor (&kaccess, KRB5INT_ACCESS_VERSION); if (code) { @@ -587,8 +583,11 @@ kg_accept_krb5(minor_status, context_handle, goto fail; } - if ((code = krb5_rd_req(context, &auth_context, &ap_req, cred->princ, - cred->keytab, &ap_req_options, &ticket))) { + if ((code = krb5_rd_req(context, &auth_context, &ap_req, + cred->name ? cred->name->princ : NULL, + cred->keytab, + &ap_req_options, + &ticket))) { major_status = GSS_S_FAILURE; goto fail; } @@ -865,15 +864,23 @@ kg_accept_krb5(minor_status, context_handle, major_status = GSS_S_FAILURE; goto fail; } - if ((code = krb5_copy_principal(context, ticket->server, &ctx->here))) { + if ((code = kg_init_name(context, ticket->server, NULL, 0, &ctx->here))) { major_status = GSS_S_FAILURE; goto fail; } - - if ((code = krb5_copy_principal(context, authdat->client, &ctx->there))) { + if ((code = krb5_auth_con_get_authdata_context(context, auth_context, + &ad_context))) { major_status = GSS_S_FAILURE; goto fail; } + if ((code = kg_init_name(context, authdat->client, + ad_context, KG_INIT_NAME_NO_COPY, &ctx->there))) { + major_status = GSS_S_FAILURE; + goto fail; + } + /* Now owned by ctx->there */ + authdat->client = NULL; + krb5_auth_con_set_authdata_context(context, auth_context, NULL); if ((code = krb5_auth_con_getrecvsubkey(context, auth_context, &ctx->subkey))) { @@ -1092,13 +1099,8 @@ kg_accept_krb5(minor_status, context_handle, /* set the return arguments */ if (src_name) { - if ((code = krb5_copy_principal(context, ctx->there, &name))) { - major_status = GSS_S_FAILURE; - goto fail; - } - /* intern the src_name */ - if (! kg_save_name((gss_name_t) name)) { - code = G_VALIDATE_FAILED; + if ((code = kg_duplicate_name(context, ctx->there, + KG_INIT_NAME_INTERN, &name))) { major_status = GSS_S_FAILURE; goto fail; } @@ -1163,15 +1165,14 @@ fail: if (deleg_cred) { /* free memory associated with the deleg credential */ if (deleg_cred->ccache) (void)krb5_cc_close(context, deleg_cred->ccache); - if (deleg_cred->princ) - krb5_free_principal(context, deleg_cred->princ); + if (deleg_cred->name) + kg_release_name(context, 0, &deleg_cred->name); xfree(deleg_cred); } if (token.value) xfree(token.value); if (name) { - (void) kg_delete_name((gss_name_t) name); - krb5_free_principal(context, name); + (void) kg_release_name(context, 0, &name); } *minor_status = code; @@ -1212,7 +1213,7 @@ fail: krb_error_data.error = code; (void) krb5_us_timeofday(context, &krb_error_data.stime, &krb_error_data.susec); - krb_error_data.server = cred->princ; + krb_error_data.server = cred->name ? cred->name->princ : NULL; code = krb5_mk_error(context, &krb_error_data, &scratch); if (code) diff --git a/src/lib/gssapi/krb5/acquire_cred.c b/src/lib/gssapi/krb5/acquire_cred.c index 4427ed763..8f8cf1e2c 100644 --- a/src/lib/gssapi/krb5/acquire_cred.c +++ b/src/lib/gssapi/krb5/acquire_cred.c @@ -131,18 +131,18 @@ gss_krb5int_register_acceptor_identity(OM_uint32 *minor_status, } /* get credentials corresponding to a key in the krb5 keytab. - If the default name is requested, return the name in output_princ. - If output_princ is non-NULL, the caller will use or free it, regardless + If the default name is requested, return the name in output_name. + If output_name is non-NULL, the caller will use or free it, regardless of the return value. If successful, set the keytab-specific fields in cred */ static OM_uint32 -acquire_accept_cred(context, minor_status, desired_name, output_princ, cred) +acquire_accept_cred(context, minor_status, desired_name, output_name, cred) krb5_context context; OM_uint32 *minor_status; - gss_name_t desired_name; - krb5_principal *output_princ; + krb5_gss_name_t desired_name; + krb5_gss_name_t *output_name; krb5_gss_cred_id_rec *cred; { krb5_error_code code; @@ -150,7 +150,7 @@ acquire_accept_cred(context, minor_status, desired_name, output_princ, cred) krb5_keytab kt; krb5_keytab_entry entry; - *output_princ = NULL; + *output_name = NULL; cred->keytab = NULL; /* open the default keytab */ @@ -178,8 +178,8 @@ acquire_accept_cred(context, minor_status, desired_name, output_princ, cred) return(GSS_S_CRED_UNAVAIL); } - if (desired_name != GSS_C_NO_NAME) { - princ = (krb5_principal) desired_name; + if (desired_name != NULL) { + princ = desired_name->princ; if ((code = krb5_kt_get_entry(context, kt, princ, 0, 0, &entry))) { (void) krb5_kt_close(context, kt); if (code == KRB5_KT_NOTFOUND) { @@ -212,18 +212,18 @@ acquire_accept_cred(context, minor_status, desired_name, output_princ, cred) #endif /* LEAN_CLIENT */ /* get credentials corresponding to the default credential cache. - If the default name is requested, return the name in output_princ. - If output_princ is non-NULL, the caller will use or free it, regardless + If the default name is requested, return the name in output_name. + If output_name is non-NULL, the caller will use or free it, regardless of the return value. If successful, set the ccache-specific fields in cred. */ static OM_uint32 -acquire_init_cred(context, minor_status, desired_name, output_princ, cred) +acquire_init_cred(context, minor_status, desired_name, output_name, cred) krb5_context context; OM_uint32 *minor_status; - gss_name_t desired_name; - krb5_principal *output_princ; + krb5_gss_name_t desired_name; + krb5_gss_name_t *output_name; krb5_gss_cred_id_rec *cred; { krb5_error_code code; @@ -255,11 +255,10 @@ acquire_init_cred(context, minor_status, desired_name, output_princ, cred) kim_ccache kimccache = NULL; kim_identity identity = NULL; kim_credential_state state; - krb5_principal desired_princ = (krb5_principal) desired_name; err = kim_identity_create_from_krb5_principal (&identity, context, - desired_princ); + desired_name->princ); if (!err) { err = kim_ccache_create_from_client_identity (&kimccache, identity); @@ -307,7 +306,7 @@ acquire_init_cred(context, minor_status, desired_name, output_princ, cred) if ( pLeash_AcquireInitialTicketsIfNeeded ) { char ccname[256]=""; - pLeash_AcquireInitialTicketsIfNeeded(context, (krb5_principal) desired_name, ccname, sizeof(ccname)); + pLeash_AcquireInitialTicketsIfNeeded(context, desired_name->princ, ccname, sizeof(ccname)); if (!ccname[0]) { *minor_status = KRB5_CC_NOTFOUND; return(GSS_S_CRED_UNAVAIL); @@ -354,17 +353,24 @@ acquire_init_cred(context, minor_status, desired_name, output_princ, cred) return(GSS_S_FAILURE); } - if (desired_name != (gss_name_t) NULL) { - if (! krb5_principal_compare(context, princ, (krb5_principal) desired_name)) { + if (desired_name != (krb5_gss_name_t)NULL) { + if (! krb5_principal_compare(context, princ, desired_name->princ)) { (void)krb5_free_principal(context, princ); (void)krb5_cc_close(context, ccache); *minor_status = KG_CCACHE_NOMATCH; return(GSS_S_CRED_UNAVAIL); } (void)krb5_free_principal(context, princ); - princ = (krb5_principal) desired_name; + princ = desired_name->princ; } else { - *output_princ = princ; + if ((code = kg_init_name(context, princ, NULL, + KG_INIT_NAME_NO_COPY | KG_INIT_NAME_INTERN, + output_name))) { + (void)krb5_free_principal(context, princ); + (void)krb5_cc_close(context, ccache); + *minor_status = code; + return(GSS_S_FAILURE); + } } /* iterate over the ccache, find the tgt */ @@ -489,7 +495,7 @@ krb5_gss_acquire_cred(minor_status, desired_name, time_req, /* validate the name */ /*SUPPRESS 29*/ - if ((desired_name != (gss_name_t) NULL) && + if ((desired_name != GSS_C_NO_NAME) && (! kg_validate_name(desired_name))) { *minor_status = (OM_uint32) G_VALIDATE_FAILED; krb5_free_context(context); @@ -531,7 +537,7 @@ krb5_gss_acquire_cred(minor_status, desired_name, time_req, memset(cred, 0, sizeof(krb5_gss_cred_id_rec)); cred->usage = cred_usage; - cred->princ = NULL; + cred->name = NULL; cred->prerfc_mech = (req_old != 0); cred->rfc_mech = (req_new != 0); @@ -561,15 +567,15 @@ krb5_gss_acquire_cred(minor_status, desired_name, time_req, } /* if requested, acquire credentials for accepting */ - /* this will fill in cred->princ if the desired_name is not specified */ + /* this will fill in cred->name if the desired_name is not specified */ #ifndef LEAN_CLIENT if ((cred_usage == GSS_C_ACCEPT) || (cred_usage == GSS_C_BOTH)) if ((ret = acquire_accept_cred(context, minor_status, desired_name, - &(cred->princ), cred)) + &(cred->name), cred)) != GSS_S_COMPLETE) { - if (cred->princ) - krb5_free_principal(context, cred->princ); + if (cred->name) + kg_release_name(context, 0, &cred->name); k5_mutex_destroy(&cred->lock); xfree(cred); /* minor_status set by acquire_accept_cred() */ @@ -580,22 +586,22 @@ krb5_gss_acquire_cred(minor_status, desired_name, time_req, #endif /* LEAN_CLIENT */ /* if requested, acquire credentials for initiation */ - /* this will fill in cred->princ if it wasn't set above, and + /* this will fill in cred->name if it wasn't set above, and the desired_name is not specified */ if ((cred_usage == GSS_C_INITIATE) || (cred_usage == GSS_C_BOTH)) if ((ret = acquire_init_cred(context, minor_status, - cred->princ?(gss_name_t)cred->princ:desired_name, - &(cred->princ), cred)) + cred->name?cred->name:(krb5_gss_name_t)desired_name, + &cred->name, cred)) != GSS_S_COMPLETE) { #ifndef LEAN_CLIENT if (cred->keytab) krb5_kt_close(context, cred->keytab); #endif /* LEAN_CLIENT */ - if (cred->princ) - krb5_free_principal(context, cred->princ); + if (cred->name) + kg_release_name(context, 0, &cred->name); k5_mutex_destroy(&cred->lock); xfree(cred); /* minor_status set by acquire_init_cred() */ @@ -606,9 +612,10 @@ krb5_gss_acquire_cred(minor_status, desired_name, time_req, /* if the princ wasn't filled in already, fill it in now */ - if (!cred->princ && (desired_name != GSS_C_NO_NAME)) - if ((code = krb5_copy_principal(context, (krb5_principal) desired_name, - &(cred->princ)))) { + if (!cred->name && (desired_name != GSS_C_NO_NAME)) + if ((code = kg_duplicate_name(context, + (krb5_gss_name_t)desired_name, + 0, &cred->name))) { if (cred->ccache) (void)krb5_cc_close(context, cred->ccache); #ifndef LEAN_CLIENT @@ -640,8 +647,8 @@ krb5_gss_acquire_cred(minor_status, desired_name, time_req, if (cred->keytab) (void)krb5_kt_close(context, cred->keytab); #endif /* LEAN_CLIENT */ - if (cred->princ) - krb5_free_principal(context, cred->princ); + if (cred->name) + kg_release_name(context, 0, &cred->name); k5_mutex_destroy(&cred->lock); xfree(cred); *minor_status = code; @@ -673,8 +680,8 @@ krb5_gss_acquire_cred(minor_status, desired_name, time_req, if (cred->keytab) (void)krb5_kt_close(context, cred->keytab); #endif /* LEAN_CLIENT */ - if (cred->princ) - krb5_free_principal(context, cred->princ); + if (cred->name) + kg_release_name(context, 0, &cred->name); k5_mutex_destroy(&cred->lock); xfree(cred); /* *minor_status set above */ @@ -694,8 +701,8 @@ krb5_gss_acquire_cred(minor_status, desired_name, time_req, if (cred->keytab) (void)krb5_kt_close(context, cred->keytab); #endif /* LEAN_CLIENT */ - if (cred->princ) - krb5_free_principal(context, cred->princ); + if (cred->name) + kg_release_name(context, 0, &cred->name); k5_mutex_destroy(&cred->lock); xfree(cred); *minor_status = (OM_uint32) G_VALIDATE_FAILED; diff --git a/src/lib/gssapi/krb5/add_cred.c b/src/lib/gssapi/krb5/add_cred.c index 3652f918b..cb14a5c9b 100644 --- a/src/lib/gssapi/krb5/add_cred.c +++ b/src/lib/gssapi/krb5/add_cred.c @@ -170,8 +170,7 @@ krb5_gss_add_cred(minor_status, input_cred_handle, /* make sure the desired_name is the same as the existing one */ if (desired_name && - !krb5_principal_compare(context, (krb5_principal) desired_name, - cred->princ)) { + !kg_compare_name(context, (krb5_gss_name_t)desired_name, cred->name)) { *minor_status = 0; krb5_free_context(context); return(GSS_S_BAD_NAME); @@ -200,8 +199,8 @@ krb5_gss_add_cred(minor_status, input_cred_handle, new_cred->rfc_mech = cred->rfc_mech; new_cred->tgt_expire = cred->tgt_expire; - if (cred->princ) - code = krb5_copy_principal(context, cred->princ, &new_cred->princ); + if (cred->name) + code = kg_duplicate_name(context, cred->name, 0, &new_cred->name); if (code) { xfree(new_cred); @@ -214,8 +213,8 @@ krb5_gss_add_cred(minor_status, input_cred_handle, if (cred->keytab) { kttype = krb5_kt_get_type(context, cred->keytab); if ((strlen(kttype)+2) > sizeof(ktboth)) { - if (new_cred->princ) - krb5_free_principal(context, new_cred->princ); + if (new_cred->name) + kg_release_name(context, 0, &new_cred->name); xfree(new_cred); *minor_status = ENOMEM; @@ -231,8 +230,8 @@ krb5_gss_add_cred(minor_status, input_cred_handle, ktboth+strlen(ktboth), sizeof(ktboth)-strlen(ktboth)); if (code) { - if(new_cred->princ) - krb5_free_principal(context, new_cred->princ); + if(new_cred->name) + kg_release_name(context, 0, &new_cred->name); xfree(new_cred); *minor_status = code; @@ -243,8 +242,8 @@ krb5_gss_add_cred(minor_status, input_cred_handle, code = krb5_kt_resolve(context, ktboth, &new_cred->keytab); if (code) { - if (new_cred->princ) - krb5_free_principal(context, new_cred->princ); + if (new_cred->name) + kg_release_name(context, 0, &new_cred->name); xfree(new_cred); *minor_status = code; @@ -261,15 +260,17 @@ krb5_gss_add_cred(minor_status, input_cred_handle, if (cred->rcache) { /* Open the replay cache for this principal. */ + assert(cred->name->princ != NULL); + if ((code = krb5_get_server_rcache(context, - krb5_princ_component(context, cred->princ, 0), + krb5_princ_component(context, cred->name->princ, 0), &new_cred->rcache))) { #ifndef LEAN_CLIENT if (new_cred->keytab) krb5_kt_close(context, new_cred->keytab); #endif /* LEAN_CLIENT */ - if (new_cred->princ) - krb5_free_principal(context, new_cred->princ); + if (new_cred->name) + kg_release_name(context, 0, &new_cred->name); xfree(new_cred); *minor_status = code; @@ -292,8 +293,8 @@ krb5_gss_add_cred(minor_status, input_cred_handle, if (new_cred->keytab) krb5_kt_close(context, new_cred->keytab); #endif /* LEAN_CLIENT */ - if (new_cred->princ) - krb5_free_principal(context, new_cred->princ); + if (new_cred->name) + kg_release_name(context, 0, &new_cred->name); xfree(new_cred); krb5_free_context(context); @@ -314,8 +315,8 @@ krb5_gss_add_cred(minor_status, input_cred_handle, if (new_cred->keytab) krb5_kt_close(context, new_cred->keytab); #endif /* LEAN_CLIENT */ - if (new_cred->princ) - krb5_free_principal(context, new_cred->princ); + if (new_cred->name) + kg_release_name(context, 0, &new_cred->name); xfree(new_cred); *minor_status = code; @@ -338,8 +339,8 @@ krb5_gss_add_cred(minor_status, input_cred_handle, if (new_cred->keytab) krb5_kt_close(context, new_cred->keytab); #endif /* LEAN_CLIENT */ - if (new_cred->princ) - krb5_free_principal(context, new_cred->princ); + if (new_cred->name) + kg_release_name(context, 0, &new_cred->name); xfree(new_cred); krb5_free_context(context); diff --git a/src/lib/gssapi/krb5/compare_name.c b/src/lib/gssapi/krb5/compare_name.c index e456ed50a..1e106da92 100644 --- a/src/lib/gssapi/krb5/compare_name.c +++ b/src/lib/gssapi/krb5/compare_name.c @@ -54,8 +54,9 @@ krb5_gss_compare_name(minor_status, name1, name2, name_equal) } *minor_status = 0; - *name_equal = krb5_principal_compare(context, (krb5_principal) name1, - (krb5_principal) name2); + *name_equal = kg_compare_name(context, + (krb5_gss_name_t)name1, + (krb5_gss_name_t)name2); krb5_free_context(context); return(GSS_S_COMPLETE); } diff --git a/src/lib/gssapi/krb5/delete_sec_context.c b/src/lib/gssapi/krb5/delete_sec_context.c index 33e0e313e..e2da3dc98 100644 --- a/src/lib/gssapi/krb5/delete_sec_context.c +++ b/src/lib/gssapi/krb5/delete_sec_context.c @@ -88,9 +88,9 @@ krb5_gss_delete_sec_context(minor_status, context_handle, output_token) krb5_free_keyblock(context, ctx->seq); if (ctx->here) - krb5_free_principal(context, ctx->here); + kg_release_name(context, 0, &ctx->here); if (ctx->there) - krb5_free_principal(context, ctx->there); + kg_release_name(context, 0, &ctx->there); if (ctx->subkey) krb5_free_keyblock(context, ctx->subkey); if (ctx->acceptor_subkey) diff --git a/src/lib/gssapi/krb5/disp_name.c b/src/lib/gssapi/krb5/disp_name.c index d6bf0f7ba..676dc4d6b 100644 --- a/src/lib/gssapi/krb5/disp_name.c +++ b/src/lib/gssapi/krb5/disp_name.c @@ -51,7 +51,8 @@ krb5_gss_display_name(minor_status, input_name, output_name_buffer, } if ((code = krb5_unparse_name(context, - (krb5_principal) input_name, &str))) { + ((krb5_gss_name_t) input_name)->princ, + &str))) { *minor_status = code; save_error_info(*minor_status, context); krb5_free_context(context); diff --git a/src/lib/gssapi/krb5/duplicate_name.c b/src/lib/gssapi/krb5/duplicate_name.c index add3a2ed0..678349324 100644 --- a/src/lib/gssapi/krb5/duplicate_name.c +++ b/src/lib/gssapi/krb5/duplicate_name.c @@ -34,7 +34,7 @@ OM_uint32 krb5_gss_duplicate_name(OM_uint32 *minor_status, { krb5_context context; krb5_error_code code; - krb5_principal princ, outprinc; + krb5_gss_name_t princ, outprinc; if (minor_status) *minor_status = 0; @@ -53,23 +53,16 @@ OM_uint32 krb5_gss_duplicate_name(OM_uint32 *minor_status, return(GSS_S_CALL_BAD_STRUCTURE|GSS_S_BAD_NAME); } - princ = (krb5_principal)input_name; - if ((code = krb5_copy_principal(context, princ, &outprinc))) { + princ = (krb5_gss_name_t)input_name; + if ((code = kg_duplicate_name(context, princ, KG_INIT_NAME_INTERN, &outprinc))) { *minor_status = code; save_error_info(*minor_status, context); krb5_free_context(context); return(GSS_S_FAILURE); } - - if (! kg_save_name((gss_name_t) outprinc)) { - krb5_free_principal(context, outprinc); - krb5_free_context(context); - *minor_status = (OM_uint32) G_VALIDATE_FAILED; - return(GSS_S_FAILURE); - } - krb5_free_context(context); *dest_name = (gss_name_t) outprinc; + assert(kg_validate_name(*dest_name)); return(GSS_S_COMPLETE); } diff --git a/src/lib/gssapi/krb5/export_name.c b/src/lib/gssapi/krb5/export_name.c index 46664e5a0..67d9ce0b2 100644 --- a/src/lib/gssapi/krb5/export_name.c +++ b/src/lib/gssapi/krb5/export_name.c @@ -58,7 +58,7 @@ OM_uint32 krb5_gss_export_name(OM_uint32 *minor_status, return(GSS_S_CALL_BAD_STRUCTURE|GSS_S_BAD_NAME); } - if ((code = krb5_unparse_name(context, (krb5_principal) input_name, + if ((code = krb5_unparse_name(context, ((krb5_gss_name_t) input_name)->princ, &str))) { if (minor_status) *minor_status = code; diff --git a/src/lib/gssapi/krb5/gssapiP_krb5.h b/src/lib/gssapi/krb5/gssapiP_krb5.h index 48da87807..e05c5bc81 100644 --- a/src/lib/gssapi/krb5/gssapiP_krb5.h +++ b/src/lib/gssapi/krb5/gssapiP_krb5.h @@ -153,7 +153,11 @@ enum qop { /** internal types **/ -typedef krb5_principal krb5_gss_name_t; +typedef struct _krb5_gss_name_rec { + krb5_principal princ; /* immutable */ + k5_mutex_t lock; /* protects ad_context only for now */ + krb5_authdata_context ad_context; +} krb5_gss_name_rec, *krb5_gss_name_t; typedef struct _krb5_gss_cred_id_rec { /* protect against simultaneous accesses */ @@ -161,7 +165,7 @@ typedef struct _krb5_gss_cred_id_rec { /* name/type of credential */ gss_cred_usage_t usage; - krb5_principal princ; /* this is not interned as a gss_name_t */ + krb5_gss_name_t name; unsigned int prerfc_mech : 1; unsigned int rfc_mech : 1; unsigned int proxy_cred : 1; @@ -184,8 +188,8 @@ typedef struct _krb5_gss_ctx_id_rec { unsigned int seed_init : 1; /* XXX tested but never actually set */ OM_uint32 gss_flags; unsigned char seed[16]; - krb5_principal here; - krb5_principal there; + krb5_gss_name_t here; + krb5_gss_name_t there; krb5_keyblock *subkey; /*One of two potential keys to use with RFC * 4121 packets; this key must always be set.*/ int signalg; @@ -825,6 +829,86 @@ OM_uint32 gss_krb5int_unseal_token_v3(krb5_context *contextptr, int gss_krb5int_rotate_left (void *ptr, size_t bufsiz, size_t rc); +/* naming_exts.c */ +#define KG_INIT_NAME_INTERN 0x1 +#define KG_INIT_NAME_NO_COPY 0x2 + +krb5_error_code +kg_init_name(krb5_context context, + krb5_principal principal, + krb5_authdata_context ad_context, + krb5_flags flags, + krb5_gss_name_t *name); + +krb5_error_code +kg_release_name(krb5_context context, + krb5_flags flags, + krb5_gss_name_t *name); + +krb5_error_code +kg_duplicate_name(krb5_context context, + const krb5_gss_name_t src, + krb5_flags flags, + krb5_gss_name_t *dst); + +krb5_boolean +kg_compare_name(krb5_context context, + krb5_gss_name_t name1, + krb5_gss_name_t name2); + +OM_uint32 +krb5_gss_display_name_ext(OM_uint32 *minor_status, + gss_name_t name, + gss_OID display_as_name_type, + gss_buffer_t display_name); + +OM_uint32 +krb5_gss_inquire_name(OM_uint32 *minor_status, + gss_name_t name, + int *name_is_MN, + gss_OID *MN_mech, + gss_buffer_set_t *attrs); + +OM_uint32 +krb5_gss_get_name_attribute(OM_uint32 *minor_status, + gss_name_t name, + gss_buffer_t attr, + int *authenticated, + int *complete, + gss_buffer_t value, + gss_buffer_t display_value, + int *more); + +OM_uint32 +krb5_gss_set_name_attribute(OM_uint32 *minor_status, + gss_name_t name, + int complete, + gss_buffer_t attr, + gss_buffer_t value); + +OM_uint32 +krb5_gss_delete_name_attribute(OM_uint32 *minor_status, + gss_name_t name, + gss_buffer_t attr); + +OM_uint32 +krb5_gss_export_name_composite(OM_uint32 *minor_status, + gss_name_t name, + gss_buffer_t exp_composite_name); + +OM_uint32 +krb5_gss_map_name_to_any(OM_uint32 *minor_status, + gss_name_t name, + int authenticated, + gss_buffer_t type_id, + gss_any_t *output); + +OM_uint32 +krb5_gss_release_any_name_mapping(OM_uint32 *minor_status, + gss_name_t name, + gss_buffer_t type_id, + gss_any_t *input); + /* s4u_gss_glue.c */ OM_uint32 kg_compose_deleg_cred(OM_uint32 *minor_status, @@ -837,7 +921,6 @@ kg_compose_deleg_cred(OM_uint32 *minor_status, OM_uint32 *time_rec, krb5_context context); - /* * These take unglued krb5-mech-specific contexts. */ diff --git a/src/lib/gssapi/krb5/gssapi_krb5.c b/src/lib/gssapi/krb5/gssapi_krb5.c index 3c1c6b8cb..351bead8a 100644 --- a/src/lib/gssapi/krb5/gssapi_krb5.c +++ b/src/lib/gssapi/krb5/gssapi_krb5.c @@ -681,6 +681,14 @@ static struct gss_config krb5_mechanism = { NULL, /* complete_auth_token */ krb5_gss_acquire_cred_impersonate_name, NULL, /* krb5_gss_add_cred_impersonate_name */ + NULL, /* display_name_ext */ + krb5_gss_inquire_name, + krb5_gss_get_name_attribute, + krb5_gss_set_name_attribute, + krb5_gss_delete_name_attribute, + krb5_gss_export_name_composite, + krb5_gss_map_name_to_any, + krb5_gss_release_any_name_mapping, }; diff --git a/src/lib/gssapi/krb5/import_name.c b/src/lib/gssapi/krb5/import_name.c index 6879c766f..b33619583 100644 --- a/src/lib/gssapi/krb5/import_name.c +++ b/src/lib/gssapi/krb5/import_name.c @@ -45,6 +45,39 @@ * GSS_S_FAILURE if memory allocation fails */ +/* + * Import serialized authdata context + */ +static krb5_error_code +import_name_composite(krb5_context context, + unsigned char *enc_data, size_t enc_length, + krb5_authdata_context *pad_context) +{ + krb5_authdata_context ad_context; + krb5_error_code code; + krb5_data data; + + code = krb5_authdata_context_init(context, &ad_context); + if (code != 0) + return code; + + data.data = (char *)enc_data; + data.length = enc_length; + + code = krb5_authdata_import_attributes(context, + ad_context, + AD_USAGE_MASK, + &data); + if (code != 0) { + krb5_authdata_context_free(context, ad_context); + return code; + } + + *pad_context = ad_context; + + return 0; +} + OM_uint32 krb5_gss_import_name(minor_status, input_name_buffer, input_name_type, output_name) @@ -54,13 +87,16 @@ krb5_gss_import_name(minor_status, input_name_buffer, gss_name_t *output_name; { krb5_context context; - krb5_principal princ; + krb5_principal princ = NULL; krb5_error_code code; - char *stringrep, *tmp, *tmp2, *cp; - OM_uint32 length; + unsigned char *cp, *end; + char *tmp, *stringrep, *tmp2; + ssize_t length; #ifndef NO_PASSWORD struct passwd *pw; #endif + int has_ad = 0; + krb5_authdata_context ad_context = NULL; code = krb5_gss_init_context(&context); if (code) { @@ -81,7 +117,7 @@ krb5_gss_import_name(minor_status, input_name_buffer, char *service, *host; if ((tmp = - (char *) xmalloc(input_name_buffer->length + 1)) == NULL) { + xmalloc(input_name_buffer->length + 1)) == NULL) { *minor_status = ENOMEM; krb5_free_context(context); return(GSS_S_FAILURE); @@ -155,28 +191,49 @@ krb5_gss_import_name(minor_status, input_name_buffer, goto do_getpwuid; #endif } else if (g_OID_equal(input_name_type, gss_nt_exported_name)) { - cp = tmp; +#define BOUNDS_CHECK(cp, end, n) do { if ((end) - (cp) < (n)) goto fail_name; } while (0) + cp = (unsigned char *)tmp; + end = cp + input_name_buffer->length; + + BOUNDS_CHECK(cp, end, 2); if (*cp++ != 0x04) goto fail_name; - if (*cp++ != 0x01) + switch (*cp++) { + case 0x01: + break; + case 0x02: + has_ad++; + break; + default: goto fail_name; + } + + BOUNDS_CHECK(cp, end, 2); if (*cp++ != 0x00) goto fail_name; length = *cp++; - if (length != gss_mech_krb5->length+2) + if (length != (ssize_t)gss_mech_krb5->length+2) goto fail_name; + + BOUNDS_CHECK(cp, end, 2); if (*cp++ != 0x06) goto fail_name; length = *cp++; - if (length != gss_mech_krb5->length) + if (length != (ssize_t)gss_mech_krb5->length) goto fail_name; + + BOUNDS_CHECK(cp, end, length); if (memcmp(cp, gss_mech_krb5->elements, length) != 0) goto fail_name; cp += length; + + BOUNDS_CHECK(cp, end, 4); length = *cp++; length = (length << 8) | *cp++; length = (length << 8) | *cp++; length = (length << 8) | *cp++; + + BOUNDS_CHECK(cp, end, length); tmp2 = malloc(length+1); if (tmp2 == NULL) { xfree(tmp); @@ -184,10 +241,27 @@ krb5_gss_import_name(minor_status, input_name_buffer, krb5_free_context(context); return GSS_S_FAILURE; } - strncpy(tmp2, cp, length); + strncpy(tmp2, (char *)cp, length); tmp2[length] = 0; - stringrep = tmp2; + cp += length; + + if (has_ad) { + BOUNDS_CHECK(cp, end, 4); + length = *cp++; + length = (length << 8) | *cp++; + length = (length << 8) | *cp++; + length = (length << 8) | *cp++; + + BOUNDS_CHECK(cp, end, length); + code = import_name_composite(context, + cp, length, + &ad_context); + if (code != 0) + goto fail_name; + cp += length; + } + assert(cp == end); } else { xfree(tmp); krb5_free_context(context); @@ -218,16 +292,21 @@ krb5_gss_import_name(minor_status, input_name_buffer, if (code) { *minor_status = (OM_uint32) code; save_error_info(*minor_status, context); + krb5_authdata_context_free(context, ad_context); krb5_free_context(context); return(GSS_S_BAD_NAME); } /* save the name in the validation database */ - - if (! kg_save_name((gss_name_t) princ)) { + code = kg_init_name(context, princ, ad_context, + KG_INIT_NAME_INTERN | KG_INIT_NAME_NO_COPY, + (krb5_gss_name_t *)output_name); + if (code != 0) { + *minor_status = (OM_uint32) code; + save_error_info(*minor_status, context); krb5_free_principal(context, princ); + krb5_authdata_context_free(context, ad_context); krb5_free_context(context); - *minor_status = (OM_uint32) G_VALIDATE_FAILED; return(GSS_S_FAILURE); } @@ -235,6 +314,5 @@ krb5_gss_import_name(minor_status, input_name_buffer, /* return it */ - *output_name = (gss_name_t) princ; return(GSS_S_COMPLETE); } diff --git a/src/lib/gssapi/krb5/init_sec_context.c b/src/lib/gssapi/krb5/init_sec_context.c index 0bb4fde02..62e7d6ed7 100644 --- a/src/lib/gssapi/krb5/init_sec_context.c +++ b/src/lib/gssapi/krb5/init_sec_context.c @@ -122,7 +122,7 @@ static krb5_error_code get_credentials(context, cred, server, now, endtime, out_creds) krb5_context context; krb5_gss_cred_id_t cred; - krb5_principal server; + krb5_gss_name_t server; krb5_timestamp now; krb5_timestamp endtime; krb5_creds **out_creds; @@ -137,6 +137,8 @@ static krb5_error_code get_credentials(context, cred, server, now, memset(&evidence_creds, 0, sizeof(krb5_creds)); in_creds.client = in_creds.server = NULL; + assert(cred->name != NULL); + if ((code = krb5_cc_get_principal(context, cred->ccache, &cc_princ))) goto cleanup; @@ -146,7 +148,7 @@ static krb5_error_code get_credentials(context, cred, server, now, * we can just use the S4U2Self or evidence ticket directly). */ if (cred->proxy_cred && - !krb5_principal_compare(context, cc_princ, server)) { + !krb5_principal_compare(context, cc_princ, server->princ)) { krb5_creds mcreds; flags |= KRB5_GC_CANONICALIZE | @@ -158,10 +160,11 @@ static krb5_error_code get_credentials(context, cred, server, now, mcreds.magic = KV5M_CREDS; mcreds.times.endtime = cred->tgt_expire; mcreds.server = cc_princ; - mcreds.client = cred->princ; + mcreds.client = cred->name->princ; code = krb5_cc_retrieve_cred(context, cred->ccache, - KRB5_TC_MATCH_TIMES, &mcreds, + KRB5_TC_MATCH_TIMES | KRB5_TC_MATCH_AUTHDATA, + &mcreds, &evidence_creds); if (code) goto cleanup; @@ -171,11 +174,26 @@ static krb5_error_code get_credentials(context, cred, server, now, in_creds.client = cc_princ; in_creds.second_ticket = evidence_creds.ticket; } else { - in_creds.client = cred->princ; + in_creds.client = cred->name->princ; } - in_creds.server = server; + in_creds.server = server->princ; in_creds.times.endtime = endtime; + in_creds.authdata = NULL; + in_creds.keyblock.enctype = 0; + + /* + * cred->name is immutable, so there is no need to acquire + * cred->name->lock. + */ + if (cred->name->ad_context != NULL) { + code = krb5_authdata_export_authdata(context, + cred->name->ad_context, + AD_USAGE_TGS_REQ, + &in_creds.authdata); + if (code != 0) + goto cleanup; + } code = krb5_get_credentials(context, flags, cred->ccache, &in_creds, out_creds); @@ -183,7 +201,7 @@ static krb5_error_code get_credentials(context, cred, server, now, goto cleanup; if (flags & KRB5_GC_CONSTRAINED_DELEGATION) { - if (!krb5_principal_compare(context, cred->princ, + if (!krb5_principal_compare(context, cred->name->princ, (*out_creds)->client)) { /* server did not support constrained delegation */ code = KRB5_KDCREP_MODIFIED; @@ -203,8 +221,8 @@ static krb5_error_code get_credentials(context, cred, server, now, } cleanup: - if (cc_princ) - krb5_free_principal(context, cc_princ); + krb5_free_authdata(context, in_creds.authdata); + krb5_free_principal(context, cc_princ); krb5_free_cred_contents(context, &evidence_creds); return code; @@ -242,8 +260,10 @@ make_gss_checksum (krb5_context context, krb5_auth_context auth_context, krb5_auth_con_setflags(context, auth_context, con_flags & ~KRB5_AUTH_CONTEXT_DO_TIME); + assert(data->cred->name != NULL); + code = krb5_fwd_tgt_creds(context, auth_context, 0, - data->cred->princ, data->ctx->there, + data->cred->name->princ, data->ctx->there->princ, data->cred->ccache, 1, &credmsg); @@ -318,11 +338,13 @@ make_gss_checksum (krb5_context context, krb5_auth_context auth_context, } static krb5_error_code -make_ap_req_v1(context, ctx, cred, k_cred, chan_bindings, mech_type, token) +make_ap_req_v1(context, ctx, cred, k_cred, ad_context, + chan_bindings, mech_type, token) krb5_context context; krb5_gss_ctx_id_rec *ctx; krb5_gss_cred_id_t cred; krb5_creds *k_cred; + krb5_authdata_context ad_context; gss_channel_bindings_t chan_bindings; gss_OID mech_type; gss_buffer_t token; @@ -375,8 +397,10 @@ make_ap_req_v1(context, ctx, cred, k_cred, chan_bindings, mech_type, token) if (ctx->gss_flags & GSS_C_MUTUAL_FLAG) mk_req_flags |= AP_OPTS_MUTUAL_REQUIRED | AP_OPTS_ETYPE_NEGOTIATION; + krb5_auth_con_set_authdata_context(context, ctx->auth_context, ad_context); code = krb5_mk_req_extended(context, &ctx->auth_context, mk_req_flags, checksum_data, k_cred, &ap_req); + krb5_auth_con_set_authdata_context(context, ctx->auth_context, NULL); krb5_free_data_contents(context, &cksum_struct.checksum_data); if (code) goto cleanup; @@ -526,11 +550,10 @@ kg_new_connection( ctx->krb_times.endtime = now + time_req; } - if ((code = krb5_copy_principal(context, cred->princ, &ctx->here))) + if ((code = kg_duplicate_name(context, cred->name, 0, &ctx->here))) goto fail; - if ((code = krb5_copy_principal(context, (krb5_principal) target_name, - &ctx->there))) + if ((code = kg_duplicate_name(context, (krb5_gss_name_t)target_name, 0, &ctx->there))) goto fail; code = get_credentials(context, cred, ctx->there, now, @@ -566,7 +589,8 @@ kg_new_connection( /* gsskrb5 v1 */ krb5_int32 seq_temp; if ((code = make_ap_req_v1(context, ctx, - cred, k_cred, input_chan_bindings, + cred, k_cred, ctx->here->ad_context, + input_chan_bindings, mech_type, &token))) { if ((code == KRB5_FCC_NOFILE) || (code == KRB5_CC_NOTFOUND) || (code == KG_EMPTY_CCACHE)) @@ -640,9 +664,9 @@ fail: if (ctx_free->auth_context) krb5_auth_con_free(context, ctx_free->auth_context); if (ctx_free->here) - krb5_free_principal(context, ctx_free->here); + kg_release_name(context, 0, &ctx_free->here); if (ctx_free->there) - krb5_free_principal(context, ctx_free->there); + kg_release_name(context, 0, &ctx_free->there); if (ctx_free->subkey) krb5_free_keyblock(context, ctx_free->subkey); xfree(ctx_free); @@ -709,8 +733,7 @@ mutual_auth( goto fail; } - if (! krb5_principal_compare(context, ctx->there, - (krb5_principal) target_name)) { + if (! kg_compare_name(context, ctx->there, (krb5_gss_name_t)target_name)) { (void)krb5_gss_delete_sec_context(minor_status, context_handle, NULL); code = 0; diff --git a/src/lib/gssapi/krb5/inq_context.c b/src/lib/gssapi/krb5/inq_context.c index f3e44cdf5..fbc389245 100644 --- a/src/lib/gssapi/krb5/inq_context.c +++ b/src/lib/gssapi/krb5/inq_context.c @@ -94,7 +94,7 @@ krb5_gss_inquire_context(minor_status, context_handle, initiator_name, krb5_context context; krb5_error_code code; krb5_gss_ctx_id_rec *ctx; - krb5_principal initiator, acceptor; + krb5_gss_name_t initiator, acceptor; krb5_timestamp now; krb5_deltat lifetime; @@ -130,38 +130,28 @@ krb5_gss_inquire_context(minor_status, context_handle, initiator_name, lifetime = 0; if (initiator_name) { - if ((code = krb5_copy_principal(context, - ctx->initiate?ctx->here:ctx->there, - &initiator))) { + if ((code = kg_duplicate_name(context, + ctx->initiate?ctx->here:ctx->there, + KG_INIT_NAME_INTERN, + &initiator))) { *minor_status = code; save_error_info(*minor_status, context); return(GSS_S_FAILURE); } - if (! kg_save_name((gss_name_t) initiator)) { - krb5_free_principal(context, initiator); - *minor_status = (OM_uint32) G_VALIDATE_FAILED; - return(GSS_S_FAILURE); - } } if (acceptor_name) { - if ((code = krb5_copy_principal(context, - ctx->initiate?ctx->there:ctx->here, - &acceptor))) { - if (initiator) krb5_free_principal(context, initiator); + if ((code = kg_duplicate_name(context, + ctx->initiate?ctx->there:ctx->here, + KG_INIT_NAME_INTERN, + &acceptor))) { + if (initiator) + kg_release_name(context, KG_INIT_NAME_INTERN, + &initiator); *minor_status = code; save_error_info(*minor_status, context); return(GSS_S_FAILURE); } - if (! kg_save_name((gss_name_t) acceptor)) { - krb5_free_principal(context, acceptor); - if (initiator) { - kg_delete_name((gss_name_t) initiator); - krb5_free_principal(context, initiator); - } - *minor_status = (OM_uint32) G_VALIDATE_FAILED; - return(GSS_S_FAILURE); - } } if (initiator_name) diff --git a/src/lib/gssapi/krb5/inq_cred.c b/src/lib/gssapi/krb5/inq_cred.c index 8560135ab..5c358eb9f 100644 --- a/src/lib/gssapi/krb5/inq_cred.c +++ b/src/lib/gssapi/krb5/inq_cred.c @@ -88,7 +88,7 @@ krb5_gss_inquire_cred(minor_status, cred_handle, name, lifetime_ret, krb5_error_code code; krb5_timestamp now; krb5_deltat lifetime; - krb5_principal ret_name; + krb5_gss_name_t ret_name; gss_OID_set mechs; OM_uint32 ret; @@ -145,8 +145,9 @@ krb5_gss_inquire_cred(minor_status, cred_handle, name, lifetime_ret, lifetime = GSS_C_INDEFINITE; if (name) { - if (cred->princ && - (code = krb5_copy_principal(context, cred->princ, &ret_name))) { + if (cred->name && + (code = kg_duplicate_name(context, cred->name, + KG_INIT_NAME_INTERN, &ret_name))) { k5_mutex_unlock(&cred->lock); *minor_status = code; save_error_info(*minor_status, context); @@ -168,24 +169,13 @@ krb5_gss_inquire_cred(minor_status, cred_handle, name, lifetime_ret, &mechs)))) { k5_mutex_unlock(&cred->lock); if (ret_name) - krb5_free_principal(context, ret_name); + kg_release_name(context, KG_INIT_NAME_INTERN, &ret_name); /* *minor_status set above */ goto fail; } } if (name) { - if (ret_name != NULL && ! kg_save_name((gss_name_t) ret_name)) { - k5_mutex_unlock(&cred->lock); - if (cred_handle == GSS_C_NO_CREDENTIAL) - krb5_gss_release_cred(minor_status, (gss_cred_id_t *)&cred); - - (void) generic_gss_release_oid_set(minor_status, &mechs); - krb5_free_principal(context, ret_name); - *minor_status = (OM_uint32) G_VALIDATE_FAILED; - krb5_free_context(context); - return(GSS_S_FAILURE); - } if (ret_name != NULL) *name = (gss_name_t) ret_name; else diff --git a/src/lib/gssapi/krb5/naming_exts.c b/src/lib/gssapi/krb5/naming_exts.c new file mode 100644 index 000000000..14b9b006d --- /dev/null +++ b/src/lib/gssapi/krb5/naming_exts.c @@ -0,0 +1,722 @@ +/* -*- mode: c; indent-tabs-mode: nil -*- */ +/* + * lib/gssapi/krb5/naming_exts.c + * + * Copyright 2009 by the Massachusetts Institute of Technology. + * All Rights Reserved. + * + * Export of this software from the United States of America may + * require a specific license from the United States Government. + * It is the responsibility of any person or organization contemplating + * export to obtain such a license before exporting. + * + * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and + * distribute this software and its documentation for any purpose and + * without fee is hereby granted, provided that the above copyright + * notice appear in all copies and that both that copyright notice and + * this permission notice appear in supporting documentation, and that + * the name of M.I.T. not be used in advertising or publicity pertaining + * to distribution of the software without specific, written prior + * permission. Furthermore if you modify this software you must label + * your software as modified software and not distribute it in such a + * fashion that it might be confused with the original M.I.T. software. + * M.I.T. makes no representations about the suitability of + * this software for any purpose. It is provided "as is" without express + * or implied warranty. + * + * + */ + +#include +#include "k5-int.h" /* for zap() */ +#include "gssapiP_krb5.h" +#include + +krb5_error_code +kg_init_name(krb5_context context, + krb5_principal principal, + krb5_authdata_context ad_context, + krb5_flags flags, + krb5_gss_name_t *ret_name) +{ + krb5_error_code code; + krb5_gss_name_t name; + + *ret_name = NULL; + + assert(principal != NULL); + + if (principal == NULL) + return EINVAL; + + name = xmalloc(sizeof(krb5_gss_name_rec)); + if (name == NULL) + return ENOMEM; + + memset(name, 0, sizeof(krb5_gss_name_rec)); + + code = k5_mutex_init(&name->lock); + if (code != 0) + goto cleanup; + + if ((flags & KG_INIT_NAME_NO_COPY) == 0) { + code = krb5_copy_principal(context, principal, &name->princ); + if (code != 0) + goto cleanup; + + if (ad_context != NULL) { + code = krb5_authdata_context_copy(context, + ad_context, + &name->ad_context); + if (code != 0) + goto cleanup; + } + } else { + name->princ = principal; + name->ad_context = ad_context; + } + + if ((flags & KG_INIT_NAME_INTERN) && + !kg_save_name((gss_name_t)name)) { + code = G_VALIDATE_FAILED; + goto cleanup; + } + + *ret_name = name; + +cleanup: + if (code != 0) + kg_release_name(context, 0, &name); + + return code; +} + +krb5_error_code +kg_release_name(krb5_context context, + krb5_flags flags, + krb5_gss_name_t *name) +{ + if (*name != NULL) { + if (flags & KG_INIT_NAME_INTERN) + kg_delete_name((gss_name_t)*name); + krb5_free_principal(context, (*name)->princ); + krb5_authdata_context_free(context, (*name)->ad_context); + k5_mutex_destroy(&(*name)->lock); + free(*name); + *name = NULL; + } + + return 0; +} + +krb5_error_code +kg_duplicate_name(krb5_context context, + const krb5_gss_name_t src, + krb5_flags flags, + krb5_gss_name_t *dst) +{ + krb5_error_code code; + + code = k5_mutex_lock(&src->lock); + if (code != 0) + return code; + + code = kg_init_name(context, src->princ, + src->ad_context, flags, dst); + + k5_mutex_unlock(&src->lock); + + return code; +} + + +krb5_boolean +kg_compare_name(krb5_context context, + krb5_gss_name_t name1, + krb5_gss_name_t name2) +{ + return krb5_principal_compare(context, name1->princ, name2->princ); +} + +static OM_uint32 +kg_map_name_error(OM_uint32 *minor_status, krb5_error_code code) +{ + OM_uint32 major_status; + + switch (code) { + case 0: + major_status = GSS_S_COMPLETE; + break; + case ENOENT: + case EPERM: + major_status = GSS_S_UNAVAILABLE; + break; + default: + major_status = GSS_S_FAILURE; + break; + } + + *minor_status = code; + + return major_status; +} + +/* Owns data on success */ +static krb5_error_code +kg_data_list_to_buffer_set_nocopy(krb5_data **pdata, + gss_buffer_set_t *buffer_set) +{ + gss_buffer_set_t set; + OM_uint32 minor_status; + unsigned int i; + krb5_data *data; + + data = *pdata; + + if (data == NULL) { + if (buffer_set != NULL) + *buffer_set = GSS_C_NO_BUFFER_SET; + return 0; + } else if (buffer_set == NULL) + return EINVAL; + + if (GSS_ERROR(gss_create_empty_buffer_set(&minor_status, + &set))) { + assert(minor_status != 0); + return minor_status; + } + + for (i = 0; data[i].data != NULL; i++) + ; + + set->count = i; + set->elements = calloc(i, sizeof(gss_buffer_desc)); + if (set->elements == NULL) { + gss_release_buffer_set(&minor_status, &set); + return ENOMEM; + } + + for (i = 0; i < set->count; i++) { + set->elements[i].length = data[i].length; + set->elements[i].value = data[i].data; + } + + free(data); + *pdata = NULL; + + *buffer_set = set; + + return 0; +} + +OM_uint32 +krb5_gss_inquire_name(OM_uint32 *minor_status, + gss_name_t name, + int *name_is_MN, + gss_OID *MN_mech, + gss_buffer_set_t *attrs) +{ + krb5_context context; + krb5_error_code code; + krb5_gss_name_t kname; + krb5_data *kattrs = NULL; + + if (minor_status != NULL) + *minor_status = 0; + + if (attrs != NULL) + *attrs = GSS_C_NO_BUFFER_SET; + + code = krb5_gss_init_context(&context); + if (code != 0) { + *minor_status = code; + return GSS_S_FAILURE; + } + + if (!kg_validate_name(name)) { + *minor_status = (OM_uint32)G_VALIDATE_FAILED; + krb5_free_context(context); + return GSS_S_CALL_BAD_STRUCTURE|GSS_S_BAD_NAME; + } + + kname = (krb5_gss_name_t)name; + + code = k5_mutex_lock(&kname->lock); + if (code != 0) { + *minor_status = code; + return GSS_S_FAILURE; + } + + if (kname->ad_context == NULL) { + code = krb5_authdata_context_init(context, &kname->ad_context); + if (code != 0) + goto cleanup; + } + + code = krb5_authdata_get_attribute_types(context, + kname->ad_context, + &kattrs); + if (code != 0) + goto cleanup; + + code = kg_data_list_to_buffer_set_nocopy(&kattrs, attrs); + if (code != 0) + goto cleanup; + +cleanup: + k5_mutex_unlock(&kname->lock); + krb5int_free_data_list(context, kattrs); + + krb5_free_context(context); + + return kg_map_name_error(minor_status, code); +} + +OM_uint32 +krb5_gss_get_name_attribute(OM_uint32 *minor_status, + gss_name_t name, + gss_buffer_t attr, + int *authenticated, + int *complete, + gss_buffer_t value, + gss_buffer_t display_value, + int *more) +{ + krb5_context context; + krb5_error_code code; + krb5_gss_name_t kname; + krb5_data kattr; + krb5_boolean kauthenticated; + krb5_boolean kcomplete; + krb5_data kvalue; + krb5_data kdisplay_value; + + if (minor_status != NULL) + *minor_status = 0; + + code = krb5_gss_init_context(&context); + if (code != 0) { + *minor_status = code; + return GSS_S_FAILURE; + } + + if (!kg_validate_name(name)) { + *minor_status = (OM_uint32)G_VALIDATE_FAILED; + krb5_free_context(context); + return GSS_S_CALL_BAD_STRUCTURE|GSS_S_BAD_NAME; + } + + kname = (krb5_gss_name_t)name; + + code = k5_mutex_lock(&kname->lock); + if (code != 0) { + *minor_status = code; + krb5_free_context(context); + return GSS_S_FAILURE; + } + + if (kname->ad_context == NULL) { + code = krb5_authdata_context_init(context, &kname->ad_context); + if (code != 0) { + *minor_status = code; + k5_mutex_unlock(&kname->lock); + krb5_free_context(context); + return GSS_S_UNAVAILABLE; + } + } + + kattr.data = (char *)attr->value; + kattr.length = attr->length; + + kauthenticated = FALSE; + kcomplete = FALSE; + + code = krb5_authdata_get_attribute(context, + kname->ad_context, + &kattr, + &kauthenticated, + &kcomplete, + value ? &kvalue : NULL, + display_value ? &kdisplay_value : NULL, + more); + if (code == 0) { + if (value != NULL) { + value->value = kvalue.data; + value->length = kvalue.length; + } + + if (authenticated != NULL) + *authenticated = kauthenticated; + if (complete != NULL) + *complete = kcomplete; + + if (display_value != NULL) { + display_value->value = kdisplay_value.data; + display_value->length = kdisplay_value.length; + } + } + + k5_mutex_unlock(&kname->lock); + krb5_free_context(context); + + return kg_map_name_error(minor_status, code); +} + +OM_uint32 +krb5_gss_set_name_attribute(OM_uint32 *minor_status, + gss_name_t name, + int complete, + gss_buffer_t attr, + gss_buffer_t value) +{ + krb5_context context; + krb5_error_code code; + krb5_gss_name_t kname; + krb5_data kattr; + krb5_data kvalue; + + if (minor_status != NULL) + *minor_status = 0; + + code = krb5_gss_init_context(&context); + if (code != 0) { + *minor_status = code; + return GSS_S_FAILURE; + } + + if (!kg_validate_name(name)) { + *minor_status = (OM_uint32)G_VALIDATE_FAILED; + krb5_free_context(context); + return GSS_S_CALL_BAD_STRUCTURE|GSS_S_BAD_NAME; + } + + kname = (krb5_gss_name_t)name; + + code = k5_mutex_lock(&kname->lock); + if (code != 0) { + *minor_status = code; + return GSS_S_FAILURE; + } + + if (kname->ad_context == NULL) { + code = krb5_authdata_context_init(context, &kname->ad_context); + if (code != 0) { + *minor_status = code; + k5_mutex_unlock(&kname->lock); + krb5_free_context(context); + return GSS_S_UNAVAILABLE; + } + } + + kattr.data = (char *)attr->value; + kattr.length = attr->length; + + kvalue.data = (char *)value->value; + kvalue.length = value->length; + + code = krb5_authdata_set_attribute(context, + kname->ad_context, + complete, + &kattr, + &kvalue); + + k5_mutex_unlock(&kname->lock); + krb5_free_context(context); + + return kg_map_name_error(minor_status, code); +} + +OM_uint32 +krb5_gss_delete_name_attribute(OM_uint32 *minor_status, + gss_name_t name, + gss_buffer_t attr) +{ + krb5_context context; + krb5_error_code code; + krb5_gss_name_t kname; + krb5_data kattr; + + if (minor_status != NULL) + *minor_status = 0; + + code = krb5_gss_init_context(&context); + if (code != 0) { + *minor_status = code; + return GSS_S_FAILURE; + } + + if (!kg_validate_name(name)) { + *minor_status = (OM_uint32)G_VALIDATE_FAILED; + krb5_free_context(context); + return GSS_S_CALL_BAD_STRUCTURE|GSS_S_BAD_NAME; + } + + kname = (krb5_gss_name_t)name; + + code = k5_mutex_lock(&kname->lock); + if (code != 0) { + *minor_status = code; + return GSS_S_FAILURE; + } + + if (kname->ad_context == NULL) { + code = krb5_authdata_context_init(context, &kname->ad_context); + if (code != 0) { + *minor_status = code; + k5_mutex_unlock(&kname->lock); + krb5_free_context(context); + return GSS_S_UNAVAILABLE; + } + } + + kattr.data = (char *)attr->value; + kattr.length = attr->length; + + code = krb5_authdata_delete_attribute(context, + kname->ad_context, + &kattr); + + k5_mutex_unlock(&kname->lock); + krb5_free_context(context); + + return kg_map_name_error(minor_status, code); +} + +OM_uint32 +krb5_gss_map_name_to_any(OM_uint32 *minor_status, + gss_name_t name, + int authenticated, + gss_buffer_t type_id, + gss_any_t *output) +{ + krb5_context context; + krb5_error_code code; + krb5_gss_name_t kname; + char *kmodule; + + if (minor_status != NULL) + *minor_status = 0; + + code = krb5_gss_init_context(&context); + if (code != 0) { + *minor_status = code; + return GSS_S_FAILURE; + } + + if (!kg_validate_name(name)) { + *minor_status = (OM_uint32)G_VALIDATE_FAILED; + krb5_free_context(context); + return GSS_S_CALL_BAD_STRUCTURE|GSS_S_BAD_NAME; + } + + kname = (krb5_gss_name_t)name; + + code = k5_mutex_lock(&kname->lock); + if (code != 0) { + *minor_status = code; + return GSS_S_FAILURE; + } + + if (kname->ad_context == NULL) { + code = krb5_authdata_context_init(context, &kname->ad_context); + if (code != 0) { + *minor_status = code; + k5_mutex_unlock(&kname->lock); + krb5_free_context(context); + return GSS_S_UNAVAILABLE; + } + } + + kmodule = (char *)type_id->value; + if (kmodule[type_id->length] != '\0') { + k5_mutex_unlock(&kname->lock); + krb5_free_context(context); + return GSS_S_UNAVAILABLE; + } + + code = krb5_authdata_export_internal(context, + kname->ad_context, + authenticated, + kmodule, + (void **)output); + + k5_mutex_unlock(&kname->lock); + krb5_free_context(context); + + return kg_map_name_error(minor_status, code); +} + +OM_uint32 +krb5_gss_release_any_name_mapping(OM_uint32 *minor_status, + gss_name_t name, + gss_buffer_t type_id, + gss_any_t *input) +{ + krb5_context context; + krb5_error_code code; + krb5_gss_name_t kname; + char *kmodule; + + if (minor_status != NULL) + *minor_status = 0; + + code = krb5_gss_init_context(&context); + if (code != 0) { + *minor_status = code; + return GSS_S_FAILURE; + } + + if (!kg_validate_name(name)) { + *minor_status = (OM_uint32)G_VALIDATE_FAILED; + krb5_free_context(context); + return GSS_S_CALL_BAD_STRUCTURE|GSS_S_BAD_NAME; + } + + kname = (krb5_gss_name_t)name; + + code = k5_mutex_lock(&kname->lock); + if (code != 0) { + *minor_status = code; + return GSS_S_FAILURE; + } + + if (kname->ad_context == NULL) { + code = krb5_authdata_context_init(context, &kname->ad_context); + if (code != 0) { + *minor_status = code; + k5_mutex_unlock(&kname->lock); + krb5_free_context(context); + return GSS_S_UNAVAILABLE; + } + } + + kmodule = (char *)type_id->value; + if (kmodule[type_id->length] != '\0') { + k5_mutex_unlock(&kname->lock); + krb5_free_context(context); + return GSS_S_UNAVAILABLE; + } + + code = krb5_authdata_free_internal(context, + kname->ad_context, + kmodule, + *input); + if (code == 0) + *input = NULL; + + k5_mutex_unlock(&kname->lock); + krb5_free_context(context); + + return kg_map_name_error(minor_status, code); + +} + +OM_uint32 +krb5_gss_export_name_composite(OM_uint32 *minor_status, + gss_name_t name, + gss_buffer_t exp_composite_name) +{ + krb5_context context; + krb5_error_code code; + krb5_gss_name_t kname; + krb5_data *attrs = NULL; + char *princstr = NULL; + unsigned char *cp; + size_t princlen; + + if (minor_status != NULL) + *minor_status = 0; + + code = krb5_gss_init_context(&context); + if (code != 0) { + *minor_status = code; + return GSS_S_FAILURE; + } + + if (!kg_validate_name(name)) { + *minor_status = (OM_uint32)G_VALIDATE_FAILED; + krb5_free_context(context); + return GSS_S_CALL_BAD_STRUCTURE|GSS_S_BAD_NAME; + } + + kname = (krb5_gss_name_t)name; + + code = k5_mutex_lock(&kname->lock); + if (code != 0) { + *minor_status = code; + return GSS_S_FAILURE; + } + + code = krb5_unparse_name(context, kname->princ, &princstr); + if (code != 0) + goto cleanup; + + princlen = strlen(princstr); + + if (kname->ad_context != NULL) { + code = krb5_authdata_export_attributes(context, + kname->ad_context, + AD_USAGE_MASK, + &attrs); + if (code != 0) + goto cleanup; + } + + /* 04 02 OID Name AuthData */ + + exp_composite_name->length = 10 + gss_mech_krb5->length + princlen; + if (attrs != NULL) + exp_composite_name->length += 4 + attrs->length; + exp_composite_name->value = malloc(exp_composite_name->length); + if (exp_composite_name->value == NULL) { + code = ENOMEM; + goto cleanup; + } + + cp = exp_composite_name->value; + + /* Note: we assume the OID will be less than 128 bytes... */ + *cp++ = 0x04; + if (attrs != NULL) + *cp++ = 0x02; + else + *cp++ = 0x01; + + store_16_be(gss_mech_krb5->length + 2, cp); + cp += 2; + *cp++ = 0x06; + *cp++ = (gss_mech_krb5->length) & 0xFF; + memcpy(cp, gss_mech_krb5->elements, gss_mech_krb5->length); + cp += gss_mech_krb5->length; + + store_32_be(princlen, cp); + cp += 4; + memcpy(cp, princstr, princlen); + cp += princlen; + + if (attrs != NULL) { + store_32_be(attrs->length, cp); + cp += 4; + memcpy(cp, attrs->data, attrs->length); + cp += attrs->length; + } + +cleanup: + krb5_free_unparsed_name(context, princstr); + krb5_free_data(context, attrs); + k5_mutex_unlock(&kname->lock); + krb5_free_context(context); + + return kg_map_name_error(minor_status, code); +} + +#if 0 +OM_uint32 +krb5_gss_display_name_ext(OM_uint32 *minor_status, + gss_name_t name, + gss_OID display_as_name_type, + gss_buffer_t display_name) +{ +} +#endif + diff --git a/src/lib/gssapi/krb5/rel_cred.c b/src/lib/gssapi/krb5/rel_cred.c index 833054326..b6b25887e 100644 --- a/src/lib/gssapi/krb5/rel_cred.c +++ b/src/lib/gssapi/krb5/rel_cred.c @@ -71,8 +71,8 @@ krb5_gss_release_cred(minor_status, cred_handle) code3 = krb5_rc_close(context, cred->rcache); else code3 = 0; - if (cred->princ) - krb5_free_principal(context, cred->princ); + if (cred->name) + kg_release_name(context, 0, &cred->name); if (cred->req_enctypes) free(cred->req_enctypes); diff --git a/src/lib/gssapi/krb5/rel_name.c b/src/lib/gssapi/krb5/rel_name.c index 49d194448..5490b8a50 100644 --- a/src/lib/gssapi/krb5/rel_name.c +++ b/src/lib/gssapi/krb5/rel_name.c @@ -43,9 +43,8 @@ krb5_gss_release_name(minor_status, input_name) return(GSS_S_CALL_BAD_STRUCTURE|GSS_S_BAD_NAME); } - (void)kg_delete_name(*input_name); - - krb5_free_principal(context, (krb5_principal) *input_name); + kg_release_name(context, KG_INIT_NAME_INTERN, + (krb5_gss_name_t *)input_name); krb5_free_context(context); *input_name = (gss_name_t) NULL; diff --git a/src/lib/gssapi/krb5/s4u_gss_glue.c b/src/lib/gssapi/krb5/s4u_gss_glue.c index 8e2d690b1..cae45039c 100644 --- a/src/lib/gssapi/krb5/s4u_gss_glue.c +++ b/src/lib/gssapi/krb5/s4u_gss_glue.c @@ -109,7 +109,7 @@ kg_is_initiator_cred(krb5_gss_cred_id_t cred) static OM_uint32 kg_impersonate_name(OM_uint32 *minor_status, const krb5_gss_cred_id_t impersonator_cred, - const krb5_principal user, + const krb5_gss_name_t user, OM_uint32 time_req, const gss_OID_set desired_mechs, krb5_gss_cred_id_t *output_cred, @@ -124,18 +124,39 @@ kg_impersonate_name(OM_uint32 *minor_status, memset(&in_creds, 0, sizeof(in_creds)); memset(&out_creds, 0, sizeof(out_creds)); - in_creds.client = user; - in_creds.server = impersonator_cred->princ; + in_creds.client = user->princ; + in_creds.server = impersonator_cred->name->princ; if (impersonator_cred->req_enctypes != NULL) in_creds.keyblock.enctype = impersonator_cred->req_enctypes[0]; + code = k5_mutex_lock(&user->lock); + if (code != 0) { + *minor_status = code; + return GSS_S_FAILURE; + } + + if (user->ad_context != NULL) { + code = krb5_authdata_export_authdata(context, + user->ad_context, + AD_USAGE_TGS_REQ, + &in_creds.authdata); + if (code != 0) { + k5_mutex_unlock(&user->lock); + *minor_status = code; + return GSS_S_FAILURE; + } + } + + k5_mutex_unlock(&user->lock); + code = krb5_get_credentials_for_user(context, KRB5_GC_CANONICALIZE | KRB5_GC_NO_STORE, impersonator_cred->ccache, &in_creds, NULL, &out_creds); if (code != 0) { + krb5_free_authdata(context, in_creds.authdata); *minor_status = code; return GSS_S_FAILURE; } @@ -150,6 +171,7 @@ kg_impersonate_name(OM_uint32 *minor_status, time_rec, context); + krb5_free_authdata(context, in_creds.authdata); krb5_free_creds(context, out_creds); return major_status; @@ -207,7 +229,7 @@ krb5_gss_acquire_cred_impersonate_name(OM_uint32 *minor_status, major_status = kg_impersonate_name(minor_status, (krb5_gss_cred_id_t)impersonator_cred_handle, - (krb5_principal)desired_name, + (krb5_gss_name_t)desired_name, time_req, desired_mechs, &cred, @@ -242,12 +264,14 @@ kg_compose_deleg_cred(OM_uint32 *minor_status, k5_mutex_assert_locked(&impersonator_cred->lock); if (!kg_is_initiator_cred(impersonator_cred) || - impersonator_cred->princ == NULL || + impersonator_cred->name == NULL || impersonator_cred->proxy_cred) { code = G_BAD_USAGE; goto cleanup; } + assert(impersonator_cred->name->princ != NULL); + assert(subject_creds != NULL); assert(subject_creds->client != NULL); @@ -277,7 +301,7 @@ kg_compose_deleg_cred(OM_uint32 *minor_status, cred->tgt_expire = impersonator_cred->tgt_expire; - code = krb5_copy_principal(context, subject_creds->client, &cred->princ); + code = kg_init_name(context, subject_creds->client, NULL, 0, &cred->name); if (code != 0) goto cleanup; @@ -286,8 +310,8 @@ kg_compose_deleg_cred(OM_uint32 *minor_status, goto cleanup; code = krb5_cc_initialize(context, cred->ccache, - cred->proxy_cred ? impersonator_cred->princ : - (krb5_principal)subject_creds->client); + cred->proxy_cred ? impersonator_cred->name->princ : + subject_creds->client); if (code != 0) goto cleanup; @@ -334,10 +358,8 @@ cleanup: if (GSS_ERROR(major_status) && cred != NULL) { k5_mutex_destroy(&cred->lock); - if (cred->ccache != NULL) - krb5_cc_destroy(context, cred->ccache); - if (cred->princ != NULL) - krb5_free_principal(context, cred->princ); + krb5_cc_destroy(context, cred->ccache); + kg_release_name(context, 0, &cred->name); xfree(cred); } diff --git a/src/lib/gssapi/krb5/ser_sctx.c b/src/lib/gssapi/krb5/ser_sctx.c index 60ea9058c..9b55a6507 100644 --- a/src/lib/gssapi/krb5/ser_sctx.c +++ b/src/lib/gssapi/krb5/ser_sctx.c @@ -292,13 +292,13 @@ kg_ctx_size(kcontext, arg, sizep) if (!kret && ctx->here) kret = krb5_size_opaque(kcontext, KV5M_PRINCIPAL, - (krb5_pointer) ctx->here, + (krb5_pointer) ctx->here->princ, &required); if (!kret && ctx->there) kret = krb5_size_opaque(kcontext, KV5M_PRINCIPAL, - (krb5_pointer) ctx->there, + (krb5_pointer) ctx->there->princ, &required); if (!kret && ctx->subkey) @@ -352,7 +352,18 @@ kg_ctx_size(kcontext, arg, sizep) &required); } } - if (!kret) + if (!kret) { + krb5_gss_name_t initiator_name; + + initiator_name = ctx->initiate ? ctx->here : ctx->there; + + if (initiator_name) { + kret = krb5_size_opaque(kcontext, + KV5M_AUTHDATA_CONTEXT, + initiator_name->ad_context, + &required); + } + } *sizep += required; } return(kret); @@ -437,13 +448,13 @@ kg_ctx_externalize(kcontext, arg, buffer, lenremain) if (!kret && ctx->here) kret = krb5_externalize_opaque(kcontext, KV5M_PRINCIPAL, - (krb5_pointer) ctx->here, + (krb5_pointer) ctx->here->princ, &bp, &remain); if (!kret && ctx->there) kret = krb5_externalize_opaque(kcontext, KV5M_PRINCIPAL, - (krb5_pointer) ctx->there, + (krb5_pointer) ctx->there->princ, &bp, &remain); if (!kret && ctx->subkey) @@ -517,6 +528,20 @@ kg_ctx_externalize(kcontext, arg, buffer, lenremain) &remain); } } + /* authdata context */ + if (!kret) { + krb5_gss_name_t initiator_name; + + initiator_name = ctx->initiate ? ctx->here : ctx->there; + + if (initiator_name) { + kret = krb5_externalize_opaque(kcontext, + KV5M_AUTHDATA_CONTEXT, + initiator_name->ad_context, + &bp, + &remain); + } + } /* trailer */ if (!kret) kret = krb5_ser_pack_int32(KG_CONTEXT, &bp, &remain); @@ -545,6 +570,7 @@ kg_ctx_internalize(kcontext, argp, buffer, lenremain) krb5_octet *bp; size_t remain; krb5int_access kaccess; + krb5_principal princ; kret = krb5int_accessor (&kaccess, KRB5INT_ACCESS_VERSION); if (kret) @@ -553,6 +579,7 @@ kg_ctx_internalize(kcontext, argp, buffer, lenremain) bp = *buffer; remain = *lenremain; kret = EINVAL; + princ = NULL; /* Read our magic number */ if (krb5_ser_unpack_int32(&ibuf, &bp, &remain)) ibuf = 0; @@ -618,19 +645,28 @@ kg_ctx_internalize(kcontext, argp, buffer, lenremain) kret = 0; } /* Now get substructure data */ - if ((kret = krb5_internalize_opaque(kcontext, - KV5M_PRINCIPAL, - (krb5_pointer *) &ctx->here, - &bp, &remain))) { - if (kret == EINVAL) - kret = 0; - } - if (!kret && - (kret = krb5_internalize_opaque(kcontext, - KV5M_PRINCIPAL, - (krb5_pointer *) &ctx->there, - &bp, &remain))) { - if (kret == EINVAL) + kret = krb5_internalize_opaque(kcontext, + KV5M_PRINCIPAL, + (krb5_pointer *) &princ, + &bp, &remain); + if (kret == 0) { + kret = kg_init_name(kcontext, princ, NULL, + KG_INIT_NAME_NO_COPY, &ctx->here); + if (kret) + krb5_free_principal(kcontext, princ); + } else if (kret == EINVAL) + kret = 0; + if (!kret) { + kret = krb5_internalize_opaque(kcontext, + KV5M_PRINCIPAL, + (krb5_pointer *) &princ, + &bp, &remain); + if (kret == 0) { + kret = kg_init_name(kcontext, princ, NULL, + KG_INIT_NAME_NO_COPY, &ctx->there); + if (kret) + krb5_free_principal(kcontext, princ); + } else if (kret == EINVAL) kret = 0; } if (!kret && @@ -718,6 +754,21 @@ kg_ctx_internalize(kcontext, argp, buffer, lenremain) } } } + /* authdata context */ + if (!kret) { + krb5_gss_name_t initiator_name; + + initiator_name = ctx->initiate ? ctx->here : ctx->there; + if (initiator_name == NULL) { + kret = EINVAL; + } else { + kret = krb5_internalize_opaque(kcontext, + KV5M_AUTHDATA_CONTEXT, + (krb5_pointer *)&initiator_name->ad_context, + &bp, + &remain); + } + } /* Get trailer */ if (!kret) kret = krb5_ser_unpack_int32(&ibuf, &bp, &remain); @@ -736,9 +787,9 @@ kg_ctx_internalize(kcontext, argp, buffer, lenremain) if (ctx->subkey) krb5_free_keyblock(kcontext, ctx->subkey); if (ctx->there) - krb5_free_principal(kcontext, ctx->there); + kg_release_name(kcontext, 0, &ctx->there); if (ctx->here) - krb5_free_principal(kcontext, ctx->here); + kg_release_name(kcontext, 0, &ctx->here); xfree(ctx); } } diff --git a/src/lib/gssapi/krb5/val_cred.c b/src/lib/gssapi/krb5/val_cred.c index 43b1f695d..747d8222e 100644 --- a/src/lib/gssapi/krb5/val_cred.c +++ b/src/lib/gssapi/krb5/val_cred.c @@ -59,7 +59,7 @@ krb5_gss_validate_cred_1(OM_uint32 *minor_status, gss_cred_id_t cred_handle, return(GSS_S_DEFECTIVE_CREDENTIAL); } if (!cred->proxy_cred && - !krb5_principal_compare(context, princ, cred->princ)) { + !krb5_principal_compare(context, princ, cred->name->princ)) { k5_mutex_unlock(&cred->lock); *minor_status = KG_CCACHE_NOMATCH; return(GSS_S_DEFECTIVE_CREDENTIAL); diff --git a/src/lib/gssapi/libgssapi_krb5.exports b/src/lib/gssapi/libgssapi_krb5.exports index d641fc65b..60754df7a 100644 --- a/src/lib/gssapi/libgssapi_krb5.exports +++ b/src/lib/gssapi/libgssapi_krb5.exports @@ -20,13 +20,17 @@ gss_complete_auth_token gss_context_time gss_create_empty_buffer_set gss_create_empty_oid_set +gss_delete_name_attribute gss_delete_sec_context gss_display_name +gss_display_name_ext gss_display_status gss_duplicate_name gss_export_name +gss_export_name_composite gss_export_sec_context gss_get_mic +gss_get_name_attribute gss_import_name gss_import_sec_context gss_indicate_mechs @@ -49,6 +53,7 @@ gss_krb5int_make_seal_token_v3 gss_krb5int_unseal_token_v3 gsskrb5_extract_authtime_from_sec_context gsskrb5_extract_authz_data_from_sec_context +gss_map_name_to_any gss_mech_krb5 gss_mech_krb5_old gss_mech_set_krb5 @@ -64,6 +69,7 @@ gss_nt_string_uid_name gss_nt_user_name gss_oid_to_str gss_process_context_token +gss_release_any_name_mapping gss_release_buffer_set gss_release_buffer gss_release_cred @@ -72,6 +78,7 @@ gss_release_name gss_release_oid gss_release_oid_set gss_seal +gss_set_name_attribute gss_set_sec_context_option gss_sign gss_str_to_oid @@ -92,3 +99,4 @@ gssspi_mech_invoke krb5_gss_dbg_client_expcreds krb5_gss_register_acceptor_identity krb5_gss_use_kdc_context +gss_inquire_name diff --git a/src/lib/gssapi/mechglue/Makefile.in b/src/lib/gssapi/mechglue/Makefile.in index 18e89f19d..61972ab75 100644 --- a/src/lib/gssapi/mechglue/Makefile.in +++ b/src/lib/gssapi/mechglue/Makefile.in @@ -21,11 +21,15 @@ SRCS = \ $(srcdir)/g_complete_auth_token.c \ $(srcdir)/g_context_time.c \ $(srcdir)/g_delete_sec_context.c \ + $(srcdir)/g_del_name_attr.c \ $(srcdir)/g_dsp_name.c \ + $(srcdir)/g_dsp_name_ext.c \ $(srcdir)/g_dsp_status.c \ $(srcdir)/g_dup_name.c \ $(srcdir)/g_exp_sec_context.c \ $(srcdir)/g_export_name.c \ + $(srcdir)/g_export_name_comp.c \ + $(srcdir)/g_get_name_attr.c \ $(srcdir)/g_glue.c \ $(srcdir)/g_imp_name.c \ $(srcdir)/g_imp_sec_context.c \ @@ -35,7 +39,9 @@ SRCS = \ $(srcdir)/g_inq_context_oid.c \ $(srcdir)/g_inq_cred.c \ $(srcdir)/g_inq_cred_oid.c \ + $(srcdir)/g_inq_name.c \ $(srcdir)/g_inq_names.c \ + $(srcdir)/g_map_name_to_any.c \ $(srcdir)/g_mech_invoke.c \ $(srcdir)/g_mechname.c \ $(srcdir)/g_oid_ops.c \ @@ -43,10 +49,12 @@ SRCS = \ $(srcdir)/g_rel_buffer.c \ $(srcdir)/g_rel_cred.c \ $(srcdir)/g_rel_name.c \ + $(srcdir)/g_rel_name_mapping.c \ $(srcdir)/g_rel_oid_set.c \ $(srcdir)/g_seal.c \ $(srcdir)/g_set_context_option.c \ $(srcdir)/g_set_cred_option.c \ + $(srcdir)/g_set_name_attr.c \ $(srcdir)/g_sign.c \ $(srcdir)/g_store_cred.c \ $(srcdir)/g_unseal.c \ @@ -66,11 +74,15 @@ OBJS = \ $(OUTPRE)g_complete_auth_token.$(OBJEXT) \ $(OUTPRE)g_context_time.$(OBJEXT) \ $(OUTPRE)g_delete_sec_context.$(OBJEXT) \ + $(OUTPRE)g_del_name_attr.$(OBJEXT) \ $(OUTPRE)g_dsp_name.$(OBJEXT) \ + $(OUTPRE)g_dsp_name_ext.$(OBJEXT) \ $(OUTPRE)g_dsp_status.$(OBJEXT) \ $(OUTPRE)g_dup_name.$(OBJEXT) \ $(OUTPRE)g_exp_sec_context.$(OBJEXT) \ $(OUTPRE)g_export_name.$(OBJEXT) \ + $(OUTPRE)g_export_name_comp.$(OBJEXT) \ + $(OUTPRE)g_get_name_attr.$(OBJEXT) \ $(OUTPRE)g_glue.$(OBJEXT) \ $(OUTPRE)g_imp_name.$(OBJEXT) \ $(OUTPRE)g_imp_sec_context.$(OBJEXT) \ @@ -80,7 +92,9 @@ OBJS = \ $(OUTPRE)g_inq_context_oid.$(OBJEXT) \ $(OUTPRE)g_inq_cred.$(OBJEXT) \ $(OUTPRE)g_inq_cred_oid.$(OBJEXT) \ + $(OUTPRE)g_inq_name.$(OBJEXT) \ $(OUTPRE)g_inq_names.$(OBJEXT) \ + $(OUTPRE)g_map_name_to_any.$(OBJEXT) \ $(OUTPRE)g_mech_invoke.$(OBJEXT) \ $(OUTPRE)g_mechname.$(OBJEXT) \ $(OUTPRE)g_oid_ops.$(OBJEXT) \ @@ -88,10 +102,12 @@ OBJS = \ $(OUTPRE)g_rel_buffer.$(OBJEXT) \ $(OUTPRE)g_rel_cred.$(OBJEXT) \ $(OUTPRE)g_rel_name.$(OBJEXT) \ + $(OUTPRE)g_rel_name_mapping.$(OBJEXT) \ $(OUTPRE)g_rel_oid_set.$(OBJEXT) \ $(OUTPRE)g_seal.$(OBJEXT) \ $(OUTPRE)g_set_context_option.$(OBJEXT) \ $(OUTPRE)g_set_cred_option.$(OBJEXT) \ + $(OUTPRE)g_set_name_attr.$(OBJEXT) \ $(OUTPRE)g_sign.$(OBJEXT) \ $(OUTPRE)g_store_cred.$(OBJEXT) \ $(OUTPRE)g_unseal.$(OBJEXT) \ @@ -111,11 +127,15 @@ STLIBOBJS = \ g_complete_auth_token.o \ g_context_time.o \ g_delete_sec_context.o \ + g_del_name_attr.o \ g_dsp_name.o \ + g_dsp_name_ext.o \ g_dsp_status.o \ g_dup_name.o \ g_exp_sec_context.o \ g_export_name.o \ + g_export_name_comp.o \ + g_get_name_attr.o \ g_glue.o \ g_imp_name.o \ g_imp_sec_context.o \ @@ -125,7 +145,9 @@ STLIBOBJS = \ g_inq_context_oid.o \ g_inq_cred.o \ g_inq_cred_oid.o \ + g_inq_name.o \ g_inq_names.o \ + g_map_name_to_any.o \ g_mech_invoke.o \ g_mechname.o \ g_oid_ops.o \ @@ -133,10 +155,12 @@ STLIBOBJS = \ g_rel_buffer.o \ g_rel_cred.o \ g_rel_name.o \ + g_rel_name_mapping.o \ g_rel_oid_set.o \ g_seal.o \ g_set_context_option.o \ g_set_cred_option.o \ + g_set_name_attr.o \ g_sign.o \ g_store_cred.o \ g_unseal.o \ diff --git a/src/lib/gssapi/mechglue/g_del_name_attr.c b/src/lib/gssapi/mechglue/g_del_name_attr.c new file mode 100644 index 000000000..4c5064217 --- /dev/null +++ b/src/lib/gssapi/mechglue/g_del_name_attr.c @@ -0,0 +1,70 @@ +/* -*- mode: c; indent-tabs-mode: nil -*- */ +/* + * Copyright 2009 by the Massachusetts Institute of Technology. + * All Rights Reserved. + * + * Export of this software from the United States of America may + * require a specific license from the United States Government. + * It is the responsibility of any person or organization contemplating + * export to obtain such a license before exporting. + * + * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and + * distribute this software and its documentation for any purpose and + * without fee is hereby granted, provided that the above copyright + * notice appear in all copies and that both that copyright notice and + * this permission notice appear in supporting documentation, and that + * the name of M.I.T. not be used in advertising or publicity pertaining + * to distribution of the software without specific, written prior + * permission. Furthermore if you modify this software you must label + * your software as modified software and not distribute it in such a + * fashion that it might be confused with the original M.I.T. software. + * M.I.T. makes no representations about the suitability of + * this software for any purpose. It is provided "as is" without express + * or implied warranty. + * + */ + +/* + * glue routine for gss_delete_name_attribute + */ + +#include "mglueP.h" + +OM_uint32 KRB5_CALLCONV +gss_delete_name_attribute(OM_uint32 *minor_status, + gss_name_t name, + gss_buffer_t attr) +{ + OM_uint32 status; + gss_union_name_t union_name; + gss_mechanism mech; + + if (minor_status == NULL) + return GSS_S_CALL_INACCESSIBLE_WRITE; + + if (name == GSS_C_NO_NAME) + return GSS_S_CALL_INACCESSIBLE_READ | GSS_S_BAD_NAME; + + *minor_status = 0; + + union_name = (gss_union_name_t)name; + + if (union_name->mech_type == GSS_C_NO_OID) + return GSS_S_UNAVAILABLE; + + mech = gssint_get_mechanism(name->mech_type); + if (mech == NULL) + return GSS_S_BAD_NAME; + + if (mech->gss_delete_name_attribute == NULL) + return GSS_S_UNAVAILABLE; + + status = (*mech->gss_delete_name_attribute)(minor_status, + union_name->mech_name, + attr); + if (status != GSS_S_COMPLETE) + map_error(minor_status, mech); + + return status; +} + diff --git a/src/lib/gssapi/mechglue/g_dsp_name.c b/src/lib/gssapi/mechglue/g_dsp_name.c index 7efd583f8..2540f21c0 100644 --- a/src/lib/gssapi/mechglue/g_dsp_name.c +++ b/src/lib/gssapi/mechglue/g_dsp_name.c @@ -1,8 +1,7 @@ /* #pragma ident "@(#)g_dsp_name.c 1.13 04/02/23 SMI" */ - /* * Copyright 1996 by Sun Microsystems, Inc. - * + * * Permission to use, copy, modify, distribute, and sell this software * and its documentation for any purpose is hereby granted without fee, * provided that the above copyright notice appears in all copies and @@ -12,7 +11,7 @@ * without specific, written prior permission. Sun Microsystems makes no * representations about the suitability of this software for any * purpose. It is provided "as is" without express or implied warranty. - * + * * SUN MICROSYSTEMS DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO * EVENT SHALL SUN MICROSYSTEMS BE LIABLE FOR ANY SPECIAL, INDIRECT OR @@ -102,7 +101,7 @@ gss_OID * output_name_type; output_name_buffer, output_name_type)); } - + /* * copy the value of the external_name component of the union * name into the output_name_buffer and point the output_name_type diff --git a/src/lib/gssapi/mechglue/g_dsp_name_ext.c b/src/lib/gssapi/mechglue/g_dsp_name_ext.c new file mode 100644 index 000000000..14326a30f --- /dev/null +++ b/src/lib/gssapi/mechglue/g_dsp_name_ext.c @@ -0,0 +1,131 @@ +/* -*- mode: c; indent-tabs-mode: nil -*- */ +/* + * Copyright 1996 by Sun Microsystems, Inc. + * + * Permission to use, copy, modify, distribute, and sell this software + * and its documentation for any purpose is hereby granted without fee, + * provided that the above copyright notice appears in all copies and + * that both that copyright notice and this permission notice appear in + * supporting documentation, and that the name of Sun Microsystems not be used + * in advertising or publicity pertaining to distribution of the software + * without specific, written prior permission. Sun Microsystems makes no + * representations about the suitability of this software for any + * purpose. It is provided "as is" without express or implied warranty. + * + * SUN MICROSYSTEMS DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, + * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO + * EVENT SHALL SUN MICROSYSTEMS BE LIABLE FOR ANY SPECIAL, INDIRECT OR + * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF + * USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR + * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +/* + * glue routine for gss_display_name_ext() + * + */ + +#include "mglueP.h" +#include +#ifdef HAVE_STDLIB_H +#include +#endif +#include + +static OM_uint32 +val_dsp_name_ext_args( + OM_uint32 *minor_status, + gss_name_t input_name, + gss_OID display_as_name_type, + gss_buffer_t output_name_buffer) +{ + + /* Initialize outputs. */ + + if (minor_status != NULL) + *minor_status = 0; + + if (output_name_buffer != GSS_C_NO_BUFFER) { + output_name_buffer->length = 0; + output_name_buffer->value = NULL; + } + + /* Validate arguments. */ + + if (minor_status == NULL) + return GSS_S_CALL_INACCESSIBLE_WRITE; + + if (output_name_buffer == GSS_C_NO_BUFFER) + return GSS_S_CALL_INACCESSIBLE_WRITE; + + if (input_name == GSS_C_NO_NAME) + return GSS_S_CALL_INACCESSIBLE_READ | GSS_S_BAD_NAME; + + if (display_as_name_type == GSS_C_NO_OID) + return GSS_S_CALL_INACCESSIBLE_READ | GSS_S_BAD_NAMETYPE; + + return GSS_S_COMPLETE; +} + + +OM_uint32 KRB5_CALLCONV +gss_display_name_ext (OM_uint32 *minor_status, + gss_name_t input_name, + gss_OID display_as_name_type, + gss_buffer_t output_name_buffer) +{ + OM_uint32 status; + gss_union_name_t union_name; + gss_mechanism mech; + + status = val_dsp_name_ext_args(minor_status, + input_name, + display_as_name_type, + output_name_buffer); + if (status != GSS_S_COMPLETE) + return status; + + union_name = (gss_union_name_t) input_name; + + if (union_name->mech_type) { + mech = gssint_get_mechanism(union_name->mech_type); + if (mech == NULL) + status = GSS_S_BAD_NAME; + else if (mech->gss_display_name_ext == NULL) { + if (mech->gss_display_name != NULL && + g_OID_equal(display_as_name_type, union_name->name_type)) { + status = (*mech->gss_display_name)(minor_status, + union_name->mech_name, + output_name_buffer, + NULL); + if (status != GSS_S_COMPLETE) + map_error(minor_status, mech); + } else + status = GSS_S_UNAVAILABLE; + } else { + status = (*mech->gss_display_name_ext)(minor_status, + union_name->mech_name, + display_as_name_type, + output_name_buffer); + if (status != GSS_S_COMPLETE) + map_error(minor_status, mech); + } + return status; + } + + if (!g_OID_equal(display_as_name_type, union_name->name_type)) + return GSS_S_UNAVAILABLE; + + if ((output_name_buffer->value = + malloc(union_name->external_name->length + 1)) == NULL) { + return GSS_S_FAILURE; + } + output_name_buffer->length = union_name->external_name->length; + (void) memcpy(output_name_buffer->value, + union_name->external_name->value, + union_name->external_name->length); + ((char *)output_name_buffer->value)[output_name_buffer->length] = '\0'; + + return GSS_S_COMPLETE; +} diff --git a/src/lib/gssapi/mechglue/g_export_name_comp.c b/src/lib/gssapi/mechglue/g_export_name_comp.c new file mode 100644 index 000000000..24eaf247e --- /dev/null +++ b/src/lib/gssapi/mechglue/g_export_name_comp.c @@ -0,0 +1,73 @@ +/* -*- mode: c; indent-tabs-mode: nil -*- */ +/* + * Copyright 2009 by the Massachusetts Institute of Technology. + * All Rights Reserved. + * + * Export of this software from the United States of America may + * require a specific license from the United States Government. + * It is the responsibility of any person or organization contemplating + * export to obtain such a license before exporting. + * + * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and + * distribute this software and its documentation for any purpose and + * without fee is hereby granted, provided that the above copyright + * notice appear in all copies and that both that copyright notice and + * this permission notice appear in supporting documentation, and that + * the name of M.I.T. not be used in advertising or publicity pertaining + * to distribution of the software without specific, written prior + * permission. Furthermore if you modify this software you must label + * your software as modified software and not distribute it in such a + * fashion that it might be confused with the original M.I.T. software. + * M.I.T. makes no representations about the suitability of + * this software for any purpose. It is provided "as is" without express + * or implied warranty. + * + */ + +/* + * glue routine for gss_export_name_composite + */ + +#include "mglueP.h" + +OM_uint32 KRB5_CALLCONV +gss_export_name_composite(OM_uint32 *minor_status, + gss_name_t name, + gss_buffer_t exp_composite_name) +{ + OM_uint32 status; + gss_union_name_t union_name; + gss_mechanism mech; + + if (minor_status == NULL) + return GSS_S_CALL_INACCESSIBLE_WRITE; + + if (name == GSS_C_NO_NAME) + return GSS_S_CALL_INACCESSIBLE_READ | GSS_S_BAD_NAME; + + if (exp_composite_name == GSS_C_NO_BUFFER) + return GSS_S_CALL_INACCESSIBLE_WRITE; + + *minor_status = 0; + + union_name = (gss_union_name_t)name; + + if (union_name->mech_type == GSS_C_NO_OID) + return GSS_S_UNAVAILABLE; + + mech = gssint_get_mechanism(name->mech_type); + if (mech == NULL) + return GSS_S_BAD_NAME; + + if (mech->gss_export_name_composite == NULL) + return GSS_S_UNAVAILABLE; + + status = (*mech->gss_export_name_composite)(minor_status, + union_name->mech_name, + exp_composite_name); + if (status != GSS_S_COMPLETE) + map_error(minor_status, mech); + + return status; +} + diff --git a/src/lib/gssapi/mechglue/g_get_name_attr.c b/src/lib/gssapi/mechglue/g_get_name_attr.c new file mode 100644 index 000000000..66238f0aa --- /dev/null +++ b/src/lib/gssapi/mechglue/g_get_name_attr.c @@ -0,0 +1,89 @@ +/* -*- mode: c; indent-tabs-mode: nil -*- */ +/* + * Copyright 2009 by the Massachusetts Institute of Technology. + * All Rights Reserved. + * + * Export of this software from the United States of America may + * require a specific license from the United States Government. + * It is the responsibility of any person or organization contemplating + * export to obtain such a license before exporting. + * + * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and + * distribute this software and its documentation for any purpose and + * without fee is hereby granted, provided that the above copyright + * notice appear in all copies and that both that copyright notice and + * this permission notice appear in supporting documentation, and that + * the name of M.I.T. not be used in advertising or publicity pertaining + * to distribution of the software without specific, written prior + * permission. Furthermore if you modify this software you must label + * your software as modified software and not distribute it in such a + * fashion that it might be confused with the original M.I.T. software. + * M.I.T. makes no representations about the suitability of + * this software for any purpose. It is provided "as is" without express + * or implied warranty. + * + */ + +/* + * glue routine for gss_get_name_attribute + */ + +#include "mglueP.h" + +OM_uint32 KRB5_CALLCONV +gss_get_name_attribute(OM_uint32 *minor_status, + gss_name_t name, + gss_buffer_t attr, + int *authenticated, + int *complete, + gss_buffer_t value, + gss_buffer_t display_value, + int *more) +{ + OM_uint32 status; + gss_union_name_t union_name; + gss_mechanism mech; + + if (minor_status == NULL) + return GSS_S_CALL_INACCESSIBLE_WRITE; + + if (name == GSS_C_NO_NAME) + return GSS_S_CALL_INACCESSIBLE_READ | GSS_S_BAD_NAME; + if (attr == GSS_C_NO_BUFFER) + return GSS_S_CALL_INACCESSIBLE_READ; + if (more == NULL) + return GSS_S_CALL_INACCESSIBLE_WRITE; + + if (authenticated != NULL) + *authenticated = 0; + if (complete != NULL) + *complete = 0; + + *minor_status = 0; + + union_name = (gss_union_name_t)name; + + if (union_name->mech_type == GSS_C_NO_OID) + return GSS_S_UNAVAILABLE; + + mech = gssint_get_mechanism(name->mech_type); + if (mech == NULL) + return GSS_S_BAD_NAME; + + if (mech->gss_get_name_attribute == NULL) + return GSS_S_UNAVAILABLE; + + status = (*mech->gss_get_name_attribute)(minor_status, + union_name->mech_name, + attr, + authenticated, + complete, + value, + display_value, + more); + if (status != GSS_S_COMPLETE) + map_error(minor_status, mech); + + return status; +} + diff --git a/src/lib/gssapi/mechglue/g_glue.c b/src/lib/gssapi/mechglue/g_glue.c index 4d35819c5..711c58fd8 100644 --- a/src/lib/gssapi/mechglue/g_glue.c +++ b/src/lib/gssapi/mechglue/g_glue.c @@ -288,7 +288,46 @@ OM_uint32 gssint_get_mech_type(OID, token) * Internal routines to get and release an internal mechanism name */ -#include "mglueP.h" +#if 0 +static OM_uint32 +import_internal_name_composite(OM_uint32 *minor_status, + gss_mechanism mech, + gss_union_name_t union_name, + gss_name_t *internal_name) +{ + OM_uint32 status, tmp; + gss_mechanism name_mech; + gss_buffer_desc composite_name; + + if (mech->gss_import_name == NULL) + return (GSS_S_UNAVAILABLE); + + name_mech = gssint_get_mechanism(union_name->mech_type); + if (name_mech == NULL) + return (GSS_S_BAD_MECH); + + if (name_mech->gss_export_name_composite == NULL) + return (GSS_S_UNAVAILABLE); + + composite_name.length = 0; + composite_name.value = NULL; + + status = (*name_mech->gss_export_name_composite)(minor_status, + union_name->mech_name, + &composite_name); + if (GSS_ERROR(status)) + return (status); + + status = (*mech->gss_import_name)(minor_status, + &composite_name, + gss_nt_exported_name, + internal_name); + + gss_release_buffer(&tmp, &composite_name); + + return (status); +} +#endif OM_uint32 gssint_import_internal_name (minor_status, mech_type, union_name, internal_name) @@ -301,22 +340,32 @@ gss_name_t *internal_name; gss_mechanism mech; mech = gssint_get_mechanism (mech_type); - if (mech) { - if (mech->gss_import_name) { - status = mech->gss_import_name ( - minor_status, - union_name->external_name, - union_name->name_type, - internal_name); - if (status != GSS_S_COMPLETE) - map_error(minor_status, mech); - } else - status = GSS_S_UNAVAILABLE; + if (mech == NULL) + return (GSS_S_BAD_MECH); - return (status); +#if 0 + /* Try composite name, it will preserve any extended attributes */ + if (union_name->mech_type && union_name->mech_name) { + status = import_internal_name_composite(minor_status, + mech, + union_name, + internal_name); + if (status == GSS_S_COMPLETE) + return (GSS_S_COMPLETE); } +#endif - return (GSS_S_BAD_MECH); + if (mech->gss_import_name == NULL) + return (GSS_S_UNAVAILABLE); + + status = mech->gss_import_name(minor_status, + union_name->external_name, + union_name->name_type, + internal_name); + if (status != GSS_S_COMPLETE) + map_error(minor_status, mech); + + return (status); } OM_uint32 gssint_export_internal_name(minor_status, mech_type, diff --git a/src/lib/gssapi/mechglue/g_imp_name.c b/src/lib/gssapi/mechglue/g_imp_name.c index c4767bf3e..6137b9825 100644 --- a/src/lib/gssapi/mechglue/g_imp_name.c +++ b/src/lib/gssapi/mechglue/g_imp_name.c @@ -176,7 +176,6 @@ allocation_failure: /* * GSS export name constants */ -static const char *expNameTokId = "\x04\x01"; static const unsigned int expNameTokIdLen = 2; static const unsigned int mechOidLenLen = 2; static const unsigned int nameTypeLenLen = 2; @@ -201,7 +200,9 @@ importExportName(minor, unionName) return (GSS_S_DEFECTIVE_TOKEN); buf = (unsigned char *)expName.value; - if (memcmp(expNameTokId, buf, expNameTokIdLen) != 0) + if (buf[0] != 0x04) + return (GSS_S_DEFECTIVE_TOKEN); + if (buf[1] != 0x01 && buf[1] != 0x02) return (GSS_S_DEFECTIVE_TOKEN); buf += expNameTokIdLen; diff --git a/src/lib/gssapi/mechglue/g_initialize.c b/src/lib/gssapi/mechglue/g_initialize.c index e34b7bf0a..41aa6821b 100644 --- a/src/lib/gssapi/mechglue/g_initialize.c +++ b/src/lib/gssapi/mechglue/g_initialize.c @@ -761,9 +761,18 @@ build_dynamicMech(void *dl, const gss_OID mech_type) GSS_ADD_DYNAMIC_METHOD(dl, mech, gss_unwrap_iov); GSS_ADD_DYNAMIC_METHOD(dl, mech, gss_wrap_iov_length); GSS_ADD_DYNAMIC_METHOD(dl, mech, gss_complete_auth_token); - /* New for 1.8 */ + /* Services4User (introduced in 1.8) */ GSS_ADD_DYNAMIC_METHOD(dl, mech, gss_acquire_cred_impersonate_name); GSS_ADD_DYNAMIC_METHOD(dl, mech, gss_add_cred_impersonate_name); + /* Naming extensions (introduced in 1.8) */ + GSS_ADD_DYNAMIC_METHOD(dl, mech, gss_display_name_ext); + GSS_ADD_DYNAMIC_METHOD(dl, mech, gss_inquire_name); + GSS_ADD_DYNAMIC_METHOD(dl, mech, gss_get_name_attribute); + GSS_ADD_DYNAMIC_METHOD(dl, mech, gss_set_name_attribute); + GSS_ADD_DYNAMIC_METHOD(dl, mech, gss_delete_name_attribute); + GSS_ADD_DYNAMIC_METHOD(dl, mech, gss_export_name_composite); + GSS_ADD_DYNAMIC_METHOD(dl, mech, gss_map_name_to_any); + GSS_ADD_DYNAMIC_METHOD(dl, mech, gss_release_any_name_mapping); assert(mech_type != GSS_C_NO_OID); diff --git a/src/lib/gssapi/mechglue/g_inq_context_oid.c b/src/lib/gssapi/mechglue/g_inq_context_oid.c index 50bfcb561..379ec419c 100644 --- a/src/lib/gssapi/mechglue/g_inq_context_oid.c +++ b/src/lib/gssapi/mechglue/g_inq_context_oid.c @@ -62,11 +62,11 @@ gss_inquire_sec_context_by_oid (OM_uint32 *minor_status, if (status != GSS_S_COMPLETE) map_error(minor_status, mech); } else - status = GSS_S_BAD_MECH; + status = GSS_S_UNAVAILABLE; return status; } - return GSS_S_NO_CONTEXT; + return GSS_S_BAD_MECH; } diff --git a/src/lib/gssapi/mechglue/g_inq_cred_oid.c b/src/lib/gssapi/mechglue/g_inq_cred_oid.c index 34056f6bd..c2cc27d33 100644 --- a/src/lib/gssapi/mechglue/g_inq_cred_oid.c +++ b/src/lib/gssapi/mechglue/g_inq_cred_oid.c @@ -93,15 +93,19 @@ gss_inquire_cred_by_oid(OM_uint32 *minor_status, return status; } - status = GSS_S_BAD_MECH; + status = GSS_S_UNAVAILABLE; for (i = 0; i < union_cred->count; i++) { mech = gssint_get_mechanism(&union_cred->mechs_array[i]); - if (mech == NULL) - continue; + if (mech == NULL) { + status = GSS_S_BAD_MECH; + break; + } - if (mech->gss_inquire_cred_by_oid == NULL) + if (mech->gss_inquire_cred_by_oid == NULL) { + status = GSS_S_UNAVAILABLE; continue; + } status = (mech->gss_inquire_cred_by_oid)(minor_status, union_cred->cred_array[i], diff --git a/src/lib/gssapi/mechglue/g_inq_name.c b/src/lib/gssapi/mechglue/g_inq_name.c new file mode 100644 index 000000000..260ef20c6 --- /dev/null +++ b/src/lib/gssapi/mechglue/g_inq_name.c @@ -0,0 +1,101 @@ +/* -*- mode: c; indent-tabs-mode: nil -*- */ +/* + * Copyright 2009 by the Massachusetts Institute of Technology. + * All Rights Reserved. + * + * Export of this software from the United States of America may + * require a specific license from the United States Government. + * It is the responsibility of any person or organization contemplating + * export to obtain such a license before exporting. + * + * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and + * distribute this software and its documentation for any purpose and + * without fee is hereby granted, provided that the above copyright + * notice appear in all copies and that both that copyright notice and + * this permission notice appear in supporting documentation, and that + * the name of M.I.T. not be used in advertising or publicity pertaining + * to distribution of the software without specific, written prior + * permission. Furthermore if you modify this software you must label + * your software as modified software and not distribute it in such a + * fashion that it might be confused with the original M.I.T. software. + * M.I.T. makes no representations about the suitability of + * this software for any purpose. It is provided "as is" without express + * or implied warranty. + * + */ + +/* + * glue routine for gss_inquire_name + */ + +#include "mglueP.h" + +OM_uint32 KRB5_CALLCONV +gss_inquire_name(OM_uint32 *minor_status, + gss_name_t name, + int *name_is_MN, + gss_OID *MN_mech, + gss_buffer_set_t *attrs) +{ + OM_uint32 status, tmp; + gss_union_name_t union_name; + gss_mechanism mech; + + if (minor_status == NULL) + return GSS_S_CALL_INACCESSIBLE_WRITE; + + if (name == GSS_C_NO_NAME) + return GSS_S_CALL_INACCESSIBLE_READ | GSS_S_BAD_NAME; + + if (MN_mech != NULL) + *MN_mech = GSS_C_NO_OID; + + if (attrs != NULL) + *attrs = GSS_C_NO_BUFFER_SET; + + *minor_status = 0; + union_name = (gss_union_name_t)name; + + if (union_name->mech_type == GSS_C_NO_OID) { + /* We don't yet support non-mechanism attributes */ + if (name_is_MN != NULL) + name_is_MN = 0; + *minor_status = 0; + return GSS_S_COMPLETE; + } + + if (name_is_MN != NULL) + *name_is_MN = 1; + + if (MN_mech != NULL) { + status = generic_gss_copy_oid(minor_status, + union_name->mech_type, + MN_mech); + if (GSS_ERROR(status)) + return status; + } + + mech = gssint_get_mechanism(name->mech_type); + if (mech == NULL) { + gss_release_oid(&tmp, MN_mech); + return GSS_S_BAD_NAME; + } + + if (mech->gss_inquire_name == NULL) { + gss_release_oid(&tmp, MN_mech); + return GSS_S_UNAVAILABLE; + } + + status = (*mech->gss_inquire_name)(minor_status, + union_name->mech_name, + NULL, + NULL, + attrs); + if (status != GSS_S_COMPLETE) { + generic_gss_release_oid(&tmp, MN_mech); + map_error(minor_status, mech); + } + + return status; +} + diff --git a/src/lib/gssapi/mechglue/g_map_name_to_any.c b/src/lib/gssapi/mechglue/g_map_name_to_any.c new file mode 100644 index 000000000..b0fa2be64 --- /dev/null +++ b/src/lib/gssapi/mechglue/g_map_name_to_any.c @@ -0,0 +1,80 @@ +/* -*- mode: c; indent-tabs-mode: nil -*- */ +/* + * Copyright 2009 by the Massachusetts Institute of Technology. + * All Rights Reserved. + * + * Export of this software from the United States of America may + * require a specific license from the United States Government. + * It is the responsibility of any person or organization contemplating + * export to obtain such a license before exporting. + * + * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and + * distribute this software and its documentation for any purpose and + * without fee is hereby granted, provided that the above copyright + * notice appear in all copies and that both that copyright notice and + * this permission notice appear in supporting documentation, and that + * the name of M.I.T. not be used in advertising or publicity pertaining + * to distribution of the software without specific, written prior + * permission. Furthermore if you modify this software you must label + * your software as modified software and not distribute it in such a + * fashion that it might be confused with the original M.I.T. software. + * M.I.T. makes no representations about the suitability of + * this software for any purpose. It is provided "as is" without express + * or implied warranty. + * + */ + +/* + * glue routine for gss_map_name_to_any + */ + +#include "mglueP.h" + +OM_uint32 KRB5_CALLCONV +gss_map_name_to_any(OM_uint32 *minor_status, + gss_name_t name, + int authenticated, + gss_buffer_t type_id, + gss_any_t *output) +{ + OM_uint32 status; + gss_union_name_t union_name; + gss_mechanism mech; + + if (minor_status == NULL) + return GSS_S_CALL_INACCESSIBLE_WRITE; + + if (name == GSS_C_NO_NAME) + return GSS_S_CALL_INACCESSIBLE_READ | GSS_S_BAD_NAME; + + if (type_id == GSS_C_NO_BUFFER) + return GSS_S_CALL_INACCESSIBLE_READ; + + if (output == NULL) + return GSS_S_CALL_INACCESSIBLE_WRITE; + + *minor_status = 0; + + union_name = (gss_union_name_t)name; + + if (union_name->mech_type == GSS_C_NO_OID) + return GSS_S_UNAVAILABLE; + + mech = gssint_get_mechanism(name->mech_type); + if (mech == NULL) + return GSS_S_BAD_NAME; + + if (mech->gss_map_name_to_any == NULL) + return GSS_S_UNAVAILABLE; + + status = (*mech->gss_map_name_to_any)(minor_status, + union_name->mech_name, + authenticated, + type_id, + output); + if (status != GSS_S_COMPLETE) + map_error(minor_status, mech); + + return status; +} + diff --git a/src/lib/gssapi/mechglue/g_rel_name_mapping.c b/src/lib/gssapi/mechglue/g_rel_name_mapping.c new file mode 100644 index 000000000..b9159a115 --- /dev/null +++ b/src/lib/gssapi/mechglue/g_rel_name_mapping.c @@ -0,0 +1,78 @@ +/* -*- mode: c; indent-tabs-mode: nil -*- */ +/* + * Copyright 2009 by the Massachusetts Institute of Technology. + * All Rights Reserved. + * + * Export of this software from the United States of America may + * require a specific license from the United States Government. + * It is the responsibility of any person or organization contemplating + * export to obtain such a license before exporting. + * + * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and + * distribute this software and its documentation for any purpose and + * without fee is hereby granted, provided that the above copyright + * notice appear in all copies and that both that copyright notice and + * this permission notice appear in supporting documentation, and that + * the name of M.I.T. not be used in advertising or publicity pertaining + * to distribution of the software without specific, written prior + * permission. Furthermore if you modify this software you must label + * your software as modified software and not distribute it in such a + * fashion that it might be confused with the original M.I.T. software. + * M.I.T. makes no representations about the suitability of + * this software for any purpose. It is provided "as is" without express + * or implied warranty. + * + */ + +/* + * glue routine for gss_release_any_name_mapping + */ + +#include "mglueP.h" + +OM_uint32 KRB5_CALLCONV +gss_release_any_name_mapping(OM_uint32 *minor_status, + gss_name_t name, + gss_buffer_t type_id, + gss_any_t *input) +{ + OM_uint32 status; + gss_union_name_t union_name; + gss_mechanism mech; + + if (minor_status == NULL) + return GSS_S_CALL_INACCESSIBLE_WRITE; + + if (name == GSS_C_NO_NAME) + return GSS_S_CALL_INACCESSIBLE_READ | GSS_S_BAD_NAME; + + if (type_id == GSS_C_NO_BUFFER) + return GSS_S_CALL_INACCESSIBLE_READ; + + if (input == NULL) + return GSS_S_CALL_INACCESSIBLE_READ; + + *minor_status = 0; + + union_name = (gss_union_name_t)name; + + if (union_name->mech_type == GSS_C_NO_OID) + return GSS_S_UNAVAILABLE; + + mech = gssint_get_mechanism(name->mech_type); + if (mech == NULL) + return GSS_S_BAD_NAME; + + if (mech->gss_release_any_name_mapping == NULL) + return GSS_S_UNAVAILABLE; + + status = (*mech->gss_release_any_name_mapping)(minor_status, + union_name->mech_name, + type_id, + input); + if (status != GSS_S_COMPLETE) + map_error(minor_status, mech); + + return status; +} + diff --git a/src/lib/gssapi/mechglue/g_set_context_option.c b/src/lib/gssapi/mechglue/g_set_context_option.c index 8f3abbc5d..2f4ba36ae 100644 --- a/src/lib/gssapi/mechglue/g_set_context_option.c +++ b/src/lib/gssapi/mechglue/g_set_context_option.c @@ -65,9 +65,10 @@ gss_set_sec_context_option (OM_uint32 *minor_status, mech = gssint_get_mechanism (ctx->mech_type); } - if (mech == NULL || mech->gss_set_sec_context_option == NULL) { + if (mech == NULL) return GSS_S_BAD_MECH; - } + if (mech->gss_set_sec_context_option == NULL) + return GSS_S_UNAVAILABLE; status = mech->gss_set_sec_context_option(minor_status, ctx ? &ctx->internal_ctx_id : diff --git a/src/lib/gssapi/mechglue/g_set_cred_option.c b/src/lib/gssapi/mechglue/g_set_cred_option.c index 84d18cdf8..bac8c5b50 100644 --- a/src/lib/gssapi/mechglue/g_set_cred_option.c +++ b/src/lib/gssapi/mechglue/g_set_cred_option.c @@ -56,15 +56,19 @@ gssspi_set_cred_option(OM_uint32 *minor_status, union_cred = (gss_union_cred_t) cred_handle; - status = GSS_S_BAD_MECH; + status = GSS_S_UNAVAILABLE; for (i = 0; i < union_cred->count; i++) { mech = gssint_get_mechanism(&union_cred->mechs_array[i]); - if (mech == NULL) - continue; + if (mech == NULL) { + status = GSS_S_BAD_MECH; + break; + } - if (mech->gssspi_set_cred_option == NULL) + if (mech->gssspi_set_cred_option == NULL) { + status = GSS_S_UNAVAILABLE; continue; + } status = (mech->gssspi_set_cred_option)(minor_status, union_cred->cred_array[i], diff --git a/src/lib/gssapi/mechglue/g_set_name_attr.c b/src/lib/gssapi/mechglue/g_set_name_attr.c new file mode 100644 index 000000000..14df2319d --- /dev/null +++ b/src/lib/gssapi/mechglue/g_set_name_attr.c @@ -0,0 +1,74 @@ +/* -*- mode: c; indent-tabs-mode: nil -*- */ +/* + * Copyright 2009 by the Massachusetts Institute of Technology. + * All Rights Reserved. + * + * Export of this software from the United States of America may + * require a specific license from the United States Government. + * It is the responsibility of any person or organization contemplating + * export to obtain such a license before exporting. + * + * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and + * distribute this software and its documentation for any purpose and + * without fee is hereby granted, provided that the above copyright + * notice appear in all copies and that both that copyright notice and + * this permission notice appear in supporting documentation, and that + * the name of M.I.T. not be used in advertising or publicity pertaining + * to distribution of the software without specific, written prior + * permission. Furthermore if you modify this software you must label + * your software as modified software and not distribute it in such a + * fashion that it might be confused with the original M.I.T. software. + * M.I.T. makes no representations about the suitability of + * this software for any purpose. It is provided "as is" without express + * or implied warranty. + * + */ + +/* + * glue routine for gss_set_name_attribute + */ + +#include "mglueP.h" + +OM_uint32 KRB5_CALLCONV +gss_set_name_attribute(OM_uint32 *minor_status, + gss_name_t name, + int complete, + gss_buffer_t attr, + gss_buffer_t value) +{ + OM_uint32 status; + gss_union_name_t union_name; + gss_mechanism mech; + + if (minor_status == NULL) + return GSS_S_CALL_INACCESSIBLE_WRITE; + + if (name == GSS_C_NO_NAME) + return GSS_S_CALL_INACCESSIBLE_READ | GSS_S_BAD_NAME; + + *minor_status = 0; + + union_name = (gss_union_name_t)name; + + if (union_name->mech_type == GSS_C_NO_OID) + return GSS_S_UNAVAILABLE; + + mech = gssint_get_mechanism(name->mech_type); + if (mech == NULL) + return GSS_S_BAD_NAME; + + if (mech->gss_set_name_attribute == NULL) + return GSS_S_UNAVAILABLE; + + status = (*mech->gss_set_name_attribute)(minor_status, + union_name->mech_name, + complete, + attr, + value); + if (status != GSS_S_COMPLETE) + map_error(minor_status, mech); + + return status; +} + diff --git a/src/lib/gssapi/mechglue/mglueP.h b/src/lib/gssapi/mechglue/mglueP.h index 46bfb9463..177db62cc 100644 --- a/src/lib/gssapi/mechglue/mglueP.h +++ b/src/lib/gssapi/mechglue/mglueP.h @@ -504,6 +504,75 @@ typedef struct gss_config { OM_uint32 * /* acceptor_time_rec */ /* */); + OM_uint32 (*gss_display_name_ext) + ( + OM_uint32 *, /* minor_status */ + gss_name_t, /* name */ + gss_OID, /* display_as_name_type */ + gss_buffer_t /* display_name */ + /* */); + + OM_uint32 (*gss_inquire_name) + ( + OM_uint32 *, /* minor_status */ + gss_name_t, /* name */ + int *, /* name_is_MN */ + gss_OID *, /* MN_mech */ + gss_buffer_set_t * /* attrs */ + /* */); + + OM_uint32 (*gss_get_name_attribute) + ( + OM_uint32 *, /* minor_status */ + gss_name_t, /* name */ + gss_buffer_t, /* attr */ + int *, /* authenticated */ + int *, /* complete */ + gss_buffer_t, /* value */ + gss_buffer_t, /* display_value */ + int * /* more */ + /* */); + + OM_uint32 (*gss_set_name_attribute) + ( + OM_uint32 *, /* minor_status */ + gss_name_t, /* name */ + int, /* complete */ + gss_buffer_t, /* attr */ + gss_buffer_t /* value */ + /* */); + + OM_uint32 (*gss_delete_name_attribute) + ( + OM_uint32 *, /* minor_status */ + gss_name_t, /* name */ + gss_buffer_t /* attr */ + /* */); + + OM_uint32 (*gss_export_name_composite) + ( + OM_uint32 *, /* minor_status */ + gss_name_t, /* name */ + gss_buffer_t /* exp_composite_name */ + /* */); + + OM_uint32 (*gss_map_name_to_any) + ( + OM_uint32 *, /* minor_status */ + gss_name_t, /* name */ + int, /* authenticated */ + gss_buffer_t, /* type_id */ + gss_any_t * /* output */ + /* */); + + OM_uint32 (*gss_release_any_name_mapping) + ( + OM_uint32 *, /* minor_status */ + gss_name_t, /* name */ + gss_buffer_t, /* type_id */ + gss_any_t * /* input */ + /* */); + } *gss_mechanism; /* This structure MUST NOT be used by any code outside libgss */ diff --git a/src/lib/gssapi/spnego/gssapiP_spnego.h b/src/lib/gssapi/spnego/gssapiP_spnego.h index 5e6cd5a0c..43b004931 100644 --- a/src/lib/gssapi/spnego/gssapiP_spnego.h +++ b/src/lib/gssapi/spnego/gssapiP_spnego.h @@ -442,6 +442,83 @@ spnego_gss_acquire_cred_impersonate_name( gss_OID_set *, /* actual_mechs */ OM_uint32 *); /* time_rec */ +OM_uint32 +spnego_gss_display_name_ext +( + OM_uint32 *minor_status, + gss_name_t name, + gss_OID display_as_name_type, + gss_buffer_t display_name +); + +OM_uint32 +spnego_gss_inquire_name +( + OM_uint32 *minor_status, + gss_name_t name, + int *name_is_MN, + gss_OID *MN_mech, + gss_buffer_set_t *attrs +); + +OM_uint32 +spnego_gss_get_name_attribute +( + OM_uint32 *minor_status, + gss_name_t name, + gss_buffer_t attr, + int *authenticated, + int *complete, + gss_buffer_t value, + gss_buffer_t display_value, + int *more +); + +OM_uint32 +spnego_gss_set_name_attribute +( + OM_uint32 *minor_status, + gss_name_t name, + int complete, + gss_buffer_t attr, + gss_buffer_t value +); + +OM_uint32 +spnego_gss_delete_name_attribute +( + OM_uint32 *minor_status, + gss_name_t name, + gss_buffer_t attr +); + +OM_uint32 +spnego_gss_export_name_composite +( + OM_uint32 *minor_status, + gss_name_t name, + gss_buffer_t exp_composite_name +); + +OM_uint32 +spnego_gss_map_name_to_any +( + OM_uint32 *minor_status, + gss_name_t name, + int authenticated, + gss_buffer_t type_id, + gss_any_t *output +); + +OM_uint32 +spnego_gss_release_any_name_mapping +( + OM_uint32 *minor_status, + gss_name_t name, + gss_buffer_t type_id, + gss_any_t *input +); + #ifdef __cplusplus } #endif diff --git a/src/lib/gssapi/spnego/spnego_mech.c b/src/lib/gssapi/spnego/spnego_mech.c index 14b65f751..999a5e3e8 100644 --- a/src/lib/gssapi/spnego/spnego_mech.c +++ b/src/lib/gssapi/spnego/spnego_mech.c @@ -260,6 +260,14 @@ static struct gss_config spnego_mechanism = spnego_gss_complete_auth_token, spnego_gss_acquire_cred_impersonate_name, NULL, /* gss_add_cred_impersonate_name */ + spnego_gss_display_name_ext, + spnego_gss_inquire_name, + spnego_gss_get_name_attribute, + spnego_gss_set_name_attribute, + spnego_gss_delete_name_attribute, + spnego_gss_export_name_composite, + spnego_gss_map_name_to_any, + spnego_gss_release_any_name_mapping, }; #ifdef _GSS_STATIC_LINK @@ -2354,6 +2362,129 @@ spnego_gss_acquire_cred_impersonate_name(OM_uint32 *minor_status, return (status); } +OM_uint32 +spnego_gss_display_name_ext(OM_uint32 *minor_status, + gss_name_t name, + gss_OID display_as_name_type, + gss_buffer_t display_name) +{ + OM_uint32 ret; + ret = gss_display_name_ext(minor_status, + name, + display_as_name_type, + display_name); + return (ret); +} + + +OM_uint32 +spnego_gss_inquire_name(OM_uint32 *minor_status, + gss_name_t name, + int *name_is_MN, + gss_OID *MN_mech, + gss_buffer_set_t *attrs) +{ + OM_uint32 ret; + ret = gss_inquire_name(minor_status, + name, + name_is_MN, + MN_mech, + attrs); + return (ret); +} + +OM_uint32 +spnego_gss_get_name_attribute(OM_uint32 *minor_status, + gss_name_t name, + gss_buffer_t attr, + int *authenticated, + int *complete, + gss_buffer_t value, + gss_buffer_t display_value, + int *more) +{ + OM_uint32 ret; + ret = gss_get_name_attribute(minor_status, + name, + attr, + authenticated, + complete, + value, + display_value, + more); + return (ret); +} + +OM_uint32 +spnego_gss_set_name_attribute(OM_uint32 *minor_status, + gss_name_t name, + int complete, + gss_buffer_t attr, + gss_buffer_t value) +{ + OM_uint32 ret; + ret = gss_set_name_attribute(minor_status, + name, + complete, + attr, + value); + return (ret); +} + +OM_uint32 +spnego_gss_delete_name_attribute(OM_uint32 *minor_status, + gss_name_t name, + gss_buffer_t attr) +{ + OM_uint32 ret; + ret = gss_delete_name_attribute(minor_status, + name, + attr); + return (ret); +} + +OM_uint32 +spnego_gss_export_name_composite(OM_uint32 *minor_status, + gss_name_t name, + gss_buffer_t exp_composite_name) +{ + OM_uint32 ret; + ret = gss_export_name_composite(minor_status, + name, + exp_composite_name); + return (ret); +} + +OM_uint32 +spnego_gss_map_name_to_any(OM_uint32 *minor_status, + gss_name_t name, + int authenticated, + gss_buffer_t type_id, + gss_any_t *output) +{ + OM_uint32 ret; + ret = gss_map_name_to_any(minor_status, + name, + authenticated, + type_id, + output); + return (ret); +} + +OM_uint32 +spnego_gss_release_any_name_mapping(OM_uint32 *minor_status, + gss_name_t name, + gss_buffer_t type_id, + gss_any_t *input) +{ + OM_uint32 ret; + ret = gss_release_any_name_mapping(minor_status, + name, + type_id, + input); + return (ret); +} + /* * We will release everything but the ctx_handle so that it * can be passed back to init/accept context. This routine should diff --git a/src/lib/krb5/asn.1/asn1_k_decode.c b/src/lib/krb5/asn.1/asn1_k_decode.c index fe168088e..1a4689448 100644 --- a/src/lib/krb5/asn.1/asn1_k_decode.c +++ b/src/lib/krb5/asn.1/asn1_k_decode.c @@ -1720,7 +1720,31 @@ asn1_error_code asn1_decode_fast_finished_ptr decode_ptr( krb5_fast_finished *, asn1_decode_fast_finished); } - +asn1_error_code asn1_decode_ad_kdcissued +(asn1buf *buf, krb5_ad_kdcissued *val) +{ + setup(); + val->ad_checksum.contents = NULL; + val->i_principal = NULL; + val->elements = NULL; + {begin_structure(); + get_field(val->ad_checksum, 0, asn1_decode_checksum); + if (tagnum == 1) { + alloc_principal(val->i_principal); + opt_field(val->i_principal, 1, asn1_decode_realm, 0); + opt_field(val->i_principal, 2, asn1_decode_principal_name, 0); + } + get_field(val->elements, 3, asn1_decode_authorization_data); + end_structure(); + } + return 0; +error_out: + krb5_free_checksum_contents(NULL, &val->ad_checksum); + krb5_free_principal(NULL, val->i_principal); + krb5_free_authdata(NULL, val->elements); + return retval; +} + #ifndef DISABLE_PKINIT /* PKINIT */ diff --git a/src/lib/krb5/asn.1/asn1_k_decode.h b/src/lib/krb5/asn.1/asn1_k_decode.h index fc62c8f4e..f0d99dcc0 100644 --- a/src/lib/krb5/asn.1/asn1_k_decode.h +++ b/src/lib/krb5/asn.1/asn1_k_decode.h @@ -282,4 +282,10 @@ asn1_error_code asn1_decode_fast_finished asn1_error_code asn1_decode_fast_finished_ptr (asn1buf *buf, krb5_fast_finished **val); +asn1_error_code asn1_decode_ad_kdcissued +(asn1buf *buf, krb5_ad_kdcissued *val); + +asn1_error_code asn1_decode_ad_kdcissued_ptr +(asn1buf *buf, krb5_ad_kdcissued **val); + #endif diff --git a/src/lib/krb5/asn.1/asn1_k_encode.c b/src/lib/krb5/asn.1/asn1_k_encode.c index cd63ffbb9..1e9f11fe8 100644 --- a/src/lib/krb5/asn.1/asn1_k_encode.c +++ b/src/lib/krb5/asn.1/asn1_k_encode.c @@ -1290,6 +1290,23 @@ DEFSEQTYPE(fast_rep, krb5_enc_data, fast_rep_fields, 0); DEFFIELDTYPE(pa_fx_fast_reply, krb5_enc_data, FIELDOF_ENCODEAS(krb5_enc_data, fast_rep, 0)); +static const struct field_info ad_kdcissued_fields[] = { + FIELDOF_NORM(krb5_ad_kdcissued, checksum, ad_checksum, 0), + FIELDOF_OPT(krb5_ad_kdcissued, realm_of_principal, i_principal, 1, 1), + FIELDOF_OPT(krb5_ad_kdcissued, principal, i_principal, 2, 1), + FIELDOF_NORM(krb5_ad_kdcissued, auth_data_ptr, elements, 3), +}; + +static unsigned int ad_kdcissued_optional(const void *p) +{ + unsigned int optional = 0; + const krb5_ad_kdcissued *val = p; + if (val->i_principal) + optional |= (1u << 1); + return optional; +} + +DEFSEQTYPE(ad_kdc_issued, krb5_ad_kdcissued, ad_kdcissued_fields, ad_kdcissued_optional); @@ -1366,7 +1383,7 @@ MAKE_FULL_ENCODER( encode_krb5_fast_req, fast_req); MAKE_FULL_ENCODER( encode_krb5_pa_fx_fast_reply, pa_fx_fast_reply); MAKE_FULL_ENCODER(encode_krb5_fast_response, fast_response); - +MAKE_FULL_ENCODER(encode_krb5_ad_kdcissued, ad_kdc_issued); diff --git a/src/lib/krb5/asn.1/krb5_decode.c b/src/lib/krb5/asn.1/krb5_decode.c index a2e9c0a4d..215608d33 100644 --- a/src/lib/krb5/asn.1/krb5_decode.c +++ b/src/lib/krb5/asn.1/krb5_decode.c @@ -1180,6 +1180,17 @@ krb5_error_code decode_krb5_pa_fx_fast_reply cleanup(free); } +krb5_error_code decode_krb5_ad_kdcissued +(const krb5_data *code, krb5_ad_kdcissued **repptr) +{ + setup_buf_only(krb5_ad_kdcissued *); + alloc_field(rep); + + retval = asn1_decode_ad_kdcissued(&buf, rep); + if (retval) clean_return(retval); + + cleanup(free); +} #ifndef DISABLE_PKINIT krb5_error_code diff --git a/src/lib/krb5/ccache/cc_file.c b/src/lib/krb5/ccache/cc_file.c index bd93fa431..32564a04e 100644 --- a/src/lib/krb5/ccache/cc_file.c +++ b/src/lib/krb5/ccache/cc_file.c @@ -859,14 +859,14 @@ krb5_fcc_read_authdatum(krb5_context context, krb5_ccache id, krb5_authdata *a) { krb5_error_code kret; krb5_int32 int32; - krb5_ui_2 ui2; + krb5_int16 ui2; /* negative authorization data types are allowed */ k5_cc_mutex_assert_locked(context, &((krb5_fcc_data *) id->data)->lock); a->magic = KV5M_AUTHDATA; a->contents = NULL; - kret = krb5_fcc_read_ui_2(context, id, &ui2); + kret = krb5_fcc_read_ui_2(context, id, (krb5_ui_2 *)&ui2); CHECK(kret); a->ad_type = (krb5_authdatatype)ui2; kret = krb5_fcc_read_int32(context, id, &int32); diff --git a/src/lib/krb5/ccache/ccfns.c b/src/lib/krb5/ccache/ccfns.c index 5d95a6428..abfc037be 100644 --- a/src/lib/krb5/ccache/ccfns.c +++ b/src/lib/krb5/ccache/ccfns.c @@ -70,7 +70,7 @@ krb5_cc_store_cred (krb5_context context, krb5_ccache cache, krb5_principal s1, s2; /* remove any dups */ - krb5_cc_remove_cred(context, cache, 0, creds); + krb5_cc_remove_cred(context, cache, KRB5_TC_MATCH_AUTHDATA, creds); ret = cache->ops->store(context, cache, creds); if (ret) return ret; @@ -87,7 +87,7 @@ krb5_cc_store_cred (krb5_context context, krb5_ccache cache, if (!krb5_principal_compare(context, s1, s2)) { creds->server = s2; /* remove any dups */ - krb5_cc_remove_cred(context, cache, 0, creds); + krb5_cc_remove_cred(context, cache, KRB5_TC_MATCH_AUTHDATA, creds); ret = cache->ops->store(context, cache, creds); creds->server = s1; } diff --git a/src/lib/krb5/error_tables/kv5m_err.et b/src/lib/krb5/error_tables/kv5m_err.et index d68398cf9..6259adab7 100644 --- a/src/lib/krb5/error_tables/kv5m_err.et +++ b/src/lib/krb5/error_tables/kv5m_err.et @@ -89,4 +89,5 @@ error_code KV5M_GSS_QUEUE, "Bad magic number for GSSAPI QUEUE" error_code KV5M_FAST_ARMORED_REQ, "Bad magic number for fast armored request" error_code KV5M_FAST_REQ, "Bad magic number for FAST request" error_code KV5M_FAST_RESPONSE, "Bad magic number for FAST response" +error_code KV5M_AUTHDATA_CONTEXT, "Bad magic number for krb5_authdata_context" end diff --git a/src/lib/krb5/krb/Makefile.in b/src/lib/krb5/krb/Makefile.in index 8b8f6d2db..3746746fe 100644 --- a/src/lib/krb5/krb/Makefile.in +++ b/src/lib/krb5/krb/Makefile.in @@ -18,6 +18,7 @@ STLIBOBJS= \ addr_srch.o \ appdefault.o \ auth_con.o \ + authdata.o \ bld_pr_ext.o \ bld_princ.o \ chk_trans.o \ @@ -107,6 +108,7 @@ OBJS= $(OUTPRE)addr_comp.$(OBJEXT) \ $(OUTPRE)addr_srch.$(OBJEXT) \ $(OUTPRE)appdefault.$(OBJEXT) \ $(OUTPRE)auth_con.$(OBJEXT) \ + $(OUTPRE)authdata.$(OBJEXT) \ $(OUTPRE)bld_pr_ext.$(OBJEXT) \ $(OUTPRE)bld_princ.$(OBJEXT) \ $(OUTPRE)chk_trans.$(OBJEXT) \ @@ -196,6 +198,7 @@ SRCS= $(srcdir)/addr_comp.c \ $(srcdir)/addr_srch.c \ $(srcdir)/appdefault.c \ $(srcdir)/auth_con.c \ + $(srcdir)/authdata.c \ $(srcdir)/bld_pr_ext.c \ $(srcdir)/bld_princ.c \ $(srcdir)/brand.c \ @@ -312,11 +315,11 @@ T_WALK_RTREE_OBJS= t_walk_rtree.o walk_rtree.o tgtname.o unparse.o \ T_KERB_OBJS= t_kerb.o conv_princ.o unparse.o set_realm.o str_conv.o T_SER_OBJS= t_ser.o ser_actx.o ser_adata.o ser_addr.o ser_auth.o ser_cksum.o \ - ser_ctx.o ser_key.o ser_princ.o serialize.o + ser_ctx.o ser_key.o ser_princ.o serialize.o authdata.o pac.o copy_data.o T_DELTAT_OBJS= t_deltat.o deltat.o -T_PAC_OBJS= t_pac.o pac.o +T_PAC_OBJS= t_pac.o pac.o copy_data.o T_PRINC_OBJS= t_princ.o parse.o unparse.o @@ -327,8 +330,8 @@ t_walk_rtree: $(T_WALK_RTREE_OBJS) $(KRB5_BASE_DEPLIBS) t_ad_fx_armor: t_ad_fx_armor.o $(CC_LINK) -o $@ t_ad_fx_armor.o $(KRB5_BASE_LIBS) -t_authdata: t_authdata.o copy_auth.o - $(CC_LINK) -o $@ t_authdata.o copy_auth.o $(KRB5_BASE_LIBS) +t_authdata: t_authdata.o $(KRB5_BASE_DEPLIBS) + $(CC_LINK) -o $@ t_authdata.o $(KRB5_BASE_LIBS) t_kerb: $(T_KERB_OBJS) $(KRB5_BASE_DEPLIBS) $(CC_LINK) -o t_kerb $(T_KERB_OBJS) $(KRB5_BASE_LIBS) diff --git a/src/lib/krb5/krb/auth_con.c b/src/lib/krb5/krb/auth_con.c index 41a2578e0..b88219cdb 100644 --- a/src/lib/krb5/krb/auth_con.c +++ b/src/lib/krb5/krb/auth_con.c @@ -66,6 +66,8 @@ krb5_auth_con_free(krb5_context context, krb5_auth_context auth_context) krb5_rc_close(context, auth_context->rcache); if (auth_context->permitted_etypes) free(auth_context->permitted_etypes); + if (auth_context->ad_context) + krb5_authdata_context_free(context, auth_context->ad_context); free(auth_context); return 0; } @@ -568,3 +570,21 @@ krb5_auth_con_get_subkey_enctype(krb5_context context, return 0; } +krb5_error_code KRB5_CALLCONV +krb5_auth_con_get_authdata_context(krb5_context context, + krb5_auth_context auth_context, + krb5_authdata_context *ad_context) +{ + *ad_context = auth_context->ad_context; + return 0; +} + +krb5_error_code KRB5_CALLCONV +krb5_auth_con_set_authdata_context(krb5_context context, + krb5_auth_context auth_context, + krb5_authdata_context ad_context) +{ + auth_context->ad_context = ad_context; + return 0; +} + diff --git a/src/lib/krb5/krb/auth_con.h b/src/lib/krb5/krb/auth_con.h index be63bedbf..6254ac67c 100644 --- a/src/lib/krb5/krb/auth_con.h +++ b/src/lib/krb5/krb/auth_con.h @@ -24,6 +24,7 @@ struct _krb5_auth_context { krb5_mk_req_checksum_func checksum_func; void *checksum_func_data; krb5_enctype negotiated_etype; + krb5_authdata_context ad_context; }; diff --git a/src/lib/krb5/krb/authdata.c b/src/lib/krb5/krb/authdata.c new file mode 100644 index 000000000..6e1b9b5b1 --- /dev/null +++ b/src/lib/krb5/krb/authdata.c @@ -0,0 +1,1245 @@ +/* -*- mode: c; indent-tabs-mode: nil -*- */ +/* + * Copyright 2009 by the Massachusetts Institute of Technology. All + * Rights Reserved. + * + * Export of this software from the United States of America may + * require a specific license from the United States Government. + * It is the responsibility of any person or organization contemplating + * export to obtain such a license before exporting. + * + * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and + * distribute this software and its documentation for any purpose and + * without fee is hereby granted, provided that the above copyright + * notice appear in all copies and that both that copyright notice and + * this permission notice appear in supporting documentation, and that + * the name of M.I.T. not be used in advertising or publicity pertaining + * to distribution of the software without specific, written prior + * permission. Furthermore if you modify this software you must label + * your software as modified software and not distribute it in such a + * fashion that it might be confused with the original M.I.T. software. + * M.I.T. makes no representations about the suitability of + * this software for any purpose. It is provided "as is" without express + * or implied warranty. + * + */ + +#include "k5-int.h" +#include "authdata.h" +#include "auth_con.h" +#include "int-proto.h" + +/* Loosely based on preauth2.c */ + +#define IS_PRIMARY_INSTANCE(_module) ((_module)->client_req_init != NULL) + +static const char *objdirs[] = { +#if TARGET_OS_MAC + KRB5_AUTHDATA_PLUGIN_BUNDLE_DIR, +#endif + LIBDIR "/krb5/plugins/authdata", + NULL + }; /* should be a list */ + +/* Internal authdata systems */ +static krb5plugin_authdata_client_ftable_v0 *authdata_systems[] = { + &krb5int_mspac_authdata_client_ftable, + NULL +}; + +static inline int +k5_ad_module_count(krb5plugin_authdata_client_ftable_v0 *table) +{ + int i; + + if (table->ad_type_list == NULL) + return 0; + + for (i = 0; table->ad_type_list[i]; i++) + ; + + return i; +} + +static krb5_error_code +k5_ad_init_modules(krb5_context kcontext, + krb5_authdata_context context, + krb5plugin_authdata_client_ftable_v0 *table, + int *module_count) +{ + int j, k = *module_count; + krb5_error_code code; + void *plugin_context = NULL; + void **rcpp; + + if (table->ad_type_list == NULL) { +#ifdef DEBUG + fprintf(stderr, "warning: module \"%s\" does not advertise " + "any AD types\n", table->name); +#endif + return ENOENT; + } + + if (table->init == NULL) + return ENOSYS; + + code = (*table->init)(kcontext, &plugin_context); + if (code != 0) { +#ifdef DEBUG + fprintf(stderr, "warning: skipping module \"%s\" which " + "failed to initialize\n", table->name); +#endif + return code; + } + + for (j = 0; table->ad_type_list[j] != 0; j++) { + context->modules[k].ad_type = table->ad_type_list[j]; + context->modules[k].plugin_context = plugin_context; + if (j == 0) + context->modules[k].client_fini = table->fini; + else + context->modules[k].client_fini = NULL; + context->modules[k].ftable = table; + context->modules[k].name = table->name; + if (table->flags != NULL) { + (*table->flags)(kcontext, plugin_context, + context->modules[k].ad_type, + &context->modules[k].flags); + } else { + context->modules[k].flags = 0; + } + context->modules[k].request_context = NULL; + if (j == 0) { + context->modules[k].client_req_init = table->request_init; + context->modules[k].client_req_fini = table->request_fini; + rcpp = &context->modules[k].request_context; + + /* For now, single request per context. That may change */ + code = (*table->request_init)(kcontext, + context, + plugin_context, + rcpp); + if ((code != 0 && code != ENOMEM) && + (context->modules[k].flags & AD_INFORMATIONAL)) + code = 0; + if (code != 0) + break; + } else { + context->modules[k].client_req_init = NULL; + context->modules[k].client_req_fini = NULL; + } + context->modules[k].request_context_pp = rcpp; + +#ifdef DEBUG + fprintf(stderr, "init module \"%s\", ad_type %d, flags %08x\n", + context->modules[k].name, + context->modules[k].ad_type, + context->modules[k].flags); +#endif + k++; + } + *module_count = k; + + return code; +} + +/* + * Determine size of to-be-externalized authdata context, for + * modules that match given flags mask. Note that this size + * does not include the magic identifier/trailer. + */ +static krb5_error_code +k5_ad_size(krb5_context kcontext, + krb5_authdata_context context, + krb5_flags flags, + size_t *sizep) +{ + int i; + krb5_error_code code = 0; + + *sizep += sizeof(krb5_int32); /* count */ + + for (i = 0; i < context->n_modules; i++) { + struct _krb5_authdata_context_module *module = &context->modules[i]; + size_t size; + + if ((module->flags & flags) == 0) + continue; + + /* externalize request context for the first instance only */ + if (!IS_PRIMARY_INSTANCE(module)) + continue; + + if (module->ftable->size == NULL) + continue; + + assert(module->ftable->externalize != NULL); + + size = sizeof(krb5_int32) /* namelen */ + strlen(module->name); + + code = (*module->ftable->size)(kcontext, + context, + module->plugin_context, + *(module->request_context_pp), + &size); + if (code != 0) + break; + + *sizep += size; + } + + return code; +} + +/* + * Externalize authdata context, for modules that match given flags + * mask. Note that the magic identifier/trailer is not included. + */ +static krb5_error_code +k5_ad_externalize(krb5_context kcontext, + krb5_authdata_context context, + krb5_flags flags, + krb5_octet **buffer, + size_t *lenremain) +{ + int i; + krb5_error_code code; + krb5_int32 ad_count = 0; + krb5_octet *bp; + size_t remain; + + bp = *buffer; + remain = *lenremain; + + /* placeholder for count */ + code = krb5_ser_pack_int32(0, &bp, &remain); + if (code != 0) + return code; + + for (i = 0; i < context->n_modules; i++) { + struct _krb5_authdata_context_module *module = &context->modules[i]; + size_t namelen; + + if ((module->flags & flags) == 0) + continue; + + /* externalize request context for the first instance only */ + if (!IS_PRIMARY_INSTANCE(module)) + continue; + + if (module->ftable->externalize == NULL) + continue; + + /* + * We use the module name rather than the authdata type, because + * there may be multiple modules for a particular authdata type. + */ + namelen = strlen(module->name); + + code = krb5_ser_pack_int32((krb5_int32)namelen, &bp, &remain); + if (code != 0) + break; + + code = krb5_ser_pack_bytes((krb5_octet *)module->name, + namelen, &bp, &remain); + if (code != 0) + break; + + code = (*module->ftable->externalize)(kcontext, + context, + module->plugin_context, + *(module->request_context_pp), + &bp, + &remain); + if (code != 0) + break; + + ad_count++; + } + + if (code == 0) { + /* store actual count */ + krb5_ser_pack_int32(ad_count, buffer, lenremain); + + *buffer = bp; + *lenremain = remain; + } + + return code; +} + +/* + * Find authdata module for authdata type that matches flag mask + */ +static struct _krb5_authdata_context_module * +k5_ad_find_module(krb5_context kcontext, + krb5_authdata_context context, + krb5_flags flags, + const krb5_data *name) +{ + int i; + struct _krb5_authdata_context_module *ret = NULL; + + for (i = 0; i < context->n_modules; i++) { + struct _krb5_authdata_context_module *module = &context->modules[i]; + + if ((module->flags & flags) == 0) + continue; + + /* internalize request context for the first instance only */ + if (!IS_PRIMARY_INSTANCE(module)) + continue; + + /* check for name match */ + if (strlen(module->name) != name->length || + memcmp(module->name, name->data, name->length) != 0) + continue; + + ret = module; + break; + } + + return ret; +} + +/* + * In-place internalize authdata context, for modules that match given + * flags mask. The magic identifier/trailer is not expected by this. + */ +static krb5_error_code +k5_ad_internalize(krb5_context kcontext, + krb5_authdata_context context, + krb5_flags flags, + krb5_octet **buffer, + size_t *lenremain) +{ + krb5_error_code code = 0; + krb5_int32 i, count; + krb5_octet *bp; + size_t remain; + + bp = *buffer; + remain = *lenremain; + + code = krb5_ser_unpack_int32(&count, &bp, &remain); + if (code != 0) + return code; + + for (i = 0; i < count; i++) { + struct _krb5_authdata_context_module *module; + krb5_int32 namelen; + krb5_data name; + + code = krb5_ser_unpack_int32(&namelen, &bp, &remain); + if (code != 0) + break; + + if (remain < (size_t)namelen) { + code = ENOMEM; + break; + } + + name.length = namelen; + name.data = (char *)bp; + + module = k5_ad_find_module(kcontext, context, flags, &name); + if (module == NULL || module->ftable->internalize == NULL) { + code = EINVAL; + break; + } + + bp += namelen; + remain -= namelen; + + code = (*module->ftable->internalize)(kcontext, + context, + module->plugin_context, + *(module->request_context_pp), + &bp, + &remain); + if (code != 0) + break; + } + + if (code == 0) { + *buffer = bp; + *lenremain = remain; + } + + return code; +} + +krb5_error_code KRB5_CALLCONV +krb5_authdata_context_init(krb5_context kcontext, + krb5_authdata_context *pcontext) +{ + int n_modules, n_tables, i, k; + void **tables = NULL; + krb5plugin_authdata_client_ftable_v0 *table; + krb5_authdata_context context = NULL; + int internal_count = 0; + struct plugin_dir_handle plugins; + krb5_error_code code; + + *pcontext = NULL; + memset(&plugins, 0, sizeof(plugins)); + + n_modules = 0; + for (n_tables = 0; authdata_systems[n_tables] != NULL; n_tables++) { + n_modules += k5_ad_module_count(authdata_systems[n_tables]); + } + internal_count = n_tables; + + if (PLUGIN_DIR_OPEN(&plugins) == 0 && + krb5int_open_plugin_dirs(objdirs, NULL, + &plugins, + &kcontext->err) == 0 && + krb5int_get_plugin_dir_data(&plugins, + "authdata_client_0", + &tables, + &kcontext->err) == 0 && + tables != NULL) + { + for (; tables[n_tables - internal_count] != NULL; n_tables++) { + table = tables[n_tables - internal_count]; + n_modules += k5_ad_module_count(table); + } + } + + context = calloc(1, sizeof(*context)); + if (kcontext == NULL) { + if (tables != NULL) + krb5int_free_plugin_dir_data(tables); + krb5int_close_plugin_dirs(&context->plugins); + return ENOMEM; + } + context->magic = KV5M_AUTHDATA_CONTEXT; + context->modules = calloc(n_modules, sizeof(context->modules[0])); + if (context->modules == NULL) { + if (tables != NULL) + krb5int_free_plugin_dir_data(tables); + krb5int_close_plugin_dirs(&context->plugins); + free(kcontext); + return ENOMEM; + } + context->n_modules = n_modules; + + /* fill in the structure */ + for (i = 0, k = 0, code = 0; i < n_tables - internal_count; i++) { + code = k5_ad_init_modules(kcontext, context, tables[i], &k); + if (code != 0) + break; + } + + if (code == 0) { + for (i = 0; i < internal_count; i++) { + code = k5_ad_init_modules(kcontext, context, authdata_systems[i], &k); + if (code != 0) + break; + } + } + + if (tables != NULL) + krb5int_free_plugin_dir_data(tables); + + context->plugins = plugins; + + if (code != 0) + krb5_authdata_context_free(kcontext, context); + else + *pcontext = context; + + return code; +} + +void KRB5_CALLCONV +krb5_authdata_context_free(krb5_context kcontext, + krb5_authdata_context context) +{ + int i; + + if (context == NULL) + return; + + for (i = 0; i < context->n_modules; i++) { + struct _krb5_authdata_context_module *module = &context->modules[i]; + + if (module->client_req_fini != NULL && + module->request_context != NULL) + (*module->client_req_fini)(kcontext, + context, + module->plugin_context, + module->request_context); + + if (module->client_fini != NULL) + (*module->client_fini)(kcontext, module->plugin_context); + + memset(module, 0, sizeof(*module)); + } + + if (context->modules != NULL) { + free(context->modules); + context->modules = NULL; + } + krb5int_close_plugin_dirs(&context->plugins); + memset(context, 0, sizeof(*context)); + free(context); +} + +krb5_error_code KRB5_CALLCONV +krb5_authdata_import_attributes(krb5_context kcontext, + krb5_authdata_context context, + krb5_flags usage, + const krb5_data *attrs) +{ + krb5_octet *bp; + size_t remain; + + bp = (krb5_octet *)attrs->data; + remain = attrs->length; + + return k5_ad_internalize(kcontext, context, usage, &bp, &remain); +} + +static krb5_error_code +k5_get_kdc_issued_authdata(krb5_context kcontext, + const krb5_ap_req *ap_req, + krb5_principal *kdc_issuer, + krb5_authdata ***kdc_issued_authdata) +{ + krb5_error_code code; + krb5_authdata **authdata; + krb5_authdata **ticket_authdata; + + *kdc_issuer = NULL; + *kdc_issued_authdata = NULL; + + ticket_authdata = ap_req->ticket->enc_part2->authorization_data; + + code = krb5int_find_authdata(kcontext, + ticket_authdata, + NULL, + KRB5_AUTHDATA_KDC_ISSUED, + &authdata); + if (code != 0 || authdata == NULL) + return code; + + /* + * Note: a module must still implement a verify_authdata + * method, even it is a NOOP that simply records the value + * of the kdc_issued_flag. + */ + code = krb5_verify_authdata_kdc_issued(kcontext, + ap_req->ticket->enc_part2->session, + authdata[0], + kdc_issuer, + kdc_issued_authdata); + + assert(code == 0 || *kdc_issued_authdata == NULL); + + krb5_free_authdata(kcontext, authdata); + + return code; +} + +krb5_error_code KRB5_CALLCONV +krb5_authdata_export_authdata(krb5_context kcontext, + krb5_authdata_context context, + krb5_flags flags, + krb5_authdata ***pauthdata) +{ + int i; + krb5_error_code code = 0; + krb5_authdata **authdata = NULL; + unsigned int len = 0; + + *pauthdata = NULL; + + for (i = 0; i < context->n_modules; i++) { + struct _krb5_authdata_context_module *module = &context->modules[i]; + krb5_authdata **authdata2 = NULL; + int j; + + if ((module->flags & flags) == 0) + continue; + + if (module->ftable->export_authdata == NULL) + continue; + + code = (*module->ftable->export_authdata)(kcontext, + context, + module->plugin_context, + *(module->request_context_pp), + flags, + &authdata2); + if (code == ENOENT) + code = 0; + else if (code != 0) + break; + + if (authdata2 == NULL) + continue; + + for (j = 0; authdata2[j] != NULL; j++) + ; + + authdata = realloc(authdata, (len + j + 1) * sizeof(krb5_authdata *)); + if (authdata == NULL) + return ENOMEM; + + memcpy(&authdata[len], authdata2, j * sizeof(krb5_authdata *)); + free(authdata2); + + len += j; + } + + if (authdata != NULL) + authdata[len] = NULL; + + *pauthdata = authdata; + + return code; +} + +krb5_error_code +krb5int_authdata_verify(krb5_context kcontext, + krb5_authdata_context context, + krb5_flags usage, + const krb5_auth_context *auth_context, + const krb5_keyblock *key, + const krb5_ap_req *ap_req) +{ + int i; + krb5_error_code code = 0; + krb5_authdata **authen_authdata; + krb5_authdata **ticket_authdata; + krb5_principal kdc_issuer = NULL; + krb5_authdata **kdc_issued_authdata = NULL; + + authen_authdata = (*auth_context)->authentp->authorization_data; + ticket_authdata = ap_req->ticket->enc_part2->authorization_data; + k5_get_kdc_issued_authdata(kcontext, ap_req, + &kdc_issuer, &kdc_issued_authdata); + + for (i = 0; i < context->n_modules; i++) { + struct _krb5_authdata_context_module *module = &context->modules[i]; + krb5_authdata **authdata = NULL; + krb5_boolean kdc_issued_flag = FALSE; + + if ((module->flags & usage) == 0) + continue; + + if (module->ftable->import_authdata == NULL) + continue; + + if (kdc_issued_authdata != NULL) { + code = krb5int_find_authdata(kcontext, + kdc_issued_authdata, + NULL, + module->ad_type, + &authdata); + if (code != 0) + break; + + kdc_issued_flag = TRUE; + } + + if (authdata == NULL) { + code = krb5int_find_authdata(kcontext, + ticket_authdata, + authen_authdata, + module->ad_type, + &authdata); + if (code != 0) + break; + } + + if (authdata == NULL) + continue; + + assert(authdata[0] != NULL); + + code = (*module->ftable->import_authdata)(kcontext, + context, + module->plugin_context, + *(module->request_context_pp), + authdata, + kdc_issued_flag, + kdc_issuer); + if (code == 0 && module->ftable->verify != NULL) { + code = (*module->ftable->verify)(kcontext, + context, + module->plugin_context, + *(module->request_context_pp), + auth_context, + key, + ap_req); + } + if (code != 0 && (module->flags & AD_INFORMATIONAL)) + code = 0; + krb5_free_authdata(kcontext, authdata); + if (code != 0) + break; + } + + krb5_free_principal(kcontext, kdc_issuer); + krb5_free_authdata(kcontext, kdc_issued_authdata); + + return code; +} + +static krb5_error_code +k5_merge_data_list(krb5_data **dst, krb5_data *src, unsigned int *len) +{ + unsigned int i; + krb5_data *d; + + if (src == NULL) + return 0; + + for (i = 0; src[i].data != NULL; i++) + ; + + d = realloc(*dst, (*len + i + 1) * sizeof(krb5_data)); + if (d == NULL) + return ENOMEM; + + memcpy(&d[*len], src, i * sizeof(krb5_data)); + + *len += i; + + d[*len].data = NULL; + d[*len].length = 0; + + *dst = d; + + return 0; +} + +krb5_error_code KRB5_CALLCONV +krb5_authdata_get_attribute_types(krb5_context kcontext, + krb5_authdata_context context, + krb5_data **out_attrs) +{ + int i; + krb5_error_code code = 0; + krb5_data *attrs = NULL; + unsigned int attrs_len = 0; + + for (i = 0; i < context->n_modules; i++) { + struct _krb5_authdata_context_module *module = &context->modules[i]; + krb5_data *attrs2 = NULL; + + if (module->ftable->get_attribute_types == NULL) + continue; + + if ((*module->ftable->get_attribute_types)(kcontext, + context, + module->plugin_context, + *(module->request_context_pp), + &attrs2)) + continue; + + code = k5_merge_data_list(&attrs, attrs2, &attrs_len); + if (code != 0) { + krb5int_free_data_list(kcontext, attrs2); + break; + } + if (attrs2 != NULL) + free(attrs2); + } + + if (code != 0) { + krb5int_free_data_list(kcontext, attrs); + attrs = NULL; + } + + *out_attrs = attrs; + + return code; +} + +krb5_error_code KRB5_CALLCONV +krb5_authdata_get_attribute(krb5_context kcontext, + krb5_authdata_context context, + const krb5_data *attribute, + krb5_boolean *authenticated, + krb5_boolean *complete, + krb5_data *value, + krb5_data *display_value, + int *more) +{ + int i; + krb5_error_code code = ENOENT; + + *authenticated = FALSE; + *complete = FALSE; + + value->data = NULL; + value->length = 0; + + display_value->data = NULL; + display_value->length = 0; + + /* + * NB at present a module is presumed to be authoritative for + * an attribute; not sure how to federate "more" across module + * yet + */ + for (i = 0; i < context->n_modules; i++) { + struct _krb5_authdata_context_module *module = &context->modules[i]; + + if (module->ftable->get_attribute == NULL) + continue; + + code = (*module->ftable->get_attribute)(kcontext, + context, + module->plugin_context, + *(module->request_context_pp), + attribute, + authenticated, + complete, + value, + display_value, + more); + if (code == 0) + break; + } + + if (code != 0) + *more = 0; + + return code; +} + +krb5_error_code KRB5_CALLCONV +krb5_authdata_set_attribute(krb5_context kcontext, + krb5_authdata_context context, + krb5_boolean complete, + const krb5_data *attribute, + const krb5_data *value) +{ + int i; + krb5_error_code code = 0; + int found = 0; + + for (i = 0; i < context->n_modules; i++) { + struct _krb5_authdata_context_module *module = &context->modules[i]; + + if (module->ftable->set_attribute == NULL) + continue; + + code = (*module->ftable->set_attribute)(kcontext, + context, + module->plugin_context, + *(module->request_context_pp), + complete, + attribute, + value); + if (code == ENOENT) + code = 0; + else if (code == 0) + found++; + else + break; + } + + if (code == 0 && found == 0) + code = ENOENT; + + return code; +} + +krb5_error_code KRB5_CALLCONV +krb5_authdata_delete_attribute(krb5_context kcontext, + krb5_authdata_context context, + const krb5_data *attribute) +{ + int i; + krb5_error_code code = ENOENT; + int found = 0; + + for (i = 0; i < context->n_modules; i++) { + struct _krb5_authdata_context_module *module = &context->modules[i]; + + if (module->ftable->delete_attribute == NULL) + continue; + + code = (*module->ftable->delete_attribute)(kcontext, + context, + module->plugin_context, + *(module->request_context_pp), + attribute); + if (code == ENOENT) + code = 0; + else if (code == 0) + found++; + else + break; + } + + if (code == 0 && found == 0) + code = ENOENT; + + return code; +} + +krb5_error_code KRB5_CALLCONV +krb5_authdata_export_attributes(krb5_context kcontext, + krb5_authdata_context context, + krb5_flags flags, + krb5_data **attrsp) +{ + krb5_error_code code; + size_t required = 0; + krb5_octet *bp; + size_t remain; + krb5_data *attrs; + + code = k5_ad_size(kcontext, context, AD_USAGE_MASK, &required); + if (code != 0) + return code; + + attrs = malloc(sizeof(*attrs)); + if (attrs == NULL) + return ENOMEM; + + attrs->magic = KV5M_DATA; + attrs->length = 0; + attrs->data = malloc(required); + if (attrs->data == NULL) { + free(attrs); + return ENOMEM; + } + + bp = (krb5_octet *)attrs->data; + remain = required; + + code = k5_ad_externalize(kcontext, context, AD_USAGE_MASK, &bp, &remain); + if (code != 0) { + krb5_free_data(kcontext, attrs); + return code; + } + + attrs->length = (bp - (krb5_octet *)attrs->data); + + *attrsp = attrs; + + return 0; +} + +krb5_error_code KRB5_CALLCONV +krb5_authdata_export_internal(krb5_context kcontext, + krb5_authdata_context context, + krb5_boolean restrict_authenticated, + const char *module_name, + void **ptr) +{ + krb5_error_code code; + krb5_data name; + struct _krb5_authdata_context_module *module; + + *ptr = NULL; + + name.length = strlen(module_name); + name.data = (char *)module_name; + + module = k5_ad_find_module(kcontext, context, AD_USAGE_MASK, &name); + if (module == NULL) + return ENOENT; + + if (module->ftable->export_internal == NULL) + return ENOENT; + + code = (*module->ftable->export_internal)(kcontext, + context, + module->plugin_context, + *(module->request_context_pp), + restrict_authenticated, + ptr); + + return code; +} + +krb5_error_code KRB5_CALLCONV +krb5_authdata_free_internal(krb5_context kcontext, + krb5_authdata_context context, + const char *module_name, + void *ptr) +{ + krb5_data name; + struct _krb5_authdata_context_module *module; + + name.length = strlen(module_name); + name.data = (char *)module_name; + + module = k5_ad_find_module(kcontext, context, AD_USAGE_MASK, &name); + if (module == NULL) + return ENOENT; + + if (module->ftable->free_internal == NULL) + return ENOENT; + + (*module->ftable->free_internal)(kcontext, + context, + module->plugin_context, + *(module->request_context_pp), + ptr); + + return 0; +} + +static krb5_error_code +k5_copy_ad_module_data(krb5_context kcontext, + krb5_authdata_context context, + struct _krb5_authdata_context_module *src_module, + krb5_authdata_context dst) +{ + int i; + krb5_error_code code; + struct _krb5_authdata_context_module *dst_module = NULL; + + for (i = 0; i < dst->n_modules; i++) { + struct _krb5_authdata_context_module *module = &dst->modules[i]; + + if (module->ftable == src_module->ftable) { + /* XXX is this safe to assume these pointers are interned? */ + dst_module = module; + break; + } + } + + if (dst_module == NULL) + return ENOENT; + + /* copy request context for the first instance only */ + if (!IS_PRIMARY_INSTANCE(dst_module)) + return 0; + + assert(strcmp(dst_module->name, src_module->name) == 0); + + /* If copy is unimplemented, externalize/internalize */ + if (src_module->ftable->copy == NULL) { + size_t size = 0, remain; + krb5_octet *contents, *bp; + + assert(src_module->ftable->size != NULL); + assert(src_module->ftable->externalize != NULL); + assert(dst_module->ftable->internalize != NULL); + + code = (*src_module->ftable->size)(kcontext, + context, + src_module->plugin_context, + src_module->request_context, + &size); + if (code != 0) + return code; + + contents = malloc(size); + if (contents == NULL) + return ENOMEM; + + bp = contents; + remain = size; + + code = (*src_module->ftable->externalize)(kcontext, + context, + src_module->plugin_context, + *(src_module->request_context_pp), + &bp, + &remain); + if (code != 0) { + free(contents); + return code; + } + + remain = (bp - contents); + bp = contents; + + code = (*dst_module->ftable->internalize)(kcontext, + context, + dst_module->plugin_context, + *(dst_module->request_context_pp), + &bp, + &remain); + if (code != 0) { + free(contents); + return code; + } + + free(contents); + } else { + assert(src_module->request_context_pp == &src_module->request_context); + assert(dst_module->request_context_pp == &dst_module->request_context); + + code = (*src_module->ftable->copy)(kcontext, + context, + src_module->plugin_context, + src_module->request_context, + dst_module->plugin_context, + dst_module->request_context); + } + + return code; +} + +krb5_error_code KRB5_CALLCONV +krb5_authdata_context_copy(krb5_context kcontext, + krb5_authdata_context src, + krb5_authdata_context *pdst) +{ + int i; + krb5_error_code code; + krb5_authdata_context dst; + + /* XXX we need to init a new context because we can't copy plugins */ + code = krb5_authdata_context_init(kcontext, &dst); + if (code != 0) + return code; + + for (i = 0; i < src->n_modules; i++) { + struct _krb5_authdata_context_module *module = &src->modules[i]; + + code = k5_copy_ad_module_data(kcontext, src, module, dst); + if (code != 0) + break; + } + + if (code != 0) { + krb5_authdata_context_free(kcontext, dst); + return code; + } + + *pdst = dst; + + return 0; +} + +/* + * Calculate size of to-be-externalized authdata context. + */ +static krb5_error_code +krb5_authdata_context_size(krb5_context kcontext, + krb5_pointer ptr, + size_t *sizep) +{ + krb5_error_code code; + krb5_authdata_context context = (krb5_authdata_context)ptr; + + code = k5_ad_size(kcontext, context, AD_USAGE_MASK, sizep); + if (code != 0) + return code; + + *sizep += 2 * sizeof(krb5_int32); /* identifier/trailer */ + + return 0; +} + +/* + * Externalize an authdata context. + */ +static krb5_error_code +krb5_authdata_context_externalize(krb5_context kcontext, + krb5_pointer ptr, + krb5_octet **buffer, + size_t *lenremain) +{ + krb5_error_code code; + krb5_authdata_context context = (krb5_authdata_context)ptr; + krb5_octet *bp; + size_t remain; + + bp = *buffer; + remain = *lenremain; + + /* Our identifier */ + code = krb5_ser_pack_int32(KV5M_AUTHDATA_CONTEXT, &bp, &remain); + if (code != 0) + return code; + + /* The actual context data */ + code = k5_ad_externalize(kcontext, context, AD_USAGE_MASK, + &bp, &remain); + if (code != 0) + return code; + + /* Our trailer */ + code = krb5_ser_pack_int32(KV5M_AUTHDATA_CONTEXT, &bp, &remain); + if (code != 0) + return code; + + *buffer = bp; + *lenremain = remain; + + return 0; +} + +/* + * Internalize an authdata context. + */ +static krb5_error_code +krb5_authdata_context_internalize(krb5_context kcontext, + krb5_pointer *ptr, + krb5_octet **buffer, + size_t *lenremain) +{ + krb5_error_code code; + krb5_authdata_context context; + krb5_int32 ibuf; + krb5_octet *bp; + size_t remain; + + bp = *buffer; + remain = *lenremain; + + code = krb5_ser_unpack_int32(&ibuf, &bp, &remain); + if (code != 0) + return code; + + if (ibuf != KV5M_AUTHDATA_CONTEXT) + return EINVAL; + + code = krb5_authdata_context_init(kcontext, &context); + if (code != 0) + return code; + + code = k5_ad_internalize(kcontext, context, AD_USAGE_MASK, + &bp, &remain); + if (code != 0) { + krb5_authdata_context_free(kcontext, context); + return code; + } + + code = krb5_ser_unpack_int32(&ibuf, &bp, &remain); + if (code != 0) + return code; + + if (ibuf != KV5M_AUTHDATA_CONTEXT) { + krb5_authdata_context_free(kcontext, context); + return EINVAL; + } + + *buffer = bp; + *lenremain = remain; + *ptr = context; + + return 0; +} + +static const krb5_ser_entry krb5_authdata_context_ser_entry = { + KV5M_AUTHDATA_CONTEXT, + krb5_authdata_context_size, + krb5_authdata_context_externalize, + krb5_authdata_context_internalize +}; + +/* + * Register the authdata context serializer. + */ +krb5_error_code +krb5_ser_authdata_context_init(krb5_context kcontext) +{ + return krb5_register_serializer(kcontext, + &krb5_authdata_context_ser_entry); +} + diff --git a/src/lib/krb5/krb/authdata.h b/src/lib/krb5/krb/authdata.h new file mode 100644 index 000000000..9e4dcceb0 --- /dev/null +++ b/src/lib/krb5/krb/authdata.h @@ -0,0 +1,48 @@ +/* + * lib/krb5/krb/authdata.h + * + * Copyright (C) 2009 by the Massachusetts Institute of Technology. + * All rights reserved. + * + * Export of this software from the United States of America may + * require a specific license from the United States Government. + * It is the responsibility of any person or organization contemplating + * export to obtain such a license before exporting. + * + * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and + * distribute this software and its documentation for any purpose and + * without fee is hereby granted, provided that the above copyright + * notice appear in all copies and that both that copyright notice and + * this permission notice appear in supporting documentation, and that + * the name of M.I.T. not be used in advertising or publicity pertaining + * to distribution of the software without specific, written prior + * permission. Furthermore if you modify this software you must label + * your software as modified software and not distribute it in such a + * fashion that it might be confused with the original M.I.T. software. + * M.I.T. makes no representations about the suitability of + * this software for any purpose. It is provided "as is" without express + * or implied warranty. + * + * + * <<< Description >>> + */ +#ifndef KRB_AUTHDATA_H + +#define KRB_AUTHDATA_H + +#include + +/* authdata.c */ +krb5_error_code +krb5int_authdata_verify(krb5_context context, + krb5_authdata_context, + krb5_flags usage, + const krb5_auth_context *auth_context, + const krb5_keyblock *key, + const krb5_ap_req *ap_req); + +/* pac.c */ +extern krb5plugin_authdata_client_ftable_v0 krb5int_mspac_authdata_client_ftable; + +#endif /* !KRB_AUTHDATA_H */ + diff --git a/src/lib/krb5/krb/copy_auth.c b/src/lib/krb5/krb/copy_auth.c index dc989acf4..ba51f3808 100644 --- a/src/lib/krb5/krb/copy_auth.c +++ b/src/lib/krb5/krb/copy_auth.c @@ -276,3 +276,126 @@ krb5_error_code krb5int_find_authdata else krb5_free_authdata(context, fctx.out); return retval; } + +krb5_error_code KRB5_CALLCONV +krb5_make_authdata_kdc_issued(krb5_context context, + const krb5_keyblock *key, + krb5_const_principal issuer, + krb5_authdata *const *authdata, + krb5_authdata ***ad_kdcissued) +{ + krb5_error_code code; + krb5_ad_kdcissued ad_kdci; + krb5_data *data; + krb5_cksumtype cksumtype; + krb5_authdata ad_datum; + krb5_authdata *ad_data[2]; + + *ad_kdcissued = NULL; + + ad_kdci.ad_checksum.contents = NULL; + ad_kdci.i_principal = (krb5_principal)issuer; + ad_kdci.elements = (krb5_authdata **)authdata; + + code = krb5int_c_mandatory_cksumtype(context, key->enctype, + &cksumtype); + if (code != 0) + return code; + + code = encode_krb5_authdata(ad_kdci.elements, &data); + if (code != 0) + return code; + + code = krb5_c_make_checksum(context, cksumtype, + key, KRB5_KEYUSAGE_AD_KDCISSUED_CKSUM, + data, &ad_kdci.ad_checksum); + if (code != 0) { + krb5_free_data(context, data); + return code; + } + + krb5_free_data(context, data); + + code = encode_krb5_ad_kdcissued(&ad_kdci, &data); + if (code != 0) + return code; + + ad_datum.ad_type = KRB5_AUTHDATA_KDC_ISSUED; + ad_datum.length = data->length; + ad_datum.contents = (unsigned char *)data->data; + + ad_data[0] = &ad_datum; + ad_data[1] = NULL; + + code = krb5_copy_authdata(context, ad_data, ad_kdcissued); + + krb5_free_data(context, data); + krb5_free_checksum_contents(context, &ad_kdci.ad_checksum); + + return code; +} + +krb5_error_code KRB5_CALLCONV +krb5_verify_authdata_kdc_issued(krb5_context context, + const krb5_keyblock *key, + const krb5_authdata *ad_kdcissued, + krb5_principal *issuer, + krb5_authdata ***authdata) +{ + krb5_error_code code; + krb5_ad_kdcissued *ad_kdci; + krb5_data data, *data2; + krb5_boolean valid = FALSE; + + if ((ad_kdcissued->ad_type & AD_TYPE_FIELD_TYPE_MASK) != + KRB5_AUTHDATA_KDC_ISSUED) + return EINVAL; + + if (issuer != NULL) + *issuer = NULL; + if (authdata != NULL) + *authdata = NULL; + + data.length = ad_kdcissued->length; + data.data = (char *)ad_kdcissued->contents; + + code = decode_krb5_ad_kdcissued(&data, &ad_kdci); + if (code != 0) + return code; + + code = encode_krb5_authdata(ad_kdci->elements, &data2); + if (code != 0) { + krb5_free_ad_kdcissued(context, ad_kdci); + return code; + } + + code = krb5_c_verify_checksum(context, key, + KRB5_KEYUSAGE_AD_KDCISSUED_CKSUM, + data2, &ad_kdci->ad_checksum, &valid); + if (code != 0) { + krb5_free_ad_kdcissued(context, ad_kdci); + krb5_free_data(context, data2); + } + + krb5_free_data(context, data2); + + if (valid == FALSE) { + krb5_free_ad_kdcissued(context, ad_kdci); + return KRB5KRB_AP_ERR_BAD_INTEGRITY; + } + + if (issuer != NULL) { + *issuer = ad_kdci->i_principal; + ad_kdci->i_principal = NULL; + } + + if (authdata != NULL) { + *authdata = ad_kdci->elements; + ad_kdci->elements = NULL; + } + + krb5_free_ad_kdcissued(context, ad_kdci); + + return 0; +} + diff --git a/src/lib/krb5/krb/gc_frm_kdc.c b/src/lib/krb5/krb/gc_frm_kdc.c index b3144c84e..4102dd728 100644 --- a/src/lib/krb5/krb/gc_frm_kdc.c +++ b/src/lib/krb5/krb/gc_frm_kdc.c @@ -934,6 +934,7 @@ krb5_get_cred_from_kdc_opt(krb5_context context, krb5_ccache ccache, krb5_boolean old_use_conf_ktypes; char **hrealms; unsigned int referral_count, i; + krb5_authdata **supplied_authdata, **out_supplied_authdata = NULL; /* * Set up client and server pointers. Make a fresh and modifyable @@ -948,8 +949,18 @@ krb5_get_cred_from_kdc_opt(krb5_context context, krb5_ccache ccache, krb5_free_principal(context, server); return retval; } + if (in_cred->authdata != NULL) { + if ((retval = krb5_copy_authdata(context, in_cred->authdata, + &out_supplied_authdata)) != 0) { + krb5_free_principal(context, out_supplied_server); + krb5_free_principal(context, server); + return retval; + } + } + supplied_server = in_cred->server; in_cred->server=server; + supplied_authdata = in_cred->authdata; DUMP_PRINC("gc_from_kdc initial client", client); DUMP_PRINC("gc_from_kdc initial server", server); @@ -1139,6 +1150,15 @@ krb5_get_cred_from_kdc_opt(krb5_context context, krb5_ccache ccache, if (tgtptr == &cc_tgt) krb5_free_cred_contents(context, tgtptr); tgtptr=*out_cred; + /* Save requested auth data with TGT in case it ends up stored */ + if (supplied_authdata != NULL) { + /* Ensure we note TGT contains authorization data */ + retval = krb5_copy_authdata(context, + supplied_authdata, + &(*out_cred)->authdata); + if (retval) + goto cleanup; + } /* Save pointer to tgt in referral_tgts. */ referral_tgts[referral_count]=*out_cred; *out_cred = NULL; @@ -1149,6 +1169,8 @@ krb5_get_cred_from_kdc_opt(krb5_context context, krb5_ccache ccache, &server->realm); if (retval) goto cleanup; + /* Don't ask for KDC to add auth data multiple times */ + in_cred->authdata = NULL; /* * Future work: rewrite server principal per any * supplied padata. @@ -1252,7 +1274,6 @@ krb5_get_cred_from_kdc_opt(krb5_context context, krb5_ccache ccache, retval = KRB5_PROG_ETYPE_NOSUPP; goto cleanup; } - context->use_conf_ktypes = old_use_conf_ktypes; retval = krb5_get_cred_via_tkt(context, tgtptr, FLAGS2OPTS(tgtptr->ticket_flags) | @@ -1272,10 +1293,13 @@ cleanup: server); krb5_free_principal(context, server); in_cred->server = supplied_server; + in_cred->authdata = supplied_authdata; if (*out_cred && !retval) { /* Success: free server, swap supplied server back in. */ krb5_free_principal (context, (*out_cred)->server); - (*out_cred)->server= out_supplied_server; + (*out_cred)->server = out_supplied_server; + assert((*out_cred)->authdata == NULL); + (*out_cred)->authdata = out_supplied_authdata; } else { /* @@ -1283,7 +1307,8 @@ cleanup: * since it's either null or a referral TGT that we free below, * and we may need it to return. */ - krb5_free_principal (context, out_supplied_server); + krb5_free_principal(context, out_supplied_server); + krb5_free_authdata(context, out_supplied_authdata); } DUMP_PRINC("gc_from_kdc: final server after reversion", in_cred->server); /* diff --git a/src/lib/krb5/krb/int-proto.h b/src/lib/krb5/krb/int-proto.h index 6da6da151..724e18bf8 100644 --- a/src/lib/krb5/krb/int-proto.h +++ b/src/lib/krb5/krb/int-proto.h @@ -47,6 +47,7 @@ krb5_error_code krb5_ser_authenticator_init (krb5_context); krb5_error_code krb5_ser_checksum_init (krb5_context); krb5_error_code krb5_ser_keyblock_init (krb5_context); krb5_error_code krb5_ser_principal_init (krb5_context); +krb5_error_code krb5_ser_authdata_context_init (krb5_context); krb5_error_code krb5_preauth_supply_preauth_data(krb5_context context, diff --git a/src/lib/krb5/krb/kfree.c b/src/lib/krb5/krb/kfree.c index 9f5c702e8..801eed0da 100644 --- a/src/lib/krb5/krb/kfree.c +++ b/src/lib/krb5/krb/kfree.c @@ -534,7 +534,8 @@ krb5_free_tkt_authent(krb5_context context, krb5_tkt_authent *val) void KRB5_CALLCONV krb5_free_unparsed_name(krb5_context context, char *val) { - free(val); + if (val != NULL) + free(val); } void KRB5_CALLCONV @@ -881,3 +882,30 @@ void krb5_free_fast_armored_req(krb5_context context, krb5_free_checksum_contents(context, &val->req_checksum); free(val); } + +void KRB5_CALLCONV +krb5int_free_data_list(krb5_context context, krb5_data *data) +{ + int i; + + if (data == NULL) + return; + + for (i = 0; data[i].data != NULL; i++) + free(data[i].data); + + free(data); +} + +void KRB5_CALLCONV +krb5_free_ad_kdcissued(krb5_context context, krb5_ad_kdcissued *val) +{ + if (val == NULL) + return; + + krb5_free_checksum_contents(context, &val->ad_checksum); + krb5_free_principal(context, val->i_principal); + krb5_free_authdata(context, val->elements); + free(val); +} + diff --git a/src/lib/krb5/krb/mk_req_ext.c b/src/lib/krb5/krb/mk_req_ext.c index 64eafe362..df5ac2872 100644 --- a/src/lib/krb5/krb/mk_req_ext.c +++ b/src/lib/krb5/krb/mk_req_ext.c @@ -75,6 +75,7 @@ krb5_generate_authenticator (krb5_context, krb5_authenticator *, krb5_principal, krb5_checksum *, krb5_keyblock *, krb5_ui_4, krb5_authdata **, + krb5_authdata_context ad_context, krb5_enctype *desired_etypes, krb5_enctype tkt_enctype); @@ -244,6 +245,7 @@ krb5_mk_req_extended(krb5_context context, krb5_auth_context *auth_context, (*auth_context)->send_subkey, (*auth_context)->local_seq_number, in_creds->authdata, + (*auth_context)->ad_context, desired_etypes, in_creds->keyblock.enctype))) goto cleanup_cksum; @@ -253,12 +255,6 @@ krb5_mk_req_extended(krb5_context context, krb5_auth_context *auth_context, &scratch))) goto cleanup_cksum; - /* Null out these fields, to prevent pointer sharing problems; - * they were supplied by the caller - */ - (*auth_context)->authentp->client = NULL; - (*auth_context)->authentp->checksum = NULL; - /* call the encryption routine */ if ((retval = krb5_encrypt_helper(context, &in_creds->keyblock, KRB5_KEYUSAGE_AP_REQ_AUTH, @@ -272,6 +268,13 @@ krb5_mk_req_extended(krb5_context context, krb5_auth_context *auth_context, free(toutbuf); cleanup_cksum: + /* Null out these fields, to prevent pointer sharing problems; + * they were supplied by the caller + */ + if ((*auth_context)->authentp != NULL) { + (*auth_context)->authentp->client = NULL; + (*auth_context)->authentp->checksum = NULL; + } if (checksump && checksump->checksum_type != 0x8003) free(checksump->contents); @@ -299,11 +302,13 @@ krb5_generate_authenticator(krb5_context context, krb5_authenticator *authent, krb5_principal client, krb5_checksum *cksum, krb5_keyblock *key, krb5_ui_4 seq_number, krb5_authdata **authorization, + krb5_authdata_context ad_context, krb5_enctype *desired_etypes, krb5_enctype tkt_enctype) { krb5_error_code retval; - + krb5_authdata **ext_authdata = NULL; + authent->client = client; authent->checksum = cksum; if (key) { @@ -315,12 +320,27 @@ krb5_generate_authenticator(krb5_context context, krb5_authenticator *authent, authent->seq_number = seq_number; authent->authorization_data = NULL; - if (authorization != NULL) { - retval = krb5_copy_authdata(context, authorization, - &authent->authorization_data); + if (ad_context != NULL) { + retval = krb5_authdata_export_authdata(context, + ad_context, + AD_USAGE_AP_REQ, + &ext_authdata); if (retval) return retval; } + + if (authorization != NULL || ext_authdata != NULL) { + retval = krb5_merge_authdata(context, + authorization, + ext_authdata, + &authent->authorization_data); + if (retval) { + krb5_free_authdata(context, ext_authdata); + return retval; + } + krb5_free_authdata(context, ext_authdata); + } + /* Only send EtypeList if we prefer another enctype to tkt_enctype */ if (desired_etypes != NULL && desired_etypes[0] != tkt_enctype) { retval = make_etype_list(context, desired_etypes, tkt_enctype, diff --git a/src/lib/krb5/krb/pac.c b/src/lib/krb5/krb/pac.c index c5a706562..297e89550 100644 --- a/src/lib/krb5/krb/pac.c +++ b/src/lib/krb5/krb/pac.c @@ -8,7 +8,7 @@ * require a specific license from the United States Government. * It is the responsibility of any person or organization contemplating * export to obtain such a license before exporting. - * + * * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and * distribute this software and its documentation for any purpose and * without fee is hereby granted, provided that the above copyright @@ -27,6 +27,7 @@ #include "k5-int.h" #include "k5-utf8.h" +#include "authdata.h" /* draft-brezak-win2k-krb-authz-00 */ @@ -46,9 +47,12 @@ typedef struct _PAC_INFO_BUFFER { /* ulType */ #define PAC_LOGON_INFO 1 +#define PAC_CREDENTIALS_INFO 2 #define PAC_SERVER_CHECKSUM 6 #define PAC_PRIVSVR_CHECKSUM 7 #define PAC_CLIENT_INFO 10 +#define PAC_DELEGATION_INFO 11 +#define PAC_UPN_DNS_INFO 12 typedef struct _PACTYPE { krb5_ui_4 cBuffers; @@ -66,6 +70,7 @@ typedef struct _PACTYPE { struct krb5_pac_data { PACTYPE *pac; /* PAC header + info buffer array */ krb5_data data; /* PAC data (including uninitialised header) */ + krb5_boolean verified; }; static krb5_error_code @@ -93,7 +98,7 @@ k5_pac_add_buffer(krb5_context context, /* Check there isn't already a buffer of this type */ if (k5_pac_locate_buffer(context, pac, type, NULL) == 0) { - return EINVAL; + return EEXIST; } header = (PACTYPE *)realloc(pac->pac, @@ -148,6 +153,8 @@ k5_pac_add_buffer(krb5_context context, out_data->length = data->length; } + pac->verified = FALSE; + return 0; } @@ -228,7 +235,7 @@ krb5_pac_get_buffer(krb5_context context, ret = k5_pac_locate_buffer(context, pac, type, &d); if (ret != 0) return ret; - + data->data = malloc(d.length); if (data->data == NULL) return ENOMEM; @@ -277,7 +284,7 @@ krb5_pac_init(krb5_context context, pac->pac = (PACTYPE *)malloc(sizeof(PACTYPE)); if (pac->pac == NULL) { - free( pac); + free(pac); return ENOMEM; } @@ -291,11 +298,54 @@ krb5_pac_init(krb5_context context, return ENOMEM; } + pac->verified = FALSE; + *ppac = pac; return 0; } +static krb5_error_code +k5_pac_copy(krb5_context context, + krb5_pac src, + krb5_pac *dst) +{ + size_t header_len; + krb5_ui_4 cbuffers; + krb5_error_code code; + krb5_pac pac; + + cbuffers = src->pac->cBuffers; + if (cbuffers != 0) + cbuffers--; + + header_len = sizeof(PACTYPE) + cbuffers * sizeof(PAC_INFO_BUFFER); + + pac = (krb5_pac)malloc(sizeof(*pac)); + if (pac == NULL) + return ENOMEM; + + pac->pac = (PACTYPE *)malloc(header_len); + if (pac->pac == NULL) { + free(pac); + return ENOMEM; + } + + memcpy(pac->pac, src->pac, header_len); + + code = krb5int_copy_data_contents(context, &src->data, &pac->data); + if (code != 0) { + free(pac->pac); + free(pac); + return ENOMEM; + } + + pac->verified = src->verified; + *dst = pac; + + return 0; +} + /* * Parse the supplied data into the PAC allocated by this function */ @@ -379,7 +429,8 @@ krb5_pac_parse(krb5_context context, } static krb5_error_code -k5_time_to_seconds_since_1970(krb5_int64 ntTime, krb5_timestamp *elapsedSeconds) +k5_time_to_seconds_since_1970(krb5_int64 ntTime, + krb5_timestamp *elapsedSeconds) { krb5_ui_8 abstime; @@ -393,10 +444,11 @@ k5_time_to_seconds_since_1970(krb5_int64 ntTime, krb5_timestamp *elapsedSeconds) *elapsedSeconds = abstime; return 0; -} +} static krb5_error_code -k5_seconds_since_1970_to_time(krb5_timestamp elapsedSeconds, krb5_ui_8 *ntTime) +k5_seconds_since_1970_to_time(krb5_timestamp elapsedSeconds, + krb5_ui_8 *ntTime) { *ntTime = elapsedSeconds; @@ -404,7 +456,7 @@ k5_seconds_since_1970_to_time(krb5_timestamp elapsedSeconds, krb5_ui_8 *ntTime) *ntTime += NT_TIME_EPOCH; *ntTime *= 10000000; - + return 0; } @@ -441,10 +493,11 @@ k5_pac_validate_client(krb5_context context, return ret; if (client_info.length < PAC_CLIENT_INFO_LENGTH + pac_princname_length || - pac_princname_length % 2) + pac_princname_length % 2) return ERANGE; - ret = krb5int_ucs2lecs_to_utf8s(p, (size_t)pac_princname_length / 2, &pac_princname, NULL); + ret = krb5int_ucs2lecs_to_utf8s(p, (size_t)pac_princname_length / 2, + &pac_princname, NULL); if (ret != 0) return ret; @@ -457,7 +510,10 @@ k5_pac_validate_client(krb5_context context, free(pac_princname); if (pac_authtime != authtime || - krb5_principal_compare(context, pac_principal, principal) == FALSE) + !krb5_principal_compare_flags(context, + pac_principal, + principal, + KRB5_PRINCIPAL_COMPARE_IGNORE_REALM)) ret = KRB5KRB_AP_WRONG_PRINC; krb5_free_principal(context, pac_principal); @@ -513,7 +569,8 @@ k5_pac_verify_server_checksum(krb5_context context, krb5_boolean valid; krb5_octet *p; - ret = k5_pac_locate_buffer(context, pac, PAC_SERVER_CHECKSUM, &checksum_data); + ret = k5_pac_locate_buffer(context, pac, + PAC_SERVER_CHECKSUM, &checksum_data); if (ret != 0) return ret; @@ -533,19 +590,22 @@ k5_pac_verify_server_checksum(krb5_context context, memcpy(pac_data.data, pac->data.data, pac->data.length); /* Zero out both checksum buffers */ - ret = k5_pac_zero_signature(context, pac, PAC_SERVER_CHECKSUM, &pac_data); + ret = k5_pac_zero_signature(context, pac, + PAC_SERVER_CHECKSUM, &pac_data); if (ret != 0) { free(pac_data.data); return ret; } - ret = k5_pac_zero_signature(context, pac, PAC_PRIVSVR_CHECKSUM, &pac_data); + ret = k5_pac_zero_signature(context, pac, + PAC_PRIVSVR_CHECKSUM, &pac_data); if (ret != 0) { free(pac_data.data); return ret; } - ret = krb5_c_verify_checksum(context, server, KRB5_KEYUSAGE_APP_DATA_CKSUM, + ret = krb5_c_verify_checksum(context, server, + KRB5_KEYUSAGE_APP_DATA_CKSUM, &pac_data, &checksum, &valid); free(pac_data.data); @@ -571,14 +631,16 @@ k5_pac_verify_kdc_checksum(krb5_context context, krb5_boolean valid; krb5_octet *p; - ret = k5_pac_locate_buffer(context, pac, PAC_PRIVSVR_CHECKSUM, &privsvr_checksum); + ret = k5_pac_locate_buffer(context, pac, + PAC_PRIVSVR_CHECKSUM, &privsvr_checksum); if (ret != 0) return ret; if (privsvr_checksum.length < PAC_SIGNATURE_DATA_LENGTH) return KRB5_BAD_MSIZE; - ret = k5_pac_locate_buffer(context, pac, PAC_SERVER_CHECKSUM, &server_checksum); + ret = k5_pac_locate_buffer(context, pac, + PAC_SERVER_CHECKSUM, &server_checksum); if (ret != 0) return ret; @@ -593,7 +655,8 @@ k5_pac_verify_kdc_checksum(krb5_context context, server_checksum.data += PAC_SIGNATURE_DATA_LENGTH; server_checksum.length -= PAC_SIGNATURE_DATA_LENGTH; - ret = krb5_c_verify_checksum(context, privsvr, KRB5_KEYUSAGE_APP_DATA_CKSUM, + ret = krb5_c_verify_checksum(context, privsvr, + KRB5_KEYUSAGE_APP_DATA_CKSUM, &server_checksum, &checksum, &valid); if (ret != 0) return ret; @@ -633,6 +696,8 @@ krb5_pac_verify(krb5_context context, return ret; } + pac->verified = TRUE; + return 0; } @@ -650,12 +715,14 @@ k5_insert_client_info(krb5_context context, krb5_ui_8 nt_authtime; /* If we already have a CLIENT_INFO buffer, then just validate it */ - if (k5_pac_locate_buffer(context, pac, PAC_CLIENT_INFO, &client_info) == 0) { + if (k5_pac_locate_buffer(context, pac, + PAC_CLIENT_INFO, &client_info) == 0) { return k5_pac_validate_client(context, pac, authtime, principal); } ret = krb5_unparse_name_flags(context, principal, - KRB5_PRINCIPAL_UNPARSE_NO_REALM, &princ_name_utf8); + KRB5_PRINCIPAL_UNPARSE_NO_REALM, + &princ_name_utf8); if (ret != 0) goto cleanup; @@ -668,7 +735,8 @@ k5_insert_client_info(krb5_context context, client_info.length = PAC_CLIENT_INFO_LENGTH + princ_name_ucs2_len; client_info.data = NULL; - ret = k5_pac_add_buffer(context, pac, PAC_CLIENT_INFO, &client_info, TRUE, &client_info); + ret = k5_pac_add_buffer(context, pac, PAC_CLIENT_INFO, + &client_info, TRUE, &client_info); if (ret != 0) goto cleanup; @@ -685,12 +753,11 @@ k5_insert_client_info(krb5_context context, /* copy in principal name */ memcpy(p, princ_name_ucs2, princ_name_ucs2_len); - + cleanup: - if (princ_name_utf8 != NULL) - free(princ_name_utf8); if (princ_name_ucs2 != NULL) free(princ_name_ucs2); + krb5_free_unparsed_name(context, princ_name_utf8); return ret; } @@ -716,7 +783,10 @@ k5_insert_checksum(krb5_context context, ret = k5_pac_locate_buffer(context, pac, type, &cksumdata); if (ret == 0) { - /* If we're resigning PAC, make sure we can fit checksum into existing buffer */ + /* + * If we're resigning PAC, make sure we can fit checksum + * into existing buffer + */ if (cksumdata.length != PAC_SIGNATURE_DATA_LENGTH + len) return ERANGE; @@ -726,7 +796,9 @@ k5_insert_checksum(krb5_context context, cksumdata.length = PAC_SIGNATURE_DATA_LENGTH + len; cksumdata.data = NULL; - ret = k5_pac_add_buffer(context, pac, type, &cksumdata, TRUE, &cksumdata); + ret = k5_pac_add_buffer(context, pac, + type, &cksumdata, + TRUE, &cksumdata); if (ret != 0) return ret; } @@ -745,7 +817,8 @@ k5_pac_encode_header(krb5_context context, krb5_pac pac) unsigned char *p; size_t header_len; - header_len = PACTYPE_LENGTH + (pac->pac->cBuffers * PAC_INFO_BUFFER_LENGTH); + header_len = PACTYPE_LENGTH + + (pac->pac->cBuffers * PAC_INFO_BUFFER_LENGTH); assert(pac->data.length >= header_len); p = (unsigned char *)pac->data.data; @@ -818,7 +891,8 @@ krb5int_pac_sign(krb5_context context, return ret; /* Generate the server checksum over the entire PAC */ - ret = k5_pac_locate_buffer(context, pac, PAC_SERVER_CHECKSUM, &server_cksum); + ret = k5_pac_locate_buffer(context, pac, + PAC_SERVER_CHECKSUM, &server_cksum); if (ret != 0) return ret; @@ -838,7 +912,8 @@ krb5int_pac_sign(krb5_context context, return ret; /* Generate the privsvr checksum over the server checksum buffer */ - ret = k5_pac_locate_buffer(context, pac, PAC_PRIVSVR_CHECKSUM, &privsvr_cksum); + ret = k5_pac_locate_buffer(context, pac, + PAC_PRIVSVR_CHECKSUM, &privsvr_cksum); if (ret != 0) return ret; @@ -865,8 +940,603 @@ krb5int_pac_sign(krb5_context context, data->length = pac->data.length; memcpy(data->data, pac->data.data, pac->data.length); - memset(pac->data.data, 0, PACTYPE_LENGTH + (pac->pac->cBuffers * PAC_INFO_BUFFER_LENGTH)); + memset(pac->data.data, 0, + PACTYPE_LENGTH + (pac->pac->cBuffers * PAC_INFO_BUFFER_LENGTH)); + + return 0; +} + +/* + * PAC auth data attribute backend + */ +struct mspac_context { + krb5_pac pac; +}; + +static krb5_error_code +mspac_init(krb5_context kcontext, void **plugin_context) +{ + *plugin_context = NULL; + return 0; +} + +static void +mspac_flags(krb5_context kcontext, + void *plugin_context, + krb5_authdatatype ad_type, + krb5_flags *flags) +{ + *flags = AD_USAGE_KDC_ISSUED; +} + +static void +mspac_fini(krb5_context kcontext, void *plugin_context) +{ + return; +} + +static krb5_error_code +mspac_request_init(krb5_context kcontext, + krb5_authdata_context context, + void *plugin_context, + void **request_context) +{ + struct mspac_context *pacctx; + + pacctx = (struct mspac_context *)malloc(sizeof(*pacctx)); + if (pacctx == NULL) + return ENOMEM; + + pacctx->pac = NULL; + + *request_context = pacctx; + + return 0; +} + +static krb5_error_code +mspac_import_authdata(krb5_context kcontext, + krb5_authdata_context context, + void *plugin_context, + void *request_context, + krb5_authdata **authdata, + krb5_boolean kdc_issued, + krb5_const_principal kdc_issuer) +{ + krb5_error_code code; + struct mspac_context *pacctx = (struct mspac_context *)request_context; + + if (kdc_issued) + return EINVAL; + + if (pacctx->pac != NULL) { + krb5_pac_free(kcontext, pacctx->pac); + pacctx->pac = NULL; + } + + assert(authdata[0] != NULL); + assert((authdata[0]->ad_type & AD_TYPE_FIELD_TYPE_MASK) == + KRB5_AUTHDATA_WIN2K_PAC); + + code = krb5_pac_parse(kcontext, authdata[0]->contents, + authdata[0]->length, &pacctx->pac); + + return code; +} + +static krb5_error_code +mspac_export_authdata(krb5_context kcontext, + krb5_authdata_context context, + void *plugin_context, + void *request_context, + krb5_flags usage, + krb5_authdata ***out_authdata) +{ + struct mspac_context *pacctx = (struct mspac_context *)request_context; + krb5_error_code code; + krb5_authdata **authdata; + krb5_data data; + + if (pacctx->pac == NULL) + return 0; + + authdata = calloc(2, sizeof(krb5_authdata *)); + if (authdata == NULL) + return ENOMEM; + + authdata[0] = calloc(1, sizeof(krb5_authdata)); + if (authdata[0] == NULL) { + free(authdata); + return ENOMEM; + } + authdata[1] = NULL; + + code = krb5int_copy_data_contents(kcontext, &pacctx->pac->data, &data); + if (code != 0) { + krb5_free_authdata(kcontext, authdata); + return code; + } + + authdata[0]->magic = KV5M_AUTHDATA; + authdata[0]->ad_type = KRB5_AUTHDATA_WIN2K_PAC; + authdata[0]->length = data.length; + authdata[0]->contents = (krb5_octet *)data.data; + + authdata[1] = NULL; + + *out_authdata = authdata; + + return 0; +} + +static krb5_error_code +mspac_verify(krb5_context kcontext, + krb5_authdata_context context, + void *plugin_context, + void *request_context, + const krb5_auth_context *auth_context, + const krb5_keyblock *key, + const krb5_ap_req *req) +{ + krb5_error_code code; + struct mspac_context *pacctx = (struct mspac_context *)request_context; + + if (pacctx->pac == NULL) + return EINVAL; + + code = krb5_pac_verify(kcontext, + pacctx->pac, + req->ticket->enc_part2->times.authtime, + req->ticket->enc_part2->client, + key, + NULL); + +#if 0 + /* + * Now, we could return 0 and just set pac->verified to FALSE. + * Thoughts? + */ + if (code == KRB5KRB_AP_ERR_BAD_INTEGRITY) { + assert(pacctx->pac->verified == FALSE); + code = 0; + } +#endif + + return code; +} + +static void +mspac_request_fini(krb5_context kcontext, + krb5_authdata_context context, + void *plugin_context, + void *request_context) +{ + struct mspac_context *pacctx = (struct mspac_context *)request_context; + + if (pacctx != NULL) { + if (pacctx->pac != NULL) + krb5_pac_free(kcontext, pacctx->pac); + + free(pacctx); + } +} + +#define STRLENOF(x) (sizeof((x)) - 1) + +static struct { + krb5_ui_4 type; + krb5_data attribute; +} mspac_attribute_types[] = { + { (krb5_ui_4)-1, { KV5M_DATA, STRLENOF("mspac:"), "mspac:" } }, + { PAC_LOGON_INFO, { KV5M_DATA, STRLENOF("mspac:logon-info"), "mspac:logon-info" } }, + { PAC_CREDENTIALS_INFO, { KV5M_DATA, STRLENOF("mspac:credentials-info"), "mspac:credentials-info" } }, + { PAC_SERVER_CHECKSUM, { KV5M_DATA, STRLENOF("mspac:server-checksum"), "mspac:server-checksum" } }, + { PAC_PRIVSVR_CHECKSUM, { KV5M_DATA, STRLENOF("mspac:privsvr-checksum"), "mspac:privsvr-checksum" } }, + { PAC_CLIENT_INFO, { KV5M_DATA, STRLENOF("mspac:client-info"), "mspac:client-info" } }, + { PAC_DELEGATION_INFO, { KV5M_DATA, STRLENOF("mspac:delegation-info"), "mspac:delegation-info" } }, + { PAC_UPN_DNS_INFO, { KV5M_DATA, STRLENOF("mspac:upn-dns-info"), "mspac:upn-dns-info" } }, +}; + +#define MSPAC_ATTRIBUTE_COUNT (sizeof(mspac_attribute_types)/sizeof(mspac_attribute_types[0])) + +static krb5_error_code +mspac_type2attr(krb5_ui_4 type, krb5_data *attr) +{ + unsigned int i; + + for (i = 0; i < MSPAC_ATTRIBUTE_COUNT; i++) { + if (mspac_attribute_types[i].type == type) { + *attr = mspac_attribute_types[i].attribute; + return 0; + } + } + + return ENOENT; +} + +static krb5_error_code +mspac_attr2type(const krb5_data *attr, krb5_ui_4 *type) +{ + unsigned int i; + + for (i = 0; i < MSPAC_ATTRIBUTE_COUNT; i++) { + if (attr->length == mspac_attribute_types[i].attribute.length && + strncasecmp(attr->data, mspac_attribute_types[i].attribute.data, attr->length) == 0) { + *type = mspac_attribute_types[i].type; + return 0; + } + } + + if (attr->length > STRLENOF("mspac:") && + strncasecmp(attr->data, "mspac:", STRLENOF("mspac:")) == 0) + { + char *p = &attr->data[STRLENOF("mspac:")]; + char *endptr; + + *type = strtoul(p, &endptr, 10); + if (*type != 0 && *endptr == '\0') + return 0; + } + + return ENOENT; +} + +static krb5_error_code +mspac_get_attribute_types(krb5_context kcontext, + krb5_authdata_context context, + void *plugin_context, + void *request_context, + krb5_data **out_attrs) +{ + struct mspac_context *pacctx = (struct mspac_context *)request_context; + unsigned int i, j; + krb5_data *attrs; + krb5_error_code code; + + if (pacctx->pac == NULL) + return ENOENT; + + attrs = calloc(1 + pacctx->pac->pac->cBuffers + 1, sizeof(krb5_data)); + if (attrs == NULL) + return ENOMEM; + + j = 0; + + /* The entire PAC */ + code = krb5int_copy_data_contents(kcontext, + &mspac_attribute_types[0].attribute, + &attrs[j++]); + if (code != 0) { + free(attrs); + return code; + } + + /* PAC buffers */ + for (i = 0; i < pacctx->pac->pac->cBuffers; i++) { + krb5_data attr; + + code = mspac_type2attr(pacctx->pac->pac->Buffers[i].ulType, &attr); + if (code == 0) { + code = krb5int_copy_data_contents(kcontext, &attr, &attrs[j++]); + if (code != 0) { + krb5int_free_data_list(kcontext, attrs); + return code; + } + } else { + int length; + + length = asprintf(&attrs[j].data, "mspac:%d", + pacctx->pac->pac->Buffers[i].ulType); + if (length < 0) { + krb5int_free_data_list(kcontext, attrs); + return ENOMEM; + } + attrs[j++].length = length; + } + } + attrs[j].data = NULL; + attrs[j].length = 0; + + *out_attrs = attrs; return 0; } +static krb5_error_code +mspac_get_attribute(krb5_context kcontext, + krb5_authdata_context context, + void *plugin_context, + void *request_context, + const krb5_data *attribute, + krb5_boolean *authenticated, + krb5_boolean *complete, + krb5_data *value, + krb5_data *display_value, + int *more) +{ + struct mspac_context *pacctx = (struct mspac_context *)request_context; + krb5_error_code code; + krb5_ui_4 type; + + value->data = NULL; + value->length = 0; + + if (display_value != NULL) { + display_value->data = NULL; + display_value->length = 0; + } + + if (*more != -1 || pacctx->pac == NULL) + return ENOENT; + + code = mspac_attr2type(attribute, &type); + if (code != 0) + return code; + + /* -1 is a magic type that refers to the entire PAC */ + if (type == (krb5_ui_4)-1) { + if (value != NULL) + code = krb5int_copy_data_contents(kcontext, + &pacctx->pac->data, + value); + else + code = 0; + } else { + if (value != NULL) + code = krb5_pac_get_buffer(kcontext, pacctx->pac, type, value); + else + code = k5_pac_locate_buffer(kcontext, pacctx->pac, type, NULL); + } + if (code == 0) { + *authenticated = pacctx->pac->verified; + *complete = TRUE; + } + + *more = 0; + + return code; +} + +static krb5_error_code +mspac_set_attribute(krb5_context kcontext, + krb5_authdata_context context, + void *plugin_context, + void *request_context, + krb5_boolean complete, + const krb5_data *attribute, + const krb5_data *value) +{ + struct mspac_context *pacctx = (struct mspac_context *)request_context; + krb5_error_code code; + krb5_ui_4 type; + + if (pacctx->pac == NULL) + return ENOENT; + + code = mspac_attr2type(attribute, &type); + if (code != 0) + return code; + + /* -1 is a magic type that refers to the entire PAC */ + if (type == (krb5_ui_4)-1) { + krb5_pac newpac; + + code = krb5_pac_parse(kcontext, value->data, value->length, &newpac); + if (code != 0) + return code; + + krb5_pac_free(kcontext, pacctx->pac); + pacctx->pac = newpac; + } else { + code = krb5_pac_add_buffer(kcontext, pacctx->pac, type, value); + } + + return code; +} + +static krb5_error_code +mspac_export_internal(krb5_context kcontext, + krb5_authdata_context context, + void *plugin_context, + void *request_context, + krb5_boolean restrict_authenticated, + void **ptr) +{ + struct mspac_context *pacctx = (struct mspac_context *)request_context; + krb5_error_code code; + krb5_pac pac; + + *ptr = NULL; + + if (pacctx->pac == NULL) + return 0; + + if (restrict_authenticated && (pacctx->pac->verified) == FALSE) + return 0; + + code = krb5_pac_parse(kcontext, pacctx->pac->data.data, + pacctx->pac->data.length, &pac); + if (code == 0) { + pac->verified = pacctx->pac->verified; + *ptr = pac; + } + + return code; +} + +static void +mspac_free_internal(krb5_context kcontext, + krb5_authdata_context context, + void *plugin_context, + void *request_context, + void *ptr) +{ + if (ptr != NULL) + krb5_pac_free(kcontext, (krb5_pac)ptr); + + return; +} + +static krb5_error_code +mspac_size(krb5_context kcontext, + krb5_authdata_context context, + void *plugin_context, + void *request_context, + size_t *sizep) +{ + struct mspac_context *pacctx = (struct mspac_context *)request_context; + + *sizep += sizeof(krb5_int32); + + if (pacctx->pac != NULL) + *sizep += pacctx->pac->data.length; + + *sizep += sizeof(krb5_int32); + + return 0; +} + +static krb5_error_code +mspac_externalize(krb5_context kcontext, + krb5_authdata_context context, + void *plugin_context, + void *request_context, + krb5_octet **buffer, + size_t *lenremain) +{ + krb5_error_code code = 0; + struct mspac_context *pacctx = (struct mspac_context *)request_context; + size_t required = 0; + krb5_octet *bp; + size_t remain; + + bp = *buffer; + remain = *lenremain; + + if (pacctx->pac != NULL) { + mspac_size(kcontext, context, plugin_context, + request_context, &required); + + if (required <= remain) { + krb5_ser_pack_int32((krb5_int32)pacctx->pac->data.length, + &bp, &remain); + krb5_ser_pack_bytes((krb5_octet *)pacctx->pac->data.data, + (size_t)pacctx->pac->data.length, + &bp, &remain); + krb5_ser_pack_int32((krb5_int32)pacctx->pac->verified, + &bp, &remain); + } else { + code = ENOMEM; + } + } else { + krb5_ser_pack_int32(0, &bp, &remain); /* length */ + krb5_ser_pack_int32(0, &bp, &remain); /* verified */ + } + + *buffer = bp; + *lenremain = remain; + + return code; +} + +static krb5_error_code +mspac_internalize(krb5_context kcontext, + krb5_authdata_context context, + void *plugin_context, + void *request_context, + krb5_octet **buffer, + size_t *lenremain) +{ + struct mspac_context *pacctx = (struct mspac_context *)request_context; + krb5_error_code code; + krb5_int32 ibuf; + krb5_octet *bp; + size_t remain; + krb5_pac pac = NULL; + + bp = *buffer; + remain = *lenremain; + + /* length */ + code = krb5_ser_unpack_int32(&ibuf, &bp, &remain); + if (code != 0) + return code; + + if (ibuf != 0) { + code = krb5_pac_parse(kcontext, bp, ibuf, &pac); + if (code != 0) + return code; + + bp += ibuf; + remain -= ibuf; + } + + /* verified */ + code = krb5_ser_unpack_int32(&ibuf, &bp, &remain); + if (code != 0) { + krb5_pac_free(kcontext, pac); + return code; + } + + if (pac != NULL) { + pac->verified = (ibuf != 0); + } + + if (pacctx->pac != NULL) { + krb5_pac_free(kcontext, pacctx->pac); + } + + pacctx->pac = pac; + + *buffer = bp; + *lenremain = remain; + + return 0; +} + +static krb5_error_code +mspac_copy(krb5_context kcontext, + krb5_authdata_context context, + void *plugin_context, + void *request_context, + void *dst_plugin_context, + void *dst_request_context) +{ + struct mspac_context *srcctx = (struct mspac_context *)request_context; + struct mspac_context *dstctx = (struct mspac_context *)dst_request_context; + krb5_error_code code = 0; + + assert(dstctx != NULL); + assert(dstctx->pac == NULL); + + if (srcctx->pac != NULL) + code = k5_pac_copy(kcontext, srcctx->pac, &dstctx->pac); + + return code; +} + +static krb5_authdatatype mspac_ad_types[] = { KRB5_AUTHDATA_WIN2K_PAC, 0 }; + +krb5plugin_authdata_client_ftable_v0 krb5int_mspac_authdata_client_ftable = { + "mspac", + mspac_ad_types, + mspac_init, + mspac_fini, + mspac_flags, + mspac_request_init, + mspac_request_fini, + mspac_get_attribute_types, + mspac_get_attribute, + mspac_set_attribute, + NULL, /* delete_attribute_proc */ + mspac_export_authdata, + mspac_import_authdata, + mspac_export_internal, + mspac_free_internal, + mspac_verify, + mspac_size, + mspac_externalize, + mspac_internalize, + mspac_copy +}; + diff --git a/src/lib/krb5/krb/rd_req.c b/src/lib/krb5/krb/rd_req.c index 5848aa776..50c3a9011 100644 --- a/src/lib/krb5/krb/rd_req.c +++ b/src/lib/krb5/krb/rd_req.c @@ -8,7 +8,7 @@ * require a specific license from the United States Government. * It is the responsibility of any person or organization contemplating * export to obtain such a license before exporting. - * + * * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and * distribute this software and its documentation for any purpose and * without fee is hereby granted, provided that the above copyright @@ -22,7 +22,7 @@ * M.I.T. makes no representations about the suitability of * this software for any purpose. It is provided "as is" without express * or implied warranty. - * + * * * krb5_rd_req() */ @@ -32,16 +32,16 @@ /* * Parses a KRB_AP_REQ message, returning its contents. - * + * * server specifies the expected server's name for the ticket. - * + * * keyproc specifies a procedure to generate a decryption key for the * ticket. If keyproc is non-NULL, keyprocarg is passed to it, and the result * used as a decryption key. If keyproc is NULL, then fetchfrom is checked; * if it is non-NULL, it specifies a parameter name from which to retrieve the * decryption key. If fetchfrom is NULL, then the default key store is * consulted. - * + * * returns system errors, encryption errors, replay errors */ @@ -58,14 +58,14 @@ krb5_rd_req(krb5_context context, krb5_auth_context *auth_context, if (!krb5_is_ap_req(inbuf)) return KRB5KRB_AP_ERR_MSG_TYPE; -#ifndef LEAN_CLIENT +#ifndef LEAN_CLIENT if ((retval = decode_krb5_ap_req(inbuf, &request))) { switch (retval) { case KRB5_BADMSGTYPE: - return KRB5KRB_AP_ERR_BADVERSION; + return KRB5KRB_AP_ERR_BADVERSION; default: return(retval); - } + } } #endif /* LEAN_CLIENT */ @@ -78,7 +78,7 @@ krb5_rd_req(krb5_context context, krb5_auth_context *auth_context, } -#ifndef LEAN_CLIENT +#ifndef LEAN_CLIENT /* Get a keytab if necessary. */ if (keytab == NULL) { if ((retval = krb5_kt_default(context, &new_keytab))) @@ -87,10 +87,10 @@ krb5_rd_req(krb5_context context, krb5_auth_context *auth_context, } #endif /* LEAN_CLIENT */ - retval = krb5_rd_req_decoded(context, auth_context, request, server, + retval = krb5_rd_req_decoded(context, auth_context, request, server, keytab, ap_req_options, ticket); -#ifndef LEAN_CLIENT +#ifndef LEAN_CLIENT if (new_keytab != NULL) (void) krb5_kt_close(context, new_keytab); #endif /* LEAN_CLIENT */ diff --git a/src/lib/krb5/krb/rd_req_dec.c b/src/lib/krb5/krb/rd_req_dec.c index c618be1ee..6edf6d760 100644 --- a/src/lib/krb5/krb/rd_req_dec.c +++ b/src/lib/krb5/krb/rd_req_dec.c @@ -31,6 +31,8 @@ #include "k5-int.h" #include "auth_con.h" +#include "authdata.h" +#include "int-proto.h" /* * essentially the same as krb_rd_req, but uses a decoded AP_REQ as @@ -92,7 +94,8 @@ krb5int_check_clockskew(krb5_context context, krb5_timestamp date) static krb5_error_code krb5_rd_req_decrypt_tkt_part(krb5_context context, const krb5_ap_req *req, - krb5_const_principal server, krb5_keytab keytab) + krb5_const_principal server, krb5_keytab keytab, + krb5_keyblock *key) { krb5_error_code retval; krb5_keytab_entry ktent; @@ -107,10 +110,12 @@ krb5_rd_req_decrypt_tkt_part(krb5_context context, const krb5_ap_req *req, req->ticket->enc_part.enctype, &ktent); if (retval == 0) { retval = krb5_decrypt_tkt_part(context, &ktent.key, req->ticket); + if (retval == 0 && key != NULL) + retval = krb5_copy_keyblock_contents(context, &ktent.key, key); (void) krb5_free_keytab_entry_contents(context, &ktent); } - } else { + } else { krb5_error_code code; krb5_kt_cursor cursor; @@ -142,6 +147,8 @@ krb5_rd_req_decrypt_tkt_part(krb5_context context, const krb5_ap_req *req, * server as it appeared in the ticket. */ retval = krb5_copy_principal(context, ktent.principal, &tmp); + if (retval == 0 && key != NULL) + retval = krb5_copy_keyblock_contents(context, &ktent.key, key); if (retval == 0) { krb5_free_principal(context, req->ticket->server); req->ticket->server = tmp; @@ -204,11 +211,15 @@ krb5_rd_req_decoded_opt(krb5_context context, krb5_auth_context *auth_context, { krb5_error_code retval = 0; krb5_principal_data princ_data; - krb5_enctype *desired_etypes = NULL; + krb5_enctype *desired_etypes = NULL; int desired_etypes_len = 0; int rfc4537_etypes_len = 0; - krb5_enctype *permitted_etypes = NULL; + krb5_enctype *permitted_etypes = NULL; int permitted_etypes_len = 0; + krb5_keyblock decrypt_key; + + decrypt_key.enctype = ENCTYPE_NULL; + decrypt_key.contents = NULL; req->ticket->enc_part2 = NULL; if (server && krb5_is_referral_realm(&server->realm)) { @@ -231,14 +242,20 @@ krb5_rd_req_decoded_opt(krb5_context context, krb5_auth_context *auth_context, if ((retval = krb5_decrypt_tkt_part(context, (*auth_context)->keyblock, req->ticket))) goto cleanup; - krb5_free_keyblock(context, (*auth_context)->keyblock); + if (check_valid_flag) { + decrypt_key = *((*auth_context)->keyblock); + free((*auth_context)->keyblock); + } else + krb5_free_keyblock(context, (*auth_context)->keyblock); (*auth_context)->keyblock = NULL; } else { - if ((retval = krb5_rd_req_decrypt_tkt_part(context, req, server, keytab))) + if ((retval = krb5_rd_req_decrypt_tkt_part(context, req, + server, keytab, + check_valid_flag ? &decrypt_key : NULL))) goto cleanup; } - /* XXX this is an evil hack. check_valid_flag is set iff the call + /* XXX this is an evil hack. check_valid_flag is set iff the call is not from inside the kdc. we can use this to determine which key usage to use */ #ifndef LEAN_CLIENT @@ -284,7 +301,7 @@ krb5_rd_req_decoded_opt(krb5_context context, krb5_auth_context *auth_context, /* If the transited list is empty, then we have at most one hop */ if (trans->tr_contents.data && trans->tr_contents.data[0]) - retval = KRB5KRB_AP_ERR_ILL_CR_TKT; + retval = KRB5KRB_AP_ERR_ILL_CR_TKT; } #elif defined(_NO_CROSS_REALM) @@ -325,7 +342,7 @@ krb5_rd_req_decoded_opt(krb5_context context, krb5_auth_context *auth_context, /* * If the transited list is not empty, then check that all realms * transited are within the hierarchy between the client's realm - * and the local realm. + * and the local realm. */ if (trans->tr_contents.data && trans->tr_contents.data[0]) { retval = krb5_check_transited_list(context, &(trans->tr_contents), @@ -344,7 +361,7 @@ krb5_rd_req_decoded_opt(krb5_context context, krb5_auth_context *auth_context, if ((*auth_context)->rcache) { krb5_donot_replay rep; - krb5_tkt_authent tktauthent; + krb5_tkt_authent tktauthent; tktauthent.ticket = req->ticket; tktauthent.authenticator = (*auth_context)->authentp; @@ -376,6 +393,17 @@ krb5_rd_req_decoded_opt(krb5_context context, krb5_auth_context *auth_context, retval = KRB5KRB_AP_ERR_TKT_INVALID; goto cleanup; } + + if ((retval = krb5_authdata_context_init(context, + &(*auth_context)->ad_context))) + goto cleanup; + if ((retval = krb5int_authdata_verify(context, + (*auth_context)->ad_context, + AD_USAGE_MASK, + auth_context, + &decrypt_key, + req))) + goto cleanup; } /* read RFC 4537 etype list from sender */ @@ -520,18 +548,21 @@ cleanup: krb5_free_enc_tkt_part(context, req->ticket->enc_part2); req->ticket->enc_part2 = NULL; } + if (check_valid_flag) + krb5_free_keyblock_contents(context, &decrypt_key); + return retval; } krb5_error_code krb5_rd_req_decoded(krb5_context context, krb5_auth_context *auth_context, - const krb5_ap_req *req, krb5_const_principal server, - krb5_keytab keytab, krb5_flags *ap_req_options, - krb5_ticket **ticket) + const krb5_ap_req *req, krb5_const_principal server, + krb5_keytab keytab, krb5_flags *ap_req_options, + krb5_ticket **ticket) { krb5_error_code retval; retval = krb5_rd_req_decoded_opt(context, auth_context, - req, server, keytab, + req, server, keytab, ap_req_options, ticket, 1); /* check_valid_flag */ return retval; @@ -539,14 +570,14 @@ krb5_rd_req_decoded(krb5_context context, krb5_auth_context *auth_context, krb5_error_code krb5_rd_req_decoded_anyflag(krb5_context context, - krb5_auth_context *auth_context, - const krb5_ap_req *req, - krb5_const_principal server, krb5_keytab keytab, - krb5_flags *ap_req_options, krb5_ticket **ticket) + krb5_auth_context *auth_context, + const krb5_ap_req *req, + krb5_const_principal server, krb5_keytab keytab, + krb5_flags *ap_req_options, krb5_ticket **ticket) { krb5_error_code retval; retval = krb5_rd_req_decoded_opt(context, auth_context, - req, server, keytab, + req, server, keytab, ap_req_options, ticket, 0); /* don't check_valid_flag */ return retval; diff --git a/src/lib/krb5/krb/s4u_creds.c b/src/lib/krb5/krb/s4u_creds.c index 883d33cc7..a7e519902 100644 --- a/src/lib/krb5/krb/s4u_creds.c +++ b/src/lib/krb5/krb/s4u_creds.c @@ -115,7 +115,7 @@ s4u_identify_user(krb5_context context, client = &client_data; } - code = krb5_get_init_creds(context, &creds, in_creds->client, + code = krb5_get_init_creds(context, &creds, client, NULL, NULL, 0, NULL, opte, krb5_get_as_key_noop, &userid, &use_master, NULL); diff --git a/src/lib/krb5/krb/ser_actx.c b/src/lib/krb5/krb/ser_actx.c index 347b300f5..487455b9d 100644 --- a/src/lib/krb5/krb/ser_actx.c +++ b/src/lib/krb5/krb/ser_actx.c @@ -560,5 +560,7 @@ krb5_ser_auth_context_init(krb5_context kcontext) kret = krb5_ser_keyblock_init(kcontext); if (!kret) kret = krb5_ser_principal_init(kcontext); + if (!kret) + kret = krb5_ser_authdata_context_init(kcontext); return(kret); } diff --git a/src/lib/krb5/krb/t_authdata.c b/src/lib/krb5/krb/t_authdata.c index 8b786875f..86838cead 100644 --- a/src/lib/krb5/krb/t_authdata.c +++ b/src/lib/krb5/krb/t_authdata.c @@ -65,6 +65,13 @@ krb5_authdata *adseq1[] = {&ad1, &ad2, &ad4, NULL}; krb5_authdata *adseq2[] = {&ad3, NULL}; +krb5_keyblock key = { + KV5M_KEYBLOCK, + ENCTYPE_AES128_CTS_HMAC_SHA1_96, + 16, + (unsigned char *)"1234567890ABCDEF" +}; + static void compare_authdata(const krb5_authdata *adc1, krb5_authdata *adc2) { assert(adc1->ad_type == adc2->ad_type); assert(adc1->length == adc2->length); @@ -77,7 +84,7 @@ int main() krb5_authdata **results; krb5_authdata *container[2]; krb5_authdata **container_out; - + krb5_authdata **kdci; assert(krb5_init_context(&context) == 0); assert(krb5_merge_authdata(context, adseq1, adseq2, &results) == 0); @@ -96,6 +103,13 @@ int main() compare_authdata( results[1], &ad4); compare_authdata( results[2], &ad3); assert( results[3] == NULL); + krb5_free_authdata(context, container_out); + assert(krb5_make_authdata_kdc_issued(context, &key, NULL, results, &kdci) == 0); + assert(krb5_verify_authdata_kdc_issued(context, &key, kdci[0], NULL, &container_out) == 0); + compare_authdata(container_out[0], results[0]); + compare_authdata(container_out[1], results[1]); + compare_authdata(container_out[2], results[2]); + krb5_free_authdata(context, kdci); krb5_free_authdata(context, results); krb5_free_authdata(context, container_out); krb5_free_context(context); diff --git a/src/lib/krb5/libkrb5.exports b/src/lib/krb5/libkrb5.exports index b809e83cf..2735c9f98 100644 --- a/src/lib/krb5/libkrb5.exports +++ b/src/lib/krb5/libkrb5.exports @@ -1,4 +1,5 @@ _krb5_conf_boolean +decode_krb5_ad_kdcissued decode_krb5_alt_method decode_krb5_ap_rep decode_krb5_ap_rep_enc_part @@ -40,6 +41,7 @@ decode_krb5_tgs_rep decode_krb5_tgs_req decode_krb5_ticket decode_krb5_typed_data +encode_krb5_ad_kdcissued encode_krb5_alt_method encode_krb5_ap_rep encode_krb5_ap_rep_enc_part @@ -108,6 +110,7 @@ krb5_appdefault_string krb5_auth_con_free krb5_auth_con_genaddrs krb5_auth_con_get_checksum_func +krb5_auth_con_get_authdata_context krb5_auth_con_getaddrs krb5_auth_con_getauthenticator krb5_auth_con_getflags @@ -123,6 +126,7 @@ krb5_auth_con_getremotesubkey krb5_auth_con_getsendsubkey krb5_auth_con_init krb5_auth_con_initivector +krb5_auth_con_set_authdata_context krb5_auth_con_set_checksum_func krb5_auth_con_set_req_cksumtype krb5_auth_con_set_safe_cksumtype @@ -136,6 +140,18 @@ krb5_auth_con_setrecvsubkey krb5_auth_con_setsendsubkey krb5_auth_con_setuseruserkey krb5_auth_to_rep +krb5_authdata_context_copy +krb5_authdata_context_free +krb5_authdata_context_init +krb5_authdata_delete_attribute +krb5_authdata_get_attribute_types +krb5_authdata_get_attribute +krb5_authdata_set_attribute +krb5_authdata_export_attributes +krb5_authdata_export_authdata +krb5_authdata_export_internal +krb5_authdata_free_internal +krb5_authdata_import_attributes krb5_build_principal krb5_build_principal_alloc_va krb5_build_principal_ext @@ -203,6 +219,7 @@ krb5_externalize_data krb5_externalize_opaque krb5_fcc_ops krb5_find_serializer +krb5_free_ad_kdcissued krb5_free_address krb5_free_addresses krb5_free_alt_method @@ -364,6 +381,7 @@ krb5_kuserok krb5_libdefault_boolean krb5_locate_kdc krb5_lock_file +krb5_make_authdata_kdc_issued krb5_make_full_ipaddr krb5_make_fulladdr krb5_max_dgram_size @@ -519,6 +537,7 @@ krb5_unparse_name_flags_ext krb5_us_timeofday krb5_use_natural_time krb5_validate_times +krb5_verify_authdata_kdc_issued krb5_verify_init_creds krb5_verify_init_creds_opt_init krb5_verify_init_creds_opt_set_ap_req_nofail @@ -534,6 +553,7 @@ krb5int_find_authdata krb5int_find_pa_data krb5int_foreach_localaddr krb5int_free_addrlist +krb5int_free_data_list krb5int_get_domain_realm_mapping krb5int_init_context_kdc krb5int_initialize_library diff --git a/src/plugins/authdata/greet_client/Makefile.in b/src/plugins/authdata/greet_client/Makefile.in new file mode 100644 index 000000000..72d665ad2 --- /dev/null +++ b/src/plugins/authdata/greet_client/Makefile.in @@ -0,0 +1,38 @@ +thisconfigdir=../../.. +myfulldir=plugins/authdata/greet_client +mydir=plugins/authdata/greet_client +BUILDTOP=$(REL)..$(S)..$(S).. +KRB5_RUN_ENV = @KRB5_RUN_ENV@ +KRB5_CONFIG_SETUP = KRB5_CONFIG=$(SRCTOP)/config-files/krb5.conf ; export KRB5_CONFIG ; +PROG_LIBPATH=-L$(TOPLIBD) +PROG_RPATH=$(KRB5_LIBDIR) +MODULE_INSTALL_DIR = $(KRB5_AD_MODULE_DIR) +DEFS=@DEFS@ + +LOCALINCLUDES = -I../../../include/krb5 + +LIBBASE=greet_client +LIBMAJOR=0 +LIBMINOR=0 +SO_EXT=.so +SHLIB_EXPDEPS = $(TOPLIBD)/libk5crypto$(SHLIBEXT) \ + $(TOPLIBD)/libkrb5$(SHLIBEXT) +SHLIB_EXPLIBS= -lkrb5 -lcom_err -lk5crypto $(SUPPORT_LIB) $(LIBS) + +SHLIB_DIRS=-L$(TOPLIBD) +SHLIB_RDIRS=$(KRB5_LIBDIR) +STOBJLISTS=OBJS.ST +STLIBOBJS= greet.o + +SRCS= greet.c + +all-unix:: all-liblinks +install-unix:: install-libs +clean-unix:: clean-libs clean-libobjs + +clean:: + $(RM) lib$(LIBBASE)$(SO_EXT) + +@libnover_frag@ +@libobj_frag@ + diff --git a/src/plugins/authdata/greet_client/deps b/src/plugins/authdata/greet_client/deps new file mode 100644 index 000000000..b754fcff9 --- /dev/null +++ b/src/plugins/authdata/greet_client/deps @@ -0,0 +1,6 @@ +# +# Generated makefile dependencies follow. +# +greet_auth.so greet_auth.po $(OUTPRE)greet_auth.$(OBJEXT): \ + $(BUILDTOP)/include/krb5/krb5.h $(COM_ERR_DEPS) $(SRCTOP)/include/krb5/authdata_plugin.h \ + greet_auth.c diff --git a/src/plugins/authdata/greet_client/greet.c b/src/plugins/authdata/greet_client/greet.c new file mode 100644 index 000000000..cb0d6e519 --- /dev/null +++ b/src/plugins/authdata/greet_client/greet.c @@ -0,0 +1,379 @@ +/* + * plugins/authdata/greet_client/ + * + * Copyright 2009 by the Massachusetts Institute of Technology. + * + * Export of this software from the United States of America may + * require a specific license from the United States Government. + * It is the responsibility of any person or organization contemplating + * export to obtain such a license before exporting. + * + * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and + * distribute this software and its documentation for any purpose and + * without fee is hereby granted, provided that the above copyright + * notice appear in all copies and that both that copyright notice and + * this permission notice appear in supporting documentation, and that + * the name of M.I.T. not be used in advertising or publicity pertaining + * to distribution of the software without specific, written prior + * permission. Furthermore if you modify this software you must label + * your software as modified software and not distribute it in such a + * fashion that it might be confused with the original M.I.T. software. + * M.I.T. makes no representations about the suitability of + * this software for any purpose. It is provided "as is" without express + * or implied warranty. + * + * + * Sample authorization data plugin + */ + +#include +#include +#include "k5-int.h" +#include +#include + +struct greet_context { + krb5_data greeting; + krb5_boolean verified; +}; + +static krb5_data greet_attr = { + KV5M_DATA, sizeof("greet:greeting") - 1, "greet:greeting" }; + +static krb5_error_code +greet_init(krb5_context kcontext, void **plugin_context) +{ + *plugin_context = 0; + return 0; +} + +static void +greet_flags(krb5_context kcontext, + void *plugin_context, + krb5_authdatatype ad_type, + krb5_flags *flags) +{ + *flags = AD_USAGE_AP_REQ | AD_USAGE_KDC_ISSUED | AD_INFORMATIONAL; +} + +static void +greet_fini(krb5_context kcontext, void *plugin_context) +{ + return; +} + +static krb5_error_code +greet_request_init(krb5_context kcontext, + krb5_authdata_context context, + void *plugin_context, + void **request_context) +{ + struct greet_context *greet; + + greet = malloc(sizeof(*greet)); + if (greet == NULL) + return ENOMEM; + + greet->greeting.data = NULL; + greet->greeting.length = 0; + greet->verified = FALSE; + + *request_context = greet; + + return 0; +} + +static krb5_error_code +greet_export_authdata(krb5_context kcontext, + krb5_authdata_context context, + void *plugin_context, + void *request_context, + krb5_flags usage, + krb5_authdata ***out_authdata) +{ + struct greet_context *greet = (struct greet_context *)request_context; + krb5_authdata *data[2]; + krb5_authdata datum; + krb5_error_code code; + + datum.ad_type = -42; + datum.length = greet->greeting.length; + datum.contents = (krb5_octet *)greet->greeting.data; + + data[0] = &datum; + data[1] = NULL; + + code = krb5_copy_authdata(kcontext, data, out_authdata); + + return code; +} + +static krb5_error_code +greet_import_authdata(krb5_context kcontext, + krb5_authdata_context context, + void *plugin_context, + void *request_context, + krb5_authdata **authdata, + krb5_boolean kdc_issued_flag, + krb5_const_principal issuer) +{ + krb5_error_code code; + struct greet_context *greet = (struct greet_context *)request_context; + krb5_data data; + + krb5_free_data_contents(kcontext, &greet->greeting); + greet->verified = FALSE; + + assert(authdata[0] != NULL); + + data.length = authdata[0]->length; + data.data = (char *)authdata[0]->contents; + + code = krb5int_copy_data_contents_add0(kcontext, &data, &greet->greeting); + if (code == 0) + greet->verified = kdc_issued_flag; + + return code; +} + +static void +greet_request_fini(krb5_context kcontext, + krb5_authdata_context context, + void *plugin_context, + void *request_context) +{ + struct greet_context *greet = (struct greet_context *)request_context; + + if (greet != NULL) { + krb5_free_data_contents(kcontext, &greet->greeting); + free(greet); + } +} + +static krb5_error_code +greet_get_attribute_types(krb5_context kcontext, + krb5_authdata_context context, + void *plugin_context, + void *request_context, + krb5_data **out_attrs) +{ + krb5_error_code code; + struct greet_context *greet = (struct greet_context *)request_context; + + if (greet->greeting.length == 0) + return ENOENT; + + *out_attrs = calloc(2, sizeof(krb5_data)); + if (*out_attrs == NULL) + return ENOMEM; + + code = krb5int_copy_data_contents_add0(kcontext, + &greet_attr, + &(*out_attrs)[0]); + if (code != 0) { + free(*out_attrs); + *out_attrs = NULL; + return code; + } + + return 0; +} + +static krb5_error_code +greet_get_attribute(krb5_context kcontext, + krb5_authdata_context context, + void *plugin_context, + void *request_context, + const krb5_data *attribute, + krb5_boolean *authenticated, + krb5_boolean *complete, + krb5_data *value, + krb5_data *display_value, + int *more) +{ + struct greet_context *greet = (struct greet_context *)request_context; + krb5_error_code code; + + if (!data_eq(*attribute, greet_attr) || greet->greeting.length == 0) + return ENOENT; + + *authenticated = greet->verified; + *complete = TRUE; + *more = 0; + + code = krb5int_copy_data_contents_add0(kcontext, &greet->greeting, value); + if (code == 0) { + code = krb5int_copy_data_contents_add0(kcontext, + &greet->greeting, + display_value); + if (code != 0) + krb5_free_data_contents(kcontext, value); + } + + return code; +} + +static krb5_error_code +greet_set_attribute(krb5_context kcontext, + krb5_authdata_context context, + void *plugin_context, + void *request_context, + krb5_boolean complete, + const krb5_data *attribute, + const krb5_data *value) +{ + struct greet_context *greet = (struct greet_context *)request_context; + krb5_data data; + krb5_error_code code; + + if (greet->greeting.data != NULL) + return EEXIST; + + code = krb5int_copy_data_contents_add0(kcontext, value, &data); + if (code != 0) + return code; + + krb5_free_data_contents(kcontext, &greet->greeting); + greet->greeting = data; + greet->verified = FALSE; + + return 0; +} + +static krb5_error_code +greet_delete_attribute(krb5_context kcontext, + krb5_authdata_context context, + void *plugin_context, + void *request_context, + const krb5_data *attribute) +{ + struct greet_context *greet = (struct greet_context *)request_context; + + krb5_free_data_contents(kcontext, &greet->greeting); + greet->verified = FALSE; + + return 0; +} + +static krb5_error_code +greet_size(krb5_context kcontext, + krb5_authdata_context context, + void *plugin_context, + void *request_context, + size_t *sizep) +{ + struct greet_context *greet = (struct greet_context *)request_context; + + *sizep += sizeof(krb5_int32) + + greet->greeting.length + + sizeof(krb5_int32); + + return 0; +} + +static krb5_error_code +greet_externalize(krb5_context kcontext, + krb5_authdata_context context, + void *plugin_context, + void *request_context, + krb5_octet **buffer, + size_t *lenremain) +{ + size_t required = 0; + struct greet_context *greet = (struct greet_context *)request_context; + + greet_size(kcontext, context, plugin_context, + request_context, &required); + + if (*lenremain < required) + return ENOMEM; + + /* Greeting Length | Greeting Contents | Verified */ + krb5_ser_pack_int32(greet->greeting.length, buffer, lenremain); + krb5_ser_pack_bytes((krb5_octet *)greet->greeting.data, + (size_t)greet->greeting.length, + buffer, lenremain); + krb5_ser_pack_int32((krb5_int32)greet->verified, buffer, lenremain); + + return 0; +} + +static krb5_error_code +greet_internalize(krb5_context kcontext, + krb5_authdata_context context, + void *plugin_context, + void *request_context, + krb5_octet **buffer, + size_t *lenremain) +{ + struct greet_context *greet = (struct greet_context *)request_context; + krb5_error_code code; + krb5_int32 length; + krb5_octet *contents = NULL; + krb5_int32 verified; + krb5_octet *bp; + size_t remain; + + bp = *buffer; + remain = *lenremain; + + /* Greeting Length */ + code = krb5_ser_unpack_int32(&length, &bp, &remain); + if (code != 0) + return code; + + /* Greeting Contents */ + if (length != 0) { + contents = malloc(length); + if (contents == NULL) + return ENOMEM; + + code = krb5_ser_unpack_bytes(contents, (size_t)length, &bp, &remain); + if (code != 0) { + free(contents); + return code; + } + } + + /* Verified */ + code = krb5_ser_unpack_int32(&verified, &bp, &remain); + if (code != 0) { + free(contents); + return code; + } + + krb5_free_data_contents(kcontext, &greet->greeting); + greet->greeting.length = length; + greet->greeting.data = (char *)contents; + greet->verified = (verified != 0); + + *buffer = bp; + *lenremain = remain; + + return 0; +} + +static krb5_authdatatype greet_ad_types[] = { -42, 0 }; + +krb5plugin_authdata_client_ftable_v0 authdata_client_0 = { + "greet", + greet_ad_types, + greet_init, + greet_fini, + greet_flags, + greet_request_init, + greet_request_fini, + greet_get_attribute_types, + greet_get_attribute, + greet_set_attribute, + greet_delete_attribute, + greet_export_authdata, + greet_import_authdata, + NULL, + NULL, + NULL, + greet_size, + greet_externalize, + greet_internalize, + NULL +}; diff --git a/src/plugins/authdata/greet_client/greet_client.exports b/src/plugins/authdata/greet_client/greet_client.exports new file mode 100644 index 000000000..8d5d5c47f --- /dev/null +++ b/src/plugins/authdata/greet_client/greet_client.exports @@ -0,0 +1 @@ +authdata_client_0 diff --git a/src/plugins/authdata/greet_server/Makefile.in b/src/plugins/authdata/greet_server/Makefile.in new file mode 100644 index 000000000..3924f1b98 --- /dev/null +++ b/src/plugins/authdata/greet_server/Makefile.in @@ -0,0 +1,38 @@ +thisconfigdir=../../.. +myfulldir=plugins/authdata/greet_server +mydir=plugins/authdata/greet_server +BUILDTOP=$(REL)..$(S)..$(S).. +KRB5_RUN_ENV = @KRB5_RUN_ENV@ +KRB5_CONFIG_SETUP = KRB5_CONFIG=$(SRCTOP)/config-files/krb5.conf ; export KRB5_CONFIG ; +PROG_LIBPATH=-L$(TOPLIBD) +PROG_RPATH=$(KRB5_LIBDIR) +MODULE_INSTALL_DIR = $(KRB5_AD_MODULE_DIR) +DEFS=@DEFS@ + +LOCALINCLUDES = -I../../../include/krb5 + +LIBBASE=greet_server +LIBMAJOR=1 +LIBMINOR=0 +SO_EXT=.so +SHLIB_EXPDEPS = $(TOPLIBD)/libk5crypto$(SHLIBEXT) \ + $(TOPLIBD)/libkrb5$(SHLIBEXT) +SHLIB_EXPLIBS= -lkrb5 -lcom_err -lk5crypto $(SUPPORT_LIB) $(LIBS) + +SHLIB_DIRS=-L$(TOPLIBD) +SHLIB_RDIRS=$(KRB5_LIBDIR) +STOBJLISTS=OBJS.ST +STLIBOBJS= greet_auth.o + +SRCS= greet_auth.c + +all-unix:: all-liblinks +install-unix:: install-libs +clean-unix:: clean-libs clean-libobjs + +clean:: + $(RM) lib$(LIBBASE)$(SO_EXT) + +@libnover_frag@ +@libobj_frag@ + diff --git a/src/plugins/authdata/greet_server/deps b/src/plugins/authdata/greet_server/deps new file mode 100644 index 000000000..b754fcff9 --- /dev/null +++ b/src/plugins/authdata/greet_server/deps @@ -0,0 +1,6 @@ +# +# Generated makefile dependencies follow. +# +greet_auth.so greet_auth.po $(OUTPRE)greet_auth.$(OBJEXT): \ + $(BUILDTOP)/include/krb5/krb5.h $(COM_ERR_DEPS) $(SRCTOP)/include/krb5/authdata_plugin.h \ + greet_auth.c diff --git a/src/plugins/authdata/greet_server/greet_auth.c b/src/plugins/authdata/greet_server/greet_auth.c new file mode 100644 index 000000000..cacbc659f --- /dev/null +++ b/src/plugins/authdata/greet_server/greet_auth.c @@ -0,0 +1,191 @@ +/* + * plugins/authdata/greet_server/ + * + * Copyright 2009 by the Massachusetts Institute of Technology. + * + * Export of this software from the United States of America may + * require a specific license from the United States Government. + * It is the responsibility of any person or organization contemplating + * export to obtain such a license before exporting. + * + * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and + * distribute this software and its documentation for any purpose and + * without fee is hereby granted, provided that the above copyright + * notice appear in all copies and that both that copyright notice and + * this permission notice appear in supporting documentation, and that + * the name of M.I.T. not be used in advertising or publicity pertaining + * to distribution of the software without specific, written prior + * permission. Furthermore if you modify this software you must label + * your software as modified software and not distribute it in such a + * fashion that it might be confused with the original M.I.T. software. + * M.I.T. makes no representations about the suitability of + * this software for any purpose. It is provided "as is" without express + * or implied warranty. + * + * + * Sample authorization data plugin + */ + +#include +#include +#include +#include +#include +#include + +static krb5_error_code +greet_init(krb5_context ctx, void **blob) +{ + return 0; +} + +static void +greet_fini(krb5_context ctx, void *blob) +{ +} + +static krb5_error_code greet_hello(krb5_context context, krb5_data **ret) +{ + krb5_data tmp; + + tmp.data = "Hello, KDC issued acceptor world!"; + tmp.length = strlen(tmp.data); + + return krb5_copy_data(context, &tmp, ret); +} + +static krb5_error_code +greet_kdc_verify(krb5_context context, + krb5_enc_tkt_part *enc_tkt_request, + krb5_data **greeting) +{ + krb5_error_code code; + krb5_authdata **tgt_authdata = NULL; + krb5_authdata **kdc_issued = NULL; + krb5_authdata **greet = NULL; + + code = krb5int_find_authdata(context, + enc_tkt_request->authorization_data, + NULL, + KRB5_AUTHDATA_KDC_ISSUED, + &tgt_authdata); + if (code != 0) + return 0; + + code = krb5_verify_authdata_kdc_issued(context, + enc_tkt_request->session, + tgt_authdata[0], + NULL, + &kdc_issued); + if (code != 0) { + krb5_free_authdata(context, tgt_authdata); + return code; + } + + code = krb5int_find_authdata(context, + kdc_issued, + NULL, + -42, + &greet); + if (code == 0) { + krb5_data tmp; + + tmp.data = (char *)greet[0]->contents; + tmp.length = greet[0]->length; + + code = krb5_copy_data(context, &tmp, greeting); + } else + code = 0; + + krb5_free_authdata(context, tgt_authdata); + krb5_free_authdata(context, kdc_issued); + krb5_free_authdata(context, greet); + + return code; +} + +static krb5_error_code +greet_kdc_sign(krb5_context context, + krb5_enc_tkt_part *enc_tkt_reply, + krb5_const_principal tgs, + krb5_data *greeting) +{ + krb5_error_code code; + krb5_authdata ad_datum, *ad_data[2], **kdc_issued = NULL; + krb5_authdata **if_relevant = NULL; + + ad_datum.ad_type = -42; + ad_datum.contents = (krb5_octet *)greeting->data; + ad_datum.length = greeting->length; + + ad_data[0] = &ad_datum; + ad_data[1] = NULL; + + code = krb5_make_authdata_kdc_issued(context, + enc_tkt_reply->session, + tgs, + ad_data, + &kdc_issued); + if (code != 0) + return code; + + code = krb5_encode_authdata_container(context, + KRB5_AUTHDATA_IF_RELEVANT, + kdc_issued, + &if_relevant); + if (code != 0) { + krb5_free_authdata(context, kdc_issued); + return code; + } + + /* this isn't very friendly to other plugins... */ + krb5_free_authdata(context, enc_tkt_reply->authorization_data); + enc_tkt_reply->authorization_data = if_relevant; + + krb5_free_authdata(context, kdc_issued); + + return 0; +} + +static krb5_error_code +greet_authdata(krb5_context context, + unsigned int flags, + krb5_db_entry *client, + krb5_db_entry *server, + krb5_db_entry *tgs, + krb5_keyblock *client_key, + krb5_keyblock *server_key, + krb5_data *req_pkt, + krb5_kdc_req *request, + krb5_const_principal for_user_princ, + krb5_enc_tkt_part *enc_tkt_request, + krb5_enc_tkt_part *enc_tkt_reply) +{ + krb5_error_code code; + krb5_data *greeting = NULL; + + if (request->msg_type == KRB5_TGS_REQ) { + code = greet_kdc_verify(context, enc_tkt_request, &greeting); + if (code != 0) + return code; + } + + if (greeting == NULL) { + code = greet_hello(context, &greeting); + if (code != 0) + return code; + } + + code = greet_kdc_sign(context, enc_tkt_reply, tgs->princ, greeting); + + krb5_free_data(context, greeting); + + return code; +} + +krb5plugin_authdata_server_ftable_v1 authdata_server_1 = { + "greet", + greet_init, + greet_fini, + greet_authdata, +}; diff --git a/src/plugins/authdata/greet_server/greet_server.exports b/src/plugins/authdata/greet_server/greet_server.exports new file mode 100644 index 000000000..74719bfa7 --- /dev/null +++ b/src/plugins/authdata/greet_server/greet_server.exports @@ -0,0 +1 @@ +authdata_server_1 diff --git a/src/tests/asn.1/krb5_decode_leak.c b/src/tests/asn.1/krb5_decode_leak.c index be0a536e9..3eb6f3c66 100644 --- a/src/tests/asn.1/krb5_decode_leak.c +++ b/src/tests/asn.1/krb5_decode_leak.c @@ -662,7 +662,6 @@ main(int argc, char **argv) /* encode_krb5_pa_s4u_x509_user */ { krb5_pa_s4u_x509_user s4u, *tmp; - setup(s4u, "pa_s4u_x509_user", ktest_make_sample_pa_s4u_x509_user); leak_test(s4u, encode_krb5_pa_s4u_x509_user, @@ -670,6 +669,17 @@ main(int argc, char **argv) krb5_free_pa_s4u_x509_user); ktest_empty_pa_s4u_x509_user(&s4u); } + /****************************************************************/ + /* encode_krb5_ad_kdcissued */ + { + krb5_ad_kdcissued kdci, *tmp; + setup(kdci, "ad_kdcissued", + ktest_make_sample_ad_kdcissued); + leak_test(kdci, encode_krb5_ad_kdcissued, + decode_krb5_ad_kdcissued, + krb5_free_ad_kdcissued); + ktest_empty_ad_kdcissued(&kdci); + } krb5_free_context(test_context); return 0; } diff --git a/src/tests/asn.1/krb5_decode_test.c b/src/tests/asn.1/krb5_decode_test.c index 2d2000422..401b26240 100644 --- a/src/tests/asn.1/krb5_decode_test.c +++ b/src/tests/asn.1/krb5_decode_test.c @@ -891,12 +891,22 @@ int main(argc, argv) ktest_empty_sam_response(&ref); } + /****************************************************************/ + /* decode_pa_s4u_x509_user */ { setup(krb5_pa_s4u_x509_user,"krb5_pa_s4u_x509_user",ktest_make_sample_pa_s4u_x509_user); decode_run("pa_s4u_x509_user","","30 68 A0 55 30 53 A0 06 02 04 00 CA 14 9A A1 1A 30 18 A0 03 02 01 01 A1 11 30 0F 1B 06 68 66 74 73 61 69 1B 05 65 78 74 72 61 A2 10 1B 0E 41 54 48 45 4E 41 2E 4D 49 54 2E 45 44 55 A3 12 04 10 70 61 5F 73 34 75 5F 78 35 30 39 5F 75 73 65 72 A4 07 03 05 00 80 00 00 00 A1 0F 30 0D A0 03 02 01 01 A1 06 04 04 31 32 33 34",decode_krb5_pa_s4u_x509_user,ktest_equal_pa_s4u_x509_user,krb5_free_pa_s4u_x509_user); ktest_empty_pa_s4u_x509_user(&ref); } + /****************************************************************/ + /* decode_ad_kdcissued */ + { + setup(krb5_ad_kdcissued,"krb5_ad_kdcissued",ktest_make_sample_ad_kdcissued); + decode_run("ad_kdcissued","","30 65 A0 0F 30 0D A0 03 02 01 01 A1 06 04 04 31 32 33 34 A1 10 1B 0E 41 54 48 45 4E 41 2E 4D 49 54 2E 45 44 55 A2 1A 30 18 A0 03 02 01 01 A1 11 30 0F 1B 06 68 66 74 73 61 69 1B 05 65 78 74 72 61 A3 24 30 22 30 0F A0 03 02 01 01 A1 08 04 06 66 6F 6F 62 61 72 30 0F A0 03 02 01 01 A1 08 04 06 66 6F 6F 62 61 72",decode_krb5_ad_kdcissued,ktest_equal_ad_kdcissued,krb5_free_ad_kdcissued); + ktest_empty_ad_kdcissued(&ref); + } + #ifdef ENABLE_LDAP /* ldap sequence_of_keys */ { diff --git a/src/tests/asn.1/krb5_encode_test.c b/src/tests/asn.1/krb5_encode_test.c index 7ae32ec75..c010af9ab 100644 --- a/src/tests/asn.1/krb5_encode_test.c +++ b/src/tests/asn.1/krb5_encode_test.c @@ -706,7 +706,17 @@ main(argc, argv) encode_krb5_pa_s4u_x509_user); ktest_empty_pa_s4u_x509_user(&s4u); } - + /****************************************************************/ + /* encode_krb5_ad_kdcissued */ + { + krb5_ad_kdcissued kdci; + setup(kdci,krb5_ad_kdcissued,"ad_kdcissued", + ktest_make_sample_ad_kdcissued); + encode_run(kdci,krb5_ad_kdcissued, + "ad_kdcissued","", + encode_krb5_ad_kdcissued); + ktest_empty_ad_kdcissued(&kdci); + } #ifdef ENABLE_LDAP { ldap_seqof_key_data skd; diff --git a/src/tests/asn.1/ktest.c b/src/tests/asn.1/ktest.c index 8b6367918..f41347c0f 100644 --- a/src/tests/asn.1/ktest.c +++ b/src/tests/asn.1/ktest.c @@ -842,6 +842,19 @@ krb5_error_code ktest_make_sample_pa_s4u_x509_user(p) return 0; } +krb5_error_code ktest_make_sample_ad_kdcissued(p) + krb5_ad_kdcissued *p; +{ + krb5_error_code retval; + retval = ktest_make_sample_checksum(&p->ad_checksum); + if (retval) return retval; + retval = ktest_make_sample_principal(&p->i_principal); + if (retval) return retval; + retval = ktest_make_sample_authorization_data(&p->elements); + if (retval) return retval; + return retval; +} + #ifdef ENABLE_LDAP static krb5_error_code ktest_make_sample_key_data(krb5_key_data *p, int i) { @@ -1445,6 +1458,14 @@ void ktest_empty_pa_s4u_x509_user(p) if (p->cksum.contents) free(p->cksum.contents); } +void ktest_empty_ad_kdcissued(p) + krb5_ad_kdcissued *p; +{ + if (p->ad_checksum.contents) free(p->ad_checksum.contents); + ktest_destroy_principal(&p->i_principal); + ktest_destroy_authorization_data(&p->elements); +} + #ifdef ENABLE_LDAP void ktest_empty_ldap_seqof_key_data(ctx, p) krb5_context ctx; diff --git a/src/tests/asn.1/ktest.h b/src/tests/asn.1/ktest.h index a2951d26f..fa33ceffd 100644 --- a/src/tests/asn.1/ktest.h +++ b/src/tests/asn.1/ktest.h @@ -106,6 +106,7 @@ krb5_error_code ktest_make_sample_enc_sam_response_enc krb5_error_code ktest_make_sample_predicted_sam_response(krb5_predicted_sam_response *p); krb5_error_code ktest_make_sample_enc_sam_response_enc_2(krb5_enc_sam_response_enc_2 *p); krb5_error_code ktest_make_sample_pa_s4u_x509_user(krb5_pa_s4u_x509_user *p); +krb5_error_code ktest_make_sample_ad_kdcissued(krb5_ad_kdcissued *p); #ifdef ENABLE_LDAP krb5_error_code ktest_make_sample_ldap_seqof_key_data(ldap_seqof_key_data * p); @@ -215,6 +216,7 @@ void ktest_empty_predicted_sam_response(krb5_predicted_sam_response *p); void ktest_empty_sam_response_2(krb5_sam_response_2 *p); void ktest_empty_enc_sam_response_enc_2(krb5_enc_sam_response_enc_2 *p); void ktest_empty_pa_s4u_x509_user(krb5_pa_s4u_x509_user *p); +void ktest_empty_ad_kdcissued(krb5_ad_kdcissued *p); #ifdef ENABLE_LDAP void ktest_empty_ldap_seqof_key_data(krb5_context, ldap_seqof_key_data *p); diff --git a/src/tests/asn.1/ktest_equal.c b/src/tests/asn.1/ktest_equal.c index da0324973..5479f8047 100644 --- a/src/tests/asn.1/ktest_equal.c +++ b/src/tests/asn.1/ktest_equal.c @@ -556,6 +556,20 @@ int ktest_equal_pa_s4u_x509_user(ref, var) p=p&&struct_equal(cksum,ktest_equal_checksum); return p; } + +int ktest_equal_ad_kdcissued(ref, var) + krb5_ad_kdcissued *ref; + krb5_ad_kdcissued *var; +{ + int p = TRUE; + if (ref == var) return TRUE; + else if (ref == NULL || var == NULL) return FALSE; + p=p&&struct_equal(ad_checksum,ktest_equal_checksum); + p=p&&ptr_equal(i_principal,ktest_equal_principal_data); + p=p&&ptr_equal(elements,ktest_equal_authorization_data); + return p; +} + #ifdef ENABLE_LDAP static int equal_key_data(ref, var) krb5_key_data *ref; diff --git a/src/tests/asn.1/ktest_equal.h b/src/tests/asn.1/ktest_equal.h index 8a0641de5..1464ebb50 100644 --- a/src/tests/asn.1/ktest_equal.h +++ b/src/tests/asn.1/ktest_equal.h @@ -95,6 +95,10 @@ int ktest_equal_pa_s4u_x509_user (krb5_pa_s4u_x509_user *ref, krb5_pa_s4u_x509_user *var); +int ktest_equal_ad_kdcissued + (krb5_ad_kdcissued *ref, + krb5_ad_kdcissued *var); + int ktest_equal_ldap_sequence_of_keys(ldap_seqof_key_data *ref, ldap_seqof_key_data *var); #endif diff --git a/src/tests/asn.1/reference_encode.out b/src/tests/asn.1/reference_encode.out index 0d913cdb2..952e69c77 100644 --- a/src/tests/asn.1/reference_encode.out +++ b/src/tests/asn.1/reference_encode.out @@ -57,3 +57,4 @@ encode_krb5_predicted_sam_response: 30 6D A0 13 30 11 A0 03 02 01 01 A1 0A 04 08 encode_krb5_sam_response_2: 30 42 A0 03 02 01 2B A1 07 03 05 00 80 00 00 00 A2 0C 04 0A 74 72 61 63 6B 20 64 61 74 61 A3 1D 30 1B A0 03 02 01 01 A1 04 02 02 0D 36 A2 0E 04 0C 6E 6F 6E 63 65 20 6F 72 20 73 61 64 A4 05 02 03 54 32 10 encode_krb5_enc_sam_response_enc_2: 30 1F A0 03 02 01 58 A1 18 04 16 65 6E 63 5F 73 61 6D 5F 72 65 73 70 6F 6E 73 65 5F 65 6E 63 5F 32 encode_krb5_pa_s4u_x509_user: 30 68 A0 55 30 53 A0 06 02 04 00 CA 14 9A A1 1A 30 18 A0 03 02 01 01 A1 11 30 0F 1B 06 68 66 74 73 61 69 1B 05 65 78 74 72 61 A2 10 1B 0E 41 54 48 45 4E 41 2E 4D 49 54 2E 45 44 55 A3 12 04 10 70 61 5F 73 34 75 5F 78 35 30 39 5F 75 73 65 72 A4 07 03 05 00 80 00 00 00 A1 0F 30 0D A0 03 02 01 01 A1 06 04 04 31 32 33 34 +encode_krb5_ad_kdcissued: 30 65 A0 0F 30 0D A0 03 02 01 01 A1 06 04 04 31 32 33 34 A1 10 1B 0E 41 54 48 45 4E 41 2E 4D 49 54 2E 45 44 55 A2 1A 30 18 A0 03 02 01 01 A1 11 30 0F 1B 06 68 66 74 73 61 69 1B 05 65 78 74 72 61 A3 24 30 22 30 0F A0 03 02 01 01 A1 08 04 06 66 6F 6F 62 61 72 30 0F A0 03 02 01 01 A1 08 04 06 66 6F 6F 62 61 72 diff --git a/src/tests/asn.1/trval_reference.out b/src/tests/asn.1/trval_reference.out index c8aa48e3f..b19ca747e 100644 --- a/src/tests/asn.1/trval_reference.out +++ b/src/tests/asn.1/trval_reference.out @@ -1263,3 +1263,23 @@ encode_krb5_pa_s4u_x509_user: . . [0] [Integer] 1 . . [1] [Octet String] "1234" +encode_krb5_ad_kdcissued: + +[Sequence/Sequence Of] +. [0] [Sequence/Sequence Of] +. . [0] [Integer] 1 +. . [1] [Octet String] "1234" +. [1] [General string] "ATHENA.MIT.EDU" +. [2] [Sequence/Sequence Of] +. . [0] [Integer] 1 +. . [1] [Sequence/Sequence Of] +. . . [General string] "hftsai" +. . . [General string] "extra" +. [3] [Sequence/Sequence Of] +. . [Sequence/Sequence Of] +. . . [0] [Integer] 1 +. . . [1] [Octet String] "foobar" +. . [Sequence/Sequence Of] +. . . [0] [Integer] 1 +. . . [1] [Octet String] "foobar" + diff --git a/src/tests/gssapi/Makefile.in b/src/tests/gssapi/Makefile.in index e385c68f6..fd7b7db5b 100644 --- a/src/tests/gssapi/Makefile.in +++ b/src/tests/gssapi/Makefile.in @@ -6,18 +6,19 @@ DEFINES = -DUSE_AUTOCONF_H PROG_LIBPATH=-L$(TOPLIBD) PROG_RPATH=$(KRB5_LIBDIR) -SRCS= $(srcdir)/t_imp_name.c $(srcdir)/t_s4u.c +SRCS= $(srcdir)/t_imp_name.c $(srcdir)/t_s4u.c $(srcdir)/t_namingexts.c -OBJS= t_imp_name.o t_s4u.o +OBJS= t_imp_name.o t_s4u.o t_namingexts.o -all:: t_imp_name t_s4u +all:: t_imp_name t_s4u t_namingexts t_imp_name: t_imp_name.o $(GSS_DEPLIBS) $(KRB5_BASE_DEPLIBS) $(CC_LINK) -o t_imp_name t_imp_name.o $(GSS_LIBS) $(KRB5_BASE_LIBS) - +t_namingexts: t_namingexts.o $(GSS_DEPLIBS) $(KRB5_BASE_DEPLIBS) + $(CC_LINK) -o t_namingexts t_namingexts.o $(GSS_LIBS) $(KRB5_BASE_LIBS) t_s4u: t_s4u.o $(GSS_DEPLIBS) $(KRB5_BASE_DEPLIBS) $(CC_LINK) -o t_s4u t_s4u.o $(GSS_LIBS) $(KRB5_BASE_LIBS) clean:: - $(RM) t_imp_name t_s4u + $(RM) t_imp_name t_s4u t_namingexts diff --git a/src/tests/gssapi/t_namingexts.c b/src/tests/gssapi/t_namingexts.c new file mode 100644 index 000000000..3d7e4e349 --- /dev/null +++ b/src/tests/gssapi/t_namingexts.c @@ -0,0 +1,488 @@ +/* -*- mode: c; indent-tabs-mode: nil -*- */ +/* + * Copyright 2009 by the Massachusetts Institute of Technology. + * All Rights Reserved. + * + * Export of this software from the United States of America may + * require a specific license from the United States Government. + * It is the responsibility of any person or organization contemplating + * export to obtain such a license before exporting. + * + * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and + * distribute this software and its documentation for any purpose and + * without fee is hereby granted, provided that the above copyright + * notice appear in all copies and that both that copyright notice and + * this permission notice appear in supporting documentation, and that + * the name of M.I.T. not be used in advertising or publicity pertaining + * to distribution of the software without specific, written prior + * permission. Furthermore if you modify this software you must label + * your software as modified software and not distribute it in such a + * fashion that it might be confused with the original M.I.T. software. + * M.I.T. makes no representations about the suitability of + * this software for any purpose. It is provided "as is" without express + * or implied warranty. + * + */ + +#include +#include +#include + +#include +#include + +static gss_OID_desc spnego_mech = { 6, "\053\006\001\005\005\002" }; + +static int use_spnego = 0; + +static void displayStatus_1(m, code, type) + char *m; + OM_uint32 code; + int type; +{ + OM_uint32 maj_stat, min_stat; + gss_buffer_desc msg; + OM_uint32 msg_ctx; + + msg_ctx = 0; + while (1) { + maj_stat = gss_display_status(&min_stat, code, + type, GSS_C_NULL_OID, + &msg_ctx, &msg); + fprintf(stderr, "%s: %s\n", m, (char *)msg.value); + (void) gss_release_buffer(&min_stat, &msg); + + if (!msg_ctx) + break; + } +} + +static void displayStatus(msg, maj_stat, min_stat) + char *msg; + OM_uint32 maj_stat; + OM_uint32 min_stat; +{ + displayStatus_1(msg, maj_stat, GSS_C_GSS_CODE); + displayStatus_1(msg, min_stat, GSS_C_MECH_CODE); +} + +static OM_uint32 +displayCanonName(OM_uint32 *minor, gss_name_t name, char *tag) +{ + gss_name_t canon; + OM_uint32 major, tmp; + gss_buffer_desc buf; + + major = gss_canonicalize_name(minor, name, (gss_OID)gss_mech_krb5, &canon); + if (GSS_ERROR(major)) { + displayStatus("gss_canonicalize_name", major, *minor); + return major; + } + + major = gss_display_name(minor, canon, &buf, NULL); + if (GSS_ERROR(major)) { + gss_release_name(&tmp, &canon); + displayStatus("gss_display_name", major, *minor); + return major; + } + + printf("%s:\t%s\n", tag, (char *)buf.value); + + gss_release_name(&tmp, &canon); + gss_release_buffer(&tmp, &buf); + + return GSS_S_COMPLETE; +} + +static void +dumpAttribute(OM_uint32 *minor, + gss_name_t name, + gss_buffer_t attribute, + int noisy) +{ + OM_uint32 major, tmp; + gss_buffer_desc value; + gss_buffer_desc display_value; + int authenticated = 0; + int complete = 0; + int more = -1; + unsigned int i; + + while (more != 0) { + value.value = NULL; + display_value.value = NULL; + + major = gss_get_name_attribute(minor, + name, + attribute, + &authenticated, + &complete, + &value, + &display_value, + &more); + if (GSS_ERROR(major)) { + displayStatus("gss_get_name_attribute", major, *minor); + break; + } + + printf("Attribute %.*s %s %s\n\n%.*s\n", + (int)attribute->length, (char *)attribute->value, + authenticated ? "Authenticated" : "", + complete ? "Complete" : "", + (int)display_value.length, (char *)display_value.value); + + if (noisy) { + for (i = 0; i < value.length; i++) { + if ((i % 32) == 0) + printf("\n"); + printf("%02x", ((char *)value.value)[i] & 0xFF); + } + printf("\n\n"); + } + + gss_release_buffer(&tmp, &value); + gss_release_buffer(&tmp, &display_value); + } +} + +static OM_uint32 +enumerateAttributes(OM_uint32 *minor, + gss_name_t name, + int noisy) +{ + OM_uint32 major, tmp; + int name_is_MN; + gss_OID mech = GSS_C_NO_OID; + gss_buffer_set_t attrs = GSS_C_NO_BUFFER_SET; + unsigned int i; + + major = gss_inquire_name(minor, + name, + &name_is_MN, + &mech, + &attrs); + if (GSS_ERROR(major)) { + displayStatus("gss_inquire_name", major, *minor); + return major; + } + + if (attrs != GSS_C_NO_BUFFER_SET) { + for (i = 0; i < attrs->count; i++) + dumpAttribute(minor, name, &attrs->elements[i], noisy); + } + + gss_release_oid(&tmp, &mech); + gss_release_buffer_set(&tmp, &attrs); + + return major; +} + +static OM_uint32 +testExportImportName(OM_uint32 *minor, + gss_name_t name) +{ + OM_uint32 major, tmp; + gss_buffer_desc exported_name; + gss_name_t imported_name = GSS_C_NO_NAME; + unsigned int i; + + exported_name.value = NULL; + + major = gss_export_name_composite(minor, + name, + &exported_name); + if (GSS_ERROR(major)) { + displayStatus("gss_export_name_composite", major, *minor); + return major; + } + + printf("Exported name:\n"); + + for (i = 0; i < exported_name.length; i++) { + if ((i % 32) == 0) + printf("\n"); + printf("%02x", ((char *)exported_name.value)[i] & 0xFF); + } + + printf("\n"); + + major = gss_import_name(minor, &exported_name, gss_nt_exported_name, + &imported_name); + if (GSS_ERROR(major)) { + displayStatus("gss_import_name", major, *minor); + gss_release_buffer(&tmp, &exported_name); + return major; + } + + gss_release_buffer(&tmp, &exported_name); + + printf("\n"); + displayCanonName(minor, imported_name, "Re-imported name"); + printf("Re-imported attributes:\n\n"); + major = enumerateAttributes(minor, imported_name, 0); + + gss_release_name(&tmp, &imported_name); + + return major; +} + +static OM_uint32 +testGreetAuthzData(OM_uint32 *minor, + gss_name_t name) +{ + OM_uint32 major; + gss_buffer_desc attr; + gss_buffer_desc value; + + attr.value = "greet:greeting"; + attr.length = strlen((char *)attr.value); + + major = gss_delete_name_attribute(minor, + name, + &attr); + if (major == GSS_S_UNAVAILABLE) { + fprintf(stderr, "Warning: greet_client plugin not installed\n"); + return GSS_S_COMPLETE; + } else if (GSS_ERROR(major)) { + displayStatus("gss_delete_name_attribute", major, *minor); + return major; + } + + value.value = "Hello, acceptor world!"; + value.length = strlen((char *)value.value); + + major = gss_set_name_attribute(minor, + name, + 1, + &attr, + &value); + if (major == GSS_S_UNAVAILABLE) + return GSS_S_COMPLETE; + else if (GSS_ERROR(major)) + displayStatus("gss_set_name_attribute", major, *minor); + + return major; +} + +static OM_uint32 +testMapNameToAny(OM_uint32 *minor, + gss_name_t name) +{ + OM_uint32 major; + OM_uint32 tmp_minor; + gss_buffer_desc type_id; + krb5_pac pac; + krb5_context context; + krb5_error_code code; + size_t len; + krb5_ui_4 *types; + + type_id.value = "mspac"; + type_id.length = strlen((char *)type_id.value); + + major = gss_map_name_to_any(minor, + name, + 1, /* authenticated */ + &type_id, + (gss_any_t *)&pac); + if (major == GSS_S_UNAVAILABLE) + return GSS_S_COMPLETE; + else if (GSS_ERROR(major)) + displayStatus("gss_map_name_to_any", major, &minor); + + code = krb5_init_context(&context); + if (code != 0) { + gss_release_any_name_mapping(&tmp_minor, name, + &type_id, (gss_any_t *)&pac); + *minor = code; + return GSS_S_FAILURE; + } + + code = krb5_pac_get_types(context, pac, &len, &types); + if (code == 0) { + size_t i; + + printf("PAC buffer types:"); + for (i = 0; i < len; i++) + printf(" %d", types[i]); + printf("\n"); + free(types); + } + + gss_release_any_name_mapping(&tmp_minor, name, + &type_id, (gss_any_t *)&pac); + + return GSS_S_COMPLETE; +} + +static OM_uint32 +initAcceptSecContext(OM_uint32 *minor, + gss_cred_id_t verifier_cred_handle) +{ + OM_uint32 major; + gss_buffer_desc token, tmp; + gss_ctx_id_t initiator_context = GSS_C_NO_CONTEXT; + gss_ctx_id_t acceptor_context = GSS_C_NO_CONTEXT; + gss_name_t source_name = GSS_C_NO_NAME; + gss_name_t target_name = GSS_C_NO_NAME; + OM_uint32 time_rec; + + token.value = NULL; + token.length = 0; + + tmp.value = NULL; + tmp.length = 0; + + major = gss_inquire_cred(minor, verifier_cred_handle, + &target_name, NULL, NULL, NULL); + if (GSS_ERROR(major)) { + displayStatus("gss_inquire_cred", major, *minor); + return major; + } + + displayCanonName(minor, target_name, "Target name"); + + major = gss_init_sec_context(minor, + verifier_cred_handle, + &initiator_context, + target_name, + use_spnego ? + (gss_OID)&spnego_mech : + (gss_OID)gss_mech_krb5, + GSS_C_REPLAY_FLAG | GSS_C_SEQUENCE_FLAG, + GSS_C_INDEFINITE, + GSS_C_NO_CHANNEL_BINDINGS, + GSS_C_NO_BUFFER, + NULL, + &token, + NULL, + &time_rec); + + if (target_name != GSS_C_NO_NAME) + (void) gss_release_name(minor, &target_name); + + if (GSS_ERROR(major)) { + displayStatus("gss_init_sec_context", major, *minor); + return major; + } + + (void) gss_delete_sec_context(minor, &initiator_context, NULL); + + major = gss_accept_sec_context(minor, + &acceptor_context, + verifier_cred_handle, + &token, + GSS_C_NO_CHANNEL_BINDINGS, + &source_name, + NULL, + &tmp, + NULL, + &time_rec, + NULL); + + if (GSS_ERROR(major)) + displayStatus("gss_accept_sec_context", major, *minor); + else { + displayCanonName(minor, source_name, "Source name"); + enumerateAttributes(minor, source_name, 1); + testExportImportName(minor, source_name); + testMapNameToAny(minor, source_name); + } + + (void) gss_release_name(minor, &source_name); + (void) gss_delete_sec_context(minor, &acceptor_context, NULL); + (void) gss_release_buffer(minor, &token); + (void) gss_release_buffer(minor, &tmp); + + return major; +} + +int main(int argc, char *argv[]) +{ + OM_uint32 minor, major, tmp; + gss_cred_id_t cred_handle = GSS_C_NO_CREDENTIAL; + gss_OID_set_desc mechs; + gss_OID_set actual_mechs = GSS_C_NO_OID_SET; + gss_name_t name = GSS_C_NO_NAME; + + if (argc > 1 && strcmp(argv[1], "--spnego") == 0) { + use_spnego++; + argc--; + argv++; + } + + if (argc > 1) { + gss_buffer_desc name_buf; + gss_name_t tmp_name; + + name_buf.value = argv[1]; + name_buf.length = strlen(argv[1]); + + major = gss_import_name(&minor, &name_buf, + (gss_OID)GSS_KRB5_NT_PRINCIPAL_NAME, &tmp_name); + if (GSS_ERROR(major)) { + displayStatus("gss_import_name", major, minor); + goto out; + } + + major = gss_canonicalize_name(&minor, tmp_name, + (gss_OID)gss_mech_krb5, &name); + if (GSS_ERROR(major)) { + gss_release_name(&tmp, &tmp_name); + displayStatus("gss_canonicalze_name", major, minor); + goto out; + } + + gss_release_name(&tmp, &tmp_name); + + major = testGreetAuthzData(&minor, name); + if (GSS_ERROR(major)) + goto out; + } else { + fprintf(stderr, "Usage: %s [--spnego] [principal] [keytab]\n", argv[0]); + exit(1); + } + + if (argc > 2) { + major = krb5_gss_register_acceptor_identity(argv[2]); + if (GSS_ERROR(major)) { + displayStatus("krb5_gss_register_acceptor_identity", major, minor); + goto out; + } + } + + + mechs.elements = use_spnego ? (gss_OID)&spnego_mech : + (gss_OID)gss_mech_krb5; + mechs.count = 1; + + /* get default cred */ + major = gss_acquire_cred(&minor, + name, + GSS_C_INDEFINITE, + &mechs, + GSS_C_BOTH, + &cred_handle, + &actual_mechs, + NULL); + if (GSS_ERROR(major)) { + displayStatus("gss_acquire_cred", major, minor); + goto out; + } + + (void) gss_release_oid_set(&minor, &actual_mechs); + + major = initAcceptSecContext(&minor, cred_handle); + if (GSS_ERROR(major)) + goto out; + + printf("\n"); + +out: + (void) gss_release_cred(&tmp, &cred_handle); + (void) gss_release_oid_set(&tmp, &actual_mechs); + (void) gss_release_name(&tmp, &name); + + return GSS_ERROR(major) ? 1 : 0; +} + diff --git a/src/tests/gssapi/t_s4u.c b/src/tests/gssapi/t_s4u.c index 264e60a60..394313a68 100644 --- a/src/tests/gssapi/t_s4u.c +++ b/src/tests/gssapi/t_s4u.c @@ -59,7 +59,7 @@ static gss_OID_desc spnego_mech = { 6, "\053\006\001\005\005\002" }; -int use_spnego = 0; +static int use_spnego = 0; static void displayStatus_1(m, code, type) char *m; @@ -140,6 +140,134 @@ displayOID(OM_uint32 *minor, gss_OID oid, char *tag) return GSS_S_COMPLETE; } +static void +dumpAttribute(OM_uint32 *minor, + gss_name_t name, + gss_buffer_t attribute, + int noisy) +{ + OM_uint32 major, tmp_minor; + gss_buffer_desc value; + gss_buffer_desc display_value; + int authenticated = 0; + int complete = 0; + int more = -1; + unsigned int i; + + while (more != 0) { + value.value = NULL; + display_value.value = NULL; + + major = gss_get_name_attribute(minor, + name, + attribute, + &authenticated, + &complete, + &value, + &display_value, + &more); + if (GSS_ERROR(major)) { + displayStatus("gss_get_name_attribute", major, *minor); + break; + } + + printf("Attribute %.*s %s %s\n\n%.*s\n", + (int)attribute->length, (char *)attribute->value, + authenticated ? "Authenticated" : "", + complete ? "Complete" : "", + (int)display_value.length, (char *)display_value.value); + + if (noisy) { + for (i = 0; i < value.length; i++) { + if ((i % 32) == 0) + printf("\n"); + printf("%02x", ((char *)value.value)[i] & 0xFF); + } + printf("\n\n"); + } + + gss_release_buffer(&tmp_minor, &value); + gss_release_buffer(&tmp_minor, &display_value); + } +} + +static OM_uint32 +enumerateAttributes(OM_uint32 *minor, + gss_name_t name, + int noisy) +{ + OM_uint32 major, tmp_minor; + int name_is_MN; + gss_OID mech = GSS_C_NO_OID; + gss_buffer_set_t attrs = GSS_C_NO_BUFFER_SET; + unsigned int i; + + major = gss_inquire_name(minor, + name, + &name_is_MN, + &mech, + &attrs); + if (GSS_ERROR(major)) { + displayStatus("gss_inquire_name", major, *minor); + return major; + } + + if (attrs != GSS_C_NO_BUFFER_SET) { + for (i = 0; i < attrs->count; i++) + dumpAttribute(minor, name, &attrs->elements[i], noisy); + } + + gss_release_oid(&tmp_minor, &mech); + gss_release_buffer_set(&tmp_minor, &attrs); + + return major; +} + +static OM_uint32 +testGreetAuthzData(OM_uint32 *minor, + gss_name_t *name) +{ + OM_uint32 major, tmp_minor; + gss_buffer_desc attr; + gss_buffer_desc value; + gss_name_t canon; + + major = gss_canonicalize_name(minor, + *name, + (gss_OID)gss_mech_krb5, + &canon); + if (GSS_ERROR(major)) { + displayStatus("gss_canonicalize_name", major, *minor); + return major; + } + + attr.value = "greet:greeting"; + attr.length = strlen((char *)attr.value); + + value.value = "Hello, acceptor world!"; + value.length = strlen((char *)value.value); + + major = gss_set_name_attribute(minor, + canon, + 1, + &attr, + &value); + if (major == GSS_S_UNAVAILABLE) + major = GSS_S_COMPLETE; + else if (GSS_ERROR(major)) + displayStatus("gss_set_name_attribute", major, *minor); + else { + gss_release_name(&tmp_minor, name); + *name = canon; + canon = GSS_C_NO_NAME; + } + + if (canon != GSS_C_NO_NAME) + gss_release_name(&tmp_minor, &canon); + + return GSS_S_COMPLETE; +} + static OM_uint32 initAcceptSecContext(OM_uint32 *minor, gss_cred_id_t claimant_cred_handle, @@ -217,6 +345,7 @@ initAcceptSecContext(OM_uint32 *minor, else { displayCanonName(minor, source_name, "Source name"); displayOID(minor, mech, "Source mech"); + enumerateAttributes(minor, source_name, 1); } (void) gss_release_name(&tmp_minor, &source_name); @@ -367,6 +496,10 @@ int main(int argc, char *argv[]) printf("Protocol transition tests follow\n"); printf("-----------------------------------\n\n"); + major = testGreetAuthzData(&minor, &user); + if (GSS_ERROR(major)) + goto out; + /* get S4U2Self cred */ major = gss_acquire_cred_impersonate_name(&minor, impersonator_cred_handle, -- 2.26.2