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 28840 : buf[0] = '\0';
142 28840 : 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 1110 : odbc_get_dsn_info(TDS_ERRS *errs, const char *DSN, TDSLOGIN * login)
187 : {
188 : char tmp[FILENAME_MAX];
189 1110 : bool freetds_conf_less = true;
190 :
191 : /* use old servername */
192 1110 : if (myGetPrivateProfileString(DSN, odbc_param_Servername, tmp) > 0) {
193 1110 : freetds_conf_less = false;
194 1110 : if (!tds_dstr_copy(&login->server_name, tmp)) {
195 0 : odbc_errs_add(errs, "HY001", NULL);
196 0 : return false;
197 : }
198 1110 : tds_read_conf_file(login, tmp);
199 1110 : 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 1110 : 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 1110 : if (myGetPrivateProfileString(DSN, odbc_param_Port, tmp) > 0)
235 0 : tds_parse_conf_section(TDS_STR_PORT, tmp, login);
236 :
237 1110 : if (myGetPrivateProfileString(DSN, odbc_param_TDS_Version, tmp) > 0)
238 0 : tds_parse_conf_section(TDS_STR_VERSION, tmp, login);
239 :
240 1110 : if (myGetPrivateProfileString(DSN, odbc_param_Language, tmp) > 0)
241 0 : tds_parse_conf_section(TDS_STR_LANGUAGE, tmp, login);
242 :
243 2220 : if (tds_dstr_isempty(&login->database)
244 1090 : && myGetPrivateProfileString(DSN, odbc_param_Database, tmp) > 0)
245 1090 : if (!tds_dstr_copy(&login->database, tmp)) {
246 0 : odbc_errs_add(errs, "HY001", NULL);
247 0 : return false;
248 : }
249 :
250 1110 : if (myGetPrivateProfileString(DSN, odbc_param_TextSize, tmp) > 0)
251 0 : tds_parse_conf_section(TDS_STR_TEXTSZ, tmp, login);
252 :
253 1110 : if (myGetPrivateProfileString(DSN, odbc_param_PacketSize, tmp) > 0)
254 0 : tds_parse_conf_section(TDS_STR_BLKSZ, tmp, login);
255 :
256 1110 : if (myGetPrivateProfileString(DSN, odbc_param_ClientCharset, tmp) > 0)
257 0 : tds_parse_conf_section(TDS_STR_CLCHARSET, tmp, login);
258 :
259 1110 : if (myGetPrivateProfileString(DSN, odbc_param_DumpFile, tmp) > 0)
260 0 : tds_parse_conf_section(TDS_STR_DUMPFILE, tmp, login);
261 :
262 1110 : if (myGetPrivateProfileString(DSN, odbc_param_DumpFileAppend, tmp) > 0)
263 0 : tds_parse_conf_section(TDS_STR_APPENDMODE, tmp, login);
264 :
265 1110 : if (myGetPrivateProfileString(DSN, odbc_param_DebugFlags, tmp) > 0)
266 0 : tds_parse_conf_section(TDS_STR_DEBUGFLAGS, tmp, login);
267 :
268 1110 : if (myGetPrivateProfileString(DSN, odbc_param_Encryption, tmp) > 0)
269 0 : tds_parse_conf_section(TDS_STR_ENCRYPTION, tmp, login);
270 :
271 1110 : if (myGetPrivateProfileString(DSN, odbc_param_Encrypt, tmp) > 0)
272 0 : tds_parse_conf_section(TDS_STR_ENCRYPTION, odbc_encrypt2encryption(tmp), login);
273 :
274 1110 : if (myGetPrivateProfileString(DSN, odbc_param_ServerCertificate, tmp) > 0)
275 0 : tds_parse_conf_section(TDS_STR_CAFILE, tmp, login);
276 :
277 1110 : if (myGetPrivateProfileString(DSN, odbc_param_ApplicationIntent, tmp) > 0)
278 0 : tds_parse_conf_section(TDS_STR_READONLY_INTENT, odbc_appintent2readonly(tmp), login);
279 :
280 1110 : if (myGetPrivateProfileString(DSN, odbc_param_UseNTLMv2, tmp) > 0)
281 0 : tds_parse_conf_section(TDS_STR_USENTLMV2, tmp, login);
282 :
283 1110 : if (myGetPrivateProfileString(DSN, odbc_param_REALM, tmp) > 0)
284 0 : tds_parse_conf_section(TDS_STR_REALM, tmp, login);
285 :
286 1110 : if (myGetPrivateProfileString(DSN, odbc_param_ServerSPN, tmp) > 0)
287 0 : tds_parse_conf_section(TDS_STR_SPN, tmp, login);
288 :
289 1110 : 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 1110 : 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 1110 : if (myGetPrivateProfileString(DSN, odbc_param_AttachDbFilename, tmp) > 0)
301 0 : tds_parse_conf_section(TDS_STR_DBFILENAME, tmp, login);
302 :
303 1110 : if (myGetPrivateProfileString(DSN, odbc_param_Timeout, tmp) > 0)
304 0 : tds_parse_conf_section(TDS_STR_TIMEOUT, tmp, login);
305 :
306 1110 : if (myGetPrivateProfileString(DSN, odbc_param_ConnectionTimeout, tmp) > 0)
307 0 : tds_parse_conf_section(TDS_STR_CONNTIMEOUT, tmp, login);
308 :
309 1110 : 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 772 : DSTR tmp = *a;
327 772 : *a = *b;
328 772 : *b = tmp;
329 : }
330 :
331 : static const char *
332 1368 : 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 1368 : if (p == connect_string_end || *p != '{') {
339 1068 : end = (const char *) memchr(p, ';', connect_string_end - p);
340 1068 : if (!end)
341 8 : end = connect_string_end;
342 1068 : 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 300 : ++p;
350 : /* search "};" */
351 300 : end = p;
352 : for (;;) {
353 : /* search next '}' */
354 360 : end = (const char *) memchr(end, '}', connect_string_end - end);
355 330 : if (end == NULL) {
356 10 : odbc_errs_add(errs, "HY000", "Syntax error in connection string");
357 10 : return NULL;
358 : }
359 320 : end++;
360 :
361 : /* termination ? */
362 320 : if (end == connect_string_end || end[0] == ';') {
363 290 : 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 290 : if (!tds_dstr_alloc(value, end - p)) {
375 0 : odbc_errs_add(errs, "HY001", NULL);
376 0 : return NULL;
377 : }
378 580 : dst = tds_dstr_buf(value);
379 2980 : for (; p < end; ++p) {
380 2690 : char ch = *p;
381 2690 : *dst++ = ch;
382 2690 : if (ch == '}')
383 30 : ++p;
384 : }
385 580 : tds_dstr_setlen(value, dst - tds_dstr_buf(value));
386 :
387 290 : 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 208 : odbc_parse_connect_string(TDS_ERRS *errs, const char *connect_string, const char *connect_string_end, TDSLOGIN * login,
399 : TDS_PARSED_PARAM *parsed_params)
400 : {
401 : const char *p, *end;
402 208 : DSTR *dest_s, value = DSTR_INITIALIZER;
403 : enum { CFG_DSN = 1, CFG_SERVERNAME = 2 };
404 208 : unsigned int cfgs = 0; /* flags for indicate second parse of string */
405 : char option[24];
406 208 : int trusted = 0;
407 :
408 208 : if (parsed_params)
409 208 : memset(parsed_params, 0, sizeof(*parsed_params)*ODBC_PARAM_SIZE);
410 :
411 1548 : 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 1368 : while (p < connect_string_end && *p == ';')
418 0 : ++p;
419 :
420 : /* parse option */
421 1368 : end = (const char *) memchr(p, '=', connect_string_end - p);
422 1368 : if (!end)
423 : break;
424 :
425 : /* account for spaces between ;'s. */
426 1368 : while (p < end && *p == ' ')
427 0 : ++p;
428 :
429 1368 : if ((end - p) >= (int) sizeof(option))
430 0 : option[0] = 0;
431 : else {
432 1368 : memcpy(option, p, end - p);
433 1368 : option[end - p] = 0;
434 : }
435 :
436 : /* parse value */
437 1368 : p = end + 1;
438 1368 : end = parse_value(errs, p, connect_string_end, &value);
439 1368 : if (!end)
440 : goto Cleanup;
441 :
442 : #define CHK_PARAM(p) (strcasecmp(option, odbc_param_##p) == 0 && (num_param=ODBC_PARAM_##p) >= 0)
443 1358 : if (CHK_PARAM(Server)) {
444 100 : dest_s = &login->server_name;
445 200 : if (!parse_server(errs, tds_dstr_buf(&value), login))
446 : goto Cleanup;
447 1258 : } 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 1218 : } else if (CHK_PARAM(DSN)) {
460 216 : 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 216 : if (!cfgs) {
465 216 : if (!odbc_get_dsn_info(errs, tds_dstr_cstr(&value), login))
466 : goto Cleanup;
467 108 : cfgs = CFG_DSN;
468 108 : p = connect_string;
469 108 : continue;
470 : }
471 1002 : } else if (CHK_PARAM(Database)) {
472 208 : dest_s = &login->database;
473 794 : } else if (CHK_PARAM(UID)) {
474 218 : dest_s = &login->user_name;
475 576 : } else if (CHK_PARAM(PWD)) {
476 218 : dest_s = &login->password;
477 358 : } else if (CHK_PARAM(APP)) {
478 8 : dest_s = &login->app_name;
479 350 : } else if (CHK_PARAM(WSID)) {
480 0 : dest_s = &login->client_host_name;
481 350 : } else if (CHK_PARAM(Language)) {
482 0 : tds_parse_conf_section(TDS_STR_LANGUAGE, tds_dstr_cstr(&value), login);
483 350 : } else if (CHK_PARAM(Port)) {
484 160 : tds_parse_conf_section(TDS_STR_PORT, tds_dstr_cstr(&value), login);
485 270 : } else if (CHK_PARAM(TDS_Version)) {
486 60 : tds_parse_conf_section(TDS_STR_VERSION, tds_dstr_cstr(&value), login);
487 240 : } else if (CHK_PARAM(TextSize)) {
488 0 : tds_parse_conf_section(TDS_STR_TEXTSZ, tds_dstr_cstr(&value), login);
489 240 : } else if (CHK_PARAM(PacketSize)) {
490 0 : tds_parse_conf_section(TDS_STR_BLKSZ, tds_dstr_cstr(&value), login);
491 240 : } else if (CHK_PARAM(ClientCharset)
492 140 : || strcasecmp(option, "client_charset") == 0) {
493 100 : num_param = ODBC_PARAM_ClientCharset;
494 200 : tds_parse_conf_section(TDS_STR_CLCHARSET, tds_dstr_cstr(&value), login);
495 140 : } else if (CHK_PARAM(DumpFile)) {
496 0 : tds_parse_conf_section(TDS_STR_DUMPFILE, tds_dstr_cstr(&value), login);
497 140 : } else if (CHK_PARAM(DumpFileAppend)) {
498 0 : tds_parse_conf_section(TDS_STR_APPENDMODE, tds_dstr_cstr(&value), login);
499 140 : } else if (CHK_PARAM(DebugFlags)) {
500 0 : tds_parse_conf_section(TDS_STR_DEBUGFLAGS, tds_dstr_cstr(&value), login);
501 140 : } else if (CHK_PARAM(Encryption)) {
502 0 : tds_parse_conf_section(TDS_STR_ENCRYPTION, tds_dstr_cstr(&value), login);
503 140 : } else if (CHK_PARAM(Encrypt)) {
504 40 : tds_parse_conf_section(TDS_STR_ENCRYPTION, odbc_encrypt2encryption(tds_dstr_cstr(&value)), login);
505 120 : } else if (CHK_PARAM(ServerCertificate)) {
506 0 : tds_parse_conf_section(TDS_STR_CAFILE, tds_dstr_cstr(&value), login);
507 120 : } else if (CHK_PARAM(UseNTLMv2)) {
508 0 : tds_parse_conf_section(TDS_STR_USENTLMV2, tds_dstr_cstr(&value), login);
509 120 : } else if (CHK_PARAM(REALM)) {
510 0 : tds_parse_conf_section(TDS_STR_REALM, tds_dstr_cstr(&value), login);
511 120 : } else if (CHK_PARAM(ServerSPN)) {
512 0 : tds_parse_conf_section(TDS_STR_SPN, tds_dstr_cstr(&value), login);
513 120 : } else if (CHK_PARAM(Trusted_Connection)) {
514 0 : trusted = tds_config_boolean(option, tds_dstr_cstr(&value), login);
515 0 : tdsdump_log(TDS_DBG_INFO1, "trusted %s -> %d\n", tds_dstr_cstr(&value), trusted);
516 : num_param = -1;
517 : /* TODO odbc_param_Address field */
518 120 : } else if (CHK_PARAM(MARS_Connection)) {
519 0 : if (tds_config_boolean(option, tds_dstr_cstr(&value), login))
520 0 : login->mars = 1;
521 120 : } else if (CHK_PARAM(AttachDbFilename)) {
522 0 : dest_s = &login->db_filename;
523 120 : } else if (CHK_PARAM(ApplicationIntent)) {
524 0 : const char *readonly_intent =
525 0 : odbc_appintent2readonly(tds_dstr_cstr(&value));
526 0 : tds_parse_conf_section(TDS_STR_READONLY_INTENT, readonly_intent, login);
527 0 : tdsdump_log(TDS_DBG_INFO1, "Application Intent %s\n", readonly_intent);
528 120 : } else if (CHK_PARAM(Timeout)) {
529 0 : tds_parse_conf_section(TDS_STR_TIMEOUT, tds_dstr_cstr(&value), login);
530 120 : } else if (CHK_PARAM(ConnectionTimeout)) {
531 0 : tds_parse_conf_section(TDS_STR_CONNTIMEOUT, tds_dstr_cstr(&value), login);
532 120 : } else if (CHK_PARAM(HostNameInCertificate)) {
533 0 : dest_s = &login->certificate_host_name;
534 : }
535 :
536 1230 : if (num_param >= 0 && parsed_params) {
537 1110 : parsed_params[num_param].p = p;
538 1110 : parsed_params[num_param].len = end - p;
539 : }
540 :
541 : /* copy to destination */
542 1230 : if (dest_s)
543 : odbc_dstr_swap(dest_s, &value);
544 :
545 1230 : p = end;
546 : /* handle "" ";.." cases */
547 1230 : if (p >= connect_string_end)
548 : break;
549 1212 : ++p;
550 : }
551 :
552 198 : if (trusted) {
553 0 : if (parsed_params) {
554 0 : parsed_params[ODBC_PARAM_Trusted_Connection].p = "Yes";
555 0 : parsed_params[ODBC_PARAM_Trusted_Connection].len = 3;
556 0 : parsed_params[ODBC_PARAM_UID].p = NULL;
557 0 : parsed_params[ODBC_PARAM_PWD].p = NULL;
558 : }
559 0 : tds_dstr_empty(&login->user_name);
560 0 : tds_dstr_empty(&login->password);
561 : }
562 :
563 198 : tds_dstr_free(&value);
564 198 : return true;
565 :
566 10 : Cleanup:
567 10 : tds_dstr_free(&value);
568 10 : return false;
569 : }
570 :
571 : #ifdef _WIN32
572 : int
573 : odbc_build_connect_string(TDS_ERRS *errs, TDS_PARSED_PARAM *params, char **out)
574 : {
575 : unsigned n;
576 : size_t len = 1;
577 : char *p;
578 :
579 : /* compute string size */
580 : for (n = 0; n < ODBC_PARAM_SIZE; ++n) {
581 : if (params[n].p)
582 : len += strlen(odbc_param_names[n]) + params[n].len + 2;
583 : }
584 :
585 : /* allocate */
586 : p = tds_new(char, len);
587 : if (!p) {
588 : odbc_errs_add(errs, "HY001", NULL);
589 : return 0;
590 : }
591 : *out = p;
592 :
593 : /* build it */
594 : for (n = 0; n < ODBC_PARAM_SIZE; ++n) {
595 : if (params[n].p)
596 : p += sprintf(p, "%s=%.*s;", odbc_param_names[n], (int) params[n].len, params[n].p);
597 : }
598 : *p = 0;
599 : return 1;
600 : }
601 : #endif
602 :
603 : #if !HAVE_SQLGETPRIVATEPROFILESTRING
604 :
605 : #if defined(_WIN32) && !defined(TDS_NO_DM)
606 : # error There is something wrong in configuration...
607 : #endif
608 :
609 : typedef struct
610 : {
611 : LPCSTR entry;
612 : LPSTR buffer;
613 : int buffer_len;
614 : int ret_val;
615 : int found;
616 : }
617 : ProfileParam;
618 :
619 : static bool
620 86520 : tdoParseProfile(const char *option, const char *value, void *param)
621 : {
622 86520 : ProfileParam *p = (ProfileParam *) param;
623 :
624 86520 : if (strcasecmp(p->entry, option) == 0) {
625 2200 : strlcpy(p->buffer, value, p->buffer_len);
626 :
627 2200 : p->ret_val = (int) strlen(p->buffer);
628 2200 : p->found = 1;
629 : }
630 86520 : return true;
631 : }
632 :
633 : #ifndef _WIN32
634 : static
635 : #endif
636 : int
637 28840 : SQLGetPrivateProfileString(LPCSTR pszSection, LPCSTR pszEntry, LPCSTR pszDefault, LPSTR pRetBuffer, int nRetBuffer,
638 : LPCSTR pszFileName)
639 : {
640 : FILE *hFile;
641 : ProfileParam param;
642 :
643 28840 : tdsdump_log(TDS_DBG_FUNC, "SQLGetPrivateProfileString(%p, %p, %p, %p, %d, %p)\n",
644 : pszSection, pszEntry, pszDefault, pRetBuffer, nRetBuffer, pszFileName);
645 :
646 28840 : if (!pszSection) {
647 : /* spec says return list of all section names - but we will just return nothing */
648 0 : tdsdump_log(TDS_DBG_WARN, "WARNING: Functionality for NULL pszSection not implemented.\n");
649 : return 0;
650 : }
651 :
652 28840 : if (!pszEntry) {
653 : /* spec says return list of all key names in section - but we will just return nothing */
654 0 : tdsdump_log(TDS_DBG_WARN, "WARNING: Functionality for NULL pszEntry not implemented.\n");
655 : return 0;
656 : }
657 :
658 28840 : if (nRetBuffer < 1)
659 0 : tdsdump_log(TDS_DBG_WARN, "WARNING: No space to return a value because nRetBuffer < 1.\n");
660 :
661 28840 : if (pszFileName && *pszFileName == '/')
662 0 : hFile = fopen(pszFileName, "r");
663 : else
664 28840 : hFile = tdoGetIniFileName();
665 :
666 28840 : if (hFile == NULL) {
667 0 : tdsdump_log(TDS_DBG_ERROR, "ERROR: Could not open configuration file\n");
668 : return 0;
669 : }
670 :
671 28840 : param.entry = pszEntry;
672 28840 : param.buffer = pRetBuffer;
673 28840 : param.buffer_len = nRetBuffer;
674 28840 : param.ret_val = 0;
675 28840 : param.found = 0;
676 :
677 28840 : pRetBuffer[0] = 0;
678 28840 : tds_read_conf_section(hFile, pszSection, tdoParseProfile, ¶m);
679 :
680 28840 : if (pszDefault && !param.found) {
681 26640 : strlcpy(pRetBuffer, pszDefault, nRetBuffer);
682 :
683 26640 : param.ret_val = (int) strlen(pRetBuffer);
684 : }
685 :
686 28840 : fclose(hFile);
687 28840 : return param.ret_val;
688 : }
689 :
690 : static FILE *
691 28840 : tdoGetIniFileName(void)
692 : {
693 28840 : FILE *ret = NULL;
694 : char *p;
695 : char *fn;
696 :
697 : /*
698 : * First, try the ODBCINI environment variable
699 : */
700 28840 : if ((p = getenv("ODBCINI")) != NULL)
701 28840 : ret = fopen(p, "r");
702 :
703 : /*
704 : * Second, try the HOME environment variable
705 : */
706 28840 : if (!ret && (p = tds_get_homedir()) != NULL) {
707 0 : fn = NULL;
708 0 : if (asprintf(&fn, "%s/.odbc.ini", p) > 0) {
709 0 : ret = fopen(fn, "r");
710 0 : free(fn);
711 : }
712 0 : free(p);
713 : }
714 :
715 : /*
716 : * As a last resort, try SYS_ODBC_INI
717 : */
718 28840 : if (!ret)
719 0 : ret = fopen(SYS_ODBC_INI, "r");
720 :
721 28840 : return ret;
722 : }
723 :
724 : #endif /* !HAVE_SQLGETPRIVATEPROFILESTRING */
|