LCOV - code coverage report
Current view: top level - src/tds - challenge.c (source / functions) Hit Total Coverage
Test: FreeTDS coverage Lines: 346 434 79.7 %
Date: 2026-11-11 18:06:03 Functions: 21 23 91.3 %

          Line data    Source code
       1             : /* FreeTDS - Library of routines accessing Sybase and Microsoft databases
       2             :  * Copyright (C) 1998-1999  Brian Bruns
       3             :  * Copyright (C) 2005-2015  Frediano Ziglio
       4             :  *
       5             :  * This library is free software; you can redistribute it and/or
       6             :  * modify it under the terms of the GNU Library General Public
       7             :  * License as published by the Free Software Foundation; either
       8             :  * version 2 of the License, or (at your option) any later version.
       9             :  *
      10             :  * This library is distributed in the hope that it will be useful,
      11             :  * but WITHOUT ANY WARRANTY; without even the implied warranty of
      12             :  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
      13             :  * Library General Public License for more details.
      14             :  *
      15             :  * You should have received a copy of the GNU Library General Public
      16             :  * License along with this library; if not, write to the
      17             :  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
      18             :  * Boston, MA 02111-1307, USA.
      19             :  */
      20             : 
      21             : #include <config.h>
      22             : 
      23             : #if HAVE_STDLIB_H
      24             : #include <stdlib.h>
      25             : #endif /* HAVE_STDLIB_H */
      26             : 
      27             : #if HAVE_STDDEF_H
      28             : #include <stddef.h>
      29             : #endif /* HAVE_STDDEF_H */
      30             : 
      31             : #include <ctype.h>
      32             : 
      33             : #if HAVE_STRING_H
      34             : #include <string.h>
      35             : #endif /* HAVE_STRING_H */
      36             : 
      37             : #include <freetds/time.h>
      38             : #include <freetds/tds.h>
      39             : #include <freetds/bytes.h>
      40             : #include <freetds/utils/string.h>
      41             : #include <freetds/tds/iconv.h>
      42             : #include <freetds/utils.h>
      43             : #include <freetds/utils/md4.h>
      44             : #include <freetds/utils/md5.h>
      45             : #include <freetds/utils/hmac_md5.h>
      46             : #include <freetds/utils/des.h>
      47             : #include <freetds/replacements.h>
      48             : #include <freetds/tds/tls.h>
      49             : 
      50             : /**
      51             :  * \ingroup libtds
      52             :  * \defgroup auth Authentication
      53             :  * Functions for handling authentication.
      54             :  */
      55             : 
      56             : /**
      57             :  * \addtogroup auth
      58             :  * @{ 
      59             :  */
      60             : 
      61             : /*
      62             :  * The following code is based on some psuedo-C code from ronald@innovation.ch
      63             :  */
      64             : 
      65             : typedef struct tds_answer
      66             : {
      67             :         unsigned char lm_resp[24];
      68             :         unsigned char nt_resp[24];
      69             :         /** NTLMv2 session base key, valid if has_session_key is set */
      70             :         unsigned char session_key[16];
      71             :         bool has_session_key;
      72             : } TDSANSWER;
      73             : 
      74             : /* NTLM negotiate flags, see MS-NLMP */
      75             : #define NTLMSSP_NEGOTIATE_UNICODE 0x00000001u
      76             : #define NTLMSSP_NEGOTIATE_SIGN 0x00000010u
      77             : #define NTLMSSP_NEGOTIATE_SEAL 0x00000020u
      78             : #define NTLMSSP_NEGOTIATE_NTLM 0x00000200u
      79             : #define NTLMSSP_NEGOTIATE_OEM_DOMAIN_SUPPLIED 0x00001000u
      80             : #define NTLMSSP_NEGOTIATE_OEM_WORKSTATION_SUPPLIED 0x00002000u
      81             : #define NTLMSSP_NEGOTIATE_LOCAL_CALL 0x00004000u
      82             : #define NTLMSSP_NEGOTIATE_ALWAYS_SIGN 0x00008000u
      83             : #define NTLMSSP_NEGOTIATE_EXTENDED_SESSIONSECURITY 0x00080000u
      84             : #define NTLMSSP_NEGOTIATE_VERSION 0x02000000u
      85             : #define NTLMSSP_NEGOTIATE_128 0x20000000u
      86             : #define NTLMSSP_NEGOTIATE_KEY_EXCH 0x40000000u
      87             : 
      88             : /* AV_PAIR identifiers, see MS-NLMP */
      89             : #define MSV_AV_EOL 0x0000
      90             : #define MSV_AV_FLAGS 0x0006
      91             : #define MSV_AV_TIMESTAMP 0x0007
      92             : #define MSV_AV_TARGET_NAME 0x0009
      93             : #define MSV_AV_CHANNEL_BINDINGS 0x000A
      94             : 
      95             : /* MsvAvFlags value, MIC is present */
      96             : #define MSV_AV_FLAG_MIC 0x00000002u
      97             : 
      98             : /* AUTHENTICATE_MESSAGE header sizes, without and with Version and MIC fields */
      99             : #define NTLM_AUTH_HEADER_LEN 64
     100             : #define NTLM_AUTH_HEADER_MIC_LEN 88
     101             : #define NTLM_AUTH_MIC_OFFSET 72
     102             : 
     103             : typedef struct
     104             : {
     105             :         uint8_t  response_type;
     106             :         uint8_t  max_response_type;
     107             :         uint16_t reserved1;
     108             :         uint32_t reserved2;
     109             :         uint64_t timestamp;
     110             :         uint8_t  challenge[8];
     111             :         uint32_t reserved3;
     112             :         /* target info block - variable length */
     113             :         uint8_t target_info[4];
     114             : } names_blob_prefix_t;
     115             : 
     116             : #define AV_PAIR_CBT_BYTES 20
     117             : 
     118             : typedef struct
     119             : {
     120             :         TDSAUTHENTICATION tds_auth;
     121             :         uint8_t cbt[16];
     122             :         bool has_cbt;
     123             :         /** service principal name, UTF-16LE */
     124             :         char *spn;
     125             :         size_t spn_len;
     126             :         /** CHALLENGE_MESSAGE received from server, used to compute MIC */
     127             :         unsigned char *challenge;
     128             :         size_t challenge_len;
     129             : } TDSNTLMAUTH;
     130             : 
     131             : static const unsigned char ntlm_id[] = "NTLMSSP";
     132             : 
     133             : static TDSRET
     134             : tds_answer_challenge(TDSSOCKET * tds,
     135             :                      TDSLOGIN * login,
     136             :                      const unsigned char *challenge,
     137             :                      uint32_t * flags,
     138             :                      const unsigned char *names_blob, int names_blob_len, TDSANSWER * answer, unsigned char **ntlm_v2_response);
     139             : static void tds_encrypt_answer(const unsigned char *hash, const unsigned char *challenge, unsigned char *answer);
     140             : static void tds_convert_key(const unsigned char *key_56, DES_KEY * ks);
     141             : 
     142             : #include "ucs2_upper.h"
     143             : 
     144             : /**
     145             :  * Convert a UTF-16 code unit to upper case, using Unicode simple case mapping
     146             :  * like Windows does.
     147             :  */
     148             : static uint16_t
     149       10334 : ucs2_upper(uint16_t c)
     150             : {
     151       10334 :         size_t low = 0, high = TDS_VECTOR_SIZE(ucs2_upper_ranges);
     152             : 
     153       10334 :         if (c < 0x80)
     154       10144 :                 return (c >= 'a' && c <= 'z') ? c - ('a' - 'A') : c;
     155             : 
     156             :         /* binary search the range containing the character */
     157        1390 :         while (low < high) {
     158        1340 :                 size_t mid = (low + high) / 2;
     159        1340 :                 const ucs2_upper_range *r = &ucs2_upper_ranges[mid];
     160             : 
     161        1340 :                 if (c < r->first) {
     162             :                         high = mid;
     163         650 :                 } else if (c > r->last) {
     164         510 :                         low = mid + 1;
     165             :                 } else {
     166             :                         /* delta 0xffff (-1) ranges contain every other character */
     167         140 :                         if (r->delta != 0xffff || ((c - r->first) & 1) == 0)
     168         140 :                                 return (uint16_t) (c + r->delta);
     169             :                         return c;
     170             :                 }
     171             :         }
     172             :         return c;
     173             : }
     174             : 
     175             : /**
     176             :  * Convert a UTF-16LE string to upper case.
     177             :  * Surrogates are not changed, characters outside the BMP have no simple mapping
     178             :  * to upper case in Windows.
     179             :  */
     180             : static void
     181             : ucs2le_to_upper(char *buf, size_t len)
     182             : {
     183          10 :         unsigned char *p = (unsigned char *) buf;
     184             : 
     185       10134 :         for (; len >= 2; len -= 2, p += 2) {
     186       10134 :                 uint16_t c = TDS_GET_UA2LE(p);
     187             : 
     188       10134 :                 c = ucs2_upper(c);
     189       10134 :                 TDS_PUT_UA2LE(p, c);
     190             :         }
     191             : }
     192             : 
     193             : static size_t
     194        4668 : convert_to_usc2le_string(TDSSOCKET * tds, const char *s, size_t len, char *out)
     195             : {
     196             :         const char *ib;
     197             :         char *ob;
     198             :         size_t il, ol;
     199             : 
     200        4668 :         TDSICONV * char_conv = tds->conn->char_convs[client2ucs2];
     201             : 
     202             :         /* char_conv is only mostly const */
     203        4668 :         TDS_ERRNO_MESSAGE_FLAGS *suppress = (TDS_ERRNO_MESSAGE_FLAGS *) & char_conv->suppress;
     204             : 
     205        4668 :         if (char_conv->flags == TDS_ENCODING_MEMCPY) {
     206           0 :                 memcpy(out, s, len);
     207           0 :                 return len;
     208             :         }
     209             : 
     210             :         /* convert */
     211        4668 :         ib = s;
     212        4668 :         il = len;
     213        4668 :         ob = out;
     214        4668 :         ol = len * 2;
     215        4668 :         memset(suppress, 0, sizeof(char_conv->suppress));
     216        4668 :         if (tds_iconv(tds, char_conv, to_server, &ib, &il, &ob, &ol) == (size_t) - 1)
     217             :                 return (size_t) -1;
     218             : 
     219        4668 :         return ob - out;
     220             : }
     221             : 
     222             : static TDSRET
     223         778 : make_ntlm_hash(TDSSOCKET *tds, const char *passwd, unsigned char ntlm_hash[16])
     224             : {
     225             : /*
     226             :  * Windows limits passwords to about 128 characters; a character can take
     227             :  * up to 4 bytes in client charset (like UTF-8), so allow 4 bytes per character.
     228             :  * Conversion needs an output buffer twice the input length.
     229             :  */
     230             : #define MAX_NTLM_PASSWD_BYTES (128 * 4)
     231             :         MD4_CTX context;
     232         778 :         size_t passwd_len = 0;
     233             :         char passwd_usc2le[MAX_NTLM_PASSWD_BYTES * 2];
     234         778 :         size_t passwd_usc2le_len = 0;
     235             : 
     236         778 :         passwd_len = strlen(passwd);
     237             : 
     238         778 :         if (passwd_len > MAX_NTLM_PASSWD_BYTES)
     239           0 :                 passwd_len = MAX_NTLM_PASSWD_BYTES;
     240             : 
     241         778 :         passwd_usc2le_len = convert_to_usc2le_string(tds, passwd, passwd_len, passwd_usc2le);
     242         778 :         if (passwd_usc2le_len == (size_t) -1) {
     243             :                 memset((char *) passwd_usc2le, 0, sizeof(passwd_usc2le));
     244             :                 return TDS_FAIL;
     245             :         }
     246             : 
     247             :         /* compute NTLM hash */
     248         778 :         MD4Init(&context);
     249         778 :         MD4Update(&context, (unsigned char *) passwd_usc2le, passwd_usc2le_len);
     250         778 :         MD4Final(&context, ntlm_hash);
     251             : 
     252             :         /* with security is best be pedantic */
     253             :         memset((char *) passwd_usc2le, 0, passwd_usc2le_len);
     254             :         memset(&context, 0, sizeof(context));
     255         778 :         return TDS_SUCCESS;
     256             : }
     257             : 
     258             : 
     259             : static TDSRET
     260         778 : make_ntlm_v2_hash(TDSSOCKET * tds, const char *passwd, unsigned char ntlm_v2_hash[16])
     261             : {
     262             :         const char *user_name, *domain;
     263         778 :         size_t domain_len, user_name_len, len, buf_usc2le_len = 0;
     264             :         const char *p;
     265             : 
     266             :         unsigned char ntlm_hash[16];
     267             :         char *buf_usc2le;
     268             :         TDSRET res;
     269             : 
     270        1556 :         user_name = tds_dstr_cstr(&tds->login->user_name);
     271             : 
     272             :         /* parse domain\username */
     273         778 :         p = strchr(user_name, '\\');
     274             : 
     275         778 :         domain = user_name;
     276         778 :         domain_len = p - user_name;
     277             : 
     278         778 :         user_name = p + 1;
     279         778 :         user_name_len = strlen(user_name);
     280             : 
     281             :         /* each byte can produce at most one UTF-16 code unit */
     282         778 :         buf_usc2le = tds_new(char, (user_name_len + domain_len) * 2 + 2);
     283             : 
     284         778 :         if (!buf_usc2le)
     285             :                 return TDS_FAIL;
     286             : 
     287             :         /* user name is converted to upper case, after converting to UTF-16 */
     288         778 :         len = convert_to_usc2le_string(tds, user_name, user_name_len, buf_usc2le);
     289         778 :         if (len == (size_t) -1) {
     290           0 :                 free(buf_usc2le);
     291           0 :                 return TDS_FAIL;
     292             :         }
     293         778 :         ucs2le_to_upper(buf_usc2le, len);
     294         778 :         buf_usc2le_len = len;
     295             : 
     296             :         /* Target is supposed to be case-sensitive */
     297             : 
     298         778 :         len = convert_to_usc2le_string(tds, domain, domain_len, buf_usc2le + len);
     299         778 :         if (len == (size_t) -1) {
     300             :                 memset(buf_usc2le, 0, buf_usc2le_len);
     301           0 :                 free(buf_usc2le);
     302           0 :                 return TDS_FAIL;
     303             :         }
     304         778 :         buf_usc2le_len += len;
     305             : 
     306         778 :         res = make_ntlm_hash(tds, passwd, ntlm_hash);
     307         778 :         hmac_md5(ntlm_hash, (const unsigned char *) buf_usc2le, buf_usc2le_len, ntlm_v2_hash);
     308             : 
     309             :         /* with security is best be pedantic */
     310             :         memset(&ntlm_hash, 0, sizeof(ntlm_hash));
     311             :         memset(buf_usc2le, 0, buf_usc2le_len);
     312         778 :         free(buf_usc2le);
     313         778 :         return res;
     314             : }
     315             : 
     316             : 
     317             : /*
     318             :  * hash - The NTLMv2 Hash.
     319             :  * client_data - The client data (blob or client nonce).
     320             :  * challenge - The server challenge from the Type 2 message.
     321             :  */
     322             : static unsigned char *
     323        1576 : make_lm_v2_response(const unsigned char ntlm_v2_hash[16],
     324             :                     const unsigned char *client_data, int client_data_len, const unsigned char challenge[8])
     325             : {
     326        1576 :         int mac_len = 16 + client_data_len;
     327             :         unsigned char *mac;
     328             : 
     329        1576 :         mac = tds_new(unsigned char, mac_len);
     330        1576 :         if (!mac)
     331             :                 return NULL;
     332             : 
     333        1576 :         memcpy(mac + 8, challenge, 8);
     334        1576 :         memcpy(mac + 16, client_data, client_data_len);
     335        1576 :         hmac_md5(ntlm_v2_hash, mac + 8, client_data_len + 8, mac);
     336             : 
     337        1576 :         return mac;
     338             : }
     339             : 
     340             : static TDSRET
     341         778 : tds_answer_challenge_ntlmv2(TDSSOCKET * tds,
     342             :                      TDSLOGIN * login,
     343             :                      const unsigned char *challenge,
     344             :                      uint32_t * flags,
     345             :                      const unsigned char *names_blob, int names_blob_len, TDSANSWER * answer, unsigned char **ntlm_v2_response)
     346             : {
     347             :         TDSRET res;
     348        1556 :         const char *passwd = tds_dstr_cstr(&login->password);
     349             : 
     350             :         /* NTLMv2 */
     351             :         unsigned char *lm_v2_response;
     352             :         unsigned char ntlm_v2_hash[16];
     353             :         const names_blob_prefix_t *names_blob_prefix;
     354             : 
     355         778 :         if (!names_blob)
     356             :                 return TDS_FAIL;
     357             : 
     358         778 :         res = make_ntlm_v2_hash(tds, passwd, ntlm_v2_hash);
     359         778 :         if (TDS_FAILED(res))
     360             :                 return res;
     361             : 
     362             :         /* LMv2 response */
     363             :         /* Take client's challenge from names_blob */
     364         778 :         names_blob_prefix = (const names_blob_prefix_t *) names_blob;
     365         778 :         lm_v2_response = make_lm_v2_response(ntlm_v2_hash, names_blob_prefix->challenge, 8, challenge);
     366         778 :         if (!lm_v2_response)
     367             :                 return TDS_FAIL;
     368         778 :         memcpy(answer->lm_resp, lm_v2_response, 24);
     369         778 :         free(lm_v2_response);
     370             : 
     371             :         /* NTLMv2 response */
     372             :         /* Size of lm_v2_response is 16 + names_blob_len */
     373         778 :         *ntlm_v2_response = make_lm_v2_response(ntlm_v2_hash, names_blob, names_blob_len, challenge);
     374         778 :         if (!*ntlm_v2_response)
     375             :                 return TDS_FAIL;
     376             : 
     377             :         /* SessionBaseKey = HMAC_MD5(ResponseKeyNT, NTProofStr), NTProofStr is the first 16 bytes of the response */
     378         778 :         hmac_md5(ntlm_v2_hash, *ntlm_v2_response, 16, answer->session_key);
     379         778 :         answer->has_session_key = true;
     380             : 
     381             :         memset(ntlm_v2_hash, 0, sizeof(ntlm_v2_hash));
     382             : 
     383             :         /* local not supported */
     384         778 :         *flags &= ~NTLMSSP_NEGOTIATE_LOCAL_CALL;
     385         778 :         return TDS_SUCCESS;
     386             : }
     387             : 
     388             : /**
     389             :  * Crypt a given password using schema required for NTLMv1 or NTLM2 authentication
     390             :  * @param passwd clear text domain password
     391             :  * @param challenge challenge data given by server
     392             :  * @param flags NTLM flags from server side
     393             :  * @param answer buffer where to store crypted password
     394             :  */
     395             : static TDSRET
     396         778 : tds_answer_challenge(TDSSOCKET * tds,
     397             :                      TDSLOGIN * login,
     398             :                      const unsigned char *challenge,
     399             :                      uint32_t * flags,
     400             :                      const unsigned char *names_blob, int names_blob_len, TDSANSWER * answer, unsigned char **ntlm_v2_response)
     401             : {
     402             : #define MAX_PW_SZ 14
     403        1556 :         const char *passwd = tds_dstr_cstr(&login->password);
     404             :         DES_KEY ks;
     405             :         unsigned char hash[24], ntlm2_challenge[16];
     406             :         TDSRET res;
     407             : 
     408         778 :         memset(answer, 0, sizeof(TDSANSWER));
     409             : 
     410         778 :         if (login->use_ntlmv2) {
     411         778 :                 return tds_answer_challenge_ntlmv2(tds, login, challenge, flags,
     412             :                                                    names_blob, names_blob_len, answer, ntlm_v2_response);
     413           0 :         } else if ((*flags & 0x80000) != 0) {
     414             :                 /* NTLM2 */
     415             :                 MD5_CTX md5_ctx;
     416             : 
     417           0 :                 tds_random_buffer(hash, 8);
     418           0 :                 memset(hash + 8, 0, 16);
     419           0 :                 memcpy(answer->lm_resp, hash, 24);
     420             : 
     421           0 :                 MD5Init(&md5_ctx);
     422           0 :                 MD5Update(&md5_ctx, challenge, 8);
     423           0 :                 MD5Update(&md5_ctx, hash, 8);
     424           0 :                 MD5Final(&md5_ctx, ntlm2_challenge);
     425           0 :                 challenge = ntlm2_challenge;
     426             :                 memset(&md5_ctx, 0, sizeof(md5_ctx));
     427           0 :         } else if (login->use_lanman) {
     428             :                 /* LM */
     429             :                 size_t len, i;
     430             :                 unsigned char passwd_buf[MAX_PW_SZ];
     431             :                 static const des_cblock magic = { 0x4B, 0x47, 0x53, 0x21, 0x40, 0x23, 0x24, 0x25 };
     432             : 
     433             :                 /* convert password to upper and pad to 14 chars */
     434           0 :                 memset(passwd_buf, 0, MAX_PW_SZ);
     435           0 :                 len = strlen(passwd);
     436           0 :                 if (len > MAX_PW_SZ)
     437           0 :                         len = MAX_PW_SZ;
     438           0 :                 for (i = 0; i < len; i++)
     439           0 :                         passwd_buf[i] = toupper((unsigned char) passwd[i]);
     440             : 
     441             :                 /* hash the first 7 characters */
     442           0 :                 tds_convert_key(passwd_buf, &ks);
     443           0 :                 tds_des_ecb_encrypt(&magic, sizeof(magic), &ks, (hash + 0));
     444             : 
     445             :                 /* hash the second 7 characters */
     446           0 :                 tds_convert_key(passwd_buf + 7, &ks);
     447           0 :                 tds_des_ecb_encrypt(&magic, sizeof(magic), &ks, (hash + 8));
     448             : 
     449           0 :                 memset(hash + 16, 0, 5);
     450             : 
     451           0 :                 tds_encrypt_answer(hash, challenge, answer->lm_resp);
     452             :                 memset(passwd_buf, 0, sizeof(passwd_buf));
     453             :         } else {
     454           0 :                 memset(answer->lm_resp, 0, sizeof(answer->lm_resp));
     455             :         }
     456           0 :         *flags = 0x8201;
     457             : 
     458             :         /* NTLM/NTLM2 response */
     459           0 :         res = make_ntlm_hash(tds, passwd, hash);
     460           0 :         memset(hash + 16, 0, 5);
     461             : 
     462           0 :         tds_encrypt_answer(hash, challenge, answer->nt_resp);
     463             : 
     464             :         /* with security is best be pedantic */
     465             :         memset(&ks, 0, sizeof(ks));
     466             :         memset(hash, 0, sizeof(hash));
     467             :         memset(ntlm2_challenge, 0, sizeof(ntlm2_challenge));
     468           0 :         return res;
     469             : }
     470             : 
     471             : 
     472             : /*
     473             : * takes a 21 byte array and treats it as 3 56-bit DES keys. The
     474             : * 8 byte plaintext is encrypted with each key and the resulting 24
     475             : * bytes are stored in the results array.
     476             : */
     477             : static void
     478           0 : tds_encrypt_answer(const unsigned char *hash, const unsigned char *challenge, unsigned char *answer)
     479             : {
     480             :         DES_KEY ks;
     481             : 
     482           0 :         tds_convert_key(hash, &ks);
     483           0 :         tds_des_ecb_encrypt(challenge, 8, &ks, answer);
     484             : 
     485           0 :         tds_convert_key(&hash[7], &ks);
     486           0 :         tds_des_ecb_encrypt(challenge, 8, &ks, &answer[8]);
     487             : 
     488           0 :         tds_convert_key(&hash[14], &ks);
     489           0 :         tds_des_ecb_encrypt(challenge, 8, &ks, &answer[16]);
     490             : 
     491             :         memset(&ks, 0, sizeof(ks));
     492           0 : }
     493             : 
     494             : 
     495             : /*
     496             : * turns a 56 bit key into the 64 bit, odd parity key and sets the key.
     497             : * The key schedule ks is also set.
     498             : */
     499             : static void
     500           0 : tds_convert_key(const unsigned char *key_56, DES_KEY * ks)
     501             : {
     502             :         des_cblock key;
     503             : 
     504           0 :         key[0] = key_56[0];
     505           0 :         key[1] = ((key_56[0] << 7) & 0xFF) | (key_56[1] >> 1);
     506           0 :         key[2] = ((key_56[1] << 6) & 0xFF) | (key_56[2] >> 2);
     507           0 :         key[3] = ((key_56[2] << 5) & 0xFF) | (key_56[3] >> 3);
     508           0 :         key[4] = ((key_56[3] << 4) & 0xFF) | (key_56[4] >> 4);
     509           0 :         key[5] = ((key_56[4] << 3) & 0xFF) | (key_56[5] >> 5);
     510           0 :         key[6] = ((key_56[5] << 2) & 0xFF) | (key_56[6] >> 6);
     511           0 :         key[7] = (key_56[6] << 1) & 0xFF;
     512             : 
     513           0 :         tds_des_set_odd_parity(key);
     514           0 :         tds_des_set_key(ks, key);
     515             : 
     516             :         memset(&key, 0, sizeof(key));
     517           0 : }
     518             : 
     519             : /**
     520             :  * RC4 encryption, used to encrypt NTLM exported session key.
     521             :  * @param key     encryption key
     522             :  * @param key_len encryption key length
     523             :  * @param in      data to encrypt
     524             :  * @param len     length of data
     525             :  * @param out     output buffer, len bytes
     526             :  */
     527             : static void
     528         788 : tds_rc4(const unsigned char *key, size_t key_len, const unsigned char *in, size_t len, unsigned char *out)
     529             : {
     530             :         unsigned char s[256], t;
     531             :         unsigned int i, j;
     532             :         size_t n;
     533             : 
     534      202516 :         for (i = 0; i < 256; ++i)
     535      201728 :                 s[i] = (unsigned char) i;
     536      201728 :         for (i = j = 0; i < 256; ++i) {
     537      201728 :                 j = (j + s[i] + key[i % key_len]) & 0xff;
     538      201728 :                 t = s[i];
     539      201728 :                 s[i] = s[j];
     540      201728 :                 s[j] = t;
     541             :         }
     542       12608 :         for (i = j = 0, n = 0; n < len; ++n) {
     543       12608 :                 i = (i + 1) & 0xff;
     544       12608 :                 j = (j + s[i]) & 0xff;
     545       12608 :                 t = s[i];
     546       12608 :                 s[i] = s[j];
     547       12608 :                 s[j] = t;
     548       12608 :                 out[n] = in[n] ^ s[(s[i] + s[j]) & 0xff];
     549             :         }
     550             :         memset(s, 0, sizeof(s));
     551         788 : }
     552             : 
     553             : /**
     554             :  * Compute NTLM message integrity code.
     555             :  * MIC = HMAC_MD5(ExportedSessionKey, NEGOTIATE_MESSAGE + CHALLENGE_MESSAGE + AUTHENTICATE_MESSAGE)
     556             :  * where AUTHENTICATE_MESSAGE has the MIC field set to zero.
     557             :  * @return false on memory error
     558             :  */
     559             : static bool
     560          10 : tds_ntlm_mic(const unsigned char key[16], const unsigned char *negotiate, size_t negotiate_len,
     561             :              const unsigned char *challenge, size_t challenge_len, const unsigned char *authenticate, size_t authenticate_len,
     562             :              unsigned char mic[16])
     563             : {
     564             :         unsigned char *buf;
     565          10 :         size_t len = negotiate_len + challenge_len + authenticate_len;
     566             : 
     567          10 :         buf = tds_new(unsigned char, len);
     568             : 
     569          10 :         if (!buf)
     570             :                 return false;
     571          10 :         memcpy(buf, negotiate, negotiate_len);
     572          10 :         memcpy(buf + negotiate_len, challenge, challenge_len);
     573          10 :         memcpy(buf + negotiate_len + challenge_len, authenticate, authenticate_len);
     574          10 :         hmac_md5(key, buf, len, mic);
     575             :         memset(buf, 0, len);
     576          10 :         free(buf);
     577          10 :         return true;
     578             : }
     579             : 
     580             : /**
     581             :  * Fill a field (length, maximum length and offset) of a NTLM message header and copy its data in the payload.
     582             :  * @param msg       message buffer
     583             :  * @param field_pos position of the field in the header
     584             :  * @param data_pos  position of data in the payload, updated
     585             :  * @param data      field data
     586             :  * @param len       field data length
     587             :  */
     588             : static void
     589        4668 : put_ntlm_field(unsigned char *msg, size_t field_pos, size_t *data_pos, const void *data, size_t len)
     590             : {
     591        4668 :         TDS_PUT_UA2LE(msg + field_pos, len);
     592        4668 :         TDS_PUT_UA2LE(msg + field_pos + 2, len);
     593        4668 :         TDS_PUT_UA4LE(msg + field_pos + 4, *data_pos);
     594        4668 :         memcpy(msg + *data_pos, data, len);
     595        4668 :         *data_pos += len;
     596        4668 : }
     597             : 
     598             : /**
     599             :  * Send AUTHENTICATE_MESSAGE.
     600             :  * @param challenge      server challenge (8 bytes)
     601             :  * @param flags          negotiate flags from server
     602             :  * @param names_blob     NTLMv2 client blob, NULL if not available
     603             :  * @param names_blob_len length of names_blob
     604             :  * @param use_mic        add message integrity code, names_blob must have MsvAvFlags with MIC bit set
     605             :  */
     606             : static TDSRET
     607         778 : tds7_send_auth(TDSSOCKET *tds, TDSNTLMAUTH *auth, const unsigned char *challenge, uint32_t flags,
     608             :                const unsigned char *names_blob, int names_blob_len, bool use_mic)
     609             : {
     610             :         TDSANSWER answer;
     611             : 
     612             :         /* FIXME: stuff duplicate in tds7_send_login */
     613             :         const char *domain;
     614             :         const char *user_name;
     615             :         const char *host_name;
     616             :         const char *p;
     617             :         char *convert_buffer;
     618             :         size_t user_name_len, host_name_len, domain_len;
     619             :         TDSRET rc;
     620             : 
     621         778 :         unsigned char *ntlm_v2_response = NULL;
     622         778 :         unsigned int ntlm_response_len = 24;
     623         778 :         const unsigned int lm_response_len = 24;
     624         778 :         unsigned int session_key_len = 0;
     625             :         unsigned char exported_key[16], encrypted_key[16];
     626             :         unsigned char *msg;
     627             :         size_t header_len, msg_len, data_pos;
     628             : 
     629         778 :         TDSLOGIN *login = tds->login;
     630             : 
     631             :         /* check connection */
     632         778 :         if (!login)
     633             :                 return TDS_FAIL;
     634             : 
     635             :         /* parse a bit of config */
     636        1556 :         user_name = tds_dstr_cstr(&login->user_name);
     637        1556 :         user_name_len = tds_dstr_len(&login->user_name);
     638        1556 :         host_name = tds_dstr_cstr(&login->client_host_name);
     639        1556 :         host_name_len = tds_dstr_len(&login->client_host_name);
     640             : 
     641             :         /* convert strings */
     642         778 :         convert_buffer = tds_new(char, (user_name_len + host_name_len) * 2);
     643         778 :         if (!convert_buffer)
     644             :                 return TDS_FAIL;
     645             : 
     646         778 :         user_name_len = convert_to_usc2le_string(tds, user_name, user_name_len, convert_buffer);
     647         778 :         user_name = convert_buffer;
     648         778 :         if (user_name_len != (size_t) -1) {
     649         778 :                 host_name_len = convert_to_usc2le_string(tds, host_name, host_name_len, convert_buffer + user_name_len);
     650         778 :                 host_name = convert_buffer + user_name_len;
     651             :         }
     652         778 :         if (user_name_len == (size_t) -1 || host_name_len == (size_t) -1) {
     653           0 :                 free(convert_buffer);
     654           0 :                 return TDS_FAIL;
     655             :         }
     656             : 
     657             :         /* parse domain\username */
     658             :         p = user_name;
     659             :         for (;;) {
     660       11670 :                 if (p >= user_name + user_name_len) {
     661           0 :                         free(convert_buffer);
     662           0 :                         return TDS_FAIL;
     663             :                 }
     664        6224 :                 if (p[0] == '\\' && p[1] == 0)
     665             :                         break;
     666        5446 :                 p += 2;
     667             :         }
     668             : 
     669         778 :         domain = user_name;
     670         778 :         domain_len = p - user_name;
     671             : 
     672         778 :         user_name = p + 2;
     673         778 :         user_name_len = domain + user_name_len - user_name;
     674             : 
     675         778 :         rc = tds_answer_challenge(tds, login, challenge, &flags, names_blob, names_blob_len, &answer, &ntlm_v2_response);
     676         778 :         if (TDS_FAILED(rc)) {
     677           0 :                 free(convert_buffer);
     678           0 :                 return rc;
     679             :         }
     680             : 
     681         778 :         ntlm_response_len = ntlm_v2_response ? 16 + names_blob_len : 24;
     682             : 
     683             :         /*
     684             :          * compute exported session key, encrypting a random one if key exchange was negotiated;
     685             :          * key exchange is done only if signing or sealing is negotiated too (MS-NLMP 3.1.5.1.2)
     686             :          */
     687         778 :         if (answer.has_session_key) {
     688         778 :                 if ((flags & NTLMSSP_NEGOTIATE_KEY_EXCH) != 0 && (flags & (NTLMSSP_NEGOTIATE_SIGN | NTLMSSP_NEGOTIATE_SEAL)) != 0) {
     689         778 :                         tds_random_buffer(exported_key, sizeof(exported_key));
     690         778 :                         tds_rc4(answer.session_key, sizeof(answer.session_key), exported_key, sizeof(exported_key), encrypted_key);
     691        1556 :                         session_key_len = sizeof(encrypted_key);
     692             :                 } else {
     693           0 :                         memcpy(exported_key, answer.session_key, sizeof(exported_key));
     694             :                 }
     695             :         } else {
     696           0 :                 flags &= ~NTLMSSP_NEGOTIATE_KEY_EXCH;
     697           0 :                 if (use_mic) {
     698           0 :                         free(ntlm_v2_response);
     699           0 :                         free(convert_buffer);
     700           0 :                         return TDS_FAIL;
     701             :                 }
     702             :         }
     703             : 
     704         778 :         if (use_mic) {
     705             :                 /* MIC requires Version field, server sent a timestamp, LmChallengeResponse should be zero */
     706           0 :                 header_len = NTLM_AUTH_HEADER_MIC_LEN;
     707           0 :                 flags |= NTLMSSP_NEGOTIATE_VERSION;
     708           0 :                 memset(answer.lm_resp, 0, sizeof(answer.lm_resp));
     709             :         } else {
     710         778 :                 header_len = NTLM_AUTH_HEADER_LEN;
     711         778 :                 flags &= ~NTLMSSP_NEGOTIATE_VERSION;
     712             :         }
     713             : 
     714         778 :         msg_len = header_len + domain_len + user_name_len + host_name_len + lm_response_len + ntlm_response_len + session_key_len;
     715         778 :         msg = tds_new0(unsigned char, msg_len);
     716             : 
     717         778 :         if (!msg) {
     718           0 :                 if (ntlm_v2_response) {
     719           0 :                         memset(ntlm_v2_response, 0, ntlm_response_len);
     720           0 :                         free(ntlm_v2_response);
     721             :                 }
     722             :                 memset(&answer, 0, sizeof(answer));
     723           0 :                 free(convert_buffer);
     724           0 :                 return TDS_FAIL;
     725             :         }
     726             : 
     727         778 :         memcpy(msg, ntlm_id, 8);
     728         778 :         TDS_PUT_UA4LE(msg + 8, 3);      /* sequence 3 */
     729             : 
     730         778 :         data_pos = header_len;
     731             :         /* Target Name - domain or server name */
     732         778 :         put_ntlm_field(msg, 28, &data_pos, domain, domain_len);
     733         778 :         put_ntlm_field(msg, 36, &data_pos, user_name, user_name_len);
     734             :         /* Workstation Name */
     735         778 :         put_ntlm_field(msg, 44, &data_pos, host_name, host_name_len);
     736             :         /* LM/LMv2 Response */
     737         778 :         put_ntlm_field(msg, 12, &data_pos, answer.lm_resp, lm_response_len);
     738             :         /* NTLM/NTLMv2 Response */
     739         778 :         put_ntlm_field(msg, 20, &data_pos, ntlm_v2_response ? ntlm_v2_response : answer.nt_resp, ntlm_response_len);
     740             :         /* Encrypted Random Session Key */
     741         778 :         put_ntlm_field(msg, 52, &data_pos, encrypted_key, session_key_len);
     742             : 
     743         778 :         TDS_PUT_UA4LE(msg + 60, flags);
     744             : 
     745         778 :         if (use_mic) {
     746             :                 /* same version we sent in NEGOTIATE_MESSAGE */
     747           0 :                 memcpy(msg + 64, auth->tds_auth.packet + 32, 8);
     748           0 :                 if (!tds_ntlm_mic(exported_key, auth->tds_auth.packet, auth->tds_auth.packet_len,
     749           0 :                                   auth->challenge, auth->challenge_len, msg, msg_len, msg + NTLM_AUTH_MIC_OFFSET))
     750             :                         rc = TDS_FAIL;
     751             :         }
     752             : 
     753             :         if (TDS_SUCCEED(rc)) {
     754         778 :                 tds->out_flag = TDS7_AUTH;
     755         778 :                 tds_put_n(tds, msg, msg_len);
     756             :         }
     757             : 
     758             :         /* for security reason clear sensitive data */
     759         778 :         if (ntlm_v2_response) {
     760         778 :                 memset(ntlm_v2_response, 0, ntlm_response_len);
     761         778 :                 free(ntlm_v2_response);
     762             :         }
     763         778 :         memset(&answer, 0, sizeof(answer));
     764         778 :         memset(exported_key, 0, sizeof(exported_key));
     765         778 :         memset(encrypted_key, 0, sizeof(encrypted_key));
     766             :         memset(msg, 0, msg_len);
     767         778 :         free(msg);
     768         778 :         free(convert_buffer);
     769             : 
     770         778 :         if (TDS_FAILED(rc))
     771             :                 return rc;
     772         778 :         return tds_flush_packet(tds);
     773             : }
     774             : 
     775             : static TDSRET
     776         778 : tds_ntlm_free(TDSCONNECTION *conn TDS_UNUSED, TDSAUTHENTICATION *tds_auth)
     777             : {
     778         778 :         TDSNTLMAUTH *auth = (TDSNTLMAUTH *) tds_auth;
     779             : 
     780         778 :         free(auth->tds_auth.packet);
     781         778 :         free(auth->spn);
     782         778 :         free(auth->challenge);
     783         778 :         free(auth);
     784             : 
     785         778 :         return TDS_SUCCESS;
     786             : }
     787             : 
     788             : /**
     789             :  * put a 8 byte filetime from a time_t
     790             :  * This takes GMT as input
     791             :  */
     792             : static void
     793             : unix_to_nt_time(uint64_t * nt, struct timeval *tv)
     794             : {
     795             :         /* C time start on 1970, nt time on 1600 */
     796             : #define TIME_FIXUP_CONSTANT (((uint64_t) 134774U) * 86400U)
     797             : 
     798             :         uint64_t t2;
     799             : 
     800         808 :         t2 = tv->tv_sec;
     801         808 :         t2 += TIME_FIXUP_CONSTANT;
     802         808 :         t2 *= 1000u * 1000u * 10u;
     803         808 :         t2 += tv->tv_usec * 10u;
     804             : 
     805         808 :         *nt = t2;
     806             : }
     807             : 
     808             : /**
     809             :  * Compute channel binding token (MD5 of gss_channel_bindings_struct).
     810             :  * @param app_data     channel binding application data, like "tls-unique:" followed by data
     811             :  * @param app_data_len application data length
     812             :  * @param cbt          output token
     813             :  */
     814             : static void
     815         798 : tds_calc_cbt(const void *app_data, size_t app_data_len, unsigned char cbt[16])
     816             : {
     817             :         MD5_CTX md5_ctx;
     818             :         unsigned char channel_binding_struct[20];
     819             : 
     820             :         /* Build channel binding structure */
     821             :         /* initiator_address: 8 bytes of zeros */
     822             :         /* acceptor_address: 8 bytes of zeros */
     823             :         /* application_data: 4 bytes length (little endian) + data */
     824         798 :         memset(channel_binding_struct, 0, sizeof(channel_binding_struct));
     825         798 :         TDS_PUT_UA4LE(channel_binding_struct + 16, app_data_len);
     826             : 
     827             :         /* Calculate MD5 hash */
     828         798 :         MD5Init(&md5_ctx);
     829         798 :         MD5Update(&md5_ctx, channel_binding_struct, sizeof(channel_binding_struct));
     830         798 :         MD5Update(&md5_ctx, app_data, app_data_len);
     831         798 :         MD5Final(&md5_ctx, cbt);
     832         798 : }
     833             : 
     834             : static void
     835         778 : get_cbt(TDSSOCKET *tds, TDSNTLMAUTH *auth)
     836             : {
     837             :         unsigned char app_data[256];
     838             :         size_t app_data_len;
     839             : 
     840         778 :         app_data_len = tds_ssl_get_cb(tds->conn, app_data, sizeof(app_data));
     841         778 :         if (app_data_len == 0)
     842           0 :                 return;
     843             : 
     844         778 :         tdsdump_dump_buf(TDS_DBG_INFO1, "Channel Binding application data", app_data, app_data_len);
     845         778 :         tds_calc_cbt(app_data, app_data_len, auth->cbt);
     846         778 :         auth->has_cbt = true;
     847         778 :         tdsdump_dump_buf(TDS_DBG_INFO1, "Channel Binding Token", auth->cbt, 16);
     848             : }
     849             : 
     850             : /**
     851             :  * Compute the service principal name to send to the server.
     852             :  * SQL Server checks it when Extended Protection is enabled.
     853             :  */
     854             : static void
     855         778 : get_spn(TDSSOCKET *tds, TDSNTLMAUTH *auth)
     856             : {
     857             :         char *spn;
     858             :         size_t spn_len;
     859             : 
     860         778 :         spn = tds_get_spn(tds);
     861         778 :         if (!spn)
     862             :                 return;
     863             : 
     864         778 :         tdsdump_log(TDS_DBG_INFO1, "NTLM target name %s\n", spn);
     865         778 :         spn_len = strlen(spn);
     866         778 :         auth->spn = tds_new(char, spn_len * 2);
     867             : 
     868         778 :         if (auth->spn) {
     869         778 :                 auth->spn_len = convert_to_usc2le_string(tds, spn, spn_len, auth->spn);
     870             :                 /* AvLen is 16 bit */
     871         778 :                 if (auth->spn_len == (size_t) -1 || auth->spn_len > 0xfff0) {
     872           0 :                         free(auth->spn);
     873           0 :                         auth->spn = NULL;
     874           0 :                         auth->spn_len = 0;
     875             :                 }
     876             :         }
     877         778 :         free(spn);
     878             : }
     879             : 
     880             : /**
     881             :  * Add an AV_PAIR to target_info in names_blob.
     882             :  * target_info is at the end of names_blob and ends with a MsvAvEOL terminator.
     883             :  * @param names_blob     names_blob buffer, must have space for the new pair
     884             :  * @param names_blob_len current length (will be updated)
     885             :  * @param av_id          AvId of the new pair
     886             :  * @param data           data of the new pair
     887             :  * @param data_len       length of data
     888             :  */
     889             : static void
     890        1586 : add_av_pair(unsigned char *names_blob, int *names_blob_len, uint16_t av_id, const void *data, size_t data_len)
     891             : {
     892             :         /* The -4 is to override the old terminator */
     893        1586 :         unsigned char *av_pair = names_blob + *names_blob_len - 4;
     894             : 
     895        1586 :         TDS_PUT_UA2LE(av_pair, av_id);
     896        1586 :         TDS_PUT_UA2LE(av_pair + 2, data_len);
     897        1586 :         memcpy(av_pair + 4, data, data_len);
     898        1586 :         memset(av_pair + 4 + data_len, 0, 4);   /* Terminator */
     899             : 
     900        1586 :         *names_blob_len += 4 + (int) data_len;
     901        1586 : }
     902             : 
     903             : /**
     904             :  * Add channel binding token (CBT) and target name AV_PAIRs to target_info in names_blob
     905             :  * @param auth           NTLM authentication data
     906             :  * @param names_blob     names_blob buffer
     907             :  * @param names_blob_len current length (will be updated)
     908             :  */
     909             : static void
     910         808 : add_av_pairs(TDSNTLMAUTH *auth, unsigned char *names_blob, int *names_blob_len)
     911             : {
     912         808 :         if (auth->has_cbt)
     913         788 :                 add_av_pair(names_blob, names_blob_len, MSV_AV_CHANNEL_BINDINGS, auth->cbt, sizeof(auth->cbt));
     914         808 :         if (auth->spn)
     915         788 :                 add_av_pair(names_blob, names_blob_len, MSV_AV_TARGET_NAME, auth->spn, auth->spn_len);
     916             : 
     917         808 :         tdsdump_dump_buf(TDS_DBG_INFO1, "New names_blob\n", names_blob, *names_blob_len);
     918         808 : }
     919             : 
     920             : static void
     921         808 : fill_names_blob_prefix(names_blob_prefix_t * prefix)
     922             : {
     923             :         struct timeval tv;
     924         808 :         uint64_t nttime = 0;
     925             : 
     926         808 :         gettimeofday(&tv, NULL);
     927         808 :         unix_to_nt_time(&nttime, &tv);
     928             : 
     929         808 :         prefix->response_type = 0x01;
     930         808 :         prefix->max_response_type = 0x01;
     931         808 :         prefix->reserved1 = 0x0000;
     932         808 :         prefix->reserved2 = 0x00000000;
     933             : #ifdef WORDS_BIGENDIAN
     934             :         tds_swap_bytes(&nttime, 8);
     935             : #endif
     936         808 :         prefix->timestamp = nttime;
     937         808 :         tds_random_buffer(prefix->challenge, sizeof(prefix->challenge));
     938             : 
     939         808 :         prefix->reserved3 = 0x00000000;
     940         808 : }
     941             : 
     942             : /**
     943             :  * Build NTLMv2 client blob (names_blob) from server target information.
     944             :  * Server AV_PAIRs are kept, MsvAvFlags (if MIC is used), channel binding token and
     945             :  * target name are added. The server timestamp, if present, is used.
     946             :  * @param auth            NTLM authentication data
     947             :  * @param target_info     target information from CHALLENGE_MESSAGE
     948             :  * @param target_info_len length of target_info
     949             :  * @param mic_allowed     whether we can provide a MIC
     950             :  * @param p_names_blob    output names_blob, to be freed
     951             :  * @param p_names_blob_len output length of names_blob
     952             :  * @param p_use_mic       output, whether MIC should be sent
     953             :  */
     954             : static TDSRET
     955         828 : build_names_blob(TDSNTLMAUTH *auth, const unsigned char *target_info, size_t target_info_len, bool mic_allowed,
     956             :                  unsigned char **p_names_blob, int *p_names_blob_len, bool *p_use_mic)
     957             : {
     958         828 :         const unsigned char *timestamp = NULL;
     959         828 :         size_t flags_pos = 0, pos = 0, pairs_len, alloc_len;
     960         828 :         const size_t prefix_len = TDS_OFFSET(names_blob_prefix_t, target_info);
     961             :         unsigned char *names_blob;
     962             :         int names_blob_len;
     963             :         bool use_mic;
     964             : 
     965             :         /* parse AV_PAIRs, checking they are well formed */
     966        3212 :         for (;;) {
     967             :                 unsigned int av_id, av_len;
     968             : 
     969        4040 :                 if (target_info_len - pos < 4)
     970             :                         return TDS_FAIL;
     971        4030 :                 av_id = TDS_GET_UA2LE(target_info + pos);
     972        4030 :                 av_len = TDS_GET_UA2LE(target_info + pos + 2);
     973        4030 :                 if (av_id == MSV_AV_EOL)
     974             :                         break;
     975        3222 :                 if (target_info_len - pos - 4 < av_len)
     976             :                         return TDS_FAIL;
     977        3212 :                 if (av_id == MSV_AV_TIMESTAMP && av_len == 8)
     978          20 :                         timestamp = target_info + pos + 4;
     979        3212 :                 if (av_id == MSV_AV_FLAGS && av_len == 4)
     980           0 :                         flags_pos = pos + 4;
     981        3212 :                 pos += 4 + av_len;
     982             :         }
     983         808 :         pairs_len = pos;
     984             : 
     985             :         /* MIC should be provided if server sent a timestamp */
     986         808 :         use_mic = mic_allowed && timestamp != NULL;
     987             : 
     988             :         /* prefix + pairs + MsvAvFlags + CBT + target name + MsvAvEOL + Z(4) */
     989         808 :         alloc_len = prefix_len + pairs_len + 8 + AV_PAIR_CBT_BYTES + 4 + auth->spn_len + 4 + 4;
     990         808 :         names_blob = tds_new0(unsigned char, alloc_len);
     991             : 
     992         808 :         if (!names_blob)
     993             :                 return TDS_FAIL;
     994             : 
     995         808 :         fill_names_blob_prefix((names_blob_prefix_t *) names_blob);
     996         808 :         if (timestamp)
     997          20 :                 memcpy(names_blob + TDS_OFFSET(names_blob_prefix_t, timestamp), timestamp, 8);
     998             : 
     999             :         /* copy server AV_PAIRs, the terminator is already zeroed */
    1000         808 :         memcpy(names_blob + prefix_len, target_info, pairs_len);
    1001         808 :         names_blob_len = (int) (prefix_len + pairs_len + 4);
    1002             : 
    1003         808 :         if (use_mic) {
    1004          10 :                 if (flags_pos) {
    1005           0 :                         unsigned char *p = names_blob + prefix_len + flags_pos;
    1006             : 
    1007           0 :                         TDS_PUT_UA4LE(p, TDS_GET_UA4LE(p) | MSV_AV_FLAG_MIC);
    1008             :                 } else {
    1009             :                         unsigned char av_flags[4];
    1010             : 
    1011          10 :                         TDS_PUT_UA4LE(av_flags, MSV_AV_FLAG_MIC);
    1012          10 :                         add_av_pair(names_blob, &names_blob_len, MSV_AV_FLAGS, av_flags, sizeof(av_flags));
    1013             :                 }
    1014             :         }
    1015             : 
    1016             :         /* Add channel binding token (CBT) and target name AV_PAIRs */
    1017         808 :         add_av_pairs(auth, names_blob, &names_blob_len);
    1018             : 
    1019             :         /* blob ends with Z(4) after AV_PAIRs, already zeroed */
    1020         808 :         names_blob_len += 4;
    1021             : 
    1022         808 :         *p_names_blob = names_blob;
    1023         808 :         *p_names_blob_len = names_blob_len;
    1024         808 :         *p_use_mic = use_mic;
    1025         808 :         return TDS_SUCCESS;
    1026             : }
    1027             : 
    1028             : static TDSRET
    1029         778 : tds_ntlm_handle_next(TDSSOCKET *tds, TDSAUTHENTICATION *tds_auth, size_t len)
    1030             : {
    1031         778 :         TDSNTLMAUTH *auth = (TDSNTLMAUTH *) tds_auth;
    1032             :         const unsigned char *msg;
    1033             :         uint32_t flags;
    1034             :         size_t data_block_offset;
    1035             : 
    1036         778 :         int names_blob_len = 0;
    1037         778 :         unsigned char *names_blob = NULL;
    1038         778 :         bool use_mic = false;
    1039             : 
    1040             :         TDSRET rc;
    1041             : 
    1042             :         /* at least 32 bytes (till context) */
    1043         778 :         if (len < 32 || len > 0xffff)
    1044             :                 return TDS_FAIL;
    1045             : 
    1046             :         /* read the entire CHALLENGE_MESSAGE, it is needed to compute MIC */
    1047         778 :         free(auth->challenge);
    1048         778 :         auth->challenge_len = 0;
    1049         778 :         auth->challenge = tds_new(unsigned char, len);
    1050             : 
    1051         778 :         if (!auth->challenge)
    1052             :                 return TDS_FAIL;
    1053         778 :         if (!tds_get_n(tds, auth->challenge, len))
    1054             :                 return TDS_FAIL;
    1055         778 :         auth->challenge_len = len;
    1056         778 :         msg = auth->challenge;
    1057             : 
    1058         778 :         if (memcmp(msg, ntlm_id, 8) != 0)
    1059             :                 return TDS_FAIL;
    1060         778 :         if (TDS_GET_UA4LE(msg + 8) != 2)        /* sequence -> 2 */
    1061             :                 return TDS_FAIL;
    1062         778 :         data_block_offset = TDS_GET_UA4LE(msg + 16);    /* domain offset */
    1063         778 :         flags = TDS_GET_UA4LE(msg + 20);
    1064         778 :         tdsdump_dump_buf(TDS_DBG_INFO1, "TDS_AUTH_TOKEN nonce", msg + 24, 8);
    1065             : 
    1066             :         /* Version 1 -- The Context, Target Information, and OS Version structure are all omitted */
    1067             :         /* Version 2 -- The Context and Target Information fields are present, but the OS Version structure is not. */
    1068         778 :         if (data_block_offset >= 48 && len >= 48) {
    1069             :                 size_t target_info_len, target_info_offset;
    1070             : 
    1071         778 :                 target_info_len = TDS_GET_UA2LE(msg + 40);
    1072         778 :                 target_info_offset = TDS_GET_UA4LE(msg + 44);
    1073             : 
    1074             :                 /* read Target Info if possible */
    1075         778 :                 if (target_info_len > 0 && target_info_offset >= 48 && target_info_offset <= len
    1076         778 :                     && target_info_len <= len - target_info_offset) {
    1077         778 :                         rc = build_names_blob(auth, msg + target_info_offset, target_info_len, tds->login->use_ntlmv2,
    1078             :                                               &names_blob, &names_blob_len, &use_mic);
    1079         778 :                         if (TDS_FAILED(rc))
    1080             :                                 return rc;
    1081             :                 }
    1082             :         }
    1083             : 
    1084         778 :         rc = tds7_send_auth(tds, auth, msg + 24, flags, names_blob, names_blob_len, use_mic);
    1085             : 
    1086         778 :         if (names_blob) {
    1087         778 :                 memset(names_blob, 0, names_blob_len);
    1088         778 :                 free(names_blob);
    1089             :         }
    1090             : 
    1091             :         return rc;
    1092             : }
    1093             : 
    1094             : /**
    1095             :  * Build a NTLMSPP packet to send to server
    1096             :  * @param tds     A pointer to the TDSSOCKET structure managing a client/server operation.
    1097             :  * @return authentication info
    1098             :  */
    1099             : TDSAUTHENTICATION * 
    1100         778 : tds_ntlm_get_auth(TDSSOCKET * tds)
    1101             : {
    1102             :         const char *domain;
    1103             :         const char *user_name;
    1104             :         const char *p;
    1105             :         uint8_t *packet;
    1106             :         int host_name_len;
    1107             :         int domain_len;
    1108             :         int auth_len;
    1109             :         uint32_t flags;
    1110             :         TDSNTLMAUTH *auth;
    1111             : 
    1112         778 :         if (!tds->login)
    1113             :                 return NULL;
    1114             : 
    1115        1556 :         user_name = tds_dstr_cstr(&tds->login->user_name);
    1116        1556 :         host_name_len = (int)tds_dstr_len(&tds->login->client_host_name);
    1117             : 
    1118             :         /* check override of domain */
    1119         778 :         if ((p = strchr(user_name, '\\')) == NULL)
    1120             :                 return NULL;
    1121             : 
    1122         778 :         domain = user_name;
    1123         778 :         domain_len = (int) (p - user_name);
    1124             : 
    1125         778 :         auth = tds_new0(TDSNTLMAUTH, 1);
    1126             : 
    1127         778 :         if (!auth)
    1128             :                 return NULL;
    1129             : 
    1130         778 :         auth->tds_auth.free = tds_ntlm_free;
    1131         778 :         auth->tds_auth.handle_next = tds_ntlm_handle_next;
    1132             : 
    1133         778 :         auth->tds_auth.packet_len = auth_len = 40 + host_name_len + domain_len;
    1134         778 :         auth->tds_auth.packet = packet = tds_new(uint8_t, auth_len);
    1135         778 :         if (!packet) {
    1136           0 :                 free(auth);
    1137           0 :                 return NULL;
    1138             :         }
    1139             : 
    1140             :         /* built NTLMSSP authentication packet */
    1141         778 :         memcpy(packet, ntlm_id, 8);
    1142             :         /* sequence 1 client -> server */
    1143         778 :         TDS_PUT_A4(packet + 8, TDS_HOST4LE(1));
    1144             :         /* flags */
    1145             :         /* key exchange requires signing (we don't sign messages, TDS uses TLS for integrity) */
    1146         778 :         flags = NTLMSSP_NEGOTIATE_UNICODE | NTLMSSP_NEGOTIATE_NTLM
    1147             :                 | NTLMSSP_NEGOTIATE_OEM_DOMAIN_SUPPLIED | NTLMSSP_NEGOTIATE_OEM_WORKSTATION_SUPPLIED
    1148             :                 | NTLMSSP_NEGOTIATE_ALWAYS_SIGN | NTLMSSP_NEGOTIATE_EXTENDED_SESSIONSECURITY
    1149             :                 | NTLMSSP_NEGOTIATE_SIGN | NTLMSSP_NEGOTIATE_KEY_EXCH | NTLMSSP_NEGOTIATE_128 | NTLMSSP_NEGOTIATE_VERSION;
    1150             :         /* no domain, like using an user principal name ("\\user@domain"), Windows rejects the flag with an empty domain */
    1151         778 :         if (domain_len == 0)
    1152           0 :                 flags &= ~NTLMSSP_NEGOTIATE_OEM_DOMAIN_SUPPLIED;
    1153         778 :         TDS_PUT_A4(packet + 12, TDS_HOST4LE(flags));
    1154             : 
    1155             :         /* domain info */
    1156         778 :         TDS_PUT_A2LE(packet + 16, domain_len);
    1157         778 :         TDS_PUT_A2LE(packet + 18, domain_len);
    1158         778 :         TDS_PUT_A4LE(packet + 20, 40 + host_name_len);
    1159             : 
    1160             :         /* hostname info */
    1161         778 :         TDS_PUT_A2LE(packet + 24, host_name_len);
    1162         778 :         TDS_PUT_A2LE(packet + 26, host_name_len);
    1163         778 :         TDS_PUT_A4  (packet + 28, TDS_HOST4LE(40));
    1164             : 
    1165             :         /*
    1166             :          * Version: product major and minor version, build number (16 bit),
    1167             :          * 3 reserved bytes and NTLM revision (15).
    1168             :          * Report Windows 10.0 build 20348 (Windows Server 2022), it's informational only.
    1169             :          */
    1170         778 :         packet[32] = 10;
    1171         778 :         packet[33] = 0;
    1172         778 :         TDS_PUT_A2LE(packet + 34, 20348);
    1173         778 :         TDS_PUT_A4(packet + 36, TDS_HOST4LE(0x0f000000));
    1174             : 
    1175             :         /* hostname and domain */
    1176        1556 :         memcpy(packet + 40, tds_dstr_cstr(&tds->login->client_host_name), host_name_len);
    1177         778 :         memcpy(packet + 40 + host_name_len, domain, domain_len);
    1178             : 
    1179         778 :         get_cbt(tds, auth);
    1180         778 :         get_spn(tds, auth);
    1181             : 
    1182         778 :         return (TDSAUTHENTICATION *) auth;
    1183             : }
    1184             : 
    1185             : /** @} */
    1186             : 

Generated by: LCOV version 1.13