~zulcss/samba/server-dailies-3.4

« back to all changes in this revision

Viewing changes to source3/utils/ntlm_auth_diagnostics.c

  • Committer: Chuck Short
  • Date: 2010-09-28 20:38:39 UTC
  • Revision ID: zulcss@ubuntu.com-20100928203839-pgjulytsi9ue63x1
Initial version

Show diffs side-by-side

added added

removed removed

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