From: Greg Hudson Date: Wed, 6 Oct 2010 18:25:04 +0000 (+0000) Subject: Merge users/lhoward/sasl-gs2 to trunk X-Git-Tag: krb5-1.9-beta1~30 X-Git-Url: http://git.tremily.us/?a=commitdiff_plain;h=014f8057c5328b3e39b5d8660a1ea1a98409006f;p=krb5.git Merge users/lhoward/sasl-gs2 to trunk git-svn-id: svn://anonsvn.mit.edu/krb5/trunk@24436 dc483132-0cff-0310-8789-dd5450dbe970 --- diff --git a/src/appl/gss-sample/gss-client.c b/src/appl/gss-sample/gss-client.c index d922cc3bd..d439f23fb 100644 --- a/src/appl/gss-sample/gss-client.c +++ b/src/appl/gss-sample/gss-client.c @@ -69,12 +69,17 @@ #include "gss-misc.h" static int verbose = 1; +static int spnego = 0; +static gss_OID_desc gss_spnego_mechanism_oid_desc = + {6, (void *)"\x2b\x06\x01\x05\x05\x02"}; static void usage() { - fprintf(stderr, "Usage: gss-client [-port port] [-mech mechanism] [-d]\n"); - fprintf(stderr, " [-seq] [-noreplay] [-nomutual] [-user user] [-pass pw]"); + fprintf(stderr, "Usage: gss-client [-port port] [-mech mechanism] " + "[-spnego] [-d]\n"); + fprintf(stderr, " [-seq] [-noreplay] [-nomutual] [-user user] " + "[-pass pw]"); #ifdef _WIN32 fprintf(stderr, " [-threads num]"); #endif @@ -176,10 +181,17 @@ client_establish_context(int s, char *service_name, OM_uint32 gss_flags, gss_name_t gss_username = GSS_C_NO_NAME; gss_OID_set_desc mechs, *mechsp = GSS_C_NO_OID_SET; - if (oid != GSS_C_NO_OID) { + if (spnego) { + mechs.elements = &gss_spnego_mechanism_oid_desc; + mechs.count = 1; + mechsp = &mechs; + } else if (oid != GSS_C_NO_OID) { mechs.elements = oid; mechs.count = 1; mechsp = &mechs; + } else { + mechs.elements = NULL; + mechs.count = 0; } if (username != NULL) { @@ -218,6 +230,20 @@ client_establish_context(int s, char *service_name, OM_uint32 gss_flags, gss_release_name(&min_stat, &gss_username); return -1; } + if (spnego && oid != GSS_C_NO_OID) { + gss_OID_set_desc neg_mechs; + + neg_mechs.elements = oid; + neg_mechs.count = 1; + + maj_stat = gss_set_neg_mechs(&min_stat, cred, &neg_mechs); + if (maj_stat != GSS_S_COMPLETE) { + display_status("setting neg mechs", maj_stat, min_stat); + gss_release_name(&min_stat, &gss_username); + gss_release_cred(&min_stat, &cred); + return -1; + } + } gss_release_name(&min_stat, &gss_username); /* @@ -264,7 +290,8 @@ client_establish_context(int s, char *service_name, OM_uint32 gss_flags, do { maj_stat = gss_init_sec_context(&init_sec_min_stat, cred, gss_context, - target_name, oid, gss_flags, 0, + target_name, mechs.elements, + gss_flags, 0, NULL, /* channel bindings */ token_ptr, NULL, /* mech type */ &send_tok, ret_flags, @@ -409,7 +436,7 @@ call_server(host, port, oid, service_name, gss_flags, auth_flag, char *username; char *password; { - gss_ctx_id_t context; + gss_ctx_id_t context = GSS_C_NO_CONTEXT; gss_buffer_desc in_buf, out_buf; int s, state; OM_uint32 ret_flags; @@ -523,7 +550,7 @@ call_server(host, port, oid, service_name, gss_flags, auth_flag, } else { /* Seal the message */ in_buf.value = msg; - in_buf.length = strlen(msg); + in_buf.length = strlen((char *)in_buf.value); } for (i = 0; i < mcount; i++) { @@ -611,6 +638,7 @@ call_server(host, port, oid, service_name, gss_flags, auth_flag, } (void) close(s); + return 0; } @@ -776,7 +804,7 @@ main(argc, argv) } else if (strcmp(*argv, "-iakerb") == 0) { mechanism = "{ 1 3 6 1 5 2 5 }"; } else if (strcmp(*argv, "-spnego") == 0) { - mechanism = "{ 1 3 6 1 5 5 2 }"; + spnego = 1; } else if (strcmp(*argv, "-krb5") == 0) { mechanism = "{ 1 3 5 1 5 2 }"; #ifdef _WIN32 diff --git a/src/appl/gss-sample/gss-server.c b/src/appl/gss-sample/gss-server.c index 0ddfaeee8..e83326791 100644 --- a/src/appl/gss-sample/gss-server.c +++ b/src/appl/gss-sample/gss-server.c @@ -67,6 +67,9 @@ #include #endif +static OM_uint32 +enumerateAttributes(OM_uint32 *minor, gss_name_t name, int noisy); + static void usage() { @@ -104,6 +107,7 @@ int verbose = 0; * fails, an error message is displayed and -1 is returned; otherwise, * 0 is returned. */ + static int server_acquire_creds(char *service_name, gss_cred_id_t *server_creds) { @@ -121,7 +125,7 @@ server_acquire_creds(char *service_name, gss_cred_id_t *server_creds) } maj_stat = gss_acquire_cred(&min_stat, server_name, 0, - GSS_C_NULL_OID_SET, GSS_C_ACCEPT, + GSS_C_NO_OID_SET, GSS_C_ACCEPT, server_creds, NULL, NULL); if (maj_stat != GSS_S_COMPLETE) { display_status("acquiring credentials", maj_stat, min_stat); @@ -262,6 +266,7 @@ server_establish_context(int s, gss_cred_id_t server_creds, display_status("displaying name", maj_stat, min_stat); return -1; } + enumerateAttributes(&min_stat, client, TRUE); maj_stat = gss_release_name(&min_stat, &client); if (maj_stat != GSS_S_COMPLETE) { display_status("releasing name", maj_stat, min_stat); @@ -410,7 +415,8 @@ sign_server(int s, gss_cred_id_t server_creds, int export) gss_buffer_desc client_name, xmit_buf, msg_buf; gss_ctx_id_t context; OM_uint32 maj_stat, min_stat; - int i, conf_state, ret_flags; + int i, conf_state; + OM_uint32 ret_flags; char *cp; int token_flags; @@ -796,3 +802,77 @@ main(int argc, char **argv) return 0; } + +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)) { + display_status("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)) { + display_status("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; +} diff --git a/src/lib/gssapi/generic/gssapi.hin b/src/lib/gssapi/generic/gssapi.hin index fb82e3c4f..15d685d8c 100644 --- a/src/lib/gssapi/generic/gssapi.hin +++ b/src/lib/gssapi/generic/gssapi.hin @@ -289,6 +289,8 @@ typedef int gss_cred_usage_t; (((OM_uint32) 17ul) << GSS_C_ROUTINE_ERROR_OFFSET) #define GSS_S_NAME_NOT_MN \ (((OM_uint32) 18ul) << GSS_C_ROUTINE_ERROR_OFFSET) +#define GSS_S_BAD_MECH_ATTR \ + (((OM_uint32) 19ul) << GSS_C_ROUTINE_ERROR_OFFSET) /* * Supplementary info bits: @@ -831,4 +833,85 @@ gss_set_neg_mechs( /* XXXX This is a necessary evil until the spec is fixed */ #define GSS_S_CRED_UNAVAIL GSS_S_FAILURE +/* + * RFC 5587 + */ +typedef const gss_buffer_desc *gss_const_buffer_t; +typedef const struct gss_channel_bindings_struct *gss_const_channel_bindings_t; +typedef const struct gss_ctx_id_struct gss_const_ctx_id_t; +typedef const struct gss_cred_id_struct gss_const_cred_id_t; +typedef const struct gss_name_struct gss_const_name_t; +typedef const gss_OID_desc *gss_const_OID; +typedef const gss_OID_set_desc *gss_const_OID_set; + +OM_uint32 KRB5_CALLCONV +gss_indicate_mechs_by_attrs( + OM_uint32 *, /* minor_status */ + gss_const_OID_set, /* desired_mech_attrs */ + gss_const_OID_set, /* except_mech_attrs */ + gss_const_OID_set, /* critical_mech_attrs */ + gss_OID_set *); /* mechs */ + +OM_uint32 KRB5_CALLCONV +gss_inquire_attrs_for_mech( + OM_uint32 *, /* minor_status */ + gss_const_OID, /* mech */ + gss_OID_set *, /* mech_attrs */ + gss_OID_set *); /* known_mech_attrs */ + +OM_uint32 KRB5_CALLCONV +gss_display_mech_attr( + OM_uint32 *, /* minor_status */ + gss_const_OID, /* mech_attr */ + gss_buffer_t, /* name */ + gss_buffer_t, /* short_desc */ + gss_buffer_t); /* long_desc */ + +GSS_DLLIMP extern gss_const_OID GSS_C_MA_MECH_CONCRETE; +GSS_DLLIMP extern gss_const_OID GSS_C_MA_MECH_PSEUDO; +GSS_DLLIMP extern gss_const_OID GSS_C_MA_MECH_COMPOSITE; +GSS_DLLIMP extern gss_const_OID GSS_C_MA_MECH_NEGO; +GSS_DLLIMP extern gss_const_OID GSS_C_MA_MECH_GLUE; +GSS_DLLIMP extern gss_const_OID GSS_C_MA_NOT_MECH; +GSS_DLLIMP extern gss_const_OID GSS_C_MA_DEPRECATED; +GSS_DLLIMP extern gss_const_OID GSS_C_MA_NOT_DFLT_MECH; +GSS_DLLIMP extern gss_const_OID GSS_C_MA_ITOK_FRAMED; +GSS_DLLIMP extern gss_const_OID GSS_C_MA_AUTH_INIT; +GSS_DLLIMP extern gss_const_OID GSS_C_MA_AUTH_TARG; +GSS_DLLIMP extern gss_const_OID GSS_C_MA_AUTH_INIT_INIT; +GSS_DLLIMP extern gss_const_OID GSS_C_MA_AUTH_TARG_INIT; +GSS_DLLIMP extern gss_const_OID GSS_C_MA_AUTH_INIT_ANON; +GSS_DLLIMP extern gss_const_OID GSS_C_MA_AUTH_TARG_ANON; +GSS_DLLIMP extern gss_const_OID GSS_C_MA_DELEG_CRED; +GSS_DLLIMP extern gss_const_OID GSS_C_MA_INTEG_PROT; +GSS_DLLIMP extern gss_const_OID GSS_C_MA_CONF_PROT; +GSS_DLLIMP extern gss_const_OID GSS_C_MA_MIC; +GSS_DLLIMP extern gss_const_OID GSS_C_MA_WRAP; +GSS_DLLIMP extern gss_const_OID GSS_C_MA_PROT_READY; +GSS_DLLIMP extern gss_const_OID GSS_C_MA_REPLAY_DET; +GSS_DLLIMP extern gss_const_OID GSS_C_MA_OOS_DET; +GSS_DLLIMP extern gss_const_OID GSS_C_MA_CBINDINGS; +GSS_DLLIMP extern gss_const_OID GSS_C_MA_PFS; +GSS_DLLIMP extern gss_const_OID GSS_C_MA_COMPRESS; +GSS_DLLIMP extern gss_const_OID GSS_C_MA_CTX_TRANS; + +/* + * RFC 5801 + */ +OM_uint32 KRB5_CALLCONV +gss_inquire_saslname_for_mech( + OM_uint32 *, /* minor_status */ + const gss_OID, /* desired_mech */ + gss_buffer_t, /* sasl_mech_name */ + gss_buffer_t, /* mech_name */ + gss_buffer_t /* mech_description */ +); + +OM_uint32 KRB5_CALLCONV +gss_inquire_mech_for_saslname( + OM_uint32 *, /* minor_status */ + const gss_buffer_t, /* sasl_mech_name */ + gss_OID * /* mech_type */ +); + #endif /* _GSSAPI_H_ */ diff --git a/src/lib/gssapi/generic/gssapiP_generic.h b/src/lib/gssapi/generic/gssapiP_generic.h index cb2340a4b..f3af8a4d1 100644 --- a/src/lib/gssapi/generic/gssapiP_generic.h +++ b/src/lib/gssapi/generic/gssapiP_generic.h @@ -294,4 +294,13 @@ OM_uint32 generic_gss_copy_oid_set const gss_OID_set_desc *, /* const oidset*/ gss_OID_set * /*new_oidset*/); +extern gss_OID_set gss_ma_known_attrs; + +OM_uint32 generic_gss_display_mech_attr( + OM_uint32 *minor_status, + gss_const_OID mech_attr, + gss_buffer_t name, + gss_buffer_t short_desc, + gss_buffer_t long_desc); + #endif /* _GSSAPIP_GENERIC_H_ */ diff --git a/src/lib/gssapi/generic/gssapi_generic.c b/src/lib/gssapi/generic/gssapi_generic.c index 1d77d3f81..f8d2c426c 100644 --- a/src/lib/gssapi/generic/gssapi_generic.c +++ b/src/lib/gssapi/generic/gssapi_generic.c @@ -122,6 +122,35 @@ static const gss_OID_desc const_oids[] = { /* GSS_C_INQ_SSPI_SESSION_KEY 1.2.840.113554.1.2.2.5.5 */ {11, (void *)"\x2a\x86\x48\x86\xf7\x12\x01\x02\x02\x05\x05"}, + + /* RFC 5587 attributes, see below */ + {7, (void *)"\x2b\x06\x01\x05\x05\x0d\x01"}, + {7, (void *)"\x2b\x06\x01\x05\x05\x0d\x02"}, + {7, (void *)"\x2b\x06\x01\x05\x05\x0d\x03"}, + {7, (void *)"\x2b\x06\x01\x05\x05\x0d\x04"}, + {7, (void *)"\x2b\x06\x01\x05\x05\x0d\x05"}, + {7, (void *)"\x2b\x06\x01\x05\x05\x0d\x06"}, + {7, (void *)"\x2b\x06\x01\x05\x05\x0d\x07"}, + {7, (void *)"\x2b\x06\x01\x05\x05\x0d\x08"}, + {7, (void *)"\x2b\x06\x01\x05\x05\x0d\x09"}, + {7, (void *)"\x2b\x06\x01\x05\x05\x0d\x0a"}, + {7, (void *)"\x2b\x06\x01\x05\x05\x0d\x0b"}, + {7, (void *)"\x2b\x06\x01\x05\x05\x0d\x0c"}, + {7, (void *)"\x2b\x06\x01\x05\x05\x0d\x0d"}, + {7, (void *)"\x2b\x06\x01\x05\x05\x0d\x0e"}, + {7, (void *)"\x2b\x06\x01\x05\x05\x0d\x0f"}, + {7, (void *)"\x2b\x06\x01\x05\x05\x0d\x10"}, + {7, (void *)"\x2b\x06\x01\x05\x05\x0d\x11"}, + {7, (void *)"\x2b\x06\x01\x05\x05\x0d\x12"}, + {7, (void *)"\x2b\x06\x01\x05\x05\x0d\x13"}, + {7, (void *)"\x2b\x06\x01\x05\x05\x0d\x14"}, + {7, (void *)"\x2b\x06\x01\x05\x05\x0d\x15"}, + {7, (void *)"\x2b\x06\x01\x05\x05\x0d\x16"}, + {7, (void *)"\x2b\x06\x01\x05\x05\x0d\x17"}, + {7, (void *)"\x2b\x06\x01\x05\x05\x0d\x18"}, + {7, (void *)"\x2b\x06\x01\x05\x05\x0d\x19"}, + {7, (void *)"\x2b\x06\x01\x05\x05\x0d\x1a"}, + {7, (void *)"\x2b\x06\x01\x05\x05\x0d\x1b"}, }; /* Here are the constants which point to the static structure above. @@ -152,3 +181,234 @@ GSS_DLLIMP gss_OID GSS_C_NT_EXPORT_NAME = oids+6; gss_OID gss_nt_exported_name = oids+6; GSS_DLLIMP gss_OID GSS_C_INQ_SSPI_SESSION_KEY = oids+7; + +GSS_DLLIMP gss_const_OID GSS_C_MA_MECH_CONCRETE = oids+8; +GSS_DLLIMP gss_const_OID GSS_C_MA_MECH_PSEUDO = oids+9; +GSS_DLLIMP gss_const_OID GSS_C_MA_MECH_COMPOSITE = oids+10; +GSS_DLLIMP gss_const_OID GSS_C_MA_MECH_NEGO = oids+11; +GSS_DLLIMP gss_const_OID GSS_C_MA_MECH_GLUE = oids+12; +GSS_DLLIMP gss_const_OID GSS_C_MA_NOT_MECH = oids+13; +GSS_DLLIMP gss_const_OID GSS_C_MA_DEPRECATED = oids+14; +GSS_DLLIMP gss_const_OID GSS_C_MA_NOT_DFLT_MECH = oids+15; +GSS_DLLIMP gss_const_OID GSS_C_MA_ITOK_FRAMED = oids+16; +GSS_DLLIMP gss_const_OID GSS_C_MA_AUTH_INIT = oids+17; +GSS_DLLIMP gss_const_OID GSS_C_MA_AUTH_TARG = oids+18; +GSS_DLLIMP gss_const_OID GSS_C_MA_AUTH_INIT_INIT = oids+19; +GSS_DLLIMP gss_const_OID GSS_C_MA_AUTH_TARG_INIT = oids+20; +GSS_DLLIMP gss_const_OID GSS_C_MA_AUTH_INIT_ANON = oids+21; +GSS_DLLIMP gss_const_OID GSS_C_MA_AUTH_TARG_ANON = oids+22; +GSS_DLLIMP gss_const_OID GSS_C_MA_DELEG_CRED = oids+23; +GSS_DLLIMP gss_const_OID GSS_C_MA_INTEG_PROT = oids+24; +GSS_DLLIMP gss_const_OID GSS_C_MA_CONF_PROT = oids+25; +GSS_DLLIMP gss_const_OID GSS_C_MA_MIC = oids+26; +GSS_DLLIMP gss_const_OID GSS_C_MA_WRAP = oids+27; +GSS_DLLIMP gss_const_OID GSS_C_MA_PROT_READY = oids+28; +GSS_DLLIMP gss_const_OID GSS_C_MA_REPLAY_DET = oids+29; +GSS_DLLIMP gss_const_OID GSS_C_MA_OOS_DET = oids+30; +GSS_DLLIMP gss_const_OID GSS_C_MA_CBINDINGS = oids+31; +GSS_DLLIMP gss_const_OID GSS_C_MA_PFS = oids+32; +GSS_DLLIMP gss_const_OID GSS_C_MA_COMPRESS = oids+33; +GSS_DLLIMP gss_const_OID GSS_C_MA_CTX_TRANS = oids+34; + +static gss_OID_set_desc gss_ma_known_attrs_desc = { 27, oids+8 }; +gss_OID_set gss_ma_known_attrs = &gss_ma_known_attrs_desc; + +#define STRING_BUFFER(x) { sizeof((x) - 1), (x) } + +static struct mech_attr_info_desc { + gss_OID mech_attr; + gss_buffer_desc name; + gss_buffer_desc short_desc; + gss_buffer_desc long_desc; +} mech_attr_info[] = { + { + oids+8, + STRING_BUFFER("GSS_C_MA_MECH_CONCRETE"), + STRING_BUFFER("Mechanism is neither a pseudo-mechanism nor a " + "composite mechanism."), + }, + { + oids+9, + STRING_BUFFER("GSS_C_MA_MECH_PSEUDO"), + STRING_BUFFER("Mechanism is a pseudo-mechanism"), + }, + { + oids+10, + STRING_BUFFER("GSS_C_MA_MECH_COMPOSITE"), + STRING_BUFFER("Mechanism is a composite of other mechanisms."), + }, + { + oids+11, + STRING_BUFFER("GSS_C_MA_MECH_NEGO"), + STRING_BUFFER("Mechanism negotiates other mechanisms."), + }, + { + oids+12, + STRING_BUFFER("GSS_C_MA_MECH_GLUE"), + STRING_BUFFER("OID is not a mechanism but the GSS-API itself."), + }, + { + oids+13, + STRING_BUFFER("GSS_C_MA_NOT_MECH"), + STRING_BUFFER("Known OID but not a mechanism OID."), + }, + { + oids+14, + STRING_BUFFER("GSS_C_MA_DEPRECATED"), + STRING_BUFFER("Mechanism is deprecated."), + }, + { + oids+15, + STRING_BUFFER("GSS_C_MA_NOT_DFLT_MECH"), + STRING_BUFFER("Mechanism must not be used as a default mechanism."), + }, + { + oids+16, + STRING_BUFFER("GSS_C_MA_ITOK_FRAMED"), + STRING_BUFFER("Mechanism's initial contexts are properly framed."), + }, + { + oids+17, + STRING_BUFFER("GSS_C_MA_AUTH_INIT"), + STRING_BUFFER("Mechanism supports authentication of initiator to " + "acceptor."), + }, + { + oids+18, + STRING_BUFFER("GSS_C_MA_AUTH_TARG"), + STRING_BUFFER("Mechanism supports authentication of acceptor to " + "initiator."), + }, + { + oids+19, + STRING_BUFFER("GSS_C_MA_AUTH_INIT_INIT"), + STRING_BUFFER("Mechanism supports authentication of initiator using " + "initial credentials."), + }, + { + oids+20, + STRING_BUFFER("GSS_C_MA_AUTH_TARG_INIT"), + STRING_BUFFER("Mechanism supports authentication of acceptor using " + "initial credentials."), + }, + { + oids+21, + STRING_BUFFER("GSS_C_MA_AUTH_INIT_ANON"), + STRING_BUFFER("Mechanism supports GSS_C_NT_ANONYMOUS as an initiator " + "name."), + }, + { + oids+22, + STRING_BUFFER("GSS_C_MA_AUTH_TARG_ANON"), + STRING_BUFFER("Mechanism supports GSS_C_NT_ANONYMOUS as an acceptor " + "name."), + }, + { + oids+23, + STRING_BUFFER("GSS_C_MA_DELEG_CRED"), + STRING_BUFFER("Mechanism supports credential delegation."), + }, + { + oids+24, + STRING_BUFFER("GSS_C_MA_INTEG_PROT"), + STRING_BUFFER("Mechanism supports per-message integrity protection."), + }, + { + oids+25, + STRING_BUFFER("GSS_C_MA_CONF_PROT"), + STRING_BUFFER("Mechanism supports per-message confidentiality" + "protection."), + }, + { + oids+26, + STRING_BUFFER("GSS_C_MA_MIC"), + STRING_BUFFER("Mechanism supports Message Integrity Code (MIC) " + "tokens."), + }, + { + oids+27, + STRING_BUFFER("GSS_C_MA_WRAP"), + STRING_BUFFER("Mechanism supports wrap tokens."), + }, + { + oids+28, + STRING_BUFFER("GSS_C_MA_PROT_READY"), + STRING_BUFFER("Mechanism supports per-message proteciton prior to " + "full context establishment."), + }, + { + oids+29, + STRING_BUFFER("GSS_C_MA_REPLAY_DET"), + STRING_BUFFER("Mechanism supports replay detection."), + }, + { + oids+30, + STRING_BUFFER("GSS_C_MA_OOS_DET"), + STRING_BUFFER("Mechanism supports out-of-sequence detection."), + }, + { + oids+31, + STRING_BUFFER("GSS_C_MA_CBINDINGS"), + STRING_BUFFER("Mechanism supports channel bindings."), + }, + { + oids+32, + STRING_BUFFER("GSS_C_MA_PFS"), + STRING_BUFFER("Mechanism supports Perfect Forward Security."), + }, + { + oids+33, + STRING_BUFFER("GSS_C_MA_COMPRESS"), + STRING_BUFFER("Mechanism supports compression of data inputs to " + "gss_wrap()."), + }, + { + oids+34, + STRING_BUFFER("GSS_C_MA_CTX_TRANS"), + STRING_BUFFER("Mechanism supports security context export/import."), + }, +}; + +OM_uint32 +generic_gss_display_mech_attr( + OM_uint32 *minor_status, + gss_const_OID mech_attr, + gss_buffer_t name, + gss_buffer_t short_desc, + gss_buffer_t long_desc) +{ + size_t i; + + if (name != GSS_C_NO_BUFFER) { + name->length = 0; + name->value = NULL; + } + if (short_desc != GSS_C_NO_BUFFER) { + short_desc->length = 0; + short_desc->value = NULL; + } + if (long_desc != GSS_C_NO_BUFFER) { + long_desc->length = 0; + long_desc->value = NULL; + } + for (i = 0; i < sizeof(mech_attr_info)/sizeof(mech_attr_info[0]); i++) { + struct mech_attr_info_desc *mai = &mech_attr_info[i]; + + if (g_OID_equal(mech_attr, mai->mech_attr)) { + if (name != GSS_C_NO_BUFFER && + !g_make_string_buffer((char *)mai->name.value, name)) { + *minor_status = ENOMEM; + return GSS_S_FAILURE; + } + if (short_desc != GSS_C_NO_BUFFER && + !g_make_string_buffer((char *)mai->short_desc.value, + short_desc)) { + *minor_status = ENOMEM; + return GSS_S_FAILURE; + } + return GSS_S_COMPLETE; + } + } + + return GSS_S_BAD_MECH_ATTR; +} diff --git a/src/lib/gssapi/generic/util_buffer.c b/src/lib/gssapi/generic/util_buffer.c index cd16862f6..81d86fc76 100644 --- a/src/lib/gssapi/generic/util_buffer.c +++ b/src/lib/gssapi/generic/util_buffer.c @@ -34,6 +34,9 @@ int g_make_string_buffer(const char *str, gss_buffer_t buffer) { + if (buffer == GSS_C_NO_BUFFER) + return (1); + buffer->length = strlen(str); if ((buffer->value = strdup(str)) == NULL) { diff --git a/src/lib/gssapi/krb5/gssapi_krb5.c b/src/lib/gssapi/krb5/gssapi_krb5.c index 8b074d616..25534e56b 100644 --- a/src/lib/gssapi/krb5/gssapi_krb5.c +++ b/src/lib/gssapi/krb5/gssapi_krb5.c @@ -630,6 +630,116 @@ krb5_gssspi_mech_invoke (OM_uint32 *minor_status, return GSS_S_UNAVAILABLE; } +#define GS2_KRB5_SASL_NAME "GS2-KRB5" +#define GS2_KRB5_SASL_NAME_LEN (sizeof(GS2_KRB5_SASL_NAME) - 1) + +#define GS2_IAKERB_SASL_NAME "GS2-IAKERB" +#define GS2_IAKERB_SASL_NAME_LEN (sizeof(GS2_IAKERB_SASL_NAME) - 1) + +static OM_uint32 +krb5_gss_inquire_mech_for_saslname(OM_uint32 *minor_status, + const gss_buffer_t sasl_mech_name, + gss_OID *mech_type) +{ + *minor_status = 0; + + if (sasl_mech_name->length == GS2_KRB5_SASL_NAME_LEN && + memcmp(sasl_mech_name->value, + GS2_KRB5_SASL_NAME, GS2_KRB5_SASL_NAME_LEN) == 0) { + if (mech_type != NULL) + *mech_type = (gss_OID)gss_mech_krb5; + return GSS_S_COMPLETE; + } else if (sasl_mech_name->length == GS2_IAKERB_SASL_NAME_LEN && + memcmp(sasl_mech_name->value, + GS2_IAKERB_SASL_NAME, GS2_IAKERB_SASL_NAME_LEN) == 0) { + if (mech_type != NULL) + *mech_type = (gss_OID)gss_mech_iakerb; + return GSS_S_COMPLETE; + } + + return GSS_S_BAD_MECH; +} + +static OM_uint32 +krb5_gss_inquire_saslname_for_mech(OM_uint32 *minor_status, + const gss_OID desired_mech, + gss_buffer_t sasl_mech_name, + gss_buffer_t mech_name, + gss_buffer_t mech_description) +{ + if (g_OID_equal(desired_mech, gss_mech_iakerb)) { + if (!g_make_string_buffer(GS2_IAKERB_SASL_NAME, sasl_mech_name) || + !g_make_string_buffer("iakerb", mech_name) || + !g_make_string_buffer("Initial and Pass Through Authentication " + "Kerberos Mechanism (IAKERB)", mech_description)) + goto fail; + } else { + if (!g_make_string_buffer(GS2_KRB5_SASL_NAME, sasl_mech_name) || + !g_make_string_buffer("krb5", mech_name) || + !g_make_string_buffer("Kerberos 5 GSS-API Mechanism", + mech_description)) + goto fail; + } + + *minor_status = 0; + return GSS_S_COMPLETE; + +fail: + *minor_status = ENOMEM; + return GSS_S_FAILURE; +} + +static OM_uint32 +krb5_gss_inquire_attrs_for_mech(OM_uint32 *minor_status, + gss_const_OID mech, + gss_OID_set *mech_attrs, + gss_OID_set *known_mech_attrs) +{ + OM_uint32 major, tmpMinor; + + if (mech_attrs == NULL) { + *minor_status = 0; + return GSS_S_COMPLETE; + } + + major = gss_create_empty_oid_set(minor_status, mech_attrs); + if (GSS_ERROR(major)) + goto cleanup; + +#define MA_SUPPORTED(ma) do { \ + major = gss_add_oid_set_member(minor_status, (gss_OID)ma, mech_attrs); \ + if (GSS_ERROR(major)) \ + goto cleanup; \ + } while (0) + + MA_SUPPORTED(GSS_C_MA_MECH_CONCRETE); + MA_SUPPORTED(GSS_C_MA_ITOK_FRAMED); + MA_SUPPORTED(GSS_C_MA_AUTH_INIT); + MA_SUPPORTED(GSS_C_MA_AUTH_TARG); + MA_SUPPORTED(GSS_C_MA_DELEG_CRED); + MA_SUPPORTED(GSS_C_MA_INTEG_PROT); + MA_SUPPORTED(GSS_C_MA_CONF_PROT); + MA_SUPPORTED(GSS_C_MA_MIC); + MA_SUPPORTED(GSS_C_MA_WRAP); + MA_SUPPORTED(GSS_C_MA_PROT_READY); + MA_SUPPORTED(GSS_C_MA_REPLAY_DET); + MA_SUPPORTED(GSS_C_MA_OOS_DET); + MA_SUPPORTED(GSS_C_MA_CBINDINGS); + MA_SUPPORTED(GSS_C_MA_CTX_TRANS); + + if (g_OID_equal(mech, gss_mech_iakerb)) { + MA_SUPPORTED(GSS_C_MA_AUTH_INIT_INIT); + } else if (!g_OID_equal(mech, gss_mech_krb5)) { + MA_SUPPORTED(GSS_C_MA_DEPRECATED); + } + +cleanup: + if (GSS_ERROR(major)) + gss_release_oid_set(&tmpMinor, mech_attrs); + + return major; +} + static struct gss_config krb5_mechanism = { { GSS_MECH_KRB5_OID_LENGTH, GSS_MECH_KRB5_OID }, NULL, @@ -701,6 +811,9 @@ static struct gss_config krb5_mechanism = { krb5_gss_release_any_name_mapping, krb5_gss_pseudo_random, NULL, /* set_neg_mechs */ + krb5_gss_inquire_saslname_for_mech, + krb5_gss_inquire_mech_for_saslname, + krb5_gss_inquire_attrs_for_mech, }; static struct gss_config_ext krb5_mechanism_ext = { diff --git a/src/lib/gssapi/libgssapi_krb5.exports b/src/lib/gssapi/libgssapi_krb5.exports index 707fe52ee..fee99c994 100644 --- a/src/lib/gssapi/libgssapi_krb5.exports +++ b/src/lib/gssapi/libgssapi_krb5.exports @@ -7,6 +7,33 @@ GSS_C_NT_MACHINE_UID_NAME GSS_C_NT_STRING_UID_NAME GSS_C_NT_USER_NAME GSS_KRB5_NT_PRINCIPAL_NAME +GSS_C_MA_MECH_CONCRETE +GSS_C_MA_MECH_PSEUDO +GSS_C_MA_MECH_COMPOSITE +GSS_C_MA_MECH_NEGO +GSS_C_MA_MECH_GLUE +GSS_C_MA_NOT_MECH +GSS_C_MA_DEPRECATED +GSS_C_MA_NOT_DFLT_MECH +GSS_C_MA_ITOK_FRAMED +GSS_C_MA_AUTH_INIT +GSS_C_MA_AUTH_TARG +GSS_C_MA_AUTH_INIT_INIT +GSS_C_MA_AUTH_TARG_INIT +GSS_C_MA_AUTH_INIT_ANON +GSS_C_MA_AUTH_TARG_ANON +GSS_C_MA_DELEG_CRED +GSS_C_MA_INTEG_PROT +GSS_C_MA_CONF_PROT +GSS_C_MA_MIC +GSS_C_MA_WRAP +GSS_C_MA_PROT_READY +GSS_C_MA_REPLAY_DET +GSS_C_MA_OOS_DET +GSS_C_MA_CBINDINGS +GSS_C_MA_PFS +GSS_C_MA_COMPRESS +GSS_C_MA_CTX_TRANS gss_accept_sec_context gss_acquire_cred gss_acquire_cred_with_password @@ -23,6 +50,7 @@ gss_create_empty_buffer_set gss_create_empty_oid_set gss_delete_name_attribute gss_delete_sec_context +gss_display_mech_attr gss_display_name gss_display_name_ext gss_display_status @@ -36,12 +64,16 @@ gss_import_name gss_import_sec_context gss_indicate_mechs gss_init_sec_context +gss_indicate_mechs_by_attrs +gss_inquire_attrs_for_mech gss_inquire_context gss_inquire_cred gss_inquire_cred_by_mech gss_inquire_cred_by_oid +gss_inquire_mech_for_saslname gss_inquire_mechs_for_name gss_inquire_names_for_mech +gss_inquire_saslname_for_mech gss_inquire_sec_context_by_oid gss_krb5_ccache_name gss_krb5_copy_ccache diff --git a/src/lib/gssapi/mechglue/Makefile.in b/src/lib/gssapi/mechglue/Makefile.in index 92cd6c99c..d2dccb46b 100644 --- a/src/lib/gssapi/mechglue/Makefile.in +++ b/src/lib/gssapi/mechglue/Makefile.in @@ -42,6 +42,7 @@ SRCS = \ $(srcdir)/g_inq_names.c \ $(srcdir)/g_map_name_to_any.c \ $(srcdir)/g_mech_invoke.c \ + $(srcdir)/g_mechattr.c \ $(srcdir)/g_mechname.c \ $(srcdir)/g_oid_ops.c \ $(srcdir)/g_prf.c \ @@ -51,6 +52,7 @@ SRCS = \ $(srcdir)/g_rel_name.c \ $(srcdir)/g_rel_name_mapping.c \ $(srcdir)/g_rel_oid_set.c \ + $(srcdir)/g_saslname.c \ $(srcdir)/g_seal.c \ $(srcdir)/g_set_context_option.c \ $(srcdir)/g_set_cred_option.c \ @@ -98,6 +100,7 @@ OBJS = \ $(OUTPRE)g_inq_names.$(OBJEXT) \ $(OUTPRE)g_map_name_to_any.$(OBJEXT) \ $(OUTPRE)g_mech_invoke.$(OBJEXT) \ + $(OUTPRE)g_mechattr.$(OBJEXT) \ $(OUTPRE)g_mechname.$(OBJEXT) \ $(OUTPRE)g_oid_ops.$(OBJEXT) \ $(OUTPRE)g_prf.$(OBJEXT) \ @@ -107,6 +110,7 @@ OBJS = \ $(OUTPRE)g_rel_name.$(OBJEXT) \ $(OUTPRE)g_rel_name_mapping.$(OBJEXT) \ $(OUTPRE)g_rel_oid_set.$(OBJEXT) \ + $(OUTPRE)g_saslname.$(OBJEXT) \ $(OUTPRE)g_seal.$(OBJEXT) \ $(OUTPRE)g_set_context_option.$(OBJEXT) \ $(OUTPRE)g_set_cred_option.$(OBJEXT) \ @@ -154,6 +158,7 @@ STLIBOBJS = \ g_inq_names.o \ g_map_name_to_any.o \ g_mech_invoke.o \ + g_mechattr.o \ g_mechname.o \ g_oid_ops.o \ g_prf.o \ @@ -163,6 +168,7 @@ STLIBOBJS = \ g_rel_name.o \ g_rel_name_mapping.o \ g_rel_oid_set.o \ + g_saslname.o \ g_seal.o \ g_set_context_option.o \ g_set_cred_option.o \ diff --git a/src/lib/gssapi/mechglue/g_initialize.c b/src/lib/gssapi/mechglue/g_initialize.c index a393a5309..d8b495640 100644 --- a/src/lib/gssapi/mechglue/g_initialize.c +++ b/src/lib/gssapi/mechglue/g_initialize.c @@ -791,6 +791,11 @@ build_dynamicMech(void *dl, const gss_OID mech_type) GSS_ADD_DYNAMIC_METHOD(dl, mech, gss_pseudo_random); /* RFC 4178 (introduced in 1.8; gss_get_neg_mechs not implemented) */ GSS_ADD_DYNAMIC_METHOD(dl, mech, gss_set_neg_mechs); + /* draft-ietf-sasl-gs2 */ + GSS_ADD_DYNAMIC_METHOD(dl, mech, gss_inquire_saslname_for_mech); + GSS_ADD_DYNAMIC_METHOD(dl, mech, gss_inquire_mech_for_saslname); + /* RFC 5587 */ + GSS_ADD_DYNAMIC_METHOD(dl, mech, gss_inquire_attrs_for_mech); assert(mech_type != GSS_C_NO_OID); diff --git a/src/lib/gssapi/mechglue/g_mechattr.c b/src/lib/gssapi/mechglue/g_mechattr.c new file mode 100644 index 000000000..63ec35768 --- /dev/null +++ b/src/lib/gssapi/mechglue/g_mechattr.c @@ -0,0 +1,224 @@ +/* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */ +/* + * src/lib/gssapi/mechglue/g_mechattr.c + * + * Copyright (C) 2010 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 "mglueP.h" + +static int +testMechAttr(gss_const_OID attr, + gss_const_OID_set against) +{ + int present = 0; + OM_uint32 minor; + + if (GSS_ERROR(generic_gss_test_oid_set_member(&minor, attr, + (gss_OID_set)against, + &present))) + return 0; + + return present; +} + +/* + * Return TRUE iff all the elements of desired and none of the elements + * of except exist in available. + */ +static int +testMechAttrsOffered(gss_const_OID_set desired, + gss_const_OID_set except, + gss_const_OID_set available) +{ + size_t i; + + if (desired != GSS_C_NO_OID_SET) { + for (i = 0; i < desired->count; i++) { + if (!testMechAttr(&desired->elements[i], available)) + return 0; + } + } + + if (except != GSS_C_NO_OID_SET) { + for (i = 0; i < except->count; i++) { + if (testMechAttr(&except->elements[i], available)) + return 0; + } + } + + return 1; +} + +/* + * Return TRUE iff all the elements of critical exist in known. + */ +static int +testMechAttrsKnown(gss_const_OID_set critical, + gss_const_OID_set known) +{ + size_t i; + + if (critical != GSS_C_NO_OID_SET) { + for (i = 0; i < critical->count; i++) { + if (!testMechAttr(&critical->elements[i], known)) + return 0; + } + } + + return 1; +} + +OM_uint32 gss_indicate_mechs_by_attrs( + OM_uint32 *minor, + gss_const_OID_set desired_mech_attrs, + gss_const_OID_set except_mech_attrs, + gss_const_OID_set critical_mech_attrs, + gss_OID_set *mechs) +{ + OM_uint32 status, tmpMinor; + gss_OID_set allMechs = GSS_C_NO_OID_SET; + size_t i; + + if (minor == NULL) + return GSS_S_CALL_INACCESSIBLE_WRITE; + + *minor = 0; + + if (mechs == NULL) + return GSS_S_CALL_INACCESSIBLE_WRITE; + + *mechs = GSS_C_NO_OID_SET; + + status = gss_indicate_mechs(minor, &allMechs); + if (GSS_ERROR(status)) + goto cleanup; + + status = generic_gss_create_empty_oid_set(minor, mechs); + if (GSS_ERROR(status)) + goto cleanup; + + for (i = 0; i < allMechs->count; i++) { + gss_OID_set supportedAttrs = GSS_C_NO_OID_SET; + gss_OID_set knownAttrs = GSS_C_NO_OID_SET; + + status = gss_inquire_attrs_for_mech(minor, &allMechs->elements[i], + &supportedAttrs, &knownAttrs); + if (GSS_ERROR(status)) + continue; + + if (testMechAttrsOffered(desired_mech_attrs, + except_mech_attrs, supportedAttrs) && + testMechAttrsKnown(critical_mech_attrs, knownAttrs)) { + status = gss_add_oid_set_member(minor, &allMechs->elements[i], + mechs); + if (GSS_ERROR(status)) { + gss_release_oid_set(&tmpMinor, &supportedAttrs); + gss_release_oid_set(&tmpMinor, &knownAttrs); + goto cleanup; + } + } + + gss_release_oid_set(&tmpMinor, &supportedAttrs); + gss_release_oid_set(&tmpMinor, &knownAttrs); + } + + *minor = 0; + status = GSS_S_COMPLETE; + +cleanup: + gss_release_oid_set(&tmpMinor, &allMechs); + + return status; +} + +OM_uint32 gss_inquire_attrs_for_mech( + OM_uint32 *minor, + gss_const_OID mech_oid, + gss_OID_set *mech_attrs, + gss_OID_set *known_mech_attrs) +{ + OM_uint32 status, tmpMinor; + gss_mechanism mech; + + if (minor == NULL) + return GSS_S_CALL_INACCESSIBLE_WRITE; + + *minor = 0; + + if (mech_attrs != NULL) + *mech_attrs = GSS_C_NO_OID_SET; + + if (known_mech_attrs != NULL) + *known_mech_attrs = GSS_C_NO_OID_SET; + + mech = gssint_get_mechanism((gss_OID)mech_oid); + if (mech != NULL && mech->gss_inquire_attrs_for_mech != NULL) { + status = mech->gss_inquire_attrs_for_mech(minor, + mech_oid, + mech_attrs, + known_mech_attrs); + if (GSS_ERROR(status)) + return status; + } + + if (mech_attrs != NULL && mech != gssint_get_mechanism(NULL)) { + if (*mech_attrs == GSS_C_NO_OID_SET) { + status = generic_gss_create_empty_oid_set(minor, mech_attrs); + if (GSS_ERROR(status)) + return status; + } + + status = generic_gss_add_oid_set_member(minor, GSS_C_MA_NOT_DFLT_MECH, + mech_attrs); + if (GSS_ERROR(status)) { + gss_release_oid_set(&tmpMinor, mech_attrs); + return status; + } + } + + if (known_mech_attrs != NULL && *known_mech_attrs == GSS_C_NO_OID_SET) { + status = generic_gss_copy_oid_set(minor, + gss_ma_known_attrs, + known_mech_attrs); + if (GSS_ERROR(status)) { + gss_release_oid_set(&tmpMinor, mech_attrs); + *mech_attrs = GSS_C_NO_OID_SET; + } + } + + return GSS_S_COMPLETE; +} + +OM_uint32 gss_display_mech_attr( + OM_uint32 *minor, + gss_const_OID mech_attr, + gss_buffer_t name, + gss_buffer_t short_desc, + gss_buffer_t long_desc) +{ + return generic_gss_display_mech_attr(minor, mech_attr, + name, short_desc, long_desc); +} diff --git a/src/lib/gssapi/mechglue/g_saslname.c b/src/lib/gssapi/mechglue/g_saslname.c new file mode 100644 index 000000000..4bffdd602 --- /dev/null +++ b/src/lib/gssapi/mechglue/g_saslname.c @@ -0,0 +1,210 @@ +/* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */ +/* + * src/lib/gssapi/mechglue/g_saslname.c + * + * Copyright (C) 2010 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 "mglueP.h" +#include + +static char basis_32[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ234567"; + +#define OID_SASL_NAME_LENGTH (sizeof("GS2-XXXXXXXXXXX") - 1) + +static OM_uint32 +oidToSaslName(OM_uint32 *minor, const gss_OID mech, + char sasl_name[OID_SASL_NAME_LENGTH + 1]) +{ + unsigned char derBuf[2]; + krb5_crypto_iov iov[3]; + unsigned char cksumBuf[20], *q = cksumBuf; + char *p = sasl_name; + + if (mech->length > 127) { + *minor = ERANGE; + return GSS_S_BAD_MECH; + } + + derBuf[0] = 0x06; + derBuf[1] = (unsigned char)mech->length; + + iov[0].flags = KRB5_CRYPTO_TYPE_SIGN_ONLY; + iov[0].data.length = 2; + iov[0].data.data = (char *)derBuf; + iov[1].flags = KRB5_CRYPTO_TYPE_SIGN_ONLY; + iov[1].data.length = mech->length; + iov[1].data.data = (char *)mech->elements; + iov[2].flags = KRB5_CRYPTO_TYPE_CHECKSUM; + iov[2].data.length = sizeof(cksumBuf); + iov[2].data.data = (char *)cksumBuf; + + *minor = krb5_k_make_checksum_iov(NULL, CKSUMTYPE_NIST_SHA, + NULL, 0, iov, 3); + if (*minor != 0) + return GSS_S_FAILURE; + + memcpy(p, "GS2-", 4); + p += 4; + + *p++ = basis_32[q[0] >> 3]; + *p++ = basis_32[((q[0] & 7) << 2) | (q[1] >> 6)]; + *p++ = basis_32[(q[1] & 0x3f) >> 1]; + *p++ = basis_32[((q[1] & 1) << 4) | (q[2] >> 4)]; + *p++ = basis_32[((q[2] & 0xf) << 1) | (q[3] >> 7)]; + *p++ = basis_32[(q[3] & 0x7f) >> 2]; + *p++ = basis_32[((q[3] & 3) << 3) | (q[4] >> 5)]; + *p++ = basis_32[(q[4] & 0x1f)]; + *p++ = basis_32[q[5] >> 3]; + *p++ = basis_32[((q[5] & 7) << 2) | (q[6] >> 6)]; + *p++ = basis_32[(q[6] & 0x3f) >> 1]; + + *p++ = '\0'; + + *minor = 0; + return GSS_S_COMPLETE; +} + +static OM_uint32 +oidToSaslNameAlloc(OM_uint32 *minor, const gss_OID mech, + gss_buffer_t sasl_name) +{ + OM_uint32 status, tmpMinor; + + sasl_name->value = malloc(OID_SASL_NAME_LENGTH + 1); + if (sasl_name->value == NULL) { + *minor = ENOMEM; + return GSS_S_FAILURE; + } + sasl_name->length = OID_SASL_NAME_LENGTH; + + status = oidToSaslName(minor, mech, (char *)sasl_name->value); + if (GSS_ERROR(status)) { + gss_release_buffer(&tmpMinor, sasl_name); + return status; + } + + return GSS_S_COMPLETE; +} + +OM_uint32 KRB5_CALLCONV gss_inquire_saslname_for_mech( + OM_uint32 *minor_status, + const gss_OID desired_mech, + gss_buffer_t sasl_mech_name, + gss_buffer_t mech_name, + gss_buffer_t mech_description) +{ + OM_uint32 status = GSS_S_BAD_MECH; + gss_mechanism mech; + + if (minor_status == NULL) + return GSS_S_CALL_INACCESSIBLE_WRITE; + + *minor_status = 0; + + if (sasl_mech_name != GSS_C_NO_BUFFER) { + sasl_mech_name->length = 0; + sasl_mech_name->value = NULL; + } + + if (mech_name != GSS_C_NO_BUFFER) { + mech_name->length = 0; + mech_name->value = NULL; + } + + if (mech_description != GSS_C_NO_BUFFER) { + mech_description->length = 0; + mech_description->value = NULL; + } + + mech = gssint_get_mechanism(desired_mech); + if (mech != NULL && mech->gss_inquire_saslname_for_mech != NULL) { + status = mech->gss_inquire_saslname_for_mech(minor_status, + desired_mech, + sasl_mech_name, + mech_name, + mech_description); + } + if (status == GSS_S_BAD_MECH) { + if (sasl_mech_name != GSS_C_NO_BUFFER) + status = oidToSaslNameAlloc(minor_status, desired_mech, + sasl_mech_name); + else + status = GSS_S_COMPLETE; + } + + return status; +} + +OM_uint32 KRB5_CALLCONV gss_inquire_mech_for_saslname( + OM_uint32 *minor_status, + const gss_buffer_t sasl_mech_name, + gss_OID *mech_type) +{ + OM_uint32 status, tmpMinor; + gss_OID_set mechSet = GSS_C_NO_OID_SET; + size_t i; + + if (minor_status == NULL) + return GSS_S_CALL_INACCESSIBLE_WRITE; + + *minor_status = 0; + + if (mech_type != NULL) + *mech_type = GSS_C_NO_OID; + + status = gss_indicate_mechs(minor_status, &mechSet); + if (status != GSS_S_COMPLETE) + return status; + + for (i = 0, status = GSS_S_BAD_MECH; i < mechSet->count; i++) { + gss_mechanism mech; + char mappedName[OID_SASL_NAME_LENGTH + 1]; + + mech = gssint_get_mechanism(&mechSet->elements[i]); + if (mech != NULL && mech->gss_inquire_mech_for_saslname != NULL) { + status = mech->gss_inquire_mech_for_saslname(minor_status, + sasl_mech_name, + mech_type); + if (status == GSS_S_COMPLETE) + break; + } + if (status == GSS_S_BAD_MECH && + sasl_mech_name->length == OID_SASL_NAME_LENGTH && + oidToSaslName(&tmpMinor, &mechSet->elements[i], + mappedName) == GSS_S_COMPLETE && + memcmp(sasl_mech_name->value, mappedName, + OID_SASL_NAME_LENGTH) == 0) { + if (mech_type != NULL) + *mech_type = &mech->mech_type; + status = GSS_S_COMPLETE; + break; + } + } + + gss_release_oid_set(&tmpMinor, &mechSet); + + return status; +} diff --git a/src/lib/gssapi/mechglue/mglueP.h b/src/lib/gssapi/mechglue/mglueP.h index da427f4a6..63d89c771 100644 --- a/src/lib/gssapi/mechglue/mglueP.h +++ b/src/lib/gssapi/mechglue/mglueP.h @@ -588,6 +588,31 @@ typedef struct gss_config { gss_cred_id_t, /* cred_handle */ const gss_OID_set /* mech_set */ /* */); + + OM_uint32 (*gss_inquire_saslname_for_mech) + ( + OM_uint32 *, /* minor_status */ + const gss_OID, /* desired_mech */ + gss_buffer_t, /* sasl_mech_name */ + gss_buffer_t, /* mech_name */ + gss_buffer_t /* mech_description */ + /* */); + + OM_uint32 (*gss_inquire_mech_for_saslname) + ( + OM_uint32 *, /* minor_status */ + const gss_buffer_t, /* sasl_mech_name */ + gss_OID * /* mech_type */ + /* */); + + OM_uint32 (*gss_inquire_attrs_for_mech) + ( + OM_uint32 *, /* minor_status */ + gss_const_OID, /* mech */ + gss_OID_set *, /* mech_attrs */ + gss_OID_set * /* known_mech_attrs */ + /* */); + } *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 e146508c5..50f05678d 100644 --- a/src/lib/gssapi/spnego/gssapiP_spnego.h +++ b/src/lib/gssapi/spnego/gssapiP_spnego.h @@ -565,6 +565,33 @@ spnego_gss_set_neg_mechs const gss_OID_set mech_list ); +OM_uint32 +spnego_gss_inquire_mech_for_saslname +( + OM_uint32 *minor_status, + const gss_buffer_t sasl_mech_name, + gss_OID *mech_type +); + +OM_uint32 +spnego_gss_inquire_saslname_for_mech +( + OM_uint32 *minor_status, + const gss_OID desired_mech, + gss_buffer_t sasl_mech_name, + gss_buffer_t mech_name, + gss_buffer_t mech_description +); + +OM_uint32 +spnego_gss_inquire_attrs_for_mech +( + OM_uint32 *minor_status, + gss_const_OID mech, + gss_OID_set *mech_attrs, + gss_OID_set *known_mech_attrs +); + #ifdef __cplusplus } #endif diff --git a/src/lib/gssapi/spnego/spnego_mech.c b/src/lib/gssapi/spnego/spnego_mech.c index 9c5a6140d..d8706af92 100644 --- a/src/lib/gssapi/spnego/spnego_mech.c +++ b/src/lib/gssapi/spnego/spnego_mech.c @@ -272,6 +272,9 @@ static struct gss_config spnego_mechanism = spnego_gss_release_any_name_mapping, spnego_gss_pseudo_random, spnego_gss_set_neg_mechs, + spnego_gss_inquire_saslname_for_mech, + spnego_gss_inquire_mech_for_saslname, + spnego_gss_inquire_attrs_for_mech, }; static struct gss_config_ext spnego_mechanism_ext = @@ -2257,7 +2260,6 @@ spnego_gss_set_cred_option( gss_cred_id_t mcred; mcred = (spcred == NULL) ? GSS_C_NO_CREDENTIAL : spcred->mcred; - ret = gss_set_cred_option(minor_status, &mcred, desired_object, @@ -2279,6 +2281,23 @@ spnego_gss_set_cred_option( *cred_handle = (gss_cred_id_t)spcred; } + if (ret == GSS_S_COMPLETE && spcred == NULL) { + /* + * If the mechanism allocated a new credential handle, then + * we need to wrap it up in an SPNEGO credential handle. + */ + + spcred = malloc(sizeof(spnego_gss_cred_id_rec)); + if (spcred == NULL) { + gss_release_cred(&tmp_minor_status, &mcred); + *minor_status = ENOMEM; + return (GSS_S_FAILURE); + } + spcred->mcred = mcred; + spcred->neg_mechs = GSS_C_NULL_OID_SET; + *cred_handle = (gss_cred_id_t)spcred; + } + return (ret); } @@ -2686,6 +2705,85 @@ spnego_gss_set_neg_mechs(OM_uint32 *minor_status, return (ret); } +#define SPNEGO_SASL_NAME "SPNEGO" +#define SPNEGO_SASL_NAME_LEN (sizeof(SPNEGO_SASL_NAME) - 1) + +OM_uint32 +spnego_gss_inquire_mech_for_saslname(OM_uint32 *minor_status, + const gss_buffer_t sasl_mech_name, + gss_OID *mech_type) +{ + if (sasl_mech_name->length == SPNEGO_SASL_NAME_LEN && + memcmp(sasl_mech_name->value, SPNEGO_SASL_NAME, + SPNEGO_SASL_NAME_LEN) == 0) { + if (mech_type != NULL) + *mech_type = (gss_OID)gss_mech_spnego; + return (GSS_S_COMPLETE); + } + + return (GSS_S_BAD_MECH); +} + +OM_uint32 +spnego_gss_inquire_saslname_for_mech(OM_uint32 *minor_status, + const gss_OID desired_mech, + gss_buffer_t sasl_mech_name, + gss_buffer_t mech_name, + gss_buffer_t mech_description) +{ + *minor_status = 0; + + if (!g_OID_equal(desired_mech, gss_mech_spnego)) + return (GSS_S_BAD_MECH); + + if (!g_make_string_buffer(SPNEGO_SASL_NAME, sasl_mech_name) || + !g_make_string_buffer("spnego", mech_name) || + !g_make_string_buffer("Simple and Protected GSS-API " + "Negotiation Mechanism", mech_description)) + goto fail; + + return (GSS_S_COMPLETE); + +fail: + *minor_status = ENOMEM; + return (GSS_S_FAILURE); +} + +OM_uint32 +spnego_gss_inquire_attrs_for_mech(OM_uint32 *minor_status, + gss_const_OID mech, + gss_OID_set *mech_attrs, + gss_OID_set *known_mech_attrs) +{ + OM_uint32 major, tmpMinor; + + /* known_mech_attrs is handled by mechglue */ + *minor_status = 0; + + if (mech_attrs == NULL) + return (GSS_S_COMPLETE); + + major = gss_create_empty_oid_set(minor_status, mech_attrs); + if (GSS_ERROR(major)) + goto cleanup; + +#define MA_SUPPORTED(ma) do { \ + major = gss_add_oid_set_member(minor_status, \ + (gss_OID)ma, mech_attrs); \ + if (GSS_ERROR(major)) \ + goto cleanup; \ + } while (0) + + MA_SUPPORTED(GSS_C_MA_MECH_NEGO); + MA_SUPPORTED(GSS_C_MA_ITOK_FRAMED); + +cleanup: + if (GSS_ERROR(major)) + gss_release_oid_set(&tmpMinor, mech_attrs); + + return (major); +} + /* * 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/tests/gssapi/Makefile.in b/src/tests/gssapi/Makefile.in index 2ba81de61..4002d001e 100644 --- a/src/tests/gssapi/Makefile.in +++ b/src/tests/gssapi/Makefile.in @@ -4,11 +4,11 @@ DEFINES = -DUSE_AUTOCONF_H PROG_LIBPATH=-L$(TOPLIBD) PROG_RPATH=$(KRB5_LIBDIR) -SRCS= $(srcdir)/t_imp_name.c $(srcdir)/t_s4u.c $(srcdir)/t_namingexts.c $(srcdir)/t_gssexts.c +SRCS= $(srcdir)/t_imp_name.c $(srcdir)/t_s4u.c $(srcdir)/t_namingexts.c $(srcdir)/t_gssexts.c $(srcdir)/t_saslname.c -OBJS= t_imp_name.o t_s4u.o t_namingexts.o t_gssexts.o t_spnego.o +OBJS= t_imp_name.o t_s4u.o t_namingexts.o t_gssexts.o t_spnego.o t_saslname.o -all:: t_imp_name t_s4u t_namingexts t_gssexts t_spnego +all:: t_imp_name t_s4u t_namingexts t_gssexts t_spnego t_saslname check-pytests:: t_spnego $(RUNPYTEST) $(srcdir)/t_gssapi.py $(PYTESTFLAGS) @@ -23,7 +23,9 @@ t_gssexts: t_gssexts.o $(GSS_DEPLIBS) $(KRB5_BASE_DEPLIBS) $(CC_LINK) -o t_gssexts t_gssexts.o $(GSS_LIBS) $(KRB5_BASE_LIBS) t_spnego: t_spnego.o $(GSS_DEPLIBS) $(KRB5_BASE_DEPLIBS) $(CC_LINK) -o t_spnego t_spnego.o $(GSS_LIBS) $(KRB5_BASE_LIBS) +t_saslname: t_saslname.o $(GSS_DEPLIBS) $(KRB5_BASE_DEPLIBS) + $(CC_LINK) -o t_saslname t_saslname.o $(GSS_LIBS) $(KRB5_BASE_LIBS) clean:: - $(RM) t_imp_name t_s4u t_namingexts t_gssexts t_spnego + $(RM) t_imp_name t_s4u t_namingexts t_gssexts t_spnego t_saslname diff --git a/src/tests/gssapi/t_saslname.c b/src/tests/gssapi/t_saslname.c new file mode 100644 index 000000000..40384f7dc --- /dev/null +++ b/src/tests/gssapi/t_saslname.c @@ -0,0 +1,188 @@ +/* -*- 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 void +displayStatus_1(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(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 dumpMechAttrs(OM_uint32 *minor, gss_OID mech) +{ + OM_uint32 major, tmpMinor; + gss_OID_set mech_attrs = GSS_C_NO_OID_SET; + gss_OID_set known_attrs = GSS_C_NO_OID_SET; + size_t i; + + major = gss_inquire_attrs_for_mech(minor, mech, &mech_attrs, &known_attrs); + if (GSS_ERROR(major)) { + displayStatus("gss_inquire_attrs_for_mech", major, *minor); + return major; + } + + printf("Mech attrs: "); + + for (i = 0; i < mech_attrs->count; i++) { + gss_buffer_desc name = GSS_C_EMPTY_BUFFER; + gss_buffer_desc short_desc = GSS_C_EMPTY_BUFFER; + gss_buffer_desc long_desc = GSS_C_EMPTY_BUFFER; + + major = gss_display_mech_attr(minor, &mech_attrs->elements[i], + &name, &short_desc, &long_desc); + if (GSS_ERROR(major)) { + displayStatus("gss_display_mech_attr", major, *minor); + continue; + } + printf("%.*s ", (int)name.length, (char *)name.value); + gss_release_buffer(minor, &name); + gss_release_buffer(minor, &short_desc); + gss_release_buffer(minor, &long_desc); + } + printf("\n"); + + printf("Known attrs: "); + + for (i = 0; i < known_attrs->count; i++) { + gss_buffer_desc name = GSS_C_EMPTY_BUFFER; + gss_buffer_desc short_desc = GSS_C_EMPTY_BUFFER; + gss_buffer_desc long_desc = GSS_C_EMPTY_BUFFER; + + major = gss_display_mech_attr(minor, &known_attrs->elements[i], + &name, &short_desc, &long_desc); + if (GSS_ERROR(major)) { + displayStatus("gss_display_mech_attr", major, *minor); + continue; + } + printf("%.*s ", (int)name.length, (char *)name.value); + gss_release_buffer(minor, &name); + gss_release_buffer(minor, &short_desc); + gss_release_buffer(minor, &long_desc); + } + printf("\n"); + + gss_release_oid_set(&tmpMinor, &mech_attrs); + gss_release_oid_set(&tmpMinor, &known_attrs); + + return GSS_S_COMPLETE; +} + +int main(int argc, char *argv[]) +{ + gss_OID_set mechs; + OM_uint32 major, minor; + size_t i; + + major = gss_indicate_mechs(&minor, &mechs); + if (GSS_ERROR(major)) { + displayStatus("gss_indicate_mechs", major, minor); + return major; + } + + for (i = 0; i < mechs->count; i++) { + gss_buffer_desc oidstr = GSS_C_EMPTY_BUFFER; + gss_buffer_desc sasl_mech_name = GSS_C_EMPTY_BUFFER; + gss_buffer_desc mech_name = GSS_C_EMPTY_BUFFER; + gss_buffer_desc mech_description = GSS_C_EMPTY_BUFFER; + gss_OID oid = GSS_C_NO_OID; + + major = gss_oid_to_str(&minor, &mechs->elements[i], &oidstr); + if (GSS_ERROR(major)) + continue; + + major = gss_inquire_saslname_for_mech(&minor, &mechs->elements[i], + &sasl_mech_name, &mech_name, + &mech_description); + if (GSS_ERROR(major)) { + gss_release_buffer(&minor, &oidstr); + continue; + } + + printf("-------------------------------------------------------------" + "-----------------\n"); + printf("OID : %.*s\n", (int)oidstr.length, + (char *)oidstr.value); + printf("SASL mech : %.*s\n", (int)sasl_mech_name.length, + (char *)sasl_mech_name.value); + printf("Mech name : %.*s\n", (int)mech_name.length, + (char *)mech_name.value); + printf("Mech desc : %.*s\n", (int)mech_description.length, + (char *)mech_description.value); + dumpMechAttrs(&minor, &mechs->elements[i]); + printf("-------------------------------------------------------------" + "-----------------\n"); + + if (GSS_ERROR(gss_inquire_mech_for_saslname(&minor, &sasl_mech_name, + &oid))) { + displayStatus("gss_inquire_mech_for_saslname", major, minor); + } else if (oid == GSS_C_NO_OID || + (oid->length != mechs->elements[i].length && + memcmp(oid->elements, mechs->elements[i].elements, + oid->length) != 0)) { + gss_release_buffer(&minor, &oidstr); + (void) gss_oid_to_str(&minor, oid, &oidstr); + fprintf(stderr, "Got different OID %.*s for mechanism %.*s\n", + (int)oidstr.length, (char *)oidstr.value, + (int)sasl_mech_name.length, (char *)sasl_mech_name.value); + } + gss_release_buffer(&minor, &oidstr); + gss_release_buffer(&minor, &sasl_mech_name); + gss_release_buffer(&minor, &mech_name); + gss_release_buffer(&minor, &mech_description); + } + + gss_release_oid_set(&minor, &mechs); + + return GSS_ERROR(major) ? 1 : 0; +}