From 58fe4d9c20203f6f55c8e995402e156becb91b3e Mon Sep 17 00:00:00 2001 From: Andrew Bartlett Date: Wed, 15 Jan 2003 12:52:38 +0000 Subject: Refactor the NTLMSSP code again - this time we use function pointers to eliminate the dependency on the auth subsystem. The next step is to add the required code to 'ntlm_auth', for export to Squid etc. Andrew Bartlett (This used to be commit 9e48ab86da40e4c1cafa70c04fb9ebdcce23dfab) --- source3/Makefile.in | 3 +- source3/include/auth.h | 9 ++ source3/include/ntlmssp.h | 17 ++- source3/libsmb/cliconnect.c | 3 +- source3/libsmb/ntlmssp.c | 278 ++++++++++++++++++++++++++++++++++++++++++++ source3/smbd/sesssetup.c | 40 ++++--- 6 files changed, 330 insertions(+), 20 deletions(-) create mode 100644 source3/libsmb/ntlmssp.c (limited to 'source3') diff --git a/source3/Makefile.in b/source3/Makefile.in index 884c041ddb..3b1d3ace4a 100644 --- a/source3/Makefile.in +++ b/source3/Makefile.in @@ -189,7 +189,8 @@ LIBSMB_OBJ = libsmb/clientgen.o libsmb/cliconnect.o libsmb/clifile.o \ libsmb/smberr.o libsmb/credentials.o libsmb/pwd_cache.o \ libsmb/clioplock.o libsmb/errormap.o libsmb/clirap2.o \ libsmb/passchange.o libsmb/unexpected.o libsmb/doserr.o \ - libsmb/namecache.o libsmb/trustdom_cache.o $(RPC_PARSE_OBJ1) + libsmb/namecache.o libsmb/trustdom_cache.o libsmb/ntlmssp.o \ + $(RPC_PARSE_OBJ1) LIBMSRPC_OBJ = rpc_client/cli_lsarpc.o rpc_client/cli_samr.o \ rpc_client/cli_netlogon.o rpc_client/cli_srvsvc.o \ diff --git a/source3/include/auth.h b/source3/include/auth.h index 846662d17c..e37f181082 100644 --- a/source3/include/auth.h +++ b/source3/include/auth.h @@ -149,4 +149,13 @@ struct auth_init_function_entry { auth_init_function init; }; + +typedef struct auth_ntlmssp_state +{ + TALLOC_CTX *mem_ctx; + struct auth_context *auth_context; + struct auth_serversupplied_info *server_info; + struct ntlmssp_state *ntlmssp_state; +} AUTH_NTLMSSP_STATE; + #endif /* _SMBAUTH_H_ */ diff --git a/source3/include/ntlmssp.h b/source3/include/ntlmssp.h index 673be83532..a8fe345cc5 100644 --- a/source3/include/ntlmssp.h +++ b/source3/include/ntlmssp.h @@ -71,9 +71,18 @@ typedef struct ntlmssp_state { TALLOC_CTX *mem_ctx; enum NTLMSSP_ROLE role; - struct auth_context *auth_context; - struct auth_serversupplied_info *server_info; BOOL unicode; - char *orig_user; - char *orig_domain; + char *user; + char *domain; + char *workstation; + DATA_BLOB lm_resp; + DATA_BLOB nt_resp; + DATA_BLOB chal; + void *auth_context; + const uint8 *(*get_challenge)(void *auth_context); + NTSTATUS (*check_password)(void *auth_context); + + const char *(*get_global_myname)(void); + const char *(*get_domain)(void); } NTLMSSP_STATE; + diff --git a/source3/libsmb/cliconnect.c b/source3/libsmb/cliconnect.c index cc3aaf92be..389b7a1733 100644 --- a/source3/libsmb/cliconnect.c +++ b/source3/libsmb/cliconnect.c @@ -465,7 +465,8 @@ static BOOL cli_session_setup_ntlmssp(struct cli_state *cli, const char *user, neg_flags = NTLMSSP_NEGOTIATE_UNICODE | NTLMSSP_NEGOTIATE_128 | - NTLMSSP_NEGOTIATE_NTLM; + NTLMSSP_NEGOTIATE_NTLM | + NTLMSSP_REQUEST_TARGET; memset(sess_key, 0, 16); diff --git a/source3/libsmb/ntlmssp.c b/source3/libsmb/ntlmssp.c new file mode 100644 index 0000000000..4183f3e77a --- /dev/null +++ b/source3/libsmb/ntlmssp.c @@ -0,0 +1,278 @@ +/* + Unix SMB/Netbios implementation. + Version 3.0 + handle NLTMSSP, server side + + Copyright (C) Andrew Tridgell 2001 + Copyright (C) Andrew Bartlett 2001-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" + +/** + * Default challange generation code. + * + */ + + +static const uint8 *get_challenge(void *cookie) +{ + static uchar chal[8]; + generate_random_buffer(chal, sizeof(chal), False); + + return chal; +} + +NTSTATUS ntlmssp_server_start(NTLMSSP_STATE **ntlmssp_state) +{ + TALLOC_CTX *mem_ctx; + + mem_ctx = talloc_init("NTLMSSP context"); + + *ntlmssp_state = talloc_zero(mem_ctx, sizeof(**ntlmssp_state)); + if (!*ntlmssp_state) { + DEBUG(0,("ntlmssp_start: talloc failed!\n")); + talloc_destroy(mem_ctx); + return NT_STATUS_NO_MEMORY; + } + + ZERO_STRUCTP(*ntlmssp_state); + + (*ntlmssp_state)->mem_ctx = mem_ctx; + (*ntlmssp_state)->get_challenge = get_challenge; + + (*ntlmssp_state)->get_global_myname = global_myname; + (*ntlmssp_state)->get_domain = lp_workgroup; + + return NT_STATUS_OK; +} + +NTSTATUS ntlmssp_server_end(NTLMSSP_STATE **ntlmssp_state) +{ + TALLOC_CTX *mem_ctx = (*ntlmssp_state)->mem_ctx; + + data_blob_free(&(*ntlmssp_state)->lm_resp); + data_blob_free(&(*ntlmssp_state)->nt_resp); + + SAFE_FREE((*ntlmssp_state)->user); + SAFE_FREE((*ntlmssp_state)->domain); + SAFE_FREE((*ntlmssp_state)->workstation); + + talloc_destroy(mem_ctx); + *ntlmssp_state = NULL; + return NT_STATUS_OK; +} + +NTSTATUS ntlmssp_server_update(NTLMSSP_STATE *ntlmssp_state, + DATA_BLOB request, DATA_BLOB *reply) +{ + uint32 ntlmssp_command; + + if (!msrpc_parse(&request, "Cd", + "NTLMSSP", + &ntlmssp_command)) { + return NT_STATUS_LOGON_FAILURE; + } + + if (ntlmssp_command == NTLMSSP_NEGOTIATE) { + return ntlmssp_negotiate(ntlmssp_state, request, reply); + } else if (ntlmssp_command == NTLMSSP_AUTH) { + return ntlmssp_auth(ntlmssp_state, request, reply); + } else { + return NT_STATUS_LOGON_FAILURE; + } +} + +static const char *ntlmssp_target_name(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 (lp_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 ""; + } +} + +NTSTATUS ntlmssp_negotiate(NTLMSSP_STATE *ntlmssp_state, + DATA_BLOB request, DATA_BLOB *reply) +{ + DATA_BLOB struct_blob; + fstring dnsname, dnsdomname; + uint32 ntlmssp_command, neg_flags, chal_flags; + char *cliname=NULL, *domname=NULL; + const uint8 *cryptkey; + const char *target_name; + + /* parse the NTLMSSP packet */ +#if 0 + file_save("ntlmssp_negotiate.dat", request.data, request.length); +#endif + + if (!msrpc_parse(&request, "CddAA", + "NTLMSSP", + &ntlmssp_command, + &neg_flags, + &cliname, + &domname)) { + return NT_STATUS_LOGON_FAILURE; + } + + SAFE_FREE(cliname); + SAFE_FREE(domname); + + debug_ntlmssp_flags(neg_flags); + + cryptkey = ntlmssp_state->get_challenge(ntlmssp_state->auth_context); + + /* Give them the challenge. For now, ignore neg_flags and just + return the flags we want. Obviously this is not correct */ + + chal_flags = + NTLMSSP_NEGOTIATE_128 | + NTLMSSP_NEGOTIATE_NTLM; + + if (neg_flags & NTLMSSP_NEGOTIATE_UNICODE) { + chal_flags |= NTLMSSP_NEGOTIATE_UNICODE; + ntlmssp_state->unicode = True; + } else { + chal_flags |= NTLMSSP_NEGOTIATE_OEM; + } + + target_name = ntlmssp_target_name(ntlmssp_state, + neg_flags, &chal_flags); + + /* This should be a 'netbios domain -> DNS domain' mapping */ + dnsdomname[0] = '\0'; + get_mydomname(dnsdomname); + strlower(dnsdomname); + + dnsname[0] = '\0'; + get_myfullname(dnsname); + strlower(dnsname); + + 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; + } + + /* the numbers here are the string type flags */ + msrpc_gen(&struct_blob, "aaaaa", + ntlmssp_state->unicode, NTLMSSP_NAME_TYPE_DOMAIN, target_name, + ntlmssp_state->unicode, NTLMSSP_NAME_TYPE_SERVER, ntlmssp_state->get_global_myname(), + ntlmssp_state->unicode, NTLMSSP_NAME_TYPE_DOMAIN_DNS, target_name_dns, + ntlmssp_state->unicode, NTLMSSP_NAME_TYPE_SERVER_DNS, dnsdomname, + ntlmssp_state->unicode, 0, ""); + } else { + struct_blob = data_blob(NULL, 0); + } + + { + const char *gen_string; + if (ntlmssp_state->unicode) { + gen_string = "CdUdbddB"; + } else { + gen_string = "CdAdbddB"; + } + + msrpc_gen(reply, gen_string, + "NTLMSSP", + NTLMSSP_CHALLENGE, + target_name, + chal_flags, + cryptkey, 8, + 0, 0, + struct_blob.data, struct_blob.length); + } + + data_blob_free(&struct_blob); + + return NT_STATUS_MORE_PROCESSING_REQUIRED; +} + +NTSTATUS ntlmssp_auth(NTLMSSP_STATE *ntlmssp_state, + DATA_BLOB request, DATA_BLOB *reply) +{ + DATA_BLOB sess_key; + uint32 ntlmssp_command, neg_flags; + NTSTATUS nt_status; + + const char *parse_string; + + /* parse the NTLMSSP packet */ +#if 0 + file_save("ntlmssp_auth.dat", request.data, request.length); +#endif + + if (ntlmssp_state->unicode) { + parse_string = "CdBBUUUBd"; + } else { + parse_string = "CdBBAAABd"; + } + + data_blob_free(&ntlmssp_state->lm_resp); + data_blob_free(&ntlmssp_state->nt_resp); + + SAFE_FREE(ntlmssp_state->user); + SAFE_FREE(ntlmssp_state->domain); + SAFE_FREE(ntlmssp_state->workstation); + + /* now the NTLMSSP encoded auth hashes */ + if (!msrpc_parse(&request, parse_string, + "NTLMSSP", + &ntlmssp_command, + &ntlmssp_state->lm_resp, + &ntlmssp_state->nt_resp, + &ntlmssp_state->domain, + &ntlmssp_state->user, + &ntlmssp_state->workstation, + &sess_key, + &neg_flags)) { + return NT_STATUS_LOGON_FAILURE; + } + + data_blob_free(&sess_key); + + DEBUG(3,("Got user=[%s] domain=[%s] workstation=[%s] len1=%d len2=%d\n", + ntlmssp_state->user, ntlmssp_state->domain, ntlmssp_state->workstation, ntlmssp_state->lm_resp.length, 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 + + nt_status = ntlmssp_state->check_password(ntlmssp_state->auth_context); + + if (!NT_STATUS_IS_OK(nt_status)) { + return nt_status; + } + + *reply = data_blob(NULL, 0); + + return nt_status; +} diff --git a/source3/smbd/sesssetup.c b/source3/smbd/sesssetup.c index ed2d5976aa..939cdf2a91 100644 --- a/source3/smbd/sesssetup.c +++ b/source3/smbd/sesssetup.c @@ -24,7 +24,7 @@ uint32 global_client_caps = 0; -static struct ntlmssp_state *global_ntlmssp_state; +static struct auth_ntlmssp_state *global_ntlmssp_state; /* on a logon error possibly map the error to success if "map to guest" @@ -236,6 +236,9 @@ static BOOL reply_sesssetup_blob(connection_struct *conn, char *outbuf, return send_smb(smbd_server_fd(),outbuf); } +/**************************************************************************** +send an NTLMSSP blob via a session setup reply, wrapped in SPNEGO +****************************************************************************/ static BOOL reply_spnego_ntlmssp_blob(connection_struct *conn, char *outbuf, DATA_BLOB *ntlmssp_blob, NTSTATUS errcode) { @@ -246,13 +249,18 @@ static BOOL reply_spnego_ntlmssp_blob(connection_struct *conn, char *outbuf, return True; } +/**************************************************************************** + send an OK via a session setup reply, wrapped in SPNEGO. + get vuid and check first. +****************************************************************************/ static BOOL reply_spnego_ntlmssp_ok(connection_struct *conn, char *outbuf, - NTLMSSP_STATE *ntlmssp_state) + AUTH_NTLMSSP_STATE *auth_ntlmssp_state) { int sess_vuid; + pstring user; DATA_BLOB null_blob = data_blob(NULL, 0); - sess_vuid = register_vuid(ntlmssp_state->server_info, ntlmssp_state->orig_user /* check this for weird */); + sess_vuid = register_vuid(auth_ntlmssp_state->server_info, auth_ntlmssp_state->ntlmssp_state->user /* check this for weird */); if (sess_vuid == -1) { return ERROR_NT(NT_STATUS_LOGON_FAILURE); @@ -261,7 +269,7 @@ static BOOL reply_spnego_ntlmssp_ok(connection_struct *conn, char *outbuf, set_message(outbuf,4,0,True); SSVAL(outbuf, smb_vwv3, 0); - if (ntlmssp_state->server_info->guest) { + if (auth_ntlmssp_state->server_info->guest) { SSVAL(outbuf,smb_vwv2,1); } @@ -313,24 +321,24 @@ static int reply_spnego_negotiate(connection_struct *conn, #endif if (global_ntlmssp_state) { - ntlmssp_server_end(&global_ntlmssp_state); + auth_ntlmssp_end(&global_ntlmssp_state); } - nt_status = ntlmssp_server_start(&global_ntlmssp_state); + nt_status = auth_ntlmssp_start(&global_ntlmssp_state); if (!NT_STATUS_IS_OK(nt_status)) { return ERROR_NT(nt_status); } - nt_status = ntlmssp_server_update(global_ntlmssp_state, - secblob, &chal); + nt_status = auth_ntlmssp_update(global_ntlmssp_state, + secblob, &chal); data_blob_free(&secblob); if (!NT_STATUS_IS_OK(nt_status)) { nt_status = do_map_to_guest(nt_status, &global_ntlmssp_state->server_info, - global_ntlmssp_state->orig_user, - global_ntlmssp_state->orig_domain); + global_ntlmssp_state->ntlmssp_state->user, + global_ntlmssp_state->ntlmssp_state->domain); } if (NT_STATUS_EQUAL(nt_status, NT_STATUS_MORE_PROCESSING_REQUIRED)) { @@ -352,13 +360,16 @@ static int reply_spnego_negotiate(connection_struct *conn, } else if (NT_STATUS_IS_OK(nt_status)) { reply_spnego_ntlmssp_ok(conn, outbuf, global_ntlmssp_state); - ntlmssp_server_end(&global_ntlmssp_state); - + auth_ntlmssp_end(&global_ntlmssp_state); data_blob_free(&chal); + /* and tell smbd that we have already replied to this packet */ return -1; } + auth_ntlmssp_end(&global_ntlmssp_state); + data_blob_free(&chal); + return ERROR_NT(nt_status_squash(nt_status)); } @@ -380,7 +391,7 @@ static int reply_spnego_auth(connection_struct *conn, char *inbuf, char *outbuf, return ERROR_NT(NT_STATUS_LOGON_FAILURE); } - nt_status = ntlmssp_server_update(global_ntlmssp_state, + nt_status = auth_ntlmssp_update(global_ntlmssp_state, auth, &auth_reply); data_blob_free(&auth); @@ -389,9 +400,10 @@ static int reply_spnego_auth(connection_struct *conn, char *inbuf, char *outbuf, if (NT_STATUS_IS_OK(nt_status)) { reply_spnego_ntlmssp_ok(conn, outbuf, global_ntlmssp_state); - ntlmssp_server_end(&global_ntlmssp_state); + auth_ntlmssp_end(&global_ntlmssp_state); } else { /* !NT_STATUS_IS_OK(nt_status) */ + auth_ntlmssp_end(&global_ntlmssp_state); return ERROR_NT(nt_status_squash(nt_status)); } -- cgit