LCOV - code coverage report
Current view: top level - src/tds - login.c (source / functions) Hit Total Coverage
Test: FreeTDS coverage Lines: 493 599 82.3 %
Date: 2026-01-01 15:30:10 Functions: 26 29 89.7 %

          Line data    Source code
       1             : /* FreeTDS - Library of routines accessing Sybase and Microsoft databases
       2             :  * Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005  Brian Bruns
       3             :  * Copyright (C) 2005-2015  Ziglio Frediano
       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             : #include <stdarg.h>
      24             : #include <stdio.h>
      25             : 
      26             : #if HAVE_STDLIB_H
      27             : #include <stdlib.h>
      28             : #endif /* HAVE_STDLIB_H */
      29             : 
      30             : #include <assert.h>
      31             : 
      32             : #if HAVE_STRING_H
      33             : #include <string.h>
      34             : #endif /* HAVE_STRING_H */
      35             : 
      36             : #if HAVE_UNISTD_H
      37             : #include <unistd.h>
      38             : #endif /* HAVE_UNISTD_H */
      39             : 
      40             : #if HAVE_SYS_SOCKET_H
      41             : #include <sys/socket.h>
      42             : #endif /* HAVE_SYS_SOCKET_H */
      43             : 
      44             : #ifdef _WIN32
      45             : #include <process.h>
      46             : #endif
      47             : 
      48             : #include <freetds/tds.h>
      49             : #include <freetds/iconv.h>
      50             : #include <freetds/utils/string.h>
      51             : #include <freetds/bytes.h>
      52             : #include <freetds/tls.h>
      53             : #include <freetds/stream.h>
      54             : #include <freetds/checks.h>
      55             : #include <freetds/replacements.h>
      56             : 
      57             : static TDSRET tds_send_login(TDSSOCKET * tds, const TDSLOGIN * login);
      58             : static TDSRET tds71_do_login(TDSSOCKET * tds, TDSLOGIN * login);
      59             : static TDSRET tds7_send_login(TDSSOCKET * tds, const TDSLOGIN * login);
      60             : static void tds7_crypt_pass(const unsigned char *clear_pass,
      61             :                             size_t len, unsigned char *crypt_pass);
      62             : 
      63             : void
      64         746 : tds_set_version(TDSLOGIN * tds_login, TDS_TINYINT major_ver, TDS_TINYINT minor_ver)
      65             : {
      66         746 :         tds_login->tds_version = ((TDS_USMALLINT) major_ver << 8) + minor_ver;
      67         746 : }
      68             : 
      69             : void
      70           0 : tds_set_packet(TDSLOGIN * tds_login, int packet_size)
      71             : {
      72           0 :         tds_login->block_size = packet_size;
      73           0 : }
      74             : 
      75             : void
      76           0 : tds_set_port(TDSLOGIN * tds_login, int port)
      77             : {
      78           0 :         tds_login->port = port;
      79           0 : }
      80             : 
      81             : bool
      82        2488 : tds_set_passwd(TDSLOGIN * tds_login, const char *password)
      83             : {
      84        2488 :         if (password) {
      85        2488 :                 tds_dstr_zero(&tds_login->password);
      86        2488 :                 return !!tds_dstr_copy(&tds_login->password, password);
      87             :         }
      88             :         return true;
      89             : }
      90             : void
      91        1390 : tds_set_bulk(TDSLOGIN * tds_login, bool enabled)
      92             : {
      93        1390 :         tds_login->bulk_copy = enabled ? 1 : 0;
      94        1390 : }
      95             : 
      96             : bool
      97        2488 : tds_set_user(TDSLOGIN * tds_login, const char *username)
      98             : {
      99        2488 :         return !!tds_dstr_copy(&tds_login->user_name, username);
     100             : }
     101             : 
     102             : bool
     103         494 : tds_set_host(TDSLOGIN * tds_login, const char *hostname)
     104             : {
     105         494 :         return !!tds_dstr_copy(&tds_login->client_host_name, hostname);
     106             : }
     107             : 
     108             : bool
     109        1148 : tds_set_app(TDSLOGIN * tds_login, const char *application)
     110             : {
     111        1148 :         return !!tds_dstr_copy(&tds_login->app_name, application);
     112             : }
     113             : 
     114             : /**
     115             :  * \brief Set the servername in a TDSLOGIN structure
     116             :  *
     117             :  * Normally copies \a server into \a tds_login.  If \a server does not point to a plausible name, the environment 
     118             :  * variables TDSQUERY and DSQUERY are used, in that order.  If they don't exist, the "default default" servername
     119             :  * is "SYBASE" (although the utility of that choice is a bit murky).  
     120             :  *
     121             :  * \param tds_login     points to a TDSLOGIN structure
     122             :  * \param server        the servername, or NULL, or a zero-length string
     123             :  * \todo open the log file earlier, so these messages can be seen.  
     124             :  */
     125             : bool
     126        2600 : tds_set_server(TDSLOGIN * tds_login, const char *server)
     127             : {
     128             : #if 0
     129             :         /* Doing this in tds_alloc_login instead */
     130             :         static const char *names[] = { "TDSQUERY", "DSQUERY", "SYBASE" };
     131             :         int i;
     132             :         
     133             :         for (i=0; i < TDS_VECTOR_SIZE(names) && (!server || strlen(server) == 0); i++) {
     134             :                 const char *source;
     135             :                 if (i + 1 == TDS_VECTOR_SIZE(names)) {
     136             :                         server = names[i];
     137             :                         source = "compiled-in default";
     138             :                 } else {
     139             :                         server = getenv(names[i]);
     140             :                         source = names[i];
     141             :                 }
     142             :                 if (server) {
     143             :                         tdsdump_log(TDS_DBG_INFO1, "Setting TDSLOGIN::server_name to '%s' from %s.\n", server, source);
     144             :                 }
     145             :         }
     146             : #endif
     147        2600 :         if (server)
     148        2600 :                 return !!tds_dstr_copy(&tds_login->server_name, server);
     149             :         return true;
     150             : }
     151             : 
     152             : bool
     153        2518 : tds_set_library(TDSLOGIN * tds_login, const char *library)
     154             : {
     155        2518 :         return !!tds_dstr_copy(&tds_login->library, library);
     156             : }
     157             : 
     158             : bool
     159         174 : tds_set_client_charset(TDSLOGIN * tds_login, const char *charset)
     160             : {
     161         174 :         return !!tds_dstr_copy(&tds_login->client_charset, charset);
     162             : }
     163             : 
     164             : bool
     165         396 : tds_set_language(TDSLOGIN * tds_login, const char *language)
     166             : {
     167         396 :         return !!tds_dstr_copy(&tds_login->language, language);
     168             : }
     169             : 
     170             : struct tds_save_msg
     171             : {
     172             :         TDSMESSAGE msg;
     173             :         char type;
     174             : };
     175             : 
     176             : struct tds_save_env
     177             : {
     178             :         char *oldval;
     179             :         char *newval;
     180             :         int type;
     181             : };
     182             : 
     183             : typedef struct tds_save_context
     184             : {
     185             :         /* must be first !!! */
     186             :         TDSCONTEXT ctx;
     187             : 
     188             :         unsigned num_msg;
     189             :         struct tds_save_msg msgs[10];
     190             : 
     191             :         unsigned num_env;
     192             :         struct tds_save_env envs[10];
     193             : } TDSSAVECONTEXT;
     194             : 
     195             : static void
     196           6 : tds_save(TDSSAVECONTEXT *ctx, char type, TDSMESSAGE *msg)
     197             : {
     198             :         struct tds_save_msg *dest_msg;
     199             : 
     200           6 :         if (ctx->num_msg >= TDS_VECTOR_SIZE(ctx->msgs))
     201             :                 return;
     202             : 
     203           6 :         dest_msg = &ctx->msgs[ctx->num_msg];
     204           6 :         dest_msg->type = type;
     205           6 :         dest_msg->msg = *msg;
     206             : #define COPY(name) if (msg->name) dest_msg->msg.name = strdup(msg->name);
     207           6 :         COPY(server);
     208           6 :         COPY(message);
     209           6 :         COPY(proc_name);
     210           6 :         COPY(sql_state);
     211             : #undef COPY
     212           6 :         ++ctx->num_msg;
     213             : }
     214             : 
     215             : static int
     216           4 : tds_save_msg(const TDSCONTEXT *ctx, TDSSOCKET *tds TDS_UNUSED, TDSMESSAGE *msg)
     217             : {
     218           4 :         tds_save((TDSSAVECONTEXT *) ctx, 0, msg);
     219           4 :         return 0;
     220             : }
     221             : 
     222             : static int
     223           2 : tds_save_err(const TDSCONTEXT *ctx, TDSSOCKET *tds TDS_UNUSED, TDSMESSAGE *msg)
     224             : {
     225           2 :         tds_save((TDSSAVECONTEXT *) ctx, 1, msg);
     226           2 :         return TDS_INT_CANCEL;
     227             : }
     228             : 
     229             : static void
     230           6 : tds_save_env(TDSSOCKET * tds, int type, char *oldval, char *newval)
     231             : {
     232             :         TDSSAVECONTEXT *ctx;
     233             :         struct tds_save_env *env;
     234             : 
     235           6 :         if (tds_get_ctx(tds)->msg_handler != tds_save_msg)
     236             :                 return;
     237             : 
     238           6 :         ctx = (TDSSAVECONTEXT *) tds_get_ctx(tds);
     239           6 :         if (ctx->num_env >= TDS_VECTOR_SIZE(ctx->envs))
     240             :                 return;
     241             : 
     242           6 :         env = &ctx->envs[ctx->num_env];
     243           6 :         env->type = type;
     244           6 :         env->oldval = oldval ? strdup(oldval) : NULL;
     245           6 :         env->newval = newval ? strdup(newval) : NULL;
     246           6 :         ++ctx->num_env;
     247             : }
     248             : 
     249             : static void
     250             : init_save_context(TDSSAVECONTEXT *ctx, const TDSCONTEXT *old_ctx)
     251             : {
     252           2 :         memset(ctx, 0, sizeof(*ctx));
     253           2 :         ctx->ctx.locale = old_ctx->locale;
     254           2 :         ctx->ctx.msg_handler = tds_save_msg;
     255           2 :         ctx->ctx.err_handler = tds_save_err;
     256             : }
     257             : 
     258             : static void
     259           2 : replay_save_context(TDSSOCKET *tds, TDSSAVECONTEXT *ctx)
     260             : {
     261             :         unsigned n;
     262             : 
     263             :         /* replay all recorded messages */
     264           6 :         for (n = 0; n < ctx->num_msg; ++n)
     265           4 :                 if (ctx->msgs[n].type == 0) {
     266           4 :                         if (tds_get_ctx(tds)->msg_handler)
     267           4 :                                 tds_get_ctx(tds)->msg_handler(tds_get_ctx(tds), tds, &ctx->msgs[n].msg);
     268             :                 } else {
     269           0 :                         if (tds_get_ctx(tds)->err_handler)
     270           0 :                                 tds_get_ctx(tds)->err_handler(tds_get_ctx(tds), tds, &ctx->msgs[n].msg);
     271             :                 }
     272             : 
     273             :         /* replay all recorded envs */
     274           6 :         for (n = 0; n < ctx->num_env; ++n)
     275           6 :                 if (tds->env_chg_func)
     276           0 :                         tds->env_chg_func(tds, ctx->envs[n].type, ctx->envs[n].oldval, ctx->envs[n].newval);
     277           2 : }
     278             : 
     279             : static void
     280           6 : reset_save_context(TDSSAVECONTEXT *ctx)
     281             : {
     282             :         unsigned n;
     283             : 
     284             :         /* free all messages */
     285          12 :         for (n = 0; n < ctx->num_msg; ++n)
     286           6 :                 tds_free_msg(&ctx->msgs[n].msg);
     287           6 :         ctx->num_msg = 0;
     288             : 
     289             :         /* free all envs */
     290          12 :         for (n = 0; n < ctx->num_env; ++n) {
     291           6 :                 free(ctx->envs[n].oldval);
     292           6 :                 free(ctx->envs[n].newval);
     293             :         }
     294           6 :         ctx->num_env = 0;
     295           6 : }
     296             : 
     297             : static void
     298             : free_save_context(TDSSAVECONTEXT *ctx)
     299             : {
     300           2 :         reset_save_context(ctx);
     301             : }
     302             : 
     303             : /**
     304             :  * Set @@spid based on column data
     305             :  * \tds
     306             :  * @param curcol  column with spid data.
     307             :  */
     308             : static TDSRET
     309         720 : tds_set_spid(TDSSOCKET * tds, TDSCOLUMN *curcol)
     310             : {
     311         720 :         switch (tds_get_conversion_type(curcol->column_type, curcol->column_size)) {
     312         720 :         case SYBINT2:
     313         720 :                 tds->conn->spid = *((TDS_USMALLINT *) curcol->column_data);
     314             :                 break;
     315           0 :         case SYBINT4:
     316           0 :                 tds->conn->spid = *((TDS_UINT *) curcol->column_data);
     317             :                 break;
     318             :         default:
     319             :                 return TDS_FAIL;
     320             :         }
     321             :         return TDS_SUCCESS;
     322             : }
     323             : 
     324             : /**
     325             :  * Set ncharsize based on column data.
     326             :  * \tds
     327             :  * @param res_info  resultset to get data from.
     328             :  */
     329             : static TDSRET
     330             : tds_set_nvc(TDSSOCKET * tds, TDSRESULTINFO *res_info)
     331             : {
     332             :         int charsize;
     333             : 
     334             :         /* Compute the ratios, put some acceptance in order to avoid issues. */
     335             :         /* The "3" constant came from the query issued (NVARCHAR(3)) */
     336         720 :         charsize = res_info->columns[0]->on_server.column_size / 3;
     337         720 :         if (charsize >= 1 && charsize <= 4)
     338         720 :                 tds->conn->ncharsize = (uint8_t) charsize;
     339             :         return TDS_SUCCESS;
     340             : }
     341             : 
     342             : /**
     343             :  * Set unicharsize based on column data.
     344             :  * \tds
     345             :  * @param res_info  resultset to get data from.
     346             :  */
     347             : static TDSRET
     348             : tds_set_uvc(TDSSOCKET * tds, TDSRESULTINFO *res_info)
     349             : {
     350             :         int charsize;
     351             : 
     352             :         /* Compute the ratios, put some acceptance in order to avoid issues. */
     353             :         /* The "3" constant came from the query issued (UNIVARCHAR(3)) */
     354         720 :         charsize = res_info->columns[0]->on_server.column_size / 3;
     355         720 :         if (charsize >= 1 && charsize <= 4)
     356         720 :                 tds->conn->unicharsize = (uint8_t) charsize;
     357             :         return TDS_SUCCESS;
     358             : }
     359             : 
     360             : /**
     361             :  * Parse the results from login queries
     362             :  * \tds
     363             :  */
     364             : static TDSRET
     365        3662 : tds_parse_login_results(TDSSOCKET * tds, bool ignore_errors)
     366             : {
     367             :         TDS_INT result_type;
     368             :         TDS_INT done_flags;
     369             :         TDSRET rc;
     370             :         TDSCOLUMN *curcol;
     371        3662 :         bool last_required = false;
     372             : 
     373        3662 :         CHECK_TDS_EXTRA(tds);
     374             : 
     375       16282 :         while ((rc = tds_process_tokens(tds, &result_type, &done_flags, TDS_RETURN_ROW|TDS_RETURN_DONE)) == TDS_SUCCESS) {
     376             : 
     377        8958 :                 switch (result_type) {
     378        2160 :                 case TDS_ROW_RESULT:
     379        2160 :                         if (!tds->res_info && tds->res_info->num_cols < 1)
     380             :                                 return TDS_FAIL;
     381        2160 :                         curcol = tds->res_info->columns[0];
     382        4320 :                         if (tds->res_info->num_cols == 1 && strcmp(tds_dstr_cstr(&curcol->column_name), "spid") == 0)
     383         720 :                                 rc = tds_set_spid(tds, curcol);
     384        4320 :                         if (tds->res_info->num_cols == 1 && strcmp(tds_dstr_cstr(&curcol->column_name), "nvc") == 0) {
     385         720 :                                 rc = tds_set_nvc(tds, tds->res_info);
     386             :                                 last_required = true;
     387             :                         }
     388        4320 :                         if (tds->res_info->num_cols == 1 && strcmp(tds_dstr_cstr(&curcol->column_name), "uvc") == 0)
     389         720 :                                 rc = tds_set_uvc(tds, tds->res_info);
     390        1440 :                         TDS_PROPAGATE(rc);
     391             :                         break;
     392             : 
     393        6798 :                 case TDS_DONE_RESULT:
     394             :                 case TDS_DONEPROC_RESULT:
     395             :                 case TDS_DONEINPROC_RESULT:
     396        6798 :                         if ((done_flags & TDS_DONE_ERROR) != 0 && !ignore_errors)
     397             :                                 return TDS_FAIL;
     398        6798 :                         if (last_required)
     399        2160 :                                 ignore_errors = true;
     400             :                         break;
     401             :                 }
     402             :         }
     403        3662 :         if (rc == TDS_NO_MORE_RESULTS)
     404        3662 :                 rc = TDS_SUCCESS;
     405             : 
     406             :         return rc;
     407             : }
     408             : 
     409             : static TDSRET
     410           0 : tds_process_single(TDSSOCKET *tds, char *query, bool ignore_errors)
     411             : {
     412             :         TDSRET erc;
     413             : 
     414           0 :         if (!query[0])
     415             :                 return TDS_SUCCESS;
     416             : 
     417             :         /* submit and parse results */
     418           0 :         erc = tds_submit_query(tds, query);
     419           0 :         if (TDS_SUCCEED(erc))
     420           0 :                 erc = tds_parse_login_results(tds, ignore_errors);
     421             : 
     422             :         /* prepare next query */
     423           0 :         query[0] = 0;
     424             : 
     425           0 :         if (TDS_FAILED(erc))
     426           0 :                 free(query);
     427             : 
     428             :         return erc;
     429             : }
     430             : 
     431             : #define process_single(ignore_errors) do { \
     432             :         if (!single_query && TDS_FAILED(erc = tds_process_single(tds, str, ignore_errors))) \
     433             :                 return erc; \
     434             : } while(0)
     435             : 
     436             : static TDSRET
     437        3662 : tds_setup_connection(TDSSOCKET *tds, TDSLOGIN *login, bool set_db, bool single_query)
     438             : {
     439             :         TDSRET erc;
     440             :         char *str;
     441             :         size_t len;
     442        3662 :         const char *const product_name = (tds->conn->product_name != NULL ? tds->conn->product_name : "");
     443        3662 :         const bool is_sql_anywhere = (strcasecmp(product_name, "SQL Anywhere") == 0);
     444        3662 :         const bool is_openserver = (strcasecmp(product_name, "OpenServer") == 0);
     445             : 
     446        7324 :         len = 192 + tds_quote_id(tds, NULL, tds_dstr_cstr(&login->database),-1);
     447        3662 :         if ((str = tds_new(char, len)) == NULL)
     448             :                 return TDS_FAIL;
     449             : 
     450        3662 :         str[0] = 0;
     451        3662 :         if (login->text_size)
     452        3662 :                 sprintf(str, "SET TEXTSIZE %d\n", login->text_size);
     453        3662 :         process_single(false);
     454             : 
     455        3662 :         if (tds->conn->spid == -1 && !is_openserver)
     456         720 :                 strcat(str, "SELECT @@spid spid\n");
     457        3662 :         process_single(true);
     458             : 
     459             :         /* Select proper database if specified.
     460             :          * SQL Anywhere does not support multiple databases and USE statement
     461             :          * so don't send the request to avoid connection failures */
     462        4382 :         if (set_db && !tds_dstr_isempty(&login->database) && !is_sql_anywhere) {
     463         256 :                 strcat(str, "USE ");
     464         512 :                 tds_quote_id(tds, strchr(str, 0), tds_dstr_cstr(&login->database), -1);
     465         256 :                 strcat(str, "\n");
     466             :         }
     467        3662 :         process_single(false);
     468             : 
     469        3662 :         if (IS_TDS50(tds->conn) && !is_sql_anywhere && !is_openserver) {
     470         720 :                 strcat(str, "SELECT CONVERT(NVARCHAR(3), 'abc') nvc\n");
     471         720 :                 if (tds->conn->product_version >= TDS_SYB_VER(12, 0, 0))
     472         720 :                         strcat(str, "EXECUTE ('SELECT CONVERT(UNIVARCHAR(3), ''xyz'') uvc')\n");
     473             :         }
     474        3662 :         process_single(true);
     475             : 
     476             :         /* nothing to set, just return */
     477        3662 :         if (str[0] == 0) {
     478           0 :                 free(str);
     479           0 :                 return TDS_SUCCESS;
     480             :         }
     481             : 
     482        3662 :         erc = tds_submit_query(tds, str);
     483        3662 :         free(str);
     484        3662 :         TDS_PROPAGATE(erc);
     485             : 
     486        3662 :         return tds_parse_login_results(tds, false);
     487             : }
     488             : 
     489             : /**
     490             :  * Do a connection to socket
     491             :  * @param tds connection structure. This should be a non-connected connection.
     492             :  * @return TDS_FAIL or TDS_SUCCESS if a connection was made to the server's port.
     493             :  * @return TDSERROR enumerated type if no TCP/IP connection could be formed. 
     494             :  * @param login info for login
     495             :  * @remark Possible error conditions:
     496             :  *              - TDSESOCK: socket(2) failed: insufficient local resources
     497             :  *              - TDSECONN: connect(2) failed: invalid hostname or port (ETIMEDOUT, ECONNREFUSED, ENETUNREACH)
     498             :  *              - TDSEFCON: connect(2) succeeded, login packet not acknowledged.  
     499             :  *              - TDS_FAIL: connect(2) succeeded, login failed.  
     500             :  */
     501             : static TDSRET
     502        3690 : tds_connect(TDSSOCKET * tds, TDSLOGIN * login, int *p_oserr)
     503             : {
     504        3690 :         int erc = -TDSEFCON;
     505        3690 :         int connect_timeout = 0;
     506        3690 :         bool db_selected = false;
     507             :         struct addrinfo *addrs;
     508             :         int orig_port;
     509        3690 :         bool rerouted = false;
     510             :         /* save to restore during redirected connection */
     511        3690 :         unsigned int orig_mars = login->mars;
     512             : 
     513             :         /*
     514             :          * A major version of 0 means try to guess the TDS version. 
     515             :          * We try them in an order that should work. 
     516             :          */
     517             :         static const TDS_USMALLINT versions[] =
     518             :                 { 0x704
     519             :                 , 0x500
     520             :                 };
     521             : 
     522        3690 :         if (!login->valid_configuration) {
     523           0 :                 tdserror(tds_get_ctx(tds), tds, TDSECONF, 0);
     524           0 :                 return TDS_FAIL;
     525             :         }
     526             : 
     527        3690 :         if (TDS_MAJOR(login) == 0) {
     528             :                 unsigned int i;
     529             :                 TDSSAVECONTEXT save_ctx;
     530           2 :                 const TDSCONTEXT *old_ctx = tds_get_ctx(tds);
     531             :                 typedef void (*env_chg_func_t) (TDSSOCKET * tds, int type, char *oldval, char *newval);
     532           2 :                 env_chg_func_t old_env_chg = tds->env_chg_func;
     533             : 
     534           4 :                 init_save_context(&save_ctx, old_ctx);
     535           2 :                 tds_set_ctx(tds, &save_ctx.ctx);
     536           2 :                 tds->env_chg_func = tds_save_env;
     537             : 
     538           4 :                 for (i = 0; i < TDS_VECTOR_SIZE(versions); ++i) {
     539           4 :                         int orig_size = tds->conn->env.block_size;
     540           4 :                         login->tds_version = versions[i];
     541           4 :                         reset_save_context(&save_ctx);
     542             : 
     543           4 :                         erc = tds_connect(tds, login, p_oserr);
     544           4 :                         if (TDS_FAILED(erc)) {
     545           2 :                                 tds_close_socket(tds);
     546           2 :                                 if (tds->conn->env.block_size != orig_size)
     547           2 :                                         tds_realloc_socket(tds, orig_size);
     548             :                         }
     549             :                         
     550           4 :                         if (erc != -TDSEFCON)   /* TDSEFCON indicates wrong TDS version */
     551             :                                 break;
     552           2 :                         if (login->server_is_valid)
     553             :                                 break;
     554             :                 }
     555             :                 
     556           2 :                 tds->env_chg_func = old_env_chg;
     557           2 :                 tds_set_ctx(tds, old_ctx);
     558           2 :                 replay_save_context(tds, &save_ctx);
     559           2 :                 free_save_context(&save_ctx);
     560             :                 
     561           2 :                 if (TDS_FAILED(erc))
     562           0 :                         tdserror(tds_get_ctx(tds), tds, -erc, *p_oserr);
     563             : 
     564             :                 return erc;
     565             :         }
     566             :         
     567             : 
     568             :         /*
     569             :          * If a dump file has been specified, start logging
     570             :          */
     571        3688 :         if (login->dump_file != NULL && !tdsdump_isopen()) {
     572           0 :                 if (login->debug_flags)
     573           0 :                         tds_debug_flags = login->debug_flags;
     574           0 :                 tdsdump_topen(login->dump_file);
     575             :         }
     576             : 
     577        3688 :         tds->login = login;
     578             : 
     579        3688 :         tds->conn->tds_version = login->tds_version;
     580             : 
     581             :         /* set up iconv if not already initialized*/
     582        3688 :         if (tds->conn->char_convs[client2ucs2]->to.cd == (iconv_t) -1) {
     583        7372 :                 if (!tds_dstr_isempty(&login->client_charset)) {
     584        7372 :                         if (TDS_FAILED(tds_iconv_open(tds->conn, tds_dstr_cstr(&login->client_charset), login->use_utf16)))
     585             :                                 return -TDSEICONVAVAIL;
     586             :                 }
     587             :         }
     588             : 
     589        3688 :         connect_timeout = login->connect_timeout;
     590             : 
     591             :         /* Jeff's hack - begin */
     592        3688 :         tds->query_timeout = connect_timeout ? connect_timeout : login->query_timeout;
     593             :         /* end */
     594             : 
     595             :         /* verify that ip_addr is not empty */
     596        3688 :         if (login->ip_addrs == NULL) {
     597           0 :                 tdserror(tds_get_ctx(tds), tds, TDSEUHST, 0 );
     598           0 :                 tdsdump_log(TDS_DBG_ERROR, "IP address pointer is empty\n");
     599           0 :                 if (!tds_dstr_isempty(&login->server_name)) {
     600           0 :                         tdsdump_log(TDS_DBG_ERROR, "Server %s not found!\n", tds_dstr_cstr(&login->server_name));
     601             :                 } else {
     602           0 :                         tdsdump_log(TDS_DBG_ERROR, "No server specified!\n");
     603             :                 }
     604             :                 return -TDSECONN;
     605             :         }
     606             : 
     607        3688 :         tds->conn->capabilities = login->capabilities;
     608             : 
     609        3688 : reroute:
     610        3688 :         tds_ssl_deinit(tds->conn);
     611        3688 :         erc = TDSEINTF;
     612        3688 :         orig_port = login->port;
     613        3688 :         for (addrs = login->ip_addrs; addrs != NULL; addrs = addrs->ai_next) {
     614             : 
     615             :                 /*
     616             :                  * By some reasons ftds forms 3 linked tds_addrinfo (addrs
     617             :                  * variable here) for one server address. The structures
     618             :                  * differs in their ai_socktype and ai_protocol field
     619             :                  * values. Typically the combinations are:
     620             :                  * ai_socktype     | ai_protocol
     621             :                  * -----------------------------
     622             :                  * 1 (SOCK_STREAM) | 6  (tcp)
     623             :                  * 2 (SOCK_DGRAM)  | 17 (udp)
     624             :                  * 3 (SOCK_RAW)    | 0  (ip)
     625             :                  *
     626             :                  * Later on these fields are not used and dtds always
     627             :                  * creates a tcp socket. In case if there is a connection
     628             :                  * problem this behavior leads to 3 tries with the provided
     629             :                  * timeout which basically multiplies the spent time
     630             :                  * without any good result. So it was decided to skip the
     631             :                  * non tcp addresses.
     632             :                  *
     633             :                  * NOTE: on Windows exactly one tds_addrinfo structure is
     634             :                  *       formed and it has 0 in both ai_socktype and
     635             :                  *       ai_protocol fields. So skipping is conditional for
     636             :                  *       non-Windows platforms
     637             :                  */
     638             : #ifndef _WIN32
     639        3688 :                 if (addrs->ai_socktype != SOCK_STREAM)
     640           0 :                         continue;
     641             : #endif
     642             : 
     643        3688 :                 login->port = orig_port;
     644             : 
     645        6654 :                 if (!IS_TDS50(tds->conn) && !tds_dstr_isempty(&login->instance_name) && !login->port)
     646           4 :                         login->port = tds7_get_instance_port(addrs, tds_dstr_cstr(&login->instance_name));
     647             : 
     648        3688 :                 if (login->port >= 1) {
     649        3688 :                         if ((erc = tds_open_socket(tds, addrs, login->port, connect_timeout, p_oserr)) == TDSEOK)
     650             :                                 break;
     651             :                 } else {
     652             :                         erc = TDSECONN;
     653             :                 }
     654             :         }
     655             : 
     656        3688 :         if (erc != TDSEOK) {
     657           0 :                 if (login->port < 1)
     658           0 :                         tdsdump_log(TDS_DBG_ERROR, "invalid port number\n");
     659             : 
     660           0 :                 tdserror(tds_get_ctx(tds), tds, erc, *p_oserr);
     661           0 :                 return -erc;
     662             :         }
     663             :                 
     664             :         /*
     665             :          * Beyond this point, we're connected to the server.  We know we have a valid TCP/IP address+socket pair.  
     666             :          * Although network errors *might* happen, most problems from here on out will be TDS-level errors, 
     667             :          * either TDS version problems or authentication problems.  
     668             :          */
     669             :                 
     670        3688 :         tds_set_state(tds, TDS_IDLE);
     671        3688 :         tds->conn->spid = -1;
     672             : 
     673             :         /* discard possible previous authentication */
     674        3688 :         if (tds->conn->authentication) {
     675           0 :                 tds->conn->authentication->free(tds->conn, tds->conn->authentication);
     676           0 :                 tds->conn->authentication = NULL;
     677             :         }
     678             : 
     679        3688 :         if (IS_TDS71_PLUS(tds->conn)) {
     680        2956 :                 erc = tds71_do_login(tds, login);
     681        2956 :                 db_selected = true;
     682         732 :         } else if (IS_TDS7_PLUS(tds->conn)) {
     683          10 :                 erc = tds7_send_login(tds, login);
     684          10 :                 db_selected = true;
     685             :         } else {
     686         722 :                 tds->out_flag = TDS_LOGIN;
     687             : 
     688             :                 /* SAP ASE 15.0+ SSL mode encrypts entire connection (like stunnel) */
     689         722 :                 if (login->encryption_level == TDS_ENCRYPTION_STRICT)
     690           0 :                         TDS_PROPAGATE(tds_ssl_init(tds, true));
     691             : 
     692         722 :                 erc = tds_send_login(tds, login);
     693             :         }
     694        3688 :         if (TDS_FAILED(erc) || TDS_FAILED(tds_process_login_tokens(tds))) {
     695          26 :                 tdsdump_log(TDS_DBG_ERROR, "login packet %s\n", TDS_SUCCEED(erc)? "accepted":"rejected");
     696          26 :                 tds_close_socket(tds);
     697          26 :                 tdserror(tds_get_ctx(tds), tds, TDSEFCON, 0);   /* "TDS server connection failed" */
     698          26 :                 return -TDSEFCON;
     699             :         }
     700             : 
     701             :         /* need to do rerouting */
     702        3662 :         if (IS_TDS71_PLUS(tds->conn)
     703        5884 :             && !tds_dstr_isempty(&login->routing_address) && login->routing_port) {
     704             :                 TDSRET ret;
     705           0 :                 char *server_name = NULL;
     706             : 
     707           0 :                 tds_close_socket(tds);
     708             :                 /* only one redirection is allowed */
     709           0 :                 if (rerouted) {
     710           0 :                         tdserror(tds_get_ctx(tds), tds, TDSEFCON, 0);
     711           0 :                         return -TDSEFCON;
     712             :                 }
     713           0 :                 if (asprintf(&server_name, "%s,%d", tds_dstr_cstr(&login->routing_address), login->routing_port) < 0) {
     714           0 :                         tdserror(tds_get_ctx(tds), tds, TDSEFCON, 0);
     715           0 :                         return -TDSEMEM;
     716             :                 }
     717           0 :                 if (!tds_dstr_set(&login->server_name, server_name)) {
     718           0 :                         free(server_name);
     719           0 :                         tdserror(tds_get_ctx(tds), tds, TDSEFCON, 0);
     720           0 :                         return -TDSEMEM;
     721             :                 }
     722           0 :                 login->mars = orig_mars;
     723           0 :                 login->port = login->routing_port;
     724           0 :                 ret = tds_lookup_host_set(tds_dstr_cstr(&login->routing_address), &login->ip_addrs);
     725           0 :                 login->routing_port = 0;
     726           0 :                 tds_dstr_free(&login->routing_address);
     727           0 :                 if (TDS_FAILED(ret)) {
     728           0 :                         tdserror(tds_get_ctx(tds), tds, TDSEFCON, 0);
     729           0 :                         return -TDSEFCON;
     730             :                 }
     731           0 :                 rerouted = true;
     732           0 :                 goto reroute;
     733             :         }
     734             : 
     735             : #if ENABLE_ODBC_MARS
     736             :         /* initialize SID */
     737        1831 :         if (IS_TDS72_PLUS(tds->conn) && login->mars) {
     738             :                 TDS72_SMP_HEADER *p;
     739             : 
     740         215 :                 tds_extra_assert(tds->sid == 0);
     741         215 :                 tds_extra_assert(tds->conn->sessions[0] == tds);
     742         215 :                 tds_extra_assert(tds->send_packet != NULL);
     743         215 :                 tds_extra_assert(!tds->send_packet->next);
     744             : 
     745         215 :                 tds->conn->mars = 1;
     746             : 
     747             :                 /* start session with a SMP SYN */
     748         215 :                 if (TDS_FAILED(tds_append_syn(tds)))
     749             :                         return -TDSEMEM;
     750             : 
     751             :                 /* reallocate send_packet */
     752         215 :                 if (!tds_realloc_socket(tds, tds->out_buf_max))
     753             :                         return -TDSEMEM;
     754             : 
     755             :                 /* start SMP DATA header */
     756         215 :                 p = (TDS72_SMP_HEADER *) tds->send_packet->buf;
     757         215 :                 p->signature = TDS72_SMP;
     758         215 :                 p->type = TDS_SMP_DATA;
     759             : 
     760         215 :                 tds_init_write_buf(tds);
     761             :         }
     762             : #endif
     763             : 
     764        3662 :         erc = tds_setup_connection(tds, login, !db_selected, true);
     765             :         /* try one query at a time, some servers do not support some queries */
     766        3662 :         if (TDS_FAILED(erc))
     767           0 :                 erc = tds_setup_connection(tds, login, !db_selected, false);
     768        3662 :         TDS_PROPAGATE(erc);
     769             : 
     770        3662 :         tds->query_timeout = login->query_timeout;
     771        3662 :         tds->login = NULL;
     772        3662 :         return TDS_SUCCESS;
     773             : }
     774             : 
     775             : TDSRET
     776        3686 : tds_connect_and_login(TDSSOCKET * tds, TDSLOGIN * login)
     777             : {
     778        3686 :         int oserr = 0;
     779             : 
     780        3686 :         TDS_PROPAGATE(tds8_adjust_login(login));
     781             : 
     782        3686 :         return tds_connect(tds, login, &oserr);
     783             : }
     784             : 
     785             : static void
     786        7220 : tds_put_buf(TDSSOCKET * tds, const unsigned char *buf, size_t dsize, size_t ssize)
     787             : {
     788             :         size_t cpsize;
     789             : 
     790        7220 :         cpsize = TDS_MIN(ssize, dsize);
     791        7220 :         tds_put_n(tds, buf, cpsize);
     792        7220 :         dsize -= cpsize;
     793        7220 :         tds_put_n(tds, NULL, dsize);
     794        7220 :         TDS_PUT_BYTE(tds, cpsize);
     795        7220 : }
     796             : 
     797             : static void
     798        5054 : tds_put_login_string(TDSSOCKET * tds, const char *buf, size_t n)
     799             : {
     800        7220 :         const size_t buf_len = buf ? strlen(buf) : 0;
     801        7220 :         tds_put_buf(tds, (const unsigned char *) buf, n, buf_len);
     802        5054 : }
     803             : 
     804             : #define tds_put_login_string(tds, buf, n) do { \
     805             :         TDS_COMPILE_CHECK(range, (n) > 0 && (n) < 256); \
     806             :         tds_put_login_string(tds, buf, (n)); \
     807             : } while(0)
     808             : 
     809             : static TDSRET
     810         722 : tds_send_login(TDSSOCKET * tds, const TDSLOGIN * login)
     811             : {
     812             :         static const unsigned char le1[] = { 0x03, 0x01, 0x06, 0x0a, 0x09, 0x01 };
     813             :         static const unsigned char le2[] = { 0x00, 13, 17 };
     814             : 
     815             :         /*
     816             :          * capabilities are now part of the tds structure.
     817             :          * unsigned char capabilities[]= {0x01,0x07,0x03,109,127,0xFF,0xFF,0xFF,0xFE,0x02,0x07,0x00,0x00,0x0A,104,0x00,0x00,0x00};
     818             :          */
     819             :         /*
     820             :          * This is the original capabilities packet we were working with (sqsh)
     821             :          * unsigned char capabilities[]= {0x01,0x07,0x03,109,127,0xFF,0xFF,0xFF,0xFE,0x02,0x07,0x00,0x00,0x0A,104,0x00,0x00,0x00};
     822             :          * original with 4.x messages
     823             :          * unsigned char capabilities[]= {0x01,0x07,0x03,109,127,0xFF,0xFF,0xFF,0xFE,0x02,0x07,0x00,0x00,0x00,120,192,0x00,0x0D};
     824             :          * This is isql 11.0.3
     825             :          * unsigned char capabilities[]= {0x01,0x07,0x00,96, 129,207, 0xFF,0xFE,62,  0x02,0x07,0x00,0x00,0x00,120,192,0x00,0x0D};
     826             :          * like isql but with 5.0 messages
     827             :          * unsigned char capabilities[]= {0x01,0x07,0x00,96, 129,207, 0xFF,0xFE,62,  0x02,0x07,0x00,0x00,0x00,120,192,0x00,0x00};
     828             :          */
     829             : 
     830             :         unsigned char protocol_version[4];
     831             :         unsigned char program_version[4];
     832         722 :         unsigned char sec_flags = 0;
     833         722 :         bool use_kerberos = false;
     834             : 
     835             :         char blockstr[16];
     836             : 
     837         722 :         TDS_TINYINT encryption_level = login->encryption_level;
     838             : 
     839             :         /* override lservname field for ASA servers */  
     840        1444 :         const char *lservname = getenv("ASA_DATABASE")? getenv("ASA_DATABASE") : tds_dstr_cstr(&login->server_name);
     841             : 
     842        1444 :         if (strchr(tds_dstr_cstr(&login->user_name), '\\') != NULL) {
     843           0 :                 tdsdump_log(TDS_DBG_ERROR, "NT login not supported using TDS 4.x or 5.0\n");
     844             :                 return TDS_FAIL;
     845             :         }
     846        1444 :         if (tds_dstr_isempty(&login->user_name)) {
     847           0 :                 if (!IS_TDS50(tds->conn)) {
     848           0 :                         tdsdump_log(TDS_DBG_ERROR, "Kerberos login not supported using TDS 4.x\n");
     849             :                         return TDS_FAIL;
     850             :                 }
     851             : 
     852             : #ifdef ENABLE_KRB5
     853             :                 /* try kerberos */
     854           0 :                 sec_flags = TDS5_SEC_LOG_SECSESS;
     855           0 :                 use_kerberos = true;
     856           0 :                 tds->conn->authentication = tds_gss_get_auth(tds);
     857           0 :                 if (!tds->conn->authentication)
     858             :                         return TDS_FAIL;
     859             : #else
     860             :                 tdsdump_log(TDS_DBG_ERROR, "requested GSS authentication but not compiled in\n");
     861             :                 return TDS_FAIL;
     862             : #endif
     863             :         }
     864         722 :         if (encryption_level == TDS_ENCRYPTION_DEFAULT)
     865         722 :                 encryption_level = TDS_ENCRYPTION_OFF;
     866         722 :         if (!use_kerberos && encryption_level != TDS_ENCRYPTION_OFF) {
     867           0 :                 if (!IS_TDS50(tds->conn)) {
     868           0 :                         tdsdump_log(TDS_DBG_ERROR, "Encryption not supported using TDS 4.x\n");
     869             :                         return TDS_FAIL;
     870             :                 }
     871           0 :                 tds->conn->authentication = tds5_negotiate_get_auth(tds);
     872           0 :                 if (!tds->conn->authentication)
     873             :                         return TDS_FAIL;
     874             :         }
     875             : 
     876         722 :         if (IS_TDS42(tds->conn)) {
     877           0 :                 memcpy(protocol_version, "\004\002\000\000", 4);
     878           0 :                 memcpy(program_version, "\004\002\000\000", 4);
     879         722 :         } else if (IS_TDS46(tds->conn)) {
     880           0 :                 memcpy(protocol_version, "\004\006\000\000", 4);
     881           0 :                 memcpy(program_version, "\004\002\000\000", 4);
     882         722 :         } else if (IS_TDS50(tds->conn)) {
     883         722 :                 memcpy(protocol_version, "\005\000\000\000", 4);
     884         722 :                 memcpy(program_version, "\005\000\000\000", 4);
     885             :         } else {
     886           0 :                 tdsdump_log(TDS_DBG_SEVERE, "Unknown protocol version!\n");
     887             :                 return TDS_FAIL;
     888             :         }
     889             :         /*
     890             :          * the following code is adapted from  Arno Pedusaar's 
     891             :          * (psaar@fenar.ee) MS-SQL Client. His was a much better way to
     892             :          * do this, (well...mine was a kludge actually) so here's mostly his
     893             :          */
     894             : 
     895        1444 :         tds_put_login_string(tds, tds_dstr_cstr(&login->client_host_name), TDS_MAXNAME); /* client host name */
     896        1444 :         tds_put_login_string(tds, tds_dstr_cstr(&login->user_name), TDS_MAXNAME);        /* account name */
     897             :         /* account password */
     898         722 :         if (encryption_level != TDS_ENCRYPTION_OFF) {
     899             :                 tds_put_login_string(tds, NULL, TDS_MAXNAME);
     900             :         } else {
     901        1444 :                 tds_put_login_string(tds, tds_dstr_cstr(&login->password), TDS_MAXNAME);
     902             :         }
     903         722 :         sprintf(blockstr, "%d", (int) getpid());
     904         722 :         tds_put_login_string(tds, blockstr, TDS_MAXNAME);       /* host process */
     905         722 :         tds_put_n(tds, le1, 6);
     906         722 :         tds_put_byte(tds, !login->bulk_copy);
     907         722 :         tds_put_n(tds, NULL, 2);
     908         722 :         if (IS_TDS42(tds->conn)) {
     909           0 :                 tds_put_int(tds, 512);
     910             :         } else {
     911         722 :                 tds_put_int(tds, 0);
     912             :         }
     913         722 :         tds_put_n(tds, NULL, 3);
     914        1444 :         tds_put_login_string(tds, tds_dstr_cstr(&login->app_name), TDS_MAXNAME);
     915         722 :         tds_put_login_string(tds, lservname, TDS_MAXNAME);
     916         722 :         if (IS_TDS42(tds->conn)) {
     917           0 :                 tds_put_login_string(tds, tds_dstr_cstr(&login->password), 255);
     918         722 :         } else if (encryption_level != TDS_ENCRYPTION_OFF) {
     919           0 :                 tds_put_n(tds, NULL, 256);
     920             :         } else {
     921        1444 :                 size_t len = tds_dstr_len(&login->password);
     922         722 :                 if (len > 253)
     923           0 :                         len = 0;
     924         722 :                 tds_put_byte(tds, 0);
     925         722 :                 TDS_PUT_BYTE(tds, len);
     926        1444 :                 tds_put_n(tds, tds_dstr_cstr(&login->password), len);
     927         722 :                 tds_put_n(tds, NULL, 253 - len);
     928         722 :                 TDS_PUT_BYTE(tds, len + 2);
     929             :         }
     930             : 
     931         722 :         tds_put_n(tds, protocol_version, 4);    /* TDS version; { 0x04,0x02,0x00,0x00 } */
     932        1444 :         tds_put_login_string(tds, tds_dstr_cstr(&login->library), TDS_PROGNLEN); /* client program name */
     933         722 :         if (IS_TDS42(tds->conn)) {
     934           0 :                 tds_put_int(tds, 0);
     935             :         } else {
     936         722 :                 tds_put_n(tds, program_version, 4);     /* program version ? */
     937             :         }
     938         722 :         tds_put_n(tds, le2, 3);
     939        1444 :         tds_put_login_string(tds, tds_dstr_cstr(&login->language), TDS_MAXNAME); /* language */
     940         722 :         tds_put_byte(tds, login->suppress_language);
     941             : 
     942             :         /* oldsecure(2), should be zero, used by old software */
     943         722 :         tds_put_n(tds, NULL, 2);
     944             :         /* seclogin(1) bitmask */
     945         722 :         if (sec_flags == 0 && encryption_level != TDS_ENCRYPTION_OFF)
     946           0 :                 sec_flags = TDS5_SEC_LOG_ENCRYPT2|TDS5_SEC_LOG_ENCRYPT3;
     947         722 :         tds_put_byte(tds, sec_flags);
     948             :         /* secbulk(1)
     949             :          * halogin(1) type of ha login
     950             :          * hasessionid(6) id of session to reconnect
     951             :          * secspare(2) not used
     952             :          */
     953         722 :         tds_put_n(tds, NULL, 10);
     954             : 
     955             :         /* use empty charset to handle conversions on client */
     956         722 :         tds_put_login_string(tds, "", TDS_MAXNAME);   /* charset */
     957             :         /* this is a flag, mean that server should use character set provided by client */
     958             :         /* TODO notify charset change ?? what's correct meaning ?? -- freddy77 */
     959         722 :         tds_put_byte(tds, 1);
     960             : 
     961             :         /* network packet size */
     962         722 :         if (login->block_size < 65536u && login->block_size >= 512)
     963           0 :                 sprintf(blockstr, "%d", login->block_size);
     964             :         else
     965         722 :                 strcpy(blockstr, "512");
     966         722 :         tds_put_login_string(tds, blockstr, TDS_PKTLEN);
     967             : 
     968         722 :         if (IS_TDS42(tds->conn)) {
     969           0 :                 tds_put_n(tds, NULL, 8);
     970         722 :         } else if (IS_TDS46(tds->conn)) {
     971           0 :                 tds_put_n(tds, NULL, 4);
     972         722 :         } else if (IS_TDS50(tds->conn)) {
     973             :                 /* just padding to 8 bytes */
     974         722 :                 tds_put_n(tds, NULL, 4);
     975             : 
     976             :                 /* send capabilities */
     977         722 :                 tds_put_byte(tds, TDS_CAPABILITY_TOKEN);
     978         722 :                 tds_put_smallint(tds, sizeof(tds->conn->capabilities));
     979         722 :                 tds_put_n(tds, &tds->conn->capabilities, sizeof(tds->conn->capabilities));
     980             :         }
     981             : 
     982             : #ifdef ENABLE_KRB5
     983         722 :         if (use_kerberos)
     984           0 :                 tds5_gss_send(tds);
     985             : #endif
     986             : 
     987         722 :         return tds_flush_packet(tds);
     988             : }
     989             : 
     990             : /**
     991             :  * tds7_send_login() -- Send a TDS 7.0 login packet
     992             :  * TDS 7.0 login packet is vastly different and so gets its own function
     993             :  * \returns the return value is ignored by the caller. :-/
     994             :  */
     995             : static TDSRET
     996        2964 : tds7_send_login(TDSSOCKET * tds, const TDSLOGIN * login)
     997             : {
     998             :         static const unsigned char 
     999             :                 client_progver[] = {   6, 0x83, 0xf2, 0xf8 }, 
    1000             : 
    1001             :                 connection_id[] = { 0x00, 0x00, 0x00, 0x00 }, 
    1002             :                 collation[] = { 0x36, 0x04, 0x00, 0x00 };
    1003             : 
    1004             :         enum {
    1005             :                 tds70Version = 0x70000000,
    1006             :                 tds71Version = 0x71000001,
    1007             :                 tds72Version = 0x72090002,
    1008             :                 tds73Version = 0x730B0003,
    1009             :                 tds74Version = 0x74000004,
    1010             :         };
    1011        2964 :         TDS_UCHAR sql_type_flag = 0x00;
    1012        2964 :         TDS_INT time_zone = -120;
    1013        2964 :         TDS_INT tds7version = tds70Version;
    1014             : 
    1015        2964 :         unsigned int block_size = 4096;
    1016             :         
    1017        2964 :         unsigned char option_flag1 = TDS_SET_LANG_ON | TDS_USE_DB_NOTIFY | TDS_INIT_DB_FATAL;
    1018        2964 :         unsigned char option_flag2 = login->option_flag2;
    1019        2964 :         unsigned char option_flag3 = 0;
    1020             : 
    1021             :         unsigned char hwaddr[6];
    1022             :         size_t packet_size, current_pos;
    1023             :         TDSRET rc;
    1024             : 
    1025        2964 :         void *data = NULL;
    1026             :         TDSDYNAMICSTREAM data_stream;
    1027             :         TDSSTATICINSTREAM input;
    1028             : 
    1029        5928 :         const char *user_name = tds_dstr_cstr(&login->user_name);
    1030             :         unsigned char *pwd;
    1031             : 
    1032             :         /* FIXME: These should be TDS_SMALLINT. */
    1033        2964 :         size_t user_name_len = strlen(user_name);
    1034        2964 :         unsigned int auth_len = 0;
    1035             : 
    1036             :         static const char ext_data[] =
    1037             :                 "\x0a\x01\x00\x00\x00\x01"    /* Enable UTF-8 */
    1038             :                 "\xff";
    1039        2964 :         size_t ext_len = IS_TDS74_PLUS(tds->conn) ? sizeof(ext_data) - 1 : 0;
    1040             : 
    1041             :         /* fields */
    1042             :         enum {
    1043             :                 HOST_NAME,
    1044             :                 USER_NAME,
    1045             :                 PASSWORD,
    1046             :                 APP_NAME,
    1047             :                 SERVER_NAME,
    1048             :                 EXTENSION,
    1049             :                 LIBRARY_NAME,
    1050             :                 LANGUAGE,
    1051             :                 DATABASE_NAME,
    1052             :                 DB_FILENAME,
    1053             :                 NEW_PASSWORD,
    1054             :                 NUM_DATA_FIELDS
    1055             :         };
    1056             :         struct {
    1057             :                 const void *ptr;
    1058             :                 size_t pos, len, limit;
    1059             :         } data_fields[NUM_DATA_FIELDS], *field;
    1060             : 
    1061        2964 :         tds->out_flag = TDS7_LOGIN;
    1062             : 
    1063        2964 :         current_pos = packet_size = IS_TDS72_PLUS(tds->conn) ? 86 + 8 : 86;  /* ? */
    1064             : 
    1065             :         /* check ntlm */
    1066             : #ifdef HAVE_SSPI
    1067             :         if (strchr(user_name, '\\') != NULL || user_name_len == 0) {
    1068             :                 tdsdump_log(TDS_DBG_INFO2, "using SSPI authentication for '%s' account\n", user_name);
    1069             :                 tds->conn->authentication = tds_sspi_get_auth(tds);
    1070             :                 if (!tds->conn->authentication)
    1071             :                         return TDS_FAIL;
    1072             :                 auth_len = tds->conn->authentication->packet_len;
    1073             :                 packet_size += auth_len;
    1074             : #else
    1075        2964 :         if (strchr(user_name, '\\') != NULL) {
    1076         720 :                 tdsdump_log(TDS_DBG_INFO2, "using NTLM authentication for '%s' account\n", user_name);
    1077         720 :                 tds->conn->authentication = tds_ntlm_get_auth(tds);
    1078         720 :                 if (!tds->conn->authentication)
    1079             :                         return TDS_FAIL;
    1080         720 :                 auth_len = tds->conn->authentication->packet_len;
    1081         720 :                 packet_size += auth_len;
    1082        2244 :         } else if (user_name_len == 0) {
    1083             : # ifdef ENABLE_KRB5
    1084             :                 /* try kerberos */
    1085           0 :                 tdsdump_log(TDS_DBG_INFO2, "using GSS authentication\n");
    1086           0 :                 tds->conn->authentication = tds_gss_get_auth(tds);
    1087           0 :                 if (!tds->conn->authentication)
    1088             :                         return TDS_FAIL;
    1089           0 :                 auth_len = tds->conn->authentication->packet_len;
    1090           0 :                 packet_size += auth_len;
    1091             : # else
    1092             :                 tdsdump_log(TDS_DBG_ERROR, "requested GSS authentication but not compiled in\n");
    1093             :                 return TDS_FAIL;
    1094             : # endif
    1095             : #endif
    1096             :         }
    1097             : 
    1098             : 
    1099             :         /* initialize ouput buffer for strings */
    1100        2964 :         TDS_PROPAGATE(tds_dynamic_stream_init(&data_stream, &data, 0));
    1101             : 
    1102             : #define SET_FIELD_DSTR(field, dstr, len_limit) do { \
    1103             :         data_fields[field].ptr = tds_dstr_cstr(&(dstr)); \
    1104             :         data_fields[field].len = tds_dstr_len(&(dstr)); \
    1105             :         data_fields[field].limit = (len_limit) * 2; \
    1106             :         } while(0)
    1107             : 
    1108             :         /* setup data fields */
    1109        2964 :         memset(data_fields, 0, sizeof(data_fields));
    1110        8892 :         SET_FIELD_DSTR(HOST_NAME, login->client_host_name, 128);
    1111        2964 :         if (!tds->conn->authentication) {
    1112        6732 :                 SET_FIELD_DSTR(USER_NAME, login->user_name, 128);
    1113        6732 :                 SET_FIELD_DSTR(PASSWORD, login->password, 128);
    1114             :         }
    1115        8892 :         SET_FIELD_DSTR(APP_NAME, login->app_name, 128);
    1116        8892 :         SET_FIELD_DSTR(SERVER_NAME, login->server_name, 128);
    1117        8892 :         SET_FIELD_DSTR(LIBRARY_NAME, login->library, 128);
    1118        8892 :         SET_FIELD_DSTR(LANGUAGE, login->language, 128);
    1119        8892 :         SET_FIELD_DSTR(DATABASE_NAME, login->database, 128);
    1120        8892 :         SET_FIELD_DSTR(DB_FILENAME, login->db_filename, 260);
    1121        2964 :         if (IS_TDS72_PLUS(tds->conn) && login->use_new_password) {
    1122           2 :                 option_flag3 |= TDS_CHANGE_PASSWORD;
    1123           6 :                 SET_FIELD_DSTR(NEW_PASSWORD, login->new_password, 128);
    1124             :         }
    1125        2964 :         if (ext_len)
    1126         726 :                 option_flag3 |= TDS_EXTENSION;
    1127             : 
    1128             :         /* convert data fields */
    1129       35568 :         for (field = data_fields; field < data_fields + TDS_VECTOR_SIZE(data_fields); ++field) {
    1130             :                 size_t data_pos;
    1131             : 
    1132       32604 :                 data_pos = data_stream.size;
    1133       32604 :                 field->pos = current_pos + data_pos;
    1134       32604 :                 if (field->len) {
    1135       17468 :                         tds_staticin_stream_init(&input, field->ptr, field->len);
    1136       17468 :                         rc = tds_convert_stream(tds, tds->conn->char_convs[client2ucs2], to_server, &input.stream, &data_stream.stream);
    1137       17468 :                         if (TDS_FAILED(rc)) {
    1138           0 :                                 free(data);
    1139           0 :                                 return TDS_FAIL;
    1140             :                         }
    1141       15136 :                 } else if (ext_len && field == &data_fields[EXTENSION]) {
    1142             :                         /* reserve 4 bytes in the stream to put the extention offset */
    1143         726 :                         if (data_stream.stream.write(&data_stream.stream, 4) != 4) {
    1144           0 :                                 free(data);
    1145           0 :                                 return TDS_FAIL;
    1146             :                         }
    1147         726 :                         field->len = 4;
    1148         726 :                         continue;
    1149             :                 }
    1150       31878 :                 data_stream.size = TDS_MIN(data_stream.size, data_pos + field->limit);
    1151       31878 :                 data_stream.stream.write(&data_stream.stream, 0);
    1152       31878 :                 field->len = data_stream.size - data_pos;
    1153             :         }
    1154        2964 :         pwd = (unsigned char *) data + data_fields[PASSWORD].pos - current_pos;
    1155        5928 :         tds7_crypt_pass(pwd, data_fields[PASSWORD].len, pwd);
    1156        2964 :         pwd = (unsigned char *) data + data_fields[NEW_PASSWORD].pos - current_pos;
    1157        5928 :         tds7_crypt_pass(pwd, data_fields[NEW_PASSWORD].len, pwd);
    1158        2964 :         packet_size += data_stream.size;
    1159        2964 :         if (ext_len) {
    1160         726 :                 packet_size += ext_len;
    1161         726 :                 pwd = (unsigned char *) data + data_fields[EXTENSION].pos - current_pos;
    1162         726 :                 TDS_PUT_UA4LE(pwd, current_pos + data_stream.size + auth_len);
    1163             :         }
    1164             : 
    1165             : #if !defined(TDS_DEBUG_LOGIN)
    1166        2964 :         tdsdump_log(TDS_DBG_INFO2, "quietly sending TDS 7+ login packet\n");
    1167             :         do { TDSDUMP_OFF_ITEM off_item;
    1168        2964 :         tdsdump_off(&off_item);
    1169             : #endif
    1170        2964 :         TDS_PUT_INT(tds, packet_size);
    1171        2964 :         switch (login->tds_version) {
    1172             :         case 0x700:
    1173             :                 tds7version = tds70Version;
    1174             :                 break;
    1175        1486 :         case 0x701:
    1176        1486 :                 tds7version = tds71Version;
    1177        1486 :                 break;
    1178           0 :         case 0x702:
    1179           0 :                 tds7version = tds72Version;
    1180           0 :                 break;
    1181         742 :         case 0x703:
    1182         742 :                 tds7version = tds73Version;
    1183         742 :                 break;
    1184         726 :         case 0x800:
    1185             :                 /* for TDS 8.0 version should be ignored and ALPN used,
    1186             :                  * practically clients/servers usually set this to 7.4 */
    1187             :         case 0x704:
    1188         726 :                 tds7version = tds74Version;
    1189         726 :                 break;
    1190             :         default:
    1191           0 :                 assert(0 && 0x700 <= login->tds_version && login->tds_version <= 0x704);
    1192             :         }
    1193             :         
    1194        2964 :         tds_put_int(tds, tds7version);
    1195             : 
    1196        2964 :         if (4096 <= login->block_size && login->block_size < 65536u)
    1197           0 :                 block_size = login->block_size;
    1198             : 
    1199        2964 :         tds_put_int(tds, block_size);   /* desired packet size being requested by client */
    1200             : 
    1201        2964 :         if (block_size > tds->out_buf_max)
    1202          10 :                 tds_realloc_socket(tds, block_size);
    1203             : 
    1204        2964 :         tds_put_n(tds, client_progver, sizeof(client_progver)); /* client program version ? */
    1205             : 
    1206        2964 :         tds_put_int(tds, getpid());     /* process id of this process */
    1207             : 
    1208        2964 :         tds_put_n(tds, connection_id, sizeof(connection_id));
    1209             : 
    1210        2964 :         if (!login->bulk_copy)
    1211           0 :                 option_flag1 |= TDS_DUMPLOAD_OFF;
    1212             :                 
    1213        2964 :         tds_put_byte(tds, option_flag1);
    1214             : 
    1215        2964 :         if (tds->conn->authentication)
    1216         720 :                 option_flag2 |= TDS_INTEGRATED_SECURITY_ON;
    1217             : 
    1218        2964 :         tds_put_byte(tds, option_flag2);
    1219             : 
    1220        2964 :         if (login->readonly_intent && IS_TDS71_PLUS(tds->conn))
    1221           0 :                 sql_type_flag |= TDS_READONLY_INTENT;
    1222        2964 :         tds_put_byte(tds, sql_type_flag);
    1223             : 
    1224        2964 :         if (IS_TDS73_PLUS(tds->conn))
    1225        1468 :                 option_flag3 |= TDS_UNKNOWN_COLLATION_HANDLING;
    1226        2964 :         tds_put_byte(tds, option_flag3);
    1227             : 
    1228        2964 :         tds_put_int(tds, time_zone);
    1229        2964 :         tds_put_n(tds, collation, sizeof(collation));
    1230             : 
    1231             : #define PUT_STRING_FIELD_PTR(field) do { \
    1232             :         TDS_PUT_SMALLINT(tds, data_fields[field].pos); \
    1233             :         TDS_PUT_SMALLINT(tds, data_fields[field].len / 2u); \
    1234             :         } while(0)
    1235             : 
    1236             :         /* host name */
    1237        2964 :         PUT_STRING_FIELD_PTR(HOST_NAME);
    1238        2964 :         if (tds->conn->authentication) {
    1239         720 :                 tds_put_int(tds, 0);
    1240         720 :                 tds_put_int(tds, 0);
    1241             :         } else {
    1242             :                 /* username */
    1243        2244 :                 PUT_STRING_FIELD_PTR(USER_NAME);
    1244             :                 /* password */
    1245        2244 :                 PUT_STRING_FIELD_PTR(PASSWORD);
    1246             :         }
    1247             :         /* app name */
    1248        2964 :         PUT_STRING_FIELD_PTR(APP_NAME);
    1249             :         /* server name */
    1250        2964 :         PUT_STRING_FIELD_PTR(SERVER_NAME);
    1251             :         /* extensions */
    1252        2964 :         if (ext_len) {
    1253         726 :                 TDS_PUT_SMALLINT(tds, data_fields[EXTENSION].pos);
    1254         726 :                 tds_put_smallint(tds, 4);
    1255             :         } else {
    1256        2238 :                 tds_put_int(tds, 0);
    1257             :         }
    1258             :         /* library name */
    1259        2964 :         PUT_STRING_FIELD_PTR(LIBRARY_NAME);
    1260             :         /* language  - kostya@warmcat.excom.spb.su */
    1261        2964 :         PUT_STRING_FIELD_PTR(LANGUAGE);
    1262             :         /* database name */
    1263        2964 :         PUT_STRING_FIELD_PTR(DATABASE_NAME);
    1264             : 
    1265             :         /* MAC address */
    1266        2964 :         tds_getmac(tds_get_s(tds), hwaddr);
    1267        2964 :         tds_put_n(tds, hwaddr, 6);
    1268             : 
    1269             :         /* authentication stuff */
    1270        2964 :         TDS_PUT_SMALLINT(tds, current_pos + data_stream.size);
    1271        2964 :         TDS_PUT_SMALLINT(tds, TDS_MIN(auth_len, 0xffffu));
    1272             : 
    1273             :         /* db file */
    1274        2964 :         PUT_STRING_FIELD_PTR(DB_FILENAME);
    1275             : 
    1276        2964 :         if (IS_TDS72_PLUS(tds->conn)) {
    1277             :                 /* new password */
    1278        1468 :                 PUT_STRING_FIELD_PTR(NEW_PASSWORD);
    1279             : 
    1280             :                 /* SSPI long */
    1281        1468 :                 tds_put_int(tds, auth_len >= 0xffffu ? auth_len : 0);
    1282             :         }
    1283             : 
    1284        2964 :         tds_put_n(tds, data, data_stream.size);
    1285             : 
    1286        2964 :         if (tds->conn->authentication)
    1287         720 :                 tds_put_n(tds, tds->conn->authentication->packet, auth_len);
    1288             : 
    1289        2964 :         if (ext_len)
    1290         726 :                 tds_put_n(tds, ext_data, ext_len);
    1291             : 
    1292        2964 :         rc = tds_flush_packet(tds);
    1293             : 
    1294             : #if !defined(TDS_DEBUG_LOGIN)
    1295        2964 :         tdsdump_on(&off_item);
    1296             :         } while(0);
    1297             : #endif
    1298             : 
    1299        2964 :         free(data);
    1300        2964 :         return rc;
    1301             : }
    1302             : 
    1303             : /**
    1304             :  * tds7_crypt_pass() -- 'encrypt' TDS 7.0 style passwords.
    1305             :  * the calling function is responsible for ensuring crypt_pass is at least 
    1306             :  * 'len' characters
    1307             :  */
    1308             : static void
    1309             : tds7_crypt_pass(const unsigned char *clear_pass, size_t len, unsigned char *crypt_pass)
    1310             : {
    1311             :         size_t i;
    1312             : 
    1313       51996 :         for (i = 0; i < len; i++)
    1314       49032 :                 crypt_pass[i] = ((clear_pass[i] << 4) | (clear_pass[i] >> 4)) ^ 0xA5;
    1315             : }
    1316             : 
    1317             : #if defined(HAVE_GNUTLS) || defined(HAVE_OPENSSL)
    1318             : static inline TDS_TINYINT
    1319             : tds7_get_encryption_byte(TDS_TINYINT encryption_level)
    1320             : {
    1321        2956 :         switch (encryption_level) {
    1322             :         /* The observation working with Microsoft SQL Server is that
    1323             :            OFF did not mean off, and you would end up with encryption
    1324             :            turned on. Therefore when the freetds.conf says encrypt = off
    1325             :            we really want no encryption, and claiming lack of support
    1326             :            works for that. Note that the configuration default in this
    1327             :            subroutine always been request due to code above that
    1328             :            tests for TDS_ENCRYPTION_DEFAULT.
    1329             :         */
    1330             :         case TDS_ENCRYPTION_OFF:
    1331             :         case TDS_ENCRYPTION_STRICT:
    1332             :                 return TDS7_ENCRYPT_NOT_SUP;
    1333        1448 :         case TDS_ENCRYPTION_REQUIRE:
    1334             :                 return TDS7_ENCRYPT_ON;
    1335             :         }
    1336             :         return TDS7_ENCRYPT_OFF;
    1337             : }
    1338             : #endif
    1339             : 
    1340             : static TDSRET
    1341        2956 : tds71_do_login(TDSSOCKET * tds, TDSLOGIN* login)
    1342             : {
    1343             :         int i, pkt_len;
    1344        8868 :         const char *instance_name = tds_dstr_isempty(&login->instance_name) ? "MSSQLServer" : tds_dstr_cstr(&login->instance_name);
    1345        2956 :         TDS_USMALLINT instance_name_len = strlen(instance_name) + 1;
    1346             :         TDS_CHAR crypt_flag;
    1347        2956 :         unsigned int start_pos = 21;
    1348             :         TDSRET ret;
    1349        2956 :         bool mars_replied = false;
    1350             : 
    1351             : #define START_POS 21
    1352             : #define UI16BE(n) ((n) >> 8), ((n) & 0xffu)
    1353             : #define SET_UI16BE(i,n) TDS_PUT_UA2BE(&buf[i],n)
    1354        2956 :         TDS_UCHAR buf[] = {
    1355             :                 /* netlib version */
    1356             :                 0, UI16BE(START_POS), UI16BE(6),
    1357             :                 /* encryption */
    1358             :                 1, UI16BE(START_POS + 6), UI16BE(1),
    1359             :                 /* instance */
    1360             :                 2, UI16BE(START_POS + 6 + 1), UI16BE(0),
    1361             :                 /* process id */
    1362             :                 3, UI16BE(0), UI16BE(4),
    1363             :                 /* MARS enables */
    1364             :                 4, UI16BE(0), UI16BE(1),
    1365             :                 /* end */
    1366             :                 0xff
    1367             :         };
    1368             :         static const TDS_UCHAR netlib8[] = { 8, 0, 1, 0x55, 0, 0 };
    1369             :         static const TDS_UCHAR netlib9[] = { 9, 0, 0,    0, 0, 0 };
    1370             : 
    1371             :         TDS_UCHAR *p;
    1372             : 
    1373        2956 :         TDS_TINYINT encryption_level = login->encryption_level;
    1374             : 
    1375        2956 :         SET_UI16BE(13, instance_name_len);
    1376        2956 :         if (!IS_TDS72_PLUS(tds->conn)) {
    1377        1486 :                 SET_UI16BE(16, START_POS + 6 + 1 + instance_name_len);
    1378             :                 /* strip MARS setting */
    1379        1486 :                 buf[20] = 0xff;
    1380             :         } else {
    1381        1470 :                 start_pos += 5;
    1382             : #undef  START_POS
    1383             : #define START_POS 26
    1384        1470 :                 SET_UI16BE(1, START_POS);
    1385        1470 :                 SET_UI16BE(6, START_POS + 6);
    1386        1470 :                 SET_UI16BE(11, START_POS + 6 + 1);
    1387        1470 :                 SET_UI16BE(16, START_POS + 6 + 1 + instance_name_len);
    1388        1470 :                 SET_UI16BE(21, START_POS + 6 + 1 + instance_name_len + 4);
    1389             :         }
    1390             : 
    1391             :         assert(start_pos >= 21 && start_pos <= sizeof(buf));
    1392        2956 :         assert(buf[start_pos-1] == 0xff);
    1393             : 
    1394        2956 :         if (encryption_level == TDS_ENCRYPTION_DEFAULT)
    1395             :                 encryption_level = TDS_ENCRYPTION_REQUEST;
    1396             : 
    1397             :         /* all encrypted */
    1398        1468 :         if (encryption_level == TDS_ENCRYPTION_STRICT)
    1399           0 :                 TDS_PROPAGATE(tds_ssl_init(tds, true));
    1400             : 
    1401             :         /*
    1402             :          * fix a problem with mssql2k which doesn't like
    1403             :          * packet splitted during SSL handshake
    1404             :          */
    1405        2956 :         if (tds->out_buf_max < 4096)
    1406        2956 :                 tds_realloc_socket(tds, 4096);
    1407             : 
    1408             :         /* do prelogin */
    1409        2956 :         tds->out_flag = TDS71_PRELOGIN;
    1410             : 
    1411        2956 :         tds_put_n(tds, buf, start_pos);
    1412             :         /* netlib version */
    1413        2956 :         tds_put_n(tds, IS_TDS72_PLUS(tds->conn) ? netlib9 : netlib8, 6);
    1414             :         /* encryption */
    1415             : #if !defined(HAVE_GNUTLS) && !defined(HAVE_OPENSSL)
    1416             :         /* not supported */
    1417             :         tds_put_byte(tds, TDS7_ENCRYPT_NOT_SUP);
    1418             : #else
    1419        2956 :         tds_put_byte(tds, tds7_get_encryption_byte(encryption_level));
    1420             : #endif
    1421             :         /* instance */
    1422        2956 :         tds_put_n(tds, instance_name, instance_name_len);
    1423             :         /* pid */
    1424        2956 :         tds_put_int(tds, getpid());
    1425             :         /* MARS (1 enabled) */
    1426        2956 :         if (IS_TDS72_PLUS(tds->conn))
    1427             : #if ENABLE_ODBC_MARS
    1428         735 :                 tds_put_byte(tds, login->mars);
    1429        1478 :         login->mars = 0;
    1430             : #else
    1431         735 :                 tds_put_byte(tds, 0);
    1432             : #endif
    1433        2956 :         TDS_PROPAGATE(tds_flush_packet(tds));
    1434             : 
    1435             :         /* now process reply from server */
    1436        2956 :         ret = tds_read_packet(tds);
    1437        2956 :         if (ret <= 0 || tds->in_flag != TDS_REPLY)
    1438             :                 return TDS_FAIL;
    1439        2954 :         login->server_is_valid = 1;
    1440        2954 :         pkt_len = tds->in_len - tds->in_pos;
    1441             : 
    1442             :         /* the only thing we care is flag */
    1443        2954 :         p = tds->in_buf + tds->in_pos;
    1444             :         /* default 2, no certificate, no encryption */
    1445        2954 :         crypt_flag = TDS7_ENCRYPT_NOT_SUP;
    1446       16964 :         for (i = 0;; i += 5) {
    1447             :                 TDS_UCHAR type;
    1448             :                 int off, len;
    1449             : 
    1450       16964 :                 if (i >= pkt_len)
    1451             :                         return TDS_FAIL;
    1452       16964 :                 type = p[i];
    1453       16964 :                 if (type == 0xff)
    1454             :                         break;
    1455             :                 /* check packet */
    1456       14010 :                 if (i+4 >= pkt_len)
    1457             :                         return TDS_FAIL;
    1458       14010 :                 off = TDS_GET_UA2BE(&p[i+1]);
    1459       14010 :                 len = TDS_GET_UA2BE(&p[i+3]);
    1460       14010 :                 if (off > pkt_len || (off+len) > pkt_len)
    1461             :                         return TDS_FAIL;
    1462       14010 :                 if (type == 1 && len >= 1) {
    1463        2954 :                         crypt_flag = p[off];
    1464             :                 }
    1465       14010 :                 if (IS_TDS72_PLUS(tds->conn) && type == 4 && len >= 1) {
    1466        1468 :                         mars_replied = true;
    1467             : #if ENABLE_ODBC_MARS
    1468         734 :                         login->mars = !!p[off];
    1469             : #endif
    1470             :                 }
    1471             :         }
    1472             :         /* we readed all packet */
    1473        2954 :         tds->in_pos += pkt_len;
    1474             :         /* TODO some mssql version do not set last packet, update tds according */
    1475             : 
    1476        2954 :         tdsdump_log(TDS_DBG_INFO1, "detected crypt flag %d\n", crypt_flag);
    1477             : 
    1478        2954 :         if (!mars_replied && encryption_level != TDS_ENCRYPTION_STRICT)
    1479        1486 :                 tds->conn->tds_version = 0x701;
    1480             : 
    1481             :         /* if server does not have certificate or TLS already setup do normal login */
    1482        2954 :         if (crypt_flag == TDS7_ENCRYPT_NOT_SUP || encryption_level == TDS_ENCRYPTION_STRICT) {
    1483             :                 /* unless we wanted encryption and got none, then fail */
    1484         772 :                 if (encryption_level == TDS_ENCRYPTION_REQUIRE)
    1485             :                         return TDS_FAIL;
    1486             : 
    1487         772 :                 return tds7_send_login(tds, login);
    1488             :         }
    1489             : 
    1490             :         /*
    1491             :          * if server has a certificate it requires at least a crypted login
    1492             :          * (even if data is not encrypted)
    1493             :          */
    1494             : 
    1495             :         /* here we have to do encryption ... */
    1496             : 
    1497        2182 :         TDS_PROPAGATE(tds_ssl_init(tds, false));
    1498             : 
    1499             :         /* server just encrypt the first packet */
    1500        2182 :         if (crypt_flag == TDS7_ENCRYPT_OFF)
    1501         734 :                 tds->conn->encrypt_single_packet = 1;
    1502             : 
    1503        2182 :         ret = tds7_send_login(tds, login);
    1504             : 
    1505             :         /* if flag is TDS7_ENCRYPT_OFF(0) it means that after login server continue not encrypted */
    1506        2182 :         if (crypt_flag == TDS7_ENCRYPT_OFF || TDS_FAILED(ret))
    1507         734 :                 tds_ssl_deinit(tds->conn);
    1508             : 
    1509             :         return ret;
    1510             : }
    1511             : 

Generated by: LCOV version 1.13