1 /*
2 * misc.c
3 *
4 * $Id$
5 *
6 * Miscellaneous functions
7 *
8 * The iODBC driver manager.
9 *
10 * Copyright (C) 1996-2021 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
81 #include <stdio.h>
82 #include <stdlib.h>
83 #include <string.h>
84 #include <unistd.h>
85 #include <sys/types.h>
86 #include <sys/stat.h>
87
88 #include "inifile.h"
89 #include "misc.h"
90
91 #ifdef _MAC
92 # include <getfpn.h>
93 #endif /* endif _MAC */
94
95 WORD wSystemDSN = USERDSN_ONLY;
96 WORD configMode = ODBC_BOTH_DSN;
97
98
99 #if !defined(WINDOWS) && !defined(WIN32) && !defined(OS2) && !defined(macintosh)
100 # include <pwd.h>
101 # define UNIX_PWD
102 #endif
103
104
105 /*
106 * Algorithm for resolving an odbc.ini reference
107 *
108 * For UNIX : 1. Check for $ODBCINI variable, if exists return $ODBCINI.
109 * 2. Check for $HOME/.odbc.ini or ~/.odbc.ini file,
110 * if exists return it.
111 * 3. Check for SYS_ODBC_INI build variable, if exists return
112 * it. (ie : /etc/odbc.ini).
113 * 4. No odbc.ini presence, return NULL.
114 *
115 * For WINDOWS, WIN32, OS2 :
116 * 1. Check for the system odbc.ini file, if exists return it.
117 * 2. No odbc.ini presence, return NULL.
118 *
119 * For VMS: 1. Check for $ODBCINI variable, if exists return $ODBCINI.
120 * 2. Check for SYS$LOGIN:ODBC.INI file, if exists return it.
121 * 3. No odbc.ini presence, return NULL.
122 *
123 * For Mac: 1. On powerPC, file is ODBC Preferences PPC
124 * On 68k, file is ODBC Preferences
125 * 2. Check for ...:System Folder:Preferences:ODBC Preferences
126 * file, if exists return it.
127 * 3. No odbc.ini presence, return NULL.
128 *
129 * For MacX: 1. Check for $ODBCINI variable, if exists return $ODBCINI.
130 * 2. Check for $HOME/Library/ODBC/odbc.ini,
131 * if exists return it.
132 * 3. Check for SYS_ODBC_INI build variable, if exists return
133 * it. (ie : /etc/odbc.ini).
134 * 4. Check for /Library/ODBC/odbc.ini
135 * file, if exists return it.
136 * 5. No odbc.ini presence, return NULL.
137 **/
138 char *
_iodbcadm_getinifile(char * buf,int size,int bIsInst,int doCreate)139 _iodbcadm_getinifile (char *buf, int size, int bIsInst, int doCreate)
140 {
141 #ifdef _MAC
142 HParamBlockRec hp;
143 long fldrDid;
144 short fldrRef;
145 OSErr result;
146 #endif /* endif _MAC */
147 int i, j;
148 char *ptr;
149
150 #ifdef _MAC
151 # ifdef __POWERPC__
152 j = STRLEN (bIsInst ? ":ODBC Installer Preferences PPC" :
153 ":ODBC Preferences PPC") + 1;
154 # else
155 j = STRLEN (bIsInst ? ":ODBC Installer Preferences" : ":ODBC Preferences") +
156 1;
157 # endif /* endif __POWERPC__ */
158 #else
159 j = STRLEN (bIsInst ? "/odbcinst.ini" : "/odbc.ini") + 1;
160 #endif /* endif _MAC */
161
162 if (size < j)
163 return NULL;
164
165 #if !defined(UNIX_PWD)
166 # ifdef _MAC
167 result =
168 FindFolder (kOnSystemDisk, kPreferencesFolderType, kDontCreateFolder,
169 &fldrRef, &fldrDid);
170 if (result != noErr)
171 return NULL;
172 ptr = get_full_pathname (fldrDid, fldrRef);
173
174 i = (ptr) ? STRLEN (ptr) : 0;
175 if (i == 0 || i > size - j)
176 {
177 if (ptr)
178 free (ptr);
179 return NULL;
180 }
181
182 # ifdef __POWERPC__
183 STRCPY (buf, ptr);
184 STRCAT (buf,
185 bIsInst ? ":ODBC Installer Preferences PPC" : ":ODBC Preferences PPC");
186 # else
187 STRCPY (buf, ptr);
188 STRCAT (buf, bIsInst ? ":ODBC Installer Preferences" : ":ODBC Preferences");
189 # endif /* endif __POWERPC__ */
190
191 if (doCreate)
192 {
193 hp.fileParam.ioCompletion = NULL;
194 hp.fileParam.ioVRefNum = fldrRef;
195 hp.fileParam.ioDirID = fldrDid;
196 # ifdef __POWERPC__
197 hp.fileParam.ioNamePtr =
198 bIsInst ? "\pODBC Installer Preferences PPC" :
199 "\pODBC Preferences PPC";
200 # else
201 hp.fileParam.ioNamePtr =
202 bIsInst ? "\pODBC Installer Preferences" : "\pODBC Preferences";
203 # endif
204 PBHCreate (&hp, FALSE);
205 }
206
207 free (ptr);
208
209 return buf;
210
211 # else /* else _MAC */
212
213 /*
214 * On Windows, there is only one place to look
215 */
216 i = GetWindowsDirectory ((LPSTR) buf, size);
217
218 if (i == 0 || i > size - j)
219 return NULL;
220
221 snprintf (buf + i, size - i, bIsInst ? "/odbcinst.ini" : "/odbc.ini");
222
223 return buf;
224 # endif /* endif _MAC */
225 #else
226 if (wSystemDSN == USERDSN_ONLY)
227 {
228 /*
229 * 1. Check $ODBCINI environment variable
230 */
231 if ((ptr = getenv (bIsInst ? "ODBCINSTINI" : "ODBCINI")) != NULL)
232 {
233 STRNCPY (buf, ptr, size);
234
235 if (access (buf, R_OK) == 0)
236 return buf;
237 else if (doCreate)
238 {
239 int f = open ((char *) buf, O_CREAT,
240 S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH);
241 if (f != -1)
242 {
243 close (f);
244 return buf;
245 }
246 }
247 }
248
249 # ifdef VMS
250 /*
251 * 2a. VMS calls this HOME
252 */
253 STRNCPY (buf, bIsInst ? "SYS$LOGIN:ODBCINST.INI" : "SYS$LOGIN:ODBC.INI",
254 size);
255
256 if (doCreate || access (buf, R_OK) == 0)
257 return buf;
258 # else /* else VMS */
259
260 if ((ptr = getenv ("HOME")) == NULL)
261 {
262 ptr = (char *) getpwuid (getuid ());
263
264 if (ptr != NULL)
265 ptr = ((struct passwd *) ptr)->pw_dir;
266 }
267
268 if (ptr != NULL)
269 {
270 #if defined(__APPLE__)
271 /*
272 * 2b. Try to check the ~/Library/ODBC/odbc.ini
273 */
274 snprintf (buf, size,
275 bIsInst ? "%s" ODBCINST_INI_APP : "%s" ODBC_INI_APP, ptr);
276
277 if (access (buf, R_OK) == 0)
278 return buf;
279 else if (doCreate)
280 {
281 int f = open ((char *) buf, O_CREAT,
282 S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH);
283 if (f != -1)
284 {
285 close (f);
286 return buf;
287 }
288 }
289 # else /* else __APPLE__ */
290
291 /*
292 * 2b. Check either $HOME/.odbc.ini or ~/.odbc.ini
293 */
294 snprintf (buf, size, bIsInst ? "%s/.odbcinst.ini" : "%s/.odbc.ini",
295 ptr);
296
297 if (doCreate || access (buf, R_OK) == 0)
298 return buf;
299 # endif /* endif __APPLE__ */
300 # endif /* endif VMS */
301 }
302 }
303
304 /*
305 * 3. Try SYS_ODBC_INI as the last resort
306 */
307 if (wSystemDSN == SYSTEMDSN_ONLY || bIsInst)
308 {
309 /*
310 * 1. Check $SYSODBCINI environment variable
311 */
312 if ((ptr = getenv (bIsInst ? "SYSODBCINSTINI" : "SYSODBCINI")) != NULL)
313 {
314 STRNCPY (buf, ptr, size);
315
316 if (access (buf, R_OK) == 0)
317 return buf;
318 else if (doCreate)
319 {
320 int f = open ((char *) buf, O_CREAT,
321 S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH);
322 if (f != -1)
323 {
324 close (f);
325 return buf;
326 }
327 }
328 }
329
330 #if defined(__APPLE__)
331 /*
332 * Try to check the /Library/ODBC/odbc.ini
333 */
334 snprintf (buf, size, "%s", bIsInst ? ODBCINST_INI_APP : ODBC_INI_APP);
335
336 if (access (buf, R_OK) == 0)
337 return buf;
338 else if (doCreate)
339 {
340 int f = open ((char *) buf, O_CREAT,
341 S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH);
342 if (f != -1)
343 {
344 close (f);
345 return buf;
346 }
347 }
348 # endif /* endif __APPLE__ */
349
350 STRNCPY (buf, bIsInst ? SYS_ODBCINST_INI : SYS_ODBC_INI, size);
351 return buf;
352 }
353
354 /*
355 * No ini file found or accessible
356 */
357 return NULL;
358 #endif /* UNIX_PWD */
359 }
360
361 const char *
_iodbcdm_check_for_string(const char * szList,const char * szString,int bContains)362 _iodbcdm_check_for_string(const char *szList, const char *szString, int bContains)
363 {
364 const char *currP = szList;
365
366 while (*currP)
367 {
368 if (bContains)
369 {
370 if (strstr (currP, szString))
371 return currP;
372 }
373 else
374 {
375 if (!strcmp (currP, szString))
376 return currP;
377 }
378 }
379 return NULL;
380 }
381
382
383 char *
_iodbcdm_remove_quotes(const char * szString)384 _iodbcdm_remove_quotes(const char *szString)
385 {
386 char *szWork, *szPtr;
387
388 while (*szString == '\'' || *szString == '\"')
389 szString += 1;
390
391 if (!*szString)
392 return NULL;
393 szWork = strdup (szString);
394 szPtr = strchr (szWork, '\'');
395 if (szPtr)
396 *szPtr = 0;
397 szPtr = strchr (szWork, '\"');
398 if (szPtr)
399 *szPtr = 0;
400
401 return szWork;
402 }
403
404 /*
405 * Get FILEDSN file name
406 *
407 * If file name does not contain path component, the default directory for
408 * saving and loading a .dsn file will be defined as follows:
409 * 1. if FILEDSNPATH is set in environment: use environment
410 * 2. if odbcinst.ini [odbc] FILEDSNPATH is set: use this
411 * 3. else use DEFAULT_FILEDSNPATH
412 *
413 * ".dsn" extension is always appended to the resulting filename
414 * (if not already exists).
415 */
416 void
_iodbcdm_getdsnfile(const char * filedsn,char * buf,size_t buf_sz)417 _iodbcdm_getdsnfile(const char *filedsn, char *buf, size_t buf_sz)
418 {
419 char *p;
420 char *default_path;
421
422 if (strchr (filedsn, '/') != NULL)
423 {
424 /* has path component -- copy as is */
425 _iodbcdm_strlcpy (buf, filedsn, buf_sz);
426 goto done;
427 }
428
429 /* get default path */
430 if ((default_path = getenv ("FILEDSNPATH")) != NULL)
431 _iodbcdm_strlcpy (buf, default_path, buf_sz);
432 else
433 {
434 SQLSetConfigMode (ODBC_BOTH_DSN);
435 if (!SQLGetPrivateProfileString ("ODBC", "FileDSNPath", "",
436 buf, buf_sz, "odbcinst.ini"))
437 _iodbcdm_strlcpy (buf, DEFAULT_FILEDSNPATH, buf_sz);
438 }
439
440 /* append filedsn file name */
441 _iodbcdm_strlcat (buf, "/", buf_sz);
442 _iodbcdm_strlcat (buf, filedsn, buf_sz);
443
444 done:
445 /* append ".dsn" if extension is not ".dsn" */
446 if ((p = strrchr (buf, '.')) == NULL ||
447 strcasecmp (p, ".dsn") != 0)
448 _iodbcdm_strlcat (buf, ".dsn", buf_sz);
449 }
450
451
452 /*
453 * Copy src to string dst of size siz. At most siz-1 characters
454 * will be copied. Always NUL terminates (unless siz == 0).
455 * Returns strlen(src); if retval >= siz, truncation occurred.
456 *
457 * Taken from FreeBSD libc.
458 */
459 size_t
_iodbcdm_strlcpy(char * dst,const char * src,size_t siz)460 _iodbcdm_strlcpy(char *dst, const char *src, size_t siz)
461 {
462 char *d = dst;
463 const char *s = src;
464 size_t n = siz;
465
466 /* Copy as many bytes as will fit */
467 if (n != 0 && --n != 0)
468 {
469 do {
470 if ((*d++ = *s++) == 0)
471 break;
472 } while (--n != 0);
473 }
474
475 /* Not enough room in dst, add NUL and traverse rest of src */
476 if (n == 0)
477 {
478 if (siz != 0)
479 *d = '\0'; /* NUL-terminate dst */
480 while (*s++)
481 ;
482 }
483
484 return(s - src - 1); /* count does not include NUL */
485 }
486
487
488 /*
489 * Appends src to string dst of size siz (unlike strncat, siz is the
490 * full size of dst, not space left). At most siz-1 characters
491 * will be copied. Always NUL terminates (unless siz <= strlen(dst)).
492 * Returns strlen(src) + MIN(siz, strlen(initial dst)).
493 * If retval >= siz, truncation occurred.
494 *
495 * Taken from FreeBSD libc.
496 */
497 size_t
_iodbcdm_strlcat(char * dst,const char * src,size_t siz)498 _iodbcdm_strlcat(char *dst, const char *src, size_t siz)
499 {
500 char *d = dst;
501 const char *s = src;
502 size_t n = siz;
503 size_t dlen;
504
505 /* Find the end of dst and adjust bytes left but don't go past end */
506 while (n-- != 0 && *d != '\0')
507 d++;
508 dlen = d - dst;
509 n = siz - dlen;
510
511 if (n == 0)
512 return(dlen + strlen(s));
513 while (*s != '\0')
514 {
515 if (n != 1)
516 {
517 *d++ = *s;
518 n--;
519 }
520 s++;
521 }
522 *d = '\0';
523
524 return(dlen + (s - src)); /* count does not include NUL */
525 }
526