r23779: Change from v2 or later to v3 or later.
[samba.git] / source3 / utils / ntlm_auth_diagnostics.c
1 /* 
2    Unix SMB/CIFS implementation.
3
4    Winbind status program.
5
6    Copyright (C) Tim Potter      2000-2003
7    Copyright (C) Andrew Bartlett <abartlet@samba.org> 2003-2004
8    Copyright (C) Francesco Chemolli <kinkie@kame.usr.dsi.unimi.it> 2000 
9
10    This program is free software; you can redistribute it and/or modify
11    it under the terms of the GNU General Public License as published by
12    the Free Software Foundation; either version 3 of the License, or
13    (at your option) any later version.
14    
15    This program is distributed in the hope that it will be useful,
16    but WITHOUT ANY WARRANTY; without even the implied warranty of
17    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18    GNU General Public License for more details.
19    
20    You should have received a copy of the GNU General Public License
21    along with this program; if not, write to the Free Software
22    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
23 */
24
25 #include "includes.h"
26 #include "utils/ntlm_auth.h"
27
28 #undef DBGC_CLASS
29 #define DBGC_CLASS DBGC_WINBIND
30
31 enum ntlm_break {
32         BREAK_NONE,
33         BREAK_LM,
34         BREAK_NT,
35         NO_LM,
36         NO_NT
37 };
38
39 /* 
40    Authenticate a user with a challenge/response, checking session key
41    and valid authentication types
42 */
43
44 /* 
45  * Test the normal 'LM and NTLM' combination
46  */
47
48 static BOOL test_lm_ntlm_broken(enum ntlm_break break_which) 
49 {
50         BOOL pass = True;
51         NTSTATUS nt_status;
52         uint32 flags = 0;
53         DATA_BLOB lm_response = data_blob(NULL, 24);
54         DATA_BLOB nt_response = data_blob(NULL, 24);
55         DATA_BLOB session_key = data_blob(NULL, 16);
56
57         uchar lm_key[8];
58         uchar user_session_key[16];
59         uchar lm_hash[16];
60         uchar nt_hash[16];
61         DATA_BLOB chall = get_challenge();
62         char *error_string;
63         
64         ZERO_STRUCT(lm_key);
65         ZERO_STRUCT(user_session_key);
66
67         flags |= WBFLAG_PAM_LMKEY;
68         flags |= WBFLAG_PAM_USER_SESSION_KEY;
69
70         SMBencrypt(opt_password,chall.data,lm_response.data);
71         E_deshash(opt_password, lm_hash); 
72
73         SMBNTencrypt(opt_password,chall.data,nt_response.data);
74
75         E_md4hash(opt_password, nt_hash);
76         SMBsesskeygen_ntv1(nt_hash, NULL, session_key.data);
77
78         switch (break_which) {
79         case BREAK_NONE:
80                 break;
81         case BREAK_LM:
82                 lm_response.data[0]++;
83                 break;
84         case BREAK_NT:
85                 nt_response.data[0]++;
86                 break;
87         case NO_LM:
88                 data_blob_free(&lm_response);
89                 break;
90         case NO_NT:
91                 data_blob_free(&nt_response);
92                 break;
93         }
94
95         nt_status = contact_winbind_auth_crap(opt_username, opt_domain, 
96                                               opt_workstation,
97                                               &chall,
98                                               &lm_response,
99                                               &nt_response,
100                                               flags,
101                                               lm_key, 
102                                               user_session_key,
103                                               &error_string, NULL);
104         
105         data_blob_free(&lm_response);
106
107         if (!NT_STATUS_IS_OK(nt_status)) {
108                 d_printf("%s (0x%x)\n", 
109                          error_string,
110                          NT_STATUS_V(nt_status));
111                 SAFE_FREE(error_string);
112                 return break_which == BREAK_NT;
113         }
114
115         if (memcmp(lm_hash, lm_key, 
116                    sizeof(lm_key)) != 0) {
117                 DEBUG(1, ("LM Key does not match expectations!\n"));
118                 DEBUG(1, ("lm_key:\n"));
119                 dump_data(1, lm_key, 8);
120                 DEBUG(1, ("expected:\n"));
121                 dump_data(1, lm_hash, 8);
122                 pass = False;
123         }
124
125         if (break_which == NO_NT) {
126                 if (memcmp(lm_hash, user_session_key, 
127                            8) != 0) {
128                         DEBUG(1, ("NT Session Key does not match expectations (should be LM hash)!\n"));
129                         DEBUG(1, ("user_session_key:\n"));
130                         dump_data(1, user_session_key, sizeof(user_session_key));
131                         DEBUG(1, ("expected:\n"));
132                         dump_data(1, lm_hash, sizeof(lm_hash));
133                         pass = False;
134                 }
135         } else {                
136                 if (memcmp(session_key.data, user_session_key, 
137                            sizeof(user_session_key)) != 0) {
138                         DEBUG(1, ("NT Session Key does not match expectations!\n"));
139                         DEBUG(1, ("user_session_key:\n"));
140                         dump_data(1, user_session_key, 16);
141                         DEBUG(1, ("expected:\n"));
142                         dump_data(1, session_key.data, session_key.length);
143                         pass = False;
144                 }
145         }
146         return pass;
147 }
148
149 /* 
150  * Test LM authentication, no NT response supplied
151  */
152
153 static BOOL test_lm(void) 
154 {
155
156         return test_lm_ntlm_broken(NO_NT);
157 }
158
159 /* 
160  * Test the NTLM response only, no LM.
161  */
162
163 static BOOL test_ntlm(void) 
164 {
165         return test_lm_ntlm_broken(NO_LM);
166 }
167
168 /* 
169  * Test the NTLM response only, but in the LM field.
170  */
171
172 static BOOL test_ntlm_in_lm(void) 
173 {
174         BOOL pass = True;
175         NTSTATUS nt_status;
176         uint32 flags = 0;
177         DATA_BLOB nt_response = data_blob(NULL, 24);
178
179         uchar lm_key[8];
180         uchar lm_hash[16];
181         uchar user_session_key[16];
182         DATA_BLOB chall = get_challenge();
183         char *error_string;
184         
185         ZERO_STRUCT(user_session_key);
186
187         flags |= WBFLAG_PAM_LMKEY;
188         flags |= WBFLAG_PAM_USER_SESSION_KEY;
189
190         SMBNTencrypt(opt_password,chall.data,nt_response.data);
191
192         E_deshash(opt_password, lm_hash); 
193
194         nt_status = contact_winbind_auth_crap(opt_username, opt_domain, 
195                                               opt_workstation,
196                                               &chall,
197                                               &nt_response,
198                                               NULL,
199                                               flags,
200                                               lm_key,
201                                               user_session_key,
202                                               &error_string, NULL);
203         
204         data_blob_free(&nt_response);
205
206         if (!NT_STATUS_IS_OK(nt_status)) {
207                 d_printf("%s (0x%x)\n", 
208                          error_string,
209                          NT_STATUS_V(nt_status));
210                 SAFE_FREE(error_string);
211                 return False;
212         }
213
214         if (memcmp(lm_hash, lm_key, 
215                    sizeof(lm_key)) != 0) {
216                 DEBUG(1, ("LM Key does not match expectations!\n"));
217                 DEBUG(1, ("lm_key:\n"));
218                 dump_data(1, lm_key, 8);
219                 DEBUG(1, ("expected:\n"));
220                 dump_data(1, lm_hash, 8);
221                 pass = False;
222         }
223         if (memcmp(lm_hash, user_session_key, 8) != 0) {
224                 DEBUG(1, ("Session Key (first 8 lm hash) does not match expectations!\n"));
225                 DEBUG(1, ("user_session_key:\n"));
226                 dump_data(1, user_session_key, 16);
227                 DEBUG(1, ("expected:\n"));
228                 dump_data(1, lm_hash, 8);
229                 pass = False;
230         }
231         return pass;
232 }
233
234 /* 
235  * Test the NTLM response only, but in the both the NT and LM fields.
236  */
237
238 static BOOL test_ntlm_in_both(void) 
239 {
240         BOOL pass = True;
241         NTSTATUS nt_status;
242         uint32 flags = 0;
243         DATA_BLOB nt_response = data_blob(NULL, 24);
244         DATA_BLOB session_key = data_blob(NULL, 16);
245
246         uint8 lm_key[8];
247         uint8 lm_hash[16];
248         uint8 user_session_key[16];
249         uint8 nt_hash[16];
250         DATA_BLOB chall = get_challenge();
251         char *error_string;
252         
253         ZERO_STRUCT(lm_key);
254         ZERO_STRUCT(user_session_key);
255
256         flags |= WBFLAG_PAM_LMKEY;
257         flags |= WBFLAG_PAM_USER_SESSION_KEY;
258
259         SMBNTencrypt(opt_password,chall.data,nt_response.data);
260         E_md4hash(opt_password, nt_hash);
261         SMBsesskeygen_ntv1(nt_hash, NULL, session_key.data);
262
263         E_deshash(opt_password, lm_hash); 
264
265         nt_status = contact_winbind_auth_crap(opt_username, opt_domain, 
266                                               opt_workstation,
267                                               &chall,
268                                               &nt_response,
269                                               &nt_response,
270                                               flags,
271                                               lm_key,
272                                               user_session_key,
273                                               &error_string, NULL);
274         
275         data_blob_free(&nt_response);
276
277         if (!NT_STATUS_IS_OK(nt_status)) {
278                 d_printf("%s (0x%x)\n", 
279                          error_string,
280                          NT_STATUS_V(nt_status));
281                 SAFE_FREE(error_string);
282                 return False;
283         }
284
285         if (memcmp(lm_hash, lm_key, 
286                    sizeof(lm_key)) != 0) {
287                 DEBUG(1, ("LM Key does not match expectations!\n"));
288                 DEBUG(1, ("lm_key:\n"));
289                 dump_data(1, lm_key, 8);
290                 DEBUG(1, ("expected:\n"));
291                 dump_data(1, lm_hash, 8);
292                 pass = False;
293         }
294         if (memcmp(session_key.data, user_session_key, 
295                    sizeof(user_session_key)) != 0) {
296                 DEBUG(1, ("NT Session Key does not match expectations!\n"));
297                 DEBUG(1, ("user_session_key:\n"));
298                 dump_data(1, user_session_key, 16);
299                 DEBUG(1, ("expected:\n"));
300                 dump_data(1, session_key.data, session_key.length);
301                 pass = False;
302         }
303
304
305         return pass;
306 }
307
308 /* 
309  * Test the NTLMv2 and LMv2 responses
310  */
311
312 static BOOL test_lmv2_ntlmv2_broken(enum ntlm_break break_which) 
313 {
314         BOOL pass = True;
315         NTSTATUS nt_status;
316         uint32 flags = 0;
317         DATA_BLOB ntlmv2_response = data_blob_null;
318         DATA_BLOB lmv2_response = data_blob_null;
319         DATA_BLOB ntlmv2_session_key = data_blob_null;
320         DATA_BLOB names_blob = NTLMv2_generate_names_blob(get_winbind_netbios_name(), get_winbind_domain());
321
322         uchar user_session_key[16];
323         DATA_BLOB chall = get_challenge();
324         char *error_string;
325
326         ZERO_STRUCT(user_session_key);
327         
328         flags |= WBFLAG_PAM_USER_SESSION_KEY;
329
330         if (!SMBNTLMv2encrypt(opt_username, opt_domain, opt_password, &chall,
331                               &names_blob,
332                               &lmv2_response, &ntlmv2_response, 
333                               &ntlmv2_session_key)) {
334                 data_blob_free(&names_blob);
335                 return False;
336         }
337         data_blob_free(&names_blob);
338
339         switch (break_which) {
340         case BREAK_NONE:
341                 break;
342         case BREAK_LM:
343                 lmv2_response.data[0]++;
344                 break;
345         case BREAK_NT:
346                 ntlmv2_response.data[0]++;
347                 break;
348         case NO_LM:
349                 data_blob_free(&lmv2_response);
350                 break;
351         case NO_NT:
352                 data_blob_free(&ntlmv2_response);
353                 break;
354         }
355
356         nt_status = contact_winbind_auth_crap(opt_username, opt_domain, 
357                                               opt_workstation,
358                                               &chall,
359                                               &lmv2_response,
360                                               &ntlmv2_response,
361                                               flags,
362                                               NULL, 
363                                               user_session_key,
364                                               &error_string, NULL);
365         
366         data_blob_free(&lmv2_response);
367         data_blob_free(&ntlmv2_response);
368
369         if (!NT_STATUS_IS_OK(nt_status)) {
370                 d_printf("%s (0x%x)\n", 
371                          error_string,
372                          NT_STATUS_V(nt_status));
373                 SAFE_FREE(error_string);
374                 return break_which == BREAK_NT;
375         }
376
377         if (break_which != NO_NT && break_which != BREAK_NT && memcmp(ntlmv2_session_key.data, user_session_key, 
378                    sizeof(user_session_key)) != 0) {
379                 DEBUG(1, ("USER (NTLMv2) Session Key does not match expectations!\n"));
380                 DEBUG(1, ("user_session_key:\n"));
381                 dump_data(1, user_session_key, 16);
382                 DEBUG(1, ("expected:\n"));
383                 dump_data(1, ntlmv2_session_key.data, ntlmv2_session_key.length);
384                 pass = False;
385         }
386         return pass;
387 }
388
389 /* 
390  * Test the NTLMv2 and LMv2 responses
391  */
392
393 static BOOL test_lmv2_ntlmv2(void) 
394 {
395         return test_lmv2_ntlmv2_broken(BREAK_NONE);
396 }
397
398 /* 
399  * Test the LMv2 response only
400  */
401
402 static BOOL test_lmv2(void) 
403 {
404         return test_lmv2_ntlmv2_broken(NO_NT);
405 }
406
407 /* 
408  * Test the NTLMv2 response only
409  */
410
411 static BOOL test_ntlmv2(void) 
412 {
413         return test_lmv2_ntlmv2_broken(NO_LM);
414 }
415
416 static BOOL test_lm_ntlm(void) 
417 {
418         return test_lm_ntlm_broken(BREAK_NONE);
419 }
420
421 static BOOL test_ntlm_lm_broken(void) 
422 {
423         return test_lm_ntlm_broken(BREAK_LM);
424 }
425
426 static BOOL test_ntlm_ntlm_broken(void) 
427 {
428         return test_lm_ntlm_broken(BREAK_NT);
429 }
430
431 static BOOL test_ntlmv2_lmv2_broken(void) 
432 {
433         return test_lmv2_ntlmv2_broken(BREAK_LM);
434 }
435
436 static BOOL test_ntlmv2_ntlmv2_broken(void) 
437 {
438         return test_lmv2_ntlmv2_broken(BREAK_NT);
439 }
440
441 static BOOL test_plaintext(enum ntlm_break break_which)
442 {
443         NTSTATUS nt_status;
444         uint32 flags = 0;
445         DATA_BLOB nt_response = data_blob_null;
446         DATA_BLOB lm_response = data_blob_null;
447         char *password;
448         smb_ucs2_t *nt_response_ucs2;
449
450         uchar user_session_key[16];
451         uchar lm_key[16];
452         static const uchar zeros[8] = { 0, };
453         DATA_BLOB chall = data_blob(zeros, sizeof(zeros));
454         char *error_string;
455
456         ZERO_STRUCT(user_session_key);
457         
458         flags |= WBFLAG_PAM_LMKEY;
459         flags |= WBFLAG_PAM_USER_SESSION_KEY;
460
461         if ((push_ucs2_allocate(&nt_response_ucs2, opt_password)) == -1) {
462                 DEBUG(0, ("push_ucs2_allocate failed!\n"));
463                 exit(1);
464         }
465
466         nt_response.data = (unsigned char *)nt_response_ucs2;
467         nt_response.length = strlen_w(nt_response_ucs2)*sizeof(smb_ucs2_t);
468
469         if ((password = strdup_upper(opt_password)) == NULL) {
470                 DEBUG(0, ("strdup_upper failed!\n"));
471                 exit(1);
472         }
473
474         if ((convert_string_allocate(NULL, CH_UNIX, 
475                                      CH_DOS, password,
476                                      strlen(password)+1, 
477                                      &lm_response.data,True)) == -1) {
478                 DEBUG(0, ("convert_string_allocate failed!\n"));
479                 exit(1);
480         }
481
482         SAFE_FREE(password);
483
484         lm_response.length = strlen((const char *)lm_response.data);
485
486         switch (break_which) {
487         case BREAK_NONE:
488                 break;
489         case BREAK_LM:
490                 lm_response.data[0]++;
491                 break;
492         case BREAK_NT:
493                 nt_response.data[0]++;
494                 break;
495         case NO_LM:
496                 SAFE_FREE(lm_response.data);
497                 lm_response.length = 0;
498                 break;
499         case NO_NT:
500                 SAFE_FREE(nt_response.data);
501                 nt_response.length = 0;
502                 break;
503         }
504
505         nt_status = contact_winbind_auth_crap(opt_username, opt_domain, 
506                                               opt_workstation,
507                                               &chall,
508                                               &lm_response,
509                                               &nt_response,
510                                               flags,
511                                               lm_key,
512                                               user_session_key,
513                                               &error_string, NULL);
514         
515         SAFE_FREE(nt_response.data);
516         SAFE_FREE(lm_response.data);
517         data_blob_free(&chall);
518
519         if (!NT_STATUS_IS_OK(nt_status)) {
520                 d_printf("%s (0x%x)\n", 
521                          error_string,
522                          NT_STATUS_V(nt_status));
523                 SAFE_FREE(error_string);
524                 return break_which == BREAK_NT;
525         }
526
527         return break_which != BREAK_NT;
528 }
529
530 static BOOL test_plaintext_none_broken(void) {
531         return test_plaintext(BREAK_NONE);
532 }
533
534 static BOOL test_plaintext_lm_broken(void) {
535         return test_plaintext(BREAK_LM);
536 }
537
538 static BOOL test_plaintext_nt_broken(void) {
539         return test_plaintext(BREAK_NT);
540 }
541
542 static BOOL test_plaintext_nt_only(void) {
543         return test_plaintext(NO_LM);
544 }
545
546 static BOOL test_plaintext_lm_only(void) {
547         return test_plaintext(NO_NT);
548 }
549
550 /* 
551    Tests:
552    
553    - LM only
554    - NT and LM             
555    - NT
556    - NT in LM field
557    - NT in both fields
558    - NTLMv2
559    - NTLMv2 and LMv2
560    - LMv2
561    - plaintext tests (in challenge-response feilds)
562   
563    check we get the correct session key in each case
564    check what values we get for the LM session key
565    
566 */
567
568 static const struct ntlm_tests {
569         BOOL (*fn)(void);
570         const char *name;
571 } test_table[] = {
572         {test_lm, "LM"},
573         {test_lm_ntlm, "LM and NTLM"},
574         {test_ntlm, "NTLM"},
575         {test_ntlm_in_lm, "NTLM in LM"},
576         {test_ntlm_in_both, "NTLM in both"},
577         {test_ntlmv2, "NTLMv2"},
578         {test_lmv2_ntlmv2, "NTLMv2 and LMv2"},
579         {test_lmv2, "LMv2"},
580         {test_ntlmv2_lmv2_broken, "NTLMv2 and LMv2, LMv2 broken"},
581         {test_ntlmv2_ntlmv2_broken, "NTLMv2 and LMv2, NTLMv2 broken"},
582         {test_ntlm_lm_broken, "NTLM and LM, LM broken"},
583         {test_ntlm_ntlm_broken, "NTLM and LM, NTLM broken"},
584         {test_plaintext_none_broken, "Plaintext"},
585         {test_plaintext_lm_broken, "Plaintext LM broken"},
586         {test_plaintext_nt_broken, "Plaintext NT broken"},
587         {test_plaintext_nt_only, "Plaintext NT only"},
588         {test_plaintext_lm_only, "Plaintext LM only"},
589         {NULL, NULL}
590 };
591
592 BOOL diagnose_ntlm_auth(void)
593 {
594         unsigned int i;
595         BOOL pass = True;
596
597         for (i=0; test_table[i].fn; i++) {
598                 if (!test_table[i].fn()) {
599                         DEBUG(1, ("Test %s failed!\n", test_table[i].name));
600                         pass = False;
601                 }
602         }
603
604         return pass;
605 }
606