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