1 /*
2 * SQLConfigDriver.c
3 *
4 * $Id$
5 *
6 * Load the appropriate driver setup DLL and calls the ConfigDriver
7 * function.
8 *
9 * The iODBC driver manager.
10 *
11 * Copyright (C) 1996-2021 OpenLink Software <iodbc@openlinksw.com>
12 * All Rights Reserved.
13 *
14 * This software is released under the terms of either of the following
15 * licenses:
16 *
17 * - GNU Library General Public License (see LICENSE.LGPL)
18 * - The BSD License (see LICENSE.BSD).
19 *
20 * Note that the only valid version of the LGPL license as far as this
21 * project is concerned is the original GNU Library General Public License
22 * Version 2, dated June 1991.
23 *
24 * While not mandated by the BSD license, any patches you make to the
25 * iODBC source code may be contributed back into the iODBC project
26 * at your discretion. Contributions will benefit the Open Source and
27 * Data Access community as a whole. Submissions may be made at:
28 *
29 * http://www.iodbc.org
30 *
31 *
32 * GNU Library Generic Public License Version 2
33 * ============================================
34 * This library is free software; you can redistribute it and/or
35 * modify it under the terms of the GNU Library General Public
36 * License as published by the Free Software Foundation; only
37 * Version 2 of the License dated June 1991.
38 *
39 * This library is distributed in the hope that it will be useful,
40 * but WITHOUT ANY WARRANTY; without even the implied warranty of
41 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
42 * Library General Public License for more details.
43 *
44 * You should have received a copy of the GNU Library General Public
45 * License along with this library; if not, write to the Free
46 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
47 *
48 *
49 * The BSD License
50 * ===============
51 * Redistribution and use in source and binary forms, with or without
52 * modification, are permitted provided that the following conditions
53 * are met:
54 *
55 * 1. Redistributions of source code must retain the above copyright
56 * notice, this list of conditions and the following disclaimer.
57 * 2. Redistributions in binary form must reproduce the above copyright
58 * notice, this list of conditions and the following disclaimer in
59 * the documentation and/or other materials provided with the
60 * distribution.
61 * 3. Neither the name of OpenLink Software Inc. nor the names of its
62 * contributors may be used to endorse or promote products derived
63 * from this software without specific prior written permission.
64 *
65 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
66 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
67 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
68 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL OPENLINK OR
69 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
70 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
71 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
72 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
73 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
74 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
75 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
76 */
77
78
79
80 #include <iodbc.h>
81 #include <odbcinst.h>
82 #include "unicode.h"
83
84 #if defined (__APPLE__) && !defined (NO_FRAMEWORKS)
85 # include <Carbon/Carbon.h>
86 #endif
87
88 #include "dlf.h"
89 #include "inifile.h"
90 #include "misc.h"
91 #include "iodbc_error.h"
92
93 #ifndef WIN32
94 #include <unistd.h>
95
96 #if defined (__APPLE__) && !defined (NO_FRAMEWORKS)
97
98 #define CALL_CONFIG_DRIVER(path) \
99 if (path) \
100 { \
101 char *tmp_path = strdup (path); \
102 if (tmp_path) \
103 { \
104 char *ptr = strstr (tmp_path, "/Contents/MacOS/"); \
105 if (ptr) \
106 *ptr = 0; \
107 liburl = CFURLCreateFromFileSystemRepresentation (NULL, (UInt8 *) tmp_path, strlen (tmp_path), FALSE); \
108 CFArrayRef arr = CFBundleCopyExecutableArchitecturesForURL (liburl); \
109 if (arr) \
110 bundle_dll = CFBundleCreate (NULL, liburl); \
111 if (arr) \
112 CFRelease (arr); \
113 if (liburl) \
114 CFRelease (liburl); \
115 } \
116 MEM_FREE (tmp_path); \
117 CALL_CONFIG_DRIVER_BUNDLE (); \
118 }
119
120 #define CALL_CONFIG_DRIVERW(path) \
121 if (path) \
122 { \
123 char *tmp_path = strdup (path); \
124 if (tmp_path) \
125 { \
126 char *ptr = strstr (tmp_path, "/Contents/MacOS/"); \
127 if (ptr) \
128 *ptr = 0; \
129 liburl = CFURLCreateFromFileSystemRepresentation (NULL, (UInt8 *) tmp_path, strlen (tmp_path), FALSE); \
130 CFArrayRef arr = CFBundleCopyExecutableArchitecturesForURL (liburl); \
131 if (arr) \
132 bundle_dll = CFBundleCreate (NULL, liburl); \
133 if (arr) \
134 CFRelease (arr); \
135 if (liburl) \
136 CFRelease (liburl); \
137 } \
138 MEM_FREE (tmp_path); \
139 CALL_CONFIG_DRIVERW_BUNDLE (); \
140 }
141
142 #define CALL_CONFIG_DRIVER_BUNDLE() \
143 if (bundle_dll != NULL) \
144 { \
145 if ((pConfigDriver = (pConfigDriverFunc) CFBundleGetFunctionPointerForName (bundle_dll, CFSTR ("ConfigDriver"))) != NULL) \
146 { \
147 if (pConfigDriver (hwndParent, fRequest, lpszDriver, lpszArgs, lpszMsg, cbMsgMax, pcbMsgOut)) \
148 { \
149 retcode = TRUE; \
150 goto done; \
151 } \
152 else \
153 { \
154 PUSH_ERROR (ODBC_ERROR_REQUEST_FAILED); \
155 retcode = FALSE; \
156 goto done; \
157 } \
158 } \
159 }
160
161 #define CALL_CONFIG_DRIVERW_BUNDLE(driverpath) \
162 if (bundle_dll != NULL) \
163 { \
164 if ((pConfigDriverW = (pConfigDriverWFunc) CFBundleGetFunctionPointerForName (bundle_dll, CFSTR ("ConfigDriverW"))) != NULL) \
165 { \
166 if (pConfigDriverW (hwndParent, fRequest, (SQLWCHAR *) lpszDriver, (SQLWCHAR *) lpszArgs, (SQLWCHAR *) lpszMsg, cbMsgMax, pcbMsgOut)) \
167 { \
168 retcode = TRUE; \
169 goto done; \
170 } \
171 else \
172 { \
173 PUSH_ERROR (ODBC_ERROR_REQUEST_FAILED); \
174 retcode = FALSE; \
175 goto done; \
176 } \
177 } \
178 else if ((pConfigDriver = (pConfigDriverFunc) CFBundleGetFunctionPointerForName (bundle_dll, CFSTR ("ConfigDriver"))) != NULL) \
179 { \
180 char *_args_u8 = (char *) dm_SQL_WtoU8 ((SQLWCHAR *) lpszArgs, SQL_NTS); \
181 char *_msg_u8 = (char *) dm_SQL_WtoU8 ((SQLWCHAR *) lpszMsg, SQL_NTS); \
182 if ((_args_u8 == NULL && lpszArgs) || (_msg_u8 == NULL && lpszMsg)) \
183 { \
184 PUSH_ERROR (ODBC_ERROR_OUT_OF_MEM); \
185 retcode = FALSE; \
186 goto done; \
187 } \
188 if (pConfigDriver (hwndParent, fRequest, _drv_u8, _args_u8, _msg_u8, STRLEN (_msg_u8), pcbMsgOut)) \
189 { \
190 MEM_FREE (_args_u8); \
191 MEM_FREE (_msg_u8); \
192 retcode = TRUE; \
193 goto done; \
194 } \
195 else \
196 { \
197 MEM_FREE (_args_u8); \
198 MEM_FREE (_msg_u8); \
199 PUSH_ERROR (ODBC_ERROR_REQUEST_FAILED); \
200 retcode = FALSE; \
201 goto done; \
202 } \
203 } \
204 }
205
206 #else
207
208 #define CALL_CONFIG_DRIVER(driverpath) \
209 if ((handle = DLL_OPEN ((driverpath))) != NULL) \
210 { \
211 if ((pConfigDriver = (pConfigDriverFunc) DLL_PROC (handle, "ConfigDriver")) != NULL) \
212 { \
213 if (pConfigDriver (hwndParent, fRequest, lpszDriver, lpszArgs, lpszMsg, cbMsgMax, pcbMsgOut)) \
214 { \
215 DLL_CLOSE (handle); \
216 retcode = TRUE; \
217 goto done; \
218 } \
219 else \
220 { \
221 PUSH_ERROR (ODBC_ERROR_REQUEST_FAILED); \
222 DLL_CLOSE (handle); \
223 retcode = FALSE; \
224 goto done; \
225 } \
226 } \
227 DLL_CLOSE (handle); \
228 }
229
230 #define CALL_CONFIG_DRIVERW(driverpath) \
231 if ((handle = DLL_OPEN ((driverpath))) != NULL) \
232 { \
233 if ((pConfigDriverW = (pConfigDriverWFunc) DLL_PROC (handle, "ConfigDriverW")) != NULL) \
234 { \
235 if (pConfigDriverW (hwndParent, fRequest, (SQLWCHAR *) lpszDriver, (SQLWCHAR *) lpszArgs, (SQLWCHAR *) lpszMsg, cbMsgMax, pcbMsgOut)) \
236 { \
237 DLL_CLOSE (handle); \
238 retcode = TRUE; \
239 goto done; \
240 } \
241 else \
242 { \
243 PUSH_ERROR (ODBC_ERROR_REQUEST_FAILED); \
244 DLL_CLOSE (handle); \
245 retcode = FALSE; \
246 goto done; \
247 } \
248 } \
249 else if ((pConfigDriver = (pConfigDriverFunc) DLL_PROC (handle, "ConfigDriver")) != NULL) \
250 { \
251 char *_args_u8 = (char *) dm_SQL_WtoU8 ((SQLWCHAR *) lpszArgs, SQL_NTS); \
252 char *_msg_u8 = (char *) dm_SQL_WtoU8 ((SQLWCHAR *) lpszMsg, SQL_NTS); \
253 if ((_args_u8 == NULL && lpszArgs) || (_msg_u8 == NULL && lpszMsg)) \
254 { \
255 PUSH_ERROR (ODBC_ERROR_OUT_OF_MEM); \
256 DLL_CLOSE (handle); \
257 retcode = FALSE; \
258 goto done; \
259 } \
260 if (pConfigDriver (hwndParent, fRequest, _drv_u8, _args_u8, _msg_u8, STRLEN (_msg_u8), pcbMsgOut)) \
261 { \
262 MEM_FREE (_args_u8); \
263 MEM_FREE (_msg_u8); \
264 DLL_CLOSE (handle); \
265 retcode = TRUE; \
266 goto done; \
267 } \
268 else \
269 { \
270 MEM_FREE (_args_u8); \
271 MEM_FREE (_msg_u8); \
272 PUSH_ERROR (ODBC_ERROR_REQUEST_FAILED); \
273 DLL_CLOSE (handle); \
274 retcode = FALSE; \
275 goto done; \
276 } \
277 } \
278 DLL_CLOSE (handle); \
279 }
280 #endif
281
282 #endif
283
284 BOOL INSTAPI
SQLConfigDriver_Internal(HWND hwndParent,WORD fRequest,LPCSTR lpszDriver,LPCSTR lpszArgs,LPSTR lpszMsg,WORD cbMsgMax,WORD FAR * pcbMsgOut,SQLCHAR waMode)285 SQLConfigDriver_Internal (HWND hwndParent, WORD fRequest, LPCSTR lpszDriver,
286 LPCSTR lpszArgs, LPSTR lpszMsg, WORD cbMsgMax, WORD FAR * pcbMsgOut,
287 SQLCHAR waMode)
288 {
289 PCONFIG pCfg;
290 BOOL retcode = FALSE;
291 void *handle;
292 pConfigDriverFunc pConfigDriver;
293 pConfigDriverWFunc pConfigDriverW;
294 #if defined (__APPLE__) && !defined (NO_FRAMEWORKS)
295 CFBundleRef bundle = NULL;
296 CFBundleRef bundle_dll = NULL;
297 CFURLRef liburl;
298 #endif
299 char *_drv_u8 = NULL;
300
301 /* Check input parameters */
302 CLEAR_ERROR ();
303
304 if (waMode == 'W')
305 {
306 _drv_u8 = (char *) dm_SQL_WtoU8 ((SQLWCHAR *) lpszDriver, SQL_NTS);
307 if (_drv_u8 == NULL && lpszDriver)
308 {
309 PUSH_ERROR (ODBC_ERROR_OUT_OF_MEM);
310 goto quit;
311 }
312 }
313 else
314 _drv_u8 = (char *) lpszDriver;
315
316 if (!_drv_u8 || !STRLEN (_drv_u8))
317 {
318 PUSH_ERROR (ODBC_ERROR_INVALID_NAME);
319 goto quit;
320 }
321
322 /* Map the request User/System */
323 if (fRequest < ODBC_INSTALL_DRIVER || fRequest > ODBC_CONFIG_DRIVER_MAX)
324 {
325 PUSH_ERROR (ODBC_ERROR_INVALID_REQUEST_TYPE);
326 goto quit;
327 }
328
329 /* Get it from the user odbcinst file */
330 wSystemDSN = USERDSN_ONLY;
331 if (!_iodbcdm_cfg_search_init (&pCfg, "odbcinst.ini", TRUE))
332 {
333 if (!_iodbcdm_cfg_find (pCfg, (char *) _drv_u8, "Setup"))
334 {
335 if (waMode == 'A')
336 {
337 CALL_CONFIG_DRIVER (pCfg->value);
338 }
339 else
340 {
341 CALL_CONFIG_DRIVERW (pCfg->value);
342 }
343 }
344 if (!_iodbcdm_cfg_find (pCfg, (char *) _drv_u8, "Driver"))
345 {
346 if (waMode == 'A')
347 {
348 CALL_CONFIG_DRIVER (pCfg->value);
349 }
350 else
351 {
352 CALL_CONFIG_DRIVERW (pCfg->value);
353 }
354 }
355 if (!access (_drv_u8, X_OK))
356 {
357 if (waMode == 'A')
358 {
359 CALL_CONFIG_DRIVER (_drv_u8);
360 }
361 else
362 {
363 CALL_CONFIG_DRIVERW (_drv_u8);
364 }
365 }
366 if (!_iodbcdm_cfg_find (pCfg, "Default", "Setup"))
367 {
368 if (waMode == 'A')
369 {
370 CALL_CONFIG_DRIVER (pCfg->value);
371 }
372 else
373 {
374 CALL_CONFIG_DRIVERW (pCfg->value);
375 }
376 }
377 if (!_iodbcdm_cfg_find (pCfg, "Default", "Driver"))
378 {
379 if (waMode == 'A')
380 {
381 CALL_CONFIG_DRIVER (pCfg->value);
382 }
383 else
384 {
385 CALL_CONFIG_DRIVERW (pCfg->value);
386 }
387 }
388 }
389
390 /* Get it from the system odbcinst file */
391 if (pCfg)
392 {
393 _iodbcdm_cfg_done (pCfg);
394 pCfg = NULL;
395 }
396 wSystemDSN = SYSTEMDSN_ONLY;
397 if (!_iodbcdm_cfg_search_init (&pCfg, "odbcinst.ini", TRUE))
398 {
399 if (!_iodbcdm_cfg_find (pCfg, (char *) _drv_u8, "Setup"))
400 {
401 if (waMode == 'A')
402 {
403 CALL_CONFIG_DRIVER (pCfg->value);
404 }
405 else
406 {
407 CALL_CONFIG_DRIVERW (pCfg->value);
408 }
409 }
410 if (!_iodbcdm_cfg_find (pCfg, (char *) _drv_u8, "Driver"))
411 {
412 if (waMode == 'A')
413 {
414 CALL_CONFIG_DRIVER (pCfg->value);
415 }
416 else
417 {
418 CALL_CONFIG_DRIVERW (pCfg->value);
419 }
420 }
421 if (!access (_drv_u8, X_OK))
422 {
423 if (waMode == 'A')
424 {
425 CALL_CONFIG_DRIVER (_drv_u8);
426 }
427 else
428 {
429 CALL_CONFIG_DRIVERW (_drv_u8);
430 }
431 }
432 if (!_iodbcdm_cfg_find (pCfg, "Default", "Setup"))
433 {
434 if (waMode == 'A')
435 {
436 CALL_CONFIG_DRIVER (pCfg->value);
437 }
438 else
439 {
440 CALL_CONFIG_DRIVERW (pCfg->value);
441 }
442 }
443 if (!_iodbcdm_cfg_find (pCfg, "Default", "Driver"))
444 {
445 if (waMode == 'A')
446 {
447 CALL_CONFIG_DRIVER (pCfg->value);
448 }
449 else
450 {
451 CALL_CONFIG_DRIVERW (pCfg->value);
452 }
453 }
454 }
455
456 /* The last ressort, a proxy driver */
457 #if defined (__APPLE__)
458 # if !defined(NO_FRAMEWORKS)
459 bundle = CFBundleGetBundleWithIdentifier (CFSTR ("org.iodbc.core"));
460 if (bundle)
461 {
462 /* Search for the drvproxy library */
463 liburl =
464 CFBundleCopyResourceURL (bundle, CFSTR ("iODBCdrvproxy.bundle"),
465 NULL, NULL);
466 if (liburl)
467 {
468 bundle_dll = CFBundleCreate (NULL, liburl);
469 CFRelease (liburl);
470 if (waMode == 'A')
471 {
472 CALL_CONFIG_DRIVER_BUNDLE ();
473 }
474 else
475 {
476 CALL_CONFIG_DRIVERW_BUNDLE ();
477 }
478 }
479 }
480 # endif
481 #else
482 if (waMode == 'A')
483 {
484 CALL_CONFIG_DRIVER ("libdrvproxy.so.2");
485 }
486 else
487 {
488 CALL_CONFIG_DRIVERW ("libdrvproxy.so.2");
489 }
490 #endif
491
492 #if defined (__APPLE__)
493 # if !defined (NO_FRAMEWORKS)
494 bundle = CFBundleGetBundleWithIdentifier (CFSTR ("org.iodbc.core"));
495 if (bundle)
496 {
497 /* Search for the drvproxy library */
498 liburl =
499 CFBundleCopyResourceURL (bundle, CFSTR ("iODBCdrvproxy.bundle"),
500 NULL, NULL);
501 if (liburl)
502 {
503 bundle_dll = CFBundleCreate (NULL, liburl);
504 if (waMode == 'A')
505 {
506 CALL_CONFIG_DRIVER_BUNDLE ();
507 }
508 else
509 {
510 CALL_CONFIG_DRIVERW_BUNDLE ();
511 }
512 }
513 if (liburl)
514 CFRelease (liburl);
515 }
516 # endif
517 #else
518 if (waMode == 'A')
519 {
520 CALL_CONFIG_DRIVER ("libdrvproxy.so.2");
521 }
522 else
523 {
524 CALL_CONFIG_DRIVERW ("libdrvproxy.so.2");
525 }
526 #endif
527
528 /* Error : ConfigDriver could no be found */
529 PUSH_ERROR (ODBC_ERROR_LOAD_LIB_FAILED);
530
531 done:
532 if (pCfg)
533 _iodbcdm_cfg_done (pCfg);
534
535 quit:
536 if (_drv_u8 != lpszDriver)
537 MEM_FREE (_drv_u8);
538
539 wSystemDSN = USERDSN_ONLY;
540 configMode = ODBC_BOTH_DSN;
541
542 if (pcbMsgOut)
543 *pcbMsgOut = 0;
544
545 return retcode;
546 }
547
548 BOOL INSTAPI
SQLConfigDriver(HWND hwndParent,WORD fRequest,LPCSTR lpszDriver,LPCSTR lpszArgs,LPSTR lpszMsg,WORD cbMsgMax,WORD FAR * pcbMsgOut)549 SQLConfigDriver (HWND hwndParent, WORD fRequest, LPCSTR lpszDriver,
550 LPCSTR lpszArgs, LPSTR lpszMsg, WORD cbMsgMax, WORD FAR * pcbMsgOut)
551 {
552 return SQLConfigDriver_Internal (hwndParent, fRequest,
553 (SQLPOINTER) lpszDriver, (SQLPOINTER) lpszArgs, (SQLPOINTER) lpszMsg,
554 cbMsgMax, pcbMsgOut, 'A');
555 }
556
557 BOOL INSTAPI
SQLConfigDriverW(HWND hwndParent,WORD fRequest,LPCWSTR lpszDriver,LPCWSTR lpszArgs,LPWSTR lpszMsg,WORD cbMsgMax,WORD FAR * pcbMsgOut)558 SQLConfigDriverW (HWND hwndParent, WORD fRequest, LPCWSTR lpszDriver,
559 LPCWSTR lpszArgs, LPWSTR lpszMsg, WORD cbMsgMax, WORD FAR * pcbMsgOut)
560 {
561 return SQLConfigDriver_Internal (hwndParent, fRequest,
562 (SQLPOINTER) lpszDriver, (SQLPOINTER) lpszArgs, (SQLPOINTER) lpszMsg,
563 cbMsgMax, pcbMsgOut, 'W');
564 }
565