root/source3/utils/ntlm_auth_diagnostics.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. test_lm_ntlm_broken
  2. test_lm
  3. test_ntlm
  4. test_ntlm_in_lm
  5. test_ntlm_in_both
  6. test_lmv2_ntlmv2_broken
  7. test_lmv2_ntlmv2
  8. test_lmv2
  9. test_ntlmv2
  10. test_lm_ntlm
  11. test_ntlm_lm_broken
  12. test_ntlm_ntlm_broken
  13. test_ntlmv2_lmv2_broken
  14. test_ntlmv2_ntlmv2_broken
  15. test_plaintext
  16. test_plaintext_none_broken
  17. test_plaintext_lm_broken
  18. test_plaintext_nt_broken
  19. test_plaintext_nt_only
  20. test_plaintext_lm_only
  21. diagnose_ntlm_auth

   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) 
     /* [<][>][^][v][top][bottom][index][help] */
  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) 
     /* [<][>][^][v][top][bottom][index][help] */
 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) 
     /* [<][>][^][v][top][bottom][index][help] */
 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) 
     /* [<][>][^][v][top][bottom][index][help] */
 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) 
     /* [<][>][^][v][top][bottom][index][help] */
 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) 
     /* [<][>][^][v][top][bottom][index][help] */
 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) 
     /* [<][>][^][v][top][bottom][index][help] */
 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) 
     /* [<][>][^][v][top][bottom][index][help] */
 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) 
     /* [<][>][^][v][top][bottom][index][help] */
 411 {
 412         return test_lmv2_ntlmv2_broken(NO_LM);
 413 }
 414 
 415 static bool test_lm_ntlm(void) 
     /* [<][>][^][v][top][bottom][index][help] */
 416 {
 417         return test_lm_ntlm_broken(BREAK_NONE);
 418 }
 419 
 420 static bool test_ntlm_lm_broken(void) 
     /* [<][>][^][v][top][bottom][index][help] */
 421 {
 422         return test_lm_ntlm_broken(BREAK_LM);
 423 }
 424 
 425 static bool test_ntlm_ntlm_broken(void) 
     /* [<][>][^][v][top][bottom][index][help] */
 426 {
 427         return test_lm_ntlm_broken(BREAK_NT);
 428 }
 429 
 430 static bool test_ntlmv2_lmv2_broken(void) 
     /* [<][>][^][v][top][bottom][index][help] */
 431 {
 432         return test_lmv2_ntlmv2_broken(BREAK_LM);
 433 }
 434 
 435 static bool test_ntlmv2_ntlmv2_broken(void) 
     /* [<][>][^][v][top][bottom][index][help] */
 436 {
 437         return test_lmv2_ntlmv2_broken(BREAK_NT);
 438 }
 439 
 440 static bool test_plaintext(enum ntlm_break break_which)
     /* [<][>][^][v][top][bottom][index][help] */
 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) {
     /* [<][>][^][v][top][bottom][index][help] */
 532         return test_plaintext(BREAK_NONE);
 533 }
 534 
 535 static bool test_plaintext_lm_broken(void) {
     /* [<][>][^][v][top][bottom][index][help] */
 536         return test_plaintext(BREAK_LM);
 537 }
 538 
 539 static bool test_plaintext_nt_broken(void) {
     /* [<][>][^][v][top][bottom][index][help] */
 540         return test_plaintext(BREAK_NT);
 541 }
 542 
 543 static bool test_plaintext_nt_only(void) {
     /* [<][>][^][v][top][bottom][index][help] */
 544         return test_plaintext(NO_LM);
 545 }
 546 
 547 static bool test_plaintext_lm_only(void) {
     /* [<][>][^][v][top][bottom][index][help] */
 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)
     /* [<][>][^][v][top][bottom][index][help] */
 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 

/* [<][>][^][v][top][bottom][index][help] */