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