1) Allow password which contains special characters like {,},=,;.
authorHiroshi Inoue <inoue@tpf.co.jp>
Sun, 17 Jan 2010 13:10:41 +0000 (13:10 +0000)
committerHiroshi Inoue <inoue@tpf.co.jp>
Sun, 17 Jan 2010 13:10:41 +0000 (13:10 +0000)
2) Add a new data source option which makes it possible to use
   Kerberos for Windows library to reply to GSSAPI authentication
   request.
3) Native support for SSPI Kerberos or Negaotiate service. It may
   be useful for the 64-bit drivers.
4) Fix an oversight of Memory overflow handling.

16 files changed:
connection.c
connection.h
convert.c
dlg_specific.c
dlg_specific.h
dlg_wingui.c
loadlib.c
psqlodbc.h
psqlodbc.rc
resource.h
socket.c
socket.h
sspisvcs.c
sspisvcs.h
statement.c
version.h

index dfbfe5f30536246fe4d8ed58a760bc024f430bf4..53c15557f48d1e9ddf7b552444b1a96b22908c66 100644 (file)
@@ -14,7 +14,6 @@
  */
 /* Multibyte support   Eiji Tokuya 2001-03-15 */
 
-#include "loadlib.h"
 #include "connection.h"
 #ifndef    NOT_USE_LIBPQ
 #include <libpq-fe.h>
 #else
 #include <errno.h>
 #endif /* WIN32 */
+#ifdef USE_KRB5
+#include "krb5svcs.h"
+#endif /* USE_KRB5 */
+#ifdef USE_GSS
+#include "gsssvcs.h"
+#endif /* USE_GSS */
 
 #include "environ.h"
 #include "socket.h"
@@ -273,6 +278,7 @@ CC_conninfo_init(ConnInfo *conninfo)
        conninfo->cvt_null_date_string = -1;
        conninfo->autocommit_public = SQL_AUTOCOMMIT_ON;
        conninfo->accessible_only = -1;
+       conninfo->gssauth_use_gssapi = -1;
 #ifdef _HANDLE_ENLIST_IN_DTC_
        conninfo->xa_opt = -1;
 #endif /* _HANDLE_ENLIST_IN_DTC_ */
@@ -447,6 +453,21 @@ CC_clear_error(ConnectionClass *self)
    CONNLOCK_RELEASE(self);
 }
 
+static void
+CC_endup_authentication(ConnectionClass *self)
+{
+   SocketClass *sock = CC_get_socket(self);
+#ifdef USE_SSPI
+   if (0 != self->auth_svcs)
+   {
+       ReleaseSvcSpecData(sock, self->auth_svcs);
+       self->auth_svcs = 0;
+   }
+#endif /* USE_SSPI */
+#ifdef USE_GSS
+   pg_GSS_cleanup(sock);
+#endif /* USE_GSS */
+}
 
 CSTR   bgncmd = "BEGIN";
 CSTR   cmtcmd = "COMMIT";
@@ -1077,9 +1098,23 @@ static int   protocol3_opts_array(ConnectionClass *self, const char *opts[][2], BO
            opts[cnt][0] = "database";  opts[cnt++][1] = ci->database;
        }
    }
-   if (ci->username[0])
+   if (ci->username[0] || !libpqopt)
    {
-       opts[cnt][0] = "user";      opts[cnt++][1] = ci->username;
+       char    *usrname = ci->username;
+#ifdef WIN32
+       DWORD namesize = sizeof(ci->username) - 2;
+#endif /* WIN32 */
+
+       opts[cnt][0] = "user";
+       if (!usrname[0])
+       {
+#ifdef WIN32
+           if (GetUserName(ci->username + 1, &namesize))
+               usrname = ci->username + 1;
+#endif /* WIN32 */
+       }
+mylog("!!! usrname=%s server=%s\n", usrname, ci->server);
+       opts[cnt++][1] = usrname;
    }
    if (libpqopt)
    {
@@ -1120,6 +1155,10 @@ static int   protocol3_opts_array(ConnectionClass *self, const char *opts[][2], BO
        {
            opts[cnt][0] = "password";  opts[cnt++][1] = ci->password;
        }
+       if (ci->gssauth_use_gssapi)
+       {
+           opts[cnt][0] = "gsslib";    opts[cnt++][1] = "gssapi";
+       }
    }
    else
    {
@@ -1379,6 +1418,38 @@ LIBPQ_CC_connect(ConnectionClass *self, char password_req, char *salt_para)
 }
 #endif /* NOT_USE_LIBPQ */
 
+#if    defined(USE_SSPI) || defined(USE_GSS)
+/*
+ * Callee should free hte returned pointer.
+ */
+static char *MakePrincHint(ConnInfo *ci, BOOL sspi)
+{
+   size_t len;
+   char    *svcprinc;
+   char    *svcname;
+   BOOL    attrFound = FALSE;
+
+   svcname = extract_extra_attribute_setting(ci->conn_settings, "krbsrvname");
+
+mylog("!!! %s settings=%s svcname=%p\n", __FUNCTION__, ci->conn_settings, svcname);
+   if (svcname)
+       attrFound = TRUE;
+   else
+       svcname = "postgres";
+   len = strlen(svcname) + 1 + strlen(ci->server) + 1;
+   if (NULL != (svcprinc = malloc(len)))
+   {
+       if (sspi)
+           snprintf(svcprinc, len, "%s/%s", svcname, ci->server);
+       else
+           snprintf(svcprinc, len, "%s@%s", svcname, ci->server);
+   }
+   if (attrFound)
+       free(svcname);
+   return svcprinc;
+}
+#endif /* USE_SSPI */
+
 static char
 original_CC_connect(ConnectionClass *self, char password_req, char *salt_para)
 {
@@ -1387,8 +1458,8 @@ original_CC_connect(ConnectionClass *self, char password_req, char *salt_para)
    QResultClass *res;
    SocketClass *sock;
    ConnInfo   *ci = &(self->connInfo);
-   int         areq = -1;
-   int         beresp, sockerr;
+   int     areq = -1;
+   int     ret = 0, beresp, sockerr;
    char        msgbuffer[ERROR_MSG_LENGTH];
    char        salt[5], notice[512];
    CSTR        func = "original_CC_connect";
@@ -1400,6 +1471,10 @@ original_CC_connect(ConnectionClass *self, char password_req, char *salt_para)
 
    mylog("%s: entering...\n", func);
 
+   /* lock the connetion during authentication */
+   ENTER_CONN_CS(self);
+#define    return  DONT_CALL_RETURN_FROM_HERE????
+
    if (password_req != AUTH_REQ_OK)
    {
        sock = self->sock;      /* already connected, just authenticate */
@@ -1408,7 +1483,7 @@ original_CC_connect(ConnectionClass *self, char password_req, char *salt_para)
    else
    {
        if (0 == CC_initial_log(self, func))
-           return 0;
+           goto error_proc;
 
 #ifdef USE_SSPI
        ssl_try_count = 0;
@@ -1453,7 +1528,7 @@ another_version_retry:
                if (PROTOCOL_62(ci))
                {
                    CC_set_error(self, CONNECTION_SERVER_NOT_REACHED, "Could not construct a socket to the server", func);
-                   return 0;
+                   goto error_proc;
                }
                if (PROTOCOL_63(ci))
                    strncpy_null(ci->protocol, PG62, sizeof(ci->protocol));
@@ -1484,7 +1559,7 @@ another_version_retry:
            if (!self->sock)
            {
                CC_set_error(self, CONNECTION_SERVER_NOT_REACHED, "Could not construct a socket to the server", func);
-               return 0;
+               goto error_proc;
            }
        }
 
@@ -1496,7 +1571,7 @@ another_version_retry:
        if (SOCK_get_errcode(sock) != 0)
        {
            CC_set_error(self, CONNECTION_SERVER_NOT_REACHED, "Could not connect to the server", func);
-           return 0;
+           goto error_proc;
        }
        mylog("connection to the server socket succeeded.\n");
 
@@ -1528,8 +1603,8 @@ inolog("protocol=%s version=%d,%d\n", ci->protocol, self->pg_version_major, self
                case 'S':
                    if (!StartupSspiService(sock, SchannelService, NULL))
                    {
-                       CC_set_error(self, CONNECTION_SERVER_NOT_REACHED, "Service negotation failed", func);
-                       return 0;
+                       CC_set_error(self, CONN_INVALID_AUTHENTICATION, "Service negotation failed", func);
+                       goto error_proc;
                    }
                    break;
                case 'N':
@@ -1543,8 +1618,8 @@ inolog("protocol=%s version=%d,%d\n", ci->protocol, self->pg_version_major, self
                        goto another_version_retry;
                    }
                default:
-                   CC_set_error(self, CONNECTION_SERVER_NOT_REACHED, "Service negotation failed", func);
-                   return 0;
+                   CC_set_error(self, CONN_INVALID_AUTHENTICATION, "Service negotation failed", func);
+                   goto error_proc;
            }
        }
 #endif /* USE_SSPI */
@@ -1565,7 +1640,7 @@ inolog("protocol=%s version=%d,%d\n", ci->protocol, self->pg_version_major, self
        else if (PROTOCOL_74(ci))
        {
            if (!protocol3_packet_build(self))
-               return 0;
+               goto error_proc;
        }
        else
        {
@@ -1592,7 +1667,7 @@ inolog("protocol=%s version=%d,%d\n", ci->protocol, self->pg_version_major, self
        if (SOCK_get_errcode(sock) != 0)
        {
            CC_set_error(self, CONN_INVALID_AUTHENTICATION, "Failed to send the authentication packet", func);
-           return 0;
+           goto error_proc;
        }
        mylog("sent the authentication block successfully.\n");
    }
@@ -1609,7 +1684,8 @@ inolog("protocol=%s version=%d,%d\n", ci->protocol, self->pg_version_major, self
    {
        BOOL        beforeV2 = PG_VERSION_LT(self, 6.4),
                    ReadyForQuery = FALSE, retry = FALSE;
-       uint32  leng;
+       uint32  leng = 0;
+       int authRet;
 
        do
        {
@@ -1664,7 +1740,7 @@ inolog("Ekita retry=%d\n", retry);
                    if (retry)
                        break;
 
-                   return 0;
+                   goto error_proc;
                case 'R':
 
                    if (password_req != AUTH_REQ_OK)
@@ -1695,11 +1771,22 @@ inolog("Ekita retry=%d\n", retry);
 
                        case AUTH_REQ_KRB4:
                            CC_set_error(self, CONN_AUTH_TYPE_UNSUPPORTED, "Kerberos 4 authentication not supported", func);
-                           return 0;
+                           goto error_proc;
 
                        case AUTH_REQ_KRB5:
+#ifdef USE_KRB5
+                           // pglock_thread();
+                           authRet = pg_krb5_sendauth(self);
+                           // pgunlock_thread();
+                           if (authRet != 0)
+                           {
+                               /* Error message already filled in */
+                               goto error_proc;
+                           }
+                           break;
+#endif /* USE_KRB5 */
                            CC_set_error(self, CONN_AUTH_TYPE_UNSUPPORTED, "Kerberos 5 authentication not supported", func);
-                           return 0;
+                           goto error_proc;
 
                        case AUTH_REQ_PASSWORD:
                            mylog("in AUTH_REQ_PASSWORD\n");
@@ -1707,7 +1794,8 @@ inolog("Ekita retry=%d\n", retry);
                            if (ci->password[0] == '\0')
                            {
                                CC_set_error(self, CONNECTION_NEED_PASSWORD, "A password is required for this connection.", func);
-                               return -areq;       /* need password */
+                               ret = -areq; /* need password */
+                               goto error_proc;
                            }
 
                            mylog("past need password\n");
@@ -1723,7 +1811,7 @@ inolog("Ekita retry=%d\n", retry);
 
                        case AUTH_REQ_CRYPT:
                            CC_set_error(self, CONN_AUTH_TYPE_UNSUPPORTED, "Password crypt authentication not supported", func);
-                           return 0;
+                           goto error_proc;
                        case AUTH_REQ_MD5:
                            mylog("in AUTH_REQ_MD5\n");
                            if (ci->password[0] == '\0')
@@ -1731,22 +1819,101 @@ inolog("Ekita retry=%d\n", retry);
                                CC_set_error(self, CONNECTION_NEED_PASSWORD, "A password is required for this connection.", func);
                                if (salt_para)
                                    memcpy(salt_para, salt, sizeof(salt));
-                               return -areq; /* need password */
+                               ret = -areq; /* need password */
+                               goto error_proc;
                            }
                            if (md5_auth_send(self, salt))
                            {
                                CC_set_error(self, CONN_INVALID_AUTHENTICATION, "md5 hashing failed", func);
-                               return 0;
+                               goto error_proc;
                            }
                            break;
 
                        case AUTH_REQ_SCM_CREDS:
                            CC_set_error(self, CONN_AUTH_TYPE_UNSUPPORTED, "Unix socket credential authentication not supported", func);
-                           return 0;
+                           goto error_proc;
+
+                       case AUTH_REQ_GSS:
+                           mylog("in AUTH_REQ_GSS\n");
+#if    defined(USE_SSPI)
+                           if (!ci->gssauth_use_gssapi)
+                           {
+                               self->auth_svcs = KerberosService;
+                               authRet = StartupSspiService(sock, self->auth_svcs, MakePrincHint(ci, TRUE));
+                               if (!authRet)
+                               {
+                                   CC_set_error(self, CONN_INVALID_AUTHENTICATION, "Service negotation failed", func);
+                                   goto error_proc;
+                               }
+                               break;
+                           }
+#endif /* USE_SSPI */
+#ifdef USE_GSS
+#ifdef USE_SSPI
+                           if (ci->gssauth_use_gssapi)
+#endif /* USE_SSPI */
+                           {
+                                               // pglock_thread();
+                                               authRet = pg_GSS_startup(self, MakePrincHint(ci, FALSE));
+                                               // pgunlock_thread();
+                                               if (authRet != 0)
+                               {
+                                   CC_set_errornumber(self, CONN_INVALID_AUTHENTICATION);
+                                   goto error_proc;
+                               }
+                               break;
+                           }
+#endif /* USE_GSS */
+                           CC_set_error(self, CONN_AUTH_TYPE_UNSUPPORTED, "GSS authentication not supported", func);
+                           goto error_proc;
+
+                       case AUTH_REQ_GSS_CONT:
+                           mylog("in AUTH_REQ_GSS_CONT\n");
+#if    defined(USE_SSPI)
+                           if (0 != self->auth_svcs)
+                           {
+                               authRet = ContinueSspiService(sock, self->auth_svcs, (void *) (leng - 4));
+                               if (!authRet)
+                               {
+                                   CC_set_error(self, CONN_INVALID_AUTHENTICATION, "Service continuation failed", func);
+                                   goto error_proc;
+                               }
+                               break;
+                           }
+#endif /* USE_SSPI */
+#ifdef USE_GSS
+                                           // pglock_thread();
+                                           authRet = pg_GSS_continue(self, leng - 4);
+                                           // pgunlock_thread();
+                                           if (authRet != 0)
+                           {
+                               CC_set_errornumber(self, CONN_INVALID_AUTHENTICATION);
+                               goto error_proc;
+                           }
+                           break;
+#else
+                           CC_set_error(self, CONN_AUTH_TYPE_UNSUPPORTED, "GSS authentication not supported", func);
+                           goto error_proc;
+#endif
+
+                       case AUTH_REQ_SSPI:
+                           mylog("in AUTH_REQ_SSPI\n");
+#if    defined(USE_SSPI)
+                           self->auth_svcs = ci->gssauth_use_gssapi ? KerberosService : NegotiateService;
+                           if (!StartupSspiService(sock, self->auth_svcs, MakePrincHint(ci, TRUE)))
+                           {
+                               CC_set_error(self, CONN_INVALID_AUTHENTICATION, "Service negotation failed", func);
+                               goto error_proc;
+                           }
+                           break;
+#else
+                           CC_set_error(self, CONN_AUTH_TYPE_UNSUPPORTED, "SSPI authentication not supported", func);
+                           goto error_proc;
+#endif
 
                        default:
                            CC_set_error(self, CONN_AUTH_TYPE_UNSUPPORTED, "Unknown authentication type", func);
-                           return 0;
+                           goto error_proc;
                    }
                    break;
                case 'S': /* parameter status */
@@ -1767,7 +1934,7 @@ inolog("Ekita retry=%d\n", retry);
                default:
                    snprintf(notice, sizeof(notice), "Unexpected protocol character='%c' during authentication", beresp);
                    CC_set_error(self, CONN_INVALID_AUTHENTICATION, notice, func);
-                   return 0;
+                   goto error_proc;
            }
            if (retry)
            {
@@ -1784,6 +1951,13 @@ inolog("Ekita retry=%d\n", retry);
    }
 
 sockerr_proc:
+   ret = 1;
+error_proc:
+#undef return
+   CC_endup_authentication(self);
+   LEAVE_CONN_CS(self);
+   if (0 >= ret)
+       return ret;
    if (0 != (sockerr = SOCK_get_errcode(sock)))
    {
        if (0 == CC_get_errornumber(self))
@@ -1846,17 +2020,15 @@ CC_connect(ConnectionClass *self, char password_req, char *salt_para)
 
    mylog("sslmode=%s\n", self->connInfo.sslmode);
 #ifndef    NOT_USE_LIBPQ
+#ifdef USE_SSPI
+   if (0 != self->svcs_allowed)
+       ;
+   else
+#endif /* USE_SSPI */
    if (self->connInfo.username[0] == '\0')
        call_libpq = TRUE;
    else if (self->connInfo.sslmode[0] != SSLLBYTE_DISABLE) 
-#ifdef USE_SSPI
-   {
-       if (0 == (SchannelService & self->svcs_allowed))
-           call_libpq = TRUE;
-   }
-#else
        call_libpq = TRUE;
-#endif /* USE_SSPI */
    if (call_libpq)
    {
        ret = LIBPQ_CC_connect(self, password_req, salt_para);
@@ -1866,7 +2038,7 @@ CC_connect(ConnectionClass *self, char password_req, char *salt_para)
         */
        if (0 == ret && CONN_UNABLE_TO_LOAD_DLL == CC_get_errornumber(self))
        {
-           self->svcs_allowed |= SchannelService;
+           self->svcs_allowed |= (SchannelService | KerberosService | NegotiateService);
            ret = original_CC_connect(self, password_req, salt_para);
        }
 #endif /* USE_SSPI */
index 51044f8133c02c6ff7a57f64d369d618731dc5ab..c62524845206100935fb123a8d707b831da740f0 100644 (file)
@@ -209,6 +209,9 @@ do { \
 #define AUTH_REQ_CRYPT     4
 #define AUTH_REQ_MD5       5
 #define AUTH_REQ_SCM_CREDS 6
+#define AUTH_REQ_GSS       7
+#define AUTH_REQ_GSS_CONT  8
+#define AUTH_REQ_SSPI      9
 
 /* Startup Packet sizes */
 #define SM_DATABASE        64
@@ -311,6 +314,7 @@ typedef struct
    signed char cvt_null_date_string;
    signed char autocommit_public;
    signed char accessible_only;
+   signed char gssauth_use_gssapi;
    UInt4       extra_opts;
 #ifdef _HANDLE_ENLIST_IN_DTC_
    signed char xa_opt;
@@ -474,6 +478,7 @@ struct ConnectionClass_
    pgNAME      tableIns;
 #ifdef USE_SSPI
    UInt4       svcs_allowed;
+   UInt4       auth_svcs;
 #endif /* USE_SSPI */
 #if defined(WIN_MULTITHREAD_SUPPORT)
    CRITICAL_SECTION    cs;
index 5d8723c6483d691eb6b0bd87293a34c6c13c17ee..5fac790e1a658f66e0aaf12e77164ffb35562da4 100644 (file)
--- a/convert.c
+++ b/convert.c
@@ -1097,6 +1097,7 @@ inolog("2stime fr=%d\n", std_time.fr);
                            new_string = malloc(cbValueMax);
                            lc = localeconv();
                            for (i = 0, j = 0; ptr[i]; i++)
+                           {
                                if (ptr[i] == '.')
                                {
                                    strncpy_null(&new_string[j], lc->decimal_point, cbValueMax - j);
@@ -1104,6 +1105,7 @@ inolog("2stime fr=%d\n", std_time.fr);
                                }
                                else
                                    new_string[j++] = ptr[i];
+                           }
                            new_string[j] = '\0';
                            strncpy_null(rgbValueBindRow, new_string, copy_len + 1);
                            free(new_string);
index c5a35234e2072c02d163882d733897befb0da709..9e0095253470ec8f4f3e457ae9cf9394e8acb04b 100644 (file)
@@ -27,8 +27,8 @@
 
 extern GLOBAL_VALUES globals;
 
-static void encode(const UCHAR *in, UCHAR *out);
-static void decode(const UCHAR *in, UCHAR *out);
+static void encode(const UCHAR *in, UCHAR *out, int outlen);
+static void decode(const UCHAR *in, UCHAR *out, int outlen);
 
 #define    OVR_EXTRA_BITS (BIT_FORCEABBREVCONNSTR | BIT_FAKE_MSS | BIT_BDE_ENVIRONMENT | BIT_CVT_NULL_DATE | BIT_ACCESSIBLE_ONLY)
 UInt4  getExtraOptions(const ConnInfo *ci)
@@ -167,13 +167,14 @@ void
 makeConnectString(char *connect_string, const ConnInfo *ci, UWORD len)
 {
    char        got_dsn = (ci->dsn[0] != '\0');
-   char        encoded_conn_settings[LARGE_REGISTRY_LEN];
+   char        encoded_item[LARGE_REGISTRY_LEN];
    ssize_t     hlen, nlen, olen;
    /*BOOL      abbrev = (len <= 400);*/
    BOOL        abbrev = (len < 1024) || 0 < ci->force_abbrev_connstr;
    UInt4       flag;
 
 inolog("force_abbrev=%d abbrev=%d\n", ci->force_abbrev_connstr, abbrev);
+   encode(ci->password, encoded_item, sizeof(encoded_item));
    /* fundamental info */
    nlen = MAX_CONNECT_STRING;
    olen = snprintf(connect_string, nlen, "%s=%s;DATABASE=%s;SERVER=%s;PORT=%s;UID=%s;PWD=%s",
@@ -183,14 +184,14 @@ inolog("force_abbrev=%d abbrev=%d\n", ci->force_abbrev_connstr, abbrev);
            ci->server,
            ci->port,
            ci->username,
-           ci->password);
+           encoded_item);
    if (olen < 0 || olen >= nlen)
    {
        connect_string[0] = '\0';
        return;
    }
 
-   encode(ci->conn_settings, encoded_conn_settings);
+   encode(ci->conn_settings, encoded_item, sizeof(encoded_item));
 
    /* extra info */
    hlen = strlen(connect_string);
@@ -237,6 +238,9 @@ inolog("hlen=%d", hlen);
            INI_BYTEAASLONGVARBINARY "=%d;"
            INI_USESERVERSIDEPREPARE "=%d;"
            INI_LOWERCASEIDENTIFIER "=%d;"
+#ifdef WIN32
+           INI_GSSAUTHUSEGSSAPI "=%d"
+#endif /* WIN32 */
 #ifdef _HANDLE_ENLIST_IN_DTC_
            INI_XAOPT "=%d" /* XAOPT */
 #endif /* _HANDLE_ENLIST_IN_DTC_ */
@@ -247,7 +251,7 @@ inolog("hlen=%d", hlen);
            ,ci->show_oid_column
            ,ci->row_versioning
            ,ci->show_system_tables
-           ,encoded_conn_settings
+           ,encoded_item
            ,ci->drivers.fetch_max
            ,ci->drivers.socket_buffersize
            ,ci->drivers.unknown_sizes
@@ -272,6 +276,9 @@ inolog("hlen=%d", hlen);
            ,ci->bytea_as_longvarbinary
            ,ci->use_server_side_prepare
            ,ci->lower_case_identifier
+#ifdef WIN32
+           ,ci->gssauth_use_gssapi
+#endif /* WIN32 */
 #ifdef _HANDLE_ENLIST_IN_DTC_
            ,ci->xa_opt
 #endif /* _HANDLE_ENLIST_IN_DTC_ */
@@ -342,6 +349,8 @@ inolog("hlen=%d", hlen);
            flag |= BIT_USESERVERSIDEPREPARE;
        if (ci->lower_case_identifier)
            flag |= BIT_LOWERCASEIDENTIFIER;
+       if (ci->gssauth_use_gssapi)
+           flag |= BIT_GSSAUTHUSEGSSAPI;
 
        if (ci->sslmode[0])
        {
@@ -361,7 +370,7 @@ inolog("hlen=%d", hlen);
                INI_INT8AS "=%d;"
                ABBR_EXTRASYSTABLEPREFIXES "=%s;"
                INI_ABBREVIATE "=%02x%x",
-               encoded_conn_settings,
+               encoded_item,
                ci->drivers.fetch_max,
                ci->drivers.socket_buffersize,
                ci->drivers.max_varchar_size,
@@ -464,6 +473,7 @@ unfoldCXAttribute(ConnInfo *ci, const char *value)
    ci->bytea_as_longvarbinary = (char)((flag & BIT_BYTEAASLONGVARBINARY) != 0);
    ci->use_server_side_prepare = (char)((flag & BIT_USESERVERSIDEPREPARE) != 0);
    ci->lower_case_identifier = (char)((flag & BIT_LOWERCASEIDENTIFIER) != 0);
+   ci->gssauth_use_gssapi = (char)((flag & BIT_GSSAUTHUSEGSSAPI) != 0);
 }
 BOOL
 copyAttributes(ConnInfo *ci, const char *attribute, const char *value)
@@ -483,11 +493,11 @@ copyAttributes(ConnInfo *ci, const char *attribute, const char *value)
    else if (stricmp(attribute, INI_SERVER) == 0 || stricmp(attribute, SPEC_SERVER) == 0)
        strcpy(ci->server, value);
 
-   else if (stricmp(attribute, INI_USER) == 0 || stricmp(attribute, INI_UID) == 0)
+   else if (stricmp(attribute, INI_USERNAME) == 0 || stricmp(attribute, INI_UID) == 0)
        strcpy(ci->username, value);
 
    else if (stricmp(attribute, INI_PASSWORD) == 0 || stricmp(attribute, "pwd") == 0)
-       strcpy(ci->password, value);
+       decode(value, ci->password, sizeof(ci->password));
 
    else if (stricmp(attribute, INI_PORT) == 0)
        strcpy(ci->port, value);
@@ -538,7 +548,7 @@ copyAttributes(ConnInfo *ci, const char *attribute, const char *value)
                ci->conn_settings[len - 1] = '\0';
        }
        else
-           decode(value, ci->conn_settings);
+           decode(value, ci->conn_settings, sizeof(ci->conn_settings));
    }
    else if (stricmp(attribute, INI_DISALLOWPREMATURE) == 0 || stricmp(attribute, ABBR_DISALLOWPREMATURE) == 0)
        ci->disallow_premature = atoi(value);
@@ -556,6 +566,8 @@ copyAttributes(ConnInfo *ci, const char *attribute, const char *value)
        ci->use_server_side_prepare = atoi(value);
    else if (stricmp(attribute, INI_LOWERCASEIDENTIFIER) == 0 || stricmp(attribute, ABBR_LOWERCASEIDENTIFIER) == 0)
        ci->lower_case_identifier = atoi(value);
+   else if (stricmp(attribute, INI_GSSAUTHUSEGSSAPI) == 0 || stricmp(attribute, ABBR_GSSAUTHUSEGSSAPI) == 0)
+       ci->gssauth_use_gssapi = atoi(value);
    else if (stricmp(attribute, INI_SSLMODE) == 0 || stricmp(attribute, ABBR_SSLMODE) == 0)
    {
        switch (value[0])
@@ -735,6 +747,8 @@ getDSNdefaults(ConnInfo *ci)
        ci->use_server_side_prepare = DEFAULT_USESERVERSIDEPREPARE;
    if (ci->lower_case_identifier < 0)
        ci->lower_case_identifier = DEFAULT_LOWERCASEIDENTIFIER;
+   if (ci->gssauth_use_gssapi < 0)
+       ci->gssauth_use_gssapi = DEFAULT_GSSAUTHUSEGSSAPI;
    if (ci->sslmode[0] == '\0')
        strcpy(ci->sslmode, DEFAULT_SSLMODE);
    if (ci->force_abbrev_connstr < 0)
@@ -774,7 +788,7 @@ getDSNinfo(ConnInfo *ci, char overwrite)
 {
    CSTR    func = "getDSNinfo";
    char       *DSN = ci->dsn;
-   char        encoded_conn_settings[LARGE_REGISTRY_LEN],
+   char        encoded_item[LARGE_REGISTRY_LEN],
                temp[SMALL_REGISTRY_LEN];
 
 /*
@@ -813,10 +827,13 @@ getDSNinfo(ConnInfo *ci, char overwrite)
        SQLGetPrivateProfileString(DSN, INI_DATABASE, "", ci->database, sizeof(ci->database), ODBC_INI);
 
    if (ci->username[0] == '\0' || overwrite)
-       SQLGetPrivateProfileString(DSN, INI_USER, "", ci->username, sizeof(ci->username), ODBC_INI);
+       SQLGetPrivateProfileString(DSN, INI_USERNAME, "", ci->username, sizeof(ci->username), ODBC_INI);
 
    if (ci->password[0] == '\0' || overwrite)
-       SQLGetPrivateProfileString(DSN, INI_PASSWORD, "", ci->password, sizeof(ci->password), ODBC_INI);
+   {
+       SQLGetPrivateProfileString(DSN, INI_PASSWORD, "", encoded_item, sizeof(encoded_item), ODBC_INI);
+       decode(encoded_item, ci->password, sizeof(ci->password));
+   }
 
    if (ci->port[0] == '\0' || overwrite)
        SQLGetPrivateProfileString(DSN, INI_PORT, "", ci->port, sizeof(ci->port), ODBC_INI);
@@ -853,8 +870,8 @@ getDSNinfo(ConnInfo *ci, char overwrite)
 
    if (ci->conn_settings[0] == '\0' || overwrite)
    {
-       SQLGetPrivateProfileString(DSN, INI_CONNSETTINGS, "", encoded_conn_settings, sizeof(encoded_conn_settings), ODBC_INI);
-       decode(encoded_conn_settings, ci->conn_settings);
+       SQLGetPrivateProfileString(DSN, INI_CONNSETTINGS, "", encoded_item, sizeof(encoded_item), ODBC_INI);
+       decode(encoded_item, ci->conn_settings, sizeof(ci->conn_settings));
    }
 
    if (ci->translation_dll[0] == '\0' || overwrite)
@@ -919,6 +936,13 @@ getDSNinfo(ConnInfo *ci, char overwrite)
            ci->lower_case_identifier = atoi(temp);
    }
 
+   if (ci->gssauth_use_gssapi < 0 || overwrite)
+   {
+       SQLGetPrivateProfileString(DSN, INI_GSSAUTHUSEGSSAPI, "", temp, sizeof(temp), ODBC_INI);
+       if (temp[0])
+           ci->gssauth_use_gssapi = atoi(temp);
+   }
+
    if (ci->sslmode[0] == '\0' || overwrite)
        SQLGetPrivateProfileString(DSN, INI_SSLMODE, "", ci->sslmode, sizeof(ci->sslmode), ODBC_INI);
 
@@ -1080,10 +1104,9 @@ void
 writeDSNinfo(const ConnInfo *ci)
 {
    const char *DSN = ci->dsn;
-   char        encoded_conn_settings[LARGE_REGISTRY_LEN],
+   char        encoded_item[LARGE_REGISTRY_LEN],
                temp[SMALL_REGISTRY_LEN];
 
-   encode(ci->conn_settings, encoded_conn_settings);
 
    SQLWritePrivateProfileString(DSN,
                                 INI_KDESC,
@@ -1106,14 +1129,15 @@ writeDSNinfo(const ConnInfo *ci)
                                 ODBC_INI);
 
    SQLWritePrivateProfileString(DSN,
-                                INI_USER,
+                                INI_USERNAME,
                                 ci->username,
                                 ODBC_INI);
    SQLWritePrivateProfileString(DSN, INI_UID, ci->username, ODBC_INI);
 
+   encode(ci->password, encoded_item, sizeof(encoded_item));
    SQLWritePrivateProfileString(DSN,
                                 INI_PASSWORD,
-                                ci->password,
+                                encoded_item,
                                 ODBC_INI);
 
    SQLWritePrivateProfileString(DSN,
@@ -1150,9 +1174,10 @@ writeDSNinfo(const ConnInfo *ci)
                                 temp,
                                 ODBC_INI);
 
+   encode(ci->conn_settings, encoded_item, sizeof(encoded_item));
    SQLWritePrivateProfileString(DSN,
                                 INI_CONNSETTINGS,
-                                encoded_conn_settings,
+                                encoded_item,
                                 ODBC_INI);
 
    sprintf(temp, "%d", ci->disallow_premature);
@@ -1200,6 +1225,11 @@ writeDSNinfo(const ConnInfo *ci)
                                 INI_LOWERCASEIDENTIFIER,
                                 temp,
                                 ODBC_INI);
+   sprintf(temp, "%d", ci->gssauth_use_gssapi);
+   SQLWritePrivateProfileString(DSN,
+                                INI_GSSAUTHUSEGSSAPI,
+                                temp,
+                                ODBC_INI);
    SQLWritePrivateProfileString(DSN,
                                 INI_SSLMODE,
                                 ci->sslmode,
@@ -1420,17 +1450,19 @@ getCommonDefaults(const char *section, const char *filename, ConnInfo *ci)
 }
 
 static void
-encode(const UCHAR *in, UCHAR *out)
+encode(const UCHAR *in, UCHAR *out, int outlen)
 {
    size_t i, ilen = strlen(in),
                o = 0;
    UCHAR   inc;
 
-   for (i = 0; i < ilen; i++)
+   for (i = 0; i < ilen && o < outlen - 1; i++)
    {
        inc = in[i];
        if (inc == '+')
        {
+           if (o + 2 >= outlen)
+               break;
            sprintf(&out[o], "%%2B");
            o += 3;
        }
@@ -1438,6 +1470,8 @@ encode(const UCHAR *in, UCHAR *out)
            out[o++] = '+';
        else if (!isalnum(inc))
        {
+           if (o + 2 >= outlen)
+               break;
            sprintf(&out[o], "%%%02x", inc);
            o += 3;
        }
@@ -1470,13 +1504,13 @@ conv_from_hex(const UCHAR *s)
 }
 
 static void
-decode(const UCHAR *in, UCHAR *out)
+decode(const UCHAR *in, UCHAR *out, int outlen)
 {
    size_t i, ilen = strlen(in),
                o = 0;
    UCHAR   inc;
 
-   for (i = 0; i < ilen; i++)
+   for (i = 0; i < ilen && o < outlen - 1; i++)
    {
        inc = in[i];
        if (inc == '+')
@@ -1491,3 +1525,233 @@ decode(const UCHAR *in, UCHAR *out)
    }
    out[o++] = '\0';
 }
+
+char *extract_attribute_setting(const char *str, const char *attr, BOOL ref_comment)
+{
+   const UCHAR *cptr, *sptr = NULL;
+   UCHAR   *rptr;
+   BOOL    allowed_cmd = TRUE, in_quote = FALSE, in_comment = FALSE;
+   int step = 0, skiplen;
+   size_t  len = 0, attrlen = strlen(attr);
+
+        for (cptr = (UCHAR *) str; *cptr; cptr++)
+        {
+       if (in_quote)
+       {
+           if (LITERAL_QUOTE == *cptr)
+           {
+               if (4 == step)
+               {
+                   len = cptr - sptr;
+                   step++;
+               }
+               in_quote = FALSE;
+           }
+           continue;
+       }
+       else if (in_comment)
+       {
+           if ('*' == *cptr &&
+               '/' == cptr[1])
+           {
+               if (4 == step)
+               {
+                   len = cptr - sptr;
+                   step++;
+               }
+               in_comment = FALSE;
+               cptr++;
+               continue;
+           }
+           if (!ref_comment)
+               continue;
+       }
+       else if ('/' == *cptr &&
+            '*' == cptr[1])
+       {
+           in_comment = TRUE;
+           cptr++;
+           continue;
+       }
+       if (';' == *cptr)
+       {
+           if (4 == step)
+           {
+               len = cptr - sptr;
+           }
+           allowed_cmd = TRUE;
+           step = 0;
+           continue;
+       }
+       if (!allowed_cmd)
+           continue;
+       if (isspace(*cptr))
+       {
+           if (4 == step)
+           {
+               len =  cptr - sptr;
+               step++;
+           }
+           continue;
+       }
+       switch (step)
+       {
+           case 0:
+               if (0 != strnicmp(cptr, "set", 3))
+               {
+                   allowed_cmd = FALSE;
+                   continue;
+               }
+               step++;
+               cptr += 3;
+               break;
+           case 1:
+               if (0 != strnicmp(cptr, attr, attrlen))
+               {
+                   allowed_cmd = FALSE;
+                   continue;
+               }
+               step++;
+               cptr += (attrlen - 1);
+               break;
+           case 2:
+               skiplen = 0;
+               if (0 != strnicmp(cptr, "=", 1))
+               {
+                   skiplen = strlen("to");
+                   if (0 != strnicmp(cptr, "to", 2))
+                   {
+                       allowed_cmd = FALSE;
+                       continue;
+                   }
+               }
+               step++;
+               cptr += skiplen;
+               break;
+           case 3:
+               if (LITERAL_QUOTE == *cptr)
+               {
+                   cptr++;
+                   sptr = cptr;
+               }
+               else
+                   sptr = cptr;
+               step++;
+               break;
+       }
+   }
+   if (!sptr)
+       return NULL;
+   rptr = malloc(len + 1);
+   memcpy(rptr, sptr, len);
+   rptr[len] = '\0';
+   mylog("extracted a %s '%s' from %s\n", attr, rptr, str);
+   return rptr;
+}
+
+/*
+ * extract the specified attribute from the comment part.
+ *     attribute=[']value[']
+ */
+char *extract_extra_attribute_setting(const char *str, const char *attr)
+{
+   const UCHAR *cptr, *sptr = NULL;
+   UCHAR   *rptr;
+   BOOL    allowed_cmd = FALSE, in_quote = FALSE, in_comment = FALSE;
+   int step = 0, step_last = 2;
+   size_t  len = 0, attrlen = strlen(attr);
+
+        for (cptr = (UCHAR *) str; *cptr; cptr++)
+        {
+       if (in_quote)
+       {
+           if (LITERAL_QUOTE == *cptr)
+           {
+               if (step_last == step)
+               {
+                   len = cptr - sptr;
+                   step = 0;
+               }
+               in_quote = FALSE;
+           }
+           continue;
+       }
+       else if (in_comment)
+       {
+           if ('*' == *cptr &&
+               '/' == cptr[1])
+           {
+               if (step_last == step)
+               {
+                   len = cptr - sptr;
+                   step = 0;
+               }
+               in_comment = FALSE;
+               allowed_cmd = FALSE;
+               cptr++;
+               continue;
+           }
+       }
+       else if ('/' == *cptr &&
+            '*' == cptr[1])
+       {
+           in_comment = TRUE;
+           allowed_cmd = TRUE;
+           cptr++;
+           continue;
+       }
+       else
+       {
+           if (LITERAL_QUOTE == *cptr)
+               in_quote = TRUE;
+           continue;
+       }
+       /* now in comment */
+       if (';' == *cptr ||
+           isspace(*cptr))
+       {
+           if (step_last == step)
+               len = cptr - sptr;
+           allowed_cmd = TRUE;
+           step = 0;
+           continue;
+       }
+       if (!allowed_cmd)
+           continue;
+       switch (step)
+       {
+           case 0:
+               if (0 != strnicmp(cptr, attr, attrlen))
+               {
+                   allowed_cmd = FALSE;
+                   continue;
+               }
+               if (cptr[attrlen] != '=')
+               {
+                   allowed_cmd = FALSE;
+                   continue;
+               }
+               step++;
+               cptr += attrlen;
+               break;
+           case 1:
+               if (LITERAL_QUOTE == *cptr)
+               {
+                   in_quote = TRUE;
+                   cptr++;
+                   sptr = cptr;
+               }
+               else
+                   sptr = cptr;
+               step++;
+               break;
+       }
+   }
+   if (!sptr)
+       return NULL;
+   rptr = malloc(len + 1);
+   memcpy(rptr, sptr, len);
+   rptr[len] = '\0';
+   mylog("extracted a %s '%s' from %s\n", attr, rptr, str);
+   return rptr;
+}
index 84e09f4ef47119e11299d50274f816681ce5d264..033b7f785e67880933c0d1d8e1b97e7095329bac 100644 (file)
@@ -57,7 +57,7 @@ extern "C" {
                         * Postmaster is listening */
 #define INI_DATABASE           "Database"  /* Database Name */
 #define INI_UID                "UID"       /* Default User Name */
-#define INI_USER           "Username"  /* Default User Name */
+#define INI_USERNAME           "Username"  /* Default User Name */
 #define INI_PASSWORD           "Password"  /* Default Password */
 
 #define    INI_ABBREVIATE          "CX"
@@ -144,6 +144,8 @@ extern "C" {
 #define ABBR_SSLMODE           "CA"
 #define INI_EXTRAOPTIONS       "AB"
 #define INI_LOGDIR         "Logdir"
+#define INI_GSSAUTHUSEGSSAPI       "GssAuthUseGSS"
+#define ABBR_GSSAUTHUSEGSSAPI      "D0"
 
 #define    SSLMODE_DISABLE     "disable"
 #define    SSLMODE_ALLOW       "allow"
@@ -189,8 +191,9 @@ const char *GetXaLibPath();
 #define BIT_BYTEAASLONGVARBINARY       (1L<<24)
 #define BIT_USESERVERSIDEPREPARE       (1L<<25)
 #define BIT_LOWERCASEIDENTIFIER            (1L<<26)
+#define BIT_GSSAUTHUSEGSSAPI           (1L<<27)
 
-#define EFFECTIVE_BIT_COUNT            27
+#define EFFECTIVE_BIT_COUNT            28
 
 /* Mask for extra options  */
 #define    BIT_FORCEABBREVCONNSTR          1L
@@ -241,6 +244,7 @@ const char *GetXaLibPath();
 #define DEFAULT_USESERVERSIDEPREPARE   0
 #define DEFAULT_LOWERCASEIDENTIFIER    0
 #define DEFAULT_SSLMODE            SSLMODE_DISABLE
+#define DEFAULT_GSSAUTHUSEGSSAPI   0
 
 #ifdef _HANDLE_ENLIST_IN_DTC_
 #define DEFAULT_XAOPT          1
@@ -290,6 +294,8 @@ int setLogDir(const char *dir);
 int     changeDriverNameOfaDSN(const char *dsn, const char *driver_name, DWORD *errcode);
 UInt4  getExtraOptions(const ConnInfo *);
 BOOL   setExtraOptions(ConnInfo *, const char *str, const char *format);
+char   *extract_attribute_setting(const char *str, const char *attr, BOOL ref_comment);
+char   *extract_extra_attribute_setting(const char *str, const char *attr);
 
 #ifdef __cplusplus
 }
index 6405ab5b2f24865e8e6408e69384b193b8792664..0fe65cb784679f49cc4508791889271c47fccf8e 100644 (file)
@@ -590,7 +590,11 @@ ds_options2Proc(HWND hdlg,
            CheckDlgButton(hdlg, DS_SERVERSIDEPREPARE, ci->use_server_side_prepare);
            CheckDlgButton(hdlg, DS_BYTEAASLONGVARBINARY, ci->bytea_as_longvarbinary);
            /*CheckDlgButton(hdlg, DS_LOWERCASEIDENTIFIER, ci->lower_case_identifier);*/
+           CheckDlgButton(hdlg, DS_GSSAUTHUSEGSSAPI, ci->gssauth_use_gssapi);
 
+#if    defined(NOT_USE_LIBPQ) && !defined(USE_SSPI) && !defined(USE_GSS)
+           EnableWindow(GetDlgItem(hdlg, DS_GSSAUTHUSEGSSAPI), FALSE);
+#endif
            EnableWindow(GetDlgItem(hdlg, DS_FAKEOIDINDEX), atoi(ci->show_oid_column));
 
            /* Datasource Connection Settings */
@@ -662,6 +666,7 @@ ds_options2Proc(HWND hdlg,
                    ci->use_server_side_prepare = IsDlgButtonChecked(hdlg, DS_SERVERSIDEPREPARE);
                    ci->bytea_as_longvarbinary = IsDlgButtonChecked(hdlg, DS_BYTEAASLONGVARBINARY);
                    /*ci->lower_case_identifier = IsDlgButtonChecked(hdlg, DS_LOWERCASEIDENTIFIER);*/
+                   ci->gssauth_use_gssapi = IsDlgButtonChecked(hdlg, DS_GSSAUTHUSEGSSAPI);
 
                    /* OID Options */
                    sprintf(ci->fake_oid_index, "%d", IsDlgButtonChecked(hdlg, DS_FAKEOIDINDEX));
index c1aa565dfea317f263351dcb5a80ab8ffb38553c..4d05d93a0468849c3cd45021ef8dd5d0536c04f4 100644 (file)
--- a/loadlib.c
+++ b/loadlib.c
 #if defined(DYNAMIC_LOAD)
 #define    WIN_DYN_LOAD
 CSTR   libpqdll = "LIBPQ.dll";
+#ifdef _WIN64
+CSTR   gssapidll = "GSSAPI64.dll";
+#else
+CSTR   gssapidll = "GSSAPI32.dll";
+#endif /* _WIN64 */
 #ifdef UNICODE_SUPPORT
 CSTR   pgenlist = "pgenlist";
 CSTR   pgenlistdll = "PGENLIST.dll";
@@ -76,7 +81,12 @@ CSTR pgenlistdll = "PGENLISTA.dll";
 #endif /* DYNAMIC_LOAD */
 #endif /* WIN32 */
 
-CSTR   libpq = "libpq";
+CSTR   libpqlib = "libpq";
+#ifdef _WIN64
+CSTR   gssapilib = "gssapi64";
+#else
+CSTR   gssapilib = "gssapi32";
+#endif /* _WIN64 */
 #ifndef    NOT_USE_LIBPQ
 CSTR   checkproc = "PQconninfoParse";
 static int sslverify_available = -1;
@@ -84,7 +94,7 @@ static int    sslverify_available = -1;
 
 #if defined(_MSC_DELAY_LOAD_IMPORT)
 static BOOL    loaded_libpq = FALSE, loaded_ssllib = FALSE;
-static BOOL    loaded_pgenlist = FALSE;
+static BOOL    loaded_pgenlist = FALSE, loaded_gssapi = FALSE;
 /*
  * Load psqlodbc path based libpq dll.
  */
@@ -141,10 +151,10 @@ DliErrorHook(unsigned dliNotify,
 #else
            __pfnDliNotifyHook2 = NULL;
 #endif /* _MSC_VER */
-           if (_strnicmp(pdli->szDll, libpq, 5) == 0)
+           if (_strnicmp(pdli->szDll, libpqlib, strlen(libpqlib)) == 0)
            {
-               if (hmodule = MODULE_load_from_psqlodbc_path(libpq), NULL == hmodule)
-                   hmodule = LoadLibrary(libpq);
+               if (hmodule = MODULE_load_from_psqlodbc_path(libpqlib), NULL == hmodule)
+                   hmodule = LoadLibrary(libpqlib);
 #ifndef    NOT_USE_LIBPQ
                if (sslverify_available < 0)
                {
@@ -162,6 +172,23 @@ DliErrorHook(unsigned  dliNotify,
                if (hmodule = MODULE_load_from_psqlodbc_path(pgenlist), NULL == hmodule)
                    hmodule = LoadLibrary(pgenlist);
            }
+#ifdef USE_GSS
+           else if (_strnicmp(pdli->szDll, gssapilib, strlen(gssapilib)) == 0)
+           {
+#ifndef    NOT_USE_LIBPQ
+                       if (hmodule = GetModuleHandle(gssapilib), NULL == hmodule)
+#endif
+               {
+                   if (hmodule = MODULE_load_from_psqlodbc_path(gssapilib), NULL == hmodule)
+                   {
+                       if (hmodule = LoadLibrary(gssapilib), NULL != hmodule)
+                           loaded_gssapi = TRUE;
+                   }
+                   else
+                       loaded_gssapi = TRUE;
+               }
+           }
+#endif /* USE_GSS */
            else if (0 == _stricmp(pdli->szDll, libarray[0]) ||
                 0 == _stricmp(pdli->szDll, libarray[1]))
            {
@@ -223,6 +250,11 @@ void CleanupDelayLoadedDLLs(void)
        success = (*func)(pgenlistdll);
        mylog("%s unload success=%d\n", pgenlistdll, success);
    }
+   if (loaded_gssapi)
+   {
+       success = (*func)(gssapidll);
+       mylog("%s unload success=%d\n", gssapidll, success);
+   }
    return;
 }
 #else
@@ -267,7 +299,7 @@ BOOL    ssl_verify_available(void)
            sslverify_available = 0;
 #else
 #ifdef HAVE_LIBLTDL
-       lt_dlhandle dlhandle = lt_dlopenext(libpq);
+       lt_dlhandle dlhandle = lt_dlopenext(libpqlib);
 
        sslverify_available = 1;
        if (NULL != dlhandle)
@@ -382,9 +414,9 @@ BOOL SSLLIB_check()
    mylog("checking libpq library\n");
    /* First search the driver's folder */
 #ifndef    NOT_USE_LIBPQ
-   if (NULL == (hmodule = MODULE_load_from_psqlodbc_path(libpq)))
+   if (NULL == (hmodule = MODULE_load_from_psqlodbc_path(libpqlib)))
        /* Second try the PATH ordinarily */
-       hmodule = LoadLibrary(libpq);
+       hmodule = LoadLibrary(libpqlib);
    mylog("libpq hmodule=%p\n", hmodule);
 #endif /* NOT_USE_LIBPQ */
 #ifdef USE_SSPI
index 5440ecd8abbc74a762c1497862ac0fb7e9d39a33..1c806a34f8fba580f09835e6edf9681ed43d9fed 100644 (file)
@@ -5,7 +5,7 @@
  *
  * Comments:       See "notice.txt" for copyright and license information.
  *
- * $Id: psqlodbc.h,v 1.132 2009/10/25 13:36:31 hinoue Exp $
+ * $Id: psqlodbc.h,v 1.133 2010/01/17 13:10:41 hinoue Exp $
  *
  */
 
@@ -102,7 +102,10 @@ typedef    UInt4   OID;
 #define    FORMAT_UINT4    "%u"    /* UInt4 */
 
 #ifdef WIN32
+#ifndef    SSIZE_T_DEFINED
 #define    ssize_t SSIZE_T
+#define    SSIZE_T_DEFINED
+#endif
 #define    FORMAT_SIZE_T   "%Iu"   /* size_t */
 #define    FORMAT_SSIZE_T  "%Id"   /* ssize_t */
 #define    FORMAT_INTEGER  "%ld"   /* SQLINTEGER */
index 1ac1c6dadef75807a15d4271093309da47746ba0..3cafa666af5f11765d11ab180a9942d953c8059a 100644 (file)
@@ -199,6 +199,8 @@ BEGIN
     PUSHBUTTON      "\93K\97p",IDAPPLY,128,224,50,14
     CONTROL         "bytea\82ðLO\82Æ\82µ\82Ä\88µ\82¤",DS_BYTEAASLONGVARBINARY,"Button",
                     BS_AUTOCHECKBOX | WS_TABSTOP,15,85,87,10
+    CONTROL         "Kerberos\89\9e\93\9a\82ÉGSSAPI\97\98\97p",DS_GSSAUTHUSEGSSAPI,"Button",
+                    BS_AUTOCHECKBOX | WS_TABSTOP,139,85,110,10
 END
 
 DLG_OPTIONS_GLOBAL DIALOG DISCARDABLE  0, 0, 306, 115
@@ -547,6 +549,8 @@ BEGIN
                     BS_AUTOCHECKBOX | WS_TABSTOP,163,71,90,10
     CONTROL         "bytea as LO",DS_BYTEAASLONGVARBINARY,"Button",
                     BS_AUTOCHECKBOX | WS_TABSTOP,16,84,87,10
+    CONTROL         "use gssapi for GSS request",DS_GSSAUTHUSEGSSAPI,"Button",
+                    BS_AUTOCHECKBOX | WS_TABSTOP,163,84,110,10
     GROUPBOX        "Int8 As",IDC_STATIC,5,97,256,25
     CONTROL         "default",DS_INT8_AS_DEFAULT,"Button",BS_AUTORADIOBUTTON | 
                     WS_GROUP,12,107,40,10
index 1239facb21f3a2dce55a7be5da9e951e71ca0fbc..a2fc09ce496db357b739f79ed002d3ee1cead8b9 100644 (file)
@@ -97,6 +97,7 @@
 #define DS_EXTRA_OPTIONS       1084
 #define IDC_TEST           1085
 #define DS_LOGDIR          1086
+#define DS_GSSAUTHUSEGSSAPI        1087
 
 // Next default values for new objects
 // 
 #ifndef APSTUDIO_READONLY_SYMBOLS
 #define _APS_NEXT_RESOURCE_VALUE        105
 #define _APS_NEXT_COMMAND_VALUE         40001
-#define _APS_NEXT_CONTROL_VALUE         1087
+#define _APS_NEXT_CONTROL_VALUE         1088
 #define _APS_NEXT_SYMED_VALUE           101
 #endif
 #endif
index 2e3e1cc7fbaa17d114b0414bf11ce4a1ea823cab..f5d17b54b1a81c821776ffc3a771cf38f7a88a78 100644 (file)
--- a/socket.c
+++ b/socket.c
@@ -17,6 +17,9 @@
 #ifdef USE_SSPI
 #include "sspisvcs.h"
 #endif /* USE_SSPI */
+#ifdef USE_GSS
+#include "gsssvcs.h"
+#endif /* USE_GSS */
 #ifndef    NOT_USE_LIBPQ
 #include <libpq-fe.h>
 #ifdef USE_SSL
@@ -84,6 +87,10 @@ SOCK_Constructor(const ConnectionClass *conn)
        rv->ssd = NULL;
        rv->sspisvcs = 0;
 #endif /* USE_SSPI */
+#ifdef USE_GSS
+       rv->gctx = NULL;
+       rv->gtarg_nam = NULL;
+#endif /* USE_GSS */
 #ifndef    NOT_USE_LIBPQ
        rv->via_libpq = FALSE;
 #ifdef USE_SSL
@@ -156,12 +163,15 @@ SOCK_Destructor(SocketClass *self)
 #ifdef USE_SSPI
        if (self->ssd)
        {
-           ReleaseSvcSpecData(self);
+           ReleaseSvcSpecData(self, (UInt4) -1);
            free(self->ssd);
            self->ssd = NULL;
        }
        self->sspisvcs = 0;
 #endif /* USE_SSPI */
+#ifdef USE_GSS
+       pg_GSS_cleanup(self);
+#endif /* USE_GSS */
    }
 
    if (self->buffer_in)
index 0cf7d47a3cb8851e1c20fe8e554ee14c83212620..1559968bb7424899978b89ddadace603ccaf566d 100644 (file)
--- a/socket.h
+++ b/socket.h
 #define __SOCKET_H__
 
 #include "psqlodbc.h"
+#if defined (USE_GSS)
+#ifdef HAVE_GSSAPI_H
+#include <gssapi.h>
+#else
+#include <gssapi/gssapi.h>
+#endif
+#endif
 #include <errno.h>
 
 #ifndef WIN32
@@ -160,10 +167,13 @@ struct SocketClass_
    void        *pqconn;    /* libpq PGConn */
    BOOL        via_libpq;  /* using libpq library ? */
 #endif /* NOT_USE_LIBPQ */
+#ifdef USE_GSS
+   gss_ctx_id_t    gctx;       /* GSS context */
+   gss_name_t  gtarg_nam;  /* GSS target name */
+#endif /* USE_GSS */
 
-   char        reverse;        /* used to handle Postgres 6.2 protocol
-                                * (reverse byte order) */
-
+   char        reverse;    /* used to handle Postgres 6.2 protocol
+                       * (reverse byte order) */
 };
 
 #define SOCK_get_char(self)    (SOCK_get_next_byte(self, FALSE))
index 3ac01d48074e581f722d7fd91ced4cc36eda1ff6..e13a3ce90f42d32bec76aba3bf8f654d06843fe5 100644 (file)
@@ -122,21 +122,121 @@ static int recvall(SOCKET sock, void *buf, int len)
    return ttllen;
 }
  
-CSTR   SCHANNEL = "sChannel";
-static int DoSchannelNegotiation(SocketClass *, const char *opt);
-int StartupSspiService(SocketClass *self, SSPI_Service svc, const char *opt)
+/* 
+ * service specific data
+ */
+
+/* Schannel specific data */
+typedef    struct {
+   CredHandle  hCred;
+   CtxtHandle  hCtxt;
+   PBYTE       ioovrbuf;
+   size_t      ioovrlen;
+   PBYTE       iobuf;
+   size_t      iobuflen;
+   size_t      ioread;
+} SchannelSpec;
+
+/* Kerberos/Negotiate common specific data */
+typedef    struct {
+   LPTSTR      svcprinc;
+   CredHandle  hKerbEtcCred;
+   BOOL        ValidCtxt;
+   CtxtHandle  hKerbEtcCtxt;
+} KerberosEtcSpec;
+
+typedef struct {
+   SchannelSpec    sdata;
+   KerberosEtcSpec kdata;
+} SspiData;
+
+static int DoSchannelNegotiation(SocketClass *, SspiData *, const void *opt);
+static int DoKerberosNegotiation(SocketClass *, SspiData *, const void *opt);
+static int DoNegotiateNegotiation(SocketClass *, SspiData *, const void *opt);
+static int DoKerberosEtcProcessAuthentication(SocketClass *, const void *opt);
+
+static SspiData *SspiDataAlloc(SocketClass *self)
+{
+   SspiData    *sspidata;
+
+   if (sspidata = self->ssd, !sspidata)
+       sspidata = calloc(sizeof(SspiData), 1);
+   return sspidata;
+}
+
+int StartupSspiService(SocketClass *self, SSPI_Service svc, const void *opt)
 {
    CSTR func = "DoServicelNegotiation";
+   SspiData    *sspidata;
 
+   if (NULL == (sspidata = SspiDataAlloc(self)))
+       return -1;
    switch (svc)
    {
        case SchannelService:
-           return DoSchannelNegotiation(self, opt);
+           return DoSchannelNegotiation(self, sspidata, opt);
+       case KerberosService:
+           return DoKerberosNegotiation(self, sspidata, opt);
+       case NegotiateService:
+           return DoNegotiateNegotiation(self, sspidata, opt);
    }
 
+   free(sspidata);
    return -1;
 }
 
+int ContinueSspiService(SocketClass *self, SSPI_Service svc, const void *opt)
+{
+   CSTR func = "ContinueSspiService";
+
+   switch (svc)
+   {
+       case KerberosService:
+       case NegotiateService:
+           return DoKerberosEtcProcessAuthentication(self, opt);
+   }
+
+   return -1;
+}
+
+static BOOL format_sspierr(char *errmsg, size_t buflen, SECURITY_STATUS r, const char *cmd, const char *cmd2)
+{
+   BOOL ret = FALSE;
+
+   if (!cmd2)
+       cmd2 = ""; 
+   if (FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM, NULL,
+       r, MAKELANGID(LANG_ENGLISH, SUBLANG_DEFAULT),
+       errmsg, (DWORD)buflen, NULL))
+       ret = TRUE;
+   if (ret)
+   {
+       size_t  tlen = strlen(errmsg);
+       errmsg += tlen;
+       buflen -= tlen;
+       snprintf(errmsg, buflen, " in %s:%s", cmd, cmd2);
+   }
+   else
+       snprintf(errmsg, buflen, "%s:%s failed ", cmd, cmd2);
+   return ret;
+}
+
+static void SSPI_set_error(SocketClass *s, SECURITY_STATUS r, const char *cmd, const char *cmd2)
+{
+   int gerrno = SOCK_ERRNO;
+   char    emsg[256];
+
+   format_sspierr(emsg, sizeof(emsg), r, cmd, cmd2);
+   s->errornumber = r;
+   if (NULL != s->_errormsg_)
+       free(s->_errormsg_);
+   if (NULL != emsg)
+       s->_errormsg_ = strdup(emsg);
+   else
+       s->_errormsg_ = NULL;
+   mylog("(%d)%s ERRNO=%d\n", r, emsg, gerrno);
+}
+
 /*
  * Stuff for Schannel service
  */
@@ -145,16 +245,6 @@ int StartupSspiService(SocketClass *self, SSPI_Service svc, const char *opt)
 #define    UNI_SCHANNEL TEXT("sChannel")
 #define    IO_BUFFER_SIZE  0x10000
 
-typedef    struct {
-   CredHandle  hCred;
-   CtxtHandle  hCtxt;
-   PBYTE       ioovrbuf;
-   size_t      ioovrlen;
-   PBYTE       iobuf;
-   size_t      iobuflen;
-   size_t      ioread;
-} SchannelSpec;
-
 static SECURITY_STATUS CreateSchannelCredentials(LPCTSTR, LPSTR, PCredHandle);
 static SECURITY_STATUS PerformSchannelClientHandshake(SOCKET, PCredHandle, LPSTR, CtxtHandle *, SecBuffer *);
 static SECURITY_STATUS SchannelClientHandshakeLoop(SOCKET, PCredHandle, CtxtHandle *, BOOL, SecBuffer *);
@@ -162,26 +252,26 @@ static void GetNewSchannelClientCredentials(PCredHandle, CtxtHandle *);
 
 static HCERTSTORE  hMyCertStore = NULL;
 
-static int DoSchannelNegotiation(SocketClass *self, const char *opt)
+static int DoSchannelNegotiation(SocketClass *self, SspiData *sspidata, const void *opt)
 {
    CSTR func = "DoSchannelNegotiation";
+   SECURITY_STATUS r = SEC_E_OK;
+   const char  *cmd = NULL;
    SecBuffer   ExtraData;
    BOOL        ret = 0, cCreds = FALSE, cCtxt = FALSE;
-   SchannelSpec    *ssd = NULL;
+   SchannelSpec    *ssd = &(sspidata->sdata);
 
-   if (NULL == (ssd = calloc(sizeof(SchannelSpec), 1)))
-   {
-       return 0;
-   }
-   if (SEC_E_OK != CreateSchannelCredentials(NULL, NULL, &ssd->hCred))
+   if (SEC_E_OK != (r = CreateSchannelCredentials(NULL, NULL, &ssd->hCred)))
    {
-       mylog("%s:CreateSchannel failed\n", func);
+       cmd = "CreateSchannelCredentials";
+       mylog("%s:%s failed\n", func, cmd);
        goto cleanup;
    }
    cCreds = TRUE;
-   if (SEC_E_OK != PerformSchannelClientHandshake(self->socket, &ssd->hCred, NULL, &ssd->hCtxt, &ExtraData))
+   if (SEC_E_OK != (r = PerformSchannelClientHandshake(self->socket, &ssd->hCred, NULL, &ssd->hCtxt, &ExtraData)))
    {
-       mylog("%s:PerformSchannelClientHandshake failed\n", func);
+       cmd = "PerformSchannelClientHandshake";
+       mylog("%s:%s failed\n", func, cmd);
        goto cleanup;
    }
    cCtxt = TRUE;
@@ -198,17 +288,19 @@ cleanup:
    if (ret)
    {
        self->sspisvcs |= SchannelService;
-       self->ssd = ssd;
+       self->ssd = sspidata;
    }
    else
    {
+       SSPI_set_error(self, r, __FUNCTION__, cmd); 
        if (cCreds)
            FreeCredentialHandle(&ssd->hCred);
        if (cCtxt)
            DeleteSecurityContext(&ssd->hCtxt);
        if (ssd->iobuf)
            free(ssd->iobuf);
-       free(ssd);
+       if (!self->ssd)
+           free(sspidata);
    }
    return ret;
 }
@@ -303,15 +395,15 @@ CreateSchannelCredentials(
     */
 
    Status = AcquireCredentialsHandle(
-           NULL,                   /* Name of principal */    
-           UNI_SCHANNEL,           /* Name of package */
-           SECPKG_CRED_OUTBOUND,   /* Flags indicating use */
-           NULL,                   /* Pointer to logon ID */
-           &SchannelCred,          /* Package specific data */
-           NULL,                   /* Pointer to GetKey() func */
-           NULL,                   /* Value to pass to GetKey() */
-           phCreds,                /* (out) Cred Handle */
-           &tsExpiry);             /* (out) Lifetime (optional) */
+           NULL,           /* Name of principal */    
+           UNI_SCHANNEL,       /* Name of package */
+           SECPKG_CRED_OUTBOUND,   /* Flags indicating use */
+           NULL,           /* Pointer to logon ID */
+           &SchannelCred,      /* Package specific data */
+           NULL,           /* Pointer to GetKey() func */
+           NULL,           /* Value to pass to GetKey() */
+           phCreds,        /* (out) Cred Handle */
+           &tsExpiry);     /* (out) Lifetime (optional) */
    if (Status != SEC_E_OK)
    {
        mylog("**** Error 0x%p returned by AcquireCredentialsHandle\n", Status);
@@ -385,7 +477,7 @@ PerformSchannelClientHandshake(
 
    if (scRet != SEC_I_CONTINUE_NEEDED)
    {
-       mylog("**** Error %d returned by InitializeSecurityContext (1)\n", scRet);
+       mylog("**** Error %x returned by InitializeSecurityContext (1)\n", scRet);
        return scRet;
    }
 
@@ -397,7 +489,7 @@ PerformSchannelClientHandshake(
                OutBuffers[0].cbBuffer);
        if (cbData <= 0)
        {
-           mylog("**** Error %d sending data to server (1)\n", SOCK_ERRNO);
+           mylog("**** Error %x sending data to server\n", SOCK_ERRNO);
            FreeContextBuffer(OutBuffers[0].pvBuffer);
            DeleteSecurityContext(phContext);
            return SEC_E_INTERNAL_ERROR;
@@ -496,6 +588,7 @@ SchannelClientHandshakeLoop(
                                continue;
                        default:
                            scRet = SEC_E_INTERNAL_ERROR;
+                           SOCK_ERRNO_SET(gerrno);
                            break;
                    }
                    break;
@@ -830,6 +923,252 @@ GetNewSchannelClientCredentials(
    }
 }
 
+/*
+ * Stuff for Kerberos etc service
+ */
+#define    UNI_KERBEROS TEXT("Kerberos")
+#define    UNI_NEGOTIATE TEXT("Negotiate")
+#define    IO_BUFFER_SIZE  0x10000
+
+
+static SECURITY_STATUS CreateKerberosEtcCredentials(LPCTSTR, SEC_CHAR *, LPCTSTR, PCredHandle);
+static SECURITY_STATUS PerformKerberosEtcClientHandshake(SocketClass *, KerberosEtcSpec *ssd, size_t);
+
+static int DoKerberosNegotiation(SocketClass *self, SspiData *sspidata, const void *opt)
+{
+   CSTR func = "DoKerberosNegotiation";
+   SECURITY_STATUS r = SEC_E_OK;
+   const char *    cmd = NULL;
+   BOOL        ret = 0;
+   KerberosEtcSpec *ssd = &(sspidata->kdata);
+
+mylog("!!! %s in\n", __FUNCTION__);
+   if (SEC_E_OK != (r = CreateKerberosEtcCredentials(NULL, UNI_KERBEROS, (LPCTSTR) opt, &ssd->hKerbEtcCred)))
+   {
+       cmd = "CreateKerberosCredentials";
+       mylog("%s:%s failed\n", func, cmd);
+       SSPI_set_error(self, r, __FUNCTION__, cmd); 
+       return 0;
+   }
+mylog("!!! CreateKerberosCredentials passed\n");
+
+   ssd->svcprinc = (LPTSTR) opt;
+   self->sspisvcs |= KerberosService;
+   self->ssd = sspidata;
+   return DoKerberosEtcProcessAuthentication(self, NULL);
+}
+
+static int DoNegotiateNegotiation(SocketClass *self, SspiData *sspidata, const void *opt)
+{
+   CSTR func = "DoNegotiateNegotiation";
+   SECURITY_STATUS r = SEC_E_OK;
+   const char *    cmd = NULL;
+   BOOL        ret = 0;
+   KerberosEtcSpec *ssd = &(sspidata->kdata);
+
+mylog("!!! %s in\n", __FUNCTION__);
+   if (SEC_E_OK != (r = CreateKerberosEtcCredentials(NULL, UNI_NEGOTIATE, (LPCTSTR) opt, &ssd->hKerbEtcCred)))
+   {
+       cmd = "CreateNegotiateCredentials";
+       mylog("%s:%s failed\n", func, cmd);
+       SSPI_set_error(self, r, __FUNCTION__, cmd); 
+       return 0;
+   }
+mylog("!!! CreateNegotiateCredentials passed\n");
+
+   ssd->svcprinc = (LPTSTR) opt;
+   self->sspisvcs |= NegotiateService;
+   self->ssd = sspidata;
+   return DoKerberosEtcProcessAuthentication(self, NULL);
+}
+
+static int DoKerberosEtcProcessAuthentication(SocketClass *self, const void *opt)
+{
+   CSTR func = "DoKerberosEtcProcessAuthentication";
+   SECURITY_STATUS r = SEC_E_OK;
+   const char *    cmd = NULL;
+   BOOL        ret = 0, cCtxt = FALSE;
+   KerberosEtcSpec *ssd;
+
+mylog("!!! %s in\n", __FUNCTION__);
+   ssd = &(((SspiData *)(self->ssd))->kdata);
+   if (SEC_E_OK != (r = PerformKerberosEtcClientHandshake(self, ssd, (size_t) opt)))
+   {
+       cmd = "PerformKerberosEtcClientHandshake";
+       mylog("%s:%s failed\n", func, cmd);
+       goto cleanup;
+   }
+mylog("!!! PerformKerberosEtcClientHandshake passed\n");
+   cCtxt = TRUE;
+   ret = TRUE;
+cleanup:
+   if (!ret)
+   {
+       SSPI_set_error(self, r, __FUNCTION__, cmd); 
+       FreeCredentialHandle(&ssd->hKerbEtcCred);
+       if (cCtxt)
+       {
+           DeleteSecurityContext(&ssd->hKerbEtcCtxt);
+       }
+       self->sspisvcs &= (~(KerberosService | NegotiateService));
+   }
+   return ret;
+}
+
+static
+SECURITY_STATUS
+CreateKerberosEtcCredentials(
+   LPCTSTR opt,        /* in */
+   SEC_CHAR *packname, /* in */
+   LPCTSTR pszUserName,    /* in */
+   PCredHandle phCreds)    /* out */
+{
+   TimeStamp   tsExpiry;
+   SECURITY_STATUS Status;
+
+   /*
+    * Create an SSPI credential.
+    */
+
+   Status = AcquireCredentialsHandle(
+           NULL,           /* Name of principal */    
+           packname,       /* Name of package */
+           SECPKG_CRED_OUTBOUND,   /* Flags indicating use */
+           NULL,           /* Pointer to logon ID */
+           NULL,           /* Package specific data */
+           NULL,           /* Pointer to GetKey() func */
+           NULL,           /* Value to pass to GetKey() */
+           phCreds,        /* (out) Cred Handle */
+           &tsExpiry);     /* (out) Lifetime (optional) */
+   if (Status != SEC_E_OK)
+   {
+       mylog("**** Error 0x%p returned by AcquireCredentialsHandle\n", Status);
+       goto cleanup;
+   }
+
+cleanup:
+
+    return Status;
+}
+
+static
+SECURITY_STATUS
+PerformKerberosEtcClientHandshake(
+   SocketClass *sock,      /* in */
+   KerberosEtcSpec *ssd,       /* i-o */
+   size_t      inlen)
+{
+   SecBufferDesc   InBuffer;
+   SecBuffer   InBuffers[1];
+   SecBufferDesc   OutBuffer;
+   SecBuffer   OutBuffers[1];
+   DWORD       dwSSPIFlags;
+   DWORD       dwSSPIOutFlags;
+   TimeStamp   tsExpiry;
+   SECURITY_STATUS scRet;
+   CtxtHandle  hContext;
+   PBYTE       inbuf = NULL;
+
+mylog("!!! inlen=%u svcprinc=%s\n", inlen, ssd->svcprinc); 
+   if (ssd->ValidCtxt && inlen > 0)
+   {
+       if (NULL == (inbuf = malloc(inlen + 1)))
+       {
+           return SEC_E_INTERNAL_ERROR;
+       }
+       SOCK_get_n_char(sock, inbuf, inlen);
+       if (SOCK_get_errcode(sock) != 0)
+       {
+           mylog("**** Error %d receiving data from server (1)\n", SOCK_ERRNO);
+           free(inbuf);
+           return SEC_E_INTERNAL_ERROR;
+       }
+
+       InBuffer.ulVersion = SECBUFFER_VERSION;
+       InBuffer.cBuffers = 1;
+       InBuffer.pBuffers = InBuffers;
+       InBuffers[0].pvBuffer = inbuf; 
+       InBuffers[0].cbBuffer = inlen; 
+       InBuffers[0].BufferType = SECBUFFER_TOKEN; 
+   }
+
+   dwSSPIFlags = ISC_REQ_SEQUENCE_DETECT   |
+           ISC_REQ_REPLAY_DETECT   |
+           ISC_REQ_CONFIDENTIALITY |
+           ISC_RET_EXTENDED_ERROR  |
+           ISC_REQ_ALLOCATE_MEMORY |
+           ISC_REQ_STREAM;
+
+   /*
+    *  Initiate a ClientHello message and generate a token.
+    */
+
+   OutBuffers[0].pvBuffer  = NULL;
+   OutBuffers[0].BufferType = SECBUFFER_TOKEN;
+   OutBuffers[0].cbBuffer  = 0;
+
+   OutBuffer.cBuffers = 1;
+   OutBuffer.pBuffers = OutBuffers;
+   OutBuffer.ulVersion = SECBUFFER_VERSION;
+
+mylog("!!! before InitializeSecurityContext\n"); 
+   scRet = InitializeSecurityContext(
+                   &ssd->hKerbEtcCred,
+                   ssd->ValidCtxt ? &ssd->hKerbEtcCtxt : NULL,
+                   ssd->svcprinc,
+                   dwSSPIFlags,
+                   0,
+                   SECURITY_NATIVE_DREP,
+                   ssd->ValidCtxt ? &InBuffer : NULL,
+                   0,
+                   &hContext,
+                   &OutBuffer,
+                   &dwSSPIOutFlags,
+                   &tsExpiry);
+mylog("!!! %s:InitializeSecurityContext ret=%x\n", __FUNCTION__, scRet); 
+
+   if (inbuf)
+       free(inbuf);
+   if (SEC_E_OK != scRet && SEC_I_CONTINUE_NEEDED != scRet)
+   {
+       mylog("**** Error %x returned by InitializeSecurityContext\n", scRet);
+       return scRet;
+   }
+   if (!ssd->ValidCtxt)
+   {
+       memcpy(&ssd->hKerbEtcCtxt, &hContext, sizeof(CtxtHandle));
+       ssd->ValidCtxt = TRUE;
+   }
+
+mylog("!!! cbBuffer=%d pvBuffer=%p\n", OutBuffers[0].cbBuffer, OutBuffers[0].pvBuffer); 
+   /* Send response to server if there is one. */
+   if (OutBuffers[0].cbBuffer != 0 && OutBuffers[0].pvBuffer != NULL)
+   {
+       int reslen = OutBuffers[0].cbBuffer;
+mylog("!!! responding 'p' + int(%d) + %dbytes of data\n", reslen + 4, reslen); 
+       SOCK_put_char(sock, 'p');
+       SOCK_put_int(sock, reslen + 4, 4);
+       SOCK_put_n_char(sock, OutBuffers[0].pvBuffer, reslen);
+       SOCK_flush_output(sock);
+       if (SOCK_get_errcode(sock) != 0)
+       {
+           mylog("**** Error %d sending data to server (1)\n", SOCK_ERRNO);
+           FreeContextBuffer(OutBuffers[0].pvBuffer);
+           return SEC_E_INTERNAL_ERROR;
+       }
+
+       mylog("%d bytes of handshake data sent\n", OutBuffers[0].cbBuffer);
+
+       /* Free output buffer. */
+       FreeContextBuffer(OutBuffers[0].pvBuffer);
+       OutBuffers[0].pvBuffer = NULL;
+   }
+
+   return SEC_E_OK;
+   // return KerberosEtcClientHandshakeLoop(Socket, ssd, TRUE, pExtraData);
+}
+
+
 int SSPI_recv(SocketClass *self, void *buffer, int len)
 {
    CSTR func = "SSPI_recv";
@@ -847,7 +1186,7 @@ int SSPI_recv(SocketClass *self, void *buffer, int len)
        DWORD   cbIoBuffer, cbIoBufferLength;
 
        DWORD   cbData;
-       SchannelSpec *ssd = (SchannelSpec *) self->ssd;
+       SchannelSpec *ssd = &(((SspiData *)(self->ssd))->sdata);
 
 mylog("buflen=%d,%d ovrlen=%d\n", ssd->iobuflen, ssd->ioread, ssd->ioovrlen);
        if (ssd->ioovrlen > 0)
@@ -914,13 +1253,12 @@ mylog("buf=%p read=%d req=%d\n", pbIoBuffer, cbIoBuffer, reqlen);
                    {
                        case EINTR:
                            continue;
-                       case ECONNRESET:
-                           break;
                        case EWOULDBLOCK:
                            retry_count++;
                            if (Socket_wait_for_ready(self->socket, FALSE, retry_count) >= 0)
                                continue;
                        default:
+                           SOCK_ERRNO_SET(gerrno);
                            scRet = SEC_E_INTERNAL_ERROR;
                            break;
                    }
@@ -1091,7 +1429,7 @@ int SSPI_send(SocketClass *self, const void *buffer, int len)
        LPVOID  lpTrail;
        SecBuffer   sb[4];
        SecBufferDesc   sbd;
-       SchannelSpec *ssd = (SchannelSpec *) self->ssd;
+       SchannelSpec *ssd = &(((SspiData *)(self->ssd))->sdata);
 
        QueryContextAttributes(&ssd->hCtxt, SECPKG_ATTR_STREAM_SIZES, &sizes);
        slen = len;
@@ -1142,13 +1480,13 @@ mylog("EMPTY=%p %d %d\n", sb[3].pvBuffer, sb[3].cbBuffer, sb[3].BufferType);
        return send(self->socket, (char *) buffer, len, SEND_FLAG);
 }
 
-void ReleaseSvcSpecData(SocketClass *self)
+void ReleaseSvcSpecData(SocketClass *self, UInt4 svc)
 {
    if (!self->ssd)
        return;
-   if (0 != (self->sspisvcs & SchannelService))
+   if (0 != (self->sspisvcs & (svc & SchannelService)))
    {
-       SchannelSpec *ssd = (SchannelSpec *) self->ssd;
+       SchannelSpec *ssd = &(((SspiData *)(self->ssd))->sdata);
 
        if (ssd->iobuf)
        {
@@ -1164,5 +1502,22 @@ void ReleaseSvcSpecData(SocketClass *self)
        DeleteSecurityContext(&ssd->hCtxt);
        self->sspisvcs &= (~SchannelService);
    }
+   if (0 != (self->sspisvcs & (svc & (KerberosService | NegotiateService))))
+   {
+       KerberosEtcSpec *ssd = &(((SspiData *)(self->ssd))->kdata);
+
+       if (ssd->svcprinc)
+       {
+           free(ssd->svcprinc);
+           ssd->svcprinc = NULL;
+       }
+       FreeCredentialHandle(&ssd->hKerbEtcCred);
+       if (ssd->ValidCtxt)
+       {
+           DeleteSecurityContext(&ssd->hKerbEtcCtxt);
+           ssd->ValidCtxt = FALSE;
+       }
+       self->sspisvcs &= (~(KerberosService | NegotiateService));
+   }
 }
 #endif /* USE_SSPI */
index eeb87543473ca479baf2ed1c911b4c6b10fa053b..8a838b81276062e1d4c32926b2c6a1d83e33ca70 100755 (executable)
 typedef enum {
    SchannelService = 1L
    ,KerberosService = (1L << 1)
+   ,NegotiateService = (1L << 2)
 } SSPI_Service;
 
-void   ReleaseSvcSpecData(SocketClass *self);
-int    StartupSspiService(SocketClass *self, SSPI_Service svc, const char *opt);
+void   ReleaseSvcSpecData(SocketClass *self, UInt4);
+int    StartupSspiService(SocketClass *self, SSPI_Service svc, const void *opt);
+int    ContinueSspiService(SocketClass *self, SSPI_Service svc, const void *opt);
 int    SSPI_recv(SocketClass *self, void *buf, int len);
 int    SSPI_send(SocketClass *self, const void *buf, int len);
 
index 0e1e342774b0995b5b101e7426a9eff499520d96..a670e050650037a8e2dfc7bc9542485e9460bd1f 100644 (file)
@@ -852,7 +852,7 @@ inolog("%s statement=%p ommitted=0\n", func, self);
 }
 
 /*
- * Scan the query wholly or partially (if specifed next_cmd).
+ * Scan the query wholly or partially (if the next_cmd param specified).
  * Also count the number of parameters respectviely.
  */
 void
@@ -867,6 +867,7 @@ SC_scanQueryAndCountParams(const char *query, const ConnectionClass *conn,
    char    tchar, bchar, escape_in_literal = '\0';
    char    in_literal = FALSE, in_identifier = FALSE,
        in_dollar_quote = FALSE, in_escape = FALSE,
+       in_line_comment = FALSE, in_comment = FALSE,
        del_found = FALSE;
    po_ind_t multi = FALSE;
    SQLSMALLINT num_p;
@@ -926,6 +927,20 @@ SC_scanQueryAndCountParams(const char *query, const ConnectionClass *conn,
            if (tchar == identifier_quote)
                in_identifier = FALSE;
        }
+       else if (in_line_comment)
+       {
+           if (PG_LINEFEED == tchar)
+               in_line_comment = FALSE;
+       }
+       else if (in_comment)
+       {
+           if ('*' == tchar && '/' == sptr[1])
+           {
+               encoded_nextchar(&encstr);
+               sptr++;
+               in_comment = FALSE;
+           }
+       }
        else
        {
            if (tchar == '?')
@@ -968,6 +983,24 @@ SC_scanQueryAndCountParams(const char *query, const ConnectionClass *conn,
            }
            else if (tchar == identifier_quote)
                in_identifier = TRUE;
+           else if ('-' == tchar)
+           {
+               if ('-' == sptr[1])
+               {
+                   encoded_nextchar(&encstr);
+                   sptr++;
+                   in_line_comment = TRUE;
+               }
+           }
+           else if ('/' == tchar)
+           {
+               if ('*' == sptr[1])
+               {
+                   encoded_nextchar(&encstr);
+                   sptr++;
+                   in_comment = TRUE;
+               }
+           }
            if (!isspace(tchar))
                bchar = tchar;
        }
@@ -2476,7 +2509,11 @@ inolog("!![%d].PGType %u->%u\n", i, PIC_get_pgtype(ipdopts->parameters[i]), CI_g
                break;
            case 'B': /* Binary data */
            case 'D': /* ASCII data */
-               QR_get_tupledata(res, id == 'B');
+               if (!QR_get_tupledata(res, id == 'B'))
+               {
+                   rcvend = TRUE;
+                   res = NULL;
+               }
                break;
            case 'S': /* parameter status */
                getParameterValues(conn);
index e98843e8b30232780110dd490218c4a206b5f37e..5abc9752dbf78af5dd1e522f8c41aecfb597e8ea 100644 (file)
--- a/version.h
+++ b/version.h
@@ -9,9 +9,9 @@
 #ifndef __VERSION_H__
 #define __VERSION_H__
 
-#define POSTGRESDRIVERVERSION      "08.04.0200"
-#define POSTGRES_RESOURCE_VERSION  "08.04.0200\0"
-#define PG_DRVFILE_VERSION     8,4,02,00
-#define PG_BUILD_VERSION       "200912260001"
+#define POSTGRESDRIVERVERSION      "08.04.0201"
+#define POSTGRES_RESOURCE_VERSION  "08.04.0201\0"
+#define PG_DRVFILE_VERSION     8,4,02,01
+#define PG_BUILD_VERSION       "201001130001"
 
 #endif