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/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 18 Jul 2007 10:07:56 -0000 *************** *** 329,339 **** /* * GSSAPI authentication system. */ - #if defined(HAVE_GSSAPI_H) - #include - #else - #include - #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) { *************** *** 504,510 **** return pg_GSS_continue(PQerrormsg, conn); } ! #endif /* * Respond to AUTH_REQ_SCM_CREDS challenge. --- 499,677 ---- 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_GSS_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 (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); ! } ! ! 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; ! } ! ! /* Cleanup is handled by the code in freePGconn() */ ! return STATUS_OK; ! } ! ! /* ! * Send initial SSPI authentication token ! */ ! static int ! pg_GSS_startup(char *PQerrormsg, PGconn *conn) ! { ! SECURITY_STATUS r; ! TimeStamp expire; ! ! /* ! * 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; ! } ! ! /* ! * XXX: Currently hardcoded to use kerberos authentication for interop with Unix. ! * Probably want to support others as well later. ! */ ! r = AcquireCredentialsHandle(NULL, "kerberos", SECPKG_CRED_OUTBOUND, NULL, NULL, NULL, NULL, conn->sspicred, &expire); ! r = SEC_E_OK; ! if (r != SEC_E_OK) ! { ! pg_SSPI_error("acquire credentials failed", PQerrormsg, PQERRORMSG_LENGTH, r); ! return STATUS_ERROR; ! } ! ! conn->sspictx = NULL; ! ! /* ! * 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. ! */ ! 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); ! ! return pg_GSS_continue(PQerrormsg, conn); ! } ! #endif /* ENABLE_SSPI */ /* * Respond to AUTH_REQ_SCM_CREDS challenge. *************** *** 671,677 **** return STATUS_ERROR; #endif ! #ifdef ENABLE_GSS case AUTH_REQ_GSS: pglock_thread(); if (pg_GSS_startup(PQerrormsg, conn) != STATUS_OK) --- 838,844 ---- return STATUS_ERROR; #endif ! #if defined(ENABLE_GSS) || defined(ENABLE_SSPI) case AUTH_REQ_GSS: pglock_thread(); if (pg_GSS_startup(PQerrormsg, conn) != STATUS_OK) 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 18 Jul 2007 09:52:11 -0000 *************** *** 181,187 **** {"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}, --- 181,187 ---- {"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}, *************** *** 412,418 **** conn->sslmode = strdup("require"); } #endif ! #if defined(KRB5) || defined(ENABLE_GSS) tmp = conninfo_getval(connOptions, "krbsrvname"); conn->krbsrvname = tmp ? strdup(tmp) : NULL; #endif --- 412,418 ---- 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 *************** *** 1661,1673 **** 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 --- 1661,1675 ---- return PGRES_POLLING_READING; } } ! #if defined(ENABLE_GSS) || defined(ENABLE_SSPI) /* * AUTH_REQ_GSS provides no input data * Just set the request flags */ + #ifdef ENABLE_GSS if (areq == AUTH_REQ_GSS) conn->gflags = GSS_C_MUTUAL_FLAG; + #endif /* * Read GSSAPI data packets *************** *** 1676,1682 **** { /* Continue GSSAPI authentication */ int llen = msgLength - 4; ! /* * We can be called repeatedly for the same buffer. * Avoid re-allocating the buffer in this case - --- 1678,1684 ---- { /* Continue GSSAPI authentication */ 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 --- 2004,2010 ---- 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 **** --- 2033,2058 ---- 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 18 Jul 2007 09:52:16 -0000 *************** *** 52,57 **** --- 52,71 ---- #endif #endif + #ifdef ENABLE_SSPI + #define SECURITY_WIN32 + #include + #undef SECURITY_WIN32 + + /* + * Define a fake structure compatible with GSSAPI on Unix. + */ + typedef struct { + void *value; + int length; + } gss_buffer_desc; + #endif + #ifdef USE_SSL #include #include *************** *** 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 --- 290,296 ---- 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 *************** *** 366,371 **** --- 380,393 ---- gss_buffer_desc goutbuf; /* GSS output token */ #endif + #ifdef ENABLE_SSPI + CredHandle *sspicred; + CtxtHandle *sspictx; + gss_buffer_desc ginbuf; + char *sspitarget; + #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); --- 437,442 ---- 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 16 Jul 2007 10:57:21 -0000 *************** *** 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 18 Jul 2007 10:03:50 -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,145 ---- 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"; } ! if ($self->{options}->{gssapi}) ! { ! print O "#defnie ENABLE_GSS 1\n"; ! } ! else ! { ! 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); *************** *** 328,339 **** $proj->AddIncludeDir($self->{options}->{nls} . '\include'); $proj->AddLibrary($self->{options}->{nls} . '\lib\libintl.lib'); } ! if ($self->{options}->{krb5}) { $proj->AddIncludeDir($self->{options}->{krb5} . '\inc\krb5'); $proj->AddLibrary($self->{options}->{krb5} . '\lib\i386\krb5_32.lib'); $proj->AddLibrary($self->{options}->{krb5} . '\lib\i386\comerr32.lib'); ! $proj->AddLibrary($self->{options}->{krb5} . '\lib\i386\gssapi32.lib'); } if ($self->{options}->{xml}) { --- 334,347 ---- $proj->AddIncludeDir($self->{options}->{nls} . '\include'); $proj->AddLibrary($self->{options}->{nls} . '\lib\libintl.lib'); } ! if ($self->{options}->{krb5} || $self->{options}->{gssapi}) { $proj->AddIncludeDir($self->{options}->{krb5} . '\inc\krb5'); $proj->AddLibrary($self->{options}->{krb5} . '\lib\i386\krb5_32.lib'); $proj->AddLibrary($self->{options}->{krb5} . '\lib\i386\comerr32.lib'); ! if ($self->{options}->{gssapi}) { ! $proj->AddLibrary($self->{options}->{krb5} . '\lib\i386\gssapi32.lib'); ! } } if ($self->{options}->{xml}) {