utils/ntlm_auth_diagnostics.c

説明を見る。
00001 /* 
00002    Unix SMB/CIFS implementation.
00003 
00004    Winbind status program.
00005 
00006    Copyright (C) Tim Potter      2000-2003
00007    Copyright (C) Andrew Bartlett <abartlet@samba.org> 2003-2004
00008    Copyright (C) Francesco Chemolli <kinkie@kame.usr.dsi.unimi.it> 2000 
00009 
00010    This program is free software; you can redistribute it and/or modify
00011    it under the terms of the GNU General Public License as published by
00012    the Free Software Foundation; either version 2 of the License, or
00013    (at your option) any later version.
00014    
00015    This program is distributed in the hope that it will be useful,
00016    but WITHOUT ANY WARRANTY; without even the implied warranty of
00017    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00018    GNU General Public License for more details.
00019    
00020    You should have received a copy of the GNU General Public License
00021    along with this program; if not, write to the Free Software
00022    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
00023 */
00024 
00025 #include "includes.h"
00026 #include "utils/ntlm_auth.h"
00027 
00028 #undef DBGC_CLASS
00029 #define DBGC_CLASS DBGC_WINBIND
00030 
00031 enum ntlm_break {
00032         BREAK_NONE,
00033         BREAK_LM,
00034         BREAK_NT,
00035         NO_LM,
00036         NO_NT
00037 };
00038 
00039 /* 
00040    Authenticate a user with a challenge/response, checking session key
00041    and valid authentication types
00042 */
00043 
00044 /* 
00045  * Test the normal 'LM and NTLM' combination
00046  */
00047 
00048 static BOOL test_lm_ntlm_broken(enum ntlm_break break_which) 
00049 {
00050         BOOL pass = True;
00051         NTSTATUS nt_status;
00052         uint32 flags = 0;
00053         DATA_BLOB lm_response = data_blob(NULL, 24);
00054         DATA_BLOB nt_response = data_blob(NULL, 24);
00055         DATA_BLOB session_key = data_blob(NULL, 16);
00056 
00057         uchar lm_key[8];
00058         uchar user_session_key[16];
00059         uchar lm_hash[16];
00060         uchar nt_hash[16];
00061         DATA_BLOB chall = get_challenge();
00062         char *error_string;
00063         
00064         ZERO_STRUCT(lm_key);
00065         ZERO_STRUCT(user_session_key);
00066 
00067         flags |= WBFLAG_PAM_LMKEY;
00068         flags |= WBFLAG_PAM_USER_SESSION_KEY;
00069 
00070         SMBencrypt(opt_password,chall.data,lm_response.data);
00071         E_deshash(opt_password, lm_hash); 
00072 
00073         SMBNTencrypt(opt_password,chall.data,nt_response.data);
00074 
00075         E_md4hash(opt_password, nt_hash);
00076         SMBsesskeygen_ntv1(nt_hash, NULL, session_key.data);
00077 
00078         switch (break_which) {
00079         case BREAK_NONE:
00080                 break;
00081         case BREAK_LM:
00082                 lm_response.data[0]++;
00083                 break;
00084         case BREAK_NT:
00085                 nt_response.data[0]++;
00086                 break;
00087         case NO_LM:
00088                 data_blob_free(&lm_response);
00089                 break;
00090         case NO_NT:
00091                 data_blob_free(&nt_response);
00092                 break;
00093         }
00094 
00095         nt_status = contact_winbind_auth_crap(opt_username, opt_domain, 
00096                                               opt_workstation,
00097                                               &chall,
00098                                               &lm_response,
00099                                               &nt_response,
00100                                               flags,
00101                                               lm_key, 
00102                                               user_session_key,
00103                                               &error_string, NULL);
00104         
00105         data_blob_free(&lm_response);
00106 
00107         if (!NT_STATUS_IS_OK(nt_status)) {
00108                 d_printf("%s (0x%x)\n", 
00109                          error_string,
00110                          NT_STATUS_V(nt_status));
00111                 SAFE_FREE(error_string);
00112                 return break_which == BREAK_NT;
00113         }
00114 
00115         if (memcmp(lm_hash, lm_key, 
00116                    sizeof(lm_key)) != 0) {
00117                 DEBUG(1, ("LM Key does not match expectations!\n"));
00118                 DEBUG(1, ("lm_key:\n"));
00119                 dump_data(1, (const char *)lm_key, 8);
00120                 DEBUG(1, ("expected:\n"));
00121                 dump_data(1, (const char *)lm_hash, 8);
00122                 pass = False;
00123         }
00124 
00125         if (break_which == NO_NT) {
00126                 if (memcmp(lm_hash, user_session_key, 
00127                            8) != 0) {
00128                         DEBUG(1, ("NT Session Key does not match expectations (should be LM hash)!\n"));
00129                         DEBUG(1, ("user_session_key:\n"));
00130                         dump_data(1, (const char *)user_session_key, sizeof(user_session_key));
00131                         DEBUG(1, ("expected:\n"));
00132                         dump_data(1, (const char *)lm_hash, sizeof(lm_hash));
00133                         pass = False;
00134                 }
00135         } else {                
00136                 if (memcmp(session_key.data, user_session_key, 
00137                            sizeof(user_session_key)) != 0) {
00138                         DEBUG(1, ("NT Session Key does not match expectations!\n"));
00139                         DEBUG(1, ("user_session_key:\n"));
00140                         dump_data(1, (const char *)user_session_key, 16);
00141                         DEBUG(1, ("expected:\n"));
00142                         dump_data(1, (const char *)session_key.data, session_key.length);
00143                         pass = False;
00144                 }
00145         }
00146         return pass;
00147 }
00148 
00149 /* 
00150  * Test LM authentication, no NT response supplied
00151  */
00152 
00153 static BOOL test_lm(void) 
00154 {
00155 
00156         return test_lm_ntlm_broken(NO_NT);
00157 }
00158 
00159 /* 
00160  * Test the NTLM response only, no LM.
00161  */
00162 
00163 static BOOL test_ntlm(void) 
00164 {
00165         return test_lm_ntlm_broken(NO_LM);
00166 }
00167 
00168 /* 
00169  * Test the NTLM response only, but in the LM field.
00170  */
00171 
00172 static BOOL test_ntlm_in_lm(void) 
00173 {
00174         BOOL pass = True;
00175         NTSTATUS nt_status;
00176         uint32 flags = 0;
00177         DATA_BLOB nt_response = data_blob(NULL, 24);
00178 
00179         uchar lm_key[8];
00180         uchar lm_hash[16];
00181         uchar user_session_key[16];
00182         DATA_BLOB chall = get_challenge();
00183         char *error_string;
00184         
00185         ZERO_STRUCT(user_session_key);
00186 
00187         flags |= WBFLAG_PAM_LMKEY;
00188         flags |= WBFLAG_PAM_USER_SESSION_KEY;
00189 
00190         SMBNTencrypt(opt_password,chall.data,nt_response.data);
00191 
00192         E_deshash(opt_password, lm_hash); 
00193 
00194         nt_status = contact_winbind_auth_crap(opt_username, opt_domain, 
00195                                               opt_workstation,
00196                                               &chall,
00197                                               &nt_response,
00198                                               NULL,
00199                                               flags,
00200                                               lm_key,
00201                                               user_session_key,
00202                                               &error_string, NULL);
00203         
00204         data_blob_free(&nt_response);
00205 
00206         if (!NT_STATUS_IS_OK(nt_status)) {
00207                 d_printf("%s (0x%x)\n", 
00208                          error_string,
00209                          NT_STATUS_V(nt_status));
00210                 SAFE_FREE(error_string);
00211                 return False;
00212         }
00213 
00214         if (memcmp(lm_hash, lm_key, 
00215                    sizeof(lm_key)) != 0) {
00216                 DEBUG(1, ("LM Key does not match expectations!\n"));
00217                 DEBUG(1, ("lm_key:\n"));
00218                 dump_data(1, (const char *)lm_key, 8);
00219                 DEBUG(1, ("expected:\n"));
00220                 dump_data(1, (const char *)lm_hash, 8);
00221                 pass = False;
00222         }
00223         if (memcmp(lm_hash, user_session_key, 8) != 0) {
00224                 DEBUG(1, ("Session Key (first 8 lm hash) does not match expectations!\n"));
00225                 DEBUG(1, ("user_session_key:\n"));
00226                 dump_data(1, (const char *)user_session_key, 16);
00227                 DEBUG(1, ("expected:\n"));
00228                 dump_data(1, (const char *)lm_hash, 8);
00229                 pass = False;
00230         }
00231         return pass;
00232 }
00233 
00234 /* 
00235  * Test the NTLM response only, but in the both the NT and LM fields.
00236  */
00237 
00238 static BOOL test_ntlm_in_both(void) 
00239 {
00240         BOOL pass = True;
00241         NTSTATUS nt_status;
00242         uint32 flags = 0;
00243         DATA_BLOB nt_response = data_blob(NULL, 24);
00244         DATA_BLOB session_key = data_blob(NULL, 16);
00245 
00246         char lm_key[8];
00247         char lm_hash[16];
00248         char user_session_key[16];
00249         char nt_hash[16];
00250         DATA_BLOB chall = get_challenge();
00251         char *error_string;
00252         
00253         ZERO_STRUCT(lm_key);
00254         ZERO_STRUCT(user_session_key);
00255 
00256         flags |= WBFLAG_PAM_LMKEY;
00257         flags |= WBFLAG_PAM_USER_SESSION_KEY;
00258 
00259         SMBNTencrypt(opt_password,chall.data,nt_response.data);
00260         E_md4hash(opt_password, (unsigned char *)nt_hash);
00261         SMBsesskeygen_ntv1((const unsigned char *)nt_hash, NULL, session_key.data);
00262 
00263         E_deshash(opt_password, (unsigned char *)lm_hash); 
00264 
00265         nt_status = contact_winbind_auth_crap(opt_username, opt_domain, 
00266                                               opt_workstation,
00267                                               &chall,
00268                                               &nt_response,
00269                                               &nt_response,
00270                                               flags,
00271                                               (unsigned char *)lm_key,
00272                                               (unsigned char *)user_session_key,
00273                                               &error_string, NULL);
00274         
00275         data_blob_free(&nt_response);
00276 
00277         if (!NT_STATUS_IS_OK(nt_status)) {
00278                 d_printf("%s (0x%x)\n", 
00279                          error_string,
00280                          NT_STATUS_V(nt_status));
00281                 SAFE_FREE(error_string);
00282                 return False;
00283         }
00284 
00285         if (memcmp(lm_hash, lm_key, 
00286                    sizeof(lm_key)) != 0) {
00287                 DEBUG(1, ("LM Key does not match expectations!\n"));
00288                 DEBUG(1, ("lm_key:\n"));
00289                 dump_data(1, lm_key, 8);
00290                 DEBUG(1, ("expected:\n"));
00291                 dump_data(1, lm_hash, 8);
00292                 pass = False;
00293         }
00294         if (memcmp(session_key.data, user_session_key, 
00295                    sizeof(user_session_key)) != 0) {
00296                 DEBUG(1, ("NT Session Key does not match expectations!\n"));
00297                 DEBUG(1, ("user_session_key:\n"));
00298                 dump_data(1, user_session_key, 16);
00299                 DEBUG(1, ("expected:\n"));
00300                 dump_data(1, (const char *)session_key.data, session_key.length);
00301                 pass = False;
00302         }
00303 
00304 
00305         return pass;
00306 }
00307 
00308 /* 
00309  * Test the NTLMv2 and LMv2 responses
00310  */
00311 
00312 static BOOL test_lmv2_ntlmv2_broken(enum ntlm_break break_which) 
00313 {
00314         BOOL pass = True;
00315         NTSTATUS nt_status;
00316         uint32 flags = 0;
00317         DATA_BLOB ntlmv2_response = data_blob(NULL, 0);
00318         DATA_BLOB lmv2_response = data_blob(NULL, 0);
00319         DATA_BLOB ntlmv2_session_key = data_blob(NULL, 0);
00320         DATA_BLOB names_blob = NTLMv2_generate_names_blob(get_winbind_netbios_name(), get_winbind_domain());
00321 
00322         uchar user_session_key[16];
00323         DATA_BLOB chall = get_challenge();
00324         char *error_string;
00325 
00326         ZERO_STRUCT(user_session_key);
00327         
00328         flags |= WBFLAG_PAM_USER_SESSION_KEY;
00329 
00330         if (!SMBNTLMv2encrypt(opt_username, opt_domain, opt_password, &chall,
00331                               &names_blob,
00332                               &lmv2_response, &ntlmv2_response, 
00333                               &ntlmv2_session_key)) {
00334                 data_blob_free(&names_blob);
00335                 return False;
00336         }
00337         data_blob_free(&names_blob);
00338 
00339         switch (break_which) {
00340         case BREAK_NONE:
00341                 break;
00342         case BREAK_LM:
00343                 lmv2_response.data[0]++;
00344                 break;
00345         case BREAK_NT:
00346                 ntlmv2_response.data[0]++;
00347                 break;
00348         case NO_LM:
00349                 data_blob_free(&lmv2_response);
00350                 break;
00351         case NO_NT:
00352                 data_blob_free(&ntlmv2_response);
00353                 break;
00354         }
00355 
00356         nt_status = contact_winbind_auth_crap(opt_username, opt_domain, 
00357                                               opt_workstation,
00358                                               &chall,
00359                                               &lmv2_response,
00360                                               &ntlmv2_response,
00361                                               flags,
00362                                               NULL, 
00363                                               user_session_key,
00364                                               &error_string, NULL);
00365         
00366         data_blob_free(&lmv2_response);
00367         data_blob_free(&ntlmv2_response);
00368 
00369         if (!NT_STATUS_IS_OK(nt_status)) {
00370                 d_printf("%s (0x%x)\n", 
00371                          error_string,
00372                          NT_STATUS_V(nt_status));
00373                 SAFE_FREE(error_string);
00374                 return break_which == BREAK_NT;
00375         }
00376 
00377         if (break_which != NO_NT && break_which != BREAK_NT && memcmp(ntlmv2_session_key.data, user_session_key, 
00378                    sizeof(user_session_key)) != 0) {
00379                 DEBUG(1, ("USER (NTLMv2) Session Key does not match expectations!\n"));
00380                 DEBUG(1, ("user_session_key:\n"));
00381                 dump_data(1, (const char *)user_session_key, 16);
00382                 DEBUG(1, ("expected:\n"));
00383                 dump_data(1, (const char *)ntlmv2_session_key.data, ntlmv2_session_key.length);
00384                 pass = False;
00385         }
00386         return pass;
00387 }
00388 
00389 /* 
00390  * Test the NTLMv2 and LMv2 responses
00391  */
00392 
00393 static BOOL test_lmv2_ntlmv2(void) 
00394 {
00395         return test_lmv2_ntlmv2_broken(BREAK_NONE);
00396 }
00397 
00398 /* 
00399  * Test the LMv2 response only
00400  */
00401 
00402 static BOOL test_lmv2(void) 
00403 {
00404         return test_lmv2_ntlmv2_broken(NO_NT);
00405 }
00406 
00407 /* 
00408  * Test the NTLMv2 response only
00409  */
00410 
00411 static BOOL test_ntlmv2(void) 
00412 {
00413         return test_lmv2_ntlmv2_broken(NO_LM);
00414 }
00415 
00416 static BOOL test_lm_ntlm(void) 
00417 {
00418         return test_lm_ntlm_broken(BREAK_NONE);
00419 }
00420 
00421 static BOOL test_ntlm_lm_broken(void) 
00422 {
00423         return test_lm_ntlm_broken(BREAK_LM);
00424 }
00425 
00426 static BOOL test_ntlm_ntlm_broken(void) 
00427 {
00428         return test_lm_ntlm_broken(BREAK_NT);
00429 }
00430 
00431 static BOOL test_ntlmv2_lmv2_broken(void) 
00432 {
00433         return test_lmv2_ntlmv2_broken(BREAK_LM);
00434 }
00435 
00436 static BOOL test_ntlmv2_ntlmv2_broken(void) 
00437 {
00438         return test_lmv2_ntlmv2_broken(BREAK_NT);
00439 }
00440 
00441 static BOOL test_plaintext(enum ntlm_break break_which)
00442 {
00443         NTSTATUS nt_status;
00444         uint32 flags = 0;
00445         DATA_BLOB nt_response = data_blob(NULL, 0);
00446         DATA_BLOB lm_response = data_blob(NULL, 0);
00447         char *password;
00448         smb_ucs2_t *nt_response_ucs2;
00449 
00450         uchar user_session_key[16];
00451         uchar lm_key[16];
00452         static const uchar zeros[8] = { 0, };
00453         DATA_BLOB chall = data_blob(zeros, sizeof(zeros));
00454         char *error_string;
00455 
00456         ZERO_STRUCT(user_session_key);
00457         
00458         flags |= WBFLAG_PAM_LMKEY;
00459         flags |= WBFLAG_PAM_USER_SESSION_KEY;
00460 
00461         if ((push_ucs2_allocate(&nt_response_ucs2, opt_password)) == -1) {
00462                 DEBUG(0, ("push_ucs2_allocate failed!\n"));
00463                 exit(1);
00464         }
00465 
00466         nt_response.data = (unsigned char *)nt_response_ucs2;
00467         nt_response.length = strlen_w(nt_response_ucs2)*sizeof(smb_ucs2_t);
00468 
00469         if ((password = strdup_upper(opt_password)) == NULL) {
00470                 DEBUG(0, ("strdup_upper failed!\n"));
00471                 exit(1);
00472         }
00473 
00474         if ((convert_string_allocate(NULL, CH_UNIX, 
00475                                      CH_DOS, password,
00476                                      strlen(password)+1, 
00477                                      &lm_response.data,True)) == -1) {
00478                 DEBUG(0, ("convert_string_allocate failed!\n"));
00479                 exit(1);
00480         }
00481 
00482         SAFE_FREE(password);
00483 
00484         lm_response.length = strlen((const char *)lm_response.data);
00485 
00486         switch (break_which) {
00487         case BREAK_NONE:
00488                 break;
00489         case BREAK_LM:
00490                 lm_response.data[0]++;
00491                 break;
00492         case BREAK_NT:
00493                 nt_response.data[0]++;
00494                 break;
00495         case NO_LM:
00496                 SAFE_FREE(lm_response.data);
00497                 lm_response.length = 0;
00498                 break;
00499         case NO_NT:
00500                 SAFE_FREE(nt_response.data);
00501                 nt_response.length = 0;
00502                 break;
00503         }
00504 
00505         nt_status = contact_winbind_auth_crap(opt_username, opt_domain, 
00506                                               opt_workstation,
00507                                               &chall,
00508                                               &lm_response,
00509                                               &nt_response,
00510                                               flags,
00511                                               lm_key,
00512                                               user_session_key,
00513                                               &error_string, NULL);
00514         
00515         SAFE_FREE(nt_response.data);
00516         SAFE_FREE(lm_response.data);
00517         data_blob_free(&chall);
00518 
00519         if (!NT_STATUS_IS_OK(nt_status)) {
00520                 d_printf("%s (0x%x)\n", 
00521                          error_string,
00522                          NT_STATUS_V(nt_status));
00523                 SAFE_FREE(error_string);
00524                 return break_which == BREAK_NT;
00525         }
00526 
00527         return break_which != BREAK_NT;
00528 }
00529 
00530 static BOOL test_plaintext_none_broken(void) {
00531         return test_plaintext(BREAK_NONE);
00532 }
00533 
00534 static BOOL test_plaintext_lm_broken(void) {
00535         return test_plaintext(BREAK_LM);
00536 }
00537 
00538 static BOOL test_plaintext_nt_broken(void) {
00539         return test_plaintext(BREAK_NT);
00540 }
00541 
00542 static BOOL test_plaintext_nt_only(void) {
00543         return test_plaintext(NO_LM);
00544 }
00545 
00546 static BOOL test_plaintext_lm_only(void) {
00547         return test_plaintext(NO_NT);
00548 }
00549 
00550 /* 
00551    Tests:
00552    
00553    - LM only
00554    - NT and LM             
00555    - NT
00556    - NT in LM field
00557    - NT in both fields
00558    - NTLMv2
00559    - NTLMv2 and LMv2
00560    - LMv2
00561    - plaintext tests (in challenge-response feilds)
00562   
00563    check we get the correct session key in each case
00564    check what values we get for the LM session key
00565    
00566 */
00567 
00568 static const struct ntlm_tests {
00569         BOOL (*fn)(void);
00570         const char *name;
00571 } test_table[] = {
00572         {test_lm, "LM"},
00573         {test_lm_ntlm, "LM and NTLM"},
00574         {test_ntlm, "NTLM"},
00575         {test_ntlm_in_lm, "NTLM in LM"},
00576         {test_ntlm_in_both, "NTLM in both"},
00577         {test_ntlmv2, "NTLMv2"},
00578         {test_lmv2_ntlmv2, "NTLMv2 and LMv2"},
00579         {test_lmv2, "LMv2"},
00580         {test_ntlmv2_lmv2_broken, "NTLMv2 and LMv2, LMv2 broken"},
00581         {test_ntlmv2_ntlmv2_broken, "NTLMv2 and LMv2, NTLMv2 broken"},
00582         {test_ntlm_lm_broken, "NTLM and LM, LM broken"},
00583         {test_ntlm_ntlm_broken, "NTLM and LM, NTLM broken"},
00584         {test_plaintext_none_broken, "Plaintext"},
00585         {test_plaintext_lm_broken, "Plaintext LM broken"},
00586         {test_plaintext_nt_broken, "Plaintext NT broken"},
00587         {test_plaintext_nt_only, "Plaintext NT only"},
00588         {test_plaintext_lm_only, "Plaintext LM only"},
00589         {NULL, NULL}
00590 };
00591 
00592 BOOL diagnose_ntlm_auth(void)
00593 {
00594         unsigned int i;
00595         BOOL pass = True;
00596 
00597         for (i=0; test_table[i].fn; i++) {
00598                 if (!test_table[i].fn()) {
00599                         DEBUG(1, ("Test %s failed!\n", test_table[i].name));
00600                         pass = False;
00601                 }
00602         }
00603 
00604         return pass;
00605 }
00606 

Sambaに対してSat Aug 29 21:23:30 2009に生成されました。  doxygen 1.4.7