1From ee105156fa151ebfd34b8febc2928e144b3b7b0e Mon Sep 17 00:00:00 2001
2From: =?UTF-8?q?G=C3=BCnther=20Deschner?= <gd@samba.org>
3Date: Sat, 26 Sep 2015 01:29:10 +0200
4Subject: [PATCH 01/15] CVE-2016-2111: s3:rpc_server/netlogon: always go
5 through netr_creds_server_step_check()
6
7The ensures we apply the "server schannel = yes" restrictions.
8
9BUG: https://bugzilla.samba.org/show_bug.cgi?id=11749
10
11Pair-Programmed-With: Stefan Metzmacher <metze@samba.org>
12
13Signed-off-by: Guenther Deschner <gd@samba.org>
14Signed-off-by: Stefan Metzmacher <metze@samba.org>
15---
16 source3/rpc_server/netlogon/srv_netlog_nt.c | 24 ++++++++++++++----------
17 1 file changed, 14 insertions(+), 10 deletions(-)
18
19--- a/source3/rpc_server/netlogon/srv_netlog_nt.c
20+++ b/source3/rpc_server/netlogon/srv_netlog_nt.c
21@@ -1508,6 +1508,7 @@ static NTSTATUS _netr_LogonSamLogon_base
22 	case NetlogonNetworkTransitiveInformation:
23 	{
24 		const char *wksname = nt_workstation;
25+		const char *workgroup = lp_workgroup();
26 
27 		status = make_auth_context_fixed(talloc_tos(), &auth_context,
28 						 logon->network->challenge);
29@@ -1532,6 +1533,14 @@ static NTSTATUS _netr_LogonSamLogon_base
30 						     logon->network->nt.length)) {
31 			status = NT_STATUS_NO_MEMORY;
32 		}
33+
34+		if (NT_STATUS_IS_OK(status)) {
35+			status = NTLMv2_RESPONSE_verify_netlogon_creds(
36+						user_info->client.account_name,
37+						user_info->client.domain_name,
38+						user_info->password.response.nt,
39+						creds, workgroup);
40+		}
41 		break;
42 	}
43 	case NetlogonInteractiveInformation:
44@@ -1636,6 +1645,14 @@ static NTSTATUS _netr_LogonSamLogon_base
45 						r->out.validation->sam3);
46 		break;
47 	case 6:
48+		/* Only allow this if the pipe is protected. */
49+		if (p->auth.auth_level < DCERPC_AUTH_LEVEL_PRIVACY) {
50+			DEBUG(0,("netr_Validation6: client %s not using privacy for netlogon\n",
51+				get_remote_machine_name()));
52+			status = NT_STATUS_INVALID_PARAMETER;
53+			break;
54+		}
55+
56 		status = serverinfo_to_SamInfo6(server_info, pipe_session_key, 16,
57 						r->out.validation->sam6);
58 		break;
59@@ -2271,11 +2288,13 @@ NTSTATUS _netr_GetForestTrustInformation
60 
61 	/* TODO: check server name */
62 
63-	status = schannel_check_creds_state(p->mem_ctx, lp_private_dir(),
64-					    r->in.computer_name,
65-					    r->in.credential,
66-					    r->out.return_authenticator,
67-					    &creds);
68+	become_root();
69+	status = netr_creds_server_step_check(p, p->mem_ctx,
70+					      r->in.computer_name,
71+					      r->in.credential,
72+					      r->out.return_authenticator,
73+					      &creds);
74+	unbecome_root();
75 	if (!NT_STATUS_IS_OK(status)) {
76 		return status;
77 	}
78@@ -2371,11 +2390,13 @@ NTSTATUS _netr_ServerGetTrustInfo(struct
79 
80 	/* TODO: check server name */
81 
82-	status = schannel_check_creds_state(p->mem_ctx, lp_private_dir(),
83-					    r->in.computer_name,
84-					    r->in.credential,
85-					    r->out.return_authenticator,
86-					    &creds);
87+	become_root();
88+	status = netr_creds_server_step_check(p, p->mem_ctx,
89+					      r->in.computer_name,
90+					      r->in.credential,
91+					      r->out.return_authenticator,
92+					      &creds);
93+	unbecome_root();
94 	if (!NT_STATUS_IS_OK(status)) {
95 		return status;
96 	}
97--- a/source4/torture/rpc/samba3rpc.c
98+++ b/source4/torture/rpc/samba3rpc.c
99@@ -1122,8 +1122,8 @@ static bool schan(struct torture_context
100 		generate_random_buffer(chal.data, chal.length);
101 		names_blob = NTLMv2_generate_names_blob(
102 			mem_ctx,
103-			cli_credentials_get_workstation(user_creds),
104-			cli_credentials_get_domain(user_creds));
105+			cli_credentials_get_workstation(wks_creds),
106+			cli_credentials_get_domain(wks_creds));
107 		status = cli_credentials_get_ntlm_response(
108 			user_creds, mem_ctx, &flags, chal, names_blob,
109 			&lm_resp, &nt_resp, NULL, NULL);
110--- a/libcli/auth/proto.h
111+++ b/libcli/auth/proto.h
112@@ -139,6 +139,11 @@ bool SMBNTLMv2encrypt(TALLOC_CTX *mem_ct
113 		      const DATA_BLOB *names_blob,
114 		      DATA_BLOB *lm_response, DATA_BLOB *nt_response, 
115 		      DATA_BLOB *lm_session_key, DATA_BLOB *user_session_key) ;
116+NTSTATUS NTLMv2_RESPONSE_verify_netlogon_creds(const char *account_name,
117+			const char *account_domain,
118+			const DATA_BLOB response,
119+			const struct netlogon_creds_CredentialState *creds,
120+			const char *workgroup);
121 
122 /***********************************************************
123  encode a password buffer with a unicode password.  The buffer
124--- a/libcli/auth/smbencrypt.c
125+++ b/libcli/auth/smbencrypt.c
126@@ -26,7 +26,7 @@
127 #include "../libcli/auth/msrpc_parse.h"
128 #include "../lib/crypto/crypto.h"
129 #include "../libcli/auth/libcli_auth.h"
130-#include "../librpc/gen_ndr/ntlmssp.h"
131+#include "../librpc/gen_ndr/ndr_ntlmssp.h"
132 
133 void SMBencrypt_hash(const uint8_t lm_hash[16], const uint8_t *c8, uint8_t p24[24])
134 {
135@@ -522,6 +522,146 @@ bool SMBNTLMv2encrypt(TALLOC_CTX *mem_ct
136 				     lm_response, nt_response, lm_session_key, user_session_key);
137 }
138 
139+NTSTATUS NTLMv2_RESPONSE_verify_netlogon_creds(const char *account_name,
140+			const char *account_domain,
141+			const DATA_BLOB response,
142+			const struct netlogon_creds_CredentialState *creds,
143+			const char *workgroup)
144+{
145+	TALLOC_CTX *frame = NULL;
146+	/* RespType + HiRespType */
147+	static const char *magic = "\x01\x01";
148+	int cmp;
149+	struct NTLMv2_RESPONSE v2_resp;
150+	enum ndr_err_code err;
151+	const struct AV_PAIR *av_nb_cn = NULL;
152+	const struct AV_PAIR *av_nb_dn = NULL;
153+
154+	if (response.length < 48) {
155+		/*
156+		 * NTLMv2_RESPONSE has at least 48 bytes.
157+		 */
158+		return NT_STATUS_OK;
159+	}
160+
161+	cmp = memcmp(response.data + 16, magic, 2);
162+	if (cmp != 0) {
163+		/*
164+		 * It doesn't look like a valid NTLMv2_RESPONSE
165+		 */
166+		return NT_STATUS_OK;
167+	}
168+
169+	frame = talloc_stackframe();
170+
171+	err = ndr_pull_struct_blob(&response, frame, &v2_resp,
172+		(ndr_pull_flags_fn_t)ndr_pull_NTLMv2_RESPONSE);
173+	if (!NDR_ERR_CODE_IS_SUCCESS(err)) {
174+		NTSTATUS status;
175+		status = ndr_map_error2ntstatus(err);
176+		DEBUG(2,("Failed to parse NTLMv2_RESPONSE "
177+			 "length %u - %s - %s\n",
178+			 (unsigned)response.length,
179+			 ndr_map_error2string(err),
180+			 nt_errstr(status)));
181+		dump_data(2, response.data, response.length);
182+		TALLOC_FREE(frame);
183+		return status;
184+	}
185+
186+	if (DEBUGLVL(10)) {
187+		NDR_PRINT_DEBUG(NTLMv2_RESPONSE, &v2_resp);
188+	}
189+
190+	/*
191+	 * Make sure the netbios computer name in the
192+	 * NTLMv2_RESPONSE matches the computer name
193+	 * in the secure channel credentials for workstation
194+	 * trusts.
195+	 *
196+	 * And the netbios domain name matches our
197+	 * workgroup.
198+	 *
199+	 * This prevents workstations from requesting
200+	 * the session key of NTLMSSP sessions of clients
201+	 * to other hosts.
202+	 */
203+	if (creds->secure_channel_type == SEC_CHAN_WKSTA) {
204+		av_nb_cn = ndr_ntlmssp_find_av(&v2_resp.Challenge.AvPairs,
205+					       MsvAvNbComputerName);
206+		av_nb_dn = ndr_ntlmssp_find_av(&v2_resp.Challenge.AvPairs,
207+					       MsvAvNbDomainName);
208+	}
209+
210+	if (av_nb_cn != NULL) {
211+		const char *v = NULL;
212+		char *a = NULL;
213+		size_t len;
214+
215+		v = av_nb_cn->Value.AvNbComputerName;
216+
217+		a = talloc_strdup(frame, creds->account_name);
218+		if (a == NULL) {
219+			TALLOC_FREE(frame);
220+			return NT_STATUS_NO_MEMORY;
221+		}
222+		len = strlen(a);
223+		if (len > 0 && a[len - 1] == '$') {
224+			a[len - 1] = '\0';
225+		}
226+
227+#ifdef SAMBA4_INTERNAL_HEIMDAL /* smbtorture4 for make test */
228+		cmp = strcasecmp_m(a, v);
229+#else /* smbd */
230+		cmp = StrCaseCmp(a, v);
231+#endif
232+		if (cmp != 0) {
233+			DEBUG(2,("%s: NTLMv2_RESPONSE with "
234+				 "NbComputerName[%s] rejected "
235+				 "for user[%s\\%s] "
236+				 "against SEC_CHAN_WKSTA[%s/%s] "
237+				 "in workgroup[%s]\n",
238+				 __func__, v,
239+				 account_domain,
240+				 account_name,
241+				 creds->computer_name,
242+				 creds->account_name,
243+				 workgroup));
244+			TALLOC_FREE(frame);
245+			return NT_STATUS_LOGON_FAILURE;
246+		}
247+	}
248+	if (av_nb_dn != NULL) {
249+		const char *v = NULL;
250+
251+		v = av_nb_dn->Value.AvNbDomainName;
252+
253+#ifdef SAMBA4_INTERNAL_HEIMDAL /* smbtorture4 for make test */
254+		cmp = strcasecmp_m(workgroup, v);
255+#else /* smbd */
256+		cmp = StrCaseCmp(workgroup, v);
257+#endif
258+		if (cmp != 0) {
259+			DEBUG(2,("%s: NTLMv2_RESPONSE with "
260+				 "NbDomainName[%s] rejected "
261+				 "for user[%s\\%s] "
262+				 "against SEC_CHAN_WKSTA[%s/%s] "
263+				 "in workgroup[%s]\n",
264+				 __func__, v,
265+				 account_domain,
266+				 account_name,
267+				 creds->computer_name,
268+				 creds->account_name,
269+				 workgroup));
270+			TALLOC_FREE(frame);
271+			return NT_STATUS_LOGON_FAILURE;
272+		}
273+	}
274+
275+	TALLOC_FREE(frame);
276+	return NT_STATUS_OK;
277+}
278+
279 /***********************************************************
280  encode a password buffer with a unicode password.  The buffer
281  is filled with random data to make it harder to attack.
282--- a/libcli/auth/wscript_build
283+++ b/libcli/auth/wscript_build
284@@ -19,7 +19,7 @@ bld.SAMBA_SUBSYSTEM('MSRPC_PARSE',
285 
286 bld.SAMBA_SUBSYSTEM('LIBCLI_AUTH',
287 	source='credentials.c session.c smbencrypt.c smbdes.c',
288-	public_deps='MSRPC_PARSE',
289+	public_deps='MSRPC_PARSE NDR_NTLMSSP',
290 	public_headers='credentials.h:domain_credentials.h'
291 	)
292 
293--- a/source3/Makefile.in
294+++ b/source3/Makefile.in
295@@ -783,6 +783,7 @@ GROUPDB_OBJ = groupdb/mapping.o groupdb/
296 PROFILE_OBJ = profile/profile.o
297 PROFILES_OBJ = utils/profiles.o \
298 	       $(LIBSMB_ERR_OBJ) \
299+	       $(LIBNDR_NTLMSSP_OBJ) \
300 	       $(PARAM_OBJ) \
301                $(LIB_OBJ) $(LIB_DUMMY_OBJ) \
302                $(POPT_LIB_OBJ) \
303@@ -995,10 +996,10 @@ SWAT_OBJ = $(SWAT_OBJ1) $(PARAM_OBJ) $(P
304 STATUS_OBJ = utils/status.o utils/status_profile.o \
305 	     $(LOCKING_OBJ) $(PARAM_OBJ) \
306              $(PROFILE_OBJ) $(LIB_NONSMBD_OBJ) $(POPT_LIB_OBJ) \
307-	     $(LIBSMB_ERR_OBJ) $(FNAME_UTIL_OBJ)
308+	     $(LIBSMB_ERR_OBJ) $(LIBNDR_NTLMSSP_OBJ) $(FNAME_UTIL_OBJ)
309 
310 SMBCONTROL_OBJ = utils/smbcontrol.o $(PARAM_OBJ) $(LIB_NONSMBD_OBJ) \
311-	$(LIBSMB_ERR_OBJ) $(POPT_LIB_OBJ) $(PRINTBASE_OBJ)
312+	$(LIBSMB_ERR_OBJ) $(LIBNDR_NTLMSSP_OBJ) $(POPT_LIB_OBJ) $(PRINTBASE_OBJ)
313 
314 SMBTREE_OBJ = utils/smbtree.o $(PARAM_OBJ) \
315              $(PROFILE_OBJ) $(LIB_NONSMBD_OBJ) $(LIBSMB_OBJ) \
316@@ -1012,11 +1013,11 @@ SMBTREE_OBJ = utils/smbtree.o $(PARAM_OB
317 
318 TESTPARM_OBJ = utils/testparm.o \
319                $(PARAM_OBJ) $(LIB_NONSMBD_OBJ) $(POPT_LIB_OBJ) \
320-	       $(LIBSMB_ERR_OBJ)
321+	       $(LIBSMB_ERR_OBJ) $(LIBNDR_NTLMSSP_OBJ)
322 
323 SMBTA_UTIL_OBJ = utils/smbta-util.o $(PARAM_OBJ) $(POPT_LIB_OBJ) \
324 	$(LIB_NONSMBD_OBJ) \
325-	$(LIBSMB_ERR_OBJ) $(FNAME_UTIL_OBJ)
326+	$(LIBSMB_ERR_OBJ) $(LIBNDR_NTLMSSP_OBJ) $(FNAME_UTIL_OBJ)
327 
328 TEST_LP_LOAD_OBJ = param/test_lp_load.o \
329 		   $(PARAM_OBJ) $(LIB_NONSMBD_OBJ) \
330@@ -1146,6 +1147,7 @@ SMBCONFTORT_OBJ = $(SMBCONFTORT_OBJ0) \
331 		  $(LIB_NONSMBD_OBJ) \
332 		  $(PARAM_OBJ) \
333 		  $(LIBSMB_ERR_OBJ) \
334+		  $(LIBNDR_NTLMSSP_OBJ) \
335 		  $(POPT_LIB_OBJ)
336 
337 PTHREADPOOLTEST_OBJ = lib/pthreadpool/pthreadpool.o \
338@@ -1229,7 +1231,7 @@ CUPS_OBJ = client/smbspool.o $(PARAM_OBJ
339 	  $(LIBNDR_GEN_OBJ0)
340 
341 NMBLOOKUP_OBJ = utils/nmblookup.o $(PARAM_OBJ) $(LIBNMB_OBJ) \
342-               $(LIB_NONSMBD_OBJ) $(POPT_LIB_OBJ) $(LIBSMB_ERR_OBJ)
343+               $(LIB_NONSMBD_OBJ) $(POPT_LIB_OBJ) $(LIBSMB_ERR_OBJ) $(LIBNDR_NTLMSSP_OBJ)
344 
345 SMBTORTURE_OBJ1 = torture/torture.o torture/nbio.o torture/scanner.o torture/utable.o \
346 		torture/denytest.o torture/mangle_test.o \
347@@ -1253,6 +1255,7 @@ MASKTEST_OBJ = torture/masktest.o $(PARA
348 		 $(LIBNDR_GEN_OBJ0)
349 
350 MSGTEST_OBJ = torture/msgtest.o $(PARAM_OBJ) $(LIBSMB_ERR_OBJ) \
351+		 $(LIBNDR_NTLMSSP_OBJ) \
352                  $(LIB_NONSMBD_OBJ) \
353 		 $(LIBNDR_GEN_OBJ0)
354 
355@@ -1269,7 +1272,7 @@ PDBTEST_OBJ = torture/pdbtest.o $(PARAM_
356 
357 VFSTEST_OBJ = torture/cmd_vfs.o torture/vfstest.o $(SMBD_OBJ_BASE) $(READLINE_OBJ)
358 
359-SMBICONV_OBJ = $(PARAM_OBJ) torture/smbiconv.o $(LIB_NONSMBD_OBJ) $(POPT_LIB_OBJ) $(LIBSMB_ERR_OBJ)
360+SMBICONV_OBJ = $(PARAM_OBJ) torture/smbiconv.o $(LIB_NONSMBD_OBJ) $(POPT_LIB_OBJ) $(LIBSMB_ERR_OBJ) $(LIBNDR_NTLMSSP_OBJ)
361 
362 LOG2PCAP_OBJ = utils/log2pcaphex.o
363 
364@@ -1297,17 +1300,17 @@ SMBCQUOTAS_OBJ = utils/smbcquotas.o $(LI
365 EVTLOGADM_OBJ0	= utils/eventlogadm.o
366 
367 EVTLOGADM_OBJ	= $(EVTLOGADM_OBJ0) $(PARAM_OBJ) $(LIB_NONSMBD_OBJ) \
368-		$(LIBSMB_ERR_OBJ) $(LIB_EVENTLOG_OBJ) \
369+		$(LIBSMB_ERR_OBJ) $(LIBNDR_NTLMSSP_OBJ) $(LIB_EVENTLOG_OBJ) \
370 		librpc/gen_ndr/ndr_eventlog.o \
371 		librpc/gen_ndr/ndr_lsa.o
372 
373 SHARESEC_OBJ0 = utils/sharesec.o
374 SHARESEC_OBJ  = $(SHARESEC_OBJ0) $(PARAM_OBJ) $(LIB_NONSMBD_OBJ) \
375-		$(LIBSMB_ERR_OBJ) \
376+		$(LIBSMB_ERR_OBJ) $(LIBNDR_NTLMSSP_OBJ) \
377                 $(POPT_LIB_OBJ)
378 
379 TALLOCTORT_OBJ = @tallocdir@/testsuite.o @tallocdir@/testsuite_main.o \
380-		$(PARAM_OBJ) $(LIB_NONSMBD_OBJ) $(LIBSMB_ERR_OBJ)
381+		$(PARAM_OBJ) $(LIB_NONSMBD_OBJ) $(LIBSMB_ERR_OBJ) $(LIBNDR_NTLMSSP_OBJ)
382 
383 REPLACETORT_OBJ = @libreplacedir@/test/testsuite.o \
384 		@libreplacedir@/test/getifaddrs.o \
385@@ -1323,7 +1326,7 @@ SMBFILTER_OBJ = utils/smbfilter.o $(PARA
386 		 $(LIBNDR_GEN_OBJ0)
387 
388 WINBIND_WINS_NSS_OBJ = ../nsswitch/wins.o $(PARAM_OBJ) \
389-	$(LIB_NONSMBD_OBJ) $(LIBSMB_ERR_OBJ) $(LIBNMB_OBJ)
390+	$(LIB_NONSMBD_OBJ) $(LIBSMB_ERR_OBJ) $(LIBNDR_NTLMSSP_OBJ) $(LIBNMB_OBJ)
391 
392 PAM_SMBPASS_OBJ_0 = pam_smbpass/pam_smb_auth.o pam_smbpass/pam_smb_passwd.o \
393 		pam_smbpass/pam_smb_acct.o pam_smbpass/support.o ../lib/util/asn1.o
394@@ -1531,12 +1534,14 @@ RPC_OPEN_TCP_OBJ = torture/rpc_open_tcp.
395 DBWRAP_TOOL_OBJ = utils/dbwrap_tool.o \
396 		  $(PARAM_OBJ) \
397 		  $(LIB_NONSMBD_OBJ) \
398-		  $(LIBSMB_ERR_OBJ)
399+		  $(LIBSMB_ERR_OBJ) \
400+		  $(LIBNDR_NTLMSSP_OBJ)
401 
402 DBWRAP_TORTURE_OBJ = utils/dbwrap_torture.o \
403 		     $(PARAM_OBJ) \
404 		     $(LIB_NONSMBD_OBJ) \
405 		     $(LIBSMB_ERR_OBJ) \
406+		     $(LIBNDR_NTLMSSP_OBJ) \
407 		     $(POPT_LIB_OBJ)
408 
409 SPLIT_TOKENS_OBJ = utils/split_tokens.o \
410--- a/source4/torture/raw/samba3misc.c
411+++ b/source4/torture/raw/samba3misc.c
412@@ -340,6 +340,7 @@ bool torture_samba3_badpath(struct tortu
413 	bool ret = true;
414 	TALLOC_CTX *mem_ctx;
415 	bool nt_status_support;
416+	bool client_ntlmv2_auth;
417 
418 	if (!(mem_ctx = talloc_init("torture_samba3_badpath"))) {
419 		d_printf("talloc_init failed\n");
420@@ -347,20 +348,17 @@ bool torture_samba3_badpath(struct tortu
421 	}
422 
423 	nt_status_support = lpcfg_nt_status_support(torture->lp_ctx);
424+	client_ntlmv2_auth = lpcfg_client_ntlmv2_auth(torture->lp_ctx);
425 
426-	if (!lpcfg_set_cmdline(torture->lp_ctx, "nt status support", "yes")) {
427-		printf("Could not set 'nt status support = yes'\n");
428-		goto fail;
429-	}
430+	torture_assert_goto(torture, lpcfg_set_cmdline(torture->lp_ctx, "nt status support", "yes"), ret, fail, "Could not set 'nt status support = yes'\n");
431+	torture_assert_goto(torture, lpcfg_set_cmdline(torture->lp_ctx, "client ntlmv2 auth", "yes"), ret, fail, "Could not set 'client ntlmv2 auth = yes'\n");
432 
433 	if (!torture_open_connection(&cli_nt, torture, 0)) {
434 		goto fail;
435 	}
436 
437-	if (!lpcfg_set_cmdline(torture->lp_ctx, "nt status support", "no")) {
438-		printf("Could not set 'nt status support = yes'\n");
439-		goto fail;
440-	}
441+	torture_assert_goto(torture, lpcfg_set_cmdline(torture->lp_ctx, "nt status support", "no"), ret, fail, "Could not set 'nt status support = no'\n");
442+	torture_assert_goto(torture, lpcfg_set_cmdline(torture->lp_ctx, "client ntlmv2 auth", "no"), ret, fail, "Could not set 'client ntlmv2 auth = no'\n");
443 
444 	if (!torture_open_connection(&cli_dos, torture, 1)) {
445 		goto fail;
446@@ -373,6 +371,12 @@ bool torture_samba3_badpath(struct tortu
447 	}
448 
449 	smbcli_deltree(cli_nt->tree, dirname);
450+	torture_assert_goto(torture, lpcfg_set_cmdline(torture->lp_ctx, "nt status support",
451+						       nt_status_support ? "yes":"no"),
452+			    ret, fail, "Could not set 'nt status support' back to where it was\n");
453+	torture_assert_goto(torture, lpcfg_set_cmdline(torture->lp_ctx, "client ntlmv2 auth",
454+						       client_ntlmv2_auth ? "yes":"no"),
455+			    ret, fail, "Could not set 'client ntlmv2 auth' back to where it was\n");
456 
457 	status = smbcli_mkdir(cli_nt->tree, dirname);
458 	if (!NT_STATUS_IS_OK(status)) {
459--- a/source4/torture/basic/base.c
460+++ b/source4/torture/basic/base.c
461@@ -1476,6 +1476,7 @@ static bool torture_chkpath_test(struct
462 static bool torture_samba3_errorpaths(struct torture_context *tctx)
463 {
464 	bool nt_status_support;
465+	bool client_ntlmv2_auth;
466 	struct smbcli_state *cli_nt = NULL, *cli_dos = NULL;
467 	bool result = false;
468 	int fnum;
469@@ -1485,18 +1486,27 @@ static bool torture_samba3_errorpaths(st
470 	NTSTATUS status;
471 
472 	nt_status_support = lpcfg_nt_status_support(tctx->lp_ctx);
473+	client_ntlmv2_auth = lpcfg_client_ntlmv2_auth(tctx->lp_ctx);
474 
475 	if (!lpcfg_set_cmdline(tctx->lp_ctx, "nt status support", "yes")) {
476 		torture_comment(tctx, "Could not set 'nt status support = yes'\n");
477 		goto fail;
478 	}
479+	if (!lpcfg_set_cmdline(tctx->lp_ctx, "client ntlmv2 auth", "yes")) {
480+		torture_result(tctx, TORTURE_FAIL, "Could not set 'client ntlmv2 auth = yes'\n");
481+		goto fail;
482+	}
483 
484 	if (!torture_open_connection(&cli_nt, tctx, 0)) {
485 		goto fail;
486 	}
487 
488 	if (!lpcfg_set_cmdline(tctx->lp_ctx, "nt status support", "no")) {
489-		torture_comment(tctx, "Could not set 'nt status support = yes'\n");
490+		torture_result(tctx, TORTURE_FAIL, "Could not set 'nt status support = no'\n");
491+		goto fail;
492+	}
493+	if (!lpcfg_set_cmdline(tctx->lp_ctx, "client ntlmv2 auth", "no")) {
494+		torture_result(tctx, TORTURE_FAIL, "Could not set 'client ntlmv2 auth = no'\n");
495 		goto fail;
496 	}
497 
498@@ -1506,7 +1516,12 @@ static bool torture_samba3_errorpaths(st
499 
500 	if (!lpcfg_set_cmdline(tctx->lp_ctx, "nt status support",
501 			    nt_status_support ? "yes":"no")) {
502-		torture_comment(tctx, "Could not reset 'nt status support = yes'");
503+		torture_result(tctx, TORTURE_FAIL, "Could not reset 'nt status support'");
504+		goto fail;
505+	}
506+	if (!lpcfg_set_cmdline(tctx->lp_ctx, "client ntlmv2 auth",
507+			       client_ntlmv2_auth ? "yes":"no")) {
508+		torture_result(tctx, TORTURE_FAIL, "Could not reset 'client ntlmv2 auth'");
509 		goto fail;
510 	}
511 
512--- a/source3/libsmb/cliconnect.c
513+++ b/source3/libsmb/cliconnect.c
514@@ -2077,6 +2077,17 @@ NTSTATUS cli_session_setup(struct cli_st
515 		NTSTATUS status;
516 
517 		/* otherwise do a NT1 style session setup */
518+		if (lp_client_ntlmv2_auth() && lp_client_use_spnego()) {
519+			/*
520+			 * Don't send an NTLMv2 response without NTLMSSP
521+			 * if we want to use spnego support
522+			 */
523+			DEBUG(1, ("Server does not support EXTENDED_SECURITY "
524+				  " but 'client use spnego = yes"
525+				  " and 'client ntlmv2 auth = yes'\n"));
526+			return NT_STATUS_ACCESS_DENIED;
527+		}
528+
529 		status = cli_session_setup_nt1(cli, user, pass, passlen,
530 					       ntpass, ntpasslen, workgroup);
531 		if (!NT_STATUS_IS_OK(status)) {
532--- a/docs-xml/smbdotconf/protocol/clientusespnego.xml
533+++ b/docs-xml/smbdotconf/protocol/clientusespnego.xml
534@@ -9,6 +9,11 @@
535     supporting servers (including WindowsXP, Windows2000 and Samba
536     3.0) to agree upon an authentication
537     mechanism.  This enables Kerberos authentication in particular.</para>
538+
539+    <para>When <smbconfoption name="client NTLMv2 auth"/> is also set to
540+    <constant>yes</constant> extended security (SPNEGO) is required
541+    in order to use NTLMv2 only within NTLMSSP. This behavior was
542+    introduced with the patches for CVE-2016-2111.</para>
543 </description>
544 
545 <value type="default">yes</value>
546--- a/docs-xml/smbdotconf/security/clientntlmv2auth.xml
547+++ b/docs-xml/smbdotconf/security/clientntlmv2auth.xml
548@@ -28,6 +28,11 @@
549     NTLMv2 by default, and some sites (particularly those following
550     'best practice' security polices) only allow NTLMv2 responses, and
551     not the weaker LM or NTLM.</para>
552+
553+    <para>When <smbconfoption name="client use spnego"/> is also set to
554+    <constant>yes</constant> extended security (SPNEGO) is required
555+    in order to use NTLMv2 only within NTLMSSP. This behavior was
556+    introduced with the patches for CVE-2016-2111.</para>
557 </description>
558 <value type="default">yes</value>
559 </samba:parameter>
560--- /dev/null
561+++ b/docs-xml/smbdotconf/security/rawntlmv2auth.xml
562@@ -0,0 +1,19 @@
563+<samba:parameter name="raw NTLMv2 auth"
564+                 context="G"
565+                 type="boolean"
566+                 xmlns:samba="http://www.samba.org/samba/DTD/samba-doc">
567+<description>
568+    <para>This parameter determines whether or not <citerefentry><refentrytitle>smbd</refentrytitle>
569+    <manvolnum>8</manvolnum></citerefentry> will allow SMB1 clients without
570+    extended security (without SPNEGO) to use NTLMv2 authentication.</para>
571+
572+    <para>If this option, <command moreinfo="none">lanman auth</command>
573+    and <command moreinfo="none">ntlm auth</command> are all disabled,
574+    then only clients with SPNEGO support will be permitted.
575+    That means NTLMv2 is only supported within NTLMSSP.</para>
576+</description>
577+
578+<related>lanman auth</related>
579+<related>ntlm auth</related>
580+<value type="default">no</value>
581+</samba:parameter>
582--- a/source3/include/proto.h
583+++ b/source3/include/proto.h
584@@ -1489,6 +1489,7 @@ bool lp_map_untrusted_to_domain(void);
585 int lp_restrict_anonymous(void);
586 bool lp_lanman_auth(void);
587 bool lp_ntlm_auth(void);
588+bool lp_raw_ntlmv2_auth(void);
589 bool lp_client_plaintext_auth(void);
590 bool lp_client_lanman_auth(void);
591 bool lp_client_ntlmv2_auth(void);
592--- a/source3/param/loadparm.c
593+++ b/source3/param/loadparm.c
594@@ -336,6 +336,7 @@ struct global {
595 	bool bAllowTrustedDomains;
596 	bool bLanmanAuth;
597 	bool bNTLMAuth;
598+	bool bRawNTLMv2Auth;
599 	bool bUseSpnego;
600 	bool bClientLanManAuth;
601 	bool bClientNTLMv2Auth;
602@@ -1383,6 +1384,15 @@ static struct parm_struct parm_table[] =
603 		.flags		= FLAG_ADVANCED,
604 	},
605 	{
606+		.label		= "raw NTLMv2 auth",
607+		.type		= P_BOOL,
608+		.p_class	= P_GLOBAL,
609+		.ptr		= &Globals.bRawNTLMv2Auth,
610+		.special	= NULL,
611+		.enum_list	= NULL,
612+		.flags		= FLAG_ADVANCED,
613+	},
614+	{
615 		.label		= "client NTLMv2 auth",
616 		.type		= P_BOOL,
617 		.p_class	= P_GLOBAL,
618@@ -5337,6 +5347,7 @@ static void init_globals(bool reinit_glo
619 	Globals.bClientPlaintextAuth = False;	/* Do NOT use a plaintext password even if is requested by the server */
620 	Globals.bLanmanAuth = False;	/* Do NOT use the LanMan hash, even if it is supplied */
621 	Globals.bNTLMAuth = True;	/* Do use NTLMv1 if it is supplied by the client (otherwise NTLMv2) */
622+	Globals.bRawNTLMv2Auth = false;	/* Allow NTLMv2 without NTLMSSP */
623 	Globals.bClientNTLMv2Auth = True; /* Client should always use use NTLMv2, as we can't tell that the server supports it, but most modern servers do */
624 	/* Note, that we will also use NTLM2 session security (which is different), if it is available */
625 
626@@ -5819,6 +5830,7 @@ FN_GLOBAL_BOOL(lp_map_untrusted_to_domai
627 FN_GLOBAL_INTEGER(lp_restrict_anonymous, &Globals.restrict_anonymous)
628 FN_GLOBAL_BOOL(lp_lanman_auth, &Globals.bLanmanAuth)
629 FN_GLOBAL_BOOL(lp_ntlm_auth, &Globals.bNTLMAuth)
630+FN_GLOBAL_BOOL(lp_raw_ntlmv2_auth, &Globals.bRawNTLMv2Auth)
631 FN_GLOBAL_BOOL(lp_client_plaintext_auth, &Globals.bClientPlaintextAuth)
632 FN_GLOBAL_BOOL(lp_client_lanman_auth, &Globals.bClientLanManAuth)
633 FN_GLOBAL_BOOL(lp_client_ntlmv2_auth, &Globals.bClientNTLMv2Auth)
634--- a/source3/auth/auth_util.c
635+++ b/source3/auth/auth_util.c
636@@ -30,6 +30,7 @@
637 #include "../lib/util/util_pw.h"
638 #include "lib/winbind_util.h"
639 #include "passdb.h"
640+#include "../lib/tsocket/tsocket.h"
641 
642 #undef DBGC_CLASS
643 #define DBGC_CLASS DBGC_AUTH
644@@ -367,6 +368,19 @@ NTSTATUS make_user_info_for_reply_enc(st
645                                       const char *client_domain, 
646                                       DATA_BLOB lm_resp, DATA_BLOB nt_resp)
647 {
648+	bool allow_raw = lp_raw_ntlmv2_auth();
649+
650+	if (!allow_raw && nt_resp.length >= 48) {
651+		/*
652+		 * NTLMv2_RESPONSE has at least 48 bytes
653+		 * and should only be supported via NTLMSSP.
654+		 */
655+		DEBUG(2,("Rejecting raw NTLMv2 authentication with "
656+			 "user [%s\\%s]\n",
657+			 client_domain, smb_name));
658+		return NT_STATUS_INVALID_PARAMETER;
659+	}
660+
661 	return make_user_info_map(user_info, smb_name, 
662 				  client_domain, 
663 				  get_remote_machine_name(), 
664--- a/selftest/target/Samba3.pm
665+++ b/selftest/target/Samba3.pm
666@@ -127,6 +127,7 @@ sub setup_dc($$)
667 	domain master = yes
668 	domain logons = yes
669 	lanman auth = yes
670+	raw NTLMv2 auth = yes
671 ";
672 
673 	my $vars = $self->provision($path,
674@@ -230,6 +231,7 @@ sub setup_secserver($$$)
675 	my $secserver_options = "
676 	security = server
677         password server = $s3dcvars->{SERVER_IP}
678+	client ntlmv2 auth = no
679 ";
680 
681 	my $ret = $self->provision($prefix,
682