r10847: Fix up new 'decrypt samlogon reply' routine to be more robust, and use
[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 2 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, write to the Free Software
22    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
23 */
24
25 #include "includes.h"
26 #include "librpc/gen_ndr/ndr_netlogon.h"
27 #include "auth/auth.h"
28 #include "lib/crypto/crypto.h"
29 #include "lib/cmdline/popt_common.h"
30
31 #define TEST_MACHINE_NAME "samlogontest"
32 #define TEST_USER_NAME "samlogontestuser"
33
34 enum ntlm_break {
35         BREAK_BOTH,
36         BREAK_NONE,
37         BREAK_LM,
38         BREAK_NT,
39         NO_LM,
40         NO_NT
41 };
42
43 struct samlogon_state {
44         TALLOC_CTX *mem_ctx;
45         const char *comment;
46         const char *account_name;
47         const char *account_domain;
48         const char *password;
49         struct dcerpc_pipe *p;
50         int function_level;
51         struct netr_LogonSamLogon r;
52         struct netr_LogonSamLogonEx r_ex;
53         struct netr_LogonSamLogonWithFlags r_flags;
54         struct netr_Authenticator auth, auth2;
55         struct creds_CredentialState *creds;
56         NTSTATUS expected_error;
57         DATA_BLOB chall;
58 };
59
60 /* 
61    Authenticate a user with a challenge/response, checking session key
62    and valid authentication types
63 */
64 static NTSTATUS check_samlogon(struct samlogon_state *samlogon_state, 
65                                enum ntlm_break break_which,
66                                DATA_BLOB *chall, 
67                                DATA_BLOB *lm_response, 
68                                DATA_BLOB *nt_response, 
69                                uint8_t lm_key[8], 
70                                uint8_t user_session_key[16], 
71                                char **error_string)
72 {
73         NTSTATUS status;
74         struct netr_LogonSamLogon *r = &samlogon_state->r;
75         struct netr_LogonSamLogonEx *r_ex = &samlogon_state->r_ex;
76         struct netr_LogonSamLogonWithFlags *r_flags = &samlogon_state->r_flags;
77         struct netr_NetworkInfo ninfo;
78         struct netr_SamBaseInfo *base = NULL;
79         uint16_t validation_level = 0;
80         
81         samlogon_state->r.in.logon.network = &ninfo;
82         samlogon_state->r_ex.in.logon.network = &ninfo;
83         samlogon_state->r_flags.in.logon.network = &ninfo;
84         
85         ninfo.identity_info.domain_name.string = samlogon_state->account_domain;
86         ninfo.identity_info.parameter_control = 0;
87         ninfo.identity_info.logon_id_low = 0;
88         ninfo.identity_info.logon_id_high = 0;
89         ninfo.identity_info.account_name.string = samlogon_state->account_name;
90         ninfo.identity_info.workstation.string = TEST_MACHINE_NAME;
91                 
92         memcpy(ninfo.challenge, chall->data, 8);
93                 
94         switch (break_which) {
95         case BREAK_NONE:
96                 break;
97         case BREAK_LM:
98                 if (lm_response && lm_response->data) {
99                         lm_response->data[0]++;
100                 }
101                 break;
102         case BREAK_NT:
103                 if (nt_response && nt_response->data) {
104                         nt_response->data[0]++;
105                 }
106                 break;
107         case BREAK_BOTH:
108                 if (lm_response && lm_response->data) {
109                         lm_response->data[0]++;
110                 }
111                 if (nt_response && nt_response->data) {
112                         nt_response->data[0]++;
113                 }
114                 break;
115         case NO_LM:
116                 data_blob_free(lm_response);
117                 break;
118         case NO_NT:
119                 data_blob_free(nt_response);
120                 break;
121         }
122                 
123         if (nt_response) {
124                 ninfo.nt.data = nt_response->data;
125                 ninfo.nt.length = nt_response->length;
126         } else {
127                 ninfo.nt.data = NULL;
128                 ninfo.nt.length = 0;
129         }
130                 
131         if (lm_response) {
132                 ninfo.lm.data = lm_response->data;
133                 ninfo.lm.length = lm_response->length;
134         } else {
135                 ninfo.lm.data = NULL;
136                 ninfo.lm.length = 0;
137         }
138         
139         switch (samlogon_state->function_level) {
140         case DCERPC_NETR_LOGONSAMLOGON: 
141                 ZERO_STRUCT(samlogon_state->auth2);
142                 creds_client_authenticator(samlogon_state->creds, &samlogon_state->auth);
143
144                 r->out.return_authenticator = NULL;
145                 status = dcerpc_netr_LogonSamLogon(samlogon_state->p, samlogon_state->mem_ctx, r);
146                 if (!r->out.return_authenticator || 
147                     !creds_client_check(samlogon_state->creds, &r->out.return_authenticator->cred)) {
148                         printf("Credential chaining failed\n");
149                 }
150                 if (!NT_STATUS_IS_OK(status)) {
151                         if (error_string) {
152                                 *error_string = strdup(nt_errstr(status));
153                         }
154                         return status;
155                 }
156
157                 validation_level = r->in.validation_level;
158
159                 creds_decrypt_samlogon(samlogon_state->creds, validation_level, &r->out.validation);
160
161                 switch (validation_level) {
162                 case 2:
163                         base = &r->out.validation.sam2->base;
164                         break;
165                 case 3:
166                         base = &r->out.validation.sam3->base;
167                         break;
168                 case 6:
169                         base = &r->out.validation.sam6->base;
170                         break;
171                 }
172                 break;
173         case DCERPC_NETR_LOGONSAMLOGONEX: 
174                 status = dcerpc_netr_LogonSamLogonEx(samlogon_state->p, samlogon_state->mem_ctx, r_ex);
175                 if (!NT_STATUS_IS_OK(status)) {
176                         if (error_string) {
177                                 *error_string = strdup(nt_errstr(status));
178                         }
179                         return status;
180                 }
181
182                 validation_level = r_ex->in.validation_level;
183
184                 creds_decrypt_samlogon(samlogon_state->creds, validation_level, &r_ex->out.validation);
185
186                 switch (validation_level) {
187                 case 2:
188                         base = &r_ex->out.validation.sam2->base;
189                         break;
190                 case 3:
191                         base = &r_ex->out.validation.sam3->base;
192                         break;
193                 case 6:
194                         base = &r_ex->out.validation.sam6->base;
195                         break;
196                 }
197                 break;
198         case DCERPC_NETR_LOGONSAMLOGONWITHFLAGS: 
199                 ZERO_STRUCT(samlogon_state->auth2);
200                 creds_client_authenticator(samlogon_state->creds, &samlogon_state->auth);
201
202                 r_flags->out.return_authenticator = NULL;
203                 status = dcerpc_netr_LogonSamLogonWithFlags(samlogon_state->p, samlogon_state->mem_ctx, r_flags);
204                 if (!r_flags->out.return_authenticator || 
205                     !creds_client_check(samlogon_state->creds, &r_flags->out.return_authenticator->cred)) {
206                         printf("Credential chaining failed\n");
207                 }
208                 if (!NT_STATUS_IS_OK(status)) {
209                         if (error_string) {
210                                 *error_string = strdup(nt_errstr(status));
211                         }
212                         return status;
213                 }
214                 
215                 validation_level = r_flags->in.validation_level;
216
217                 creds_decrypt_samlogon(samlogon_state->creds, validation_level, &r_flags->out.validation);
218
219                 switch (validation_level) {
220                 case 2:
221                         base = &r_flags->out.validation.sam2->base;
222                         break;
223                 case 3:
224                         base = &r_flags->out.validation.sam3->base;
225                         break;
226                 case 6:
227                         base = &r_flags->out.validation.sam6->base;
228                         break;
229                 }
230                 break;
231         }
232                 
233         if (!base) {
234                 printf("No user info returned from 'successful' SamLogon*() call!\n");
235                 return NT_STATUS_INVALID_PARAMETER;
236         }
237
238         if (user_session_key) {
239                 memcpy(user_session_key, base->key.key, 16);
240         }
241         if (lm_key) {
242                 memcpy(lm_key, base->LMSessKey.key, 8);
243         }
244                         
245         return status;
246
247
248
249 /* 
250  * Test the normal 'LM and NTLM' combination
251  */
252
253 static BOOL test_lm_ntlm_broken(struct samlogon_state *samlogon_state, enum ntlm_break break_which, char **error_string) 
254 {
255         BOOL pass = True;
256         BOOL lm_good;
257         NTSTATUS nt_status;
258         DATA_BLOB lm_response = data_blob_talloc(samlogon_state->mem_ctx, NULL, 24);
259         DATA_BLOB nt_response = data_blob_talloc(samlogon_state->mem_ctx, NULL, 24);
260         DATA_BLOB session_key = data_blob_talloc(samlogon_state->mem_ctx, NULL, 16);
261
262         uint8_t lm_key[8];
263         uint8_t user_session_key[16];
264         uint8_t lm_hash[16];
265         uint8_t nt_hash[16];
266         
267         ZERO_STRUCT(lm_key);
268         ZERO_STRUCT(user_session_key);
269
270         lm_good = SMBencrypt(samlogon_state->password, samlogon_state->chall.data, lm_response.data);
271         if (!lm_good) {
272                 ZERO_STRUCT(lm_hash);
273         } else {
274                 E_deshash(samlogon_state->password, lm_hash); 
275         }
276                 
277         SMBNTencrypt(samlogon_state->password, samlogon_state->chall.data, nt_response.data);
278
279         E_md4hash(samlogon_state->password, nt_hash);
280         SMBsesskeygen_ntv1(nt_hash, session_key.data);
281
282         nt_status = check_samlogon(samlogon_state,
283                                    break_which,
284                                    &samlogon_state->chall,
285                                    &lm_response,
286                                    &nt_response,
287                                    lm_key, 
288                                    user_session_key,
289                                    error_string);
290         
291         data_blob_free(&lm_response);
292
293         if (NT_STATUS_EQUAL(NT_STATUS_WRONG_PASSWORD, nt_status)) {
294                 /* for 'long' passwords, the LM password is invalid */
295                 if (break_which == NO_NT && !lm_good) {
296                         return True;
297                 }
298                 return ((break_which == BREAK_NT) || (break_which == BREAK_BOTH));
299         }
300
301         if (!NT_STATUS_EQUAL(samlogon_state->expected_error, nt_status)) {
302                 SAFE_FREE(*error_string);
303                 asprintf(error_string, "Expected error: %s, got %s", nt_errstr(samlogon_state->expected_error), nt_errstr(nt_status));
304                 return False;
305         } else if (NT_STATUS_EQUAL(samlogon_state->expected_error, nt_status) && !NT_STATUS_IS_OK(nt_status)) {
306                 return True;
307         } else if (!NT_STATUS_IS_OK(nt_status)) {
308                 return False;
309         }
310
311         if (break_which == NO_NT && !lm_good) {
312                 *error_string = strdup("LM password is 'long' (> 14 chars and therefore invalid) but login did not fail!");
313                 return False;
314         }
315
316         if (memcmp(lm_hash, lm_key, 
317                    sizeof(lm_key)) != 0) {
318                 printf("LM Key does not match expectations!\n");
319                 printf("lm_key:\n");
320                 dump_data(1, lm_key, 8);
321                 printf("expected:\n");
322                 dump_data(1, lm_hash, 8);
323                 pass = False;
324         }
325
326         switch (break_which) {
327         case NO_NT:
328         {
329                 uint8_t lm_key_expected[16];
330                 memcpy(lm_key_expected, lm_hash, 8);
331                 memset(lm_key_expected+8, '\0', 8);
332                 if (memcmp(lm_key_expected, user_session_key, 
333                            16) != 0) {
334                         *error_string = strdup("NT Session Key does not match expectations (should be first-8 LM hash)!\n");
335                         printf("user_session_key:\n");
336                         dump_data(1, user_session_key, sizeof(user_session_key));
337                         printf("expected:\n");
338                         dump_data(1, lm_key_expected, sizeof(lm_key_expected));
339                         pass = False;
340                 }
341                 break;
342         }
343         default:
344                 if (memcmp(session_key.data, user_session_key, 
345                            sizeof(user_session_key)) != 0) {
346                         *error_string = strdup("NT Session Key does not match expectations!\n");
347                         printf("user_session_key:\n");
348                         dump_data(1, user_session_key, 16);
349                         printf("expected:\n");
350                         dump_data(1, session_key.data, session_key.length);
351                         pass = False;
352                 }
353         }
354         return pass;
355 }
356
357 /* 
358  * Test LM authentication, no NT response supplied
359  */
360
361 static BOOL test_lm(struct samlogon_state *samlogon_state, char **error_string) 
362 {
363
364         return test_lm_ntlm_broken(samlogon_state, NO_NT, error_string);
365 }
366
367 /* 
368  * Test the NTLM response only, no LM.
369  */
370
371 static BOOL test_ntlm(struct samlogon_state *samlogon_state, char **error_string) 
372 {
373         return test_lm_ntlm_broken(samlogon_state, NO_LM, error_string);
374 }
375
376 /* 
377  * Test the NTLM response only, but in the LM field.
378  */
379
380 static BOOL test_ntlm_in_lm(struct samlogon_state *samlogon_state, char **error_string) 
381 {
382         BOOL lm_good;
383         BOOL pass = True;
384         NTSTATUS nt_status;
385         DATA_BLOB nt_response = data_blob_talloc(samlogon_state->mem_ctx, NULL, 24);
386         DATA_BLOB session_key = data_blob_talloc(samlogon_state->mem_ctx, NULL, 16);
387
388         uint8_t lm_key[8];
389         uint8_t lm_hash[16];
390         uint8_t user_session_key[16];
391         uint8_t nt_hash[16];
392         
393         ZERO_STRUCT(lm_key);
394         ZERO_STRUCT(user_session_key);
395
396         SMBNTencrypt(samlogon_state->password, samlogon_state->chall.data, 
397                      nt_response.data);
398         E_md4hash(samlogon_state->password, nt_hash);
399         SMBsesskeygen_ntv1(nt_hash, 
400                            session_key.data);
401
402         lm_good = E_deshash(samlogon_state->password, lm_hash); 
403         if (!lm_good) {
404                 ZERO_STRUCT(lm_hash);
405         }
406         nt_status = check_samlogon(samlogon_state,
407                                    BREAK_NONE,
408                                    &samlogon_state->chall,
409                                    &nt_response,
410                                    NULL,
411                                    lm_key, 
412                                    user_session_key,
413                                    error_string);
414         
415         if (!NT_STATUS_EQUAL(samlogon_state->expected_error, nt_status)) {
416                 SAFE_FREE(*error_string);
417                 asprintf(error_string, "Expected error: %s, got %s", nt_errstr(samlogon_state->expected_error), nt_errstr(nt_status));
418                 return False;
419         } else if (NT_STATUS_EQUAL(samlogon_state->expected_error, nt_status) && !NT_STATUS_IS_OK(nt_status)) {
420                 return True;
421         } else if (!NT_STATUS_IS_OK(nt_status)) {
422                 return False;
423         }
424
425         if (lm_good) {
426                 if (memcmp(lm_hash, lm_key, 
427                            sizeof(lm_key)) != 0) {
428                         printf("LM Key does not match expectations!\n");
429                         printf("lm_key:\n");
430                         dump_data(1, lm_key, 8);
431                         printf("expected:\n");
432                         dump_data(1, lm_hash, 8);
433                         pass = False;
434                 }
435         } else {
436                 if (memcmp(session_key.data, lm_key, 
437                            sizeof(lm_key)) != 0) {
438                         printf("LM Key does not match expectations (first 8 session key)!\n");
439                         printf("lm_key:\n");
440                         dump_data(1, lm_key, 8);
441                         printf("expected:\n");
442                         dump_data(1, session_key.data, 8);
443                         pass = False;
444                 }
445         }
446         if (memcmp(lm_hash, user_session_key, 8) != 0) {
447                 uint8_t lm_key_expected[16];
448                 memcpy(lm_key_expected, lm_hash, 8);
449                 memset(lm_key_expected+8, '\0', 8);
450                 if (memcmp(lm_key_expected, user_session_key, 
451                            16) != 0) {
452                         printf("NT Session Key does not match expectations (should be first-8 LM hash)!\n");
453                         printf("user_session_key:\n");
454                         dump_data(1, user_session_key, sizeof(user_session_key));
455                         printf("expected:\n");
456                         dump_data(1, lm_key_expected, sizeof(lm_key_expected));
457                         pass = False;
458                 }
459         }
460         return pass;
461 }
462
463 /* 
464  * Test the NTLM response only, but in the both the NT and LM fields.
465  */
466
467 static BOOL test_ntlm_in_both(struct samlogon_state *samlogon_state, char **error_string) 
468 {
469         BOOL pass = True;
470         BOOL lm_good;
471         NTSTATUS nt_status;
472         DATA_BLOB nt_response = data_blob_talloc(samlogon_state->mem_ctx, NULL, 24);
473         DATA_BLOB session_key = data_blob_talloc(samlogon_state->mem_ctx, NULL, 16);
474
475         uint8_t lm_key[8];
476         uint8_t lm_hash[16];
477         uint8_t user_session_key[16];
478         uint8_t nt_hash[16];
479         
480         ZERO_STRUCT(lm_key);
481         ZERO_STRUCT(user_session_key);
482
483         SMBNTencrypt(samlogon_state->password, samlogon_state->chall.data, 
484                      nt_response.data);
485         E_md4hash(samlogon_state->password, nt_hash);
486         SMBsesskeygen_ntv1(nt_hash, 
487                            session_key.data);
488
489         lm_good = E_deshash(samlogon_state->password, lm_hash); 
490         if (!lm_good) {
491                 ZERO_STRUCT(lm_hash);
492         }
493
494         nt_status = check_samlogon(samlogon_state,
495                                    BREAK_NONE,
496                                    &samlogon_state->chall,
497                                    NULL, 
498                                    &nt_response,
499                                    lm_key, 
500                                    user_session_key,
501                                    error_string);
502         
503         if (!NT_STATUS_EQUAL(samlogon_state->expected_error, nt_status)) {
504                 SAFE_FREE(*error_string);
505                 asprintf(error_string, "Expected error: %s, got %s", nt_errstr(samlogon_state->expected_error), nt_errstr(nt_status));
506                 return False;
507         } else if (NT_STATUS_EQUAL(samlogon_state->expected_error, nt_status) && !NT_STATUS_IS_OK(nt_status)) {
508                 return True;
509         } else if (!NT_STATUS_IS_OK(nt_status)) {
510                 return False;
511         }
512
513         if (!NT_STATUS_IS_OK(nt_status)) {
514                 return False;
515         }
516
517         if (memcmp(lm_hash, lm_key, 
518                    sizeof(lm_key)) != 0) {
519                 printf("LM Key does not match expectations!\n");
520                 printf("lm_key:\n");
521                 dump_data(1, lm_key, 8);
522                 printf("expected:\n");
523                 dump_data(1, lm_hash, 8);
524                 pass = False;
525         }
526         if (memcmp(session_key.data, user_session_key, 
527                    sizeof(user_session_key)) != 0) {
528                 printf("NT Session Key does not match expectations!\n");
529                 printf("user_session_key:\n");
530                 dump_data(1, user_session_key, 16);
531                 printf("expected:\n");
532                 dump_data(1, session_key.data, session_key.length);
533                 pass = False;
534         }
535
536
537         return pass;
538 }
539
540 /* 
541  * Test the NTLMv2 and LMv2 responses
542  */
543
544 enum ntlmv2_domain {
545         UPPER_DOMAIN,
546         NO_DOMAIN
547 };
548
549 static BOOL test_lmv2_ntlmv2_broken(struct samlogon_state *samlogon_state, 
550                                     enum ntlm_break break_which, 
551                                     enum ntlmv2_domain ntlmv2_domain, 
552                                     char **error_string) 
553 {
554         BOOL pass = True;
555         NTSTATUS nt_status;
556         DATA_BLOB ntlmv2_response = data_blob(NULL, 0);
557         DATA_BLOB lmv2_response = data_blob(NULL, 0);
558         DATA_BLOB lmv2_session_key = data_blob(NULL, 0);
559         DATA_BLOB ntlmv2_session_key = data_blob(NULL, 0);
560         DATA_BLOB names_blob = NTLMv2_generate_names_blob(samlogon_state->mem_ctx, TEST_MACHINE_NAME, lp_workgroup());
561
562         uint8_t lm_session_key[8];
563         uint8_t user_session_key[16];
564
565         ZERO_STRUCT(lm_session_key);
566         ZERO_STRUCT(user_session_key);
567         
568         switch (ntlmv2_domain) {
569         case UPPER_DOMAIN:
570                 if (!SMBNTLMv2encrypt(samlogon_state->mem_ctx, 
571                                       samlogon_state->account_name, samlogon_state->account_domain, 
572                                       samlogon_state->password, &samlogon_state->chall,
573                                       &names_blob,
574                                       &lmv2_response, &ntlmv2_response, 
575                                       &lmv2_session_key, &ntlmv2_session_key)) {
576                         data_blob_free(&names_blob);
577                         return False;
578                 }
579                 break;
580         case NO_DOMAIN:
581                 if (!SMBNTLMv2encrypt(samlogon_state->mem_ctx, 
582                                       samlogon_state->account_name, "",
583                                       samlogon_state->password, &samlogon_state->chall,
584                                       &names_blob,
585                                       &lmv2_response, &ntlmv2_response, 
586                                       &lmv2_session_key, &ntlmv2_session_key)) {
587                         data_blob_free(&names_blob);
588                         return False;
589                 }
590                 break;
591         }
592         data_blob_free(&names_blob);
593
594         nt_status = check_samlogon(samlogon_state,
595                                    break_which,
596                                    &samlogon_state->chall,
597                                    &lmv2_response,
598                                    &ntlmv2_response,
599                                    lm_session_key, 
600                                    user_session_key,
601                                    error_string);
602         
603         data_blob_free(&lmv2_response);
604         data_blob_free(&ntlmv2_response);
605
606
607         if (NT_STATUS_EQUAL(nt_status, NT_STATUS_WRONG_PASSWORD)) {
608                 return break_which == BREAK_BOTH;
609         }
610
611         if (!NT_STATUS_EQUAL(samlogon_state->expected_error, nt_status)) {
612                 SAFE_FREE(*error_string);
613                 asprintf(error_string, "Expected error: %s, got %s", nt_errstr(samlogon_state->expected_error), nt_errstr(nt_status));
614                 return False;
615         } else if (NT_STATUS_EQUAL(samlogon_state->expected_error, nt_status) && !NT_STATUS_IS_OK(nt_status)) {
616                 return True;
617         } else if (!NT_STATUS_IS_OK(nt_status)) {
618                 return False;
619         }
620
621
622         switch (break_which) {
623         case NO_NT:
624                 if (memcmp(lmv2_session_key.data, user_session_key,
625                            sizeof(user_session_key)) != 0) {
626                         printf("USER (LMv2) Session Key does not match expectations!\n");
627                         printf("user_session_key:\n");
628                         dump_data(1, user_session_key, 16);
629                         printf("expected:\n");
630                         dump_data(1, lmv2_session_key.data, ntlmv2_session_key.length);
631                         pass = False;
632                 }
633                 if (memcmp(lmv2_session_key.data, lm_session_key, 
634                                    sizeof(lm_session_key)) != 0) {
635                         printf("LM (LMv2) Session Key does not match expectations!\n");
636                         printf("lm_session_key:\n");
637                         dump_data(1, lm_session_key, 8);
638                         printf("expected:\n");
639                         dump_data(1, lmv2_session_key.data, 8);
640                         pass = False;
641                 }
642                 break;
643         default:
644                 if (memcmp(ntlmv2_session_key.data, user_session_key, 
645                            sizeof(user_session_key)) != 0) {
646                         if (memcmp(lmv2_session_key.data, user_session_key,
647                                    sizeof(user_session_key)) == 0) {
648                                 printf("USER (NTLMv2) Session Key expected, got LMv2 sessesion key instead:\n");
649                                 printf("user_session_key:\n");
650                                 dump_data(1, user_session_key, 16);
651                                 printf("expected:\n");
652                                 dump_data(1, ntlmv2_session_key.data, ntlmv2_session_key.length);
653                                 pass = False;
654                                 
655                         } else {
656                                 printf("USER (NTLMv2) Session Key does not match expectations!\n");
657                                 printf("user_session_key:\n");
658                                 dump_data(1, user_session_key, 16);
659                                 printf("expected:\n");
660                                 dump_data(1, ntlmv2_session_key.data, ntlmv2_session_key.length);
661                                 pass = False;
662                         }
663                 }
664                 if (memcmp(ntlmv2_session_key.data, lm_session_key, 
665                            sizeof(lm_session_key)) != 0) {
666                         if (memcmp(lmv2_session_key.data, lm_session_key,
667                                    sizeof(lm_session_key)) == 0) {
668                                 printf("LM (NTLMv2) Session Key expected, got LMv2 sessesion key instead:\n");
669                                 printf("user_session_key:\n");
670                                 dump_data(1, lm_session_key, 8);
671                                 printf("expected:\n");
672                                 dump_data(1, ntlmv2_session_key.data, 8);
673                                 pass = False;
674                         } else {
675                                 printf("LM (NTLMv2) Session Key does not match expectations!\n");
676                                 printf("lm_session_key:\n");
677                                 dump_data(1, lm_session_key, 8);
678                                 printf("expected:\n");
679                                 dump_data(1, ntlmv2_session_key.data, 8);
680                                 pass = False;
681                         }
682                 }
683         }
684
685         return pass;
686 }
687
688 /* 
689  * Test the NTLM and LMv2 responses
690  */
691
692 static BOOL test_lmv2_ntlm_broken(struct samlogon_state *samlogon_state, 
693                                   enum ntlm_break break_which, 
694                                   enum ntlmv2_domain ntlmv2_domain, 
695                                   char **error_string) 
696 {
697         BOOL pass = True;
698         NTSTATUS nt_status;
699         DATA_BLOB ntlmv2_response = data_blob(NULL, 0);
700         DATA_BLOB lmv2_response = data_blob(NULL, 0);
701         DATA_BLOB lmv2_session_key = data_blob(NULL, 0);
702         DATA_BLOB ntlmv2_session_key = data_blob(NULL, 0);
703         DATA_BLOB names_blob = NTLMv2_generate_names_blob(samlogon_state->mem_ctx, lp_netbios_name(), lp_workgroup());
704
705         DATA_BLOB ntlm_response = data_blob_talloc(samlogon_state->mem_ctx, NULL, 24);
706         DATA_BLOB ntlm_session_key = data_blob_talloc(samlogon_state->mem_ctx, NULL, 16);
707
708         BOOL lm_good;
709         uint8_t lm_hash[16];
710         uint8_t lm_session_key[8];
711         uint8_t user_session_key[16];
712         uint8_t nt_hash[16];
713
714         SMBNTencrypt(samlogon_state->password, samlogon_state->chall.data, 
715                      ntlm_response.data);
716         E_md4hash(samlogon_state->password, nt_hash);
717         SMBsesskeygen_ntv1(nt_hash, 
718                            ntlm_session_key.data);
719
720         lm_good = E_deshash(samlogon_state->password, lm_hash); 
721         if (!lm_good) {
722                 ZERO_STRUCT(lm_hash);
723         }
724
725         ZERO_STRUCT(lm_session_key);
726         ZERO_STRUCT(user_session_key);
727
728         switch (ntlmv2_domain) {
729         case UPPER_DOMAIN:
730                 /* TODO - test with various domain cases, and without domain */
731                 if (!SMBNTLMv2encrypt(samlogon_state->mem_ctx, 
732                                       samlogon_state->account_name, samlogon_state->account_domain, 
733                                       samlogon_state->password, &samlogon_state->chall,
734                                       &names_blob,
735                                       &lmv2_response, &ntlmv2_response, 
736                                       &lmv2_session_key, &ntlmv2_session_key)) {
737                         data_blob_free(&names_blob);
738                         return False;
739                 }
740                 break;
741         case NO_DOMAIN:
742                 /* TODO - test with various domain cases, and without domain */
743                 if (!SMBNTLMv2encrypt(samlogon_state->mem_ctx, 
744                                       samlogon_state->account_name, "",
745                                       samlogon_state->password, &samlogon_state->chall,
746                                       &names_blob,
747                                       &lmv2_response, &ntlmv2_response, 
748                                       &lmv2_session_key, &ntlmv2_session_key)) {
749                         data_blob_free(&names_blob);
750                         return False;
751                 }
752                 break;
753         }
754
755         data_blob_free(&names_blob);
756
757         nt_status = check_samlogon(samlogon_state,
758                                    break_which,
759                                    &samlogon_state->chall,
760                                    &lmv2_response,
761                                    &ntlm_response,
762                                    lm_session_key, 
763                                    user_session_key,
764                                    error_string);
765         
766         data_blob_free(&lmv2_response);
767         data_blob_free(&ntlmv2_response);
768
769
770         if (NT_STATUS_EQUAL(NT_STATUS_WRONG_PASSWORD, nt_status)) {
771                 return ((break_which == BREAK_NT) || (break_which == BREAK_BOTH));
772         }
773
774         if (!NT_STATUS_EQUAL(samlogon_state->expected_error, nt_status)) {
775                 SAFE_FREE(*error_string);
776                 asprintf(error_string, "Expected error: %s, got %s", nt_errstr(samlogon_state->expected_error), nt_errstr(nt_status));
777                 return False;
778         } else if (NT_STATUS_EQUAL(samlogon_state->expected_error, nt_status) && !NT_STATUS_IS_OK(nt_status)) {
779                 return True;
780         } else if (!NT_STATUS_IS_OK(nt_status)) {
781                 return False;
782         }
783
784         switch (break_which) {
785         case NO_NT:
786                 if (memcmp(lmv2_session_key.data, user_session_key, 
787                            sizeof(user_session_key)) != 0) {
788                         printf("USER (LMv2) Session Key does not match expectations!\n");
789                         printf("user_session_key:\n");
790                         dump_data(1, user_session_key, 16);
791                         printf("expected:\n");
792                         dump_data(1, lmv2_session_key.data, ntlmv2_session_key.length);
793                         pass = False;
794                 }
795                 if (memcmp(lmv2_session_key.data, lm_session_key, 
796                            sizeof(lm_session_key)) != 0) {
797                         printf("LM (LMv2) Session Key does not match expectations!\n");
798                         printf("lm_session_key:\n");
799                         dump_data(1, lm_session_key, 8);
800                         printf("expected:\n");
801                         dump_data(1, lmv2_session_key.data, 8);
802                         pass = False;
803                 }
804                 break;
805         case BREAK_LM:
806                 if (memcmp(ntlm_session_key.data, user_session_key, 
807                            sizeof(user_session_key)) != 0) {
808                         printf("USER (NTLMv2) Session Key does not match expectations!\n");
809                         printf("user_session_key:\n");
810                         dump_data(1, user_session_key, 16);
811                         printf("expected:\n");
812                         dump_data(1, ntlm_session_key.data, ntlm_session_key.length);
813                         pass = False;
814                 }
815                 if (lm_good) {
816                         if (memcmp(lm_hash, lm_session_key, 
817                                    sizeof(lm_session_key)) != 0) {
818                                 printf("LM Session Key does not match expectations!\n");
819                                 printf("lm_session_key:\n");
820                                 dump_data(1, lm_session_key, 8);
821                                 printf("expected:\n");
822                                 dump_data(1, lm_hash, 8);
823                                 pass = False;
824                         }
825                 } else {
826                         static const char zeros[8];
827                         if (memcmp(zeros, lm_session_key, 
828                                    sizeof(lm_session_key)) != 0) {
829                                 printf("LM Session Key does not match expectations (zeros)!\n");
830                                 printf("lm_session_key:\n");
831                                 dump_data(1, lm_session_key, 8);
832                                 printf("expected:\n");
833                                 dump_data(1, zeros, 8);
834                                 pass = False;
835                         }
836                 }
837                 break;
838         default:
839                 if (memcmp(ntlm_session_key.data, user_session_key, 
840                            sizeof(user_session_key)) != 0) {
841                         printf("USER (NTLMv2) Session Key does not match expectations!\n");
842                         printf("user_session_key:\n");
843                         dump_data(1, user_session_key, 16);
844                         printf("expected:\n");
845                         dump_data(1, ntlm_session_key.data, ntlm_session_key.length);
846                         pass = False;
847                 }
848                 if (memcmp(ntlm_session_key.data, lm_session_key, 
849                            sizeof(lm_session_key)) != 0) {
850                         printf("LM (NTLMv2) Session Key does not match expectations!\n");
851                         printf("lm_session_key:\n");
852                         dump_data(1, lm_session_key, 8);
853                         printf("expected:\n");
854                         dump_data(1, ntlm_session_key.data, 8);
855                         pass = False;
856                 }
857         }
858
859         return pass;
860 }
861
862 /* 
863  * Test the NTLMv2 and LMv2 responses
864  */
865
866 static BOOL test_lmv2_ntlmv2(struct samlogon_state *samlogon_state, char **error_string) 
867 {
868         return test_lmv2_ntlmv2_broken(samlogon_state, BREAK_NONE, UPPER_DOMAIN, error_string);
869 }
870
871 #if 0
872 static BOOL test_lmv2_ntlmv2_no_dom(struct samlogon_state *samlogon_state, char **error_string) 
873 {
874         return test_lmv2_ntlmv2_broken(samlogon_state, BREAK_NONE, NO_DOMAIN, error_string);
875 }
876 #endif
877
878 /* 
879  * Test the LMv2 response only
880  */
881
882 static BOOL test_lmv2(struct samlogon_state *samlogon_state, char **error_string) 
883 {
884         return test_lmv2_ntlmv2_broken(samlogon_state, NO_NT, UPPER_DOMAIN, error_string);
885 }
886
887 static BOOL test_lmv2_no_dom(struct samlogon_state *samlogon_state, char **error_string) 
888 {
889         return test_lmv2_ntlmv2_broken(samlogon_state, NO_NT, NO_DOMAIN, error_string);
890 }
891
892 /* 
893  * Test the NTLMv2 response only
894  */
895
896 static BOOL test_ntlmv2(struct samlogon_state *samlogon_state, char **error_string) 
897 {
898         return test_lmv2_ntlmv2_broken(samlogon_state, NO_LM, UPPER_DOMAIN, error_string);
899 }
900
901 static BOOL test_ntlmv2_no_dom(struct samlogon_state *samlogon_state, char **error_string) 
902 {
903         return test_lmv2_ntlmv2_broken(samlogon_state, NO_LM, NO_DOMAIN, error_string);
904 }
905
906 static BOOL test_lm_ntlm(struct samlogon_state *samlogon_state, char **error_string) 
907 {
908         return test_lm_ntlm_broken(samlogon_state, BREAK_NONE, error_string);
909 }
910
911 static BOOL test_ntlm_lm_broken(struct samlogon_state *samlogon_state, char **error_string) 
912 {
913         return test_lm_ntlm_broken(samlogon_state, BREAK_LM, error_string);
914 }
915
916 static BOOL test_ntlm_ntlm_broken(struct samlogon_state *samlogon_state, char **error_string) 
917 {
918         return test_lm_ntlm_broken(samlogon_state, BREAK_NT, error_string);
919 }
920
921 static BOOL test_lm_ntlm_both_broken(struct samlogon_state *samlogon_state, char **error_string) 
922 {
923         return test_lm_ntlm_broken(samlogon_state, BREAK_BOTH, error_string);
924 }
925 static BOOL test_ntlmv2_lmv2_broken(struct samlogon_state *samlogon_state, char **error_string) 
926 {
927         return test_lmv2_ntlmv2_broken(samlogon_state, BREAK_LM, UPPER_DOMAIN, error_string);
928 }
929
930 static BOOL test_ntlmv2_lmv2_broken_no_dom(struct samlogon_state *samlogon_state, char **error_string) 
931 {
932         return test_lmv2_ntlmv2_broken(samlogon_state, BREAK_LM, NO_DOMAIN, error_string);
933 }
934
935 static BOOL test_ntlmv2_ntlmv2_broken(struct samlogon_state *samlogon_state, char **error_string) 
936 {
937         return test_lmv2_ntlmv2_broken(samlogon_state, BREAK_NT, UPPER_DOMAIN, error_string);
938 }
939
940 #if 0
941 static BOOL test_ntlmv2_ntlmv2_broken_no_dom(struct samlogon_state *samlogon_state, char **error_string) 
942 {
943         return test_lmv2_ntlmv2_broken(samlogon_state, BREAK_NT, NO_DOMAIN, error_string);
944 }
945 #endif
946
947 static BOOL test_ntlmv2_both_broken(struct samlogon_state *samlogon_state, char **error_string) 
948 {
949         return test_lmv2_ntlmv2_broken(samlogon_state, BREAK_BOTH, UPPER_DOMAIN, error_string);
950 }
951
952 static BOOL test_ntlmv2_both_broken_no_dom(struct samlogon_state *samlogon_state, char **error_string) 
953 {
954         return test_lmv2_ntlmv2_broken(samlogon_state, BREAK_BOTH, NO_DOMAIN, error_string);
955 }
956
957 static BOOL test_lmv2_ntlm_both_broken(struct samlogon_state *samlogon_state, char **error_string) 
958 {
959         return test_lmv2_ntlm_broken(samlogon_state, BREAK_BOTH, UPPER_DOMAIN, error_string);
960 }
961
962 static BOOL test_lmv2_ntlm_both_broken_no_dom(struct samlogon_state *samlogon_state, char **error_string) 
963 {
964         return test_lmv2_ntlm_broken(samlogon_state, BREAK_BOTH, NO_DOMAIN, error_string);
965 }
966
967 static BOOL test_lmv2_ntlm_break_ntlm(struct samlogon_state *samlogon_state, char **error_string) 
968 {
969         return test_lmv2_ntlm_broken(samlogon_state, BREAK_NT, UPPER_DOMAIN, error_string);
970 }
971
972 static BOOL test_lmv2_ntlm_break_ntlm_no_dom(struct samlogon_state *samlogon_state, char **error_string) 
973 {
974         return test_lmv2_ntlm_broken(samlogon_state, BREAK_NT, NO_DOMAIN, error_string);
975 }
976
977 static BOOL test_lmv2_ntlm_break_lm(struct samlogon_state *samlogon_state, char **error_string) 
978 {
979         return test_lmv2_ntlm_broken(samlogon_state, BREAK_LM, UPPER_DOMAIN, error_string);
980 }
981
982 static BOOL test_lmv2_ntlm_break_lm_no_dom(struct samlogon_state *samlogon_state, char **error_string) 
983 {
984         return test_lmv2_ntlm_broken(samlogon_state, BREAK_LM, NO_DOMAIN, error_string);
985 }
986
987 /* 
988  * Test the NTLM2 response (extra challenge in LM feild)
989  *
990  * This test is the same as the 'break LM' test, but checks that the
991  * server implements NTLM2 session security in the right place
992  * (NETLOGON is the wrong place).
993  */
994
995 static BOOL test_ntlm2(struct samlogon_state *samlogon_state, char **error_string) 
996 {
997         BOOL pass = True;
998         NTSTATUS nt_status;
999         DATA_BLOB lm_response = data_blob_talloc(samlogon_state->mem_ctx, NULL, 24);
1000         DATA_BLOB nt_response = data_blob_talloc(samlogon_state->mem_ctx, NULL, 24);
1001
1002         BOOL lm_good;
1003         uint8_t lm_key[8];
1004         uint8_t nt_hash[16];
1005         uint8_t lm_hash[16];
1006         uint8_t nt_key[16];
1007         uint8_t user_session_key[16];
1008         uint8_t expected_user_session_key[16];
1009         uint8_t session_nonce_hash[16];
1010         uint8_t client_chall[8];
1011         
1012         struct MD5Context md5_session_nonce_ctx;
1013         HMACMD5Context hmac_ctx;
1014                         
1015         ZERO_STRUCT(user_session_key);
1016         ZERO_STRUCT(lm_key);
1017         generate_random_buffer(client_chall, 8);
1018         
1019         MD5Init(&md5_session_nonce_ctx);
1020         MD5Update(&md5_session_nonce_ctx, samlogon_state->chall.data, 8);
1021         MD5Update(&md5_session_nonce_ctx, client_chall, 8);
1022         MD5Final(session_nonce_hash, &md5_session_nonce_ctx);
1023         
1024         E_md4hash(samlogon_state->password, (uint8_t *)nt_hash);
1025         lm_good = E_deshash(samlogon_state->password, (uint8_t *)lm_hash);
1026         SMBsesskeygen_ntv1((const uint8_t *)nt_hash, 
1027                            nt_key);
1028
1029         SMBNTencrypt(samlogon_state->password, samlogon_state->chall.data, nt_response.data);
1030
1031         memcpy(lm_response.data, session_nonce_hash, 8);
1032         memset(lm_response.data + 8, 0, 16);
1033
1034         hmac_md5_init_rfc2104(nt_key, 16, &hmac_ctx);
1035         hmac_md5_update(samlogon_state->chall.data, 8, &hmac_ctx);
1036         hmac_md5_update(client_chall, 8, &hmac_ctx);
1037         hmac_md5_final(expected_user_session_key, &hmac_ctx);
1038
1039         nt_status = check_samlogon(samlogon_state,
1040                                    BREAK_NONE,
1041                                    &samlogon_state->chall,
1042                                    &lm_response,
1043                                    &nt_response,
1044                                    lm_key, 
1045                                    user_session_key,
1046                                    error_string);
1047         
1048         if (!NT_STATUS_EQUAL(samlogon_state->expected_error, nt_status)) {
1049                 SAFE_FREE(*error_string);
1050                 asprintf(error_string, "Expected error: %s, got %s", nt_errstr(samlogon_state->expected_error), nt_errstr(nt_status));
1051                 return False;
1052         } else if (NT_STATUS_EQUAL(samlogon_state->expected_error, nt_status) && !NT_STATUS_IS_OK(nt_status)) {
1053                 return True;
1054         } else if (!NT_STATUS_IS_OK(nt_status)) {
1055                 return False;
1056         }
1057
1058         if (lm_good) {
1059                 if (memcmp(lm_hash, lm_key, 
1060                            sizeof(lm_key)) != 0) {
1061                         printf("LM Key does not match expectations!\n");
1062                         printf("lm_key:\n");
1063                         dump_data(1, lm_key, 8);
1064                         printf("expected:\n");
1065                         dump_data(1, lm_hash, 8);
1066                         pass = False;
1067                 }
1068         } else {
1069                 static const char zeros[8];
1070                 if (memcmp(zeros, lm_key, 
1071                            sizeof(lm_key)) != 0) {
1072                         printf("LM Session Key does not match expectations (zeros)!\n");
1073                         printf("lm_key:\n");
1074                         dump_data(1, lm_key, 8);
1075                         printf("expected:\n");
1076                         dump_data(1, zeros, 8);
1077                         pass = False;
1078                 }
1079         }
1080         if (memcmp(nt_key, user_session_key, 16) != 0) {
1081                 printf("NT Session Key does not match expectations (should be NT Key)!\n");
1082                 printf("user_session_key:\n");
1083                 dump_data(1, user_session_key, sizeof(user_session_key));
1084                 printf("expected:\n");
1085                 dump_data(1, nt_key, sizeof(nt_key));
1086                 pass = False;
1087         }
1088         return pass;
1089 }
1090
1091 static BOOL test_plaintext(struct samlogon_state *samlogon_state, enum ntlm_break break_which, char **error_string)
1092 {
1093         NTSTATUS nt_status;
1094         DATA_BLOB nt_response = data_blob(NULL, 0);
1095         DATA_BLOB lm_response = data_blob(NULL, 0);
1096         char *password;
1097         char *dospw;
1098         void *unicodepw;
1099
1100         uint8_t user_session_key[16];
1101         uint8_t lm_key[16];
1102         static const uint8_t zeros[8];
1103         DATA_BLOB chall = data_blob_talloc(samlogon_state->mem_ctx, zeros, sizeof(zeros));
1104
1105         ZERO_STRUCT(user_session_key);
1106         
1107         if ((push_ucs2_talloc(samlogon_state->mem_ctx, &unicodepw, 
1108                               samlogon_state->password)) == -1) {
1109                 DEBUG(0, ("push_ucs2_allocate failed!\n"));
1110                 exit(1);
1111         }
1112
1113         nt_response = data_blob_talloc(samlogon_state->mem_ctx, unicodepw, strlen_m(samlogon_state->password)*2);
1114
1115         password = strupper_talloc(samlogon_state->mem_ctx, samlogon_state->password);
1116
1117         if ((convert_string_talloc(samlogon_state->mem_ctx, CH_UNIX, 
1118                                    CH_DOS, password,
1119                                    strlen(password)+1, 
1120                                    (void**)&dospw)) == -1) {
1121                 DEBUG(0, ("convert_string_talloc failed!\n"));
1122                 exit(1);
1123         }
1124
1125         lm_response = data_blob_talloc(samlogon_state->mem_ctx, dospw, strlen(dospw));
1126
1127         nt_status = check_samlogon(samlogon_state,
1128                                    break_which,
1129                                    &chall,
1130                                    &lm_response,
1131                                    &nt_response,
1132                                    lm_key, 
1133                                    user_session_key,
1134                                    error_string);
1135         
1136         if (!NT_STATUS_IS_OK(nt_status)) {
1137                 return break_which == BREAK_NT;
1138         }
1139
1140         return True;
1141 }
1142
1143 static BOOL test_plaintext_none_broken(struct samlogon_state *samlogon_state, 
1144                                        char **error_string) {
1145         return test_plaintext(samlogon_state, BREAK_NONE, error_string);
1146 }
1147
1148 static BOOL test_plaintext_lm_broken(struct samlogon_state *samlogon_state, 
1149                                      char **error_string) {
1150         return test_plaintext(samlogon_state, BREAK_LM, error_string);
1151 }
1152
1153 static BOOL test_plaintext_nt_broken(struct samlogon_state *samlogon_state, 
1154                                      char **error_string) {
1155         return test_plaintext(samlogon_state, BREAK_NT, error_string);
1156 }
1157
1158 static BOOL test_plaintext_nt_only(struct samlogon_state *samlogon_state, 
1159                                    char **error_string) {
1160         return test_plaintext(samlogon_state, NO_LM, error_string);
1161 }
1162
1163 static BOOL test_plaintext_lm_only(struct samlogon_state *samlogon_state, 
1164                                    char **error_string) {
1165         return test_plaintext(samlogon_state, NO_NT, error_string);
1166 }
1167
1168 /* 
1169    Tests:
1170    
1171    - LM only
1172    - NT and LM             
1173    - NT
1174    - NT in LM field
1175    - NT in both fields
1176    - NTLMv2
1177    - NTLMv2 and LMv2
1178    - LMv2
1179    - plaintext tests (in challenge-response fields)
1180   
1181    check we get the correct session key in each case
1182    check what values we get for the LM session key
1183    
1184 */
1185
1186 static const struct ntlm_tests {
1187         BOOL (*fn)(struct samlogon_state *, char **);
1188         const char *name;
1189         BOOL expect_fail;
1190 } test_table[] = {
1191         {test_lmv2_ntlmv2, "NTLMv2 and LMv2", False},
1192 #if 0
1193         {test_lmv2_ntlmv2_no_dom, "NTLMv2 and LMv2 (no domain)", False},
1194 #endif
1195         {test_lm, "LM", False},
1196         {test_lm_ntlm, "LM and NTLM", False},
1197         {test_lm_ntlm_both_broken, "LM and NTLM, both broken", False},
1198         {test_ntlm, "NTLM", False},
1199         {test_ntlm_in_lm, "NTLM in LM", False},
1200         {test_ntlm_in_both, "NTLM in both", False},
1201         {test_ntlmv2, "NTLMv2", False},
1202         {test_ntlmv2_no_dom, "NTLMv2 (no domain)", False},
1203         {test_lmv2, "LMv2", False},
1204         {test_lmv2_no_dom, "LMv2 (no domain)", False},
1205         {test_ntlmv2_lmv2_broken, "NTLMv2 and LMv2, LMv2 broken", False},
1206         {test_ntlmv2_lmv2_broken_no_dom, "NTLMv2 and LMv2, LMv2 broken (no domain)", False},
1207         {test_ntlmv2_ntlmv2_broken, "NTLMv2 and LMv2, NTLMv2 broken", False},
1208 #if 0
1209         {test_ntlmv2_ntlmv2_broken_no_dom, "NTLMv2 and LMv2, NTLMv2 broken (no domain)", False},
1210 #endif
1211         {test_ntlmv2_both_broken, "NTLMv2 and LMv2, both broken", False},
1212         {test_ntlmv2_both_broken_no_dom, "NTLMv2 and LMv2, both broken (no domain)", False},
1213         {test_ntlm_lm_broken, "NTLM and LM, LM broken", False},
1214         {test_ntlm_ntlm_broken, "NTLM and LM, NTLM broken", False},
1215         {test_ntlm2, "NTLM2 (NTLMv2 session security)", False},
1216         {test_lmv2_ntlm_both_broken, "LMv2 and NTLM, both broken", False},
1217         {test_lmv2_ntlm_both_broken_no_dom, "LMv2 and NTLM, both broken (no domain)", False},
1218         {test_lmv2_ntlm_break_ntlm, "LMv2 and NTLM, NTLM broken", False},
1219         {test_lmv2_ntlm_break_ntlm_no_dom, "LMv2 and NTLM, NTLM broken (no domain)", False},
1220         {test_lmv2_ntlm_break_lm, "LMv2 and NTLM, LMv2 broken", False},
1221         {test_lmv2_ntlm_break_lm_no_dom, "LMv2 and NTLM, LMv2 broken (no domain)", False},
1222         {test_plaintext_none_broken, "Plaintext", True},
1223         {test_plaintext_lm_broken, "Plaintext LM broken", True},
1224         {test_plaintext_nt_broken, "Plaintext NT broken", True},
1225         {test_plaintext_nt_only, "Plaintext NT only", True},
1226         {test_plaintext_lm_only, "Plaintext LM only", True},
1227         {NULL, NULL}
1228 };
1229
1230 /*
1231   try a netlogon SamLogon
1232 */
1233 static BOOL test_SamLogon(struct dcerpc_pipe *p, TALLOC_CTX *mem_ctx, 
1234                           struct creds_CredentialState *creds, 
1235                           const char *comment,
1236                           const char *account_domain, const char *account_name, 
1237                           const char *plain_pass, NTSTATUS expected_error,
1238                           int n_subtests)
1239 {
1240         TALLOC_CTX *fn_ctx = talloc_named(mem_ctx, 0, "test_SamLogon function-level context");
1241         int i, v, l, f;
1242         BOOL ret = True;
1243         int validation_levels[] = {2,3,6};
1244         int logon_levels[] = { 2, 6 };
1245         int function_levels[] = { 
1246                 DCERPC_NETR_LOGONSAMLOGON,
1247                 DCERPC_NETR_LOGONSAMLOGONEX,
1248                 DCERPC_NETR_LOGONSAMLOGONWITHFLAGS };
1249         struct samlogon_state samlogon_state;
1250         
1251         printf("testing netr_LogonSamLogon and netr_LogonSamLogonWithFlags\n");
1252         
1253         samlogon_state.comment = comment;
1254         samlogon_state.account_name = account_name;
1255         samlogon_state.account_domain = account_domain;
1256         samlogon_state.password = plain_pass;
1257         samlogon_state.p = p;
1258         samlogon_state.creds = creds;
1259         samlogon_state.expected_error = expected_error;
1260         samlogon_state.chall = data_blob_talloc(fn_ctx, NULL, 8);
1261
1262         generate_random_buffer(samlogon_state.chall.data, 8);
1263         samlogon_state.r_flags.in.server_name = talloc_asprintf(fn_ctx, "\\\\%s", dcerpc_server_name(p));
1264         samlogon_state.r_flags.in.workstation = TEST_MACHINE_NAME;
1265         samlogon_state.r_flags.in.credential = &samlogon_state.auth;
1266         samlogon_state.r_flags.in.return_authenticator = &samlogon_state.auth2;
1267         samlogon_state.r_flags.in.flags = 0;
1268
1269         samlogon_state.r_ex.in.server_name = talloc_asprintf(fn_ctx, "\\\\%s", dcerpc_server_name(p));
1270         samlogon_state.r_ex.in.workstation = TEST_MACHINE_NAME;
1271         samlogon_state.r_ex.in.flags = 0;
1272
1273         samlogon_state.r.in.server_name = talloc_asprintf(fn_ctx, "\\\\%s", dcerpc_server_name(p));
1274         samlogon_state.r.in.workstation = TEST_MACHINE_NAME;
1275         samlogon_state.r.in.credential = &samlogon_state.auth;
1276         samlogon_state.r.in.return_authenticator = &samlogon_state.auth2;
1277
1278         for (f=0;f<ARRAY_SIZE(function_levels);f++) {
1279                 for (i=0; test_table[i].fn; i++) {
1280                         if (n_subtests && (i > n_subtests)) {
1281                                 continue;
1282                         }
1283                         for (v=0;v<ARRAY_SIZE(validation_levels);v++) {
1284                                 for (l=0;l<ARRAY_SIZE(logon_levels);l++) {
1285                                         char *error_string = NULL;
1286                                         TALLOC_CTX *tmp_ctx = talloc_named(fn_ctx, 0, "test_SamLogon inner loop");
1287                                         samlogon_state.mem_ctx = tmp_ctx;
1288                                         samlogon_state.function_level = function_levels[f];
1289                                         samlogon_state.r.in.validation_level = validation_levels[v];
1290                                         samlogon_state.r.in.logon_level = logon_levels[l];
1291                                         samlogon_state.r_ex.in.validation_level = validation_levels[v];
1292                                         samlogon_state.r_ex.in.logon_level = logon_levels[l];
1293                                         samlogon_state.r_flags.in.validation_level = validation_levels[v];
1294                                         samlogon_state.r_flags.in.logon_level = logon_levels[l];
1295                                         if (!test_table[i].fn(&samlogon_state, &error_string)) {
1296                                                 printf("Testing '%s' [%s]\\[%s] '%s' at validation level %d, logon level %d, function %d: \n",
1297                                                        samlogon_state.comment,
1298                                                        samlogon_state.account_domain,
1299                                                        samlogon_state.account_name,
1300                                                        test_table[i].name, validation_levels[v], 
1301                                                        logon_levels[l], function_levels[f]);
1302                                                 
1303                                                 if (test_table[i].expect_fail) {
1304                                                         printf(" failed (expected, test incomplete): %s\n", error_string);
1305                                                 } else {
1306                                                         printf(" failed: %s\n", error_string);
1307                                                         ret = False;
1308                                                 }
1309                                                 SAFE_FREE(error_string);
1310                                         }
1311                                         talloc_free(tmp_ctx);
1312                                 }
1313                         }
1314                 }
1315         }
1316         talloc_free(fn_ctx);
1317         return ret;
1318 }
1319
1320 /*
1321   test an ADS style interactive domain logon
1322 */
1323 BOOL test_InteractiveLogon(struct dcerpc_pipe *p, TALLOC_CTX *mem_ctx,
1324                            struct creds_CredentialState *creds, 
1325                            const char *comment,
1326                            const char *workstation_name,
1327                            const char *account_domain, const char *account_name,
1328                            const char *plain_pass, NTSTATUS expected_error)
1329 {
1330         NTSTATUS status;
1331         TALLOC_CTX *fn_ctx = talloc_named(mem_ctx, 0, "test_InteractiveLogon function-level context");
1332         struct netr_LogonSamLogonWithFlags r;
1333         struct netr_Authenticator a, ra;
1334         struct netr_PasswordInfo pinfo;
1335
1336         ZERO_STRUCT(a);
1337         ZERO_STRUCT(r);
1338         ZERO_STRUCT(ra);
1339
1340         creds_client_authenticator(creds, &a);
1341
1342         r.in.server_name = talloc_asprintf(fn_ctx, "\\\\%s", dcerpc_server_name(p));
1343         r.in.workstation = TEST_MACHINE_NAME;
1344         r.in.credential = &a;
1345         r.in.return_authenticator = &ra;
1346         r.in.logon_level = 5;
1347         r.in.logon.password = &pinfo;
1348         r.in.validation_level = 6;
1349         r.in.flags = 0;
1350
1351         pinfo.identity_info.domain_name.string = account_domain;
1352         pinfo.identity_info.parameter_control = 0;
1353         pinfo.identity_info.logon_id_low = 0;
1354         pinfo.identity_info.logon_id_high = 0;
1355         pinfo.identity_info.account_name.string = account_name;
1356         pinfo.identity_info.workstation.string = workstation_name;
1357
1358         if (!E_deshash(plain_pass, pinfo.lmpassword.hash)) {
1359                 ZERO_STRUCT(pinfo.lmpassword.hash);
1360         }
1361         E_md4hash(plain_pass, pinfo.ntpassword.hash);
1362
1363         if (creds->negotiate_flags & NETLOGON_NEG_ARCFOUR) {
1364                 creds_arcfour_crypt(creds, pinfo.lmpassword.hash, 16);
1365                 creds_arcfour_crypt(creds, pinfo.ntpassword.hash, 16);
1366         } else {
1367                 creds_des_encrypt(creds, &pinfo.lmpassword);
1368                 creds_des_encrypt(creds, &pinfo.ntpassword);
1369         }
1370
1371         printf("Testing netr_LogonSamLogonWithFlags '%s' (Interactive Logon)\n", comment);
1372
1373         status = dcerpc_netr_LogonSamLogonWithFlags(p, fn_ctx, &r);
1374         if (!r.out.return_authenticator 
1375             || !creds_client_check(creds, &r.out.return_authenticator->cred)) {
1376                 printf("Credential chaining failed\n");
1377                 talloc_free(fn_ctx);
1378                 return False;
1379         }
1380
1381         talloc_free(fn_ctx);
1382
1383         if (!NT_STATUS_EQUAL(expected_error, status)) {
1384                 printf("[%s]\\[%s] netr_LogonSamLogonWithFlags - expected %s got %s\n", 
1385                        account_domain, account_name, nt_errstr(expected_error), nt_errstr(status));
1386                 return False;
1387         }
1388
1389         return True;
1390 }
1391
1392
1393
1394 BOOL torture_rpc_samlogon(void)
1395 {
1396         NTSTATUS status;
1397         struct dcerpc_pipe *p;
1398         struct dcerpc_binding *b;
1399         struct cli_credentials *machine_credentials;
1400         TALLOC_CTX *mem_ctx = talloc_init("torture_rpc_netlogon");
1401         BOOL ret = True;
1402         struct test_join *join_ctx;
1403         struct test_join *user_ctx;
1404         const char *user_password;
1405         const char *old_user_password;
1406         char *test_machine_account;
1407         const char *binding = lp_parm_string(-1, "torture", "binding");
1408         const char *userdomain;
1409         int i;
1410         int ci;
1411
1412         unsigned int credential_flags[] = {
1413                 NETLOGON_NEG_AUTH2_FLAGS,
1414                 NETLOGON_NEG_ARCFOUR,
1415                 NETLOGON_NEG_ARCFOUR | NETLOGON_NEG_128BIT,
1416                 NETLOGON_NEG_AUTH2_ADS_FLAGS, 
1417                 0 /* yes, this is a valid flag, causes the use of DES */ 
1418         };
1419
1420         struct creds_CredentialState *creds;
1421
1422         test_machine_account = talloc_asprintf(mem_ctx, "%s$", TEST_MACHINE_NAME);
1423         /* We only need to join as a workstation here, and in future,
1424          * if we wish to test against trusted domains, we must be a
1425          * workstation here */
1426         join_ctx = torture_join_domain(TEST_MACHINE_NAME, ACB_WSTRUST, 
1427                                        &machine_credentials);
1428         if (!join_ctx) {
1429                 printf("Failed to join as Workstation\n");
1430                 return False;
1431         }
1432
1433         userdomain = lp_parm_string(-1, "torture", "userdomain");
1434         if (!userdomain) {
1435                 userdomain = lp_workgroup();
1436         }
1437
1438         user_ctx = torture_create_testuser(TEST_USER_NAME,
1439                                            userdomain,
1440                                            ACB_NORMAL, 
1441                                            &user_password);
1442         if (!user_ctx) {
1443                 printf("Failed to join as Workstation\n");
1444                 return False;
1445         }
1446
1447         old_user_password = user_password;
1448
1449         test_ChangePasswordUser3(torture_join_samr_pipe(user_ctx), mem_ctx,
1450                                  TEST_USER_NAME, 16 /* > 14 */, &user_password);
1451
1452         status = dcerpc_parse_binding(mem_ctx, binding, &b);
1453         if (!NT_STATUS_IS_OK(status)) {
1454                 printf("Bad binding string %s\n", binding);
1455                 ret = False;
1456                 goto failed;
1457         }
1458
1459         /* We have to use schannel, otherwise the SamLogonEx fails
1460          * with INTERNAL_ERROR */
1461
1462         b->flags &= ~DCERPC_AUTH_OPTIONS;
1463         b->flags |= DCERPC_SCHANNEL | DCERPC_SIGN | DCERPC_SCHANNEL_128;
1464
1465         status = dcerpc_pipe_connect_b(mem_ctx, &p, b, 
1466                                        DCERPC_NETLOGON_UUID,
1467                                        DCERPC_NETLOGON_VERSION,
1468                                        machine_credentials, NULL);
1469
1470         if (!NT_STATUS_IS_OK(status)) {
1471                 printf("RPC pipe connect as domain member failed: %s\n", nt_errstr(status));
1472                 ret = False;
1473                 goto failed;
1474         }
1475
1476         status = dcerpc_schannel_creds(p->conn->security_state.generic_state, mem_ctx, &creds);
1477         if (!NT_STATUS_IS_OK(status)) {
1478                 ret = False;
1479                 goto failed;
1480         }
1481
1482         {
1483                 
1484                 struct {
1485                         const char *comment;
1486                         const char *domain;
1487                         const char *username;
1488                         const char *password;
1489                         BOOL network_login;
1490                         NTSTATUS expected_interactive_error;
1491                         NTSTATUS expected_network_error;
1492                 } usercreds[] = {
1493                         {
1494                                 .comment       = "domain\\user",
1495                                 .domain        = cli_credentials_get_domain(cmdline_credentials),
1496                                 .username      = cli_credentials_get_username(cmdline_credentials),
1497                                 .password      = cli_credentials_get_password(cmdline_credentials),
1498                                 .network_login = True,
1499                                 .expected_interactive_error = NT_STATUS_OK,
1500                                 .expected_network_error     = NT_STATUS_OK
1501                         },
1502                         {
1503                                 .comment       = "realm\\user",
1504                                 .domain        = cli_credentials_get_realm(cmdline_credentials),
1505                                 .username      = cli_credentials_get_username(cmdline_credentials),
1506                                 .password      = cli_credentials_get_password(cmdline_credentials),
1507                                 .network_login = True,
1508                                 .expected_interactive_error = NT_STATUS_OK,
1509                                 .expected_network_error     = NT_STATUS_OK
1510                         },
1511                         {
1512                                 .comment       = "user@domain",
1513                                 .domain        = NULL,
1514                                 .username      = talloc_asprintf(mem_ctx, 
1515                                                 "%s@%s", 
1516                                                 cli_credentials_get_username(cmdline_credentials),
1517                                                 cli_credentials_get_domain(cmdline_credentials)
1518                                         ),
1519                                 .password      = cli_credentials_get_password(cmdline_credentials),
1520                                 .network_login = False,
1521                                 .expected_interactive_error = NT_STATUS_OK,
1522                                 .expected_network_error     = NT_STATUS_OK
1523                         },
1524                         {
1525                                 .comment       = "user@realm",
1526                                 .domain        = NULL,
1527                                 .username      = talloc_asprintf(mem_ctx, 
1528                                                 "%s@%s", 
1529                                                 cli_credentials_get_username(cmdline_credentials),
1530                                                 cli_credentials_get_realm(cmdline_credentials)
1531                                         ),
1532                                 .password      = cli_credentials_get_password(cmdline_credentials),
1533                                 .network_login = True,
1534                                 .expected_interactive_error = NT_STATUS_OK,
1535                                 .expected_network_error     = NT_STATUS_OK
1536                         },
1537                         {
1538                                 .comment      = "machine domain\\user",
1539                                 .domain       = cli_credentials_get_domain(machine_credentials),
1540                                 .username     = cli_credentials_get_username(machine_credentials),
1541                                 .password     = cli_credentials_get_password(machine_credentials),
1542                                 .network_login = True,
1543                                 .expected_interactive_error = NT_STATUS_NO_SUCH_USER,
1544                                 .expected_network_error     = NT_STATUS_NOLOGON_WORKSTATION_TRUST_ACCOUNT
1545                         },
1546                         {
1547                                 .comment       = "machine realm\\user",
1548                                 .domain        = cli_credentials_get_realm(machine_credentials),
1549                                 .username      = cli_credentials_get_username(machine_credentials),
1550                                 .password      = cli_credentials_get_password(machine_credentials),
1551                                 .network_login = True,
1552                                 .expected_interactive_error = NT_STATUS_NO_SUCH_USER,
1553                                 .expected_network_error     = NT_STATUS_NOLOGON_WORKSTATION_TRUST_ACCOUNT
1554                         },
1555                         {
1556                                 .comment       = "machine user@domain",
1557                                 .domain        = NULL,
1558                                 .username      = talloc_asprintf(mem_ctx, 
1559                                                                 "%s@%s", 
1560                                                                 cli_credentials_get_username(machine_credentials),
1561                                                                 cli_credentials_get_domain(machine_credentials)
1562                                         ), 
1563                                 .password      = cli_credentials_get_password(machine_credentials),
1564                                 .network_login = False,
1565                                 .expected_interactive_error = NT_STATUS_NO_SUCH_USER,
1566                                 .expected_network_error     = NT_STATUS_NOLOGON_WORKSTATION_TRUST_ACCOUNT
1567                         },
1568                         {
1569                                 .comment       = "machine user@realm",
1570                                 .domain        = NULL,
1571                                 .username      = talloc_asprintf(mem_ctx, 
1572                                                                 "%s@%s", 
1573                                                                 cli_credentials_get_username(machine_credentials),
1574                                                                 cli_credentials_get_realm(machine_credentials)
1575                                         ),
1576                                 .password      = cli_credentials_get_password(machine_credentials),
1577                                 .network_login = True,
1578                                 .expected_interactive_error = NT_STATUS_NO_SUCH_USER,
1579                                 .expected_network_error     = NT_STATUS_NOLOGON_WORKSTATION_TRUST_ACCOUNT
1580                         },
1581                         {       
1582                                 .comment       = "test user (long pw): domain\\user",
1583                                 .domain        = userdomain,
1584                                 .username      = TEST_USER_NAME,
1585                                 .password      = user_password,
1586                                 .network_login = True,
1587                                 .expected_interactive_error = NT_STATUS_OK,
1588                                 .expected_network_error     = NT_STATUS_OK
1589                         },
1590                         {
1591                                 .comment       = "test user (long pw): user@realm", 
1592                                 .domain        = NULL,
1593                                 .username      = talloc_asprintf(mem_ctx, 
1594                                                                  "%s@%s", 
1595                                                                  TEST_USER_NAME,
1596                                                                  lp_realm()),
1597                                 .password      = user_password,
1598                                 .network_login = True,
1599                                 .expected_interactive_error = NT_STATUS_OK,
1600                                 .expected_network_error     = NT_STATUS_OK
1601                         },
1602                         {
1603                                 .comment       = "test user (long pw): user@domain",
1604                                 .domain        = NULL,
1605                                 .username      = talloc_asprintf(mem_ctx, 
1606                                                                  "%s@%s", 
1607                                                                  TEST_USER_NAME,
1608                                                                  userdomain),
1609                                 .password      = user_password,
1610                                 .network_login = False,
1611                                 .expected_interactive_error = NT_STATUS_OK,
1612                                 .expected_network_error     = NT_STATUS_OK
1613                         },
1614                         /* Oddball, can we use the old password ? */
1615                         {       
1616                                 .comment       = "test user: user\\domain OLD PASSWORD",
1617                                 .domain        = userdomain,
1618                                 .username      = TEST_USER_NAME,
1619                                 .password      = old_user_password,
1620                                 .network_login = True,
1621                                 .expected_interactive_error = NT_STATUS_WRONG_PASSWORD,
1622                                 .expected_network_error     = NT_STATUS_OK
1623                         }
1624                 };
1625                 
1626                 /* Try all the tests for different username forms */
1627                 for (ci = 0; ci < ARRAY_SIZE(usercreds); ci++) {
1628                 
1629                         if (!test_InteractiveLogon(p, mem_ctx, creds,
1630                                                    usercreds[ci].comment,
1631                                                    TEST_MACHINE_NAME,
1632                                                    usercreds[ci].domain,
1633                                                    usercreds[ci].username,
1634                                                    usercreds[ci].password,
1635                                                    usercreds[ci].expected_interactive_error)) {
1636                                 ret = False;
1637                         }
1638                 
1639                         if (usercreds[ci].network_login) {
1640                                 if (!test_SamLogon(p, mem_ctx, creds, 
1641                                                    usercreds[ci].comment,
1642                                                    usercreds[ci].domain,
1643                                                    usercreds[ci].username,
1644                                                    usercreds[ci].password,
1645                                                    usercreds[ci].expected_network_error,
1646                                                    0)) {
1647                                         ret = False;
1648                                 }
1649                         }
1650                 }
1651
1652                 /* Using the first username form, try the different
1653                  * credentials flag setups, on only one of the tests (checks
1654                  * session key encryption) */
1655
1656                 for (i=0; i < ARRAY_SIZE(credential_flags); i++) {
1657                         if (!test_InteractiveLogon(p, mem_ctx, creds,
1658                                                    usercreds[0].comment,
1659                                                    TEST_MACHINE_NAME,
1660                                                    usercreds[0].domain,
1661                                                    usercreds[0].username,
1662                                                    usercreds[0].password,
1663                                                    usercreds[0].expected_interactive_error)) {
1664                                 ret = False;
1665                         }
1666                 
1667                         if (usercreds[ci].network_login) {
1668                                 if (!test_SamLogon(p, mem_ctx, creds,
1669                                                    usercreds[0].comment,
1670                                                    usercreds[0].domain,
1671                                                    usercreds[0].username,
1672                                                    usercreds[0].password,
1673                                                    usercreds[0].expected_network_error,
1674                                                    1)) {
1675                                         ret = False;
1676                                 }
1677                         }
1678                 }
1679
1680         }
1681 failed:
1682         talloc_free(mem_ctx);
1683
1684         torture_leave_domain(join_ctx);
1685         torture_leave_domain(user_ctx);
1686         return ret;
1687 }