1996-07-09 08:22:35 +02:00
|
|
|
/*-------------------------------------------------------------------------
|
|
|
|
*
|
|
|
|
* auth.c--
|
|
|
|
* Routines to handle network authentication
|
|
|
|
*
|
|
|
|
* Copyright (c) 1994, Regents of the University of California
|
|
|
|
*
|
|
|
|
*
|
|
|
|
* IDENTIFICATION
|
1996-08-14 06:51:34 +02:00
|
|
|
* $Header: /cvsroot/pgsql/src/backend/libpq/auth.c,v 1.2 1996/08/14 04:51:02 scrappy Exp $
|
1996-07-09 08:22:35 +02:00
|
|
|
*
|
|
|
|
*-------------------------------------------------------------------------
|
|
|
|
*/
|
|
|
|
/*
|
|
|
|
* INTERFACE ROUTINES
|
|
|
|
*
|
|
|
|
* 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>
|
|
|
|
#include <sys/param.h> /* for MAX{HOSTNAME,PATH}LEN, NOFILE */
|
|
|
|
#include <pwd.h>
|
|
|
|
#include <ctype.h> /* isspace() declaration */
|
|
|
|
|
|
|
|
#include <netinet/in.h>
|
|
|
|
#include <arpa/inet.h>
|
|
|
|
#include "libpq/auth.h"
|
|
|
|
#include "libpq/libpq.h"
|
|
|
|
#include "libpq/pqcomm.h"
|
|
|
|
#include "libpq/libpq-be.h"
|
|
|
|
|
|
|
|
/*----------------------------------------------------------------
|
|
|
|
* common definitions for generic fe/be routines
|
|
|
|
*----------------------------------------------------------------
|
|
|
|
*/
|
|
|
|
|
|
|
|
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.
|
|
|
|
*/
|
|
|
|
static struct authsvc authsvcs[] = {
|
|
|
|
#ifdef KRB4
|
|
|
|
{ "krb4", STARTUP_KRB4_MSG, 1 },
|
|
|
|
{ "kerberos", STARTUP_KRB4_MSG, 1 },
|
|
|
|
#endif /* KRB4 */
|
|
|
|
#ifdef KRB5
|
|
|
|
{ "krb5", STARTUP_KRB5_MSG, 1 },
|
|
|
|
{ "kerberos", STARTUP_KRB5_MSG, 1 },
|
|
|
|
#endif /* KRB5 */
|
|
|
|
{ UNAUTHNAME, STARTUP_MSG,
|
|
|
|
#if defined(KRB4) || defined(KRB5)
|
|
|
|
0
|
|
|
|
#else /* !(KRB4 || KRB5) */
|
|
|
|
1
|
|
|
|
#endif /* !(KRB4 || KRB5) */
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
static n_authsvcs = sizeof(authsvcs) / sizeof(struct authsvc);
|
|
|
|
|
|
|
|
#ifdef KRB4
|
|
|
|
/*----------------------------------------------------------------
|
|
|
|
* MIT Kerberos authentication system - protocol version 4
|
|
|
|
*----------------------------------------------------------------
|
|
|
|
*/
|
|
|
|
|
|
|
|
#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
|
|
|
|
*
|
|
|
|
* Nothing unusual here, except that we compare the username obtained from
|
|
|
|
* the client's setup packet to the authenticated name. (We have to retain
|
|
|
|
* the name in the setup packet since we have to retain the ability to handle
|
|
|
|
* unauthenticated connections.)
|
|
|
|
*/
|
|
|
|
static int
|
|
|
|
pg_krb4_recvauth(int sock,
|
|
|
|
struct sockaddr_in *laddr,
|
|
|
|
struct sockaddr_in *raddr,
|
|
|
|
char *username)
|
|
|
|
{
|
|
|
|
long krbopts = 0; /* one-way authentication */
|
|
|
|
KTEXT_ST clttkt;
|
|
|
|
char instance[INST_SZ];
|
|
|
|
AUTH_DAT auth_data;
|
|
|
|
Key_schedule key_sched;
|
|
|
|
char version[KRB_SENDAUTH_VLEN];
|
|
|
|
int status;
|
|
|
|
|
|
|
|
strcpy(instance, "*"); /* don't care, but arg gets expanded anyway */
|
|
|
|
status = krb_recvauth(krbopts,
|
|
|
|
sock,
|
|
|
|
&clttkt,
|
|
|
|
PG_KRB_SRVNAM,
|
|
|
|
instance,
|
|
|
|
raddr,
|
|
|
|
laddr,
|
|
|
|
&auth_data,
|
|
|
|
PG_KRB_SRVTAB,
|
|
|
|
key_sched,
|
|
|
|
version);
|
|
|
|
if (status != KSUCCESS) {
|
|
|
|
(void) sprintf(PQerrormsg,
|
|
|
|
"pg_krb4_recvauth: kerberos error: %s\n",
|
|
|
|
krb_err_txt[status]);
|
|
|
|
fputs(PQerrormsg, stderr);
|
|
|
|
pqdebug("%s", PQerrormsg);
|
|
|
|
return(STATUS_ERROR);
|
|
|
|
}
|
|
|
|
if (strncmp(version, PG_KRB4_VERSION, KRB_SENDAUTH_VLEN)) {
|
|
|
|
(void) sprintf(PQerrormsg,
|
|
|
|
"pg_krb4_recvauth: protocol version != \"%s\"\n",
|
|
|
|
PG_KRB4_VERSION);
|
|
|
|
fputs(PQerrormsg, stderr);
|
|
|
|
pqdebug("%s", PQerrormsg);
|
|
|
|
return(STATUS_ERROR);
|
|
|
|
}
|
|
|
|
if (username && *username &&
|
|
|
|
strncmp(username, auth_data.pname, NAMEDATALEN)) {
|
|
|
|
(void) sprintf(PQerrormsg,
|
|
|
|
"pg_krb4_recvauth: name \"%s\" != \"%s\"\n",
|
|
|
|
username,
|
|
|
|
auth_data.pname);
|
|
|
|
fputs(PQerrormsg, stderr);
|
|
|
|
pqdebug("%s", PQerrormsg);
|
|
|
|
return(STATUS_ERROR);
|
|
|
|
}
|
|
|
|
return(STATUS_OK);
|
|
|
|
}
|
|
|
|
|
|
|
|
#endif /* !FRONTEND */
|
|
|
|
|
|
|
|
#endif /* KRB4 */
|
|
|
|
|
|
|
|
#ifdef KRB5
|
|
|
|
/*----------------------------------------------------------------
|
|
|
|
* MIT Kerberos authentication system - protocol version 5
|
|
|
|
*----------------------------------------------------------------
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include "krb5/krb5.h"
|
|
|
|
|
|
|
|
/*
|
|
|
|
* pg_an_to_ln -- return the local name corresponding to an authentication
|
|
|
|
* name
|
|
|
|
*
|
|
|
|
* XXX Assumes that the first aname component is the user name. This is NOT
|
|
|
|
* necessarily so, since an aname can actually be something out of your
|
|
|
|
* worst X.400 nightmare, like
|
|
|
|
* ORGANIZATION=U. C. Berkeley/NAME=Paul M. Aoki@CS.BERKELEY.EDU
|
|
|
|
* Note that the MIT an_to_ln code does the same thing if you don't
|
|
|
|
* provide an aname mapping database...it may be a better idea to use
|
|
|
|
* krb5_an_to_ln, except that it punts if multiple components are found,
|
|
|
|
* and we can't afford to punt.
|
|
|
|
*/
|
|
|
|
static char *
|
|
|
|
pg_an_to_ln(char *aname)
|
|
|
|
{
|
|
|
|
char *p;
|
|
|
|
|
|
|
|
if ((p = strchr(aname, '/')) || (p = strchr(aname, '@')))
|
|
|
|
*p = '\0';
|
|
|
|
return(aname);
|
|
|
|
}
|
|
|
|
|
|
|
|
#ifdef FRONTEND
|
|
|
|
/* moves to src/libpq/fe-auth.c */
|
|
|
|
#else /* !FRONTEND */
|
|
|
|
|
|
|
|
/*
|
|
|
|
* pg_krb4_recvauth -- server routine to receive authentication information
|
|
|
|
* from the client
|
|
|
|
*
|
|
|
|
* We still need to compare the username obtained from the client's setup
|
|
|
|
* packet to the authenticated name, as described in pg_krb4_recvauth. This
|
|
|
|
* is a bit more problematic in v5, as described above in pg_an_to_ln.
|
|
|
|
*
|
|
|
|
* In addition, as described above in pg_krb5_sendauth, we still need to
|
|
|
|
* canonicalize the server name v4-style before constructing a principal
|
|
|
|
* from it. Again, this is kind of iffy.
|
|
|
|
*
|
|
|
|
* Finally, we need to tangle with the fact that v5 doesn't let you explicitly
|
|
|
|
* set server keytab file names -- you have to feed lower-level routines a
|
|
|
|
* function to retrieve the contents of a keytab, along with a single argument
|
|
|
|
* that allows them to open the keytab. We assume that a server keytab is
|
|
|
|
* always a real file so we can allow people to specify their own filenames.
|
|
|
|
* (This is important because the POSTGRES keytab needs to be readable by
|
|
|
|
* non-root users/groups; the v4 tools used to force you do dump a whole
|
|
|
|
* host's worth of keys into a file, effectively forcing you to use one file,
|
|
|
|
* 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)
|
|
|
|
{
|
|
|
|
char servbuf[MAXHOSTNAMELEN + 1 +
|
|
|
|
sizeof(PG_KRB_SRVNAM)];
|
|
|
|
char *hostp, *kusername = (char *) NULL;
|
|
|
|
krb5_error_code code;
|
|
|
|
krb5_principal client, server;
|
|
|
|
krb5_address sender_addr;
|
|
|
|
krb5_rdreq_key_proc keyproc = (krb5_rdreq_key_proc) NULL;
|
|
|
|
krb5_pointer keyprocarg = (krb5_pointer) NULL;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Set up server side -- since we have no ticket file to make this
|
|
|
|
* easy, we construct our own name and parse it. See note on
|
|
|
|
* canonicalization above.
|
|
|
|
*/
|
|
|
|
(void) strcpy(servbuf, PG_KRB_SRVNAM);
|
|
|
|
*(hostp = servbuf + (sizeof(PG_KRB_SRVNAM) - 1)) = '/';
|
|
|
|
if (gethostname(++hostp, MAXHOSTNAMELEN) < 0)
|
|
|
|
(void) strcpy(hostp, "localhost");
|
|
|
|
if (hostp = strchr(hostp, '.'))
|
|
|
|
*hostp = '\0';
|
|
|
|
if (code = krb5_parse_name(servbuf, &server)) {
|
|
|
|
(void) sprintf(PQerrormsg,
|
|
|
|
"pg_krb5_recvauth: Kerberos error %d in krb5_parse_name\n",
|
|
|
|
code);
|
|
|
|
com_err("pg_krb5_recvauth", code, "in krb5_parse_name");
|
|
|
|
return(STATUS_ERROR);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* 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);
|
|
|
|
|
|
|
|
if (strcmp(PG_KRB_SRVTAB, "")) {
|
|
|
|
keyproc = krb5_kt_read_service_key;
|
|
|
|
keyprocarg = PG_KRB_SRVTAB;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (code = krb5_recvauth((krb5_pointer) &sock,
|
|
|
|
PG_KRB5_VERSION,
|
|
|
|
server,
|
|
|
|
&sender_addr,
|
|
|
|
(krb5_pointer) NULL,
|
|
|
|
keyproc,
|
|
|
|
keyprocarg,
|
|
|
|
(char *) NULL,
|
|
|
|
(krb5_int32 *) NULL,
|
|
|
|
&client,
|
|
|
|
(krb5_ticket **) NULL,
|
|
|
|
(krb5_authenticator **) NULL)) {
|
|
|
|
(void) sprintf(PQerrormsg,
|
|
|
|
"pg_krb5_recvauth: Kerberos error %d in krb5_recvauth\n",
|
|
|
|
code);
|
|
|
|
com_err("pg_krb5_recvauth", code, "in krb5_recvauth");
|
|
|
|
krb5_free_principal(server);
|
|
|
|
return(STATUS_ERROR);
|
|
|
|
}
|
|
|
|
krb5_free_principal(server);
|
|
|
|
|
|
|
|
/*
|
|
|
|
* The "client" structure comes out of the ticket and is therefore
|
|
|
|
* authenticated. Use it to check the username obtained from the
|
|
|
|
* postmaster startup packet.
|
|
|
|
*/
|
|
|
|
if ((code = krb5_unparse_name(client, &kusername))) {
|
|
|
|
(void) sprintf(PQerrormsg,
|
|
|
|
"pg_krb5_recvauth: Kerberos error %d in krb5_unparse_name\n",
|
|
|
|
code);
|
|
|
|
com_err("pg_krb5_recvauth", code, "in krb5_unparse_name");
|
|
|
|
krb5_free_principal(client);
|
|
|
|
return(STATUS_ERROR);
|
|
|
|
}
|
|
|
|
krb5_free_principal(client);
|
|
|
|
if (!kusername) {
|
|
|
|
(void) sprintf(PQerrormsg,
|
|
|
|
"pg_krb5_recvauth: could not decode username\n");
|
|
|
|
fputs(PQerrormsg, stderr);
|
|
|
|
pqdebug("%s", PQerrormsg);
|
|
|
|
return(STATUS_ERROR);
|
|
|
|
}
|
|
|
|
kusername = pg_an_to_ln(kusername);
|
|
|
|
if (username && strncmp(username, kusername, NAMEDATALEN)) {
|
|
|
|
(void) sprintf(PQerrormsg,
|
|
|
|
"pg_krb5_recvauth: name \"%s\" != \"%s\"\n",
|
|
|
|
username, kusername);
|
|
|
|
fputs(PQerrormsg, stderr);
|
|
|
|
pqdebug("%s", PQerrormsg);
|
|
|
|
free(kusername);
|
|
|
|
return(STATUS_ERROR);
|
|
|
|
}
|
|
|
|
free(kusername);
|
|
|
|
return(STATUS_OK);
|
|
|
|
}
|
|
|
|
|
|
|
|
#endif /* !FRONTEND */
|
|
|
|
|
|
|
|
#endif /* KRB5 */
|
|
|
|
|
|
|
|
|
|
|
|
/*----------------------------------------------------------------
|
|
|
|
* host based authentication
|
|
|
|
*----------------------------------------------------------------
|
|
|
|
* 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)
|
|
|
|
*/
|
|
|
|
|
|
|
|
#define CONF_FILE "pg_hba" /* Name of the config file */
|
|
|
|
|
|
|
|
#define MAX_LINES 255 /* Maximum number of config lines *
|
|
|
|
* that can apply to one database */
|
|
|
|
|
|
|
|
#define ALL_NAME "all" /* Name used in config file for *
|
|
|
|
* lines that apply to all databases */
|
|
|
|
|
|
|
|
#define MAX_TOKEN 80 /* Maximum size of one token in the *
|
|
|
|
* configuration file */
|
|
|
|
|
|
|
|
struct conf_line { /* Info about config file line */
|
|
|
|
u_long adr, mask;
|
|
|
|
};
|
|
|
|
|
|
|
|
static int next_token(FILE *, char *, int);
|
|
|
|
|
|
|
|
/* hba_recvauth */
|
|
|
|
/* check for host-based authentication */
|
|
|
|
/*
|
|
|
|
* hba_recvauth - check the sockaddr_in "addr" to see if it corresponds
|
|
|
|
* to an acceptable host for the database that's being
|
|
|
|
* connected to. Return STATUS_OK if acceptable,
|
|
|
|
* otherwise return STATUS_ERROR.
|
|
|
|
*/
|
|
|
|
|
|
|
|
static int
|
|
|
|
hba_recvauth(struct sockaddr_in *addr, PacketBuf *pbuf, StartupInfo *sp)
|
|
|
|
{
|
|
|
|
u_long ip_addr;
|
|
|
|
static struct conf_line conf[MAX_LINES];
|
|
|
|
static int nconf;
|
|
|
|
int i;
|
|
|
|
|
|
|
|
char buf[MAX_TOKEN];
|
|
|
|
FILE *file;
|
|
|
|
|
|
|
|
char *conf_file;
|
|
|
|
|
|
|
|
/* put together the full pathname to the config file */
|
1996-08-14 06:51:34 +02:00
|
|
|
conf_file = (char *) malloc((strlen(DataDir)+strlen(CONF_FILE)+2)*sizeof(char));
|
|
|
|
sprintf(conf_file, "%s/%s", DataDir, CONF_FILE);
|
1996-07-09 08:22:35 +02:00
|
|
|
|
|
|
|
/* Open the config file. */
|
|
|
|
file = fopen(conf_file, "r");
|
|
|
|
if (file)
|
|
|
|
{
|
|
|
|
free(conf_file);
|
|
|
|
nconf = 0;
|
|
|
|
|
|
|
|
/* Grab the "name" */
|
|
|
|
while ((i = next_token(file, buf, sizeof(buf))) != EOF)
|
|
|
|
{
|
|
|
|
/* If only token on the line, ignore */
|
|
|
|
if (i == '\n') continue;
|
|
|
|
|
|
|
|
/* Comment -- read until end of line then next line */
|
|
|
|
if (buf[0] == '#')
|
|
|
|
{
|
|
|
|
while (next_token(file, buf, sizeof(buf)) == 0) ;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Check to make sure this says "all" or that it matches
|
|
|
|
* the database name.
|
|
|
|
*/
|
|
|
|
|
|
|
|
if (strcmp(buf, ALL_NAME) == 0 || (strcmp(buf, sp->database) == 0))
|
|
|
|
{
|
|
|
|
/* Get next token, if last on line, ignore */
|
|
|
|
if (next_token(file, buf, sizeof(buf)) != 0)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
/* Got address */
|
|
|
|
conf[nconf].adr = inet_addr(buf);
|
|
|
|
|
|
|
|
/* Get next token (mask) */
|
|
|
|
i = next_token(file, buf, sizeof(buf));
|
|
|
|
|
|
|
|
/* Only ignore if we got no text at all */
|
|
|
|
if (i != EOF)
|
|
|
|
{
|
|
|
|
/* Add to list, quit if array is full */
|
|
|
|
conf[nconf++].mask = inet_addr(buf);
|
|
|
|
if (nconf == MAX_LINES) break;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* If not at end-of-line, keep reading til we are */
|
|
|
|
while (i == 0)
|
|
|
|
i = next_token(file, buf, sizeof(buf));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
fclose(file);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{ (void) sprintf(PQerrormsg,
|
1996-08-14 06:51:34 +02:00
|
|
|
"hba_recvauth: Host-based authentication config file "
|
|
|
|
"does not exist or permissions are not setup correctly! "
|
|
|
|
"Unable to open file \"%s\".\n",
|
|
|
|
conf_file);
|
1996-07-09 08:22:35 +02:00
|
|
|
fputs(PQerrormsg, stderr);
|
|
|
|
pqdebug("%s", PQerrormsg);
|
|
|
|
free(conf_file);
|
|
|
|
return(STATUS_ERROR);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* Config lines now in memory so start checking address */
|
|
|
|
/* grab just the address */
|
|
|
|
ip_addr = addr->sin_addr.s_addr;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Go through the conf array, turn off the bits given by the mask
|
|
|
|
* and then compare the result with the address. A match means
|
|
|
|
* that this address is ok.
|
|
|
|
*/
|
|
|
|
for (i = 0; i < nconf; ++i)
|
|
|
|
if ((ip_addr & ~conf[i].mask) == conf[i].adr) return(STATUS_OK);
|
|
|
|
|
|
|
|
/* no match, so we can't approve the address */
|
|
|
|
return(STATUS_ERROR);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Grab one token out of fp. Defined as the next string of non-whitespace
|
|
|
|
* in the file. After we get the token, continue reading until EOF, end of
|
|
|
|
* line or the next token. If it's the last token on the line, return '\n'
|
|
|
|
* for the value. If we get EOF before reading a token, return EOF. In all
|
|
|
|
* other cases return 0.
|
|
|
|
*/
|
|
|
|
static int
|
|
|
|
next_token(FILE *fp, char *buf, int bufsz)
|
|
|
|
{
|
|
|
|
int c;
|
|
|
|
char *eb = buf+(bufsz-1);
|
|
|
|
|
|
|
|
/* Discard inital whitespace */
|
|
|
|
while (isspace(c = getc(fp))) ;
|
|
|
|
|
|
|
|
/* EOF seen before any token so return EOF */
|
|
|
|
if (c == EOF) return -1;
|
|
|
|
|
|
|
|
/* Form a token in buf */
|
|
|
|
do {
|
|
|
|
if (buf < eb) *buf++ = c;
|
|
|
|
c = getc(fp);
|
|
|
|
} while (!isspace(c) && c != EOF);
|
|
|
|
*buf = '\0';
|
|
|
|
|
|
|
|
/* Discard trailing tabs and spaces */
|
|
|
|
while (c == ' ' || c == '\t') c = getc(fp);
|
|
|
|
|
|
|
|
/* Put back the char that was non-whitespace (putting back EOF is ok) */
|
|
|
|
(void) ungetc(c, fp);
|
|
|
|
|
|
|
|
/* If we ended with a newline, return that, otherwise return 0 */
|
|
|
|
return (c == '\n' ? '\n' : 0);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* be_recvauth -- server demux routine for incoming authentication information
|
|
|
|
*/
|
|
|
|
int
|
|
|
|
be_recvauth(MsgType msgtype, Port *port, char *username, StartupInfo* sp)
|
|
|
|
{
|
|
|
|
if (!username) {
|
|
|
|
(void) sprintf(PQerrormsg,
|
|
|
|
"be_recvauth: no user name passed\n");
|
|
|
|
fputs(PQerrormsg, stderr);
|
|
|
|
pqdebug("%s", PQerrormsg);
|
|
|
|
return(STATUS_ERROR);
|
|
|
|
}
|
|
|
|
if (!port) {
|
|
|
|
(void) sprintf(PQerrormsg,
|
|
|
|
"be_recvauth: no port structure passed\n");
|
|
|
|
fputs(PQerrormsg, stderr);
|
|
|
|
pqdebug("%s", PQerrormsg);
|
|
|
|
return(STATUS_ERROR);
|
|
|
|
}
|
|
|
|
|
|
|
|
switch (msgtype) {
|
|
|
|
#ifdef KRB4
|
|
|
|
case STARTUP_KRB4_MSG:
|
|
|
|
if (!be_getauthsvc(msgtype)) {
|
|
|
|
(void) sprintf(PQerrormsg,
|
|
|
|
"be_recvauth: krb4 authentication disallowed\n");
|
|
|
|
fputs(PQerrormsg, stderr);
|
|
|
|
pqdebug("%s", PQerrormsg);
|
|
|
|
return(STATUS_ERROR);
|
|
|
|
}
|
|
|
|
if (pg_krb4_recvauth(port->sock, &port->laddr, &port->raddr,
|
|
|
|
username) != STATUS_OK) {
|
|
|
|
(void) sprintf(PQerrormsg,
|
|
|
|
"be_recvauth: krb4 authentication failed\n");
|
|
|
|
fputs(PQerrormsg, stderr);
|
|
|
|
pqdebug("%s", PQerrormsg);
|
|
|
|
return(STATUS_ERROR);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
#endif
|
|
|
|
#ifdef KRB5
|
|
|
|
case STARTUP_KRB5_MSG:
|
|
|
|
if (!be_getauthsvc(msgtype)) {
|
|
|
|
(void) sprintf(PQerrormsg,
|
|
|
|
"be_recvauth: krb5 authentication disallowed\n");
|
|
|
|
fputs(PQerrormsg, stderr);
|
|
|
|
pqdebug("%s", PQerrormsg);
|
|
|
|
return(STATUS_ERROR);
|
|
|
|
}
|
|
|
|
if (pg_krb5_recvauth(port->sock, &port->laddr, &port->raddr,
|
|
|
|
username) != STATUS_OK) {
|
|
|
|
(void) sprintf(PQerrormsg,
|
|
|
|
"be_recvauth: krb5 authentication failed\n");
|
|
|
|
fputs(PQerrormsg, stderr);
|
|
|
|
pqdebug("%s", PQerrormsg);
|
|
|
|
return(STATUS_ERROR);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
#endif
|
|
|
|
case STARTUP_MSG:
|
|
|
|
if (!be_getauthsvc(msgtype)) {
|
|
|
|
(void) sprintf(PQerrormsg,
|
|
|
|
"be_recvauth: unauthenticated connections disallowed failed\n");
|
|
|
|
fputs(PQerrormsg, stderr);
|
|
|
|
pqdebug("%s", PQerrormsg);
|
|
|
|
return(STATUS_ERROR);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case STARTUP_HBA_MSG:
|
|
|
|
if (hba_recvauth(&port->raddr, &port->buf, sp) != STATUS_OK) {
|
|
|
|
(void) sprintf(PQerrormsg,
|
|
|
|
"be_recvauth: host-based authentication failed\n");
|
|
|
|
fputs(PQerrormsg, stderr);
|
|
|
|
pqdebug("%s", PQerrormsg);
|
|
|
|
return(STATUS_ERROR);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
(void) sprintf(PQerrormsg,
|
|
|
|
"be_recvauth: unrecognized message type: %d\n",
|
|
|
|
msgtype);
|
|
|
|
fputs(PQerrormsg, stderr);
|
|
|
|
pqdebug("%s", PQerrormsg);
|
|
|
|
return(STATUS_ERROR);
|
|
|
|
}
|
|
|
|
return(STATUS_OK);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* 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.
|
|
|
|
*/
|
|
|
|
void
|
|
|
|
be_setauthsvc(char *name)
|
|
|
|
{
|
|
|
|
int i, j;
|
|
|
|
int turnon = 1;
|
|
|
|
|
|
|
|
if (!name)
|
|
|
|
return;
|
|
|
|
if (!strncmp("no", name, 2)) {
|
|
|
|
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) {
|
|
|
|
(void) sprintf(PQerrormsg,
|
|
|
|
"be_setauthsvc: invalid name %s, ignoring...\n",
|
|
|
|
name);
|
|
|
|
fputs(PQerrormsg, stderr);
|
|
|
|
pqdebug("%s", PQerrormsg);
|
|
|
|
}
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
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);
|
|
|
|
}
|