LCOV - code coverage report
Current view: top level - auth/credentials - credentials_ntlm.c (source / functions) Hit Total Coverage
Test: coverage report for abartlet/fix-coverage dd10fb34 Lines: 148 242 61.2 %
Date: 2021-09-23 10:06:22 Functions: 5 7 71.4 %

          Line data    Source code
       1             : /* 
       2             :    Unix SMB/CIFS implementation.
       3             : 
       4             :    User credentials handling
       5             : 
       6             :    Copyright (C) Andrew Tridgell      2001
       7             :    Copyright (C) Andrew Bartlett <abartlet@samba.org> 2001-2005
       8             :    Copyright (C) Stefan Metzmacher 2005
       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 "librpc/gen_ndr/samr.h" /* for struct samrPassword */
      26             : #include "../lib/crypto/crypto.h"
      27             : #include "libcli/auth/libcli_auth.h"
      28             : #include "auth/credentials/credentials.h"
      29             : #include "auth/credentials/credentials_internal.h"
      30             : 
      31             : #include "lib/crypto/gnutls_helpers.h"
      32             : #include <gnutls/gnutls.h>
      33             : #include <gnutls/crypto.h>
      34             : 
      35             : #undef DBGC_CLASS
      36             : #define DBGC_CLASS DBGC_AUTH
      37             : 
      38       32135 : _PUBLIC_ NTSTATUS cli_credentials_get_ntlm_response(struct cli_credentials *cred, TALLOC_CTX *mem_ctx, 
      39             :                                            int *flags,
      40             :                                            DATA_BLOB challenge,
      41             :                                            const NTTIME *server_timestamp,
      42             :                                            DATA_BLOB target_info,
      43             :                                            DATA_BLOB *_lm_response, DATA_BLOB *_nt_response, 
      44             :                                            DATA_BLOB *_lm_session_key, DATA_BLOB *_session_key) 
      45             : {
      46       32135 :         TALLOC_CTX *frame = talloc_stackframe();
      47       32135 :         const char *user = NULL;
      48       32135 :         const char *domain = NULL;
      49       32135 :         DATA_BLOB lm_response = data_blob_null;
      50       32135 :         DATA_BLOB nt_response = data_blob_null;
      51       32135 :         DATA_BLOB lm_session_key = data_blob_null;
      52       32135 :         DATA_BLOB session_key = data_blob_null;
      53       32135 :         const struct samr_Password *nt_hash = NULL;
      54             :         int rc;
      55             : 
      56       32135 :         if (cred->kerberos_state == CRED_USE_KERBEROS_REQUIRED) {
      57           0 :                 TALLOC_FREE(frame);
      58           0 :                 return NT_STATUS_INVALID_PARAMETER_MIX;
      59             :         }
      60             : 
      61             :         /* We may already have an NTLM response we prepared earlier.
      62             :          * This is used for NTLM pass-though authentication */
      63       32135 :         if (cred->nt_response.data || cred->lm_response.data) {
      64           0 :                 if (cred->nt_response.length != 0) {
      65           0 :                         nt_response = data_blob_dup_talloc(frame,
      66             :                                                            cred->nt_response);
      67           0 :                         if (nt_response.data == NULL) {
      68           0 :                                 TALLOC_FREE(frame);
      69           0 :                                 return NT_STATUS_NO_MEMORY;
      70             :                         }
      71             :                 }
      72           0 :                 if (cred->lm_response.length != 0) {
      73           0 :                         lm_response = data_blob_dup_talloc(frame,
      74             :                                                            cred->lm_response);
      75           0 :                         if (lm_response.data == NULL) {
      76           0 :                                 TALLOC_FREE(frame);
      77           0 :                                 return NT_STATUS_NO_MEMORY;
      78             :                         }
      79             :                 }
      80             : 
      81           0 :                 if (cred->lm_response.data == NULL) {
      82           0 :                         *flags = *flags & ~CLI_CRED_LANMAN_AUTH;
      83             :                 }
      84           0 :                 goto done;
      85             :         }
      86             : 
      87       32135 :         nt_hash = cli_credentials_get_nt_hash(cred, frame);
      88             : 
      89       32135 :         cli_credentials_get_ntlm_username_domain(cred, frame, &user, &domain);
      90       32135 :         if (user == NULL) {
      91           0 :                 TALLOC_FREE(frame);
      92           0 :                 return NT_STATUS_NO_MEMORY;
      93             :         }
      94       32135 :         if (domain == NULL) {
      95           0 :                 TALLOC_FREE(frame);
      96           0 :                 return NT_STATUS_NO_MEMORY;
      97             :         }
      98             : 
      99             :         /* If we are sending a username@realm login (see function
     100             :          * above), then we will not send LM, it will not be
     101             :          * accepted */
     102       32135 :         if (cred->principal_obtained > cred->username_obtained) {
     103           0 :                 *flags = *flags & ~CLI_CRED_LANMAN_AUTH;
     104             :         }
     105             : 
     106             :         /* Likewise if we are a machine account (avoid protocol downgrade attacks) */
     107       32135 :         if (cred->machine_account) {
     108         126 :                 *flags = *flags & ~CLI_CRED_LANMAN_AUTH;
     109             :         }
     110             : 
     111       32135 :         if (!nt_hash) {
     112             :                 /* do nothing - blobs are zero length */
     113             : 
     114             :                 /* session key is all zeros */
     115         942 :                 session_key = data_blob_talloc_zero(frame, 16);
     116         942 :                 if (session_key.data == NULL) {
     117           0 :                         TALLOC_FREE(frame);
     118           0 :                         return NT_STATUS_NO_MEMORY;
     119             :                 }
     120         942 :                 lm_session_key = data_blob_talloc_zero(frame, 16);
     121         942 :                 if (lm_session_key.data == NULL) {
     122           0 :                         TALLOC_FREE(frame);
     123           0 :                         return NT_STATUS_NO_MEMORY;
     124             :                 }
     125             : 
     126             :                 /* not doing NTLM2 without a password */
     127         942 :                 *flags &= ~CLI_CRED_NTLM2;
     128       31193 :         } else if (*flags & CLI_CRED_NTLMv2_AUTH) {
     129             : 
     130       30328 :                 if (!target_info.length) {
     131             :                         /* be lazy, match win2k - we can't do NTLMv2 without it */
     132           0 :                         DEBUG(1, ("Server did not provide 'target information', required for NTLMv2\n"));
     133           0 :                         TALLOC_FREE(frame);
     134           0 :                         return NT_STATUS_INVALID_PARAMETER;
     135             :                 }
     136             : 
     137             :                 /* TODO: if the remote server is standalone, then we should replace 'domain'
     138             :                    with the server name as supplied above */
     139             :                 
     140       30328 :                 if (!SMBNTLMv2encrypt_hash(frame,
     141             :                                            user, 
     142             :                                            domain, 
     143       30328 :                                            nt_hash->hash, &challenge, 
     144             :                                            server_timestamp, &target_info,
     145             :                                            &lm_response, &nt_response, 
     146             :                                            NULL, &session_key)) {
     147           0 :                         TALLOC_FREE(frame);
     148           0 :                         return NT_STATUS_NO_MEMORY;
     149             :                 }
     150             : 
     151             :                 /* LM Key is incompatible... */
     152       30328 :                 *flags &= ~CLI_CRED_LANMAN_AUTH;
     153       30328 :                 if (lm_response.length != 0) {
     154             :                         /*
     155             :                          * We should not expose the lm key.
     156             :                          */
     157       30328 :                         memset(lm_response.data, 0, lm_response.length);
     158             :                 }
     159         865 :         } else if (*flags & CLI_CRED_NTLM2) {
     160             :                 uint8_t session_nonce[16];
     161             :                 uint8_t session_nonce_hash[16];
     162             :                 uint8_t user_session_key[16];
     163             : 
     164         170 :                 lm_response = data_blob_talloc_zero(frame, 24);
     165         170 :                 if (lm_response.data == NULL) {
     166           0 :                         TALLOC_FREE(frame);
     167           0 :                         return NT_STATUS_NO_MEMORY;
     168             :                 }
     169         170 :                 generate_random_buffer(lm_response.data, 8);
     170             : 
     171         170 :                 memcpy(session_nonce, challenge.data, 8);
     172         170 :                 memcpy(&session_nonce[8], lm_response.data, 8);
     173             : 
     174         170 :                 rc = gnutls_hash_fast(GNUTLS_DIG_MD5,
     175             :                                       session_nonce,
     176             :                                       sizeof(session_nonce),
     177             :                                       session_nonce_hash);
     178         170 :                 if (rc < 0) {
     179           0 :                         return gnutls_error_to_ntstatus(rc, NT_STATUS_NTLM_BLOCKED);
     180             :                 }
     181             : 
     182         170 :                 DEBUG(5, ("NTLMSSP challenge set by NTLM2\n"));
     183         170 :                 DEBUG(5, ("challenge is: \n"));
     184         170 :                 dump_data(5, session_nonce_hash, 8);
     185             : 
     186         170 :                 nt_response = data_blob_talloc_zero(frame, 24);
     187         170 :                 if (nt_response.data == NULL) {
     188           0 :                         TALLOC_FREE(frame);
     189           0 :                         return NT_STATUS_NO_MEMORY;
     190             :                 }
     191         170 :                 rc = SMBOWFencrypt(nt_hash->hash,
     192             :                                    session_nonce_hash,
     193             :                                    nt_response.data);
     194         170 :                 if (rc != 0) {
     195           0 :                         TALLOC_FREE(frame);
     196           0 :                         return gnutls_error_to_ntstatus(rc, NT_STATUS_ACCESS_DISABLED_BY_POLICY_OTHER);
     197             :                 }
     198             : 
     199         170 :                 ZERO_ARRAY(session_nonce_hash);
     200             : 
     201         170 :                 session_key = data_blob_talloc_zero(frame, 16);
     202         170 :                 if (session_key.data == NULL) {
     203           0 :                         TALLOC_FREE(frame);
     204           0 :                         return NT_STATUS_NO_MEMORY;
     205             :                 }
     206             : 
     207         170 :                 SMBsesskeygen_ntv1(nt_hash->hash, user_session_key);
     208             : 
     209         170 :                 rc = gnutls_hmac_fast(GNUTLS_MAC_MD5,
     210             :                                       user_session_key,
     211             :                                       sizeof(user_session_key),
     212             :                                       session_nonce,
     213             :                                       sizeof(session_nonce),
     214         170 :                                       session_key.data);
     215         170 :                 if (rc < 0) {
     216           0 :                         return gnutls_error_to_ntstatus(rc, NT_STATUS_NTLM_BLOCKED);
     217             :                 }
     218             : 
     219         170 :                 ZERO_ARRAY(user_session_key);
     220             : 
     221         170 :                 dump_data_pw("NTLM2 session key:\n", session_key.data, session_key.length);
     222             : 
     223             :                 /* LM Key is incompatible... */
     224         170 :                 *flags &= ~CLI_CRED_LANMAN_AUTH;
     225             :         } else {
     226         695 :                 const char *password = cli_credentials_get_password(cred);
     227             :                 uint8_t lm_hash[16];
     228         695 :                 bool do_lm = false;
     229             : 
     230         695 :                 nt_response = data_blob_talloc_zero(frame, 24);
     231         695 :                 if (nt_response.data == NULL) {
     232           0 :                         TALLOC_FREE(frame);
     233           0 :                         return NT_STATUS_NO_MEMORY;
     234             :                 }
     235         695 :                 rc = SMBOWFencrypt(nt_hash->hash, challenge.data,
     236             :                                    nt_response.data);
     237         695 :                 if (rc != 0) {
     238           0 :                         TALLOC_FREE(frame);
     239           0 :                         return gnutls_error_to_ntstatus(rc, NT_STATUS_ACCESS_DISABLED_BY_POLICY_OTHER);
     240             :                 }
     241             : 
     242         695 :                 session_key = data_blob_talloc_zero(frame, 16);
     243         695 :                 if (session_key.data == NULL) {
     244           0 :                         TALLOC_FREE(frame);
     245           0 :                         return NT_STATUS_NO_MEMORY;
     246             :                 }
     247         695 :                 SMBsesskeygen_ntv1(nt_hash->hash, session_key.data);
     248         695 :                 dump_data_pw("NT session key:\n", session_key.data, session_key.length);
     249             : 
     250             :                 /* lanman auth is insecure, it may be disabled.  
     251             :                    We may also not have a password */
     252             : 
     253         695 :                 if (password != NULL) {
     254         695 :                         do_lm = E_deshash(password, lm_hash);
     255             :                 }
     256             : 
     257         695 :                 if (*flags & CLI_CRED_LANMAN_AUTH && do_lm) {
     258         676 :                         lm_response = data_blob_talloc_zero(frame, 24);
     259         676 :                         if (lm_response.data == NULL) {
     260           0 :                                 ZERO_STRUCT(lm_hash);
     261           0 :                                 TALLOC_FREE(frame);
     262           0 :                                 return NT_STATUS_NO_MEMORY;
     263             :                         }
     264             : 
     265        1343 :                         rc = SMBencrypt_hash(lm_hash,
     266         676 :                                              challenge.data,
     267             :                                              lm_response.data);
     268        1343 :                         if (rc != 0) {
     269           0 :                                 ZERO_STRUCT(lm_hash);
     270           0 :                                 TALLOC_FREE(frame);
     271           0 :                                 return gnutls_error_to_ntstatus(rc, NT_STATUS_ACCESS_DISABLED_BY_POLICY_OTHER);
     272             :                         }
     273             :                 } else {
     274             :                         /* just copy the nt_response */
     275          19 :                         lm_response = data_blob_dup_talloc(frame, nt_response);
     276          19 :                         if (lm_response.data == NULL) {
     277           0 :                                 ZERO_STRUCT(lm_hash);
     278           0 :                                 TALLOC_FREE(frame);
     279           0 :                                 return NT_STATUS_NO_MEMORY;
     280             :                         }
     281             :                 }
     282             : 
     283         695 :                 if (do_lm) {
     284         689 :                         lm_session_key = data_blob_talloc_zero(frame, 16);
     285         689 :                         if (lm_session_key.data == NULL) {
     286           0 :                                 ZERO_STRUCT(lm_hash);
     287           0 :                                 TALLOC_FREE(frame);
     288           0 :                                 return NT_STATUS_NO_MEMORY;
     289             :                         }
     290         698 :                         memcpy(lm_session_key.data, lm_hash, 8);
     291             : 
     292         689 :                         if (!(*flags & CLI_CRED_NTLM_AUTH)) {
     293          26 :                                 memcpy(session_key.data, lm_session_key.data, 16);
     294             :                         }
     295         689 :                         ZERO_STRUCT(lm_hash);
     296             :                 }
     297             :         }
     298             : 
     299       32135 : done:
     300       32135 :         if (_lm_response != NULL) {
     301       32135 :                 talloc_steal(mem_ctx, lm_response.data);
     302       32135 :                 *_lm_response = lm_response;
     303             :         } else {
     304           0 :                 data_blob_clear(&lm_response);
     305             :         }
     306       32135 :         if (_nt_response != NULL) {
     307       32131 :                 talloc_steal(mem_ctx, nt_response.data);
     308       32131 :                 *_nt_response = nt_response;
     309             :         } else {
     310           4 :                 data_blob_clear(&nt_response);
     311             :         }
     312       32135 :         if (_lm_session_key != NULL) {
     313       29414 :                 talloc_steal(mem_ctx, lm_session_key.data);
     314       29414 :                 *_lm_session_key = lm_session_key;
     315             :         } else {
     316        2721 :                 data_blob_clear(&lm_session_key);
     317             :         }
     318       32135 :         if (_session_key != NULL) {
     319       29437 :                 talloc_steal(mem_ctx, session_key.data);
     320       29437 :                 *_session_key = session_key;
     321             :         } else {
     322        2698 :                 data_blob_clear(&session_key);
     323             :         }
     324       32135 :         TALLOC_FREE(frame);
     325       32135 :         return NT_STATUS_OK;
     326             : }
     327             : 
     328             : /*
     329             :  * Set a utf16 password on the credentials context, including an indication
     330             :  * of 'how' the password was obtained
     331             :  *
     332             :  * This is required because the nt_hash is calculated over the raw utf16 blob,
     333             :  * which might not be completely valid utf16, which means the conversion
     334             :  * from CH_UTF16MUNGED to CH_UTF8 might loose information.
     335             :  */
     336         127 : _PUBLIC_ bool cli_credentials_set_utf16_password(struct cli_credentials *cred,
     337             :                                                  const DATA_BLOB *password_utf16,
     338             :                                                  enum credentials_obtained obtained)
     339             : {
     340         127 :         cred->password_will_be_nt_hash = false;
     341             : 
     342         127 :         if (password_utf16 == NULL) {
     343           0 :                 return cli_credentials_set_password(cred, NULL, obtained);
     344             :         }
     345             : 
     346         127 :         if (obtained >= cred->password_obtained) {
     347         127 :                 struct samr_Password *nt_hash = NULL;
     348         127 :                 char *password_talloc = NULL;
     349         127 :                 size_t password_len = 0;
     350             :                 bool ok;
     351             : 
     352         127 :                 nt_hash = talloc(cred, struct samr_Password);
     353         127 :                 if (nt_hash == NULL) {
     354           0 :                         return false;
     355             :                 }
     356             : 
     357         194 :                 ok = convert_string_talloc(cred,
     358             :                                            CH_UTF16MUNGED, CH_UTF8,
     359         127 :                                            password_utf16->data,
     360          60 :                                            password_utf16->length,
     361             :                                            (void *)&password_talloc,
     362             :                                            &password_len);
     363         127 :                 if (!ok) {
     364           0 :                         TALLOC_FREE(nt_hash);
     365           0 :                         return false;
     366             :                 }
     367             : 
     368         127 :                 ok = cli_credentials_set_password(cred, password_talloc, obtained);
     369         127 :                 TALLOC_FREE(password_talloc);
     370         127 :                 if (!ok) {
     371           0 :                         TALLOC_FREE(nt_hash);
     372           0 :                         return false;
     373             :                 }
     374             : 
     375         127 :                 mdfour(nt_hash->hash, password_utf16->data, password_utf16->length);
     376         127 :                 cred->nt_hash = nt_hash;
     377         127 :                 return true;
     378             :         }
     379             : 
     380           0 :         return false;
     381             : }
     382             : 
     383             : /*
     384             :  * Set a old utf16 password on the credentials context.
     385             :  *
     386             :  * This is required because the nt_hash is calculated over the raw utf16 blob,
     387             :  * which might not be completely valid utf16, which means the conversion
     388             :  * from CH_UTF16MUNGED to CH_UTF8 might loose information.
     389             :  */
     390           1 : _PUBLIC_ bool cli_credentials_set_old_utf16_password(struct cli_credentials *cred,
     391             :                                                      const DATA_BLOB *password_utf16)
     392             : {
     393           1 :         struct samr_Password *nt_hash = NULL;
     394           1 :         char *password_talloc = NULL;
     395           1 :         size_t password_len = 0;
     396             :         bool ok;
     397             : 
     398           1 :         if (password_utf16 == NULL) {
     399           0 :                 return cli_credentials_set_old_password(cred, NULL, CRED_SPECIFIED);
     400             :         }
     401             : 
     402           1 :         nt_hash = talloc(cred, struct samr_Password);
     403           1 :         if (nt_hash == NULL) {
     404           0 :                 return false;
     405             :         }
     406             : 
     407           2 :         ok = convert_string_talloc(cred,
     408             :                                    CH_UTF16MUNGED, CH_UTF8,
     409           1 :                                    password_utf16->data,
     410           0 :                                    password_utf16->length,
     411             :                                    (void *)&password_talloc,
     412             :                                    &password_len);
     413           1 :         if (!ok) {
     414           0 :                 TALLOC_FREE(nt_hash);
     415           0 :                 return false;
     416             :         }
     417             : 
     418           1 :         ok = cli_credentials_set_old_password(cred, password_talloc, CRED_SPECIFIED);
     419           1 :         TALLOC_FREE(password_talloc);
     420           1 :         if (!ok) {
     421           0 :                 TALLOC_FREE(nt_hash);
     422           0 :                 return false;
     423             :         }
     424             : 
     425           1 :         mdfour(nt_hash->hash, password_utf16->data, password_utf16->length);
     426           1 :         cred->old_nt_hash = nt_hash;
     427           1 :         return true;
     428             : }
     429             : 
     430           3 : _PUBLIC_ void cli_credentials_set_password_will_be_nt_hash(struct cli_credentials *cred,
     431             :                                                            bool val)
     432             : {
     433             :         /*
     434             :          * We set this here and the next cli_credentials_set_password()
     435             :          * that resets the password or password callback
     436             :          * will pick this up.
     437             :          *
     438             :          * cli_credentials_set_nt_hash() and
     439             :          * cli_credentials_set_utf16_password() will reset this
     440             :          * to false.
     441             :          */
     442           3 :         cred->password_will_be_nt_hash = val;
     443           3 : }
     444             : 
     445          42 : _PUBLIC_ bool cli_credentials_set_nt_hash(struct cli_credentials *cred,
     446             :                                  const struct samr_Password *nt_hash, 
     447             :                                  enum credentials_obtained obtained)
     448             : {
     449          42 :         cred->password_will_be_nt_hash = false;
     450             : 
     451          42 :         if (obtained >= cred->password_obtained) {
     452          42 :                 cli_credentials_set_password(cred, NULL, obtained);
     453          42 :                 if (nt_hash) {
     454          42 :                         cred->nt_hash = talloc(cred, struct samr_Password);
     455          42 :                         if (cred->nt_hash == NULL) {
     456           0 :                                 return false;
     457             :                         }
     458          42 :                         *cred->nt_hash = *nt_hash;
     459             :                 } else {
     460           0 :                         cred->nt_hash = NULL;
     461             :                 }
     462          36 :                 return true;
     463             :         }
     464             : 
     465           0 :         return false;
     466             : }
     467             : 
     468           0 : _PUBLIC_ bool cli_credentials_set_old_nt_hash(struct cli_credentials *cred,
     469             :                                               const struct samr_Password *nt_hash)
     470             : {
     471           0 :         cli_credentials_set_old_password(cred, NULL, CRED_SPECIFIED);
     472           0 :         if (nt_hash) {
     473           0 :                 cred->old_nt_hash = talloc(cred, struct samr_Password);
     474           0 :                 if (cred->old_nt_hash == NULL) {
     475           0 :                         return false;
     476             :                 }
     477           0 :                 *cred->old_nt_hash = *nt_hash;
     478             :         } else {
     479           0 :                 cred->old_nt_hash = NULL;
     480             :         }
     481             : 
     482           0 :         return true;
     483             : }
     484             : 
     485           0 : _PUBLIC_ bool cli_credentials_set_ntlm_response(struct cli_credentials *cred,
     486             :                                                 const DATA_BLOB *lm_response, 
     487             :                                                 const DATA_BLOB *nt_response, 
     488             :                                                 enum credentials_obtained obtained)
     489             : {
     490           0 :         if (obtained >= cred->password_obtained) {
     491           0 :                 cli_credentials_set_password(cred, NULL, obtained);
     492           0 :                 if (nt_response) {
     493           0 :                         cred->nt_response = data_blob_talloc(cred, nt_response->data, nt_response->length);
     494           0 :                         talloc_steal(cred, cred->nt_response.data);
     495             :                 }
     496           0 :                 if (nt_response) {
     497           0 :                         cred->lm_response = data_blob_talloc(cred, lm_response->data, lm_response->length);
     498             :                 }
     499           0 :                 return true;
     500             :         }
     501             : 
     502           0 :         return false;
     503             : }
     504             : 

Generated by: LCOV version 1.13