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

Generated by: LCOV version 1.13