017882380180af7b658695208536b9a1e59dc6cd
[ira/wip.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, see <http://www.gnu.org/licenses/>.
22 */
23
24 #include "includes.h"
25 #include "utils/ntlm_auth.h"
26 #include "../libcli/auth/libcli_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, 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, 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(NULL, 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(NULL, opt_username, opt_domain, opt_password, &chall,
331                               &names_blob,
332                               &lmv2_response, &ntlmv2_response, NULL,
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         size_t converted_size;
450
451         uchar user_session_key[16];
452         uchar lm_key[16];
453         static const uchar zeros[8] = { 0, };
454         DATA_BLOB chall = data_blob(zeros, sizeof(zeros));
455         char *error_string;
456
457         ZERO_STRUCT(user_session_key);
458         
459         flags |= WBFLAG_PAM_LMKEY;
460         flags |= WBFLAG_PAM_USER_SESSION_KEY;
461
462         if (!push_ucs2_talloc(talloc_tos(), &nt_response_ucs2, opt_password,
463                                 &converted_size))
464         {
465                 DEBUG(0, ("push_ucs2_talloc failed!\n"));
466                 exit(1);
467         }
468
469         nt_response.data = (unsigned char *)nt_response_ucs2;
470         nt_response.length = strlen_w(nt_response_ucs2)*sizeof(smb_ucs2_t);
471
472         if ((password = strupper_talloc(talloc_tos(), opt_password)) == NULL) {
473                 DEBUG(0, ("strupper_talloc() failed!\n"));
474                 exit(1);
475         }
476
477         if (!convert_string_talloc(talloc_tos(), CH_UNIX,
478                                    CH_DOS, password,
479                                    strlen(password)+1, 
480                                    &lm_response.data,
481                                    &lm_response.length, True)) {
482                 DEBUG(0, ("convert_string_talloc failed!\n"));
483                 exit(1);
484         }
485
486         TALLOC_FREE(password);
487
488         switch (break_which) {
489         case BREAK_NONE:
490                 break;
491         case BREAK_LM:
492                 lm_response.data[0]++;
493                 break;
494         case BREAK_NT:
495                 nt_response.data[0]++;
496                 break;
497         case NO_LM:
498                 SAFE_FREE(lm_response.data);
499                 lm_response.length = 0;
500                 break;
501         case NO_NT:
502                 SAFE_FREE(nt_response.data);
503                 nt_response.length = 0;
504                 break;
505         }
506
507         nt_status = contact_winbind_auth_crap(opt_username, opt_domain, 
508                                               opt_workstation,
509                                               &chall,
510                                               &lm_response,
511                                               &nt_response,
512                                               flags,
513                                               lm_key,
514                                               user_session_key,
515                                               &error_string, NULL);
516         
517         TALLOC_FREE(nt_response.data);
518         TALLOC_FREE(lm_response.data);
519         data_blob_free(&chall);
520
521         if (!NT_STATUS_IS_OK(nt_status)) {
522                 d_printf("%s (0x%x)\n", 
523                          error_string,
524                          NT_STATUS_V(nt_status));
525                 SAFE_FREE(error_string);
526                 return break_which == BREAK_NT;
527         }
528
529         return break_which != BREAK_NT;
530 }
531
532 static bool test_plaintext_none_broken(void) {
533         return test_plaintext(BREAK_NONE);
534 }
535
536 static bool test_plaintext_lm_broken(void) {
537         return test_plaintext(BREAK_LM);
538 }
539
540 static bool test_plaintext_nt_broken(void) {
541         return test_plaintext(BREAK_NT);
542 }
543
544 static bool test_plaintext_nt_only(void) {
545         return test_plaintext(NO_LM);
546 }
547
548 static bool test_plaintext_lm_only(void) {
549         return test_plaintext(NO_NT);
550 }
551
552 /* 
553    Tests:
554    
555    - LM only
556    - NT and LM             
557    - NT
558    - NT in LM field
559    - NT in both fields
560    - NTLMv2
561    - NTLMv2 and LMv2
562    - LMv2
563    - plaintext tests (in challenge-response feilds)
564   
565    check we get the correct session key in each case
566    check what values we get for the LM session key
567    
568 */
569
570 static const struct ntlm_tests {
571         bool (*fn)(void);
572         const char *name;
573 } test_table[] = {
574         {test_lm, "LM"},
575         {test_lm_ntlm, "LM and NTLM"},
576         {test_ntlm, "NTLM"},
577         {test_ntlm_in_lm, "NTLM in LM"},
578         {test_ntlm_in_both, "NTLM in both"},
579         {test_ntlmv2, "NTLMv2"},
580         {test_lmv2_ntlmv2, "NTLMv2 and LMv2"},
581         {test_lmv2, "LMv2"},
582         {test_ntlmv2_lmv2_broken, "NTLMv2 and LMv2, LMv2 broken"},
583         {test_ntlmv2_ntlmv2_broken, "NTLMv2 and LMv2, NTLMv2 broken"},
584         {test_ntlm_lm_broken, "NTLM and LM, LM broken"},
585         {test_ntlm_ntlm_broken, "NTLM and LM, NTLM broken"},
586         {test_plaintext_none_broken, "Plaintext"},
587         {test_plaintext_lm_broken, "Plaintext LM broken"},
588         {test_plaintext_nt_broken, "Plaintext NT broken"},
589         {test_plaintext_nt_only, "Plaintext NT only"},
590         {test_plaintext_lm_only, "Plaintext LM only"},
591         {NULL, NULL}
592 };
593
594 bool diagnose_ntlm_auth(void)
595 {
596         unsigned int i;
597         bool pass = True;
598
599         for (i=0; test_table[i].fn; i++) {
600                 if (!test_table[i].fn()) {
601                         DEBUG(1, ("Test %s failed!\n", test_table[i].name));
602                         pass = False;
603                 }
604         }
605
606         return pass;
607 }
608