1/*
2 *  SQLConfigDriver.c
3 *
4 *  $Id: SQLConfigDriver.c,v 1.12 2006/01/20 15:58:35 source Exp $
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-2006 by 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) || defined (_LP64))
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#define CALL_CONFIG_DRIVER(driverpath) \
96  if ((handle = DLL_OPEN((driverpath))) != NULL) \
97	{ \
98		if ((pConfigDriver = (pConfigDriverFunc)DLL_PROC(handle, "ConfigDriver")) != NULL) \
99		{ \
100			if (pConfigDriver (hwndParent, fRequest, lpszDriver, lpszArgs, lpszMsg, cbMsgMax, pcbMsgOut))  \
101	  	{ \
102	    	DLL_CLOSE(handle); \
103	    	retcode = TRUE; \
104	    	goto done; \
105	  	} \
106			else \
107			{ \
108				PUSH_ERROR(ODBC_ERROR_REQUEST_FAILED); \
109	    	DLL_CLOSE(handle); \
110	    	retcode = FALSE; \
111	    	goto done; \
112			} \
113		} \
114		DLL_CLOSE(handle); \
115	}
116
117#define CALL_CONFIG_DRIVERW(driverpath) \
118  if ((handle = DLL_OPEN((driverpath))) != NULL) \
119	{ \
120		if ((pConfigDriverW = (pConfigDriverWFunc)DLL_PROC(handle, "ConfigDriverW")) != NULL) \
121		{ \
122			if (pConfigDriverW (hwndParent, fRequest, (SQLWCHAR*)lpszDriver, (SQLWCHAR*)lpszArgs, (SQLWCHAR*)lpszMsg, cbMsgMax, pcbMsgOut))  \
123	  	{ \
124	    	DLL_CLOSE(handle); \
125	    	retcode = TRUE; \
126	    	goto done; \
127	  	} \
128			else \
129			{ \
130				PUSH_ERROR(ODBC_ERROR_REQUEST_FAILED); \
131	    	DLL_CLOSE(handle); \
132	    	retcode = FALSE; \
133	    	goto done; \
134			} \
135		} \
136                else if ((pConfigDriver = (pConfigDriverFunc)DLL_PROC(handle, "ConfigDriver")) != NULL) \
137                { \
138                  char *_args_u8 = (char *) dm_SQL_WtoU8((SQLWCHAR*)lpszArgs, SQL_NTS); \
139                  char *_msg_u8 = (char *) dm_SQL_WtoU8((SQLWCHAR*)lpszMsg, SQL_NTS); \
140                  if ((_args_u8 == NULL && lpszArgs) || (_msg_u8 == NULL && lpszMsg)) \
141                  { \
142                    PUSH_ERROR (ODBC_ERROR_OUT_OF_MEM); \
143                    DLL_CLOSE(handle); \
144                    retcode = FALSE; \
145                    goto done; \
146                  } \
147			if (pConfigDriver (hwndParent, fRequest, _drv_u8, _args_u8, _msg_u8, STRLEN(_msg_u8), pcbMsgOut))  \
148	  	{ \
149                MEM_FREE (_args_u8); \
150                MEM_FREE (_msg_u8); \
151	    	DLL_CLOSE(handle); \
152	    	retcode = TRUE; \
153	    	goto done; \
154	  	} \
155			else \
156			{ \
157                MEM_FREE (_args_u8); \
158                MEM_FREE (_msg_u8); \
159				PUSH_ERROR(ODBC_ERROR_REQUEST_FAILED); \
160	    	DLL_CLOSE(handle); \
161	    	retcode = FALSE; \
162	    	goto done; \
163			} \
164                } \
165		DLL_CLOSE(handle); \
166	}
167#endif
168
169BOOL INSTAPI
170SQLConfigDriver_Internal (HWND hwndParent, WORD fRequest, LPCSTR lpszDriver,
171    LPCSTR lpszArgs, LPSTR lpszMsg, WORD cbMsgMax, WORD FAR * pcbMsgOut,
172    SQLCHAR waMode)
173{
174  PCONFIG pCfg;
175  BOOL retcode = FALSE;
176  void *handle;
177  pConfigDriverFunc pConfigDriver;
178  pConfigDriverWFunc pConfigDriverW;
179#if defined (__APPLE__) && !(defined (NO_FRAMEWORKS) || defined (_LP64))
180  CFStringRef libname = NULL;
181  CFBundleRef bundle;
182  CFURLRef liburl;
183  char name[1024] = { 0 };
184#endif
185  char *_drv_u8 = NULL;
186
187  /* Check input parameters */
188  CLEAR_ERROR ();
189
190  if (waMode == 'W')
191    {
192      _drv_u8 = (char *) dm_SQL_WtoU8 ((SQLWCHAR *) lpszDriver, SQL_NTS);
193      if (_drv_u8 == NULL && lpszDriver)
194	{
195	  PUSH_ERROR (ODBC_ERROR_OUT_OF_MEM);
196	  goto quit;
197	}
198    }
199  else
200    _drv_u8 = (char *) lpszDriver;
201
202  if (!_drv_u8 || !STRLEN (_drv_u8))
203    {
204      PUSH_ERROR (ODBC_ERROR_INVALID_NAME);
205      goto quit;
206    }
207
208  /* Map the request User/System */
209  if (fRequest < ODBC_INSTALL_DRIVER || fRequest > ODBC_CONFIG_DRIVER_MAX)
210    {
211      PUSH_ERROR (ODBC_ERROR_INVALID_REQUEST_TYPE);
212      goto quit;
213    }
214
215  /* Get it from the user odbcinst file */
216  wSystemDSN = USERDSN_ONLY;
217  if (!_iodbcdm_cfg_search_init (&pCfg, "odbcinst.ini", TRUE))
218    {
219      if (!_iodbcdm_cfg_find (pCfg, (char *) _drv_u8, "Setup"))
220	{
221	  if (waMode == 'A')
222	    {
223	      CALL_CONFIG_DRIVER (pCfg->value);
224	    }
225	  else
226	    {
227	      CALL_CONFIG_DRIVERW (pCfg->value);
228	    }
229	}
230      if (!_iodbcdm_cfg_find (pCfg, (char *) _drv_u8, "Driver"))
231	{
232	  if (waMode == 'A')
233	    {
234	      CALL_CONFIG_DRIVER (pCfg->value);
235	    }
236	  else
237	    {
238	      CALL_CONFIG_DRIVERW (pCfg->value);
239	    }
240	}
241      if (!access (_drv_u8, X_OK))
242	{
243	  if (waMode == 'A')
244	    {
245	      CALL_CONFIG_DRIVER (_drv_u8);
246	    }
247	  else
248	    {
249	      CALL_CONFIG_DRIVERW (_drv_u8);
250	    }
251	}
252      if (!_iodbcdm_cfg_find (pCfg, "Default", "Setup"))
253	{
254	  if (waMode == 'A')
255	    {
256	      CALL_CONFIG_DRIVER (pCfg->value);
257	    }
258	  else
259	    {
260	      CALL_CONFIG_DRIVERW (pCfg->value);
261	    }
262	}
263      if (!_iodbcdm_cfg_find (pCfg, "Default", "Driver"))
264	{
265	  if (waMode == 'A')
266	    {
267	      CALL_CONFIG_DRIVER (pCfg->value);
268	    }
269	  else
270	    {
271	      CALL_CONFIG_DRIVERW (pCfg->value);
272	    }
273	}
274    }
275
276  /* Get it from the system odbcinst file */
277  if (pCfg)
278    {
279      _iodbcdm_cfg_done (pCfg);
280      pCfg = NULL;
281    }
282  wSystemDSN = SYSTEMDSN_ONLY;
283  if (!_iodbcdm_cfg_search_init (&pCfg, "odbcinst.ini", TRUE))
284    {
285      if (!_iodbcdm_cfg_find (pCfg, (char *) _drv_u8, "Setup"))
286	{
287	  if (waMode == 'A')
288	    {
289	      CALL_CONFIG_DRIVER (pCfg->value);
290	    }
291	  else
292	    {
293	      CALL_CONFIG_DRIVERW (pCfg->value);
294	    }
295	}
296      if (!_iodbcdm_cfg_find (pCfg, (char *) _drv_u8, "Driver"))
297	{
298	  if (waMode == 'A')
299	    {
300	      CALL_CONFIG_DRIVER (pCfg->value);
301	    }
302	  else
303	    {
304	      CALL_CONFIG_DRIVERW (pCfg->value);
305	    }
306	}
307      if (!access (_drv_u8, X_OK))
308	{
309	  if (waMode == 'A')
310	    {
311	      CALL_CONFIG_DRIVER (_drv_u8);
312	    }
313	  else
314	    {
315	      CALL_CONFIG_DRIVERW (_drv_u8);
316	    }
317	}
318      if (!_iodbcdm_cfg_find (pCfg, "Default", "Setup"))
319	{
320	  if (waMode == 'A')
321	    {
322	      CALL_CONFIG_DRIVER (pCfg->value);
323	    }
324	  else
325	    {
326	      CALL_CONFIG_DRIVERW (pCfg->value);
327	    }
328	}
329      if (!_iodbcdm_cfg_find (pCfg, "Default", "Driver"))
330	{
331	  if (waMode == 'A')
332	    {
333	      CALL_CONFIG_DRIVER (pCfg->value);
334	    }
335	  else
336	    {
337	      CALL_CONFIG_DRIVERW (pCfg->value);
338	    }
339	}
340    }
341
342  /* The last ressort, a proxy driver */
343#if defined (__APPLE__) && !(defined (NO_FRAMEWORKS) || defined (_LP64))
344  bundle = CFBundleGetBundleWithIdentifier (CFSTR ("org.iodbc.inst"));
345  if (bundle)
346    {
347      /* Search for the drvproxy library */
348      liburl =
349	  CFBundleCopyResourceURL (bundle, CFSTR ("iODBCdrvproxy.bundle"),
350	  NULL, NULL);
351      if (liburl
352	  && (libname =
353	      CFURLCopyFileSystemPath (liburl, kCFURLPOSIXPathStyle)))
354	{
355	  CFStringGetCString (libname, name, sizeof (name),
356	      kCFStringEncodingASCII);
357	  strcat (name, "/Contents/MacOS/iODBCdrvproxy");
358	  if (waMode == 'A')
359	    {
360	      CALL_CONFIG_DRIVER (name);
361	    }
362	  else
363	    {
364	      CALL_CONFIG_DRIVERW (name);
365	    }
366	}
367      if (liburl)
368	CFRelease (liburl);
369      if (libname)
370	CFRelease (libname);
371    }
372#else
373  if (waMode == 'A')
374    {
375      CALL_CONFIG_DRIVER ("libdrvproxy.so");
376    }
377  else
378    {
379      CALL_CONFIG_DRIVERW ("libdrvproxy.so");
380    }
381#endif
382
383  /* Error : ConfigDriver could no be found */
384  PUSH_ERROR (ODBC_ERROR_LOAD_LIB_FAILED);
385
386done:
387  if (pCfg)
388    _iodbcdm_cfg_done (pCfg);
389
390quit:
391  if (_drv_u8 != lpszDriver)
392    MEM_FREE (_drv_u8);
393
394  wSystemDSN = USERDSN_ONLY;
395  configMode = ODBC_BOTH_DSN;
396
397  if (pcbMsgOut)
398    *pcbMsgOut = 0;
399
400  return retcode;
401}
402
403BOOL INSTAPI
404SQLConfigDriver (HWND hwndParent, WORD fRequest, LPCSTR lpszDriver,
405    LPCSTR lpszArgs, LPSTR lpszMsg, WORD cbMsgMax, WORD FAR * pcbMsgOut)
406{
407  return SQLConfigDriver_Internal (hwndParent, fRequest,
408      (SQLPOINTER) lpszDriver, (SQLPOINTER) lpszArgs, (SQLPOINTER) lpszMsg,
409      cbMsgMax, pcbMsgOut, 'A');
410}
411
412BOOL INSTAPI
413SQLConfigDriverW (HWND hwndParent, WORD fRequest, LPCWSTR lpszDriver,
414    LPCWSTR lpszArgs, LPWSTR lpszMsg, WORD cbMsgMax, WORD FAR * pcbMsgOut)
415{
416  return SQLConfigDriver_Internal (hwndParent, fRequest,
417      (SQLPOINTER) lpszDriver, (SQLPOINTER) lpszArgs, (SQLPOINTER) lpszMsg,
418      cbMsgMax, pcbMsgOut, 'W');
419}
420