📄 ntlmssp.c
字号:
/* Unix SMB/Netbios implementation. Version 3.0 handle NLTMSSP, server side Copyright (C) Andrew Tridgell 2001 Copyright (C) Andrew Bartlett 2001-2003 Copyright (C) Andrew Bartlett 2005 (Updated from gensec). 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"static NTSTATUS ntlmssp_client_initial(struct ntlmssp_state *ntlmssp_state, DATA_BLOB reply, DATA_BLOB *next_request);static NTSTATUS ntlmssp_server_negotiate(struct ntlmssp_state *ntlmssp_state, const DATA_BLOB in, DATA_BLOB *out);static NTSTATUS ntlmssp_client_challenge(struct ntlmssp_state *ntlmssp_state, const DATA_BLOB reply, DATA_BLOB *next_request);static NTSTATUS ntlmssp_server_auth(struct ntlmssp_state *ntlmssp_state, const DATA_BLOB request, DATA_BLOB *reply);/** * Callbacks for NTLMSSP - for both client and server operating modes * */static const struct ntlmssp_callbacks { enum NTLMSSP_ROLE role; enum NTLM_MESSAGE_TYPE ntlmssp_command; NTSTATUS (*fn)(struct ntlmssp_state *ntlmssp_state, 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}, {NTLMSSP_CLIENT, NTLMSSP_UNKNOWN, NULL}, {NTLMSSP_SERVER, NTLMSSP_UNKNOWN, NULL}};/** * Print out the NTLMSSP flags for debugging * @param neg_flags The flags from the packet */void debug_ntlmssp_flags(uint32 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_DATAGRAM_STYLE) DEBUGADD(4, (" NTLMSSP_NEGOTIATE_DATAGRAM_STYLE\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_CHAL_ACCEPT_RESPONSE) DEBUGADD(4, (" NTLMSSP_CHAL_ACCEPT_RESPONSE\n")); if (neg_flags & NTLMSSP_CHAL_NON_NT_SESSION_KEY) DEBUGADD(4, (" NTLMSSP_CHAL_NON_NT_SESSION_KEY\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")); if (neg_flags & NTLMSSP_NEGOTIATE_56) DEBUGADD(4, (" NTLMSSP_NEGOTIATE_56\n"));}/** * Default challenge generation code. * */ static const uint8 *get_challenge(const struct ntlmssp_state *ntlmssp_state){ static uchar chal[8]; generate_random_buffer(chal, sizeof(chal)); 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(NTLMSSP_STATE *ntlmssp_state, const char *user) { ntlmssp_state->user = talloc_strdup(ntlmssp_state->mem_ctx, user ? 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(NTLMSSP_STATE *ntlmssp_state, const char *password) { if (!password) { ntlmssp_state->password = NULL; } else { ntlmssp_state->password = talloc_strdup(ntlmssp_state->mem_ctx, 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(NTLMSSP_STATE *ntlmssp_state, const char *domain) { ntlmssp_state->domain = talloc_strdup(ntlmssp_state->mem_ctx, domain ? 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(NTLMSSP_STATE *ntlmssp_state, const char *workstation) { ntlmssp_state->workstation = talloc_strdup(ntlmssp_state->mem_ctx, 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(NTLMSSP_STATE *ntlmssp_state, DATA_BLOB response) { ntlmssp_state->stored_response = data_blob_talloc(ntlmssp_state->mem_ctx, response.data, response.length); return NT_STATUS_OK;}/** * Next state function for the NTLMSSP state machine * * @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. */NTSTATUS ntlmssp_update(NTLMSSP_STATE *ntlmssp_state, const DATA_BLOB in, DATA_BLOB *out) { DATA_BLOB input; uint32 ntlmssp_command; int i; if (ntlmssp_state->expected_state == NTLMSSP_DONE) { /* Called update after negotiations finished. */ DEBUG(1, ("Called NTLMSSP after state machine was 'done'\n")); return NT_STATUS_INVALID_PARAMETER; } *out = data_blob(NULL, 0); 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(&input, "Cd", "NTLMSSP", &ntlmssp_command)) { DEBUG(1, ("Failed to parse NTLMSSP packet, could not extract NTLMSSP command\n")); dump_data(2, (const char *)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; ntlmssp_callbacks[i].fn; i++) { if (ntlmssp_callbacks[i].role == ntlmssp_state->role && ntlmssp_callbacks[i].ntlmssp_command == ntlmssp_command) { return ntlmssp_callbacks[i].fn(ntlmssp_state, input, out); } } DEBUG(1, ("failed to find NTLMSSP callback for NTLMSSP mode %u, command %u\n", ntlmssp_state->role, ntlmssp_command)); return NT_STATUS_INVALID_PARAMETER;}/** * End an NTLMSSP state machine * * @param ntlmssp_state NTLMSSP State, free()ed by this function */void ntlmssp_end(NTLMSSP_STATE **ntlmssp_state){ TALLOC_CTX *mem_ctx = (*ntlmssp_state)->mem_ctx; (*ntlmssp_state)->ref_count--; if ((*ntlmssp_state)->ref_count == 0) { data_blob_free(&(*ntlmssp_state)->chal); data_blob_free(&(*ntlmssp_state)->lm_resp); data_blob_free(&(*ntlmssp_state)->nt_resp); talloc_destroy(mem_ctx); } *ntlmssp_state = NULL; return;}/** * 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 neg_flags, uint32 *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->get_global_myname(); } 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 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) { /* other end forcing us to use LM */ ntlmssp_state->neg_flags |= NTLMSSP_NEGOTIATE_LM_KEY; ntlmssp_state->use_ntlmv2 = False; } 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_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
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -