summaryrefslogtreecommitdiff
path: root/source4/auth/gensec/gensec_gssapi.c
diff options
context:
space:
mode:
Diffstat (limited to 'source4/auth/gensec/gensec_gssapi.c')
-rw-r--r--source4/auth/gensec/gensec_gssapi.c110
1 files changed, 84 insertions, 26 deletions
diff --git a/source4/auth/gensec/gensec_gssapi.c b/source4/auth/gensec/gensec_gssapi.c
index 1541c88e07..20d08078be 100644
--- a/source4/auth/gensec/gensec_gssapi.c
+++ b/source4/auth/gensec/gensec_gssapi.c
@@ -65,6 +65,7 @@ struct gensec_gssapi_state {
struct smb_krb5_context *smb_krb5_context;
struct gssapi_creds_container *client_cred;
struct gssapi_creds_container *server_cred;
+ gss_krb5_lucid_context_v1_t *lucid;
gss_cred_id_t delegated_cred_handle;
@@ -143,9 +144,45 @@ static int gensec_gssapi_destructor(struct gensec_gssapi_state *gensec_gssapi_st
if (gensec_gssapi_state->client_name != GSS_C_NO_NAME) {
maj_stat = gss_release_name(&min_stat, &gensec_gssapi_state->client_name);
}
+
+ if (gensec_gssapi_state->lucid) {
+ gss_krb5_free_lucid_sec_context(&min_stat, gensec_gssapi_state->lucid);
+ }
+
return 0;
}
+static NTSTATUS gensec_gssapi_init_lucid(struct gensec_gssapi_state *gensec_gssapi_state)
+{
+ OM_uint32 maj_stat, min_stat;
+
+ if (gensec_gssapi_state->lucid) {
+ return NT_STATUS_OK;
+ }
+
+ maj_stat = gss_krb5_export_lucid_sec_context(&min_stat,
+ &gensec_gssapi_state->gssapi_context,
+ 1,
+ (void **)&gensec_gssapi_state->lucid);
+ if (maj_stat != GSS_S_COMPLETE) {
+ DEBUG(0,("gensec_gssapi_init_lucid: %s\n",
+ gssapi_error_string(gensec_gssapi_state,
+ maj_stat, min_stat,
+ gensec_gssapi_state->gss_oid)));
+ return NT_STATUS_INTERNAL_ERROR;
+ }
+
+ if (gensec_gssapi_state->lucid->version != 1) {
+ DEBUG(0,("gensec_gssapi_init_lucid: lucid version[%d] != 1\n",
+ gensec_gssapi_state->lucid->version));
+ gss_krb5_free_lucid_sec_context(&min_stat, gensec_gssapi_state->lucid);
+ gensec_gssapi_state->lucid = NULL;
+ return NT_STATUS_INTERNAL_ERROR;
+ }
+
+ return NT_STATUS_OK;
+}
+
static NTSTATUS gensec_gssapi_start(struct gensec_security *gensec_security)
{
struct gensec_gssapi_state *gensec_gssapi_state;
@@ -169,6 +206,7 @@ static NTSTATUS gensec_gssapi_start(struct gensec_security *gensec_security)
gensec_gssapi_state->gssapi_context = GSS_C_NO_CONTEXT;
gensec_gssapi_state->server_name = GSS_C_NO_NAME;
gensec_gssapi_state->client_name = GSS_C_NO_NAME;
+ gensec_gssapi_state->lucid = NULL;
/* TODO: Fill in channel bindings */
gensec_gssapi_state->input_chan_bindings = GSS_C_NO_CHANNEL_BINDINGS;
@@ -1083,10 +1121,10 @@ static NTSTATUS gensec_gssapi_check_packet(struct gensec_security *gensec_securi
if (gensec_security->want_features & GENSEC_FEATURE_SIGN_PKT_HEADER) {
input_message.length = pdu_length;
- input_message.value = whole_pdu;
+ input_message.value = discard_const(whole_pdu);
} else {
input_message.length = length;
- input_message.value = data;
+ input_message.value = discard_const(data);
}
input_token.length = sig->length;
@@ -1139,6 +1177,31 @@ static bool gensec_gssapi_have_feature(struct gensec_security *gensec_security,
if (feature & GENSEC_FEATURE_DCE_STYLE) {
return gensec_gssapi_state->got_flags & GSS_C_DCE_STYLE;
}
+ if (feature & GENSEC_FEATURE_NEW_SPNEGO) {
+ NTSTATUS status;
+
+ if (!(gensec_gssapi_state->got_flags & GSS_C_INTEG_FLAG)) {
+ return false;
+ }
+
+ if (lp_parm_bool(gensec_security->lp_ctx, NULL, "gensec_gssapi", "force_new_spnego", false)) {
+ return true;
+ }
+ if (lp_parm_bool(gensec_security->lp_ctx, NULL, "gensec_gssapi", "disable_new_spnego", false)) {
+ return false;
+ }
+
+ status = gensec_gssapi_init_lucid(gensec_gssapi_state);
+ if (!NT_STATUS_IS_OK(status)) {
+ return false;
+ }
+
+ if (gensec_gssapi_state->lucid->protocol == 1) {
+ return true;
+ }
+
+ return false;
+ }
/* We can always do async (rather than strict request/reply) packets. */
if (feature & GENSEC_FEATURE_ASYNC_REPLIES) {
return true;
@@ -1165,20 +1228,24 @@ static NTSTATUS gensec_gssapi_session_key(struct gensec_security *gensec_securit
return NT_STATUS_OK;
}
- maj_stat = gsskrb5_get_initiator_subkey(&min_stat,
- gensec_gssapi_state->gssapi_context,
- &subkey);
+ maj_stat = gsskrb5_get_subkey(&min_stat,
+ gensec_gssapi_state->gssapi_context,
+ &subkey);
if (maj_stat != 0) {
DEBUG(1, ("NO session key for this mech\n"));
return NT_STATUS_NO_USER_SESSION_KEY;
}
- DEBUG(10, ("Got KRB5 session key of length %d\n",
- (int)KRB5_KEY_LENGTH(subkey)));
- gensec_gssapi_state->session_key = data_blob_talloc(gensec_gssapi_state,
- KRB5_KEY_DATA(subkey), KRB5_KEY_LENGTH(subkey));
+ DEBUG(10, ("Got KRB5 session key of length %d%s\n",
+ (int)KRB5_KEY_LENGTH(subkey),
+ (gensec_gssapi_state->sasl_state == STAGE_DONE)?" (done)":""));
+ *session_key = data_blob_talloc(gensec_gssapi_state,
+ KRB5_KEY_DATA(subkey), KRB5_KEY_LENGTH(subkey));
krb5_free_keyblock(gensec_gssapi_state->smb_krb5_context->krb5_context, subkey);
- *session_key = gensec_gssapi_state->session_key;
+ if (gensec_gssapi_state->sasl_state == STAGE_DONE) {
+ /* only cache in the done stage */
+ gensec_gssapi_state->session_key = *session_key;
+ }
dump_data_pw("KRB5 Session Key:\n", session_key->data, session_key->length);
return NT_STATUS_OK;
@@ -1386,8 +1453,7 @@ size_t gensec_gssapi_sig_size(struct gensec_security *gensec_security, size_t da
{
struct gensec_gssapi_state *gensec_gssapi_state
= talloc_get_type(gensec_security->private_data, struct gensec_gssapi_state);
- OM_uint32 maj_stat, min_stat;
- gss_krb5_lucid_context_v1_t *lucid = NULL;
+ NTSTATUS status;
if (gensec_gssapi_state->sig_size) {
return gensec_gssapi_state->sig_size;
@@ -1399,29 +1465,23 @@ size_t gensec_gssapi_sig_size(struct gensec_security *gensec_security, size_t da
gensec_gssapi_state->sig_size = 37;
}
- maj_stat = gss_krb5_export_lucid_sec_context(&min_stat,
- &gensec_gssapi_state->gssapi_context,
- 1, (void **)&lucid);
- if (maj_stat != GSS_S_COMPLETE) {
- return gensec_gssapi_state->sig_size;
- }
-
- if (lucid->version != 1) {
+ status = gensec_gssapi_init_lucid(gensec_gssapi_state);
+ if (!NT_STATUS_IS_OK(status)) {
return gensec_gssapi_state->sig_size;
}
- if (lucid->protocol == 1) {
+ if (gensec_gssapi_state->lucid->protocol == 1) {
if (gensec_gssapi_state->got_flags & GSS_C_CONF_FLAG) {
/*
* TODO: windows uses 76 here, but we don't know
* gss_wrap works with aes keys yet
*/
- gensec_gssapi_state->sig_size = 60;
+ gensec_gssapi_state->sig_size = 76;
} else {
gensec_gssapi_state->sig_size = 28;
}
- } else if (lucid->protocol == 0) {
- switch (lucid->rfc1964_kd.ctx_key.type) {
+ } else if (gensec_gssapi_state->lucid->protocol == 0) {
+ switch (gensec_gssapi_state->lucid->rfc1964_kd.ctx_key.type) {
case KEYTYPE_DES:
case KEYTYPE_ARCFOUR:
case KEYTYPE_ARCFOUR_56:
@@ -1441,8 +1501,6 @@ size_t gensec_gssapi_sig_size(struct gensec_security *gensec_security, size_t da
}
}
- gss_krb5_free_lucid_sec_context(&min_stat, lucid);
-
return gensec_gssapi_state->sig_size;
}