mirror of
https://github.com/postgres/postgres.git
synced 2025-11-12 05:01:15 +03:00
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.
This commit is contained in:
@@ -7,7 +7,7 @@
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $Header: /cvsroot/pgsql/src/backend/libpq/auth.c,v 1.20 1997/12/09 03:10:31 scrappy Exp $
|
||||
* $Header: /cvsroot/pgsql/src/backend/libpq/auth.c,v 1.21 1998/01/26 01:41:04 scrappy Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@@ -16,39 +16,6 @@
|
||||
*
|
||||
* backend (postmaster) routines:
|
||||
* be_recvauth receive authentication information
|
||||
* be_setauthsvc do/do not permit an authentication service
|
||||
* be_getauthsvc is an authentication service permitted?
|
||||
*
|
||||
* NOTES
|
||||
* To add a new authentication system:
|
||||
* 0. If you can't do your authentication over an existing socket,
|
||||
* you lose -- get ready to hack around this framework instead of
|
||||
* using it. Otherwise, you can assume you have an initialized
|
||||
* and empty connection to work with. (Please don't leave leftover
|
||||
* gunk in the connection after the authentication transactions, or
|
||||
* the POSTGRES routines that follow will be very unhappy.)
|
||||
* 1. Write a set of routines that:
|
||||
* let a client figure out what user/principal name to use
|
||||
* send authentication information (client side)
|
||||
* receive authentication information (server side)
|
||||
* You can include both routines in this file, using #ifdef FRONTEND
|
||||
* to separate them.
|
||||
* 2. Edit libpq/pqcomm.h and assign a MsgType for your protocol.
|
||||
* 3. Edit the static "struct authsvc" array and the generic
|
||||
* {be,fe}_{get,set}auth{name,svc} routines in this file to reflect
|
||||
* the new service. You may have to change the arguments of these
|
||||
* routines; they basically just reflect what Kerberos v4 needs.
|
||||
* 4. Hack on src/{,bin}/Makefile.global and src/{backend,libpq}/Makefile
|
||||
* to add library and CFLAGS hooks -- basically, grep the Makefile
|
||||
* hierarchy for KRBVERS to see where you need to add things.
|
||||
*
|
||||
* Send mail to post_hackers@postgres.Berkeley.EDU if you have to make
|
||||
* any changes to arguments, etc. Context diffs would be nice, too.
|
||||
*
|
||||
* Someday, this cruft will go away and magically be replaced by a
|
||||
* nice interface based on the GSS API or something. For now, though,
|
||||
* there's no (stable) UNIX security API to work with...
|
||||
*
|
||||
*/
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
@@ -68,66 +35,21 @@
|
||||
|
||||
#include <libpq/auth.h>
|
||||
#include <libpq/libpq.h>
|
||||
#include <libpq/libpq-be.h>
|
||||
#include <libpq/hba.h>
|
||||
#include <libpq/password.h>
|
||||
#include <libpq/crypt.h>
|
||||
|
||||
static int be_getauthsvc(MsgType msgtype);
|
||||
|
||||
/*----------------------------------------------------------------
|
||||
* common definitions for generic fe/be routines
|
||||
*----------------------------------------------------------------
|
||||
*/
|
||||
static void sendAuthRequest(Port *port, AuthRequest areq, void (*handler)());
|
||||
static void handle_done_auth(Port *port);
|
||||
static void handle_krb4_auth(Port *port);
|
||||
static void handle_krb5_auth(Port *port);
|
||||
static void handle_password_auth(Port *port);
|
||||
static void readPasswordPacket(char *arg, PacketLen len, char *pkt);
|
||||
static void pg_passwordv0_recvauth(char *arg, PacketLen len, char *pkt);
|
||||
static int old_be_recvauth(Port *port);
|
||||
static int map_old_to_new(Port *port, UserAuth old, int status);
|
||||
|
||||
struct authsvc
|
||||
{
|
||||
char name[16]; /* service nickname (for command line) */
|
||||
MsgType msgtype; /* startup packet header type */
|
||||
int allowed; /* initially allowed (before command line
|
||||
* option parsing)? */
|
||||
};
|
||||
|
||||
/*
|
||||
* Command-line parsing routines use this structure to map nicknames
|
||||
* onto service types (and the startup packets to use with them).
|
||||
*
|
||||
* Programs receiving an authentication request use this structure to
|
||||
* decide which authentication service types are currently permitted.
|
||||
* By default, all authentication systems compiled into the system are
|
||||
* allowed. Unauthenticated connections are disallowed unless there
|
||||
* isn't any authentication system.
|
||||
*/
|
||||
|
||||
#if defined(HBA)
|
||||
static int useHostBasedAuth = 1;
|
||||
|
||||
#else
|
||||
static int useHostBasedAuth = 0;
|
||||
|
||||
#endif
|
||||
|
||||
#if defined(KRB4) || defined(KRB5) || defined(HBA)
|
||||
#define UNAUTH_ALLOWED 0
|
||||
#else
|
||||
#define UNAUTH_ALLOWED 1
|
||||
#endif
|
||||
|
||||
static struct authsvc authsvcs[] = {
|
||||
{"unauth", STARTUP_UNAUTH_MSG, UNAUTH_ALLOWED},
|
||||
{"hba", STARTUP_HBA_MSG, 1},
|
||||
{"krb4", STARTUP_KRB4_MSG, 1},
|
||||
{"krb5", STARTUP_KRB5_MSG, 1},
|
||||
#if defined(KRB5)
|
||||
{"kerberos", STARTUP_KRB5_MSG, 1},
|
||||
#else
|
||||
{"kerberos", STARTUP_KRB4_MSG, 1},
|
||||
#endif
|
||||
{"password", STARTUP_PASSWORD_MSG, 1},
|
||||
{"crypt", STARTUP_CRYPT_MSG, 1}
|
||||
};
|
||||
|
||||
static n_authsvcs = sizeof(authsvcs) / sizeof(struct authsvc);
|
||||
|
||||
#ifdef KRB4
|
||||
/* This has to be ifdef'd out because krb.h does exist. This needs
|
||||
@@ -140,10 +62,6 @@ static n_authsvcs = sizeof(authsvcs) / sizeof(struct authsvc);
|
||||
|
||||
#include <krb.h>
|
||||
|
||||
#ifdef FRONTEND
|
||||
/* moves to src/libpq/fe-auth.c */
|
||||
#else /* !FRONTEND */
|
||||
|
||||
/*
|
||||
* pg_krb4_recvauth -- server routine to receive authentication information
|
||||
* from the client
|
||||
@@ -154,10 +72,7 @@ static n_authsvcs = sizeof(authsvcs) / sizeof(struct authsvc);
|
||||
* unauthenticated connections.)
|
||||
*/
|
||||
static int
|
||||
pg_krb4_recvauth(int sock,
|
||||
struct sockaddr_in * laddr,
|
||||
struct sockaddr_in * raddr,
|
||||
char *username)
|
||||
pg_krb4_recvauth(Port *)
|
||||
{
|
||||
long krbopts = 0; /* one-way authentication */
|
||||
KTEXT_ST clttkt;
|
||||
@@ -170,12 +85,12 @@ pg_krb4_recvauth(int sock,
|
||||
strcpy(instance, "*"); /* don't care, but arg gets expanded
|
||||
* anyway */
|
||||
status = krb_recvauth(krbopts,
|
||||
sock,
|
||||
port->sock,
|
||||
&clttkt,
|
||||
PG_KRB_SRVNAM,
|
||||
instance,
|
||||
raddr,
|
||||
laddr,
|
||||
&port->raddr.in,
|
||||
&port->laddr.in,
|
||||
&auth_data,
|
||||
PG_KRB_SRVTAB,
|
||||
key_sched,
|
||||
@@ -198,12 +113,11 @@ pg_krb4_recvauth(int sock,
|
||||
pqdebug("%s", PQerrormsg);
|
||||
return (STATUS_ERROR);
|
||||
}
|
||||
if (username && *username &&
|
||||
strncmp(username, auth_data.pname, NAMEDATALEN))
|
||||
if (strncmp(port->user, auth_data.pname, SM_USER))
|
||||
{
|
||||
sprintf(PQerrormsg,
|
||||
"pg_krb4_recvauth: name \"%s\" != \"%s\"\n",
|
||||
username,
|
||||
port->username,
|
||||
auth_data.pname);
|
||||
fputs(PQerrormsg, stderr);
|
||||
pqdebug("%s", PQerrormsg);
|
||||
@@ -212,14 +126,9 @@ pg_krb4_recvauth(int sock,
|
||||
return (STATUS_OK);
|
||||
}
|
||||
|
||||
#endif /* !FRONTEND */
|
||||
|
||||
#else
|
||||
static int
|
||||
pg_krb4_recvauth(int sock,
|
||||
struct sockaddr_in * laddr,
|
||||
struct sockaddr_in * raddr,
|
||||
char *username)
|
||||
pg_krb4_recvauth(Port *port)
|
||||
{
|
||||
sprintf(PQerrormsg,
|
||||
"pg_krb4_recvauth: Kerberos not implemented on this "
|
||||
@@ -267,10 +176,6 @@ pg_an_to_ln(char *aname)
|
||||
return (aname);
|
||||
}
|
||||
|
||||
#ifdef FRONTEND
|
||||
/* moves to src/libpq/fe-auth.c */
|
||||
#else /* !FRONTEND */
|
||||
|
||||
/*
|
||||
* pg_krb5_recvauth -- server routine to receive authentication information
|
||||
* from the client
|
||||
@@ -294,10 +199,7 @@ pg_an_to_ln(char *aname)
|
||||
* but kdb5_edit allows you to select which principals to dump. Yay!)
|
||||
*/
|
||||
static int
|
||||
pg_krb5_recvauth(int sock,
|
||||
struct sockaddr_in * laddr,
|
||||
struct sockaddr_in * raddr,
|
||||
char *username)
|
||||
pg_krb5_recvauth(Port *port)
|
||||
{
|
||||
char servbuf[MAXHOSTNAMELEN + 1 +
|
||||
sizeof(PG_KRB_SRVNAM)];
|
||||
@@ -334,9 +236,9 @@ pg_krb5_recvauth(int sock,
|
||||
* krb5_sendauth needs this to verify the address in the client
|
||||
* authenticator.
|
||||
*/
|
||||
sender_addr.addrtype = raddr->sin_family;
|
||||
sender_addr.length = sizeof(raddr->sin_addr);
|
||||
sender_addr.contents = (krb5_octet *) & (raddr->sin_addr);
|
||||
sender_addr.addrtype = port->raddr.in.sin_family;
|
||||
sender_addr.length = sizeof(port->raddr.in.sin_addr);
|
||||
sender_addr.contents = (krb5_octet *) & (port->raddr.in.sin_addr);
|
||||
|
||||
if (strcmp(PG_KRB_SRVTAB, ""))
|
||||
{
|
||||
@@ -344,7 +246,7 @@ pg_krb5_recvauth(int sock,
|
||||
keyprocarg = PG_KRB_SRVTAB;
|
||||
}
|
||||
|
||||
if (code = krb5_recvauth((krb5_pointer) & sock,
|
||||
if (code = krb5_recvauth((krb5_pointer) & port->sock,
|
||||
PG_KRB5_VERSION,
|
||||
server,
|
||||
&sender_addr,
|
||||
@@ -390,11 +292,11 @@ pg_krb5_recvauth(int sock,
|
||||
return (STATUS_ERROR);
|
||||
}
|
||||
kusername = pg_an_to_ln(kusername);
|
||||
if (username && strncmp(username, kusername, NAMEDATALEN))
|
||||
if (strncmp(username, kusername, SM_USER))
|
||||
{
|
||||
sprintf(PQerrormsg,
|
||||
"pg_krb5_recvauth: name \"%s\" != \"%s\"\n",
|
||||
username, kusername);
|
||||
port->username, kusername);
|
||||
fputs(PQerrormsg, stderr);
|
||||
pqdebug("%s", PQerrormsg);
|
||||
pfree(kusername);
|
||||
@@ -404,15 +306,9 @@ pg_krb5_recvauth(int sock,
|
||||
return (STATUS_OK);
|
||||
}
|
||||
|
||||
#endif /* !FRONTEND */
|
||||
|
||||
|
||||
#else
|
||||
static int
|
||||
pg_krb5_recvauth(int sock,
|
||||
struct sockaddr_in * laddr,
|
||||
struct sockaddr_in * raddr,
|
||||
char *username)
|
||||
pg_krb5_recvauth(Port *port)
|
||||
{
|
||||
sprintf(PQerrormsg,
|
||||
"pg_krb5_recvauth: Kerberos not implemented on this "
|
||||
@@ -425,246 +321,360 @@ pg_krb5_recvauth(int sock,
|
||||
|
||||
#endif /* KRB5 */
|
||||
|
||||
static int
|
||||
pg_password_recvauth(Port *port, char *database, char *DataDir)
|
||||
{
|
||||
PacketBuf buf;
|
||||
char *user,
|
||||
*password;
|
||||
|
||||
if (PacketReceive(port, &buf, BLOCKING) != STATUS_OK)
|
||||
/*
|
||||
* Handle a v0 password packet.
|
||||
*/
|
||||
|
||||
static void pg_passwordv0_recvauth(char *arg, PacketLen len, char *pkt)
|
||||
{
|
||||
Port *port;
|
||||
PasswordPacketV0 *pp;
|
||||
char *user, *password, *cp, *start;
|
||||
|
||||
port = (Port *)arg;
|
||||
pp = (PasswordPacketV0 *)pkt;
|
||||
|
||||
/*
|
||||
* The packet is supposed to comprise the user name and the password
|
||||
* as C strings. Be careful the check that this is the case.
|
||||
*/
|
||||
|
||||
user = password = NULL;
|
||||
|
||||
len -= sizeof (pp->unused);
|
||||
|
||||
cp = start = pp->data;
|
||||
|
||||
while (len > 0)
|
||||
if (*cp++ == '\0')
|
||||
{
|
||||
sprintf(PQerrormsg,
|
||||
"pg_password_recvauth: failed to receive authentication packet.\n");
|
||||
fputs(PQerrormsg, stderr);
|
||||
pqdebug("%s", PQerrormsg);
|
||||
return STATUS_ERROR;
|
||||
if (user == NULL)
|
||||
user = start;
|
||||
else
|
||||
{
|
||||
password = start;
|
||||
break;
|
||||
}
|
||||
|
||||
start = cp;
|
||||
}
|
||||
|
||||
user = buf.data;
|
||||
password = buf.data + strlen(user) + 1;
|
||||
if (user == NULL || password == NULL)
|
||||
{
|
||||
sprintf(PQerrormsg,
|
||||
"pg_password_recvauth: badly formed password packet.\n");
|
||||
fputs(PQerrormsg, stderr);
|
||||
pqdebug("%s", PQerrormsg);
|
||||
|
||||
return verify_password(user, password, port, database, DataDir);
|
||||
auth_failed(port);
|
||||
}
|
||||
else if (map_old_to_new(port, uaPassword,
|
||||
verify_password(port->auth_arg, user, password)) != STATUS_OK)
|
||||
auth_failed(port);
|
||||
}
|
||||
|
||||
static int
|
||||
crypt_recvauth(Port *port)
|
||||
|
||||
/*
|
||||
* Tell the user the authentication failed, but not why.
|
||||
*/
|
||||
|
||||
void auth_failed(Port *port)
|
||||
{
|
||||
PacketBuf buf;
|
||||
char *user,
|
||||
*password;
|
||||
|
||||
if (PacketReceive(port, &buf, BLOCKING) != STATUS_OK)
|
||||
{
|
||||
sprintf(PQerrormsg,
|
||||
"crypt_recvauth: failed to receive authentication packet.\n");
|
||||
fputs(PQerrormsg, stderr);
|
||||
pqdebug("%s", PQerrormsg);
|
||||
return STATUS_ERROR;
|
||||
}
|
||||
|
||||
user = buf.data;
|
||||
password = buf.data + strlen(user) + 1;
|
||||
|
||||
return crypt_verify(port, user, password);
|
||||
PacketSendError(&port->pktInfo, "User authentication failed");
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* be_recvauth -- server demux routine for incoming authentication information
|
||||
*/
|
||||
int
|
||||
be_recvauth(MsgType msgtype_arg, Port *port, char *username, StartupInfo *sp)
|
||||
void be_recvauth(Port *port)
|
||||
{
|
||||
MsgType msgtype;
|
||||
AuthRequest areq;
|
||||
void (*auth_handler)();
|
||||
|
||||
/*
|
||||
* A message type of STARTUP_MSG (which once upon a time was the only
|
||||
* startup message type) means user wants us to choose. "unauth" is
|
||||
* what used to be the only choice, but installation may choose "hba"
|
||||
* instead.
|
||||
* Get the authentication method to use for this frontend/database
|
||||
* combination.
|
||||
*/
|
||||
if (msgtype_arg == STARTUP_MSG)
|
||||
{
|
||||
if (useHostBasedAuth)
|
||||
msgtype = STARTUP_HBA_MSG;
|
||||
else
|
||||
msgtype = STARTUP_UNAUTH_MSG;
|
||||
}
|
||||
else
|
||||
msgtype = msgtype_arg;
|
||||
|
||||
|
||||
if (!username)
|
||||
if (hba_getauthmethod(&port->raddr, port->database, port->auth_arg,
|
||||
&port->auth_method) != STATUS_OK)
|
||||
{
|
||||
sprintf(PQerrormsg,
|
||||
"be_recvauth: no user name passed\n");
|
||||
fputs(PQerrormsg, stderr);
|
||||
pqdebug("%s", PQerrormsg);
|
||||
return (STATUS_ERROR);
|
||||
}
|
||||
if (!port)
|
||||
{
|
||||
sprintf(PQerrormsg,
|
||||
"be_recvauth: no port structure passed\n");
|
||||
fputs(PQerrormsg, stderr);
|
||||
pqdebug("%s", PQerrormsg);
|
||||
return (STATUS_ERROR);
|
||||
PacketSendError(&port->pktInfo, "Error getting authentication method");
|
||||
return;
|
||||
}
|
||||
|
||||
switch (msgtype)
|
||||
{
|
||||
case STARTUP_KRB4_MSG:
|
||||
if (!be_getauthsvc(msgtype))
|
||||
{
|
||||
sprintf(PQerrormsg,
|
||||
"be_recvauth: krb4 authentication disallowed\n");
|
||||
fputs(PQerrormsg, stderr);
|
||||
pqdebug("%s", PQerrormsg);
|
||||
return (STATUS_ERROR);
|
||||
}
|
||||
if (pg_krb4_recvauth(port->sock, (struct sockaddr_in *) &port->laddr,
|
||||
(struct sockaddr_in *) &port->raddr,
|
||||
username) != STATUS_OK)
|
||||
{
|
||||
sprintf(PQerrormsg,
|
||||
"be_recvauth: krb4 authentication failed\n");
|
||||
fputs(PQerrormsg, stderr);
|
||||
pqdebug("%s", PQerrormsg);
|
||||
return (STATUS_ERROR);
|
||||
}
|
||||
break;
|
||||
case STARTUP_KRB5_MSG:
|
||||
if (!be_getauthsvc(msgtype))
|
||||
{
|
||||
sprintf(PQerrormsg,
|
||||
"be_recvauth: krb5 authentication disallowed\n");
|
||||
fputs(PQerrormsg, stderr);
|
||||
pqdebug("%s", PQerrormsg);
|
||||
return (STATUS_ERROR);
|
||||
}
|
||||
if (pg_krb5_recvauth(port->sock, (struct sockaddr_in *) &port->laddr,
|
||||
(struct sockaddr_in *) &port->raddr,
|
||||
username) != STATUS_OK)
|
||||
{
|
||||
sprintf(PQerrormsg,
|
||||
"be_recvauth: krb5 authentication failed\n");
|
||||
fputs(PQerrormsg, stderr);
|
||||
pqdebug("%s", PQerrormsg);
|
||||
return (STATUS_ERROR);
|
||||
}
|
||||
break;
|
||||
case STARTUP_UNAUTH_MSG:
|
||||
if (!be_getauthsvc(msgtype))
|
||||
{
|
||||
sprintf(PQerrormsg,
|
||||
"be_recvauth: "
|
||||
"unauthenticated connections disallowed\n");
|
||||
fputs(PQerrormsg, stderr);
|
||||
pqdebug("%s", PQerrormsg);
|
||||
return (STATUS_ERROR);
|
||||
}
|
||||
break;
|
||||
case STARTUP_HBA_MSG:
|
||||
if (hba_recvauth(port, sp->database, sp->user, DataDir) != STATUS_OK)
|
||||
{
|
||||
sprintf(PQerrormsg,
|
||||
"be_recvauth: host-based authentication failed\n");
|
||||
fputs(PQerrormsg, stderr);
|
||||
pqdebug("%s", PQerrormsg);
|
||||
return (STATUS_ERROR);
|
||||
}
|
||||
break;
|
||||
case STARTUP_PASSWORD_MSG:
|
||||
if (!be_getauthsvc(msgtype))
|
||||
{
|
||||
sprintf(PQerrormsg,
|
||||
"be_recvauth: "
|
||||
"plaintext password authentication disallowed\n");
|
||||
fputs(PQerrormsg, stderr);
|
||||
pqdebug("%s", PQerrormsg);
|
||||
return (STATUS_ERROR);
|
||||
}
|
||||
if (pg_password_recvauth(port, sp->database, DataDir) != STATUS_OK)
|
||||
{
|
||||
/* Handle old style authentication. */
|
||||
|
||||
/*
|
||||
* pg_password_recvauth or lower-level routines have
|
||||
* already set
|
||||
*/
|
||||
/* the error message */
|
||||
return (STATUS_ERROR);
|
||||
}
|
||||
break;
|
||||
case STARTUP_CRYPT_MSG:
|
||||
if (crypt_recvauth(port) != STATUS_OK)
|
||||
return STATUS_ERROR;
|
||||
break;
|
||||
default:
|
||||
sprintf(PQerrormsg,
|
||||
"be_recvauth: unrecognized message type: %d\n",
|
||||
msgtype);
|
||||
fputs(PQerrormsg, stderr);
|
||||
pqdebug("%s", PQerrormsg);
|
||||
return (STATUS_ERROR);
|
||||
if (PG_PROTOCOL_MAJOR(port->proto) == 0)
|
||||
{
|
||||
if (old_be_recvauth(port) != STATUS_OK)
|
||||
auth_failed(port);
|
||||
|
||||
return;
|
||||
}
|
||||
return (STATUS_OK);
|
||||
|
||||
/* Handle new style authentication. */
|
||||
|
||||
switch (port->auth_method)
|
||||
{
|
||||
case uaReject:
|
||||
auth_failed(port);
|
||||
return;
|
||||
|
||||
case uaKrb4:
|
||||
areq = AUTH_REQ_KRB4;
|
||||
auth_handler = handle_krb4_auth;
|
||||
break;
|
||||
|
||||
case uaKrb5:
|
||||
areq = AUTH_REQ_KRB5;
|
||||
auth_handler = handle_krb5_auth;
|
||||
break;
|
||||
|
||||
case uaTrust:
|
||||
areq = AUTH_REQ_OK;
|
||||
auth_handler = handle_done_auth;
|
||||
break;
|
||||
|
||||
case uaIdent:
|
||||
if (authident(&port->raddr.in, &port->laddr.in, port->user,
|
||||
port->auth_arg) != STATUS_OK)
|
||||
{
|
||||
auth_failed(port);
|
||||
return;
|
||||
}
|
||||
|
||||
areq = AUTH_REQ_OK;
|
||||
auth_handler = handle_done_auth;
|
||||
break;
|
||||
|
||||
case uaPassword:
|
||||
areq = AUTH_REQ_PASSWORD;
|
||||
auth_handler = handle_password_auth;
|
||||
break;
|
||||
|
||||
case uaCrypt:
|
||||
areq = AUTH_REQ_CRYPT;
|
||||
auth_handler = handle_password_auth;
|
||||
break;
|
||||
}
|
||||
|
||||
/* Tell the frontend what we want next. */
|
||||
|
||||
sendAuthRequest(port, areq, auth_handler);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* be_setauthsvc -- enable/disable the authentication services currently
|
||||
* selected for use by the backend
|
||||
* be_getauthsvc -- returns whether a particular authentication system
|
||||
* (indicated by its message type) is permitted by the
|
||||
* current selections
|
||||
*
|
||||
* be_setauthsvc encodes the command-line syntax that
|
||||
* -a "<service-name>"
|
||||
* enables a service, whereas
|
||||
* -a "no<service-name>"
|
||||
* disables it.
|
||||
* Send an authentication request packet to the frontend.
|
||||
*/
|
||||
void
|
||||
be_setauthsvc(char *name)
|
||||
{
|
||||
int i,
|
||||
j;
|
||||
int turnon = 1;
|
||||
|
||||
if (!name)
|
||||
return;
|
||||
if (!strncmp("no", name, 2))
|
||||
static void sendAuthRequest(Port *port, AuthRequest areq, void (*handler)())
|
||||
{
|
||||
char *dp, *sp;
|
||||
int i;
|
||||
uint32 net_areq;
|
||||
|
||||
/* Convert to a byte stream. */
|
||||
|
||||
net_areq = htonl(areq);
|
||||
|
||||
dp = port->pktInfo.pkt.ar.data;
|
||||
sp = (char *)&net_areq;
|
||||
|
||||
*dp++ = 'R';
|
||||
|
||||
for (i = 1; i <= 4; ++i)
|
||||
*dp++ = *sp++;
|
||||
|
||||
/* Add the salt for encrypted passwords. */
|
||||
|
||||
if (areq == AUTH_REQ_CRYPT)
|
||||
{
|
||||
turnon = 0;
|
||||
name += 2;
|
||||
}
|
||||
if (name[0] == '\0')
|
||||
return;
|
||||
for (i = 0; i < n_authsvcs; ++i)
|
||||
if (!strcmp(name, authsvcs[i].name))
|
||||
{
|
||||
for (j = 0; j < n_authsvcs; ++j)
|
||||
if (authsvcs[j].msgtype == authsvcs[i].msgtype)
|
||||
authsvcs[j].allowed = turnon;
|
||||
break;
|
||||
}
|
||||
if (i == n_authsvcs)
|
||||
{
|
||||
sprintf(PQerrormsg,
|
||||
"be_setauthsvc: invalid name %s, ignoring...\n",
|
||||
name);
|
||||
fputs(PQerrormsg, stderr);
|
||||
pqdebug("%s", PQerrormsg);
|
||||
*dp++ = port->salt[0];
|
||||
*dp++ = port->salt[1];
|
||||
i += 2;
|
||||
}
|
||||
|
||||
PacketSendSetup(&port -> pktInfo, i, handler, (char *)port);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Called when we have told the front end that it is authorised.
|
||||
*/
|
||||
|
||||
static void handle_done_auth(Port *port)
|
||||
{
|
||||
/*
|
||||
* Don't generate any more traffic. This will cause the backend to
|
||||
* start.
|
||||
*/
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
static int
|
||||
be_getauthsvc(MsgType msgtype)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < n_authsvcs; ++i)
|
||||
if (msgtype == authsvcs[i].msgtype)
|
||||
return (authsvcs[i].allowed);
|
||||
return (0);
|
||||
/*
|
||||
* Called when we have told the front end that it should use Kerberos V4
|
||||
* authentication.
|
||||
*/
|
||||
|
||||
static void handle_krb4_auth(Port *port)
|
||||
{
|
||||
if (pg_krb4_recvauth(port) != STATUS_OK)
|
||||
auth_failed(port);
|
||||
else
|
||||
sendAuthRequest(port, AUTH_REQ_OK, handle_done_auth);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Called when we have told the front end that it should use Kerberos V5
|
||||
* authentication.
|
||||
*/
|
||||
|
||||
static void handle_krb5_auth(Port *port)
|
||||
{
|
||||
if (pg_krb5_recvauth(port) != STATUS_OK)
|
||||
auth_failed(port);
|
||||
else
|
||||
sendAuthRequest(port, AUTH_REQ_OK, handle_done_auth);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Called when we have told the front end that it should use password
|
||||
* authentication.
|
||||
*/
|
||||
|
||||
static void handle_password_auth(Port *port)
|
||||
{
|
||||
/* Set up the read of the password packet. */
|
||||
|
||||
PacketReceiveSetup(&port->pktInfo, readPasswordPacket, (char *)port);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Called when we have received the password packet.
|
||||
*/
|
||||
|
||||
static void readPasswordPacket(char *arg, PacketLen len, char *pkt)
|
||||
{
|
||||
char password[sizeof (PasswordPacket) + 1];
|
||||
Port *port;
|
||||
|
||||
port = (Port *)arg;
|
||||
|
||||
/* Silently truncate a password that is too big. */
|
||||
|
||||
if (len > sizeof (PasswordPacket))
|
||||
len = sizeof (PasswordPacket);
|
||||
|
||||
StrNCpy(password, ((PasswordPacket *)pkt)->passwd, len);
|
||||
|
||||
/*
|
||||
* Use the local flat password file if clear passwords are used and the
|
||||
* file is specified. Otherwise use the password in the pg_user table,
|
||||
* encrypted or not.
|
||||
*/
|
||||
|
||||
if (port->auth_method == uaPassword && port->auth_arg[0] != '\0')
|
||||
{
|
||||
if (verify_password(port->auth_arg, port->user, password) != STATUS_OK)
|
||||
auth_failed(port);
|
||||
}
|
||||
else if (crypt_verify(port, port->user, password) != STATUS_OK)
|
||||
auth_failed(port);
|
||||
else
|
||||
sendAuthRequest(port, AUTH_REQ_OK, handle_done_auth);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Server demux routine for incoming authentication information for protocol
|
||||
* version 0.
|
||||
*/
|
||||
static int old_be_recvauth(Port *port)
|
||||
{
|
||||
int status;
|
||||
MsgType msgtype = (MsgType)port->proto;
|
||||
|
||||
/* Handle the authentication that's offered. */
|
||||
|
||||
switch (msgtype)
|
||||
{
|
||||
case STARTUP_KRB4_MSG:
|
||||
status = map_old_to_new(port,uaKrb4,pg_krb4_recvauth(port));
|
||||
break;
|
||||
|
||||
case STARTUP_KRB5_MSG:
|
||||
status = map_old_to_new(port,uaKrb5,pg_krb5_recvauth(port));
|
||||
break;
|
||||
|
||||
case STARTUP_MSG:
|
||||
status = map_old_to_new(port,uaTrust,STATUS_OK);
|
||||
break;
|
||||
|
||||
case STARTUP_PASSWORD_MSG:
|
||||
PacketReceiveSetup(&port->pktInfo, pg_passwordv0_recvauth,
|
||||
(char *)port);
|
||||
|
||||
return STATUS_OK;
|
||||
|
||||
default:
|
||||
fprintf(stderr, "Invalid startup message type: %u\n", msgtype);
|
||||
|
||||
return STATUS_OK;
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* The old style authentication has been done. Modify the result of this (eg.
|
||||
* allow the connection anyway, disallow it anyway, or use the result)
|
||||
* depending on what authentication we really want to use.
|
||||
*/
|
||||
|
||||
static int map_old_to_new(Port *port, UserAuth old, int status)
|
||||
{
|
||||
switch (port->auth_method)
|
||||
{
|
||||
case uaCrypt:
|
||||
case uaReject:
|
||||
status = STATUS_ERROR;
|
||||
break;
|
||||
|
||||
case uaKrb4:
|
||||
if (old != uaKrb4)
|
||||
status = STATUS_ERROR;
|
||||
break;
|
||||
|
||||
case uaKrb5:
|
||||
if (old != uaKrb5)
|
||||
status = STATUS_ERROR;
|
||||
break;
|
||||
|
||||
case uaTrust:
|
||||
status = STATUS_OK;
|
||||
break;
|
||||
|
||||
case uaIdent:
|
||||
status = authident(&port->raddr.in, &port->laddr.in,
|
||||
port->user, port->auth_arg);
|
||||
break;
|
||||
|
||||
case uaPassword:
|
||||
if (old != uaPassword)
|
||||
status = STATUS_ERROR;
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $Header: /cvsroot/pgsql/src/backend/libpq/Attic/be-dumpdata.c,v 1.9 1997/09/12 04:07:50 momjian Exp $
|
||||
* $Header: /cvsroot/pgsql/src/backend/libpq/Attic/be-dumpdata.c,v 1.10 1998/01/26 01:41:05 scrappy Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@@ -34,7 +34,7 @@
|
||||
#include <postgres.h>
|
||||
|
||||
#include <lib/dllist.h>
|
||||
#include <libpq/libpq-be.h>
|
||||
#include <libpq/libpq.h>
|
||||
#include <access/heapam.h>
|
||||
#include <access/htup.h>
|
||||
#include <storage/buf.h>
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $Header: /cvsroot/pgsql/src/backend/libpq/Attic/be-pqexec.c,v 1.13 1998/01/07 21:03:16 momjian Exp $
|
||||
* $Header: /cvsroot/pgsql/src/backend/libpq/Attic/be-pqexec.c,v 1.14 1998/01/26 01:41:06 scrappy Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@@ -27,7 +27,7 @@
|
||||
#include <tcop/fastpath.h>
|
||||
#include <tcop/tcopprot.h>
|
||||
#include <lib/dllist.h>
|
||||
#include <libpq/libpq-be.h>
|
||||
#include <libpq/libpq.h>
|
||||
#include <fmgr.h>
|
||||
#include <utils/exc.h>
|
||||
#include <utils/builtins.h>
|
||||
|
||||
@@ -17,9 +17,6 @@
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#ifdef HAVE_CRYPT_H
|
||||
#include <crypt.h>
|
||||
#endif
|
||||
|
||||
#include "postgres.h"
|
||||
#include "miscadmin.h"
|
||||
@@ -27,6 +24,10 @@
|
||||
#include "storage/fd.h"
|
||||
#include "libpq/crypt.h"
|
||||
|
||||
#ifdef HAVE_CRYPT_H
|
||||
#include <crypt.h>
|
||||
#endif
|
||||
|
||||
char** pwd_cache = NULL;
|
||||
int pwd_cache_count = 0;
|
||||
|
||||
@@ -219,6 +220,7 @@ int crypt_getloginfo(const char* user, char** passwd, char** valuntil) {
|
||||
|
||||
/*-------------------------------------------------------------------------*/
|
||||
|
||||
#ifdef 0
|
||||
MsgType crypt_salt(const char* user) {
|
||||
|
||||
char* passwd;
|
||||
@@ -237,6 +239,7 @@ MsgType crypt_salt(const char* user) {
|
||||
if (valuntil) free((void*)valuntil);
|
||||
return STARTUP_SALT_MSG;
|
||||
}
|
||||
#endif
|
||||
|
||||
/*-------------------------------------------------------------------------*/
|
||||
|
||||
@@ -258,7 +261,13 @@ int crypt_verify(Port* port, const char* user, const char* pgpass) {
|
||||
return STATUS_ERROR;
|
||||
}
|
||||
|
||||
crypt_pwd = crypt(passwd, port->salt);
|
||||
/*
|
||||
* Compare with the encrypted or plain password depending on the
|
||||
* authentication method being used for this connection.
|
||||
*/
|
||||
|
||||
crypt_pwd = (port->auth_method == uaCrypt ? crypt(passwd, port->salt) : passwd);
|
||||
|
||||
if (!strcmp(pgpass, crypt_pwd)) {
|
||||
/* check here to be sure we are not past valuntil
|
||||
*/
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $Header: /cvsroot/pgsql/src/backend/libpq/hba.c,v 1.25 1997/12/09 03:10:38 scrappy Exp $
|
||||
* $Header: /cvsroot/pgsql/src/backend/libpq/hba.c,v 1.26 1998/01/26 01:41:08 scrappy Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@@ -97,84 +97,56 @@ read_through_eol(FILE *file)
|
||||
|
||||
|
||||
static void
|
||||
read_hba_entry2(FILE *file, enum Userauth * userauth_p, char usermap_name[],
|
||||
bool *error_p, bool *matches_p, bool find_password_entries)
|
||||
read_hba_entry2(FILE *file, UserAuth * userauth_p, char auth_arg[],
|
||||
bool *error_p)
|
||||
{
|
||||
/*--------------------------------------------------------------------------
|
||||
Read from file FILE the rest of a host record, after the mask field,
|
||||
and return the interpretation of it as *userauth_p, usermap_name, and
|
||||
and return the interpretation of it as *userauth_p, auth_arg, and
|
||||
*error_p.
|
||||
---------------------------------------------------------------------------*/
|
||||
char buf[MAX_TOKEN];
|
||||
|
||||
bool userauth_valid;
|
||||
|
||||
/* Get authentication type token. */
|
||||
next_token(file, buf, sizeof(buf));
|
||||
userauth_valid = false;
|
||||
if (buf[0] == '\0')
|
||||
|
||||
if (strcmp(buf, "trust") == 0)
|
||||
*userauth_p = uaTrust;
|
||||
else if (strcmp(buf, "ident") == 0)
|
||||
*userauth_p = uaIdent;
|
||||
else if (strcmp(buf, "password") == 0)
|
||||
*userauth_p = uaPassword;
|
||||
else if (strcmp(buf, "krb4") == 0)
|
||||
*userauth_p = uaKrb4;
|
||||
else if (strcmp(buf, "krb5") == 0)
|
||||
*userauth_p = uaKrb5;
|
||||
else if (strcmp(buf, "reject") == 0)
|
||||
*userauth_p = uaReject;
|
||||
else if (strcmp(buf, "crypt") == 0)
|
||||
*userauth_p = uaCrypt;
|
||||
else
|
||||
{
|
||||
*error_p = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
userauth_valid = true;
|
||||
if (strcmp(buf, "trust") == 0)
|
||||
{
|
||||
*userauth_p = Trust;
|
||||
}
|
||||
else if (strcmp(buf, "ident") == 0)
|
||||
{
|
||||
*userauth_p = Ident;
|
||||
}
|
||||
else if (strcmp(buf, "password") == 0)
|
||||
{
|
||||
*userauth_p = Password;
|
||||
}
|
||||
else
|
||||
{
|
||||
userauth_valid = false;
|
||||
}
|
||||
|
||||
if ((find_password_entries && strcmp(buf, "password") == 0) ||
|
||||
(!find_password_entries && strcmp(buf, "password") != 0))
|
||||
{
|
||||
*matches_p = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
*matches_p = false;
|
||||
}
|
||||
if (buf[0] != '\0')
|
||||
read_through_eol(file);
|
||||
}
|
||||
|
||||
if (!userauth_valid || !*matches_p || *error_p)
|
||||
if (!*error_p)
|
||||
{
|
||||
if (!userauth_valid)
|
||||
{
|
||||
*error_p = true;
|
||||
}
|
||||
read_through_eol(file);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Get the map name token, if any */
|
||||
/* Get the authentication argument token, if any */
|
||||
next_token(file, buf, sizeof(buf));
|
||||
if (buf[0] == '\0')
|
||||
{
|
||||
*error_p = false;
|
||||
usermap_name[0] = '\0';
|
||||
}
|
||||
auth_arg[0] = '\0';
|
||||
else
|
||||
{
|
||||
strncpy(usermap_name, buf, USERMAP_NAME_SIZE);
|
||||
StrNCpy(auth_arg, buf, MAX_AUTH_ARG - 1);
|
||||
next_token(file, buf, sizeof(buf));
|
||||
if (buf[0] != '\0')
|
||||
{
|
||||
*error_p = true;
|
||||
read_through_eol(file);
|
||||
}
|
||||
else
|
||||
*error_p = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -182,139 +154,150 @@ read_hba_entry2(FILE *file, enum Userauth * userauth_p, char usermap_name[],
|
||||
|
||||
|
||||
static void
|
||||
process_hba_record(FILE *file,
|
||||
const struct in_addr ip_addr, const char database[],
|
||||
process_hba_record(FILE *file, SockAddr *raddr, const char database[],
|
||||
bool *matches_p, bool *error_p,
|
||||
enum Userauth * userauth_p, char usermap_name[],
|
||||
bool find_password_entries)
|
||||
UserAuth * userauth_p, char auth_arg[])
|
||||
{
|
||||
/*---------------------------------------------------------------------------
|
||||
Process the non-comment record in the config file that is next on the file.
|
||||
See if it applies to a connection to a host with IP address "ip_addr"
|
||||
See if it applies to a connection to a host with IP address "*raddr"
|
||||
to a database named "database[]". If so, return *matches_p true
|
||||
and *userauth_p and usermap_name[] as the values from the entry.
|
||||
If not, return matches_p false. If the record has a syntax error,
|
||||
and *userauth_p and auth_arg[] as the values from the entry.
|
||||
If not, leave *matches_p as it was. If the record has a syntax error,
|
||||
return *error_p true, after issuing a message to stderr. If no error,
|
||||
leave *error_p as it was.
|
||||
---------------------------------------------------------------------------*/
|
||||
char buf[MAX_TOKEN]; /* A token from the record */
|
||||
char db[MAX_TOKEN], buf[MAX_TOKEN];
|
||||
|
||||
/* Read the record type field. */
|
||||
|
||||
/* Read the record type field */
|
||||
next_token(file, buf, sizeof(buf));
|
||||
|
||||
if (buf[0] == '\0')
|
||||
*matches_p = false;
|
||||
return;
|
||||
|
||||
/* Check the record type. */
|
||||
|
||||
if (strcmp(buf, "local") == 0)
|
||||
{
|
||||
/* Get the database. */
|
||||
|
||||
next_token(file, db, sizeof(db));
|
||||
|
||||
if (db[0] == '\0')
|
||||
goto syntax;
|
||||
|
||||
/* Read the rest of the line. */
|
||||
|
||||
read_hba_entry2(file, userauth_p, 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))
|
||||
*error_p = true;
|
||||
|
||||
if (*error_p)
|
||||
goto syntax;
|
||||
|
||||
/*
|
||||
* 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) ||
|
||||
raddr->sa.sa_family != AF_UNIX)
|
||||
return;
|
||||
}
|
||||
else if (strcmp(buf, "host") == 0)
|
||||
{
|
||||
struct in_addr file_ip_addr, mask;
|
||||
|
||||
/* Get the database. */
|
||||
|
||||
next_token(file, db, sizeof(db));
|
||||
|
||||
if (db[0] == '\0')
|
||||
goto syntax;
|
||||
|
||||
/* Read the IP address field. */
|
||||
|
||||
next_token(file, buf, sizeof(buf));
|
||||
|
||||
if (buf[0] == '\0')
|
||||
goto syntax;
|
||||
|
||||
/* Remember the IP address field and go get mask field. */
|
||||
|
||||
if (!inet_aton(buf, &file_ip_addr))
|
||||
{
|
||||
read_through_eol(file);
|
||||
goto syntax;
|
||||
}
|
||||
|
||||
/* Read the mask field. */
|
||||
|
||||
next_token(file, buf, sizeof(buf));
|
||||
|
||||
if (buf[0] == '\0')
|
||||
goto syntax;
|
||||
|
||||
if (!inet_aton(buf, &mask))
|
||||
{
|
||||
read_through_eol(file);
|
||||
goto syntax;
|
||||
}
|
||||
|
||||
/*
|
||||
* This is the record we're looking for. Read the rest of the
|
||||
* info from it.
|
||||
*/
|
||||
|
||||
read_hba_entry2(file, userauth_p, auth_arg, error_p);
|
||||
|
||||
if (*error_p)
|
||||
goto syntax;
|
||||
|
||||
/*
|
||||
* 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) ||
|
||||
raddr->sa.sa_family != AF_INET ||
|
||||
((file_ip_addr.s_addr ^ raddr->in.sin_addr.s_addr) & mask.s_addr) != 0x0000)
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* if this isn't a "host" record, it can't match. */
|
||||
if (strcmp(buf, "host") != 0)
|
||||
{
|
||||
*matches_p = false;
|
||||
read_through_eol(file);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* It's a "host" record. Read the database name field. */
|
||||
next_token(file, buf, sizeof(buf));
|
||||
if (buf[0] == '\0')
|
||||
*matches_p = false;
|
||||
else
|
||||
{
|
||||
/* If this record isn't for our database, ignore it. */
|
||||
if (strcmp(buf, database) != 0 && strcmp(buf, "all") != 0)
|
||||
{
|
||||
*matches_p = false;
|
||||
read_through_eol(file);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Read the IP address field */
|
||||
next_token(file, buf, sizeof(buf));
|
||||
if (buf[0] == '\0')
|
||||
*matches_p = false;
|
||||
else
|
||||
{
|
||||
int valid; /* Field is valid dotted
|
||||
* decimal */
|
||||
|
||||
/*
|
||||
* Remember the IP address field and go get mask
|
||||
* field
|
||||
*/
|
||||
struct in_addr file_ip_addr; /* IP address field
|
||||
* value */
|
||||
|
||||
valid = inet_aton(buf, &file_ip_addr);
|
||||
if (!valid)
|
||||
{
|
||||
*matches_p = false;
|
||||
read_through_eol(file);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Read the mask field */
|
||||
next_token(file, buf, sizeof(buf));
|
||||
if (buf[0] == '\0')
|
||||
*matches_p = false;
|
||||
else
|
||||
{
|
||||
struct in_addr mask;
|
||||
|
||||
/*
|
||||
* Got mask. Now see if this record is
|
||||
* for our host.
|
||||
*/
|
||||
valid = inet_aton(buf, &mask);
|
||||
if (!valid)
|
||||
{
|
||||
*matches_p = false;
|
||||
read_through_eol(file);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (((file_ip_addr.s_addr ^ ip_addr.s_addr) & mask.s_addr)
|
||||
!= 0x0000)
|
||||
{
|
||||
*matches_p = false;
|
||||
read_through_eol(file);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
/*
|
||||
* This is the record we're
|
||||
* looking for. Read the rest of
|
||||
* the info from it.
|
||||
*/
|
||||
read_hba_entry2(file, userauth_p, usermap_name,
|
||||
error_p, matches_p, find_password_entries);
|
||||
if (*error_p)
|
||||
{
|
||||
sprintf(PQerrormsg,
|
||||
"process_hba_record: invalid syntax in "
|
||||
"hba config file "
|
||||
"for host record for IP address %s\n",
|
||||
inet_ntoa(file_ip_addr));
|
||||
fputs(PQerrormsg, stderr);
|
||||
pqdebug("%s", PQerrormsg);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
read_through_eol(file);
|
||||
goto syntax;
|
||||
}
|
||||
|
||||
*matches_p = true;
|
||||
|
||||
return;
|
||||
|
||||
syntax:
|
||||
sprintf(PQerrormsg,
|
||||
"process_hba_record: invalid syntax in pg_hba.conf file\n");
|
||||
|
||||
fputs(PQerrormsg, stderr);
|
||||
pqdebug("%s", PQerrormsg);
|
||||
|
||||
*error_p = true;
|
||||
}
|
||||
|
||||
|
||||
|
||||
static void
|
||||
process_open_config_file(FILE *file,
|
||||
const struct in_addr ip_addr, const char database[],
|
||||
bool *host_ok_p, enum Userauth * userauth_p,
|
||||
char usermap_name[], bool find_password_entries)
|
||||
process_open_config_file(FILE *file, SockAddr *raddr, const char database[],
|
||||
bool *host_ok_p, UserAuth * userauth_p,
|
||||
char auth_arg[])
|
||||
{
|
||||
/*---------------------------------------------------------------------------
|
||||
This function does the same thing as find_hba_entry, only with
|
||||
@@ -348,36 +331,26 @@ process_open_config_file(FILE *file,
|
||||
read_through_eol(file);
|
||||
else
|
||||
{
|
||||
process_hba_record(file, ip_addr, database,
|
||||
&found_entry, &error, userauth_p, usermap_name,
|
||||
find_password_entries);
|
||||
process_hba_record(file, raddr, database,
|
||||
&found_entry, &error, userauth_p, auth_arg);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (found_entry)
|
||||
{
|
||||
if (error)
|
||||
*host_ok_p = false;
|
||||
else
|
||||
*host_ok_p = true;
|
||||
}
|
||||
else
|
||||
*host_ok_p = false;
|
||||
|
||||
if (found_entry && !error)
|
||||
*host_ok_p = true;
|
||||
}
|
||||
|
||||
|
||||
|
||||
void
|
||||
find_hba_entry(const char DataDir[], const struct in_addr ip_addr,
|
||||
const char database[],
|
||||
bool *host_ok_p, enum Userauth * userauth_p,
|
||||
char usermap_name[], bool find_password_entries)
|
||||
static void
|
||||
find_hba_entry(SockAddr *raddr, const char database[], bool *host_ok_p,
|
||||
UserAuth * userauth_p, char auth_arg[])
|
||||
{
|
||||
/*--------------------------------------------------------------------------
|
||||
Read the config file and find an entry that allows connection from
|
||||
host "ip_addr" to database "database". If not found, return
|
||||
*host_ok_p == false. If found, return *userauth_p and *usermap_name
|
||||
representing the contents of that entry.
|
||||
host "*raddr" to database "database". If found, return *host_ok_p == true
|
||||
and *userauth_p and *auth_arg representing the contents of that entry.
|
||||
|
||||
When a record has invalid syntax, we either ignore it or reject the
|
||||
connection (depending on where it's invalid). No message or anything.
|
||||
@@ -436,8 +409,6 @@ find_hba_entry(const char DataDir[], const struct in_addr ip_addr,
|
||||
{
|
||||
/* The open of the config file failed. */
|
||||
|
||||
*host_ok_p = false;
|
||||
|
||||
sprintf(PQerrormsg,
|
||||
"find_hba_entry: Host-based authentication config file "
|
||||
"does not exist or permissions are not setup correctly! "
|
||||
@@ -448,8 +419,8 @@ find_hba_entry(const char DataDir[], const struct in_addr ip_addr,
|
||||
}
|
||||
else
|
||||
{
|
||||
process_open_config_file(file, ip_addr, database, host_ok_p, userauth_p,
|
||||
usermap_name, find_password_entries);
|
||||
process_open_config_file(file, raddr, database, host_ok_p, userauth_p,
|
||||
auth_arg);
|
||||
FreeFile(file);
|
||||
}
|
||||
pfree(conf_file);
|
||||
@@ -754,8 +725,7 @@ verify_against_open_usermap(FILE *file,
|
||||
|
||||
|
||||
static void
|
||||
verify_against_usermap(const char DataDir[],
|
||||
const char pguser[],
|
||||
verify_against_usermap(const char pguser[],
|
||||
const char ident_username[],
|
||||
const char usermap_name[],
|
||||
bool *checks_out_p)
|
||||
@@ -834,20 +804,20 @@ verify_against_usermap(const char DataDir[],
|
||||
|
||||
|
||||
|
||||
static void
|
||||
authident(const char DataDir[],
|
||||
const Port port, const char postgres_username[],
|
||||
const char usermap_name[],
|
||||
bool *authentic_p)
|
||||
int
|
||||
authident(struct sockaddr_in *raddr, struct sockaddr_in *laddr,
|
||||
const char postgres_username[],
|
||||
const char auth_arg[])
|
||||
{
|
||||
/*---------------------------------------------------------------------------
|
||||
Talk to the ident server on the remote host and find out who owns the
|
||||
connection described by "port". Then look in the usermap file under
|
||||
the usermap usermap_name[] and see if that user is equivalent to
|
||||
the usermap auth_arg[] and see if that user is equivalent to
|
||||
Postgres user user[].
|
||||
|
||||
Return *authentic_p true iff yes.
|
||||
Return STATUS_OK if yes.
|
||||
---------------------------------------------------------------------------*/
|
||||
bool checks_out;
|
||||
bool ident_failed;
|
||||
|
||||
/* We were unable to get ident to give us a username */
|
||||
@@ -855,120 +825,35 @@ authident(const char DataDir[],
|
||||
|
||||
/* The username returned by ident */
|
||||
|
||||
ident(port.raddr.in.sin_addr, port.laddr.in.sin_addr,
|
||||
port.raddr.in.sin_port, port.laddr.in.sin_port,
|
||||
ident(raddr->sin_addr, laddr->sin_addr,
|
||||
raddr->sin_port, laddr->sin_port,
|
||||
&ident_failed, ident_username);
|
||||
|
||||
if (ident_failed)
|
||||
*authentic_p = false;
|
||||
else
|
||||
{
|
||||
bool checks_out;
|
||||
return STATUS_ERROR;
|
||||
|
||||
verify_against_usermap(DataDir,
|
||||
postgres_username, ident_username, usermap_name,
|
||||
verify_against_usermap(postgres_username, ident_username, auth_arg,
|
||||
&checks_out);
|
||||
if (checks_out)
|
||||
*authentic_p = true;
|
||||
else
|
||||
*authentic_p = false;
|
||||
}
|
||||
|
||||
return (checks_out ? STATUS_OK : STATUS_ERROR);
|
||||
}
|
||||
|
||||
|
||||
|
||||
extern int
|
||||
hba_recvauth(const Port *port, const char database[], const char user[],
|
||||
const char DataDir[])
|
||||
hba_getauthmethod(SockAddr *raddr, char *database, char *auth_arg,
|
||||
UserAuth *auth_method)
|
||||
{
|
||||
/*---------------------------------------------------------------------------
|
||||
Determine if the TCP connection described by "port" is with someone
|
||||
allowed to act as user "user" and access database "database". Return
|
||||
STATUS_OK if yes; STATUS_ERROR if not.
|
||||
Determine what authentication method should be used when accessing database
|
||||
"database" from frontend "raddr". Return the method, an optional argument,
|
||||
and STATUS_OK.
|
||||
----------------------------------------------------------------------------*/
|
||||
bool host_ok;
|
||||
|
||||
/*
|
||||
* There's an entry for this database and remote host in the pg_hba
|
||||
* file
|
||||
*/
|
||||
char usermap_name[USERMAP_NAME_SIZE + 1];
|
||||
host_ok = false;
|
||||
|
||||
/*
|
||||
* The name of the map pg_hba specifies for this connection (or
|
||||
* special value "SAMEUSER")
|
||||
*/
|
||||
enum Userauth userauth;
|
||||
find_hba_entry(raddr, database, &host_ok, auth_method, auth_arg);
|
||||
|
||||
/*
|
||||
* The type of user authentication pg_hba specifies for this
|
||||
* connection
|
||||
*/
|
||||
int retvalue;
|
||||
|
||||
/* UNIX socket always OK, for now */
|
||||
if (port->raddr.in.sin_family == AF_UNIX)
|
||||
return STATUS_OK;
|
||||
/* Our eventual return value */
|
||||
|
||||
|
||||
find_hba_entry(DataDir, port->raddr.in.sin_addr, database,
|
||||
&host_ok, &userauth, usermap_name,
|
||||
false /* don't find password entries of type
|
||||
'password' */ );
|
||||
|
||||
if (!host_ok)
|
||||
retvalue = STATUS_ERROR;
|
||||
else
|
||||
{
|
||||
switch (userauth)
|
||||
{
|
||||
case Trust:
|
||||
retvalue = STATUS_OK;
|
||||
break;
|
||||
case Ident:
|
||||
{
|
||||
|
||||
/*
|
||||
* Here's where we need to call up ident and
|
||||
* authenticate the user
|
||||
*/
|
||||
|
||||
bool authentic; /* He is who he says he
|
||||
* is. */
|
||||
|
||||
authident(DataDir, *port, user, usermap_name, &authentic);
|
||||
|
||||
if (authentic)
|
||||
retvalue = STATUS_OK;
|
||||
else
|
||||
retvalue = STATUS_ERROR;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
retvalue = STATUS_ERROR;
|
||||
Assert(false);
|
||||
}
|
||||
}
|
||||
return (retvalue);
|
||||
return (host_ok ? STATUS_OK : STATUS_ERROR);
|
||||
}
|
||||
|
||||
|
||||
/*----------------------------------------------------------------
|
||||
* This version of hba was written by Bryan Henderson
|
||||
* in September 1996 for Release 6.0. It changed the format of the
|
||||
* hba file and added ident function.
|
||||
*
|
||||
* Here are some notes about the original host based authentication
|
||||
* the preceded this one.
|
||||
*
|
||||
* based on the securelib package originally written by William
|
||||
* LeFebvre, EECS Department, Northwestern University
|
||||
* (phil@eecs.nwu.edu) - orginal configuration file code handling
|
||||
* by Sam Horrocks (sam@ics.uci.edu)
|
||||
*
|
||||
* modified and adapted for use with Postgres95 by Paul Fisher
|
||||
* (pnfisher@unity.ncsu.edu)
|
||||
*
|
||||
-----------------------------------------------------------------*/
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
#include <postgres.h>
|
||||
#include <miscadmin.h>
|
||||
#include <libpq/password.h>
|
||||
#include <libpq/hba.h>
|
||||
#include <libpq/libpq.h>
|
||||
#include <storage/fd.h>
|
||||
#include <string.h>
|
||||
@@ -10,56 +10,15 @@
|
||||
#endif
|
||||
|
||||
int
|
||||
verify_password(char *user, char *password, Port *port,
|
||||
char *database, char *DataDir)
|
||||
verify_password(char *auth_arg, char *user, char *password)
|
||||
{
|
||||
bool host_ok;
|
||||
enum Userauth userauth;
|
||||
char pw_file_name[PWFILE_NAME_SIZE + 1];
|
||||
char *pw_file_fullname;
|
||||
FILE *pw_file;
|
||||
|
||||
char *pw_file_fullname;
|
||||
FILE *pw_file;
|
||||
|
||||
char pw_file_line[255];
|
||||
char *p,
|
||||
*test_user,
|
||||
*test_pw;
|
||||
|
||||
find_hba_entry(DataDir, port->raddr.in.sin_addr, database,
|
||||
&host_ok, &userauth, pw_file_name, true);
|
||||
|
||||
if (!host_ok)
|
||||
{
|
||||
sprintf(PQerrormsg,
|
||||
"verify_password: couldn't find entry for connecting host\n");
|
||||
fputs(PQerrormsg, stderr);
|
||||
pqdebug("%s", PQerrormsg);
|
||||
return STATUS_ERROR;
|
||||
}
|
||||
|
||||
if (userauth != Password)
|
||||
{
|
||||
sprintf(PQerrormsg,
|
||||
"verify_password: couldn't find entry of type 'password' "
|
||||
"for this host\n");
|
||||
fputs(PQerrormsg, stderr);
|
||||
pqdebug("%s", PQerrormsg);
|
||||
return STATUS_ERROR;
|
||||
}
|
||||
|
||||
if (!pw_file_name || pw_file_name[0] == '\0')
|
||||
{
|
||||
sprintf(PQerrormsg,
|
||||
"verify_password: no password file specified\n");
|
||||
fputs(PQerrormsg, stderr);
|
||||
pqdebug("%s", PQerrormsg);
|
||||
return STATUS_ERROR;
|
||||
}
|
||||
|
||||
pw_file_fullname = (char *) palloc(strlen(DataDir) + strlen(pw_file_name) + 2);
|
||||
pw_file_fullname = (char *) palloc(strlen(DataDir) + strlen(auth_arg) + 2);
|
||||
strcpy(pw_file_fullname, DataDir);
|
||||
strcat(pw_file_fullname, "/");
|
||||
strcat(pw_file_fullname, pw_file_name);
|
||||
strcat(pw_file_fullname, auth_arg);
|
||||
|
||||
pw_file = AllocateFile(pw_file_fullname, "r");
|
||||
if (!pw_file)
|
||||
@@ -69,12 +28,17 @@ verify_password(char *user, char *password, Port *port,
|
||||
pw_file_fullname);
|
||||
fputs(PQerrormsg, stderr);
|
||||
pqdebug("%s", PQerrormsg);
|
||||
|
||||
pfree(pw_file_fullname);
|
||||
|
||||
return STATUS_ERROR;
|
||||
}
|
||||
|
||||
while (!feof(pw_file))
|
||||
{
|
||||
fgets(pw_file_line, 255, pw_file);
|
||||
char pw_file_line[255], *p, *test_user, *test_pw;
|
||||
|
||||
fgets(pw_file_line, sizeof (pw_file_line), pw_file);
|
||||
p = pw_file_line;
|
||||
|
||||
test_user = strtok(p, ":");
|
||||
@@ -97,6 +61,9 @@ verify_password(char *user, char *password, Port *port,
|
||||
if (strcmp(crypt(password, test_pw), test_pw) == 0)
|
||||
{
|
||||
/* it matched. */
|
||||
|
||||
pfree(pw_file_fullname);
|
||||
|
||||
return STATUS_OK;
|
||||
}
|
||||
|
||||
@@ -105,6 +72,9 @@ verify_password(char *user, char *password, Port *port,
|
||||
user);
|
||||
fputs(PQerrormsg, stderr);
|
||||
pqdebug("%s", PQerrormsg);
|
||||
|
||||
pfree(pw_file_fullname);
|
||||
|
||||
return STATUS_ERROR;
|
||||
}
|
||||
}
|
||||
@@ -114,5 +84,8 @@ verify_password(char *user, char *password, Port *port,
|
||||
user);
|
||||
fputs(PQerrormsg, stderr);
|
||||
pqdebug("%s", PQerrormsg);
|
||||
|
||||
pfree(pw_file_fullname);
|
||||
|
||||
return STATUS_ERROR;
|
||||
}
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
#
|
||||
# This file controls what hosts are allowed to connect to what databases
|
||||
# and specifies some options on how users on a particular host are identified.
|
||||
# It is read each time a host tries to make a connection to a database.
|
||||
#
|
||||
# Each line (terminated by a newline character) is a record. A record cannot
|
||||
# be continued across two lines.
|
||||
@@ -29,13 +30,14 @@
|
||||
# Record type "host"
|
||||
# ------------------
|
||||
#
|
||||
# This record identifies a set of hosts that are permitted to connect to
|
||||
# databases. No hosts are permitted to connect except as specified by a
|
||||
# "host" record.
|
||||
# This record identifies a set of network hosts that are permitted to connect
|
||||
# to databases. No network hosts are permitted to connect except as specified
|
||||
# by a "host" record. See the record type "local" to specify permitted
|
||||
# connections using UNIX sockets.
|
||||
#
|
||||
# Format:
|
||||
#
|
||||
# host DBNAME IP_ADDRESS ADDRESS_MASK USERAUTH [MAP]
|
||||
# host DBNAME IP_ADDRESS ADDRESS_MASK USERAUTH [AUTH_ARGUMENT]
|
||||
#
|
||||
# DBNAME is the name of a Postgres database, or "all" to indicate all
|
||||
# databases.
|
||||
@@ -49,33 +51,54 @@
|
||||
# under the Postgres username he supplies in his connection parameters.
|
||||
#
|
||||
# ident: Authentication is done by the ident server on the remote
|
||||
# host, via the ident (RFC 1413) protocol.
|
||||
# host, via the ident (RFC 1413) protocol. AUTH_ARGUMENT, if
|
||||
# specified, is a map name to be found in the pg_ident.conf file.
|
||||
# That table maps from ident usernames to Postgres usernames. The
|
||||
# special map name "sameuser" indicates an implied map (not found
|
||||
# in pg_ident.conf) that maps every ident username to the identical
|
||||
# Postgres username.
|
||||
#
|
||||
# trust: No authentication is done. Trust that the user has the
|
||||
# authority to user whatever username he says he does.
|
||||
# Before Postgres Version 6, all authentication was this way.
|
||||
#
|
||||
# MAP is the name of a map that matches an authenticated principal with
|
||||
# a Postgres username. If USERNAME is "trust", this value is ignored and
|
||||
# may be absent.
|
||||
# reject: Reject the connection.
|
||||
#
|
||||
# In the case of USERAUTH=ident, this is a map name to be found in the
|
||||
# pg_ident.conf file. That table maps from ident usernames to Postgres
|
||||
# usernames. The special map name "sameuser" indicates an implied map
|
||||
# (not found in pg_ident.conf) that maps every ident username to the identical
|
||||
# Postgres username.
|
||||
# password: Authentication is done by matching a password supplied in clear
|
||||
# by the host. If AUTH_ARGUMENT is specified then the password is
|
||||
# compared with the user's entry in that file (in the $PGDATA
|
||||
# directory). See pg_passwd(1). If it is omitted then the
|
||||
# password is compared with the user's entry in the pg_user table.
|
||||
#
|
||||
# crypt: Authentication is done by matching an encrypted password supplied
|
||||
# by the host with that held for the user in the pg_user table.
|
||||
#
|
||||
# krb4: Kerberos V4 authentication is used.
|
||||
#
|
||||
# krb5: Kerberos V5 authentication is used.
|
||||
|
||||
# Record type "local"
|
||||
# ------------------
|
||||
#
|
||||
# This record identifies the authentication to use when connecting to a
|
||||
# particular database via a local UNIX socket.
|
||||
#
|
||||
# Format:
|
||||
#
|
||||
# local DBNAME USERAUTH [AUTH_ARGUMENT]
|
||||
#
|
||||
# The format is the same as that of the "host" record type except that the
|
||||
# IP_ADDRESS and ADDRESS_MASK are omitted and the "ident", "krb4" and "krb5"
|
||||
# values of USERAUTH are no allowed.
|
||||
|
||||
# For backwards compatibility, PostgreSQL also accepts pre-Version 6 records,
|
||||
# which look like:
|
||||
#
|
||||
# all 127.0.0.1 0.0.0.0
|
||||
#
|
||||
#
|
||||
|
||||
# TYPE DATABASE IP_ADDRESS MASK USERAUTH MAP
|
||||
|
||||
host all 127.0.0.1 255.255.255.255 trust
|
||||
#host all 127.0.0.1 255.255.255.255 trust
|
||||
|
||||
# The above allows any user on the local system to connect to any database
|
||||
# under any username.
|
||||
@@ -86,10 +109,11 @@ host all 127.0.0.1 255.255.255.255 trust
|
||||
# connect to database template1 as the same username that ident on that host
|
||||
# identifies him as (typically his Unix username).
|
||||
|
||||
#host all 192.168.0.1 255.255.255.255 reject
|
||||
#host all 0.0.0.0 0.0.0.0 trust
|
||||
|
||||
# The above would allow anyone anywhere to connect to any database under
|
||||
# any username.
|
||||
# The above would allow anyone anywhere except from 192.168.0.1 to connect to
|
||||
# any database under any username.
|
||||
|
||||
#host all 192.168.0.0 255.255.255.0 ident omicron
|
||||
#
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $Header: /cvsroot/pgsql/src/backend/libpq/pqcomm.c,v 1.34 1998/01/25 05:13:18 momjian Exp $
|
||||
* $Header: /cvsroot/pgsql/src/backend/libpq/pqcomm.c,v 1.35 1998/01/26 01:41:11 scrappy Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@@ -43,6 +43,7 @@
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/un.h>
|
||||
#include <netdb.h>
|
||||
#include <netinet/in.h>
|
||||
#include <netinet/tcp.h>
|
||||
@@ -269,28 +270,6 @@ int
|
||||
pq_getnchar(char *s, int off, int maxlen)
|
||||
{
|
||||
return pqGetNBytes(s + off, maxlen, Pfin);
|
||||
|
||||
#if 0
|
||||
int c = '\0';
|
||||
|
||||
if (Pfin == (FILE *) NULL)
|
||||
{
|
||||
/* elog(DEBUG, "Input descriptor is null"); */
|
||||
return (EOF);
|
||||
}
|
||||
|
||||
s += off;
|
||||
while (maxlen-- && (c = pq_getc(Pfin)) != EOF)
|
||||
*s++ = c;
|
||||
|
||||
/* -----------------
|
||||
* If EOF reached let caller know
|
||||
* -----------------
|
||||
*/
|
||||
if (c == EOF)
|
||||
return (EOF);
|
||||
return (!EOF);
|
||||
#endif
|
||||
}
|
||||
|
||||
/* --------------------------------
|
||||
@@ -591,11 +570,7 @@ do_unlink()
|
||||
int
|
||||
StreamServerPort(char *hostName, short portName, int *fdP)
|
||||
{
|
||||
union
|
||||
{
|
||||
struct sockaddr_in in;
|
||||
struct sockaddr_un un;
|
||||
} saddr;
|
||||
SockAddr saddr;
|
||||
int fd,
|
||||
err,
|
||||
family;
|
||||
@@ -624,20 +599,19 @@ StreamServerPort(char *hostName, short portName, int *fdP)
|
||||
return (STATUS_ERROR);
|
||||
}
|
||||
bzero(&saddr, sizeof(saddr));
|
||||
saddr.sa.sa_family = family;
|
||||
if (family == AF_UNIX)
|
||||
{
|
||||
saddr.un.sun_family = family;
|
||||
len = UNIXSOCK_PATH(saddr.un, portName);
|
||||
strcpy(sock_path, saddr.un.sun_path);
|
||||
}
|
||||
else
|
||||
{
|
||||
saddr.in.sin_family = family;
|
||||
saddr.in.sin_addr.s_addr = htonl(INADDR_ANY);
|
||||
saddr.in.sin_port = htons(portName);
|
||||
len = sizeof saddr.in;
|
||||
len = sizeof (struct sockaddr_in);
|
||||
}
|
||||
err = bind(fd, (struct sockaddr *) & saddr, len);
|
||||
err = bind(fd, &saddr.sa, len);
|
||||
if (err < 0)
|
||||
{
|
||||
sprintf(PQerrormsg,
|
||||
@@ -685,7 +659,7 @@ StreamConnection(int server_fd, Port *port)
|
||||
{
|
||||
int len,
|
||||
addrlen;
|
||||
int family = port->raddr.in.sin_family;
|
||||
int family = port->raddr.sa.sa_family;
|
||||
|
||||
/* accept connection (and fill in the client (remote) address) */
|
||||
len = family == AF_INET ?
|
||||
@@ -726,8 +700,6 @@ StreamConnection(int server_fd, Port *port)
|
||||
}
|
||||
}
|
||||
|
||||
port->mask = 1 << port->sock;
|
||||
|
||||
/* reset to non-blocking */
|
||||
fcntl(port->sock, F_SETFL, 1);
|
||||
|
||||
@@ -788,7 +760,7 @@ StreamOpen(char *hostName, short portName, Port *port)
|
||||
len = UNIXSOCK_PATH(port->raddr.un, portName);
|
||||
}
|
||||
/* connect to the server */
|
||||
if ((port->sock = socket(port->raddr.in.sin_family, SOCK_STREAM, 0)) < 0)
|
||||
if ((port->sock = socket(port->raddr.sa.sa_family, SOCK_STREAM, 0)) < 0)
|
||||
{
|
||||
sprintf(PQerrormsg,
|
||||
"FATAL: StreamOpen: socket() failed: errno=%d\n",
|
||||
@@ -797,7 +769,7 @@ StreamOpen(char *hostName, short portName, Port *port)
|
||||
pqdebug("%s", PQerrormsg);
|
||||
return (STATUS_ERROR);
|
||||
}
|
||||
err = connect(port->sock, (struct sockaddr *) & port->raddr, len);
|
||||
err = connect(port->sock, &port->raddr.sa, len);
|
||||
if (err < 0)
|
||||
{
|
||||
sprintf(PQerrormsg,
|
||||
@@ -809,8 +781,7 @@ StreamOpen(char *hostName, short portName, Port *port)
|
||||
}
|
||||
|
||||
/* fill in the client address */
|
||||
if (getsockname(port->sock, (struct sockaddr *) & port->laddr,
|
||||
&len) < 0)
|
||||
if (getsockname(port->sock, &port->laddr.sa, &len) < 0)
|
||||
{
|
||||
sprintf(PQerrormsg,
|
||||
"FATAL: StreamOpen: getsockname() failed: errno=%d\n",
|
||||
@@ -822,32 +793,3 @@ StreamOpen(char *hostName, short portName, Port *port)
|
||||
|
||||
return (STATUS_OK);
|
||||
}
|
||||
|
||||
static char *authentication_type_name[] = {
|
||||
0, 0, 0, 0, 0, 0, 0,
|
||||
"the default authentication type",
|
||||
0, 0,
|
||||
"Kerberos v4",
|
||||
"Kerberos v5",
|
||||
"host-based authentication",
|
||||
"unauthenication",
|
||||
"plaintext password authentication"
|
||||
};
|
||||
|
||||
char *
|
||||
name_of_authentication_type(int type)
|
||||
{
|
||||
char *result = 0;
|
||||
|
||||
if (type >= 1 && type <= LAST_AUTHENTICATION_TYPE)
|
||||
{
|
||||
result = authentication_type_name[type];
|
||||
}
|
||||
|
||||
if (result == 0)
|
||||
{
|
||||
result = "<unknown authentication type>";
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -1,122 +1,150 @@
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <netinet/in.h>
|
||||
|
||||
#include "postgres.h"
|
||||
#include "libpq/pqcomm.h"
|
||||
|
||||
#ifdef HAVE_ENDIAN_H
|
||||
#include <endian.h>
|
||||
#endif
|
||||
|
||||
|
||||
/* --------------------------------------------------------------------- */
|
||||
/* These definitions for ntoh/hton are the other way around from the
|
||||
* default system definitions, so we roll our own here.
|
||||
/*
|
||||
* The backend supports the old little endian byte order and the current
|
||||
* network byte order.
|
||||
*/
|
||||
|
||||
#ifndef FRONTEND
|
||||
|
||||
#include "libpq/libpq-be.h"
|
||||
|
||||
#ifdef HAVE_ENDIAN_H
|
||||
#include <endian.h>
|
||||
#endif
|
||||
|
||||
#ifndef BYTE_ORDER
|
||||
#error BYTE_ORDER must be defined as LITTLE_ENDIAN, BIG_ENDIAN or PDP_ENDIAN
|
||||
#endif
|
||||
|
||||
#if BYTE_ORDER == LITTLE_ENDIAN
|
||||
#define ntoh_s(n) n
|
||||
#define ntoh_l(n) n
|
||||
#define hton_s(n) n
|
||||
#define hton_l(n) n
|
||||
#else /* BYTE_ORDER != LITTLE_ENDIAN */
|
||||
|
||||
#define ntoh_s(n) n
|
||||
#define ntoh_l(n) n
|
||||
#define hton_s(n) n
|
||||
#define hton_l(n) n
|
||||
|
||||
#else
|
||||
#if BYTE_ORDER == BIG_ENDIAN
|
||||
#define ntoh_s(n) (u_short)(((u_char *)&n)[1] << 8 \
|
||||
| ((u_char *)&n)[0])
|
||||
#define ntoh_l(n) (uint32) (((u_char *)&n)[3] << 24 \
|
||||
| ((u_char *)&n)[2] << 16 \
|
||||
| ((u_char *)&n)[1] << 8 \
|
||||
| ((u_char *)&n)[0])
|
||||
#define hton_s(n) (ntoh_s(n))
|
||||
#define hton_l(n) (ntoh_l(n))
|
||||
|
||||
#define ntoh_s(n) (uint16)(((u_char *)&n)[1] << 8 \
|
||||
| ((u_char *)&n)[0])
|
||||
#define ntoh_l(n) (uint32)(((u_char *)&n)[3] << 24 \
|
||||
| ((u_char *)&n)[2] << 16 \
|
||||
| ((u_char *)&n)[1] << 8 \
|
||||
| ((u_char *)&n)[0])
|
||||
#define hton_s(n) (ntoh_s(n))
|
||||
#define hton_l(n) (ntoh_l(n))
|
||||
|
||||
#else
|
||||
/* BYTE_ORDER != BIG_ENDIAN */
|
||||
#if BYTE_ORDER == PDP_ENDIAN
|
||||
|
||||
#error PDP_ENDIAN macros not written yet
|
||||
|
||||
#else
|
||||
/* BYTE_ORDER != anything known */
|
||||
|
||||
#error BYTE_ORDER not defined as anything understood
|
||||
#endif /* BYTE_ORDER == PDP_ENDIAN */
|
||||
#endif /* BYTE_ORDER == BIG_ENDIAN */
|
||||
#endif /* BYTE_ORDER == LITTLE_ENDIAN */
|
||||
|
||||
#endif
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
/* --------------------------------------------------------------------- */
|
||||
int
|
||||
pqPutShort(int integer, FILE *f)
|
||||
{
|
||||
int retval = 0;
|
||||
u_short n,
|
||||
s;
|
||||
uint16 n;
|
||||
|
||||
s = integer;
|
||||
n = hton_s(s);
|
||||
if (fwrite(&n, sizeof(u_short), 1, f) != 1)
|
||||
retval = EOF;
|
||||
#ifdef FRONTEND
|
||||
n = htons((uint16)integer);
|
||||
#else
|
||||
n = ((PG_PROTOCOL_MAJOR(FrontendProtocol) == 0) ? hton_s(integer) : htons((uint16)integer));
|
||||
#endif
|
||||
|
||||
return retval;
|
||||
if (fwrite(&n, 2, 1, f) != 1)
|
||||
return EOF;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* --------------------------------------------------------------------- */
|
||||
int
|
||||
pqPutLong(int integer, FILE *f)
|
||||
{
|
||||
int retval = 0;
|
||||
uint32 n;
|
||||
uint32 n;
|
||||
|
||||
n = hton_l(integer);
|
||||
if (fwrite(&n, sizeof(uint32), 1, f) != 1)
|
||||
retval = EOF;
|
||||
#ifdef FRONTEND
|
||||
n = htonl((uint32)integer);
|
||||
#else
|
||||
n = ((PG_PROTOCOL_MAJOR(FrontendProtocol) == 0) ? hton_l(integer) : htonl((uint32)integer));
|
||||
#endif
|
||||
|
||||
return retval;
|
||||
if (fwrite(&n, 4, 1, f) != 1)
|
||||
return EOF;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* --------------------------------------------------------------------- */
|
||||
int
|
||||
pqGetShort(int *result, FILE *f)
|
||||
{
|
||||
int retval = 0;
|
||||
u_short n;
|
||||
uint16 n;
|
||||
|
||||
if (fread(&n, sizeof(u_short), 1, f) != 1)
|
||||
retval = EOF;
|
||||
if (fread(&n, 2, 1, f) != 1)
|
||||
return EOF;
|
||||
|
||||
*result = ntoh_s(n);
|
||||
return retval;
|
||||
#ifdef FRONTEND
|
||||
*result = (int)ntohs(n);
|
||||
#else
|
||||
*result = (int)((PG_PROTOCOL_MAJOR(FrontendProtocol) == 0) ? ntoh_s(n) : ntohs(n));
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* --------------------------------------------------------------------- */
|
||||
int
|
||||
pqGetLong(int *result, FILE *f)
|
||||
{
|
||||
int retval = 0;
|
||||
uint32 n;
|
||||
uint32 n;
|
||||
|
||||
if (fread(&n, sizeof(uint32), 1, f) != 1)
|
||||
retval = EOF;
|
||||
if (fread(&n, 4, 1, f) != 1)
|
||||
return EOF;
|
||||
|
||||
*result = ntoh_l(n);
|
||||
return retval;
|
||||
#ifdef FRONTEND
|
||||
*result = (int)ntohl(n);
|
||||
#else
|
||||
*result = (int)((PG_PROTOCOL_MAJOR(FrontendProtocol) == 0) ? ntoh_l(n) : ntohl(n));
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* --------------------------------------------------------------------- */
|
||||
/* pqGetNBytes: Read a chunk of exactly len bytes in buffer s.
|
||||
/* pqGetNBytes: Read a chunk of exactly len bytes in buffer s (which must be 1
|
||||
byte longer) and terminate it with a '\0'.
|
||||
Return 0 if ok.
|
||||
*/
|
||||
int
|
||||
pqGetNBytes(char *s, size_t len, FILE *f)
|
||||
{
|
||||
int cnt;
|
||||
int cnt;
|
||||
|
||||
if (f == NULL)
|
||||
return EOF;
|
||||
|
||||
cnt = fread(s, 1, len, f);
|
||||
s[cnt] = '\0';
|
||||
/* mjl: actually needs up to len+1 bytes, is this okay? XXX */
|
||||
|
||||
return (cnt == len) ? 0 : EOF;
|
||||
}
|
||||
@@ -126,7 +154,7 @@ int
|
||||
pqPutNBytes(const char *s, size_t len, FILE *f)
|
||||
{
|
||||
if (f == NULL)
|
||||
return 0;
|
||||
return EOF;
|
||||
|
||||
if (fwrite(s, 1, len, f) != len)
|
||||
return EOF;
|
||||
@@ -138,15 +166,27 @@ pqPutNBytes(const char *s, size_t len, FILE *f)
|
||||
int
|
||||
pqGetString(char *s, size_t len, FILE *f)
|
||||
{
|
||||
int c;
|
||||
int c;
|
||||
|
||||
if (f == NULL)
|
||||
return EOF;
|
||||
|
||||
while (len-- && (c = getc(f)) != EOF && c)
|
||||
*s++ = c;
|
||||
/*
|
||||
* Keep on reading until we get the terminating '\0' and discard those
|
||||
* bytes we don't have room for.
|
||||
*/
|
||||
|
||||
while ((c = getc(f)) != EOF && c != '\0')
|
||||
if (len > 1)
|
||||
{
|
||||
*s++ = c;
|
||||
len--;
|
||||
}
|
||||
|
||||
*s = '\0';
|
||||
/* mjl: actually needs up to len+1 bytes, is this okay? XXX */
|
||||
|
||||
if (c == EOF)
|
||||
return EOF;
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -183,5 +223,3 @@ pqPutByte(int c, FILE *f)
|
||||
|
||||
return (putc(c, f) == c) ? 0 : EOF;
|
||||
}
|
||||
|
||||
/* --------------------------------------------------------------------- */
|
||||
|
||||
@@ -8,36 +8,14 @@
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $Header: /cvsroot/pgsql/src/backend/libpq/Attic/pqpacket.c,v 1.12 1997/12/09 03:10:51 scrappy Exp $
|
||||
* $Header: /cvsroot/pgsql/src/backend/libpq/Attic/pqpacket.c,v 1.13 1998/01/26 01:41:12 scrappy Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
/* NOTES
|
||||
* This is the module that understands the lowest-level part
|
||||
* of the communication protocol. All of the trickiness in
|
||||
* this module is for making sure that non-blocking I/O in
|
||||
* the Postmaster works correctly. Check the notes in PacketRecv
|
||||
* on non-blocking I/O.
|
||||
*
|
||||
* Data Structures:
|
||||
* Port has two important functions. (1) It records the
|
||||
* sock/addr used in communication. (2) It holds partially
|
||||
* read in messages. This is especially important when
|
||||
* we haven't seen enough to construct a complete packet
|
||||
* header.
|
||||
*
|
||||
* PacketBuf -- None of the clients of this module should know
|
||||
* what goes into a packet hdr (although they know how big
|
||||
* it is). This routine is in charge of host to net order
|
||||
* conversion for headers. Data conversion is someone elses
|
||||
* responsibility.
|
||||
*
|
||||
* IMPORTANT: these routines are called by backends, clients, and
|
||||
* the Postmaster.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <unistd.h>
|
||||
#include <string.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/socket.h>
|
||||
#include <netdb.h>
|
||||
@@ -50,260 +28,158 @@
|
||||
#include <storage/ipc.h>
|
||||
#include <libpq/libpq.h>
|
||||
|
||||
|
||||
/*
|
||||
* PacketReceive -- receive a packet on a port.
|
||||
*
|
||||
* RETURNS: connection id of the packet sender, if one
|
||||
* is available.
|
||||
*
|
||||
* Set up a packet read for the postmaster event loop.
|
||||
*/
|
||||
int
|
||||
PacketReceive(Port *port, /* receive port */
|
||||
PacketBuf *buf, /* MAX_PACKET_SIZE-worth of buffer space */
|
||||
bool nonBlocking) /* NON_BLOCKING or BLOCKING i/o */
|
||||
|
||||
void PacketReceiveSetup(Packet *pkt, void (*iodone)(), char *arg)
|
||||
{
|
||||
PacketLen max_size = sizeof(PacketBuf);
|
||||
PacketLen cc; /* character count -- bytes recvd */
|
||||
PacketLen packetLen; /* remaining packet chars to read */
|
||||
Addr tmp; /* curr recv buf pointer */
|
||||
int hdrLen;
|
||||
int flag;
|
||||
int decr;
|
||||
pkt->nrtodo = sizeof (pkt->len);
|
||||
pkt->ptr = (char *)&pkt->len;
|
||||
pkt->iodone = iodone;
|
||||
pkt->arg = arg;
|
||||
pkt->state = ReadingPacketLength;
|
||||
}
|
||||
|
||||
hdrLen = sizeof(buf->len);
|
||||
|
||||
if (nonBlocking == NON_BLOCKING)
|
||||
/*
|
||||
* Read a packet fragment. Return STATUS_OK if the connection should stay
|
||||
* open.
|
||||
*/
|
||||
|
||||
int PacketReceiveFragment(Packet *pkt, int sock)
|
||||
{
|
||||
int got;
|
||||
|
||||
if ((got = read(sock,pkt->ptr,pkt->nrtodo)) > 0)
|
||||
{
|
||||
flag = MSG_PEEK;
|
||||
decr = 0;
|
||||
pkt->nrtodo -= got;
|
||||
pkt->ptr += got;
|
||||
|
||||
/* See if we have got what we need for the packet length. */
|
||||
|
||||
if (pkt->nrtodo == 0 && pkt->state == ReadingPacketLength)
|
||||
{
|
||||
pkt->len = ntohl(pkt->len);
|
||||
|
||||
if (pkt->len < sizeof (pkt->len) ||
|
||||
pkt->len > sizeof (pkt->len) + sizeof (pkt->pkt))
|
||||
{
|
||||
PacketSendError(pkt,"Invalid packet length");
|
||||
|
||||
return STATUS_OK;
|
||||
}
|
||||
|
||||
/* Set up for the rest of the packet. */
|
||||
|
||||
pkt->nrtodo = pkt->len - sizeof (pkt->len);
|
||||
pkt->ptr = (char *)&pkt->pkt;
|
||||
pkt->state = ReadingPacket;
|
||||
}
|
||||
|
||||
/* See if we have got what we need for the packet. */
|
||||
|
||||
if (pkt->nrtodo == 0 && pkt->state == ReadingPacket)
|
||||
{
|
||||
pkt->state = Idle;
|
||||
|
||||
/* Special case to close the connection. */
|
||||
|
||||
if (pkt->iodone == NULL)
|
||||
return STATUS_ERROR;
|
||||
|
||||
(*pkt->iodone)(pkt->arg, pkt->len - sizeof (pkt->len),
|
||||
(char *)&pkt->pkt);
|
||||
}
|
||||
|
||||
return STATUS_OK;
|
||||
}
|
||||
else
|
||||
|
||||
if (got == 0)
|
||||
return STATUS_ERROR;
|
||||
|
||||
if (errno == EINTR)
|
||||
return STATUS_OK;
|
||||
|
||||
fprintf(stderr, "read() system call failed\n");
|
||||
|
||||
return STATUS_ERROR;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Set up a packet write for the postmaster event loop.
|
||||
*/
|
||||
|
||||
void PacketSendSetup(Packet *pkt, int nbytes, void (*iodone)(), char *arg)
|
||||
{
|
||||
pkt->nrtodo = nbytes;
|
||||
pkt->ptr = (char *)&pkt->pkt;
|
||||
pkt->iodone = iodone;
|
||||
pkt->arg = arg;
|
||||
pkt->state = WritingPacket;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Write a packet fragment. Return STATUS_OK if the connection should stay
|
||||
* open.
|
||||
*/
|
||||
|
||||
int PacketSendFragment(Packet *pkt, int sock)
|
||||
{
|
||||
int done;
|
||||
|
||||
if ((done = write(sock,pkt->ptr,pkt->nrtodo)) > 0)
|
||||
{
|
||||
flag = 0;
|
||||
decr = hdrLen;
|
||||
pkt->nrtodo -= done;
|
||||
pkt->ptr += done;
|
||||
|
||||
/* See if we have written the whole packet. */
|
||||
|
||||
if (pkt->nrtodo == 0)
|
||||
{
|
||||
pkt->state = Idle;
|
||||
|
||||
/* Special case to close the connection. */
|
||||
|
||||
if (pkt->iodone == NULL)
|
||||
return STATUS_ERROR;
|
||||
|
||||
(*pkt->iodone)(pkt->arg);
|
||||
}
|
||||
|
||||
return STATUS_OK;
|
||||
}
|
||||
|
||||
if (done == 0)
|
||||
return STATUS_ERROR;
|
||||
|
||||
if (errno == EINTR)
|
||||
return STATUS_OK;
|
||||
|
||||
fprintf(stderr, "write() system call failed\n");
|
||||
|
||||
return STATUS_ERROR;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Send an error message from the postmaster to the frontend.
|
||||
*/
|
||||
|
||||
void PacketSendError(Packet *pkt, char *errormsg)
|
||||
{
|
||||
fprintf(stderr, "%s\n", errormsg);
|
||||
|
||||
pkt->pkt.em.data[0] = 'E';
|
||||
StrNCpy(&pkt->pkt.em.data[1], errormsg, sizeof (pkt->pkt.em.data) - 2);
|
||||
|
||||
/*
|
||||
* Assume port->nBytes is zero unless we were interrupted during
|
||||
* non-blocking I/O. This first recv() is to get the hdr information
|
||||
* so we know how many bytes to read. Life would be very complicated
|
||||
* if we read too much data (buffering).
|
||||
* The NULL i/o callback will cause the connection to be broken when
|
||||
* the error message has been sent.
|
||||
*/
|
||||
tmp = ((Addr) buf) + port->nBytes;
|
||||
|
||||
if (port->nBytes >= hdrLen)
|
||||
{
|
||||
packetLen = ntohl(buf->len) - port->nBytes;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* peeking into the incoming message */
|
||||
cc = recv(port->sock, (char *) &(buf->len), hdrLen, flag);
|
||||
if (cc < hdrLen)
|
||||
{
|
||||
/* if cc is negative, the system call failed */
|
||||
if (cc < 0)
|
||||
{
|
||||
return (STATUS_ERROR);
|
||||
}
|
||||
|
||||
/*
|
||||
* cc == 0 means the connection was broken at the other end.
|
||||
*/
|
||||
else if (!cc)
|
||||
{
|
||||
return (STATUS_INVALID);
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
/*
|
||||
* Worst case. We didn't even read in enough data to get
|
||||
* the header length. since we are using a data stream,
|
||||
* this happens only if the client is mallicious.
|
||||
*
|
||||
* Don't save the number of bytes we've read so far. Since we
|
||||
* only peeked at the incoming message, the kernel is
|
||||
* going to keep it for us.
|
||||
*/
|
||||
return (STATUS_NOT_DONE);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
/*
|
||||
* This is an attempt to shield the Postmaster from mallicious
|
||||
* attacks by placing tighter restrictions on the reported
|
||||
* packet length.
|
||||
*
|
||||
* Check for negative packet length
|
||||
*/
|
||||
if ((buf->len) <= 0)
|
||||
{
|
||||
return (STATUS_INVALID);
|
||||
}
|
||||
|
||||
/*
|
||||
* Check for oversize packet
|
||||
*/
|
||||
if ((ntohl(buf->len)) > max_size)
|
||||
{
|
||||
return (STATUS_INVALID);
|
||||
}
|
||||
|
||||
/*
|
||||
* great. got the header. now get the true length (including
|
||||
* header size).
|
||||
*/
|
||||
packetLen = ntohl(buf->len);
|
||||
|
||||
/*
|
||||
* if someone is sending us junk, close the connection
|
||||
*/
|
||||
if (packetLen > max_size)
|
||||
{
|
||||
port->nBytes = packetLen;
|
||||
return (STATUS_BAD_PACKET);
|
||||
}
|
||||
packetLen -= decr;
|
||||
tmp += decr - port->nBytes;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Now that we know how big it is, read the packet. We read the
|
||||
* entire packet, since the last call was just a peek.
|
||||
*/
|
||||
while (packetLen)
|
||||
{
|
||||
cc = read(port->sock, tmp, packetLen);
|
||||
if (cc < 0)
|
||||
return (STATUS_ERROR);
|
||||
|
||||
/*
|
||||
* cc == 0 means the connection was broken at the other end.
|
||||
*/
|
||||
else if (!cc)
|
||||
return (STATUS_INVALID);
|
||||
|
||||
/*
|
||||
fprintf(stderr,"expected packet of %d bytes, got %d bytes\n",
|
||||
packetLen, cc);
|
||||
*/
|
||||
tmp += cc;
|
||||
packetLen -= cc;
|
||||
|
||||
/* if non-blocking, we're done. */
|
||||
if (nonBlocking && packetLen)
|
||||
{
|
||||
port->nBytes += cc;
|
||||
return (STATUS_NOT_DONE);
|
||||
}
|
||||
}
|
||||
|
||||
port->nBytes = 0;
|
||||
return (STATUS_OK);
|
||||
PacketSendSetup(pkt, strlen(pkt->pkt.em.data) + 1, NULL, NULL);
|
||||
}
|
||||
|
||||
/*
|
||||
* PacketSend -- send a single-packet message.
|
||||
*
|
||||
* 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)
|
||||
{
|
||||
PacketLen doneLen;
|
||||
|
||||
Assert(!nonBlocking);
|
||||
Assert(buf);
|
||||
|
||||
doneLen = write(port->sock, buf, len);
|
||||
if (doneLen < len)
|
||||
{
|
||||
sprintf(PQerrormsg,
|
||||
"FATAL: PacketSend: couldn't send complete packet: errno=%d\n",
|
||||
errno);
|
||||
fputs(PQerrormsg, stderr);
|
||||
return (STATUS_ERROR);
|
||||
}
|
||||
|
||||
return (STATUS_OK);
|
||||
}
|
||||
|
||||
/*
|
||||
* StartupInfo2PacketBuf -
|
||||
* convert the fields of the StartupInfo to a PacketBuf
|
||||
*
|
||||
*/
|
||||
/* moved to src/libpq/fe-connect.c */
|
||||
/*
|
||||
PacketBuf*
|
||||
StartupInfo2PacketBuf(StartupInfo* s)
|
||||
{
|
||||
PacketBuf* res;
|
||||
char* tmp;
|
||||
|
||||
res = (PacketBuf*)palloc(sizeof(PacketBuf));
|
||||
res->len = htonl(sizeof(PacketBuf));
|
||||
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->execFile));
|
||||
|
||||
return res;
|
||||
}
|
||||
*/
|
||||
|
||||
/*
|
||||
* PacketBuf2StartupInfo -
|
||||
* convert the fields of the StartupInfo to a PacketBuf
|
||||
*
|
||||
*/
|
||||
/* moved to postmaster.c
|
||||
StartupInfo*
|
||||
PacketBuf2StartupInfo(PacketBuf* p)
|
||||
{
|
||||
StartupInfo* res;
|
||||
char* tmp;
|
||||
|
||||
res = (StartupInfo*)palloc(sizeof(StartupInfo));
|
||||
|
||||
res->database[0]='\0';
|
||||
res->user[0]='\0';
|
||||
res->options[0]='\0';
|
||||
res->execFile[0]='\0';
|
||||
res->tty[0]='\0';
|
||||
|
||||
tmp= p->data;
|
||||
strncpy(res->database,tmp,sizeof(res->database));
|
||||
tmp += sizeof(res->database);
|
||||
strncpy(res->user,tmp, sizeof(res->user));
|
||||
tmp += sizeof(res->user);
|
||||
strncpy(res->options,tmp, sizeof(res->options));
|
||||
tmp += sizeof(res->options);
|
||||
strncpy(res->execFile,tmp, sizeof(res->execFile));
|
||||
tmp += sizeof(res->execFile);
|
||||
strncpy(res->tty,tmp, sizeof(res->tty));
|
||||
|
||||
return res;
|
||||
}
|
||||
*/
|
||||
|
||||
Reference in New Issue
Block a user