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