summaryrefslogtreecommitdiff
path: root/source3/libsmb/ntlmssp.c
diff options
context:
space:
mode:
authorAndrew Bartlett <abartlet@samba.org>2010-08-06 21:31:21 +1000
committerGünther Deschner <gd@samba.org>2010-08-10 16:22:04 +0200
commit75adca63f21ab4b415e0f909a54972d8dd57a153 (patch)
treef02639e6b35063ed914589659f5dd8375444ab4d /source3/libsmb/ntlmssp.c
parent979b672dcb013ed38a312b280fa6c0642469649b (diff)
downloadsamba-75adca63f21ab4b415e0f909a54972d8dd57a153.tar.gz
samba-75adca63f21ab4b415e0f909a54972d8dd57a153.tar.bz2
samba-75adca63f21ab4b415e0f909a54972d8dd57a153.zip
libcli/auth Make the source3/ implementation of the NTLMSSP server common
This means that the core logic (but not the initialisation) of the NTLMSSP server is in common, but uses different authentication backends. Andrew Bartlett Signed-off-by: Günther Deschner <gd@samba.org>
Diffstat (limited to 'source3/libsmb/ntlmssp.c')
-rw-r--r--source3/libsmb/ntlmssp.c527
1 files changed, 0 insertions, 527 deletions
diff --git a/source3/libsmb/ntlmssp.c b/source3/libsmb/ntlmssp.c
index d393404c1e..6958a0dd16 100644
--- a/source3/libsmb/ntlmssp.c
+++ b/source3/libsmb/ntlmssp.c
@@ -34,16 +34,9 @@
static NTSTATUS ntlmssp_client_initial(struct ntlmssp_state *ntlmssp_state,
TALLOC_CTX *out_mem_ctx, /* Unused at this time */
DATA_BLOB reply, DATA_BLOB *next_request);
-static NTSTATUS ntlmssp_server_negotiate(struct ntlmssp_state *ntlmssp_state,
- TALLOC_CTX *out_mem_ctx,
- const DATA_BLOB in, DATA_BLOB *out);
static NTSTATUS ntlmssp_client_challenge(struct ntlmssp_state *ntlmssp_state,
TALLOC_CTX *out_mem_ctx, /* Unused at this time */
const DATA_BLOB reply, DATA_BLOB *next_request);
-static NTSTATUS ntlmssp_server_auth(struct ntlmssp_state *ntlmssp_state,
- TALLOC_CTX *out_mem_ctx,
- const DATA_BLOB request, DATA_BLOB *reply);
-
/**
* Callbacks for NTLMSSP - for both client and server operating modes
*
@@ -280,526 +273,6 @@ NTSTATUS ntlmssp_update(struct ntlmssp_state *ntlmssp_state,
}
/**
- * Next state function for the Negotiate packet
- *
- * @param ntlmssp_state NTLMSSP state
- * @param out_mem_ctx Memory context for *out
- * @param in The request, as a DATA_BLOB. reply.data must be NULL
- * @param out The reply, as an allocated DATA_BLOB, caller to free.
- * @return Errors or MORE_PROCESSING_REQUIRED if (normal) a reply is required.
- */
-
-static NTSTATUS ntlmssp_server_negotiate(struct ntlmssp_state *ntlmssp_state,
- TALLOC_CTX *out_mem_ctx,
- const DATA_BLOB request, DATA_BLOB *reply)
-{
- DATA_BLOB struct_blob;
- uint32_t neg_flags = 0;
- uint32_t ntlmssp_command, chal_flags;
- uint8_t cryptkey[8];
- const char *target_name;
- NTSTATUS status;
-
- /* parse the NTLMSSP packet */
-#if 0
- file_save("ntlmssp_negotiate.dat", request.data, request.length);
-#endif
-
- if (request.length) {
- if ((request.length < 16) || !msrpc_parse(ntlmssp_state, &request, "Cdd",
- "NTLMSSP",
- &ntlmssp_command,
- &neg_flags)) {
- DEBUG(1, ("ntlmssp_server_negotiate: failed to parse NTLMSSP Negotiate of length %u\n",
- (unsigned int)request.length));
- dump_data(2, request.data, request.length);
- return NT_STATUS_INVALID_PARAMETER;
- }
- debug_ntlmssp_flags(neg_flags);
-
- if (DEBUGLEVEL >= 10) {
- struct NEGOTIATE_MESSAGE *negotiate = talloc(
- ntlmssp_state, struct NEGOTIATE_MESSAGE);
- if (negotiate != NULL) {
- status = ntlmssp_pull_NEGOTIATE_MESSAGE(
- &request, negotiate, negotiate);
- if (NT_STATUS_IS_OK(status)) {
- NDR_PRINT_DEBUG(NEGOTIATE_MESSAGE,
- negotiate);
- }
- TALLOC_FREE(negotiate);
- }
- }
- }
-
- ntlmssp_handle_neg_flags(ntlmssp_state, neg_flags, ntlmssp_state->allow_lm_key);
-
- /* Ask our caller what challenge they would like in the packet */
- status = ntlmssp_state->get_challenge(ntlmssp_state, cryptkey);
- if (!NT_STATUS_IS_OK(status)) {
- DEBUG(1, ("ntlmssp_server_negotiate: backend doesn't give a challenge: %s\n",
- nt_errstr(status)));
- return status;
- }
-
- /* Check if we may set the challenge */
- if (!ntlmssp_state->may_set_challenge(ntlmssp_state)) {
- ntlmssp_state->neg_flags &= ~NTLMSSP_NEGOTIATE_NTLM2;
- }
-
- /* The flags we send back are not just the negotiated flags,
- * they are also 'what is in this packet'. Therfore, we
- * operate on 'chal_flags' from here on
- */
-
- chal_flags = ntlmssp_state->neg_flags;
-
- /* get the right name to fill in as 'target' */
- target_name = ntlmssp_target_name(ntlmssp_state,
- neg_flags, &chal_flags);
- if (target_name == NULL)
- return NT_STATUS_INVALID_PARAMETER;
-
- ntlmssp_state->chal = data_blob_talloc(ntlmssp_state, cryptkey, 8);
- ntlmssp_state->internal_chal = data_blob_talloc(ntlmssp_state,
- cryptkey, 8);
-
- /* This creates the 'blob' of names that appears at the end of the packet */
- if (chal_flags & NTLMSSP_NEGOTIATE_TARGET_INFO)
- {
- msrpc_gen(ntlmssp_state, &struct_blob, "aaaaa",
- MsvAvNbDomainName, target_name,
- MsvAvNbComputerName, ntlmssp_state->server.netbios_name,
- MsvAvDnsDomainName, ntlmssp_state->server.dns_domain,
- MsvAvDnsComputerName, ntlmssp_state->server.dns_name,
- MsvAvEOL, "");
- } else {
- struct_blob = data_blob_null;
- }
-
- {
- /* Marshal the packet in the right format, be it unicode or ASCII */
- const char *gen_string;
- DATA_BLOB version_blob = data_blob_null;
-
- if (chal_flags & NTLMSSP_NEGOTIATE_VERSION) {
- enum ndr_err_code err;
- struct VERSION vers;
-
- /* "What Windows returns" as a version number. */
- ZERO_STRUCT(vers);
- vers.ProductMajorVersion = NTLMSSP_WINDOWS_MAJOR_VERSION_6;
- vers.ProductMinorVersion = NTLMSSP_WINDOWS_MINOR_VERSION_1;
- vers.ProductBuild = 0;
- vers.NTLMRevisionCurrent = NTLMSSP_REVISION_W2K3;
-
- err = ndr_push_struct_blob(&version_blob,
- ntlmssp_state,
- &vers,
- (ndr_push_flags_fn_t)ndr_push_VERSION);
-
- if (!NDR_ERR_CODE_IS_SUCCESS(err)) {
- data_blob_free(&struct_blob);
- return NT_STATUS_NO_MEMORY;
- }
- }
-
- if (ntlmssp_state->unicode) {
- gen_string = "CdUdbddBb";
- } else {
- gen_string = "CdAdbddBb";
- }
-
- msrpc_gen(out_mem_ctx, reply, gen_string,
- "NTLMSSP",
- NTLMSSP_CHALLENGE,
- target_name,
- chal_flags,
- cryptkey, 8,
- 0, 0,
- struct_blob.data, struct_blob.length,
- version_blob.data, version_blob.length);
-
- data_blob_free(&version_blob);
-
- if (DEBUGLEVEL >= 10) {
- struct CHALLENGE_MESSAGE *challenge = talloc(
- ntlmssp_state, struct CHALLENGE_MESSAGE);
- if (challenge != NULL) {
- challenge->NegotiateFlags = chal_flags;
- status = ntlmssp_pull_CHALLENGE_MESSAGE(
- reply, challenge, challenge);
- if (NT_STATUS_IS_OK(status)) {
- NDR_PRINT_DEBUG(CHALLENGE_MESSAGE,
- challenge);
- }
- TALLOC_FREE(challenge);
- }
- }
- }
-
- data_blob_free(&struct_blob);
-
- ntlmssp_state->expected_state = NTLMSSP_AUTH;
-
- return NT_STATUS_MORE_PROCESSING_REQUIRED;
-}
-
-struct ntlmssp_server_auth_state {
- DATA_BLOB user_session_key;
- DATA_BLOB lm_session_key;
- /* internal variables used by KEY_EXCH (client-supplied user session key */
- DATA_BLOB encrypted_session_key;
- bool doing_ntlm2;
- /* internal variables used by NTLM2 */
- uint8_t session_nonce[16];
-};
-
-/**
- * Next state function for the Authenticate packet
- *
- * @param ntlmssp_state NTLMSSP State
- * @param request The request, as a DATA_BLOB
- * @return Errors or NT_STATUS_OK.
- */
-
-static NTSTATUS ntlmssp_server_preauth(struct ntlmssp_state *ntlmssp_state,
- struct ntlmssp_server_auth_state *state,
- const DATA_BLOB request)
-{
- uint32_t ntlmssp_command, auth_flags;
- NTSTATUS nt_status;
-
- uint8_t session_nonce_hash[16];
-
- const char *parse_string;
-
-#if 0
- file_save("ntlmssp_auth.dat", request.data, request.length);
-#endif
-
- if (ntlmssp_state->unicode) {
- parse_string = "CdBBUUUBd";
- } else {
- parse_string = "CdBBAAABd";
- }
-
- /* zero these out */
- data_blob_free(&ntlmssp_state->session_key);
- data_blob_free(&ntlmssp_state->lm_resp);
- data_blob_free(&ntlmssp_state->nt_resp);
-
- ntlmssp_state->user = NULL;
- ntlmssp_state->domain = NULL;
- ntlmssp_state->client.netbios_name = NULL;
-
- /* now the NTLMSSP encoded auth hashes */
- if (!msrpc_parse(ntlmssp_state, &request, parse_string,
- "NTLMSSP",
- &ntlmssp_command,
- &ntlmssp_state->lm_resp,
- &ntlmssp_state->nt_resp,
- &ntlmssp_state->domain,
- &ntlmssp_state->user,
- &ntlmssp_state->client.netbios_name,
- &state->encrypted_session_key,
- &auth_flags)) {
- DEBUG(10, ("ntlmssp_server_auth: failed to parse NTLMSSP (nonfatal):\n"));
- dump_data(10, request.data, request.length);
-
- /* zero this out */
- data_blob_free(&state->encrypted_session_key);
- auth_flags = 0;
-
- /* Try again with a shorter string (Win9X truncates this packet) */
- if (ntlmssp_state->unicode) {
- parse_string = "CdBBUUU";
- } else {
- parse_string = "CdBBAAA";
- }
-
- /* now the NTLMSSP encoded auth hashes */
- if (!msrpc_parse(ntlmssp_state, &request, parse_string,
- "NTLMSSP",
- &ntlmssp_command,
- &ntlmssp_state->lm_resp,
- &ntlmssp_state->nt_resp,
- &ntlmssp_state->domain,
- &ntlmssp_state->user,
- &ntlmssp_state->client.netbios_name)) {
- DEBUG(1, ("ntlmssp_server_auth: failed to parse NTLMSSP (tried both formats):\n"));
- dump_data(2, request.data, request.length);
-
- return NT_STATUS_INVALID_PARAMETER;
- }
- }
-
- talloc_steal(state, state->encrypted_session_key.data);
-
- if (auth_flags)
- ntlmssp_handle_neg_flags(ntlmssp_state, auth_flags, ntlmssp_state->allow_lm_key);
-
- if (DEBUGLEVEL >= 10) {
- struct AUTHENTICATE_MESSAGE *authenticate = talloc(
- ntlmssp_state, struct AUTHENTICATE_MESSAGE);
- if (authenticate != NULL) {
- NTSTATUS status;
- authenticate->NegotiateFlags = auth_flags;
- status = ntlmssp_pull_AUTHENTICATE_MESSAGE(
- &request, authenticate, authenticate);
- if (NT_STATUS_IS_OK(status)) {
- NDR_PRINT_DEBUG(AUTHENTICATE_MESSAGE,
- authenticate);
- }
- TALLOC_FREE(authenticate);
- }
- }
-
- DEBUG(3,("Got user=[%s] domain=[%s] workstation=[%s] len1=%lu len2=%lu\n",
- ntlmssp_state->user, ntlmssp_state->domain,
- ntlmssp_state->client.netbios_name,
- (unsigned long)ntlmssp_state->lm_resp.length,
- (unsigned long)ntlmssp_state->nt_resp.length));
-
-#if 0
- file_save("nthash1.dat", &ntlmssp_state->nt_resp.data, &ntlmssp_state->nt_resp.length);
- file_save("lmhash1.dat", &ntlmssp_state->lm_resp.data, &ntlmssp_state->lm_resp.length);
-#endif
-
- /* NTLM2 uses a 'challenge' that is made of up both the server challenge, and a
- client challenge
-
- However, the NTLM2 flag may still be set for the real NTLMv2 logins, be careful.
- */
- if (ntlmssp_state->neg_flags & NTLMSSP_NEGOTIATE_NTLM2) {
- if (ntlmssp_state->nt_resp.length == 24 && ntlmssp_state->lm_resp.length == 24) {
- struct MD5Context md5_session_nonce_ctx;
- state->doing_ntlm2 = true;
-
- memcpy(state->session_nonce, ntlmssp_state->internal_chal.data, 8);
- memcpy(&state->session_nonce[8], ntlmssp_state->lm_resp.data, 8);
-
- SMB_ASSERT(ntlmssp_state->internal_chal.data && ntlmssp_state->internal_chal.length == 8);
-
- MD5Init(&md5_session_nonce_ctx);
- MD5Update(&md5_session_nonce_ctx, state->session_nonce, 16);
- MD5Final(session_nonce_hash, &md5_session_nonce_ctx);
-
- ntlmssp_state->chal = data_blob_talloc(
- ntlmssp_state, session_nonce_hash, 8);
-
- /* LM response is no longer useful */
- data_blob_free(&ntlmssp_state->lm_resp);
-
- /* We changed the effective challenge - set it */
- if (!NT_STATUS_IS_OK(nt_status = ntlmssp_state->set_challenge(ntlmssp_state, &ntlmssp_state->chal))) {
- return nt_status;
- }
-
- /* LM Key is incompatible. */
- ntlmssp_state->neg_flags &= ~NTLMSSP_NEGOTIATE_LM_KEY;
- }
- }
- return NT_STATUS_OK;
-}
-
-/**
- * Next state function for the Authenticate packet
- * (after authentication - figures out the session keys etc)
- *
- * @param ntlmssp_state NTLMSSP State
- * @return Errors or NT_STATUS_OK.
- */
-
-static NTSTATUS ntlmssp_server_postauth(struct ntlmssp_state *ntlmssp_state,
- struct ntlmssp_server_auth_state *state)
-{
- DATA_BLOB user_session_key = state->user_session_key;
- DATA_BLOB lm_session_key = state->lm_session_key;
- NTSTATUS nt_status;
- DATA_BLOB session_key = data_blob(NULL, 0);
-
- dump_data_pw("NT session key:\n", user_session_key.data, user_session_key.length);
- dump_data_pw("LM first-8:\n", lm_session_key.data, lm_session_key.length);
-
- /* Handle the different session key derivation for NTLM2 */
- if (state->doing_ntlm2) {
- if (user_session_key.data && user_session_key.length == 16) {
- session_key = data_blob_talloc(ntlmssp_state,
- NULL, 16);
- hmac_md5(user_session_key.data, state->session_nonce,
- sizeof(state->session_nonce), session_key.data);
- DEBUG(10,("ntlmssp_server_auth: Created NTLM2 session key.\n"));
- dump_data_pw("NTLM2 session key:\n", session_key.data, session_key.length);
-
- } else {
- DEBUG(10,("ntlmssp_server_auth: Failed to create NTLM2 session key.\n"));
- session_key = data_blob_null;
- }
- } else if ((ntlmssp_state->neg_flags & NTLMSSP_NEGOTIATE_LM_KEY)
- /* Ensure we can never get here on NTLMv2 */
- && (ntlmssp_state->nt_resp.length == 0 || ntlmssp_state->nt_resp.length == 24)) {
-
- if (lm_session_key.data && lm_session_key.length >= 8) {
- if (ntlmssp_state->lm_resp.data && ntlmssp_state->lm_resp.length == 24) {
- session_key = data_blob_talloc(ntlmssp_state,
- NULL, 16);
- if (session_key.data == NULL) {
- return NT_STATUS_NO_MEMORY;
- }
- SMBsesskeygen_lm_sess_key(lm_session_key.data, ntlmssp_state->lm_resp.data,
- session_key.data);
- DEBUG(10,("ntlmssp_server_auth: Created NTLM session key.\n"));
- } else {
- static const uint8_t zeros[24] = {0, };
- session_key = data_blob_talloc(
- ntlmssp_state, NULL, 16);
- if (session_key.data == NULL) {
- return NT_STATUS_NO_MEMORY;
- }
- SMBsesskeygen_lm_sess_key(zeros, zeros,
- session_key.data);
- DEBUG(10,("ntlmssp_server_auth: Created NTLM session key.\n"));
- }
- dump_data_pw("LM session key:\n", session_key.data,
- session_key.length);
- } else {
- /* LM Key not selected */
- ntlmssp_state->neg_flags &= ~NTLMSSP_NEGOTIATE_LM_KEY;
-
- DEBUG(10,("ntlmssp_server_auth: Failed to create NTLM session key.\n"));
- session_key = data_blob_null;
- }
-
- } else if (user_session_key.data) {
- session_key = user_session_key;
- DEBUG(10,("ntlmssp_server_auth: Using unmodified nt session key.\n"));
- dump_data_pw("unmodified session key:\n", session_key.data, session_key.length);
-
- /* LM Key not selected */
- ntlmssp_state->neg_flags &= ~NTLMSSP_NEGOTIATE_LM_KEY;
-
- } else if (lm_session_key.data) {
- /* Very weird to have LM key, but no user session key, but anyway.. */
- session_key = lm_session_key;
- DEBUG(10,("ntlmssp_server_auth: Using unmodified lm session key.\n"));
- dump_data_pw("unmodified session key:\n", session_key.data, session_key.length);
-
- /* LM Key not selected */
- ntlmssp_state->neg_flags &= ~NTLMSSP_NEGOTIATE_LM_KEY;
-
- } else {
- DEBUG(10,("ntlmssp_server_auth: Failed to create unmodified session key.\n"));
- session_key = data_blob_null;
-
- /* LM Key not selected */
- ntlmssp_state->neg_flags &= ~NTLMSSP_NEGOTIATE_LM_KEY;
- }
-
- /* With KEY_EXCH, the client supplies the proposed session key,
- but encrypts it with the long-term key */
- if (ntlmssp_state->neg_flags & NTLMSSP_NEGOTIATE_KEY_EXCH) {
- if (!state->encrypted_session_key.data
- || state->encrypted_session_key.length != 16) {
- data_blob_free(&state->encrypted_session_key);
- DEBUG(1, ("Client-supplied KEY_EXCH session key was of invalid length (%u)!\n",
- (unsigned)state->encrypted_session_key.length));
- return NT_STATUS_INVALID_PARAMETER;
- } else if (!session_key.data || session_key.length != 16) {
- DEBUG(5, ("server session key is invalid (len == %u), cannot do KEY_EXCH!\n",
- (unsigned int)session_key.length));
- ntlmssp_state->session_key = session_key;
- } else {
- dump_data_pw("KEY_EXCH session key (enc):\n",
- state->encrypted_session_key.data,
- state->encrypted_session_key.length);
- arcfour_crypt(state->encrypted_session_key.data,
- session_key.data,
- state->encrypted_session_key.length);
- ntlmssp_state->session_key = data_blob_talloc(ntlmssp_state,
- state->encrypted_session_key.data,
- state->encrypted_session_key.length);
- dump_data_pw("KEY_EXCH session key:\n",
- state->encrypted_session_key.data,
- state->encrypted_session_key.length);
- talloc_free(session_key.data);
- }
- } else {
- ntlmssp_state->session_key = session_key;
- }
-
- if (ntlmssp_state->session_key.length) {
- nt_status = ntlmssp_sign_init(ntlmssp_state);
- }
-
- ntlmssp_state->expected_state = NTLMSSP_DONE;
-
- return nt_status;
-}
-
-
-/**
- * Next state function for the Authenticate packet
- *
- * @param gensec_security GENSEC state
- * @param out_mem_ctx Memory context for *out
- * @param in The request, as a DATA_BLOB. reply.data must be NULL
- * @param out The reply, as an allocated DATA_BLOB, caller to free.
- * @return Errors or NT_STATUS_OK if authentication sucessful
- */
-
-static NTSTATUS ntlmssp_server_auth(struct ntlmssp_state *ntlmssp_state,
- TALLOC_CTX *out_mem_ctx,
- const DATA_BLOB in, DATA_BLOB *out)
-{
- struct ntlmssp_server_auth_state *state;
- NTSTATUS nt_status;
-
- /* zero the outbound NTLMSSP packet */
- *out = data_blob_null;
-
- state = talloc_zero(ntlmssp_state, struct ntlmssp_server_auth_state);
- if (state == NULL) {
- return NT_STATUS_NO_MEMORY;
- }
-
- nt_status = ntlmssp_server_preauth(ntlmssp_state, state, in);
- if (!NT_STATUS_IS_OK(nt_status)) {
- TALLOC_FREE(state);
- return nt_status;
- }
-
- /*
- * Note we don't check here for NTLMv2 auth settings. If NTLMv2 auth
- * is required (by "ntlm auth = no" and "lm auth = no" being set in the
- * smb.conf file) and no NTLMv2 response was sent then the password check
- * will fail here. JRA.
- */
-
- /* Finally, actually ask if the password is OK */
- nt_status = ntlmssp_state->check_password(ntlmssp_state,
- &state->user_session_key,
- &state->lm_session_key);
- if (!NT_STATUS_IS_OK(nt_status)) {
- TALLOC_FREE(state);
- return nt_status;
- }
-
- /* When we get more async in the auth code behind
- ntlmssp_state->check_password, the ntlmssp_server_postpath
- can be done in a callback */
-
- nt_status = ntlmssp_server_postauth(ntlmssp_state, state);
- if (!NT_STATUS_IS_OK(nt_status)) {
- TALLOC_FREE(state);
- return nt_status;
- }
-
- TALLOC_FREE(state);
- return NT_STATUS_OK;
-}
-
-/**
* Create an NTLMSSP state machine
*
* @param ntlmssp_state NTLMSSP State, allocated by this function