LCOV - code coverage report
Current view: top level - src/odbc - connectparams.c (source / functions) Hit Total Coverage
Test: FreeTDS coverage Lines: 177 289 61.2 %
Date: 2024-04-18 21:21:48 Functions: 7 7 100.0 %

          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) 2005-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             : #include <stdlib.h>
      26             : #include <string.h>
      27             : #include <ctype.h>
      28             : #include <sys/stat.h>
      29             : 
      30             : #include <freetds/odbc.h>
      31             : #include <freetds/utils/string.h>
      32             : #include <freetds/utils.h>
      33             : #include <freetds/replacements.h>
      34             : 
      35             : #define ODBC_PARAM(p) static const char odbc_param_##p[] = #p;
      36             : ODBC_PARAM_LIST
      37             : #undef ODBC_PARAM
      38             : 
      39             : #ifdef _WIN32
      40             : #define ODBC_PARAM(p) odbc_param_##p,
      41             : static const char *odbc_param_names[] = {
      42             :         ODBC_PARAM_LIST
      43             : };
      44             : #undef ODBC_PARAM
      45             : #endif
      46             : 
      47             : #if !HAVE_SQLGETPRIVATEPROFILESTRING
      48             : 
      49             : /*
      50             :  * Last resort place to check for INI file. This is usually set at compile time
      51             :  * by build scripts.
      52             :  */
      53             : #ifndef SYS_ODBC_INI
      54             : #define SYS_ODBC_INI "/etc/odbc.ini"
      55             : #endif
      56             : 
      57             : /**
      58             :  * Call this to get the INI file containing Data Source Names.
      59             :  * @note rules for determining the location of ODBC config may be different 
      60             :  * then what you expect - at this time they differ from unixODBC 
      61             :  *
      62             :  * @return file opened or NULL if error
      63             :  * @retval 1 worked
      64             :  */
      65             : static FILE *tdoGetIniFileName(void);
      66             : 
      67             : /* avoid name collision with system headers */
      68             : #define SQLGetPrivateProfileString tds_SQLGetPrivateProfileString
      69             : 
      70             : /**
      71             :  * SQLGetPrivateProfileString
      72             :  *
      73             :  * PURPOSE
      74             :  *
      75             :  *  This is an implementation of a common MS API call. This implementation 
      76             :  *  should only be used if the ODBC sub-system/SDK does not have it.
      77             :  *  For example; unixODBC has its own so those using unixODBC should NOT be
      78             :  *  using this implementation because unixODBC;
      79             :  *  - provides caching of ODBC config data 
      80             :  *  - provides consistent interpretation of ODBC config data (i.e, location)
      81             :  *
      82             :  * ARGS
      83             :  *
      84             :  *  see ODBC documentation
      85             :  *                      
      86             :  * RETURNS
      87             :  *
      88             :  *  see ODBC documentation
      89             :  *
      90             :  * NOTES:
      91             :  *
      92             :  *  - the spec is not entirely implemented... consider this a lite version
      93             :  *  - rules for determining the location of ODBC config may be different then what you 
      94             :  *    expect see tdoGetIniFileName().
      95             :  *
      96             :  */
      97             : static int SQLGetPrivateProfileString(LPCSTR pszSection, LPCSTR pszEntry, LPCSTR pszDefault, LPSTR pRetBuffer, int nRetBuffer,
      98             :                                       LPCSTR pszFileName);
      99             : #endif
     100             : 
     101             : #if defined(FILENAME_MAX) && FILENAME_MAX < 512
     102             : #undef FILENAME_MAX
     103             : #define FILENAME_MAX 512
     104             : #endif
     105             : 
     106             : static int
     107          48 : parse_server(TDS_ERRS *errs, char *server, TDSLOGIN * login)
     108             : {
     109          48 :         char *p = (char *) strchr(server, '\\');
     110             : 
     111          48 :         if (p) {
     112           0 :                 if (!tds_dstr_copy(&login->instance_name, p+1)) {
     113           0 :                         odbc_errs_add(errs, "HY001", NULL);
     114           0 :                         return 0;
     115             :                 }
     116           0 :                 *p = 0;
     117             :         } else {
     118          48 :                 p = (char *) strchr(server, ',');
     119          48 :                 if (p && atoi(p+1) > 0) {
     120           0 :                         login->port = atoi(p+1);
     121           0 :                         *p = 0;
     122             :                 }
     123             :         }
     124             : 
     125          48 :         if (TDS_SUCCEED(tds_lookup_host_set(server, &login->ip_addrs)))
     126          48 :                 if (!tds_dstr_copy(&login->server_host_name, server)) {
     127           0 :                         odbc_errs_add(errs, "HY001", NULL);
     128           0 :                         return 0;
     129             :                 }
     130             : 
     131             :         return 1;
     132             : }
     133             : 
     134             : static int
     135             : myGetPrivateProfileString(const char *DSN, const char *key, char *buf)
     136             : {
     137       18044 :         buf[0] = '\0';
     138       18044 :         return SQLGetPrivateProfileString(DSN, key, "", buf, FILENAME_MAX, "odbc.ini");
     139             : }
     140             : 
     141             : /** 
     142             :  * Read connection information from given DSN
     143             :  * @param DSN           DSN name
     144             :  * @param login    where to store connection info
     145             :  * @return 1 if success 0 otherwhise
     146             :  */
     147             : int
     148         860 : odbc_get_dsn_info(TDS_ERRS *errs, const char *DSN, TDSLOGIN * login)
     149             : {
     150             :         char tmp[FILENAME_MAX];
     151         860 :         int freetds_conf_less = 1;
     152             : 
     153             :         /* use old servername */
     154         860 :         if (myGetPrivateProfileString(DSN, odbc_param_Servername, tmp) > 0) {
     155         860 :                 freetds_conf_less = 0;
     156         860 :                 if (!tds_dstr_copy(&login->server_name, tmp)) {
     157           0 :                         odbc_errs_add(errs, "HY001", NULL);
     158           0 :                         return 0;
     159             :                 }
     160         860 :                 tds_read_conf_file(login, tmp);
     161         860 :                 if (myGetPrivateProfileString(DSN, odbc_param_Server, tmp) > 0) {
     162           0 :                         odbc_errs_add(errs, "HY000", "You cannot specify both SERVERNAME and SERVER");
     163           0 :                         return 0;
     164             :                 }
     165         860 :                 if (myGetPrivateProfileString(DSN, odbc_param_Address, tmp) > 0) {
     166           0 :                         odbc_errs_add(errs, "HY000", "You cannot specify both SERVERNAME and ADDRESS");
     167           0 :                         return 0;
     168             :                 }
     169             :         }
     170             : 
     171             :         /* search for server (compatible with ms one) */
     172             :         if (freetds_conf_less) {
     173           0 :                 int address_specified = 0;
     174             : 
     175           0 :                 if (myGetPrivateProfileString(DSN, odbc_param_Address, tmp) > 0) {
     176           0 :                         address_specified = 1;
     177             :                         /* TODO parse like MS */
     178             : 
     179           0 :                         if (TDS_FAILED(tds_lookup_host_set(tmp, &login->ip_addrs))) {
     180           0 :                                 odbc_errs_add(errs, "HY000", "Error parsing ADDRESS attribute");
     181           0 :                                 return 0;
     182             :                         }
     183             :                 }
     184           0 :                 if (myGetPrivateProfileString(DSN, odbc_param_Server, tmp) > 0) {
     185           0 :                         if (!tds_dstr_copy(&login->server_name, tmp)) {
     186           0 :                                 odbc_errs_add(errs, "HY001", NULL);
     187           0 :                                 return 0;
     188             :                         }
     189           0 :                         if (!address_specified) {
     190           0 :                                 if (!parse_server(errs, tmp, login))
     191             :                                         return 0;
     192             :                         }
     193             :                 }
     194             :         }
     195             : 
     196         860 :         if (myGetPrivateProfileString(DSN, odbc_param_Port, tmp) > 0)
     197           0 :                 tds_parse_conf_section(TDS_STR_PORT, tmp, login);
     198             : 
     199         860 :         if (myGetPrivateProfileString(DSN, odbc_param_TDS_Version, tmp) > 0)
     200           0 :                 tds_parse_conf_section(TDS_STR_VERSION, tmp, login);
     201             : 
     202         860 :         if (myGetPrivateProfileString(DSN, odbc_param_Language, tmp) > 0)
     203           0 :                 tds_parse_conf_section(TDS_STR_LANGUAGE, tmp, login);
     204             : 
     205        1720 :         if (tds_dstr_isempty(&login->database)
     206         844 :             && myGetPrivateProfileString(DSN, odbc_param_Database, tmp) > 0)
     207         844 :                 if (!tds_dstr_copy(&login->database, tmp)) {
     208           0 :                         odbc_errs_add(errs, "HY001", NULL);
     209           0 :                         return 0;
     210             :                 }
     211             : 
     212         860 :         if (myGetPrivateProfileString(DSN, odbc_param_TextSize, tmp) > 0)
     213           0 :                 tds_parse_conf_section(TDS_STR_TEXTSZ, tmp, login);
     214             : 
     215         860 :         if (myGetPrivateProfileString(DSN, odbc_param_PacketSize, tmp) > 0)
     216           0 :                 tds_parse_conf_section(TDS_STR_BLKSZ, tmp, login);
     217             : 
     218         860 :         if (myGetPrivateProfileString(DSN, odbc_param_ClientCharset, tmp) > 0)
     219           0 :                 tds_parse_conf_section(TDS_STR_CLCHARSET, tmp, login);
     220             : 
     221         860 :         if (myGetPrivateProfileString(DSN, odbc_param_DumpFile, tmp) > 0)
     222           0 :                 tds_parse_conf_section(TDS_STR_DUMPFILE, tmp, login);
     223             : 
     224         860 :         if (myGetPrivateProfileString(DSN, odbc_param_DumpFileAppend, tmp) > 0)
     225           0 :                 tds_parse_conf_section(TDS_STR_APPENDMODE, tmp, login);
     226             : 
     227         860 :         if (myGetPrivateProfileString(DSN, odbc_param_DebugFlags, tmp) > 0)
     228           0 :                 tds_parse_conf_section(TDS_STR_DEBUGFLAGS, tmp, login);
     229             : 
     230         860 :         if (myGetPrivateProfileString(DSN, odbc_param_Encryption, tmp) > 0)
     231           0 :                 tds_parse_conf_section(TDS_STR_ENCRYPTION, tmp, login);
     232             : 
     233         860 :         if (myGetPrivateProfileString(DSN, odbc_param_UseNTLMv2, tmp) > 0)
     234           0 :                 tds_parse_conf_section(TDS_STR_USENTLMV2, tmp, login);
     235             : 
     236         860 :         if (myGetPrivateProfileString(DSN, odbc_param_REALM, tmp) > 0)
     237           0 :                 tds_parse_conf_section(TDS_STR_REALM, tmp, login);
     238             : 
     239         860 :         if (myGetPrivateProfileString(DSN, odbc_param_ServerSPN, tmp) > 0)
     240           0 :                 tds_parse_conf_section(TDS_STR_SPN, tmp, login);
     241             : 
     242         860 :         if (myGetPrivateProfileString(DSN, odbc_param_Trusted_Connection, tmp) > 0 && tds_config_boolean(odbc_param_Trusted_Connection, tmp, login)) {
     243           0 :                 tds_dstr_empty(&login->user_name);
     244           0 :                 tds_dstr_empty(&login->password);
     245             :         }
     246             : 
     247         860 :         if (myGetPrivateProfileString(DSN, odbc_param_MARS_Connection, tmp) > 0 && tds_config_boolean(odbc_param_MARS_Connection, tmp, login)) {
     248           0 :                 login->mars = 1;
     249             :         }
     250             : 
     251         860 :         if (myGetPrivateProfileString(DSN, odbc_param_AttachDbFilename, tmp) > 0)
     252           0 :                 tds_parse_conf_section(TDS_STR_DBFILENAME, tmp, login);
     253             : 
     254         860 :         if (myGetPrivateProfileString(DSN, odbc_param_Timeout, tmp) > 0)
     255           0 :                 tds_parse_conf_section(TDS_STR_TIMEOUT, tmp, login);
     256             : 
     257             :         return 1;
     258             : }
     259             : 
     260             : /**
     261             :  * Swap two DSTR
     262             :  */
     263             : static void
     264             : odbc_dstr_swap(DSTR *a, DSTR *b)
     265             : {
     266         464 :         DSTR tmp = *a;
     267         464 :         *a = *b;
     268         464 :         *b = tmp;
     269             : }
     270             : 
     271             : static const char *
     272         836 : parse_value(TDS_ERRS *errs, const char *p, const char *connect_string_end, DSTR *value)
     273             : {
     274             :         const char *end;
     275             :         char *dst;
     276             : 
     277             :         /* easy case, just ';' terminated */
     278         836 :         if (p == connect_string_end || *p != '{') {
     279         612 :                 end = (const char *) memchr(p, ';', connect_string_end - p);
     280         612 :                 if (!end)
     281           6 :                         end = connect_string_end;
     282         612 :                 if (!tds_dstr_copyn(value, p, end - p)) {
     283           0 :                         odbc_errs_add(errs, "HY001", NULL);
     284           0 :                         return NULL;
     285             :                 }
     286             :                 return end;
     287             :         }
     288             : 
     289         224 :         ++p;
     290             :         /* search "};" */
     291         224 :         end = p;
     292             :         for (;;) {
     293             :                 /* search next '}' */
     294         272 :                 end = (const char *) memchr(end, '}', connect_string_end - end);
     295         248 :                 if (end == NULL) {
     296           0 :                         odbc_errs_add(errs, "HY000", "Syntax error in connection string");
     297           0 :                         return NULL;
     298             :                 }
     299         248 :                 end++;
     300             : 
     301             :                 /* termination ? */
     302         248 :                 if (end == connect_string_end || end[0] == ';') {
     303         224 :                         end--;
     304             :                         break;
     305             :                 }
     306             : 
     307             :                 /* wrong syntax ? */
     308          24 :                 if (end[0] != '}') {
     309           0 :                         odbc_errs_add(errs, "HY000", "Syntax error in connection string");
     310           0 :                         return NULL;
     311             :                 }
     312          24 :                 end++;
     313             :         }
     314         224 :         if (!tds_dstr_alloc(value, end - p)) {
     315           0 :                 odbc_errs_add(errs, "HY001", NULL);
     316           0 :                 return NULL;
     317             :         }
     318         448 :         dst = tds_dstr_buf(value);
     319        2312 :         for (; p < end; ++p) {
     320        2088 :                 char ch = *p;
     321        2088 :                 *dst++ = ch;
     322        2088 :                 if (ch == '}')
     323          24 :                         ++p;
     324             :         }
     325         448 :         tds_dstr_setlen(value, dst - tds_dstr_buf(value));
     326             : 
     327         224 :         return end + 1;
     328             : }
     329             : 
     330             : /** 
     331             :  * Parse connection string and fill login according
     332             :  * @param connect_string     connect string
     333             :  * @param connect_string_end connect string end (pointer to char past last)
     334             :  * @param login         where to store connection info
     335             :  * @return true if success false otherwise
     336             :  */
     337             : bool
     338         134 : odbc_parse_connect_string(TDS_ERRS *errs, const char *connect_string, const char *connect_string_end, TDSLOGIN * login,
     339             :                           TDS_PARSED_PARAM *parsed_params)
     340             : {
     341             :         const char *p, *end;
     342         134 :         DSTR *dest_s, value = DSTR_INITIALIZER;
     343             :         enum { CFG_DSN = 1, CFG_SERVER = 2, CFG_SERVERNAME = 4 };
     344         134 :         unsigned int cfgs = 0;  /* flags for indicate second parse of string */
     345             :         char option[24];
     346         134 :         int trusted = 0;
     347             : 
     348         134 :         if (parsed_params)
     349         134 :                 memset(parsed_params, 0, sizeof(*parsed_params)*ODBC_PARAM_SIZE);
     350             : 
     351         964 :         for (p = connect_string; p < connect_string_end && *p;) {
     352             :                 int num_param = -1;
     353             : 
     354             :                 dest_s = NULL;
     355             : 
     356             :                 /* handle empty options */
     357         836 :                 while (p < connect_string_end && *p == ';')
     358           0 :                         ++p;
     359             : 
     360             :                 /* parse option */
     361         836 :                 end = (const char *) memchr(p, '=', connect_string_end - p);
     362         836 :                 if (!end)
     363             :                         break;
     364             : 
     365             :                 /* account for spaces between ;'s. */
     366         836 :                 while (p < end && *p == ' ')
     367           0 :                         ++p;
     368             : 
     369         836 :                 if ((end - p) >= (int) sizeof(option))
     370           0 :                         option[0] = 0;
     371             :                 else {
     372         836 :                         memcpy(option, p, end - p);
     373         836 :                         option[end - p] = 0;
     374             :                 }
     375             : 
     376             :                 /* parse value */
     377         836 :                 p = end + 1;
     378         836 :                 end = parse_value(errs, p, connect_string_end, &value);
     379         836 :                 if (!end)
     380             :                         return false;
     381             : 
     382             : #define CHK_PARAM(p) (strcasecmp(option, odbc_param_##p) == 0 && (num_param=ODBC_PARAM_##p) >= 0)
     383         836 :                 if (CHK_PARAM(Server)) {
     384             :                         /* error if servername or DSN specified */
     385          48 :                         if ((cfgs & (CFG_DSN|CFG_SERVERNAME)) != 0) {
     386           0 :                                 tds_dstr_free(&value);
     387           0 :                                 odbc_errs_add(errs, "HY000", "Only one between SERVER, SERVERNAME and DSN can be specified");
     388           0 :                                 return false;
     389             :                         }
     390          48 :                         if (!cfgs) {
     391          48 :                                 dest_s = &login->server_name;
     392             :                                 /* not that safe cast but works -- freddy77 */
     393          96 :                                 if (!parse_server(errs, (char *) tds_dstr_cstr(&value), login)) {
     394           0 :                                         tds_dstr_free(&value);
     395           0 :                                         return false;
     396             :                                 }
     397             :                                 cfgs = CFG_SERVER;
     398             :                         }
     399         788 :                 } else if (CHK_PARAM(Servername)) {
     400          32 :                         if ((cfgs & (CFG_DSN|CFG_SERVER)) != 0) {
     401           0 :                                 tds_dstr_free(&value);
     402           0 :                                 odbc_errs_add(errs, "HY000", "Only one between SERVER, SERVERNAME and DSN can be specified");
     403           0 :                                 return false;
     404             :                         }
     405          32 :                         if (!cfgs) {
     406          32 :                                 odbc_dstr_swap(&login->server_name, &value);
     407          32 :                                 tds_read_conf_file(login, tds_dstr_cstr(&login->server_name));
     408          16 :                                 cfgs = CFG_SERVERNAME;
     409          16 :                                 p = connect_string;
     410          16 :                                 continue;
     411             :                         }
     412         756 :                 } else if (CHK_PARAM(DSN)) {
     413         140 :                         if ((cfgs & (CFG_SERVER|CFG_SERVERNAME)) != 0) {
     414           0 :                                 tds_dstr_free(&value);
     415           0 :                                 odbc_errs_add(errs, "HY000", "Only one between SERVER, SERVERNAME and DSN can be specified");
     416           0 :                                 return false;
     417             :                         }
     418         140 :                         if (!cfgs) {
     419         140 :                                 if (!odbc_get_dsn_info(errs, tds_dstr_cstr(&value), login)) {
     420           0 :                                         tds_dstr_free(&value);
     421           0 :                                         return false;
     422             :                                 }
     423          70 :                                 cfgs = CFG_DSN;
     424          70 :                                 p = connect_string;
     425          70 :                                 continue;
     426             :                         }
     427         616 :                 } else if (CHK_PARAM(Database)) {
     428         126 :                         dest_s = &login->database;
     429         490 :                 } else if (CHK_PARAM(UID)) {
     430         134 :                         dest_s = &login->user_name;
     431         356 :                 } else if (CHK_PARAM(PWD)) {
     432         134 :                         dest_s = &login->password;
     433         222 :                 } else if (CHK_PARAM(APP)) {
     434           6 :                         dest_s = &login->app_name;
     435         216 :                 } else if (CHK_PARAM(WSID)) {
     436           0 :                         dest_s = &login->client_host_name;
     437         216 :                 } else if (CHK_PARAM(Language)) {
     438           0 :                         tds_parse_conf_section(TDS_STR_LANGUAGE, tds_dstr_cstr(&value), login);
     439         216 :                 } else if (CHK_PARAM(Port)) {
     440          96 :                         tds_parse_conf_section(TDS_STR_PORT, tds_dstr_cstr(&value), login);
     441         168 :                 } else if (CHK_PARAM(TDS_Version)) {
     442          16 :                         tds_parse_conf_section(TDS_STR_VERSION, tds_dstr_cstr(&value), login);
     443         160 :                 } else if (CHK_PARAM(TextSize)) {
     444           0 :                         tds_parse_conf_section(TDS_STR_TEXTSZ, tds_dstr_cstr(&value), login);
     445         160 :                 } else if (CHK_PARAM(PacketSize)) {
     446           0 :                         tds_parse_conf_section(TDS_STR_BLKSZ, tds_dstr_cstr(&value), login);
     447         160 :                 } else if (CHK_PARAM(ClientCharset)
     448          80 :                            ||  strcasecmp(option, "client_charset") == 0) {
     449          80 :                         num_param = ODBC_PARAM_ClientCharset;
     450         160 :                         tds_parse_conf_section(TDS_STR_CLCHARSET, tds_dstr_cstr(&value), login);
     451          80 :                 } else if (CHK_PARAM(DumpFile)) {
     452           0 :                         tds_parse_conf_section(TDS_STR_DUMPFILE, tds_dstr_cstr(&value), login);
     453          80 :                 } else if (CHK_PARAM(DumpFileAppend)) {
     454           0 :                         tds_parse_conf_section(TDS_STR_APPENDMODE, tds_dstr_cstr(&value), login);
     455          80 :                 } else if (CHK_PARAM(DebugFlags)) {
     456           0 :                         tds_parse_conf_section(TDS_STR_DEBUGFLAGS, tds_dstr_cstr(&value), login);
     457          80 :                 } else if (CHK_PARAM(Encryption)) {
     458           0 :                         tds_parse_conf_section(TDS_STR_ENCRYPTION, tds_dstr_cstr(&value), login);
     459          80 :                 } else if (CHK_PARAM(UseNTLMv2)) {
     460           0 :                         tds_parse_conf_section(TDS_STR_USENTLMV2, tds_dstr_cstr(&value), login);
     461          80 :                 } else if (CHK_PARAM(REALM)) {
     462           0 :                         tds_parse_conf_section(TDS_STR_REALM, tds_dstr_cstr(&value), login);
     463          80 :                 } else if (CHK_PARAM(ServerSPN)) {
     464           0 :                         tds_parse_conf_section(TDS_STR_SPN, tds_dstr_cstr(&value), login);
     465          80 :                 } else if (CHK_PARAM(Trusted_Connection)) {
     466           0 :                         trusted = tds_config_boolean(option, tds_dstr_cstr(&value), login);
     467           0 :                         tdsdump_log(TDS_DBG_INFO1, "trusted %s -> %d\n", tds_dstr_cstr(&value), trusted);
     468             :                         num_param = -1;
     469             :                         /* TODO odbc_param_Address field */
     470          80 :                 } else if (CHK_PARAM(MARS_Connection)) {
     471           0 :                         if (tds_config_boolean(option, tds_dstr_cstr(&value), login))
     472           0 :                                 login->mars = 1;
     473          80 :                 } else if (CHK_PARAM(AttachDbFilename)) {
     474           0 :                         dest_s = &login->db_filename;
     475          80 :                 } else if (CHK_PARAM(ApplicationIntent)) {
     476             :                         const char *readonly_intent;
     477             : 
     478           0 :                         if (strcasecmp(tds_dstr_cstr(&value), "ReadOnly") == 0) {
     479             :                                 readonly_intent = "yes";
     480           0 :                         } else if (strcasecmp(tds_dstr_cstr(&value), "ReadWrite") == 0) {
     481             :                                 readonly_intent = "no";
     482             :                         } else {
     483           0 :                                 tdsdump_log(TDS_DBG_ERROR, "Invalid ApplicationIntent %s\n", tds_dstr_cstr(&value));
     484           0 :                                 tds_dstr_free(&value);
     485           0 :                                 return false;
     486             :                         }
     487             : 
     488           0 :                         tds_parse_conf_section(TDS_STR_READONLY_INTENT, readonly_intent, login);
     489           0 :                         tdsdump_log(TDS_DBG_INFO1, "Application Intent %s\n", readonly_intent);
     490          80 :                 } else if (CHK_PARAM(Timeout)) {
     491           0 :                         tds_parse_conf_section(TDS_STR_TIMEOUT, tds_dstr_cstr(&value), login);
     492             :                 }
     493             : 
     494         750 :                 if (num_param >= 0 && parsed_params) {
     495         670 :                         parsed_params[num_param].p = p;
     496         670 :                         parsed_params[num_param].len = end - p;
     497             :                 }
     498             : 
     499             :                 /* copy to destination */
     500         750 :                 if (dest_s)
     501             :                         odbc_dstr_swap(dest_s, &value);
     502             : 
     503         750 :                 p = end;
     504             :                 /* handle "" ";.." cases */
     505         750 :                 if (p >= connect_string_end)
     506             :                         break;
     507         744 :                 ++p;
     508             :         }
     509             : 
     510         134 :         if (trusted) {
     511           0 :                 if (parsed_params) {
     512           0 :                         parsed_params[ODBC_PARAM_Trusted_Connection].p = "Yes";
     513           0 :                         parsed_params[ODBC_PARAM_Trusted_Connection].len = 3;
     514           0 :                         parsed_params[ODBC_PARAM_UID].p = NULL;
     515           0 :                         parsed_params[ODBC_PARAM_PWD].p = NULL;
     516             :                 }
     517           0 :                 tds_dstr_empty(&login->user_name);
     518           0 :                 tds_dstr_empty(&login->password);
     519             :         }
     520             : 
     521         134 :         tds_dstr_free(&value);
     522         134 :         return true;
     523             : }
     524             : 
     525             : #ifdef _WIN32
     526             : int
     527             : odbc_build_connect_string(TDS_ERRS *errs, TDS_PARSED_PARAM *params, char **out)
     528             : {
     529             :         unsigned n;
     530             :         size_t len = 1;
     531             :         char *p;
     532             : 
     533             :         /* compute string size */
     534             :         for (n = 0; n < ODBC_PARAM_SIZE; ++n) {
     535             :                 if (params[n].p)
     536             :                         len += strlen(odbc_param_names[n]) + params[n].len + 2;
     537             :         }
     538             : 
     539             :         /* allocate */
     540             :         p = tds_new(char, len);
     541             :         if (!p) {
     542             :                 odbc_errs_add(errs, "HY001", NULL);
     543             :                 return 0;
     544             :         }
     545             :         *out = p;
     546             : 
     547             :         /* build it */
     548             :         for (n = 0; n < ODBC_PARAM_SIZE; ++n) {
     549             :                 if (params[n].p)
     550             :                         p += sprintf(p, "%s=%.*s;", odbc_param_names[n], (int) params[n].len, params[n].p);
     551             :         }
     552             :         *p = 0;
     553             :         return 1;
     554             : }
     555             : #endif
     556             : 
     557             : #if !HAVE_SQLGETPRIVATEPROFILESTRING
     558             : 
     559             : #ifdef _WIN32
     560             : #  error There is something wrong  in configuration...
     561             : #endif
     562             : 
     563             : typedef struct
     564             : {
     565             :         LPCSTR entry;
     566             :         LPSTR buffer;
     567             :         int buffer_len;
     568             :         int ret_val;
     569             :         int found;
     570             : }
     571             : ProfileParam;
     572             : 
     573             : static void
     574       54132 : tdoParseProfile(const char *option, const char *value, void *param)
     575             : {
     576       54132 :         ProfileParam *p = (ProfileParam *) param;
     577             : 
     578       54132 :         if (strcasecmp(p->entry, option) == 0) {
     579        1704 :                 strlcpy(p->buffer, value, p->buffer_len);
     580             : 
     581        1704 :                 p->ret_val = strlen(p->buffer);
     582        1704 :                 p->found = 1;
     583             :         }
     584       54132 : }
     585             : 
     586             : static int
     587       18044 : SQLGetPrivateProfileString(LPCSTR pszSection, LPCSTR pszEntry, LPCSTR pszDefault, LPSTR pRetBuffer, int nRetBuffer,
     588             :                            LPCSTR pszFileName)
     589             : {
     590             :         FILE *hFile;
     591             :         ProfileParam param;
     592             : 
     593       18044 :         tdsdump_log(TDS_DBG_FUNC, "SQLGetPrivateProfileString(%p, %p, %p, %p, %d, %p)\n", 
     594             :                         pszSection, pszEntry, pszDefault, pRetBuffer, nRetBuffer, pszFileName);
     595             : 
     596       18044 :         if (!pszSection) {
     597             :                 /* spec says return list of all section names - but we will just return nothing */
     598           0 :                 tdsdump_log(TDS_DBG_WARN, "WARNING: Functionality for NULL pszSection not implemented.\n");
     599             :                 return 0;
     600             :         }
     601             : 
     602       18044 :         if (!pszEntry) {
     603             :                 /* spec says return list of all key names in section - but we will just return nothing */
     604           0 :                 tdsdump_log(TDS_DBG_WARN, "WARNING: Functionality for NULL pszEntry not implemented.\n");
     605             :                 return 0;
     606             :         }
     607             : 
     608       18044 :         if (nRetBuffer < 1)
     609           0 :                 tdsdump_log(TDS_DBG_WARN, "WARNING: No space to return a value because nRetBuffer < 1.\n");
     610             : 
     611       18044 :         if (pszFileName && *pszFileName == '/')
     612           0 :                 hFile = fopen(pszFileName, "r");
     613             :         else
     614       18044 :                 hFile = tdoGetIniFileName();
     615             : 
     616       18044 :         if (hFile == NULL) {
     617           0 :                 tdsdump_log(TDS_DBG_ERROR, "ERROR: Could not open configuration file\n");
     618             :                 return 0;
     619             :         }
     620             : 
     621       18044 :         param.entry = pszEntry;
     622       18044 :         param.buffer = pRetBuffer;
     623       18044 :         param.buffer_len = nRetBuffer;
     624       18044 :         param.ret_val = 0;
     625       18044 :         param.found = 0;
     626             : 
     627       18044 :         pRetBuffer[0] = 0;
     628       18044 :         tds_read_conf_section(hFile, pszSection, tdoParseProfile, &param);
     629             : 
     630       18044 :         if (pszDefault && !param.found) {
     631       16340 :                 strlcpy(pRetBuffer, pszDefault, nRetBuffer);
     632             : 
     633       16340 :                 param.ret_val = strlen(pRetBuffer);
     634             :         }
     635             : 
     636       18044 :         fclose(hFile);
     637       18044 :         return param.ret_val;
     638             : }
     639             : 
     640             : static FILE *
     641       18044 : tdoGetIniFileName()
     642             : {
     643       18044 :         FILE *ret = NULL;
     644             :         char *p;
     645             :         char *fn;
     646             : 
     647             :         /*
     648             :          * First, try the ODBCINI environment variable
     649             :          */
     650       18044 :         if ((p = getenv("ODBCINI")) != NULL)
     651       18044 :                 ret = fopen(p, "r");
     652             : 
     653             :         /*
     654             :          * Second, try the HOME environment variable
     655             :          */
     656       18044 :         if (!ret && (p = tds_get_homedir()) != NULL) {
     657           0 :                 fn = NULL;
     658           0 :                 if (asprintf(&fn, "%s/.odbc.ini", p) > 0) {
     659           0 :                         ret = fopen(fn, "r");
     660           0 :                         free(fn);
     661             :                 }
     662           0 :                 free(p);
     663             :         }
     664             : 
     665             :         /*
     666             :          * As a last resort, try SYS_ODBC_INI
     667             :          */
     668       18044 :         if (!ret)
     669           0 :                 ret = fopen(SYS_ODBC_INI, "r");
     670             : 
     671       18044 :         return ret;
     672             : }
     673             : 
     674             : #endif /* !HAVE_SQLGETPRIVATEPROFILESTRING */
     675             : 
     676             : #ifdef UNIXODBC
     677             : 
     678             : /*
     679             :  * Begin BIG Hack.
     680             :  *  
     681             :  * We need these from odbcinstext.h but it wants to 
     682             :  * include <log.h> and <ini.h>, which are not in the 
     683             :  * standard include path.  XXX smurph
     684             :  * confirmed by unixODBC stuff, odbcinstext.h shouldn't be installed. freddy77
     685             :  */
     686             : #define     INI_MAX_LINE            1000
     687             : #define     INI_MAX_OBJECT_NAME     INI_MAX_LINE
     688             : #define     INI_MAX_PROPERTY_NAME   INI_MAX_LINE
     689             : #define     INI_MAX_PROPERTY_VALUE  INI_MAX_LINE
     690             : 
     691             : #define ODBCINST_PROMPTTYPE_LABEL               0       /* readonly */
     692             : #define ODBCINST_PROMPTTYPE_TEXTEDIT    1
     693             : #define ODBCINST_PROMPTTYPE_LISTBOX             2
     694             : #define ODBCINST_PROMPTTYPE_COMBOBOX    3
     695             : #define ODBCINST_PROMPTTYPE_FILENAME    4
     696             : #define ODBCINST_PROMPTTYPE_HIDDEN          5
     697             : 
     698             : typedef struct tODBCINSTPROPERTY
     699             : {
     700             :         /** pointer to next property, NULL if last property */
     701             :         struct tODBCINSTPROPERTY *pNext;
     702             : 
     703             :         /** property name */
     704             :         char szName[INI_MAX_PROPERTY_NAME + 1];
     705             : 
     706             :         /** property value */
     707             :         char szValue[INI_MAX_PROPERTY_VALUE + 1];
     708             : 
     709             :         /** PROMPTTYPE_TEXTEDIT, PROMPTTYPE_LISTBOX, PROMPTTYPE_COMBOBOX, PROMPTTYPE_FILENAME */
     710             :         int nPromptType;
     711             : 
     712             :         /** array of pointers terminated with a NULL value in array */
     713             :         char **aPromptData;
     714             : 
     715             :         /** help on this property (driver setups should keep it short) */
     716             :         char *pszHelp;
     717             : 
     718             :         /** CALLER CAN STORE A POINTER TO ? HERE */
     719             :         void *pWidget;
     720             : 
     721             :         /** app should refresh widget ie Driver Setup has changed aPromptData or szValue */
     722             :         int bRefresh;
     723             : 
     724             :         /** for odbcinst internal use... only first property has valid one */
     725             :         void *hDLL;
     726             : }
     727             : ODBCINSTPROPERTY, *HODBCINSTPROPERTY;
     728             : 
     729             : /* 
     730             :  * End BIG Hack.
     731             :  */
     732             : 
     733             : int ODBCINSTGetProperties(HODBCINSTPROPERTY hLastProperty);
     734             : 
     735             : static const char *const aTDSver[] = {
     736             :         "",
     737             :         "4.2",
     738             :         "5.0",
     739             :         "7.0",
     740             :         "7.1",
     741             :         "7.2",
     742             :         "7.3",
     743             :         "7.4",
     744             :         NULL
     745             : };
     746             : 
     747             : static const char *const aLanguage[] = {
     748             :         "us_english",
     749             :         NULL
     750             : };
     751             : 
     752             : static const char *const aEncryption[] = {
     753             :         TDS_STR_ENCRYPTION_OFF,
     754             :         TDS_STR_ENCRYPTION_REQUEST,
     755             :         TDS_STR_ENCRYPTION_REQUIRE,
     756             :         NULL
     757             : };
     758             : 
     759             : static const char *const aBoolean[] = {
     760             :         "Yes",
     761             :         "No",
     762             :         NULL
     763             : };
     764             : 
     765             : /*
     766             : static const char *aAuth[] = {
     767             :         "Server",
     768             :         "Domain",
     769             :         "Both",
     770             :         NULL
     771             : };
     772             : */
     773             : 
     774             : static HODBCINSTPROPERTY
     775             : addProperty(HODBCINSTPROPERTY hLastProperty)
     776             : {
     777             :         hLastProperty->pNext = (HODBCINSTPROPERTY) calloc(1, sizeof(ODBCINSTPROPERTY));
     778             :         hLastProperty = hLastProperty->pNext;
     779             :         return hLastProperty;
     780             : }
     781             : 
     782             : static HODBCINSTPROPERTY
     783             : definePropertyString(HODBCINSTPROPERTY hLastProperty, const char *name, const char *value, const char *comment)
     784             : {
     785             :         hLastProperty = addProperty(hLastProperty);
     786             :         hLastProperty->nPromptType = ODBCINST_PROMPTTYPE_TEXTEDIT;
     787             :         strlcpy(hLastProperty->szName, name, INI_MAX_PROPERTY_NAME);
     788             :         strlcpy(hLastProperty->szValue, value, INI_MAX_PROPERTY_VALUE);
     789             :         hLastProperty->pszHelp = (char *) strdup(comment);
     790             :         return hLastProperty;
     791             : }
     792             : 
     793             : static HODBCINSTPROPERTY
     794             : definePropertyBoolean(HODBCINSTPROPERTY hLastProperty, const char *name, const char *value, const char *comment)
     795             : {
     796             :         hLastProperty = addProperty(hLastProperty);
     797             :         hLastProperty->nPromptType = ODBCINST_PROMPTTYPE_LISTBOX;
     798             :         hLastProperty->aPromptData = malloc(sizeof(aBoolean));
     799             :         memcpy(hLastProperty->aPromptData, aBoolean, sizeof(aBoolean));
     800             :         strlcpy(hLastProperty->szName, name, INI_MAX_PROPERTY_NAME);
     801             :         strlcpy(hLastProperty->szValue, value, INI_MAX_PROPERTY_VALUE);
     802             :         hLastProperty->pszHelp = (char *) strdup(comment);
     803             :         return hLastProperty;
     804             : }
     805             : 
     806             : static HODBCINSTPROPERTY
     807             : definePropertyHidden(HODBCINSTPROPERTY hLastProperty, const char *name, const char *value, const char *comment)
     808             : {
     809             :         hLastProperty = addProperty(hLastProperty);
     810             :         hLastProperty->nPromptType = ODBCINST_PROMPTTYPE_HIDDEN;
     811             :         strlcpy(hLastProperty->szName, name, INI_MAX_PROPERTY_NAME);
     812             :         strlcpy(hLastProperty->szValue, value, INI_MAX_PROPERTY_VALUE);
     813             :         hLastProperty->pszHelp = (char *) strdup(comment);
     814             :         return hLastProperty;
     815             : }
     816             : 
     817             : static HODBCINSTPROPERTY
     818             : definePropertyList(HODBCINSTPROPERTY hLastProperty, const char *name, const char *value, const void *list, int size, const char *comment)
     819             : {
     820             :         hLastProperty = addProperty(hLastProperty);
     821             :         hLastProperty->nPromptType = ODBCINST_PROMPTTYPE_LISTBOX;
     822             :         hLastProperty->aPromptData = malloc(size);
     823             :         memcpy(hLastProperty->aPromptData, list, size);
     824             :         strlcpy(hLastProperty->szName, name, INI_MAX_PROPERTY_NAME);
     825             :         strlcpy(hLastProperty->szValue, value, INI_MAX_PROPERTY_VALUE);
     826             :         hLastProperty->pszHelp = (char *) strdup(comment);
     827             :         return hLastProperty;
     828             : }
     829             : 
     830             : int
     831             : ODBCINSTGetProperties(HODBCINSTPROPERTY hLastProperty)
     832             : {
     833             :         hLastProperty = definePropertyString(hLastProperty, odbc_param_Servername, "", 
     834             :                 "Name of FreeTDS connection to connect to.\n"
     835             :                 "This server name refer to entry in freetds.conf file, not real server name.\n"
     836             :                 "This property cannot be used with Server property.");
     837             : 
     838             :         hLastProperty = definePropertyString(hLastProperty, odbc_param_Server, "", 
     839             :                 "Name of server to connect to.\n"
     840             :                 "This should be the name of real server.\n"
     841             :                 "This property cannot be used with Servername property.");
     842             : 
     843             :         hLastProperty = definePropertyString(hLastProperty, odbc_param_Address, "", 
     844             :                 "The hostname or ip address of the server.");
     845             : 
     846             :         hLastProperty = definePropertyString(hLastProperty, odbc_param_Port, "1433", 
     847             :                 "TCP/IP Port to connect to.");
     848             : 
     849             :         hLastProperty = definePropertyString(hLastProperty, odbc_param_Database, "", 
     850             :                 "Default database.");
     851             : 
     852             :         hLastProperty = definePropertyList(hLastProperty, odbc_param_TDS_Version, "4.2", (void*) aTDSver, sizeof(aTDSver),
     853             :                 "The TDS protocol version.\n"
     854             :                 " 4.2 MSSQL 6.5 or Sybase < 10.x\n"
     855             :                 " 5.0 Sybase >= 10.x\n"
     856             :                 " 7.0 MSSQL 7\n"
     857             :                 " 7.1 MSSQL 2000\n"
     858             :                 " 7.2 MSSQL 2005\n"
     859             :                 " 7.3 MSSQL 2008\n"
     860             :                 " 7.4 MSSQL 2012 or 2014"
     861             :                 );
     862             : 
     863             :         hLastProperty = definePropertyList(hLastProperty, odbc_param_Language, "us_english", (void*) aLanguage, sizeof(aLanguage),
     864             :                 "The default language setting.");
     865             : 
     866             :         hLastProperty = definePropertyHidden(hLastProperty, odbc_param_TextSize, "", 
     867             :                 "Text datatype limit.");
     868             : 
     869             :         /* ??? in odbc.ini ??? */
     870             : /*
     871             :         hLastProperty = definePropertyString(hLastProperty, odbc_param_UID, "", 
     872             :                 "User ID (Beware of security issues).");
     873             : 
     874             :         hLastProperty = definePropertyString(hLastProperty, odbc_param_PWD, "", 
     875             :                 "Password (Beware of security issues).");
     876             : */
     877             : 
     878             : /*
     879             :         hLastProperty = definePropertyList(hLastProperty, odbc_param_Authentication, "Server", aAuth, sizeof(aAuth),
     880             :                 "The server authentication mechanism.");
     881             : 
     882             :         hLastProperty = definePropertyString(hLastProperty, odbc_param_Domain, "", 
     883             :                 "The default domain to use when using Domain Authentication.");
     884             : */
     885             : 
     886             :         hLastProperty = definePropertyString(hLastProperty, odbc_param_PacketSize, "", 
     887             :                 "Size of network packets.");
     888             : 
     889             :         hLastProperty = definePropertyString(hLastProperty, odbc_param_ClientCharset, "", 
     890             :                 "The client character set name to convert application characters to UCS-2 in TDS 7.0 and higher.");
     891             : 
     892             :         hLastProperty = definePropertyString(hLastProperty, odbc_param_DumpFile, "",
     893             :                 "Specifies the location of a tds dump file and turns on logging.");
     894             : 
     895             :         hLastProperty = definePropertyBoolean(hLastProperty, odbc_param_DumpFileAppend, "",
     896             :                 "Appends dump file instead of overwriting it. Useful for debugging when many processes are active.");
     897             : 
     898             :         hLastProperty = definePropertyString(hLastProperty, odbc_param_DebugFlags, "", 
     899             :                 "Sets granularity of logging. A set of bit that specify levels and informations. See table below for bit specification.");
     900             : 
     901             :         hLastProperty = definePropertyList(hLastProperty, odbc_param_Encryption, TDS_STR_ENCRYPTION_OFF, aEncryption, sizeof(aEncryption),
     902             :                 "The encryption method.");
     903             : 
     904             :         hLastProperty = definePropertyString(hLastProperty, odbc_param_Timeout, "10",
     905             :                 "Connection timeout.");
     906             : 
     907             :         return 1;
     908             : }
     909             : 
     910             : #endif

Generated by: LCOV version 1.13