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