ntlm_auth.c
来自「samba最新软件」· C语言 代码 · 共 1,160 行 · 第 1/3 页
C
1,160 行
/* 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 3 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, see <http://www.gnu.org/licenses/>.*/#include "includes.h"#include "system/filesys.h"#include "lib/cmdline/popt_common.h"#include "lib/ldb/include/ldb.h"#include "auth/credentials/credentials.h"#include "auth/gensec/gensec.h"#include "auth/auth.h"#include "librpc/gen_ndr/ndr_netlogon.h"#include "auth/auth_sam.h"#include "auth/ntlm/ntlm_check.h"#include "pstring.h"#include "libcli/auth/libcli_auth.h"#include "libcli/security/security.h"#include "lib/events/events.h"#include "lib/messaging/messaging.h"#include "lib/messaging/irpc.h"#include "auth/ntlmssp/ntlmssp.h"#include "param/param.h"#define INITIAL_BUFFER_SIZE 300#define MAX_BUFFER_SIZE 63000enum stdio_helper_mode { SQUID_2_4_BASIC, SQUID_2_5_BASIC, SQUID_2_5_NTLMSSP, NTLMSSP_CLIENT_1, GSS_SPNEGO_CLIENT, GSS_SPNEGO_SERVER, NTLM_SERVER_1, NUM_HELPER_MODES};#define NTLM_AUTH_FLAG_USER_SESSION_KEY 0x0004#define NTLM_AUTH_FLAG_LMKEY 0x0008typedef void (*stdio_helper_function)(enum stdio_helper_mode stdio_helper_mode, struct loadparm_context *lp_ctx, char *buf, int length, void **private, unsigned int mux_id, void **private2);static void manage_squid_basic_request (enum stdio_helper_mode stdio_helper_mode, struct loadparm_context *lp_ctx, char *buf, int length, void **private, unsigned int mux_id, void **private2);static void manage_gensec_request (enum stdio_helper_mode stdio_helper_mode, struct loadparm_context *lp_ctx, char *buf, int length, void **private, unsigned int mux_id, void **private2);static void manage_ntlm_server_1_request (enum stdio_helper_mode stdio_helper_mode, struct loadparm_context *lp_ctx, char *buf, int length, void **private, unsigned int mux_id, void **private2);static void manage_squid_request(struct loadparm_context *lp_ctx, enum stdio_helper_mode helper_mode, stdio_helper_function fn, void **private2);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_gensec_request}, { GSS_SPNEGO_CLIENT, "gss-spnego-client", manage_gensec_request}, { GSS_SPNEGO_SERVER, "gss-spnego", manage_gensec_request}, { NTLMSSP_CLIENT_1, "ntlmssp-client-1", manage_gensec_request}, { NTLM_SERVER_1, "ntlm-server-1", manage_ntlm_server_1_request}, { NUM_HELPER_MODES, NULL, NULL}};extern int winbindd_fd;static const char *opt_username;static const char *opt_domain;static const char *opt_workstation;static const char *opt_password;static int opt_multiplex;static int use_cached_creds;static void mux_printf(unsigned int mux_id, const char *format, ...) PRINTF_ATTRIBUTE(2, 3);static void mux_printf(unsigned int mux_id, const char *format, ...){ va_list ap; if (opt_multiplex) { x_fprintf(x_stdout, "%d ", mux_id); } va_start(ap, format); x_vfprintf(x_stdout, format, ap); va_end(ap);}/* 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 winbind_separator){ char *p = strchr(domuser, winbind_separator); if (!p) { return false; } fstrcpy(user, p+1); fstrcpy(domain, domuser); domain[PTR_DIFF(p, domuser)] = 0; return true;}/** * Decode a base64 string into a DATA_BLOB - simple and slow algorithm **/static DATA_BLOB base64_decode_data_blob(TALLOC_CTX *mem_ctx, const char *s){ DATA_BLOB ret = data_blob_talloc(mem_ctx, s, strlen(s)+1); ret.length = ldb_base64_decode((char *)ret.data); return ret;}/** * Encode a base64 string into a talloc()ed string caller to free. **/static char *base64_encode_data_blob(TALLOC_CTX *mem_ctx, DATA_BLOB data){ return ldb_base64_encode(mem_ctx, (const char *)data.data, data.length);}/** * Decode a base64 string in-place - wrapper for the above **/static void base64_decode_inplace(char *s){ ldb_base64_decode(s);}/* Authenticate a user with a plaintext password */static bool check_plaintext_auth(const char *user, const char *pass, bool stdout_diagnostics){ return (strcmp(pass, opt_password) == 0);}/* authenticate a user with an encrypted username/password */static NTSTATUS local_pw_check_specified(struct loadparm_context *lp_ctx, const char *username, const char *domain, const char *workstation, const DATA_BLOB *challenge, const DATA_BLOB *lm_response, const DATA_BLOB *nt_response, uint32_t flags, DATA_BLOB *lm_session_key, DATA_BLOB *user_session_key, char **error_string, char **unix_name) { NTSTATUS nt_status; struct samr_Password lm_pw, nt_pw; struct samr_Password *lm_pwd, *nt_pwd; TALLOC_CTX *mem_ctx = talloc_init("local_pw_check_specified"); if (!mem_ctx) { nt_status = NT_STATUS_NO_MEMORY; } else { E_md4hash(opt_password, nt_pw.hash); if (E_deshash(opt_password, lm_pw.hash)) { lm_pwd = &lm_pw; } else { lm_pwd = NULL; } nt_pwd = &nt_pw; nt_status = ntlm_password_check(mem_ctx, lp_ctx, MSV1_0_ALLOW_SERVER_TRUST_ACCOUNT | MSV1_0_ALLOW_WORKSTATION_TRUST_ACCOUNT, challenge, lm_response, nt_response, username, username, domain, lm_pwd, nt_pwd, user_session_key, lm_session_key); if (NT_STATUS_IS_OK(nt_status)) { if (unix_name) { asprintf(unix_name, "%s%c%s", domain, *lp_winbind_separator(lp_ctx), username); } } else { DEBUG(3, ("Login for user [%s]\\[%s]@[%s] failed due to [%s]\n", domain, username, workstation, nt_errstr(nt_status))); } talloc_free(mem_ctx); } if (error_string) { *error_string = strdup(nt_errstr(nt_status)); } return nt_status; }static void manage_squid_basic_request(enum stdio_helper_mode stdio_helper_mode, struct loadparm_context *lp_ctx, char *buf, int length, void **private, unsigned int mux_id, void **private2) { char *user, *pass; user=buf; pass = memchr(buf, ' ', length); if (!pass) { DEBUG(2, ("Password not found. Denying access\n")); mux_printf(mux_id, "ERR\n"); return; } *pass='\0'; pass++; if (stdio_helper_mode == SQUID_2_5_BASIC) { rfc1738_unescape(user); rfc1738_unescape(pass); } if (check_plaintext_auth(user, pass, false)) { mux_printf(mux_id, "OK\n"); } else { mux_printf(mux_id, "ERR\n"); }}/* This is a bit hairy, but the basic idea is to do a password callback to the calling application. The callback comes from within gensec */static void manage_gensec_get_pw_request(enum stdio_helper_mode stdio_helper_mode, struct loadparm_context *lp_ctx, char *buf, int length, void **private, unsigned int mux_id, void **password) { DATA_BLOB in; if (strlen(buf) < 2) { DEBUG(1, ("query [%s] invalid", buf)); mux_printf(mux_id, "BH Query invalid\n"); return; } if (strlen(buf) > 3) { in = base64_decode_data_blob(NULL, buf + 3); } else { in = data_blob(NULL, 0); } if (strncmp(buf, "PW ", 3) == 0) { *password = talloc_strndup(*private /* hopefully the right gensec context, useful to use for talloc */, (const char *)in.data, in.length); if (*password == NULL) { DEBUG(1, ("Out of memory\n")); mux_printf(mux_id, "BH Out of memory\n"); data_blob_free(&in); return; } mux_printf(mux_id, "OK\n"); data_blob_free(&in); return; } DEBUG(1, ("Asked for (and expected) a password\n")); mux_printf(mux_id, "BH Expected a password\n"); data_blob_free(&in);}/** * Callback for password credentials. This is not async, and when * GENSEC and the credentials code is made async, it will look rather * different. */static const char *get_password(struct cli_credentials *credentials) { char *password = NULL; /* Ask for a password */ mux_printf((unsigned int)credentials->priv_data, "PW\n"); credentials->priv_data = NULL; manage_squid_request(cmdline_lp_ctx, NUM_HELPER_MODES /* bogus */, manage_gensec_get_pw_request, (void **)&password); return password;}/** Check if a string is part of a list.**/static bool in_list(const char *s, const char *list, bool casesensitive){ char *tok; size_t tok_len = 1024; const char *p=list; if (!list) return false; tok = (char *)malloc(tok_len); if (!tok) { return false; } while (next_token(&p, tok, LIST_SEP, tok_len)) { if ((casesensitive?strcmp:strcasecmp_m)(tok,s) == 0) { free(tok); return true; } } free(tok); return false;}static void gensec_want_feature_list(struct gensec_security *state, char* feature_list){ if (in_list("NTLMSSP_FEATURE_SESSION_KEY", feature_list, true)) { DEBUG(10, ("want GENSEC_FEATURE_SESSION_KEY\n")); gensec_want_feature(state, GENSEC_FEATURE_SESSION_KEY); } if (in_list("NTLMSSP_FEATURE_SIGN", feature_list, true)) { DEBUG(10, ("want GENSEC_FEATURE_SIGN\n")); gensec_want_feature(state, GENSEC_FEATURE_SIGN); } if (in_list("NTLMSSP_FEATURE_SEAL", feature_list, true)) { DEBUG(10, ("want GENSEC_FEATURE_SEAL\n")); gensec_want_feature(state, GENSEC_FEATURE_SEAL); }}static void manage_gensec_request(enum stdio_helper_mode stdio_helper_mode, struct loadparm_context *lp_ctx, char *buf, int length, void **private, unsigned int mux_id, void **private2) { DATA_BLOB in; DATA_BLOB out = data_blob(NULL, 0);
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?