📄 ntlm_auth.c
字号:
/* Unix SMB/CIFS implementation. Winbind status program. Copyright (C) Tim Potter 2000-2003 Copyright (C) Andrew Bartlett <abartlet@samba.org> 2003-2004 Copyright (C) Francesco Chemolli <kinkie@kame.usr.dsi.unimi.it> 2000 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 "utils/ntlm_auth.h"#undef DBGC_CLASS#define DBGC_CLASS DBGC_WINBIND#define SQUID_BUFFER_SIZE 2010enum stdio_helper_mode { SQUID_2_4_BASIC, SQUID_2_5_BASIC, SQUID_2_5_NTLMSSP, NTLMSSP_CLIENT_1, GSS_SPNEGO, GSS_SPNEGO_CLIENT, NTLM_SERVER_1, NUM_HELPER_MODES};typedef void (*stdio_helper_function)(enum stdio_helper_mode stdio_helper_mode, char *buf, int length);static void manage_squid_basic_request (enum stdio_helper_mode stdio_helper_mode, char *buf, int length);static void manage_squid_ntlmssp_request (enum stdio_helper_mode stdio_helper_mode, char *buf, int length);static void manage_client_ntlmssp_request (enum stdio_helper_mode stdio_helper_mode, char *buf, int length);static void manage_gss_spnego_request (enum stdio_helper_mode stdio_helper_mode, char *buf, int length);static void manage_gss_spnego_client_request (enum stdio_helper_mode stdio_helper_mode, char *buf, int length);static void manage_ntlm_server_1_request (enum stdio_helper_mode stdio_helper_mode, char *buf, int length);static const struct { enum stdio_helper_mode mode; const char *name; stdio_helper_function fn;} stdio_helper_protocols[] = { { SQUID_2_4_BASIC, "squid-2.4-basic", manage_squid_basic_request}, { SQUID_2_5_BASIC, "squid-2.5-basic", manage_squid_basic_request}, { SQUID_2_5_NTLMSSP, "squid-2.5-ntlmssp", manage_squid_ntlmssp_request}, { NTLMSSP_CLIENT_1, "ntlmssp-client-1", manage_client_ntlmssp_request}, { GSS_SPNEGO, "gss-spnego", manage_gss_spnego_request}, { GSS_SPNEGO_CLIENT, "gss-spnego-client", manage_gss_spnego_client_request}, { NTLM_SERVER_1, "ntlm-server-1", manage_ntlm_server_1_request}, { NUM_HELPER_MODES, NULL, NULL}};extern int winbindd_fd;const char *opt_username;const char *opt_domain;const char *opt_workstation;const char *opt_password;static DATA_BLOB opt_challenge;static DATA_BLOB opt_lm_response;static DATA_BLOB opt_nt_response;static int request_lm_key;static int request_user_session_key;static const char *require_membership_of;static const char *require_membership_of_sid;static char winbind_separator(void){ struct winbindd_response response; static BOOL got_sep; static char sep; if (got_sep) return sep; ZERO_STRUCT(response); /* Send off request */ if (winbindd_request_response(WINBINDD_INFO, NULL, &response) != NSS_STATUS_SUCCESS) { d_printf("could not obtain winbind separator!\n"); return *lp_winbind_separator(); } sep = response.data.info.winbind_separator; got_sep = True; if (!sep) { d_printf("winbind separator was NULL!\n"); return *lp_winbind_separator(); } return sep;}const char *get_winbind_domain(void){ struct winbindd_response response; static fstring winbind_domain; if (*winbind_domain) { return winbind_domain; } ZERO_STRUCT(response); /* Send off request */ if (winbindd_request_response(WINBINDD_DOMAIN_NAME, NULL, &response) != NSS_STATUS_SUCCESS) { DEBUG(0, ("could not obtain winbind domain name!\n")); return lp_workgroup(); } fstrcpy(winbind_domain, response.data.domain_name); return winbind_domain;}const char *get_winbind_netbios_name(void){ struct winbindd_response response; static fstring winbind_netbios_name; if (*winbind_netbios_name) { return winbind_netbios_name; } ZERO_STRUCT(response); /* Send off request */ if (winbindd_request_response(WINBINDD_NETBIOS_NAME, NULL, &response) != NSS_STATUS_SUCCESS) { DEBUG(0, ("could not obtain winbind netbios name!\n")); return global_myname(); } fstrcpy(winbind_netbios_name, response.data.netbios_name); return winbind_netbios_name;}DATA_BLOB get_challenge(void) { static DATA_BLOB chal; if (opt_challenge.length) return opt_challenge; chal = data_blob(NULL, 8); generate_random_buffer(chal.data, chal.length); return chal;}/* Copy of parse_domain_user from winbindd_util.c. Parse a string of the form DOMAIN/user into a domain and a user */static BOOL parse_ntlm_auth_domain_user(const char *domuser, fstring domain, fstring user){ char *p = strchr(domuser,winbind_separator()); if (!p) { return False; } fstrcpy(user, p+1); fstrcpy(domain, domuser); domain[PTR_DIFF(p, domuser)] = 0; strupper_m(domain); return True;}static BOOL get_require_membership_sid(void) { struct winbindd_request request; struct winbindd_response response; if (!require_membership_of) { return True; } if (require_membership_of_sid) { return True; } /* Otherwise, ask winbindd for the name->sid request */ ZERO_STRUCT(request); ZERO_STRUCT(response); if (!parse_ntlm_auth_domain_user(require_membership_of, request.data.name.dom_name, request.data.name.name)) { DEBUG(0, ("Could not parse %s into seperate domain/name parts!\n", require_membership_of)); return False; } if (winbindd_request_response(WINBINDD_LOOKUPNAME, &request, &response) != NSS_STATUS_SUCCESS) { DEBUG(0, ("Winbindd lookupname failed to resolve %s into a SID!\n", require_membership_of)); return False; } require_membership_of_sid = SMB_STRDUP(response.data.sid.sid); if (require_membership_of_sid) return True; return False;}/* Authenticate a user with a plaintext password */static BOOL check_plaintext_auth(const char *user, const char *pass, BOOL stdout_diagnostics){ struct winbindd_request request; struct winbindd_response response; NSS_STATUS result; if (!get_require_membership_sid()) { return False; } /* Send off request */ ZERO_STRUCT(request); ZERO_STRUCT(response); fstrcpy(request.data.auth.user, user); fstrcpy(request.data.auth.pass, pass); if (require_membership_of_sid) fstrcpy(request.data.auth.require_membership_of_sid, require_membership_of_sid); result = winbindd_request_response(WINBINDD_PAM_AUTH, &request, &response); /* Display response */ if (stdout_diagnostics) { if ((result != NSS_STATUS_SUCCESS) && (response.data.auth.nt_status == 0)) { d_printf("Reading winbind reply failed! (0x01)\n"); } d_printf("%s: %s (0x%x)\n", response.data.auth.nt_status_string, response.data.auth.error_string, response.data.auth.nt_status); } else { if ((result != NSS_STATUS_SUCCESS) && (response.data.auth.nt_status == 0)) { DEBUG(1, ("Reading winbind reply failed! (0x01)\n")); } DEBUG(3, ("%s: %s (0x%x)\n", response.data.auth.nt_status_string, response.data.auth.error_string, response.data.auth.nt_status)); } return (result == NSS_STATUS_SUCCESS);}/* authenticate a user with an encrypted username/password */NTSTATUS contact_winbind_auth_crap(const char *username, const char *domain, const char *workstation, const DATA_BLOB *challenge, const DATA_BLOB *lm_response, const DATA_BLOB *nt_response, uint32 flags, uint8 lm_key[8], uint8 user_session_key[16], char **error_string, char **unix_name) { NTSTATUS nt_status; NSS_STATUS result; struct winbindd_request request; struct winbindd_response response; if (!get_require_membership_sid()) { return NT_STATUS_INVALID_PARAMETER; } ZERO_STRUCT(request); ZERO_STRUCT(response); request.flags = flags; request.data.auth_crap.logon_parameters = MSV1_0_ALLOW_WORKSTATION_TRUST_ACCOUNT | MSV1_0_ALLOW_SERVER_TRUST_ACCOUNT; if (require_membership_of_sid) fstrcpy(request.data.auth_crap.require_membership_of_sid, require_membership_of_sid); fstrcpy(request.data.auth_crap.user, username); fstrcpy(request.data.auth_crap.domain, domain); fstrcpy(request.data.auth_crap.workstation, workstation); memcpy(request.data.auth_crap.chal, challenge->data, MIN(challenge->length, 8)); if (lm_response && lm_response->length) { memcpy(request.data.auth_crap.lm_resp, lm_response->data, MIN(lm_response->length, sizeof(request.data.auth_crap.lm_resp))); request.data.auth_crap.lm_resp_len = lm_response->length; } if (nt_response && nt_response->length) { memcpy(request.data.auth_crap.nt_resp, nt_response->data, MIN(nt_response->length, sizeof(request.data.auth_crap.nt_resp))); request.data.auth_crap.nt_resp_len = nt_response->length; } result = winbindd_request_response(WINBINDD_PAM_AUTH_CRAP, &request, &response); /* Display response */ if ((result != NSS_STATUS_SUCCESS) && (response.data.auth.nt_status == 0)) { nt_status = NT_STATUS_UNSUCCESSFUL; if (error_string) *error_string = smb_xstrdup("Reading winbind reply failed!"); free_response(&response); return nt_status; } nt_status = (NT_STATUS(response.data.auth.nt_status)); if (!NT_STATUS_IS_OK(nt_status)) { if (error_string) *error_string = smb_xstrdup(response.data.auth.error_string); free_response(&response); return nt_status; } if ((flags & WBFLAG_PAM_LMKEY) && lm_key) { memcpy(lm_key, response.data.auth.first_8_lm_hash, sizeof(response.data.auth.first_8_lm_hash)); } if ((flags & WBFLAG_PAM_USER_SESSION_KEY) && user_session_key) { memcpy(user_session_key, response.data.auth.user_session_key, sizeof(response.data.auth.user_session_key)); } if (flags & WBFLAG_PAM_UNIX_NAME) { *unix_name = SMB_STRDUP((char *)response.extra_data); if (!*unix_name) { free_response(&response); return NT_STATUS_NO_MEMORY; } } free_response(&response); return nt_status;} static NTSTATUS winbind_pw_check(struct ntlmssp_state *ntlmssp_state, DATA_BLOB *user_session_key, DATA_BLOB *lm_session_key) { static const char zeros[16]; NTSTATUS nt_status; char *error_string; uint8 lm_key[8]; uint8 user_sess_key[16]; char *unix_name; nt_status = contact_winbind_auth_crap(ntlmssp_state->user, ntlmssp_state->domain, ntlmssp_state->workstation, &ntlmssp_state->chal, &ntlmssp_state->lm_resp, &ntlmssp_state->nt_resp, WBFLAG_PAM_LMKEY | WBFLAG_PAM_USER_SESSION_KEY | WBFLAG_PAM_UNIX_NAME, lm_key, user_sess_key, &error_string, &unix_name); if (NT_STATUS_IS_OK(nt_status)) { if (memcmp(lm_key, zeros, 8) != 0) { *lm_session_key = data_blob(NULL, 16); memcpy(lm_session_key->data, lm_key, 8); memset(lm_session_key->data+8, '\0', 8); } if (memcmp(user_sess_key, zeros, 16) != 0) { *user_session_key = data_blob(user_sess_key, 16); } ntlmssp_state->auth_context = talloc_strdup(ntlmssp_state->mem_ctx, unix_name); SAFE_FREE(unix_name); } else { DEBUG(NT_STATUS_EQUAL(nt_status, NT_STATUS_ACCESS_DENIED) ? 0 : 3, ("Login for user [%s]\\[%s]@[%s] failed due to [%s]\n", ntlmssp_state->domain, ntlmssp_state->user, ntlmssp_state->workstation, error_string ? error_string : "unknown error (NULL)")); ntlmssp_state->auth_context = NULL; } return nt_status;}static NTSTATUS local_pw_check(struct ntlmssp_state *ntlmssp_state, DATA_BLOB *user_session_key, DATA_BLOB *lm_session_key) { NTSTATUS nt_status; uint8 lm_pw[16], nt_pw[16]; nt_lm_owf_gen (opt_password, nt_pw, lm_pw); nt_status = ntlm_password_check(ntlmssp_state->mem_ctx, &ntlmssp_state->chal, &ntlmssp_state->lm_resp, &ntlmssp_state->nt_resp, NULL, NULL, ntlmssp_state->user, ntlmssp_state->user, ntlmssp_state->domain, lm_pw, nt_pw, user_session_key, lm_session_key); if (NT_STATUS_IS_OK(nt_status)) { ntlmssp_state->auth_context = talloc_asprintf(ntlmssp_state->mem_ctx, "%s%c%s", ntlmssp_state->domain, *lp_winbind_separator(), ntlmssp_state->user); } else { DEBUG(3, ("Login for user [%s]\\[%s]@[%s] failed due to [%s]\n", ntlmssp_state->domain, ntlmssp_state->user, ntlmssp_state->workstation, nt_errstr(nt_status))); ntlmssp_state->auth_context = NULL; } return nt_status;}static NTSTATUS ntlm_auth_start_ntlmssp_client(NTLMSSP_STATE **client_ntlmssp_state) { NTSTATUS status; if ( (opt_username == NULL) || (opt_domain == NULL) ) { status = NT_STATUS_UNSUCCESSFUL;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -