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