summaryrefslogtreecommitdiff
path: root/src/interfaces/libpq/fe-connect.c
diff options
context:
space:
mode:
authorMarc G. Fournier <scrappy@hub.org>1998-01-26 01:42:53 +0000
committerMarc G. Fournier <scrappy@hub.org>1998-01-26 01:42:53 +0000
commitd5bbe2aca55bc833e38c768d7f82c129b8b70c83 (patch)
tree47f4e1ecb3277869bb276e5433df335d920d1baf /src/interfaces/libpq/fe-connect.c
parent91d983aa1140e3ae109684ff7c916583ed059e0e (diff)
From: Phil Thompson <phil@river-bank.demon.co.uk>
I've completed the patch to fix the protocol and authentication issues I was discussing a couple of weeks ago. The particular changes are: - the protocol has a version number - network byte order is used throughout - the pg_hba.conf file is used to specify what method is used to authenticate a frontend (either password, ident, trust, reject, krb4 or krb5) - support for multiplexed backends is removed - appropriate changes to man pages - the -a switch to many programs to specify an authentication service no longer has any effect - the libpq.so version number has changed to 1.1 The new backend still supports the old protocol so old interfaces won't break.
Diffstat (limited to 'src/interfaces/libpq/fe-connect.c')
-rw-r--r--src/interfaces/libpq/fe-connect.c354
1 files changed, 116 insertions, 238 deletions
diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 37dd88d425d..ee95ac59de5 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -7,7 +7,7 @@
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/interfaces/libpq/fe-connect.c,v 1.58 1998/01/23 02:31:18 scrappy Exp $
+ * $Header: /cvsroot/pgsql/src/interfaces/libpq/fe-connect.c,v 1.59 1998/01/26 01:42:28 scrappy Exp $
*
*-------------------------------------------------------------------------
*/
@@ -21,14 +21,14 @@
#include <ctype.h>
#include <string.h>
#include <netdb.h>
+#include <sys/un.h>
+#include <netinet/in.h>
#include <netinet/tcp.h>
#include <errno.h>
#include <signal.h>
#include <ctype.h> /* for isspace() */
#include "postgres.h"
-#include "libpq/pqcomm.h" /* for decls of MsgType, PacketBuf,
- * StartupInfo */
#include "fe-auth.h"
#include "fe-connect.h"
#include "libpq-fe.h"
@@ -44,7 +44,6 @@
/* use a local version instead of the one found in pqpacket.c */
static ConnStatusType connectDB(PGconn *conn);
-static void startup2PacketBuf(StartupInfo *s, PacketBuf *res);
static void freePGconn(PGconn *conn);
static void closePGconn(PGconn *conn);
static int conninfo_parse(const char *conninfo, char *errorMessage);
@@ -78,6 +77,7 @@ static PQconninfoOption PQconninfoOptions[] = {
/* Option-name Environment-Var Compiled-in Current value */
/* Label Disp-Char */
/* ----------------- --------------- --------------- --------------- */
+ /* "authtype" is ignored as it is no longer used. */
{"authtype", "PGAUTHTYPE", DefaultAuthtype, NULL,
"Database-Authtype", "", 20},
@@ -183,7 +183,6 @@ PQconnectdb(const char *conninfo)
conn->Pfout = NULL;
conn->Pfin = NULL;
conn->Pfdebug = NULL;
- conn->port = NULL;
conn->notifyList = DLNewList();
tmp = conninfo_getval("host");
@@ -198,8 +197,6 @@ PQconnectdb(const char *conninfo)
conn->pguser = tmp ? strdup(tmp) : NULL;
tmp = conninfo_getval("password");
conn->pgpass = tmp ? strdup(tmp) : NULL;
- tmp = conninfo_getval("authtype");
- conn->pgauth = tmp ? strdup(tmp) : NULL;
tmp = conninfo_getval("dbname");
conn->dbName = tmp ? strdup(tmp) : NULL;
@@ -209,14 +206,6 @@ PQconnectdb(const char *conninfo)
*/
conninfo_free();
- /*
- * try to set the auth service if one was specified
- */
- if (conn->pgauth)
- {
- fe_setauthsvc(conn->pgauth, conn->errorMessage);
- }
-
/* ----------
* Connect to the database
* ----------
@@ -326,7 +315,6 @@ PQsetdbLogin(const char *pghost, const char *pgport, const char *pgoptions, cons
conn->Pfout = NULL;
conn->Pfin = NULL;
conn->Pfdebug = NULL;
- conn->port = NULL;
conn->notifyList = DLNewList();
if ((pghost == NULL) || pghost[0] == '\0')
@@ -467,44 +455,31 @@ connectDB(PGconn *conn)
{
struct hostent *hp;
- StartupInfo startup;
- PacketBuf pacBuf;
- PacketLen pacLen;
- int status;
- MsgType msgtype;
- int laddrlen = sizeof(struct sockaddr);
- Port *port = conn->port;
+ StartupPacket sp;
+ AuthRequest areq;
+ int laddrlen = sizeof(SockAddr);
int portno,
family,
len;
- bool salted = false;
- char* tmp;
/*
* Initialize the startup packet.
- *
- * This data structure is used for the seq-packet protocol. It describes
- * the frontend-backend connection.
- *
- *
*/
- strncpy(startup.user, conn->pguser, sizeof(startup.user));
- strncpy(startup.database, conn->dbName, sizeof(startup.database));
- strncpy(startup.tty, conn->pgtty, sizeof(startup.tty));
+
+ MemSet((char *)&sp, 0, sizeof (StartupPacket));
+
+ sp.protoVersion = (ProtocolVersion)htonl(PG_PROTOCOL_LATEST);
+
+ strncpy(sp.user, conn->pguser, SM_USER);
+ strncpy(sp.database, conn->dbName, SM_DATABASE);
+ strncpy(sp.tty, conn->pgtty, SM_TTY);
+
if (conn->pgoptions)
- {
- strncpy(startup.options, conn->pgoptions, sizeof(startup.options));
- }
- else
- startup.options[0] = '\0';
- startup.execFile[0] = '\0'; /* not used */
+ strncpy(sp.options, conn->pgoptions, SM_OPTIONS);
/*
* Open a connection to postmaster/backend.
- *
*/
- port = (Port *) malloc(sizeof(Port));
- MemSet((char *) port, 0, sizeof(Port));
if (conn->pghost != NULL)
{
@@ -524,28 +499,28 @@ connectDB(PGconn *conn)
#endif
portno = atoi(conn->pgport);
family = (conn->pghost != NULL) ? AF_INET : AF_UNIX;
- port->raddr.in.sin_family = family;
+ conn->raddr.sa.sa_family = family;
if (family == AF_INET)
{
- memmove((char *) &(port->raddr.in.sin_addr),
+ memmove((char *) &(conn->raddr.in.sin_addr),
(char *) hp->h_addr,
hp->h_length);
- port->raddr.in.sin_port = htons((unsigned short) (portno));
+ conn->raddr.in.sin_port = htons((unsigned short) (portno));
len = sizeof(struct sockaddr_in);
}
else
{
- len = UNIXSOCK_PATH(port->raddr.un, portno);
+ len = UNIXSOCK_PATH(conn->raddr.un, portno);
}
/* connect to the server */
- if ((port->sock = socket(family, SOCK_STREAM, 0)) < 0)
+ if ((conn->sock = socket(family, SOCK_STREAM, 0)) < 0)
{
(void) sprintf(conn->errorMessage,
"connectDB() -- socket() failed: errno=%d\n%s\n",
errno, strerror(errno));
goto connect_errReturn;
}
- if (connect(port->sock, (struct sockaddr *) & port->raddr, len) < 0)
+ if (connect(conn->sock, &conn->raddr.sa, len) < 0)
{
(void) sprintf(conn->errorMessage,
"connectDB() failed: Is the postmaster running and accepting%s connections at '%s' on port '%s'?\n",
@@ -566,7 +541,7 @@ connectDB(PGconn *conn)
"connectDB(): getprotobyname failed\n");
goto connect_errReturn;
}
- if (setsockopt(port->sock, pe->p_proto, TCP_NODELAY,
+ if (setsockopt(conn->sock, pe->p_proto, TCP_NODELAY,
&on, sizeof(on)) < 0)
{
(void) sprintf(conn->errorMessage,
@@ -576,8 +551,7 @@ connectDB(PGconn *conn)
}
/* fill in the client address */
- if (getsockname(port->sock, (struct sockaddr *) & port->laddr,
- &laddrlen) < 0)
+ if (getsockname(conn->sock, &conn->laddr.sa, &laddrlen) < 0)
{
(void) sprintf(conn->errorMessage,
"connectDB() -- getsockname() failed: errno=%d\n%s\n",
@@ -585,81 +559,93 @@ connectDB(PGconn *conn)
goto connect_errReturn;
}
- /* by this point, connection has been opened */
-
- /* This section of code is new as of Nov 19, 1997. It sends just the
- * user's login to the backend. This allows the backend to search
- * pg_user to see if the user has a password defined. If the user
- * does have a password in pg_user, then the backend will send a
- * packet back with a randomly generated salt, so the user's password
- * can be encrypted.
- */
- pacLen = sizeof(pacBuf.len) + sizeof(pacBuf.msgtype) + strlen(startup.user) + 1;
- pacBuf.len = htonl(pacLen);
- pacBuf.msgtype = htonl(STARTUP_USER_MSG);
- strcpy(pacBuf.data, startup.user);
- status = packetSend(port, &pacBuf, pacLen, BLOCKING);
- if (status == STATUS_ERROR) {
- sprintf(conn->errorMessage, "connectDB() -- couldn't send complete packet: errno=%d\n%s\n", errno, strerror(errno));
- goto connect_errReturn;
- }
-
- /* Check to see if the server sent us a salt back to encrypt the
- * password to send for authentication. --TAB
- */
- status = packetReceive(port, &pacBuf, BLOCKING);
-
- if (status != STATUS_OK) {
- sprintf(conn->errorMessage, "connectDB() -- couldn't receive un/salt packet: errno=%d\n%s\n", errno, strerror(errno));
- goto connect_errReturn;
- }
- pacBuf.msgtype = ntohl(pacBuf.msgtype);
- switch (pacBuf.msgtype) {
- case STARTUP_SALT_MSG:
- salted = true;
- if (!conn->pgpass) {
- sprintf(conn->errorMessage, "connectDB() -- backend requested a password, but none was given\n");
- goto connect_errReturn;
- }
- tmp = crypt(conn->pgpass, pacBuf.data);
- free((void*)conn->pgpass);
- conn->pgpass = strdup(tmp);
- break;
- case STARTUP_UNSALT_MSG:
- salted = false;
- break;
- default:
- sprintf(conn->errorMessage, "connectDB() -- backend did not supply a salt packet\n");
- goto connect_errReturn;
- }
-
- if (salted)
- msgtype = STARTUP_CRYPT_MSG;
- else
- msgtype = fe_getauthsvc(conn->errorMessage);
-
-/* pacBuf = startup2PacketBuf(&startup);*/
- startup2PacketBuf(&startup, &pacBuf);
- pacBuf.msgtype = (MsgType) htonl(msgtype);
- status = packetSend(port, &pacBuf, sizeof(PacketBuf), BLOCKING);
-
- if (status == STATUS_ERROR)
+ /* set up the socket file descriptors */
+ conn->Pfout = fdopen(conn->sock, "w");
+ conn->Pfin = fdopen(dup(conn->sock), "r");
+ if ((conn->Pfout == NULL) || (conn->Pfin == NULL))
+ {
+ (void) sprintf(conn->errorMessage,
+ "connectDB() -- fdopen() failed: errno=%d\n%s\n",
+ errno, strerror(errno));
+ goto connect_errReturn;
+ }
+
+ /* Send the startup packet. */
+
+ if (packetSend(conn, (char *)&sp, sizeof(StartupPacket)) != STATUS_OK)
{
sprintf(conn->errorMessage,
"connectDB() -- couldn't send complete packet: errno=%d\n%s\n", errno, strerror(errno));
goto connect_errReturn;
}
- /* authenticate as required */
- if (fe_sendauth(msgtype, port, conn->pghost,
- conn->pguser, conn->pgpass,
- conn->errorMessage) != STATUS_OK)
+ /*
+ * Get the response from the backend, either an error message or an
+ * authentication request.
+ */
+
+ do
{
- (void) sprintf(conn->errorMessage,
- "connectDB() -- authentication failed with %s\n",
- conn->pghost);
- goto connect_errReturn;
+ int beresp;
+
+ if ((beresp = pqGetc(conn->Pfin, conn->Pfdebug)) == EOF)
+ {
+ (void)sprintf(conn->errorMessage,
+ "connectDB() -- error getting authentication request\n");
+
+ goto connect_errReturn;
+ }
+
+ /* Handle errors. */
+
+ if (beresp == 'E')
+ {
+ pqGets(conn->errorMessage, sizeof (conn->errorMessage),
+ conn->Pfin, conn->Pfdebug);
+
+ goto connect_errReturn;
+ }
+
+ /* Check it was an authentication request. */
+
+ if (beresp != 'R')
+ {
+ (void)sprintf(conn->errorMessage,
+ "connectDB() -- expected authentication request\n");
+
+ goto connect_errReturn;
+ }
+
+ /* Get the type of request. */
+
+ if (pqGetInt((int *)&areq, 4, conn->Pfin, conn->Pfdebug))
+ {
+ (void)sprintf(conn->errorMessage,
+ "connectDB() -- error getting authentication request type\n");
+
+ goto connect_errReturn;
+ }
+
+ /* Get the password salt if there is one. */
+
+ if (areq == AUTH_REQ_CRYPT &&
+ pqGetnchar(conn->salt, sizeof (conn->salt),
+ conn->Pfin, conn->Pfdebug))
+ {
+ (void)sprintf(conn->errorMessage,
+ "connectDB() -- error getting password salt\n");
+
+ goto connect_errReturn;
+ }
+
+
+ /* Respond to the request. */
+
+ if (fe_sendauth(areq, conn, conn->pghost, conn->pgpass,
+ conn->errorMessage) != STATUS_OK)
+ goto connect_errReturn;
}
+ while (areq != AUTH_REQ_OK);
/* free the password so it's not hanging out in memory forever */
if (conn->pgpass != NULL)
@@ -667,30 +653,9 @@ connectDB(PGconn *conn)
free(conn->pgpass);
}
- /* set up the socket file descriptors */
- conn->Pfout = fdopen(port->sock, "w");
- conn->Pfin = fdopen(dup(port->sock), "r");
- if ((conn->Pfout == NULL) || (conn->Pfin == NULL))
- {
- (void) sprintf(conn->errorMessage,
- "connectDB() -- fdopen() failed: errno=%d\n%s\n",
- errno, strerror(errno));
- goto connect_errReturn;
- }
-
- conn->port = port;
-
return CONNECTION_OK;
connect_errReturn:
-
- /*
- * Igor/6/3/97 - We need to free it here...otherwise the function
- * returns without setting conn->port to port. Because of that any way
- * of referencing this variable will be lost and it's allocated memory
- * will not be freed.
- */
- free(port); /* PURIFY */
return CONNECTION_BAD;
}
@@ -746,8 +711,6 @@ freePGconn(PGconn *conn)
free(conn->pguser);
if (conn->notifyList)
DLFreeList(conn->notifyList);
- if (conn->port)
- free(conn->port);
free(conn);
}
@@ -845,113 +808,28 @@ PQreset(PGconn *conn)
*
* RETURNS: STATUS_ERROR if the write fails, STATUS_OK otherwise.
* SIDE_EFFECTS: may block.
- * NOTES: Non-blocking writes would significantly complicate
- * buffer management. For now, we're not going to do it.
- *
*/
int
-packetSend(Port *port,
- PacketBuf *buf,
- PacketLen len,
- bool nonBlocking)
+packetSend(PGconn *conn,
+ char *buf,
+ size_t len)
{
- PacketLen doneLen = write(port->sock, buf, len);
+ /* Send the total packet size. */
- if (doneLen < len)
- {
- return (STATUS_ERROR);
- }
- return (STATUS_OK);
-}
+ if (pqPutInt(4 + len, 4, conn->Pfout, conn->Pfdebug))
+ return STATUS_ERROR;
-/*
- * packetReceive()
- *
- This is a less stringent PacketReceive(), defined in backend/libpq/pqpacket.c
- We define it here to avoid linking in all of libpq.a
+ /* Send the packet itself. */
- * packetReceive -- receive a packet on a port
- *
- * RETURNS: STATUS_ERROR if the read fails, STATUS_OK otherwise.
- * SIDE_EFFECTS: may block.
- * NOTES: Non-blocking reads would significantly complicate
- * buffer management. For now, we're not going to do it.
- *
-*/
-int
-packetReceive(Port *port, PacketBuf *buf, bool nonBlocking) {
-
- PacketLen max_size = sizeof(PacketBuf);
- PacketLen cc; /* character count -- recvd */
- PacketLen packetLen;
- int addrLen = sizeof(struct sockaddr_in);
- int hdrLen;
- int msgLen;
-
- /* Read the packet length into the PacketBuf
- */
- hdrLen = sizeof(PacketLen);
- cc = recvfrom(port->sock, (char*)&packetLen, hdrLen, 0, (struct sockaddr*)&port->raddr, &addrLen);
- if (cc < 0)
- return STATUS_ERROR;
- else if (!cc)
- return STATUS_INVALID;
- else if (cc < hdrLen)
- return STATUS_NOT_DONE;
-
- /* convert to local form of integer and check for oversized packet
- */
- buf->len = packetLen;
- if ((packetLen = ntohl(packetLen)) > max_size) {
- port->nBytes = packetLen;
- return STATUS_INVALID;
- }
-
- /* fetch the rest of the message
- */
- msgLen = packetLen - cc;
- cc = recvfrom(port->sock, (char*)&buf->msgtype, msgLen, 0, (struct sockaddr*)&port->raddr, &addrLen);
- if (cc < 0)
- return STATUS_ERROR;
- else if (!cc)
- return STATUS_INVALID;
- else if (cc < msgLen)
- return STATUS_NOT_DONE;
-
- return STATUS_OK;
-}
+ if (pqPutnchar(buf, len, conn->Pfout, conn->Pfdebug))
+ return STATUS_ERROR;
-/*
- * startup2PacketBuf()
- *
- * this is just like StartupInfo2Packet(), defined in backend/libpq/pqpacket.c
- * but we repeat it here so we don't have to link in libpq.a
- *
- * converts a StartupInfo structure to a PacketBuf
- */
-static void
-startup2PacketBuf(StartupInfo *s, PacketBuf *res)
-{
- char *tmp;
+ pqFlush(conn->Pfout, conn->Pfdebug);
-/* res = (PacketBuf*)malloc(sizeof(PacketBuf)); */
- res->len = htonl(sizeof(PacketBuf));
- /* use \n to delimit the strings */
- res->data[0] = '\0';
-
- tmp = res->data;
-
- strncpy(tmp, s->database, sizeof(s->database));
- tmp += sizeof(s->database);
- strncpy(tmp, s->user, sizeof(s->user));
- tmp += sizeof(s->user);
- strncpy(tmp, s->options, sizeof(s->options));
- tmp += sizeof(s->options);
- strncpy(tmp, s->execFile, sizeof(s->execFile));
- tmp += sizeof(s->execFile);
- strncpy(tmp, s->tty, sizeof(s->tty));
+ return STATUS_OK;
}
+
/* ----------------
* Conninfo parser routine
* ----------------