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