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:
parent
91d983aa11
commit
d5bbe2aca5
|
@ -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;
|
||||
}
|
||||
*/
|
||||
|
|
|
@ -10,7 +10,7 @@
|
|||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $Header: /cvsroot/pgsql/src/backend/postmaster/postmaster.c,v 1.69 1998/01/25 05:13:35 momjian Exp $
|
||||
* $Header: /cvsroot/pgsql/src/backend/postmaster/postmaster.c,v 1.70 1998/01/26 01:41:15 scrappy Exp $
|
||||
*
|
||||
* NOTES
|
||||
*
|
||||
|
@ -102,7 +102,8 @@
|
|||
#endif
|
||||
#endif
|
||||
|
||||
#define LINGER_TIME 3
|
||||
#define INVALID_SOCK (-1)
|
||||
#define ARGV_SIZE 64
|
||||
|
||||
/*
|
||||
* Max time in seconds for socket to linger (close() to block) waiting
|
||||
|
@ -182,28 +183,24 @@ static int SendStop = 0;
|
|||
|
||||
static int NetServer = 0; /* if not zero, postmaster listen for
|
||||
* non-local connections */
|
||||
static int MultiplexedBackends = 0;
|
||||
static int MultiplexedBackendPort;
|
||||
|
||||
/*
|
||||
* postmaster.c - function prototypes
|
||||
*/
|
||||
static void pmdaemonize(void);
|
||||
static void
|
||||
ConnStartup(Port *port, int *status,
|
||||
char *errormsg, const int errormsg_len);
|
||||
static int ConnCreate(int serverFd, int *newFdP);
|
||||
static Port *ConnCreate(int serverFd);
|
||||
static void reset_shared(short port);
|
||||
static void pmdie(SIGNAL_ARGS);
|
||||
static void reaper(SIGNAL_ARGS);
|
||||
static void dumpstatus(SIGNAL_ARGS);
|
||||
static void CleanupProc(int pid, int exitstatus);
|
||||
static int DoExec(StartupInfo *packet, int portFd);
|
||||
static int DoExec(Port *port);
|
||||
static void ExitPostmaster(int status);
|
||||
static void usage(const char *);
|
||||
static int ServerLoop(void);
|
||||
static int BackendStartup(StartupInfo *packet, Port *port, int *pidPtr);
|
||||
static void send_error_reply(Port *port, const char *errormsg);
|
||||
static int BackendStartup(Port *port);
|
||||
static void readStartupPacket(char *arg, PacketLen len, char *pkt);
|
||||
static int initMasks(fd_set *rmask, fd_set *wmask);
|
||||
static void RandomSalt(char* salt);
|
||||
|
||||
extern char *optarg;
|
||||
|
@ -307,8 +304,7 @@ PostmasterMain(int argc, char *argv[])
|
|||
switch (opt)
|
||||
{
|
||||
case 'a':
|
||||
/* Set the authentication system. */
|
||||
be_setauthsvc(optarg);
|
||||
/* Can no longer set authentication method. */
|
||||
break;
|
||||
case 'B':
|
||||
|
||||
|
@ -354,8 +350,7 @@ PostmasterMain(int argc, char *argv[])
|
|||
NetServer = 1;
|
||||
break;
|
||||
case 'm':
|
||||
MultiplexedBackends = 1;
|
||||
MultiplexedBackendPort = atoi(optarg);
|
||||
/* Multiplexed backends no longer supported. */
|
||||
break;
|
||||
case 'M':
|
||||
|
||||
|
@ -501,13 +496,11 @@ static void
|
|||
usage(const char *progname)
|
||||
{
|
||||
fprintf(stderr, "usage: %s [options..]\n", progname);
|
||||
fprintf(stderr, "\t-a authsys\tdo/do not permit use of an authentication system\n");
|
||||
fprintf(stderr, "\t-B nbufs\tset number of shared buffers\n");
|
||||
fprintf(stderr, "\t-b backend\tuse a specific backend server executable\n");
|
||||
fprintf(stderr, "\t-d [1|2|3]\tset debugging level\n");
|
||||
fprintf(stderr, "\t-D datadir\tset data directory\n");
|
||||
fprintf(stderr, "\t-i \tlisten on TCP/IP sockets as well as Unix domain socket\n");
|
||||
fprintf(stderr, "\t-m \tstart up multiplexing backends\n");
|
||||
fprintf(stderr, "\t-n\t\tdon't reinitialize shared memory after abnormal exit\n");
|
||||
fprintf(stderr, "\t-o option\tpass 'option' to each backend servers\n");
|
||||
fprintf(stderr, "\t-p port\t\tspecify port for postmaster to listen on\n");
|
||||
|
@ -519,15 +512,9 @@ usage(const char *progname)
|
|||
static int
|
||||
ServerLoop(void)
|
||||
{
|
||||
fd_set rmask,
|
||||
basemask;
|
||||
int nSockets,
|
||||
nSelected,
|
||||
status,
|
||||
oldFd,
|
||||
newFd;
|
||||
Dlelem *next,
|
||||
*curr;
|
||||
fd_set readmask, writemask;
|
||||
int nSockets;
|
||||
Dlelem *curr;
|
||||
|
||||
/*
|
||||
* GH: For !HAVE_SIGPROCMASK (NEXTSTEP), TRH implemented an
|
||||
|
@ -541,16 +528,8 @@ ServerLoop(void)
|
|||
int orgsigmask = sigblock(0);
|
||||
|
||||
#endif
|
||||
FD_ZERO(&basemask);
|
||||
FD_SET(ServerSock_UNIX, &basemask);
|
||||
nSockets = ServerSock_UNIX;
|
||||
if (ServerSock_INET != INVALID_SOCK)
|
||||
{
|
||||
FD_SET(ServerSock_INET, &basemask);
|
||||
if (ServerSock_INET > ServerSock_UNIX)
|
||||
nSockets = ServerSock_INET;
|
||||
}
|
||||
nSockets++;
|
||||
|
||||
nSockets = initMasks(&readmask, &writemask);
|
||||
|
||||
#ifdef HAVE_SIGPROCMASK
|
||||
sigprocmask(0, 0, &oldsigmask);
|
||||
|
@ -559,17 +538,19 @@ ServerLoop(void)
|
|||
#endif
|
||||
for (;;)
|
||||
{
|
||||
Port *port;
|
||||
fd_set rmask, wmask;
|
||||
|
||||
#ifdef HAVE_SIGPROCMASK
|
||||
sigprocmask(SIG_SETMASK, &oldsigmask, 0);
|
||||
#else
|
||||
sigsetmask(orgsigmask);
|
||||
#endif
|
||||
newFd = -1;
|
||||
memmove((char *) &rmask, (char *) &basemask, sizeof(fd_set));
|
||||
if ((nSelected = select(nSockets, &rmask,
|
||||
(fd_set *) NULL,
|
||||
(fd_set *) NULL,
|
||||
(struct timeval *) NULL)) < 0)
|
||||
|
||||
memmove((char *) &rmask, (char *) &readmask, sizeof(fd_set));
|
||||
memmove((char *) &wmask, (char *) &writemask, sizeof(fd_set));
|
||||
if (select(nSockets, &rmask, &wmask, (fd_set *) NULL,
|
||||
(struct timeval *) NULL) < 0)
|
||||
{
|
||||
if (errno == EINTR)
|
||||
continue;
|
||||
|
@ -589,344 +570,209 @@ ServerLoop(void)
|
|||
#else
|
||||
sigblock(sigmask(SIGCHLD)); /* XXX[TRH] portability */
|
||||
#endif
|
||||
if (DebugLvl > 1)
|
||||
{
|
||||
fprintf(stderr, "%s: ServerLoop: %d sockets pending\n",
|
||||
progname, nSelected);
|
||||
}
|
||||
|
||||
/* new connection pending on our well-known port's socket */
|
||||
oldFd = -1;
|
||||
if (FD_ISSET(ServerSock_UNIX, &rmask))
|
||||
oldFd = ServerSock_UNIX;
|
||||
else if (ServerSock_INET != INVALID_SOCK &&
|
||||
FD_ISSET(ServerSock_INET, &rmask))
|
||||
oldFd = ServerSock_INET;
|
||||
if (oldFd >= 0)
|
||||
{
|
||||
|
||||
/*
|
||||
* connect and make an addition to PortList. If the
|
||||
* connection dies and we notice it, just forget about the
|
||||
* whole thing.
|
||||
*/
|
||||
if (ConnCreate(oldFd, &newFd) == STATUS_OK)
|
||||
{
|
||||
if (newFd >= nSockets)
|
||||
nSockets = newFd + 1;
|
||||
FD_SET(newFd, &rmask);
|
||||
FD_SET(newFd, &basemask);
|
||||
if (DebugLvl)
|
||||
fprintf(stderr, "%s: ServerLoop: connect on %d\n",
|
||||
progname, newFd);
|
||||
}
|
||||
else if (DebugLvl)
|
||||
fprintf(stderr,
|
||||
"%s: ServerLoop: connect failed: (%d) %s\n",
|
||||
progname, errno, strerror(errno));
|
||||
--nSelected;
|
||||
FD_CLR(oldFd, &rmask);
|
||||
}
|
||||
if (ServerSock_UNIX != INVALID_SOCK &&
|
||||
FD_ISSET(ServerSock_UNIX, &rmask) &&
|
||||
(port = ConnCreate(ServerSock_UNIX)) != NULL)
|
||||
PacketReceiveSetup(&port->pktInfo,
|
||||
readStartupPacket,
|
||||
(char *)port);
|
||||
|
||||
if (DebugLvl > 1)
|
||||
{
|
||||
fprintf(stderr, "%s: ServerLoop:\tnSelected=%d\n",
|
||||
progname, nSelected);
|
||||
curr = DLGetHead(PortList);
|
||||
while (curr)
|
||||
{
|
||||
Port *port = DLE_VAL(curr);
|
||||
if (ServerSock_INET != INVALID_SOCK &&
|
||||
FD_ISSET(ServerSock_INET, &rmask) &&
|
||||
(port = ConnCreate(ServerSock_INET)) != NULL)
|
||||
PacketReceiveSetup(&port->pktInfo,
|
||||
readStartupPacket,
|
||||
(char *)port);
|
||||
|
||||
fprintf(stderr, "%s: ServerLoop:\t\tport %d%s pending\n",
|
||||
progname, port->sock,
|
||||
FD_ISSET(port->sock, &rmask)
|
||||
? "" :
|
||||
" not");
|
||||
curr = DLGetSucc(curr);
|
||||
}
|
||||
}
|
||||
/* Build up new masks for select(). */
|
||||
|
||||
nSockets = initMasks(&readmask, &writemask);
|
||||
|
||||
curr = DLGetHead(PortList);
|
||||
|
||||
while (curr)
|
||||
{
|
||||
Port *port = (Port *) DLE_VAL(curr);
|
||||
int lastbytes = port->nBytes;
|
||||
int status = STATUS_OK;
|
||||
Dlelem *next;
|
||||
|
||||
if (FD_ISSET(port->sock, &rmask) && port->sock != newFd)
|
||||
if (FD_ISSET(port->sock, &rmask))
|
||||
{
|
||||
if (DebugLvl > 1)
|
||||
fprintf(stderr, "%s: ServerLoop:\t\thandling %d\n",
|
||||
fprintf(stderr, "%s: ServerLoop:\t\thandling reading %d\n",
|
||||
progname, port->sock);
|
||||
--nSelected;
|
||||
|
||||
if (PacketReceiveFragment(&port->pktInfo, port->sock) != STATUS_OK)
|
||||
status = STATUS_ERROR;
|
||||
}
|
||||
|
||||
if (FD_ISSET(port->sock, &wmask))
|
||||
{
|
||||
if (DebugLvl > 1)
|
||||
fprintf(stderr, "%s: ServerLoop:\t\thandling writing %d\n",
|
||||
progname, port->sock);
|
||||
|
||||
if (PacketSendFragment(&port->pktInfo, port->sock) != STATUS_OK)
|
||||
status = STATUS_ERROR;
|
||||
}
|
||||
|
||||
/* Get this before the connection might be closed. */
|
||||
|
||||
next = DLGetSucc(curr);
|
||||
|
||||
/*
|
||||
* If there is no error and no outstanding data transfer
|
||||
* going on, then the authentication handshake must be
|
||||
* complete to the postmaster's satisfaction. So,
|
||||
* start the backend.
|
||||
*/
|
||||
|
||||
if (status == STATUS_OK && port->pktInfo.state == Idle)
|
||||
{
|
||||
/*
|
||||
* Read the incoming packet into its packet buffer. Read
|
||||
* the connection id out of the packet so we know who the
|
||||
* packet is from.
|
||||
* If the backend start fails then keep the
|
||||
* connection open to report it. Otherwise,
|
||||
* pretend there is an error to close the
|
||||
* connection which will now be managed by the
|
||||
* backend.
|
||||
*/
|
||||
receive_again:
|
||||
status = PacketReceive(port, &port->buf, NON_BLOCKING);
|
||||
switch (status)
|
||||
{
|
||||
case STATUS_OK:
|
||||
/* Here is where we check for a USER login packet. If there is one, then
|
||||
* we must deterine whether the login has a password in pg_user. If so, send
|
||||
* back a salt to crypt() the password with. Otherwise, send an unsalt packet
|
||||
* back and read the real startup packet.
|
||||
*/
|
||||
if (ntohl(port->buf.msgtype) == STARTUP_USER_MSG) {
|
||||
PacketLen plen;
|
||||
|
||||
port->buf.msgtype = htonl(crypt_salt(port->buf.data));
|
||||
plen = sizeof(port->buf.len) + sizeof(port->buf.msgtype) + 2;
|
||||
port->buf.len = htonl(plen);
|
||||
RandomSalt(port->salt);
|
||||
memcpy((void*)port->buf.data, (void*)port->salt, 2);
|
||||
if (BackendStartup(port) != STATUS_OK)
|
||||
PacketSendError(&port->pktInfo,
|
||||
"Backend startup failed");
|
||||
else
|
||||
status = STATUS_ERROR;
|
||||
}
|
||||
|
||||
status = PacketSend(port, &port->buf, plen, BLOCKING);
|
||||
if (status != STATUS_OK)
|
||||
break;
|
||||
/* Close the connection if required. */
|
||||
|
||||
/* port->nBytes = 0; */
|
||||
goto receive_again;
|
||||
} else {
|
||||
int CSstatus; /* Completion status of
|
||||
* ConnStartup */
|
||||
char errormsg[200]; /* error msg from
|
||||
* ConnStartup */
|
||||
|
||||
ConnStartup(port, &CSstatus, errormsg, sizeof(errormsg));
|
||||
|
||||
if (CSstatus == STATUS_ERROR)
|
||||
send_error_reply(port, errormsg);
|
||||
ActiveBackends = TRUE;
|
||||
}
|
||||
/* FALLTHROUGH */
|
||||
case STATUS_INVALID:
|
||||
if (DebugLvl)
|
||||
fprintf(stderr, "%s: ServerLoop:\t\tdone with %d\n",
|
||||
progname, port->sock);
|
||||
break;
|
||||
case STATUS_BAD_PACKET:
|
||||
|
||||
/*
|
||||
* This is a bogus client, kill the connection and
|
||||
* forget the whole thing.
|
||||
*/
|
||||
if (DebugLvl)
|
||||
fprintf(stderr, "%s: ServerLoop:\t\tbad packet format (reported packet size of %d read on port %d\n", progname, port->nBytes, port->sock);
|
||||
break;
|
||||
case STATUS_NOT_DONE:
|
||||
if (DebugLvl)
|
||||
fprintf(stderr, "%s: ServerLoop:\t\tpartial packet (%d bytes actually read) on %d\n",
|
||||
progname, port->nBytes, port->sock);
|
||||
|
||||
/*
|
||||
* If we've received at least a PacketHdr's worth
|
||||
* of data and we're still receiving data each
|
||||
* time we read, we're ok. If the client gives us
|
||||
* less than a PacketHdr at the beginning, just
|
||||
* kill the connection and forget about the whole
|
||||
* thing.
|
||||
*/
|
||||
if (lastbytes < port->nBytes)
|
||||
{
|
||||
if (DebugLvl)
|
||||
fprintf(stderr, "%s: ServerLoop:\t\tpartial packet on %d ok\n",
|
||||
progname, port->sock);
|
||||
curr = DLGetSucc(curr);
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
case STATUS_ERROR: /* system call error - die */
|
||||
fprintf(stderr, "%s: ServerLoop:\t\terror receiving packet\n",
|
||||
progname);
|
||||
return (STATUS_ERROR);
|
||||
}
|
||||
FD_CLR(port->sock, &basemask);
|
||||
if (status != STATUS_OK)
|
||||
{
|
||||
StreamClose(port->sock);
|
||||
next = DLGetSucc(curr);
|
||||
DLRemove(curr);
|
||||
free(port);
|
||||
DLFreeElem(curr);
|
||||
curr = next;
|
||||
continue;
|
||||
}
|
||||
curr = DLGetSucc(curr);
|
||||
}
|
||||
Assert(nSelected == 0);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*
|
||||
ConnStartup: get the startup packet from the front end (client),
|
||||
authenticate the user, and start up a backend.
|
||||
|
||||
If all goes well, return *status == STATUS_OK.
|
||||
Otherwise, return *status == STATUS_ERROR and return a text string
|
||||
explaining why in the "errormsg_len" bytes at "errormsg",
|
||||
*/
|
||||
|
||||
static void
|
||||
ConnStartup(Port *port, int *status,
|
||||
char *errormsg, const int errormsg_len)
|
||||
{
|
||||
MsgType msgType;
|
||||
char namebuf[NAMEDATALEN];
|
||||
int pid;
|
||||
PacketBuf *p;
|
||||
StartupInfo sp;
|
||||
char *tmp;
|
||||
|
||||
p = &port->buf;
|
||||
|
||||
sp.database[0] = '\0';
|
||||
sp.user[0] = '\0';
|
||||
sp.options[0] = '\0';
|
||||
sp.execFile[0] = '\0';
|
||||
sp.tty[0] = '\0';
|
||||
|
||||
tmp = p->data;
|
||||
strncpy(sp.database, tmp, sizeof(sp.database));
|
||||
tmp += sizeof(sp.database);
|
||||
strncpy(sp.user, tmp, sizeof(sp.user));
|
||||
tmp += sizeof(sp.user);
|
||||
strncpy(sp.options, tmp, sizeof(sp.options));
|
||||
tmp += sizeof(sp.options);
|
||||
strncpy(sp.execFile, tmp, sizeof(sp.execFile));
|
||||
tmp += sizeof(sp.execFile);
|
||||
strncpy(sp.tty, tmp, sizeof(sp.tty));
|
||||
|
||||
msgType = (MsgType) ntohl(port->buf.msgtype);
|
||||
|
||||
StrNCpy(namebuf, sp.user, NAMEDATALEN);
|
||||
if (!namebuf[0])
|
||||
{
|
||||
strncpy(errormsg,
|
||||
"No Postgres username specified in startup packet.",
|
||||
errormsg_len);
|
||||
*status = STATUS_ERROR;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (be_recvauth(msgType, port, namebuf, &sp) != STATUS_OK)
|
||||
{
|
||||
char buffer[200 + sizeof(namebuf)];
|
||||
|
||||
sprintf(buffer,
|
||||
"Failed to authenticate client as Postgres user '%s' "
|
||||
"using %s: %s",
|
||||
namebuf, name_of_authentication_type(msgType), PQerrormsg);
|
||||
strncpy(errormsg, buffer, errormsg_len);
|
||||
*status = STATUS_ERROR;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (BackendStartup(&sp, port, &pid) != STATUS_OK)
|
||||
{
|
||||
strncpy(errormsg, "Startup (fork) of backend failed.",
|
||||
errormsg_len);
|
||||
*status = STATUS_ERROR;
|
||||
}
|
||||
else
|
||||
{
|
||||
errormsg[0] = '\0'; /* just for robustness */
|
||||
*status = STATUS_OK;
|
||||
/* Set the masks for this connection. */
|
||||
|
||||
if (nSockets <= port->sock)
|
||||
nSockets = port->sock + 1;
|
||||
|
||||
if (port->pktInfo.state == WritingPacket)
|
||||
FD_SET(port->sock, &writemask);
|
||||
else
|
||||
FD_SET(port->sock, &readmask);
|
||||
}
|
||||
|
||||
curr = next;
|
||||
}
|
||||
}
|
||||
if (*status == STATUS_ERROR)
|
||||
fprintf(stderr, "%s: ConnStartup: %s\n", progname, errormsg);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
send_error_reply: send a reply to the front end telling it that
|
||||
the connection was a bust, and why.
|
||||
* Initialise the read and write masks for select() for the well-known ports
|
||||
* we are listening on. Return the number of sockets to listen on.
|
||||
*/
|
||||
|
||||
"port" tells to whom and how to send the reply. "errormsg" is
|
||||
the string of text telling what the problem was.
|
||||
|
||||
It should be noted that we're executing a pretty messy protocol
|
||||
here. The postmaster does not reply when the connection is
|
||||
successful, but rather just hands the connection off to the
|
||||
backend and the backend waits for a query from the frontend.
|
||||
Thus, the frontend is not expecting any reply in regards to the
|
||||
connect request.
|
||||
|
||||
But when the connection fails, we send this reply that starts
|
||||
with "E". The frontend only gets this reply when it sends its
|
||||
first query and waits for the reply. Nobody receives that query,
|
||||
but this reply is already in the pipe, so that's what the
|
||||
frontend sees.
|
||||
|
||||
Note that the backend closes the socket immediately after sending
|
||||
the reply, so to give the frontend a fighting chance to see the
|
||||
error info, we set the socket to linger up to 3 seconds waiting
|
||||
for the frontend to retrieve the message. That's all the delay
|
||||
we can afford, since we have other clients to serve and the
|
||||
postmaster will be blocked the whole time. Also, if there is no
|
||||
message space in the socket for the reply (shouldn't be a
|
||||
problem) the postmaster will block until the frontend reads the
|
||||
reply.
|
||||
|
||||
*/
|
||||
|
||||
static void
|
||||
send_error_reply(Port *port, const char *errormsg)
|
||||
static int initMasks(fd_set *rmask, fd_set *wmask)
|
||||
{
|
||||
int rc; /* return code from write */
|
||||
char *reply;
|
||||
int nsocks = -1;
|
||||
|
||||
/*
|
||||
* The literal reply string we put into the socket. This is a pointer
|
||||
* to storage we malloc.
|
||||
*/
|
||||
const struct linger linger_parm = {true, LINGER_TIME};
|
||||
FD_ZERO(rmask);
|
||||
FD_ZERO(wmask);
|
||||
|
||||
/*
|
||||
* A parameter for setsockopt() that tells it to have close() block
|
||||
* for a while waiting for the frontend to read its outstanding
|
||||
* messages.
|
||||
*/
|
||||
if (ServerSock_UNIX != INVALID_SOCK)
|
||||
{
|
||||
FD_SET(ServerSock_UNIX, rmask);
|
||||
|
||||
reply = malloc(strlen(errormsg) + 10);
|
||||
if (ServerSock_UNIX > nsocks)
|
||||
nsocks = ServerSock_UNIX;
|
||||
}
|
||||
|
||||
sprintf(reply, "E%s", errormsg);
|
||||
if (ServerSock_INET != INVALID_SOCK)
|
||||
{
|
||||
FD_SET(ServerSock_INET, rmask);
|
||||
|
||||
rc = write(port->sock, (Addr) reply, strlen(reply) + 1);
|
||||
if (rc < 0)
|
||||
fprintf(stderr,
|
||||
"%s: ServerLoop:\t\t"
|
||||
"Failed to send error reply to front end\n",
|
||||
progname);
|
||||
else if (rc < strlen(reply) + 1)
|
||||
fprintf(stderr,
|
||||
"%s: ServerLoop:\t\t"
|
||||
"Only partial error reply sent to front end.\n",
|
||||
progname);
|
||||
if (ServerSock_INET > nsocks)
|
||||
nsocks = ServerSock_INET;
|
||||
}
|
||||
|
||||
free(reply);
|
||||
return (nsocks + 1);
|
||||
}
|
||||
|
||||
/*
|
||||
* Now we have to make sure frontend has a chance to see what we just
|
||||
* wrote.
|
||||
*/
|
||||
rc = setsockopt(port->sock, SOL_SOCKET, SO_LINGER,
|
||||
&linger_parm, sizeof(linger_parm));
|
||||
|
||||
/*
|
||||
* Called when the startup packet has been read.
|
||||
*/
|
||||
|
||||
static void readStartupPacket(char *arg, PacketLen len, char *pkt)
|
||||
{
|
||||
Port *port;
|
||||
StartupPacket *si;
|
||||
|
||||
port = (Port *)arg;
|
||||
si = (StartupPacket *)pkt;
|
||||
|
||||
/* At the moment the startup packet must be a fixed length. */
|
||||
|
||||
if (len != sizeof (StartupPacket))
|
||||
{
|
||||
PacketSendError(&port->pktInfo, "Invalid startup packet.");
|
||||
return;
|
||||
}
|
||||
|
||||
/* Get the parameters from the startup packet as C strings. */
|
||||
|
||||
StrNCpy(port->database, si->database, sizeof (port->database) - 1);
|
||||
StrNCpy(port->user, si->user, sizeof (port->user) - 1);
|
||||
StrNCpy(port->options, si->options, sizeof (port->options) - 1);
|
||||
StrNCpy(port->tty, si->tty, sizeof (port->tty) - 1);
|
||||
|
||||
/* The database defaults to the user name. */
|
||||
|
||||
if (port->database[0] == '\0')
|
||||
StrNCpy(port->database, si->user, sizeof (port->database) - 1);
|
||||
|
||||
/* Check we can handle the protocol the frontend is using. */
|
||||
|
||||
port->proto = ntohl(si->protoVersion);
|
||||
|
||||
if (PG_PROTOCOL_MAJOR(port->proto) < PG_PROTOCOL_MAJOR(PG_PROTOCOL_EARLIEST) ||
|
||||
PG_PROTOCOL_MAJOR(port->proto) > PG_PROTOCOL_MAJOR(PG_PROTOCOL_LATEST) ||
|
||||
(PG_PROTOCOL_MAJOR(port->proto) == PG_PROTOCOL_MAJOR(PG_PROTOCOL_LATEST) &&
|
||||
PG_PROTOCOL_MINOR(port->proto) > PG_PROTOCOL_MINOR(PG_PROTOCOL_LATEST)))
|
||||
{
|
||||
PacketSendError(&port->pktInfo, "Unsupported frontend protocol.");
|
||||
return;
|
||||
}
|
||||
|
||||
/* Check a user name was given. */
|
||||
|
||||
if (port->user[0] == '\0')
|
||||
{
|
||||
PacketSendError(&port->pktInfo,
|
||||
"No Postgres username specified in startup packet.");
|
||||
return;
|
||||
}
|
||||
|
||||
/* Start the authentication itself. */
|
||||
|
||||
be_recvauth(port);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* ConnCreate -- create a local connection data structure
|
||||
*/
|
||||
static int
|
||||
ConnCreate(int serverFd, int *newFdP)
|
||||
static Port *
|
||||
ConnCreate(int serverFd)
|
||||
{
|
||||
int status;
|
||||
Port *port;
|
||||
|
||||
|
||||
|
@ -937,18 +783,20 @@ ConnCreate(int serverFd, int *newFdP)
|
|||
ExitPostmaster(1);
|
||||
}
|
||||
|
||||
if ((status = StreamConnection(serverFd, port)) != STATUS_OK)
|
||||
if (StreamConnection(serverFd, port) != STATUS_OK)
|
||||
{
|
||||
StreamClose(port->sock);
|
||||
free(port);
|
||||
port = NULL;
|
||||
}
|
||||
else
|
||||
{
|
||||
DLAddHead(PortList, DLNewElem(port));
|
||||
*newFdP = port->sock;
|
||||
RandomSalt(port->salt);
|
||||
port->pktInfo.state = Idle;
|
||||
}
|
||||
|
||||
return (status);
|
||||
return port;
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -1125,9 +973,7 @@ CleanupProc(int pid,
|
|||
*
|
||||
*/
|
||||
static int
|
||||
BackendStartup(StartupInfo *packet, /* client's startup packet */
|
||||
Port *port,
|
||||
int *pidPtr)
|
||||
BackendStartup(Port *port)
|
||||
{
|
||||
Backend *bn; /* for backend cleanup */
|
||||
int pid,
|
||||
|
@ -1148,7 +994,7 @@ BackendStartup(StartupInfo *packet, /* client's startup packet */
|
|||
putenv(envEntry[0]);
|
||||
sprintf(envEntry[1], "POSTID=%d", NextBackendId);
|
||||
putenv(envEntry[1]);
|
||||
sprintf(envEntry[2], "PG_USER=%s", packet->user);
|
||||
sprintf(envEntry[2], "PG_USER=%s", port->user);
|
||||
putenv(envEntry[2]);
|
||||
if (!getenv("PGDATA"))
|
||||
{
|
||||
|
@ -1173,7 +1019,7 @@ BackendStartup(StartupInfo *packet, /* client's startup packet */
|
|||
|
||||
if ((pid = FORK()) == 0)
|
||||
{ /* child */
|
||||
if (DoExec(packet, port->sock))
|
||||
if (DoExec(port))
|
||||
fprintf(stderr, "%s child[%d]: BackendStartup: execv failed\n",
|
||||
progname, pid);
|
||||
/* use _exit to keep from double-flushing stdio */
|
||||
|
@ -1190,8 +1036,7 @@ BackendStartup(StartupInfo *packet, /* client's startup packet */
|
|||
|
||||
if (DebugLvl)
|
||||
fprintf(stderr, "%s: BackendStartup: pid %d user %s db %s socket %d\n",
|
||||
progname, pid, packet->user,
|
||||
(packet->database[0] == '\0' ? packet->user : packet->database),
|
||||
progname, pid, port->user, port->database,
|
||||
port->sock);
|
||||
|
||||
/* adjust backend counter */
|
||||
|
@ -1212,10 +1057,7 @@ BackendStartup(StartupInfo *packet, /* client's startup packet */
|
|||
bn->pid = pid;
|
||||
DLAddHead(BackendList, DLNewElem(bn));
|
||||
|
||||
if (MultiplexedBackends)
|
||||
MultiplexedBackendPort++;
|
||||
|
||||
*pidPtr = pid;
|
||||
ActiveBackends = TRUE;
|
||||
|
||||
return (STATUS_OK);
|
||||
}
|
||||
|
@ -1262,19 +1104,19 @@ split_opts(char **argv, int *argcp, char *s)
|
|||
* If execv() fails, return status.
|
||||
*/
|
||||
static int
|
||||
DoExec(StartupInfo *packet, int portFd)
|
||||
DoExec(Port *port)
|
||||
{
|
||||
char execbuf[MAXPATHLEN];
|
||||
char portbuf[ARGV_SIZE];
|
||||
char mbbuf[ARGV_SIZE];
|
||||
char debugbuf[ARGV_SIZE];
|
||||
char ttybuf[ARGV_SIZE + 1];
|
||||
char protobuf[ARGV_SIZE + 1];
|
||||
char argbuf[(2 * ARGV_SIZE) + 1];
|
||||
|
||||
/*
|
||||
* each argument takes at least three chars, so we can't have more
|
||||
* than ARGV_SIZE arguments in (2 * ARGV_SIZE) chars (i.e.,
|
||||
* packet->options plus ExtraOptions)...
|
||||
* port->options plus ExtraOptions)...
|
||||
*/
|
||||
char *av[ARGV_SIZE];
|
||||
char dbbuf[ARGV_SIZE + 1];
|
||||
|
@ -1304,34 +1146,30 @@ DoExec(StartupInfo *packet, int portFd)
|
|||
av[ac++] = "-Q";
|
||||
|
||||
/* Pass the requested debugging output file */
|
||||
if (packet->tty[0])
|
||||
if (port->tty[0])
|
||||
{
|
||||
strncpy(ttybuf, packet->tty, ARGV_SIZE);
|
||||
strncpy(ttybuf, port->tty, ARGV_SIZE);
|
||||
av[ac++] = "-o";
|
||||
av[ac++] = ttybuf;
|
||||
}
|
||||
|
||||
/* tell the multiplexed backend to start on a certain port */
|
||||
if (MultiplexedBackends)
|
||||
{
|
||||
sprintf(mbbuf, "-m %d", MultiplexedBackendPort);
|
||||
av[ac++] = mbbuf;
|
||||
}
|
||||
/* Tell the backend the descriptor of the fe/be socket */
|
||||
sprintf(portbuf, "-P%d", portFd);
|
||||
sprintf(portbuf, "-P%d", port->sock);
|
||||
av[ac++] = portbuf;
|
||||
|
||||
StrNCpy(argbuf, packet->options, ARGV_SIZE);
|
||||
StrNCpy(argbuf, port->options, ARGV_SIZE);
|
||||
strncat(argbuf, ExtraOptions, ARGV_SIZE);
|
||||
argbuf[(2 * ARGV_SIZE)] = '\0';
|
||||
split_opts(av, &ac, argbuf);
|
||||
|
||||
if (packet->database[0])
|
||||
StrNCpy(dbbuf, packet->database, ARGV_SIZE);
|
||||
else
|
||||
StrNCpy(dbbuf, packet->user, NAMEDATALEN);
|
||||
StrNCpy(dbbuf, port->database, ARGV_SIZE);
|
||||
av[ac++] = dbbuf;
|
||||
|
||||
/* Tell the backend what protocol the frontend is using. */
|
||||
|
||||
sprintf(protobuf, "-v %u", port->proto);
|
||||
av[ac++] = protobuf;
|
||||
|
||||
av[ac] = (char *) NULL;
|
||||
|
||||
if (DebugLvl > 1)
|
||||
|
@ -1375,10 +1213,7 @@ dumpstatus(SIGNAL_ARGS)
|
|||
Port *port = DLE_VAL(curr);
|
||||
|
||||
fprintf(stderr, "%s: dumpstatus:\n", progname);
|
||||
fprintf(stderr, "\tsock %d: nBytes=%d, laddr=0x%lx, raddr=0x%lx\n",
|
||||
port->sock, port->nBytes,
|
||||
(long int) port->laddr.in.sin_addr.s_addr,
|
||||
(long int) port->raddr.in.sin_addr.s_addr);
|
||||
fprintf(stderr, "\tsock %d\n", port->sock);
|
||||
curr = DLGetSucc(curr);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $Header: /cvsroot/pgsql/src/backend/tcop/dest.c,v 1.15 1997/12/06 22:57:02 momjian Exp $
|
||||
* $Header: /cvsroot/pgsql/src/backend/tcop/dest.c,v 1.16 1998/01/26 01:41:23 scrappy Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
|
@ -29,7 +29,7 @@
|
|||
#include "postgres.h"
|
||||
|
||||
#include "access/htup.h"
|
||||
#include "libpq/libpq-be.h"
|
||||
#include "libpq/libpq.h"
|
||||
#include "access/printtup.h"
|
||||
#include "utils/portal.h"
|
||||
#include "utils/palloc.h"
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $Header: /cvsroot/pgsql/src/backend/tcop/fastpath.c,v 1.11 1998/01/11 21:16:01 scrappy Exp $
|
||||
* $Header: /cvsroot/pgsql/src/backend/tcop/fastpath.c,v 1.12 1998/01/26 01:41:28 scrappy Exp $
|
||||
*
|
||||
* NOTES
|
||||
* This cruft is the server side of PQfn.
|
||||
|
@ -336,7 +336,7 @@ HandleFunctionRequest()
|
|||
else
|
||||
{ /* ... fixed */
|
||||
/* XXX cross our fingers and trust "argsize" */
|
||||
if (!(p = palloc(argsize)))
|
||||
if (!(p = palloc(argsize + 1)))
|
||||
{
|
||||
elog(ERROR, "HandleFunctionRequest: palloc failed");
|
||||
}
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $Header: /cvsroot/pgsql/src/backend/tcop/postgres.c,v 1.62 1998/01/25 05:14:18 momjian Exp $
|
||||
* $Header: /cvsroot/pgsql/src/backend/tcop/postgres.c,v 1.63 1998/01/26 01:41:35 scrappy Exp $
|
||||
*
|
||||
* NOTES
|
||||
* this is the "main" module of the postgres backend and
|
||||
|
@ -47,8 +47,8 @@
|
|||
#include "commands/async.h"
|
||||
#include "executor/execdebug.h"
|
||||
#include "executor/executor.h"
|
||||
#include "lib/dllist.h"
|
||||
#include "libpq/libpq.h"
|
||||
#include "libpq/libpq-be.h"
|
||||
#include "libpq/pqsignal.h"
|
||||
#include "nodes/pg_list.h"
|
||||
#include "nodes/print.h"
|
||||
|
@ -131,18 +131,6 @@ static int ShowPlannerStats;
|
|||
int ShowExecutorStats;
|
||||
FILE *StatFp;
|
||||
|
||||
typedef struct frontend
|
||||
{
|
||||
bool fn_connected;
|
||||
Port fn_port;
|
||||
FILE *fn_Pfin; /* the input fd */
|
||||
FILE *fn_Pfout; /* the output fd */
|
||||
bool fn_done; /* set after the frontend closes its
|
||||
* connection */
|
||||
} FrontEnd;
|
||||
|
||||
static Dllist *frontendList;
|
||||
|
||||
/* ----------------
|
||||
* people who want to use EOF should #define DONTUSENEWLINE in
|
||||
* tcop/tcopdebug.h
|
||||
|
@ -188,8 +176,8 @@ int _exec_repeat_ = 1;
|
|||
* ----------------------------------------------------------------
|
||||
*/
|
||||
static char InteractiveBackend(char *inBuf);
|
||||
static char SocketBackend(char *inBuf, bool multiplexedBackend);
|
||||
static char ReadCommand(char *inBuf, bool multiplexedBackend);
|
||||
static char SocketBackend(char *inBuf);
|
||||
static char ReadCommand(char *inBuf);
|
||||
|
||||
|
||||
/* ----------------------------------------------------------------
|
||||
|
@ -305,7 +293,7 @@ InteractiveBackend(char *inBuf)
|
|||
*/
|
||||
|
||||
static char
|
||||
SocketBackend(char *inBuf, bool multiplexedBackend)
|
||||
SocketBackend(char *inBuf)
|
||||
{
|
||||
char qtype[2];
|
||||
char result = '\0';
|
||||
|
@ -321,12 +309,7 @@ SocketBackend(char *inBuf, bool multiplexedBackend)
|
|||
* when front-end applications quits/dies
|
||||
* ------------
|
||||
*/
|
||||
if (multiplexedBackend)
|
||||
{
|
||||
return 'X';
|
||||
}
|
||||
else
|
||||
exitpg(0);
|
||||
exitpg(0);
|
||||
}
|
||||
|
||||
switch (*qtype)
|
||||
|
@ -380,10 +363,10 @@ SocketBackend(char *inBuf, bool multiplexedBackend)
|
|||
* ----------------
|
||||
*/
|
||||
static char
|
||||
ReadCommand(char *inBuf, bool multiplexedBackend)
|
||||
ReadCommand(char *inBuf)
|
||||
{
|
||||
if (IsUnderPostmaster || multiplexedBackend)
|
||||
return SocketBackend(inBuf, multiplexedBackend);
|
||||
if (IsUnderPostmaster)
|
||||
return SocketBackend(inBuf);
|
||||
else
|
||||
return InteractiveBackend(inBuf);
|
||||
}
|
||||
|
@ -793,7 +776,7 @@ static void
|
|||
usage(char *progname)
|
||||
{
|
||||
fprintf(stderr,
|
||||
"Usage: %s [-B nbufs] [-d lvl] ] [-f plantype] \t[-m portno] [\t -o filename]\n",
|
||||
"Usage: %s [-B nbufs] [-d lvl] ] [-f plantype] \t[-v protocol] [\t -o filename]\n",
|
||||
progname);
|
||||
fprintf(stderr, "\t[-P portno] [-t tracetype] [-x opttype] [-bCEiLFNopQSs] [dbname]\n");
|
||||
fprintf(stderr, " b: consider bushy plan trees during optimization\n");
|
||||
|
@ -809,7 +792,6 @@ usage(char *progname)
|
|||
fprintf(stderr, " K: set locking debug level [0|1|2]\n");
|
||||
#endif
|
||||
fprintf(stderr, " L: turn off locking\n");
|
||||
fprintf(stderr, " m: set up a listening backend at portno to support multiple front-ends\n");
|
||||
fprintf(stderr, " M: start as postmaster\n");
|
||||
fprintf(stderr, " N: don't use newline as query delimiter\n");
|
||||
fprintf(stderr, " o: send stdout and stderr to given filename \n");
|
||||
|
@ -820,6 +802,7 @@ usage(char *progname)
|
|||
fprintf(stderr, " s: show stats after each query\n");
|
||||
fprintf(stderr, " t: trace component execution times\n");
|
||||
fprintf(stderr, " T: execute all possible plans for each query\n");
|
||||
fprintf(stderr, " v: set protocol version being used by frontend\n");
|
||||
fprintf(stderr, " x: control expensive function optimization\n");
|
||||
}
|
||||
|
||||
|
@ -845,24 +828,6 @@ PostgresMain(int argc, char *argv[])
|
|||
char parser_input[MAX_PARSE_BUFFER];
|
||||
char *userName;
|
||||
|
||||
bool multiplexedBackend;
|
||||
char *hostName; /* the host name of the backend server */
|
||||
int serverSock;
|
||||
int serverPortnum = 0;
|
||||
int nSelected; /* number of descriptors ready from
|
||||
* select(); */
|
||||
int maxFd = 0; /* max file descriptor + 1 */
|
||||
fd_set rmask,
|
||||
basemask;
|
||||
FrontEnd *newFE,
|
||||
*currentFE = NULL;
|
||||
int numFE = 0; /* keep track of number of active
|
||||
* frontends */
|
||||
Port *newPort;
|
||||
int newFd;
|
||||
Dlelem *curr;
|
||||
int status;
|
||||
|
||||
char *DBDate = NULL;
|
||||
extern int optind;
|
||||
extern char *optarg;
|
||||
|
@ -906,7 +871,6 @@ PostgresMain(int argc, char *argv[])
|
|||
* get hostname is either the environment variable PGHOST or NULL
|
||||
* NULL means Unix-socket only
|
||||
*/
|
||||
hostName = getenv("PGHOST");
|
||||
DataDir = getenv("PGDATA");
|
||||
/*
|
||||
* Try to get initial values for date styles and formats.
|
||||
|
@ -933,9 +897,8 @@ PostgresMain(int argc, char *argv[])
|
|||
else if (strcasecmp(DBDate, "EURO") == 0)
|
||||
EuroDates = TRUE;
|
||||
}
|
||||
multiplexedBackend = false;
|
||||
|
||||
while ((flag = getopt(argc, argv, "B:bCD:d:Eef:iK:Lm:MNo:P:pQS:st:x:F"))
|
||||
while ((flag = getopt(argc, argv, "B:bCD:d:Eef:iK:Lm:MNo:P:pQS:st:v:x:F"))
|
||||
!= EOF)
|
||||
switch (flag)
|
||||
{
|
||||
|
@ -1051,16 +1014,7 @@ PostgresMain(int argc, char *argv[])
|
|||
break;
|
||||
|
||||
case 'm':
|
||||
|
||||
/*
|
||||
* start up a listening backend that can respond to
|
||||
* multiple front-ends. (Note: all the front-end
|
||||
* connections are still connected to a single-threaded
|
||||
* backend. Requests are FCFS. Everything is in one
|
||||
* transaction
|
||||
*/
|
||||
multiplexedBackend = true;
|
||||
serverPortnum = atoi(optarg);
|
||||
/* Multiplexed backends are no longer supported. */
|
||||
break;
|
||||
case 'M':
|
||||
exit(PostmasterMain(argc, argv));
|
||||
|
@ -1162,6 +1116,10 @@ PostgresMain(int argc, char *argv[])
|
|||
}
|
||||
break;
|
||||
|
||||
case 'v':
|
||||
FrontendProtocol = (ProtocolVersion)atoi(optarg);
|
||||
break;
|
||||
|
||||
case 'x':
|
||||
#if 0 /* planner/xfunc.h */
|
||||
|
||||
|
@ -1267,7 +1225,6 @@ PostgresMain(int argc, char *argv[])
|
|||
printf("\tsortmem = %d\n", SortMem);
|
||||
|
||||
printf("\tquery echo = %c\n", EchoQuery ? 't' : 'f');
|
||||
printf("\tmultiplexed backend? = %c\n", multiplexedBackend ? 't' : 'f');
|
||||
printf("\tDatabaseName = [%s]\n", DBName);
|
||||
puts("\t----------------\n");
|
||||
}
|
||||
|
@ -1285,53 +1242,8 @@ PostgresMain(int argc, char *argv[])
|
|||
Portfd = open(NULL_DEV, O_RDWR, 0666);
|
||||
}
|
||||
pq_init(Portfd);
|
||||
}
|
||||
|
||||
if (multiplexedBackend)
|
||||
{
|
||||
if (serverPortnum == 0 ||
|
||||
StreamServerPort(hostName, serverPortnum, &serverSock) != STATUS_OK)
|
||||
{
|
||||
fprintf(stderr, "Postgres: cannot create stream port %d\n", serverPortnum);
|
||||
exit(1);
|
||||
}
|
||||
/*
|
||||
{
|
||||
char buf[100];
|
||||
sprintf(buf, "stream port %d created, socket = %d\n", serverPortnum, serverSock);
|
||||
puts(buf);
|
||||
}
|
||||
*/
|
||||
FD_ZERO(&rmask);
|
||||
FD_ZERO(&basemask);
|
||||
FD_SET(serverSock, &basemask);
|
||||
|
||||
frontendList = DLNewList();
|
||||
/* add the original FrontEnd to the list */
|
||||
if (IsUnderPostmaster == true)
|
||||
{
|
||||
FrontEnd *fe = malloc(sizeof(FrontEnd));
|
||||
|
||||
FD_SET(Portfd, &basemask);
|
||||
maxFd = Max(serverSock, Portfd) + 1;
|
||||
|
||||
fe->fn_connected = true;
|
||||
fe->fn_Pfin = Pfin;
|
||||
fe->fn_Pfout = Pfout;
|
||||
fe->fn_done = false;
|
||||
(fe->fn_port).sock = Portfd;
|
||||
DLAddHead(frontendList, DLNewElem(fe));
|
||||
numFE++;
|
||||
}
|
||||
else
|
||||
{
|
||||
numFE = 1;
|
||||
maxFd = serverSock + 1;
|
||||
}
|
||||
}
|
||||
|
||||
if (IsUnderPostmaster || multiplexedBackend)
|
||||
whereToSendOutput = Remote;
|
||||
}
|
||||
else
|
||||
whereToSendOutput = Debug;
|
||||
|
||||
|
@ -1381,7 +1293,7 @@ PostgresMain(int argc, char *argv[])
|
|||
if (IsUnderPostmaster == false)
|
||||
{
|
||||
puts("\nPOSTGRES backend interactive interface");
|
||||
puts("$Revision: 1.62 $ $Date: 1998/01/25 05:14:18 $");
|
||||
puts("$Revision: 1.63 $ $Date: 1998/01/26 01:41:35 $");
|
||||
}
|
||||
|
||||
/* ----------------
|
||||
|
@ -1395,106 +1307,13 @@ PostgresMain(int argc, char *argv[])
|
|||
|
||||
for (;;)
|
||||
{
|
||||
|
||||
if (multiplexedBackend)
|
||||
{
|
||||
if (numFE == 0)
|
||||
break;
|
||||
|
||||
memmove((char *) &rmask, (char *) &basemask, sizeof(fd_set));
|
||||
nSelected = select(maxFd, &rmask, 0, 0, 0);
|
||||
|
||||
if (nSelected < 0)
|
||||
{
|
||||
|
||||
if (errno == EINTR)
|
||||
continue;
|
||||
fprintf(stderr, "postgres: multiplexed backend select failed\n");
|
||||
exitpg(1);
|
||||
}
|
||||
if (FD_ISSET(serverSock, &rmask))
|
||||
{
|
||||
/* new connection pending on our well-known port's socket */
|
||||
newFE = (FrontEnd *) malloc(sizeof(FrontEnd));
|
||||
MemSet(newFE, 0, sizeof(FrontEnd));
|
||||
newFE->fn_connected = false;
|
||||
newFE->fn_done = false;
|
||||
newPort = &(newFE->fn_port);
|
||||
if (StreamConnection(serverSock, newPort) != STATUS_OK)
|
||||
{
|
||||
StreamClose(newPort->sock);
|
||||
newFd = -1;
|
||||
}
|
||||
else
|
||||
{
|
||||
DLAddHead(frontendList, DLNewElem(newFE));
|
||||
numFE++;
|
||||
newFd = newPort->sock;
|
||||
if (newFd >= maxFd)
|
||||
maxFd = newFd + 1;
|
||||
FD_SET(newFd, &rmask);
|
||||
FD_SET(newFd, &basemask);
|
||||
--nSelected;
|
||||
FD_CLR(serverSock, &rmask);
|
||||
}
|
||||
continue;
|
||||
} /* if FD_ISSET(serverSock) */
|
||||
|
||||
/*
|
||||
* if we get here, it means that the serverSocket was not the
|
||||
* one selected. Instead, one of the front ends was selected.
|
||||
* find which one
|
||||
*/
|
||||
curr = DLGetHead(frontendList);
|
||||
while (curr)
|
||||
{
|
||||
FrontEnd *fe = (FrontEnd *) DLE_VAL(curr);
|
||||
Port *port = &(fe->fn_port);
|
||||
|
||||
/* this is lifted from postmaster.c */
|
||||
if (FD_ISSET(port->sock, &rmask))
|
||||
{
|
||||
if (fe->fn_connected == false)
|
||||
{
|
||||
/* we have a message from a new frontEnd */
|
||||
status = PacketReceive(port, &port->buf, NON_BLOCKING);
|
||||
if (status == STATUS_OK)
|
||||
{
|
||||
fe->fn_connected = true;
|
||||
pq_init(port->sock);
|
||||
fe->fn_Pfin = Pfin;
|
||||
fe->fn_Pfout = Pfout;
|
||||
}
|
||||
else
|
||||
fprintf(stderr, "Multiplexed backend: error in reading packets from %d\n", port->sock);
|
||||
}
|
||||
else
|
||||
/* we have a query from an existing, active FrontEnd */
|
||||
{
|
||||
Pfin = fe->fn_Pfin;
|
||||
Pfout = fe->fn_Pfout;
|
||||
currentFE = fe;
|
||||
}
|
||||
if (fe->fn_done)
|
||||
{
|
||||
Dlelem *c = curr;
|
||||
|
||||
curr = DLGetSucc(curr);
|
||||
DLRemove(c);
|
||||
}
|
||||
break;
|
||||
}
|
||||
else
|
||||
curr = DLGetSucc(curr);
|
||||
}
|
||||
}
|
||||
/* ----------------
|
||||
* (1) read a command.
|
||||
* ----------------
|
||||
*/
|
||||
MemSet(parser_input, 0, MAX_PARSE_BUFFER);
|
||||
|
||||
firstchar = ReadCommand(parser_input, multiplexedBackend);
|
||||
firstchar = ReadCommand(parser_input);
|
||||
/* process the command */
|
||||
switch (firstchar)
|
||||
{
|
||||
|
@ -1564,12 +1383,6 @@ PostgresMain(int argc, char *argv[])
|
|||
*/
|
||||
case 'X':
|
||||
IsEmptyQuery = true;
|
||||
if (multiplexedBackend)
|
||||
{
|
||||
FD_CLR(currentFE->fn_port.sock, &basemask);
|
||||
currentFE->fn_done = true;
|
||||
numFE--;
|
||||
}
|
||||
pq_close();
|
||||
break;
|
||||
|
||||
|
@ -1596,7 +1409,7 @@ PostgresMain(int argc, char *argv[])
|
|||
}
|
||||
else
|
||||
{
|
||||
if (IsUnderPostmaster || multiplexedBackend)
|
||||
if (IsUnderPostmaster)
|
||||
NullCommand(Remote);
|
||||
}
|
||||
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $Header: /cvsroot/pgsql/src/backend/utils/init/globals.c,v 1.18 1998/01/25 05:14:42 momjian Exp $
|
||||
* $Header: /cvsroot/pgsql/src/backend/utils/init/globals.c,v 1.19 1998/01/26 01:41:42 scrappy Exp $
|
||||
*
|
||||
* NOTES
|
||||
* Globals used all over the place should be declared here and not
|
||||
|
@ -32,9 +32,10 @@
|
|||
#include "storage/sinvaladt.h"
|
||||
#include "storage/lmgr.h"
|
||||
#include "utils/elog.h"
|
||||
|
||||
#include "libpq/pqcomm.h"
|
||||
#include "catalog/catname.h"
|
||||
|
||||
ProtocolVersion FrontendProtocol = PG_PROTOCOL_LATEST;
|
||||
int Portfd = -1;
|
||||
int Noversion = 0;
|
||||
int Quiet = 1;
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
*
|
||||
* Copyright (c) 1994, Regents of the University of California
|
||||
*
|
||||
* $Id: c.h,v 1.28 1998/01/24 22:47:43 momjian Exp $
|
||||
* $Id: c.h,v 1.29 1998/01/26 01:41:49 scrappy Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
|
@ -204,21 +204,23 @@ typedef char *Pointer;
|
|||
|
||||
/*
|
||||
* intN --
|
||||
* Signed integer, AT LEAST N BITS IN SIZE,
|
||||
* used for numerical computations.
|
||||
* Signed integer, EXACTLY N BITS IN SIZE,
|
||||
* used for numerical computations and the
|
||||
* frontend/backend protocol.
|
||||
*/
|
||||
typedef signed char int8; /* >= 8 bits */
|
||||
typedef signed short int16; /* >= 16 bits */
|
||||
typedef signed int int32; /* >= 32 bits */
|
||||
typedef signed char int8; /* == 8 bits */
|
||||
typedef signed short int16; /* == 16 bits */
|
||||
typedef signed int int32; /* == 32 bits */
|
||||
|
||||
/*
|
||||
* uintN --
|
||||
* Unsigned integer, AT LEAST N BITS IN SIZE,
|
||||
* used for numerical computations.
|
||||
* Unsigned integer, EXACTLY N BITS IN SIZE,
|
||||
* used for numerical computations and the
|
||||
* frontend/backend protocol.
|
||||
*/
|
||||
typedef unsigned char uint8; /* >= 8 bits */
|
||||
typedef unsigned short uint16; /* >= 16 bits */
|
||||
typedef unsigned int uint32; /* >= 32 bits */
|
||||
typedef unsigned char uint8; /* == 8 bits */
|
||||
typedef unsigned short uint16; /* == 16 bits */
|
||||
typedef unsigned int uint32; /* == 32 bits */
|
||||
|
||||
/*
|
||||
* floatN --
|
||||
|
|
|
@ -6,40 +6,22 @@
|
|||
*
|
||||
* Copyright (c) 1994, Regents of the University of California
|
||||
*
|
||||
* $Id: auth.h,v 1.7 1997/09/08 21:52:28 momjian Exp $
|
||||
* $Id: auth.h,v 1.8 1998/01/26 01:42:05 scrappy Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
#ifndef AUTH_H
|
||||
#define AUTH_H
|
||||
|
||||
#include <libpq/pqcomm.h>
|
||||
#include "libpq/libpq-be.h"
|
||||
|
||||
/*----------------------------------------------------------------
|
||||
* Common routines and definitions
|
||||
*----------------------------------------------------------------
|
||||
*/
|
||||
|
||||
/* what we call "no authentication system" */
|
||||
#define UNAUTHNAME "unauth"
|
||||
|
||||
/* what a frontend uses by default */
|
||||
#if !defined(KRB4) && !defined(KRB5)
|
||||
#define DEFAULT_CLIENT_AUTHSVC UNAUTHNAME
|
||||
#else /* KRB4 || KRB5 */
|
||||
#define DEFAULT_CLIENT_AUTHSVC "kerberos"
|
||||
#endif /* KRB4 || KRB5 */
|
||||
|
||||
extern int fe_sendauth(MsgType msgtype, Port *port, char *hostname);
|
||||
extern void fe_setauthsvc(char *name);
|
||||
extern MsgType fe_getauthsvc();
|
||||
extern char *fe_getauthname(void);
|
||||
extern int be_recvauth(MsgType msgtype, Port *port, char *username, StartupInfo *sp);
|
||||
extern void be_setauthsvc(char *name);
|
||||
|
||||
/* the value that matches any dbName value when doing
|
||||
host based authentication*/
|
||||
#define ALL_DBNAME "*"
|
||||
void be_recvauth(Port *port);
|
||||
void auth_failed(Port *port);
|
||||
|
||||
#define PG_KRB4_VERSION "PGVER4.1" /* at most KRB_SENDAUTH_VLEN chars */
|
||||
#define PG_KRB5_VERSION "PGVER5.1"
|
||||
|
|
|
@ -9,7 +9,7 @@
|
|||
#ifndef PG_CRYPT_H
|
||||
#define PG_CRYPT_H
|
||||
|
||||
#include <libpq/pqcomm.h>
|
||||
#include <libpq/libpq-be.h>
|
||||
|
||||
#define CRYPT_PWD_FILE "pg_pwd"
|
||||
#define CRYPT_PWD_FILE_SEPCHAR "'\\t'"
|
||||
|
@ -21,7 +21,9 @@ extern int pwd_cache_count;
|
|||
|
||||
extern char* crypt_getpwdfilename(void);
|
||||
extern char* crypt_getpwdreloadfilename(void);
|
||||
#ifdef 0
|
||||
extern MsgType crypt_salt(const char* user);
|
||||
#endif
|
||||
extern int crypt_verify(Port* port, const char* user, const char* pgpass);
|
||||
|
||||
#endif
|
||||
|
|
|
@ -4,14 +4,17 @@
|
|||
* Interface to hba.c
|
||||
*
|
||||
*
|
||||
* $Id: hba.h,v 1.6 1998/01/24 22:49:15 momjian Exp $
|
||||
* $Id: hba.h,v 1.7 1998/01/26 01:42:15 scrappy Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
#ifndef HBA_H
|
||||
#define HBA_H
|
||||
|
||||
#include <libpq/pqcomm.h>
|
||||
#include <netinet/in.h>
|
||||
|
||||
#include "libpq/libpq-be.h"
|
||||
|
||||
|
||||
#define CONF_FILE "pg_hba.conf"
|
||||
/* Name of the config file */
|
||||
|
@ -28,7 +31,7 @@
|
|||
#define MAX_TOKEN 80
|
||||
/* Maximum size of one token in the configuration file */
|
||||
|
||||
#define USERMAP_NAME_SIZE 16 /* Max size of a usermap name */
|
||||
#define MAX_AUTH_ARG 80 /* Max size of an authentication arg */
|
||||
|
||||
#define IDENT_PORT 113
|
||||
/* Standard TCP port number for Ident service. Assigned by IANA */
|
||||
|
@ -36,18 +39,19 @@
|
|||
#define IDENT_USERNAME_MAX 512
|
||||
/* Max size of username ident server can return */
|
||||
|
||||
enum Userauth
|
||||
{
|
||||
Trust, Ident,
|
||||
Password
|
||||
};
|
||||
typedef enum UserAuth {
|
||||
uaReject,
|
||||
uaKrb4,
|
||||
uaKrb5,
|
||||
uaTrust,
|
||||
uaIdent,
|
||||
uaPassword,
|
||||
uaCrypt
|
||||
} UserAuth;
|
||||
|
||||
extern int hba_recvauth(const Port *port, const char database[], const char user[],
|
||||
const char DataDir[]);
|
||||
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);
|
||||
int hba_getauthmethod(SockAddr *raddr, char *database, char *auth_arg,
|
||||
UserAuth *auth_method);
|
||||
int authident(struct sockaddr_in *raddr, struct sockaddr_in *laddr,
|
||||
const char postgres_username[], const char auth_arg[]);
|
||||
|
||||
#endif
|
||||
|
|
|
@ -7,45 +7,126 @@
|
|||
*
|
||||
* Copyright (c) 1994, Regents of the University of California
|
||||
*
|
||||
* $Id: libpq-be.h,v 1.8 1998/01/24 22:49:18 momjian Exp $
|
||||
* $Id: libpq-be.h,v 1.9 1998/01/26 01:42:17 scrappy Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
#ifndef LIBPQ_BE_H
|
||||
#define LIBPQ_BE_H
|
||||
|
||||
#include <access/htup.h>
|
||||
#include <access/tupdesc.h>
|
||||
#include <libpq/libpq.h>
|
||||
#include <stdio.h>
|
||||
#include <sys/types.h>
|
||||
|
||||
/* ----------------
|
||||
* include stuff common to fe and be
|
||||
* ----------------
|
||||
#include "libpq/pqcomm.h"
|
||||
#include "libpq/hba.h"
|
||||
|
||||
|
||||
/* Protocol v0 password packet. */
|
||||
|
||||
typedef struct PasswordPacketV0 {
|
||||
uint32 unused;
|
||||
char data[288]; /* User and password as strings. */
|
||||
} PasswordPacketV0;
|
||||
|
||||
|
||||
/*
|
||||
* Password packet. The length of the password can be changed without
|
||||
* affecting anything.
|
||||
*/
|
||||
|
||||
typedef struct PasswordPacket {
|
||||
char passwd[100]; /* The password. */
|
||||
} PasswordPacket;
|
||||
|
||||
|
||||
/* ----------------
|
||||
* declarations for backend libpq support routines
|
||||
* ----------------
|
||||
/* Error message packet. */
|
||||
|
||||
typedef struct ErrorMessagePacket {
|
||||
char data[1 + 100]; /* 'E' + the message. */
|
||||
} ErrorMessagePacket;
|
||||
|
||||
|
||||
/* Authentication request packet. */
|
||||
|
||||
typedef struct AuthRequestPacket {
|
||||
char data[1 + sizeof (AuthRequest) + 2]; /* 'R' + the request + optional salt. */
|
||||
} AuthRequestPacket;
|
||||
|
||||
|
||||
/* These are used by the packet handling routines. */
|
||||
|
||||
typedef enum {
|
||||
Idle,
|
||||
ReadingPacketLength,
|
||||
ReadingPacket,
|
||||
WritingPacket
|
||||
} PacketState;
|
||||
|
||||
typedef struct Packet {
|
||||
PacketState state; /* What's in progress. */
|
||||
PacketLen len; /* Actual length */
|
||||
int nrtodo; /* Bytes still to transfer */
|
||||
char *ptr; /* Buffer pointer */
|
||||
void (*iodone)(); /* I/O complete callback */
|
||||
char *arg; /* Argument to callback */
|
||||
|
||||
/* A union of all the different packets. */
|
||||
|
||||
union {
|
||||
/* These are outgoing so have no packet length prepended. */
|
||||
|
||||
ErrorMessagePacket em;
|
||||
AuthRequestPacket ar;
|
||||
|
||||
/* These are incoming and have a packet length prepended. */
|
||||
|
||||
StartupPacket si;
|
||||
PasswordPacketV0 pwv0;
|
||||
PasswordPacket pw;
|
||||
} pkt;
|
||||
} Packet;
|
||||
|
||||
|
||||
/*
|
||||
* This is used by the postmaster in its communication with frontends. It is
|
||||
* contains all state information needed during this communication before the
|
||||
* backend is run.
|
||||
*/
|
||||
|
||||
typedef struct Port {
|
||||
int sock; /* File descriptor */
|
||||
Packet pktInfo; /* For the packet handlers */
|
||||
SockAddr laddr; /* local addr (us) */
|
||||
SockAddr raddr; /* remote addr (them) */
|
||||
char salt[2]; /* Password salt */
|
||||
|
||||
/* in be-dumpdata.c */
|
||||
extern void be_portalinit(void);
|
||||
extern void be_portalpush(PortalEntry *entry);
|
||||
extern PortalEntry *be_portalpop(void);
|
||||
extern PortalEntry *be_currentportal(void);
|
||||
extern PortalEntry *be_newportal(void);
|
||||
extern void be_typeinit(PortalEntry *entry, TupleDesc attrs,
|
||||
int natts);
|
||||
extern void be_printtup(HeapTuple tuple, TupleDesc typeinfo);
|
||||
/*
|
||||
* Information that needs to be held during the fe/be authentication
|
||||
* handshake.
|
||||
*/
|
||||
|
||||
ProtocolVersion proto;
|
||||
char database[SM_DATABASE + 1];
|
||||
char user[SM_USER + 1];
|
||||
char options[SM_OPTIONS + 1];
|
||||
char tty[SM_TTY + 1];
|
||||
char auth_arg[MAX_AUTH_ARG];
|
||||
UserAuth auth_method;
|
||||
} Port;
|
||||
|
||||
|
||||
/* in be-pqexec.c */
|
||||
extern char * PQfn(int fnid, int *result_buf, int result_len, int result_is_int,
|
||||
PQArgBlock *args, int nargs);
|
||||
extern char *PQexec(char *query);
|
||||
extern int pqtest_PQexec(char *q);
|
||||
extern int pqtest_PQfn(char *q);
|
||||
extern int32 pqtest(struct varlena * vlena);
|
||||
extern FILE *Pfout, *Pfin;
|
||||
extern int PQAsyncNotifyWaiting;
|
||||
extern ProtocolVersion FrontendProtocol;
|
||||
|
||||
|
||||
/*
|
||||
* prototypes for functions in pqpacket.c
|
||||
*/
|
||||
void PacketReceiveSetup(Packet *pkt, void (*iodone)(), char *arg);
|
||||
int PacketReceiveFragment(Packet *pkt, int sock);
|
||||
void PacketSendSetup(Packet *pkt, int nbytes, void (*iodone)(), char *arg);
|
||||
int PacketSendFragment(Packet *pkt, int sock);
|
||||
void PacketSendError(Packet *pkt, char *errormsg);
|
||||
|
||||
#endif /* LIBPQ_BE_H */
|
||||
|
|
|
@ -6,20 +6,19 @@
|
|||
*
|
||||
* Copyright (c) 1994, Regents of the University of California
|
||||
*
|
||||
* $Id: libpq.h,v 1.9 1998/01/24 22:49:21 momjian Exp $
|
||||
*
|
||||
* NOTES
|
||||
* This file contains definitions for structures and
|
||||
* externs for functions used by both frontend applications
|
||||
* and the POSTGRES backend. See the files libpq-fe.h and
|
||||
* libpq-be.h for frontend/backend specific information
|
||||
* $Id: libpq.h,v 1.10 1998/01/26 01:42:18 scrappy Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
#ifndef LIBPQ_H
|
||||
#define LIBPQ_H
|
||||
|
||||
#include <libpq/pqcomm.h>
|
||||
#include <netinet/in.h>
|
||||
|
||||
#include "libpq/libpq-be.h"
|
||||
#include "access/htup.h"
|
||||
#include "access/tupdesc.h"
|
||||
|
||||
|
||||
/* ----------------
|
||||
* PQArgBlock --
|
||||
|
@ -228,6 +227,27 @@ extern int pbuf_findFnumber(GroupBuffer *group, char *field_name);
|
|||
extern void pbuf_checkFnumber(GroupBuffer *group, int field_number);
|
||||
extern char *pbuf_findFname(GroupBuffer *group, int field_number);
|
||||
|
||||
/* in be-dumpdata.c */
|
||||
extern void be_portalinit(void);
|
||||
extern void be_portalpush(PortalEntry *entry);
|
||||
extern PortalEntry *be_portalpop(void);
|
||||
extern PortalEntry *be_currentportal(void);
|
||||
extern PortalEntry *be_newportal(void);
|
||||
extern void
|
||||
be_typeinit(PortalEntry *entry, TupleDesc attrs,
|
||||
int natts);
|
||||
extern void be_printtup(HeapTuple tuple, TupleDesc typeinfo);
|
||||
|
||||
|
||||
/* in be-pqexec.c */
|
||||
extern char *
|
||||
PQfn(int fnid, int *result_buf, int result_len, int result_is_int,
|
||||
PQArgBlock *args, int nargs);
|
||||
extern char *PQexec(char *query);
|
||||
extern int pqtest_PQexec(char *q);
|
||||
extern int pqtest_PQfn(char *q);
|
||||
extern int32 pqtest(struct varlena * vlena);
|
||||
|
||||
/*
|
||||
* prototypes for functions in pqcomm.c
|
||||
*/
|
||||
|
|
|
@ -1,13 +1,6 @@
|
|||
#ifndef PASSWORD_H
|
||||
#define PASSWORD_H
|
||||
|
||||
#include <libpq/hba.h>
|
||||
#include <libpq/pqcomm.h>
|
||||
|
||||
#define PWFILE_NAME_SIZE USERMAP_NAME_SIZE
|
||||
|
||||
int
|
||||
verify_password(char *user, char *password, Port *port,
|
||||
char *database, char *DataDir);
|
||||
int verify_password(char *auth_arg, char *user, char *password);
|
||||
|
||||
#endif
|
||||
|
|
|
@ -1,15 +1,12 @@
|
|||
/*-------------------------------------------------------------------------
|
||||
*
|
||||
* pqcomm.h--
|
||||
* Parameters for the communication module
|
||||
* Definitions common to frontends and backends.
|
||||
*
|
||||
*
|
||||
* Copyright (c) 1994, Regents of the University of California
|
||||
*
|
||||
* $Id: pqcomm.h,v 1.18 1998/01/24 22:49:23 momjian Exp $
|
||||
*
|
||||
* NOTES
|
||||
* Some of this should move to libpq.h
|
||||
* $Id: pqcomm.h,v 1.19 1998/01/26 01:42:21 scrappy Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
|
@ -18,134 +15,105 @@
|
|||
|
||||
#include <stdio.h>
|
||||
#include <sys/types.h>
|
||||
#include <netinet/in.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/un.h>
|
||||
#include <netinet/in.h>
|
||||
|
||||
#include "c.h"
|
||||
|
||||
|
||||
/* Define a generic socket address type. */
|
||||
|
||||
typedef union SockAddr {
|
||||
struct sockaddr sa;
|
||||
struct sockaddr_in in;
|
||||
struct sockaddr_un un;
|
||||
} SockAddr;
|
||||
|
||||
|
||||
/* Configure the UNIX socket address for the well known port. */
|
||||
|
||||
#define UNIXSOCK_PATH(sun,port) \
|
||||
(sprintf((sun).sun_path, "/tmp/.s.PGSQL.%d", (port)) + \
|
||||
sizeof ((sun).sun_family))
|
||||
|
||||
|
||||
/*
|
||||
* startup msg parameters: path length, argument string length
|
||||
* These manipulate the frontend/backend protocol version number.
|
||||
*
|
||||
* The major number should be incremented for incompatible changes. The minor
|
||||
* number should be incremented for compatible changes (eg. additional
|
||||
* functionality).
|
||||
*
|
||||
* If a backend supports version m.n of the protocol it must actually support
|
||||
* versions m.0..n]. Backend support for version m-1 can be dropped after a
|
||||
* `reasonable' length of time.
|
||||
*
|
||||
* A frontend isn't required to support anything other than the current
|
||||
* version.
|
||||
*/
|
||||
#define PATH_SIZE 64
|
||||
#define ARGV_SIZE 64
|
||||
|
||||
#define UNIXSOCK_PATH(sun,port) \
|
||||
sprintf(sun.sun_path,"/tmp/.s.PGSQL.%d",port) + sizeof(sun.sun_family) + 1;
|
||||
#define PG_PROTOCOL_MAJOR(v) ((v) >> 16)
|
||||
#define PG_PROTOCOL_MINOR(v) ((v) & 0x0000ffff)
|
||||
#define PG_PROTOCOL(m,n) (((m) << 16) | (n))
|
||||
|
||||
/* The earliest and latest frontend/backend protocol version supported. */
|
||||
|
||||
/* The various kinds of startup messages are for the various kinds of
|
||||
user authentication systems. In the beginning, there was only
|
||||
STARTUP_MSG and all connections were unauthenticated. Now, there are
|
||||
several choices of authentication method (the client picks one, but
|
||||
the server needn't necessarily accept it). So now, the STARTUP_MSG
|
||||
message means to start either an unauthenticated or a host-based
|
||||
authenticated connection, depending on what the server prefers. This
|
||||
is possible because the protocol between server and client is the same
|
||||
in both cases (basically, no negotiation is required at all).
|
||||
*/
|
||||
|
||||
typedef enum _MsgType
|
||||
{
|
||||
ACK_MSG = 0, /* acknowledge a message */
|
||||
ERROR_MSG = 1, /* error response to client from server */
|
||||
RESET_MSG = 2, /* client must reset connection */
|
||||
PRINT_MSG = 3, /* tuples for client from server */
|
||||
NET_ERROR = 4, /* error in net system call */
|
||||
FUNCTION_MSG = 5, /* fastpath call (unused) */
|
||||
QUERY_MSG = 6, /* client query to server */
|
||||
STARTUP_MSG = 7, /* initialize a connection with a backend */
|
||||
DUPLICATE_MSG = 8, /* duplicate msg arrived (errors msg only) */
|
||||
INVALID_MSG = 9, /* for some control functions */
|
||||
STARTUP_KRB4_MSG = 10, /* krb4 session follows startup packet */
|
||||
STARTUP_KRB5_MSG = 11, /* krb5 session follows startup packet */
|
||||
STARTUP_HBA_MSG = 12, /* use host-based authentication */
|
||||
STARTUP_UNAUTH_MSG = 13, /* use unauthenticated connection */
|
||||
STARTUP_PASSWORD_MSG = 14, /* use plaintext password authentication */
|
||||
/* The following three are not really a named authentication method
|
||||
* since the front end has no choice in choosing the method. The
|
||||
* backend sends the SALT/UNSALT messages back to the frontend after
|
||||
* the USER login has been given to the backend.
|
||||
*/
|
||||
STARTUP_CRYPT_MSG = 15, /* use crypt()'ed password authentication */
|
||||
STARTUP_USER_MSG = 16, /* send user name to check pg_user for password */
|
||||
STARTUP_SALT_MSG = 17, /* frontend should crypt the password it sends */
|
||||
STARTUP_UNSALT_MSG = 18 /* frontend should NOT crypt the password it sends */
|
||||
/* insert new values here -- DO NOT REORDER OR DELETE ENTRIES */
|
||||
/* also change LAST_AUTHENTICATION_TYPE below and add to the */
|
||||
/* authentication_type_name[] array in pqcomm.c */
|
||||
} MsgType;
|
||||
|
||||
#define LAST_AUTHENTICATION_TYPE 14
|
||||
|
||||
typedef char *Addr;
|
||||
typedef int PacketLen; /* packet length */
|
||||
|
||||
|
||||
typedef struct StartupInfo
|
||||
{
|
||||
/* PacketHdr hdr; */
|
||||
char database[PATH_SIZE]; /* database name */
|
||||
char user[NAMEDATALEN]; /* user name */
|
||||
char options[ARGV_SIZE]; /* possible additional args */
|
||||
char execFile[ARGV_SIZE]; /* possible backend to use */
|
||||
char tty[PATH_SIZE]; /* possible tty for debug output */
|
||||
} StartupInfo;
|
||||
|
||||
/* amount of available data in a packet buffer */
|
||||
#define MESSAGE_SIZE sizeof(StartupInfo)
|
||||
|
||||
/* I/O can be blocking or non-blocking */
|
||||
#define BLOCKING (FALSE)
|
||||
#define NON_BLOCKING (TRUE)
|
||||
|
||||
/* a PacketBuf gets shipped from client to server so be careful
|
||||
of differences in representation.
|
||||
Be sure to use htonl() and ntohl() on the len and msgtype fields! */
|
||||
typedef struct PacketBuf
|
||||
{
|
||||
int len;
|
||||
MsgType msgtype;
|
||||
char data[MESSAGE_SIZE];
|
||||
} PacketBuf;
|
||||
|
||||
/* update the conversion routines
|
||||
StartupInfo2PacketBuf() and PacketBuf2StartupInfo() (decl. below)
|
||||
if StartupInfo or PacketBuf structs ever change */
|
||||
#define PG_PROTOCOL_EARLIEST PG_PROTOCOL(0,0)
|
||||
#define PG_PROTOCOL_LATEST PG_PROTOCOL(1,0)
|
||||
|
||||
/*
|
||||
* socket descriptor port
|
||||
* we need addresses of both sides to do authentication calls
|
||||
* All packets sent to the postmaster start with the length. This is omitted
|
||||
* from the different packet definitions specified below.
|
||||
*/
|
||||
typedef struct Port
|
||||
{
|
||||
int sock; /* file descriptor */
|
||||
int mask; /* select mask */
|
||||
int nBytes; /* nBytes read in so far */
|
||||
/* local addr (us) */
|
||||
union { struct sockaddr_in in; struct sockaddr_un un; } laddr;
|
||||
/* remote addr (them) */
|
||||
union { struct sockaddr_in in; struct sockaddr_un un; } raddr;
|
||||
/*
|
||||
* PacketBufId id;
|
||||
*//* id of packet buf currently in use */
|
||||
PacketBuf buf; /* stream implementation (curr pack buf) */
|
||||
char salt[2];
|
||||
} Port;
|
||||
|
||||
/* invalid socket descriptor */
|
||||
#define INVALID_SOCK (-1)
|
||||
typedef uint32 PacketLen;
|
||||
|
||||
#define INVALID_ID (-1)
|
||||
#define MAX_CONNECTIONS 10
|
||||
#define N_PACK_BUFS 20
|
||||
|
||||
/*
|
||||
* Startup message parameters sizes. These must not be changed without changing
|
||||
* the protcol version. These are all strings that are '\0' terminated only if
|
||||
* there is room.
|
||||
*/
|
||||
|
||||
/* no multi-packet messages yet */
|
||||
#define MAX_PACKET_BACKLOG 1
|
||||
#define SM_DATABASE 64
|
||||
#define SM_USER 32
|
||||
#define SM_OPTIONS 64
|
||||
#define SM_UNUSED 64
|
||||
#define SM_TTY 64
|
||||
|
||||
#define DEFAULT_STRING ""
|
||||
typedef uint32 ProtocolVersion; /* Fe/Be protocol version nr. */
|
||||
|
||||
typedef struct StartupPacket {
|
||||
ProtocolVersion protoVersion; /* Protocol version */
|
||||
char database[SM_DATABASE]; /* Database name */
|
||||
char user[SM_USER]; /* User name */
|
||||
char options[SM_OPTIONS]; /* Optional additional args */
|
||||
char unused[SM_UNUSED]; /* Unused */
|
||||
char tty[SM_TTY]; /* Tty for debug output */
|
||||
} StartupPacket;
|
||||
|
||||
|
||||
/* These are the authentication requests sent by the backend. */
|
||||
|
||||
#define AUTH_REQ_OK 0 /* User is authenticated */
|
||||
#define AUTH_REQ_KRB4 1 /* Kerberos V4 */
|
||||
#define AUTH_REQ_KRB5 2 /* Kerberos V5 */
|
||||
#define AUTH_REQ_PASSWORD 3 /* Password */
|
||||
#define AUTH_REQ_CRYPT 4 /* Encrypted password */
|
||||
|
||||
typedef uint32 AuthRequest;
|
||||
|
||||
|
||||
/* This next section is to maintain compatibility with protocol v0.0. */
|
||||
|
||||
#define STARTUP_MSG 7 /* Initialise a connection */
|
||||
#define STARTUP_KRB4_MSG 10 /* krb4 session follows */
|
||||
#define STARTUP_KRB5_MSG 11 /* krb5 session follows */
|
||||
#define STARTUP_PASSWORD_MSG 14 /* Password follows */
|
||||
|
||||
typedef ProtocolVersion MsgType;
|
||||
|
||||
extern FILE *Pfout,
|
||||
*Pfin;
|
||||
extern int PQAsyncNotifyWaiting;
|
||||
|
||||
/* in pqcompriv.c */
|
||||
int pqGetShort(int *, FILE *);
|
||||
|
@ -160,15 +128,4 @@ int pqPutNBytes(const char *, size_t, FILE *);
|
|||
int pqPutString(const char *, FILE *);
|
||||
int pqPutByte(int, FILE *);
|
||||
|
||||
/*
|
||||
* prototypes for functions in pqpacket.c
|
||||
*/
|
||||
extern int PacketReceive(Port *port, PacketBuf *buf, char nonBlocking);
|
||||
extern int PacketSend(Port *port, PacketBuf *buf,
|
||||
PacketLen len, char nonBlocking);
|
||||
|
||||
/* extern PacketBuf* StartupInfo2PacketBuf(StartupInfo*); */
|
||||
/* extern StartupInfo* PacketBuf2StartupInfo(PacketBuf*); */
|
||||
extern char *name_of_authentication_type(int type);
|
||||
|
||||
#endif /* PQCOMM_H */
|
||||
|
|
|
@ -7,10 +7,13 @@
|
|||
#
|
||||
#
|
||||
# IDENTIFICATION
|
||||
# $Header: /cvsroot/pgsql/src/interfaces/libpq/Attic/Makefile.in,v 1.4 1998/01/17 23:39:11 scrappy Exp $
|
||||
# $Header: /cvsroot/pgsql/src/interfaces/libpq/Attic/Makefile.in,v 1.5 1998/01/26 01:42:24 scrappy Exp $
|
||||
#
|
||||
#-------------------------------------------------------------------------
|
||||
|
||||
SO_MAJOR_VERSION=1
|
||||
SO_MINOR_VERSION=1
|
||||
|
||||
SRCDIR= ../..
|
||||
include $(SRCDIR)/Makefile.global
|
||||
|
||||
|
@ -19,7 +22,7 @@ INCLUDE_OPT= -I$(SRCDIR)/include -I$(SRCDIR)/backend
|
|||
|
||||
PORTNAME=@PORTNAME@
|
||||
|
||||
CFLAGS+= $(INCLUDE_OPT)
|
||||
CFLAGS+= $(INCLUDE_OPT) -DFRONTEND
|
||||
|
||||
ifdef KRBVERS
|
||||
CFLAGS+= $(KRBFLAGS)
|
||||
|
@ -34,20 +37,20 @@ install-shlib-dep :=
|
|||
ifeq ($(PORTNAME), linux)
|
||||
ifdef LINUX_ELF
|
||||
install-shlib-dep := install-shlib
|
||||
shlib := libpq.so.1
|
||||
shlib := libpq.so.$(SO_MAJOR_VERSION).$(SO_MINOR_VERSION)
|
||||
LDFLAGS_SL = -shared
|
||||
CFLAGS += $(CFLAGS_SL)
|
||||
endif
|
||||
endif
|
||||
ifeq ($(PORTNAME), bsd)
|
||||
install-shlib-dep := install-shlib
|
||||
shlib := libpq.so.1.0
|
||||
shlib := libpq.so.$(SO_MAJOR_VERSION).$(SO_MINOR_VERSION)
|
||||
LDFLAGS_SL = -x -Bshareable -Bforcearchive
|
||||
CFLAGS += $(CFLAGS_SL)
|
||||
endif
|
||||
ifeq ($(PORTNAME), i386_solaris)
|
||||
install-shlib-dep := install-shlib
|
||||
shlib := libpq.so.1
|
||||
shlib := libpq.so.$(SO_MAJOR_VERSION).$(SO_MINOR_VERSION)
|
||||
LDFLAGS_SL = -G -z text
|
||||
CFLAGS += $(CFLAGS_SL)
|
||||
endif
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $Header: /cvsroot/pgsql/src/interfaces/libpq/fe-auth.c,v 1.12 1997/12/04 00:28:08 scrappy Exp $
|
||||
* $Header: /cvsroot/pgsql/src/interfaces/libpq/fe-auth.c,v 1.13 1998/01/26 01:42:25 scrappy Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
|
@ -42,6 +42,11 @@
|
|||
#include "fe-auth.h"
|
||||
#include "fe-connect.h"
|
||||
|
||||
#ifdef HAVE_CRYPT_H
|
||||
#include <crypt.h>
|
||||
#endif
|
||||
|
||||
|
||||
/*----------------------------------------------------------------
|
||||
* common definitions for generic fe/be routines
|
||||
*----------------------------------------------------------------
|
||||
|
@ -457,49 +462,49 @@ pg_krb5_sendauth(const char *PQerrormsg, int sock,
|
|||
#endif /* KRB5 */
|
||||
|
||||
static int
|
||||
pg_password_sendauth(Port *port, const char *user, const char *password)
|
||||
pg_password_sendauth(PGconn *conn, const char *password, AuthRequest areq)
|
||||
{
|
||||
PacketBuf buf;
|
||||
char *tmp;
|
||||
/* Encrypt the password if needed. */
|
||||
|
||||
buf.len = htonl(sizeof(PacketBuf));
|
||||
buf.msgtype = STARTUP_PASSWORD_MSG;
|
||||
buf.data[0] = '\0';
|
||||
if (areq == AUTH_REQ_CRYPT)
|
||||
password = crypt(password, conn->salt);
|
||||
|
||||
tmp = buf.data;
|
||||
strncpy(tmp, user, strlen(user) + 1);
|
||||
tmp += strlen(user) + 1;
|
||||
strncpy(tmp, password, strlen(password) + 1);
|
||||
|
||||
return packetSend(port, &buf, sizeof(PacketBuf), BLOCKING);
|
||||
return packetSend(conn, password, strlen(password) + 1);
|
||||
}
|
||||
|
||||
/*
|
||||
* fe_sendauth -- client demux routine for outgoing authentication information
|
||||
*/
|
||||
int
|
||||
fe_sendauth(MsgType msgtype, Port *port, const char *hostname,
|
||||
const char *user, const char *password, const char *PQerrormsg)
|
||||
fe_sendauth(AuthRequest areq, PGconn *conn, const char *hostname,
|
||||
const char *password, const char *PQerrormsg)
|
||||
{
|
||||
switch (msgtype)
|
||||
switch (areq)
|
||||
{
|
||||
case AUTH_REQ_OK:
|
||||
break;
|
||||
|
||||
case AUTH_REQ_KRB4:
|
||||
#ifdef KRB4
|
||||
case STARTUP_KRB4_MSG:
|
||||
if (pg_krb4_sendauth(PQerrormsg, port->sock, &port->laddr,
|
||||
&port->raddr,
|
||||
if (pg_krb4_sendauth(PQerrormsg, conn->sock, &conn->laddr.in,
|
||||
&conn->raddr.in,
|
||||
hostname) != STATUS_OK)
|
||||
{
|
||||
(void) sprintf(PQerrormsg,
|
||||
"fe_sendauth: krb4 authentication failed\n");
|
||||
/* fputs(PQerrormsg, stderr); */
|
||||
return (STATUS_ERROR);
|
||||
}
|
||||
break;
|
||||
#else
|
||||
(void)sprintf(PQerrormsg,
|
||||
"fe_sendauth: krb4 authentication not supported\n");
|
||||
return (STATUS_ERROR);
|
||||
#endif
|
||||
|
||||
case AUTH_REQ_KRB5:
|
||||
#ifdef KRB5
|
||||
case STARTUP_KRB5_MSG:
|
||||
if (pg_krb5_sendauth(PQerrormsg, port->sock, &port->laddr,
|
||||
&port->raddr,
|
||||
if (pg_krb5_sendauth(PQerrormsg, conn->sock, &conn->laddr.in,
|
||||
&conn->raddr.in,
|
||||
hostname) != STATUS_OK)
|
||||
{
|
||||
(void) sprintf(PQerrormsg,
|
||||
|
@ -507,15 +512,29 @@ fe_sendauth(MsgType msgtype, Port *port, const char *hostname,
|
|||
return (STATUS_ERROR);
|
||||
}
|
||||
break;
|
||||
#else
|
||||
(void)sprintf(PQerrormsg,
|
||||
"fe_sendauth: krb5 authentication not supported\n");
|
||||
return (STATUS_ERROR);
|
||||
#endif
|
||||
case STARTUP_MSG:
|
||||
break;
|
||||
case STARTUP_PASSWORD_MSG:
|
||||
case STARTUP_CRYPT_MSG:
|
||||
pg_password_sendauth(port, user, password);
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
case AUTH_REQ_PASSWORD:
|
||||
case AUTH_REQ_CRYPT:
|
||||
if (pg_password_sendauth(conn, password, areq) != STATUS_OK)
|
||||
{
|
||||
(void)sprintf(PQerrormsg,
|
||||
"fe_sendauth: error sending password authentication\n");
|
||||
return (STATUS_ERROR);
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
default:
|
||||
(void)sprintf(PQerrormsg,
|
||||
"fe_sendauth: authentication type %u not supported\n",areq);
|
||||
return (STATUS_ERROR);
|
||||
}
|
||||
|
||||
return (STATUS_OK);
|
||||
}
|
||||
|
||||
|
|
|
@ -6,13 +6,16 @@
|
|||
*
|
||||
* Copyright (c) 1994, Regents of the University of California
|
||||
*
|
||||
* $Id: fe-auth.h,v 1.6 1997/09/08 21:55:35 momjian Exp $
|
||||
* $Id: fe-auth.h,v 1.7 1998/01/26 01:42:26 scrappy Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
#ifndef FE_AUTH_H
|
||||
#define FE_AUTH_H
|
||||
|
||||
#include "libpq-fe.h"
|
||||
|
||||
|
||||
/*----------------------------------------------------------------
|
||||
* Common routines and definitions
|
||||
*----------------------------------------------------------------
|
||||
|
@ -29,9 +32,8 @@
|
|||
#endif /* KRB4 || KRB5 */
|
||||
|
||||
extern int
|
||||
fe_sendauth(MsgType msgtype, Port *port, const char *hostname,
|
||||
const char *user, const char *password,
|
||||
const char *PQerromsg);
|
||||
fe_sendauth(AuthRequest areq, PGconn *conn, const char *hostname,
|
||||
const char *password, const char *PQerromsg);
|
||||
extern void fe_setauthsvc(const char *name, char *PQerrormsg);
|
||||
|
||||
#define PG_KRB4_VERSION "PGVER4.1" /* at most KRB_SENDAUTH_VLEN chars */
|
||||
|
|
|
@ -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,91 +559,9 @@ 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)
|
||||
{
|
||||
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)
|
||||
{
|
||||
(void) sprintf(conn->errorMessage,
|
||||
"connectDB() -- authentication failed with %s\n",
|
||||
conn->pghost);
|
||||
goto connect_errReturn;
|
||||
}
|
||||
|
||||
/* free the password so it's not hanging out in memory forever */
|
||||
if (conn->pgpass != NULL)
|
||||
{
|
||||
free(conn->pgpass);
|
||||
}
|
||||
|
||||
/* set up the socket file descriptors */
|
||||
conn->Pfout = fdopen(port->sock, "w");
|
||||
conn->Pfin = fdopen(dup(port->sock), "r");
|
||||
conn->Pfout = fdopen(conn->sock, "w");
|
||||
conn->Pfin = fdopen(dup(conn->sock), "r");
|
||||
if ((conn->Pfout == NULL) || (conn->Pfin == NULL))
|
||||
{
|
||||
(void) sprintf(conn->errorMessage,
|
||||
|
@ -678,19 +570,92 @@ connectDB(PGconn *conn)
|
|||
goto connect_errReturn;
|
||||
}
|
||||
|
||||
conn->port = port;
|
||||
/* 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;
|
||||
}
|
||||
|
||||
/*
|
||||
* Get the response from the backend, either an error message or an
|
||||
* authentication request.
|
||||
*/
|
||||
|
||||
do
|
||||
{
|
||||
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)
|
||||
{
|
||||
free(conn->pgpass);
|
||||
}
|
||||
|
||||
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,112 +808,27 @@ 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;
|
||||
|
||||
/* Send the packet itself. */
|
||||
|
||||
if (pqPutnchar(buf, len, conn->Pfout, conn->Pfdebug))
|
||||
return STATUS_ERROR;
|
||||
|
||||
pqFlush(conn->Pfout, conn->Pfdebug);
|
||||
|
||||
return STATUS_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
* 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
|
||||
|
||||
* 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;
|
||||
}
|
||||
|
||||
/*
|
||||
* 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;
|
||||
|
||||
/* 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));
|
||||
}
|
||||
|
||||
/* ----------------
|
||||
* Conninfo parser routine
|
||||
|
|
|
@ -6,26 +6,23 @@
|
|||
*
|
||||
* Copyright (c) 1994, Regents of the University of California
|
||||
*
|
||||
* $Id: fe-connect.h,v 1.5 1997/12/04 00:28:13 scrappy Exp $
|
||||
* $Id: fe-connect.h,v 1.6 1998/01/26 01:42:30 scrappy Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
#ifndef FE_CONNECT_H
|
||||
#define FE_CONNECT_H
|
||||
|
||||
#include <sys/types.h>
|
||||
|
||||
#include "libpq-fe.h"
|
||||
|
||||
|
||||
/*----------------------------------------------------------------
|
||||
* Common routines and definitions
|
||||
*----------------------------------------------------------------
|
||||
*/
|
||||
|
||||
extern int packetSend(Port *port, PacketBuf *buf, PacketLen len, bool nonBlocking);
|
||||
extern int packetReceive(Port *port, PacketBuf *buf, bool nonBlocking);
|
||||
int packetSend(PGconn *conn, char *buf, size_t len);
|
||||
|
||||
#endif /* FE_CONNECT_H */
|
||||
#ifndef FE_CONNECT_H
|
||||
#define FE_CONNECT_H
|
||||
|
||||
int packetSend(Port *port, PacketBuf *buf, PacketLen len, bool nonBlocking);
|
||||
int packetReceive(Port *port, PacketBuf *buf, bool nonBlocking);
|
||||
|
||||
#endif
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $Header: /cvsroot/pgsql/src/interfaces/libpq/fe-exec.c,v 1.45 1997/12/23 20:00:06 thomas Exp $
|
||||
* $Header: /cvsroot/pgsql/src/interfaces/libpq/fe-exec.c,v 1.46 1998/01/26 01:42:35 scrappy Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
|
@ -168,7 +168,7 @@ getTuple(PGconn *conn, PGresult *result, int binary)
|
|||
if ((nfields % BYTELEN) > 0)
|
||||
nbytes++;
|
||||
|
||||
if (pqGetnchar(bitmap, nbytes, pfin, pfdebug) == 1)
|
||||
if (nbytes >= MAX_FIELDS || pqGetnchar(bitmap, nbytes, pfin, pfdebug) == 1)
|
||||
{
|
||||
sprintf(conn->errorMessage,
|
||||
"Error reading null-values bitmap from row data stream\n");
|
||||
|
@ -189,10 +189,10 @@ getTuple(PGconn *conn, PGresult *result, int binary)
|
|||
else
|
||||
{
|
||||
/* get the value length (the first four bytes are for length) */
|
||||
pqGetInt(&vlen, VARHDRSZ, pfin, pfdebug);
|
||||
pqGetInt(&vlen, 4, pfin, pfdebug);
|
||||
if (binary == 0)
|
||||
{
|
||||
vlen = vlen - VARHDRSZ;
|
||||
vlen = vlen - 4;
|
||||
}
|
||||
if (vlen < 0)
|
||||
vlen = 0;
|
||||
|
|
|
@ -11,7 +11,7 @@
|
|||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $Header: /cvsroot/pgsql/src/interfaces/libpq/fe-misc.c,v 1.8 1997/09/08 21:55:44 momjian Exp $
|
||||
* $Header: /cvsroot/pgsql/src/interfaces/libpq/fe-misc.c,v 1.9 1998/01/26 01:42:36 scrappy Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
|
@ -51,38 +51,28 @@ pqGetc(FILE *fin, FILE *debug)
|
|||
int
|
||||
pqPutnchar(const char *s, int len, FILE *f, FILE *debug)
|
||||
{
|
||||
if (f == NULL)
|
||||
return 1;
|
||||
|
||||
if (debug)
|
||||
fprintf(debug, "To backend> %s\n", s);
|
||||
|
||||
if (fwrite(s, 1, len, f) != len)
|
||||
return 1;
|
||||
|
||||
return 0;
|
||||
return (pqPutNBytes(s, len, f) == EOF ? 1 : 0);
|
||||
}
|
||||
|
||||
/* --------------------------------------------------------------------- */
|
||||
/* pqGetnchar:
|
||||
get a string of exactly len length from stream f
|
||||
get a string of exactly len bytes in buffer s (which must be 1 byte
|
||||
longer) from stream f and terminate it with a '\0'.
|
||||
*/
|
||||
int
|
||||
pqGetnchar(char *s, int len, FILE *f, FILE *debug)
|
||||
{
|
||||
int cnt;
|
||||
int status;
|
||||
|
||||
if (f == NULL)
|
||||
return 1;
|
||||
|
||||
cnt = fread(s, 1, len, f);
|
||||
s[cnt] = '\0';
|
||||
/* mjl: actually needs up to len+1 bytes, is this okay? XXX */
|
||||
status = pqGetNBytes(s, len, f);
|
||||
|
||||
if (debug)
|
||||
fprintf(debug, "From backend (%d)> %s\n", len, s);
|
||||
|
||||
return 0;
|
||||
return (status == EOF ? 1 : 0);
|
||||
}
|
||||
|
||||
/* --------------------------------------------------------------------- */
|
||||
|
@ -92,21 +82,14 @@ pqGetnchar(char *s, int len, FILE *f, FILE *debug)
|
|||
int
|
||||
pqGets(char *s, int len, FILE *f, FILE *debug)
|
||||
{
|
||||
int c;
|
||||
const char *str = s;
|
||||
int status;
|
||||
|
||||
if (f == NULL)
|
||||
return 1;
|
||||
|
||||
while (len-- && (c = getc(f)) != EOF && c)
|
||||
*s++ = c;
|
||||
*s = '\0';
|
||||
/* mjl: actually needs up to len+1 bytes, is this okay? XXX */
|
||||
status = pqGetString(s, len, f);
|
||||
|
||||
if (debug)
|
||||
fprintf(debug, "From backend> \"%s\"\n", str);
|
||||
fprintf(debug, "From backend> \"%s\"\n", s);
|
||||
|
||||
return 0;
|
||||
return (status == EOF ? 1 : 0);
|
||||
}
|
||||
|
||||
/* --------------------------------------------------------------------- */
|
||||
|
@ -173,20 +156,13 @@ pqGetInt(int *result, int bytes, FILE *f, FILE *debug)
|
|||
int
|
||||
pqPuts(const char *s, FILE *f, FILE *debug)
|
||||
{
|
||||
if (f == NULL)
|
||||
if (pqPutString(s, f) == EOF)
|
||||
return 1;
|
||||
|
||||
if (fputs(s, f) == EOF)
|
||||
return 1;
|
||||
|
||||
fputc('\0', f); /* important to send an ending \0 since
|
||||
* backend expects it */
|
||||
fflush(f);
|
||||
|
||||
if (debug)
|
||||
{
|
||||
fprintf(debug, "To backend> %s\n", s);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
*
|
||||
* Copyright (c) 1994, Regents of the University of California
|
||||
*
|
||||
* $Id: libpq-fe.h,v 1.24 1997/12/04 00:28:15 scrappy Exp $
|
||||
* $Id: libpq-fe.h,v 1.25 1998/01/26 01:42:37 scrappy Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
|
@ -138,13 +138,15 @@ extern "C"
|
|||
FILE *Pfin;
|
||||
FILE *Pfout;
|
||||
FILE *Pfdebug;
|
||||
void *port; /* really a Port* */
|
||||
int sock; /* The socket */
|
||||
SockAddr laddr; /* Local address */
|
||||
SockAddr raddr; /* Remote address */
|
||||
char salt[2];
|
||||
int asyncNotifyWaiting;
|
||||
Dllist *notifyList;
|
||||
char *pguser; /* Postgres username of user who is
|
||||
* connected */
|
||||
char *pgpass;
|
||||
char *pgauth;
|
||||
PGlobjfuncs *lobjfuncs; /* Backend function OID's for large object
|
||||
* access */
|
||||
} PGconn;
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
.\" This is -*-nroff-*-
|
||||
.\" XXX standard disclaimer belongs here....
|
||||
.\" $Header: /cvsroot/pgsql/src/man/Attic/createdb.1,v 1.6 1998/01/11 22:17:23 momjian Exp $
|
||||
.\" $Header: /cvsroot/pgsql/src/man/Attic/createdb.1,v 1.7 1998/01/26 01:42:42 scrappy Exp $
|
||||
.TH CREATEDB UNIX 11/05/95 PostgreSQL PostgreSQL
|
||||
.SH NAME
|
||||
createdb - create a database
|
||||
|
@ -60,7 +60,7 @@ Specifies an authentication system
|
|||
.IR pgintro (1))
|
||||
to use in connecting to the
|
||||
.IR postmaster
|
||||
process. The default is site-specific.
|
||||
process. This option no longer has any effect.
|
||||
.TP
|
||||
.BR "-D" " dbpath"
|
||||
Specifies the alternate database location for this database.
|
||||
|
@ -79,13 +79,13 @@ is listening for connections. Defaults to 5432, or the value of the
|
|||
environment variable (if set).
|
||||
.SH EXAMPLES
|
||||
.nf
|
||||
# create 5432 demo database
|
||||
# create the demo database using the postmaster on the local host, port 5432.
|
||||
createdb demo
|
||||
.fi
|
||||
.nf
|
||||
# create the demo database using the postmaster on host eden,
|
||||
# port using the Kerberos authentication system.
|
||||
createdb -a kerberos -p 5432 -h eden demo
|
||||
# port 5000.
|
||||
createdb -p 5000 -h eden demo
|
||||
.fi
|
||||
.SH FILES
|
||||
.TP 5n
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
.\" This is -*-nroff-*-
|
||||
.\" XXX standard disclaimer belongs here....
|
||||
.\" $Header: /cvsroot/pgsql/src/man/Attic/createuser.1,v 1.5 1998/01/11 22:17:23 momjian Exp $
|
||||
.\" $Header: /cvsroot/pgsql/src/man/Attic/createuser.1,v 1.6 1998/01/26 01:42:44 scrappy Exp $
|
||||
.TH CREATEUSER UNIX 11/05/95 PostgreSQL PostgreSQL
|
||||
.SH NAME
|
||||
createuser - create a Postgres user
|
||||
|
@ -55,7 +55,7 @@ Specifies an authentication system
|
|||
.IR pgintro (1))
|
||||
to use in connecting to the
|
||||
.IR postmaster
|
||||
process. The default is site-specific.
|
||||
process. This option no longer has any effect.
|
||||
.TP
|
||||
.BR "-h" " host"
|
||||
Specifies the hostname of the machine on which the
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
.\" This is -*-nroff-*-
|
||||
.\" XXX standard disclaimer belongs here....
|
||||
.\" $Header: /cvsroot/pgsql/src/man/Attic/destroydb.1,v 1.6 1998/01/11 22:17:25 momjian Exp $
|
||||
.\" $Header: /cvsroot/pgsql/src/man/Attic/destroydb.1,v 1.7 1998/01/26 01:42:45 scrappy Exp $
|
||||
.TH DESTROYDB UNIX 11/05/95 PostgreSQL PostgreSQL
|
||||
.SH NAME
|
||||
destroydb - destroy an existing database
|
||||
|
@ -65,7 +65,7 @@ Specifies an authentication system
|
|||
.IR pgintro (1))
|
||||
to use in connecting to the
|
||||
.IR postmaster
|
||||
process. The default is site-specific.
|
||||
process. This option no longer has any effect.
|
||||
.TP
|
||||
.BR "-h" " host"
|
||||
Specifies the hostname of the machine on which the
|
||||
|
@ -85,9 +85,8 @@ environment variable (if set).
|
|||
destroydb demo
|
||||
.fi
|
||||
.nf
|
||||
# destroy 5432 demo database using the postmaster on host eden,
|
||||
# port using the Kerberos authentication system.
|
||||
destroydb -a kerberos -p 5432 -h eden demo
|
||||
# destroy the demo database using the postmaster on host eden, port 5000.
|
||||
destroydb -p 5000 -h eden demo
|
||||
.fi
|
||||
.SH FILES
|
||||
.TP 5n
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
.\" This is -*-nroff-*-
|
||||
.\" XXX standard disclaimer belongs here....
|
||||
.\" $Header: /cvsroot/pgsql/src/man/Attic/destroyuser.1,v 1.5 1998/01/11 22:17:25 momjian Exp $
|
||||
.\" $Header: /cvsroot/pgsql/src/man/Attic/destroyuser.1,v 1.6 1998/01/26 01:42:46 scrappy Exp $
|
||||
.TH DESTROYUSER UNIX 11/05/95 PostgreSQL PostgreSQL
|
||||
.SH NAME
|
||||
destroyuser - destroy a Postgres user and associated databases
|
||||
|
@ -55,7 +55,7 @@ Specifies an authentication system
|
|||
.IR pgintro (1))
|
||||
to use in connecting to the
|
||||
.IR postmaster
|
||||
process. The default is site-specific.
|
||||
process. This option no longer has any effect.
|
||||
.TP
|
||||
.BR "-h" " host"
|
||||
Specifies the hostname of the machine on which the
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
.\" This is -*-nroff-*-
|
||||
.\" XXX standard disclaimer belongs here....
|
||||
.\" $Header: /cvsroot/pgsql/src/man/Attic/libpq.3,v 1.11 1997/12/04 20:26:31 momjian Exp $
|
||||
.\" $Header: /cvsroot/pgsql/src/man/Attic/libpq.3,v 1.12 1998/01/26 01:42:47 scrappy Exp $
|
||||
.TH LIBPQ INTRO 03/12/94 PostgreSQL PostgreSQL
|
||||
.SH DESCRIPTION
|
||||
Libpq is the programmer's interface to Postgres. Libpq is a set of
|
||||
|
@ -591,9 +591,9 @@ If the user has generated the appropriate authentication credentials
|
|||
.I Kerberos
|
||||
tickets), the frontend/backend authentication process is handled by
|
||||
.I PQexec
|
||||
without any further intervention. The following routines may be
|
||||
called by Libpq programs to tailor the behavior of the authentication
|
||||
process.
|
||||
without any further intervention. The authentication method is now
|
||||
determined entirely by the DBA (see pga_hba.conf(5)). The following
|
||||
routines no longer have any effect and should not be used.
|
||||
.PP
|
||||
.B fe_getauthname
|
||||
.IP
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
.\" This is -*-nroff-*-
|
||||
.\" XXX standard disclaimer belongs here....
|
||||
.\" $Header: /cvsroot/pgsql/src/man/Attic/pg_passwd.1,v 1.2 1998/01/11 22:17:48 momjian Exp $
|
||||
.\" $Header: /cvsroot/pgsql/src/man/Attic/pg_passwd.1,v 1.3 1998/01/26 01:42:49 scrappy Exp $
|
||||
.TH PG_PASSWD UNIX 11/05/95 PostgreSQL PostgreSQL
|
||||
.SH NAME
|
||||
pg_passwd - manipulate the flat password file
|
||||
|
@ -80,7 +80,7 @@ The following lines show the sample usage of the option:
|
|||
uses the new style of the Pg.pm like this:
|
||||
.nf
|
||||
|
||||
$conn = Pg::connectdb("host=hyalos authtype=password dbname=unv
|
||||
$conn = Pg::connectdb("host=hyalos dbname=unv
|
||||
user=pg_guest password=xxxxxxx");
|
||||
|
||||
.fi
|
||||
|
@ -96,7 +96,7 @@ option thus:
|
|||
.nf
|
||||
|
||||
% set conn [pg_connect -conninfo \\
|
||||
"host=hyalos authtype=password dbname=unv \\
|
||||
"host=hyalos dbname=unv \\
|
||||
user=pg_guest password=xxxxxxx "]
|
||||
|
||||
.fi
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
.\" This is -*-nroff-*-
|
||||
.\" XXX standard disclaimer belongs here....
|
||||
.\" $Header: /cvsroot/pgsql/src/man/Attic/pgintro.1,v 1.2 1998/01/11 22:17:50 momjian Exp $
|
||||
.\" $Header: /cvsroot/pgsql/src/man/Attic/pgintro.1,v 1.3 1998/01/26 01:42:50 scrappy Exp $
|
||||
.TH PGINTRO UNIX 11/05/95 PostgreSQL PostgreSQL
|
||||
.SP INFORMATION UNIX 11/05/95
|
||||
.BH "SECTION 2 - Unix COMMANDS (Unix)"
|
||||
|
@ -105,26 +105,15 @@ conducted.
|
|||
If the Postgres system is built as distributed, access to the Internet
|
||||
TCP port of the
|
||||
.IR postmaster
|
||||
process is available to anyone. However, Postgres offers optional
|
||||
host-based authentication where only access from certain hosts are
|
||||
allowed. Of course, host-based authentication is not fool-proof in
|
||||
process is available to anyone. The DBA configures the pg_hba.conf file
|
||||
in the PGDATA directory to specify what authentication system is to be used
|
||||
according to the host making the connection and which database it is
|
||||
connecting to. See pg_hba.conf(5) for a description of the authentication
|
||||
systems available. Of course, host-based authentication is not fool-proof in
|
||||
Unix, either. It is possible for determined intruders to also
|
||||
masquerade the origination host. Those security issues are beyond the
|
||||
scope of Postgres.
|
||||
.PP
|
||||
If greater security is desired, Postgres and its clients may be
|
||||
modified to use a network authentication system. For example, the
|
||||
.IR postmaster ,
|
||||
.IR psql
|
||||
and the
|
||||
.IR libpq
|
||||
library have already been configured to use either Version 4 or Version 5 of
|
||||
the
|
||||
.IR Kerberos
|
||||
authentication system from the Massachusetts Institute of Technology.
|
||||
For more information on using
|
||||
.IR Kerberos
|
||||
with Postgres, see the appendix below.
|
||||
.SH "ACCESS CONTROL"
|
||||
Postgres provides mechanisms to allow users to limit the access to
|
||||
their data that is provided to other users.
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
.\" This is -*-nroff-*-
|
||||
.\" XXX standard disclaimer belongs here....
|
||||
.\" $Header: /cvsroot/pgsql/src/man/Attic/postgres.1,v 1.9 1998/01/11 22:17:51 momjian Exp $
|
||||
.\" $Header: /cvsroot/pgsql/src/man/Attic/postgres.1,v 1.10 1998/01/26 01:42:51 scrappy Exp $
|
||||
.TH POSTGRESQL UNIX 12/08/96 PostgreSQL PostgreSQL
|
||||
.SH NAME
|
||||
postgres - the Postgres backend server
|
||||
|
@ -31,6 +31,9 @@ filedes]
|
|||
[\c
|
||||
.BR "-e"
|
||||
]
|
||||
[\c
|
||||
.BR "-v protocol"
|
||||
]
|
||||
.br
|
||||
[\c
|
||||
.BR "-d"
|
||||
|
@ -145,6 +148,10 @@ but debugging output is sent to the controlling tty of the
|
|||
Print time information and other statistics at the end of each query.
|
||||
This is useful for benchmarking or for use in tuning the number of
|
||||
buffers.
|
||||
.TP
|
||||
.BR "-v" " protocol"
|
||||
Specifies the number of the frontend/backend protocol to be used for this
|
||||
particular session.
|
||||
.SH "DEPRECATED COMMAND OPTIONS"
|
||||
There are several other options that may be specified, used mainly
|
||||
for debugging purposes. These are listed here only for the use by
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
.\" This is -*-nroff-*-
|
||||
.\" XXX standard disclaimer belongs here....
|
||||
.\" $Header: /cvsroot/pgsql/src/man/Attic/postmaster.1,v 1.10 1998/01/11 22:17:53 momjian Exp $
|
||||
.\" $Header: /cvsroot/pgsql/src/man/Attic/postmaster.1,v 1.11 1998/01/26 01:42:52 scrappy Exp $
|
||||
.TH POSTMASTER UNIX 11/05/95 PostgreSQL PostgreSQL
|
||||
.SH "NAME"
|
||||
postmaster - run the Postgres postmaster
|
||||
|
@ -105,7 +105,7 @@ authentication, use
|
|||
to deny any unauthenticated
|
||||
connections, use
|
||||
.BR "-a nounauth .
|
||||
The default is site-specific.
|
||||
This option no longer has any effect.
|
||||
.TP
|
||||
.BR "-b" " backend_pathname"
|
||||
.IR "backend_pathname"
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
.\" This is -*-nroff-*-
|
||||
.\" XXX standard disclaimer belongs here....
|
||||
.\" $Header: /cvsroot/pgsql/src/man/Attic/psql.1,v 1.22 1998/01/25 06:12:52 scrappy Exp $
|
||||
.\" $Header: /cvsroot/pgsql/src/man/Attic/psql.1,v 1.23 1998/01/26 01:42:53 scrappy Exp $
|
||||
.TH PSQL UNIX 1/20/96 PostgreSQL PostgreSQL
|
||||
.SH NAME
|
||||
psql - run the interactive query front-end
|
||||
|
@ -125,7 +125,7 @@ Specifies an authentication system
|
|||
.IR pgintro (1))
|
||||
to use in connecting to the
|
||||
.IR postmaster
|
||||
process. The default is site-specific.
|
||||
process. This option no longer has any effect.
|
||||
.TP
|
||||
.BR "-A"
|
||||
Turn off fill justification when printing out table elements.
|
||||
|
@ -221,7 +221,11 @@ tabular output. For example
|
|||
will give you tables with borders.
|
||||
.TP
|
||||
.BR "-u"
|
||||
Turns on username/password authentication.
|
||||
Asks the user for the user name and password before connecting to the database.
|
||||
If the database does not require password authentication then these are
|
||||
ignored. If the option i snot used (and the PGPASSWORD environment variable
|
||||
is not set) and the database requires password authentication, then the
|
||||
connection will fail. The user name is ignored anyway.
|
||||
.TP
|
||||
.BR "-x"
|
||||
Turns on extended row format mode. When enabled each row will have its column
|
||||
|
|
Loading…
Reference in New Issue