LCOV - code coverage report
Current view: top level - src/tds - config.c (source / functions) Hit Total Coverage
Test: FreeTDS coverage Lines: 330 580 56.9 %
Date: 2025-01-18 11:50:39 Functions: 22 28 78.6 %

          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             : /** @} */

Generated by: LCOV version 1.13