samba: fix some security problems
[openwrt.git] / package / network / services / samba36 / patches / 024-CVE-2016-2111-v3-6.patch
1 From ee105156fa151ebfd34b8febc2928e144b3b7b0e Mon Sep 17 00:00:00 2001
2 From: =?UTF-8?q?G=C3=BCnther=20Deschner?= <gd@samba.org>
3 Date: Sat, 26 Sep 2015 01:29:10 +0200
4 Subject: [PATCH 01/15] CVE-2016-2111: s3:rpc_server/netlogon: always go
5  through netr_creds_server_step_check()
6
7 The ensures we apply the "server schannel = yes" restrictions.
8
9 BUG: https://bugzilla.samba.org/show_bug.cgi?id=11749
10
11 Pair-Programmed-With: Stefan Metzmacher <metze@samba.org>
12
13 Signed-off-by: Guenther Deschner <gd@samba.org>
14 Signed-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,