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