summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--source3/Makefile.in2
-rw-r--r--source3/auth/auth.c10
-rw-r--r--source3/auth/auth_ntlmssp.c284
-rw-r--r--source3/include/includes.h2
-rw-r--r--source3/include/ntlmssp.h79
-rw-r--r--source3/include/rpc_dce.h32
-rw-r--r--source3/libsmb/asn1.c2
-rw-r--r--source3/libsmb/cliconnect.c4
-rw-r--r--source3/libsmb/clispnego.c61
-rw-r--r--source3/smbd/sesssetup.c282
10 files changed, 514 insertions, 244 deletions
diff --git a/source3/Makefile.in b/source3/Makefile.in
index bf870b0c76..884c041ddb 100644
--- a/source3/Makefile.in
+++ b/source3/Makefile.in
@@ -267,7 +267,7 @@ UNIGRP_OBJ = libsmb/netlogon_unigrp.o
AUTH_OBJ = auth/auth.o auth/auth_sam.o auth/auth_server.o auth/auth_domain.o \
auth/auth_rhosts.o auth/auth_unix.o auth/auth_util.o auth/auth_winbind.o \
- auth/auth_builtin.o auth/auth_compat.o \
+ auth/auth_builtin.o auth/auth_compat.o auth/auth_ntlmssp.o \
$(PLAINTEXT_AUTH_OBJ) $(UNIGRP_OBJ)
MANGLE_OBJ = smbd/mangle.o smbd/mangle_hash.o smbd/mangle_map.o smbd/mangle_hash2.o
diff --git a/source3/auth/auth.c b/source3/auth/auth.c
index 3c4448445a..5d56603b9f 100644
--- a/source3/auth/auth.c
+++ b/source3/auth/auth.c
@@ -57,7 +57,8 @@ static const uint8 *get_ntlm_challenge(struct auth_context *auth_context)
TALLOC_CTX *mem_ctx;
if (auth_context->challenge.length) {
- DEBUG(5, ("get_ntlm_challenge (auth subsystem): returning previous challenge (normal)\n"));
+ DEBUG(5, ("get_ntlm_challenge (auth subsystem): returning previous challenge by module %s (normal)\n",
+ auth_context->challenge_set_by));
return auth_context->challenge.data;
}
@@ -190,6 +191,12 @@ static NTSTATUS check_ntlm_password(const struct auth_context *auth_context,
DEBUG(3, ("check_ntlm_password: mapped user is: [%s]\\[%s]@[%s]\n",
user_info->domain.str, user_info->internal_username.str, user_info->wksta_name.str));
+
+ if (auth_context->challenge.length != 8) {
+ DEBUG(0, ("check_ntlm_password: Invalid challenge stored for this auth context - cannot continue\n"));
+ return NT_STATUS_LOGON_FAILURE;
+ }
+
if (auth_context->challenge_set_by)
DEBUG(10, ("check_ntlm_password: auth_context challenge created by %s\n",
auth_context->challenge_set_by));
@@ -441,6 +448,7 @@ NTSTATUS make_auth_context_fixed(struct auth_context **auth_context, uchar chal[
}
(*auth_context)->challenge = data_blob(chal, 8);
+ (*auth_context)->challenge_set_by = "fixed";
return nt_status;
}
diff --git a/source3/auth/auth_ntlmssp.c b/source3/auth/auth_ntlmssp.c
new file mode 100644
index 0000000000..f5e5c987ba
--- /dev/null
+++ b/source3/auth/auth_ntlmssp.c
@@ -0,0 +1,284 @@
+/*
+ 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"
+
+NTSTATUS ntlmssp_server_start(NTLMSSP_STATE **ntlmssp_state)
+{
+ NTSTATUS nt_status;
+ 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;
+
+ if (!NT_STATUS_IS_OK(nt_status = make_auth_context_subsystem(&(*ntlmssp_state)->auth_context))) {
+ return nt_status;
+ }
+ return NT_STATUS_OK;
+}
+
+NTSTATUS ntlmssp_server_end(NTLMSSP_STATE **ntlmssp_state)
+{
+ TALLOC_CTX *mem_ctx = (*ntlmssp_state)->mem_ctx;
+ if ((*ntlmssp_state)->auth_context) {
+ ((*ntlmssp_state)->auth_context->free)(&(*ntlmssp_state)->auth_context);
+ }
+ if ((*ntlmssp_state)->server_info) {
+ free_server_info(&(*ntlmssp_state)->server_info);
+ }
+
+ talloc_destroy(mem_ctx);
+ 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(uint32 neg_flags, uint32 *chal_flags)
+{
+ if (neg_flags & NTLMSSP_REQUEST_TARGET) {
+ if (lp_server_role() == ROLE_STANDALONE) {
+ *chal_flags |= NTLMSSP_TARGET_TYPE_SERVER;
+ return global_myname();
+ } else {
+ *chal_flags |= NTLMSSP_TARGET_TYPE_DOMAIN;
+ return lp_workgroup();
+ };
+ } 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->auth_context->get_ntlm_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 |
+ NTLMSSP_CHAL_TARGET_INFO;
+
+ 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(neg_flags, &chal_flags);
+
+ dnsdomname[0] = '\0';
+ get_mydomname(dnsdomname);
+ strlower(dnsdomname);
+
+ dnsname[0] = '\0';
+ get_myfullname(dnsname);
+ strlower(dnsname);
+
+ /* the numbers here are the string type flags */
+ msrpc_gen(&struct_blob, "aaaaa",
+ ntlmssp_state->unicode, NTLMSSP_NAME_TYPE_DOMAIN, lp_workgroup(),
+ ntlmssp_state->unicode, NTLMSSP_NAME_TYPE_SERVER, global_myname(),
+ ntlmssp_state->unicode, NTLMSSP_NAME_TYPE_DOMAIN_DNS, dnsname,
+ ntlmssp_state->unicode, NTLMSSP_NAME_TYPE_SERVER_DNS, dnsdomname,
+ ntlmssp_state->unicode, 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)
+{
+ char *workgroup = NULL, *user = NULL, *machine = NULL;
+ DATA_BLOB lmhash, nthash, sess_key;
+ DATA_BLOB plaintext_password = data_blob(NULL, 0);
+ uint32 ntlmssp_command, neg_flags;
+ NTSTATUS nt_status;
+ uint32 auth_flags = AUTH_FLAG_NONE;
+ auth_usersupplied_info *user_info = NULL;
+
+ 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";
+ }
+
+ /* now the NTLMSSP encoded auth hashes */
+ if (!msrpc_parse(&request, parse_string,
+ "NTLMSSP",
+ &ntlmssp_command,
+ &lmhash,
+ &nthash,
+ &workgroup,
+ &user,
+ &machine,
+ &sess_key,
+ &neg_flags)) {
+ return NT_STATUS_LOGON_FAILURE;
+ }
+
+ data_blob_free(&sess_key);
+
+ DEBUG(3,("Got user=[%s] workgroup=[%s] machine=[%s] len1=%d len2=%d\n",
+ user, workgroup, machine, lmhash.length, nthash.length));
+
+ /* the client has given us its machine name (which we otherwise would not get on port 445).
+ we need to possibly reload smb.conf if smb.conf includes depend on the machine name */
+
+ set_remote_machine_name(machine);
+
+ /* setup the string used by %U */
+ sub_set_smb_name(user);
+
+ reload_services(True);
+
+#if 0
+ file_save("nthash1.dat", nthash.data, nthash.length);
+ file_save("lmhash1.dat", lmhash.data, lmhash.length);
+#endif
+
+ if (lmhash.length) {
+ auth_flags |= AUTH_FLAG_LM_RESP;
+ }
+
+ if (nthash.length == 24) {
+ auth_flags |= AUTH_FLAG_NTLM_RESP;
+ } else if (nthash.length > 24) {
+ auth_flags |= AUTH_FLAG_NTLMv2_RESP;
+ };
+
+
+
+ nt_status = make_user_info_map(&user_info, user, workgroup, machine,
+ lmhash, nthash, plaintext_password,
+ auth_flags, True);
+
+ ntlmssp_state->orig_user = talloc_strdup(ntlmssp_state->mem_ctx, user);
+ ntlmssp_state->orig_domain = talloc_strdup(ntlmssp_state->mem_ctx, workgroup);
+
+ SAFE_FREE(user);
+ SAFE_FREE(workgroup);
+ SAFE_FREE(machine);
+
+ if (!NT_STATUS_IS_OK(nt_status)) {
+ return nt_status;
+ }
+
+ nt_status = ntlmssp_state->auth_context->check_ntlm_password(ntlmssp_state->auth_context, user_info, &ntlmssp_state->server_info);
+
+ (ntlmssp_state->auth_context->free)(&ntlmssp_state->auth_context);
+
+ free_user_info(&user_info);
+
+ data_blob_free(&lmhash);
+
+ data_blob_free(&nthash);
+
+ *reply = data_blob(NULL, 0);
+
+ return nt_status;
+}
diff --git a/source3/include/includes.h b/source3/include/includes.h
index 29580a9192..160d5bb8e5 100644
--- a/source3/include/includes.h
+++ b/source3/include/includes.h
@@ -754,6 +754,8 @@ extern int errno;
#include "md5.h"
#include "hmacmd5.h"
+#include "ntlmssp.h"
+
#include "auth.h"
#include "passdb.h"
diff --git a/source3/include/ntlmssp.h b/source3/include/ntlmssp.h
new file mode 100644
index 0000000000..673be83532
--- /dev/null
+++ b/source3/include/ntlmssp.h
@@ -0,0 +1,79 @@
+/*
+ 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.
+*/
+
+/* NTLMSSP mode */
+enum NTLMSSP_ROLE
+{
+ NTLMSSP_SERVER,
+ NTLMSSP_CLIENT
+};
+
+/* NTLMSSP message types */
+enum NTLM_MESSAGE_TYPE
+{
+ NTLMSSP_NEGOTIATE = 1,
+ NTLMSSP_CHALLENGE = 2,
+ NTLMSSP_AUTH = 3,
+ NTLMSSP_UNKNOWN = 4
+};
+
+/* 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_080000000 0x80000000
+
+#define NTLMSSP_NAME_TYPE_DOMAIN 0x01
+#define NTLMSSP_NAME_TYPE_SERVER 0x02
+#define NTLMSSP_NAME_TYPE_DOMAIN_DNS 0x03
+#define NTLMSSP_NAME_TYPE_SERVER_DNS 0x04
+
+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;
+} NTLMSSP_STATE;
diff --git a/source3/include/rpc_dce.h b/source3/include/rpc_dce.h
index 031f7de6d7..6a8c650650 100644
--- a/source3/include/rpc_dce.h
+++ b/source3/include/rpc_dce.h
@@ -46,38 +46,6 @@ enum RPC_PKT_TYPE
#define RPC_FLG_LAST 0x02
#define RPC_FLG_NOCALL 0x20
-/* NTLMSSP message types */
-enum NTLM_MESSAGE_TYPE
-{
- NTLMSSP_NEGOTIATE = 1,
- NTLMSSP_CHALLENGE = 2,
- NTLMSSP_AUTH = 3,
- NTLMSSP_UNKNOWN = 4
-};
-
-/* 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_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_080000000 0x80000000
-
#define SMBD_NTLMSSP_NEG_FLAGS 0x000082b1 /* ALWAYS_SIGN|NEG_NTLM|NEG_LM|NEG_SEAL|NEG_SIGN|NEG_UNICODE */
/* NTLMSSP signature version */
diff --git a/source3/libsmb/asn1.c b/source3/libsmb/asn1.c
index b967927871..333d157905 100644
--- a/source3/libsmb/asn1.c
+++ b/source3/libsmb/asn1.c
@@ -407,7 +407,7 @@ BOOL asn1_check_enumerated(ASN1_DATA *data, int v)
return !data->has_error && (v == b);
}
-/* check a enumarted value is correct */
+/* write an enumarted value to the stream */
BOOL asn1_write_enumerated(ASN1_DATA *data, uint8 v)
{
if (!asn1_push_tag(data, ASN1_ENUMERATED)) return False;
diff --git a/source3/libsmb/cliconnect.c b/source3/libsmb/cliconnect.c
index b758af41c4..cc3aaf92be 100644
--- a/source3/libsmb/cliconnect.c
+++ b/source3/libsmb/cliconnect.c
@@ -476,8 +476,8 @@ static BOOL cli_session_setup_ntlmssp(struct cli_state *cli, const char *user,
"NTLMSSP",
NTLMSSP_NEGOTIATE,
neg_flags,
- workgroup, strlen(workgroup),
- cli->calling.name, strlen(cli->calling.name) + 1);
+ workgroup,
+ cli->calling.name);
DEBUG(10, ("neg_flags: %0X, workgroup: %s, calling name %s\n",
neg_flags, workgroup, cli->calling.name));
/* and wrap it in a SPNEGO wrapper */
diff --git a/source3/libsmb/clispnego.c b/source3/libsmb/clispnego.c
index 55f49c5987..6a5f6c00ae 100644
--- a/source3/libsmb/clispnego.c
+++ b/source3/libsmb/clispnego.c
@@ -485,7 +485,7 @@ BOOL spnego_parse_auth(DATA_BLOB blob, DATA_BLOB *auth)
/*
generate a minimal SPNEGO NTLMSSP response packet. Doesn't contain much.
*/
-DATA_BLOB spnego_gen_auth_response(void)
+DATA_BLOB spnego_gen_auth_response(DATA_BLOB *ntlmssp_reply)
{
ASN1_DATA data;
DATA_BLOB ret;
@@ -495,8 +495,13 @@ DATA_BLOB spnego_gen_auth_response(void)
asn1_push_tag(&data, ASN1_CONTEXT(1));
asn1_push_tag(&data, ASN1_SEQUENCE(0));
asn1_push_tag(&data, ASN1_CONTEXT(0));
- asn1_write_enumerated(&data, 0);
+ asn1_write_enumerated(&data, ntlmssp_reply->length ? 1 : 0);
asn1_pop_tag(&data);
+ if (ntlmssp_reply->length) {
+ asn1_push_tag(&data,ASN1_CONTEXT(2));
+ asn1_write_OctetString(&data, ntlmssp_reply->data, ntlmssp_reply->length);
+ asn1_pop_tag(&data);
+ }
asn1_pop_tag(&data);
asn1_pop_tag(&data);
@@ -514,8 +519,9 @@ DATA_BLOB spnego_gen_auth_response(void)
format specifiers are:
U = unicode string (input is unix string)
- a = address (1 byte type, 1 byte length, unicode string, all inline)
- A = ASCII string (pointer + length) Actually same as B
+ a = address (input is BOOL unicode, 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
@@ -531,6 +537,7 @@ BOOL msrpc_gen(DATA_BLOB *blob,
uint8 *b;
int head_size=0, data_size=0;
int head_ofs, data_ofs;
+ BOOL unicode;
/* first scan the format to work out the header and body size */
va_start(ap, format);
@@ -541,12 +548,21 @@ BOOL msrpc_gen(DATA_BLOB *blob,
head_size += 8;
data_size += str_charnum(s) * 2;
break;
+ case 'A':
+ s = va_arg(ap, char *);
+ head_size += 8;
+ data_size += str_ascii_charnum(s);
+ break;
case 'a':
+ unicode = va_arg(ap, BOOL);
n = va_arg(ap, int);
s = va_arg(ap, char *);
- data_size += (str_charnum(s) * 2) + 4;
+ if (unicode) {
+ data_size += (str_charnum(s) * 2) + 4;
+ } else {
+ data_size += (str_ascii_charnum(s)) + 4;
+ }
break;
- case 'A':
case 'B':
b = va_arg(ap, uint8 *);
head_size += 8;
@@ -586,20 +602,39 @@ BOOL msrpc_gen(DATA_BLOB *blob,
push_string(NULL, blob->data+data_ofs, s, n*2, STR_UNICODE|STR_NOALIGN);
data_ofs += n*2;
break;
+ case 'A':
+ s = va_arg(ap, char *);
+ n = str_ascii_charnum(s);
+ 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;
+ push_string(NULL, blob->data+data_ofs, s, n, STR_ASCII|STR_NOALIGN);
+ data_ofs += n;
+ break;
case 'a':
+ unicode = va_arg(ap, BOOL);
n = va_arg(ap, int);
SSVAL(blob->data, data_ofs, n); data_ofs += 2;
s = va_arg(ap, char *);
- n = str_charnum(s);
- SSVAL(blob->data, data_ofs, n*2); data_ofs += 2;
- if (0 < n) {
- push_string(NULL, blob->data+data_ofs, s, n*2,
- STR_UNICODE|STR_NOALIGN);
+ if (unicode) {
+ n = str_charnum(s);
+ SSVAL(blob->data, data_ofs, n*2); data_ofs += 2;
+ if (0 < n) {
+ push_string(NULL, blob->data+data_ofs, s, n*2,
+ STR_UNICODE|STR_NOALIGN);
+ }
+ data_ofs += n*2;
+ } else {
+ n = str_ascii_charnum(s);
+ SSVAL(blob->data, data_ofs, n); data_ofs += 2;
+ if (0 < n) {
+ push_string(NULL, blob->data+data_ofs, s, n,
+ STR_ASCII|STR_NOALIGN);
+ }
+ data_ofs += n;
}
- data_ofs += n*2;
break;
- case 'A':
case 'B':
b = va_arg(ap, uint8 *);
n = va_arg(ap, int);
diff --git a/source3/smbd/sesssetup.c b/source3/smbd/sesssetup.c
index f689893fab..ed2d5976aa 100644
--- a/source3/smbd/sesssetup.c
+++ b/source3/smbd/sesssetup.c
@@ -23,7 +23,8 @@
#include "includes.h"
uint32 global_client_caps = 0;
-static struct auth_context *ntlmssp_auth_context = NULL;
+
+static struct ntlmssp_state *global_ntlmssp_state;
/*
on a logon error possibly map the error to success if "map to guest"
@@ -212,7 +213,7 @@ static int reply_spnego_kerberos(connection_struct *conn,
send a security blob via a session setup reply
****************************************************************************/
static BOOL reply_sesssetup_blob(connection_struct *conn, char *outbuf,
- DATA_BLOB blob, uint32 errcode)
+ DATA_BLOB blob, NTSTATUS errcode)
{
char *p;
@@ -221,7 +222,7 @@ static BOOL reply_sesssetup_blob(connection_struct *conn, char *outbuf,
/* we set NT_STATUS_MORE_PROCESSING_REQUIRED to tell the other end
that we aren't finished yet */
- SIVAL(outbuf, smb_rcls, errcode);
+ SIVAL(outbuf, smb_rcls, NT_STATUS_V(errcode));
SSVAL(outbuf, smb_vwv0, 0xFF); /* no chaining possible */
SSVAL(outbuf, smb_vwv3, blob.length);
p = smb_buf(outbuf);
@@ -235,6 +236,42 @@ static BOOL reply_sesssetup_blob(connection_struct *conn, char *outbuf,
return send_smb(smbd_server_fd(),outbuf);
}
+static BOOL reply_spnego_ntlmssp_blob(connection_struct *conn, char *outbuf,
+ DATA_BLOB *ntlmssp_blob, NTSTATUS errcode)
+{
+ DATA_BLOB response;
+ response = spnego_gen_auth_response(ntlmssp_blob);
+ reply_sesssetup_blob(conn, outbuf, response, errcode);
+ data_blob_free(&response);
+ return True;
+}
+
+static BOOL reply_spnego_ntlmssp_ok(connection_struct *conn, char *outbuf,
+ NTLMSSP_STATE *ntlmssp_state)
+{
+ int sess_vuid;
+ DATA_BLOB null_blob = data_blob(NULL, 0);
+
+ sess_vuid = register_vuid(ntlmssp_state->server_info, ntlmssp_state->orig_user /* check this for weird */);
+
+ if (sess_vuid == -1) {
+ return ERROR_NT(NT_STATUS_LOGON_FAILURE);
+ }
+
+ set_message(outbuf,4,0,True);
+ SSVAL(outbuf, smb_vwv3, 0);
+
+ if (ntlmssp_state->server_info->guest) {
+ SSVAL(outbuf,smb_vwv2,1);
+ }
+
+ add_signature(outbuf);
+
+ SSVAL(outbuf,smb_uid,sess_vuid);
+ reply_spnego_ntlmssp_blob(conn, outbuf, &null_blob, NT_STATUS_OK);
+ return True;
+}
+
/****************************************************************************
reply to a session setup spnego negotiate packet
****************************************************************************/
@@ -247,12 +284,9 @@ static int reply_spnego_negotiate(connection_struct *conn,
char *OIDs[ASN1_MAX_OIDS];
DATA_BLOB secblob;
int i;
- uint32 ntlmssp_command, neg_flags, chal_flags;
DATA_BLOB chal, spnego_chal;
- const uint8 *cryptkey;
BOOL got_kerberos = False;
NTSTATUS nt_status;
- char *cliname=NULL, *domname=NULL;
/* parse out the OIDs and the first sec blob */
if (!parse_negTokenTarg(blob1, OIDs, &secblob)) {
@@ -278,96 +312,54 @@ static int reply_spnego_negotiate(connection_struct *conn,
}
#endif
- /* parse the NTLMSSP packet */
-#if 0
- file_save("secblob.dat", secblob.data, secblob.length);
-#endif
-
- if (!msrpc_parse(&secblob, "CddAA",
- "NTLMSSP",
- &ntlmssp_command,
- &neg_flags,
- &cliname,
- &domname)) {
- return ERROR_NT(NT_STATUS_LOGON_FAILURE);
+ if (global_ntlmssp_state) {
+ ntlmssp_server_end(&global_ntlmssp_state);
}
-
- data_blob_free(&secblob);
- if (ntlmssp_command != NTLMSSP_NEGOTIATE) {
- return ERROR_NT(NT_STATUS_LOGON_FAILURE);
+ nt_status = ntlmssp_server_start(&global_ntlmssp_state);
+ if (!NT_STATUS_IS_OK(nt_status)) {
+ return ERROR_NT(nt_status);
}
- debug_ntlmssp_flags(neg_flags);
+ nt_status = ntlmssp_server_update(global_ntlmssp_state,
+ secblob, &chal);
- if (ntlmssp_auth_context) {
- (ntlmssp_auth_context->free)(&ntlmssp_auth_context);
- }
+ data_blob_free(&secblob);
- if (!NT_STATUS_IS_OK(nt_status = make_auth_context_subsystem(&ntlmssp_auth_context))) {
- return ERROR_NT(nt_status);
+ 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);
}
-
- cryptkey = ntlmssp_auth_context->get_ntlm_challenge(ntlmssp_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_UNICODE |
- NTLMSSP_NEGOTIATE_128 |
- NTLMSSP_NEGOTIATE_NTLM |
- NTLMSSP_CHAL_TARGET_INFO;
-
- {
- DATA_BLOB domain_blob, struct_blob;
- fstring dnsname, dnsdomname;
+ if (NT_STATUS_EQUAL(nt_status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {
+ if (!spnego_gen_challenge(&spnego_chal, &chal, NULL)) {
+ DEBUG(3,("Failed to generate challenge\n"));
+ data_blob_free(&chal);
+ return ERROR_NT(NT_STATUS_LOGON_FAILURE);
+ }
+
+ /* now tell the client to send the auth packet */
+ reply_sesssetup_blob(conn, outbuf, spnego_chal, nt_status);
- msrpc_gen(&domain_blob,
- "U",
- lp_workgroup());
-
- fstrcpy(dnsdomname, (SEC_ADS == lp_security())?lp_realm():"");
- strlower(dnsdomname);
-
- fstrcpy(dnsname, global_myname());
- fstrcat(dnsname, ".");
- fstrcat(dnsname, dnsdomname);
- strlower(dnsname);
-
- msrpc_gen(&struct_blob, "aaaaa",
- 2, lp_workgroup(),
- 1, global_myname(),
- 4, dnsdomname,
- 3, dnsname,
- 0, "");
-
- msrpc_gen(&chal, "CdUdbddB",
- "NTLMSSP",
- NTLMSSP_CHALLENGE,
- lp_workgroup(),
- chal_flags,
- cryptkey, 8,
- 0, 0,
- struct_blob.data, struct_blob.length);
-
- data_blob_free(&domain_blob);
- data_blob_free(&struct_blob);
- }
-
- if (!spnego_gen_challenge(&spnego_chal, &chal, &chal)) {
- DEBUG(3,("Failed to generate challenge\n"));
data_blob_free(&chal);
- return ERROR_NT(NT_STATUS_LOGON_FAILURE);
- }
+ data_blob_free(&spnego_chal);
- /* now tell the client to send the auth packet */
- reply_sesssetup_blob(conn, outbuf, spnego_chal, NT_STATUS_V(NT_STATUS_MORE_PROCESSING_REQUIRED));
+ /* and tell smbd that we have already replied to this packet */
+ return -1;
- data_blob_free(&chal);
- data_blob_free(&spnego_chal);
+ } else if (NT_STATUS_IS_OK(nt_status)) {
+ reply_spnego_ntlmssp_ok(conn, outbuf,
+ global_ntlmssp_state);
+ ntlmssp_server_end(&global_ntlmssp_state);
- /* and tell smbd that we have already replied to this packet */
- return -1;
+ data_blob_free(&chal);
+ /* and tell smbd that we have already replied to this packet */
+ return -1;
+ }
+
+ return ERROR_NT(nt_status_squash(nt_status));
}
@@ -378,23 +370,8 @@ static int reply_spnego_auth(connection_struct *conn, char *inbuf, char *outbuf,
int length, int bufsize,
DATA_BLOB blob1)
{
- DATA_BLOB auth, response;
- char *workgroup = NULL, *user = NULL, *machine = NULL;
- DATA_BLOB lmhash, nthash, sess_key;
- DATA_BLOB plaintext_password = data_blob(NULL, 0);
- uint32 ntlmssp_command, neg_flags;
+ DATA_BLOB auth, auth_reply;
NTSTATUS nt_status;
- int sess_vuid;
- BOOL as_guest;
- uint32 auth_flags = AUTH_FLAG_NONE;
- auth_usersupplied_info *user_info = NULL;
- auth_serversupplied_info *server_info = NULL;
-
- /* we must have setup the auth context by now */
- if (!ntlmssp_auth_context) {
- DEBUG(2,("ntlmssp_auth_context is NULL in reply_spnego_auth\n"));
- return ERROR_NT(NT_STATUS_LOGON_FAILURE);
- }
if (!spnego_parse_auth(blob1, &auth)) {
#if 0
@@ -403,108 +380,21 @@ static int reply_spnego_auth(connection_struct *conn, char *inbuf, char *outbuf,
return ERROR_NT(NT_STATUS_LOGON_FAILURE);
}
- /* now the NTLMSSP encoded auth hashes */
- if (!msrpc_parse(&auth, "CdBBUUUBd",
- "NTLMSSP",
- &ntlmssp_command,
- &lmhash,
- &nthash,
- &workgroup,
- &user,
- &machine,
- &sess_key,
- &neg_flags)) {
- return ERROR_NT(NT_STATUS_LOGON_FAILURE);
- }
+ nt_status = ntlmssp_server_update(global_ntlmssp_state,
+ auth, &auth_reply);
data_blob_free(&auth);
- data_blob_free(&sess_key);
-
- DEBUG(3,("Got user=[%s] workgroup=[%s] machine=[%s] len1=%d len2=%d\n",
- user, workgroup, machine, lmhash.length, nthash.length));
-
- /* the client has given us its machine name (which we otherwise would not get on port 445).
- we need to possibly reload smb.conf if smb.conf includes depend on the machine name */
-
- set_remote_machine_name(machine);
-
- /* setup the string used by %U */
- sub_set_smb_name(user);
-
- reload_services(True);
+ data_blob_free(&auth_reply);
-#if 0
- file_save("nthash1.dat", nthash.data, nthash.length);
- file_save("lmhash1.dat", lmhash.data, lmhash.length);
-#endif
-
- if (lmhash.length) {
- auth_flags |= AUTH_FLAG_LM_RESP;
- }
+ if (NT_STATUS_IS_OK(nt_status)) {
+ reply_spnego_ntlmssp_ok(conn, outbuf,
+ global_ntlmssp_state);
+ ntlmssp_server_end(&global_ntlmssp_state);
- if (nthash.length == 24) {
- auth_flags |= AUTH_FLAG_NTLM_RESP;
- } else if (nthash.length > 24) {
- auth_flags |= AUTH_FLAG_NTLMv2_RESP;
- };
-
- nt_status = make_user_info_map(&user_info, user, workgroup, machine,
- lmhash, nthash, plaintext_password,
- auth_flags, True);
-
- /* it looks a bit weird, but this function returns int type... */
- if (!NT_STATUS_IS_OK(nt_status)) {
- return ERROR_NT(NT_STATUS_NO_MEMORY);
- }
-
- nt_status = ntlmssp_auth_context->check_ntlm_password(ntlmssp_auth_context, user_info, &server_info);
-
- if (!NT_STATUS_IS_OK(nt_status)) {
- nt_status = do_map_to_guest(nt_status, &server_info, user, workgroup);
- }
-
- SAFE_FREE(workgroup);
- SAFE_FREE(machine);
-
- (ntlmssp_auth_context->free)(&ntlmssp_auth_context);
-
- free_user_info(&user_info);
-
- data_blob_free(&lmhash);
-
- data_blob_free(&nthash);
-
- if (!NT_STATUS_IS_OK(nt_status)) {
- SAFE_FREE(user);
+ } else { /* !NT_STATUS_IS_OK(nt_status) */
return ERROR_NT(nt_status_squash(nt_status));
}
- as_guest = server_info->guest;
-
- sess_vuid = register_vuid(server_info, user);
- free_server_info(&server_info);
-
- SAFE_FREE(user);
-
- if (sess_vuid == -1) {
- return ERROR_NT(NT_STATUS_LOGON_FAILURE);
- }
-
- set_message(outbuf,4,0,True);
- SSVAL(outbuf, smb_vwv3, 0);
-
- if (as_guest) {
- SSVAL(outbuf,smb_vwv2,1);
- }
-
- add_signature(outbuf);
-
- SSVAL(outbuf,smb_uid,sess_vuid);
- SSVAL(inbuf,smb_uid,sess_vuid);
-
- response = spnego_gen_auth_response();
- reply_sesssetup_blob(conn, outbuf, response, 0);
-
/* and tell smbd that we have already replied to this packet */
return -1;
}
@@ -786,6 +676,10 @@ int reply_sesssetup_and_X(connection_struct *conn, char *inbuf,char *outbuf,
nt_status = check_guest_password(&server_info);
} else if (doencrypt) {
+ if (!negprot_global_auth_context) {
+ DEBUG(0, ("reply_sesssetup_and_X: Attempted encrypted session setup without negprot denied!\n"));
+ return ERROR_NT(NT_STATUS_LOGON_FAILURE);
+ }
nt_status = make_user_info_for_reply_enc(&user_info, user, domain,
lm_resp, nt_resp);
if (NT_STATUS_IS_OK(nt_status)) {