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 :
|