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