LCOV - code coverage report
Current view: top level - src/odbc - connectparams.c (source / functions) Hit Total Coverage
Test: FreeTDS coverage Lines: 195 301 64.8 %
Date: 2025-02-21 09:36:06 Functions: 8 8 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-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         100 : parse_server(TDS_ERRS *errs, char *server, TDSLOGIN * login)
     112             : {
     113         100 :         char *p = (char *) strchr(server, '\\');
     114             : 
     115         100 :         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         100 :                 p = (char *) strchr(server, ',');
     123         120 :                 if (p && atoi(p+1) > 0) {
     124          40 :                         login->port = atoi(p+1);
     125          20 :                         *p = 0;
     126             :                 }
     127             :         }
     128             : 
     129         100 :         if (TDS_SUCCEED(tds_lookup_host_set(server, &login->ip_addrs)))
     130         100 :                 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       25510 :         buf[0] = '\0';
     142       25510 :         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             : /** 
     169             :  * Read connection information from given DSN
     170             :  * @param DSN           DSN name
     171             :  * @param login    where to store connection info
     172             :  * @return true if success false otherwhise
     173             :  */
     174             : bool
     175        1110 : odbc_get_dsn_info(TDS_ERRS *errs, const char *DSN, TDSLOGIN * login)
     176             : {
     177             :         char tmp[FILENAME_MAX];
     178        1110 :         bool freetds_conf_less = true;
     179             : 
     180             :         /* use old servername */
     181        1110 :         if (myGetPrivateProfileString(DSN, odbc_param_Servername, tmp) > 0) {
     182        1110 :                 freetds_conf_less = false;
     183        1110 :                 if (!tds_dstr_copy(&login->server_name, tmp)) {
     184           0 :                         odbc_errs_add(errs, "HY001", NULL);
     185           0 :                         return false;
     186             :                 }
     187        1110 :                 tds_read_conf_file(login, tmp);
     188        1110 :                 if (myGetPrivateProfileString(DSN, odbc_param_Server, tmp) > 0) {
     189           0 :                         odbc_errs_add(errs, "HY000", "You cannot specify both SERVERNAME and SERVER");
     190           0 :                         return false;
     191             :                 }
     192        1110 :                 if (myGetPrivateProfileString(DSN, odbc_param_Address, tmp) > 0) {
     193           0 :                         odbc_errs_add(errs, "HY000", "You cannot specify both SERVERNAME and ADDRESS");
     194           0 :                         return false;
     195             :                 }
     196             :         }
     197             : 
     198             :         /* search for server (compatible with ms one) */
     199             :         if (freetds_conf_less) {
     200           0 :                 bool address_specified = false;
     201             : 
     202           0 :                 if (myGetPrivateProfileString(DSN, odbc_param_Address, tmp) > 0) {
     203           0 :                         address_specified = true;
     204             :                         /* TODO parse like MS */
     205             : 
     206           0 :                         if (TDS_FAILED(tds_lookup_host_set(tmp, &login->ip_addrs))) {
     207           0 :                                 odbc_errs_add(errs, "HY000", "Error parsing ADDRESS attribute");
     208           0 :                                 return false;
     209             :                         }
     210             :                 }
     211           0 :                 if (myGetPrivateProfileString(DSN, odbc_param_Server, tmp) > 0) {
     212           0 :                         if (!tds_dstr_copy(&login->server_name, tmp)) {
     213           0 :                                 odbc_errs_add(errs, "HY001", NULL);
     214           0 :                                 return false;
     215             :                         }
     216           0 :                         if (!address_specified) {
     217           0 :                                 if (!parse_server(errs, tmp, login))
     218             :                                         return false;
     219             :                         }
     220             :                 }
     221             :         }
     222             : 
     223        1110 :         if (myGetPrivateProfileString(DSN, odbc_param_Port, tmp) > 0)
     224           0 :                 tds_parse_conf_section(TDS_STR_PORT, tmp, login);
     225             : 
     226        1110 :         if (myGetPrivateProfileString(DSN, odbc_param_TDS_Version, tmp) > 0)
     227           0 :                 tds_parse_conf_section(TDS_STR_VERSION, tmp, login);
     228             : 
     229        1110 :         if (myGetPrivateProfileString(DSN, odbc_param_Language, tmp) > 0)
     230           0 :                 tds_parse_conf_section(TDS_STR_LANGUAGE, tmp, login);
     231             : 
     232        2220 :         if (tds_dstr_isempty(&login->database)
     233        1090 :             && myGetPrivateProfileString(DSN, odbc_param_Database, tmp) > 0)
     234        1090 :                 if (!tds_dstr_copy(&login->database, tmp)) {
     235           0 :                         odbc_errs_add(errs, "HY001", NULL);
     236           0 :                         return false;
     237             :                 }
     238             : 
     239        1110 :         if (myGetPrivateProfileString(DSN, odbc_param_TextSize, tmp) > 0)
     240           0 :                 tds_parse_conf_section(TDS_STR_TEXTSZ, tmp, login);
     241             : 
     242        1110 :         if (myGetPrivateProfileString(DSN, odbc_param_PacketSize, tmp) > 0)
     243           0 :                 tds_parse_conf_section(TDS_STR_BLKSZ, tmp, login);
     244             : 
     245        1110 :         if (myGetPrivateProfileString(DSN, odbc_param_ClientCharset, tmp) > 0)
     246           0 :                 tds_parse_conf_section(TDS_STR_CLCHARSET, tmp, login);
     247             : 
     248        1110 :         if (myGetPrivateProfileString(DSN, odbc_param_DumpFile, tmp) > 0)
     249           0 :                 tds_parse_conf_section(TDS_STR_DUMPFILE, tmp, login);
     250             : 
     251        1110 :         if (myGetPrivateProfileString(DSN, odbc_param_DumpFileAppend, tmp) > 0)
     252           0 :                 tds_parse_conf_section(TDS_STR_APPENDMODE, tmp, login);
     253             : 
     254        1110 :         if (myGetPrivateProfileString(DSN, odbc_param_DebugFlags, tmp) > 0)
     255           0 :                 tds_parse_conf_section(TDS_STR_DEBUGFLAGS, tmp, login);
     256             : 
     257        1110 :         if (myGetPrivateProfileString(DSN, odbc_param_Encryption, tmp) > 0)
     258           0 :                 tds_parse_conf_section(TDS_STR_ENCRYPTION, tmp, login);
     259             : 
     260        1110 :         if (myGetPrivateProfileString(DSN, odbc_param_Encrypt, tmp) > 0)
     261           0 :                 tds_parse_conf_section(TDS_STR_ENCRYPTION, odbc_encrypt2encryption(tmp), login);
     262             : 
     263        1110 :         if (myGetPrivateProfileString(DSN, odbc_param_UseNTLMv2, tmp) > 0)
     264           0 :                 tds_parse_conf_section(TDS_STR_USENTLMV2, tmp, login);
     265             : 
     266        1110 :         if (myGetPrivateProfileString(DSN, odbc_param_REALM, tmp) > 0)
     267           0 :                 tds_parse_conf_section(TDS_STR_REALM, tmp, login);
     268             : 
     269        1110 :         if (myGetPrivateProfileString(DSN, odbc_param_ServerSPN, tmp) > 0)
     270           0 :                 tds_parse_conf_section(TDS_STR_SPN, tmp, login);
     271             : 
     272        1110 :         if (myGetPrivateProfileString(DSN, odbc_param_Trusted_Connection, tmp) > 0
     273           0 :             && tds_config_boolean(odbc_param_Trusted_Connection, tmp, login)) {
     274           0 :                 tds_dstr_empty(&login->user_name);
     275           0 :                 tds_dstr_empty(&login->password);
     276             :         }
     277             : 
     278        1110 :         if (myGetPrivateProfileString(DSN, odbc_param_MARS_Connection, tmp) > 0
     279           0 :             && tds_config_boolean(odbc_param_MARS_Connection, tmp, login)) {
     280           0 :                 login->mars = 1;
     281             :         }
     282             : 
     283        1110 :         if (myGetPrivateProfileString(DSN, odbc_param_AttachDbFilename, tmp) > 0)
     284           0 :                 tds_parse_conf_section(TDS_STR_DBFILENAME, tmp, login);
     285             : 
     286        1110 :         if (myGetPrivateProfileString(DSN, odbc_param_Timeout, tmp) > 0)
     287           0 :                 tds_parse_conf_section(TDS_STR_TIMEOUT, tmp, login);
     288             : 
     289        1110 :         if (myGetPrivateProfileString(DSN, odbc_param_HostNameInCertificate, tmp) > 0
     290           0 :             && (tmp[0] && strcmp(tmp, "null") != 0)) {
     291           0 :                 if (!tds_dstr_copy(&login->certificate_host_name, tmp)) {
     292           0 :                         odbc_errs_add(errs, "HY001", NULL);
     293           0 :                         return false;
     294             :                 }
     295             :         }
     296             : 
     297             :         return true;
     298             : }
     299             : 
     300             : /**
     301             :  * Swap two DSTR
     302             :  */
     303             : static void
     304             : odbc_dstr_swap(DSTR *a, DSTR *b)
     305             : {
     306         772 :         DSTR tmp = *a;
     307         772 :         *a = *b;
     308         772 :         *b = tmp;
     309             : }
     310             : 
     311             : static const char *
     312        1368 : parse_value(TDS_ERRS *errs, const char *p, const char *connect_string_end, DSTR *value)
     313             : {
     314             :         const char *end;
     315             :         char *dst;
     316             : 
     317             :         /* easy case, just ';' terminated */
     318        1368 :         if (p == connect_string_end || *p != '{') {
     319        1068 :                 end = (const char *) memchr(p, ';', connect_string_end - p);
     320        1068 :                 if (!end)
     321           8 :                         end = connect_string_end;
     322        1068 :                 if (!tds_dstr_copyn(value, p, end - p)) {
     323           0 :                         odbc_errs_add(errs, "HY001", NULL);
     324           0 :                         return NULL;
     325             :                 }
     326             :                 return end;
     327             :         }
     328             : 
     329         300 :         ++p;
     330             :         /* search "};" */
     331         300 :         end = p;
     332             :         for (;;) {
     333             :                 /* search next '}' */
     334         360 :                 end = (const char *) memchr(end, '}', connect_string_end - end);
     335         330 :                 if (end == NULL) {
     336          10 :                         odbc_errs_add(errs, "HY000", "Syntax error in connection string");
     337          10 :                         return NULL;
     338             :                 }
     339         320 :                 end++;
     340             : 
     341             :                 /* termination ? */
     342         320 :                 if (end == connect_string_end || end[0] == ';') {
     343         290 :                         end--;
     344             :                         break;
     345             :                 }
     346             : 
     347             :                 /* wrong syntax ? */
     348          30 :                 if (end[0] != '}') {
     349           0 :                         odbc_errs_add(errs, "HY000", "Syntax error in connection string");
     350           0 :                         return NULL;
     351             :                 }
     352          30 :                 end++;
     353             :         }
     354         290 :         if (!tds_dstr_alloc(value, end - p)) {
     355           0 :                 odbc_errs_add(errs, "HY001", NULL);
     356           0 :                 return NULL;
     357             :         }
     358         580 :         dst = tds_dstr_buf(value);
     359        2980 :         for (; p < end; ++p) {
     360        2690 :                 char ch = *p;
     361        2690 :                 *dst++ = ch;
     362        2690 :                 if (ch == '}')
     363          30 :                         ++p;
     364             :         }
     365         580 :         tds_dstr_setlen(value, dst - tds_dstr_buf(value));
     366             : 
     367         290 :         return end + 1;
     368             : }
     369             : 
     370             : /** 
     371             :  * Parse connection string and fill login according
     372             :  * @param connect_string     connect string
     373             :  * @param connect_string_end connect string end (pointer to char past last)
     374             :  * @param login         where to store connection info
     375             :  * @return true if success false otherwise
     376             :  */
     377             : bool
     378         208 : odbc_parse_connect_string(TDS_ERRS *errs, const char *connect_string, const char *connect_string_end, TDSLOGIN * login,
     379             :                           TDS_PARSED_PARAM *parsed_params)
     380             : {
     381             :         const char *p, *end;
     382         208 :         DSTR *dest_s, value = DSTR_INITIALIZER;
     383             :         enum { CFG_DSN = 1, CFG_SERVERNAME = 2 };
     384         208 :         unsigned int cfgs = 0;  /* flags for indicate second parse of string */
     385             :         char option[24];
     386         208 :         int trusted = 0;
     387             : 
     388         208 :         if (parsed_params)
     389         208 :                 memset(parsed_params, 0, sizeof(*parsed_params)*ODBC_PARAM_SIZE);
     390             : 
     391        1548 :         for (p = connect_string; p < connect_string_end && *p;) {
     392             :                 int num_param = -1;
     393             : 
     394             :                 dest_s = NULL;
     395             : 
     396             :                 /* handle empty options */
     397        1368 :                 while (p < connect_string_end && *p == ';')
     398           0 :                         ++p;
     399             : 
     400             :                 /* parse option */
     401        1368 :                 end = (const char *) memchr(p, '=', connect_string_end - p);
     402        1368 :                 if (!end)
     403             :                         break;
     404             : 
     405             :                 /* account for spaces between ;'s. */
     406        1368 :                 while (p < end && *p == ' ')
     407           0 :                         ++p;
     408             : 
     409        1368 :                 if ((end - p) >= (int) sizeof(option))
     410           0 :                         option[0] = 0;
     411             :                 else {
     412        1368 :                         memcpy(option, p, end - p);
     413        1368 :                         option[end - p] = 0;
     414             :                 }
     415             : 
     416             :                 /* parse value */
     417        1368 :                 p = end + 1;
     418        1368 :                 end = parse_value(errs, p, connect_string_end, &value);
     419        1368 :                 if (!end)
     420             :                         goto Cleanup;
     421             : 
     422             : #define CHK_PARAM(p) (strcasecmp(option, odbc_param_##p) == 0 && (num_param=ODBC_PARAM_##p) >= 0)
     423        1358 :                 if (CHK_PARAM(Server)) {
     424         100 :                         dest_s = &login->server_name;
     425         200 :                         if (!parse_server(errs, tds_dstr_buf(&value), login))
     426             :                                 goto Cleanup;
     427        1258 :                 } else if (CHK_PARAM(Servername)) {
     428          40 :                         if ((cfgs & CFG_DSN) != 0) {
     429           0 :                                 odbc_errs_add(errs, "HY000", "Only one between SERVERNAME and DSN can be specified");
     430           0 :                                 goto Cleanup;
     431             :                         }
     432          40 :                         if (!cfgs) {
     433          40 :                                 odbc_dstr_swap(&login->server_name, &value);
     434          40 :                                 tds_read_conf_file(login, tds_dstr_cstr(&login->server_name));
     435          20 :                                 cfgs = CFG_SERVERNAME;
     436          20 :                                 p = connect_string;
     437          20 :                                 continue;
     438             :                         }
     439        1218 :                 } else if (CHK_PARAM(DSN)) {
     440         216 :                         if ((cfgs & CFG_SERVERNAME) != 0) {
     441           0 :                                 odbc_errs_add(errs, "HY000", "Only one between SERVERNAME and DSN can be specified");
     442           0 :                                 goto Cleanup;
     443             :                         }
     444         216 :                         if (!cfgs) {
     445         216 :                                 if (!odbc_get_dsn_info(errs, tds_dstr_cstr(&value), login))
     446             :                                         goto Cleanup;
     447         108 :                                 cfgs = CFG_DSN;
     448         108 :                                 p = connect_string;
     449         108 :                                 continue;
     450             :                         }
     451        1002 :                 } else if (CHK_PARAM(Database)) {
     452         208 :                         dest_s = &login->database;
     453         794 :                 } else if (CHK_PARAM(UID)) {
     454         218 :                         dest_s = &login->user_name;
     455         576 :                 } else if (CHK_PARAM(PWD)) {
     456         218 :                         dest_s = &login->password;
     457         358 :                 } else if (CHK_PARAM(APP)) {
     458           8 :                         dest_s = &login->app_name;
     459         350 :                 } else if (CHK_PARAM(WSID)) {
     460           0 :                         dest_s = &login->client_host_name;
     461         350 :                 } else if (CHK_PARAM(Language)) {
     462           0 :                         tds_parse_conf_section(TDS_STR_LANGUAGE, tds_dstr_cstr(&value), login);
     463         350 :                 } else if (CHK_PARAM(Port)) {
     464         160 :                         tds_parse_conf_section(TDS_STR_PORT, tds_dstr_cstr(&value), login);
     465         270 :                 } else if (CHK_PARAM(TDS_Version)) {
     466          60 :                         tds_parse_conf_section(TDS_STR_VERSION, tds_dstr_cstr(&value), login);
     467         240 :                 } else if (CHK_PARAM(TextSize)) {
     468           0 :                         tds_parse_conf_section(TDS_STR_TEXTSZ, tds_dstr_cstr(&value), login);
     469         240 :                 } else if (CHK_PARAM(PacketSize)) {
     470           0 :                         tds_parse_conf_section(TDS_STR_BLKSZ, tds_dstr_cstr(&value), login);
     471         240 :                 } else if (CHK_PARAM(ClientCharset)
     472         140 :                            ||  strcasecmp(option, "client_charset") == 0) {
     473         100 :                         num_param = ODBC_PARAM_ClientCharset;
     474         200 :                         tds_parse_conf_section(TDS_STR_CLCHARSET, tds_dstr_cstr(&value), login);
     475         140 :                 } else if (CHK_PARAM(DumpFile)) {
     476           0 :                         tds_parse_conf_section(TDS_STR_DUMPFILE, tds_dstr_cstr(&value), login);
     477         140 :                 } else if (CHK_PARAM(DumpFileAppend)) {
     478           0 :                         tds_parse_conf_section(TDS_STR_APPENDMODE, tds_dstr_cstr(&value), login);
     479         140 :                 } else if (CHK_PARAM(DebugFlags)) {
     480           0 :                         tds_parse_conf_section(TDS_STR_DEBUGFLAGS, tds_dstr_cstr(&value), login);
     481         140 :                 } else if (CHK_PARAM(Encryption)) {
     482           0 :                         tds_parse_conf_section(TDS_STR_ENCRYPTION, tds_dstr_cstr(&value), login);
     483         140 :                 } else if (CHK_PARAM(Encrypt)) {
     484          40 :                         tds_parse_conf_section(TDS_STR_ENCRYPTION, odbc_encrypt2encryption(tds_dstr_cstr(&value)), login);
     485         120 :                 } else if (CHK_PARAM(UseNTLMv2)) {
     486           0 :                         tds_parse_conf_section(TDS_STR_USENTLMV2, tds_dstr_cstr(&value), login);
     487         120 :                 } else if (CHK_PARAM(REALM)) {
     488           0 :                         tds_parse_conf_section(TDS_STR_REALM, tds_dstr_cstr(&value), login);
     489         120 :                 } else if (CHK_PARAM(ServerSPN)) {
     490           0 :                         tds_parse_conf_section(TDS_STR_SPN, tds_dstr_cstr(&value), login);
     491         120 :                 } else if (CHK_PARAM(Trusted_Connection)) {
     492           0 :                         trusted = tds_config_boolean(option, tds_dstr_cstr(&value), login);
     493           0 :                         tdsdump_log(TDS_DBG_INFO1, "trusted %s -> %d\n", tds_dstr_cstr(&value), trusted);
     494             :                         num_param = -1;
     495             :                         /* TODO odbc_param_Address field */
     496         120 :                 } else if (CHK_PARAM(MARS_Connection)) {
     497           0 :                         if (tds_config_boolean(option, tds_dstr_cstr(&value), login))
     498           0 :                                 login->mars = 1;
     499         120 :                 } else if (CHK_PARAM(AttachDbFilename)) {
     500           0 :                         dest_s = &login->db_filename;
     501         120 :                 } else if (CHK_PARAM(ApplicationIntent)) {
     502             :                         const char *readonly_intent;
     503             : 
     504           0 :                         if (strcasecmp(tds_dstr_cstr(&value), "ReadOnly") == 0) {
     505             :                                 readonly_intent = "yes";
     506           0 :                         } else if (strcasecmp(tds_dstr_cstr(&value), "ReadWrite") == 0) {
     507             :                                 readonly_intent = "no";
     508             :                         } else {
     509           0 :                                 tdsdump_log(TDS_DBG_ERROR, "Invalid ApplicationIntent %s\n", tds_dstr_cstr(&value));
     510             :                                 goto Cleanup;
     511             :                         }
     512             : 
     513           0 :                         tds_parse_conf_section(TDS_STR_READONLY_INTENT, readonly_intent, login);
     514           0 :                         tdsdump_log(TDS_DBG_INFO1, "Application Intent %s\n", readonly_intent);
     515         120 :                 } else if (CHK_PARAM(Timeout)) {
     516           0 :                         tds_parse_conf_section(TDS_STR_TIMEOUT, tds_dstr_cstr(&value), login);
     517         120 :                 } else if (CHK_PARAM(HostNameInCertificate)) {
     518           0 :                         dest_s = &login->certificate_host_name;
     519             :                 }
     520             : 
     521        1230 :                 if (num_param >= 0 && parsed_params) {
     522        1110 :                         parsed_params[num_param].p = p;
     523        1110 :                         parsed_params[num_param].len = end - p;
     524             :                 }
     525             : 
     526             :                 /* copy to destination */
     527        1230 :                 if (dest_s)
     528             :                         odbc_dstr_swap(dest_s, &value);
     529             : 
     530        1230 :                 p = end;
     531             :                 /* handle "" ";.." cases */
     532        1230 :                 if (p >= connect_string_end)
     533             :                         break;
     534        1212 :                 ++p;
     535             :         }
     536             : 
     537         198 :         if (trusted) {
     538           0 :                 if (parsed_params) {
     539           0 :                         parsed_params[ODBC_PARAM_Trusted_Connection].p = "Yes";
     540           0 :                         parsed_params[ODBC_PARAM_Trusted_Connection].len = 3;
     541           0 :                         parsed_params[ODBC_PARAM_UID].p = NULL;
     542           0 :                         parsed_params[ODBC_PARAM_PWD].p = NULL;
     543             :                 }
     544           0 :                 tds_dstr_empty(&login->user_name);
     545           0 :                 tds_dstr_empty(&login->password);
     546             :         }
     547             : 
     548         198 :         tds_dstr_free(&value);
     549         198 :         return true;
     550             : 
     551          10 : Cleanup:
     552          10 :         tds_dstr_free(&value);
     553          10 :         return false;
     554             : }
     555             : 
     556             : #ifdef _WIN32
     557             : int
     558             : odbc_build_connect_string(TDS_ERRS *errs, TDS_PARSED_PARAM *params, char **out)
     559             : {
     560             :         unsigned n;
     561             :         size_t len = 1;
     562             :         char *p;
     563             : 
     564             :         /* compute string size */
     565             :         for (n = 0; n < ODBC_PARAM_SIZE; ++n) {
     566             :                 if (params[n].p)
     567             :                         len += strlen(odbc_param_names[n]) + params[n].len + 2;
     568             :         }
     569             : 
     570             :         /* allocate */
     571             :         p = tds_new(char, len);
     572             :         if (!p) {
     573             :                 odbc_errs_add(errs, "HY001", NULL);
     574             :                 return 0;
     575             :         }
     576             :         *out = p;
     577             : 
     578             :         /* build it */
     579             :         for (n = 0; n < ODBC_PARAM_SIZE; ++n) {
     580             :                 if (params[n].p)
     581             :                         p += sprintf(p, "%s=%.*s;", odbc_param_names[n], (int) params[n].len, params[n].p);
     582             :         }
     583             :         *p = 0;
     584             :         return 1;
     585             : }
     586             : #endif
     587             : 
     588             : #if !HAVE_SQLGETPRIVATEPROFILESTRING
     589             : 
     590             : #if defined(_WIN32) && !defined(TDS_NO_DM)
     591             : #  error There is something wrong  in configuration...
     592             : #endif
     593             : 
     594             : typedef struct
     595             : {
     596             :         LPCSTR entry;
     597             :         LPSTR buffer;
     598             :         int buffer_len;
     599             :         int ret_val;
     600             :         int found;
     601             : }
     602             : ProfileParam;
     603             : 
     604             : static bool
     605       76530 : tdoParseProfile(const char *option, const char *value, void *param)
     606             : {
     607       76530 :         ProfileParam *p = (ProfileParam *) param;
     608             : 
     609       76530 :         if (strcasecmp(p->entry, option) == 0) {
     610        2200 :                 strlcpy(p->buffer, value, p->buffer_len);
     611             : 
     612        2200 :                 p->ret_val = strlen(p->buffer);
     613        2200 :                 p->found = 1;
     614             :         }
     615       76530 :         return true;
     616             : }
     617             : 
     618             : #ifndef _WIN32
     619             : static
     620             : #endif
     621             : int
     622       25510 : SQLGetPrivateProfileString(LPCSTR pszSection, LPCSTR pszEntry, LPCSTR pszDefault, LPSTR pRetBuffer, int nRetBuffer,
     623             :                            LPCSTR pszFileName)
     624             : {
     625             :         FILE *hFile;
     626             :         ProfileParam param;
     627             : 
     628       25510 :         tdsdump_log(TDS_DBG_FUNC, "SQLGetPrivateProfileString(%p, %p, %p, %p, %d, %p)\n", 
     629             :                         pszSection, pszEntry, pszDefault, pRetBuffer, nRetBuffer, pszFileName);
     630             : 
     631       25510 :         if (!pszSection) {
     632             :                 /* spec says return list of all section names - but we will just return nothing */
     633           0 :                 tdsdump_log(TDS_DBG_WARN, "WARNING: Functionality for NULL pszSection not implemented.\n");
     634             :                 return 0;
     635             :         }
     636             : 
     637       25510 :         if (!pszEntry) {
     638             :                 /* spec says return list of all key names in section - but we will just return nothing */
     639           0 :                 tdsdump_log(TDS_DBG_WARN, "WARNING: Functionality for NULL pszEntry not implemented.\n");
     640             :                 return 0;
     641             :         }
     642             : 
     643       25510 :         if (nRetBuffer < 1)
     644           0 :                 tdsdump_log(TDS_DBG_WARN, "WARNING: No space to return a value because nRetBuffer < 1.\n");
     645             : 
     646       25510 :         if (pszFileName && *pszFileName == '/')
     647           0 :                 hFile = fopen(pszFileName, "r");
     648             :         else
     649       25510 :                 hFile = tdoGetIniFileName();
     650             : 
     651       25510 :         if (hFile == NULL) {
     652           0 :                 tdsdump_log(TDS_DBG_ERROR, "ERROR: Could not open configuration file\n");
     653             :                 return 0;
     654             :         }
     655             : 
     656       25510 :         param.entry = pszEntry;
     657       25510 :         param.buffer = pRetBuffer;
     658       25510 :         param.buffer_len = nRetBuffer;
     659       25510 :         param.ret_val = 0;
     660       25510 :         param.found = 0;
     661             : 
     662       25510 :         pRetBuffer[0] = 0;
     663       25510 :         tds_read_conf_section(hFile, pszSection, tdoParseProfile, &param);
     664             : 
     665       25510 :         if (pszDefault && !param.found) {
     666       23310 :                 strlcpy(pRetBuffer, pszDefault, nRetBuffer);
     667             : 
     668       23310 :                 param.ret_val = strlen(pRetBuffer);
     669             :         }
     670             : 
     671       25510 :         fclose(hFile);
     672       25510 :         return param.ret_val;
     673             : }
     674             : 
     675             : static FILE *
     676       25510 : tdoGetIniFileName(void)
     677             : {
     678       25510 :         FILE *ret = NULL;
     679             :         char *p;
     680             :         char *fn;
     681             : 
     682             :         /*
     683             :          * First, try the ODBCINI environment variable
     684             :          */
     685       25510 :         if ((p = getenv("ODBCINI")) != NULL)
     686       25510 :                 ret = fopen(p, "r");
     687             : 
     688             :         /*
     689             :          * Second, try the HOME environment variable
     690             :          */
     691       25510 :         if (!ret && (p = tds_get_homedir()) != NULL) {
     692           0 :                 fn = NULL;
     693           0 :                 if (asprintf(&fn, "%s/.odbc.ini", p) > 0) {
     694           0 :                         ret = fopen(fn, "r");
     695           0 :                         free(fn);
     696             :                 }
     697           0 :                 free(p);
     698             :         }
     699             : 
     700             :         /*
     701             :          * As a last resort, try SYS_ODBC_INI
     702             :          */
     703       25510 :         if (!ret)
     704           0 :                 ret = fopen(SYS_ODBC_INI, "r");
     705             : 
     706       25510 :         return ret;
     707             : }
     708             : 
     709             : #endif /* !HAVE_SQLGETPRIVATEPROFILESTRING */

Generated by: LCOV version 1.13