mirror of
https://github.com/postgres/postgres.git
synced 2025-04-24 10:47:04 +03:00
SSPI authentication on Windows. GSSAPI compatible client when doing Kerberos
against a Unix server, and Windows-specific server-side authentication using SSPI "negotiate" method (Kerberos or NTLM). Only builds properly with MSVC for now.
This commit is contained in:
parent
a0dab332a2
commit
f70866fb23
@ -1,4 +1,4 @@
|
|||||||
<!-- $PostgreSQL: pgsql/doc/src/sgml/client-auth.sgml,v 1.99 2007/07/18 12:00:47 mha Exp $ -->
|
<!-- $PostgreSQL: pgsql/doc/src/sgml/client-auth.sgml,v 1.100 2007/07/23 10:16:53 mha Exp $ -->
|
||||||
|
|
||||||
<chapter id="client-authentication">
|
<chapter id="client-authentication">
|
||||||
<title>Client Authentication</title>
|
<title>Client Authentication</title>
|
||||||
@ -358,6 +358,17 @@ hostnossl <replaceable>database</replaceable> <replaceable>user</replaceable>
|
|||||||
</listitem>
|
</listitem>
|
||||||
</varlistentry>
|
</varlistentry>
|
||||||
|
|
||||||
|
<varlistentry>
|
||||||
|
<term><literal>sspi</></term>
|
||||||
|
<listitem>
|
||||||
|
<para>
|
||||||
|
Use SSPI to authenticate the user. This is only
|
||||||
|
available on Windows. See <xref
|
||||||
|
linkend="sspi-auth"> for details.
|
||||||
|
</para>
|
||||||
|
</listitem>
|
||||||
|
</varlistentry>
|
||||||
|
|
||||||
<varlistentry>
|
<varlistentry>
|
||||||
<term><literal>krb5</></term>
|
<term><literal>krb5</></term>
|
||||||
<listitem>
|
<listitem>
|
||||||
@ -677,6 +688,33 @@ local db1,db2,@demodbs all md5
|
|||||||
|
|
||||||
</sect2>
|
</sect2>
|
||||||
|
|
||||||
|
<sect2 id="sspi-auth">
|
||||||
|
<title>SSPI authentication</title>
|
||||||
|
|
||||||
|
<indexterm zone="sspi-auth">
|
||||||
|
<primary>SSPI</primary>
|
||||||
|
</indexterm>
|
||||||
|
|
||||||
|
<para>
|
||||||
|
<productname>SSPI</productname> is a <productname>Windows</productname>
|
||||||
|
technology for secure authentication with single sign-on.
|
||||||
|
<productname>PostgreSQL</productname> will use SSPI in
|
||||||
|
<literal>negotiate</literal> mode, which will use
|
||||||
|
<productname>Kerberos</productname> when possible and automatically
|
||||||
|
fall back to <productname>NTLM</productname> in other cases.
|
||||||
|
<productname>SSPI</productname> authentication only works when both
|
||||||
|
server and client are running <productname>Windows</productname>.
|
||||||
|
</para>
|
||||||
|
|
||||||
|
<para>
|
||||||
|
When using <productname>Kerberos</productname> authentication,
|
||||||
|
<productname>SSPI</productname> works the same way
|
||||||
|
<productname>GSSAPI</productname> does. See <xref linkend="gssapi-auth">
|
||||||
|
for details.
|
||||||
|
</para>
|
||||||
|
|
||||||
|
</sect2>
|
||||||
|
|
||||||
<sect2 id="kerberos-auth">
|
<sect2 id="kerberos-auth">
|
||||||
<title>Kerberos authentication</title>
|
<title>Kerberos authentication</title>
|
||||||
|
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
<!-- $PostgreSQL: pgsql/doc/src/sgml/libpq.sgml,v 1.238 2007/07/18 12:00:47 mha Exp $ -->
|
<!-- $PostgreSQL: pgsql/doc/src/sgml/libpq.sgml,v 1.239 2007/07/23 10:16:53 mha Exp $ -->
|
||||||
|
|
||||||
<chapter id="libpq">
|
<chapter id="libpq">
|
||||||
<title><application>libpq</application> - C Library</title>
|
<title><application>libpq</application> - C Library</title>
|
||||||
@ -290,6 +290,17 @@ PGconn *PQconnectdb(const char *conninfo);
|
|||||||
</listitem>
|
</listitem>
|
||||||
</varlistentry>
|
</varlistentry>
|
||||||
|
|
||||||
|
<varlistentry>
|
||||||
|
<term><literal>gsslib</literal></term>
|
||||||
|
<listitem>
|
||||||
|
<para>
|
||||||
|
GSS library to use for GSSAPI authentication. Only used on Windows.
|
||||||
|
Set to <literal>gssapi</literal> to force libpq to use the GSSAPI
|
||||||
|
library for authentication instead of the default SSPI.
|
||||||
|
</para>
|
||||||
|
</listitem>
|
||||||
|
</varlistentry>
|
||||||
|
|
||||||
<varlistentry>
|
<varlistentry>
|
||||||
<term><literal>service</literal></term>
|
<term><literal>service</literal></term>
|
||||||
<listitem>
|
<listitem>
|
||||||
@ -4220,6 +4231,15 @@ authenticating with Kerberos 5 or GSSAPI.
|
|||||||
</listitem>
|
</listitem>
|
||||||
<listitem>
|
<listitem>
|
||||||
<para>
|
<para>
|
||||||
|
<indexterm>
|
||||||
|
<primary><envar>PGGSSLIB</envar></primary>
|
||||||
|
</indexterm>
|
||||||
|
<envar>PGGSSLIB</envar> sets the GSS library to use for GSSAPI
|
||||||
|
authentication.
|
||||||
|
</para>
|
||||||
|
</listitem>
|
||||||
|
<listitem>
|
||||||
|
<para>
|
||||||
<indexterm>
|
<indexterm>
|
||||||
<primary><envar>PGCONNECT_TIMEOUT</envar></primary>
|
<primary><envar>PGCONNECT_TIMEOUT</envar></primary>
|
||||||
</indexterm>
|
</indexterm>
|
||||||
|
@ -8,7 +8,7 @@
|
|||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $PostgreSQL: pgsql/src/backend/libpq/auth.c,v 1.153 2007/07/12 20:36:11 tgl Exp $
|
* $PostgreSQL: pgsql/src/backend/libpq/auth.c,v 1.154 2007/07/23 10:16:53 mha Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
@ -464,10 +464,14 @@ pg_GSS_recvauth(Port *port)
|
|||||||
/*
|
/*
|
||||||
* Negotiation generated data to be sent to the client.
|
* Negotiation generated data to be sent to the client.
|
||||||
*/
|
*/
|
||||||
|
OM_uint32 lmin_s;
|
||||||
|
|
||||||
elog(DEBUG4, "sending GSS response token of length %u",
|
elog(DEBUG4, "sending GSS response token of length %u",
|
||||||
(unsigned int) port->gss->outbuf.length);
|
(unsigned int) port->gss->outbuf.length);
|
||||||
|
|
||||||
sendAuthRequest(port, AUTH_REQ_GSS_CONT);
|
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)
|
if (maj_stat != GSS_S_COMPLETE && maj_stat != GSS_S_CONTINUE_NEEDED)
|
||||||
@ -536,7 +540,7 @@ pg_GSS_recvauth(Port *port)
|
|||||||
return STATUS_OK;
|
return STATUS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
#else /* no ENABLE_GSS */
|
#else /* no ENABLE_GSS */
|
||||||
static int
|
static int
|
||||||
pg_GSS_recvauth(Port *port)
|
pg_GSS_recvauth(Port *port)
|
||||||
{
|
{
|
||||||
@ -547,6 +551,245 @@ pg_GSS_recvauth(Port *port)
|
|||||||
}
|
}
|
||||||
#endif /* ENABLE_GSS */
|
#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.
|
* Tell the user the authentication failed, but not (much about) why.
|
||||||
@ -589,6 +832,9 @@ auth_failed(Port *port, int status)
|
|||||||
case uaGSS:
|
case uaGSS:
|
||||||
errstr = gettext_noop("GSSAPI authentication failed for user \"%s\"");
|
errstr = gettext_noop("GSSAPI authentication failed for user \"%s\"");
|
||||||
break;
|
break;
|
||||||
|
case uaSSPI:
|
||||||
|
errstr = gettext_noop("SSPI authentication failed for user \"%s\"");
|
||||||
|
break;
|
||||||
case uaTrust:
|
case uaTrust:
|
||||||
errstr = gettext_noop("\"trust\" authentication failed for user \"%s\"");
|
errstr = gettext_noop("\"trust\" authentication failed for user \"%s\"");
|
||||||
break;
|
break;
|
||||||
@ -689,6 +935,11 @@ ClientAuthentication(Port *port)
|
|||||||
status = pg_GSS_recvauth(port);
|
status = pg_GSS_recvauth(port);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case uaSSPI:
|
||||||
|
sendAuthRequest(port, AUTH_REQ_SSPI);
|
||||||
|
status = pg_SSPI_recvauth(port);
|
||||||
|
break;
|
||||||
|
|
||||||
case uaIdent:
|
case uaIdent:
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -778,20 +1029,17 @@ sendAuthRequest(Port *port, AuthRequest areq)
|
|||||||
else if (areq == AUTH_REQ_CRYPT)
|
else if (areq == AUTH_REQ_CRYPT)
|
||||||
pq_sendbytes(&buf, port->cryptSalt, 2);
|
pq_sendbytes(&buf, port->cryptSalt, 2);
|
||||||
|
|
||||||
#ifdef ENABLE_GSS
|
#if defined(ENABLE_GSS) || defined(ENABLE_SSPI)
|
||||||
/* Add the authentication data for the next step of
|
/* Add the authentication data for the next step of
|
||||||
* the GSSAPI negotiation. */
|
* the GSSAPI or SSPI negotiation. */
|
||||||
else if (areq == AUTH_REQ_GSS_CONT)
|
else if (areq == AUTH_REQ_GSS_CONT)
|
||||||
{
|
{
|
||||||
if (port->gss->outbuf.length > 0)
|
if (port->gss->outbuf.length > 0)
|
||||||
{
|
{
|
||||||
OM_uint32 lmin_s;
|
|
||||||
|
|
||||||
elog(DEBUG4, "sending GSS token of length %u",
|
elog(DEBUG4, "sending GSS token of length %u",
|
||||||
(unsigned int) port->gss->outbuf.length);
|
(unsigned int) port->gss->outbuf.length);
|
||||||
|
|
||||||
pq_sendbytes(&buf, port->gss->outbuf.value, port->gss->outbuf.length);
|
pq_sendbytes(&buf, port->gss->outbuf.value, port->gss->outbuf.length);
|
||||||
gss_release_buffer(&lmin_s, &port->gss->outbuf);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
@ -10,7 +10,7 @@
|
|||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $PostgreSQL: pgsql/src/backend/libpq/hba.c,v 1.161 2007/07/10 13:14:20 mha Exp $
|
* $PostgreSQL: pgsql/src/backend/libpq/hba.c,v 1.162 2007/07/23 10:16:53 mha Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
@ -604,6 +604,8 @@ parse_hba_auth(ListCell **line_item, UserAuth *userauth_p,
|
|||||||
*userauth_p = uaKrb5;
|
*userauth_p = uaKrb5;
|
||||||
else if (strcmp(token, "gss") == 0)
|
else if (strcmp(token, "gss") == 0)
|
||||||
*userauth_p = uaGSS;
|
*userauth_p = uaGSS;
|
||||||
|
else if (strcmp(token, "sspi") == 0)
|
||||||
|
*userauth_p = uaSSPI;
|
||||||
else if (strcmp(token, "reject") == 0)
|
else if (strcmp(token, "reject") == 0)
|
||||||
*userauth_p = uaReject;
|
*userauth_p = uaReject;
|
||||||
else if (strcmp(token, "md5") == 0)
|
else if (strcmp(token, "md5") == 0)
|
||||||
|
@ -34,7 +34,7 @@
|
|||||||
# the number of significant bits in the mask. Alternatively, you can write
|
# 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.
|
# an IP address and netmask in separate columns to specify the set of hosts.
|
||||||
#
|
#
|
||||||
# METHOD can be "trust", "reject", "md5", "crypt", "password", "gss",
|
# METHOD can be "trust", "reject", "md5", "crypt", "password", "gss", "sspi",
|
||||||
# "krb5", "ident", "pam" or "ldap". Note that "password" sends passwords
|
# "krb5", "ident", "pam" or "ldap". Note that "password" sends passwords
|
||||||
# in clear text; "md5" is preferred since it sends encrypted passwords.
|
# in clear text; "md5" is preferred since it sends encrypted passwords.
|
||||||
#
|
#
|
||||||
|
@ -30,7 +30,7 @@
|
|||||||
* Portions Copyright (c) 1996-2007, PostgreSQL Global Development Group
|
* Portions Copyright (c) 1996-2007, PostgreSQL Global Development Group
|
||||||
* Portions Copyright (c) 1994, Regents of the University of California
|
* Portions Copyright (c) 1994, Regents of the University of California
|
||||||
*
|
*
|
||||||
* $PostgreSQL: pgsql/src/backend/libpq/pqcomm.c,v 1.193 2007/07/10 13:14:20 mha Exp $
|
* $PostgreSQL: pgsql/src/backend/libpq/pqcomm.c,v 1.194 2007/07/23 10:16:54 mha Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
@ -173,15 +173,21 @@ pq_close(int code, Datum arg)
|
|||||||
{
|
{
|
||||||
if (MyProcPort != NULL)
|
if (MyProcPort != NULL)
|
||||||
{
|
{
|
||||||
|
#if defined(ENABLE_GSS) || defined(ENABLE_SSPI)
|
||||||
#ifdef ENABLE_GSS
|
#ifdef ENABLE_GSS
|
||||||
OM_uint32 min_s;
|
OM_uint32 min_s;
|
||||||
|
|
||||||
/* Shutdown GSSAPI layer */
|
/* Shutdown GSSAPI layer */
|
||||||
if (MyProcPort->gss->ctx)
|
if (MyProcPort->gss->ctx)
|
||||||
gss_delete_sec_context(&min_s, MyProcPort->gss->ctx, NULL);
|
gss_delete_sec_context(&min_s, MyProcPort->gss->ctx, NULL);
|
||||||
|
|
||||||
if (MyProcPort->gss->cred)
|
if (MyProcPort->gss->cred)
|
||||||
gss_release_cred(&min_s, MyProcPort->gss->cred);
|
gss_release_cred(&min_s, MyProcPort->gss->cred);
|
||||||
#endif
|
#endif /* ENABLE_GSS */
|
||||||
|
/* GSS and SSPI share the port->gss struct */
|
||||||
|
|
||||||
|
free(MyProcPort->gss);
|
||||||
|
#endif /* ENABLE_GSS || ENABLE_SSPI */
|
||||||
|
|
||||||
/* Cleanly shut down SSL layer */
|
/* Cleanly shut down SSL layer */
|
||||||
secure_close(MyProcPort);
|
secure_close(MyProcPort);
|
||||||
|
@ -37,7 +37,7 @@
|
|||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $PostgreSQL: pgsql/src/backend/postmaster/postmaster.c,v 1.533 2007/07/19 19:13:43 adunstan Exp $
|
* $PostgreSQL: pgsql/src/backend/postmaster/postmaster.c,v 1.534 2007/07/23 10:16:54 mha Exp $
|
||||||
*
|
*
|
||||||
* NOTES
|
* NOTES
|
||||||
*
|
*
|
||||||
@ -1733,7 +1733,8 @@ ConnCreate(int serverFd)
|
|||||||
/*
|
/*
|
||||||
* Allocate GSSAPI specific state struct
|
* Allocate GSSAPI specific state struct
|
||||||
*/
|
*/
|
||||||
#ifdef ENABLE_GSS
|
#ifndef EXEC_BACKEND
|
||||||
|
#if defined(ENABLE_GSS) || defined(ENABLE_SSPI)
|
||||||
port->gss = (pg_gssinfo *)calloc(1, sizeof(pg_gssinfo));
|
port->gss = (pg_gssinfo *)calloc(1, sizeof(pg_gssinfo));
|
||||||
if (!port->gss)
|
if (!port->gss)
|
||||||
{
|
{
|
||||||
@ -1742,6 +1743,7 @@ ConnCreate(int serverFd)
|
|||||||
errmsg("out of memory")));
|
errmsg("out of memory")));
|
||||||
ExitPostmaster(1);
|
ExitPostmaster(1);
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
return port;
|
return port;
|
||||||
@ -3344,6 +3346,19 @@ SubPostmasterMain(int argc, char *argv[])
|
|||||||
memset(&port, 0, sizeof(Port));
|
memset(&port, 0, sizeof(Port));
|
||||||
read_backend_variables(argv[2], &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 */
|
/* Check we got appropriate args */
|
||||||
if (argc < 3)
|
if (argc < 3)
|
||||||
elog(FATAL, "invalid subpostmaster invocation");
|
elog(FATAL, "invalid subpostmaster invocation");
|
||||||
|
@ -4,7 +4,7 @@
|
|||||||
* Interface to hba.c
|
* Interface to hba.c
|
||||||
*
|
*
|
||||||
*
|
*
|
||||||
* $PostgreSQL: pgsql/src/include/libpq/hba.h,v 1.46 2007/07/10 13:14:21 mha Exp $
|
* $PostgreSQL: pgsql/src/include/libpq/hba.h,v 1.47 2007/07/23 10:16:54 mha Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
@ -23,7 +23,8 @@ typedef enum UserAuth
|
|||||||
uaPassword,
|
uaPassword,
|
||||||
uaCrypt,
|
uaCrypt,
|
||||||
uaMD5,
|
uaMD5,
|
||||||
uaGSS
|
uaGSS,
|
||||||
|
uaSSPI
|
||||||
#ifdef USE_PAM
|
#ifdef USE_PAM
|
||||||
,uaPAM
|
,uaPAM
|
||||||
#endif /* USE_PAM */
|
#endif /* USE_PAM */
|
||||||
|
@ -11,7 +11,7 @@
|
|||||||
* Portions Copyright (c) 1996-2007, PostgreSQL Global Development Group
|
* Portions Copyright (c) 1996-2007, PostgreSQL Global Development Group
|
||||||
* Portions Copyright (c) 1994, Regents of the University of California
|
* Portions Copyright (c) 1994, Regents of the University of California
|
||||||
*
|
*
|
||||||
* $PostgreSQL: pgsql/src/include/libpq/libpq-be.h,v 1.61 2007/07/12 14:43:21 mha Exp $
|
* $PostgreSQL: pgsql/src/include/libpq/libpq-be.h,v 1.62 2007/07/23 10:16:54 mha Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
@ -45,6 +45,22 @@
|
|||||||
#endif
|
#endif
|
||||||
#endif /* ENABLE_GSS */
|
#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/hba.h"
|
||||||
#include "libpq/pqcomm.h"
|
#include "libpq/pqcomm.h"
|
||||||
#include "utils/timestamp.h"
|
#include "utils/timestamp.h"
|
||||||
@ -59,13 +75,15 @@ typedef enum CAC_state
|
|||||||
/*
|
/*
|
||||||
* GSSAPI specific state information
|
* GSSAPI specific state information
|
||||||
*/
|
*/
|
||||||
#ifdef ENABLE_GSS
|
#if defined(ENABLE_GSS) | defined(ENABLE_SSPI)
|
||||||
typedef struct
|
typedef struct
|
||||||
{
|
{
|
||||||
|
gss_buffer_desc outbuf; /* GSSAPI output token buffer */
|
||||||
|
#ifdef ENABLE_GSS
|
||||||
gss_cred_id_t cred; /* GSSAPI connection cred's */
|
gss_cred_id_t cred; /* GSSAPI connection cred's */
|
||||||
gss_ctx_id_t ctx; /* GSSAPI connection context */
|
gss_ctx_id_t ctx; /* GSSAPI connection context */
|
||||||
gss_name_t name; /* GSSAPI client name */
|
gss_name_t name; /* GSSAPI client name */
|
||||||
gss_buffer_desc outbuf; /* GSSAPI output token buffer */
|
#endif
|
||||||
} pg_gssinfo;
|
} pg_gssinfo;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
@ -128,7 +146,7 @@ typedef struct Port
|
|||||||
int keepalives_interval;
|
int keepalives_interval;
|
||||||
int keepalives_count;
|
int keepalives_count;
|
||||||
|
|
||||||
#ifdef ENABLE_GSS
|
#if defined(ENABLE_GSS) || defined(ENABLE_SSPI)
|
||||||
/*
|
/*
|
||||||
* If GSSAPI is supported, store GSSAPI information.
|
* If GSSAPI is supported, store GSSAPI information.
|
||||||
* Oterwise, store a NULL pointer to make sure offsets
|
* Oterwise, store a NULL pointer to make sure offsets
|
||||||
|
@ -9,7 +9,7 @@
|
|||||||
* Portions Copyright (c) 1996-2007, PostgreSQL Global Development Group
|
* Portions Copyright (c) 1996-2007, PostgreSQL Global Development Group
|
||||||
* Portions Copyright (c) 1994, Regents of the University of California
|
* Portions Copyright (c) 1994, Regents of the University of California
|
||||||
*
|
*
|
||||||
* $PostgreSQL: pgsql/src/include/libpq/pqcomm.h,v 1.105 2007/07/10 13:14:21 mha Exp $
|
* $PostgreSQL: pgsql/src/include/libpq/pqcomm.h,v 1.106 2007/07/23 10:16:54 mha Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
@ -158,6 +158,7 @@ extern bool Db_user_namespace;
|
|||||||
#define AUTH_REQ_SCM_CREDS 6 /* transfer SCM credentials */
|
#define AUTH_REQ_SCM_CREDS 6 /* transfer SCM credentials */
|
||||||
#define AUTH_REQ_GSS 7 /* GSSAPI without wrap() */
|
#define AUTH_REQ_GSS 7 /* GSSAPI without wrap() */
|
||||||
#define AUTH_REQ_GSS_CONT 8 /* Continue GSS exchanges */
|
#define AUTH_REQ_GSS_CONT 8 /* Continue GSS exchanges */
|
||||||
|
#define AUTH_REQ_SSPI 9 /* SSPI negotiate without wrap() */
|
||||||
|
|
||||||
typedef uint32 AuthRequest;
|
typedef uint32 AuthRequest;
|
||||||
|
|
||||||
|
@ -10,7 +10,7 @@
|
|||||||
* exceed INITIAL_EXPBUFFER_SIZE (currently 256 bytes).
|
* exceed INITIAL_EXPBUFFER_SIZE (currently 256 bytes).
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $PostgreSQL: pgsql/src/interfaces/libpq/fe-auth.c,v 1.127 2007/07/12 14:43:21 mha Exp $
|
* $PostgreSQL: pgsql/src/interfaces/libpq/fe-auth.c,v 1.128 2007/07/23 10:16:54 mha Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
@ -329,11 +329,6 @@ pg_krb5_sendauth(char *PQerrormsg, int sock, const char *hostname, const char *s
|
|||||||
/*
|
/*
|
||||||
* GSSAPI authentication system.
|
* GSSAPI authentication system.
|
||||||
*/
|
*/
|
||||||
#if defined(HAVE_GSSAPI_H)
|
|
||||||
#include <gssapi.h>
|
|
||||||
#else
|
|
||||||
#include <gssapi/gssapi.h>
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#if defined(WIN32) && !defined(WIN32_ONLY_COMPILER)
|
#if defined(WIN32) && !defined(WIN32_ONLY_COMPILER)
|
||||||
/*
|
/*
|
||||||
@ -378,7 +373,7 @@ pg_GSS_error_int(char *mprefix, char *msg, int msglen,
|
|||||||
* GSSAPI errors contains two parts. Put as much as possible of
|
* GSSAPI errors contains two parts. Put as much as possible of
|
||||||
* both parts into the string.
|
* both parts into the string.
|
||||||
*/
|
*/
|
||||||
void
|
static void
|
||||||
pg_GSS_error(char *mprefix, char *msg, int msglen,
|
pg_GSS_error(char *mprefix, char *msg, int msglen,
|
||||||
OM_uint32 maj_stat, OM_uint32 min_stat)
|
OM_uint32 maj_stat, OM_uint32 min_stat)
|
||||||
{
|
{
|
||||||
@ -407,7 +402,7 @@ pg_GSS_continue(char *PQerrormsg, PGconn *conn)
|
|||||||
&conn->gctx,
|
&conn->gctx,
|
||||||
conn->gtarg_nam,
|
conn->gtarg_nam,
|
||||||
GSS_C_NO_OID,
|
GSS_C_NO_OID,
|
||||||
conn->gflags,
|
GSS_C_MUTUAL_FLAG,
|
||||||
0,
|
0,
|
||||||
GSS_C_NO_CHANNEL_BINDINGS,
|
GSS_C_NO_CHANNEL_BINDINGS,
|
||||||
(conn->gctx==GSS_C_NO_CONTEXT)?GSS_C_NO_BUFFER:&conn->ginbuf,
|
(conn->gctx==GSS_C_NO_CONTEXT)?GSS_C_NO_BUFFER:&conn->ginbuf,
|
||||||
@ -504,7 +499,192 @@ pg_GSS_startup(char *PQerrormsg, PGconn *conn)
|
|||||||
|
|
||||||
return pg_GSS_continue(PQerrormsg, conn);
|
return pg_GSS_continue(PQerrormsg, conn);
|
||||||
}
|
}
|
||||||
#endif
|
#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.
|
* Respond to AUTH_REQ_SCM_CREDS challenge.
|
||||||
@ -671,27 +851,60 @@ pg_fe_sendauth(AuthRequest areq, PGconn *conn, const char *hostname,
|
|||||||
return STATUS_ERROR;
|
return STATUS_ERROR;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef ENABLE_GSS
|
#if defined(ENABLE_GSS) || defined(ENABLE_SSPI)
|
||||||
case AUTH_REQ_GSS:
|
case AUTH_REQ_GSS:
|
||||||
pglock_thread();
|
|
||||||
if (pg_GSS_startup(PQerrormsg, conn) != STATUS_OK)
|
|
||||||
{
|
{
|
||||||
/* PQerrormsg already filled in. */
|
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();
|
pgunlock_thread();
|
||||||
return STATUS_ERROR;
|
|
||||||
}
|
}
|
||||||
pgunlock_thread();
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case AUTH_REQ_GSS_CONT:
|
case AUTH_REQ_GSS_CONT:
|
||||||
pglock_thread();
|
|
||||||
if (pg_GSS_continue(PQerrormsg, conn) != STATUS_OK)
|
|
||||||
{
|
{
|
||||||
/* PQerrormsg already filled in. */
|
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();
|
pgunlock_thread();
|
||||||
return STATUS_ERROR;
|
|
||||||
}
|
}
|
||||||
pgunlock_thread();
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
#else
|
#else
|
||||||
@ -702,6 +915,30 @@ pg_fe_sendauth(AuthRequest areq, PGconn *conn, const char *hostname,
|
|||||||
return STATUS_ERROR;
|
return STATUS_ERROR;
|
||||||
#endif
|
#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_MD5:
|
||||||
case AUTH_REQ_CRYPT:
|
case AUTH_REQ_CRYPT:
|
||||||
case AUTH_REQ_PASSWORD:
|
case AUTH_REQ_PASSWORD:
|
||||||
|
@ -8,7 +8,7 @@
|
|||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $PostgreSQL: pgsql/src/interfaces/libpq/fe-connect.c,v 1.349 2007/07/11 08:27:33 mha Exp $
|
* $PostgreSQL: pgsql/src/interfaces/libpq/fe-connect.c,v 1.350 2007/07/23 10:16:54 mha Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
@ -181,12 +181,18 @@ static const PQconninfoOption PQconninfoOptions[] = {
|
|||||||
{"sslmode", "PGSSLMODE", DefaultSSLMode, NULL,
|
{"sslmode", "PGSSLMODE", DefaultSSLMode, NULL,
|
||||||
"SSL-Mode", "", 8}, /* sizeof("disable") == 8 */
|
"SSL-Mode", "", 8}, /* sizeof("disable") == 8 */
|
||||||
|
|
||||||
#if defined(KRB5) || defined(ENABLE_GSS)
|
#if defined(KRB5) || defined(ENABLE_GSS) || defined(ENABLE_SSPI)
|
||||||
/* Kerberos and GSSAPI authentication support specifying the service name */
|
/* Kerberos and GSSAPI authentication support specifying the service name */
|
||||||
{"krbsrvname", "PGKRBSRVNAME", PG_KRB_SRVNAM, NULL,
|
{"krbsrvname", "PGKRBSRVNAME", PG_KRB_SRVNAM, NULL,
|
||||||
"Kerberos-service-name", "", 20},
|
"Kerberos-service-name", "", 20},
|
||||||
#endif
|
#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 */
|
/* Terminating entry --- MUST BE LAST */
|
||||||
{NULL, NULL, NULL, NULL,
|
{NULL, NULL, NULL, NULL,
|
||||||
NULL, NULL, 0}
|
NULL, NULL, 0}
|
||||||
@ -412,10 +418,14 @@ connectOptions1(PGconn *conn, const char *conninfo)
|
|||||||
conn->sslmode = strdup("require");
|
conn->sslmode = strdup("require");
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
#if defined(KRB5) || defined(ENABLE_GSS)
|
#if defined(KRB5) || defined(ENABLE_GSS) || defined(ENABLE_SSPI)
|
||||||
tmp = conninfo_getval(connOptions, "krbsrvname");
|
tmp = conninfo_getval(connOptions, "krbsrvname");
|
||||||
conn->krbsrvname = tmp ? strdup(tmp) : NULL;
|
conn->krbsrvname = tmp ? strdup(tmp) : NULL;
|
||||||
#endif
|
#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
|
* Free the option info - all is in conn now
|
||||||
@ -1661,22 +1671,13 @@ keep_going: /* We will come back to here until there is
|
|||||||
return PGRES_POLLING_READING;
|
return PGRES_POLLING_READING;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#ifdef ENABLE_GSS
|
#if defined(ENABLE_GSS) || defined(ENABLE_SSPI)
|
||||||
/*
|
/*
|
||||||
* AUTH_REQ_GSS provides no input data
|
* Continue GSSAPI/SSPI authentication
|
||||||
* 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)
|
if (areq == AUTH_REQ_GSS_CONT)
|
||||||
{
|
{
|
||||||
/* Continue GSSAPI authentication */
|
|
||||||
int llen = msgLength - 4;
|
int llen = msgLength - 4;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* We can be called repeatedly for the same buffer.
|
* We can be called repeatedly for the same buffer.
|
||||||
* Avoid re-allocating the buffer in this case -
|
* Avoid re-allocating the buffer in this case -
|
||||||
@ -2002,7 +2003,7 @@ freePGconn(PGconn *conn)
|
|||||||
free(conn->pgpass);
|
free(conn->pgpass);
|
||||||
if (conn->sslmode)
|
if (conn->sslmode)
|
||||||
free(conn->sslmode);
|
free(conn->sslmode);
|
||||||
#if defined(KRB5) || defined(ENABLE_GSS)
|
#if defined(KRB5) || defined(ENABLE_GSS) || defined(ENABLE_SSPI)
|
||||||
if (conn->krbsrvname)
|
if (conn->krbsrvname)
|
||||||
free(conn->krbsrvname);
|
free(conn->krbsrvname);
|
||||||
#endif
|
#endif
|
||||||
@ -2030,6 +2031,26 @@ freePGconn(PGconn *conn)
|
|||||||
if (conn->goutbuf.length)
|
if (conn->goutbuf.length)
|
||||||
gss_release_buffer(&min_s, &conn->goutbuf);
|
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
|
#endif
|
||||||
pstatus = conn->pstatus;
|
pstatus = conn->pstatus;
|
||||||
while (pstatus != NULL)
|
while (pstatus != NULL)
|
||||||
|
@ -12,7 +12,7 @@
|
|||||||
* Portions Copyright (c) 1996-2007, PostgreSQL Global Development Group
|
* Portions Copyright (c) 1996-2007, PostgreSQL Global Development Group
|
||||||
* Portions Copyright (c) 1994, Regents of the University of California
|
* Portions Copyright (c) 1994, Regents of the University of California
|
||||||
*
|
*
|
||||||
* $PostgreSQL: pgsql/src/interfaces/libpq/libpq-int.h,v 1.123 2007/07/12 14:36:52 mha Exp $
|
* $PostgreSQL: pgsql/src/interfaces/libpq/libpq-int.h,v 1.124 2007/07/23 10:16:54 mha Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
@ -52,6 +52,22 @@
|
|||||||
#endif
|
#endif
|
||||||
#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
|
#ifdef USE_SSL
|
||||||
#include <openssl/ssl.h>
|
#include <openssl/ssl.h>
|
||||||
#include <openssl/err.h>
|
#include <openssl/err.h>
|
||||||
@ -276,7 +292,7 @@ struct pg_conn
|
|||||||
char *pguser; /* Postgres username and password, if any */
|
char *pguser; /* Postgres username and password, if any */
|
||||||
char *pgpass;
|
char *pgpass;
|
||||||
char *sslmode; /* SSL mode (require,prefer,allow,disable) */
|
char *sslmode; /* SSL mode (require,prefer,allow,disable) */
|
||||||
#if defined(KRB5) || defined(ENABLE_GSS)
|
#if defined(KRB5) || defined(ENABLE_GSS) || defined(ENABLE_SSPI)
|
||||||
char *krbsrvname; /* Kerberos service name */
|
char *krbsrvname; /* Kerberos service name */
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
@ -361,11 +377,23 @@ struct pg_conn
|
|||||||
#ifdef ENABLE_GSS
|
#ifdef ENABLE_GSS
|
||||||
gss_ctx_id_t gctx; /* GSS context */
|
gss_ctx_id_t gctx; /* GSS context */
|
||||||
gss_name_t gtarg_nam; /* GSS target name */
|
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 ginbuf; /* GSS input token */
|
||||||
gss_buffer_desc goutbuf; /* GSS output token */
|
gss_buffer_desc goutbuf; /* GSS output token */
|
||||||
#endif
|
#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 */
|
/* Buffer for current error message */
|
||||||
PQExpBufferData errorMessage; /* expansible string */
|
PQExpBufferData errorMessage; /* expansible string */
|
||||||
|
|
||||||
@ -415,12 +443,6 @@ extern pgthreadlock_t pg_g_threadlock;
|
|||||||
#define pgunlock_thread() ((void) 0)
|
#define pgunlock_thread() ((void) 0)
|
||||||
#endif
|
#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 === */
|
/* === in fe-exec.c === */
|
||||||
|
|
||||||
extern void pqSetResultError(PGresult *res, const char *msg);
|
extern void pqSetResultError(PGresult *res, const char *msg);
|
||||||
|
@ -3,7 +3,7 @@ package Mkvcbuild;
|
|||||||
#
|
#
|
||||||
# Package that generates build files for msvc build
|
# Package that generates build files for msvc build
|
||||||
#
|
#
|
||||||
# $PostgreSQL: pgsql/src/tools/msvc/Mkvcbuild.pm,v 1.14 2007/07/07 07:43:20 mha Exp $
|
# $PostgreSQL: pgsql/src/tools/msvc/Mkvcbuild.pm,v 1.15 2007/07/23 10:16:54 mha Exp $
|
||||||
#
|
#
|
||||||
use Carp;
|
use Carp;
|
||||||
use Win32;
|
use Win32;
|
||||||
@ -66,7 +66,7 @@ sub mkvcbuild
|
|||||||
$postgres->AddFiles('src\backend\bootstrap','bootscanner.l','bootparse.y');
|
$postgres->AddFiles('src\backend\bootstrap','bootscanner.l','bootparse.y');
|
||||||
$postgres->AddFiles('src\backend\utils\misc','guc-file.l');
|
$postgres->AddFiles('src\backend\utils\misc','guc-file.l');
|
||||||
$postgres->AddDefine('BUILDING_DLL');
|
$postgres->AddDefine('BUILDING_DLL');
|
||||||
$postgres->AddLibrary('wsock32.lib ws2_32.lib');
|
$postgres->AddLibrary('wsock32.lib ws2_32.lib secur32.lib');
|
||||||
$postgres->AddLibrary('wldap32.lib') if ($solution->{options}->{ldap});
|
$postgres->AddLibrary('wldap32.lib') if ($solution->{options}->{ldap});
|
||||||
$postgres->FullExportDLL('postgres.lib');
|
$postgres->FullExportDLL('postgres.lib');
|
||||||
|
|
||||||
@ -120,6 +120,7 @@ sub mkvcbuild
|
|||||||
$libpq->AddDefine('FRONTEND');
|
$libpq->AddDefine('FRONTEND');
|
||||||
$libpq->AddIncludeDir('src\port');
|
$libpq->AddIncludeDir('src\port');
|
||||||
$libpq->AddLibrary('wsock32.lib');
|
$libpq->AddLibrary('wsock32.lib');
|
||||||
|
$libpq->AddLibrary('secur32.lib');
|
||||||
$libpq->AddLibrary('wldap32.lib') if ($solution->{options}->{ldap});
|
$libpq->AddLibrary('wldap32.lib') if ($solution->{options}->{ldap});
|
||||||
$libpq->UseDef('src\interfaces\libpq\libpqdll.def');
|
$libpq->UseDef('src\interfaces\libpq\libpqdll.def');
|
||||||
$libpq->ReplaceFile('src\interfaces\libpq\libpqrc.c','src\interfaces\libpq\libpq.rc');
|
$libpq->ReplaceFile('src\interfaces\libpq\libpqrc.c','src\interfaces\libpq\libpq.rc');
|
||||||
|
@ -3,7 +3,7 @@ package Solution;
|
|||||||
#
|
#
|
||||||
# Package that encapsulates a Visual C++ solution file generation
|
# Package that encapsulates a Visual C++ solution file generation
|
||||||
#
|
#
|
||||||
# $PostgreSQL: pgsql/src/tools/msvc/Solution.pm,v 1.29 2007/07/12 14:43:21 mha Exp $
|
# $PostgreSQL: pgsql/src/tools/msvc/Solution.pm,v 1.30 2007/07/23 10:16:54 mha Exp $
|
||||||
#
|
#
|
||||||
use Carp;
|
use Carp;
|
||||||
use strict;
|
use strict;
|
||||||
@ -124,16 +124,16 @@ s{PG_VERSION_STR "[^"]+"}{__STRINGIFY(x) #x\n#define __STRINGIFY2(z) __STRINGIFY
|
|||||||
print O "#define HAVE_KRB5_ERROR_TEXT_DATA 1\n";
|
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_TICKET_ENC_PART2 1\n";
|
||||||
print O "#define HAVE_KRB5_FREE_UNPARSED_NAME 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 1\n";
|
||||||
print O "#define ENABLE_GSS\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";
|
||||||
}
|
}
|
||||||
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 "#define VAL_CONFIGURE \"" . $self->GetFakeConfigure() . "\"\n";
|
||||||
print O "#endif /* IGNORE_CONFIGURED_SETTINGS */\n";
|
print O "#endif /* IGNORE_CONFIGURED_SETTINGS */\n";
|
||||||
close(O);
|
close(O);
|
||||||
|
Loading…
x
Reference in New Issue
Block a user