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) 2006, 2007, 2008, 2009, 2010, 2011 Frediano Ziglio
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_ERRNO_H
27 : #include <errno.h>
28 : #endif /* HAVE_ERRNO_H */
29 :
30 : #include <assert.h>
31 : #include <ctype.h>
32 :
33 : #if HAVE_STDLIB_H
34 : #include <stdlib.h>
35 : #endif /* HAVE_STDLIB_H */
36 :
37 : #if HAVE_LIMITS_H
38 : #include <limits.h>
39 : #endif
40 :
41 : #if HAVE_STRING_H
42 : #include <string.h>
43 : #endif /* HAVE_STRING_H */
44 :
45 : #if HAVE_UNISTD_H
46 : #include <unistd.h>
47 : #endif /* HAVE_UNISTD_H */
48 :
49 : #if HAVE_NETDB_H
50 : #include <netdb.h>
51 : #endif /* HAVE_NETDB_H */
52 :
53 : #if HAVE_SYS_SOCKET_H
54 : #include <sys/socket.h>
55 : #endif /* HAVE_SYS_SOCKET_H */
56 :
57 : #if HAVE_SYS_TYPES_H
58 : #include <sys/types.h>
59 : #endif /* HAVE_SYS_TYPES_H */
60 :
61 : #if HAVE_NETINET_IN_H
62 : #include <netinet/in.h>
63 : #endif /* HAVE_NETINET_IN_H */
64 :
65 : #if HAVE_ARPA_INET_H
66 : #include <arpa/inet.h>
67 : #endif /* HAVE_ARPA_INET_H */
68 :
69 : #ifdef _WIN32
70 : #include <process.h>
71 : #endif
72 :
73 : #include <freetds/tds.h>
74 : #include <freetds/configs.h>
75 : #include <freetds/utils/string.h>
76 : #include <freetds/utils.h>
77 : #include <freetds/replacements.h>
78 :
79 : static bool tds_config_login(TDSLOGIN * connection, TDSLOGIN * login);
80 : static bool tds_config_env_tdsdump(TDSLOGIN * login);
81 : static void tds_config_env_tdsver(TDSLOGIN * login);
82 : static void tds_config_env_tdsport(TDSLOGIN * login);
83 : static bool tds_config_env_tdshost(TDSLOGIN * login);
84 : static bool tds_read_conf_sections(FILE * in, const char *server, TDSLOGIN * login);
85 : static bool tds_read_interfaces(const char *server, TDSLOGIN * login);
86 : static bool parse_server_name_for_port(TDSLOGIN * connection, TDSLOGIN * login, bool update_server);
87 : static int tds_lookup_port(const char *portname);
88 : static bool tds_config_encryption(const char * value, TDSLOGIN * login);
89 :
90 : static tds_dir_char *interf_file = NULL;
91 :
92 : #define TDS_ISSPACE(c) isspace((unsigned char ) (c))
93 :
94 : const char STD_DATETIME_FMT[] = "%b %e %Y %I:%M%p";
95 :
96 : #if !defined(_WIN32) && !defined(DOS32X)
97 : static const char pid_config_logpath[] = "/tmp/tdsconfig.log.%d";
98 : static const char freetds_conf[] = "etc/freetds.conf";
99 : static const char location[] = "(from $FREETDS/etc)";
100 : static const char pid_logpath[] = "/tmp/freetds.log.%d";
101 : static const char interfaces_path[] = "/etc/freetds";
102 : #else
103 : static const tds_dir_char pid_config_logpath[] = L"c:\\tdsconfig.log.%d";
104 : static const tds_dir_char freetds_conf[] = L"freetds.conf";
105 : static const char location[] = "(from $FREETDS)";
106 : static const tds_dir_char pid_logpath[] = L"c:\\freetds.log.%d";
107 : static const tds_dir_char interfaces_path[] = L"c:\\";
108 : #endif
109 :
110 : /**
111 : * \ingroup libtds
112 : * \defgroup config Configuration
113 : * Handle reading of configuration
114 : */
115 :
116 : /**
117 : * \addtogroup config
118 : * @{
119 : */
120 :
121 : /**
122 : * tds_read_config_info() will fill the tds connection structure based on configuration
123 : * information gathered in the following order:
124 : * 1) Program specified in TDSLOGIN structure
125 : * 2) The environment variables TDSVER, TDSDUMP, TDSPORT, TDSQUERY, TDSHOST
126 : * 3) A config file with the following search order:
127 : * a) a readable file specified by environment variable FREETDSCONF
128 : * b) a readable file in ~/.freetds.conf
129 : * c) a readable file in $prefix/etc/freetds.conf
130 : * 3) ~/.interfaces if exists
131 : * 4) $SYBASE/interfaces if exists
132 : * 5) TDS_DEF_* default values
133 : *
134 : * .tdsrc and freetds.conf have been added to make the package easier to
135 : * integration with various Linux and *BSD distributions.
136 : */
137 : TDSLOGIN *
138 2590 : tds_read_config_info(TDSSOCKET * tds, TDSLOGIN * login, TDSLOCALE * locale)
139 : {
140 : TDSLOGIN *connection;
141 : tds_dir_char *s;
142 2590 : int opened = 0;
143 : bool found;
144 :
145 : /* allocate a new structure with hard coded and build-time defaults */
146 2590 : connection = tds_alloc_login(false);
147 2590 : if (!connection || !tds_init_login(connection, locale)) {
148 0 : tds_free_login(connection);
149 0 : return NULL;
150 : }
151 :
152 2590 : s = tds_dir_getenv(TDS_DIR("TDSDUMPCONFIG"));
153 2590 : if (s) {
154 0 : if (*s) {
155 0 : opened = tdsdump_open(s);
156 : } else {
157 : tds_dir_char path[TDS_VECTOR_SIZE(pid_config_logpath) + 22];
158 0 : pid_t pid = getpid();
159 0 : tds_dir_snprintf(path, TDS_VECTOR_SIZE(path), pid_config_logpath, (int) pid);
160 0 : opened = tdsdump_open(path);
161 : }
162 : }
163 :
164 2590 : tdsdump_log(TDS_DBG_INFO1, "Getting connection information for [%s].\n",
165 0 : tds_dstr_cstr(&login->server_name)); /* (The server name is set in login.c.) */
166 :
167 : /* Read the config files. */
168 2590 : tdsdump_log(TDS_DBG_INFO1, "Attempting to read conf files.\n");
169 5180 : found = tds_read_conf_file(connection, tds_dstr_cstr(&login->server_name));
170 2590 : if (!found) {
171 74 : if (parse_server_name_for_port(connection, login, true)) {
172 :
173 148 : found = tds_read_conf_file(connection, tds_dstr_cstr(&connection->server_name));
174 : /* do it again to really override what found in freetds.conf */
175 74 : parse_server_name_for_port(connection, login, false);
176 124 : if (!found && TDS_SUCCEED(tds_lookup_host_set(tds_dstr_cstr(&connection->server_name), &connection->ip_addrs))) {
177 50 : if (!tds_dstr_dup(&connection->server_host_name, &connection->server_name)) {
178 0 : tds_free_login(connection);
179 0 : return NULL;
180 : }
181 : found = true;
182 : }
183 74 : if (!tds_dstr_dup(&login->server_name, &connection->server_name)) {
184 0 : tds_free_login(connection);
185 0 : return NULL;
186 : }
187 : }
188 : }
189 2590 : if (!found) {
190 : /* fallback to interfaces file */
191 0 : tdsdump_log(TDS_DBG_INFO1, "Failed in reading conf file. Trying interface files.\n");
192 0 : if (!tds_read_interfaces(tds_dstr_cstr(&login->server_name), connection)) {
193 0 : tdsdump_log(TDS_DBG_INFO1, "Failed to find [%s] in configuration files; trying '%s' instead.\n",
194 0 : tds_dstr_cstr(&login->server_name), tds_dstr_cstr(&connection->server_name));
195 0 : if (connection->ip_addrs == NULL)
196 0 : tdserror(tds_get_ctx(tds), tds, TDSEINTF, 0);
197 : }
198 : }
199 :
200 : /* Override config file settings with environment variables. */
201 2590 : tds_fix_login(connection);
202 :
203 : /* And finally apply anything from the login structure */
204 2590 : if (!tds_config_login(connection, login)) {
205 0 : tds_free_login(connection);
206 0 : return NULL;
207 : }
208 :
209 2590 : if (opened) {
210 : struct addrinfo *addrs;
211 : char tmp[128];
212 :
213 0 : tdsdump_log(TDS_DBG_INFO1, "Final connection parameters:\n");
214 0 : tdsdump_log(TDS_DBG_INFO1, "\t%20s = %s\n", "server_name", tds_dstr_cstr(&connection->server_name));
215 0 : tdsdump_log(TDS_DBG_INFO1, "\t%20s = %s\n", "server_host_name", tds_dstr_cstr(&connection->server_host_name));
216 :
217 0 : for (addrs = connection->ip_addrs; addrs != NULL; addrs = addrs->ai_next)
218 0 : tdsdump_log(TDS_DBG_INFO1, "\t%20s = %s\n", "ip_addr", tds_addrinfo2str(addrs, tmp, sizeof(tmp)));
219 :
220 0 : if (connection->ip_addrs == NULL)
221 0 : tdsdump_log(TDS_DBG_INFO1, "\t%20s = %s\n", "ip_addr", "");
222 :
223 0 : tdsdump_log(TDS_DBG_INFO1, "\t%20s = %s\n", "instance_name", tds_dstr_cstr(&connection->instance_name));
224 0 : tdsdump_log(TDS_DBG_INFO1, "\t%20s = %d\n", "port", connection->port);
225 0 : tdsdump_log(TDS_DBG_INFO1, "\t%20s = %d\n", "major_version", TDS_MAJOR(connection));
226 0 : tdsdump_log(TDS_DBG_INFO1, "\t%20s = %d\n", "minor_version", TDS_MINOR(connection));
227 0 : tdsdump_log(TDS_DBG_INFO1, "\t%20s = %d\n", "block_size", connection->block_size);
228 0 : tdsdump_log(TDS_DBG_INFO1, "\t%20s = %s\n", "language", tds_dstr_cstr(&connection->language));
229 0 : tdsdump_log(TDS_DBG_INFO1, "\t%20s = %s\n", "server_charset", tds_dstr_cstr(&connection->server_charset));
230 0 : tdsdump_log(TDS_DBG_INFO1, "\t%20s = %d\n", "connect_timeout", connection->connect_timeout);
231 0 : tdsdump_log(TDS_DBG_INFO1, "\t%20s = %s\n", "client_host_name", tds_dstr_cstr(&connection->client_host_name));
232 0 : tdsdump_log(TDS_DBG_INFO1, "\t%20s = %s\n", "client_charset", tds_dstr_cstr(&connection->client_charset));
233 0 : tdsdump_log(TDS_DBG_INFO1, "\t%20s = %d\n", "use_utf16", connection->use_utf16);
234 0 : tdsdump_log(TDS_DBG_INFO1, "\t%20s = %s\n", "app_name", tds_dstr_cstr(&connection->app_name));
235 0 : tdsdump_log(TDS_DBG_INFO1, "\t%20s = %s\n", "user_name", tds_dstr_cstr(&connection->user_name));
236 : /* tdsdump_log(TDS_DBG_PASSWD, "\t%20s = %s\n", "password", tds_dstr_cstr(&connection->password));
237 : (no such flag yet) */
238 0 : tdsdump_log(TDS_DBG_INFO1, "\t%20s = %s\n", "library", tds_dstr_cstr(&connection->library));
239 0 : tdsdump_log(TDS_DBG_INFO1, "\t%20s = %d\n", "bulk_copy", (int)connection->bulk_copy);
240 0 : tdsdump_log(TDS_DBG_INFO1, "\t%20s = %d\n", "suppress_language", (int)connection->suppress_language);
241 0 : tdsdump_log(TDS_DBG_INFO1, "\t%20s = %d\n", "encrypt level", (int)connection->encryption_level);
242 0 : tdsdump_log(TDS_DBG_INFO1, "\t%20s = %d\n", "query_timeout", connection->query_timeout);
243 : /* tdsdump_log(TDS_DBG_INFO1, "\t%20s = %s\n", "capabilities", tds_dstr_cstr(&connection->capabilities));
244 : (not null terminated) */
245 0 : tdsdump_log(TDS_DBG_INFO1, "\t%20s = %s\n", "database", tds_dstr_cstr(&connection->database));
246 0 : tdsdump_log(TDS_DBG_INFO1, "\t%20s = %" tdsPRIdir "\n", "dump_file", connection->dump_file);
247 0 : tdsdump_log(TDS_DBG_INFO1, "\t%20s = %x\n", "debug_flags", connection->debug_flags);
248 0 : tdsdump_log(TDS_DBG_INFO1, "\t%20s = %d\n", "text_size", connection->text_size);
249 0 : tdsdump_log(TDS_DBG_INFO1, "\t%20s = %s\n", "server_realm_name", tds_dstr_cstr(&connection->server_realm_name));
250 0 : tdsdump_log(TDS_DBG_INFO1, "\t%20s = %s\n", "server_spn", tds_dstr_cstr(&connection->server_spn));
251 0 : tdsdump_log(TDS_DBG_INFO1, "\t%20s = %s\n", "cafile", tds_dstr_cstr(&connection->cafile));
252 0 : tdsdump_log(TDS_DBG_INFO1, "\t%20s = %s\n", "crlfile", tds_dstr_cstr(&connection->crlfile));
253 0 : tdsdump_log(TDS_DBG_INFO1, "\t%20s = %d\n", "check_ssl_hostname", connection->check_ssl_hostname);
254 0 : tdsdump_log(TDS_DBG_INFO1, "\t%20s = %s\n", "db_filename", tds_dstr_cstr(&connection->db_filename));
255 0 : tdsdump_log(TDS_DBG_INFO1, "\t%20s = %d\n", "readonly_intent", connection->readonly_intent);
256 : #ifdef HAVE_OPENSSL
257 0 : tdsdump_log(TDS_DBG_INFO1, "\t%20s = %s\n", "openssl_ciphers", tds_dstr_cstr(&connection->openssl_ciphers));
258 : #endif
259 :
260 0 : tdsdump_close();
261 : }
262 :
263 : /*
264 : * If a dump file has been specified, start logging
265 : */
266 2590 : if (connection->dump_file != NULL && !tdsdump_isopen()) {
267 4 : if (connection->debug_flags)
268 4 : tds_debug_flags = connection->debug_flags;
269 4 : tdsdump_open(connection->dump_file);
270 : }
271 :
272 : return connection;
273 : }
274 :
275 : /**
276 : * Fix configuration after reading it.
277 : * Currently this read some environment variables and replace some options.
278 : */
279 : void
280 4584 : tds_fix_login(TDSLOGIN * login)
281 : {
282 : /* Now check the environment variables */
283 4584 : tds_config_env_tdsver(login);
284 4584 : tds_config_env_tdsdump(login);
285 4584 : tds_config_env_tdsport(login);
286 4584 : tds_config_env_tdshost(login);
287 4584 : }
288 :
289 : static bool
290 7932 : tds_try_conf_file(const tds_dir_char *path, const char *how, const char *server, TDSLOGIN * login)
291 : {
292 7932 : bool found = false;
293 : FILE *in;
294 :
295 7932 : if ((in = tds_dir_open(path, TDS_DIR("r"))) == NULL) {
296 3774 : tdsdump_log(TDS_DBG_INFO1, "Could not open '%" tdsPRIdir "' (%s).\n", path, how);
297 : return found;
298 : }
299 :
300 4158 : tdsdump_log(TDS_DBG_INFO1, "Found conf file '%" tdsPRIdir "' %s.\n", path, how);
301 4158 : found = tds_read_conf_sections(in, server, login);
302 :
303 4158 : if (found) {
304 3670 : tdsdump_log(TDS_DBG_INFO1, "Success: [%s] defined in %" tdsPRIdir ".\n", server, path);
305 : } else {
306 488 : tdsdump_log(TDS_DBG_INFO2, "[%s] not found.\n", server);
307 : }
308 :
309 4158 : fclose(in);
310 :
311 4158 : return found;
312 : }
313 :
314 : /**
315 : * Read configuration info for given server
316 : * return 0 on error
317 : * @param login where to store configuration
318 : * @param server section of file configuration that hold
319 : * configuration for a server
320 : */
321 : bool
322 3794 : tds_read_conf_file(TDSLOGIN * login, const char *server)
323 : {
324 3794 : tds_dir_char *path = NULL;
325 3794 : tds_dir_char *eptr = NULL;
326 3794 : bool found = false;
327 :
328 3794 : if (interf_file) {
329 140 : found = tds_try_conf_file(interf_file, "set programmatically", server, login);
330 : }
331 :
332 : /* FREETDSCONF env var, pkleef@openlinksw.com 01/21/02 */
333 140 : if (!found) {
334 3774 : path = tds_dir_getenv(TDS_DIR("FREETDSCONF"));
335 3774 : if (path) {
336 120 : found = tds_try_conf_file(path, "(from $FREETDSCONF)", server, login);
337 : } else {
338 3654 : tdsdump_log(TDS_DBG_INFO2, "... $FREETDSCONF not set. Trying $FREETDS/etc.\n");
339 : }
340 : }
341 :
342 : /* FREETDS env var, Bill Thompson 16/07/03 */
343 3794 : if (!found) {
344 3774 : eptr = tds_dir_getenv(TDS_DIR("FREETDS"));
345 3774 : if (eptr) {
346 0 : path = tds_join_path(eptr, freetds_conf);
347 0 : if (path) {
348 0 : found = tds_try_conf_file(path, location, server, login);
349 0 : free(path);
350 : }
351 : } else {
352 3774 : tdsdump_log(TDS_DBG_INFO2, "... $FREETDS not set. Trying $HOME.\n");
353 : }
354 : }
355 :
356 : #if !defined(_WIN32) && !defined(DOS32X)
357 3794 : if (!found) {
358 3774 : path = tds_get_home_file(TDS_DIR(".config/freetds.conf"));
359 3774 : if (path) {
360 3774 : found = tds_try_conf_file(path, "(.config/freetds.conf)", server, login);
361 3774 : free(path);
362 : }
363 : }
364 : #endif
365 :
366 3794 : if (!found) {
367 3774 : path = tds_get_home_file(TDS_DIR(".freetds.conf"));
368 3774 : if (path) {
369 3774 : found = tds_try_conf_file(path, "(.freetds.conf)", server, login);
370 3774 : free(path);
371 : } else {
372 0 : tdsdump_log(TDS_DBG_INFO2, "... Error getting ~/.freetds.conf. Trying %" tdsPRIdir ".\n",
373 : FREETDS_SYSCONFFILE);
374 : }
375 : }
376 :
377 3794 : if (!found) {
378 124 : found = tds_try_conf_file(FREETDS_SYSCONFFILE, "(default)", server, login);
379 : }
380 :
381 3794 : return found;
382 : }
383 :
384 : static bool
385 4158 : tds_read_conf_sections(FILE * in, const char *server, TDSLOGIN * login)
386 : {
387 4158 : DSTR default_instance = DSTR_INITIALIZER;
388 : int default_port;
389 :
390 : bool found;
391 :
392 4158 : tds_read_conf_section(in, "global", tds_parse_conf_section, login);
393 :
394 4158 : if (!server[0])
395 : return false;
396 4158 : rewind(in);
397 :
398 4158 : if (!tds_dstr_dup(&default_instance, &login->instance_name))
399 : return false;
400 4158 : default_port = login->port;
401 :
402 4158 : found = tds_read_conf_section(in, server, tds_parse_conf_section, login);
403 4158 : if (!login->valid_configuration) {
404 0 : tds_dstr_free(&default_instance);
405 0 : return false;
406 : }
407 :
408 : /*
409 : * If both instance and port are specified and neither one came from the default, it's an error
410 : * TODO: If port/instance is specified in the non-default, it has priority over the default setting.
411 : * TODO: test this.
412 : */
413 8408 : if (!tds_dstr_isempty(&login->instance_name) && login->port &&
414 92 : !(!tds_dstr_isempty(&default_instance) || default_port)) {
415 0 : tdsdump_log(TDS_DBG_ERROR, "error: cannot specify both port %d and instance %s.\n",
416 0 : login->port, tds_dstr_cstr(&login->instance_name));
417 : /* tdserror(tds_get_ctx(tds), tds, TDSEPORTINSTANCE, 0); */
418 : }
419 4158 : tds_dstr_free(&default_instance);
420 4158 : return found;
421 : }
422 :
423 : static const struct {
424 : char value[7];
425 : unsigned char to_return;
426 : } boolean_values[] = {
427 : { "yes", 1 },
428 : { "no", 0 },
429 : { "on", 1 },
430 : { "off", 0 },
431 : { "true", 1 },
432 : { "false", 0 }
433 : };
434 :
435 : int
436 0 : tds_parse_boolean(const char *value, int default_value)
437 : {
438 : int p;
439 :
440 10164 : for (p = 0; p < TDS_VECTOR_SIZE(boolean_values); ++p) {
441 10164 : if (!strcasecmp(value, boolean_values[p].value))
442 2898 : return boolean_values[p].to_return;
443 : }
444 : return default_value;
445 : }
446 :
447 : int
448 0 : tds_config_boolean(const char *option, const char *value, TDSLOGIN *login)
449 : {
450 0 : int ret = tds_parse_boolean(value, -1);
451 0 : if (ret >= 0)
452 : return ret;
453 :
454 0 : tdsdump_log(TDS_DBG_ERROR, "UNRECOGNIZED option value '%s' for boolean setting '%s'!\n",
455 : value, option);
456 0 : login->valid_configuration = 0;
457 0 : return 0;
458 : }
459 :
460 : static int
461 2898 : tds_parse_boolean_option(const char *option, const char *value, int default_value, bool *p_error)
462 : {
463 2898 : int ret = tds_parse_boolean(value, -1);
464 2898 : if (ret >= 0)
465 : return ret;
466 :
467 0 : tdsdump_log(TDS_DBG_ERROR, "UNRECOGNIZED option value '%s' for boolean setting '%s'!\n",
468 : value, option);
469 0 : *p_error = true;
470 0 : return default_value;
471 : }
472 :
473 : static bool
474 1462 : tds_config_encryption(const char * value, TDSLOGIN * login)
475 : {
476 1462 : TDS_ENCRYPTION_LEVEL lvl = TDS_ENCRYPTION_OFF;
477 :
478 1462 : if (!strcasecmp(value, TDS_STR_ENCRYPTION_OFF))
479 : ;
480 1462 : else if (!strcasecmp(value, TDS_STR_ENCRYPTION_REQUEST))
481 : lvl = TDS_ENCRYPTION_REQUEST;
482 1442 : else if (!strcasecmp(value, TDS_STR_ENCRYPTION_REQUIRE))
483 : lvl = TDS_ENCRYPTION_REQUIRE;
484 0 : else if (!strcasecmp(value, TDS_STR_ENCRYPTION_STRICT))
485 : lvl = TDS_ENCRYPTION_STRICT;
486 : else {
487 0 : tdsdump_log(TDS_DBG_ERROR, "UNRECOGNIZED option value '%s' for '%s' setting!\n",
488 : value, TDS_STR_ENCRYPTION);
489 0 : tdsdump_log(TDS_DBG_ERROR, "Valid settings are: ('%s', '%s', '%s', '%s')\n",
490 : TDS_STR_ENCRYPTION_OFF, TDS_STR_ENCRYPTION_REQUEST, TDS_STR_ENCRYPTION_REQUIRE,
491 : TDS_STR_ENCRYPTION_STRICT);
492 : lvl = TDS_ENCRYPTION_REQUIRE; /* Assuming "require" is safer than "no" */
493 : return false;
494 : }
495 :
496 1462 : login->encryption_level = lvl;
497 : return true;
498 : }
499 :
500 : /**
501 : * Read a section of configuration file (INI style file)
502 : * @param in configuration file
503 : * @param section section to read
504 : * @param tds_conf_parse callback that receive every entry in section
505 : * @param param parameter to pass to callback function
506 : */
507 : bool
508 41114 : tds_read_conf_section(FILE * in, const char *section, TDSCONFPARSE tds_conf_parse, void *param)
509 : {
510 : char line[256], *value;
511 : #define option line
512 : char *s;
513 : char p;
514 : int i;
515 41114 : bool insection = false;
516 41114 : bool found = false;
517 :
518 41114 : tdsdump_log(TDS_DBG_INFO1, "Looking for section %s.\n", section);
519 2534644 : while (fgets(line, sizeof(line), in)) {
520 : s = line;
521 :
522 : /* skip leading whitespace */
523 3923616 : while (*s && TDS_ISSPACE(*s))
524 1430086 : s++;
525 :
526 : /* skip it if it's a comment line */
527 2493530 : if (*s == ';' || *s == '#')
528 889320 : continue;
529 :
530 : /* read up to the = ignoring duplicate spaces */
531 : p = 0;
532 : i = 0;
533 13190088 : while (*s && *s != '=') {
534 11585878 : if (!TDS_ISSPACE(*s)) {
535 9938476 : if (TDS_ISSPACE(p))
536 369770 : option[i++] = ' ';
537 9938476 : option[i++] = tolower((unsigned char) *s);
538 : }
539 11585878 : p = *s;
540 11585878 : s++;
541 : }
542 :
543 : /* skip if empty option */
544 1604210 : if (!i)
545 332772 : continue;
546 :
547 : /* skip the = */
548 1271438 : if (*s)
549 989344 : s++;
550 :
551 : /* terminate the option, must be done after skipping = */
552 1271438 : option[i] = '\0';
553 :
554 : /* skip leading whitespace */
555 3531100 : while (*s && TDS_ISSPACE(*s))
556 988224 : s++;
557 :
558 : /* read up to a # ; or null ignoring duplicate spaces */
559 : value = s;
560 : p = 0;
561 : i = 0;
562 10252021 : while (*s && *s != ';' && *s != '#') {
563 8980583 : if (!TDS_ISSPACE(*s)) {
564 7911355 : if (TDS_ISSPACE(p))
565 79824 : value[i++] = ' ';
566 7911355 : value[i++] = *s;
567 : }
568 8980583 : p = *s;
569 8980583 : s++;
570 : }
571 1271438 : value[i] = '\0';
572 :
573 1271438 : if (option[0] == '[') {
574 282094 : s = strchr(option, ']');
575 282094 : if (s)
576 282094 : *s = '\0';
577 282094 : tdsdump_log(TDS_DBG_INFO1, "\tFound section %s.\n", &option[1]);
578 :
579 282094 : if (!strcasecmp(section, &option[1])) {
580 36867 : tdsdump_log(TDS_DBG_INFO1, "Got a match.\n");
581 : insection = true;
582 : found = true;
583 : } else {
584 : insection = false;
585 : }
586 989344 : } else if (insection) {
587 114660 : tds_conf_parse(option, value, param);
588 : }
589 :
590 : }
591 41114 : tdsdump_log(TDS_DBG_INFO1, "\tReached EOF\n");
592 41114 : return found;
593 : #undef option
594 : }
595 :
596 : /* Also used to scan ODBC.INI entries */
597 : bool
598 31084 : tds_parse_conf_section(const char *option, const char *value, void *param)
599 : {
600 : #define parse_boolean(option, value, variable) do { \
601 : variable = tds_parse_boolean_option(option, value, variable, &got_error); \
602 : } while(0)
603 31084 : TDSLOGIN *login = (TDSLOGIN *) param;
604 31084 : void *s = param;
605 31084 : bool got_error = false;
606 :
607 31084 : tdsdump_log(TDS_DBG_INFO1, "\t%s = '%s'\n", option, value);
608 :
609 31084 : if (!strcmp(option, TDS_STR_VERSION)) {
610 3804 : tds_config_verstr(value, login);
611 27280 : } else if (!strcmp(option, TDS_STR_BLKSZ)) {
612 0 : int val = atoi(value);
613 0 : if (val >= 512 && val < 65536)
614 0 : login->block_size = val;
615 27280 : } else if (!strcmp(option, TDS_STR_SWAPDT)) {
616 : /* this option is deprecated, just check value for compatibility */
617 0 : tds_config_boolean(option, value, login);
618 27280 : } else if (!strcmp(option, TDS_GSSAPI_DELEGATION)) {
619 : /* gssapi flag addition */
620 0 : parse_boolean(option, value, login->gssapi_use_delegation);
621 27280 : } else if (!strcmp(option, TDS_STR_MUTUAL_AUTHENTICATION)) {
622 0 : parse_boolean(option, value, login->mutual_authentication);
623 27280 : } else if (!strcmp(option, TDS_STR_DUMPFILE)) {
624 0 : TDS_ZERO_FREE(login->dump_file);
625 0 : if (value[0]) {
626 0 : login->dump_file = tds_dir_from_cstr(value);
627 0 : if (!login->dump_file)
628 : s = NULL;
629 : }
630 27280 : } else if (!strcmp(option, TDS_STR_DEBUGFLAGS)) {
631 : char *end;
632 : long flags;
633 3774 : flags = strtol(value, &end, 0);
634 3774 : if (*value != '\0' && *end == '\0' && flags != LONG_MIN && flags != LONG_MAX)
635 3774 : login->debug_flags = flags;
636 23506 : } else if (!strcmp(option, TDS_STR_TIMEOUT) || !strcmp(option, TDS_STR_QUERY_TIMEOUT)) {
637 3774 : if (atoi(value))
638 3774 : login->query_timeout = atoi(value);
639 19732 : } else if (!strcmp(option, TDS_STR_CONNTIMEOUT)) {
640 3774 : if (atoi(value))
641 3774 : login->connect_timeout = atoi(value);
642 15958 : } else if (!strcmp(option, TDS_STR_HOST)) {
643 : char tmp[128];
644 : struct addrinfo *addrs;
645 :
646 3670 : if (TDS_FAILED(tds_lookup_host_set(value, &login->ip_addrs))) {
647 0 : tdsdump_log(TDS_DBG_WARN, "Found host entry %s however name resolution failed. \n", value);
648 0 : return false;
649 : }
650 :
651 3670 : tdsdump_log(TDS_DBG_INFO1, "Found host entry %s \n", value);
652 3670 : s = tds_dstr_copy(&login->server_host_name, value);
653 7340 : for (addrs = login->ip_addrs; addrs != NULL; addrs = addrs->ai_next)
654 3670 : tdsdump_log(TDS_DBG_INFO1, "IP addr is %s.\n", tds_addrinfo2str(addrs, tmp, sizeof(tmp)));
655 :
656 12288 : } else if (!strcmp(option, TDS_STR_PORT)) {
657 3890 : if (atoi(value))
658 3890 : login->port = atoi(value);
659 8398 : } else if (!strcmp(option, TDS_STR_EMUL_LE)) {
660 : /* obsolete, ignore */
661 0 : tds_config_boolean(option, value, login);
662 8398 : } else if (!strcmp(option, TDS_STR_TEXTSZ)) {
663 3898 : if (atoi(value))
664 3898 : login->text_size = atoi(value);
665 4500 : } else if (!strcmp(option, TDS_STR_CHARSET)) {
666 0 : s = tds_dstr_copy(&login->server_charset, value);
667 0 : tdsdump_log(TDS_DBG_INFO1, "%s is %s.\n", option, tds_dstr_cstr(&login->server_charset));
668 4500 : } else if (!strcmp(option, TDS_STR_CLCHARSET)) {
669 100 : s = tds_dstr_copy(&login->client_charset, value);
670 100 : tdsdump_log(TDS_DBG_INFO1, "tds_parse_conf_section: %s is %s.\n", option, tds_dstr_cstr(&login->client_charset));
671 4400 : } else if (!strcmp(option, TDS_STR_USE_UTF_16)) {
672 0 : parse_boolean(option, value, login->use_utf16);
673 4400 : } else if (!strcmp(option, TDS_STR_LANGUAGE)) {
674 0 : s = tds_dstr_copy(&login->language, value);
675 4400 : } else if (!strcmp(option, TDS_STR_APPENDMODE)) {
676 0 : parse_boolean(option, value, tds_append_mode);
677 4400 : } else if (!strcmp(option, TDS_STR_INSTANCE)) {
678 0 : s = tds_dstr_copy(&login->instance_name, value);
679 4400 : } else if (!strcmp(option, TDS_STR_ENCRYPTION)) {
680 1462 : if (!tds_config_encryption(value, login))
681 : s = NULL;
682 2938 : } else if (!strcmp(option, TDS_STR_ASA_DATABASE)) {
683 20 : s = tds_dstr_copy(&login->server_name, value);
684 2918 : } else if (!strcmp(option, TDS_STR_USENTLMV2)) {
685 0 : parse_boolean(option, value, login->use_ntlmv2);
686 0 : login->use_ntlmv2_specified = 1;
687 2918 : } else if (!strcmp(option, TDS_STR_USELANMAN)) {
688 0 : parse_boolean(option, value, login->use_lanman);
689 2918 : } else if (!strcmp(option, TDS_STR_REALM)) {
690 0 : s = tds_dstr_copy(&login->server_realm_name, value);
691 2918 : } else if (!strcmp(option, TDS_STR_SPN)) {
692 0 : s = tds_dstr_copy(&login->server_spn, value);
693 2918 : } else if (!strcmp(option, TDS_STR_CAFILE)) {
694 0 : s = tds_dstr_copy(&login->cafile, value);
695 2918 : } else if (!strcmp(option, TDS_STR_CRLFILE)) {
696 0 : s = tds_dstr_copy(&login->crlfile, value);
697 2918 : } else if (!strcmp(option, TDS_STR_CHECKSSLHOSTNAME)) {
698 1442 : parse_boolean(option, value, login->check_ssl_hostname);
699 1476 : } else if (!strcmp(option, TDS_STR_SSLHOSTNAME)) {
700 0 : s = tds_dstr_copy(&login->certificate_host_name, value);
701 1476 : } else if (!strcmp(option, TDS_STR_DBFILENAME)) {
702 0 : s = tds_dstr_copy(&login->db_filename, value);
703 1476 : } else if (!strcmp(option, TDS_STR_DATABASE)) {
704 0 : s = tds_dstr_copy(&login->database, value);
705 1476 : } else if (!strcmp(option, TDS_STR_READONLY_INTENT)) {
706 0 : parse_boolean(option, value, login->readonly_intent);
707 0 : tdsdump_log(TDS_DBG_FUNC, "Setting ReadOnly Intent to '%s'.\n", value);
708 1476 : } else if (!strcmp(option, TLS_STR_OPENSSL_CIPHERS)) {
709 0 : s = tds_dstr_copy(&login->openssl_ciphers, value);
710 1476 : } else if (!strcmp(option, TDS_STR_ENABLE_TLS_V1)) {
711 1456 : parse_boolean(option, value, login->enable_tls_v1);
712 1456 : login->enable_tls_v1_specified = 1;
713 : } else {
714 20 : tdsdump_log(TDS_DBG_INFO1, "UNRECOGNIZED option '%s' ... ignoring.\n", option);
715 : }
716 :
717 31084 : if (!s || got_error) {
718 0 : login->valid_configuration = 0;
719 0 : return false;
720 : }
721 : return true;
722 : #undef parse_boolean
723 : }
724 :
725 : static bool
726 2590 : tds_config_login(TDSLOGIN * connection, TDSLOGIN * login)
727 : {
728 2590 : DSTR *res = &login->server_name;
729 :
730 5180 : if (!tds_dstr_isempty(&login->server_name)) {
731 : if (1 || tds_dstr_isempty(&connection->server_name))
732 2590 : res = tds_dstr_dup(&connection->server_name, &login->server_name);
733 : }
734 :
735 2590 : if (login->tds_version)
736 22 : connection->tds_version = login->tds_version;
737 :
738 5180 : if (res && !tds_dstr_isempty(&login->language))
739 326 : res = tds_dstr_dup(&connection->language, &login->language);
740 :
741 5180 : if (res && !tds_dstr_isempty(&login->server_charset))
742 0 : res = tds_dstr_dup(&connection->server_charset, &login->server_charset);
743 :
744 5180 : if (res && !tds_dstr_isempty(&login->client_charset)) {
745 174 : res = tds_dstr_dup(&connection->client_charset, &login->client_charset);
746 174 : tdsdump_log(TDS_DBG_INFO1, "tds_config_login: %s is %s.\n", "client_charset",
747 0 : tds_dstr_cstr(&connection->client_charset));
748 : }
749 :
750 2590 : if (!login->use_utf16)
751 0 : connection->use_utf16 = login->use_utf16;
752 :
753 5180 : if (res && !tds_dstr_isempty(&login->database)) {
754 54 : res = tds_dstr_dup(&connection->database, &login->database);
755 54 : tdsdump_log(TDS_DBG_INFO1, "tds_config_login: %s is %s.\n", "database_name",
756 0 : tds_dstr_cstr(&connection->database));
757 : }
758 :
759 5180 : if (res && !tds_dstr_isempty(&login->client_host_name))
760 494 : res = tds_dstr_dup(&connection->client_host_name, &login->client_host_name);
761 :
762 5180 : if (res && !tds_dstr_isempty(&login->app_name))
763 1180 : res = tds_dstr_dup(&connection->app_name, &login->app_name);
764 :
765 5180 : if (res && !tds_dstr_isempty(&login->user_name))
766 2520 : res = tds_dstr_dup(&connection->user_name, &login->user_name);
767 :
768 5180 : if (res && !tds_dstr_isempty(&login->password)) {
769 : /* for security reason clear memory */
770 2520 : tds_dstr_zero(&connection->password);
771 2520 : res = tds_dstr_dup(&connection->password, &login->password);
772 : }
773 :
774 5180 : if (res && !tds_dstr_isempty(&login->library))
775 2520 : res = tds_dstr_dup(&connection->library, &login->library);
776 :
777 2590 : if (login->encryption_level)
778 0 : connection->encryption_level = login->encryption_level;
779 :
780 2590 : if (login->suppress_language)
781 0 : connection->suppress_language = 1;
782 :
783 2590 : if (!login->bulk_copy)
784 0 : connection->bulk_copy = 0;
785 :
786 2590 : if (login->block_size)
787 0 : connection->block_size = login->block_size;
788 :
789 2590 : if (login->gssapi_use_delegation)
790 0 : connection->gssapi_use_delegation = login->gssapi_use_delegation;
791 :
792 2590 : if (login->mutual_authentication)
793 0 : connection->mutual_authentication = login->mutual_authentication;
794 :
795 2590 : if (login->port)
796 42 : connection->port = login->port;
797 :
798 2590 : if (login->connect_timeout)
799 0 : connection->connect_timeout = login->connect_timeout;
800 :
801 2590 : if (login->query_timeout)
802 0 : connection->query_timeout = login->query_timeout;
803 :
804 2590 : if (!login->check_ssl_hostname)
805 0 : connection->check_ssl_hostname = login->check_ssl_hostname;
806 :
807 5180 : if (res && !tds_dstr_isempty(&login->db_filename))
808 0 : res = tds_dstr_dup(&connection->db_filename, &login->db_filename);
809 :
810 5180 : if (res && !tds_dstr_isempty(&login->openssl_ciphers))
811 0 : res = tds_dstr_dup(&connection->openssl_ciphers, &login->openssl_ciphers);
812 :
813 5180 : if (res && !tds_dstr_isempty(&login->server_spn))
814 0 : res = tds_dstr_dup(&connection->server_spn, &login->server_spn);
815 :
816 : /* copy other info not present in configuration file */
817 2590 : connection->capabilities = login->capabilities;
818 :
819 2590 : if (login->readonly_intent)
820 0 : connection->readonly_intent = login->readonly_intent;
821 :
822 2590 : connection->use_new_password = login->use_new_password;
823 :
824 2590 : if (login->use_ntlmv2_specified) {
825 0 : connection->use_ntlmv2_specified = login->use_ntlmv2_specified;
826 0 : connection->use_ntlmv2 = login->use_ntlmv2;
827 : }
828 :
829 2590 : if (login->enable_tls_v1_specified) {
830 0 : connection->enable_tls_v1_specified = login->enable_tls_v1_specified;
831 0 : connection->enable_tls_v1 = login->enable_tls_v1;
832 : }
833 :
834 2590 : if (res)
835 2590 : res = tds_dstr_dup(&connection->new_password, &login->new_password);
836 :
837 2590 : return res != NULL;
838 : }
839 :
840 : static bool
841 4584 : tds_config_env_tdsdump(TDSLOGIN * login)
842 : {
843 : tds_dir_char path[TDS_VECTOR_SIZE(pid_logpath) + 22];
844 :
845 4584 : tds_dir_char *s = tds_dir_getenv(TDS_DIR("TDSDUMP"));
846 4584 : if (!s)
847 : return true;
848 :
849 4 : if (!tds_dir_len(s)) {
850 0 : pid_t pid = getpid();
851 0 : tds_dir_snprintf(path, TDS_VECTOR_SIZE(path), pid_logpath, (int) pid);
852 0 : s = path;
853 : }
854 :
855 4 : if (!(s = tds_dir_dup(s)))
856 : return false;
857 4 : free(login->dump_file);
858 4 : login->dump_file = s;
859 :
860 4 : tdsdump_log(TDS_DBG_INFO1, "Setting 'dump_file' to '%" tdsPRIdir "' from $TDSDUMP.\n", login->dump_file);
861 : return true;
862 : }
863 :
864 : static void
865 4584 : tds_config_env_tdsport(TDSLOGIN * login)
866 : {
867 : char *s;
868 :
869 4584 : if ((s = getenv("TDSPORT"))) {
870 12 : login->port = tds_lookup_port(s);
871 12 : tds_dstr_empty(&login->instance_name);
872 12 : tdsdump_log(TDS_DBG_INFO1, "Setting 'port' to %s from $TDSPORT.\n", s);
873 : }
874 4584 : return;
875 : }
876 : static void
877 4584 : tds_config_env_tdsver(TDSLOGIN * login)
878 : {
879 : char *tdsver;
880 :
881 4584 : if ((tdsver = getenv("TDSVER"))) {
882 14 : TDS_USMALLINT *pver = tds_config_verstr(tdsver, login);
883 14 : tdsdump_log(TDS_DBG_INFO1, "TDS version %sset to %s from $TDSVER.\n", (pver? "":"not "), tdsver);
884 :
885 : }
886 4584 : return;
887 : }
888 :
889 : /* TDSHOST env var, pkleef@openlinksw.com 01/21/02 */
890 : static bool
891 4584 : tds_config_env_tdshost(TDSLOGIN * login)
892 : {
893 : const char *tdshost;
894 : char tmp[128];
895 : struct addrinfo *addrs;
896 :
897 4584 : if (!(tdshost = getenv("TDSHOST")))
898 : return true;
899 :
900 10 : if (TDS_FAILED(tds_lookup_host_set(tdshost, &login->ip_addrs))) {
901 0 : tdsdump_log(TDS_DBG_WARN, "Name resolution failed for '%s' from $TDSHOST.\n", tdshost);
902 : return false;
903 : }
904 :
905 10 : if (!tds_dstr_copy(&login->server_host_name, tdshost))
906 : return false;
907 20 : for (addrs = login->ip_addrs; addrs != NULL; addrs = addrs->ai_next) {
908 10 : tdsdump_log(TDS_DBG_INFO1, "Setting IP Address to %s (%s) from $TDSHOST.\n",
909 : tds_addrinfo2str(addrs, tmp, sizeof(tmp)), tdshost);
910 : }
911 : return true;
912 : }
913 : #define TDS_FIND(k,b,c) tds_find(k, b, TDS_VECTOR_SIZE(b), sizeof(b[0]), c)
914 :
915 :
916 : static const void *
917 : tds_find(const void *key, const void *base, size_t nelem, size_t width,
918 : int (*compar)(const void *, const void *))
919 : {
920 : size_t n;
921 : const char *p = (const char*) base;
922 :
923 27434 : for (n = nelem; n != 0; --n) {
924 31252 : if (0 == compar(key, p))
925 : return p;
926 27434 : p += width;
927 : }
928 : return NULL;
929 : }
930 :
931 : struct tdsvername_t
932 : {
933 : const char name[6];
934 : TDS_USMALLINT version;
935 : };
936 :
937 : static int
938 31252 : tds_vername_cmp(const void *key, const void *pelem)
939 : {
940 31252 : return strcmp((const char *)key, ((const struct tdsvername_t *)pelem)->name);
941 : }
942 :
943 : /**
944 : * Set TDS version from given string
945 : * @param tdsver tds string version
946 : * @param login where to store information
947 : * @return as encoded hex value: high byte major, low byte minor.
948 : */
949 : TDS_USMALLINT *
950 3818 : tds_config_verstr(const char *tdsver, TDSLOGIN * login)
951 : {
952 : static const struct tdsvername_t tds_versions[] =
953 : { { "0", 0x000 }
954 : , {"auto", 0x000 }
955 : , { "4.2", 0x402 }
956 : , { "50", 0x500 }
957 : , { "5.0", 0x500 }
958 : , { "70", 0x700 }
959 : , { "7.0", 0x700 }
960 : , { "7.1", 0x701 }
961 : , { "7.2", 0x702 }
962 : , { "7.3", 0x703 }
963 : , { "7.4", 0x704 }
964 : , { "8.0", 0x800 }
965 : };
966 : const struct tdsvername_t *pver;
967 :
968 3818 : if (!login) {
969 0 : assert(login);
970 : return NULL;
971 : }
972 :
973 3818 : if ((pver = (const struct tdsvername_t *) TDS_FIND(tdsver, tds_versions, tds_vername_cmp)) == NULL) {
974 0 : tdsdump_log(TDS_DBG_INFO1, "error: no such version: %s\n", tdsver);
975 : return NULL;
976 : }
977 :
978 3818 : login->tds_version = pver->version;
979 3818 : tdsdump_log(TDS_DBG_INFO1, "Setting tds version to %s (0x%0x).\n", tdsver, pver->version);
980 :
981 3818 : return &login->tds_version;
982 : }
983 :
984 : /**
985 : * Set the full name of interface file
986 : * @param interf file name
987 : */
988 : TDSRET
989 20 : tds_set_interfaces_file_loc(const char *interf)
990 : {
991 : /* Free it if already set */
992 20 : if (interf_file != NULL)
993 10 : TDS_ZERO_FREE(interf_file);
994 : /* If no filename passed, leave it NULL */
995 20 : if ((interf == NULL) || (interf[0] == '\0')) {
996 : return TDS_SUCCESS;
997 : }
998 : /* Set to new value */
999 10 : if ((interf_file = tds_dir_from_cstr(interf)) == NULL) {
1000 : return TDS_FAIL;
1001 : }
1002 10 : return TDS_SUCCESS;
1003 : }
1004 :
1005 : /**
1006 : * Get the IP address for a hostname. Store server's IP address
1007 : * in the string 'ip' in dotted-decimal notation. (The "hostname" might itself
1008 : * be a dotted-decimal address.
1009 : *
1010 : * If we can't determine the IP address then 'ip' will be set to empty
1011 : * string.
1012 : */
1013 : /* TODO callers seem to set always connection info... change it */
1014 : struct addrinfo *
1015 3830 : tds_lookup_host(const char *servername) /* (I) name of the server */
1016 : {
1017 3830 : struct addrinfo hints, *addr = NULL;
1018 3830 : assert(servername != NULL);
1019 :
1020 3830 : memset(&hints, '\0', sizeof(hints));
1021 : hints.ai_family = AF_UNSPEC;
1022 3830 : hints.ai_socktype = SOCK_STREAM;
1023 3830 : hints.ai_protocol = IPPROTO_TCP;
1024 :
1025 : #ifdef AI_ADDRCONFIG
1026 3830 : hints.ai_flags |= AI_ADDRCONFIG;
1027 3830 : switch (getaddrinfo(servername, NULL, &hints, &addr)) {
1028 3830 : case 0:
1029 3830 : return addr;
1030 0 : case EAI_FAMILY:
1031 : # ifdef EAI_ADDRFAMILY
1032 : case EAI_ADDRFAMILY:
1033 : # endif
1034 0 : hints.ai_flags &= ~AI_ADDRCONFIG;
1035 : break;
1036 : default:
1037 : return NULL;
1038 : }
1039 : #endif
1040 :
1041 0 : if (getaddrinfo(servername, NULL, &hints, &addr))
1042 : return NULL;
1043 0 : return addr;
1044 : }
1045 :
1046 : TDSRET
1047 3830 : tds_lookup_host_set(const char *servername, struct addrinfo **addr)
1048 : {
1049 : struct addrinfo *newaddr;
1050 3830 : assert(servername != NULL && addr != NULL);
1051 :
1052 3830 : if ((newaddr = tds_lookup_host(servername)) != NULL) {
1053 3830 : if (*addr != NULL)
1054 30 : freeaddrinfo(*addr);
1055 3830 : *addr = newaddr;
1056 3830 : return TDS_SUCCESS;
1057 : }
1058 : return TDS_FAIL;
1059 : }
1060 :
1061 : /**
1062 : * Given a portname lookup the port.
1063 : *
1064 : * If we can't determine the port number then return 0.
1065 : */
1066 : static int
1067 12 : tds_lookup_port(const char *portname)
1068 : {
1069 12 : int num = atoi(portname);
1070 12 : if (!num)
1071 2 : num = tds_getservice(portname);
1072 12 : return num;
1073 : }
1074 :
1075 : /* TODO same code in convert.c ?? */
1076 : static int
1077 : hexdigit(int c)
1078 : {
1079 0 : if (c >= '0' && c <= '9')
1080 0 : return c - '0';
1081 : /* ASCII optimization, 'A' -> 'a', 'a' -> 'a' */
1082 0 : c |= 0x20;
1083 0 : if (c >= 'a' && c <= 'f')
1084 0 : return c - 'a' + 10;
1085 : return 0; /* bad hex digit */
1086 : }
1087 :
1088 : static int
1089 0 : hex2num(char *hex)
1090 : {
1091 0 : return hexdigit(hex[0]) * 16 + hexdigit(hex[1]);
1092 : }
1093 :
1094 : /**
1095 : * Open and read the file 'file' searching for a logical server
1096 : * by the name of 'host'. If one is found then lookup
1097 : * the IP address and port number and store them in 'login'
1098 : *
1099 : * \param dir name of base directory for interface file
1100 : * \param file name of the interface file
1101 : * \param host logical host to search for
1102 : * \return false if not fount true if found
1103 : */
1104 : static bool
1105 0 : search_interface_file(TDSLOGIN * login, const tds_dir_char *dir, const tds_dir_char *file, const char *host)
1106 : {
1107 : tds_dir_char *pathname;
1108 : char line[255];
1109 : char tmp_ip[sizeof(line)];
1110 : char tmp_port[sizeof(line)];
1111 : char tmp_ver[sizeof(line)];
1112 : FILE *in;
1113 : char *field;
1114 0 : bool found = false;
1115 0 : bool server_found = false;
1116 : char *lasts;
1117 :
1118 0 : line[0] = '\0';
1119 0 : tmp_ip[0] = '\0';
1120 0 : tmp_port[0] = '\0';
1121 0 : tmp_ver[0] = '\0';
1122 :
1123 0 : tdsdump_log(TDS_DBG_INFO1, "Searching interfaces file %" tdsPRIdir "/%" tdsPRIdir ".\n", dir, file);
1124 :
1125 : /*
1126 : * create the full pathname to the interface file
1127 : */
1128 0 : if (file[0] == '\0') {
1129 0 : pathname = tds_dir_dup(TDS_DIR(""));
1130 : } else {
1131 0 : pathname = tds_join_path(dir, file);
1132 : }
1133 0 : if (!pathname)
1134 : return false;
1135 :
1136 : /*
1137 : * parse the interfaces file and find the server and port
1138 : */
1139 0 : if ((in = tds_dir_open(pathname, TDS_DIR("r"))) == NULL) {
1140 0 : tdsdump_log(TDS_DBG_INFO1, "Couldn't open %" tdsPRIdir ".\n", pathname);
1141 0 : free(pathname);
1142 0 : return false;
1143 : }
1144 0 : tdsdump_log(TDS_DBG_INFO1, "Interfaces file %" tdsPRIdir " opened.\n", pathname);
1145 :
1146 0 : while (fgets(line, sizeof(line) - 1, in)) {
1147 0 : if (line[0] == '#')
1148 0 : continue; /* comment */
1149 :
1150 0 : if (!TDS_ISSPACE(line[0])) {
1151 0 : field = strtok_r(line, "\n\t ", &lasts);
1152 0 : if (!strcmp(field, host)) {
1153 0 : found = true;
1154 0 : tdsdump_log(TDS_DBG_INFO1, "Found matching entry for host %s.\n", host);
1155 : } else
1156 : found = false;
1157 0 : } else if (found && TDS_ISSPACE(line[0])) {
1158 0 : field = strtok_r(line, "\n\t ", &lasts);
1159 0 : if (field != NULL && !strcmp(field, "query")) {
1160 0 : field = strtok_r(NULL, "\n\t ", &lasts); /* tcp or tli */
1161 0 : if (!strcmp(field, "tli")) {
1162 0 : tdsdump_log(TDS_DBG_INFO1, "TLI service.\n");
1163 0 : field = strtok_r(NULL, "\n\t ", &lasts); /* tcp */
1164 0 : field = strtok_r(NULL, "\n\t ", &lasts); /* device */
1165 0 : field = strtok_r(NULL, "\n\t ", &lasts); /* host/port */
1166 0 : if (strlen(field) >= 18) {
1167 0 : sprintf(tmp_port, "%d", hex2num(&field[6]) * 256 + hex2num(&field[8]));
1168 0 : sprintf(tmp_ip, "%d.%d.%d.%d", hex2num(&field[10]),
1169 : hex2num(&field[12]), hex2num(&field[14]), hex2num(&field[16]));
1170 0 : tdsdump_log(TDS_DBG_INFO1, "tmp_port = %s. tmp_ip = %s.\n", tmp_port, tmp_ip);
1171 : }
1172 : } else {
1173 0 : field = strtok_r(NULL, "\n\t ", &lasts); /* ether */
1174 0 : strcpy(tmp_ver, field);
1175 0 : field = strtok_r(NULL, "\n\t ", &lasts); /* host */
1176 0 : strcpy(tmp_ip, field);
1177 0 : tdsdump_log(TDS_DBG_INFO1, "host field %s.\n", tmp_ip);
1178 0 : field = strtok_r(NULL, "\n\t ", &lasts); /* port */
1179 0 : strcpy(tmp_port, field);
1180 : } /* else */
1181 : server_found = true;
1182 : } /* if */
1183 : } /* else if */
1184 : } /* while */
1185 0 : fclose(in);
1186 0 : free(pathname);
1187 :
1188 :
1189 : /*
1190 : * Look up the host and service
1191 : */
1192 0 : if (server_found) {
1193 :
1194 0 : if (TDS_SUCCEED(tds_lookup_host_set(tmp_ip, &login->ip_addrs))) {
1195 : struct addrinfo *addrs;
1196 0 : if (!tds_dstr_copy(&login->server_host_name, tmp_ip))
1197 : return false;
1198 0 : for (addrs = login->ip_addrs; addrs != NULL; addrs = addrs->ai_next) {
1199 0 : tdsdump_log(TDS_DBG_INFO1, "Resolved IP as '%s'.\n",
1200 : tds_addrinfo2str(login->ip_addrs, line, sizeof(line)));
1201 : }
1202 : } else {
1203 0 : tdsdump_log(TDS_DBG_WARN, "Name resolution failed for IP '%s'.\n", tmp_ip);
1204 : }
1205 :
1206 0 : if (tmp_port[0])
1207 0 : login->port = tds_lookup_port(tmp_port);
1208 0 : if (tmp_ver[0])
1209 0 : tds_config_verstr(tmp_ver, login);
1210 : }
1211 : return server_found;
1212 : } /* search_interface_file() */
1213 :
1214 : /**
1215 : * Try to find the IP number and port for a (possibly) logical server name.
1216 : *
1217 : * @note This function uses only the interfaces file and is deprecated.
1218 : */
1219 : static bool
1220 0 : tds_read_interfaces(const char *server, TDSLOGIN * login)
1221 : {
1222 0 : bool found = false;
1223 :
1224 : /* read $SYBASE/interfaces */
1225 :
1226 0 : if (!server || !server[0]) {
1227 0 : server = getenv("TDSQUERY");
1228 0 : if (!server || !server[0])
1229 0 : server = "SYBASE";
1230 0 : tdsdump_log(TDS_DBG_INFO1, "Setting server to %s from $TDSQUERY.\n", server);
1231 :
1232 : }
1233 0 : tdsdump_log(TDS_DBG_INFO1, "Looking for server %s....\n", server);
1234 :
1235 : /*
1236 : * Look for the server in the interf_file iff interf_file has been set.
1237 : */
1238 0 : if (interf_file) {
1239 0 : tdsdump_log(TDS_DBG_INFO1, "Looking for server in file %" tdsPRIdir ".\n", interf_file);
1240 0 : found = search_interface_file(login, TDS_DIR(""), interf_file, server);
1241 : }
1242 :
1243 : /*
1244 : * if we haven't found the server yet then look for a $HOME/.interfaces file
1245 : */
1246 0 : if (!found) {
1247 0 : tds_dir_char *path = tds_get_home_file(TDS_DIR(".interfaces"));
1248 :
1249 0 : if (path) {
1250 0 : tdsdump_log(TDS_DBG_INFO1, "Looking for server in %" tdsPRIdir ".\n", path);
1251 0 : found = search_interface_file(login, TDS_DIR(""), path, server);
1252 0 : free(path);
1253 : }
1254 : }
1255 :
1256 : /*
1257 : * if we haven't found the server yet then look in $SYBBASE/interfaces file
1258 : */
1259 0 : if (!found) {
1260 0 : const tds_dir_char *sybase = tds_dir_getenv(TDS_DIR("SYBASE"));
1261 : #ifdef __VMS
1262 : /* We've got to be in unix syntax for later slash-joined concatenation. */
1263 : #include <unixlib.h>
1264 : const char *unixspec = decc$translate_vms(sybase);
1265 : if ( (int)unixspec != 0 && (int)unixspec != -1 ) sybase = unixspec;
1266 : #endif
1267 0 : if (!sybase || !sybase[0])
1268 0 : sybase = interfaces_path;
1269 :
1270 0 : tdsdump_log(TDS_DBG_INFO1, "Looking for server in %" tdsPRIdir "/interfaces.\n", sybase);
1271 0 : found = search_interface_file(login, sybase, TDS_DIR("interfaces"), server);
1272 : }
1273 :
1274 : /*
1275 : * If we still don't have the server and port then assume the user
1276 : * typed an actual server host name.
1277 : */
1278 0 : if (!found) {
1279 : int ip_port;
1280 : const char *env_port;
1281 :
1282 : /*
1283 : * Make a guess about the port number
1284 : */
1285 :
1286 0 : if (login->port == 0) {
1287 : /*
1288 : * Not set in the [global] section of the
1289 : * configure file, take a guess.
1290 : */
1291 : ip_port = TDS_DEF_PORT;
1292 : } else {
1293 : /*
1294 : * Preserve setting from the [global] section
1295 : * of the configure file.
1296 : */
1297 0 : ip_port = login->port;
1298 : }
1299 0 : if ((env_port = getenv("TDSPORT")) != NULL) {
1300 0 : ip_port = tds_lookup_port(env_port);
1301 0 : tdsdump_log(TDS_DBG_INFO1, "Setting 'ip_port' to %s from $TDSPORT.\n", env_port);
1302 : } else
1303 0 : tdsdump_log(TDS_DBG_INFO1, "Setting 'ip_port' to %d as a guess.\n", ip_port);
1304 :
1305 : /*
1306 : * look up the host
1307 : */
1308 :
1309 0 : if (TDS_SUCCEED(tds_lookup_host_set(server, &login->ip_addrs)))
1310 0 : if (!tds_dstr_copy(&login->server_host_name, server))
1311 : return false;
1312 :
1313 0 : if (ip_port)
1314 0 : login->port = ip_port;
1315 : }
1316 :
1317 : return found;
1318 : }
1319 :
1320 : /**
1321 : * Check the server name to find port info first
1322 : * Warning: connection-> & login-> are all modified when needed
1323 : * \return true when found, else false
1324 : */
1325 : static bool
1326 148 : parse_server_name_for_port(TDSLOGIN * connection, TDSLOGIN * login, bool update_server)
1327 : {
1328 : const char *pSep;
1329 : const char *server;
1330 :
1331 : /* seek the ':' in login server_name */
1332 296 : server = tds_dstr_cstr(&login->server_name);
1333 :
1334 : /* IPv6 address can be quoted */
1335 148 : if (server[0] == '[') {
1336 40 : pSep = strstr(server, "]:");
1337 40 : if (pSep)
1338 20 : ++pSep;
1339 : } else {
1340 108 : pSep = strrchr(server, ':');
1341 : }
1342 :
1343 148 : if (pSep && pSep != server) { /* yes, i found it! */
1344 : /* modify connection-> && login->server_name & ->port */
1345 168 : login->port = connection->port = atoi(pSep + 1);
1346 84 : tds_dstr_empty(&connection->instance_name);
1347 : } else {
1348 : /* handle instance name */
1349 64 : pSep = strrchr(server, '\\');
1350 64 : if (!pSep || pSep == server)
1351 : return false;
1352 :
1353 64 : if (!tds_dstr_copy(&connection->instance_name, pSep + 1))
1354 : return false;
1355 64 : connection->port = 0;
1356 : }
1357 :
1358 148 : if (!update_server)
1359 : return true;
1360 :
1361 74 : if (server[0] == '[' && pSep > server && pSep[-1] == ']') {
1362 20 : server++;
1363 20 : pSep--;
1364 : }
1365 74 : if (!tds_dstr_copyn(&connection->server_name, server, pSep - server))
1366 : return false;
1367 :
1368 74 : return true;
1369 : }
1370 :
1371 : /**
1372 : * Return a structure capturing the compile-time settings provided to the
1373 : * configure script.
1374 : */
1375 :
1376 : const TDS_COMPILETIME_SETTINGS *
1377 0 : tds_get_compiletime_settings(void)
1378 : {
1379 : static const TDS_COMPILETIME_SETTINGS settings = {
1380 : TDS_VERSION_NO
1381 : , FREETDS_SYSCONFDIR
1382 : , "unknown" /* need fancy script in makefile */
1383 : # if TDS50
1384 : , "5.0"
1385 : # elif TDS71
1386 : , "7.1"
1387 : # elif TDS72
1388 : , "7.2"
1389 : # elif TDS73
1390 : , "7.3"
1391 : # elif TDS74
1392 : , "7.4"
1393 : # else
1394 : , "auto"
1395 : # endif
1396 : # ifdef MSDBLIB
1397 : , true
1398 : # else
1399 : , false
1400 : # endif
1401 : # ifdef TDS_SYBASE_COMPAT
1402 : , true
1403 : # else
1404 : , false
1405 : # endif
1406 : # ifdef _REENTRANT
1407 : , true
1408 : # else
1409 : , false
1410 : # endif
1411 : # ifdef HAVE_ICONV
1412 : , true
1413 : # else
1414 : , false
1415 : # endif
1416 : # ifdef IODBC
1417 : , true
1418 : # else
1419 : , false
1420 : # endif
1421 : # ifdef UNIXODBC
1422 : , true
1423 : # else
1424 : , false
1425 : # endif
1426 : # ifdef HAVE_OPENSSL
1427 : , true
1428 : # else
1429 : , false
1430 : # endif
1431 : # ifdef HAVE_GNUTLS
1432 : , true
1433 : # else
1434 : , false
1435 : # endif
1436 : # if ENABLE_ODBC_MARS
1437 : , true
1438 : # else
1439 : , false
1440 : # endif
1441 : # ifdef HAVE_SSPI
1442 : , true
1443 : # else
1444 : , false
1445 : # endif
1446 : # ifdef ENABLE_KRB5
1447 : , true
1448 : # else
1449 : , false
1450 : # endif
1451 : };
1452 :
1453 : assert(settings.tdsver);
1454 :
1455 0 : return &settings;
1456 : }
1457 :
1458 : /**
1459 : * Make sure proper setting are in place for TDS 8.0
1460 : */
1461 : TDSRET
1462 3660 : tds8_adjust_login(TDSLOGIN *login)
1463 : {
1464 3660 : if (!IS_TDS80_PLUS(login) && login->encryption_level != TDS_ENCRYPTION_STRICT)
1465 : return TDS_SUCCESS;
1466 :
1467 0 : login->tds_version = 0x800;
1468 0 : login->encryption_level = TDS_ENCRYPTION_STRICT;
1469 :
1470 : /* we must have certificates */
1471 0 : if (tds_dstr_isempty(&login->cafile)) {
1472 0 : if (!tds_dstr_copy(&login->cafile, "system"))
1473 : return -TDSEMEM;
1474 : }
1475 :
1476 : return TDS_SUCCESS;
1477 : }
1478 :
1479 : /** @} */
|