summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSimo Sorce <simo@redhat.com>2014-08-04 16:28:13 -0400
committerSimo Sorce <simo@redhat.com>2014-08-07 12:44:46 -0400
commitc6cfa7da62273ede9902c765748ba899861fde56 (patch)
tree8df8d0c3b99c407b308f49fa13701f21fee4e54f
parente212afb93ad332ae773a387ff66052b2ebdaa6d8 (diff)
downloadgss-ntlmssp-c6cfa7da62273ede9902c765748ba899861fde56.tar.gz
gss-ntlmssp-c6cfa7da62273ede9902c765748ba899861fde56.tar.xz
gss-ntlmssp-c6cfa7da62273ede9902c765748ba899861fde56.zip
Move client auth bits to gss_auth
This will makes it easier to plug in external auth handlers like winbind.
-rw-r--r--src/gss_auth.c290
-rw-r--r--src/gss_ntlmssp.h6
-rw-r--r--src/gss_sec_ctx.c274
3 files changed, 304 insertions, 266 deletions
diff --git a/src/gss_auth.c b/src/gss_auth.c
index 710099f..6103ba9 100644
--- a/src/gss_auth.c
+++ b/src/gss_auth.c
@@ -1,8 +1,298 @@
/* Copyright (C) 2014 GSS-NTLMSSP contributors, see COPYING for License */
#include <errno.h>
+#include <string.h>
#include "gss_ntlmssp.h"
+
+uint32_t gssntlm_cli_auth(uint32_t *minor,
+ struct gssntlm_ctx *ctx,
+ struct gssntlm_cred *cred,
+ struct ntlm_buffer *target_info,
+ uint32_t in_flags,
+ gss_channel_bindings_t input_chan_bindings)
+{
+ struct ntlm_buffer nt_chal_resp = { 0 };
+ struct ntlm_buffer lm_chal_resp = { 0 };
+ struct ntlm_buffer client_target_info = { 0 };
+ struct ntlm_key key_exchange_key = { .length = 16 };
+ struct ntlm_key encrypted_random_session_key = { .length = 16 };
+ struct ntlm_buffer enc_sess_key = { 0 };
+ struct ntlm_buffer auth_mic = { NULL, 16 };
+ uint8_t micbuf[16];
+ struct ntlm_buffer mic = { micbuf, 16 };
+ bool add_mic = false;
+ bool key_exch;
+ uint32_t retmaj = GSS_S_FAILURE;
+ uint32_t retmin = 0;
+
+ switch (cred->type) {
+
+ case GSSNTLM_CRED_USER:
+
+ if (ctx->gss_flags & GSS_C_ANON_FLAG) {
+ /* Anonymous auth, empty responses */
+ memset(&nt_chal_resp, 0, sizeof(nt_chal_resp));
+ lm_chal_resp.data = malloc(1);
+ if (!lm_chal_resp.data) {
+ retmin = ENOMEM;
+ retmaj = GSS_S_FAILURE;
+ goto done;
+ }
+ lm_chal_resp.data[0] = 0;
+ lm_chal_resp.length = 1;
+
+ } else if (ctx->sec_req & SEC_V2_ONLY) {
+
+ /* ### NTLMv2 ### */
+ uint8_t client_chal[8];
+ struct ntlm_buffer cli_chal = { client_chal, 8 };
+ struct ntlm_key ntlmv2_key = { .length = 16 };
+ struct ntlm_buffer nt_proof = { 0 };
+ struct ntlm_buffer cb = { 0 };
+ uint64_t srv_time = 0;
+
+ if (target_info->length == 0 &&
+ input_chan_bindings != GSS_C_NO_CHANNEL_BINDINGS) {
+ retmaj = GSS_S_UNAVAILABLE;
+ goto done;
+ }
+
+ if (target_info->length > 0) {
+ bool *add_mic_ptr = NULL;
+ bool protect;
+
+ if (input_chan_bindings != GSS_C_NO_CHANNEL_BINDINGS) {
+ if (input_chan_bindings->initiator_addrtype != 0 ||
+ input_chan_bindings->initiator_address.length != 0 ||
+ input_chan_bindings->acceptor_addrtype != 0 ||
+ input_chan_bindings->acceptor_address.length != 0 ||
+ input_chan_bindings->application_data.length == 0) {
+ retmin = EINVAL;
+ retmaj = GSS_S_BAD_BINDINGS;
+ goto done;
+ }
+ cb.length = input_chan_bindings->application_data.length;
+ cb.data = input_chan_bindings->application_data.value;
+ }
+
+ protect = in_flags & (NTLMSSP_NEGOTIATE_SIGN
+ | NTLMSSP_NEGOTIATE_SEAL);
+ if (protect) {
+ if (ctx->int_flags & NTLMSSP_CTX_FLAG_SPNEGO_CAN_MIC) {
+ add_mic_ptr = &add_mic;
+ }
+ }
+
+ retmin = ntlm_process_target_info(
+ ctx->ntlm, protect, target_info,
+ ctx->target_name.data.server.name,
+ &cb, &client_target_info,
+ &srv_time, add_mic_ptr);
+ if (retmin) {
+ if (retmin == ERR_DECODE) {
+ retmaj = GSS_S_DEFECTIVE_TOKEN;
+ } else {
+ retmaj = GSS_S_FAILURE;
+ }
+ goto done;
+ }
+
+ if (srv_time != 0) {
+ long int tdiff;
+ tdiff = ntlm_timestamp_now() - srv_time;
+ if ((tdiff / 10000000) > MAX_CHALRESP_LIFETIME) {
+ retmin = EINVAL;
+ retmaj = GSS_S_CONTEXT_EXPIRED;
+ goto done;
+ }
+ }
+ }
+
+ /* Random client challenge */
+ retmin = RAND_BUFFER(&cli_chal);
+ if (retmin) {
+ retmaj = GSS_S_FAILURE;
+ goto done;
+ }
+
+ /* NTLMv2 Key */
+ retmin = NTOWFv2(ctx->ntlm, &cred->cred.user.nt_hash,
+ cred->cred.user.user.data.user.name,
+ cred->cred.user.user.data.user.domain,
+ &ntlmv2_key);
+ if (retmin) {
+ retmaj = GSS_S_FAILURE;
+ goto done;
+ }
+
+ /* NTLMv2 Response */
+ retmin = ntlmv2_compute_nt_response(&ntlmv2_key,
+ ctx->server_chal, client_chal,
+ srv_time, &client_target_info,
+ &nt_chal_resp);
+ if (retmin) {
+ retmaj = GSS_S_FAILURE;
+ goto done;
+ }
+
+ if (target_info->length == 0) {
+ /* LMv2 Response
+ * (only sent if challenge response has no target_info) */
+ retmin = ntlmv2_compute_lm_response(&ntlmv2_key,
+ ctx->server_chal,
+ client_chal,
+ &lm_chal_resp);
+ if (retmin) {
+ retmaj = GSS_S_FAILURE;
+ goto done;
+ }
+ }
+
+ /* The NT proof is the first 16 bytes */
+ nt_proof.data = nt_chal_resp.data;
+ nt_proof.length = 16;
+
+ /* The Session Base Key */
+ /* In NTLMv2 the Key Exchange Key is the Session Base Key */
+ retmin = ntlmv2_session_base_key(&ntlmv2_key, &nt_proof,
+ &key_exchange_key);
+ if (retmin) {
+ retmaj = GSS_S_FAILURE;
+ goto done;
+ }
+ } else {
+ /* ### NTLMv1 ### */
+ uint8_t client_chal[8];
+ uint8_t nt_resp_buf[24];
+ uint8_t lm_resp_buf[24];
+ struct ntlm_buffer cli_chal = { client_chal, 8 };
+ struct ntlm_buffer nt_response = { nt_resp_buf, 24 };
+ struct ntlm_buffer lm_response = { lm_resp_buf, 24 };
+ struct ntlm_key session_base_key = { .length = 16 };
+ bool NoLMResponseNTLMv1 = true; /* FIXME: get from conf/env */
+ bool ext_sec;
+
+ /* Random client challenge */
+ retmin = RAND_BUFFER(&cli_chal);
+ if (retmin) {
+ retmaj = GSS_S_FAILURE;
+ goto done;
+ }
+
+ ext_sec = (in_flags & NTLMSSP_NEGOTIATE_EXTENDED_SESSIONSECURITY);
+
+ retmin = ntlm_compute_nt_response(&cred->cred.user.nt_hash,
+ ext_sec, ctx->server_chal,
+ client_chal, &nt_response);
+ if (retmin) {
+ retmaj = GSS_S_FAILURE;
+ goto done;
+ }
+
+ if (!ext_sec && NoLMResponseNTLMv1) {
+ memcpy(lm_response.data, nt_response.data, 24);
+ } else {
+ retmin = ntlm_compute_lm_response(&cred->cred.user.lm_hash,
+ ext_sec, ctx->server_chal,
+ client_chal, &lm_response);
+ if (retmin) {
+ retmaj = GSS_S_FAILURE;
+ goto done;
+ }
+ }
+
+ retmin = ntlm_session_base_key(&cred->cred.user.nt_hash,
+ &session_base_key);
+ if (retmin) {
+ retmaj = GSS_S_FAILURE;
+ goto done;
+ }
+
+ retmin = KXKEY(ctx->ntlm, ext_sec,
+ (in_flags & NTLMSSP_NEGOTIATE_LM_KEY),
+ (in_flags & NTLMSSP_REQUEST_NON_NT_SESSION_KEY),
+ ctx->server_chal, &cred->cred.user.lm_hash,
+ &session_base_key, &lm_response, &key_exchange_key);
+ if (retmin) {
+ retmaj = GSS_S_FAILURE;
+ goto done;
+ }
+ }
+
+ key_exch = (in_flags & NTLMSSP_NEGOTIATE_KEY_EXCH);
+
+ retmin = ntlm_exported_session_key(&key_exchange_key, key_exch,
+ &ctx->exported_session_key);
+ if (retmin) {
+ retmaj = GSS_S_FAILURE;
+ goto done;
+ }
+
+ if (key_exch) {
+ retmin = ntlm_encrypted_session_key(&key_exchange_key,
+ &ctx->exported_session_key,
+ &encrypted_random_session_key);
+ if (retmin) {
+ retmaj = GSS_S_FAILURE;
+ goto done;
+ }
+ }
+
+ /* in_flags all verified, assign as current flags */
+ ctx->neg_flags |= in_flags;
+
+ enc_sess_key.data = encrypted_random_session_key.data;
+ enc_sess_key.length = encrypted_random_session_key.length;
+
+ retmin = ntlm_encode_auth_msg(ctx->ntlm, ctx->neg_flags,
+ &lm_chal_resp, &nt_chal_resp,
+ cred->cred.user.user.data.user.domain,
+ cred->cred.user.user.data.user.name,
+ ctx->workstation, &enc_sess_key,
+ add_mic ? &auth_mic : NULL,
+ &ctx->auth_msg);
+ if (retmin) {
+ retmaj = GSS_S_FAILURE;
+ goto done;
+ }
+
+ /* Now we need to calculate the MIC, because the MIC is part of the
+ * message it protects, ntlm_encode_auth_msg() always add a zeroeth
+ * buffer, however it returns in data_mic the pointer to the actual
+ * area in the auth_msg that points at the mic, so we can backfill */
+ if (add_mic) {
+ retmin = ntlm_mic(&ctx->exported_session_key, &ctx->nego_msg,
+ &ctx->chal_msg, &ctx->auth_msg, &mic);
+ if (retmin) {
+ retmaj = GSS_S_FAILURE;
+ goto done;
+ }
+ /* 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;
+ }
+
+ retmin = 0;
+ retmaj = GSS_S_COMPLETE;
+ break;
+
+ default:
+ retmin = EINVAL;
+ retmaj = GSS_S_FAILURE;
+ }
+
+done:
+ ntlm_free_buffer_data(&client_target_info);
+ ntlm_free_buffer_data(&nt_chal_resp);
+ ntlm_free_buffer_data(&lm_chal_resp);
+ *minor = retmin;
+ return retmaj;
+}
+
+
uint32_t gssntlm_srv_auth(uint32_t *minor,
struct gssntlm_ctx *ctx,
struct gssntlm_cred *cred,
diff --git a/src/gss_ntlmssp.h b/src/gss_ntlmssp.h
index 08401b0..964483b 100644
--- a/src/gss_ntlmssp.h
+++ b/src/gss_ntlmssp.h
@@ -182,6 +182,12 @@ uint32_t external_srv_auth(char *user, char *domain,
uint32_t netbios_get_names(char *computer_name,
char **netbios_host, char **netbios_domain);
+uint32_t gssntlm_cli_auth(uint32_t *minor,
+ struct gssntlm_ctx *ctx,
+ struct gssntlm_cred *cred,
+ struct ntlm_buffer *target_info,
+ uint32_t in_flags,
+ gss_channel_bindings_t input_chan_bindings);
uint32_t gssntlm_srv_auth(uint32_t *minor,
struct gssntlm_ctx *ctx,
struct gssntlm_cred *cred,
diff --git a/src/gss_sec_ctx.c b/src/gss_sec_ctx.c
index 3fe0b36..3f8d569 100644
--- a/src/gss_sec_ctx.c
+++ b/src/gss_sec_ctx.c
@@ -48,28 +48,12 @@ uint32_t gssntlm_init_sec_context(uint32_t *minor_status,
uint32_t in_flags;
uint32_t msg_type;
char *trgt_name = NULL;
- uint8_t server_chal[8];
- struct ntlm_buffer challenge = { server_chal, 8 };
+ struct ntlm_buffer challenge = { 0 };
struct ntlm_buffer target_info = { 0 };
- struct ntlm_buffer client_target_info = { 0 };
- const char *server_name = NULL;
- struct ntlm_buffer cb = { 0 };
- uint64_t srv_time = 0;
- struct ntlm_buffer nt_chal_resp = { 0 };
- struct ntlm_buffer lm_chal_resp = { 0 };
- struct ntlm_buffer enc_sess_key = { 0 };
- struct ntlm_key encrypted_random_session_key = { .length = 16 };
- struct ntlm_key key_exchange_key = { .length = 16 };
- struct ntlm_buffer auth_mic = { NULL, 16 };
- uint8_t micbuf[16];
- struct ntlm_buffer mic = { micbuf, 16 };
int lm_compat_lvl;
uint32_t tmpmin;
uint32_t retmin = 0;
uint32_t retmaj = 0;
- bool key_exch;
- bool add_mic = false;
- bool protect;
ctx = (struct gssntlm_ctx *)(*context_handle);
@@ -326,6 +310,9 @@ uint32_t gssntlm_init_sec_context(uint32_t *minor_status,
goto done;
}
+ /* store challenge in ctx */
+ challenge.data = ctx->server_chal;
+ challenge.length = 8;
retmin = ntlm_decode_chal_msg(ctx->ntlm, &ctx->chal_msg, &in_flags,
&trgt_name, &challenge, &target_info);
if (retmin) {
@@ -393,253 +380,11 @@ uint32_t gssntlm_init_sec_context(uint32_t *minor_status,
in_flags &= ~NTLMSSP_NEGOTIATE_DATAGRAM;
}
- protect = in_flags & (NTLMSSP_NEGOTIATE_SIGN | NTLMSSP_NEGOTIATE_SEAL);
-
- if (ctx->gss_flags & GSS_C_ANON_FLAG) {
- /* Anonymous auth, empty responses */
- memset(&nt_chal_resp, 0, sizeof(nt_chal_resp));
- lm_chal_resp.data = malloc(1);
- if (!lm_chal_resp.data) {
- retmin = ENOMEM;
- retmaj = GSS_S_FAILURE;
- goto done;
- }
- lm_chal_resp.data[0] = 0;
- lm_chal_resp.length = 1;
-
- } else if (ctx->sec_req & SEC_V2_ONLY) {
-
- /* ### NTLMv2 ### */
- uint8_t client_chal[8];
- struct ntlm_buffer cli_chal = { client_chal, 8 };
- struct ntlm_key ntlmv2_key = { .length = 16 };
- struct ntlm_buffer nt_proof = { 0 };
-
- if (target_info.length == 0 &&
- input_chan_bindings != GSS_C_NO_CHANNEL_BINDINGS) {
- retmaj = GSS_S_UNAVAILABLE;
- goto done;
- }
-
- if (server) {
- server_name = server->data.server.name;
- }
-
- if (target_info.length > 0) {
- bool *add_mic_ptr = NULL;
-
- if (input_chan_bindings != GSS_C_NO_CHANNEL_BINDINGS) {
- if (input_chan_bindings->initiator_addrtype != 0 ||
- input_chan_bindings->initiator_address.length != 0 ||
- input_chan_bindings->acceptor_addrtype != 0 ||
- input_chan_bindings->acceptor_address.length != 0 ||
- input_chan_bindings->application_data.length == 0) {
- retmin = EINVAL;
- retmaj = GSS_S_BAD_BINDINGS;
- goto done;
- }
- cb.length = input_chan_bindings->application_data.length;
- cb.data = input_chan_bindings->application_data.value;
- }
-
- if (protect) {
- if (ctx->int_flags & NTLMSSP_CTX_FLAG_SPNEGO_CAN_MIC) {
- add_mic_ptr = &add_mic;
- }
- }
-
- retmin = ntlm_process_target_info(ctx->ntlm, protect,
- &target_info,
- server_name, &cb,
- &client_target_info,
- &srv_time,
- add_mic_ptr);
- if (retmin) {
- if (retmin == ERR_DECODE) {
- retmaj = GSS_S_DEFECTIVE_TOKEN;
- } else {
- retmaj = GSS_S_FAILURE;
- }
- goto done;
- }
-
- if (srv_time != 0) {
- long int tdiff;
- tdiff = ntlm_timestamp_now() - srv_time;
- if ((tdiff / 10000000) > MAX_CHALRESP_LIFETIME) {
- retmin = EINVAL;
- retmaj = GSS_S_CONTEXT_EXPIRED;
- goto done;
- }
- }
- }
-
- /* Random client challenge */
- retmin = RAND_BUFFER(&cli_chal);
- if (retmin) {
- retmaj = GSS_S_FAILURE;
- goto done;
- }
-
- /* NTLMv2 Key */
- retmin = NTOWFv2(ctx->ntlm, &cred->cred.user.nt_hash,
- cred->cred.user.user.data.user.name,
- cred->cred.user.user.data.user.domain,
- &ntlmv2_key);
- if (retmin) {
- retmaj = GSS_S_FAILURE;
- goto done;
- }
-
- /* NTLMv2 Response */
- retmin = ntlmv2_compute_nt_response(&ntlmv2_key,
- server_chal, client_chal,
- srv_time, &client_target_info,
- &nt_chal_resp);
- if (retmin) {
- retmaj = GSS_S_FAILURE;
- goto done;
- }
-
- if (target_info.length == 0) {
- /* LMv2 Response
- * (only sent if challenge response has not target_info*/
- retmin = ntlmv2_compute_lm_response(&ntlmv2_key,
- server_chal, client_chal,
- &lm_chal_resp);
- if (retmin) {
- retmaj = GSS_S_FAILURE;
- goto done;
- }
- }
-
- /* The NT proof is the first 16 bytes */
- nt_proof.data = nt_chal_resp.data;
- nt_proof.length = 16;
-
- /* The Session Base Key */
- /* In NTLMv2 the Key Exchange Key is the Session Base Key */
- retmin = ntlmv2_session_base_key(&ntlmv2_key, &nt_proof,
- &key_exchange_key);
- if (retmin) {
- retmaj = GSS_S_FAILURE;
- goto done;
- }
- } else {
- /* ### NTLMv1 ### */
- uint8_t client_chal[8];
- uint8_t nt_resp_buf[24];
- uint8_t lm_resp_buf[24];
- struct ntlm_buffer cli_chal = { client_chal, 8 };
- struct ntlm_buffer nt_response = { nt_resp_buf, 24 };
- struct ntlm_buffer lm_response = { lm_resp_buf, 24 };
- struct ntlm_key session_base_key = { .length = 16 };
- bool NoLMResponseNTLMv1 = true; /* FIXME: get from conf/env */
- bool ext_sec;
-
- /* Random client challenge */
- retmin = RAND_BUFFER(&cli_chal);
- if (retmin) {
- retmaj = GSS_S_FAILURE;
- goto done;
- }
-
- ext_sec = (in_flags & NTLMSSP_NEGOTIATE_EXTENDED_SESSIONSECURITY);
-
- retmin = ntlm_compute_nt_response(&cred->cred.user.nt_hash,
- ext_sec, server_chal,
- client_chal, &nt_response);
- if (retmin) {
- retmaj = GSS_S_FAILURE;
- goto done;
- }
-
- if (!ext_sec && NoLMResponseNTLMv1) {
- memcpy(lm_response.data, nt_response.data, 24);
- } else {
- retmin = ntlm_compute_lm_response(&cred->cred.user.lm_hash,
- ext_sec, server_chal,
- client_chal, &lm_response);
- if (retmin) {
- retmaj = GSS_S_FAILURE;
- goto done;
- }
- }
-
- retmin = ntlm_session_base_key(&cred->cred.user.nt_hash,
- &session_base_key);
- if (retmin) {
- retmaj = GSS_S_FAILURE;
- goto done;
- }
-
- retmin = KXKEY(ctx->ntlm, ext_sec,
- (in_flags & NTLMSSP_NEGOTIATE_LM_KEY),
- (in_flags & NTLMSSP_REQUEST_NON_NT_SESSION_KEY),
- server_chal, &cred->cred.user.lm_hash,
- &session_base_key, &lm_response, &key_exchange_key);
- if (retmin) {
- retmaj = GSS_S_FAILURE;
- goto done;
- }
- }
-
- key_exch = (in_flags & NTLMSSP_NEGOTIATE_KEY_EXCH);
-
- retmin = ntlm_exported_session_key(&key_exchange_key, key_exch,
- &ctx->exported_session_key);
- if (retmin) {
- retmaj = GSS_S_FAILURE;
- goto done;
- }
-
- if (key_exch) {
- retmin = ntlm_encrypted_session_key(&key_exchange_key,
- &ctx->exported_session_key,
- &encrypted_random_session_key);
- if (retmin) {
- retmaj = GSS_S_FAILURE;
- goto done;
- }
- }
-
- /* in_flags all verified, assign as current flags */
- ctx->neg_flags |= in_flags;
-
- enc_sess_key.data = encrypted_random_session_key.data;
- enc_sess_key.length = encrypted_random_session_key.length;
-
- retmin = ntlm_encode_auth_msg(ctx->ntlm, ctx->neg_flags,
- &lm_chal_resp, &nt_chal_resp,
- cred->cred.user.user.data.user.domain,
- cred->cred.user.user.data.user.name,
- ctx->workstation, &enc_sess_key,
- add_mic ? &auth_mic : NULL,
- &ctx->auth_msg);
- if (retmin) {
- retmaj = GSS_S_FAILURE;
- goto done;
- }
-
- /* Now we need to calculate the MIC, because the MIC is part of the
- * message it protects, ntlm_encode_auth_msg() always add a zeroeth
- * buffer, however it returns in data_mic the pointer to the actual
- * area in the auth_msg that points at the mic, so we can backfill */
- if (add_mic) {
- retmin = ntlm_mic(&ctx->exported_session_key, &ctx->nego_msg,
- &ctx->chal_msg, &ctx->auth_msg, &mic);
- if (retmin) {
- retmaj = GSS_S_FAILURE;
- goto done;
- }
- /* 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;
- }
+ retmaj = gssntlm_cli_auth(&retmin, ctx, cred, &target_info,
+ in_flags, input_chan_bindings);
+ if (retmaj) goto done;
- if (protect) {
+ if (in_flags & (NTLMSSP_NEGOTIATE_SIGN | NTLMSSP_NEGOTIATE_SEAL)) {
retmin = ntlm_signseal_keys(in_flags, true,
&ctx->exported_session_key,
&ctx->crypto_state);
@@ -693,10 +438,7 @@ done:
safefree(nb_computer_name);
safefree(nb_domain_name);
safefree(trgt_name);
- ntlm_free_buffer_data(&client_target_info);
ntlm_free_buffer_data(&target_info);
- ntlm_free_buffer_data(&nt_chal_resp);
- ntlm_free_buffer_data(&lm_chal_resp);
return retmaj;
}