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:
Marc G. Fournier 1998-01-26 01:42:53 +00:00
parent 91d983aa11
commit d5bbe2aca5
41 changed files with 1611 additions and 2288 deletions

View File

@ -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;
}

View File

@ -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>

View File

@ -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>

View File

@ -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
*/

View File

@ -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)
*
-----------------------------------------------------------------*/

View File

@ -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;
}

View File

@ -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
#

View File

@ -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;
}

View File

@ -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;
}
/* --------------------------------------------------------------------- */

View File

@ -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;
}
*/

View File

@ -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);
}
}

View File

@ -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"

View File

@ -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");
}

View File

@ -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);
}

View File

@ -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;

View File

@ -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 --

View File

@ -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"

View File

@ -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

View File

@ -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

View File

@ -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 */

View File

@ -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
*/

View File

@ -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

View File

@ -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 */

View File

@ -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

View File

@ -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);
}

View File

@ -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 */

View File

@ -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

View File

@ -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

View File

@ -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;

View File

@ -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;
}

View File

@ -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;

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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.

View File

@ -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

View File

@ -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"

View File

@ -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