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