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