LCOV - code coverage report
Current view: top level - src/tds - login.c (source / functions) Hit Total Coverage
Test: FreeTDS coverage Lines: 457 568 80.5 %
Date: 2024-03-23 09:12:27 Functions: 25 27 92.6 %

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

Generated by: LCOV version 1.13