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