diff options
Diffstat (limited to 'source4/auth/gensec')
-rw-r--r-- | source4/auth/gensec/gensec.mk | 15 | ||||
-rw-r--r-- | source4/auth/gensec/ntlmssp.c | 1605 | ||||
-rw-r--r-- | source4/auth/gensec/ntlmssp.h | 198 | ||||
-rw-r--r-- | source4/auth/gensec/ntlmssp_parse.c | 338 | ||||
-rw-r--r-- | source4/auth/gensec/ntlmssp_sign.c | 555 |
5 files changed, 1 insertions, 2710 deletions
diff --git a/source4/auth/gensec/gensec.mk b/source4/auth/gensec/gensec.mk index 7b5fa7ae36..02823fc11f 100644 --- a/source4/auth/gensec/gensec.mk +++ b/source4/auth/gensec/gensec.mk @@ -50,19 +50,6 @@ ADD_OBJ_FILES = \ ################################################ ################################################ -# Start MODULE gensec_ntlmssp -[MODULE::gensec_ntlmssp] -SUBSYSTEM = GENSEC -INIT_FUNCTION = gensec_ntlmssp_init -INIT_OBJ_FILES = auth/gensec/ntlmssp.o -ADD_OBJ_FILES = \ - auth/gensec/ntlmssp_parse.o \ - auth/gensec/ntlmssp_sign.o -REQUIRED_SUBSYSTEMS = AUTH -# End MODULE gensec_ntlmssp -################################################ - -################################################ # Start MODULE gensec_schannel [MODULE::gensec_schannel] SUBSYSTEM = GENSEC @@ -71,7 +58,7 @@ INIT_OBJ_FILES = auth/gensec/schannel.o ADD_OBJ_FILES = \ auth/gensec/schannel_sign.o REQUIRED_SUBSYSTEMS = AUTH SCHANNELDB -# End MODULE gensec_ntlmssp +# End MODULE gensec_schannel ################################################ ################################################ diff --git a/source4/auth/gensec/ntlmssp.c b/source4/auth/gensec/ntlmssp.c deleted file mode 100644 index 5b40a412bd..0000000000 --- a/source4/auth/gensec/ntlmssp.c +++ /dev/null @@ -1,1605 +0,0 @@ -/* - Unix SMB/Netbios implementation. - Version 3.0 - handle NLTMSSP, client server side parsing - - Copyright (C) Andrew Tridgell 2001 - Copyright (C) Andrew Bartlett <abartlet@samba.org> 2001-2005 - Copyright (C) Stefan Metzmacher 2005 - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -*/ - -#include "includes.h" -#include "auth/auth.h" -#include "lib/crypto/crypto.h" -#include "pstring.h" - -static NTSTATUS ntlmssp_client_initial(struct ntlmssp_state *ntlmssp_state, - TALLOC_CTX *out_mem_ctx, - DATA_BLOB in, DATA_BLOB *out); -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, - const DATA_BLOB in, DATA_BLOB *out); -static NTSTATUS ntlmssp_server_auth(struct ntlmssp_state *ntlmssp_state, - TALLOC_CTX *out_mem_ctx, - const DATA_BLOB in, DATA_BLOB *out); - -/** - * Callbacks for NTLMSSP - for both client and server operating modes - * - */ - -static const struct ntlmssp_callbacks { - enum ntlmssp_role role; - enum ntlmssp_message_type ntlmssp_command; - NTSTATUS (*fn)(struct ntlmssp_state *ntlmssp_state, - TALLOC_CTX *out_mem_ctx, - DATA_BLOB in, DATA_BLOB *out); -} ntlmssp_callbacks[] = { - {NTLMSSP_CLIENT, NTLMSSP_INITIAL, ntlmssp_client_initial}, - {NTLMSSP_SERVER, NTLMSSP_NEGOTIATE, ntlmssp_server_negotiate}, - {NTLMSSP_CLIENT, NTLMSSP_CHALLENGE, ntlmssp_client_challenge}, - {NTLMSSP_SERVER, NTLMSSP_AUTH, ntlmssp_server_auth}, -}; - - -/** - * Print out the NTLMSSP flags for debugging - * @param neg_flags The flags from the packet - */ - -void debug_ntlmssp_flags(uint32_t neg_flags) -{ - DEBUG(3,("Got NTLMSSP neg_flags=0x%08x\n", neg_flags)); - - if (neg_flags & NTLMSSP_NEGOTIATE_UNICODE) - DEBUGADD(4, (" NTLMSSP_NEGOTIATE_UNICODE\n")); - if (neg_flags & NTLMSSP_NEGOTIATE_OEM) - DEBUGADD(4, (" NTLMSSP_NEGOTIATE_OEM\n")); - if (neg_flags & NTLMSSP_REQUEST_TARGET) - DEBUGADD(4, (" NTLMSSP_REQUEST_TARGET\n")); - if (neg_flags & NTLMSSP_NEGOTIATE_SIGN) - DEBUGADD(4, (" NTLMSSP_NEGOTIATE_SIGN\n")); - if (neg_flags & NTLMSSP_NEGOTIATE_SEAL) - DEBUGADD(4, (" NTLMSSP_NEGOTIATE_SEAL\n")); - if (neg_flags & NTLMSSP_NEGOTIATE_LM_KEY) - DEBUGADD(4, (" NTLMSSP_NEGOTIATE_LM_KEY\n")); - if (neg_flags & NTLMSSP_NEGOTIATE_NETWARE) - DEBUGADD(4, (" NTLMSSP_NEGOTIATE_NETWARE\n")); - if (neg_flags & NTLMSSP_NEGOTIATE_NTLM) - DEBUGADD(4, (" NTLMSSP_NEGOTIATE_NTLM\n")); - if (neg_flags & NTLMSSP_NEGOTIATE_DOMAIN_SUPPLIED) - DEBUGADD(4, (" NTLMSSP_NEGOTIATE_DOMAIN_SUPPLIED\n")); - if (neg_flags & NTLMSSP_NEGOTIATE_WORKSTATION_SUPPLIED) - DEBUGADD(4, (" NTLMSSP_NEGOTIATE_WORKSTATION_SUPPLIED\n")); - if (neg_flags & NTLMSSP_NEGOTIATE_THIS_IS_LOCAL_CALL) - DEBUGADD(4, (" NTLMSSP_NEGOTIATE_THIS_IS_LOCAL_CALL\n")); - if (neg_flags & NTLMSSP_NEGOTIATE_ALWAYS_SIGN) - DEBUGADD(4, (" NTLMSSP_NEGOTIATE_ALWAYS_SIGN\n")); - if (neg_flags & NTLMSSP_NEGOTIATE_NTLM2) - DEBUGADD(4, (" NTLMSSP_NEGOTIATE_NTLM2\n")); - if (neg_flags & NTLMSSP_CHAL_TARGET_INFO) - DEBUGADD(4, (" NTLMSSP_CHAL_TARGET_INFO\n")); - if (neg_flags & NTLMSSP_NEGOTIATE_128) - DEBUGADD(4, (" NTLMSSP_NEGOTIATE_128\n")); - if (neg_flags & NTLMSSP_NEGOTIATE_KEY_EXCH) - DEBUGADD(4, (" NTLMSSP_NEGOTIATE_KEY_EXCH\n")); -} - -/** - * Default challenge generation code. - * - */ - -static const uint8_t *get_challenge(const struct ntlmssp_state *ntlmssp_state) -{ - uint8_t *chal = talloc_size(ntlmssp_state, 8); - generate_random_buffer(chal, 8); - - return chal; -} - -/** - * Default 'we can set the challenge to anything we like' implementation - * - */ - -static BOOL may_set_challenge(const struct ntlmssp_state *ntlmssp_state) -{ - return True; -} - -/** - * Default 'we can set the challenge to anything we like' implementation - * - * Does not actually do anything, as the value is always in the structure anyway. - * - */ - -static NTSTATUS set_challenge(struct ntlmssp_state *ntlmssp_state, DATA_BLOB *challenge) -{ - SMB_ASSERT(challenge->length == 8); - return NT_STATUS_OK; -} - -/** - * Set a username on an NTLMSSP context - ensures it is talloc()ed - * - */ - -NTSTATUS ntlmssp_set_username(struct ntlmssp_state *ntlmssp_state, const char *user) -{ - if (!user) { - /* it should be at least "" */ - DEBUG(1, ("NTLMSSP failed to set username - cannot accept NULL username\n")); - return NT_STATUS_INVALID_PARAMETER; - } - ntlmssp_state->user = talloc_strdup(ntlmssp_state, user); - if (!ntlmssp_state->user) { - return NT_STATUS_NO_MEMORY; - } - return NT_STATUS_OK; -} - -/** - * Set a password on an NTLMSSP context - ensures it is talloc()ed - * - */ -NTSTATUS ntlmssp_set_password(struct ntlmssp_state *ntlmssp_state, const char *password) -{ - if (!password) { - ntlmssp_state->password = NULL; - } else { - ntlmssp_state->password = talloc_strdup(ntlmssp_state, password); - if (!ntlmssp_state->password) { - return NT_STATUS_NO_MEMORY; - } - } - return NT_STATUS_OK; -} - -/** - * Set a domain on an NTLMSSP context - ensures it is talloc()ed - * - */ -NTSTATUS ntlmssp_set_domain(struct ntlmssp_state *ntlmssp_state, const char *domain) -{ - ntlmssp_state->domain = talloc_strdup(ntlmssp_state, domain); - if (!ntlmssp_state->domain) { - return NT_STATUS_NO_MEMORY; - } - return NT_STATUS_OK; -} - -/** - * Set a workstation on an NTLMSSP context - ensures it is talloc()ed - * - */ -NTSTATUS ntlmssp_set_workstation(struct ntlmssp_state *ntlmssp_state, const char *workstation) -{ - ntlmssp_state->workstation = talloc_strdup(ntlmssp_state, workstation); - if (!ntlmssp_state->workstation) { - return NT_STATUS_NO_MEMORY; - } - return NT_STATUS_OK; -} - -/** - * Store a DATA_BLOB containing an NTLMSSP response, for use later. - * This copies the data blob - */ - -NTSTATUS ntlmssp_store_response(struct ntlmssp_state *ntlmssp_state, - DATA_BLOB response) -{ - ntlmssp_state->stored_response = data_blob_talloc(ntlmssp_state, - response.data, response.length); - return NT_STATUS_OK; -} - -/** - * Next state function for the wrapped NTLMSSP state machine - * - * @param gensec_security GENSEC state, initialised to NTLMSSP - * @param out_mem_ctx The TALLOC_CTX for *out to be allocated on - * @param in The request, as a DATA_BLOB - * @param out The reply, as an talloc()ed DATA_BLOB, on *out_mem_ctx - * @return Error, MORE_PROCESSING_REQUIRED if a reply is sent, - * or NT_STATUS_OK if the user is authenticated. - */ - -static NTSTATUS gensec_ntlmssp_update(struct gensec_security *gensec_security, TALLOC_CTX *out_mem_ctx, - const DATA_BLOB in, DATA_BLOB *out) -{ - struct gensec_ntlmssp_state *gensec_ntlmssp_state = gensec_security->private_data; - struct ntlmssp_state *ntlmssp_state = gensec_ntlmssp_state->ntlmssp_state; - NTSTATUS status; - - DATA_BLOB input; - uint32_t ntlmssp_command; - int i; - - *out = data_blob(NULL, 0); - - if (ntlmssp_state->expected_state == NTLMSSP_DONE) { - return NT_STATUS_OK; - } - - if (!out_mem_ctx) { - /* if the caller doesn't want to manage/own the memory, - we can put it on our context */ - out_mem_ctx = ntlmssp_state; - } - - if (!in.length && ntlmssp_state->stored_response.length) { - input = ntlmssp_state->stored_response; - - /* we only want to read the stored response once - overwrite it */ - ntlmssp_state->stored_response = data_blob(NULL, 0); - } else { - input = in; - } - - if (!input.length) { - switch (ntlmssp_state->role) { - case NTLMSSP_CLIENT: - ntlmssp_command = NTLMSSP_INITIAL; - break; - case NTLMSSP_SERVER: - /* 'datagram' mode - no neg packet */ - ntlmssp_command = NTLMSSP_NEGOTIATE; - break; - } - } else { - if (!msrpc_parse(ntlmssp_state, - &input, "Cd", - "NTLMSSP", - &ntlmssp_command)) { - DEBUG(1, ("Failed to parse NTLMSSP packet, could not extract NTLMSSP command\n")); - dump_data(2, input.data, input.length); - return NT_STATUS_INVALID_PARAMETER; - } - } - - if (ntlmssp_command != ntlmssp_state->expected_state) { - DEBUG(1, ("got NTLMSSP command %u, expected %u\n", ntlmssp_command, ntlmssp_state->expected_state)); - return NT_STATUS_INVALID_PARAMETER; - } - - for (i=0; i < ARRAY_SIZE(ntlmssp_callbacks); i++) { - if (ntlmssp_callbacks[i].role == ntlmssp_state->role - && ntlmssp_callbacks[i].ntlmssp_command == ntlmssp_command) { - status = ntlmssp_callbacks[i].fn(ntlmssp_state, out_mem_ctx, input, out); - break; - } - } - - if (i == ARRAY_SIZE(ntlmssp_callbacks)) { - - DEBUG(1, ("failed to find NTLMSSP callback for NTLMSSP mode %u, command %u\n", - ntlmssp_state->role, ntlmssp_command)); - - return NT_STATUS_INVALID_PARAMETER; - } - - if (!NT_STATUS_EQUAL(status, NT_STATUS_MORE_PROCESSING_REQUIRED) && !NT_STATUS_IS_OK(status)) { - return status; - } - - gensec_ntlmssp_state->have_features = 0; - - if (gensec_ntlmssp_state->ntlmssp_state->neg_flags & NTLMSSP_NEGOTIATE_SIGN) { - gensec_ntlmssp_state->have_features |= GENSEC_FEATURE_SIGN; - } - - if (gensec_ntlmssp_state->ntlmssp_state->neg_flags & NTLMSSP_NEGOTIATE_SEAL) { - gensec_ntlmssp_state->have_features |= GENSEC_FEATURE_SEAL; - } - - if (gensec_ntlmssp_state->ntlmssp_state->session_key.data) { - gensec_ntlmssp_state->have_features |= GENSEC_FEATURE_SESSION_KEY; - } - - return status; -} - -/** - * Return the NTLMSSP master session key - * - * @param ntlmssp_state NTLMSSP State - */ - -NTSTATUS gensec_ntlmssp_session_key(struct gensec_security *gensec_security, - DATA_BLOB *session_key) -{ - struct gensec_ntlmssp_state *gensec_ntlmssp_state = gensec_security->private_data; - struct ntlmssp_state *ntlmssp_state = gensec_ntlmssp_state->ntlmssp_state; - - if (!ntlmssp_state->session_key.data) { - return NT_STATUS_NO_USER_SESSION_KEY; - } - *session_key = ntlmssp_state->session_key; - - return NT_STATUS_OK; -} - -/** - * Determine correct target name flags for reply, given server role - * and negotiated flags - * - * @param ntlmssp_state NTLMSSP State - * @param neg_flags The flags from the packet - * @param chal_flags The flags to be set in the reply packet - * @return The 'target name' string. - */ - -static const char *ntlmssp_target_name(struct ntlmssp_state *ntlmssp_state, - uint32_t neg_flags, uint32_t *chal_flags) -{ - if (neg_flags & NTLMSSP_REQUEST_TARGET) { - *chal_flags |= NTLMSSP_CHAL_TARGET_INFO; - *chal_flags |= NTLMSSP_REQUEST_TARGET; - if (ntlmssp_state->server_role == ROLE_STANDALONE) { - *chal_flags |= NTLMSSP_TARGET_TYPE_SERVER; - return ntlmssp_state->server_name; - } else { - *chal_flags |= NTLMSSP_TARGET_TYPE_DOMAIN; - return ntlmssp_state->get_domain(); - }; - } else { - return ""; - } -} - -static void ntlmssp_handle_neg_flags(struct ntlmssp_state *ntlmssp_state, - uint32_t neg_flags, BOOL allow_lm) { - if (neg_flags & NTLMSSP_NEGOTIATE_UNICODE) { - ntlmssp_state->neg_flags |= NTLMSSP_NEGOTIATE_UNICODE; - ntlmssp_state->neg_flags &= ~NTLMSSP_NEGOTIATE_OEM; - ntlmssp_state->unicode = True; - } else { - ntlmssp_state->neg_flags &= ~NTLMSSP_NEGOTIATE_UNICODE; - ntlmssp_state->neg_flags |= NTLMSSP_NEGOTIATE_OEM; - ntlmssp_state->unicode = False; - } - - if ((neg_flags & NTLMSSP_NEGOTIATE_LM_KEY) && allow_lm && !ntlmssp_state->use_ntlmv2) { - /* other end forcing us to use LM */ - ntlmssp_state->neg_flags |= NTLMSSP_NEGOTIATE_LM_KEY; - ntlmssp_state->neg_flags &= ~NTLMSSP_NEGOTIATE_NTLM2; - } else { - ntlmssp_state->neg_flags &= ~NTLMSSP_NEGOTIATE_LM_KEY; - } - - if (neg_flags & NTLMSSP_NEGOTIATE_ALWAYS_SIGN) { - ntlmssp_state->neg_flags |= NTLMSSP_NEGOTIATE_ALWAYS_SIGN; - } - - if (!(neg_flags & NTLMSSP_NEGOTIATE_SIGN)) { - ntlmssp_state->neg_flags &= ~NTLMSSP_NEGOTIATE_SIGN; - } - - if (!(neg_flags & NTLMSSP_NEGOTIATE_SEAL)) { - ntlmssp_state->neg_flags &= ~NTLMSSP_NEGOTIATE_SEAL; - } - - if (!(neg_flags & NTLMSSP_NEGOTIATE_NTLM2)) { - ntlmssp_state->neg_flags &= ~NTLMSSP_NEGOTIATE_NTLM2; - } - - if (!(neg_flags & NTLMSSP_NEGOTIATE_128)) { - ntlmssp_state->neg_flags &= ~NTLMSSP_NEGOTIATE_128; - if (neg_flags & NTLMSSP_NEGOTIATE_56) { - ntlmssp_state->neg_flags |= NTLMSSP_NEGOTIATE_56; - } - } - - if (!(neg_flags & NTLMSSP_NEGOTIATE_56)) { - ntlmssp_state->neg_flags &= ~NTLMSSP_NEGOTIATE_56; - } - - if (!(neg_flags & NTLMSSP_NEGOTIATE_KEY_EXCH)) { - ntlmssp_state->neg_flags &= ~NTLMSSP_NEGOTIATE_KEY_EXCH; - } - - if ((neg_flags & NTLMSSP_REQUEST_TARGET)) { - ntlmssp_state->neg_flags |= NTLMSSP_REQUEST_TARGET; - } - -} - -/** - Weaken NTLMSSP keys to cope with down-level clients and servers. - - We probably should have some parameters to control this, but as - it only occours for LM_KEY connections, and this is controlled - by the client lanman auth/lanman auth parameters, it isn't too bad. -*/ - -static void ntlmssp_weaken_keys(struct ntlmssp_state *ntlmssp_state) { - /* Key weakening not performed on the master key for NTLM2 - and does not occour for NTLM1. Therefore we only need - to do this for the LM_KEY. - */ - - if (ntlmssp_state->neg_flags & NTLMSSP_NEGOTIATE_LM_KEY) { - if (ntlmssp_state->neg_flags & NTLMSSP_NEGOTIATE_128) { - - } else if (ntlmssp_state->neg_flags & NTLMSSP_NEGOTIATE_56) { - ntlmssp_state->session_key.data[7] = 0xa0; - } else { /* forty bits */ - ntlmssp_state->session_key.data[5] = 0xe5; - ntlmssp_state->session_key.data[6] = 0x38; - ntlmssp_state->session_key.data[7] = 0xb0; - } - ntlmssp_state->session_key.length = 8; - } -} - -/** - * Next state function for the Negotiate packet - * - * @param ntlmssp_state NTLMSSP State - * @param out_mem_ctx The TALLOC_CTX for *out to be allocated on - * @param in The request, as a DATA_BLOB - * @param out The reply, as an talloc()ed DATA_BLOB, on *out_mem_ctx - * @return Errors or MORE_PROCESSING_REQUIRED if a reply is sent. - */ - -static NTSTATUS ntlmssp_server_negotiate(struct ntlmssp_state *ntlmssp_state, - TALLOC_CTX *out_mem_ctx, - const DATA_BLOB in, DATA_BLOB *out) -{ - DATA_BLOB struct_blob; - fstring dnsname, dnsdomname; - uint32_t neg_flags = 0; - uint32_t ntlmssp_command, chal_flags; - char *cliname=NULL, *domname=NULL; - const uint8_t *cryptkey; - const char *target_name; - - /* parse the NTLMSSP packet */ -#if 0 - file_save("ntlmssp_negotiate.dat", request.data, request.length); -#endif - - if (in.length) { - if (!msrpc_parse(ntlmssp_state, - &in, "CddAA", - "NTLMSSP", - &ntlmssp_command, - &neg_flags, - &cliname, - &domname)) { - DEBUG(1, ("ntlmssp_server_negotiate: failed to parse NTLMSSP:\n")); - dump_data(2, in.data, in.length); - return NT_STATUS_INVALID_PARAMETER; - } - - debug_ntlmssp_flags(neg_flags); - } - - ntlmssp_handle_neg_flags(ntlmssp_state, neg_flags, ntlmssp_state->allow_lm_key); - - /* Ask our caller what challenge they would like in the packet */ - cryptkey = ntlmssp_state->get_challenge(ntlmssp_state); - - /* 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 should be a 'netbios domain -> DNS domain' mapping */ - dnsdomname[0] = '\0'; - get_mydomname(dnsdomname); - strlower_m(dnsdomname); - - dnsname[0] = '\0'; - get_myfullname(dnsname); - - /* This creates the 'blob' of names that appears at the end of the packet */ - if (chal_flags & NTLMSSP_CHAL_TARGET_INFO) - { - const char *target_name_dns = ""; - if (chal_flags |= NTLMSSP_TARGET_TYPE_DOMAIN) { - target_name_dns = dnsdomname; - } else if (chal_flags |= NTLMSSP_TARGET_TYPE_SERVER) { - target_name_dns = dnsname; - } - - msrpc_gen(out_mem_ctx, - &struct_blob, "aaaaa", - NTLMSSP_NAME_TYPE_DOMAIN, target_name, - NTLMSSP_NAME_TYPE_SERVER, ntlmssp_state->server_name, - NTLMSSP_NAME_TYPE_DOMAIN_DNS, dnsdomname, - NTLMSSP_NAME_TYPE_SERVER_DNS, dnsname, - 0, ""); - } else { - struct_blob = data_blob(NULL, 0); - } - - { - /* Marshel the packet in the right format, be it unicode or ASCII */ - const char *gen_string; - if (ntlmssp_state->unicode) { - gen_string = "CdUdbddB"; - } else { - gen_string = "CdAdbddB"; - } - - msrpc_gen(out_mem_ctx, - out, gen_string, - "NTLMSSP", - NTLMSSP_CHALLENGE, - target_name, - chal_flags, - cryptkey, 8, - 0, 0, - struct_blob.data, struct_blob.length); - } - - ntlmssp_state->expected_state = NTLMSSP_AUTH; - - return NT_STATUS_MORE_PROCESSING_REQUIRED; -} - -/** - * 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, - const DATA_BLOB request) -{ - uint32_t ntlmssp_command, auth_flags; - NTSTATUS nt_status; - - uint8_t session_nonce_hash[16]; - - const char *parse_string; - char *domain = NULL; - char *user = NULL; - char *workstation = NULL; - -#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->lm_resp); - data_blob_free(&ntlmssp_state->nt_resp); - - ntlmssp_state->user = NULL; - ntlmssp_state->domain = NULL; - ntlmssp_state->workstation = 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, - &domain, - &user, - &workstation, - &ntlmssp_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(&ntlmssp_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, - &domain, - &user, - &workstation)) { - DEBUG(1, ("ntlmssp_server_auth: failed to parse NTLMSSP:\n")); - dump_data(2, request.data, request.length); - - return NT_STATUS_INVALID_PARAMETER; - } - } - - if (auth_flags) - ntlmssp_handle_neg_flags(ntlmssp_state, auth_flags, ntlmssp_state->allow_lm_key); - - if (!NT_STATUS_IS_OK(nt_status = ntlmssp_set_domain(ntlmssp_state, domain))) { - /* zero this out */ - data_blob_free(&ntlmssp_state->encrypted_session_key); - return nt_status; - } - - if (!NT_STATUS_IS_OK(nt_status = ntlmssp_set_username(ntlmssp_state, user))) { - /* zero this out */ - data_blob_free(&ntlmssp_state->encrypted_session_key); - return nt_status; - } - - if (!NT_STATUS_IS_OK(nt_status = ntlmssp_set_workstation(ntlmssp_state, workstation))) { - /* zero this out */ - data_blob_free(&ntlmssp_state->encrypted_session_key); - return nt_status; - } - - DEBUG(3,("Got user=[%s] domain=[%s] workstation=[%s] len1=%lu len2=%lu\n", - ntlmssp_state->user, ntlmssp_state->domain, ntlmssp_state->workstation, (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; - SMB_ASSERT(ntlmssp_state->internal_chal.data - && ntlmssp_state->internal_chal.length == 8); - - ntlmssp_state->doing_ntlm2 = True; - - memcpy(ntlmssp_state->session_nonce, ntlmssp_state->internal_chal.data, 8); - memcpy(&ntlmssp_state->session_nonce[8], ntlmssp_state->lm_resp.data, 8); - - MD5Init(&md5_session_nonce_ctx); - MD5Update(&md5_session_nonce_ctx, ntlmssp_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, zero it out */ - 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))) { - /* zero this out */ - data_blob_free(&ntlmssp_state->encrypted_session_key); - 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, - DATA_BLOB *user_session_key, - DATA_BLOB *lm_session_key) -{ - NTSTATUS nt_status; - DATA_BLOB session_key = data_blob(NULL, 0); - - if (user_session_key) - dump_data_pw("USER session key:\n", user_session_key->data, user_session_key->length); - - if (lm_session_key) - dump_data_pw("LM first-8:\n", lm_session_key->data, lm_session_key->length); - - /* Handle the different session key derivation for NTLM2 */ - if (ntlmssp_state->doing_ntlm2) { - if (user_session_key && user_session_key->data && user_session_key->length == 16) { - session_key = data_blob_talloc(ntlmssp_state, NULL, 16); - hmac_md5(user_session_key->data, ntlmssp_state->session_nonce, - sizeof(ntlmssp_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, 0); - } - } 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 && 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); - 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")); - dump_data_pw("LM session key:\n", session_key.data, session_key.length); - } else { - - /* When there is no LM response, just use zeros */ - static const uint8_t zeros[24]; - session_key = data_blob_talloc(ntlmssp_state, NULL, 16); - 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, 0); - } - - } else if (user_session_key && 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 && 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, 0); - - /* 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 (!ntlmssp_state->encrypted_session_key.data - || ntlmssp_state->encrypted_session_key.length != 16) { - data_blob_free(&ntlmssp_state->encrypted_session_key); - DEBUG(1, ("Client-supplied KEY_EXCH session key was of invalid length (%u)!\n", - ntlmssp_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", - session_key.length)); - ntlmssp_state->session_key = session_key; - } else { - dump_data_pw("KEY_EXCH session key (enc):\n", - ntlmssp_state->encrypted_session_key.data, - ntlmssp_state->encrypted_session_key.length); - arcfour_crypt(ntlmssp_state->encrypted_session_key.data, - session_key.data, - ntlmssp_state->encrypted_session_key.length); - ntlmssp_state->session_key = data_blob_talloc(ntlmssp_state, - ntlmssp_state->encrypted_session_key.data, - ntlmssp_state->encrypted_session_key.length); - dump_data_pw("KEY_EXCH session key:\n", ntlmssp_state->encrypted_session_key.data, - ntlmssp_state->encrypted_session_key.length); - } - } else { - ntlmssp_state->session_key = session_key; - } - - /* The server might need us to use a partial-strength session key */ - ntlmssp_weaken_keys(ntlmssp_state); - - nt_status = ntlmssp_sign_init(ntlmssp_state); - - data_blob_free(&ntlmssp_state->encrypted_session_key); - - /* allow arbitarily many authentications, but watch that this will cause a - memory leak, until the ntlmssp_state is shutdown - */ - - if (ntlmssp_state->server_multiple_authentications) { - ntlmssp_state->expected_state = NTLMSSP_AUTH; - } else { - ntlmssp_state->expected_state = NTLMSSP_DONE; - } - - return nt_status; -} - - -/** - * Next state function for the Authenticate packet - * - * @param ntlmssp_state NTLMSSP State - * @param in The packet in from the NTLMSSP partner, as a DATA_BLOB - * @param out The reply, as an allocated DATA_BLOB, caller to free. - * @return Errors, NT_STATUS_MORE_PROCESSING_REQUIRED or NT_STATUS_OK. - */ - -static NTSTATUS ntlmssp_server_auth(struct ntlmssp_state *ntlmssp_state, - TALLOC_CTX *out_mem_ctx, - const DATA_BLOB in, DATA_BLOB *out) -{ - DATA_BLOB user_session_key = data_blob(NULL, 0); - DATA_BLOB lm_session_key = data_blob(NULL, 0); - NTSTATUS nt_status; - - /* zero the outbound NTLMSSP packet */ - *out = data_blob_talloc(out_mem_ctx, NULL, 0); - - if (!NT_STATUS_IS_OK(nt_status = ntlmssp_server_preauth(ntlmssp_state, in))) { - 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 */ - - if (!NT_STATUS_IS_OK(nt_status = ntlmssp_state->check_password(ntlmssp_state, - &user_session_key, &lm_session_key))) { - return nt_status; - } - - if (ntlmssp_state->server_use_session_keys) { - return ntlmssp_server_postauth(ntlmssp_state, &user_session_key, &lm_session_key); - } else { - ntlmssp_state->session_key = data_blob(NULL, 0); - return NT_STATUS_OK; - } -} - -/** - * Create an NTLMSSP state machine - * - * @param ntlmssp_state NTLMSSP State, allocated by this function - */ - -NTSTATUS ntlmssp_server_start(TALLOC_CTX *mem_ctx, struct ntlmssp_state **ntlmssp_state) -{ - *ntlmssp_state = talloc(mem_ctx, struct ntlmssp_state); - if (!*ntlmssp_state) { - DEBUG(0,("ntlmssp_server_start: talloc failed!\n")); - return NT_STATUS_NO_MEMORY; - } - ZERO_STRUCTP(*ntlmssp_state); - - (*ntlmssp_state)->role = NTLMSSP_SERVER; - - (*ntlmssp_state)->get_challenge = get_challenge; - (*ntlmssp_state)->set_challenge = set_challenge; - (*ntlmssp_state)->may_set_challenge = may_set_challenge; - - (*ntlmssp_state)->workstation = NULL; - (*ntlmssp_state)->server_name = lp_netbios_name(); - - (*ntlmssp_state)->get_domain = lp_workgroup; - (*ntlmssp_state)->server_role = ROLE_DOMAIN_MEMBER; /* a good default */ - - (*ntlmssp_state)->expected_state = NTLMSSP_NEGOTIATE; - - (*ntlmssp_state)->allow_lm_key = (lp_lanman_auth() - && lp_parm_bool(-1, "ntlmssp_server", "allow_lm_key", False)); - - (*ntlmssp_state)->server_use_session_keys = True; - (*ntlmssp_state)->server_multiple_authentications = False; - - (*ntlmssp_state)->ref_count = 1; - - (*ntlmssp_state)->neg_flags = - NTLMSSP_NEGOTIATE_NTLM; - - if (lp_parm_bool(-1, "ntlmssp_server", "128bit", True)) { - (*ntlmssp_state)->neg_flags |= NTLMSSP_NEGOTIATE_128; - } - - if (lp_parm_bool(-1, "ntlmssp_server", "keyexchange", True)) { - (*ntlmssp_state)->neg_flags |= NTLMSSP_NEGOTIATE_KEY_EXCH; - } - - if (lp_parm_bool(-1, "ntlmssp_server", "ntlm2", True)) { - (*ntlmssp_state)->neg_flags |= NTLMSSP_NEGOTIATE_NTLM2; - } - - return NT_STATUS_OK; -} - -/********************************************************************* - Client side NTLMSSP -*********************************************************************/ - -/** - * Next state function for the Initial packet - * - * @param ntlmssp_state NTLMSSP State - * @param out_mem_ctx The DATA_BLOB *out will be allocated on this context - * @param in The request, as a DATA_BLOB. reply.data must be NULL - * @param out The reply, as an talloc()ed DATA_BLOB, on out_mem_ctx - * @return Errors or NT_STATUS_OK. - */ - -static NTSTATUS ntlmssp_client_initial(struct ntlmssp_state *ntlmssp_state, - TALLOC_CTX *out_mem_ctx, - DATA_BLOB in, DATA_BLOB *out) -{ - if (ntlmssp_state->unicode) { - ntlmssp_state->neg_flags |= NTLMSSP_NEGOTIATE_UNICODE; - } else { - ntlmssp_state->neg_flags |= NTLMSSP_NEGOTIATE_OEM; - } - - if (ntlmssp_state->use_ntlmv2) { - ntlmssp_state->neg_flags |= NTLMSSP_NEGOTIATE_NTLM2; - } - - /* generate the ntlmssp negotiate packet */ - msrpc_gen(out_mem_ctx, - out, "CddAA", - "NTLMSSP", - NTLMSSP_NEGOTIATE, - ntlmssp_state->neg_flags, - ntlmssp_state->get_domain(), - ntlmssp_state->workstation); - - ntlmssp_state->expected_state = NTLMSSP_CHALLENGE; - - return NT_STATUS_MORE_PROCESSING_REQUIRED; -} - -/** - * Next state function for the Challenge Packet. Generate an auth packet. - * - * @param ntlmssp_state NTLMSSP State - * @param request The request, as a DATA_BLOB. reply.data must be NULL - * @param request The reply, as an allocated DATA_BLOB, caller to free. - * @return Errors or NT_STATUS_OK. - */ - -static NTSTATUS ntlmssp_client_challenge(struct ntlmssp_state *ntlmssp_state, - TALLOC_CTX *out_mem_ctx, - const DATA_BLOB in, DATA_BLOB *out) -{ - uint32_t chal_flags, ntlmssp_command, unkn1, unkn2; - DATA_BLOB server_domain_blob; - DATA_BLOB challenge_blob; - DATA_BLOB struct_blob = data_blob(NULL, 0); - char *server_domain; - const char *chal_parse_string; - const char *auth_gen_string; - uint8_t lm_hash[16]; - DATA_BLOB lm_response = data_blob(NULL, 0); - DATA_BLOB nt_response = data_blob(NULL, 0); - DATA_BLOB session_key = data_blob(NULL, 0); - DATA_BLOB lm_session_key = data_blob(NULL, 0); - DATA_BLOB encrypted_session_key = data_blob(NULL, 0); - NTSTATUS nt_status; - - if (!msrpc_parse(ntlmssp_state, - &in, "CdBd", - "NTLMSSP", - &ntlmssp_command, - &server_domain_blob, - &chal_flags)) { - DEBUG(1, ("Failed to parse the NTLMSSP Challenge: (#1)\n")); - dump_data(2, in.data, in.length); - - return NT_STATUS_INVALID_PARAMETER; - } - - data_blob_free(&server_domain_blob); - - DEBUG(3, ("Got challenge flags:\n")); - debug_ntlmssp_flags(chal_flags); - - ntlmssp_handle_neg_flags(ntlmssp_state, chal_flags, ntlmssp_state->allow_lm_key); - - if (ntlmssp_state->unicode) { - if (chal_flags & NTLMSSP_CHAL_TARGET_INFO) { - chal_parse_string = "CdUdbddB"; - } else { - chal_parse_string = "CdUdbdd"; - } - auth_gen_string = "CdBBUUUBd"; - } else { - if (chal_flags & NTLMSSP_CHAL_TARGET_INFO) { - chal_parse_string = "CdAdbddB"; - } else { - chal_parse_string = "CdAdbdd"; - } - - auth_gen_string = "CdBBAAABd"; - } - - DEBUG(3, ("NTLMSSP: Set final flags:\n")); - debug_ntlmssp_flags(ntlmssp_state->neg_flags); - - if (!msrpc_parse(ntlmssp_state, - &in, chal_parse_string, - "NTLMSSP", - &ntlmssp_command, - &server_domain, - &chal_flags, - &challenge_blob, 8, - &unkn1, &unkn2, - &struct_blob)) { - DEBUG(1, ("Failed to parse the NTLMSSP Challenge: (#2)\n")); - dump_data(2, in.data, in.length); - return NT_STATUS_INVALID_PARAMETER; - } - - ntlmssp_state->server_domain = server_domain; - - if (challenge_blob.length != 8) { - return NT_STATUS_INVALID_PARAMETER; - } - - if (!ntlmssp_state->password) { - static const uint8_t zeros[16]; - /* do nothing - blobs are zero length */ - - /* session key is all zeros */ - session_key = data_blob_talloc(ntlmssp_state, zeros, 16); - lm_session_key = data_blob_talloc(ntlmssp_state, zeros, 16); - - /* not doing NLTM2 without a password */ - ntlmssp_state->neg_flags &= ~NTLMSSP_NEGOTIATE_NTLM2; - } else if (ntlmssp_state->use_ntlmv2) { - - if (!struct_blob.length) { - /* be lazy, match win2k - we can't do NTLMv2 without it */ - DEBUG(1, ("Server did not provide 'target information', required for NTLMv2\n")); - return NT_STATUS_INVALID_PARAMETER; - } - - /* TODO: if the remote server is standalone, then we should replace 'domain' - with the server name as supplied above */ - - if (!SMBNTLMv2encrypt(ntlmssp_state->user, - ntlmssp_state->domain, - ntlmssp_state->password, &challenge_blob, - &struct_blob, - &lm_response, &nt_response, - NULL, &session_key)) { - data_blob_free(&challenge_blob); - data_blob_free(&struct_blob); - return NT_STATUS_NO_MEMORY; - } - - /* LM Key is incompatible... */ - ntlmssp_state->neg_flags &= ~NTLMSSP_NEGOTIATE_LM_KEY; - - } else if (ntlmssp_state->neg_flags & NTLMSSP_NEGOTIATE_NTLM2) { - struct MD5Context md5_session_nonce_ctx; - uint8_t nt_hash[16]; - uint8_t session_nonce[16]; - uint8_t session_nonce_hash[16]; - uint8_t user_session_key[16]; - E_md4hash(ntlmssp_state->password, nt_hash); - - lm_response = data_blob_talloc(ntlmssp_state, NULL, 24); - generate_random_buffer(lm_response.data, 8); - memset(lm_response.data+8, 0, 16); - - memcpy(session_nonce, challenge_blob.data, 8); - memcpy(&session_nonce[8], lm_response.data, 8); - - MD5Init(&md5_session_nonce_ctx); - MD5Update(&md5_session_nonce_ctx, challenge_blob.data, 8); - MD5Update(&md5_session_nonce_ctx, lm_response.data, 8); - MD5Final(session_nonce_hash, &md5_session_nonce_ctx); - - DEBUG(5, ("NTLMSSP challenge set by NTLM2\n")); - DEBUG(5, ("challenge is: \n")); - dump_data(5, session_nonce_hash, 8); - - nt_response = data_blob_talloc(ntlmssp_state, NULL, 24); - SMBNTencrypt(ntlmssp_state->password, - session_nonce_hash, - nt_response.data); - - session_key = data_blob_talloc(ntlmssp_state, NULL, 16); - - SMBsesskeygen_ntv1(nt_hash, user_session_key); - hmac_md5(user_session_key, session_nonce, sizeof(session_nonce), session_key.data); - dump_data_pw("NTLM2 session key:\n", session_key.data, session_key.length); - - /* LM Key is incompatible... */ - ntlmssp_state->neg_flags &= ~NTLMSSP_NEGOTIATE_LM_KEY; - } else { - uint8_t nt_hash[16]; - - if (ntlmssp_state->use_nt_response) { - nt_response = data_blob_talloc(ntlmssp_state, NULL, 24); - SMBNTencrypt(ntlmssp_state->password,challenge_blob.data, - nt_response.data); - E_md4hash(ntlmssp_state->password, nt_hash); - session_key = data_blob_talloc(ntlmssp_state, NULL, 16); - SMBsesskeygen_ntv1(nt_hash, session_key.data); - dump_data_pw("NT session key:\n", session_key.data, session_key.length); - } - - /* lanman auth is insecure, it may be disabled */ - if (lp_client_lanman_auth()) { - lm_response = data_blob_talloc(ntlmssp_state, NULL, 24); - if (!SMBencrypt(ntlmssp_state->password,challenge_blob.data, - lm_response.data)) { - /* If the LM password was too long (and therefore the LM hash being - of the first 14 chars only), don't send it */ - data_blob_free(&lm_response); - - /* LM Key is incompatible with 'long' passwords */ - ntlmssp_state->neg_flags &= ~NTLMSSP_NEGOTIATE_LM_KEY; - } else { - E_deshash(ntlmssp_state->password, lm_hash); - lm_session_key = data_blob_talloc(ntlmssp_state, NULL, 16); - memcpy(lm_session_key.data, lm_hash, 8); - memset(&lm_session_key.data[8], '\0', 8); - - if (!ntlmssp_state->use_nt_response) { - session_key = lm_session_key; - } - } - } else { - /* LM Key is incompatible... */ - ntlmssp_state->neg_flags &= ~NTLMSSP_NEGOTIATE_LM_KEY; - } - } - - if ((ntlmssp_state->neg_flags & NTLMSSP_NEGOTIATE_LM_KEY) - && lp_client_lanman_auth() && lm_session_key.length == 16) { - DATA_BLOB new_session_key = data_blob_talloc(ntlmssp_state, NULL, 16); - if (lm_response.length == 24) { - SMBsesskeygen_lm_sess_key(lm_session_key.data, lm_response.data, - new_session_key.data); - } else { - static const uint8_t zeros[24]; - SMBsesskeygen_lm_sess_key(lm_session_key.data, zeros, - new_session_key.data); - } - new_session_key.length = 16; - session_key = new_session_key; - dump_data_pw("LM session key\n", session_key.data, session_key.length); - } - - - /* Key exchange encryptes a new client-generated session key with - the password-derived key */ - if (ntlmssp_state->neg_flags & NTLMSSP_NEGOTIATE_KEY_EXCH) { - /* Make up a new session key */ - uint8_t client_session_key[16]; - generate_random_buffer(client_session_key, sizeof(client_session_key)); - - /* Encrypt the new session key with the old one */ - encrypted_session_key = data_blob_talloc(ntlmssp_state, - client_session_key, sizeof(client_session_key)); - dump_data_pw("KEY_EXCH session key:\n", encrypted_session_key.data, encrypted_session_key.length); - arcfour_crypt(encrypted_session_key.data, session_key.data, encrypted_session_key.length); - dump_data_pw("KEY_EXCH session key (enc):\n", encrypted_session_key.data, encrypted_session_key.length); - - /* Mark the new session key as the 'real' session key */ - session_key = data_blob_talloc(ntlmssp_state, client_session_key, sizeof(client_session_key)); - } - - /* this generates the actual auth packet */ - if (!msrpc_gen(out_mem_ctx, - out, auth_gen_string, - "NTLMSSP", - NTLMSSP_AUTH, - lm_response.data, lm_response.length, - nt_response.data, nt_response.length, - ntlmssp_state->domain, - ntlmssp_state->user, - ntlmssp_state->workstation, - encrypted_session_key.data, encrypted_session_key.length, - ntlmssp_state->neg_flags)) { - - return NT_STATUS_NO_MEMORY; - } - - ntlmssp_state->session_key = session_key; - - /* The client might be using 56 or 40 bit weakened keys */ - ntlmssp_weaken_keys(ntlmssp_state); - - ntlmssp_state->chal = challenge_blob; - ntlmssp_state->lm_resp = lm_response; - ntlmssp_state->nt_resp = nt_response; - - ntlmssp_state->expected_state = NTLMSSP_DONE; - - nt_status = ntlmssp_sign_init(ntlmssp_state); - if (!NT_STATUS_IS_OK(nt_status)) { - DEBUG(1, ("Could not setup NTLMSSP signing/sealing system (error was: %s)\n", - nt_errstr(nt_status))); - return nt_status; - } - - return nt_status; -} - -static NTSTATUS ntlmssp_client_start(TALLOC_CTX *mem_ctx, struct ntlmssp_state **ntlmssp_state) -{ - *ntlmssp_state = talloc(mem_ctx, struct ntlmssp_state); - if (!*ntlmssp_state) { - DEBUG(0,("ntlmssp_client_start: talloc failed!\n")); - return NT_STATUS_NO_MEMORY; - } - ZERO_STRUCTP(*ntlmssp_state); - - (*ntlmssp_state)->role = NTLMSSP_CLIENT; - - (*ntlmssp_state)->workstation = lp_netbios_name(); - (*ntlmssp_state)->get_domain = lp_workgroup; - - (*ntlmssp_state)->unicode = lp_parm_bool(-1, "ntlmssp_client", "unicode", True); - - (*ntlmssp_state)->use_nt_response = lp_parm_bool(-1, "ntlmssp_client", "send_nt_reponse", True); - - (*ntlmssp_state)->allow_lm_key = (lp_lanman_auth() - && lp_parm_bool(-1, "ntlmssp_client", "allow_lm_key", False)); - - (*ntlmssp_state)->use_ntlmv2 = lp_client_ntlmv2_auth(); - - (*ntlmssp_state)->expected_state = NTLMSSP_INITIAL; - - (*ntlmssp_state)->ref_count = 1; - - (*ntlmssp_state)->neg_flags = - NTLMSSP_NEGOTIATE_NTLM | - NTLMSSP_REQUEST_TARGET; - - if (lp_parm_bool(-1, "ntlmssp_client", "128bit", True)) { - (*ntlmssp_state)->neg_flags |= NTLMSSP_NEGOTIATE_128; - } - - if (lp_parm_bool(-1, "ntlmssp_client", "keyexchange", True)) { - (*ntlmssp_state)->neg_flags |= NTLMSSP_NEGOTIATE_KEY_EXCH; - } - - if (lp_parm_bool(-1, "ntlmssp_client", "ntlm2", True)) { - (*ntlmssp_state)->neg_flags |= NTLMSSP_NEGOTIATE_NTLM2; - } else { - /* apparently we can't do ntlmv2 if we don't do ntlm2 */ - (*ntlmssp_state)->use_ntlmv2 = False; - } - - return NT_STATUS_OK; -} - -/** - * Return the challenge as determined by the authentication subsystem - * @return an 8 byte random challenge - */ - -static const uint8_t *auth_ntlmssp_get_challenge(const struct ntlmssp_state *ntlmssp_state) -{ - struct gensec_ntlmssp_state *gensec_ntlmssp_state = ntlmssp_state->auth_context; - NTSTATUS status; - const uint8_t *chal; - - status = auth_get_challenge(gensec_ntlmssp_state->auth_context, &chal); - if (!NT_STATUS_IS_OK(status)) { - return NULL; - } - - return chal; -} - -/** - * Some authentication methods 'fix' the challenge, so we may not be able to set it - * - * @return If the effective challenge used by the auth subsystem may be modified - */ -static BOOL auth_ntlmssp_may_set_challenge(const struct ntlmssp_state *ntlmssp_state) -{ - struct gensec_ntlmssp_state *gensec_ntlmssp_state = ntlmssp_state->auth_context; - - return auth_challenge_may_be_modified(gensec_ntlmssp_state->auth_context); -} - -/** - * NTLM2 authentication modifies the effective challenge, - * @param challenge The new challenge value - */ -static NTSTATUS auth_ntlmssp_set_challenge(struct ntlmssp_state *ntlmssp_state, DATA_BLOB *challenge) -{ - NTSTATUS nt_status; - struct gensec_ntlmssp_state *gensec_ntlmssp_state = ntlmssp_state->auth_context; - struct auth_context *auth_context = gensec_ntlmssp_state->auth_context; - const uint8_t *chal; - - if (challenge->length != 8) { - return NT_STATUS_INVALID_PARAMETER; - } - - chal = challenge->data; - - nt_status = auth_context_set_challenge(auth_context, chal, "NTLMSSP callback (NTLM2)"); - - return nt_status; -} - -/** - * Check the password on an NTLMSSP login. - * - * Return the session keys used on the connection. - */ - -static NTSTATUS auth_ntlmssp_check_password(struct ntlmssp_state *ntlmssp_state, DATA_BLOB *user_session_key, DATA_BLOB *lm_session_key) -{ - struct gensec_ntlmssp_state *gensec_ntlmssp_state = ntlmssp_state->auth_context; - struct auth_usersupplied_info *user_info = NULL; - NTSTATUS nt_status; - - nt_status = make_user_info_map(ntlmssp_state, - gensec_ntlmssp_state->ntlmssp_state->user, - gensec_ntlmssp_state->ntlmssp_state->domain, - gensec_ntlmssp_state->ntlmssp_state->workstation, - gensec_ntlmssp_state->ntlmssp_state->lm_resp.data ? &gensec_ntlmssp_state->ntlmssp_state->lm_resp : NULL, - gensec_ntlmssp_state->ntlmssp_state->nt_resp.data ? &gensec_ntlmssp_state->ntlmssp_state->nt_resp : NULL, - NULL, NULL, NULL, True, - &user_info); - NT_STATUS_NOT_OK_RETURN(nt_status); - - nt_status = auth_check_password(gensec_ntlmssp_state->auth_context, gensec_ntlmssp_state, - user_info, &gensec_ntlmssp_state->server_info); - talloc_free(user_info); - NT_STATUS_NOT_OK_RETURN(nt_status); - - if (gensec_ntlmssp_state->server_info->user_session_key.length) { - DEBUG(10, ("Got NT session key of length %u\n", gensec_ntlmssp_state->server_info->user_session_key.length)); - *user_session_key = data_blob_talloc(ntlmssp_state, - gensec_ntlmssp_state->server_info->user_session_key.data, - gensec_ntlmssp_state->server_info->user_session_key.length); - } - if (gensec_ntlmssp_state->server_info->lm_session_key.length) { - DEBUG(10, ("Got LM session key of length %u\n", gensec_ntlmssp_state->server_info->lm_session_key.length)); - *lm_session_key = data_blob_talloc(ntlmssp_state, - gensec_ntlmssp_state->server_info->lm_session_key.data, - gensec_ntlmssp_state->server_info->lm_session_key.length); - } - return nt_status; -} - -static NTSTATUS gensec_ntlmssp_start(struct gensec_security *gensec_security) -{ - struct gensec_ntlmssp_state *gensec_ntlmssp_state; - - gensec_ntlmssp_state = talloc(gensec_security, struct gensec_ntlmssp_state); - if (!gensec_ntlmssp_state) { - return NT_STATUS_NO_MEMORY; - } - - gensec_ntlmssp_state->ntlmssp_state = NULL; - gensec_ntlmssp_state->auth_context = NULL; - gensec_ntlmssp_state->server_info = NULL; - gensec_ntlmssp_state->have_features = 0; - - gensec_security->private_data = gensec_ntlmssp_state; - return NT_STATUS_OK; -} - -static NTSTATUS gensec_ntlmssp_server_start(struct gensec_security *gensec_security) -{ - NTSTATUS nt_status; - struct ntlmssp_state *ntlmssp_state; - struct gensec_ntlmssp_state *gensec_ntlmssp_state; - - nt_status = gensec_ntlmssp_start(gensec_security); - NT_STATUS_NOT_OK_RETURN(nt_status); - - gensec_ntlmssp_state = gensec_security->private_data; - - nt_status = ntlmssp_server_start(gensec_ntlmssp_state, &gensec_ntlmssp_state->ntlmssp_state); - NT_STATUS_NOT_OK_RETURN(nt_status); - - if (gensec_security->want_features & GENSEC_FEATURE_SIGN) { - gensec_ntlmssp_state->ntlmssp_state->neg_flags |= NTLMSSP_NEGOTIATE_SIGN; - } - if (gensec_security->want_features & GENSEC_FEATURE_SEAL) { - gensec_ntlmssp_state->ntlmssp_state->neg_flags |= NTLMSSP_NEGOTIATE_SEAL; - } - - nt_status = auth_context_create(gensec_ntlmssp_state, lp_auth_methods(), &gensec_ntlmssp_state->auth_context); - NT_STATUS_NOT_OK_RETURN(nt_status); - - ntlmssp_state = gensec_ntlmssp_state->ntlmssp_state; - ntlmssp_state->auth_context = gensec_ntlmssp_state; - ntlmssp_state->get_challenge = auth_ntlmssp_get_challenge; - ntlmssp_state->may_set_challenge = auth_ntlmssp_may_set_challenge; - ntlmssp_state->set_challenge = auth_ntlmssp_set_challenge; - ntlmssp_state->check_password = auth_ntlmssp_check_password; - ntlmssp_state->server_role = lp_server_role(); - - return NT_STATUS_OK; -} - -static NTSTATUS gensec_ntlmssp_client_start(struct gensec_security *gensec_security) -{ - struct gensec_ntlmssp_state *gensec_ntlmssp_state; - const char *password = NULL; - NTSTATUS nt_status; - - nt_status = gensec_ntlmssp_start(gensec_security); - NT_STATUS_NOT_OK_RETURN(nt_status); - - gensec_ntlmssp_state = gensec_security->private_data; - nt_status = ntlmssp_client_start(gensec_ntlmssp_state, - &gensec_ntlmssp_state->ntlmssp_state); - NT_STATUS_NOT_OK_RETURN(nt_status); - - if (gensec_security->want_features & GENSEC_FEATURE_SESSION_KEY) { - /* - * We need to set this to allow a later SetPassword - * via the SAMR pipe to succeed. Strange.... We could - * also add NTLMSSP_NEGOTIATE_SEAL here. JRA. - * - * Without this, Windows will not create the master key - * that it thinks is only used for NTLMSSP signing and - * sealing. (It is actually pulled out and used directly) - */ - gensec_ntlmssp_state->ntlmssp_state->neg_flags |= NTLMSSP_NEGOTIATE_SIGN; - } - if (gensec_security->want_features & GENSEC_FEATURE_SIGN) { - gensec_ntlmssp_state->ntlmssp_state->neg_flags |= NTLMSSP_NEGOTIATE_SIGN; - } - if (gensec_security->want_features & GENSEC_FEATURE_SEAL) { - gensec_ntlmssp_state->ntlmssp_state->neg_flags |= NTLMSSP_NEGOTIATE_SEAL; - } - - nt_status = ntlmssp_set_domain(gensec_ntlmssp_state->ntlmssp_state, - cli_credentials_get_domain(gensec_security->credentials)); - NT_STATUS_NOT_OK_RETURN(nt_status); - - nt_status = ntlmssp_set_username(gensec_ntlmssp_state->ntlmssp_state, - cli_credentials_get_username(gensec_security->credentials)); - NT_STATUS_NOT_OK_RETURN(nt_status); - - password = cli_credentials_get_password(gensec_security->credentials); - - nt_status = ntlmssp_set_password(gensec_ntlmssp_state->ntlmssp_state, password); - NT_STATUS_NOT_OK_RETURN(nt_status); - - nt_status = ntlmssp_set_workstation(gensec_ntlmssp_state->ntlmssp_state, - cli_credentials_get_workstation(gensec_security->credentials)); - - gensec_security->private_data = gensec_ntlmssp_state; - - return NT_STATUS_OK; -} - -/** - * Return the credentials of a logged on user, including session keys - * etc. - * - * Only valid after a successful authentication - * - * May only be called once per authentication. - * - */ - -static NTSTATUS gensec_ntlmssp_session_info(struct gensec_security *gensec_security, - struct auth_session_info **session_info) -{ - NTSTATUS nt_status; - struct gensec_ntlmssp_state *gensec_ntlmssp_state = gensec_security->private_data; - - nt_status = auth_generate_session_info(gensec_ntlmssp_state, gensec_ntlmssp_state->server_info, session_info); - NT_STATUS_NOT_OK_RETURN(nt_status); - - (*session_info)->session_key = data_blob_talloc(*session_info, - gensec_ntlmssp_state->ntlmssp_state->session_key.data, - gensec_ntlmssp_state->ntlmssp_state->session_key.length); - - return NT_STATUS_OK; -} - -static BOOL gensec_ntlmssp_have_feature(struct gensec_security *gensec_security, - uint32_t feature) -{ - struct gensec_ntlmssp_state *gensec_ntlmssp_state = gensec_security->private_data; - if (gensec_ntlmssp_state->have_features & feature) { - return True; - } - - return False; -} - -static const struct gensec_security_ops gensec_ntlmssp_security_ops = { - .name = "ntlmssp", - .sasl_name = "NTLM", - .auth_type = DCERPC_AUTH_TYPE_NTLMSSP, - .oid = GENSEC_OID_NTLMSSP, - .client_start = gensec_ntlmssp_client_start, - .server_start = gensec_ntlmssp_server_start, - .update = gensec_ntlmssp_update, - .sig_size = gensec_ntlmssp_sig_size, - .sign_packet = gensec_ntlmssp_sign_packet, - .check_packet = gensec_ntlmssp_check_packet, - .seal_packet = gensec_ntlmssp_seal_packet, - .unseal_packet = gensec_ntlmssp_unseal_packet, - .wrap = gensec_ntlmssp_wrap, - .unwrap = gensec_ntlmssp_unwrap, - .session_key = gensec_ntlmssp_session_key, - .session_info = gensec_ntlmssp_session_info, - .have_feature = gensec_ntlmssp_have_feature, - .enabled = True -}; - - -NTSTATUS gensec_ntlmssp_init(void) -{ - NTSTATUS ret; - ret = gensec_register(&gensec_ntlmssp_security_ops); - if (!NT_STATUS_IS_OK(ret)) { - DEBUG(0,("Failed to register '%s' gensec backend!\n", - gensec_ntlmssp_security_ops.name)); - return ret; - } - - return ret; -} diff --git a/source4/auth/gensec/ntlmssp.h b/source4/auth/gensec/ntlmssp.h deleted file mode 100644 index 0fe04a7c0f..0000000000 --- a/source4/auth/gensec/ntlmssp.h +++ /dev/null @@ -1,198 +0,0 @@ -/* - Unix SMB/CIFS implementation. - SMB parameters and setup - Copyright (C) Andrew Tridgell 1992-1997 - Copyright (C) Luke Kenneth Casson Leighton 1996-1997 - Copyright (C) Paul Ashton 1997 - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -*/ - -#include "librpc/gen_ndr/ndr_samr.h" - -/* NTLMSSP mode */ -enum ntlmssp_role -{ - NTLMSSP_SERVER, - NTLMSSP_CLIENT -}; - -/* NTLMSSP message types */ -enum ntlmssp_message_type -{ - NTLMSSP_INITIAL = 0 /* samba internal state */, - NTLMSSP_NEGOTIATE = 1, - NTLMSSP_CHALLENGE = 2, - NTLMSSP_AUTH = 3, - NTLMSSP_UNKNOWN = 4, - NTLMSSP_DONE = 5 /* samba final state */ -}; - -/* NTLMSSP negotiation flags */ -#define NTLMSSP_NEGOTIATE_UNICODE 0x00000001 -#define NTLMSSP_NEGOTIATE_OEM 0x00000002 -#define NTLMSSP_REQUEST_TARGET 0x00000004 -#define NTLMSSP_NEGOTIATE_SIGN 0x00000010 /* Message integrity */ -#define NTLMSSP_NEGOTIATE_SEAL 0x00000020 /* Message confidentiality */ -#define NTLMSSP_NEGOTIATE_DATAGRAM_STYLE 0x00000040 -#define NTLMSSP_NEGOTIATE_LM_KEY 0x00000080 -#define NTLMSSP_NEGOTIATE_NETWARE 0x00000100 -#define NTLMSSP_NEGOTIATE_NTLM 0x00000200 -#define NTLMSSP_NEGOTIATE_DOMAIN_SUPPLIED 0x00001000 -#define NTLMSSP_NEGOTIATE_WORKSTATION_SUPPLIED 0x00002000 -#define NTLMSSP_NEGOTIATE_THIS_IS_LOCAL_CALL 0x00004000 -#define NTLMSSP_NEGOTIATE_ALWAYS_SIGN 0x00008000 -#define NTLMSSP_TARGET_TYPE_DOMAIN 0x10000 -#define NTLMSSP_TARGET_TYPE_SERVER 0x20000 -#define NTLMSSP_CHAL_INIT_RESPONSE 0x00010000 - -#define NTLMSSP_CHAL_ACCEPT_RESPONSE 0x00020000 -#define NTLMSSP_CHAL_NON_NT_SESSION_KEY 0x00040000 -#define NTLMSSP_NEGOTIATE_NTLM2 0x00080000 -#define NTLMSSP_CHAL_TARGET_INFO 0x00800000 -#define NTLMSSP_NEGOTIATE_128 0x20000000 /* 128-bit encryption */ -#define NTLMSSP_NEGOTIATE_KEY_EXCH 0x40000000 -#define NTLMSSP_NEGOTIATE_56 0x80000000 - -#define NTLMSSP_NAME_TYPE_SERVER 0x01 -#define NTLMSSP_NAME_TYPE_DOMAIN 0x02 -#define NTLMSSP_NAME_TYPE_SERVER_DNS 0x03 -#define NTLMSSP_NAME_TYPE_DOMAIN_DNS 0x04 - -#define NTLMSSP_SIGN_VERSION 1 - -#define NTLMSSP_SIG_SIZE 16 - -struct ntlmssp_state -{ - uint_t ref_count; - enum ntlmssp_role role; - enum samr_Role server_role; - uint32_t expected_state; - - BOOL unicode; - BOOL use_ntlmv2; - BOOL use_nt_response; /* Set to 'False' to debug what happens when the NT response is omited */ - BOOL allow_lm_key; /* The LM_KEY code is not functional at this point, and it's not - very secure anyway */ - - BOOL server_use_session_keys; /* Set to 'False' for authentication only, - that will never return a session key */ - BOOL server_multiple_authentications; /* Set to 'True' to allow squid 2.5 - style 'challenge caching' */ - - char *user; - char *domain; - const char *workstation; - char *password; - char *server_domain; - - DATA_BLOB internal_chal; /* Random challenge as supplied to the client for NTLM authentication */ - - DATA_BLOB chal; /* Random challenge as input into the actual NTLM (or NTLM2) authentication */ - DATA_BLOB lm_resp; - DATA_BLOB nt_resp; - DATA_BLOB session_key; - - uint32_t neg_flags; /* the current state of negotiation with the NTLMSSP partner */ - - /* internal variables used by NTLM2 */ - BOOL doing_ntlm2; - uint8_t session_nonce[16]; - - /* internal variables used by KEY_EXCH (client-supplied user session key */ - DATA_BLOB encrypted_session_key; - - void *auth_context; - - /** - * Callback to get the 'challenge' used for NTLM authentication. - * - * @param ntlmssp_state This structure - * @return 8 bytes of challenge data, determined by the server to be the challenge for NTLM authentication - * - */ - const uint8_t *(*get_challenge)(const struct ntlmssp_state *ntlmssp_state); - - /** - * Callback to find if the challenge used by NTLM authentication may be modified - * - * The NTLM2 authentication scheme modifies the effective challenge, but this is not compatiable with the - * current 'security=server' implementation.. - * - * @param ntlmssp_state This structure - * @return Can the challenge be set to arbitary values? - * - */ - BOOL (*may_set_challenge)(const struct ntlmssp_state *ntlmssp_state); - - /** - * Callback to set the 'challenge' used for NTLM authentication. - * - * The callback may use the void *auth_context to store state information, but the same value is always available - * from the DATA_BLOB chal on this structure. - * - * @param ntlmssp_state This structure - * @param challange 8 bytes of data, agreed by the client and server to be the effective challenge for NTLM2 authentication - * - */ - NTSTATUS (*set_challenge)(struct ntlmssp_state *ntlmssp_state, DATA_BLOB *challenge); - - /** - * Callback to check the user's password. - * - * The callback must reads the feilds of this structure for the information it needs on the user - * @param ntlmssp_state This structure - * @param nt_session_key If an NT session key is returned by the authentication process, return it here - * @param lm_session_key If an LM session key is returned by the authentication process, return it here - * - */ - NTSTATUS (*check_password)(struct ntlmssp_state *ntlmssp_state, DATA_BLOB *nt_session_key, DATA_BLOB *lm_session_key); - - const char *server_name; - const char *(*get_domain)(void); - - /* SMB Signing */ - uint32_t ntlm_seq_num; - uint32_t ntlm2_send_seq_num; - uint32_t ntlm2_recv_seq_num; - - /* ntlmv2 */ - DATA_BLOB send_sign_key; - DATA_BLOB send_seal_key; - DATA_BLOB recv_sign_key; - DATA_BLOB recv_seal_key; - - uint8_t send_seal_hash[258]; - uint8_t recv_seal_hash[258]; - - /* ntlmv1 */ - uint8_t ntlmssp_hash[258]; - - /* it turns out that we don't always get the - response in at the time we want to process it. - Store it here, until we need it */ - DATA_BLOB stored_response; - -}; - -struct gensec_ntlmssp_state { - struct auth_context *auth_context; - struct auth_serversupplied_info *server_info; - struct ntlmssp_state *ntlmssp_state; - uint32_t have_features; -}; - - diff --git a/source4/auth/gensec/ntlmssp_parse.c b/source4/auth/gensec/ntlmssp_parse.c deleted file mode 100644 index 42546cb130..0000000000 --- a/source4/auth/gensec/ntlmssp_parse.c +++ /dev/null @@ -1,338 +0,0 @@ -/* - Unix SMB/CIFS implementation. - simple kerberos5/SPNEGO routines - Copyright (C) Andrew Tridgell 2001 - Copyright (C) Jim McDonough <jmcd@us.ibm.com> 2002 - Copyright (C) Andrew Bartlett 2002-2003 - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -*/ - -#include "includes.h" -#include "pstring.h" - -/* - this is a tiny msrpc packet generator. I am only using this to - avoid tying this code to a particular varient of our rpc code. This - generator is not general enough for all our rpc needs, its just - enough for the spnego/ntlmssp code - - format specifiers are: - - U = unicode string (input is unix string) - a = address (input is char *unix_string) - (1 byte type, 1 byte length, unicode/ASCII string, all inline) - A = ASCII string (input is unix string) - B = data blob (pointer + length) - b = data blob in header (pointer + length) - D - d = word (4 bytes) - C = constant ascii string - */ -BOOL msrpc_gen(TALLOC_CTX *mem_ctx, DATA_BLOB *blob, - const char *format, ...) -{ - int i; - ssize_t n; - va_list ap; - char *s; - uint8_t *b; - int head_size=0, data_size=0; - int head_ofs, data_ofs; - int *intargs; - - DATA_BLOB *pointers; - - pointers = talloc_array(mem_ctx, DATA_BLOB, strlen(format)); - intargs = talloc_array(pointers, int, strlen(format)); - - /* first scan the format to work out the header and body size */ - va_start(ap, format); - for (i=0; format[i]; i++) { - switch (format[i]) { - case 'U': - s = va_arg(ap, char *); - head_size += 8; - n = push_ucs2_talloc(pointers, (void **)&pointers[i].data, s); - if (n == -1) { - return False; - } - pointers[i].length = n; - pointers[i].length -= 2; - data_size += pointers[i].length; - break; - case 'A': - s = va_arg(ap, char *); - head_size += 8; - n = push_ascii_talloc(pointers, (char **)&pointers[i].data, s); - if (n == -1) { - return False; - } - pointers[i].length = n; - pointers[i].length -= 1; - data_size += pointers[i].length; - break; - case 'a': - n = va_arg(ap, int); - intargs[i] = n; - s = va_arg(ap, char *); - n = push_ucs2_talloc(pointers, (void **)&pointers[i].data, s); - if (n == -1) { - return False; - } - pointers[i].length = n; - pointers[i].length -= 2; - data_size += pointers[i].length + 4; - break; - case 'B': - b = va_arg(ap, uint8_t *); - head_size += 8; - pointers[i].data = b; - pointers[i].length = va_arg(ap, int); - data_size += pointers[i].length; - break; - case 'b': - b = va_arg(ap, uint8_t *); - pointers[i].data = b; - pointers[i].length = va_arg(ap, int); - head_size += pointers[i].length; - break; - case 'd': - n = va_arg(ap, int); - intargs[i] = n; - head_size += 4; - break; - case 'C': - s = va_arg(ap, char *); - pointers[i].data = (uint8_t *)s; - pointers[i].length = strlen(s)+1; - head_size += pointers[i].length; - break; - } - } - va_end(ap); - - /* allocate the space, then scan the format again to fill in the values */ - *blob = data_blob_talloc(mem_ctx, NULL, head_size + data_size); - - head_ofs = 0; - data_ofs = head_size; - - va_start(ap, format); - for (i=0; format[i]; i++) { - switch (format[i]) { - case 'U': - case 'A': - case 'B': - n = pointers[i].length; - SSVAL(blob->data, head_ofs, n); head_ofs += 2; - SSVAL(blob->data, head_ofs, n); head_ofs += 2; - SIVAL(blob->data, head_ofs, data_ofs); head_ofs += 4; - if (pointers[i].data && n) /* don't follow null pointers... */ - memcpy(blob->data+data_ofs, pointers[i].data, n); - data_ofs += n; - break; - case 'a': - n = intargs[i]; - SSVAL(blob->data, data_ofs, n); data_ofs += 2; - - n = pointers[i].length; - SSVAL(blob->data, data_ofs, n); data_ofs += 2; - if (n >= 0) { - memcpy(blob->data+data_ofs, pointers[i].data, n); - } - data_ofs += n; - break; - case 'd': - n = intargs[i]; - SIVAL(blob->data, head_ofs, n); - head_ofs += 4; - break; - case 'b': - n = pointers[i].length; - memcpy(blob->data + head_ofs, pointers[i].data, n); - head_ofs += n; - break; - case 'C': - n = pointers[i].length; - memcpy(blob->data + head_ofs, pointers[i].data, n); - head_ofs += n; - break; - } - } - va_end(ap); - - talloc_free(pointers); - - return True; -} - - -/* a helpful macro to avoid running over the end of our blob */ -#define NEED_DATA(amount) \ -if ((head_ofs + amount) > blob->length) { \ - return False; \ -} - -/* - this is a tiny msrpc packet parser. This the the partner of msrpc_gen - - format specifiers are: - - U = unicode string (output is unix string) - A = ascii string - B = data blob - b = data blob in header - d = word (4 bytes) - C = constant ascii string - */ - -BOOL msrpc_parse(TALLOC_CTX *mem_ctx, const DATA_BLOB *blob, - const char *format, ...) -{ - int i; - va_list ap; - const char **ps, *s; - DATA_BLOB *b; - size_t head_ofs = 0; - uint16_t len1, len2; - uint32_t ptr; - uint32_t *v; - pstring p; - - va_start(ap, format); - for (i=0; format[i]; i++) { - switch (format[i]) { - case 'U': - NEED_DATA(8); - len1 = SVAL(blob->data, head_ofs); head_ofs += 2; - len2 = SVAL(blob->data, head_ofs); head_ofs += 2; - ptr = IVAL(blob->data, head_ofs); head_ofs += 4; - - ps = (const char **)va_arg(ap, char **); - if (len1 == 0 && len2 == 0) { - *ps = ""; - } else { - /* make sure its in the right format - be strict */ - if ((len1 != len2) || (ptr + len1 < ptr) || (ptr + len1 < len1) || (ptr + len1 > blob->length)) { - return False; - } - if (len1 & 1) { - /* if odd length and unicode */ - return False; - } - if (blob->data + ptr < (uint8_t *)ptr || blob->data + ptr < blob->data) - return False; - - if (0 < len1) { - pull_string(p, blob->data + ptr, sizeof(p), - len1, - STR_UNICODE|STR_NOALIGN); - (*ps) = talloc_strdup(mem_ctx, p); - if (!(*ps)) { - return False; - } - } else { - (*ps) = ""; - } - } - break; - case 'A': - NEED_DATA(8); - len1 = SVAL(blob->data, head_ofs); head_ofs += 2; - len2 = SVAL(blob->data, head_ofs); head_ofs += 2; - ptr = IVAL(blob->data, head_ofs); head_ofs += 4; - - ps = (const char **)va_arg(ap, char **); - /* make sure its in the right format - be strict */ - if (len1 == 0 && len2 == 0) { - *ps = ""; - } else { - if ((len1 != len2) || (ptr + len1 < ptr) || (ptr + len1 < len1) || (ptr + len1 > blob->length)) { - return False; - } - - if (blob->data + ptr < (uint8_t *)ptr || blob->data + ptr < blob->data) - return False; - - if (0 < len1) { - pull_string(p, blob->data + ptr, sizeof(p), - len1, - STR_ASCII|STR_NOALIGN); - (*ps) = talloc_strdup(mem_ctx, p); - if (!(*ps)) { - return False; - } - } else { - (*ps) = ""; - } - } - break; - case 'B': - NEED_DATA(8); - len1 = SVAL(blob->data, head_ofs); head_ofs += 2; - len2 = SVAL(blob->data, head_ofs); head_ofs += 2; - ptr = IVAL(blob->data, head_ofs); head_ofs += 4; - - b = (DATA_BLOB *)va_arg(ap, void *); - if (len1 == 0 && len2 == 0) { - *b = data_blob_talloc(mem_ctx, NULL, 0); - } else { - /* make sure its in the right format - be strict */ - if ((len1 != len2) || (ptr + len1 < ptr) || (ptr + len1 < len1) || (ptr + len1 > blob->length)) { - return False; - } - - if (blob->data + ptr < (uint8_t *)ptr || blob->data + ptr < blob->data) - return False; - - *b = data_blob_talloc(mem_ctx, blob->data + ptr, len1); - } - break; - case 'b': - b = (DATA_BLOB *)va_arg(ap, void *); - len1 = va_arg(ap, uint_t); - /* make sure its in the right format - be strict */ - NEED_DATA(len1); - if (blob->data + head_ofs < (uint8_t *)head_ofs || blob->data + head_ofs < blob->data) - return False; - - *b = data_blob_talloc(mem_ctx, blob->data + head_ofs, len1); - head_ofs += len1; - break; - case 'd': - v = va_arg(ap, uint32_t *); - NEED_DATA(4); - *v = IVAL(blob->data, head_ofs); head_ofs += 4; - break; - case 'C': - s = va_arg(ap, char *); - - if (blob->data + head_ofs < (uint8_t *)head_ofs || blob->data + head_ofs < blob->data) - return False; - - head_ofs += pull_string(p, blob->data+head_ofs, sizeof(p), - blob->length - head_ofs, - STR_ASCII|STR_TERMINATE); - if (strcmp(s, p) != 0) { - return False; - } - break; - } - } - va_end(ap); - - return True; -} diff --git a/source4/auth/gensec/ntlmssp_sign.c b/source4/auth/gensec/ntlmssp_sign.c deleted file mode 100644 index dba3dbee29..0000000000 --- a/source4/auth/gensec/ntlmssp_sign.c +++ /dev/null @@ -1,555 +0,0 @@ -/* - * Unix SMB/CIFS implementation. - * Version 3.0 - * NTLMSSP Signing routines - * Copyright (C) Luke Kenneth Casson Leighton 1996-2001 - * Copyright (C) Andrew Bartlett <abartlet@samba.org> 2003-2005 - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - */ - -#include "includes.h" -#include "auth/auth.h" -#include "lib/crypto/crypto.h" - -#define CLI_SIGN "session key to client-to-server signing key magic constant" -#define CLI_SEAL "session key to client-to-server sealing key magic constant" -#define SRV_SIGN "session key to server-to-client signing key magic constant" -#define SRV_SEAL "session key to server-to-client sealing key magic constant" - -/** - * Some notes on then NTLM2 code: - * - * NTLM2 is a AEAD system. This means that the data encrypted is not - * all the data that is signed. In DCE-RPC case, the headers of the - * DCE-RPC packets are also signed. This prevents some of the - * fun-and-games one might have by changing them. - * - */ - -static void calc_ntlmv2_key(TALLOC_CTX *mem_ctx, - DATA_BLOB *subkey, - DATA_BLOB session_key, - const char *constant) -{ - struct MD5Context ctx3; - *subkey = data_blob_talloc(mem_ctx, NULL, 16); - MD5Init(&ctx3); - MD5Update(&ctx3, session_key.data, session_key.length); - MD5Update(&ctx3, constant, strlen(constant)+1); - MD5Final(subkey->data, &ctx3); -} - -enum ntlmssp_direction { - NTLMSSP_SEND, - NTLMSSP_RECEIVE -}; - -static NTSTATUS ntlmssp_make_packet_signature(struct ntlmssp_state *ntlmssp_state, - TALLOC_CTX *sig_mem_ctx, - const uint8_t *data, size_t length, - const uint8_t *whole_pdu, size_t pdu_length, - enum ntlmssp_direction direction, - DATA_BLOB *sig, BOOL encrypt_sig) -{ - if (ntlmssp_state->neg_flags & NTLMSSP_NEGOTIATE_NTLM2) { - - HMACMD5Context ctx; - uint8_t digest[16]; - uint8_t seq_num[4]; - - *sig = data_blob_talloc(sig_mem_ctx, NULL, NTLMSSP_SIG_SIZE); - if (!sig->data) { - return NT_STATUS_NO_MEMORY; - } - - switch (direction) { - case NTLMSSP_SEND: - SIVAL(seq_num, 0, ntlmssp_state->ntlm2_send_seq_num); - ntlmssp_state->ntlm2_send_seq_num++; - hmac_md5_init_limK_to_64(ntlmssp_state->send_sign_key.data, - ntlmssp_state->send_sign_key.length, &ctx); - break; - case NTLMSSP_RECEIVE: - SIVAL(seq_num, 0, ntlmssp_state->ntlm2_recv_seq_num); - ntlmssp_state->ntlm2_recv_seq_num++; - hmac_md5_init_limK_to_64(ntlmssp_state->recv_sign_key.data, - ntlmssp_state->recv_sign_key.length, &ctx); - break; - } - hmac_md5_update(seq_num, sizeof(seq_num), &ctx); - hmac_md5_update(whole_pdu, pdu_length, &ctx); - hmac_md5_final(digest, &ctx); - - if (encrypt_sig && ntlmssp_state->neg_flags & NTLMSSP_NEGOTIATE_KEY_EXCH) { - switch (direction) { - case NTLMSSP_SEND: - arcfour_crypt_sbox(ntlmssp_state->send_seal_hash, digest, 8); - break; - case NTLMSSP_RECEIVE: - arcfour_crypt_sbox(ntlmssp_state->recv_seal_hash, digest, 8); - break; - } - } - - SIVAL(sig->data, 0, NTLMSSP_SIGN_VERSION); - memcpy(sig->data + 4, digest, 8); - memcpy(sig->data + 12, seq_num, 4); - - } else { - uint32_t crc; - crc = crc32_calc_buffer(data, length); - if (!msrpc_gen(sig_mem_ctx, sig, "dddd", NTLMSSP_SIGN_VERSION, 0, crc, ntlmssp_state->ntlm_seq_num)) { - return NT_STATUS_NO_MEMORY; - } - ntlmssp_state->ntlm_seq_num++; - - arcfour_crypt_sbox(ntlmssp_state->ntlmssp_hash, sig->data+4, sig->length-4); - } - dump_data_pw("calculated ntlmssp signature\n", sig->data, sig->length); - return NT_STATUS_OK; -} - -NTSTATUS gensec_ntlmssp_sign_packet(struct gensec_security *gensec_security, - TALLOC_CTX *sig_mem_ctx, - const uint8_t *data, size_t length, - const uint8_t *whole_pdu, size_t pdu_length, - DATA_BLOB *sig) -{ - struct gensec_ntlmssp_state *gensec_ntlmssp_state = gensec_security->private_data; - struct ntlmssp_state *ntlmssp_state = gensec_ntlmssp_state->ntlmssp_state; - - if (!ntlmssp_state->session_key.length) { - DEBUG(3, ("NO session key, cannot check sign packet\n")); - return NT_STATUS_NO_USER_SESSION_KEY; - } - - if (!ntlmssp_state->neg_flags & NTLMSSP_NEGOTIATE_SIGN) { - DEBUG(3, ("NTLMSSP Signing not negotiated - cannot sign packet!\n")); - return NT_STATUS_INVALID_PARAMETER; - } - - return ntlmssp_make_packet_signature(ntlmssp_state, sig_mem_ctx, - data, length, - whole_pdu, pdu_length, - NTLMSSP_SEND, sig, True); -} - -/** - * Check the signature of an incoming packet - * - */ - -NTSTATUS gensec_ntlmssp_check_packet(struct gensec_security *gensec_security, - TALLOC_CTX *sig_mem_ctx, - const uint8_t *data, size_t length, - const uint8_t *whole_pdu, size_t pdu_length, - const DATA_BLOB *sig) -{ - struct gensec_ntlmssp_state *gensec_ntlmssp_state = gensec_security->private_data; - struct ntlmssp_state *ntlmssp_state = gensec_ntlmssp_state->ntlmssp_state; - - DATA_BLOB local_sig; - NTSTATUS nt_status; - - if (!ntlmssp_state->session_key.length) { - DEBUG(3, ("NO session key, cannot check packet signature\n")); - return NT_STATUS_NO_USER_SESSION_KEY; - } - - if (sig->length < 8) { - DEBUG(0, ("NTLMSSP packet check failed due to short signature (%lu bytes)!\n", - (unsigned long)sig->length)); - } - - nt_status = ntlmssp_make_packet_signature(ntlmssp_state, sig_mem_ctx, - data, length, - whole_pdu, pdu_length, - NTLMSSP_RECEIVE, &local_sig, True); - - if (!NT_STATUS_IS_OK(nt_status)) { - DEBUG(0, ("NTLMSSP packet check failed with %s\n", nt_errstr(nt_status))); - return nt_status; - } - - if (ntlmssp_state->neg_flags & NTLMSSP_NEGOTIATE_NTLM2) { - if (local_sig.length != sig->length || - memcmp(local_sig.data, - sig->data, sig->length) != 0) { - DEBUG(5, ("BAD SIG NTLM2: wanted signature of\n")); - dump_data(5, local_sig.data, local_sig.length); - - DEBUG(5, ("BAD SIG: got signature of\n")); - dump_data(5, sig->data, sig->length); - - DEBUG(0, ("NTLMSSP NTLM2 packet check failed due to invalid signature!\n")); - return NT_STATUS_ACCESS_DENIED; - } - } else { - if (local_sig.length != sig->length || - memcmp(local_sig.data + 8, - sig->data + 8, sig->length - 8) != 0) { - DEBUG(5, ("BAD SIG NTLM1: wanted signature of\n")); - dump_data(5, local_sig.data, local_sig.length); - - DEBUG(5, ("BAD SIG: got signature of\n")); - dump_data(5, sig->data, sig->length); - - DEBUG(0, ("NTLMSSP NTLM1 packet check failed due to invalid signature!\n")); - return NT_STATUS_ACCESS_DENIED; - } - } - dump_data_pw("checked ntlmssp signature\n", sig->data, sig->length); - - return NT_STATUS_OK; -} - - -/** - * Seal data with the NTLMSSP algorithm - * - */ - -NTSTATUS gensec_ntlmssp_seal_packet(struct gensec_security *gensec_security, - TALLOC_CTX *sig_mem_ctx, - uint8_t *data, size_t length, - const uint8_t *whole_pdu, size_t pdu_length, - DATA_BLOB *sig) -{ - struct gensec_ntlmssp_state *gensec_ntlmssp_state = gensec_security->private_data; - struct ntlmssp_state *ntlmssp_state = gensec_ntlmssp_state->ntlmssp_state; - NTSTATUS nt_status; - if (!ntlmssp_state->session_key.length) { - DEBUG(3, ("NO session key, cannot seal packet\n")); - return NT_STATUS_NO_USER_SESSION_KEY; - } - - if (!ntlmssp_state->neg_flags & NTLMSSP_NEGOTIATE_SEAL) { - DEBUG(3, ("NTLMSSP Sealing not negotiated - cannot seal packet!\n")); - return NT_STATUS_INVALID_PARAMETER; - } - - DEBUG(10,("ntlmssp_seal_data: seal\n")); - dump_data_pw("ntlmssp clear data\n", data, length); - if (ntlmssp_state->neg_flags & NTLMSSP_NEGOTIATE_NTLM2) { - /* The order of these two operations matters - we must first seal the packet, - then seal the sequence number - this is becouse the send_seal_hash is not - constant, but is is rather updated with each iteration */ - nt_status = ntlmssp_make_packet_signature(ntlmssp_state, sig_mem_ctx, - data, length, - whole_pdu, pdu_length, - NTLMSSP_SEND, sig, False); - arcfour_crypt_sbox(ntlmssp_state->send_seal_hash, data, length); - if (ntlmssp_state->neg_flags & NTLMSSP_NEGOTIATE_KEY_EXCH) { - arcfour_crypt_sbox(ntlmssp_state->send_seal_hash, sig->data+4, 8); - } - } else { - uint32_t crc; - crc = crc32_calc_buffer(data, length); - if (!msrpc_gen(sig_mem_ctx, sig, "dddd", NTLMSSP_SIGN_VERSION, 0, crc, ntlmssp_state->ntlm_seq_num)) { - return NT_STATUS_NO_MEMORY; - } - - /* The order of these two operations matters - we must - first seal the packet, then seal the sequence - number - this is becouse the ntlmssp_hash is not - constant, but is is rather updated with each - iteration */ - - arcfour_crypt_sbox(ntlmssp_state->ntlmssp_hash, data, length); - arcfour_crypt_sbox(ntlmssp_state->ntlmssp_hash, sig->data+4, sig->length-4); - /* increment counter on send */ - ntlmssp_state->ntlm_seq_num++; - nt_status = NT_STATUS_OK; - } - dump_data_pw("ntlmssp signature\n", sig->data, sig->length); - dump_data_pw("ntlmssp sealed data\n", data, length); - - - return nt_status; -} - -/** - * Unseal data with the NTLMSSP algorithm - * - */ - -/* - wrappers for the ntlmssp_*() functions -*/ -NTSTATUS gensec_ntlmssp_unseal_packet(struct gensec_security *gensec_security, - TALLOC_CTX *sig_mem_ctx, - uint8_t *data, size_t length, - const uint8_t *whole_pdu, size_t pdu_length, - const DATA_BLOB *sig) -{ - struct gensec_ntlmssp_state *gensec_ntlmssp_state = gensec_security->private_data; - struct ntlmssp_state *ntlmssp_state = gensec_ntlmssp_state->ntlmssp_state; - DATA_BLOB local_sig; - NTSTATUS nt_status; - if (!ntlmssp_state->session_key.length) { - DEBUG(3, ("NO session key, cannot unseal packet\n")); - return NT_STATUS_NO_USER_SESSION_KEY; - } - - dump_data_pw("ntlmssp sealed data\n", data, length); - if (ntlmssp_state->neg_flags & NTLMSSP_NEGOTIATE_NTLM2) { - arcfour_crypt_sbox(ntlmssp_state->recv_seal_hash, data, length); - - nt_status = ntlmssp_make_packet_signature(ntlmssp_state, sig_mem_ctx, - data, length, - whole_pdu, pdu_length, - NTLMSSP_RECEIVE, &local_sig, True); - if (!NT_STATUS_IS_OK(nt_status)) { - return nt_status; - } - - if (local_sig.length != sig->length || - memcmp(local_sig.data, - sig->data, sig->length) != 0) { - DEBUG(5, ("BAD SIG NTLM2: wanted signature of\n")); - dump_data(5, local_sig.data, local_sig.length); - - DEBUG(5, ("BAD SIG: got signature of\n")); - dump_data(5, sig->data, sig->length); - - DEBUG(0, ("NTLMSSP NTLM2 packet check failed due to invalid signature!\n")); - return NT_STATUS_ACCESS_DENIED; - } - - dump_data_pw("ntlmssp clear data\n", data, length); - return NT_STATUS_OK; - } else { - arcfour_crypt_sbox(ntlmssp_state->ntlmssp_hash, data, length); - dump_data_pw("ntlmssp clear data\n", data, length); - return gensec_ntlmssp_check_packet(gensec_security, sig_mem_ctx, data, length, whole_pdu, pdu_length, sig); - } -} - -/** - Initialise the state for NTLMSSP signing. -*/ -NTSTATUS ntlmssp_sign_init(struct ntlmssp_state *ntlmssp_state) -{ - uint8_t p24[24]; - ZERO_STRUCT(p24); - - DEBUG(3, ("NTLMSSP Sign/Seal - Initialising with flags:\n")); - debug_ntlmssp_flags(ntlmssp_state->neg_flags); - - if (!ntlmssp_state->session_key.length) { - DEBUG(3, ("NO session key, cannot intialise signing\n")); - return NT_STATUS_NO_USER_SESSION_KEY; - } - - if (ntlmssp_state->neg_flags & NTLMSSP_NEGOTIATE_NTLM2) - { - DATA_BLOB weak_session_key = ntlmssp_state->session_key; - const char *send_sign_const; - const char *send_seal_const; - const char *recv_sign_const; - const char *recv_seal_const; - - switch (ntlmssp_state->role) { - case NTLMSSP_CLIENT: - send_sign_const = CLI_SIGN; - send_seal_const = CLI_SEAL; - recv_sign_const = SRV_SIGN; - recv_seal_const = SRV_SEAL; - break; - case NTLMSSP_SERVER: - send_sign_const = SRV_SIGN; - send_seal_const = SRV_SEAL; - recv_sign_const = CLI_SIGN; - recv_seal_const = CLI_SEAL; - break; - default: - return NT_STATUS_INTERNAL_ERROR; - } - - /** - Weaken NTLMSSP keys to cope with down-level clients, servers and export restrictions. - - We probably should have some parameters to control this, once we get NTLM2 working. - */ - - - if (ntlmssp_state->neg_flags & NTLMSSP_NEGOTIATE_128) { - - } else if (ntlmssp_state->neg_flags & NTLMSSP_NEGOTIATE_56) { - weak_session_key.length = 6; - } else { /* forty bits */ - weak_session_key.length = 5; - } - dump_data_pw("NTLMSSP weakend master key:\n", - weak_session_key.data, - weak_session_key.length); - - /* SEND */ - calc_ntlmv2_key(ntlmssp_state, - &ntlmssp_state->send_sign_key, - ntlmssp_state->session_key, send_sign_const); - dump_data_pw("NTLMSSP send sign key:\n", - ntlmssp_state->send_sign_key.data, - ntlmssp_state->send_sign_key.length); - - calc_ntlmv2_key(ntlmssp_state, - &ntlmssp_state->send_seal_key, - weak_session_key, send_seal_const); - dump_data_pw("NTLMSSP send seal key:\n", - ntlmssp_state->send_seal_key.data, - ntlmssp_state->send_seal_key.length); - - arcfour_init(ntlmssp_state->send_seal_hash, - &ntlmssp_state->send_seal_key); - - dump_data_pw("NTLMSSP send sesl hash:\n", - ntlmssp_state->send_seal_hash, - sizeof(ntlmssp_state->send_seal_hash)); - - /* RECV */ - calc_ntlmv2_key(ntlmssp_state, - &ntlmssp_state->recv_sign_key, - ntlmssp_state->session_key, recv_sign_const); - dump_data_pw("NTLMSSP recv sign key:\n", - ntlmssp_state->recv_sign_key.data, - ntlmssp_state->recv_sign_key.length); - - calc_ntlmv2_key(ntlmssp_state, - &ntlmssp_state->recv_seal_key, - weak_session_key, recv_seal_const); - dump_data_pw("NTLMSSP recv seal key:\n", - ntlmssp_state->recv_seal_key.data, - ntlmssp_state->recv_seal_key.length); - arcfour_init(ntlmssp_state->recv_seal_hash, - &ntlmssp_state->recv_seal_key); - - dump_data_pw("NTLMSSP receive seal hash:\n", - ntlmssp_state->recv_seal_hash, - sizeof(ntlmssp_state->recv_seal_hash)); - } else { - DEBUG(5, ("NTLMSSP Sign/Seal - using NTLM1\n")); - - arcfour_init(ntlmssp_state->ntlmssp_hash, - &ntlmssp_state->session_key); - dump_data_pw("NTLMSSP hash:\n", ntlmssp_state->ntlmssp_hash, - sizeof(ntlmssp_state->ntlmssp_hash)); - } - - ntlmssp_state->ntlm_seq_num = 0; - ntlmssp_state->ntlm2_send_seq_num = 0; - ntlmssp_state->ntlm2_recv_seq_num = 0; - - return NT_STATUS_OK; -} - -size_t gensec_ntlmssp_sig_size(struct gensec_security *gensec_security) -{ - return NTLMSSP_SIG_SIZE; -} - -NTSTATUS gensec_ntlmssp_wrap(struct gensec_security *gensec_security, - TALLOC_CTX *sig_mem_ctx, - const DATA_BLOB *in, - DATA_BLOB *out) -{ - struct gensec_ntlmssp_state *gensec_ntlmssp_state = gensec_security->private_data; - DATA_BLOB sig; - NTSTATUS nt_status; - - if (gensec_ntlmssp_state->ntlmssp_state->neg_flags & NTLMSSP_NEGOTIATE_SEAL) { - - *out = data_blob_talloc(sig_mem_ctx, NULL, in->length + NTLMSSP_SIG_SIZE); - memcpy(out->data + NTLMSSP_SIG_SIZE, in->data, in->length); - - nt_status = gensec_ntlmssp_seal_packet(gensec_security, sig_mem_ctx, - out->data + NTLMSSP_SIG_SIZE, - out->length - NTLMSSP_SIG_SIZE, - out->data + NTLMSSP_SIG_SIZE, - out->length - NTLMSSP_SIG_SIZE, - &sig); - - if (NT_STATUS_IS_OK(nt_status)) { - memcpy(out->data, sig.data, NTLMSSP_SIG_SIZE); - } - return nt_status; - - } else if ((gensec_ntlmssp_state->ntlmssp_state->neg_flags & NTLMSSP_NEGOTIATE_SIGN) - || (gensec_ntlmssp_state->ntlmssp_state->neg_flags & NTLMSSP_NEGOTIATE_ALWAYS_SIGN)) { - - *out = data_blob_talloc(sig_mem_ctx, NULL, in->length + NTLMSSP_SIG_SIZE); - memcpy(out->data + NTLMSSP_SIG_SIZE, in->data, in->length); - - nt_status = gensec_ntlmssp_sign_packet(gensec_security, sig_mem_ctx, - out->data + NTLMSSP_SIG_SIZE, - out->length - NTLMSSP_SIG_SIZE, - out->data + NTLMSSP_SIG_SIZE, - out->length - NTLMSSP_SIG_SIZE, - &sig); - - if (NT_STATUS_IS_OK(nt_status)) { - memcpy(out->data, sig.data, NTLMSSP_SIG_SIZE); - } - return nt_status; - - } else { - *out = *in; - return NT_STATUS_OK; - } -} - - -NTSTATUS gensec_ntlmssp_unwrap(struct gensec_security *gensec_security, - TALLOC_CTX *sig_mem_ctx, - const DATA_BLOB *in, - DATA_BLOB *out) -{ - struct gensec_ntlmssp_state *gensec_ntlmssp_state = gensec_security->private_data; - DATA_BLOB sig; - - if (gensec_ntlmssp_state->ntlmssp_state->neg_flags & NTLMSSP_NEGOTIATE_SEAL) { - if (in->length < NTLMSSP_SIG_SIZE) { - return NT_STATUS_INVALID_PARAMETER; - } - sig.data = in->data; - sig.length = NTLMSSP_SIG_SIZE; - - *out = data_blob_talloc(sig_mem_ctx, in->data + NTLMSSP_SIG_SIZE, in->length - NTLMSSP_SIG_SIZE); - - return gensec_ntlmssp_unseal_packet(gensec_security, sig_mem_ctx, - out->data, out->length, - out->data, out->length, - &sig); - - } else if ((gensec_ntlmssp_state->ntlmssp_state->neg_flags & NTLMSSP_NEGOTIATE_SIGN) - || (gensec_ntlmssp_state->ntlmssp_state->neg_flags & NTLMSSP_NEGOTIATE_ALWAYS_SIGN)) { - if (in->length < NTLMSSP_SIG_SIZE) { - return NT_STATUS_INVALID_PARAMETER; - } - sig.data = in->data; - sig.length = NTLMSSP_SIG_SIZE; - - *out = data_blob_talloc(sig_mem_ctx, in->data + NTLMSSP_SIG_SIZE, in->length - NTLMSSP_SIG_SIZE); - - return gensec_ntlmssp_check_packet(gensec_security, sig_mem_ctx, - out->data, out->length, - out->data, out->length, - &sig); - } else { - *out = *in; - return NT_STATUS_OK; - } -} - |