PageRenderTime 31ms CodeModel.GetById 20ms RepoModel.GetById 0ms app.codeStats 0ms

/vxodbc/drvconn.cc

http://versaplex.googlecode.com/
C++ | 521 lines | 399 code | 82 blank | 40 comment | 95 complexity | ea0be271b1b6ff61f28facb1e96fa583 MD5 | raw file
Possible License(s): LGPL-2.0
  1. /*
  2. * Description: This module contains only routines related to
  3. * implementing SQLDriverConnect.
  4. */
  5. #include "psqlodbc.h"
  6. #include <stdio.h>
  7. #include <stdlib.h>
  8. #include <string.h>
  9. #include "connection.h"
  10. #ifndef WIN32
  11. #include <sys/types.h>
  12. #include <sys/socket.h>
  13. #define NEAR
  14. #else
  15. #include <winsock2.h>
  16. #endif
  17. #include <string.h>
  18. #ifdef WIN32
  19. #include <windowsx.h>
  20. #include "resource.h"
  21. #endif
  22. #include "pgapifunc.h"
  23. #include "wvdbusconn.h"
  24. #include "dlg_specific.h"
  25. #define NULL_IF_NULL(a) (a ? a : "(NULL)")
  26. static char *hide_password(const char *str)
  27. {
  28. char *outstr, *pwdp;
  29. if (!str)
  30. return NULL;
  31. outstr = strdup(str);
  32. if (pwdp = strstr(outstr, "PWD="), !pwdp)
  33. pwdp = strstr(outstr, "pwd=");
  34. if (pwdp)
  35. {
  36. char *p;
  37. for (p = pwdp + 4; *p && *p != ';'; p++)
  38. *p = 'x';
  39. }
  40. return outstr;
  41. }
  42. /* prototypes */
  43. void dconn_get_connect_attributes(const SQLCHAR FAR * connect_string,
  44. ConnInfo * ci);
  45. static void dconn_get_common_attributes(const SQLCHAR FAR *
  46. connect_string, ConnInfo * ci);
  47. #ifdef WIN32
  48. #ifdef __cplusplus
  49. extern "C" {
  50. #endif
  51. BOOL CALLBACK dconn_FDriverConnectProc(HWND hdlg, UINT wMsg,
  52. WPARAM wParam, LPARAM lParam);
  53. RETCODE dconn_DoDialog(HWND hwnd, ConnInfo* ci);
  54. #ifdef __cplusplus
  55. }
  56. #endif
  57. extern HINSTANCE NEAR s_hModule; /* Saved module handle. */
  58. #endif
  59. RETCODE SQL_API
  60. PGAPI_DriverConnect(HDBC hdbc,
  61. HWND hwnd,
  62. const SQLCHAR FAR * szConnStrIn,
  63. SQLSMALLINT cbConnStrIn,
  64. SQLCHAR FAR * szConnStrOut,
  65. SQLSMALLINT cbConnStrOutMax,
  66. SQLSMALLINT FAR * pcbConnStrOut,
  67. SQLUSMALLINT fDriverCompletion)
  68. {
  69. CSTR func = "PGAPI_DriverConnect";
  70. ConnectionClass *conn = (ConnectionClass *) hdbc;
  71. ConnInfo *ci;
  72. #ifdef WIN32
  73. RETCODE dialog_result;
  74. #endif
  75. BOOL paramRequired, didUI = FALSE;
  76. RETCODE result;
  77. char *connStrIn = NULL;
  78. char connStrOut[MAX_CONNECT_STRING];
  79. int retval;
  80. char salt[5];
  81. char password_required = AUTH_REQ_OK;
  82. ssize_t len = 0;
  83. SQLSMALLINT lenStrout;
  84. mylog("%s: entering...\n", func);
  85. if (!conn)
  86. {
  87. CC_log_error(func, "", NULL);
  88. return SQL_INVALID_HANDLE;
  89. }
  90. connStrIn = make_string(szConnStrIn, cbConnStrIn, NULL, 0);
  91. #ifdef FORCE_PASSWORD_DISPLAY
  92. mylog
  93. ("**** PGAPI_DriverConnect: fDriverCompletion=%d, connStrIn='%s'\n",
  94. fDriverCompletion, connStrIn);
  95. qlog("conn=%p, PGAPI_DriverConnect( in)='%s', fDriverCompletion=%d\n", conn, connStrIn, fDriverCompletion);
  96. #else
  97. if (get_qlog() || get_mylog())
  98. {
  99. char *hide_str = hide_password(connStrIn);
  100. mylog
  101. ("**** PGAPI_DriverConnect: fDriverCompletion=%d, connStrIn='%s'\n",
  102. fDriverCompletion, NULL_IF_NULL(hide_str));
  103. qlog("conn=%p, PGAPI_DriverConnect( in)='%s', fDriverCompletion=%d\n", conn, NULL_IF_NULL(hide_str), fDriverCompletion);
  104. if (hide_str)
  105. free(hide_str);
  106. }
  107. #endif /* FORCE_PASSWORD_DISPLAY */
  108. ci = &(conn->connInfo);
  109. /* Parse the connect string and fill in conninfo for this hdbc. */
  110. dconn_get_connect_attributes((const UCHAR *)connStrIn, ci);
  111. bool dbus_provided = ci->dbus_moniker != NULL && ci->dbus_moniker[0] != '\0';
  112. /*
  113. * If the ConnInfo in the hdbc is missing anything, this function will
  114. * fill them in from the registry (assuming of course there is a DSN
  115. * given -- if not, it does nothing!)
  116. */
  117. getDSNinfo(ci, CONN_DONT_OVERWRITE);
  118. dconn_get_common_attributes((const UCHAR *)connStrIn, ci);
  119. logs_on_off(1, TRUE, TRUE);
  120. if (connStrIn)
  121. {
  122. free(connStrIn);
  123. connStrIn = NULL;
  124. }
  125. /* Fill in any default parameters if they are not there. */
  126. getDSNdefaults(ci);
  127. CC_initialize_pg_version(conn);
  128. memset(salt, 0, sizeof(salt));
  129. ci->focus_password = password_required;
  130. inolog("DriverCompletion=%d\n", fDriverCompletion);
  131. switch (fDriverCompletion)
  132. {
  133. #ifdef WIN32
  134. case SQL_DRIVER_PROMPT:
  135. dialog_result = dconn_DoDialog(hwnd, ci);
  136. didUI = TRUE;
  137. if (dialog_result != SQL_SUCCESS)
  138. return dialog_result;
  139. break;
  140. case SQL_DRIVER_COMPLETE_REQUIRED:
  141. /* Fall through */
  142. case SQL_DRIVER_COMPLETE:
  143. paramRequired = password_required;
  144. /* Password is not a required parameter. */
  145. if (ci->database[0] == '\0')
  146. paramRequired = TRUE;
  147. else if (!dbus_provided && ci->port[0] == '\0')
  148. paramRequired = TRUE;
  149. #ifdef WIN32
  150. else if (!dbus_provided && ci->server[0] == '\0')
  151. paramRequired = TRUE;
  152. #endif /* WIN32 */
  153. if (paramRequired)
  154. {
  155. dialog_result = dconn_DoDialog(hwnd, ci);
  156. didUI = TRUE;
  157. if (dialog_result != SQL_SUCCESS)
  158. return dialog_result;
  159. }
  160. break;
  161. #else
  162. case SQL_DRIVER_PROMPT:
  163. case SQL_DRIVER_COMPLETE:
  164. case SQL_DRIVER_COMPLETE_REQUIRED:
  165. #endif
  166. case SQL_DRIVER_NOPROMPT:
  167. break;
  168. }
  169. /*
  170. * Password is not a required parameter unless authentication asks for
  171. * it. For now, I think it's better to just let the application ask
  172. * over and over until a password is entered (the user can always hit
  173. * Cancel to get out)
  174. */
  175. paramRequired = FALSE;
  176. WvString missingoptions = "Connection string lacks options: ";
  177. if (ci->database[0] == '\0')
  178. {
  179. paramRequired = TRUE;
  180. missingoptions.append("'database' ");
  181. }
  182. else if (!dbus_provided && ci->port[0] == '\0')
  183. {
  184. paramRequired = TRUE;
  185. missingoptions.append("'port' ");
  186. }
  187. else if (!dbus_provided && ci->server[0] == '\0')
  188. {
  189. paramRequired = TRUE;
  190. missingoptions.append("'server' ");
  191. }
  192. if (!dbus_provided)
  193. {
  194. missingoptions.append("'dbus connection' ");
  195. }
  196. if (paramRequired)
  197. {
  198. if (didUI)
  199. return SQL_NO_DATA_FOUND;
  200. CC_set_error(conn, CONN_OPENDB_ERROR,
  201. missingoptions, func);
  202. return SQL_ERROR;
  203. }
  204. if (!dbus_provided)
  205. {
  206. // If we weren't provided with a pre-made DBus moniker, use the
  207. // provided server and port. If we weren't provided with those
  208. // either, we'll have already returned an error above.
  209. WvString moniker("dbus:tcp:host=%s,port=%s", ci->server, ci->port);
  210. mylog("Moniker=%s\n", moniker.cstr());
  211. if (moniker.len() < sizeof(ci->dbus_moniker))
  212. strncpy(ci->dbus_moniker, moniker.cstr(), sizeof(ci->dbus_moniker));
  213. else
  214. {
  215. CC_set_error(conn, CONN_OPENDB_ERROR,
  216. "The DBus connection moniker was too long.", func);
  217. return SQL_ERROR;
  218. }
  219. }
  220. mylog("PGAPI_DriverConnect making DBus connection to %s\n",
  221. ci->dbus_moniker);
  222. mylog("dbus:session is '%s'\n", getenv("DBUS_SESSION_BUS_ADDRESS"));
  223. conn->dbus = new WvDBusConn(ci->dbus_moniker);
  224. WvDBusMsg reply = conn->dbus->send_and_wait
  225. (WvDBusMsg("com.versabanq.versaplex", "/com/versabanq/versaplex",
  226. "com.versabanq.versaplex.db", "Test"),
  227. 15000);
  228. if (!conn->dbus->isok())
  229. {
  230. CC_set_error(conn, CONN_OPENDB_ERROR, WvString(
  231. "Could not open DBus connection to %s: %s (%s).",
  232. ci->dbus_moniker,
  233. conn->dbus->errstr(), conn->dbus->geterr()).cstr(),
  234. func);
  235. return SQL_ERROR;
  236. }
  237. if (reply.iserror())
  238. {
  239. WvDBusMsg::Iter i(reply);
  240. WvString errstr = i.getnext();
  241. CC_set_error(conn, CONN_OPENDB_ERROR, WvString(
  242. "DBus connected, but test failed: %s. Is versaplexd running?",
  243. errstr).cstr(),
  244. func);
  245. return SQL_ERROR;
  246. }
  247. /*
  248. * Create the Output Connection String
  249. */
  250. result = SQL_SUCCESS;
  251. lenStrout = cbConnStrOutMax;
  252. if (conn->ms_jet && lenStrout > 255)
  253. lenStrout = 255;
  254. makeConnectString(connStrOut, ci, lenStrout);
  255. len = strlen(connStrOut);
  256. if (szConnStrOut)
  257. {
  258. /*
  259. * Return the completed string to the caller. The correct method
  260. * is to only construct the connect string if a dialog was put up,
  261. * otherwise, it should just copy the connection input string to
  262. * the output. However, it seems ok to just always construct an
  263. * output string. There are possible bad side effects on working
  264. * applications (Access) by implementing the correct behavior,
  265. * anyway.
  266. */
  267. /*strncpy_null(szConnStrOut, connStrOut, cbConnStrOutMax); */
  268. strncpy((char *)szConnStrOut, connStrOut, cbConnStrOutMax);
  269. if (len >= cbConnStrOutMax)
  270. {
  271. int clen;
  272. for (clen = cbConnStrOutMax - 1;
  273. clen >= 0 && szConnStrOut[clen] != ';'; clen--)
  274. szConnStrOut[clen] = '\0';
  275. result = SQL_SUCCESS_WITH_INFO;
  276. CC_set_error(conn, CONN_TRUNCATED,
  277. "The buffer was too small for the ConnStrOut.",
  278. func);
  279. }
  280. }
  281. if (pcbConnStrOut)
  282. *pcbConnStrOut = (SQLSMALLINT) len;
  283. #ifdef FORCE_PASSWORD_DISPLAY
  284. if (cbConnStrOutMax > 0)
  285. {
  286. mylog("szConnStrOut = '%s' len=%d,%d\n",
  287. NULL_IF_NULL(szConnStrOut), len, cbConnStrOutMax);
  288. qlog("conn=%p, PGAPI_DriverConnect(out)='%s'\n", conn,
  289. NULL_IF_NULL(szConnStrOut));
  290. }
  291. #else
  292. if (get_qlog() || get_mylog())
  293. {
  294. char *hide_str = NULL;
  295. if (cbConnStrOutMax > 0)
  296. hide_str = hide_password((const char *)szConnStrOut);
  297. mylog("szConnStrOut = '%s' len=%d,%d\n", NULL_IF_NULL(hide_str),
  298. len, cbConnStrOutMax);
  299. qlog("conn=%p, PGAPI_DriverConnect(out)='%s'\n", conn,
  300. NULL_IF_NULL(hide_str));
  301. if (hide_str)
  302. free(hide_str);
  303. }
  304. #endif /* FORCE_PASSWORD_DISPLAY */
  305. if (connStrIn)
  306. free(connStrIn);
  307. mylog("PGAPI_DriverConnect: returning %d\n", result);
  308. return result;
  309. }
  310. #ifdef WIN32
  311. RETCODE dconn_DoDialog(HWND hwnd, ConnInfo * ci)
  312. {
  313. LRESULT dialog_result;
  314. mylog("dconn_DoDialog: ci = %p\n", ci);
  315. if (hwnd)
  316. {
  317. dialog_result =
  318. DialogBoxParam(s_hModule, MAKEINTRESOURCE(DLG_CONFIG), hwnd,
  319. dconn_FDriverConnectProc, (LPARAM) ci);
  320. if (!dialog_result || (dialog_result == -1))
  321. return SQL_NO_DATA_FOUND;
  322. else
  323. return SQL_SUCCESS;
  324. }
  325. return SQL_ERROR;
  326. }
  327. BOOL CALLBACK dconn_FDriverConnectProc(HWND hdlg, UINT wMsg,
  328. WPARAM wParam, LPARAM lParam)
  329. {
  330. ConnInfo *ci;
  331. switch (wMsg)
  332. {
  333. case WM_INITDIALOG:
  334. ci = (ConnInfo *) lParam;
  335. /* Change the caption for the setup dialog */
  336. SetWindowText(hdlg, "Versabanq PLEXUS Connection");
  337. /* Hide the DSN and description fields */
  338. ShowWindow(GetDlgItem(hdlg, IDC_DSNAMETEXT), SW_HIDE);
  339. ShowWindow(GetDlgItem(hdlg, IDC_DSNAME), SW_HIDE);
  340. ShowWindow(GetDlgItem(hdlg, IDC_TEST), SW_HIDE);
  341. if ('\0' != ci->server[0])
  342. EnableWindow(GetDlgItem(hdlg, IDC_SERVER), FALSE);
  343. if ('\0' != ci->port[0])
  344. EnableWindow(GetDlgItem(hdlg, IDC_PORT), FALSE);
  345. SetWindowLongPtr(hdlg, DWLP_USER, lParam); /* Save the ConnInfo for
  346. * the "OK" */
  347. SetDlgStuff(hdlg, ci);
  348. if (ci->database[0] == '\0')
  349. ; /* default focus */
  350. else if (ci->server[0] == '\0')
  351. SetFocus(GetDlgItem(hdlg, IDC_SERVER));
  352. else if (ci->port[0] == '\0')
  353. SetFocus(GetDlgItem(hdlg, IDC_PORT));
  354. else if (ci->username[0] == '\0')
  355. SetFocus(GetDlgItem(hdlg, IDC_USER));
  356. else if (ci->focus_password)
  357. SetFocus(GetDlgItem(hdlg, IDC_PASSWORD));
  358. break;
  359. case WM_COMMAND:
  360. switch (GET_WM_COMMAND_ID(wParam, lParam))
  361. {
  362. case IDOK:
  363. ci = (ConnInfo *) GetWindowLongPtr(hdlg, DWLP_USER);
  364. GetDlgStuff(hdlg, ci);
  365. case IDCANCEL:
  366. EndDialog(hdlg, GET_WM_COMMAND_ID(wParam, lParam) == IDOK);
  367. return TRUE;
  368. }
  369. }
  370. return FALSE;
  371. }
  372. #endif /* WIN32 */
  373. typedef BOOL (*copyfunc) (ConnInfo *, const char *attribute,
  374. const char *value);
  375. static void dconn_get_attributes(copyfunc func,
  376. const SQLCHAR FAR * connect_string,
  377. ConnInfo * ci)
  378. {
  379. char *our_connect_string;
  380. const char *pair, *attribute, *value;
  381. char *equals;
  382. char *strtok_arg;
  383. #ifdef HAVE_STRTOK_R
  384. char *last;
  385. #endif /* HAVE_STRTOK_R */
  386. our_connect_string = strdup((const char *)connect_string);
  387. strtok_arg = our_connect_string;
  388. #ifdef FORCE_PASSWORD_DISPLAY
  389. mylog("our_connect_string = '%s'\n", our_connect_string);
  390. #else
  391. if (get_mylog())
  392. {
  393. char *hide_str = hide_password(our_connect_string);
  394. mylog("our_connect_string = '%s'\n", hide_str);
  395. free(hide_str);
  396. }
  397. #endif /* FORCE_PASSWORD_DISPLAY */
  398. while (1)
  399. {
  400. #ifdef HAVE_STRTOK_R
  401. pair = strtok_r(strtok_arg, ";", &last);
  402. #else
  403. pair = strtok(strtok_arg, ";");
  404. #endif /* HAVE_STRTOK_R */
  405. if (strtok_arg)
  406. strtok_arg = 0;
  407. if (!pair)
  408. break;
  409. equals = strchr(pair, '=');
  410. if (!equals)
  411. continue;
  412. *equals = '\0';
  413. attribute = pair; /* ex. DSN */
  414. value = equals + 1; /* ex. 'CEO co1' */
  415. #ifndef FORCE_PASSWORD_DISPLAY
  416. if (stricmp(attribute, INI_PASSWORD) == 0 ||
  417. stricmp(attribute, "pwd") == 0)
  418. mylog("attribute = '%s', value = 'xxxxx'\n", attribute);
  419. else
  420. #endif /* FORCE_PASSWORD_DISPLAY */
  421. mylog("attribute = '%s', value = '%s'\n", attribute, value);
  422. if (!attribute || !value)
  423. continue;
  424. /* Copy the appropriate value to the conninfo */
  425. (*func) (ci, attribute, value);
  426. }
  427. free(our_connect_string);
  428. }
  429. void dconn_get_connect_attributes(const SQLCHAR FAR * connect_string,
  430. ConnInfo * ci)
  431. {
  432. CC_conninfo_init(ci);
  433. dconn_get_attributes(copyAttributes, connect_string, ci);
  434. }
  435. static void dconn_get_common_attributes(const SQLCHAR FAR * connect_string,
  436. ConnInfo * ci)
  437. {
  438. dconn_get_attributes(copyCommonAttributes, connect_string, ci);
  439. }