~ubuntu-branches/ubuntu/wily/psqlodbc/wily-proposed

« back to all changes in this revision

Viewing changes to drvconn.c

  • Committer: Package Import Robot
  • Author(s): Christoph Berg
  • Date: 2014-05-29 23:17:25 UTC
  • mfrom: (16.1.8 sid)
  • Revision ID: package-import@ubuntu.com-20140529231725-nhpolx85545e4rk8
Tags: 1:09.03.0300-1
* New upstream release.
* Patch bogus expected output of test catalogfunctions.
* Set team as maintainer.
* Bump to dh 9.
* Use /usr/share/cdbs/1/rules/autoreconf.mk. Closes: #744650.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
/*-------
2
 
  Module:                       drvconn.c
3
 
 *
4
 
 * Description:         This module contains only routines related to
5
 
 *                                      implementing SQLDriverConnect.
6
 
 *
7
 
 * Classes:                     n/a
8
 
 *
9
 
 * API functions:       SQLDriverConnect
10
 
 *
11
 
 * Comments:            See "readme.txt" for copyright and license information.
12
 
 *-------
13
 
 */
14
 
 
15
 
#include "psqlodbc.h"
16
 
 
17
 
#include <stdio.h>
18
 
#include <stdlib.h>
19
 
 
20
 
#include "connection.h"
21
 
 
22
 
#ifndef WIN32
23
 
#include <sys/types.h>
24
 
#include <sys/socket.h>
25
 
#define NEAR
26
 
#else
27
 
#include <winsock2.h>
28
 
#endif
29
 
 
30
 
#include <string.h>
31
 
 
32
 
#ifdef WIN32
33
 
#include <windowsx.h>
34
 
#include "resource.h"
35
 
#endif
36
 
#include "pgapifunc.h"
37
 
 
38
 
#include "dlg_specific.h"
39
 
 
40
 
#define FORCE_PASSWORD_DISPLAY
41
 
#define NULL_IF_NULL(a) (a ? a : "(NULL)")
42
 
 
43
 
static char * hide_password(const char *str)
44
 
{
45
 
        char *outstr, *pwdp;
46
 
 
47
 
        if (!str)       return NULL;
48
 
        outstr = strdup(str);
49
 
        if (pwdp = strstr(outstr, "PWD="), !pwdp)
50
 
                pwdp = strstr(outstr, "pwd=");
51
 
        if (pwdp)
52
 
        {
53
 
                char    *p;
54
 
 
55
 
                for (p=pwdp + 4; *p && *p != ';'; p++)
56
 
                        *p = 'x';
57
 
        }
58
 
        return outstr;
59
 
}
60
 
 
61
 
/* prototypes */
62
 
void            dconn_get_connect_attributes(const SQLCHAR FAR * connect_string, ConnInfo *ci);
63
 
static void dconn_get_common_attributes(const SQLCHAR FAR * connect_string, ConnInfo *ci);
64
 
 
65
 
#ifdef WIN32
66
 
LRESULT CALLBACK dconn_FDriverConnectProc(HWND hdlg, UINT wMsg, WPARAM wParam, LPARAM lParam);
67
 
RETCODE         dconn_DoDialog(HWND hwnd, ConnInfo *ci);
68
 
 
69
 
extern HINSTANCE NEAR s_hModule;        /* Saved module handle. */
70
 
#endif
71
 
 
72
 
 
73
 
RETCODE         SQL_API
74
 
PGAPI_DriverConnect(
75
 
                                        HDBC hdbc,
76
 
                                        HWND hwnd,
77
 
                                        const SQLCHAR FAR * szConnStrIn,
78
 
                                        SQLSMALLINT cbConnStrIn,
79
 
                                        SQLCHAR FAR * szConnStrOut,
80
 
                                        SQLSMALLINT cbConnStrOutMax,
81
 
                                        SQLSMALLINT FAR * pcbConnStrOut,
82
 
                                        SQLUSMALLINT fDriverCompletion)
83
 
{
84
 
        CSTR func = "PGAPI_DriverConnect";
85
 
        ConnectionClass *conn = (ConnectionClass *) hdbc;
86
 
        ConnInfo   *ci;
87
 
 
88
 
#ifdef WIN32
89
 
        RETCODE         dialog_result;
90
 
#endif
91
 
        BOOL            paramRequired, didUI = FALSE;
92
 
        RETCODE         result;
93
 
        char            *connStrIn = NULL;
94
 
        char            connStrOut[MAX_CONNECT_STRING];
95
 
        int                     retval;
96
 
        char            salt[5];
97
 
        char            password_required = AUTH_REQ_OK;
98
 
        ssize_t         len = 0;
99
 
        SQLSMALLINT     lenStrout;
100
 
 
101
 
 
102
 
        mylog("%s: entering...\n", func);
103
 
 
104
 
        if (!conn)
105
 
        {
106
 
                CC_log_error(func, "", NULL);
107
 
                return SQL_INVALID_HANDLE;
108
 
        }
109
 
 
110
 
        connStrIn = make_string(szConnStrIn, cbConnStrIn, NULL, 0);
111
 
 
112
 
#ifdef  FORCE_PASSWORD_DISPLAY
113
 
        mylog("**** PGAPI_DriverConnect: fDriverCompletion=%d, connStrIn='%s'\n", fDriverCompletion, connStrIn);
114
 
        qlog("conn=%p, PGAPI_DriverConnect( in)='%s', fDriverCompletion=%d\n", conn, connStrIn, fDriverCompletion);
115
 
#else
116
 
        if (get_qlog() || get_mylog())
117
 
        {
118
 
                char    *hide_str = hide_password(connStrIn);
119
 
 
120
 
                mylog("**** PGAPI_DriverConnect: fDriverCompletion=%d, connStrIn='%s'\n", fDriverCompletion, NULL_IF_NULL(hide_str));
121
 
                qlog("conn=%p, PGAPI_DriverConnect( in)='%s', fDriverCompletion=%d\n", conn, NULL_IF_NULL(hide_str), fDriverCompletion);
122
 
                if (hide_str)
123
 
                        free(hide_str);
124
 
        }
125
 
#endif  /* FORCE_PASSWORD_DISPLAY */
126
 
 
127
 
        ci = &(conn->connInfo);
128
 
 
129
 
        /* Parse the connect string and fill in conninfo for this hdbc. */
130
 
        dconn_get_connect_attributes(connStrIn, ci);
131
 
 
132
 
        /*
133
 
         * If the ConnInfo in the hdbc is missing anything, this function will
134
 
         * fill them in from the registry (assuming of course there is a DSN
135
 
         * given -- if not, it does nothing!)
136
 
         */
137
 
        getDSNinfo(ci, CONN_DONT_OVERWRITE);
138
 
        dconn_get_common_attributes(connStrIn, ci);
139
 
        logs_on_off(1, ci->drivers.debug, ci->drivers.commlog);
140
 
        if (connStrIn)
141
 
        {
142
 
                free(connStrIn);
143
 
                connStrIn = NULL;
144
 
        }
145
 
 
146
 
        /* Fill in any default parameters if they are not there. */
147
 
        getDSNdefaults(ci);
148
 
        /* initialize pg_version */
149
 
        CC_initialize_pg_version(conn);
150
 
        memset(salt, 0, sizeof(salt));
151
 
 
152
 
#ifdef WIN32
153
 
dialog:
154
 
#endif
155
 
        ci->focus_password = password_required;
156
 
 
157
 
inolog("DriverCompletion=%d\n", fDriverCompletion);
158
 
        switch (fDriverCompletion)
159
 
        {
160
 
#ifdef WIN32
161
 
                case SQL_DRIVER_PROMPT:
162
 
                        dialog_result = dconn_DoDialog(hwnd, ci);
163
 
                        didUI = TRUE;
164
 
                        if (dialog_result != SQL_SUCCESS)
165
 
                                return dialog_result;
166
 
                        break;
167
 
 
168
 
                case SQL_DRIVER_COMPLETE_REQUIRED:
169
 
 
170
 
                        /* Fall through */
171
 
 
172
 
                case SQL_DRIVER_COMPLETE:
173
 
 
174
 
                        paramRequired = password_required;
175
 
                        /* Password is not a required parameter. */
176
 
                        if (ci->database[0] == '\0')
177
 
                                paramRequired = TRUE;
178
 
                        else if (ci->port[0] == '\0')
179
 
                                paramRequired = TRUE;
180
 
#ifdef  WIN32
181
 
                        else if (ci->server[0] == '\0')
182
 
                                paramRequired = TRUE;
183
 
#endif /* WIN32 */
184
 
                        if (paramRequired)
185
 
                        {
186
 
                                dialog_result = dconn_DoDialog(hwnd, ci);
187
 
                                didUI = TRUE;
188
 
                                if (dialog_result != SQL_SUCCESS)
189
 
                                        return dialog_result;
190
 
                        }
191
 
                        break;
192
 
#else
193
 
                case SQL_DRIVER_PROMPT:
194
 
                case SQL_DRIVER_COMPLETE:
195
 
                case SQL_DRIVER_COMPLETE_REQUIRED:
196
 
#endif
197
 
                case SQL_DRIVER_NOPROMPT:
198
 
                        break;
199
 
        }
200
 
 
201
 
        /*
202
 
         * Password is not a required parameter unless authentication asks for
203
 
         * it. For now, I think it's better to just let the application ask
204
 
         * over and over until a password is entered (the user can always hit
205
 
         * Cancel to get out)
206
 
         */
207
 
        paramRequired = FALSE;
208
 
        if (ci->database[0] == '\0')
209
 
                paramRequired = TRUE;
210
 
        else if (ci->port[0] == '\0')
211
 
                paramRequired = TRUE;
212
 
#ifdef  WIN32
213
 
        else if (ci->server[0] == '\0')
214
 
                paramRequired = TRUE;
215
 
#endif /* WIN32 */
216
 
        if (paramRequired)
217
 
        {
218
 
                if (didUI)
219
 
                        return SQL_NO_DATA_FOUND;
220
 
                CC_set_error(conn, CONN_OPENDB_ERROR, "connction string lacks some options", func);
221
 
                return SQL_ERROR;
222
 
        }
223
 
 
224
 
inolog("before CC_connect\n");
225
 
        /* do the actual connect */
226
 
        retval = CC_connect(conn, password_required, salt);
227
 
        if (retval < 0)
228
 
        {                                                       /* need a password */
229
 
                if (fDriverCompletion == SQL_DRIVER_NOPROMPT)
230
 
                {
231
 
                        CC_log_error(func, "Need password but Driver_NoPrompt", conn);
232
 
                        return SQL_ERROR;       /* need a password but not allowed to
233
 
                                                                 * prompt so error */
234
 
                }
235
 
                else
236
 
                {
237
 
#ifdef WIN32
238
 
                        password_required = -retval;
239
 
                        goto dialog;
240
 
#else
241
 
                        return SQL_ERROR;       /* until a better solution is found. */
242
 
#endif
243
 
                }
244
 
        }
245
 
        else if (retval == 0)
246
 
        {
247
 
                /* error msg filled in above */
248
 
                CC_log_error(func, "Error from CC_Connect", conn);
249
 
                return SQL_ERROR;
250
 
        }
251
 
 
252
 
        /*
253
 
         * Create the Output Connection String
254
 
         */
255
 
        result = (1 == retval ? SQL_SUCCESS : SQL_SUCCESS_WITH_INFO);
256
 
 
257
 
        lenStrout = cbConnStrOutMax;
258
 
        if (conn->ms_jet && lenStrout > 255)
259
 
                lenStrout = 255;
260
 
        makeConnectString(connStrOut, ci, lenStrout);
261
 
        len = strlen(connStrOut);
262
 
 
263
 
        if (szConnStrOut)
264
 
        {
265
 
                /*
266
 
                 * Return the completed string to the caller. The correct method
267
 
                 * is to only construct the connect string if a dialog was put up,
268
 
                 * otherwise, it should just copy the connection input string to
269
 
                 * the output. However, it seems ok to just always construct an
270
 
                 * output string.  There are possible bad side effects on working
271
 
                 * applications (Access) by implementing the correct behavior,
272
 
                 * anyway.
273
 
                 */
274
 
                /*strncpy_null(szConnStrOut, connStrOut, cbConnStrOutMax);*/
275
 
                strncpy(szConnStrOut, connStrOut, cbConnStrOutMax);
276
 
 
277
 
                if (len >= cbConnStrOutMax)
278
 
                {
279
 
                        int                     clen;
280
 
 
281
 
                        for (clen = cbConnStrOutMax - 1; clen >= 0 && szConnStrOut[clen] != ';'; clen--)
282
 
                                szConnStrOut[clen] = '\0';
283
 
                        result = SQL_SUCCESS_WITH_INFO;
284
 
                        CC_set_error(conn, CONN_TRUNCATED, "The buffer was too small for the ConnStrOut.", func);
285
 
                }
286
 
        }
287
 
 
288
 
        if (pcbConnStrOut)
289
 
                *pcbConnStrOut = (SQLSMALLINT) len;
290
 
 
291
 
#ifdef  FORCE_PASSWORD_DISPLAY
292
 
        if (cbConnStrOutMax > 0)
293
 
        {
294
 
                mylog("szConnStrOut = '%s' len=%d,%d\n", NULL_IF_NULL(szConnStrOut), len, cbConnStrOutMax);
295
 
                qlog("conn=%p, PGAPI_DriverConnect(out)='%s'\n", conn, NULL_IF_NULL(szConnStrOut));
296
 
        }
297
 
#else
298
 
        if (get_qlog() || get_mylog())
299
 
        {
300
 
                char    *hide_str = NULL;
301
 
 
302
 
                if (cbConnStrOutMax > 0)
303
 
                        hide_str = hide_password(szConnStrOut);
304
 
                mylog("szConnStrOut = '%s' len=%d,%d\n", NULL_IF_NULL(hide_str), len, cbConnStrOutMax);
305
 
                qlog("conn=%p, PGAPI_DriverConnect(out)='%s'\n", conn, NULL_IF_NULL(hide_str));
306
 
                if (hide_str)
307
 
                        free(hide_str);
308
 
        }
309
 
#endif /* FORCE_PASSWORD_DISPLAY */
310
 
 
311
 
        if (connStrIn)
312
 
                free(connStrIn);
313
 
        mylog("PGAPI_DriverConnect: returning %d\n", result);
314
 
        return result;
315
 
}
316
 
 
317
 
 
318
 
#ifdef WIN32
319
 
RETCODE
320
 
dconn_DoDialog(HWND hwnd, ConnInfo *ci)
321
 
{
322
 
        LRESULT                 dialog_result;
323
 
 
324
 
        mylog("dconn_DoDialog: ci = %p\n", ci);
325
 
 
326
 
        if (hwnd)
327
 
        {
328
 
                dialog_result = DialogBoxParam(s_hModule, MAKEINTRESOURCE(DLG_CONFIG),
329
 
                                hwnd, dconn_FDriverConnectProc, (LPARAM) ci);
330
 
                if (!dialog_result || (dialog_result == -1))
331
 
                        return SQL_NO_DATA_FOUND;
332
 
                else
333
 
                        return SQL_SUCCESS;
334
 
        }
335
 
 
336
 
        return SQL_ERROR;
337
 
}
338
 
 
339
 
 
340
 
LRESULT CALLBACK
341
 
dconn_FDriverConnectProc(
342
 
                                                 HWND hdlg,
343
 
                                                 UINT wMsg,
344
 
                                                 WPARAM wParam,
345
 
                                                 LPARAM lParam)
346
 
{
347
 
        ConnInfo   *ci;
348
 
        char    strbuf[64];
349
 
 
350
 
        switch (wMsg)
351
 
        {
352
 
                case WM_INITDIALOG:
353
 
                        ci = (ConnInfo *) lParam;
354
 
 
355
 
                        /* Change the caption for the setup dialog */
356
 
                        SetWindowText(hdlg, "PostgreSQL Connection");
357
 
 
358
 
                        LoadString(s_hModule, IDS_ADVANCE_CONNECTION, strbuf, sizeof(strbuf));
359
 
                        SetWindowText(GetDlgItem(hdlg, IDC_DATASOURCE), strbuf);
360
 
 
361
 
                        /* Hide the DSN and description fields */
362
 
                        ShowWindow(GetDlgItem(hdlg, IDC_DSNAMETEXT), SW_HIDE);
363
 
                        ShowWindow(GetDlgItem(hdlg, IDC_DSNAME), SW_HIDE);
364
 
                        ShowWindow(GetDlgItem(hdlg, IDC_DESCTEXT), SW_HIDE);
365
 
                        ShowWindow(GetDlgItem(hdlg, IDC_DESC), SW_HIDE);
366
 
                        ShowWindow(GetDlgItem(hdlg, IDC_DRIVER), SW_HIDE);
367
 
                        ShowWindow(GetDlgItem(hdlg, IDC_TEST), SW_HIDE);
368
 
                        if ('\0' != ci->server[0])
369
 
                                EnableWindow(GetDlgItem(hdlg, IDC_SERVER), FALSE);
370
 
                        if ('\0' != ci->port[0])
371
 
                                EnableWindow(GetDlgItem(hdlg, IDC_PORT), FALSE);
372
 
 
373
 
                        SetWindowLongPtr(hdlg, DWLP_USER, lParam);              /* Save the ConnInfo for
374
 
                                                                                                                 * the "OK" */
375
 
                        SetDlgStuff(hdlg, ci);
376
 
 
377
 
                        if (ci->database[0] == '\0')
378
 
                                ;                               /* default focus */
379
 
                        else if (ci->server[0] == '\0')
380
 
                                SetFocus(GetDlgItem(hdlg, IDC_SERVER));
381
 
                        else if (ci->port[0] == '\0')
382
 
                                SetFocus(GetDlgItem(hdlg, IDC_PORT));
383
 
                        else if (ci->username[0] == '\0')
384
 
                                SetFocus(GetDlgItem(hdlg, IDC_USER));
385
 
                        else if (ci->focus_password)
386
 
                                SetFocus(GetDlgItem(hdlg, IDC_PASSWORD));
387
 
                        break;
388
 
 
389
 
                case WM_COMMAND:
390
 
                        switch (GET_WM_COMMAND_ID(wParam, lParam))
391
 
                        {
392
 
                                case IDOK:
393
 
                                        ci = (ConnInfo *) GetWindowLongPtr(hdlg, DWLP_USER);
394
 
 
395
 
                                        GetDlgStuff(hdlg, ci);
396
 
 
397
 
                                case IDCANCEL:
398
 
                                        EndDialog(hdlg, GET_WM_COMMAND_ID(wParam, lParam) == IDOK);
399
 
                                        return TRUE;
400
 
 
401
 
                                case IDC_DATASOURCE:
402
 
                                        ci = (ConnInfo *) GetWindowLongPtr(hdlg, DWLP_USER);
403
 
                                        DialogBoxParam(s_hModule, MAKEINTRESOURCE(DLG_OPTIONS_DRV),
404
 
                                                                   hdlg, ds_options1Proc, (LPARAM) ci);
405
 
                                        break;
406
 
 
407
 
                                case IDC_DRIVER:
408
 
                                        ci = (ConnInfo *) GetWindowLongPtr(hdlg, DWLP_USER);
409
 
                                        DialogBoxParam(s_hModule, MAKEINTRESOURCE(DLG_OPTIONS_DRV),
410
 
                                                                   hdlg, driver_optionsProc, (LPARAM) ci);
411
 
                                        break;
412
 
                        }
413
 
        }
414
 
 
415
 
        return FALSE;
416
 
}
417
 
#endif   /* WIN32 */
418
 
 
419
 
#define ATTRIBUTE_DELIMITER     ';'
420
 
#define OPENING_BRACKET         '{'
421
 
#define CLOSING_BRACKET         '}'
422
 
 
423
 
typedef BOOL (*copyfunc)(ConnInfo *, const char *attribute, const char *value);
424
 
static void
425
 
dconn_get_attributes(copyfunc func, const SQLCHAR FAR * connect_string, ConnInfo *ci)
426
 
{
427
 
        char    *our_connect_string;
428
 
        const   char    *pair,
429
 
                        *attribute,
430
 
                        *value,
431
 
                        *termp;
432
 
        BOOL    eoftok;
433
 
        char    *equals, *delp;
434
 
        char    *strtok_arg;
435
 
#ifdef  HAVE_STRTOK_R
436
 
        char    *last;
437
 
#endif /* HAVE_STRTOK_R */
438
 
 
439
 
        if (our_connect_string = strdup(connect_string), NULL == our_connect_string)
440
 
                return;
441
 
        strtok_arg = our_connect_string;
442
 
 
443
 
#ifdef  FORCE_PASSWORD_DISPLAY
444
 
        mylog("our_connect_string = '%s'\n", our_connect_string);
445
 
#else
446
 
        if (get_mylog())
447
 
        {
448
 
                char    *hide_str = hide_password(our_connect_string);
449
 
 
450
 
                mylog("our_connect_string = '%s'\n", hide_str);
451
 
                free(hide_str);
452
 
        }
453
 
#endif /* FORCE_PASSWORD_DISPLAY */
454
 
 
455
 
        termp = strchr(our_connect_string, '\0');
456
 
        eoftok = FALSE;
457
 
        while (!eoftok)
458
 
        {
459
 
#ifdef  HAVE_STRTOK_R
460
 
                pair = strtok_r(strtok_arg, ";", &last);
461
 
#else
462
 
                pair = strtok(strtok_arg, ";");
463
 
#endif /* HAVE_STRTOK_R */
464
 
                if (strtok_arg)
465
 
                        strtok_arg = NULL;
466
 
                if (!pair)
467
 
                        break;
468
 
 
469
 
                equals = strchr(pair, '=');
470
 
                if (!equals)
471
 
                        continue;
472
 
 
473
 
                *equals = '\0';
474
 
                attribute = pair;               /* ex. DSN */
475
 
                value = equals + 1;             /* ex. 'CEO co1' *
476
 
                /*
477
 
                 * Values enclosed with braces({}) can contain ; etc
478
 
                 * We don't remove the braces here because 
479
 
                 * decode_or_remove_braces() in dlg_specifi.c
480
 
                 * would remove them later.
481
 
                 * Just correct the misdetected delimter(;).  
482
 
                 */
483
 
                if (OPENING_BRACKET == *value)
484
 
                {
485
 
                        delp = strchr(value, '\0');
486
 
                        if (NULL == delp) continue; /* shouldn't occur */
487
 
                        if (delp == termp)
488
 
                        {
489
 
                                /* there's a corresponding closing bracket? */
490
 
                                if (CLOSING_BRACKET == delp[-1])
491
 
                                        eoftok = TRUE;
492
 
                        }
493
 
                        else
494
 
                        {
495
 
                                char    *closep;
496
 
 
497
 
                                /* Where's a corresponding closing bracket? */
498
 
                                closep = strchr(value, CLOSING_BRACKET);
499
 
                                if (NULL == closep)
500
 
                                {
501
 
                                        closep = strchr(delp + 1, CLOSING_BRACKET);
502
 
                                        if (NULL != closep) /* the delimiter is misdetected */
503
 
                                        {
504
 
                                                *delp = ATTRIBUTE_DELIMITER;
505
 
                                                strtok_arg = closep + 1;
506
 
                                                if (delp = strchr(closep + 1, ATTRIBUTE_DELIMITER), NULL != delp)
507
 
                                                {
508
 
                                                        *delp = '\0'; 
509
 
                                                        strtok_arg = delp + 1;
510
 
                                                }
511
 
                                                if (strtok_arg + 1 >= termp)
512
 
                                                        eoftok = TRUE;
513
 
                                        }
514
 
                                }
515
 
                        }
516
 
                }
517
 
 
518
 
#ifndef FORCE_PASSWORD_DISPLAY
519
 
                if (stricmp(attribute, INI_PASSWORD) == 0 ||
520
 
                    stricmp(attribute, "pwd") == 0)
521
 
                        mylog("attribute = '%s', value = 'xxxxx'\n", attribute);
522
 
                else
523
 
#endif /* FORCE_PASSWORD_DISPLAY */
524
 
                        mylog("attribute = '%s', value = '%s'\n", attribute, value);
525
 
 
526
 
                if (!attribute || !value)
527
 
                        continue;
528
 
 
529
 
                /* Copy the appropriate value to the conninfo  */
530
 
                (*func)(ci, attribute, value);
531
 
 
532
 
        }
533
 
 
534
 
        free(our_connect_string);
535
 
}
536
 
 
537
 
void
538
 
dconn_get_connect_attributes(const SQLCHAR FAR * connect_string, ConnInfo *ci)
539
 
{
540
 
 
541
 
        CC_conninfo_init(ci);
542
 
        dconn_get_attributes(copyAttributes, connect_string, ci);
543
 
}
544
 
 
545
 
static void
546
 
dconn_get_common_attributes(const SQLCHAR FAR * connect_string, ConnInfo *ci)
547
 
{
548
 
        dconn_get_attributes(copyCommonAttributes, connect_string, ci);
549
 
}
 
1
/*-------
 
2
  Module:                       drvconn.c
 
3
 *
 
4
 * Description:         This module contains only routines related to
 
5
 *                                      implementing SQLDriverConnect.
 
6
 *
 
7
 * Classes:                     n/a
 
8
 *
 
9
 * API functions:       SQLDriverConnect
 
10
 *
 
11
 * Comments:            See "readme.txt" for copyright and license information.
 
12
 *-------
 
13
 */
 
14
 
 
15
#include "psqlodbc.h"
 
16
 
 
17
#include <stdio.h>
 
18
#include <stdlib.h>
 
19
 
 
20
#include "connection.h"
 
21
#include "misc.h"
 
22
 
 
23
#ifndef WIN32
 
24
#include <sys/types.h>
 
25
#include <sys/socket.h>
 
26
#define NEAR
 
27
#else
 
28
#include <winsock2.h>
 
29
#endif
 
30
 
 
31
#include <string.h>
 
32
 
 
33
#ifdef WIN32
 
34
#include <windowsx.h>
 
35
#include "resource.h"
 
36
#endif
 
37
#include "pgapifunc.h"
 
38
 
 
39
#include "dlg_specific.h"
 
40
 
 
41
#define FORCE_PASSWORD_DISPLAY
 
42
#define NULL_IF_NULL(a) (a ? a : "(NULL)")
 
43
 
 
44
#ifndef FORCE_PASSWORD_DISPLAY
 
45
static char * hide_password(const char *str)
 
46
{
 
47
        char *outstr, *pwdp;
 
48
 
 
49
        if (!str)       return NULL;
 
50
        outstr = strdup(str);
 
51
        if (pwdp = strstr(outstr, "PWD="), !pwdp)
 
52
                pwdp = strstr(outstr, "pwd=");
 
53
        if (pwdp)
 
54
        {
 
55
                char    *p;
 
56
 
 
57
                for (p=pwdp + 4; *p && *p != ';'; p++)
 
58
                        *p = 'x';
 
59
        }
 
60
        return outstr;
 
61
}
 
62
#endif
 
63
 
 
64
/* prototypes */
 
65
static void dconn_get_connect_attributes(const char *connect_string, ConnInfo *ci);
 
66
static void dconn_get_common_attributes(const char *connect_string, ConnInfo *ci);
 
67
 
 
68
#ifdef WIN32
 
69
LRESULT CALLBACK dconn_FDriverConnectProc(HWND hdlg, UINT wMsg, WPARAM wParam, LPARAM lParam);
 
70
RETCODE         dconn_DoDialog(HWND hwnd, ConnInfo *ci);
 
71
 
 
72
extern HINSTANCE NEAR s_hModule;        /* Saved module handle. */
 
73
#endif
 
74
 
 
75
 
 
76
RETCODE         SQL_API
 
77
PGAPI_DriverConnect(HDBC hdbc,
 
78
                                        HWND hwnd,
 
79
                                        const SQLCHAR FAR * szConnStrIn,
 
80
                                        SQLSMALLINT cbConnStrIn,
 
81
                                        SQLCHAR FAR * szConnStrOut,
 
82
                                        SQLSMALLINT cbConnStrOutMax,
 
83
                                        SQLSMALLINT FAR * pcbConnStrOut,
 
84
                                        SQLUSMALLINT fDriverCompletion)
 
85
{
 
86
        CSTR func = "PGAPI_DriverConnect";
 
87
        ConnectionClass *conn = (ConnectionClass *) hdbc;
 
88
        ConnInfo   *ci;
 
89
 
 
90
#ifdef WIN32
 
91
        RETCODE         dialog_result;
 
92
#endif
 
93
        BOOL            paramRequired, didUI = FALSE;
 
94
        RETCODE         result;
 
95
        char            *connStrIn = NULL;
 
96
        char            connStrOut[MAX_CONNECT_STRING];
 
97
        int                     retval;
 
98
        char            salt[5];
 
99
        char            password_required = AUTH_REQ_OK;
 
100
        ssize_t         len = 0;
 
101
        SQLSMALLINT     lenStrout;
 
102
 
 
103
 
 
104
        mylog("%s: entering...\n", func);
 
105
 
 
106
        if (!conn)
 
107
        {
 
108
                CC_log_error(func, "", NULL);
 
109
                return SQL_INVALID_HANDLE;
 
110
        }
 
111
 
 
112
        connStrIn = make_string(szConnStrIn, cbConnStrIn, NULL, 0);
 
113
 
 
114
#ifdef  FORCE_PASSWORD_DISPLAY
 
115
        mylog("**** PGAPI_DriverConnect: fDriverCompletion=%d, connStrIn='%s'\n", fDriverCompletion, connStrIn);
 
116
        qlog("conn=%p, PGAPI_DriverConnect( in)='%s', fDriverCompletion=%d\n", conn, connStrIn, fDriverCompletion);
 
117
#else
 
118
        if (get_qlog() || get_mylog())
 
119
        {
 
120
                char    *hide_str = hide_password(connStrIn);
 
121
 
 
122
                mylog("**** PGAPI_DriverConnect: fDriverCompletion=%d, connStrIn='%s'\n", fDriverCompletion, NULL_IF_NULL(hide_str));
 
123
                qlog("conn=%p, PGAPI_DriverConnect( in)='%s', fDriverCompletion=%d\n", conn, NULL_IF_NULL(hide_str), fDriverCompletion);
 
124
                if (hide_str)
 
125
                        free(hide_str);
 
126
        }
 
127
#endif  /* FORCE_PASSWORD_DISPLAY */
 
128
 
 
129
        ci = &(conn->connInfo);
 
130
 
 
131
        /* Parse the connect string and fill in conninfo for this hdbc. */
 
132
        dconn_get_connect_attributes(connStrIn, ci);
 
133
 
 
134
        /*
 
135
         * If the ConnInfo in the hdbc is missing anything, this function will
 
136
         * fill them in from the registry (assuming of course there is a DSN
 
137
         * given -- if not, it does nothing!)
 
138
         */
 
139
        getDSNinfo(ci, CONN_DONT_OVERWRITE);
 
140
        dconn_get_common_attributes(connStrIn, ci);
 
141
        logs_on_off(1, ci->drivers.debug, ci->drivers.commlog);
 
142
        if (connStrIn)
 
143
        {
 
144
                free(connStrIn);
 
145
                connStrIn = NULL;
 
146
        }
 
147
 
 
148
        /* Fill in any default parameters if they are not there. */
 
149
        getDSNdefaults(ci);
 
150
        /* initialize pg_version */
 
151
        CC_initialize_pg_version(conn);
 
152
        memset(salt, 0, sizeof(salt));
 
153
 
 
154
#ifdef WIN32
 
155
dialog:
 
156
#endif
 
157
        ci->focus_password = password_required;
 
158
 
 
159
inolog("DriverCompletion=%d\n", fDriverCompletion);
 
160
        switch (fDriverCompletion)
 
161
        {
 
162
#ifdef WIN32
 
163
                case SQL_DRIVER_PROMPT:
 
164
                        dialog_result = dconn_DoDialog(hwnd, ci);
 
165
                        didUI = TRUE;
 
166
                        if (dialog_result != SQL_SUCCESS)
 
167
                                return dialog_result;
 
168
                        break;
 
169
 
 
170
                case SQL_DRIVER_COMPLETE_REQUIRED:
 
171
 
 
172
                        /* Fall through */
 
173
 
 
174
                case SQL_DRIVER_COMPLETE:
 
175
 
 
176
                        paramRequired = password_required;
 
177
                        /* Password is not a required parameter. */
 
178
                        if (ci->database[0] == '\0')
 
179
                                paramRequired = TRUE;
 
180
                        else if (ci->port[0] == '\0')
 
181
                                paramRequired = TRUE;
 
182
#ifdef  WIN32
 
183
                        else if (ci->server[0] == '\0')
 
184
                                paramRequired = TRUE;
 
185
#endif /* WIN32 */
 
186
                        if (paramRequired)
 
187
                        {
 
188
                                dialog_result = dconn_DoDialog(hwnd, ci);
 
189
                                didUI = TRUE;
 
190
                                if (dialog_result != SQL_SUCCESS)
 
191
                                        return dialog_result;
 
192
                        }
 
193
                        break;
 
194
#else
 
195
                case SQL_DRIVER_PROMPT:
 
196
                case SQL_DRIVER_COMPLETE:
 
197
                case SQL_DRIVER_COMPLETE_REQUIRED:
 
198
#endif
 
199
                case SQL_DRIVER_NOPROMPT:
 
200
                        break;
 
201
        }
 
202
 
 
203
        /*
 
204
         * Password is not a required parameter unless authentication asks for
 
205
         * it. For now, I think it's better to just let the application ask
 
206
         * over and over until a password is entered (the user can always hit
 
207
         * Cancel to get out)
 
208
         */
 
209
        paramRequired = FALSE;
 
210
        if (ci->database[0] == '\0')
 
211
                paramRequired = TRUE;
 
212
        else if (ci->port[0] == '\0')
 
213
                paramRequired = TRUE;
 
214
#ifdef  WIN32
 
215
        else if (ci->server[0] == '\0')
 
216
                paramRequired = TRUE;
 
217
#endif /* WIN32 */
 
218
        if (paramRequired)
 
219
        {
 
220
                if (didUI)
 
221
                        return SQL_NO_DATA_FOUND;
 
222
                CC_set_error(conn, CONN_OPENDB_ERROR, "connction string lacks some options", func);
 
223
                return SQL_ERROR;
 
224
        }
 
225
 
 
226
inolog("before CC_connect\n");
 
227
        /* do the actual connect */
 
228
        retval = CC_connect(conn, password_required, salt);
 
229
        if (retval < 0)
 
230
        {                                                       /* need a password */
 
231
                if (fDriverCompletion == SQL_DRIVER_NOPROMPT)
 
232
                {
 
233
                        CC_log_error(func, "Need password but Driver_NoPrompt", conn);
 
234
                        return SQL_ERROR;       /* need a password but not allowed to
 
235
                                                                 * prompt so error */
 
236
                }
 
237
                else
 
238
                {
 
239
#ifdef WIN32
 
240
                        password_required = -retval;
 
241
                        goto dialog;
 
242
#else
 
243
                        return SQL_ERROR;       /* until a better solution is found. */
 
244
#endif
 
245
                }
 
246
        }
 
247
        else if (retval == 0)
 
248
        {
 
249
                /* error msg filled in above */
 
250
                CC_log_error(func, "Error from CC_Connect", conn);
 
251
                return SQL_ERROR;
 
252
        }
 
253
 
 
254
        /*
 
255
         * Create the Output Connection String
 
256
         */
 
257
        result = (1 == retval ? SQL_SUCCESS : SQL_SUCCESS_WITH_INFO);
 
258
 
 
259
        lenStrout = cbConnStrOutMax;
 
260
        if (conn->ms_jet && lenStrout > 255)
 
261
                lenStrout = 255;
 
262
        makeConnectString(connStrOut, ci, lenStrout);
 
263
        len = strlen(connStrOut);
 
264
 
 
265
        if (szConnStrOut)
 
266
        {
 
267
                /*
 
268
                 * Return the completed string to the caller. The correct method
 
269
                 * is to only construct the connect string if a dialog was put up,
 
270
                 * otherwise, it should just copy the connection input string to
 
271
                 * the output. However, it seems ok to just always construct an
 
272
                 * output string.  There are possible bad side effects on working
 
273
                 * applications (Access) by implementing the correct behavior,
 
274
                 * anyway.
 
275
                 */
 
276
                /*strncpy_null(szConnStrOut, connStrOut, cbConnStrOutMax);*/
 
277
                strncpy((char *) szConnStrOut, connStrOut, cbConnStrOutMax);
 
278
 
 
279
                if (len >= cbConnStrOutMax)
 
280
                {
 
281
                        int                     clen;
 
282
 
 
283
                        for (clen = cbConnStrOutMax - 1; clen >= 0 && szConnStrOut[clen] != ';'; clen--)
 
284
                                szConnStrOut[clen] = '\0';
 
285
                        result = SQL_SUCCESS_WITH_INFO;
 
286
                        CC_set_error(conn, CONN_TRUNCATED, "The buffer was too small for the ConnStrOut.", func);
 
287
                }
 
288
        }
 
289
 
 
290
        if (pcbConnStrOut)
 
291
                *pcbConnStrOut = (SQLSMALLINT) len;
 
292
 
 
293
#ifdef  FORCE_PASSWORD_DISPLAY
 
294
        if (cbConnStrOutMax > 0)
 
295
        {
 
296
                mylog("szConnStrOut = '%s' len=%d,%d\n", NULL_IF_NULL((char *) szConnStrOut), len, cbConnStrOutMax);
 
297
                qlog("conn=%p, PGAPI_DriverConnect(out)='%s'\n", conn, NULL_IF_NULL((char *) szConnStrOut));
 
298
        }
 
299
#else
 
300
        if (get_qlog() || get_mylog())
 
301
        {
 
302
                char    *hide_str = NULL;
 
303
 
 
304
                if (cbConnStrOutMax > 0)
 
305
                        hide_str = hide_password(szConnStrOut);
 
306
                mylog("szConnStrOut = '%s' len=%d,%d\n", NULL_IF_NULL(hide_str), len, cbConnStrOutMax);
 
307
                qlog("conn=%p, PGAPI_DriverConnect(out)='%s'\n", conn, NULL_IF_NULL(hide_str));
 
308
                if (hide_str)
 
309
                        free(hide_str);
 
310
        }
 
311
#endif /* FORCE_PASSWORD_DISPLAY */
 
312
 
 
313
        if (connStrIn)
 
314
                free(connStrIn);
 
315
        mylog("PGAPI_DriverConnect: returning %d\n", result);
 
316
        return result;
 
317
}
 
318
 
 
319
 
 
320
#ifdef WIN32
 
321
RETCODE
 
322
dconn_DoDialog(HWND hwnd, ConnInfo *ci)
 
323
{
 
324
        LRESULT                 dialog_result;
 
325
 
 
326
        mylog("dconn_DoDialog: ci = %p\n", ci);
 
327
 
 
328
        if (hwnd)
 
329
        {
 
330
                dialog_result = DialogBoxParam(s_hModule, MAKEINTRESOURCE(DLG_CONFIG),
 
331
                                hwnd, dconn_FDriverConnectProc, (LPARAM) ci);
 
332
                if (!dialog_result || (dialog_result == -1))
 
333
                        return SQL_NO_DATA_FOUND;
 
334
                else
 
335
                        return SQL_SUCCESS;
 
336
        }
 
337
 
 
338
        return SQL_ERROR;
 
339
}
 
340
 
 
341
 
 
342
LRESULT CALLBACK
 
343
dconn_FDriverConnectProc(
 
344
                                                 HWND hdlg,
 
345
                                                 UINT wMsg,
 
346
                                                 WPARAM wParam,
 
347
                                                 LPARAM lParam)
 
348
{
 
349
        ConnInfo   *ci;
 
350
        char    strbuf[64];
 
351
 
 
352
        switch (wMsg)
 
353
        {
 
354
                case WM_INITDIALOG:
 
355
                        ci = (ConnInfo *) lParam;
 
356
 
 
357
                        /* Change the caption for the setup dialog */
 
358
                        SetWindowText(hdlg, "PostgreSQL Connection");
 
359
 
 
360
                        LoadString(s_hModule, IDS_ADVANCE_CONNECTION, strbuf, sizeof(strbuf));
 
361
                        SetWindowText(GetDlgItem(hdlg, IDC_DATASOURCE), strbuf);
 
362
 
 
363
                        /* Hide the DSN and description fields */
 
364
                        ShowWindow(GetDlgItem(hdlg, IDC_DSNAMETEXT), SW_HIDE);
 
365
                        ShowWindow(GetDlgItem(hdlg, IDC_DSNAME), SW_HIDE);
 
366
                        ShowWindow(GetDlgItem(hdlg, IDC_DESCTEXT), SW_HIDE);
 
367
                        ShowWindow(GetDlgItem(hdlg, IDC_DESC), SW_HIDE);
 
368
                        ShowWindow(GetDlgItem(hdlg, IDC_DRIVER), SW_HIDE);
 
369
                        ShowWindow(GetDlgItem(hdlg, IDC_TEST), SW_HIDE);
 
370
                        if ('\0' != ci->server[0])
 
371
                                EnableWindow(GetDlgItem(hdlg, IDC_SERVER), FALSE);
 
372
                        if ('\0' != ci->port[0])
 
373
                                EnableWindow(GetDlgItem(hdlg, IDC_PORT), FALSE);
 
374
 
 
375
                        SetWindowLongPtr(hdlg, DWLP_USER, lParam);              /* Save the ConnInfo for
 
376
                                                                                                                 * the "OK" */
 
377
                        SetDlgStuff(hdlg, ci);
 
378
 
 
379
                        if (ci->database[0] == '\0')
 
380
                                ;                               /* default focus */
 
381
                        else if (ci->server[0] == '\0')
 
382
                                SetFocus(GetDlgItem(hdlg, IDC_SERVER));
 
383
                        else if (ci->port[0] == '\0')
 
384
                                SetFocus(GetDlgItem(hdlg, IDC_PORT));
 
385
                        else if (ci->username[0] == '\0')
 
386
                                SetFocus(GetDlgItem(hdlg, IDC_USER));
 
387
                        else if (ci->focus_password)
 
388
                                SetFocus(GetDlgItem(hdlg, IDC_PASSWORD));
 
389
                        break;
 
390
 
 
391
                case WM_COMMAND:
 
392
                        switch (GET_WM_COMMAND_ID(wParam, lParam))
 
393
                        {
 
394
                                case IDOK:
 
395
                                        ci = (ConnInfo *) GetWindowLongPtr(hdlg, DWLP_USER);
 
396
 
 
397
                                        GetDlgStuff(hdlg, ci);
 
398
 
 
399
                                case IDCANCEL:
 
400
                                        EndDialog(hdlg, GET_WM_COMMAND_ID(wParam, lParam) == IDOK);
 
401
                                        return TRUE;
 
402
 
 
403
                                case IDC_DATASOURCE:
 
404
                                        ci = (ConnInfo *) GetWindowLongPtr(hdlg, DWLP_USER);
 
405
                                        DialogBoxParam(s_hModule, MAKEINTRESOURCE(DLG_OPTIONS_DRV),
 
406
                                                                   hdlg, ds_options1Proc, (LPARAM) ci);
 
407
                                        break;
 
408
 
 
409
                                case IDC_DRIVER:
 
410
                                        ci = (ConnInfo *) GetWindowLongPtr(hdlg, DWLP_USER);
 
411
                                        DialogBoxParam(s_hModule, MAKEINTRESOURCE(DLG_OPTIONS_DRV),
 
412
                                                                   hdlg, driver_optionsProc, (LPARAM) ci);
 
413
                                        break;
 
414
                        }
 
415
        }
 
416
 
 
417
        return FALSE;
 
418
}
 
419
#endif   /* WIN32 */
 
420
 
 
421
#define ATTRIBUTE_DELIMITER     ';'
 
422
#define OPENING_BRACKET         '{'
 
423
#define CLOSING_BRACKET         '}'
 
424
 
 
425
typedef BOOL (*copyfunc)(ConnInfo *, const char *attribute, const char *value);
 
426
static void
 
427
dconn_get_attributes(copyfunc func, const char *connect_string, ConnInfo *ci)
 
428
{
 
429
        char    *our_connect_string;
 
430
        const   char    *pair,
 
431
                        *attribute,
 
432
                        *value,
 
433
                        *termp;
 
434
        BOOL    eoftok;
 
435
        char    *equals, *delp;
 
436
        char    *strtok_arg;
 
437
#ifdef  HAVE_STRTOK_R
 
438
        char    *last;
 
439
#endif /* HAVE_STRTOK_R */
 
440
 
 
441
        if (our_connect_string = strdup(connect_string), NULL == our_connect_string)
 
442
                return;
 
443
        strtok_arg = our_connect_string;
 
444
 
 
445
#ifdef  FORCE_PASSWORD_DISPLAY
 
446
        mylog("our_connect_string = '%s'\n", our_connect_string);
 
447
#else
 
448
        if (get_mylog())
 
449
        {
 
450
                char    *hide_str = hide_password(our_connect_string);
 
451
 
 
452
                mylog("our_connect_string = '%s'\n", hide_str);
 
453
                free(hide_str);
 
454
        }
 
455
#endif /* FORCE_PASSWORD_DISPLAY */
 
456
 
 
457
        termp = strchr(our_connect_string, '\0');
 
458
        eoftok = FALSE;
 
459
        while (!eoftok)
 
460
        {
 
461
#ifdef  HAVE_STRTOK_R
 
462
                pair = strtok_r(strtok_arg, ";", &last);
 
463
#else
 
464
                pair = strtok(strtok_arg, ";");
 
465
#endif /* HAVE_STRTOK_R */
 
466
                if (strtok_arg)
 
467
                        strtok_arg = NULL;
 
468
                if (!pair)
 
469
                        break;
 
470
 
 
471
                equals = strchr(pair, '=');
 
472
                if (!equals)
 
473
                        continue;
 
474
 
 
475
                *equals = '\0';
 
476
                attribute = pair;               /* ex. DSN */
 
477
                value = equals + 1;             /* ex. 'CEO co1' */
 
478
                /*
 
479
                 * Values enclosed with braces({}) can contain ; etc
 
480
                 * We don't remove the braces here because
 
481
                 * decode_or_remove_braces() in dlg_specifi.c
 
482
                 * would remove them later.
 
483
                 * Just correct the misdetected delimter(;).
 
484
                 */
 
485
                if (OPENING_BRACKET == *value)
 
486
                {
 
487
                        delp = strchr(value, '\0');
 
488
                        if (NULL == delp) continue; /* shouldn't occur */
 
489
                        if (delp == termp)
 
490
                        {
 
491
                                /* there's a corresponding closing bracket? */
 
492
                                if (CLOSING_BRACKET == delp[-1])
 
493
                                        eoftok = TRUE;
 
494
                        }
 
495
                        else
 
496
                        {
 
497
                                char    *closep;
 
498
 
 
499
                                /* Where's a corresponding closing bracket? */
 
500
                                closep = strchr(value, CLOSING_BRACKET);
 
501
                                if (NULL == closep)
 
502
                                {
 
503
                                        closep = strchr(delp + 1, CLOSING_BRACKET);
 
504
                                        if (NULL != closep) /* the delimiter is misdetected */
 
505
                                        {
 
506
                                                *delp = ATTRIBUTE_DELIMITER;
 
507
                                                strtok_arg = closep + 1;
 
508
                                                if (delp = strchr(closep + 1, ATTRIBUTE_DELIMITER), NULL != delp)
 
509
                                                {
 
510
                                                        *delp = '\0';
 
511
                                                        strtok_arg = delp + 1;
 
512
                                                }
 
513
                                                if (strtok_arg + 1 >= termp)
 
514
                                                        eoftok = TRUE;
 
515
                                        }
 
516
                                }
 
517
                        }
 
518
                }
 
519
 
 
520
#ifndef FORCE_PASSWORD_DISPLAY
 
521
                if (stricmp(attribute, INI_PASSWORD) == 0 ||
 
522
                    stricmp(attribute, "pwd") == 0)
 
523
                        mylog("attribute = '%s', value = 'xxxxx'\n", attribute);
 
524
                else
 
525
#endif /* FORCE_PASSWORD_DISPLAY */
 
526
                        mylog("attribute = '%s', value = '%s'\n", attribute, value);
 
527
 
 
528
                if (!attribute || !value)
 
529
                        continue;
 
530
 
 
531
                /* Copy the appropriate value to the conninfo  */
 
532
                (*func)(ci, attribute, value);
 
533
 
 
534
        }
 
535
 
 
536
        free(our_connect_string);
 
537
}
 
538
 
 
539
static void
 
540
dconn_get_connect_attributes(const char *connect_string, ConnInfo *ci)
 
541
{
 
542
 
 
543
        CC_conninfo_init(ci, COPY_GLOBALS);
 
544
        dconn_get_attributes(copyAttributes, connect_string, ci);
 
545
}
 
546
 
 
547
static void
 
548
dconn_get_common_attributes(const char *connect_string, ConnInfo *ci)
 
549
{
 
550
        dconn_get_attributes(copyCommonAttributes, connect_string, ci);
 
551
}