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