On Wed, Jul 18, 2007 at 12:16:42PM +0200, Magnus Hagander wrote:
> Attached is the patch to support SSPI authentication in libpq. With this
> patch, I can authenticate windows clients against a linux server using
> kerberos *without* reqiring setting up MIT kerberos on the windows side.
> Protocol has not changed at all.

Here's an updated version of this patch. This version has full SSPI support
in the server as well, so I can do both kerberos and NTLM between two
windows machines using the negotiate method.

I've added a libpq connection parameter gsslib and the corresponding
environment variable PGGSSLIB. If it's set to "gssapi", libpq will use the
MIT GSSAPI implementation to authenticate to GSSAPI servers. If it's not
set, or set to anything else, SSPI will be used in Kerberos mode. SSPI in
negotiate mode will only be used if the server requests "sspi"
authentication instead of "gss".

Server-side, I've added the new authentication method "sspi" so the server
can inform the client that it wants to do SSPI "negotiate" auth instead of
plain Kerberos.

Since SSPI and GSSAPI can now both be used, my plan is not to have an
autoconf to disable SSPI, but to just enable it unconditionally on win32.
Or does this seem like a bad idea?

Comments welcome.

//Magnus
Index: src/backend/libpq/auth.c
===================================================================
RCS file: /projects/cvsroot/pgsql/src/backend/libpq/auth.c,v
retrieving revision 1.153
diff -c -r1.153 auth.c
*** src/backend/libpq/auth.c    12 Jul 2007 20:36:11 -0000      1.153
--- src/backend/libpq/auth.c    19 Jul 2007 11:25:34 -0000
***************
*** 464,473 ****
--- 464,477 ----
                        /*
                         * Negotiation generated data to be sent to the client.
                         */
+                       OM_uint32       lmin_s;
+ 
                        elog(DEBUG4, "sending GSS response token of length %u",
                                 (unsigned int) port->gss->outbuf.length);
  
                        sendAuthRequest(port, AUTH_REQ_GSS_CONT);
+ 
+                       gss_release_buffer(&lmin_s, &port->gss->outbuf);
                }
  
                if (maj_stat != GSS_S_COMPLETE && maj_stat != 
GSS_S_CONTINUE_NEEDED)
***************
*** 536,542 ****
        return STATUS_OK;
  }
  
! #else /* no ENABLE_GSS */
  static int
  pg_GSS_recvauth(Port *port)
  {
--- 540,546 ----
        return STATUS_OK;
  }
  
! #else /* no ENABLE_GSS */
  static int
  pg_GSS_recvauth(Port *port)
  {
***************
*** 547,552 ****
--- 551,795 ----
  }
  #endif        /* ENABLE_GSS */
  
+ #ifdef ENABLE_SSPI
+ static void
+ pg_SSPI_error(int severity, char *errmsg, SECURITY_STATUS r)
+ {
+       char sysmsg[256];
+ 
+       if (FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM, NULL, r, 0, sysmsg, 
sizeof(sysmsg), NULL) == 0)
+               ereport(severity,
+                       (errmsg_internal("%s", errmsg),
+                               errdetail("sspi error %x", r)));
+       else
+               ereport(severity,
+                       (errmsg_internal("%s", errmsg),
+                               errdetail("%s (%x)", sysmsg, r)));
+ }
+ 
+ 
+ static int
+ pg_SSPI_recvauth(Port *port)
+ {
+       int                             mtype;
+       StringInfoData  buf;
+       SECURITY_STATUS r;
+       CredHandle              sspicred;
+       CtxtHandle              *sspictx = NULL,
+                           newctx;
+       TimeStamp               expiry;
+       ULONG                   contextattr;
+       SecBufferDesc   inbuf;
+       SecBufferDesc   outbuf;
+       SecBuffer               OutBuffers[1];
+       SecBuffer               InBuffers[1];
+       HANDLE                  token;
+       TOKEN_USER              *tokenuser;
+       DWORD                   retlen;
+       char                    accountname[MAXPGPATH];
+       char                    domainname[MAXPGPATH];
+       DWORD                   accountnamesize = sizeof(accountname);
+       DWORD                   domainnamesize = sizeof(domainname);
+       SID_NAME_USE    accountnameuse;
+ 
+ 
+       /*
+        * Acquire a handle to the server credentials.
+        */
+       r = AcquireCredentialsHandle(NULL,
+               "negotiate",
+               SECPKG_CRED_INBOUND,
+               NULL,
+               NULL,
+               NULL,
+               NULL,
+               &sspicred,
+               &expiry);
+       if (r != SEC_E_OK)
+               pg_SSPI_error(ERROR, 
+                                       gettext_noop("could not acquire SSPI 
credentials handle"), r);
+ 
+       /*
+        * Loop through SSPI message exchange. This exchange can consist
+        * of multiple messags sent in both directions. First message is always
+        * from the client. All messages from client to server are password
+        * packets (type 'p').
+        */
+       do 
+       {
+               mtype = pq_getbyte();
+               if (mtype != 'p')
+               {
+                       /* Only log error if client didn't disconnect. */
+                       if (mtype != EOF)
+                               ereport(COMMERROR,
+                                               
(errcode(ERRCODE_PROTOCOL_VIOLATION),
+                                                errmsg("expected SSPI 
response, got message type %d",
+                                                        mtype)));
+                       return STATUS_ERROR;
+               }
+ 
+               /* Get the actual SSPI token */
+               initStringInfo(&buf);
+               if (pq_getmessage(&buf, 2000))
+               {
+                       /* EOF - pq_getmessage already logged error */
+                       pfree(buf.data);
+                       return STATUS_ERROR;
+               }
+ 
+               /* Map to SSPI style buffer */
+               inbuf.ulVersion = SECBUFFER_VERSION;
+               inbuf.cBuffers = 1;
+               inbuf.pBuffers = InBuffers;
+               InBuffers[0].pvBuffer = buf.data;
+               InBuffers[0].cbBuffer = buf.len;
+               InBuffers[0].BufferType = SECBUFFER_TOKEN;
+ 
+               /* Prepare output buffer */
+               OutBuffers[0].pvBuffer = NULL;
+               OutBuffers[0].BufferType = SECBUFFER_TOKEN;
+               OutBuffers[0].cbBuffer = 0;
+               outbuf.cBuffers = 1;
+               outbuf.pBuffers = OutBuffers;
+               outbuf.ulVersion = SECBUFFER_VERSION;
+ 
+ 
+               elog(DEBUG4, "Processing received SSPI token of length %u", 
+                        (unsigned int) buf.len);
+ 
+               r = AcceptSecurityContext(&sspicred,
+                       sspictx,
+                       &inbuf,
+                       ASC_REQ_ALLOCATE_MEMORY,
+                       SECURITY_NETWORK_DREP,
+                       &newctx,
+                       &outbuf,
+                       &contextattr,
+                       NULL);
+ 
+               /* input buffer no longer used */
+               pfree(buf.data);
+ 
+               if (outbuf.cBuffers > 0 && outbuf.pBuffers[0].cbBuffer > 0)
+               {
+                       /*
+                        * Negotiation generated data to be sent to the client.
+                        */
+                       elog(DEBUG4, "sending SSPI response token of length %u",
+                                (unsigned int) outbuf.pBuffers[0].cbBuffer);
+ 
+                       port->gss->outbuf.length = outbuf.pBuffers[0].cbBuffer;
+                       port->gss->outbuf.value = outbuf.pBuffers[0].pvBuffer;
+ 
+                       sendAuthRequest(port, AUTH_REQ_GSS_CONT);
+ 
+                       FreeContextBuffer(outbuf.pBuffers[0].pvBuffer);
+               }
+ 
+               if (r != SEC_E_OK && r != SEC_I_CONTINUE_NEEDED)
+               {
+                       if (sspictx != NULL)
+                       {
+                               DeleteSecurityContext(sspictx);
+                               free(sspictx);
+                       }
+                       FreeCredentialsHandle(&sspicred);
+                       pg_SSPI_error(ERROR, 
+                                       gettext_noop("could not accept SSPI 
security context"), r);
+               }
+ 
+               if (sspictx == NULL)
+               {
+                       sspictx = malloc(sizeof(CtxtHandle));
+                       if (sspictx == NULL)
+                               ereport(ERROR,
+                                       (errmsg("out of memory")));
+ 
+                       memcpy(sspictx, &newctx, sizeof(CtxtHandle));
+               }
+ 
+               if (r == SEC_I_CONTINUE_NEEDED)
+                       elog(DEBUG4, "SSPI continue needed");
+ 
+       } while (r == SEC_I_CONTINUE_NEEDED);
+ 
+ 
+       /*
+        * Release service principal credentials
+        */
+       FreeCredentialsHandle(&sspicred);
+ 
+ 
+       /*
+        * SEC_E_OK indicates that authentication is now complete.
+        *
+        * Get the name of the user that authenticated, and compare it to the
+        * pg username that was specified for the connection.
+        */
+ 
+       r = QuerySecurityContextToken(sspictx, &token);
+       if (r != SEC_E_OK)
+               pg_SSPI_error(ERROR,
+                       gettext_noop("could not get security token from 
context"), r);
+ 
+       /*
+        * No longer need the security context, everything from here on uses the
+        * token instead.
+        */
+       DeleteSecurityContext(sspictx);
+       free(sspictx);
+ 
+       if (!GetTokenInformation(token, TokenUser, NULL, 0, &retlen) && 
GetLastError() != 122)
+               ereport(ERROR,
+                               (errmsg_internal("could not get token user 
size: error code %d",
+                                       (int) GetLastError())));
+ 
+       tokenuser = malloc(retlen);
+       if (tokenuser == NULL)
+               ereport(ERROR,
+                               (errmsg("out of memory")));
+ 
+       if (!GetTokenInformation(token, TokenUser, tokenuser, retlen, &retlen))
+               ereport(ERROR,
+                               (errmsg_internal("could not get user token: 
error code %d",
+                                       (int) GetLastError())));
+ 
+       if (!LookupAccountSid(NULL, tokenuser->User.Sid, accountname, 
&accountnamesize, 
+                                                       domainname, 
&domainnamesize, &accountnameuse))
+               ereport(ERROR,
+                               (errmsg_internal("could not lookup acconut sid: 
error code %d",
+                                       (int) GetLastError())));
+ 
+       free(tokenuser);
+ 
+       /*
+        * We have the username (without domain/realm) in accountname, compare 
+        * to the supplied value. In SSPI, always compare case insensitive.
+        */
+       if (pg_strcasecmp(port->user_name, accountname))
+       {
+               /* GSS name and PGUSER are not equivalent */
+               elog(DEBUG2, 
+                        "provided username (%s) and SSPI username (%s) don't 
match",
+                        port->user_name, accountname);
+ 
+               return STATUS_ERROR;
+       }
+       
+       return STATUS_OK;
+ }
+ #else /* no ENABLE_SSPI */
+ static int
+ pg_SSPI_recvauth(Port *port)
+ {
+       ereport(LOG,
+                       (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
+                        errmsg("SSPI not implemented on this server.")));
+       return STATUS_ERROR;
+ }
+ #endif        /* ENABLE_SSPI */
+ 
  
  /*
   * Tell the user the authentication failed, but not (much about) why.
***************
*** 589,594 ****
--- 832,840 ----
                case uaGSS:
                        errstr = gettext_noop("GSSAPI authentication failed for 
user \"%s\"");
                        break;
+               case uaSSPI:
+                       errstr = gettext_noop("SSPI authentication failed for 
user \"%s\"");
+                       break;
                case uaTrust:
                        errstr = gettext_noop("\"trust\" authentication failed 
for user \"%s\"");
                        break;
***************
*** 689,694 ****
--- 935,945 ----
                        status = pg_GSS_recvauth(port);
                        break;
  
+               case uaSSPI:
+                       sendAuthRequest(port, AUTH_REQ_SSPI);
+                       status = pg_SSPI_recvauth(port);
+                       break;
+ 
                case uaIdent:
  
                        /*
***************
*** 778,797 ****
        else if (areq == AUTH_REQ_CRYPT)
                pq_sendbytes(&buf, port->cryptSalt, 2);
  
! #ifdef ENABLE_GSS
        /* Add the authentication data for the next step of
!        * the GSSAPI negotiation. */
        else if (areq == AUTH_REQ_GSS_CONT)
        {
                if (port->gss->outbuf.length > 0)
                {
-                       OM_uint32       lmin_s;
- 
                        elog(DEBUG4, "sending GSS token of length %u",
                                 (unsigned int) port->gss->outbuf.length);
  
                        pq_sendbytes(&buf, port->gss->outbuf.value, 
port->gss->outbuf.length);
-                       gss_release_buffer(&lmin_s, &port->gss->outbuf);
                }
        }
  #endif
--- 1029,1045 ----
        else if (areq == AUTH_REQ_CRYPT)
                pq_sendbytes(&buf, port->cryptSalt, 2);
  
! #if defined(ENABLE_GSS) || defined(ENABLE_SSPI)
        /* Add the authentication data for the next step of
!        * the GSSAPI or SSPI negotiation. */
        else if (areq == AUTH_REQ_GSS_CONT)
        {
                if (port->gss->outbuf.length > 0)
                {
                        elog(DEBUG4, "sending GSS token of length %u",
                                 (unsigned int) port->gss->outbuf.length);
  
                        pq_sendbytes(&buf, port->gss->outbuf.value, 
port->gss->outbuf.length);
                }
        }
  #endif
Index: src/backend/libpq/hba.c
===================================================================
RCS file: /projects/cvsroot/pgsql/src/backend/libpq/hba.c,v
retrieving revision 1.161
diff -c -r1.161 hba.c
*** src/backend/libpq/hba.c     10 Jul 2007 13:14:20 -0000      1.161
--- src/backend/libpq/hba.c     19 Jul 2007 08:28:39 -0000
***************
*** 604,609 ****
--- 604,611 ----
                *userauth_p = uaKrb5;
        else if (strcmp(token, "gss") == 0)
                *userauth_p = uaGSS;
+       else if (strcmp(token, "sspi") == 0)
+               *userauth_p = uaSSPI;
        else if (strcmp(token, "reject") == 0)
                *userauth_p = uaReject;
        else if (strcmp(token, "md5") == 0)
Index: src/backend/libpq/pg_hba.conf.sample
===================================================================
RCS file: /projects/cvsroot/pgsql/src/backend/libpq/pg_hba.conf.sample,v
retrieving revision 1.63
diff -c -r1.63 pg_hba.conf.sample
*** src/backend/libpq/pg_hba.conf.sample        10 Jul 2007 13:14:20 -0000      
1.63
--- src/backend/libpq/pg_hba.conf.sample        19 Jul 2007 10:17:18 -0000
***************
*** 34,40 ****
  # the number of significant bits in the mask.  Alternatively, you can write
  # an IP address and netmask in separate columns to specify the set of hosts.
  #
! # METHOD can be "trust", "reject", "md5", "crypt", "password", "gss",
  # "krb5", "ident", "pam" or "ldap".  Note that "password" sends passwords
  # in clear text; "md5" is preferred since it sends encrypted passwords.
  #
--- 34,40 ----
  # the number of significant bits in the mask.  Alternatively, you can write
  # an IP address and netmask in separate columns to specify the set of hosts.
  #
! # METHOD can be "trust", "reject", "md5", "crypt", "password", "gss", "sspi",
  # "krb5", "ident", "pam" or "ldap".  Note that "password" sends passwords
  # in clear text; "md5" is preferred since it sends encrypted passwords.
  #
Index: src/backend/libpq/pqcomm.c
===================================================================
RCS file: /projects/cvsroot/pgsql/src/backend/libpq/pqcomm.c,v
retrieving revision 1.193
diff -c -r1.193 pqcomm.c
*** src/backend/libpq/pqcomm.c  10 Jul 2007 13:14:20 -0000      1.193
--- src/backend/libpq/pqcomm.c  19 Jul 2007 10:43:27 -0000
***************
*** 173,187 ****
  {
        if (MyProcPort != NULL)
        {
  #ifdef ENABLE_GSS
                OM_uint32       min_s;
                /* Shutdown GSSAPI layer */
                if (MyProcPort->gss->ctx)
                        gss_delete_sec_context(&min_s, MyProcPort->gss->ctx, 
NULL);
  
                if (MyProcPort->gss->cred)
                        gss_release_cred(&min_s, MyProcPort->gss->cred);
! #endif
  
                /* Cleanly shut down SSL layer */
                secure_close(MyProcPort);
--- 173,193 ----
  {
        if (MyProcPort != NULL)
        {
+ #if defined(ENABLE_GSS) || defined(ENABLE_SSPI)
  #ifdef ENABLE_GSS
                OM_uint32       min_s;
+ 
                /* Shutdown GSSAPI layer */
                if (MyProcPort->gss->ctx)
                        gss_delete_sec_context(&min_s, MyProcPort->gss->ctx, 
NULL);
  
                if (MyProcPort->gss->cred)
                        gss_release_cred(&min_s, MyProcPort->gss->cred);
! #endif /* ENABLE_GSS */
!               /* GSS and SSPI share the port->gss struct */
! 
!               free(MyProcPort->gss);
! #endif /* ENABLE_GSS || ENABLE_SSPI */
  
                /* Cleanly shut down SSL layer */
                secure_close(MyProcPort);
Index: src/backend/postmaster/postmaster.c
===================================================================
RCS file: /projects/cvsroot/pgsql/src/backend/postmaster/postmaster.c,v
retrieving revision 1.532
diff -c -r1.532 postmaster.c
*** src/backend/postmaster/postmaster.c 11 Jul 2007 08:27:33 -0000      1.532
--- src/backend/postmaster/postmaster.c 19 Jul 2007 11:29:16 -0000
***************
*** 1730,1736 ****
        /*
       * Allocate GSSAPI specific state struct
         */
! #ifdef ENABLE_GSS
        port->gss = (pg_gssinfo *)calloc(1, sizeof(pg_gssinfo));
        if (!port->gss)
        {
--- 1730,1737 ----
        /*
       * Allocate GSSAPI specific state struct
         */
! #ifndef EXEC_BACKEND
! #if defined(ENABLE_GSS) || defined(ENABLE_SSPI) 
        port->gss = (pg_gssinfo *)calloc(1, sizeof(pg_gssinfo));
        if (!port->gss)
        {
***************
*** 1740,1745 ****
--- 1741,1747 ----
                ExitPostmaster(1);
        }
  #endif
+ #endif
  
        return port;
  }
***************
*** 3341,3346 ****
--- 3343,3361 ----
        memset(&port, 0, sizeof(Port));
        read_backend_variables(argv[2], &port);
  
+       /* 
+        * Set up memory area for GSS information. Mirrors the code in
+        * ConnCreate for the non-exec case.
+        */
+ #if defined(ENABLE_GSS) || defined(ENABLE_SSPI)
+       port.gss = (pg_gssinfo *)calloc(1, sizeof(pg_gssinfo));
+       if (!port.gss)
+               ereport(FATAL,
+                               (errcode(ERRCODE_OUT_OF_MEMORY),
+                                errmsg("out of memory")));
+ #endif
+ 
+ 
        /* Check we got appropriate args */
        if (argc < 3)
                elog(FATAL, "invalid subpostmaster invocation");
Index: src/include/pg_config.h.win32
===================================================================
RCS file: /projects/cvsroot/pgsql/src/include/pg_config.h.win32,v
retrieving revision 1.42
diff -c -r1.42 pg_config.h.win32
*** src/include/pg_config.h.win32       16 Apr 2007 18:39:19 -0000      1.42
--- src/include/pg_config.h.win32       18 Jul 2007 10:03:43 -0000
***************
*** 582,588 ****
  
  /* Define to the name of the default PostgreSQL service principal in Kerberos.
     (--with-krb-srvnam=NAME) */
! #define PG_KRB_SRVNAM "postgres"
  
  /* A string containing the version number, platform, and C compiler */
  #define PG_VERSION_STR "Uninitialized version string (win32)"
--- 582,588 ----
  
  /* Define to the name of the default PostgreSQL service principal in Kerberos.
     (--with-krb-srvnam=NAME) */
! #define PG_KRB_SRVNAM "POSTGRES"
  
  /* A string containing the version number, platform, and C compiler */
  #define PG_VERSION_STR "Uninitialized version string (win32)"
Index: src/include/libpq/hba.h
===================================================================
RCS file: /projects/cvsroot/pgsql/src/include/libpq/hba.h,v
retrieving revision 1.46
diff -c -r1.46 hba.h
*** src/include/libpq/hba.h     10 Jul 2007 13:14:21 -0000      1.46
--- src/include/libpq/hba.h     19 Jul 2007 08:29:21 -0000
***************
*** 23,29 ****
        uaPassword,
        uaCrypt,
        uaMD5,
!       uaGSS
  #ifdef USE_PAM
        ,uaPAM
  #endif   /* USE_PAM */
--- 23,30 ----
        uaPassword,
        uaCrypt,
        uaMD5,
!       uaGSS,
!       uaSSPI
  #ifdef USE_PAM
        ,uaPAM
  #endif   /* USE_PAM */
Index: src/include/libpq/libpq-be.h
===================================================================
RCS file: /projects/cvsroot/pgsql/src/include/libpq/libpq-be.h,v
retrieving revision 1.61
diff -c -r1.61 libpq-be.h
*** src/include/libpq/libpq-be.h        12 Jul 2007 14:43:21 -0000      1.61
--- src/include/libpq/libpq-be.h        19 Jul 2007 11:30:16 -0000
***************
*** 45,50 ****
--- 45,66 ----
  #endif
  #endif /* ENABLE_GSS */
  
+ #ifdef ENABLE_SSPI
+ #define SECURITY_WIN32
+ #include <security.h>
+ #undef SECURITY_WIN32
+ 
+ #ifndef ENABLE_GSS
+ /*
+  * Define a fake structure compatible with GSSAPI on Unix.
+  */
+ typedef struct {
+       void *value;
+       int length;
+ } gss_buffer_desc;
+ #endif
+ #endif /* ENABLE_SSPI */
+ 
  #include "libpq/hba.h"
  #include "libpq/pqcomm.h"
  #include "utils/timestamp.h"
***************
*** 59,71 ****
  /*
   * GSSAPI specific state information
   */
! #ifdef ENABLE_GSS
  typedef struct
  {
        gss_cred_id_t   cred;           /* GSSAPI connection cred's */
        gss_ctx_id_t    ctx;            /* GSSAPI connection context */
        gss_name_t              name;           /* GSSAPI client name */
!       gss_buffer_desc outbuf;         /* GSSAPI output token buffer */
  } pg_gssinfo;
  #endif
  
--- 75,89 ----
  /*
   * GSSAPI specific state information
   */
! #if defined(ENABLE_GSS) | defined(ENABLE_SSPI)
  typedef struct
  {
+       gss_buffer_desc outbuf;         /* GSSAPI output token buffer */
+ #ifdef ENABLE_GSS
        gss_cred_id_t   cred;           /* GSSAPI connection cred's */
        gss_ctx_id_t    ctx;            /* GSSAPI connection context */
        gss_name_t              name;           /* GSSAPI client name */
! #endif
  } pg_gssinfo;
  #endif
  
***************
*** 128,134 ****
        int                     keepalives_interval;
        int                     keepalives_count;
  
! #ifdef ENABLE_GSS
        /*
         * If GSSAPI is supported, store GSSAPI information.
         * Oterwise, store a NULL pointer to make sure offsets
--- 146,152 ----
        int                     keepalives_interval;
        int                     keepalives_count;
  
! #if defined(ENABLE_GSS) || defined(ENABLE_SSPI)
        /*
         * If GSSAPI is supported, store GSSAPI information.
         * Oterwise, store a NULL pointer to make sure offsets
Index: src/include/libpq/pqcomm.h
===================================================================
RCS file: /projects/cvsroot/pgsql/src/include/libpq/pqcomm.h,v
retrieving revision 1.105
diff -c -r1.105 pqcomm.h
*** src/include/libpq/pqcomm.h  10 Jul 2007 13:14:21 -0000      1.105
--- src/include/libpq/pqcomm.h  19 Jul 2007 08:30:25 -0000
***************
*** 158,163 ****
--- 158,164 ----
  #define AUTH_REQ_SCM_CREDS    6       /* transfer SCM credentials */
  #define AUTH_REQ_GSS          7       /* GSSAPI without wrap() */
  #define AUTH_REQ_GSS_CONT     8       /* Continue GSS exchanges */
+ #define AUTH_REQ_SSPI         9   /* SSPI negotiate without wrap() */
  
  typedef uint32 AuthRequest;
  
Index: src/interfaces/libpq/fe-auth.c
===================================================================
RCS file: /projects/cvsroot/pgsql/src/interfaces/libpq/fe-auth.c,v
retrieving revision 1.127
diff -c -r1.127 fe-auth.c
*** src/interfaces/libpq/fe-auth.c      12 Jul 2007 14:43:21 -0000      1.127
--- src/interfaces/libpq/fe-auth.c      19 Jul 2007 11:39:41 -0000
***************
*** 329,339 ****
  /*
   * GSSAPI authentication system.
   */
- #if defined(HAVE_GSSAPI_H)
- #include <gssapi.h>
- #else
- #include <gssapi/gssapi.h>
- #endif
  
  #if defined(WIN32) && !defined(WIN32_ONLY_COMPILER)
  /*
--- 329,334 ----
***************
*** 378,384 ****
   * GSSAPI errors contains two parts. Put as much as possible of
   * both parts into the string.
   */
! void
  pg_GSS_error(char *mprefix, char *msg, int msglen,
        OM_uint32 maj_stat, OM_uint32 min_stat)
  {
--- 373,379 ----
   * GSSAPI errors contains two parts. Put as much as possible of
   * both parts into the string.
   */
! static void
  pg_GSS_error(char *mprefix, char *msg, int msglen,
        OM_uint32 maj_stat, OM_uint32 min_stat)
  {
***************
*** 407,413 ****
                        &conn->gctx,
                        conn->gtarg_nam,
                        GSS_C_NO_OID,
!                       conn->gflags,
                        0,
                        GSS_C_NO_CHANNEL_BINDINGS,
                        
(conn->gctx==GSS_C_NO_CONTEXT)?GSS_C_NO_BUFFER:&conn->ginbuf,
--- 402,408 ----
                        &conn->gctx,
                        conn->gtarg_nam,
                        GSS_C_NO_OID,
!                       GSS_C_MUTUAL_FLAG,
                        0,
                        GSS_C_NO_CHANNEL_BINDINGS,
                        
(conn->gctx==GSS_C_NO_CONTEXT)?GSS_C_NO_BUFFER:&conn->ginbuf,
***************
*** 504,510 ****
  
        return pg_GSS_continue(PQerrormsg, conn);
  }
! #endif
  
  /*
   * Respond to AUTH_REQ_SCM_CREDS challenge.
--- 499,690 ----
  
        return pg_GSS_continue(PQerrormsg, conn);
  }
! #endif /* ENABLE_GSS */
! 
! 
! #ifdef ENABLE_SSPI
! /*
!  * SSPI authentication system (Windows only)
!  */
! 
! static void
! pg_SSPI_error(char *mprefix, char *msg, int msglen, SECURITY_STATUS r)
! {
!       char sysmsg[256];
! 
!       if (FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM, NULL, r, 0, sysmsg, 
sizeof(sysmsg), NULL) == 0)
!               snprintf(msg, msglen, "%s: sspi error %x", mprefix, r);
!       else
!               snprintf(msg, msglen, "%s: %s (%x)", mprefix, sysmsg, r);
! }
! 
! /* 
!  * Continue SSPI authentication with next token as needed.
!  */
! static int
! pg_SSPI_continue(char *PQerrormsg, PGconn *conn)
! {
!       SECURITY_STATUS r;
!       CtxtHandle              newContext;
!       ULONG                   contextAttr;
!       SecBufferDesc   inbuf;
!       SecBufferDesc   outbuf;
!       SecBuffer               OutBuffers[1];
!       SecBuffer               InBuffers[1];
! 
!       if (conn->sspictx != NULL)
!       {
!               /*
!                * On runs other than the first we have some data to send. Put 
this
!                * data in a SecBuffer type structure.
!                */
!               inbuf.ulVersion = SECBUFFER_VERSION;
!               inbuf.cBuffers = 1;
!               inbuf.pBuffers = InBuffers;
!               InBuffers[0].pvBuffer = conn->ginbuf.value;
!               InBuffers[0].cbBuffer = conn->ginbuf.length;
!               InBuffers[0].BufferType = SECBUFFER_TOKEN;
!       }
! 
!       OutBuffers[0].pvBuffer = NULL;
!       OutBuffers[0].BufferType = SECBUFFER_TOKEN;
!       OutBuffers[0].cbBuffer = 0;
!       outbuf.cBuffers = 1;
!       outbuf.pBuffers = OutBuffers;
!       outbuf.ulVersion = SECBUFFER_VERSION;
! 
!       r = InitializeSecurityContext(conn->sspicred,
!               conn->sspictx,
!               conn->sspitarget,
!               ISC_REQ_ALLOCATE_MEMORY,
!               0,
!               SECURITY_NETWORK_DREP,
!               (conn->sspictx == NULL)?NULL:&inbuf,
!               0,
!               &newContext,
!               &outbuf,
!               &contextAttr,
!               NULL);
!       
!       if (r != SEC_E_OK && r != SEC_I_CONTINUE_NEEDED)
!       {
!               pg_SSPI_error(libpq_gettext("SSPI continuation error"),
!                       PQerrormsg, PQERRORMSG_LENGTH, r);
! 
!               return STATUS_ERROR;
!       }
! 
!       if (conn->sspictx == NULL)
!       {
!               /* On first run, transfer retreived context handle */
!               conn->sspictx = malloc(sizeof(CtxtHandle));
!               if (conn->sspictx == NULL)
!               {
!                       strncpy(PQerrormsg, libpq_gettext("out of memory\n"), 
PQERRORMSG_LENGTH);
!                       return STATUS_ERROR;
!               }
!               memcpy(conn->sspictx, &newContext, sizeof(CtxtHandle));
!       }
!       else
!       {
!               /*
!                * On subsequent runs when we had data to send, free buffers 
that contained
!                * this data.
!                */
!               free(conn->ginbuf.value);
!               conn->ginbuf.value = NULL;
!               conn->ginbuf.length = 0;
!       }
! 
!       /*
!        * If SSPI returned any data to be sent to the server (as it normally 
would),
!        * send this data as a password packet.
!        */
!       if (outbuf.cBuffers > 0)
!       {
!               if (outbuf.cBuffers != 1)
!               {
!                       /*
!                        * This should never happen, at least not for Kerberos 
authentication. Keep check
!                        * in case it shows up with other authentication 
methods later.
!                        */
!                       strncpy(PQerrormsg, "SSPI returned invalid number of 
output buffers\n", PQERRORMSG_LENGTH);
!                       return STATUS_ERROR;
!               }
! 
!               if (pqPacketSend(conn, 'p',
!                       outbuf.pBuffers[0].pvBuffer, 
outbuf.pBuffers[0].cbBuffer))
!               {
!                       FreeContextBuffer(outbuf.pBuffers[0].pvBuffer);
!                       return STATUS_ERROR;
!               }
!               FreeContextBuffer(outbuf.pBuffers[0].pvBuffer);
!       }
! 
!       /* Cleanup is handled by the code in freePGconn() */
!       return STATUS_OK;
! }
! 
! /* 
!  * Send initial SSPI authentication token.
!  * If use_negotiate is 0, use kerberos authentication package which is
!  * compatible with Unix. If use_negotiate is 1, use the negotiate package
!  * which supports both kerberos and NTLM, but is not compatible with Unix.
!  */
! static int
! pg_SSPI_startup(char *PQerrormsg, PGconn *conn, int use_negotiate)
! {
!       SECURITY_STATUS r;
!       TimeStamp               expire;
! 
!       conn->sspictx = NULL;
! 
!       /*
!        * Retreive credentials handle
!        */
!       conn->sspicred = malloc(sizeof(CredHandle));
!       if (conn->sspicred == NULL)
!       {
!               strncpy(PQerrormsg, libpq_gettext("out of memory\n"), 
PQERRORMSG_LENGTH);
!               return STATUS_ERROR;
!       }
! 
!       r = AcquireCredentialsHandle(NULL, 
use_negotiate?"negotiate":"kerberos", SECPKG_CRED_OUTBOUND, NULL, NULL, NULL, 
NULL, conn->sspicred, &expire);
!       if (r != SEC_E_OK)
!       {
!               pg_SSPI_error("acquire credentials failed", PQerrormsg, 
PQERRORMSG_LENGTH, r);
!               free(conn->sspicred);
!               conn->sspicred = NULL;
!               return STATUS_ERROR;
!       }
! 
!       /*
!        * Compute target principal name. SSPI has a different format from 
GSSAPI, but
!        * not more complex. We can skip the @REALM part, because Windows will 
fill that
!        * in for us automatically.
!        */
!       if (conn->pghost == NULL)
!       {
!               strncpy(PQerrormsg, libpq_gettext("hostname must be 
specified\n"), PQERRORMSG_LENGTH);
!               return STATUS_ERROR;
!       }
!       conn->sspitarget = 
malloc(strlen(conn->krbsrvname)+strlen(conn->pghost)+2);
!       if (!conn->sspitarget)
!       {
!               strncpy(PQerrormsg, libpq_gettext("out of memory\n"), 
PQERRORMSG_LENGTH);
!               return STATUS_ERROR;
!       }
!       sprintf(conn->sspitarget, "%s/%s", conn->krbsrvname, conn->pghost);
! 
!       /*
!        * Indicate that we're in SSPI authentication mode to make sure that
!        * pg_SSPI_continue is called next time in the negotiation.
!        */
!       conn->usesspi = 1;
! 
!       return pg_SSPI_continue(PQerrormsg, conn);
! }
! #endif /* ENABLE_SSPI */
  
  /*
   * Respond to AUTH_REQ_SCM_CREDS challenge.
***************
*** 671,697 ****
                        return STATUS_ERROR;
  #endif
  
! #ifdef ENABLE_GSS
                case AUTH_REQ_GSS:
-                       pglock_thread();
-                       if (pg_GSS_startup(PQerrormsg, conn) != STATUS_OK)
                        {
!                               /* PQerrormsg already filled in. */
                                pgunlock_thread();
-                               return STATUS_ERROR;
                        }
-                       pgunlock_thread();
                        break;
  
                case AUTH_REQ_GSS_CONT:
-                       pglock_thread();
-                       if (pg_GSS_continue(PQerrormsg, conn) != STATUS_OK)
                        {
!                               /* PQerrormsg already filled in. */
                                pgunlock_thread();
-                               return STATUS_ERROR;
                        }
-                       pgunlock_thread();
                        break;
  
  #else
--- 851,910 ----
                        return STATUS_ERROR;
  #endif
  
! #if defined(ENABLE_GSS) || defined(ENABLE_SSPI)
                case AUTH_REQ_GSS:
                        {
!                               int r;
!                               pglock_thread();
!                               /*
!                                * If we have both GSS and SSPI support 
compiled in, use SSPI
!                                * support by default. This is overridable by a 
connection string parameter.
!                                * Note that when using SSPI we still leave the 
negotiate parameter off,
!                                * since we want SSPI to use the GSSAPI 
kerberos protocol. For actual
!                                * SSPI negotiate protocol, we use 
AUTH_REQ_SSPI.
!                                */
! #if defined(ENABLE_GSS) && defined(ENABLE_SSPI)
!                               if (conn->gsslib && 
(pg_strcasecmp(conn->gsslib, "gssapi") == 0))
!                                       r = pg_GSS_startup(PQerrormsg, conn);
!                               else
!                                       r = pg_SSPI_startup(PQerrormsg, conn, 
0);
! #elif defined(ENABLE_GSS) && !defined(ENABLE_SSPI)
!                               r = pg_GSS_startup(PQerrormsg, conn);
! #elif !defined(ENABLE_GSS) && defined(ENABLE_SSPI)
!                               r = pg_SSPI_startup(PQerrormsg, conn, 0);
! #endif
!                               if (r != STATUS_OK)
!                               {
!                                       /* PQerrormsg already filled in. */
!                                       pgunlock_thread();
!                                       return STATUS_ERROR;
!                               }
                                pgunlock_thread();
                        }
                        break;
  
                case AUTH_REQ_GSS_CONT:
                        {
!                               int r;
!                               pglock_thread();
! #if defined(ENABLE_GSS) && defined(ENABLE_SSPI)
!                               if (conn->usesspi)
!                                       r = pg_SSPI_continue(PQerrormsg, conn);
!                               else
!                                       r = pg_GSS_continue(PQerrormsg, conn);
! #elif defined(ENABLE_GSS) && !defined(ENABLE_SSPI)
!                               r = pg_GSS_continue(PQerrormsg, conn);
! #elif !defined(ENABLE_GSS) && defined(ENABLE_SSPI)
!                               r = pg_SSPI_continue(PQerrormsg, conn);
! #endif
!                               if (r != STATUS_OK)
!                               {
!                                       /* PQerrormsg already filled in. */
!                                       pgunlock_thread();
!                                       return STATUS_ERROR;
!                               }
                                pgunlock_thread();
                        }
                        break;
  
  #else
***************
*** 702,707 ****
--- 915,944 ----
                        return STATUS_ERROR;
  #endif
  
+ #ifdef ENABLE_SSPI
+               case AUTH_REQ_SSPI:
+                       /* 
+                        * SSPI has it's own startup message so libpq can 
decide which
+                        * method to use. Indicate to pg_SSPI_startup that we 
want
+                        * SSPI negotiation instead of Kerberos.
+                        */
+                       pglock_thread();
+                       if (pg_SSPI_startup(PQerrormsg, conn, 1) != STATUS_OK)
+                       {
+                               /* PQerrormsg already filled in. */
+                               pgunlock_thread();
+                               return STATUS_ERROR;
+                       }
+                       pgunlock_thread();
+                       break;
+ #else
+               case AUTH_REQ_SSPI:
+                       snpritnf(PQerrormsg, PQERRORMSG_LENGTH,
+                                       libpq_gettext("SSPI authentication not 
supported\n"));
+                       return STATUS_ERROR;
+ #endif
+ 
+ 
                case AUTH_REQ_MD5:
                case AUTH_REQ_CRYPT:
                case AUTH_REQ_PASSWORD:
Index: src/interfaces/libpq/fe-connect.c
===================================================================
RCS file: /projects/cvsroot/pgsql/src/interfaces/libpq/fe-connect.c,v
retrieving revision 1.349
diff -c -r1.349 fe-connect.c
*** src/interfaces/libpq/fe-connect.c   11 Jul 2007 08:27:33 -0000      1.349
--- src/interfaces/libpq/fe-connect.c   19 Jul 2007 11:41:33 -0000
***************
*** 181,192 ****
        {"sslmode", "PGSSLMODE", DefaultSSLMode, NULL,
        "SSL-Mode", "", 8},                     /* sizeof("disable") == 8 */
  
! #if defined(KRB5) || defined(ENABLE_GSS)
        /* Kerberos and GSSAPI authentication support specifying the service 
name */
        {"krbsrvname", "PGKRBSRVNAME", PG_KRB_SRVNAM, NULL,
        "Kerberos-service-name", "", 20},
  #endif
  
        /* Terminating entry --- MUST BE LAST */
        {NULL, NULL, NULL, NULL,
        NULL, NULL, 0}
--- 181,198 ----
        {"sslmode", "PGSSLMODE", DefaultSSLMode, NULL,
        "SSL-Mode", "", 8},                     /* sizeof("disable") == 8 */
  
! #if defined(KRB5) || defined(ENABLE_GSS) || defined(ENABLE_SSPI)
        /* Kerberos and GSSAPI authentication support specifying the service 
name */
        {"krbsrvname", "PGKRBSRVNAME", PG_KRB_SRVNAM, NULL,
        "Kerberos-service-name", "", 20},
  #endif
  
+ #if defined(ENABLE_GSS) && defined(ENABLE_SSPI)
+       /* GSSAPI and SSPI both enabled, give a way to override which is used 
by default */
+       {"gsslib", "PGGSSLIB", NULL, NULL,
+       "GSS-library", "", 7},          /* sizeof("gssapi") = 7 */
+ #endif
+ 
        /* Terminating entry --- MUST BE LAST */
        {NULL, NULL, NULL, NULL,
        NULL, NULL, 0}
***************
*** 412,421 ****
                conn->sslmode = strdup("require");
        }
  #endif
! #if defined(KRB5) || defined(ENABLE_GSS)
        tmp = conninfo_getval(connOptions, "krbsrvname");
        conn->krbsrvname = tmp ? strdup(tmp) : NULL;
  #endif
  
        /*
         * Free the option info - all is in conn now
--- 418,431 ----
                conn->sslmode = strdup("require");
        }
  #endif
! #if defined(KRB5) || defined(ENABLE_GSS) || defined(ENABLE_SSPI)
        tmp = conninfo_getval(connOptions, "krbsrvname");
        conn->krbsrvname = tmp ? strdup(tmp) : NULL;
  #endif
+ #if defined(ENABLE_GSS) && defined(ENABLE_SSPI)
+       tmp = conninfo_getval(connOptions, "gsslib");
+       conn->gsslib = tmp ? strdup(tmp) : NULL;
+ #endif
  
        /*
         * Free the option info - all is in conn now
***************
*** 1661,1682 ****
                                                return PGRES_POLLING_READING;
                                        }
                                }
! #ifdef ENABLE_GSS
                                /*
!                                * AUTH_REQ_GSS provides no input data
!                                * Just set the request flags 
!                                */
!                               if (areq == AUTH_REQ_GSS)
!                                       conn->gflags = GSS_C_MUTUAL_FLAG;
! 
!                               /*
!                                * Read GSSAPI data packets
                                 */
                                if (areq == AUTH_REQ_GSS_CONT)
                                {
-                                       /* Continue GSSAPI authentication */
                                        int llen = msgLength - 4;
-                                       
                                        /*
                                         * We can be called repeatedly for the 
same buffer.
                                         * Avoid re-allocating the buffer in 
this case - 
--- 1671,1683 ----
                                                return PGRES_POLLING_READING;
                                        }
                                }
! #if defined(ENABLE_GSS) || defined(ENABLE_SSPI)
                                /*
!                                * Continue GSSAPI/SSPI authentication
                                 */
                                if (areq == AUTH_REQ_GSS_CONT)
                                {
                                        int llen = msgLength - 4;
                                        /*
                                         * We can be called repeatedly for the 
same buffer.
                                         * Avoid re-allocating the buffer in 
this case - 
***************
*** 2002,2008 ****
                free(conn->pgpass);
        if (conn->sslmode)
                free(conn->sslmode);
! #if defined(KRB5) || defined(ENABLE_GSS)
        if (conn->krbsrvname)
                free(conn->krbsrvname);
  #endif
--- 2003,2009 ----
                free(conn->pgpass);
        if (conn->sslmode)
                free(conn->sslmode);
! #if defined(KRB5) || defined(ENABLE_GSS) || defined(ENABLE_SSPI)
        if (conn->krbsrvname)
                free(conn->krbsrvname);
  #endif
***************
*** 2031,2036 ****
--- 2032,2057 ----
                        gss_release_buffer(&min_s, &conn->goutbuf);
        }
  #endif
+ #ifdef ENABLE_SSPI
+       {
+               if (conn->ginbuf.length)
+                       free(conn->ginbuf.value);
+ 
+               if (conn->sspitarget)
+                       free(conn->sspitarget);
+ 
+               if (conn->sspicred)
+               {
+                       FreeCredentialsHandle(conn->sspicred);
+                       free(conn->sspicred);
+               }
+               if (conn->sspictx)
+               {
+                       DeleteSecurityContext(conn->sspictx);
+                       free(conn->sspictx);
+               }
+       }
+ #endif
        pstatus = conn->pstatus;
        while (pstatus != NULL)
        {
Index: src/interfaces/libpq/libpq-int.h
===================================================================
RCS file: /projects/cvsroot/pgsql/src/interfaces/libpq/libpq-int.h,v
retrieving revision 1.123
diff -c -r1.123 libpq-int.h
*** src/interfaces/libpq/libpq-int.h    12 Jul 2007 14:36:52 -0000      1.123
--- src/interfaces/libpq/libpq-int.h    19 Jul 2007 11:39:59 -0000
***************
*** 52,57 ****
--- 52,73 ----
  #endif
  #endif
  
+ #ifdef ENABLE_SSPI
+ #define SECURITY_WIN32
+ #include <security.h>
+ #undef SECURITY_WIN32
+ 
+ #ifndef ENABLE_GSS
+ /*
+  * Define a fake structure compatible with GSSAPI on Unix.
+  */
+ typedef struct {
+       void *value;
+       int length;
+ } gss_buffer_desc;
+ #endif
+ #endif /* ENABLE_SSPI */
+ 
  #ifdef USE_SSL
  #include <openssl/ssl.h>
  #include <openssl/err.h>
***************
*** 276,282 ****
        char       *pguser;                     /* Postgres username and 
password, if any */
        char       *pgpass;
        char       *sslmode;            /* SSL mode 
(require,prefer,allow,disable) */
! #if defined(KRB5) || defined(ENABLE_GSS)
        char       *krbsrvname;         /* Kerberos service name */
  #endif
  
--- 292,298 ----
        char       *pguser;                     /* Postgres username and 
password, if any */
        char       *pgpass;
        char       *sslmode;            /* SSL mode 
(require,prefer,allow,disable) */
! #if defined(KRB5) || defined(ENABLE_GSS) || defined(ENABLE_SSPI)
        char       *krbsrvname;         /* Kerberos service name */
  #endif
  
***************
*** 361,371 ****
  #ifdef ENABLE_GSS
        gss_ctx_id_t    gctx;           /* GSS context */
        gss_name_t              gtarg_nam;      /* GSS target name */
-       OM_uint32               gflags;         /* GSS service request flags */
        gss_buffer_desc ginbuf;         /* GSS input token */
        gss_buffer_desc goutbuf;        /* GSS output token */
  #endif
  
        /* Buffer for current error message */
        PQExpBufferData errorMessage;           /* expansible string */
  
--- 377,399 ----
  #ifdef ENABLE_GSS
        gss_ctx_id_t    gctx;           /* GSS context */
        gss_name_t              gtarg_nam;      /* GSS target name */
        gss_buffer_desc ginbuf;         /* GSS input token */
        gss_buffer_desc goutbuf;        /* GSS output token */
  #endif
  
+ #ifdef ENABLE_SSPI
+ #ifndef ENABLE_GSS
+       gss_buffer_desc ginbuf;         /* GSS input token */
+ #else
+       char                    *gsslib;        /* What GSS librart to use 
("gssapi" or "sspi") */
+ #endif
+       CredHandle              *sspicred;      /* SSPI credentials handle */
+       CtxtHandle              *sspictx;       /* SSPI context */
+       char                    *sspitarget;/* SSPI target name */
+       int                             usesspi;        /* Indicate if SSPI is 
in use on the connection */
+ #endif
+ 
+ 
        /* Buffer for current error message */
        PQExpBufferData errorMessage;           /* expansible string */
  
***************
*** 415,426 ****
  #define pgunlock_thread()     ((void) 0)
  #endif
  
- /* === in fe-auth.c === */
- #ifdef ENABLE_GSS
- extern void pg_GSS_error(char *mprefix, char *msg, int msglen,
-         OM_uint32 maj_stat, OM_uint32 min_stat);
- #endif
- 
  /* === in fe-exec.c === */
  
  extern void pqSetResultError(PGresult *res, const char *msg);
--- 443,448 ----
Index: src/tools/msvc/Mkvcbuild.pm
===================================================================
RCS file: /projects/cvsroot/pgsql/src/tools/msvc/Mkvcbuild.pm,v
retrieving revision 1.14
diff -c -r1.14 Mkvcbuild.pm
*** src/tools/msvc/Mkvcbuild.pm 7 Jul 2007 07:43:20 -0000       1.14
--- src/tools/msvc/Mkvcbuild.pm 18 Jul 2007 13:28:39 -0000
***************
*** 66,72 ****
      
$postgres->AddFiles('src\backend\bootstrap','bootscanner.l','bootparse.y');
      $postgres->AddFiles('src\backend\utils\misc','guc-file.l');
      $postgres->AddDefine('BUILDING_DLL');
!     $postgres->AddLibrary('wsock32.lib ws2_32.lib');
      $postgres->AddLibrary('wldap32.lib') if ($solution->{options}->{ldap});
      $postgres->FullExportDLL('postgres.lib');
  
--- 66,72 ----
      
$postgres->AddFiles('src\backend\bootstrap','bootscanner.l','bootparse.y');
      $postgres->AddFiles('src\backend\utils\misc','guc-file.l');
      $postgres->AddDefine('BUILDING_DLL');
!     $postgres->AddLibrary('wsock32.lib ws2_32.lib secur32.lib');
      $postgres->AddLibrary('wldap32.lib') if ($solution->{options}->{ldap});
      $postgres->FullExportDLL('postgres.lib');
  
***************
*** 120,125 ****
--- 120,126 ----
      $libpq->AddDefine('FRONTEND');
      $libpq->AddIncludeDir('src\port');
      $libpq->AddLibrary('wsock32.lib');
+     $libpq->AddLibrary('secur32.lib');
      $libpq->AddLibrary('wldap32.lib') if ($solution->{options}->{ldap});
      $libpq->UseDef('src\interfaces\libpq\libpqdll.def');
      
$libpq->ReplaceFile('src\interfaces\libpq\libpqrc.c','src\interfaces\libpq\libpq.rc');
Index: src/tools/msvc/Solution.pm
===================================================================
RCS file: /projects/cvsroot/pgsql/src/tools/msvc/Solution.pm,v
retrieving revision 1.29
diff -c -r1.29 Solution.pm
*** src/tools/msvc/Solution.pm  12 Jul 2007 14:43:21 -0000      1.29
--- src/tools/msvc/Solution.pm  19 Jul 2007 08:46:23 -0000
***************
*** 124,139 ****
              print O "#define HAVE_KRB5_ERROR_TEXT_DATA 1\n";
              print O "#define HAVE_KRB5_TICKET_ENC_PART2 1\n";
              print O "#define HAVE_KRB5_FREE_UNPARSED_NAME 1\n";
!             print O "#define PG_KRB_SRVNAM \"postgres\"\n";
!             print O "#define ENABLE_GSS\n";
          }
-               if (my $port = $self->{options}->{"--with-pgport"})
-               {
-                       print O "#undef DEF_PGPORT\n";
-                       print O "#undef DEF_PGPORT_STR\n";
-                       print O "#define DEF_PGPORT $port\n";
-                       print O "#define DEF_PGPORT_STR \"$port\"\n";
-               }
          print O "#define VAL_CONFIGURE \"" . $self->GetFakeConfigure() . 
"\"\n";
          print O "#endif /* IGNORE_CONFIGURED_SETTINGS */\n";
          close(O);
--- 124,139 ----
              print O "#define HAVE_KRB5_ERROR_TEXT_DATA 1\n";
              print O "#define HAVE_KRB5_TICKET_ENC_PART2 1\n";
              print O "#define HAVE_KRB5_FREE_UNPARSED_NAME 1\n";
!             print O "#define ENABLE_GSS 1\n";
!         }
!         print O "#define ENABLE_SSPI 1\n";
!         if (my $port = $self->{options}->{"--with-pgport"})
!         {
!             print O "#undef DEF_PGPORT\n";
!             print O "#undef DEF_PGPORT_STR\n";
!             print O "#define DEF_PGPORT $port\n";
!             print O "#define DEF_PGPORT_STR \"$port\"\n";
          }
          print O "#define VAL_CONFIGURE \"" . $self->GetFakeConfigure() . 
"\"\n";
          print O "#endif /* IGNORE_CONFIGURED_SETTINGS */\n";
          close(O);
---------------------------(end of broadcast)---------------------------
TIP 9: In versions below 8.0, the planner will ignore your desire to
       choose an index scan if your joining column's datatypes do not
       match

Reply via email to