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, ¶m);
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 */
|