LCOV - code coverage report
Current view: top level - src/odbc - connectparams.c (source / functions) Hit Total Coverage
Test: FreeTDS coverage Lines: 203 320 63.4 %
Date: 2026-07-19 14:02:14 Functions: 8 9 88.9 %

          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-2024  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/path.h>
      33             : #include <freetds/utils.h>
      34             : #include <freetds/replacements.h>
      35             : 
      36             : #define ODBC_PARAM(p) const char odbc_param_##p[] = #p;
      37             : ODBC_PARAM_LIST
      38             : #undef ODBC_PARAM
      39             : 
      40             : #ifdef _WIN32
      41             : #define ODBC_PARAM(p) odbc_param_##p,
      42             : static const char *odbc_param_names[] = {
      43             :         ODBC_PARAM_LIST
      44             : };
      45             : #undef ODBC_PARAM
      46             : #endif
      47             : 
      48             : #if !HAVE_SQLGETPRIVATEPROFILESTRING
      49             : 
      50             : /*
      51             :  * Last resort place to check for INI file. This is usually set at compile time
      52             :  * by build scripts.
      53             :  */
      54             : #ifndef SYS_ODBC_INI
      55             : #define SYS_ODBC_INI "/etc/odbc.ini"
      56             : #endif
      57             : 
      58             : /**
      59             :  * Call this to get the INI file containing Data Source Names.
      60             :  * @note rules for determining the location of ODBC config may be different 
      61             :  * then what you expect - at this time they differ from unixODBC 
      62             :  *
      63             :  * @return file opened or NULL if error
      64             :  * @retval 1 worked
      65             :  */
      66             : static FILE *tdoGetIniFileName(void);
      67             : 
      68             : /* avoid name collision with system headers */
      69             : #define SQLGetPrivateProfileString tds_SQLGetPrivateProfileString
      70             : 
      71             : /**
      72             :  * SQLGetPrivateProfileString
      73             :  *
      74             :  * PURPOSE
      75             :  *
      76             :  *  This is an implementation of a common MS API call. This implementation 
      77             :  *  should only be used if the ODBC sub-system/SDK does not have it.
      78             :  *  For example; unixODBC has its own so those using unixODBC should NOT be
      79             :  *  using this implementation because unixODBC;
      80             :  *  - provides caching of ODBC config data 
      81             :  *  - provides consistent interpretation of ODBC config data (i.e, location)
      82             :  *
      83             :  * ARGS
      84             :  *
      85             :  *  see ODBC documentation
      86             :  *                      
      87             :  * RETURNS
      88             :  *
      89             :  *  see ODBC documentation
      90             :  *
      91             :  * NOTES:
      92             :  *
      93             :  *  - the spec is not entirely implemented... consider this a lite version
      94             :  *  - rules for determining the location of ODBC config may be different then what you 
      95             :  *    expect see tdoGetIniFileName().
      96             :  *
      97             :  */
      98             : #ifndef _WIN32
      99             : static
     100             : #endif
     101             : int SQLGetPrivateProfileString(LPCSTR pszSection, LPCSTR pszEntry, LPCSTR pszDefault,
     102             :                                LPSTR pRetBuffer, int nRetBuffer, LPCSTR pszFileName);
     103             : #endif
     104             : 
     105             : #if defined(FILENAME_MAX) && FILENAME_MAX < 512
     106             : #undef FILENAME_MAX
     107             : #define FILENAME_MAX 512
     108             : #endif
     109             : 
     110             : static int
     111         110 : parse_server(TDS_ERRS *errs, char *server, TDSLOGIN * login)
     112             : {
     113         110 :         char *p = (char *) strchr(server, '\\');
     114             : 
     115         110 :         if (p) {
     116           0 :                 if (!tds_dstr_copy(&login->instance_name, p+1)) {
     117           0 :                         odbc_errs_add(errs, "HY001", NULL);
     118           0 :                         return 0;
     119             :                 }
     120           0 :                 *p = 0;
     121             :         } else {
     122         110 :                 p = (char *) strchr(server, ',');
     123         130 :                 if (p && atoi(p+1) > 0) {
     124          40 :                         login->port = atoi(p+1);
     125          20 :                         *p = 0;
     126             :                 }
     127             :         }
     128             : 
     129         110 :         if (TDS_SUCCEED(tds_lookup_host_set(server, &login->ip_addrs)))
     130         110 :                 if (!tds_dstr_copy(&login->server_host_name, server)) {
     131           0 :                         odbc_errs_add(errs, "HY001", NULL);
     132           0 :                         return 0;
     133             :                 }
     134             : 
     135             :         return 1;
     136             : }
     137             : 
     138             : static int
     139             : myGetPrivateProfileString(const char *DSN, const char *key, char *buf)
     140             : {
     141       30036 :         buf[0] = '\0';
     142       30036 :         return SQLGetPrivateProfileString(DSN, key, "", buf, FILENAME_MAX, "odbc.ini");
     143             : }
     144             : 
     145             : /**
     146             :  * Converts Encrypt option to Encryption option.
     147             :  * Encryption is FreeTDS specific and older than Encrypt.
     148             :  */
     149             : static const char *
     150          20 : odbc_encrypt2encryption(const char *encrypt)
     151             : {
     152          20 :         if (strcasecmp(encrypt, "strict") == 0)
     153             :                 return TDS_STR_ENCRYPTION_STRICT;
     154             : 
     155          20 :         if (strcasecmp(encrypt, "mandatory") == 0
     156          20 :             || strcasecmp(encrypt, "true") == 0
     157          20 :             || strcasecmp(encrypt, "yes") == 0)
     158             :                 return TDS_STR_ENCRYPTION_REQUIRE;
     159             : 
     160          20 :         if (strcasecmp(encrypt, "optional") == 0
     161          20 :             || strcasecmp(encrypt, "false") == 0
     162          20 :             || strcasecmp(encrypt, "no") == 0)
     163             :                 return TDS_STR_ENCRYPTION_REQUEST;
     164             : 
     165           0 :         return "invalid_encrypt";
     166             : }
     167             : 
     168             : static const char *
     169           0 : odbc_appintent2readonly(const char *appintent)
     170             : {
     171           0 :         if (strcasecmp(appintent,"ReadOnly") == 0)
     172             :                 return "yes";
     173           0 :         if (strcasecmp(appintent,"ReadWrite") == 0)
     174             :                 return "no";
     175             : 
     176           0 :         return "Invalid_application_intent";
     177             : }
     178             : 
     179             : /** 
     180             :  * Read connection information from given DSN
     181             :  * @param DSN           DSN name
     182             :  * @param login    where to store connection info
     183             :  * @return true if success false otherwhise
     184             :  */
     185             : bool
     186        1156 : odbc_get_dsn_info(TDS_ERRS *errs, const char *DSN, TDSLOGIN * login)
     187             : {
     188             :         char tmp[FILENAME_MAX];
     189        1156 :         bool freetds_conf_less = true;
     190             : 
     191             :         /* use old servername */
     192        1156 :         if (myGetPrivateProfileString(DSN, odbc_param_Servername, tmp) > 0) {
     193        1156 :                 freetds_conf_less = false;
     194        1156 :                 if (!tds_dstr_copy(&login->server_name, tmp)) {
     195           0 :                         odbc_errs_add(errs, "HY001", NULL);
     196           0 :                         return false;
     197             :                 }
     198        1156 :                 tds_read_conf_file(login, tmp);
     199        1156 :                 if (myGetPrivateProfileString(DSN, odbc_param_Server, tmp) > 0) {
     200           0 :                         odbc_errs_add(errs, "HY000", "You cannot specify both SERVERNAME and SERVER");
     201           0 :                         return false;
     202             :                 }
     203        1156 :                 if (myGetPrivateProfileString(DSN, odbc_param_Address, tmp) > 0) {
     204           0 :                         odbc_errs_add(errs, "HY000", "You cannot specify both SERVERNAME and ADDRESS");
     205           0 :                         return false;
     206             :                 }
     207             :         }
     208             : 
     209             :         /* search for server (compatible with ms one) */
     210             :         if (freetds_conf_less) {
     211           0 :                 bool address_specified = false;
     212             : 
     213           0 :                 if (myGetPrivateProfileString(DSN, odbc_param_Address, tmp) > 0) {
     214           0 :                         address_specified = true;
     215             :                         /* TODO parse like MS */
     216             : 
     217           0 :                         if (TDS_FAILED(tds_lookup_host_set(tmp, &login->ip_addrs))) {
     218           0 :                                 odbc_errs_add(errs, "HY000", "Error parsing ADDRESS attribute");
     219           0 :                                 return false;
     220             :                         }
     221             :                 }
     222           0 :                 if (myGetPrivateProfileString(DSN, odbc_param_Server, tmp) > 0) {
     223           0 :                         if (!tds_dstr_copy(&login->server_name, tmp)) {
     224           0 :                                 odbc_errs_add(errs, "HY001", NULL);
     225           0 :                                 return false;
     226             :                         }
     227           0 :                         if (!address_specified) {
     228           0 :                                 if (!parse_server(errs, tmp, login))
     229             :                                         return false;
     230             :                         }
     231             :                 }
     232             :         }
     233             : 
     234        1156 :         if (myGetPrivateProfileString(DSN, odbc_param_Port, tmp) > 0)
     235           0 :                 tds_parse_conf_section(TDS_STR_PORT, tmp, login);
     236             : 
     237        1156 :         if (myGetPrivateProfileString(DSN, odbc_param_TDS_Version, tmp) > 0)
     238           0 :                 tds_parse_conf_section(TDS_STR_VERSION, tmp, login);
     239             : 
     240        1156 :         if (myGetPrivateProfileString(DSN, odbc_param_Language, tmp) > 0)
     241           0 :                 tds_parse_conf_section(TDS_STR_LANGUAGE, tmp, login);
     242             : 
     243        2312 :         if (tds_dstr_isempty(&login->database)
     244        1136 :             && myGetPrivateProfileString(DSN, odbc_param_Database, tmp) > 0)
     245        1136 :                 if (!tds_dstr_copy(&login->database, tmp)) {
     246           0 :                         odbc_errs_add(errs, "HY001", NULL);
     247           0 :                         return false;
     248             :                 }
     249             : 
     250        1156 :         if (myGetPrivateProfileString(DSN, odbc_param_TextSize, tmp) > 0)
     251           0 :                 tds_parse_conf_section(TDS_STR_TEXTSZ, tmp, login);
     252             : 
     253        1156 :         if (myGetPrivateProfileString(DSN, odbc_param_PacketSize, tmp) > 0)
     254           0 :                 tds_parse_conf_section(TDS_STR_BLKSZ, tmp, login);
     255             : 
     256        1156 :         if (myGetPrivateProfileString(DSN, odbc_param_ClientCharset, tmp) > 0)
     257           0 :                 tds_parse_conf_section(TDS_STR_CLCHARSET, tmp, login);
     258             : 
     259        1156 :         if (myGetPrivateProfileString(DSN, odbc_param_DumpFile, tmp) > 0)
     260           0 :                 tds_parse_conf_section(TDS_STR_DUMPFILE, tmp, login);
     261             : 
     262        1156 :         if (myGetPrivateProfileString(DSN, odbc_param_DumpFileAppend, tmp) > 0)
     263           0 :                 tds_parse_conf_section(TDS_STR_APPENDMODE, tmp, login);
     264             : 
     265        1156 :         if (myGetPrivateProfileString(DSN, odbc_param_DebugFlags, tmp) > 0)
     266           0 :                 tds_parse_conf_section(TDS_STR_DEBUGFLAGS, tmp, login);
     267             : 
     268        1156 :         if (myGetPrivateProfileString(DSN, odbc_param_Encryption, tmp) > 0)
     269           0 :                 tds_parse_conf_section(TDS_STR_ENCRYPTION, tmp, login);
     270             : 
     271        1156 :         if (myGetPrivateProfileString(DSN, odbc_param_Encrypt, tmp) > 0)
     272           0 :                 tds_parse_conf_section(TDS_STR_ENCRYPTION, odbc_encrypt2encryption(tmp), login);
     273             : 
     274        1156 :         if (myGetPrivateProfileString(DSN, odbc_param_ServerCertificate, tmp) > 0)
     275           0 :                 tds_parse_conf_section(TDS_STR_CAFILE, tmp, login);
     276             : 
     277        1156 :         if (myGetPrivateProfileString(DSN, odbc_param_ApplicationIntent, tmp) > 0)
     278           0 :                 tds_parse_conf_section(TDS_STR_READONLY_INTENT, odbc_appintent2readonly(tmp), login);
     279             : 
     280        1156 :         if (myGetPrivateProfileString(DSN, odbc_param_UseNTLMv2, tmp) > 0)
     281           0 :                 tds_parse_conf_section(TDS_STR_USENTLMV2, tmp, login);
     282             : 
     283        1156 :         if (myGetPrivateProfileString(DSN, odbc_param_REALM, tmp) > 0)
     284           0 :                 tds_parse_conf_section(TDS_STR_REALM, tmp, login);
     285             : 
     286        1156 :         if (myGetPrivateProfileString(DSN, odbc_param_ServerSPN, tmp) > 0)
     287           0 :                 tds_parse_conf_section(TDS_STR_SPN, tmp, login);
     288             : 
     289        1156 :         if (myGetPrivateProfileString(DSN, odbc_param_Trusted_Connection, tmp) > 0
     290           0 :             && tds_config_boolean(odbc_param_Trusted_Connection, tmp, login)) {
     291           0 :                 tds_dstr_empty(&login->user_name);
     292           0 :                 tds_dstr_empty(&login->password);
     293             :         }
     294             : 
     295        1156 :         if (myGetPrivateProfileString(DSN, odbc_param_MARS_Connection, tmp) > 0
     296           0 :             && tds_config_boolean(odbc_param_MARS_Connection, tmp, login)) {
     297           0 :                 login->mars = 1;
     298             :         }
     299             : 
     300        1156 :         if (myGetPrivateProfileString(DSN, odbc_param_AttachDbFilename, tmp) > 0)
     301           0 :                 tds_parse_conf_section(TDS_STR_DBFILENAME, tmp, login);
     302             : 
     303        1156 :         if (myGetPrivateProfileString(DSN, odbc_param_Timeout, tmp) > 0)
     304           0 :                 tds_parse_conf_section(TDS_STR_TIMEOUT, tmp, login);
     305             : 
     306        1156 :         if (myGetPrivateProfileString(DSN, odbc_param_ConnectionTimeout, tmp) > 0)
     307           0 :                 tds_parse_conf_section(TDS_STR_CONNTIMEOUT, tmp, login);
     308             : 
     309        1156 :         if (myGetPrivateProfileString(DSN, odbc_param_HostNameInCertificate, tmp) > 0
     310           0 :             && (tmp[0] && strcmp(tmp, "null") != 0)) {
     311           0 :                 if (!tds_dstr_copy(&login->certificate_host_name, tmp)) {
     312           0 :                         odbc_errs_add(errs, "HY001", NULL);
     313           0 :                         return false;
     314             :                 }
     315             :         }
     316             : 
     317             :         return true;
     318             : }
     319             : 
     320             : /**
     321             :  * Swap two DSTR
     322             :  */
     323             : static void
     324             : odbc_dstr_swap(DSTR *a, DSTR *b)
     325             : {
     326         842 :         DSTR tmp = *a;
     327         842 :         *a = *b;
     328         842 :         *b = tmp;
     329             : }
     330             : 
     331             : static const char *
     332        1578 : parse_value(TDS_ERRS *errs, const char *p, const char *connect_string_end, DSTR *value)
     333             : {
     334             :         const char *end;
     335             :         char *dst;
     336             : 
     337             :         /* easy case, just ';' terminated */
     338        1578 :         if (p == connect_string_end || *p != '{') {
     339        1258 :                 end = (const char *) memchr(p, ';', connect_string_end - p);
     340        1258 :                 if (!end)
     341           8 :                         end = connect_string_end;
     342        1258 :                 if (!tds_dstr_copyn(value, p, end - p)) {
     343           0 :                         odbc_errs_add(errs, "HY001", NULL);
     344           0 :                         return NULL;
     345             :                 }
     346             :                 return end;
     347             :         }
     348             : 
     349         320 :         ++p;
     350             :         /* search "};" */
     351         320 :         end = p;
     352             :         for (;;) {
     353             :                 /* search next '}' */
     354         380 :                 end = (const char *) memchr(end, '}', connect_string_end - end);
     355         350 :                 if (end == NULL) {
     356          20 :                         odbc_errs_add(errs, "HY000", "Syntax error in connection string");
     357          20 :                         return NULL;
     358             :                 }
     359         330 :                 end++;
     360             : 
     361             :                 /* termination ? */
     362         330 :                 if (end == connect_string_end || end[0] == ';') {
     363         300 :                         end--;
     364             :                         break;
     365             :                 }
     366             : 
     367             :                 /* wrong syntax ? */
     368          30 :                 if (end[0] != '}') {
     369           0 :                         odbc_errs_add(errs, "HY000", "Syntax error in connection string");
     370           0 :                         return NULL;
     371             :                 }
     372          30 :                 end++;
     373             :         }
     374         300 :         if (!tds_dstr_alloc(value, end - p)) {
     375           0 :                 odbc_errs_add(errs, "HY001", NULL);
     376           0 :                 return NULL;
     377             :         }
     378         600 :         dst = tds_dstr_buf(value);
     379        3160 :         for (; p < end; ++p) {
     380        2860 :                 char ch = *p;
     381        2860 :                 *dst++ = ch;
     382        2860 :                 if (ch == '}')
     383          30 :                         ++p;
     384             :         }
     385         600 :         tds_dstr_setlen(value, dst - tds_dstr_buf(value));
     386             : 
     387         300 :         return end + 1;
     388             : }
     389             : 
     390             : /** 
     391             :  * Parse connection string and fill login according
     392             :  * @param connect_string     connect string
     393             :  * @param connect_string_end connect string end (pointer to char past last)
     394             :  * @param login         where to store connection info
     395             :  * @return true if success false otherwise
     396             :  */
     397             : bool
     398         248 : odbc_parse_connect_string(TDS_ERRS *errs, const char *connect_string, const char *connect_string_end, TDSLOGIN *login,
     399             :                           TDS_DBC *dbc, TDS_PARSED_PARAM *parsed_params)
     400             : {
     401             :         const char *p, *end;
     402         248 :         DSTR *dest_s, value = DSTR_INITIALIZER;
     403             :         enum { CFG_DSN = 1, CFG_SERVERNAME = 2 };
     404         248 :         unsigned int cfgs = 0;  /* flags for indicate second parse of string */
     405             :         char option[24];
     406         248 :         int trusted = 0;
     407             : 
     408         248 :         if (parsed_params)
     409         248 :                 memset(parsed_params, 0, sizeof(*parsed_params)*ODBC_PARAM_SIZE);
     410             : 
     411        1778 :         for (p = connect_string; p < connect_string_end && *p;) {
     412             :                 int num_param = -1;
     413             : 
     414             :                 dest_s = NULL;
     415             : 
     416             :                 /* handle empty options */
     417        1578 :                 while (p < connect_string_end && *p == ';')
     418           0 :                         ++p;
     419             : 
     420             :                 /* parse option */
     421        1578 :                 end = (const char *) memchr(p, '=', connect_string_end - p);
     422        1578 :                 if (!end)
     423             :                         break;
     424             : 
     425             :                 /* account for spaces between ;'s. */
     426        1578 :                 while (p < end && *p == ' ')
     427           0 :                         ++p;
     428             : 
     429        1578 :                 if ((end - p) >= (int) sizeof(option))
     430           0 :                         option[0] = 0;
     431             :                 else {
     432        1578 :                         memcpy(option, p, end - p);
     433        1578 :                         option[end - p] = 0;
     434             :                 }
     435             : 
     436             :                 /* parse value */
     437        1578 :                 p = end + 1;
     438        1578 :                 end = parse_value(errs, p, connect_string_end, &value);
     439        1578 :                 if (!end)
     440             :                         goto Cleanup;
     441             : 
     442             : #define CHK_PARAM(p) (strcasecmp(option, odbc_param_##p) == 0 && (num_param=ODBC_PARAM_##p) >= 0)
     443        1558 :                 if (CHK_PARAM(Server)) {
     444         110 :                         dest_s = &login->server_name;
     445         220 :                         if (!parse_server(errs, tds_dstr_buf(&value), login))
     446             :                                 goto Cleanup;
     447        1448 :                 } else if (CHK_PARAM(Servername)) {
     448          40 :                         if ((cfgs & CFG_DSN) != 0) {
     449           0 :                                 odbc_errs_add(errs, "HY000", "Only one between SERVERNAME and DSN can be specified");
     450           0 :                                 goto Cleanup;
     451             :                         }
     452          40 :                         if (!cfgs) {
     453          40 :                                 odbc_dstr_swap(&login->server_name, &value);
     454          40 :                                 tds_read_conf_file(login, tds_dstr_cstr(&login->server_name));
     455          20 :                                 cfgs = CFG_SERVERNAME;
     456          20 :                                 p = connect_string;
     457          20 :                                 continue;
     458             :                         }
     459        1408 :                 } else if (CHK_PARAM(DSN)) {
     460         276 :                         if ((cfgs & CFG_SERVERNAME) != 0) {
     461           0 :                                 odbc_errs_add(errs, "HY000", "Only one between SERVERNAME and DSN can be specified");
     462           0 :                                 goto Cleanup;
     463             :                         }
     464         276 :                         if (!cfgs) {
     465         276 :                                 if (!odbc_get_dsn_info(errs, tds_dstr_cstr(&value), login))
     466             :                                         goto Cleanup;
     467         138 :                                 cfgs = CFG_DSN;
     468         138 :                                 p = connect_string;
     469         138 :                                 continue;
     470             :                         }
     471        1132 :                 } else if (CHK_PARAM(Database)) {
     472         228 :                         dest_s = &login->database;
     473         904 :                 } else if (CHK_PARAM(UID)) {
     474         238 :                         dest_s = &login->user_name;
     475         666 :                 } else if (CHK_PARAM(PWD)) {
     476         238 :                         dest_s = &login->password;
     477         428 :                 } else if (CHK_PARAM(APP)) {
     478           8 :                         dest_s = &login->app_name;
     479         420 :                 } else if (CHK_PARAM(WSID)) {
     480           0 :                         dest_s = &login->client_host_name;
     481         420 :                 } else if (CHK_PARAM(Language)) {
     482           0 :                         tds_parse_conf_section(TDS_STR_LANGUAGE, tds_dstr_cstr(&value), login);
     483         420 :                 } else if (CHK_PARAM(Port)) {
     484         180 :                         tds_parse_conf_section(TDS_STR_PORT, tds_dstr_cstr(&value), login);
     485         330 :                 } else if (CHK_PARAM(TDS_Version)) {
     486          60 :                         tds_parse_conf_section(TDS_STR_VERSION, tds_dstr_cstr(&value), login);
     487         300 :                 } else if (CHK_PARAM(TextSize)) {
     488           0 :                         tds_parse_conf_section(TDS_STR_TEXTSZ, tds_dstr_cstr(&value), login);
     489         300 :                 } else if (CHK_PARAM(PacketSize)) {
     490           0 :                         tds_parse_conf_section(TDS_STR_BLKSZ, tds_dstr_cstr(&value), login);
     491         300 :                 } else if (CHK_PARAM(ClientCharset)
     492         180 :                            || strcasecmp(option, "client_charset") == 0) {
     493         120 :                         num_param = ODBC_PARAM_ClientCharset;
     494         240 :                         tds_parse_conf_section(TDS_STR_CLCHARSET, tds_dstr_cstr(&value), login);
     495         180 :                 } else if (CHK_PARAM(DateTimeFmt) && dbc != NULL) {
     496           0 :                         dest_s = &dbc->datetime_fmt;
     497         180 :                 } else if (CHK_PARAM(DateFmt) && dbc != NULL) {
     498           0 :                         dest_s = &dbc->date_fmt;
     499         180 :                 } else if (CHK_PARAM(TimeFmt) && dbc != NULL) {
     500           0 :                         dest_s = &dbc->time_fmt;
     501         180 :                 } else if (CHK_PARAM(DumpFile)) {
     502           0 :                         tds_parse_conf_section(TDS_STR_DUMPFILE, tds_dstr_cstr(&value), login);
     503         180 :                 } else if (CHK_PARAM(DumpFileAppend)) {
     504           0 :                         tds_parse_conf_section(TDS_STR_APPENDMODE, tds_dstr_cstr(&value), login);
     505         180 :                 } else if (CHK_PARAM(DebugFlags)) {
     506           0 :                         tds_parse_conf_section(TDS_STR_DEBUGFLAGS, tds_dstr_cstr(&value), login);
     507         180 :                 } else if (CHK_PARAM(Encryption)) {
     508           0 :                         tds_parse_conf_section(TDS_STR_ENCRYPTION, tds_dstr_cstr(&value), login);
     509         180 :                 } else if (CHK_PARAM(Encrypt)) {
     510          40 :                         tds_parse_conf_section(TDS_STR_ENCRYPTION, odbc_encrypt2encryption(tds_dstr_cstr(&value)), login);
     511         160 :                 } else if (CHK_PARAM(ServerCertificate)) {
     512           0 :                         tds_parse_conf_section(TDS_STR_CAFILE, tds_dstr_cstr(&value), login);
     513         160 :                 } else if (CHK_PARAM(UseNTLMv2)) {
     514           0 :                         tds_parse_conf_section(TDS_STR_USENTLMV2, tds_dstr_cstr(&value), login);
     515         160 :                 } else if (CHK_PARAM(REALM)) {
     516           0 :                         tds_parse_conf_section(TDS_STR_REALM, tds_dstr_cstr(&value), login);
     517         160 :                 } else if (CHK_PARAM(ServerSPN)) {
     518           0 :                         tds_parse_conf_section(TDS_STR_SPN, tds_dstr_cstr(&value), login);
     519         160 :                 } else if (CHK_PARAM(Trusted_Connection)) {
     520           0 :                         trusted = tds_config_boolean(option, tds_dstr_cstr(&value), login);
     521           0 :                         tdsdump_log(TDS_DBG_INFO1, "trusted %s -> %d\n", tds_dstr_cstr(&value), trusted);
     522             :                         num_param = -1;
     523             :                         /* TODO odbc_param_Address field */
     524         160 :                 } else if (CHK_PARAM(MARS_Connection)) {
     525           0 :                         if (tds_config_boolean(option, tds_dstr_cstr(&value), login))
     526           0 :                                 login->mars = 1;
     527         160 :                 } else if (CHK_PARAM(AttachDbFilename)) {
     528           0 :                         dest_s = &login->db_filename;
     529         160 :                 } else if (CHK_PARAM(ApplicationIntent)) {
     530           0 :                         const char *readonly_intent =
     531           0 :                                 odbc_appintent2readonly(tds_dstr_cstr(&value));
     532           0 :                         tds_parse_conf_section(TDS_STR_READONLY_INTENT, readonly_intent, login);
     533           0 :                         tdsdump_log(TDS_DBG_INFO1, "Application Intent %s\n", readonly_intent);
     534         160 :                 } else if (CHK_PARAM(Timeout)) {
     535           0 :                         tds_parse_conf_section(TDS_STR_TIMEOUT, tds_dstr_cstr(&value), login);
     536         160 :                 } else if (CHK_PARAM(ConnectionTimeout)) {
     537           0 :                         tds_parse_conf_section(TDS_STR_CONNTIMEOUT, tds_dstr_cstr(&value), login);
     538         160 :                 } else if (CHK_PARAM(HostNameInCertificate)) {
     539           0 :                         dest_s = &login->certificate_host_name;
     540             :                 }
     541             : 
     542        1400 :                 if (num_param >= 0 && parsed_params) {
     543        1270 :                         parsed_params[num_param].p = p;
     544        1270 :                         parsed_params[num_param].len = end - p;
     545             :                 }
     546             : 
     547             :                 /* copy to destination */
     548        1400 :                 if (dest_s)
     549             :                         odbc_dstr_swap(dest_s, &value);
     550             : 
     551        1400 :                 p = end;
     552             :                 /* handle "" ";.." cases */
     553        1400 :                 if (p >= connect_string_end)
     554             :                         break;
     555        1372 :                 ++p;
     556             :         }
     557             : 
     558         228 :         if (trusted) {
     559           0 :                 if (parsed_params) {
     560           0 :                         parsed_params[ODBC_PARAM_Trusted_Connection].p = "Yes";
     561           0 :                         parsed_params[ODBC_PARAM_Trusted_Connection].len = 3;
     562           0 :                         parsed_params[ODBC_PARAM_UID].p = NULL;
     563           0 :                         parsed_params[ODBC_PARAM_PWD].p = NULL;
     564             :                 }
     565           0 :                 tds_dstr_empty(&login->user_name);
     566           0 :                 tds_dstr_empty(&login->password);
     567             :         }
     568             : 
     569         228 :         tds_dstr_free(&value);
     570         228 :         return true;
     571             : 
     572          20 : Cleanup:
     573          20 :         tds_dstr_free(&value);
     574          20 :         return false;
     575             : }
     576             : 
     577             : #ifdef _WIN32
     578             : int
     579             : odbc_build_connect_string(TDS_ERRS *errs, TDS_PARSED_PARAM *params, char **out)
     580             : {
     581             :         unsigned n;
     582             :         size_t len = 1;
     583             :         char *p;
     584             : 
     585             :         /* compute string size */
     586             :         for (n = 0; n < ODBC_PARAM_SIZE; ++n) {
     587             :                 if (params[n].p)
     588             :                         len += strlen(odbc_param_names[n]) + params[n].len + 2;
     589             :         }
     590             : 
     591             :         /* allocate */
     592             :         p = tds_new(char, len);
     593             :         if (!p) {
     594             :                 odbc_errs_add(errs, "HY001", NULL);
     595             :                 return 0;
     596             :         }
     597             :         *out = p;
     598             : 
     599             :         /* build it */
     600             :         for (n = 0; n < ODBC_PARAM_SIZE; ++n) {
     601             :                 if (params[n].p)
     602             :                         p += sprintf(p, "%s=%.*s;", odbc_param_names[n], (int) params[n].len, params[n].p);
     603             :         }
     604             :         *p = 0;
     605             :         return 1;
     606             : }
     607             : #endif
     608             : 
     609             : #if !HAVE_SQLGETPRIVATEPROFILESTRING
     610             : 
     611             : #if defined(_WIN32) && !defined(TDS_NO_DM)
     612             : #  error There is something wrong  in configuration...
     613             : #endif
     614             : 
     615             : typedef struct
     616             : {
     617             :         LPCSTR entry;
     618             :         LPSTR buffer;
     619             :         int buffer_len;
     620             :         int ret_val;
     621             :         int found;
     622             : }
     623             : ProfileParam;
     624             : 
     625             : static bool
     626       90108 : tdoParseProfile(const char *option, const char *value, void *param)
     627             : {
     628       90108 :         ProfileParam *p = (ProfileParam *) param;
     629             : 
     630       90108 :         if (strcasecmp(p->entry, option) == 0) {
     631        2292 :                 strlcpy(p->buffer, value, p->buffer_len);
     632             : 
     633        2292 :                 p->ret_val = (int) strlen(p->buffer);
     634        2292 :                 p->found = 1;
     635             :         }
     636       90108 :         return true;
     637             : }
     638             : 
     639             : #ifndef _WIN32
     640             : static
     641             : #endif
     642             : int
     643       30036 : SQLGetPrivateProfileString(LPCSTR pszSection, LPCSTR pszEntry, LPCSTR pszDefault, LPSTR pRetBuffer, int nRetBuffer,
     644             :                            LPCSTR pszFileName)
     645             : {
     646             :         FILE *hFile;
     647             :         ProfileParam param;
     648             : 
     649       30036 :         tdsdump_log(TDS_DBG_FUNC, "SQLGetPrivateProfileString(%p, %p, %p, %p, %d, %p)\n", 
     650             :                         pszSection, pszEntry, pszDefault, pRetBuffer, nRetBuffer, pszFileName);
     651             : 
     652       30036 :         if (!pszSection) {
     653             :                 /* spec says return list of all section names - but we will just return nothing */
     654           0 :                 tdsdump_log(TDS_DBG_WARN, "WARNING: Functionality for NULL pszSection not implemented.\n");
     655             :                 return 0;
     656             :         }
     657             : 
     658       30036 :         if (!pszEntry) {
     659             :                 /* spec says return list of all key names in section - but we will just return nothing */
     660           0 :                 tdsdump_log(TDS_DBG_WARN, "WARNING: Functionality for NULL pszEntry not implemented.\n");
     661             :                 return 0;
     662             :         }
     663             : 
     664       30036 :         if (nRetBuffer < 1)
     665           0 :                 tdsdump_log(TDS_DBG_WARN, "WARNING: No space to return a value because nRetBuffer < 1.\n");
     666             : 
     667       30036 :         if (pszFileName && *pszFileName == '/')
     668           0 :                 hFile = fopen(pszFileName, "r");
     669             :         else
     670       30036 :                 hFile = tdoGetIniFileName();
     671             : 
     672       30036 :         if (hFile == NULL) {
     673           0 :                 tdsdump_log(TDS_DBG_ERROR, "ERROR: Could not open configuration file\n");
     674             :                 return 0;
     675             :         }
     676             : 
     677       30036 :         param.entry = pszEntry;
     678       30036 :         param.buffer = pRetBuffer;
     679       30036 :         param.buffer_len = nRetBuffer;
     680       30036 :         param.ret_val = 0;
     681       30036 :         param.found = 0;
     682             : 
     683       30036 :         pRetBuffer[0] = 0;
     684       30036 :         tds_read_conf_section(hFile, pszSection, tdoParseProfile, &param);
     685             : 
     686       30036 :         if (pszDefault && !param.found) {
     687       27744 :                 strlcpy(pRetBuffer, pszDefault, nRetBuffer);
     688             : 
     689       27744 :                 param.ret_val = (int) strlen(pRetBuffer);
     690             :         }
     691             : 
     692       30036 :         fclose(hFile);
     693       30036 :         return param.ret_val;
     694             : }
     695             : 
     696             : static FILE *
     697       30036 : tdoGetIniFileName(void)
     698             : {
     699       30036 :         FILE *ret = NULL;
     700             :         char *p;
     701             :         char *fn;
     702             : 
     703             :         /*
     704             :          * First, try the ODBCINI environment variable
     705             :          */
     706       30036 :         if ((p = getenv("ODBCINI")) != NULL)
     707       30036 :                 ret = fopen(p, "r");
     708             : 
     709             :         /*
     710             :          * Second, try the HOME environment variable
     711             :          */
     712       30036 :         if (!ret && (p = tds_get_homedir()) != NULL) {
     713           0 :                 fn = NULL;
     714           0 :                 if (asprintf(&fn, "%s/.odbc.ini", p) > 0) {
     715           0 :                         ret = fopen(fn, "r");
     716           0 :                         free(fn);
     717             :                 }
     718           0 :                 free(p);
     719             :         }
     720             : 
     721             :         /*
     722             :          * As a last resort, try SYS_ODBC_INI
     723             :          */
     724       30036 :         if (!ret)
     725           0 :                 ret = fopen(SYS_ODBC_INI, "r");
     726             : 
     727       30036 :         return ret;
     728             : }
     729             : 
     730             : #endif /* !HAVE_SQLGETPRIVATEPROFILESTRING */

Generated by: LCOV version 1.13