*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/libpq/auth.c,v 1.40 1999/07/17 20:17:00 momjian Exp $
+ * $Header: /cvsroot/pgsql/src/backend/libpq/auth.c,v 1.41 1999/09/27 03:12:58 momjian Exp $
*
*-------------------------------------------------------------------------
*/
* an error message into the postmaster logfile if it failed.
*/
- if (hba_getauthmethod(&port->raddr, port->user, port->database,
- port->auth_arg, &port->auth_method) != STATUS_OK)
+ if (hba_getauthmethod(port) != STATUS_OK)
PacketSendError(&port->pktInfo,
"Missing or erroneous pg_hba.conf file, see postmaster log for details");
AuthRequest areq = AUTH_REQ_OK;
PacketDoneProc auth_handler = NULL;
-
switch (port->auth_method)
{
case uaReject:
* wherein you authenticate a user by seeing what IP address the system
* says he comes from and possibly using ident).
*
- * $Id: hba.c,v 1.47 1999/07/17 20:17:02 momjian Exp $
+ * $Id: hba.c,v 1.48 1999/09/27 03:12:59 momjian Exp $
*
*-------------------------------------------------------------------------
*/
static void
-process_hba_record(FILE *file, SockAddr *raddr, const char *user,
- const char *database, bool *matches_p, bool *error_p,
- UserAuth *userauth_p, char *auth_arg)
+process_hba_record(FILE *file, hbaPort *port, bool *matches_p, bool *error_p)
{
/*---------------------------------------------------------------------------
Process the non-comment record in the config file that is next on the file.
/* Read the rest of the line. */
- read_hba_entry2(file, userauth_p, auth_arg, error_p);
+ read_hba_entry2(file, &port->auth_method, port->auth_arg, error_p);
/*
* For now, disallow methods that need AF_INET sockets to work.
*/
if (!*error_p &&
- (*userauth_p == uaIdent ||
- *userauth_p == uaKrb4 ||
- *userauth_p == uaKrb5))
+ (port->auth_method == uaIdent ||
+ port->auth_method == uaKrb4 ||
+ port->auth_method == uaKrb5))
*error_p = true;
if (*error_p)
* sort of connection, ignore it.
*/
- if ((strcmp(db, database) != 0 && strcmp(db, "all") != 0 &&
- (strcmp(db, "sameuser") != 0 || strcmp(database, user) != 0)) ||
- raddr->sa.sa_family != AF_UNIX)
+ if ((strcmp(db, port->database) != 0 && strcmp(db, "all") != 0 &&
+ (strcmp(db, "sameuser") != 0 || strcmp(port->database, port->user) != 0)) ||
+ port->raddr.sa.sa_family != AF_UNIX)
return;
}
- else if (strcmp(buf, "host") == 0)
+ else if (strcmp(buf, "host") == 0 || strcmp(buf, "hostssl") == 0)
{
struct in_addr file_ip_addr,
mask;
+ bool discard = 0; /* Discard this entry */
+
+#ifdef USE_SSL
+ /* If SSL, then check that we are on SSL */
+ if (strcmp(buf, "hostssl") == 0) {
+ if (!port->ssl)
+ discard = 1;
+
+ /* Placeholder to require specific SSL level, perhaps? */
+ /* Or a client certificate */
+
+ /* Since we were on SSL, proceed as with normal 'host' mode */
+ }
+#else
+ /* If not SSL, we don't support this */
+ if (strcmp(buf,"hostssl") == 0)
+ goto syntax;
+#endif
/* Get the database. */
* info from it.
*/
- read_hba_entry2(file, userauth_p, auth_arg, error_p);
+ read_hba_entry2(file, &port->auth_method, port->auth_arg, error_p);
if (*error_p)
goto syntax;
+ /*
+ * If told to discard earlier. Moved down here so we don't get
+ * "out of sync" with the file.
+ */
+ if (discard)
+ return;
+
/*
* If this record isn't for our database, or this is the wrong
* sort of connection, ignore it.
*/
- if ((strcmp(db, database) != 0 && strcmp(db, "all") != 0 &&
- (strcmp(db, "sameuser") != 0 || strcmp(database, user) != 0)) ||
- raddr->sa.sa_family != AF_INET ||
- ((file_ip_addr.s_addr ^ raddr->in.sin_addr.s_addr) & mask.s_addr) != 0x0000)
+ if ((strcmp(db, port->database) != 0 && strcmp(db, "all") != 0 &&
+ (strcmp(db, "sameuser") != 0 || strcmp(port->database, port->user) != 0)) ||
+ port->raddr.sa.sa_family != AF_INET ||
+ ((file_ip_addr.s_addr ^ port->raddr.in.sin_addr.s_addr) & mask.s_addr) != 0x0000)
return;
}
else
static void
-process_open_config_file(FILE *file, SockAddr *raddr, const char *user,
- const char *database, bool *hba_ok_p,
- UserAuth *userauth_p, char *auth_arg)
+process_open_config_file(FILE *file, hbaPort *port, bool *hba_ok_p)
{
/*---------------------------------------------------------------------------
This function does the same thing as find_hba_entry, only with
if (c == '#')
read_through_eol(file);
else
- process_hba_record(file, raddr, user, database,
- &found_entry, &error, userauth_p, auth_arg);
+ process_hba_record(file, port, &found_entry, &error);
}
}
/* If no matching entry was found, synthesize 'reject' entry. */
if (!found_entry)
- *userauth_p = uaReject;
+ port->auth_method = uaReject;
*hba_ok_p = true;
}
static void
-find_hba_entry(SockAddr *raddr, const char *user, const char *database,
- bool *hba_ok_p, UserAuth *userauth_p, char *auth_arg)
+find_hba_entry(hbaPort *port, bool *hba_ok_p)
{
/*
* Read the config file and find an entry that allows connection from
}
else
{
- process_open_config_file(file, raddr, user, database, hba_ok_p,
- userauth_p, auth_arg);
+ process_open_config_file(file, port, hba_ok_p);
FreeFile(file);
}
pfree(conf_file);
#endif
int
-hba_getauthmethod(SockAddr *raddr, char *user, char *database,
- char *auth_arg, UserAuth *auth_method)
+hba_getauthmethod(hbaPort *port)
{
/*---------------------------------------------------------------------------
Determine what authentication method should be used when accessing database
----------------------------------------------------------------------------*/
bool hba_ok = false;
- find_hba_entry(raddr, user, database, &hba_ok, auth_method, auth_arg);
+ find_hba_entry(port, &hba_ok);
return hba_ok ? STATUS_OK : STATUS_ERROR;
}
#
# krb5: Kerberos V5 authentication is used.
+# Record type "hostssl"
+# ---------------------
+#
+# This record identifies the authentication to use when connecting to a
+# particular database via TCP/IP sockets over SSL. Note that normal
+# "host" records are also matched - "hostssl" records can be used to
+# require a SSL connection.
+# This keyword is only available if the server is compiled with SSL support
+# enabled.
+#
+# The format of this record is identical to that of "host".
+
# Record type "local"
# ------------------
#
*
* Copyright (c) 1994, Regents of the University of California
*
- * $Id: pqcomm.c,v 1.83 1999/09/08 22:57:12 tgl Exp $
+ * $Id: pqcomm.c,v 1.84 1999/09/27 03:12:59 momjian Exp $
*
*-------------------------------------------------------------------------
*/
/* Can fill buffer from PqRecvLength and upwards */
for (;;)
{
- int r = recv(MyProcPort->sock, PqRecvBuffer + PqRecvLength,
- PQ_BUFFER_SIZE - PqRecvLength, 0);
+ int r;
+
+#ifdef USE_SSL
+ if (MyProcPort->ssl)
+ r = SSL_read(MyProcPort->ssl, PqRecvBuffer + PqRecvLength,
+ PQ_BUFFER_SIZE - PqRecvLength);
+ else
+#endif
+ r = recv(MyProcPort->sock, PqRecvBuffer + PqRecvLength,
+ PQ_BUFFER_SIZE - PqRecvLength, 0);
if (r < 0)
{
while (bufptr < bufend)
{
- int r = send(MyProcPort->sock, bufptr, bufend - bufptr, 0);
+ int r;
+#ifdef USE_SSL
+ if (MyProcPort->ssl)
+ r = SSL_write(MyProcPort->ssl, bufptr, bufend - bufptr);
+ else
+#endif
+ r = send(MyProcPort->sock, bufptr, bufend - bufptr, 0);
if (r <= 0)
{
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/libpq/Attic/pqpacket.c,v 1.22 1999/07/17 20:17:03 momjian Exp $
+ * $Header: /cvsroot/pgsql/src/backend/libpq/Attic/pqpacket.c,v 1.23 1999/09/27 03:12:59 momjian Exp $
*
*-------------------------------------------------------------------------
*/
*/
int
-PacketReceiveFragment(Packet *pkt, int sock)
+PacketReceiveFragment(Port *port)
{
int got;
-
- if ((got = read(sock, pkt->ptr, pkt->nrtodo)) > 0)
+ Packet *pkt = &port->pktInfo;
+
+#ifdef USE_SSL
+ if (port->ssl)
+ got = SSL_read(port->ssl, pkt->ptr, pkt->nrtodo);
+ else
+#endif
+ got = read(port->sock, pkt->ptr, pkt->nrtodo);
+ if (got > 0)
{
- pkt->nrtodo -= got;
+ pkt->nrtodo -= got;
pkt->ptr += got;
/* See if we have got what we need for the packet length. */
*/
int
-PacketSendFragment(Packet *pkt, int sock)
+PacketSendFragment(Port *port)
{
int done;
+ Packet *pkt = &port->pktInfo;
+
+#ifdef USE_SSL
+ if (port->ssl)
+ done = SSL_write(port->ssl, pkt->ptr, pkt->nrtodo);
+ else
+#endif
+ done = write(port->sock, pkt->ptr, pkt->nrtodo);
- if ((done = write(sock, pkt->ptr, pkt->nrtodo)) > 0)
+ if (done > 0)
{
pkt->nrtodo -= done;
pkt->ptr += done;
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/postmaster/postmaster.c,v 1.116 1999/09/21 20:58:19 momjian Exp $
+ * $Header: /cvsroot/pgsql/src/backend/postmaster/postmaster.c,v 1.117 1999/09/27 03:13:05 momjian Exp $
*
* NOTES
*
#endif
+#ifdef USE_SSL
+static SSL_CTX *SSL_context = NULL; /* Global SSL context */
+#endif
+
/*
* Set by the -o option
*/
static bool NetServer = false; /* if not zero, postmaster listen for
* non-local connections */
+static bool SecureNetServer = false; /* if not zero, postmaster listens for only SSL
+ * non-local connections */
/*
*/
static void pmdaemonize(void);
static Port *ConnCreate(int serverFd);
+static void ConnFree(Port *port);
static void reset_shared(unsigned short port);
static void pmdie(SIGNAL_ARGS);
static void reaper(SIGNAL_ARGS);
static void RandomSalt(char *salt);
static void SignalChildren(SIGNAL_ARGS);
static int CountChildren(void);
+#ifdef USE_SSL
+static void InitSSL(void);
+#endif
#ifdef CYR_RECODE
void GetCharSetByHost(char *, int, char *);
DataDir = getenv("PGDATA"); /* default value */
opterr = 0;
- while ((opt = getopt(nonblank_argc, argv, "A:a:B:b:D:dim:MN:no:p:Ss")) != EOF)
+ while ((opt = getopt(nonblank_argc, argv, "A:a:B:b:D:i::dm:MN:no:p:Ss")) != EOF)
{
switch (opt)
{
break;
case 'i':
NetServer = true;
+#ifdef USE_SSL
+ if (optarg && !strcasecmp(optarg,"s"))
+ SecureNetServer = true;
+#endif
break;
case 'm':
/* Multiplexed backends no longer supported. */
exit(1);
}
+#ifdef USE_SSL
+ InitSSL();
+#endif
+
if (NetServer)
{
- status = StreamServerPort(hostName, PostPortName, &ServerSock_INET);
- if (status != STATUS_OK)
- {
- fprintf(stderr, "%s: cannot create INET stream port\n",
- progname);
- exit(1);
- }
+ status = StreamServerPort(hostName, PostPortName, &ServerSock_INET);
+ if (status != STATUS_OK)
+ {
+ fprintf(stderr, "%s: cannot create INET stream port\n",
+ progname);
+ exit(1);
+ }
}
+
#ifndef __CYGWIN32__
status = StreamServerPort(NULL, PostPortName, &ServerSock_UNIX);
if (status != STATUS_OK)
fprintf(stderr, "\t-b backend\tuse a specific backend server executable\n");
fprintf(stderr, "\t-d [1|2|3]\tset debugging level\n");
fprintf(stderr, "\t-i \t\tlisten on TCP/IP sockets as well as Unix domain socket\n");
+#ifdef USE_SSL
+ fprintf(stderr," \t-is\t\tlisten on TCP/IP sockets as above, but only SSL connections\n");
+#endif
fprintf(stderr, "\t-N nprocs\tset max number of backends (1..%d, default %d)\n",
MAXBACKENDS, DEF_MAXBACKENDS);
fprintf(stderr, "\t-n \t\tdon't reinitialize shared memory after abnormal exit\n");
Port *port;
fd_set rmask,
wmask;
+#ifdef USE_SSL
+ int no_select = 0;
+#endif
#ifdef HAVE_SIGPROCMASK
sigprocmask(SIG_SETMASK, &oldsigmask, 0);
memmove((char *) &rmask, (char *) &readmask, sizeof(fd_set));
memmove((char *) &wmask, (char *) &writemask, sizeof(fd_set));
+
+#ifdef USE_SSL
+ for (curr = DLGetHead(PortList); curr; curr = DLGetSucc(curr))
+ if (((Port *)DLE_VAL(curr))->ssl &&
+ SSL_pending(((Port *)DLE_VAL(curr))->ssl) > 0) {
+ no_select = 1;
+ break;
+ }
+ if (no_select)
+ FD_ZERO(&rmask); /* So we don't accept() anything below */
+ else
+#endif
if (select(nSockets, &rmask, &wmask, (fd_set *) NULL,
(struct timeval *) NULL) < 0)
{
#ifndef __CYGWIN32__
if (ServerSock_UNIX != INVALID_SOCK &&
FD_ISSET(ServerSock_UNIX, &rmask) &&
- (port = ConnCreate(ServerSock_UNIX)) != NULL)
- PacketReceiveSetup(&port->pktInfo,
+ (port = ConnCreate(ServerSock_UNIX)) != NULL) {
+ PacketReceiveSetup(&port->pktInfo,
readStartupPacket,
(void *) port);
+ }
#endif
if (ServerSock_INET != INVALID_SOCK &&
- FD_ISSET(ServerSock_INET, &rmask) &&
- (port = ConnCreate(ServerSock_INET)) != NULL)
+ FD_ISSET(ServerSock_INET, &rmask) &&
+ (port = ConnCreate(ServerSock_INET)) != NULL) {
PacketReceiveSetup(&port->pktInfo,
readStartupPacket,
(void *) port);
+ }
/* Build up new masks for select(). */
Port *port = (Port *) DLE_VAL(curr);
int status = STATUS_OK;
Dlelem *next;
+ int readyread = 0;
+
+#ifdef USE_SSL
+ if (port->ssl) {
+ if (SSL_pending(port->ssl) ||
+ FD_ISSET(port->sock, &rmask))
+ readyread = 1;
+ }
+ else
+#endif
+ if (FD_ISSET(port->sock, &rmask))
+ readyread = 1;
- if (FD_ISSET(port->sock, &rmask))
+ if (readyread)
{
if (DebugLvl > 1)
fprintf(stderr, "%s: ServerLoop:\t\thandling reading %d\n",
progname, port->sock);
- if (PacketReceiveFragment(&port->pktInfo, port->sock) != STATUS_OK)
+ if (PacketReceiveFragment(port) != STATUS_OK)
status = STATUS_ERROR;
}
fprintf(stderr, "%s: ServerLoop:\t\thandling writing %d\n",
progname, port->sock);
- if (PacketSendFragment(&port->pktInfo, port->sock) != STATUS_OK)
+ if (PacketSendFragment(port) != STATUS_OK)
status = STATUS_ERROR;
}
{
StreamClose(port->sock);
DLRemove(curr);
- free(port);
+ ConnFree(port);
DLFreeElem(curr);
}
else
port = (Port *) arg;
si = (StartupPacket *) pkt;
-
+
/*
* The first field is either a protocol version number or a special
* request code.
if (port->proto == CANCEL_REQUEST_CODE)
return processCancelRequest(port, len, pkt);
+ if (port->proto == NEGOTIATE_SSL_CODE) {
+ char SSLok;
+
+#ifdef USE_SSL
+ SSLok = 'S'; /* Support for SSL */
+#else
+ SSLok = 'N'; /* No support for SSL */
+#endif
+ if (send(port->sock, &SSLok, 1, 0) != 1) {
+ perror("Failed to send SSL negotiation response");
+ return STATUS_ERROR; /* Close connection */
+ }
+
+#ifdef USE_SSL
+ if (!(port->ssl = SSL_new(SSL_context)) ||
+ !SSL_set_fd(port->ssl, port->sock) ||
+ SSL_accept(port->ssl) <= 0)
+ {
+ fprintf(stderr,"Failed to initialize SSL connection: %s, errno: %d (%s)\n",
+ ERR_reason_error_string(ERR_get_error()), errno, strerror(errno));
+ return STATUS_ERROR;
+ }
+#endif
+ /* ready for the normal startup packet */
+ PacketReceiveSetup(&port->pktInfo,
+ readStartupPacket,
+ (void *)port);
+ return STATUS_OK; /* Do not close connection */
+ }
+
/* Could add additional special packet types here */
+ /* Any SSL negotiation must have taken place here, so drop the connection
+ * ASAP if we require SSL */
+ if (SecureNetServer && !port->ssl) {
+ PacketSendError(&port->pktInfo, "Backend requires secure connection.");
+ return STATUS_OK;
+ }
+
/* Check we can handle the protocol the frontend is using. */
if (PG_PROTOCOL_MAJOR(port->proto) < PG_PROTOCOL_MAJOR(PG_PROTOCOL_EARLIEST) ||
return STATUS_OK; /* don't close the connection yet */
}
-
/*
* The client has sent a cancel request packet, not a normal
* start-a-new-backend packet. Perform the necessary processing.
return port;
}
+/*
+ * ConnFree -- cree a local connection data structure
+ */
+void
+ConnFree(Port *conn)
+{
+#ifdef USE_SSL
+ if (conn->ssl) {
+ SSL_free(conn->ssl);
+ }
+#endif
+ free(conn);
+}
+
/*
* reset_shared -- reset shared memory and semaphores
*/
sigprocmask(SIG_SETMASK, &oldsigmask, 0);
/* Close the postmaster sockets */
- if (NetServer)
+ if (NetServer)
StreamClose(ServerSock_INET);
#ifndef __CYGWIN32__
StreamClose(ServerSock_UNIX);
}
return cnt;
}
+
+
+/*
+ * Initialize SSL library and structures
+ */
+static void InitSSL(void) {
+ char fnbuf[2048];
+
+ SSL_load_error_strings();
+ SSL_library_init();
+ SSL_context = SSL_CTX_new(SSLv23_method());
+ if (!SSL_context) {
+ fprintf(stderr, "Failed to create SSL context: %s\n",ERR_reason_error_string(ERR_get_error()));
+ exit(1);
+ }
+ snprintf(fnbuf,sizeof(fnbuf),"%s/server.crt", DataDir);
+ if (!SSL_CTX_use_certificate_file(SSL_context, fnbuf, SSL_FILETYPE_PEM)) {
+ fprintf(stderr, "Failed to load server certificate (%s): %s\n",fnbuf,ERR_reason_error_string(ERR_get_error()));
+ exit(1);
+ }
+ snprintf(fnbuf,sizeof(fnbuf),"%s/server.key", DataDir);
+ if (!SSL_CTX_use_PrivateKey_file(SSL_context, fnbuf, SSL_FILETYPE_PEM)) {
+ fprintf(stderr, "Failed to load private key file (%s): %s\n",fnbuf,ERR_reason_error_string(ERR_get_error()));
+ exit(1);
+ }
+ if (!SSL_CTX_check_private_key(SSL_context)) {
+ fprintf(stderr, "Check of private key failed: %s\n",ERR_reason_error_string(ERR_get_error()));
+ exit(1);
+ }
+}
* Interface to hba.c
*
*
- * $Id: hba.h,v 1.14 1999/07/14 01:20:17 momjian Exp $
+ * $Id: hba.h,v 1.15 1999/09/27 03:13:10 momjian Exp $
*
*-------------------------------------------------------------------------
*/
uaCrypt
} UserAuth;
-int hba_getauthmethod(SockAddr *raddr, char *user, char *database,
- char *auth_arg, UserAuth *auth_method);
+typedef struct Port hbaPort;
+
+int hba_getauthmethod(hbaPort *port);
int authident(struct sockaddr_in * raddr, struct sockaddr_in * laddr,
const char *postgres_username, const char *auth_arg);
*
* Copyright (c) 1994, Regents of the University of California
*
- * $Id: libpq-be.h,v 1.16 1999/07/17 20:18:28 momjian Exp $
+ * $Id: libpq-be.h,v 1.17 1999/09/27 03:13:11 momjian Exp $
*
*-------------------------------------------------------------------------
*/
#include "libpq/hba.h"
+#ifdef USE_SSL
+#include <openssl/ssl.h>
+#include <openssl/err.h>
+#endif
+
/* Protocol v0 password packet. */
char tty[SM_TTY + 1];
char auth_arg[MAX_AUTH_ARG];
UserAuth auth_method;
+
+ /*
+ * SSL structures
+ */
+#ifdef USE_SSL
+ SSL *ssl;
+#endif
} Port;
* prototypes for functions in pqpacket.c
*/
void PacketReceiveSetup(Packet *pkt, PacketDoneProc iodone, void *arg);
-int PacketReceiveFragment(Packet *pkt, int sock);
+int PacketReceiveFragment(Port *port);
void PacketSendSetup(Packet *pkt, int nbytes, PacketDoneProc iodone, void *arg);
-int PacketSendFragment(Packet *pkt, int sock);
+int PacketSendFragment(Port *port);
void PacketSendError(Packet *pkt, char *errormsg);
#endif /* LIBPQ_BE_H */
*
* Copyright (c) 1994, Regents of the University of California
*
- * $Id: pqcomm.h,v 1.39 1999/08/31 04:26:33 tgl Exp $
+ * $Id: pqcomm.h,v 1.40 1999/09/27 03:13:11 momjian Exp $
*
*-------------------------------------------------------------------------
*/
uint32 cancelAuthCode; /* secret key to authorize cancel */
} CancelRequestPacket;
+
+/*
+ * A client can also start by sending a SSL negotiation request, to get a
+ * secure channel.
+ */
+#define NEGOTIATE_SSL_CODE PG_PROTOCOL(1234,5679)
+
#endif /* PQCOMM_H */
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/interfaces/libpq/fe-connect.c,v 1.102 1999/08/31 01:37:36 tgl Exp $
+ * $Header: /cvsroot/pgsql/src/interfaces/libpq/fe-connect.c,v 1.103 1999/09/27 03:13:16 momjian Exp $
*
*-------------------------------------------------------------------------
*/
#include "mb/pg_wchar.h"
#endif
+#ifdef USE_SSL
+static SSL_CTX *SSL_context = NULL;
+#endif
+
static ConnStatusType connectDB(PGconn *conn);
static PGconn *makeEmptyPGconn(void);
static void freePGconn(PGconn *conn);
family;
char beresp;
int on = 1;
+#ifdef USE_SSL
+ StartupPacket np; /* Used to negotiate SSL connection */
+ char SSLok;
+ static int allow_ssl_try = 1; /* Allowed to do SSL negotiation */
+ int tried_ssl = 0; /* Set if SSL negotiation was tried */
+#endif
/*
* parse dbName to get all additional info in it, if any
goto connect_errReturn;
}
+ /* This needs to be done before we set into nonblocking, since SSL negotiation
+ * does not like that mode */
+
+#ifdef USE_SSL
+ /* Attempt to negotiate SSL usage */
+ if (allow_ssl_try) {
+ tried_ssl = 1;
+ memset((char *)&np, 0, sizeof(np));
+ np.protoVersion = htonl(NEGOTIATE_SSL_CODE);
+ if (pqPacketSend(conn, (char *) &np, sizeof(StartupPacket)) != STATUS_OK)
+ {
+ sprintf(conn->errorMessage,
+ "connectDB() -- couldn't send SSL negotiation packet: errno=%d\n%s\n",
+ errno, strerror(errno));
+ goto connect_errReturn;
+ }
+ /* Now receive the backends response */
+ if (recv(conn->sock, &SSLok, 1, 0) != 1) {
+ sprintf(conn->errorMessage, "PQconnectDB() -- couldn't read backend response: errno=%d\n%s\n",
+ errno, strerror(errno));
+ goto connect_errReturn;
+ }
+ if (SSLok == 'S') {
+ if (!SSL_context)
+ {
+ SSL_load_error_strings();
+ SSL_library_init();
+ SSL_context = SSL_CTX_new(SSLv23_method());
+ if (!SSL_context) {
+ sprintf(conn->errorMessage,
+ "connectDB() -- couldn't create SSL context: %s\n",
+ ERR_reason_error_string(ERR_get_error()));
+ goto connect_errReturn;
+ }
+ }
+ if (!(conn->ssl = SSL_new(SSL_context)) ||
+ !SSL_set_fd(conn->ssl, conn->sock) ||
+ SSL_connect(conn->ssl) <= 0)
+ {
+ sprintf(conn->errorMessage,
+ "connectDB() -- couldn't establish SSL connection: %s\n",
+ ERR_reason_error_string(ERR_get_error()));
+ goto connect_errReturn;
+ }
+ /* SSL connection finished. Continue to send startup packet */
+ }
+ else if (SSLok == 'E') {
+ /* Received error - probably protocol mismatch */
+ if (conn->Pfdebug)
+ fprintf(conn->Pfdebug, "Backend reports error, attempting fallback to pre-6.6.\n");
+ close(conn->sock);
+ allow_ssl_try = 0;
+ return connectDB(conn);
+ }
+ else if (SSLok != 'N') {
+ strcpy(conn->errorMessage,
+ "Received invalid negotiation response.\n");
+ goto connect_errReturn;
+ }
+ }
+ else
+ allow_ssl_try = 1; /* We'll allow an attempt to use SSL next time */
+#endif
+
/*
* Set the right options. We need nonblocking I/O, and we don't want
* delay of outgoing data.
if (!conn)
return;
pqClearAsyncResult(conn); /* deallocate result and curTuple */
+#ifdef USE_SSL
+ if (conn->ssl)
+ SSL_free(conn->ssl);
+#endif
if (conn->sock >= 0)
#ifdef WIN32
closesocket(conn->sock);
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/interfaces/libpq/fe-misc.c,v 1.30 1999/09/13 03:00:19 tgl Exp $
+ * $Header: /cvsroot/pgsql/src/interfaces/libpq/fe-misc.c,v 1.31 1999/09/27 03:13:16 momjian Exp $
*
*-------------------------------------------------------------------------
*/
/* OK, try to read some data */
tryAgain:
- nread = recv(conn->sock, conn->inBuffer + conn->inEnd,
+#ifdef USE_SSL
+ if (conn->ssl)
+ nread = SSL_read(conn->ssl, conn->inBuffer + conn->inEnd,
+ conn->inBufSize - conn->inEnd);
+ else
+#endif
+ nread = recv(conn->sock, conn->inBuffer + conn->inEnd,
conn->inBufSize - conn->inEnd, 0);
if (nread < 0)
{
* arrived.
*/
tryAgain2:
- nread = recv(conn->sock, conn->inBuffer + conn->inEnd,
+#ifdef USE_SSL
+ if (conn->ssl)
+ nread = SSL_read(conn->ssl, conn->inBuffer + conn->inEnd,
+ conn->inBufSize - conn->inEnd);
+ else
+#endif
+ nread = recv(conn->sock, conn->inBuffer + conn->inEnd,
conn->inBufSize - conn->inEnd, 0);
if (nread < 0)
{
pqsigfunc oldsighandler = pqsignal(SIGPIPE, SIG_IGN);
#endif
- int sent = send(conn->sock, ptr, len, 0);
+ int sent;
+#ifdef USE_SSL
+ if (conn->ssl)
+ sent = SSL_write(conn->ssl, ptr, len);
+ else
+#endif
+ sent = send(conn->sock, ptr, len, 0);
#ifndef WIN32
pqsignal(SIGPIPE, oldsighandler);
*
* Copyright (c) 1994, Regents of the University of California
*
- * $Id: libpq-int.h,v 1.11 1999/08/31 01:37:37 tgl Exp $
+ * $Id: libpq-int.h,v 1.12 1999/09/27 03:13:16 momjian Exp $
*
*-------------------------------------------------------------------------
*/
#include "pqexpbuffer.h"
+#ifdef USE_SSL
+#include "openssl/ssl.h"
+#include "openssl/err.h"
+#endif
+
/* libpq supports this version of the frontend/backend protocol.
*
* NB: we used to use PG_PROTOCOL_LATEST from the backend pqcomm.h file,
PGresult *result; /* result being constructed */
PGresAttValue *curTuple; /* tuple currently being read */
+#ifdef USE_SSL
+ SSL *ssl;
+#endif
+
/* Buffer for current error message */
PQExpBufferData errorMessage; /* expansible string */