LCOV - code coverage report
Current view: top level - src/tds - config.c (source / functions) Hit Total Coverage
Test: FreeTDS coverage Lines: 330 572 57.7 %
Date: 2024-04-18 21:21:48 Functions: 22 27 81.5 %

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

Generated by: LCOV version 1.13