libcli/auth: rename netlogon_creds_decrypt_samlogon() to netlogon_creds_decrypt_samlo...
[samba.git] / source4 / torture / rpc / samlogon.c
1 /*
2    Unix SMB/CIFS implementation.
3
4    test suite for netlogon SamLogon operations
5
6    Copyright (C) Andrew Tridgell 2003
7    Copyright (C) Andrew Bartlett <abartlet@samba.org> 2003-2004
8    Copyright (C) Tim Potter      2003
9
10    This program is free software; you can redistribute it and/or modify
11    it under the terms of the GNU General Public License as published by
12    the Free Software Foundation; either version 3 of the License, or
13    (at your option) any later version.
14
15    This program is distributed in the hope that it will be useful,
16    but WITHOUT ANY WARRANTY; without even the implied warranty of
17    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18    GNU General Public License for more details.
19
20    You should have received a copy of the GNU General Public License
21    along with this program.  If not, see <http://www.gnu.org/licenses/>.
22 */
23
24 #include "includes.h"
25 #include "librpc/gen_ndr/ndr_netlogon.h"
26 #include "librpc/gen_ndr/ndr_netlogon_c.h"
27 #include "librpc/gen_ndr/ndr_samr_c.h"
28 #include "../lib/crypto/crypto.h"
29 #include "lib/cmdline/popt_common.h"
30 #include "torture/rpc/torture_rpc.h"
31 #include "auth/gensec/gensec.h"
32 #include "auth/gensec/schannel.h"
33 #include "libcli/auth/libcli_auth.h"
34 #include "param/param.h"
35
36 #define TEST_MACHINE_NAME "samlogontest"
37 #define TEST_USER_NAME "samlogontestuser"
38 #define TEST_USER_NAME_WRONG_WKS "samlogontest2"
39 #define TEST_USER_NAME_WRONG_TIME "samlogontest3"
40
41 enum ntlm_break {
42         BREAK_BOTH,
43         BREAK_NONE,
44         BREAK_LM,
45         BREAK_NT,
46         NO_LM,
47         NO_NT
48 };
49
50 struct samlogon_state {
51         TALLOC_CTX *mem_ctx;
52         struct torture_context *tctx;
53         const char *comment;
54         const char *account_name;
55         const char *account_domain;
56         const char *netbios_name;
57         const char *password;
58         const char *workgroup;
59         struct dcerpc_pipe *p;
60         int function_level;
61         uint32_t parameter_control;
62         struct netr_LogonSamLogon r;
63         struct netr_LogonSamLogonEx r_ex;
64         struct netr_LogonSamLogonWithFlags r_flags;
65         struct netr_Authenticator auth, auth2;
66         struct netlogon_creds_CredentialState *creds;
67         NTSTATUS expected_error;
68         bool old_password; /* Allow an old password to be accepted or rejected without error, as well as session key bugs */
69         DATA_BLOB chall;
70 };
71
72 /*
73    Authenticate a user with a challenge/response, checking session key
74    and valid authentication types
75 */
76 static NTSTATUS check_samlogon(struct samlogon_state *samlogon_state,
77                                enum ntlm_break break_which,
78                                uint32_t parameter_control,
79                                DATA_BLOB *chall,
80                                DATA_BLOB *lm_response,
81                                DATA_BLOB *nt_response,
82                                uint8_t lm_key[8],
83                                uint8_t user_session_key[16],
84                                char **error_string)
85 {
86         NTSTATUS status;
87         struct netr_LogonSamLogon *r = &samlogon_state->r;
88         struct netr_LogonSamLogonEx *r_ex = &samlogon_state->r_ex;
89         struct netr_LogonSamLogonWithFlags *r_flags = &samlogon_state->r_flags;
90         struct netr_NetworkInfo ninfo;
91         struct netr_SamBaseInfo *base = NULL;
92         uint16_t validation_level = 0;
93
94         samlogon_state->r.in.logon->network = &ninfo;
95         samlogon_state->r_ex.in.logon->network = &ninfo;
96         samlogon_state->r_flags.in.logon->network = &ninfo;
97
98         ninfo.identity_info.domain_name.string = samlogon_state->account_domain;
99         ninfo.identity_info.parameter_control = parameter_control;
100         ninfo.identity_info.logon_id_low = 0;
101         ninfo.identity_info.logon_id_high = 0;
102         ninfo.identity_info.account_name.string = samlogon_state->account_name;
103         ninfo.identity_info.workstation.string = TEST_MACHINE_NAME;
104
105         memcpy(ninfo.challenge, chall->data, 8);
106
107         switch (break_which) {
108         case BREAK_NONE:
109                 break;
110         case BREAK_LM:
111                 if (lm_response && lm_response->data) {
112                         lm_response->data[0]++;
113                 }
114                 break;
115         case BREAK_NT:
116                 if (nt_response && nt_response->data) {
117                         nt_response->data[0]++;
118                 }
119                 break;
120         case BREAK_BOTH:
121                 if (lm_response && lm_response->data) {
122                         lm_response->data[0]++;
123                 }
124                 if (nt_response && nt_response->data) {
125                         nt_response->data[0]++;
126                 }
127                 break;
128         case NO_LM:
129                 data_blob_free(lm_response);
130                 break;
131         case NO_NT:
132                 data_blob_free(nt_response);
133                 break;
134         }
135
136         if (nt_response) {
137                 ninfo.nt.data = nt_response->data;
138                 ninfo.nt.length = nt_response->length;
139         } else {
140                 ninfo.nt.data = NULL;
141                 ninfo.nt.length = 0;
142         }
143
144         if (lm_response) {
145                 ninfo.lm.data = lm_response->data;
146                 ninfo.lm.length = lm_response->length;
147         } else {
148                 ninfo.lm.data = NULL;
149                 ninfo.lm.length = 0;
150         }
151
152         switch (samlogon_state->function_level) {
153         case NDR_NETR_LOGONSAMLOGON:
154                 ZERO_STRUCT(samlogon_state->auth2);
155                 netlogon_creds_client_authenticator(samlogon_state->creds, &samlogon_state->auth);
156
157                 r->out.return_authenticator = NULL;
158                 status = dcerpc_netr_LogonSamLogon_r(samlogon_state->p->binding_handle,
159                                                      samlogon_state->mem_ctx, r);
160                 if (!NT_STATUS_IS_OK(status)) {
161                         if (error_string) {
162                                 *error_string = strdup(nt_errstr(status));
163                         }
164                         return status;
165                 }
166                 if (!r->out.return_authenticator ||
167                     !netlogon_creds_client_check(samlogon_state->creds, &r->out.return_authenticator->cred)) {
168                         torture_comment(samlogon_state->tctx, "Credential chaining failed\n");
169                 }
170                 if (!NT_STATUS_IS_OK(r->out.result)) {
171                         if (error_string) {
172                                 *error_string = strdup(nt_errstr(r->out.result));
173                         }
174                         return r->out.result;
175                 }
176
177                 validation_level = r->in.validation_level;
178
179                 netlogon_creds_decrypt_samlogon_validation(samlogon_state->creds,
180                                                            validation_level,
181                                                            r->out.validation);
182
183                 switch (validation_level) {
184                 case 2:
185                         base = &r->out.validation->sam2->base;
186                         break;
187                 case 3:
188                         base = &r->out.validation->sam3->base;
189                         break;
190                 case 6:
191                         base = &r->out.validation->sam6->base;
192                         break;
193                 }
194                 break;
195         case NDR_NETR_LOGONSAMLOGONEX:
196                 status = dcerpc_netr_LogonSamLogonEx_r(samlogon_state->p->binding_handle,
197                                                        samlogon_state->mem_ctx, r_ex);
198                 if (!NT_STATUS_IS_OK(status)) {
199                         if (error_string) {
200                                 *error_string = strdup(nt_errstr(status));
201                         }
202                         return status;
203                 }
204                 if (!NT_STATUS_IS_OK(r_ex->out.result)) {
205                         if (error_string) {
206                                 *error_string = strdup(nt_errstr(r_ex->out.result));
207                         }
208                         return r_ex->out.result;
209                 }
210
211                 validation_level = r_ex->in.validation_level;
212
213                 netlogon_creds_decrypt_samlogon_validation(samlogon_state->creds,
214                                                            validation_level,
215                                                            r_ex->out.validation);
216
217                 switch (validation_level) {
218                 case 2:
219                         base = &r_ex->out.validation->sam2->base;
220                         break;
221                 case 3:
222                         base = &r_ex->out.validation->sam3->base;
223                         break;
224                 case 6:
225                         base = &r_ex->out.validation->sam6->base;
226                         break;
227                 }
228                 break;
229         case NDR_NETR_LOGONSAMLOGONWITHFLAGS:
230                 ZERO_STRUCT(samlogon_state->auth2);
231                 netlogon_creds_client_authenticator(samlogon_state->creds, &samlogon_state->auth);
232
233                 r_flags->out.return_authenticator = NULL;
234                 status = dcerpc_netr_LogonSamLogonWithFlags_r(samlogon_state->p->binding_handle,
235                                                               samlogon_state->mem_ctx, r_flags);
236                 if (!NT_STATUS_IS_OK(status)) {
237                         if (error_string) {
238                                 *error_string = strdup(nt_errstr(status));
239                         }
240                         return status;
241                 }
242                 if (!r_flags->out.return_authenticator ||
243                     !netlogon_creds_client_check(samlogon_state->creds, &r_flags->out.return_authenticator->cred)) {
244                         torture_comment(samlogon_state->tctx, "Credential chaining failed\n");
245                 }
246                 if (!NT_STATUS_IS_OK(r_flags->out.result)) {
247                         if (error_string) {
248                                 *error_string = strdup(nt_errstr(r_flags->out.result));
249                         }
250                         return r_flags->out.result;
251                 }
252
253                 validation_level = r_flags->in.validation_level;
254
255                 netlogon_creds_decrypt_samlogon_validation(samlogon_state->creds,
256                                                            validation_level,
257                                                            r_flags->out.validation);
258
259                 switch (validation_level) {
260                 case 2:
261                         base = &r_flags->out.validation->sam2->base;
262                         break;
263                 case 3:
264                         base = &r_flags->out.validation->sam3->base;
265                         break;
266                 case 6:
267                         base = &r_flags->out.validation->sam6->base;
268                         break;
269                 }
270                 break;
271         default:
272                 /* can't happen */
273                 return NT_STATUS_INVALID_PARAMETER;
274         }
275
276         if (!base) {
277                 torture_comment(samlogon_state->tctx, "No user info returned from 'successful' SamLogon*() call!\n");
278                 return NT_STATUS_INVALID_PARAMETER;
279         }
280
281         if (user_session_key) {
282                 memcpy(user_session_key, base->key.key, 16);
283         }
284         if (lm_key) {
285                 memcpy(lm_key, base->LMSessKey.key, 8);
286         }
287
288         return status;
289 }
290
291
292 /*
293  * Test the normal 'LM and NTLM' combination
294  */
295
296 static bool test_lm_ntlm_broken(struct samlogon_state *samlogon_state, enum ntlm_break break_which, char **error_string)
297 {
298         bool pass = true;
299         bool lm_good;
300         NTSTATUS nt_status;
301         DATA_BLOB lm_response = data_blob_talloc(samlogon_state->mem_ctx, NULL, 24);
302         DATA_BLOB nt_response = data_blob_talloc(samlogon_state->mem_ctx, NULL, 24);
303         DATA_BLOB session_key = data_blob_talloc(samlogon_state->mem_ctx, NULL, 16);
304
305         uint8_t lm_key[8];
306         uint8_t user_session_key[16];
307         uint8_t lm_hash[16];
308         uint8_t nt_hash[16];
309
310         ZERO_STRUCT(lm_key);
311         ZERO_STRUCT(user_session_key);
312
313         lm_good = SMBencrypt(samlogon_state->password, samlogon_state->chall.data, lm_response.data);
314         if (!lm_good) {
315                 ZERO_STRUCT(lm_hash);
316         } else {
317                 E_deshash(samlogon_state->password, lm_hash);
318         }
319
320         SMBNTencrypt(samlogon_state->password, samlogon_state->chall.data, nt_response.data);
321
322         E_md4hash(samlogon_state->password, nt_hash);
323         SMBsesskeygen_ntv1(nt_hash, session_key.data);
324
325         nt_status = check_samlogon(samlogon_state,
326                                    break_which,
327                                    samlogon_state->parameter_control,
328                                    &samlogon_state->chall,
329                                    &lm_response,
330                                    &nt_response,
331                                    lm_key,
332                                    user_session_key,
333                                    error_string);
334
335         data_blob_free(&lm_response);
336
337         if (NT_STATUS_EQUAL(NT_STATUS_WRONG_PASSWORD, nt_status)) {
338                 /* for 'long' passwords, the LM password is invalid */
339                 if (break_which == NO_NT && !lm_good) {
340                         return true;
341                 }
342                 /* for 'old' passwords, we allow the server to be OK or wrong password */
343                 if (samlogon_state->old_password) {
344                         return true;
345                 }
346                 return ((break_which == BREAK_NT) || (break_which == BREAK_BOTH));
347         } else if (NT_STATUS_EQUAL(NT_STATUS_NOT_FOUND, nt_status) && strchr_m(samlogon_state->account_name, '@')) {
348                 return ((break_which == BREAK_NT) || (break_which == BREAK_BOTH) || (break_which == NO_NT));
349         } else if (!NT_STATUS_EQUAL(samlogon_state->expected_error, nt_status)) {
350                 SAFE_FREE(*error_string);
351                 asprintf(error_string, "Expected error: %s, got %s", nt_errstr(samlogon_state->expected_error), nt_errstr(nt_status));
352                 return false;
353         } else if (NT_STATUS_EQUAL(samlogon_state->expected_error, nt_status) && !NT_STATUS_IS_OK(nt_status)) {
354                 return true;
355         } else if (!NT_STATUS_IS_OK(nt_status)) {
356                 return false;
357         }
358
359         if (break_which == NO_NT && !lm_good) {
360                 *error_string = strdup("LM password is 'long' (> 14 chars and therefore invalid) but login did not fail!");
361                 return false;
362         }
363
364         if (memcmp(lm_hash, lm_key,
365                    sizeof(lm_key)) != 0) {
366                 torture_comment(samlogon_state->tctx, "LM Key does not match expectations!\n");
367                 torture_comment(samlogon_state->tctx, "lm_key:\n");
368                 dump_data(1, lm_key, 8);
369                 torture_comment(samlogon_state->tctx, "expected:\n");
370                 dump_data(1, lm_hash, 8);
371                 pass = false;
372         }
373
374         switch (break_which) {
375         case NO_NT:
376         {
377                 uint8_t lm_key_expected[16];
378                 memcpy(lm_key_expected, lm_hash, 8);
379                 memset(lm_key_expected+8, '\0', 8);
380                 if (memcmp(lm_key_expected, user_session_key,
381                            16) != 0) {
382                         *error_string = strdup("NT Session Key does not match expectations (should be first-8 LM hash)!\n");
383                         torture_comment(samlogon_state->tctx, "user_session_key:\n");
384                         dump_data(1, user_session_key, sizeof(user_session_key));
385                         torture_comment(samlogon_state->tctx, "expected:\n");
386                         dump_data(1, lm_key_expected, sizeof(lm_key_expected));
387                         pass = false;
388                 }
389                 break;
390         }
391         default:
392                 if (memcmp(session_key.data, user_session_key,
393                            sizeof(user_session_key)) != 0) {
394                         *error_string = strdup("NT Session Key does not match expectations!\n");
395                         torture_comment(samlogon_state->tctx, "user_session_key:\n");
396                         dump_data(1, user_session_key, 16);
397                         torture_comment(samlogon_state->tctx, "expected:\n");
398                         dump_data(1, session_key.data, session_key.length);
399                         pass = false;
400                 }
401         }
402         return pass;
403 }
404
405 /*
406  * Test LM authentication, no NT response supplied
407  */
408
409 static bool test_lm(struct samlogon_state *samlogon_state, char **error_string)
410 {
411
412         return test_lm_ntlm_broken(samlogon_state, NO_NT, error_string);
413 }
414
415 /*
416  * Test the NTLM response only, no LM.
417  */
418
419 static bool test_ntlm(struct samlogon_state *samlogon_state, char **error_string)
420 {
421         return test_lm_ntlm_broken(samlogon_state, NO_LM, error_string);
422 }
423
424 /*
425  * Test the NTLM response only, but in the LM field.
426  */
427
428 static bool test_ntlm_in_lm(struct samlogon_state *samlogon_state, char **error_string)
429 {
430         bool lm_good;
431         bool pass = true;
432         NTSTATUS nt_status;
433         DATA_BLOB nt_response = data_blob_talloc(samlogon_state->mem_ctx, NULL, 24);
434         DATA_BLOB session_key = data_blob_talloc(samlogon_state->mem_ctx, NULL, 16);
435
436         uint8_t lm_key[8];
437         uint8_t lm_hash[16];
438         uint8_t user_session_key[16];
439         uint8_t nt_hash[16];
440
441         ZERO_STRUCT(lm_key);
442         ZERO_STRUCT(user_session_key);
443
444         SMBNTencrypt(samlogon_state->password, samlogon_state->chall.data,
445                      nt_response.data);
446         E_md4hash(samlogon_state->password, nt_hash);
447         SMBsesskeygen_ntv1(nt_hash,
448                            session_key.data);
449
450         lm_good = E_deshash(samlogon_state->password, lm_hash);
451         if (!lm_good) {
452                 ZERO_STRUCT(lm_hash);
453         }
454         nt_status = check_samlogon(samlogon_state,
455                                    BREAK_NONE,
456                                    samlogon_state->parameter_control,
457                                    &samlogon_state->chall,
458                                    &nt_response,
459                                    NULL,
460                                    lm_key,
461                                    user_session_key,
462                                    error_string);
463
464         if (NT_STATUS_EQUAL(NT_STATUS_WRONG_PASSWORD, nt_status)) {
465                 /* for 'old' passwords, we allow the server to be OK or wrong password */
466                 if (samlogon_state->old_password) {
467                         return true;
468                 }
469                 return false;
470         } else if (!NT_STATUS_EQUAL(samlogon_state->expected_error, nt_status)) {
471                 SAFE_FREE(*error_string);
472                 asprintf(error_string, "Expected error: %s, got %s", nt_errstr(samlogon_state->expected_error), nt_errstr(nt_status));
473                 return false;
474         } else if (NT_STATUS_EQUAL(samlogon_state->expected_error, nt_status) && !NT_STATUS_IS_OK(nt_status)) {
475                 return true;
476         } else if (!NT_STATUS_IS_OK(nt_status)) {
477                 return false;
478         }
479
480         if (lm_good) {
481                 if (memcmp(lm_hash, lm_key,
482                            sizeof(lm_key)) != 0) {
483                         torture_comment(samlogon_state->tctx, "LM Key does not match expectations!\n");
484                         torture_comment(samlogon_state->tctx, "lm_key:\n");
485                         dump_data(1, lm_key, 8);
486                         torture_comment(samlogon_state->tctx, "expected:\n");
487                         dump_data(1, lm_hash, 8);
488                         pass = false;
489                 }
490 #if 0
491         } else {
492                 if (memcmp(session_key.data, lm_key,
493                            sizeof(lm_key)) != 0) {
494                         torture_comment(samlogon_state->tctx, "LM Key does not match expectations (first 8 session key)!\n");
495                         torture_comment(samlogon_state->tctx, "lm_key:\n");
496                         dump_data(1, lm_key, 8);
497                         torture_comment(samlogon_state->tctx, "expected:\n");
498                         dump_data(1, session_key.data, 8);
499                         pass = false;
500                 }
501 #endif
502         }
503         if (lm_good && memcmp(lm_hash, user_session_key, 8) != 0) {
504                 uint8_t lm_key_expected[16];
505                 memcpy(lm_key_expected, lm_hash, 8);
506                 memset(lm_key_expected+8, '\0', 8);
507                 if (memcmp(lm_key_expected, user_session_key,
508                            16) != 0) {
509                         torture_comment(samlogon_state->tctx, "NT Session Key does not match expectations (should be first-8 LM hash)!\n");
510                         torture_comment(samlogon_state->tctx, "user_session_key:\n");
511                         dump_data(1, user_session_key, sizeof(user_session_key));
512                         torture_comment(samlogon_state->tctx, "expected:\n");
513                         dump_data(1, lm_key_expected, sizeof(lm_key_expected));
514                         pass = false;
515                 }
516         }
517         return pass;
518 }
519
520 /*
521  * Test the NTLM response only, but in the both the NT and LM fields.
522  */
523
524 static bool test_ntlm_in_both(struct samlogon_state *samlogon_state, char **error_string)
525 {
526         bool pass = true;
527         bool lm_good;
528         NTSTATUS nt_status;
529         DATA_BLOB nt_response = data_blob_talloc(samlogon_state->mem_ctx, NULL, 24);
530         DATA_BLOB session_key = data_blob_talloc(samlogon_state->mem_ctx, NULL, 16);
531
532         uint8_t lm_key[8];
533         uint8_t lm_hash[16];
534         uint8_t user_session_key[16];
535         uint8_t nt_hash[16];
536
537         ZERO_STRUCT(lm_key);
538         ZERO_STRUCT(user_session_key);
539
540         SMBNTencrypt(samlogon_state->password, samlogon_state->chall.data,
541                      nt_response.data);
542         E_md4hash(samlogon_state->password, nt_hash);
543         SMBsesskeygen_ntv1(nt_hash,
544                            session_key.data);
545
546         lm_good = E_deshash(samlogon_state->password, lm_hash);
547         if (!lm_good) {
548                 ZERO_STRUCT(lm_hash);
549         }
550
551         nt_status = check_samlogon(samlogon_state,
552                                    BREAK_NONE,
553                                    samlogon_state->parameter_control,
554                                    &samlogon_state->chall,
555                                    NULL,
556                                    &nt_response,
557                                    lm_key,
558                                    user_session_key,
559                                    error_string);
560
561         if (NT_STATUS_EQUAL(NT_STATUS_WRONG_PASSWORD, nt_status)) {
562                 /* for 'old' passwords, we allow the server to be OK or wrong password */
563                 if (samlogon_state->old_password) {
564                         return true;
565                 }
566                 return false;
567         } else if (!NT_STATUS_EQUAL(samlogon_state->expected_error, nt_status)) {
568                 SAFE_FREE(*error_string);
569                 asprintf(error_string, "Expected error: %s, got %s", nt_errstr(samlogon_state->expected_error), nt_errstr(nt_status));
570                 return false;
571         } else if (NT_STATUS_EQUAL(samlogon_state->expected_error, nt_status) && !NT_STATUS_IS_OK(nt_status)) {
572                 return true;
573         } else if (!NT_STATUS_IS_OK(nt_status)) {
574                 return false;
575         }
576
577         if (!NT_STATUS_IS_OK(nt_status)) {
578                 return false;
579         }
580
581         if (memcmp(lm_hash, lm_key,
582                    sizeof(lm_key)) != 0) {
583                 torture_comment(samlogon_state->tctx, "LM Key does not match expectations!\n");
584                 torture_comment(samlogon_state->tctx, "lm_key:\n");
585                 dump_data(1, lm_key, 8);
586                 torture_comment(samlogon_state->tctx, "expected:\n");
587                 dump_data(1, lm_hash, 8);
588                 pass = false;
589         }
590         if (memcmp(session_key.data, user_session_key,
591                    sizeof(user_session_key)) != 0) {
592                 torture_comment(samlogon_state->tctx, "NT Session Key does not match expectations!\n");
593                 torture_comment(samlogon_state->tctx, "user_session_key:\n");
594                 dump_data(1, user_session_key, 16);
595                 torture_comment(samlogon_state->tctx, "expected:\n");
596                 dump_data(1, session_key.data, session_key.length);
597                 pass = false;
598         }
599
600
601         return pass;
602 }
603
604 /*
605  * Test the NTLMv2 and LMv2 responses
606  */
607
608 enum ntlmv2_domain {
609         UPPER_DOMAIN,
610         NO_DOMAIN
611 };
612
613 static bool test_lmv2_ntlmv2_broken(struct samlogon_state *samlogon_state,
614                                     enum ntlm_break break_which,
615                                     enum ntlmv2_domain ntlmv2_domain,
616                                     char **error_string)
617 {
618         bool pass = true;
619         NTSTATUS nt_status;
620         DATA_BLOB ntlmv2_response = data_blob(NULL, 0);
621         DATA_BLOB lmv2_response = data_blob(NULL, 0);
622         DATA_BLOB lmv2_session_key = data_blob(NULL, 0);
623         DATA_BLOB ntlmv2_session_key = data_blob(NULL, 0);
624         DATA_BLOB names_blob = NTLMv2_generate_names_blob(samlogon_state->mem_ctx, TEST_MACHINE_NAME, samlogon_state->workgroup);
625
626         uint8_t lm_session_key[8];
627         uint8_t user_session_key[16];
628
629         ZERO_STRUCT(lm_session_key);
630         ZERO_STRUCT(user_session_key);
631
632         switch (ntlmv2_domain) {
633         case UPPER_DOMAIN:
634                 if (!SMBNTLMv2encrypt(samlogon_state->mem_ctx,
635                                       samlogon_state->account_name, samlogon_state->account_domain,
636                                       samlogon_state->password, &samlogon_state->chall,
637                                       &names_blob,
638                                       &lmv2_response, &ntlmv2_response,
639                                       &lmv2_session_key, &ntlmv2_session_key)) {
640                         data_blob_free(&names_blob);
641                         return false;
642                 }
643                 break;
644         case NO_DOMAIN:
645                 if (!SMBNTLMv2encrypt(samlogon_state->mem_ctx,
646                                       samlogon_state->account_name, "",
647                                       samlogon_state->password, &samlogon_state->chall,
648                                       &names_blob,
649                                       &lmv2_response, &ntlmv2_response,
650                                       &lmv2_session_key, &ntlmv2_session_key)) {
651                         data_blob_free(&names_blob);
652                         return false;
653                 }
654                 break;
655         }
656         data_blob_free(&names_blob);
657
658         nt_status = check_samlogon(samlogon_state,
659                                    break_which,
660                                    samlogon_state->parameter_control,
661                                    &samlogon_state->chall,
662                                    &lmv2_response,
663                                    &ntlmv2_response,
664                                    lm_session_key,
665                                    user_session_key,
666                                    error_string);
667
668         data_blob_free(&lmv2_response);
669         data_blob_free(&ntlmv2_response);
670
671
672         if (NT_STATUS_EQUAL(NT_STATUS_WRONG_PASSWORD, nt_status)) {
673                 /* for 'old' passwords, we allow the server to be OK or wrong password */
674                 if (samlogon_state->old_password) {
675                         return true;
676                 }
677                 return break_which == BREAK_BOTH;
678         } else if (NT_STATUS_EQUAL(NT_STATUS_NOT_FOUND, nt_status) && strchr_m(samlogon_state->account_name, '@')) {
679                 return ((break_which == BREAK_NT) || (break_which == BREAK_BOTH) || (break_which == NO_NT));
680         } else if (!NT_STATUS_EQUAL(samlogon_state->expected_error, nt_status)) {
681                 SAFE_FREE(*error_string);
682                 asprintf(error_string, "Expected error: %s, got %s", nt_errstr(samlogon_state->expected_error), nt_errstr(nt_status));
683                 return false;
684         } else if (NT_STATUS_EQUAL(samlogon_state->expected_error, nt_status) && !NT_STATUS_IS_OK(nt_status)) {
685                 return true;
686         } else if (!NT_STATUS_IS_OK(nt_status)) {
687                 return false;
688         }
689
690
691         switch (break_which) {
692         case NO_NT:
693                 if (memcmp(lmv2_session_key.data, user_session_key,
694                            sizeof(user_session_key)) != 0) {
695                         torture_comment(samlogon_state->tctx, "USER (LMv2) Session Key does not match expectations!\n");
696                         torture_comment(samlogon_state->tctx, "user_session_key:\n");
697                         dump_data(1, user_session_key, 16);
698                         torture_comment(samlogon_state->tctx, "expected:\n");
699                         dump_data(1, lmv2_session_key.data, ntlmv2_session_key.length);
700                         pass = false;
701                 }
702                 if (memcmp(lmv2_session_key.data, lm_session_key,
703                                    sizeof(lm_session_key)) != 0) {
704                         torture_comment(samlogon_state->tctx, "LM (LMv2) Session Key does not match expectations!\n");
705                         torture_comment(samlogon_state->tctx, "lm_session_key:\n");
706                         dump_data(1, lm_session_key, 8);
707                         torture_comment(samlogon_state->tctx, "expected:\n");
708                         dump_data(1, lmv2_session_key.data, 8);
709                         pass = false;
710                 }
711                 break;
712         default:
713                 if (memcmp(ntlmv2_session_key.data, user_session_key,
714                            sizeof(user_session_key)) != 0) {
715                         if (memcmp(lmv2_session_key.data, user_session_key,
716                                    sizeof(user_session_key)) == 0) {
717                                 torture_comment(samlogon_state->tctx, "USER (NTLMv2) Session Key expected, got LMv2 sessesion key instead:\n");
718                                 torture_comment(samlogon_state->tctx, "user_session_key:\n");
719                                 dump_data(1, user_session_key, 16);
720                                 torture_comment(samlogon_state->tctx, "expected:\n");
721                                 dump_data(1, ntlmv2_session_key.data, ntlmv2_session_key.length);
722                                 pass = false;
723
724                         } else {
725                                 torture_comment(samlogon_state->tctx, "USER (NTLMv2) Session Key does not match expectations!\n");
726                                 torture_comment(samlogon_state->tctx, "user_session_key:\n");
727                                 dump_data(1, user_session_key, 16);
728                                 torture_comment(samlogon_state->tctx, "expected:\n");
729                                 dump_data(1, ntlmv2_session_key.data, ntlmv2_session_key.length);
730                                 pass = false;
731                         }
732                 }
733                 if (memcmp(ntlmv2_session_key.data, lm_session_key,
734                            sizeof(lm_session_key)) != 0) {
735                         if (memcmp(lmv2_session_key.data, lm_session_key,
736                                    sizeof(lm_session_key)) == 0) {
737                                 torture_comment(samlogon_state->tctx, "LM (NTLMv2) Session Key expected, got LMv2 sessesion key instead:\n");
738                                 torture_comment(samlogon_state->tctx, "user_session_key:\n");
739                                 dump_data(1, lm_session_key, 8);
740                                 torture_comment(samlogon_state->tctx, "expected:\n");
741                                 dump_data(1, ntlmv2_session_key.data, 8);
742                                 pass = false;
743                         } else {
744                                 torture_comment(samlogon_state->tctx, "LM (NTLMv2) Session Key does not match expectations!\n");
745                                 torture_comment(samlogon_state->tctx, "lm_session_key:\n");
746                                 dump_data(1, lm_session_key, 8);
747                                 torture_comment(samlogon_state->tctx, "expected:\n");
748                                 dump_data(1, ntlmv2_session_key.data, 8);
749                                 pass = false;
750                         }
751                 }
752         }
753
754         return pass;
755 }
756
757 /*
758  * Test the NTLM and LMv2 responses
759  */
760
761 static bool test_lmv2_ntlm_broken(struct samlogon_state *samlogon_state,
762                                   enum ntlm_break break_which,
763                                   enum ntlmv2_domain ntlmv2_domain,
764                                   char **error_string)
765 {
766         bool pass = true;
767         NTSTATUS nt_status;
768         DATA_BLOB ntlmv2_response = data_blob(NULL, 0);
769         DATA_BLOB lmv2_response = data_blob(NULL, 0);
770         DATA_BLOB lmv2_session_key = data_blob(NULL, 0);
771         DATA_BLOB ntlmv2_session_key = data_blob(NULL, 0);
772         DATA_BLOB names_blob = NTLMv2_generate_names_blob(samlogon_state->mem_ctx, samlogon_state->netbios_name, samlogon_state->workgroup);
773
774         DATA_BLOB ntlm_response = data_blob_talloc(samlogon_state->mem_ctx, NULL, 24);
775         DATA_BLOB ntlm_session_key = data_blob_talloc(samlogon_state->mem_ctx, NULL, 16);
776
777         bool lm_good;
778         uint8_t lm_hash[16];
779         uint8_t lm_session_key[8];
780         uint8_t user_session_key[16];
781         uint8_t nt_hash[16];
782
783         SMBNTencrypt(samlogon_state->password, samlogon_state->chall.data,
784                      ntlm_response.data);
785         E_md4hash(samlogon_state->password, nt_hash);
786         SMBsesskeygen_ntv1(nt_hash,
787                            ntlm_session_key.data);
788
789         lm_good = E_deshash(samlogon_state->password, lm_hash);
790         if (!lm_good) {
791                 ZERO_STRUCT(lm_hash);
792         }
793
794         ZERO_STRUCT(lm_session_key);
795         ZERO_STRUCT(user_session_key);
796
797         switch (ntlmv2_domain) {
798         case UPPER_DOMAIN:
799                 /* TODO - test with various domain cases, and without domain */
800                 if (!SMBNTLMv2encrypt(samlogon_state->mem_ctx,
801                                       samlogon_state->account_name, samlogon_state->account_domain,
802                                       samlogon_state->password, &samlogon_state->chall,
803                                       &names_blob,
804                                       &lmv2_response, &ntlmv2_response,
805                                       &lmv2_session_key, &ntlmv2_session_key)) {
806                         data_blob_free(&names_blob);
807                         return false;
808                 }
809                 break;
810         case NO_DOMAIN:
811                 /* TODO - test with various domain cases, and without domain */
812                 if (!SMBNTLMv2encrypt(samlogon_state->mem_ctx,
813                                       samlogon_state->account_name, "",
814                                       samlogon_state->password, &samlogon_state->chall,
815                                       &names_blob,
816                                       &lmv2_response, &ntlmv2_response,
817                                       &lmv2_session_key, &ntlmv2_session_key)) {
818                         data_blob_free(&names_blob);
819                         return false;
820                 }
821                 break;
822         }
823
824         data_blob_free(&names_blob);
825
826         nt_status = check_samlogon(samlogon_state,
827                                    break_which,
828                                    samlogon_state->parameter_control,
829                                    &samlogon_state->chall,
830                                    &lmv2_response,
831                                    &ntlm_response,
832                                    lm_session_key,
833                                    user_session_key,
834                                    error_string);
835
836         data_blob_free(&lmv2_response);
837         data_blob_free(&ntlmv2_response);
838
839
840         if (NT_STATUS_EQUAL(NT_STATUS_WRONG_PASSWORD, nt_status)) {
841                 /* for 'old' passwords, we allow the server to be OK or wrong password */
842                 if (samlogon_state->old_password) {
843                         return true;
844                 }
845                 return ((break_which == BREAK_NT) || (break_which == BREAK_BOTH));
846         } else if (NT_STATUS_EQUAL(NT_STATUS_NOT_FOUND, nt_status) && strchr_m(samlogon_state->account_name, '@')) {
847                 return ((break_which == BREAK_NT) || (break_which == BREAK_BOTH));
848         } else if (!NT_STATUS_EQUAL(samlogon_state->expected_error, nt_status)) {
849                 SAFE_FREE(*error_string);
850                 asprintf(error_string, "Expected error: %s, got %s", nt_errstr(samlogon_state->expected_error), nt_errstr(nt_status));
851                 return false;
852         } else if (NT_STATUS_EQUAL(samlogon_state->expected_error, nt_status) && !NT_STATUS_IS_OK(nt_status)) {
853                 return true;
854         } else if (!NT_STATUS_IS_OK(nt_status)) {
855                 return false;
856         }
857
858         switch (break_which) {
859         case NO_NT:
860                 if (memcmp(lmv2_session_key.data, user_session_key,
861                            sizeof(user_session_key)) != 0) {
862                         torture_comment(samlogon_state->tctx, "USER (LMv2) Session Key does not match expectations!\n");
863                         torture_comment(samlogon_state->tctx, "user_session_key:\n");
864                         dump_data(1, user_session_key, 16);
865                         torture_comment(samlogon_state->tctx, "expected:\n");
866                         dump_data(1, lmv2_session_key.data, ntlmv2_session_key.length);
867                         pass = false;
868                 }
869                 if (memcmp(lmv2_session_key.data, lm_session_key,
870                            sizeof(lm_session_key)) != 0) {
871                         torture_comment(samlogon_state->tctx, "LM (LMv2) Session Key does not match expectations!\n");
872                         torture_comment(samlogon_state->tctx, "lm_session_key:\n");
873                         dump_data(1, lm_session_key, 8);
874                         torture_comment(samlogon_state->tctx, "expected:\n");
875                         dump_data(1, lmv2_session_key.data, 8);
876                         pass = false;
877                 }
878                 break;
879         case BREAK_LM:
880                 if (memcmp(ntlm_session_key.data, user_session_key,
881                            sizeof(user_session_key)) != 0) {
882                         torture_comment(samlogon_state->tctx, "USER (NTLMv2) Session Key does not match expectations!\n");
883                         torture_comment(samlogon_state->tctx, "user_session_key:\n");
884                         dump_data(1, user_session_key, 16);
885                         torture_comment(samlogon_state->tctx, "expected:\n");
886                         dump_data(1, ntlm_session_key.data, ntlm_session_key.length);
887                         pass = false;
888                 }
889                 if (lm_good) {
890                         if (memcmp(lm_hash, lm_session_key,
891                                    sizeof(lm_session_key)) != 0) {
892                                 torture_comment(samlogon_state->tctx, "LM Session Key does not match expectations!\n");
893                                 torture_comment(samlogon_state->tctx, "lm_session_key:\n");
894                                 dump_data(1, lm_session_key, 8);
895                                 torture_comment(samlogon_state->tctx, "expected:\n");
896                                 dump_data(1, lm_hash, 8);
897                                 pass = false;
898                         }
899                 } else {
900                         static const uint8_t zeros[8];
901                         if (memcmp(zeros, lm_session_key,
902                                    sizeof(lm_session_key)) != 0) {
903                                 torture_comment(samlogon_state->tctx, "LM Session Key does not match expectations (zeros)!\n");
904                                 torture_comment(samlogon_state->tctx, "lm_session_key:\n");
905                                 dump_data(1, lm_session_key, 8);
906                                 torture_comment(samlogon_state->tctx, "expected:\n");
907                                 dump_data(1, zeros, 8);
908                                 pass = false;
909                         }
910                 }
911                 break;
912         default:
913                 if (memcmp(ntlm_session_key.data, user_session_key,
914                            sizeof(user_session_key)) != 0) {
915                         torture_comment(samlogon_state->tctx, "USER (NTLMv2) Session Key does not match expectations!\n");
916                         torture_comment(samlogon_state->tctx, "user_session_key:\n");
917                         dump_data(1, user_session_key, 16);
918                         torture_comment(samlogon_state->tctx, "expected:\n");
919                         dump_data(1, ntlm_session_key.data, ntlm_session_key.length);
920                         pass = false;
921                 }
922                 if (memcmp(ntlm_session_key.data, lm_session_key,
923                            sizeof(lm_session_key)) != 0) {
924                         torture_comment(samlogon_state->tctx, "LM (NTLMv2) Session Key does not match expectations!\n");
925                         torture_comment(samlogon_state->tctx, "lm_session_key:\n");
926                         dump_data(1, lm_session_key, 8);
927                         torture_comment(samlogon_state->tctx, "expected:\n");
928                         dump_data(1, ntlm_session_key.data, 8);
929                         pass = false;
930                 }
931         }
932
933         return pass;
934 }
935
936 /*
937  * Test the NTLMv2 and LMv2 responses
938  */
939
940 static bool test_lmv2_ntlmv2(struct samlogon_state *samlogon_state, char **error_string)
941 {
942         return test_lmv2_ntlmv2_broken(samlogon_state, BREAK_NONE, UPPER_DOMAIN, error_string);
943 }
944
945 #if 0
946 static bool test_lmv2_ntlmv2_no_dom(struct samlogon_state *samlogon_state, char **error_string)
947 {
948         return test_lmv2_ntlmv2_broken(samlogon_state, BREAK_NONE, NO_DOMAIN, error_string);
949 }
950 #endif
951
952 /*
953  * Test the LMv2 response only
954  */
955
956 static bool test_lmv2(struct samlogon_state *samlogon_state, char **error_string)
957 {
958         return test_lmv2_ntlmv2_broken(samlogon_state, NO_NT, UPPER_DOMAIN, error_string);
959 }
960
961 static bool test_lmv2_no_dom(struct samlogon_state *samlogon_state, char **error_string)
962 {
963         return test_lmv2_ntlmv2_broken(samlogon_state, NO_NT, NO_DOMAIN, error_string);
964 }
965
966 /*
967  * Test the NTLMv2 response only
968  */
969
970 static bool test_ntlmv2(struct samlogon_state *samlogon_state, char **error_string)
971 {
972         return test_lmv2_ntlmv2_broken(samlogon_state, NO_LM, UPPER_DOMAIN, error_string);
973 }
974
975 static bool test_ntlmv2_no_dom(struct samlogon_state *samlogon_state, char **error_string)
976 {
977         return test_lmv2_ntlmv2_broken(samlogon_state, NO_LM, NO_DOMAIN, error_string);
978 }
979
980 static bool test_lm_ntlm(struct samlogon_state *samlogon_state, char **error_string)
981 {
982         return test_lm_ntlm_broken(samlogon_state, BREAK_NONE, error_string);
983 }
984
985 static bool test_ntlm_lm_broken(struct samlogon_state *samlogon_state, char **error_string)
986 {
987         return test_lm_ntlm_broken(samlogon_state, BREAK_LM, error_string);
988 }
989
990 static bool test_ntlm_ntlm_broken(struct samlogon_state *samlogon_state, char **error_string)
991 {
992         return test_lm_ntlm_broken(samlogon_state, BREAK_NT, error_string);
993 }
994
995 static bool test_lm_ntlm_both_broken(struct samlogon_state *samlogon_state, char **error_string)
996 {
997         return test_lm_ntlm_broken(samlogon_state, BREAK_BOTH, error_string);
998 }
999 static bool test_ntlmv2_lmv2_broken(struct samlogon_state *samlogon_state, char **error_string)
1000 {
1001         return test_lmv2_ntlmv2_broken(samlogon_state, BREAK_LM, UPPER_DOMAIN, error_string);
1002 }
1003
1004 static bool test_ntlmv2_lmv2_broken_no_dom(struct samlogon_state *samlogon_state, char **error_string)
1005 {
1006         return test_lmv2_ntlmv2_broken(samlogon_state, BREAK_LM, NO_DOMAIN, error_string);
1007 }
1008
1009 static bool test_ntlmv2_ntlmv2_broken(struct samlogon_state *samlogon_state, char **error_string)
1010 {
1011         return test_lmv2_ntlmv2_broken(samlogon_state, BREAK_NT, UPPER_DOMAIN, error_string);
1012 }
1013
1014 #if 0
1015 static bool test_ntlmv2_ntlmv2_broken_no_dom(struct samlogon_state *samlogon_state, char **error_string)
1016 {
1017         return test_lmv2_ntlmv2_broken(samlogon_state, BREAK_NT, NO_DOMAIN, error_string);
1018 }
1019 #endif
1020
1021 static bool test_ntlmv2_both_broken(struct samlogon_state *samlogon_state, char **error_string)
1022 {
1023         return test_lmv2_ntlmv2_broken(samlogon_state, BREAK_BOTH, UPPER_DOMAIN, error_string);
1024 }
1025
1026 static bool test_ntlmv2_both_broken_no_dom(struct samlogon_state *samlogon_state, char **error_string)
1027 {
1028         return test_lmv2_ntlmv2_broken(samlogon_state, BREAK_BOTH, NO_DOMAIN, error_string);
1029 }
1030
1031 static bool test_lmv2_ntlm_both_broken(struct samlogon_state *samlogon_state, char **error_string)
1032 {
1033         return test_lmv2_ntlm_broken(samlogon_state, BREAK_BOTH, UPPER_DOMAIN, error_string);
1034 }
1035
1036 static bool test_lmv2_ntlm_both_broken_no_dom(struct samlogon_state *samlogon_state, char **error_string)
1037 {
1038         return test_lmv2_ntlm_broken(samlogon_state, BREAK_BOTH, NO_DOMAIN, error_string);
1039 }
1040
1041 static bool test_lmv2_ntlm_break_ntlm(struct samlogon_state *samlogon_state, char **error_string)
1042 {
1043         return test_lmv2_ntlm_broken(samlogon_state, BREAK_NT, UPPER_DOMAIN, error_string);
1044 }
1045
1046 static bool test_lmv2_ntlm_break_ntlm_no_dom(struct samlogon_state *samlogon_state, char **error_string)
1047 {
1048         return test_lmv2_ntlm_broken(samlogon_state, BREAK_NT, NO_DOMAIN, error_string);
1049 }
1050
1051 static bool test_lmv2_ntlm_break_lm(struct samlogon_state *samlogon_state, char **error_string)
1052 {
1053         return test_lmv2_ntlm_broken(samlogon_state, BREAK_LM, UPPER_DOMAIN, error_string);
1054 }
1055
1056 static bool test_lmv2_ntlm_break_lm_no_dom(struct samlogon_state *samlogon_state, char **error_string)
1057 {
1058         return test_lmv2_ntlm_broken(samlogon_state, BREAK_LM, NO_DOMAIN, error_string);
1059 }
1060
1061 /*
1062  * Test the NTLM2 response (extra challenge in LM feild)
1063  *
1064  * This test is the same as the 'break LM' test, but checks that the
1065  * server implements NTLM2 session security in the right place
1066  * (NETLOGON is the wrong place).
1067  */
1068
1069 static bool test_ntlm2(struct samlogon_state *samlogon_state, char **error_string)
1070 {
1071         bool pass = true;
1072         NTSTATUS nt_status;
1073         DATA_BLOB lm_response = data_blob_talloc(samlogon_state->mem_ctx, NULL, 24);
1074         DATA_BLOB nt_response = data_blob_talloc(samlogon_state->mem_ctx, NULL, 24);
1075
1076         bool lm_good;
1077         uint8_t lm_key[8];
1078         uint8_t nt_hash[16];
1079         uint8_t lm_hash[16];
1080         uint8_t nt_key[16];
1081         uint8_t user_session_key[16];
1082         uint8_t expected_user_session_key[16];
1083         uint8_t session_nonce_hash[16];
1084         uint8_t client_chall[8];
1085
1086         struct MD5Context md5_session_nonce_ctx;
1087         HMACMD5Context hmac_ctx;
1088
1089         ZERO_STRUCT(user_session_key);
1090         ZERO_STRUCT(lm_key);
1091         generate_random_buffer(client_chall, 8);
1092
1093         MD5Init(&md5_session_nonce_ctx);
1094         MD5Update(&md5_session_nonce_ctx, samlogon_state->chall.data, 8);
1095         MD5Update(&md5_session_nonce_ctx, client_chall, 8);
1096         MD5Final(session_nonce_hash, &md5_session_nonce_ctx);
1097
1098         E_md4hash(samlogon_state->password, (uint8_t *)nt_hash);
1099         lm_good = E_deshash(samlogon_state->password, (uint8_t *)lm_hash);
1100         SMBsesskeygen_ntv1((const uint8_t *)nt_hash,
1101                            nt_key);
1102
1103         SMBNTencrypt(samlogon_state->password, samlogon_state->chall.data, nt_response.data);
1104
1105         memcpy(lm_response.data, session_nonce_hash, 8);
1106         memset(lm_response.data + 8, 0, 16);
1107
1108         hmac_md5_init_rfc2104(nt_key, 16, &hmac_ctx);
1109         hmac_md5_update(samlogon_state->chall.data, 8, &hmac_ctx);
1110         hmac_md5_update(client_chall, 8, &hmac_ctx);
1111         hmac_md5_final(expected_user_session_key, &hmac_ctx);
1112
1113         nt_status = check_samlogon(samlogon_state,
1114                                    BREAK_NONE,
1115                                    samlogon_state->parameter_control,
1116                                    &samlogon_state->chall,
1117                                    &lm_response,
1118                                    &nt_response,
1119                                    lm_key,
1120                                    user_session_key,
1121                                    error_string);
1122
1123         if (NT_STATUS_EQUAL(NT_STATUS_WRONG_PASSWORD, nt_status)) {
1124                 /* for 'old' passwords, we allow the server to be OK or wrong password */
1125                 if (samlogon_state->old_password) {
1126                         return true;
1127                 }
1128                 return false;
1129         } else if (!NT_STATUS_EQUAL(samlogon_state->expected_error, nt_status)) {
1130                 SAFE_FREE(*error_string);
1131                 asprintf(error_string, "Expected error: %s, got %s", nt_errstr(samlogon_state->expected_error), nt_errstr(nt_status));
1132                 return false;
1133         } else if (NT_STATUS_EQUAL(samlogon_state->expected_error, nt_status) && !NT_STATUS_IS_OK(nt_status)) {
1134                 return true;
1135         } else if (!NT_STATUS_IS_OK(nt_status)) {
1136                 return false;
1137         }
1138
1139         if (lm_good) {
1140                 if (memcmp(lm_hash, lm_key,
1141                            sizeof(lm_key)) != 0) {
1142                         torture_comment(samlogon_state->tctx, "LM Key does not match expectations!\n");
1143                         torture_comment(samlogon_state->tctx, "lm_key:\n");
1144                         dump_data(1, lm_key, 8);
1145                         torture_comment(samlogon_state->tctx, "expected:\n");
1146                         dump_data(1, lm_hash, 8);
1147                         pass = false;
1148                 }
1149         } else {
1150                 static const uint8_t zeros[8];
1151                 if (memcmp(zeros, lm_key,
1152                            sizeof(lm_key)) != 0) {
1153                         torture_comment(samlogon_state->tctx, "LM Session Key does not match expectations (zeros)!\n");
1154                         torture_comment(samlogon_state->tctx, "lm_key:\n");
1155                         dump_data(1, lm_key, 8);
1156                         torture_comment(samlogon_state->tctx, "expected:\n");
1157                         dump_data(1, zeros, 8);
1158                         pass = false;
1159                 }
1160         }
1161         if (memcmp(nt_key, user_session_key, 16) != 0) {
1162                 torture_comment(samlogon_state->tctx, "NT Session Key does not match expectations (should be NT Key)!\n");
1163                 torture_comment(samlogon_state->tctx, "user_session_key:\n");
1164                 dump_data(1, user_session_key, sizeof(user_session_key));
1165                 torture_comment(samlogon_state->tctx, "expected:\n");
1166                 dump_data(1, nt_key, sizeof(nt_key));
1167                 pass = false;
1168         }
1169         return pass;
1170 }
1171
1172 static bool test_plaintext(struct samlogon_state *samlogon_state, enum ntlm_break break_which, char **error_string)
1173 {
1174         NTSTATUS nt_status;
1175         DATA_BLOB nt_response = data_blob(NULL, 0);
1176         DATA_BLOB lm_response = data_blob(NULL, 0);
1177         char *password;
1178         char *dospw;
1179         smb_ucs2_t *unicodepw;
1180         size_t converted_size = 0;
1181         uint8_t user_session_key[16];
1182         uint8_t lm_key[16];
1183         uint8_t lm_hash[16];
1184         static const uint8_t zeros[8];
1185         DATA_BLOB chall = data_blob_talloc(samlogon_state->mem_ctx, zeros, sizeof(zeros));
1186         bool lm_good = E_deshash(samlogon_state->password, lm_hash);
1187
1188         ZERO_STRUCT(user_session_key);
1189
1190         if (!push_ucs2_talloc(samlogon_state->mem_ctx,
1191                               &unicodepw, samlogon_state->password, &converted_size)) {
1192                 DEBUG(0, ("push_ucs2_allocate failed!\n"));
1193                 exit(1);
1194         }
1195
1196         nt_response = data_blob_talloc(samlogon_state->mem_ctx, unicodepw, strlen_m(samlogon_state->password)*2);
1197
1198         password = strupper_talloc(samlogon_state->mem_ctx, samlogon_state->password);
1199
1200         if (!convert_string_talloc(samlogon_state->mem_ctx,
1201                                    CH_UNIX, CH_DOS,
1202                                    password, strlen(password)+1,
1203                                    (void**)&dospw, &converted_size)) {
1204                 DEBUG(0, ("convert_string_talloc failed!\n"));
1205                 exit(1);
1206         }
1207
1208         lm_response = data_blob_talloc(samlogon_state->mem_ctx, dospw, strlen(dospw));
1209
1210         nt_status = check_samlogon(samlogon_state,
1211                                    break_which,
1212                                    samlogon_state->parameter_control | MSV1_0_CLEARTEXT_PASSWORD_ALLOWED,
1213                                    &chall,
1214                                    &lm_response,
1215                                    &nt_response,
1216                                    lm_key,
1217                                    user_session_key,
1218                                    error_string);
1219
1220         if (NT_STATUS_EQUAL(NT_STATUS_WRONG_PASSWORD, nt_status)) {
1221                 /* for 'old' passwords, we allow the server to be OK or wrong password */
1222                 if (samlogon_state->old_password) {
1223                         return true;
1224                 }
1225                 /* for 'long' passwords, the LM password is invalid */
1226                 if (break_which == NO_NT && !lm_good) {
1227                         return true;
1228                 }
1229                 return ((break_which == BREAK_NT) || (break_which == BREAK_BOTH));
1230         } else if (NT_STATUS_EQUAL(NT_STATUS_NOT_FOUND, nt_status) && strchr_m(samlogon_state->account_name, '@')) {
1231                 return ((break_which == BREAK_NT) || (break_which == BREAK_BOTH) || (break_which == NO_NT));
1232         } else if (!NT_STATUS_EQUAL(samlogon_state->expected_error, nt_status)) {
1233                 SAFE_FREE(*error_string);
1234                 asprintf(error_string, "Expected error: %s, got %s", nt_errstr(samlogon_state->expected_error), nt_errstr(nt_status));
1235                 return false;
1236         } else if (NT_STATUS_EQUAL(samlogon_state->expected_error, nt_status) && !NT_STATUS_IS_OK(nt_status)) {
1237                 return true;
1238         } else if (!NT_STATUS_IS_OK(nt_status)) {
1239                 return false;
1240         }
1241
1242         if (break_which == NO_NT && !lm_good) {
1243                 *error_string = strdup("LM password is 'long' (> 14 chars and therefore invalid) but login did not fail!");
1244                 return false;
1245         }
1246
1247         return true;
1248 }
1249
1250 static bool test_plaintext_none_broken(struct samlogon_state *samlogon_state,
1251                                        char **error_string) {
1252         return test_plaintext(samlogon_state, BREAK_NONE, error_string);
1253 }
1254
1255 static bool test_plaintext_lm_broken(struct samlogon_state *samlogon_state,
1256                                      char **error_string) {
1257         return test_plaintext(samlogon_state, BREAK_LM, error_string);
1258 }
1259
1260 static bool test_plaintext_nt_broken(struct samlogon_state *samlogon_state,
1261                                      char **error_string) {
1262         return test_plaintext(samlogon_state, BREAK_NT, error_string);
1263 }
1264
1265 static bool test_plaintext_nt_only(struct samlogon_state *samlogon_state,
1266                                    char **error_string) {
1267         return test_plaintext(samlogon_state, NO_LM, error_string);
1268 }
1269
1270 static bool test_plaintext_lm_only(struct samlogon_state *samlogon_state,
1271                                    char **error_string) {
1272         return test_plaintext(samlogon_state, NO_NT, error_string);
1273 }
1274
1275 /*
1276    Tests:
1277
1278    - LM only
1279    - NT and LM
1280    - NT
1281    - NT in LM field
1282    - NT in both fields
1283    - NTLMv2
1284    - NTLMv2 and LMv2
1285    - LMv2
1286    - plaintext tests (in challenge-response fields)
1287
1288    check we get the correct session key in each case
1289    check what values we get for the LM session key
1290
1291 */
1292
1293 static const struct ntlm_tests {
1294         bool (*fn)(struct samlogon_state *, char **);
1295         const char *name;
1296         bool expect_fail;
1297 } test_table[] = {
1298         {test_lmv2_ntlmv2, "NTLMv2 and LMv2", false},
1299 #if 0
1300         {test_lmv2_ntlmv2_no_dom, "NTLMv2 and LMv2 (no domain)", false},
1301 #endif
1302         {test_lm, "LM", false},
1303         {test_lm_ntlm, "LM and NTLM", false},
1304         {test_lm_ntlm_both_broken, "LM and NTLM, both broken", false},
1305         {test_ntlm, "NTLM", false},
1306         {test_ntlm_in_lm, "NTLM in LM", false},
1307         {test_ntlm_in_both, "NTLM in both", false},
1308         {test_ntlmv2, "NTLMv2", false},
1309         {test_ntlmv2_no_dom, "NTLMv2 (no domain)", false},
1310         {test_lmv2, "LMv2", false},
1311         {test_lmv2_no_dom, "LMv2 (no domain)", false},
1312         {test_ntlmv2_lmv2_broken, "NTLMv2 and LMv2, LMv2 broken", false},
1313         {test_ntlmv2_lmv2_broken_no_dom, "NTLMv2 and LMv2, LMv2 broken (no domain)", false},
1314         {test_ntlmv2_ntlmv2_broken, "NTLMv2 and LMv2, NTLMv2 broken", false},
1315 #if 0
1316         {test_ntlmv2_ntlmv2_broken_no_dom, "NTLMv2 and LMv2, NTLMv2 broken (no domain)", false},
1317 #endif
1318         {test_ntlmv2_both_broken, "NTLMv2 and LMv2, both broken", false},
1319         {test_ntlmv2_both_broken_no_dom, "NTLMv2 and LMv2, both broken (no domain)", false},
1320         {test_ntlm_lm_broken, "NTLM and LM, LM broken", false},
1321         {test_ntlm_ntlm_broken, "NTLM and LM, NTLM broken", false},
1322         {test_ntlm2, "NTLM2 (NTLMv2 session security)", false},
1323         {test_lmv2_ntlm_both_broken, "LMv2 and NTLM, both broken", false},
1324         {test_lmv2_ntlm_both_broken_no_dom, "LMv2 and NTLM, both broken (no domain)", false},
1325         {test_lmv2_ntlm_break_ntlm, "LMv2 and NTLM, NTLM broken", false},
1326         {test_lmv2_ntlm_break_ntlm_no_dom, "LMv2 and NTLM, NTLM broken (no domain)", false},
1327         {test_lmv2_ntlm_break_lm, "LMv2 and NTLM, LMv2 broken", false},
1328         {test_lmv2_ntlm_break_lm_no_dom, "LMv2 and NTLM, LMv2 broken (no domain)", false},
1329         {test_plaintext_none_broken, "Plaintext", false},
1330         {test_plaintext_lm_broken, "Plaintext LM broken", false},
1331         {test_plaintext_nt_broken, "Plaintext NT broken", false},
1332         {test_plaintext_nt_only, "Plaintext NT only", false},
1333         {test_plaintext_lm_only, "Plaintext LM only", false},
1334         {NULL, NULL}
1335 };
1336
1337 /*
1338   try a netlogon SamLogon
1339 */
1340 static bool test_SamLogon(struct dcerpc_pipe *p, TALLOC_CTX *mem_ctx,
1341                           struct torture_context *tctx,
1342                           struct netlogon_creds_CredentialState *creds,
1343                           const char *comment,
1344                           const char *account_domain, const char *account_name,
1345                           const char *plain_pass, uint32_t parameter_control,
1346                           NTSTATUS expected_error, bool old_password,
1347                           int n_subtests)
1348 {
1349         TALLOC_CTX *fn_ctx = talloc_named(mem_ctx, 0, "test_SamLogon function-level context");
1350         int i, v, l, f;
1351         bool ret = true;
1352         int validation_levels[] = {2,3,6};
1353         int logon_levels[] = { NetlogonNetworkInformation, NetlogonNetworkTransitiveInformation };
1354         int function_levels[] = {
1355                 NDR_NETR_LOGONSAMLOGON,
1356                 NDR_NETR_LOGONSAMLOGONEX,
1357                 NDR_NETR_LOGONSAMLOGONWITHFLAGS };
1358         struct samlogon_state samlogon_state;
1359
1360         union netr_LogonLevel logon;
1361         union netr_Validation validation;
1362         uint8_t authoritative = 0;
1363         uint32_t flags = 0;
1364
1365         ZERO_STRUCT(logon);
1366
1367         torture_comment(tctx, "Testing netr_LogonSamLogon and netr_LogonSamLogonWithFlags\n");
1368
1369         samlogon_state.comment = comment;
1370         samlogon_state.account_name = account_name;
1371         samlogon_state.account_domain = account_domain;
1372         samlogon_state.password = plain_pass;
1373         samlogon_state.workgroup = lpcfg_workgroup(tctx->lp_ctx);
1374         samlogon_state.netbios_name = lpcfg_netbios_name(tctx->lp_ctx);
1375         samlogon_state.p = p;
1376         samlogon_state.creds = creds;
1377         samlogon_state.expected_error = expected_error;
1378         samlogon_state.chall = data_blob_talloc(fn_ctx, NULL, 8);
1379         samlogon_state.parameter_control = parameter_control;
1380         samlogon_state.old_password = old_password;
1381         samlogon_state.tctx = tctx;
1382
1383         generate_random_buffer(samlogon_state.chall.data, 8);
1384         samlogon_state.r_flags.in.server_name = talloc_asprintf(fn_ctx, "\\\\%s", dcerpc_server_name(p));
1385         samlogon_state.r_flags.in.computer_name = TEST_MACHINE_NAME;
1386         samlogon_state.r_flags.in.credential = &samlogon_state.auth;
1387         samlogon_state.r_flags.in.return_authenticator = &samlogon_state.auth2;
1388         samlogon_state.r_flags.in.flags = &flags;
1389         samlogon_state.r_flags.in.logon = &logon;
1390         samlogon_state.r_flags.out.validation = &validation;
1391         samlogon_state.r_flags.out.authoritative = &authoritative;
1392         samlogon_state.r_flags.out.flags = &flags;
1393
1394         samlogon_state.r_ex.in.server_name = talloc_asprintf(fn_ctx, "\\\\%s", dcerpc_server_name(p));
1395         samlogon_state.r_ex.in.computer_name = TEST_MACHINE_NAME;
1396         samlogon_state.r_ex.in.flags = &flags;
1397         samlogon_state.r_ex.in.logon = &logon;
1398         samlogon_state.r_ex.out.validation = &validation;
1399         samlogon_state.r_ex.out.authoritative = &authoritative;
1400         samlogon_state.r_ex.out.flags = &flags;
1401
1402         samlogon_state.r.in.server_name = talloc_asprintf(fn_ctx, "\\\\%s", dcerpc_server_name(p));
1403         samlogon_state.r.in.computer_name = TEST_MACHINE_NAME;
1404         samlogon_state.r.in.credential = &samlogon_state.auth;
1405         samlogon_state.r.in.return_authenticator = &samlogon_state.auth2;
1406         samlogon_state.r.in.logon = &logon;
1407         samlogon_state.r.out.validation = &validation;
1408         samlogon_state.r.out.authoritative = &authoritative;
1409
1410
1411         for (f=0;f<ARRAY_SIZE(function_levels);f++) {
1412                 for (i=0; test_table[i].fn; i++) {
1413                         if (n_subtests && (i > n_subtests)) {
1414                                 continue;
1415                         }
1416                         for (v=0;v<ARRAY_SIZE(validation_levels);v++) {
1417                                 for (l=0;l<ARRAY_SIZE(logon_levels);l++) {
1418                                         char *error_string = NULL;
1419                                         TALLOC_CTX *tmp_ctx = talloc_named(fn_ctx, 0, "test_SamLogon inner loop");
1420                                         samlogon_state.mem_ctx = tmp_ctx;
1421                                         samlogon_state.function_level = function_levels[f];
1422                                         samlogon_state.r.in.validation_level = validation_levels[v];
1423                                         samlogon_state.r.in.logon_level = logon_levels[l];
1424                                         samlogon_state.r_ex.in.validation_level = validation_levels[v];
1425                                         samlogon_state.r_ex.in.logon_level = logon_levels[l];
1426                                         samlogon_state.r_flags.in.validation_level = validation_levels[v];
1427                                         samlogon_state.r_flags.in.logon_level = logon_levels[l];
1428                                         if (!test_table[i].fn(&samlogon_state, &error_string)) {
1429                                                 torture_comment(tctx, "Testing '%s' [%s]\\[%s] '%s' at validation level %d, logon level %d, function %d: \n",
1430                                                        samlogon_state.comment,
1431                                                        samlogon_state.account_domain,
1432                                                        samlogon_state.account_name,
1433                                                        test_table[i].name, validation_levels[v],
1434                                                        logon_levels[l], function_levels[f]);
1435
1436                                                 if (test_table[i].expect_fail) {
1437                                                         torture_comment(tctx, " failed (expected, test incomplete): %s\n", error_string);
1438                                                 } else {
1439                                                         torture_comment(tctx, " failed: %s\n", error_string);
1440                                                         ret = false;
1441                                                 }
1442                                                 SAFE_FREE(error_string);
1443                                         }
1444                                         talloc_free(tmp_ctx);
1445                                 }
1446                         }
1447                 }
1448         }
1449         talloc_free(fn_ctx);
1450         return ret;
1451 }
1452
1453 /*
1454   test an ADS style interactive domain logon
1455 */
1456 bool test_InteractiveLogon(struct dcerpc_pipe *p, TALLOC_CTX *mem_ctx,
1457                            struct torture_context *tctx,
1458                            struct netlogon_creds_CredentialState *creds,
1459                            const char *comment,
1460                            const char *workstation_name,
1461                            const char *account_domain, const char *account_name,
1462                            const char *plain_pass, uint32_t parameter_control,
1463                            NTSTATUS expected_error)
1464 {
1465         NTSTATUS status;
1466         TALLOC_CTX *fn_ctx = talloc_named(mem_ctx, 0, "test_InteractiveLogon function-level context");
1467         bool ret = true;
1468         struct netr_LogonSamLogonWithFlags r;
1469         struct netr_Authenticator a, ra;
1470         struct netr_PasswordInfo pinfo;
1471         uint32_t flags = 0;
1472
1473         union netr_LogonLevel logon;
1474         union netr_Validation validation;
1475         uint8_t authoritative = 0;
1476         struct dcerpc_binding_handle *b = p->binding_handle;
1477
1478         ZERO_STRUCT(a);
1479         ZERO_STRUCT(r);
1480         ZERO_STRUCT(ra);
1481
1482         ZERO_STRUCT(logon);
1483         ZERO_STRUCT(validation);
1484
1485         netlogon_creds_client_authenticator(creds, &a);
1486
1487         logon.password = &pinfo;
1488
1489         r.in.server_name = talloc_asprintf(fn_ctx, "\\\\%s", dcerpc_server_name(p));
1490         r.in.computer_name = TEST_MACHINE_NAME;
1491         r.in.credential = &a;
1492         r.in.return_authenticator = &ra;
1493         r.in.logon_level = NetlogonInteractiveTransitiveInformation;
1494         r.in.logon = &logon;
1495         r.in.validation_level = 6;
1496         r.in.flags = &flags;
1497         r.out.validation = &validation;
1498         r.out.authoritative = &authoritative;
1499         r.out.flags = &flags;
1500
1501         pinfo.identity_info.domain_name.string = account_domain;
1502         pinfo.identity_info.parameter_control = parameter_control;
1503         pinfo.identity_info.logon_id_low = 0;
1504         pinfo.identity_info.logon_id_high = 0;
1505         pinfo.identity_info.account_name.string = account_name;
1506         pinfo.identity_info.workstation.string = workstation_name;
1507
1508         if (!E_deshash(plain_pass, pinfo.lmpassword.hash)) {
1509                 ZERO_STRUCT(pinfo.lmpassword.hash);
1510         }
1511         E_md4hash(plain_pass, pinfo.ntpassword.hash);
1512
1513         if (creds->negotiate_flags & NETLOGON_NEG_ARCFOUR) {
1514                 netlogon_creds_arcfour_crypt(creds, pinfo.lmpassword.hash, 16);
1515                 netlogon_creds_arcfour_crypt(creds, pinfo.ntpassword.hash, 16);
1516         } else {
1517                 netlogon_creds_des_encrypt(creds, &pinfo.lmpassword);
1518                 netlogon_creds_des_encrypt(creds, &pinfo.ntpassword);
1519         }
1520
1521         torture_comment(tctx, "Testing netr_LogonSamLogonWithFlags '%s' (Interactive Logon)\n", comment);
1522
1523         torture_assert_ntstatus_ok_goto(tctx,
1524                 dcerpc_netr_LogonSamLogonWithFlags_r(b, fn_ctx, &r),
1525                 ret, failed,
1526                 talloc_asprintf(tctx, "%s: netr_LogonSamLogonWithFlags - %s\n",
1527                          __location__, nt_errstr(status)));
1528
1529         if (!r.out.return_authenticator) {
1530                 talloc_free(fn_ctx);
1531                 torture_fail(tctx, "no authenticator returned");
1532         }
1533
1534         torture_assert_goto(tctx,
1535                 netlogon_creds_client_check(creds, &r.out.return_authenticator->cred),
1536                 ret, failed,
1537                 "Credential chaining failed\n");
1538
1539         torture_assert_ntstatus_equal(tctx, r.out.result, expected_error,
1540                 talloc_asprintf(tctx, "[%s]\\[%s] netr_LogonSamLogonWithFlags - expected %s got %s\n",
1541                        account_domain, account_name, nt_errstr(expected_error), nt_errstr(r.out.result)));
1542
1543         ret = true;
1544  failed:
1545         talloc_free(fn_ctx);
1546
1547         return ret;
1548 }
1549
1550 /* This sets and resets the "minPwdAge" (in order to allow immediate user
1551  * password changes). The behaviour is controlled by the "set" boolean. */
1552 static bool handle_minPwdAge(struct torture_context *torture,
1553                              TALLOC_CTX *mem_ctx, bool set)
1554 {
1555         struct dcerpc_pipe *p;
1556         struct policy_handle connect_handle, domain_handle;
1557         struct samr_Connect c_r;
1558         struct samr_LookupDomain ld_r;
1559         struct samr_OpenDomain od_r;
1560         struct samr_QueryDomainInfo qdi_r;
1561         struct samr_SetDomainInfo sdi_r;
1562         struct samr_Close cl_r;
1563         struct lsa_String domName;
1564         struct dom_sid *domSid = NULL;
1565         union samr_DomainInfo *domInfo = NULL;
1566         static int64_t old_minPwdAge = 0;
1567         NTSTATUS status;
1568
1569         status = torture_rpc_connection(torture, &p, &ndr_table_samr);
1570         if (!NT_STATUS_IS_OK(status)) {
1571                 return false;
1572         }
1573
1574         c_r.in.system_name = 0;
1575         c_r.in.access_mask = SEC_FLAG_MAXIMUM_ALLOWED;
1576         c_r.out.connect_handle = &connect_handle;
1577
1578         torture_assert_ntstatus_ok(torture,
1579                                    dcerpc_samr_Connect_r(p->binding_handle, mem_ctx, &c_r),
1580                                    "Connect failed");
1581         torture_assert_ntstatus_ok(torture, c_r.out.result, "Connect failed");
1582
1583         ld_r.in.connect_handle = &connect_handle;
1584         ld_r.in.domain_name = &domName;
1585         ld_r.in.domain_name->string = lpcfg_workgroup(torture->lp_ctx);
1586         ld_r.out.sid = &domSid;
1587
1588         torture_assert_ntstatus_ok(torture,
1589                                    dcerpc_samr_LookupDomain_r(p->binding_handle, mem_ctx, &ld_r),
1590                                    "LookupDomain failed");
1591         torture_assert_ntstatus_ok(torture, ld_r.out.result,
1592                                    "LookupDomain failed");
1593
1594         od_r.in.connect_handle = &connect_handle;
1595         od_r.in.access_mask = SEC_FLAG_MAXIMUM_ALLOWED;
1596         od_r.in.sid = *ld_r.out.sid;
1597         od_r.out.domain_handle = &domain_handle;
1598
1599         torture_assert_ntstatus_ok(torture,
1600                                    dcerpc_samr_OpenDomain_r(p->binding_handle, mem_ctx, &od_r),
1601                                    "OpenDomain failed");
1602         torture_assert_ntstatus_ok(torture, od_r.out.result,
1603                                    "OpenDomain failed");
1604
1605         qdi_r.in.domain_handle = &domain_handle;
1606         qdi_r.in.level = DomainPasswordInformation;
1607         qdi_r.out.info = &domInfo;
1608
1609         torture_assert_ntstatus_ok(torture,
1610                                    dcerpc_samr_QueryDomainInfo_r(p->binding_handle, mem_ctx, &qdi_r),
1611                                    "QueryDomainInfo failed");
1612         torture_assert_ntstatus_ok(torture, qdi_r.out.result,
1613                                    "QueryDomainInfo failed");
1614
1615         if (set) {
1616                 old_minPwdAge = domInfo->info1.min_password_age;
1617                 domInfo->info1.min_password_age = 0;
1618         } else {
1619                 domInfo->info1.min_password_age = old_minPwdAge;
1620         }
1621
1622         sdi_r.in.domain_handle = &domain_handle;
1623         sdi_r.in.level = DomainPasswordInformation;
1624         sdi_r.in.info = domInfo;
1625
1626         torture_assert_ntstatus_ok(torture,
1627                                    dcerpc_samr_SetDomainInfo_r(p->binding_handle, mem_ctx, &sdi_r),
1628                                    "SetDomainInfo failed");
1629         torture_assert_ntstatus_ok(torture, sdi_r.out.result,
1630                                    "SetDomainInfo failed");
1631
1632         cl_r.in.handle = &connect_handle;
1633         cl_r.out.handle = &connect_handle;
1634
1635         torture_assert_ntstatus_ok(torture,
1636                                    dcerpc_samr_Close_r(p->binding_handle, mem_ctx, &cl_r),
1637                                    "Close failed");
1638         torture_assert_ntstatus_ok(torture, cl_r.out.result, "Close failed");
1639
1640         return true;
1641 }
1642
1643 bool torture_rpc_samlogon(struct torture_context *torture)
1644 {
1645         NTSTATUS status;
1646         struct dcerpc_pipe *p;
1647         struct dcerpc_binding *b;
1648         struct cli_credentials *machine_credentials;
1649         TALLOC_CTX *mem_ctx = talloc_init("torture_rpc_netlogon");
1650         bool ret = true;
1651         struct test_join *join_ctx = NULL;
1652         struct test_join *user_ctx = NULL, *user_ctx_wrong_wks = NULL, *user_ctx_wrong_time = NULL;
1653         char *user_password, *user_password_wrong_wks, *user_password_wrong_time;
1654         const char *old_user_password;
1655         char *test_machine_account;
1656         const char *userdomain;
1657         struct samr_SetUserInfo s;
1658         union samr_UserInfo u;
1659         int i;
1660         int ci;
1661
1662         unsigned int credential_flags[] = {
1663                 NETLOGON_NEG_AUTH2_FLAGS,
1664                 NETLOGON_NEG_ARCFOUR,
1665                 NETLOGON_NEG_ARCFOUR | NETLOGON_NEG_128BIT,
1666                 NETLOGON_NEG_AUTH2_ADS_FLAGS,
1667                 0 /* yes, this is a valid flag, causes the use of DES */
1668         };
1669
1670         struct netlogon_creds_CredentialState *creds;
1671         struct dcerpc_pipe *tmp_p = NULL;
1672
1673         torture_assert(torture, handle_minPwdAge(torture, mem_ctx, true),
1674                        "handle_minPwdAge error!");
1675
1676         test_machine_account = talloc_asprintf(mem_ctx, "%s$", TEST_MACHINE_NAME);
1677         /* We only need to join as a workstation here, and in future,
1678          * if we wish to test against trusted domains, we must be a
1679          * workstation here */
1680         join_ctx = torture_join_domain(torture, TEST_MACHINE_NAME, ACB_WSTRUST,
1681                                        &machine_credentials);
1682         torture_assert(torture, join_ctx, "Failed to join as Workstation\n");
1683
1684         userdomain = torture_setting_string(torture, "userdomain", lpcfg_workgroup(torture->lp_ctx));
1685
1686         user_ctx = torture_create_testuser(torture,
1687                                            TEST_USER_NAME,
1688                                            userdomain,
1689                                            ACB_NORMAL,
1690                                            (const char **)&user_password);
1691         torture_assert(torture, user_ctx, "Failed to create a test user\n");
1692
1693         old_user_password = user_password;
1694
1695         tmp_p = torture_join_samr_pipe(user_ctx);
1696         test_ChangePasswordUser3(tmp_p, torture,
1697                                  TEST_USER_NAME, 16 /* > 14 */, &user_password,
1698                                  NULL, 0, false);
1699
1700         user_ctx_wrong_wks = torture_create_testuser(torture,
1701                                                      TEST_USER_NAME_WRONG_WKS,
1702                                            userdomain,
1703                                            ACB_NORMAL,
1704                                            (const char **)&user_password_wrong_wks);
1705         torture_assert(torture, user_ctx_wrong_wks,
1706                 "Failed to create a test user (wrong workstation test)\n");
1707
1708         ZERO_STRUCT(u);
1709         s.in.user_handle = torture_join_samr_user_policy(user_ctx_wrong_wks);
1710         s.in.info = &u;
1711         s.in.level = 21;
1712
1713         u.info21.fields_present = SAMR_FIELD_WORKSTATIONS;
1714         u.info21.workstations.string = "not" TEST_MACHINE_NAME;
1715
1716         tmp_p = torture_join_samr_pipe(user_ctx_wrong_wks);
1717         status = dcerpc_samr_SetUserInfo_r(tmp_p->binding_handle, mem_ctx, &s);
1718         torture_assert_ntstatus_ok_goto(torture, status, ret, failed,
1719                 talloc_asprintf(torture, "SetUserInfo (list of workstations) failed - %s\n", nt_errstr(status)));
1720         torture_assert_ntstatus_ok_goto(torture, s.out.result, ret, failed,
1721                 talloc_asprintf(torture, "SetUserInfo (list of workstations) failed - %s\n", nt_errstr(s.out.result)));
1722
1723         user_ctx_wrong_time
1724                 = torture_create_testuser(torture, TEST_USER_NAME_WRONG_TIME,
1725                                            userdomain,
1726                                            ACB_NORMAL,
1727                                            (const char **)&user_password_wrong_time);
1728         torture_assert(torture, user_ctx_wrong_time,
1729                 "Failed to create a test user (wrong workstation test)\n");
1730
1731         ZERO_STRUCT(u);
1732         s.in.user_handle = torture_join_samr_user_policy(user_ctx_wrong_time);
1733         s.in.info = &u;
1734         s.in.level = 21;
1735
1736         u.info21.fields_present = SAMR_FIELD_WORKSTATIONS | SAMR_FIELD_LOGON_HOURS;
1737         u.info21.workstations.string = TEST_MACHINE_NAME;
1738         u.info21.logon_hours.units_per_week = 168;
1739         u.info21.logon_hours.bits = talloc_zero_array(mem_ctx, uint8_t, 168);
1740
1741         tmp_p = torture_join_samr_pipe(user_ctx_wrong_time);
1742         status = dcerpc_samr_SetUserInfo_r(tmp_p->binding_handle, mem_ctx, &s);
1743         torture_assert_ntstatus_ok_goto(torture, status, ret, failed,
1744                 talloc_asprintf(torture, "SetUserInfo (logon times and list of workstations) failed - %s\n", nt_errstr(status)));
1745         torture_assert_ntstatus_ok_goto(torture, s.out.result, ret, failed,
1746                 talloc_asprintf(torture, "SetUserInfo (list of workstations) failed - %s\n", nt_errstr(s.out.result)));
1747
1748         status = torture_rpc_binding(torture, &b);
1749         if (!NT_STATUS_IS_OK(status)) {
1750                 ret = false;
1751                 goto failed;
1752         }
1753
1754         /* We have to use schannel, otherwise the SamLogonEx fails
1755          * with INTERNAL_ERROR */
1756
1757         b->flags &= ~DCERPC_AUTH_OPTIONS;
1758         b->flags |= DCERPC_SCHANNEL | DCERPC_SIGN | DCERPC_SCHANNEL_128;
1759
1760         status = dcerpc_pipe_connect_b(mem_ctx, &p, b,
1761                                        &ndr_table_netlogon,
1762                                        machine_credentials, torture->ev, torture->lp_ctx);
1763
1764         torture_assert_ntstatus_ok_goto(torture, status, ret, failed,
1765                 talloc_asprintf(torture, "RPC pipe connect as domain member failed: %s\n", nt_errstr(status)));
1766
1767         status = dcerpc_schannel_creds(p->conn->security_state.generic_state, mem_ctx, &creds);
1768         if (!NT_STATUS_IS_OK(status)) {
1769                 ret = false;
1770                 goto failed;
1771         }
1772
1773         {
1774
1775                 struct {
1776                         const char *comment;
1777                         const char *domain;
1778                         const char *username;
1779                         const char *password;
1780                         bool network_login;
1781                         NTSTATUS expected_interactive_error;
1782                         NTSTATUS expected_network_error;
1783                         uint32_t parameter_control;
1784                         bool old_password; /* Allow an old password to be accepted or rejected without error, as well as session key bugs */
1785                 } usercreds[] = {
1786                         {
1787                                 .comment       = "domain\\user",
1788                                 .domain        = cli_credentials_get_domain(cmdline_credentials),
1789                                 .username      = cli_credentials_get_username(cmdline_credentials),
1790                                 .password      = cli_credentials_get_password(cmdline_credentials),
1791                                 .network_login = true,
1792                                 .expected_interactive_error = NT_STATUS_OK,
1793                                 .expected_network_error     = NT_STATUS_OK
1794                         },
1795                         {
1796                                 .comment       = "realm\\user",
1797                                 .domain        = cli_credentials_get_realm(cmdline_credentials),
1798                                 .username      = cli_credentials_get_username(cmdline_credentials),
1799                                 .password      = cli_credentials_get_password(cmdline_credentials),
1800                                 .network_login = true,
1801                                 .expected_interactive_error = NT_STATUS_OK,
1802                                 .expected_network_error     = NT_STATUS_OK
1803                         },
1804                         {
1805                                 .comment       = "user@domain",
1806                                 .domain        = NULL,
1807                                 .username      = talloc_asprintf(mem_ctx,
1808                                                 "%s@%s",
1809                                                 cli_credentials_get_username(cmdline_credentials),
1810                                                 cli_credentials_get_domain(cmdline_credentials)
1811                                         ),
1812                                 .password      = cli_credentials_get_password(cmdline_credentials),
1813                                 .network_login = false, /* works for some things, but not NTLMv2.  Odd */
1814                                 .expected_interactive_error = NT_STATUS_OK,
1815                                 .expected_network_error     = NT_STATUS_OK
1816                         },
1817                         {
1818                                 .comment       = "user@realm",
1819                                 .domain        = NULL,
1820                                 .username      = talloc_asprintf(mem_ctx,
1821                                                 "%s@%s",
1822                                                 cli_credentials_get_username(cmdline_credentials),
1823                                                 cli_credentials_get_realm(cmdline_credentials)
1824                                         ),
1825                                 .password      = cli_credentials_get_password(cmdline_credentials),
1826                                 .network_login = true,
1827                                 .expected_interactive_error = NT_STATUS_OK,
1828                                 .expected_network_error     = NT_STATUS_OK
1829                         },
1830                         {
1831                                 .comment      = "machine domain\\user",
1832                                 .domain       = cli_credentials_get_domain(machine_credentials),
1833                                 .username     = cli_credentials_get_username(machine_credentials),
1834                                 .password     = cli_credentials_get_password(machine_credentials),
1835                                 .network_login = true,
1836                                 .expected_interactive_error = NT_STATUS_NO_SUCH_USER,
1837                                 .parameter_control = MSV1_0_ALLOW_WORKSTATION_TRUST_ACCOUNT
1838                         },
1839                         {
1840                                 .comment      = "machine domain\\user",
1841                                 .domain       = cli_credentials_get_domain(machine_credentials),
1842                                 .username     = cli_credentials_get_username(machine_credentials),
1843                                 .password     = cli_credentials_get_password(machine_credentials),
1844                                 .network_login = true,
1845                                 .expected_interactive_error = NT_STATUS_NO_SUCH_USER,
1846                                 .expected_network_error = NT_STATUS_NOLOGON_WORKSTATION_TRUST_ACCOUNT
1847                         },
1848                         {
1849                                 .comment       = "machine realm\\user",
1850                                 .domain        = cli_credentials_get_realm(machine_credentials),
1851                                 .username      = cli_credentials_get_username(machine_credentials),
1852                                 .password      = cli_credentials_get_password(machine_credentials),
1853                                 .network_login = true,
1854                                 .expected_interactive_error = NT_STATUS_NO_SUCH_USER,
1855                                 .parameter_control = MSV1_0_ALLOW_WORKSTATION_TRUST_ACCOUNT
1856                         },
1857                         {
1858                                 .comment       = "machine user@domain",
1859                                 .domain        = NULL,
1860                                 .username      = talloc_asprintf(mem_ctx,
1861                                                                 "%s@%s",
1862                                                                 cli_credentials_get_username(machine_credentials),
1863                                                                 cli_credentials_get_domain(machine_credentials)
1864                                         ),
1865                                 .password      = cli_credentials_get_password(machine_credentials),
1866                                 .network_login = false, /* works for some things, but not NTLMv2.  Odd */
1867                                 .expected_interactive_error = NT_STATUS_NO_SUCH_USER,
1868                                 .parameter_control = MSV1_0_ALLOW_WORKSTATION_TRUST_ACCOUNT
1869                         },
1870                         {
1871                                 .comment       = "machine user@realm",
1872                                 .domain        = NULL,
1873                                 .username      = talloc_asprintf(mem_ctx,
1874                                                                 "%s@%s",
1875                                                                 cli_credentials_get_username(machine_credentials),
1876                                                                 cli_credentials_get_realm(machine_credentials)
1877                                         ),
1878                                 .password      = cli_credentials_get_password(machine_credentials),
1879                                 .network_login = true,
1880                                 .expected_interactive_error = NT_STATUS_NO_SUCH_USER,
1881                                 .parameter_control = MSV1_0_ALLOW_WORKSTATION_TRUST_ACCOUNT
1882                         },
1883                         {
1884                                 .comment       = "test user (long pw): domain\\user",
1885                                 .domain        = userdomain,
1886                                 .username      = TEST_USER_NAME,
1887                                 .password      = user_password,
1888                                 .network_login = true,
1889                                 .expected_interactive_error = NT_STATUS_OK,
1890                                 .expected_network_error     = NT_STATUS_OK
1891                         },
1892                         {
1893                                 .comment       = "test user (long pw): user@realm",
1894                                 .domain        = NULL,
1895                                 .username      = talloc_asprintf(mem_ctx,
1896                                                                  "%s@%s",
1897                                                                  TEST_USER_NAME,
1898                                                                  lpcfg_realm(torture->lp_ctx)),
1899                                 .password      = user_password,
1900                                 .network_login = true,
1901                                 .expected_interactive_error = NT_STATUS_OK,
1902                                 .expected_network_error     = NT_STATUS_OK
1903                         },
1904                         {
1905                                 .comment       = "test user (long pw): user@domain",
1906                                 .domain        = NULL,
1907                                 .username      = talloc_asprintf(mem_ctx,
1908                                                                  "%s@%s",
1909                                                                  TEST_USER_NAME,
1910                                                                  userdomain),
1911                                 .password      = user_password,
1912                                 .network_login = false, /* works for some things, but not NTLMv2.  Odd */
1913                                 .expected_interactive_error = NT_STATUS_OK,
1914                                 .expected_network_error     = NT_STATUS_OK
1915                         },
1916                         /* Oddball, can we use the old password ? */
1917                         {
1918                                 .comment       = "test user: user\\domain OLD PASSWORD",
1919                                 .domain        = userdomain,
1920                                 .username      = TEST_USER_NAME,
1921                                 .password      = old_user_password,
1922                                 .network_login = true,
1923                                 .expected_interactive_error = NT_STATUS_WRONG_PASSWORD,
1924                                 .expected_network_error     = NT_STATUS_OK,
1925                                 .old_password  = true
1926                         },
1927                         {
1928                                 .comment       = "test user (wrong workstation): domain\\user",
1929                                 .domain        = userdomain,
1930                                 .username      = TEST_USER_NAME_WRONG_WKS,
1931                                 .password      = user_password_wrong_wks,
1932                                 .network_login = true,
1933                                 .expected_interactive_error = NT_STATUS_INVALID_WORKSTATION,
1934                                 .expected_network_error     = NT_STATUS_INVALID_WORKSTATION
1935                         }
1936                 };
1937
1938                 /* Try all the tests for different username forms */
1939                 for (ci = 0; ci < ARRAY_SIZE(usercreds); ci++) {
1940
1941                         if (!test_InteractiveLogon(p, mem_ctx, torture, creds,
1942                                                    usercreds[ci].comment,
1943                                                    TEST_MACHINE_NAME,
1944                                                    usercreds[ci].domain,
1945                                                    usercreds[ci].username,
1946                                                    usercreds[ci].password,
1947                                                    usercreds[ci].parameter_control,
1948                                                    usercreds[ci].expected_interactive_error)) {
1949                                 ret = false;
1950                                 goto failed;
1951                         }
1952
1953                         if (usercreds[ci].network_login) {
1954                                 if (!test_SamLogon(p, mem_ctx, torture, creds,
1955                                                    usercreds[ci].comment,
1956                                                    usercreds[ci].domain,
1957                                                    usercreds[ci].username,
1958                                                    usercreds[ci].password,
1959                                                    usercreds[ci].parameter_control,
1960                                                    usercreds[ci].expected_network_error,
1961                                                    usercreds[ci].old_password,
1962                                                    0)) {
1963                                         ret = false;
1964                                         goto failed;
1965                                 }
1966                         }
1967                 }
1968
1969                 /* Using the first username form, try the different
1970                  * credentials flag setups, on only one of the tests (checks
1971                  * session key encryption) */
1972
1973                 for (i=0; i < ARRAY_SIZE(credential_flags); i++) {
1974                         /* TODO:  Somehow we lost setting up the different credential flags here! */
1975
1976                         torture_comment(torture,
1977                                         "Testing with flags: 0x%08x\n",
1978                                         credential_flags[i]);
1979
1980                         if (!test_InteractiveLogon(p, mem_ctx, torture, creds,
1981                                                    usercreds[0].comment,
1982                                                    TEST_MACHINE_NAME,
1983                                                    usercreds[0].domain,
1984                                                    usercreds[0].username,
1985                                                    usercreds[0].password,
1986                                                    usercreds[0].parameter_control,
1987                                                    usercreds[0].expected_interactive_error)) {
1988                                 ret = false;
1989                                 goto failed;
1990                         }
1991
1992                         if (usercreds[0].network_login) {
1993                                 if (!test_SamLogon(p, mem_ctx, torture, creds,
1994                                                    usercreds[0].comment,
1995                                                    usercreds[0].domain,
1996                                                    usercreds[0].username,
1997                                                    usercreds[0].password,
1998                                                    usercreds[0].parameter_control,
1999                                                    usercreds[0].expected_network_error,
2000                                                    usercreds[0].old_password,
2001                                                    1)) {
2002                                         ret = false;
2003                                         goto failed;
2004                                 }
2005                         }
2006                 }
2007
2008         }
2009 failed:
2010         torture_assert(torture, handle_minPwdAge(torture, mem_ctx, false),
2011                        "handle_minPwdAge error!");
2012
2013         talloc_free(mem_ctx);
2014
2015         torture_leave_domain(torture, join_ctx);
2016         torture_leave_domain(torture, user_ctx);
2017         torture_leave_domain(torture, user_ctx_wrong_wks);
2018         torture_leave_domain(torture, user_ctx_wrong_time);
2019         return ret;
2020 }