summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSimo Sorce <simo@redhat.com>2014-05-05 17:05:50 -0400
committerSimo Sorce <simo@redhat.com>2014-05-05 17:05:50 -0400
commitbdb7be8468140550b59d1ec6694130f51ba9a799 (patch)
treee797f81b6f8336ccfdec1e4c28635e2a313b57ad
parent2d7f4ec84126d88b66eed5a06d20d980f88c5b67 (diff)
downloadgss-ntlmssp-bdb7be8468140550b59d1ec6694130f51ba9a799.tar.gz
gss-ntlmssp-bdb7be8468140550b59d1ec6694130f51ba9a799.tar.xz
gss-ntlmssp-bdb7be8468140550b59d1ec6694130f51ba9a799.zip
Add way to talk about MIC with SPNEGO
As agreed with MIT people, add an inquire mechanism that serves 2 roles. On the one hand, if the spnego mechanism makes this call at all it means it is recent enough to support forcing the mechlistMIC on if we create an Authenticate message MIC. So remove the environment variable and instead depend on the SPNEGO layer to call this function before the Authenticate token is generated (usually right after the Negotiate token has been produced). On the other hand if this function has been called assume SPNEGO will call again right after the authenticate message has been genrated to know whether the mechlistMIC needs to be added.
-rw-r--r--src/gss_ntlmssp.c4
-rw-r--r--src/gss_ntlmssp.h11
-rw-r--r--src/gss_sec_ctx.c74
-rw-r--r--src/gss_serialize.c6
-rw-r--r--src/gss_spi.c11
-rw-r--r--src/gssapi_ntlmssp.h12
6 files changed, 106 insertions, 12 deletions
diff --git a/src/gss_ntlmssp.c b/src/gss_ntlmssp.c
index 7246359..180909b 100644
--- a/src/gss_ntlmssp.c
+++ b/src/gss_ntlmssp.c
@@ -70,7 +70,9 @@ uint32_t gssntlm_context_is_valid(struct gssntlm_ctx *ctx, time_t *time_now)
time_t now;
if (!ctx) return GSS_S_NO_CONTEXT;
- if (!ctx->established) return GSS_S_NO_CONTEXT;
+ if (!(ctx->int_flags & NTLMSSP_CTX_FLAG_ESTABLISHED)) {
+ return GSS_S_NO_CONTEXT;
+ }
now = time(NULL);
if (now > ctx->expiration_time) return GSS_S_CONTEXT_EXPIRED;
diff --git a/src/gss_ntlmssp.h b/src/gss_ntlmssp.h
index c25cb52..194e954 100644
--- a/src/gss_ntlmssp.h
+++ b/src/gss_ntlmssp.h
@@ -61,6 +61,10 @@
NTLMSSP_NEGOTIATE_OEM | \
NTLMSSP_NEGOTIATE_UNICODE)
+#define NTLMSSP_CTX_FLAG_ESTABLISHED 0x01 /* context was established */
+#define NTLMSSP_CTX_FLAG_SPNEGO_CAN_MIC 0x02 /* SPNEGO asks for MIC */
+#define NTLMSSP_CTX_FLAG_AUTH_WITH_MIC 0x04 /* Auth MIC was created */
+
struct gssntlm_name {
enum ntlm_name_type {
GSSNTLM_NAME_NULL,
@@ -150,7 +154,7 @@ struct gssntlm_ctx {
struct gssntlm_signseal send;
struct gssntlm_signseal recv;
- bool established;
+ uint32_t int_flags;
time_t expiration_time;
};
@@ -262,6 +266,11 @@ uint32_t gssntlm_set_sec_context_option(uint32_t *minor_status,
const gss_OID desired_object,
const gss_buffer_t value);
+uint32_t gssntlm_inquire_sec_context_by_oid(uint32_t *minor_status,
+ const gss_ctx_id_t context_handle,
+ const gss_OID desired_object,
+ gss_buffer_set_t *data_set);
+
uint32_t gssntlm_get_mic(uint32_t *minor_status,
gss_ctx_id_t context_handle,
gss_qop_t qop_req,
diff --git a/src/gss_sec_ctx.c b/src/gss_sec_ctx.c
index 9836ac2..c682b14 100644
--- a/src/gss_sec_ctx.c
+++ b/src/gss_sec_ctx.c
@@ -434,7 +434,6 @@ uint32_t gssntlm_init_sec_context(uint32_t *minor_status,
if (target_info.length > 0) {
bool *add_mic_ptr = NULL;
- const char *envvar;
if (input_chan_bindings != GSS_C_NO_CHANNEL_BINDINGS) {
if (input_chan_bindings->initiator_addrtype != 0 ||
@@ -451,9 +450,7 @@ uint32_t gssntlm_init_sec_context(uint32_t *minor_status,
}
if (protect) {
- envvar = getenv("NTLMSSP_ENABLE_MIC");
- if ((envvar != NULL) &&
- (strcasecmp(envvar, "1") == 0)) {
+ if (ctx->int_flags & NTLMSSP_CTX_FLAG_SPNEGO_CAN_MIC) {
add_mic_ptr = &add_mic;
}
}
@@ -666,6 +663,9 @@ uint32_t gssntlm_init_sec_context(uint32_t *minor_status,
}
/* now that we have the mic, copy it into the auth message */
memcpy(auth_mic.data, mic.data, 16);
+
+ /* Make sure SPNEGO gets to know it has to add mechlistMIC too */
+ ctx->int_flags |= NTLMSSP_CTX_FLAG_AUTH_WITH_MIC;
}
ctx->stage = NTLMSSP_STAGE_DONE;
@@ -681,7 +681,7 @@ uint32_t gssntlm_init_sec_context(uint32_t *minor_status,
/* For now use the same as the challenge/response lifetime (36h) */
ctx->expiration_time = time(NULL) + MAX_CHALRESP_LIFETIME;
- ctx->established = true;
+ ctx->int_flags |= NTLMSSP_CTX_FLAG_ESTABLISHED;
retmaj = GSS_S_COMPLETE;
}
@@ -1344,7 +1344,7 @@ uint32_t gssntlm_accept_sec_context(uint32_t *minor_status,
ctx->stage = NTLMSSP_STAGE_DONE;
ctx->expiration_time = time(NULL) + MAX_CHALRESP_LIFETIME;
- ctx->established = true;
+ ctx->int_flags |= NTLMSSP_CTX_FLAG_ESTABLISHED;
retmaj = GSS_S_COMPLETE;
}
@@ -1422,7 +1422,7 @@ uint32_t gssntlm_inquire_context(uint32_t *minor_status,
}
}
- if (ctx->established) {
+ if (ctx->int_flags & NTLMSSP_CTX_FLAG_ESTABLISHED) {
if (lifetime_rec) {
now = time(NULL);
if (ctx->expiration_time > now) {
@@ -1493,3 +1493,63 @@ uint32_t gssntlm_set_sec_context_option(uint32_t *minor_status,
*minor_status = EINVAL;
return GSS_S_UNAVAILABLE;
}
+
+gss_OID_desc spnego_req_mic_oid = {
+ GSS_SPNEGO_REQUIRE_MIC_OID_LENGTH,
+ GSS_SPNEGO_REQUIRE_MIC_OID_STRING
+};
+
+uint32_t gssntlm_inquire_sec_context_by_oid(uint32_t *minor_status,
+ const gss_ctx_id_t context_handle,
+ const gss_OID desired_object,
+ gss_buffer_set_t *data_set)
+{
+ struct gssntlm_ctx *ctx;
+ gss_buffer_desc mic_buf;
+ uint32_t maj, min;
+ uint8_t mic_set;
+
+ if (minor_status == NULL) {
+ return GSS_S_CALL_INACCESSIBLE_WRITE;
+ }
+
+ *minor_status = 0;
+
+ if (context_handle == NULL) {
+ return GSS_S_CALL_INACCESSIBLE_READ;
+ }
+
+ ctx = (struct gssntlm_ctx *)context_handle;
+
+ if (desired_object == GSS_C_NO_OID) {
+ return GSS_S_CALL_INACCESSIBLE_READ;
+ }
+
+ *data_set = GSS_C_NO_BUFFER_SET;
+
+ /* the simple fact the spnego layer is asking means it can handle
+ * forcing mechlistMIC if we add a MIC to the Authenticate packet.
+ * We expect this to be called before the authenticate token is
+ * generated to set this flag ... */
+ ctx->int_flags |= NTLMSSP_CTX_FLAG_SPNEGO_CAN_MIC;
+
+ /* ... and then again after, in which case if we actually did add
+ * a MIC we can tell spnego to add a mechlistMIC */
+ if (ctx->int_flags & NTLMSSP_CTX_FLAG_AUTH_WITH_MIC) {
+ mic_set = 1;
+ } else {
+ mic_set = 0;
+ }
+
+ mic_buf.value = &mic_set;
+ mic_buf.length = sizeof(mic_set);
+
+ maj = gss_add_buffer_set_member(&min, &mic_buf, data_set);
+ if (maj != GSS_S_COMPLETE) {
+ *minor_status = min;
+ (void)gss_release_buffer_set(&min, data_set);
+ return maj;
+ }
+
+ return GSS_S_COMPLETE;
+}
diff --git a/src/gss_serialize.c b/src/gss_serialize.c
index 9ea02f4..6b137ce 100644
--- a/src/gss_serialize.c
+++ b/src/gss_serialize.c
@@ -67,7 +67,7 @@ struct export_ctx {
struct export_keys send;
struct export_keys recv;
- uint8_t established;
+ uint8_t int_flags;
uint64_t expration_time;
uint8_t data[];
@@ -378,7 +378,7 @@ uint32_t gssntlm_export_sec_context(uint32_t *minor_status,
ret = export_keys(&state, &ctx->recv, &ectx->recv);
if (ret) goto done;
- ectx->established = ctx->established ? 1 : 0;
+ ectx->int_flags = ctx->int_flags;
expiration = ctx->expiration_time;
ectx->expration_time = htole64(expiration);
@@ -707,7 +707,7 @@ uint32_t gssntlm_import_sec_context(uint32_t *minor_status,
maj = import_keys(minor_status, &state, &ectx->recv, &ctx->recv);
if (maj != GSS_S_COMPLETE) goto done;
- ctx->established = (ectx->established == 1) ? true : false;
+ ctx->int_flags = ectx->int_flags;
time = le64toh(ectx->expration_time);
ctx->expiration_time = time;
diff --git a/src/gss_spi.c b/src/gss_spi.c
index bc681e9..a74bace 100644
--- a/src/gss_spi.c
+++ b/src/gss_spi.c
@@ -297,6 +297,17 @@ OM_uint32 gss_set_sec_context_option(OM_uint32 *minor_status,
value);
}
+OM_uint32 gss_inquire_sec_context_by_oid(OM_uint32 *minor_status,
+ const gss_ctx_id_t context_handle,
+ const gss_OID desired_object,
+ gss_buffer_set_t *data_set)
+{
+ return gssntlm_inquire_sec_context_by_oid(minor_status,
+ context_handle,
+ desired_object,
+ data_set);
+}
+
OM_uint32 gss_inquire_cred(OM_uint32 *minor_status,
gss_cred_id_t cred_handle,
gss_name_t *name,
diff --git a/src/gssapi_ntlmssp.h b/src/gssapi_ntlmssp.h
index f34230f..2aae434 100644
--- a/src/gssapi_ntlmssp.h
+++ b/src/gssapi_ntlmssp.h
@@ -47,6 +47,18 @@ extern "C" {
#define GSS_NTLMSSP_SET_SEQ_NUM_OID_STRING GSS_NTLMSSP_BASE_OID_STRING "\x01"
#define GSS_NTLMSSP_SET_SEQ_NUM_OID_LENGTH GSS_NTLMSSP_BASE_OID_LENGTH + 1
+/* SPNEGO Require MIC OID
+ * When the NTLMSSP mechanism produces a MIC in the authenticate message,
+ * the SPNEGO mechanism also must produce a mechlistMIC token otherwise
+ * Windows servers get confused and fail the authentication.
+ * This OID is queried by the SPNEGO mechanism after each token is generated.
+ * After the Negotiate token is produced, a query for this context property
+ * signals us that the SPNEGO implementation knows how to deal with the MIC,
+ * After the Authenticate token is produced we return whether a MIC was
+ * produced or not */
+#define GSS_SPNEGO_REQUIRE_MIC_OID_STRING GSS_NTLMSSP_BASE_OID_STRING "\x02"
+#define GSS_SPNEGO_REQUIRE_MIC_OID_LENGTH GSS_NTLMSSP_BASE_OID_LENGTH + 1
+
#define GSS_NTLMSSP_CS_DOMAIN "ntlmssp_domain"
#define GSS_NTLMSSP_CS_NTHASH "ntlmssp_nthash"
#define GSS_NTLMSSP_CS_PASSWORD "ntlmssp_password"