1996-10-12 09:47:12 +02:00
|
|
|
/*-------------------------------------------------------------------------
|
|
|
|
*
|
1999-02-14 00:22:53 +01:00
|
|
|
* hba.c
|
1997-09-07 07:04:48 +02:00
|
|
|
* Routines to handle host based authentication (that's the scheme
|
|
|
|
* wherein you authenticate a user by seeing what IP address the system
|
|
|
|
* says he comes from and possibly using ident).
|
1996-10-12 09:47:12 +02:00
|
|
|
*
|
1999-10-23 05:13:33 +02:00
|
|
|
* $Id: hba.c,v 1.49 1999/10/23 03:13:21 tgl Exp $
|
1996-10-12 09:47:12 +02:00
|
|
|
*
|
|
|
|
*-------------------------------------------------------------------------
|
|
|
|
*/
|
1996-10-13 20:37:19 +02:00
|
|
|
#include <errno.h>
|
1996-10-12 09:47:12 +02:00
|
|
|
#include <pwd.h>
|
1997-08-27 05:48:50 +02:00
|
|
|
#include <sys/types.h>
|
|
|
|
#include <fcntl.h>
|
1996-10-13 20:37:19 +02:00
|
|
|
#include <sys/socket.h>
|
1996-10-12 09:47:12 +02:00
|
|
|
#include <netinet/in.h>
|
|
|
|
#include <arpa/inet.h>
|
1996-11-03 08:00:57 +01:00
|
|
|
#include <unistd.h>
|
1996-10-12 09:47:12 +02:00
|
|
|
|
1999-07-16 01:04:24 +02:00
|
|
|
#include "postgres.h"
|
1999-10-23 05:13:33 +02:00
|
|
|
|
1999-07-16 01:04:24 +02:00
|
|
|
#include "libpq/libpq.h"
|
1999-07-16 07:00:38 +02:00
|
|
|
#include "miscadmin.h"
|
1996-10-12 09:47:12 +02:00
|
|
|
|
1999-10-23 05:13:33 +02:00
|
|
|
|
|
|
|
#define MAX_TOKEN 80
|
|
|
|
/* Maximum size of one token in the configuration file */
|
|
|
|
|
|
|
|
#define IDENT_USERNAME_MAX 512
|
|
|
|
/* Max size of username ident server can return */
|
|
|
|
|
|
|
|
|
1996-10-28 10:03:50 +01:00
|
|
|
/* Some standard C libraries, including GNU, have an isblank() function.
|
|
|
|
Others, including Solaris, do not. So we have our own.
|
|
|
|
*/
|
1997-09-08 04:41:22 +02:00
|
|
|
static bool
|
1997-09-07 07:04:48 +02:00
|
|
|
isblank(const char c)
|
|
|
|
{
|
1998-09-01 05:29:17 +02:00
|
|
|
return c == ' ' || c == 9 /* tab */ ;
|
1996-10-28 10:03:50 +01:00
|
|
|
}
|
|
|
|
|
1996-10-12 09:47:12 +02:00
|
|
|
|
1997-09-07 07:04:48 +02:00
|
|
|
static void
|
1997-09-08 23:56:23 +02:00
|
|
|
next_token(FILE *fp, char *buf, const int bufsz)
|
1997-09-07 07:04:48 +02:00
|
|
|
{
|
1996-10-12 09:47:12 +02:00
|
|
|
/*--------------------------------------------------------------------------
|
|
|
|
Grab one token out of fp. Tokens are strings of non-blank
|
|
|
|
characters bounded by blank characters, beginning of line, and end
|
1997-09-07 07:04:48 +02:00
|
|
|
of line. Blank means space or tab. Return the token as *buf.
|
1996-10-12 09:47:12 +02:00
|
|
|
Leave file positioned to character immediately after the token or
|
|
|
|
EOF, whichever comes first. If no more tokens on line, return null
|
|
|
|
string as *buf and position file to beginning of next line or EOF,
|
1997-09-07 07:04:48 +02:00
|
|
|
whichever comes first.
|
1996-10-12 09:47:12 +02:00
|
|
|
--------------------------------------------------------------------------*/
|
1997-09-08 04:41:22 +02:00
|
|
|
int c;
|
|
|
|
char *eb = buf + (bufsz - 1);
|
1997-09-07 07:04:48 +02:00
|
|
|
|
|
|
|
/* Move over inital token-delimiting blanks */
|
|
|
|
while (isblank(c = getc(fp)));
|
|
|
|
|
|
|
|
if (c != '\n')
|
|
|
|
{
|
|
|
|
|
|
|
|
/*
|
|
|
|
* build a token in buf of next characters up to EOF, eol, or
|
|
|
|
* blank.
|
|
|
|
*/
|
|
|
|
while (c != EOF && c != '\n' && !isblank(c))
|
|
|
|
{
|
|
|
|
if (buf < eb)
|
|
|
|
*buf++ = c;
|
|
|
|
c = getc(fp);
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Put back the char right after the token (putting back EOF
|
|
|
|
* is ok)
|
|
|
|
*/
|
|
|
|
}
|
|
|
|
ungetc(c, fp);
|
|
|
|
}
|
|
|
|
*buf = '\0';
|
1996-10-12 09:47:12 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static void
|
1997-09-08 23:56:23 +02:00
|
|
|
read_through_eol(FILE *file)
|
1997-09-07 07:04:48 +02:00
|
|
|
{
|
1997-09-08 04:41:22 +02:00
|
|
|
int c;
|
1997-09-07 07:04:48 +02:00
|
|
|
|
|
|
|
do
|
|
|
|
c = getc(file);
|
|
|
|
while (c != '\n' && c != EOF);
|
1996-10-12 09:47:12 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static void
|
1998-09-01 05:29:17 +02:00
|
|
|
read_hba_entry2(FILE *file, UserAuth *userauth_p, char *auth_arg,
|
1998-02-26 05:46:47 +01:00
|
|
|
bool *error_p)
|
1997-09-07 07:04:48 +02:00
|
|
|
{
|
1996-10-12 09:47:12 +02:00
|
|
|
/*--------------------------------------------------------------------------
|
|
|
|
Read from file FILE the rest of a host record, after the mask field,
|
1998-01-26 02:42:53 +01:00
|
|
|
and return the interpretation of it as *userauth_p, auth_arg, and
|
1996-10-12 09:47:12 +02:00
|
|
|
*error_p.
|
|
|
|
---------------------------------------------------------------------------*/
|
1997-09-08 04:41:22 +02:00
|
|
|
char buf[MAX_TOKEN];
|
1997-09-07 07:04:48 +02:00
|
|
|
|
|
|
|
/* Get authentication type token. */
|
|
|
|
next_token(file, buf, sizeof(buf));
|
1998-01-26 02:42:53 +01:00
|
|
|
|
|
|
|
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;
|
1997-09-07 07:04:48 +02:00
|
|
|
else
|
|
|
|
{
|
1998-01-26 02:42:53 +01:00
|
|
|
*error_p = true;
|
1997-09-07 07:04:48 +02:00
|
|
|
|
1998-01-26 02:42:53 +01:00
|
|
|
if (buf[0] != '\0')
|
|
|
|
read_through_eol(file);
|
1997-09-07 07:04:48 +02:00
|
|
|
}
|
|
|
|
|
1998-01-26 02:42:53 +01:00
|
|
|
if (!*error_p)
|
1997-09-07 07:04:48 +02:00
|
|
|
{
|
1998-01-26 02:42:53 +01:00
|
|
|
/* Get the authentication argument token, if any */
|
1997-09-07 07:04:48 +02:00
|
|
|
next_token(file, buf, sizeof(buf));
|
|
|
|
if (buf[0] == '\0')
|
1998-01-26 02:42:53 +01:00
|
|
|
auth_arg[0] = '\0';
|
1997-09-07 07:04:48 +02:00
|
|
|
else
|
|
|
|
{
|
1998-01-26 02:42:53 +01:00
|
|
|
StrNCpy(auth_arg, buf, MAX_AUTH_ARG - 1);
|
1997-09-07 07:04:48 +02:00
|
|
|
next_token(file, buf, sizeof(buf));
|
|
|
|
if (buf[0] != '\0')
|
|
|
|
{
|
|
|
|
*error_p = true;
|
|
|
|
read_through_eol(file);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
1996-10-12 09:47:12 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static void
|
1999-09-27 05:13:16 +02:00
|
|
|
process_hba_record(FILE *file, hbaPort *port, bool *matches_p, bool *error_p)
|
1997-09-07 07:04:48 +02:00
|
|
|
{
|
1996-10-12 09:47:12 +02:00
|
|
|
/*---------------------------------------------------------------------------
|
|
|
|
Process the non-comment record in the config file that is next on the file.
|
1998-01-26 02:42:53 +01:00
|
|
|
See if it applies to a connection to a host with IP address "*raddr"
|
1998-09-01 06:40:42 +02:00
|
|
|
to a database named "*database". If so, return *matches_p true
|
1998-09-01 05:29:17 +02:00
|
|
|
and *userauth_p and *auth_arg as the values from the entry.
|
1998-01-26 02:42:53 +01:00
|
|
|
If not, leave *matches_p as it was. If the record has a syntax error,
|
1997-09-07 07:04:48 +02:00
|
|
|
return *error_p true, after issuing a message to stderr. If no error,
|
1996-10-12 09:47:12 +02:00
|
|
|
leave *error_p as it was.
|
|
|
|
---------------------------------------------------------------------------*/
|
1998-02-26 05:46:47 +01:00
|
|
|
char db[MAX_TOKEN],
|
|
|
|
buf[MAX_TOKEN];
|
1998-01-26 02:42:53 +01:00
|
|
|
|
|
|
|
/* Read the record type field. */
|
1997-09-07 07:04:48 +02:00
|
|
|
|
|
|
|
next_token(file, buf, sizeof(buf));
|
1998-01-26 02:42:53 +01:00
|
|
|
|
1997-09-07 07:04:48 +02:00
|
|
|
if (buf[0] == '\0')
|
1998-01-26 02:42:53 +01:00
|
|
|
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. */
|
|
|
|
|
1999-09-27 05:13:16 +02:00
|
|
|
read_hba_entry2(file, &port->auth_method, port->auth_arg, error_p);
|
1998-01-26 02:42:53 +01:00
|
|
|
|
|
|
|
/*
|
|
|
|
* For now, disallow methods that need AF_INET sockets to work.
|
|
|
|
*/
|
|
|
|
|
|
|
|
if (!*error_p &&
|
1999-09-27 05:13:16 +02:00
|
|
|
(port->auth_method == uaIdent ||
|
|
|
|
port->auth_method == uaKrb4 ||
|
|
|
|
port->auth_method == uaKrb5))
|
1998-01-26 02:42:53 +01:00
|
|
|
*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.
|
|
|
|
*/
|
|
|
|
|
1999-09-27 05:13:16 +02:00
|
|
|
if ((strcmp(db, port->database) != 0 && strcmp(db, "all") != 0 &&
|
|
|
|
(strcmp(db, "sameuser") != 0 || strcmp(port->database, port->user) != 0)) ||
|
|
|
|
port->raddr.sa.sa_family != AF_UNIX)
|
1998-01-26 02:42:53 +01:00
|
|
|
return;
|
|
|
|
}
|
1999-09-27 05:13:16 +02:00
|
|
|
else if (strcmp(buf, "host") == 0 || strcmp(buf, "hostssl") == 0)
|
1997-09-07 07:04:48 +02:00
|
|
|
{
|
1998-02-26 05:46:47 +01:00
|
|
|
struct in_addr file_ip_addr,
|
|
|
|
mask;
|
1999-09-27 05:13:16 +02:00
|
|
|
bool discard = 0; /* Discard this entry */
|
|
|
|
|
|
|
|
#ifdef USE_SSL
|
|
|
|
/* If SSL, then check that we are on SSL */
|
|
|
|
if (strcmp(buf, "hostssl") == 0) {
|
|
|
|
if (!port->ssl)
|
|
|
|
discard = 1;
|
|
|
|
|
|
|
|
/* Placeholder to require specific SSL level, perhaps? */
|
|
|
|
/* Or a client certificate */
|
|
|
|
|
|
|
|
/* Since we were on SSL, proceed as with normal 'host' mode */
|
|
|
|
}
|
|
|
|
#else
|
|
|
|
/* If not SSL, we don't support this */
|
|
|
|
if (strcmp(buf,"hostssl") == 0)
|
|
|
|
goto syntax;
|
|
|
|
#endif
|
1998-01-26 02:42:53 +01:00
|
|
|
|
|
|
|
/* 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))
|
1997-09-07 07:04:48 +02:00
|
|
|
{
|
|
|
|
read_through_eol(file);
|
1998-01-26 02:42:53 +01:00
|
|
|
goto syntax;
|
1997-09-07 07:04:48 +02:00
|
|
|
}
|
1998-01-26 02:42:53 +01:00
|
|
|
|
|
|
|
/* Read the mask field. */
|
|
|
|
|
|
|
|
next_token(file, buf, sizeof(buf));
|
|
|
|
|
|
|
|
if (buf[0] == '\0')
|
|
|
|
goto syntax;
|
|
|
|
|
|
|
|
if (!inet_aton(buf, &mask))
|
1997-09-07 07:04:48 +02:00
|
|
|
{
|
1998-01-26 02:42:53 +01:00
|
|
|
read_through_eol(file);
|
|
|
|
goto syntax;
|
1997-09-07 07:04:48 +02:00
|
|
|
}
|
1998-01-26 02:42:53 +01:00
|
|
|
|
|
|
|
/*
|
|
|
|
* This is the record we're looking for. Read the rest of the
|
|
|
|
* info from it.
|
|
|
|
*/
|
|
|
|
|
1999-09-27 05:13:16 +02:00
|
|
|
read_hba_entry2(file, &port->auth_method, port->auth_arg, error_p);
|
1998-01-26 02:42:53 +01:00
|
|
|
|
|
|
|
if (*error_p)
|
|
|
|
goto syntax;
|
|
|
|
|
1999-09-27 05:13:16 +02:00
|
|
|
/*
|
|
|
|
* If told to discard earlier. Moved down here so we don't get
|
|
|
|
* "out of sync" with the file.
|
|
|
|
*/
|
|
|
|
if (discard)
|
|
|
|
return;
|
|
|
|
|
1998-01-26 02:42:53 +01:00
|
|
|
/*
|
|
|
|
* If this record isn't for our database, or this is the wrong
|
|
|
|
* sort of connection, ignore it.
|
|
|
|
*/
|
|
|
|
|
1999-09-27 05:13:16 +02:00
|
|
|
if ((strcmp(db, port->database) != 0 && strcmp(db, "all") != 0 &&
|
|
|
|
(strcmp(db, "sameuser") != 0 || strcmp(port->database, port->user) != 0)) ||
|
|
|
|
port->raddr.sa.sa_family != AF_INET ||
|
|
|
|
((file_ip_addr.s_addr ^ port->raddr.in.sin_addr.s_addr) & mask.s_addr) != 0x0000)
|
1998-01-26 02:42:53 +01:00
|
|
|
return;
|
1997-09-07 07:04:48 +02:00
|
|
|
}
|
1998-01-26 02:42:53 +01:00
|
|
|
else
|
|
|
|
{
|
|
|
|
read_through_eol(file);
|
|
|
|
goto syntax;
|
|
|
|
}
|
|
|
|
|
|
|
|
*matches_p = true;
|
|
|
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
syntax:
|
1999-10-23 05:13:33 +02:00
|
|
|
snprintf(PQerrormsg, PQERRORMSG_LENGTH,
|
1999-05-25 18:15:34 +02:00
|
|
|
"process_hba_record: invalid syntax in pg_hba.conf file\n");
|
1998-01-26 02:42:53 +01:00
|
|
|
fputs(PQerrormsg, stderr);
|
|
|
|
pqdebug("%s", PQerrormsg);
|
|
|
|
|
|
|
|
*error_p = true;
|
1996-10-12 09:47:12 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static void
|
1999-09-27 05:13:16 +02:00
|
|
|
process_open_config_file(FILE *file, hbaPort *port, bool *hba_ok_p)
|
1997-09-07 07:04:48 +02:00
|
|
|
{
|
1996-10-12 09:47:12 +02:00
|
|
|
/*---------------------------------------------------------------------------
|
|
|
|
This function does the same thing as find_hba_entry, only with
|
|
|
|
the config file already open on stream descriptor "file".
|
|
|
|
----------------------------------------------------------------------------*/
|
1999-05-25 18:15:34 +02:00
|
|
|
bool found_entry = false; /* found an applicable entry? */
|
|
|
|
bool error = false; /* found an erroneous entry? */
|
|
|
|
bool eof = false; /* end of hba file */
|
1997-09-07 07:04:48 +02:00
|
|
|
|
|
|
|
while (!eof && !found_entry && !error)
|
|
|
|
{
|
|
|
|
/* Process a line from the config file */
|
1999-05-25 18:15:34 +02:00
|
|
|
int c = getc(file);
|
|
|
|
|
1997-09-07 07:04:48 +02:00
|
|
|
if (c == EOF)
|
|
|
|
eof = true;
|
|
|
|
else
|
|
|
|
{
|
1999-04-16 06:59:03 +02:00
|
|
|
ungetc(c, file);
|
1997-09-07 07:04:48 +02:00
|
|
|
if (c == '#')
|
|
|
|
read_through_eol(file);
|
|
|
|
else
|
1999-09-27 05:13:16 +02:00
|
|
|
process_hba_record(file, port, &found_entry, &error);
|
1997-09-07 07:04:48 +02:00
|
|
|
}
|
|
|
|
}
|
1998-01-26 02:42:53 +01:00
|
|
|
|
1998-01-27 04:25:14 +01:00
|
|
|
if (!error)
|
|
|
|
{
|
1999-04-16 06:59:03 +02:00
|
|
|
/* If no matching entry was found, synthesize 'reject' entry. */
|
1998-01-27 04:25:14 +01:00
|
|
|
|
|
|
|
if (!found_entry)
|
1999-09-27 05:13:16 +02:00
|
|
|
port->auth_method = uaReject;
|
1998-01-27 04:25:14 +01:00
|
|
|
|
1999-04-16 06:59:03 +02:00
|
|
|
*hba_ok_p = true;
|
1998-01-27 04:25:14 +01:00
|
|
|
}
|
1997-09-07 07:04:48 +02:00
|
|
|
}
|
1996-10-12 09:47:12 +02:00
|
|
|
|
|
|
|
|
|
|
|
|
1998-01-26 02:42:53 +01:00
|
|
|
static void
|
1999-09-27 05:13:16 +02:00
|
|
|
find_hba_entry(hbaPort *port, bool *hba_ok_p)
|
1997-09-07 07:04:48 +02:00
|
|
|
{
|
1998-12-14 07:50:32 +01:00
|
|
|
/*
|
|
|
|
* Read the config file and find an entry that allows connection from
|
1999-04-16 06:59:03 +02:00
|
|
|
* host "raddr", user "user", to database "database". If found,
|
|
|
|
* return *hba_ok_p = true and *userauth_p and *auth_arg representing
|
1999-05-25 18:15:34 +02:00
|
|
|
* the contents of that entry. If there is no matching entry, we
|
1999-04-16 06:59:03 +02:00
|
|
|
* set *hba_ok_p = true, *userauth_p = uaReject.
|
1998-12-14 07:50:32 +01:00
|
|
|
*
|
1999-04-16 06:59:03 +02:00
|
|
|
* If the config file is unreadable or contains invalid syntax, we
|
|
|
|
* issue a diagnostic message to stderr (ie, the postmaster log file)
|
|
|
|
* and return without changing *hba_ok_p.
|
1998-12-14 07:50:32 +01:00
|
|
|
*
|
|
|
|
* If we find a file by the old name of the config file (pg_hba), we issue
|
1999-05-25 18:15:34 +02:00
|
|
|
* an error message because it probably needs to be converted. He didn't
|
1998-12-14 07:50:32 +01:00
|
|
|
* follow directions and just installed his old hba file in the new database
|
|
|
|
* system.
|
|
|
|
*/
|
1997-09-07 07:04:48 +02:00
|
|
|
|
1999-05-25 18:15:34 +02:00
|
|
|
int fd,
|
1998-12-14 07:50:32 +01:00
|
|
|
bufsize;
|
1999-05-25 18:15:34 +02:00
|
|
|
FILE *file; /* The config file we have to read */
|
|
|
|
char *old_conf_file;
|
1997-09-07 07:04:48 +02:00
|
|
|
|
|
|
|
/* The name of old config file that better not exist. */
|
|
|
|
|
|
|
|
/* Fail if config file by old name exists. */
|
|
|
|
|
|
|
|
|
|
|
|
/* put together the full pathname to the old config file */
|
1998-12-14 07:50:32 +01:00
|
|
|
bufsize = (strlen(DataDir) + strlen(OLD_CONF_FILE) + 2) * sizeof(char);
|
|
|
|
old_conf_file = (char *) palloc(bufsize);
|
|
|
|
snprintf(old_conf_file, bufsize, "%s/%s", DataDir, OLD_CONF_FILE);
|
1997-09-07 07:04:48 +02:00
|
|
|
|
1999-01-17 07:20:06 +01:00
|
|
|
#ifndef __CYGWIN32__
|
1997-09-07 07:04:48 +02:00
|
|
|
if ((fd = open(old_conf_file, O_RDONLY, 0)) != -1)
|
1999-01-17 07:20:06 +01:00
|
|
|
#else
|
|
|
|
if ((fd = open(old_conf_file, O_RDONLY | O_BINARY, 0)) != -1)
|
|
|
|
#endif
|
1997-09-07 07:04:48 +02:00
|
|
|
{
|
|
|
|
/* Old config file exists. Tell this guy he needs to upgrade. */
|
|
|
|
close(fd);
|
1999-10-23 05:13:33 +02:00
|
|
|
snprintf(PQerrormsg, PQERRORMSG_LENGTH,
|
1997-09-07 07:04:48 +02:00
|
|
|
"A file exists by the name used for host-based authentication "
|
|
|
|
"in prior releases of Postgres (%s). The name and format of "
|
|
|
|
"the configuration file have changed, so this file should be "
|
1999-05-25 18:15:34 +02:00
|
|
|
"converted.\n",
|
|
|
|
old_conf_file);
|
1997-09-07 07:04:48 +02:00
|
|
|
fputs(PQerrormsg, stderr);
|
|
|
|
pqdebug("%s", PQerrormsg);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
1999-05-25 18:15:34 +02:00
|
|
|
char *conf_file; /* The name of the config file we have to
|
|
|
|
* read */
|
1997-09-07 07:04:48 +02:00
|
|
|
|
|
|
|
/* put together the full pathname to the config file */
|
1998-12-14 07:50:32 +01:00
|
|
|
bufsize = (strlen(DataDir) + strlen(CONF_FILE) + 2) * sizeof(char);
|
|
|
|
conf_file = (char *) palloc(bufsize);
|
|
|
|
snprintf(conf_file, bufsize, "%s/%s", DataDir, CONF_FILE);
|
1997-09-07 07:04:48 +02:00
|
|
|
|
|
|
|
file = AllocateFile(conf_file, "r");
|
|
|
|
if (file == NULL)
|
|
|
|
{
|
|
|
|
/* The open of the config file failed. */
|
|
|
|
|
1999-10-23 05:13:33 +02:00
|
|
|
snprintf(PQerrormsg, PQERRORMSG_LENGTH,
|
1999-05-25 18:15:34 +02:00
|
|
|
"find_hba_entry: Host-based authentication config file "
|
|
|
|
"does not exist or permissions are not setup correctly! "
|
|
|
|
"Unable to open file \"%s\".\n",
|
|
|
|
conf_file);
|
1997-09-07 07:04:48 +02:00
|
|
|
fputs(PQerrormsg, stderr);
|
|
|
|
pqdebug("%s", PQerrormsg);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
1999-09-27 05:13:16 +02:00
|
|
|
process_open_config_file(file, port, hba_ok_p);
|
1997-09-07 07:04:48 +02:00
|
|
|
FreeFile(file);
|
|
|
|
}
|
1997-12-09 04:11:25 +01:00
|
|
|
pfree(conf_file);
|
1997-09-07 07:04:48 +02:00
|
|
|
}
|
1997-12-09 04:11:25 +01:00
|
|
|
pfree(old_conf_file);
|
1996-10-12 09:47:12 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static void
|
1998-09-01 05:29:17 +02:00
|
|
|
interpret_ident_response(char *ident_response,
|
|
|
|
bool *error_p, char *ident_username)
|
1997-09-07 07:04:48 +02:00
|
|
|
{
|
1996-10-12 09:47:12 +02:00
|
|
|
/*----------------------------------------------------------------------------
|
1998-09-01 05:29:17 +02:00
|
|
|
Parse the string "*ident_response" as a response from a query to an Ident
|
1997-09-07 07:04:48 +02:00
|
|
|
server. If it's a normal response indicating a username, return
|
1998-09-01 05:29:17 +02:00
|
|
|
*error_p == false and the username as *ident_username. If it's anything
|
|
|
|
else, return *error_p == true and *ident_username undefined.
|
1996-10-12 09:47:12 +02:00
|
|
|
----------------------------------------------------------------------------*/
|
1998-09-01 05:29:17 +02:00
|
|
|
char *cursor; /* Cursor into *ident_response */
|
1997-09-07 07:04:48 +02:00
|
|
|
|
|
|
|
cursor = &ident_response[0];
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Ident's response, in the telnet tradition, should end in crlf
|
|
|
|
* (\r\n).
|
|
|
|
*/
|
|
|
|
if (strlen(ident_response) < 2)
|
|
|
|
*error_p = true;
|
|
|
|
else if (ident_response[strlen(ident_response) - 2] != '\r')
|
|
|
|
*error_p = true;
|
|
|
|
else
|
|
|
|
{
|
|
|
|
while (*cursor != ':' && *cursor != '\r')
|
|
|
|
cursor++; /* skip port field */
|
|
|
|
|
|
|
|
if (*cursor != ':')
|
|
|
|
*error_p = true;
|
|
|
|
else
|
|
|
|
{
|
|
|
|
/* We're positioned to colon before response type field */
|
1997-09-08 04:41:22 +02:00
|
|
|
char response_type[80];
|
1998-09-01 05:29:17 +02:00
|
|
|
int i; /* Index into *response_type */
|
1997-09-07 07:04:48 +02:00
|
|
|
|
|
|
|
cursor++; /* Go over colon */
|
|
|
|
while (isblank(*cursor))
|
|
|
|
cursor++; /* skip blanks */
|
|
|
|
i = 0;
|
|
|
|
while (*cursor != ':' && *cursor != '\r' && !isblank(*cursor)
|
|
|
|
&& i < sizeof(response_type) - 1)
|
|
|
|
response_type[i++] = *cursor++;
|
|
|
|
response_type[i] = '\0';
|
|
|
|
while (isblank(*cursor))
|
|
|
|
cursor++; /* skip blanks */
|
|
|
|
if (strcmp(response_type, "USERID") != 0)
|
|
|
|
*error_p = true;
|
|
|
|
else
|
|
|
|
{
|
|
|
|
|
|
|
|
/*
|
|
|
|
* It's a USERID response. Good. "cursor" should be
|
|
|
|
* pointing to the colon that precedes the operating
|
|
|
|
* system type.
|
|
|
|
*/
|
|
|
|
if (*cursor != ':')
|
|
|
|
*error_p = true;
|
|
|
|
else
|
|
|
|
{
|
|
|
|
cursor++; /* Go over colon */
|
|
|
|
/* Skip over operating system field. */
|
|
|
|
while (*cursor != ':' && *cursor != '\r')
|
|
|
|
cursor++;
|
|
|
|
if (*cursor != ':')
|
|
|
|
*error_p = true;
|
|
|
|
else
|
|
|
|
{
|
1998-09-01 05:29:17 +02:00
|
|
|
int i; /* Index into *ident_username */
|
1997-09-07 07:04:48 +02:00
|
|
|
|
|
|
|
cursor++; /* Go over colon */
|
|
|
|
while (isblank(*cursor))
|
|
|
|
cursor++; /* skip blanks */
|
|
|
|
/* Rest of line is username. Copy it over. */
|
|
|
|
i = 0;
|
|
|
|
while (*cursor != '\r' && i < IDENT_USERNAME_MAX)
|
|
|
|
ident_username[i++] = *cursor++;
|
|
|
|
ident_username[i] = '\0';
|
|
|
|
*error_p = false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
1996-10-12 09:47:12 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
ident(const struct in_addr remote_ip_addr, const struct in_addr local_ip_addr,
|
1997-09-07 07:04:48 +02:00
|
|
|
const ushort remote_port, const ushort local_port,
|
1998-09-01 05:29:17 +02:00
|
|
|
bool *ident_failed, char *ident_username)
|
1997-09-07 07:04:48 +02:00
|
|
|
{
|
1996-10-12 09:47:12 +02:00
|
|
|
/*--------------------------------------------------------------------------
|
|
|
|
Talk to the ident server on host "remote_ip_addr" and find out who
|
|
|
|
owns the tcp connection from his port "remote_port" to port
|
|
|
|
"local_port_addr" on host "local_ip_addr". Return the username the
|
1998-09-01 05:29:17 +02:00
|
|
|
ident server gives as "*ident_username".
|
1996-10-12 09:47:12 +02:00
|
|
|
|
|
|
|
IP addresses and port numbers are in network byte order.
|
|
|
|
|
|
|
|
But iff we're unable to get the information from ident, return
|
1998-09-01 05:29:17 +02:00
|
|
|
*ident_failed == true (and *ident_username undefined).
|
1996-10-12 09:47:12 +02:00
|
|
|
----------------------------------------------------------------------------*/
|
|
|
|
|
1997-09-07 07:04:48 +02:00
|
|
|
|
1999-05-25 18:15:34 +02:00
|
|
|
int sock_fd, /* File descriptor for socket on which we
|
|
|
|
* talk to Ident */
|
|
|
|
rc; /* Return code from a locally called
|
|
|
|
* function */
|
1997-09-07 07:04:48 +02:00
|
|
|
|
|
|
|
sock_fd = socket(AF_INET, SOCK_STREAM, IPPROTO_IP);
|
|
|
|
if (sock_fd == -1)
|
|
|
|
{
|
1999-10-23 05:13:33 +02:00
|
|
|
snprintf(PQerrormsg, PQERRORMSG_LENGTH,
|
1999-05-25 18:15:34 +02:00
|
|
|
"Failed to create socket on which to talk to Ident server. "
|
|
|
|
"socket() returned errno = %s (%d)\n",
|
|
|
|
strerror(errno), errno);
|
1997-09-07 07:04:48 +02:00
|
|
|
fputs(PQerrormsg, stderr);
|
|
|
|
pqdebug("%s", PQerrormsg);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
struct sockaddr_in ident_server;
|
1998-10-02 18:18:20 +02:00
|
|
|
struct sockaddr_in la;
|
1997-09-07 07:04:48 +02:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Socket address of Ident server on the system from which client
|
|
|
|
* is attempting to connect to us.
|
|
|
|
*/
|
|
|
|
ident_server.sin_family = AF_INET;
|
|
|
|
ident_server.sin_port = htons(IDENT_PORT);
|
|
|
|
ident_server.sin_addr = remote_ip_addr;
|
1998-10-02 18:18:20 +02:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Bind to the address which the client originally contacted,
|
1999-05-25 18:15:34 +02:00
|
|
|
* otherwise the ident server won't be able to match up the right
|
|
|
|
* connection. This is necessary if the PostgreSQL server is
|
|
|
|
* running on an IP alias.
|
1998-10-02 18:18:20 +02:00
|
|
|
*/
|
|
|
|
memset(&la, 0, sizeof(la));
|
|
|
|
la.sin_family = AF_INET;
|
|
|
|
la.sin_addr = local_ip_addr;
|
1999-05-25 18:15:34 +02:00
|
|
|
rc = bind(sock_fd, (struct sockaddr *) & la, sizeof(la));
|
1998-10-02 18:18:20 +02:00
|
|
|
if (rc == 0)
|
|
|
|
{
|
|
|
|
rc = connect(sock_fd,
|
1999-05-25 18:15:34 +02:00
|
|
|
(struct sockaddr *) & ident_server, sizeof(ident_server));
|
1998-10-02 18:18:20 +02:00
|
|
|
}
|
1997-09-07 07:04:48 +02:00
|
|
|
if (rc != 0)
|
|
|
|
{
|
1999-10-23 05:13:33 +02:00
|
|
|
snprintf(PQerrormsg, PQERRORMSG_LENGTH,
|
1999-05-25 18:15:34 +02:00
|
|
|
"Unable to connect to Ident server on the host which is "
|
|
|
|
"trying to connect to Postgres "
|
|
|
|
"(IP address %s, Port %d). "
|
|
|
|
"errno = %s (%d)\n",
|
|
|
|
inet_ntoa(remote_ip_addr), IDENT_PORT, strerror(errno), errno);
|
1997-09-07 07:04:48 +02:00
|
|
|
fputs(PQerrormsg, stderr);
|
|
|
|
pqdebug("%s", PQerrormsg);
|
|
|
|
*ident_failed = true;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
1999-05-25 18:15:34 +02:00
|
|
|
char ident_query[80];
|
1997-09-07 07:04:48 +02:00
|
|
|
|
|
|
|
/* The query we send to the Ident server */
|
1998-12-14 07:50:32 +01:00
|
|
|
snprintf(ident_query, 80, "%d,%d\n",
|
1999-05-25 18:15:34 +02:00
|
|
|
ntohs(remote_port), ntohs(local_port));
|
1997-09-07 07:04:48 +02:00
|
|
|
rc = send(sock_fd, ident_query, strlen(ident_query), 0);
|
|
|
|
if (rc < 0)
|
|
|
|
{
|
1999-10-23 05:13:33 +02:00
|
|
|
snprintf(PQerrormsg, PQERRORMSG_LENGTH,
|
1999-05-25 18:15:34 +02:00
|
|
|
"Unable to send query to Ident server on the host which is "
|
1997-09-07 07:04:48 +02:00
|
|
|
"trying to connect to Postgres (Host %s, Port %d),"
|
1999-05-25 18:15:34 +02:00
|
|
|
"even though we successfully connected to it. "
|
|
|
|
"errno = %s (%d)\n",
|
|
|
|
inet_ntoa(remote_ip_addr), IDENT_PORT, strerror(errno), errno);
|
1997-09-07 07:04:48 +02:00
|
|
|
fputs(PQerrormsg, stderr);
|
|
|
|
pqdebug("%s", PQerrormsg);
|
|
|
|
*ident_failed = true;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
1999-05-25 18:15:34 +02:00
|
|
|
char ident_response[80 + IDENT_USERNAME_MAX];
|
1997-09-07 07:04:48 +02:00
|
|
|
|
|
|
|
rc = recv(sock_fd, ident_response, sizeof(ident_response) - 1, 0);
|
|
|
|
if (rc < 0)
|
|
|
|
{
|
1999-10-23 05:13:33 +02:00
|
|
|
snprintf(PQerrormsg, PQERRORMSG_LENGTH,
|
1999-05-25 18:15:34 +02:00
|
|
|
"Unable to receive response from Ident server "
|
|
|
|
"on the host which is "
|
|
|
|
"trying to connect to Postgres (Host %s, Port %d),"
|
|
|
|
"even though we successfully sent our query to it. "
|
|
|
|
"errno = %s (%d)\n",
|
|
|
|
inet_ntoa(remote_ip_addr), IDENT_PORT,
|
|
|
|
strerror(errno), errno);
|
1997-09-07 07:04:48 +02:00
|
|
|
fputs(PQerrormsg, stderr);
|
|
|
|
pqdebug("%s", PQerrormsg);
|
|
|
|
*ident_failed = true;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
1997-09-08 04:41:22 +02:00
|
|
|
bool error; /* response from Ident is garbage. */
|
1997-09-07 07:04:48 +02:00
|
|
|
|
|
|
|
ident_response[rc] = '\0';
|
|
|
|
interpret_ident_response(ident_response, &error, ident_username);
|
|
|
|
*ident_failed = error;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
close(sock_fd);
|
|
|
|
}
|
|
|
|
}
|
1996-10-12 09:47:12 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static void
|
1997-09-08 23:56:23 +02:00
|
|
|
parse_map_record(FILE *file,
|
1998-09-01 05:29:17 +02:00
|
|
|
char *file_map, char *file_pguser, char *file_iuser)
|
1997-09-07 07:04:48 +02:00
|
|
|
{
|
1996-10-12 09:47:12 +02:00
|
|
|
/*---------------------------------------------------------------------------
|
|
|
|
Take the noncomment line which is next on file "file" and interpret
|
|
|
|
it as a line in a usermap file. Specifically, return the first
|
1997-09-07 07:04:48 +02:00
|
|
|
3 tokens as file_map, file_iuser, and file_pguser, respectively. If
|
1996-10-12 09:47:12 +02:00
|
|
|
there are fewer than 3 tokens, return null strings for the missing
|
|
|
|
ones.
|
|
|
|
|
|
|
|
---------------------------------------------------------------------------*/
|
1997-09-08 04:41:22 +02:00
|
|
|
char buf[MAX_TOKEN];
|
1997-09-07 07:04:48 +02:00
|
|
|
|
|
|
|
/* A token read from the file */
|
|
|
|
|
|
|
|
/* Set defaults in case fields not in file */
|
|
|
|
file_map[0] = '\0';
|
|
|
|
file_pguser[0] = '\0';
|
|
|
|
file_iuser[0] = '\0';
|
|
|
|
|
|
|
|
next_token(file, buf, sizeof(buf));
|
1998-03-15 09:18:03 +01:00
|
|
|
if (buf[0] != '\0')
|
1997-09-07 07:04:48 +02:00
|
|
|
{
|
|
|
|
strcpy(file_map, buf);
|
|
|
|
next_token(file, buf, sizeof(buf));
|
1998-03-15 09:18:03 +01:00
|
|
|
if (buf[0] != '\0')
|
1997-09-07 07:04:48 +02:00
|
|
|
{
|
|
|
|
strcpy(file_iuser, buf);
|
|
|
|
next_token(file, buf, sizeof(buf));
|
1998-03-15 09:18:03 +01:00
|
|
|
if (buf[0] != '\0')
|
1997-09-07 07:04:48 +02:00
|
|
|
{
|
|
|
|
strcpy(file_pguser, buf);
|
|
|
|
read_through_eol(file);
|
1998-03-15 09:18:03 +01:00
|
|
|
return;
|
1997-09-07 07:04:48 +02:00
|
|
|
}
|
|
|
|
}
|
1999-10-23 05:13:33 +02:00
|
|
|
snprintf(PQerrormsg, PQERRORMSG_LENGTH,
|
1999-05-25 18:15:34 +02:00
|
|
|
"Incomplete line in pg_ident: %s", file_map);
|
1998-03-15 09:18:03 +01:00
|
|
|
fputs(PQerrormsg, stderr);
|
|
|
|
pqdebug("%s", PQerrormsg);
|
1997-09-07 07:04:48 +02:00
|
|
|
}
|
1996-10-12 09:47:12 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static void
|
1997-09-08 23:56:23 +02:00
|
|
|
verify_against_open_usermap(FILE *file,
|
1998-09-01 05:29:17 +02:00
|
|
|
const char *pguser,
|
|
|
|
const char *ident_username,
|
|
|
|
const char *usermap_name,
|
1997-09-08 23:56:23 +02:00
|
|
|
bool *checks_out_p)
|
1997-09-07 07:04:48 +02:00
|
|
|
{
|
1996-10-12 09:47:12 +02:00
|
|
|
/*--------------------------------------------------------------------------
|
|
|
|
This function does the same thing as verify_against_usermap,
|
|
|
|
only with the config file already open on stream descriptor "file".
|
|
|
|
---------------------------------------------------------------------------*/
|
1997-09-08 04:41:22 +02:00
|
|
|
bool match; /* We found a matching entry in the map
|
1997-09-07 07:04:48 +02:00
|
|
|
* file */
|
1997-09-08 04:41:22 +02:00
|
|
|
bool eof; /* We've reached the end of the file we're
|
1997-09-07 07:04:48 +02:00
|
|
|
* reading */
|
|
|
|
|
|
|
|
match = false; /* initial value */
|
|
|
|
eof = false; /* initial value */
|
|
|
|
while (!eof && !match)
|
|
|
|
{
|
|
|
|
/* Process a line from the map file */
|
|
|
|
|
1997-09-08 04:41:22 +02:00
|
|
|
int c; /* a character read from the file */
|
1997-09-07 07:04:48 +02:00
|
|
|
|
|
|
|
c = getc(file);
|
|
|
|
ungetc(c, file);
|
|
|
|
if (c == EOF)
|
|
|
|
eof = true;
|
|
|
|
else
|
|
|
|
{
|
|
|
|
if (c == '#')
|
|
|
|
read_through_eol(file);
|
|
|
|
else
|
|
|
|
{
|
|
|
|
/* The following are fields read from a record of the file */
|
1997-09-08 04:41:22 +02:00
|
|
|
char file_map[MAX_TOKEN + 1];
|
|
|
|
char file_pguser[MAX_TOKEN + 1];
|
|
|
|
char file_iuser[MAX_TOKEN + 1];
|
1997-09-07 07:04:48 +02:00
|
|
|
|
|
|
|
parse_map_record(file, file_map, file_pguser, file_iuser);
|
|
|
|
if (strcmp(file_map, usermap_name) == 0 &&
|
|
|
|
strcmp(file_pguser, pguser) == 0 &&
|
|
|
|
strcmp(file_iuser, ident_username) == 0)
|
|
|
|
match = true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
*checks_out_p = match;
|
1996-10-12 09:47:12 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static void
|
1998-09-01 05:29:17 +02:00
|
|
|
verify_against_usermap(const char *pguser,
|
|
|
|
const char *ident_username,
|
|
|
|
const char *usermap_name,
|
1997-09-08 23:56:23 +02:00
|
|
|
bool *checks_out_p)
|
1997-09-07 07:04:48 +02:00
|
|
|
{
|
1996-10-12 09:47:12 +02:00
|
|
|
/*--------------------------------------------------------------------------
|
|
|
|
See if the user with ident username "ident_username" is allowed to act
|
|
|
|
as Postgres user "pguser" according to usermap "usermap_name". Look
|
|
|
|
it up in the usermap file.
|
|
|
|
|
|
|
|
Special case: For usermap "sameuser", don't look in the usermap
|
|
|
|
file. That's an implied map where "pguser" must be identical to
|
|
|
|
"ident_username" in order to be authorized.
|
|
|
|
|
|
|
|
Iff authorized, return *checks_out_p == true.
|
1997-09-07 07:04:48 +02:00
|
|
|
|
1996-10-12 09:47:12 +02:00
|
|
|
--------------------------------------------------------------------------*/
|
|
|
|
|
1997-09-07 07:04:48 +02:00
|
|
|
if (usermap_name[0] == '\0')
|
|
|
|
{
|
|
|
|
*checks_out_p = false;
|
1999-10-23 05:13:33 +02:00
|
|
|
snprintf(PQerrormsg, PQERRORMSG_LENGTH,
|
1999-05-25 18:15:34 +02:00
|
|
|
"verify_against_usermap: hba configuration file does not "
|
|
|
|
"have the usermap field filled in in the entry that pertains "
|
|
|
|
"to this connection. That field is essential for Ident-based "
|
|
|
|
"authentication.\n");
|
1997-09-07 07:04:48 +02:00
|
|
|
fputs(PQerrormsg, stderr);
|
|
|
|
pqdebug("%s", PQerrormsg);
|
|
|
|
}
|
|
|
|
else if (strcmp(usermap_name, "sameuser") == 0)
|
|
|
|
{
|
|
|
|
if (strcmp(ident_username, pguser) == 0)
|
|
|
|
*checks_out_p = true;
|
|
|
|
else
|
|
|
|
*checks_out_p = false;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
1999-05-25 18:15:34 +02:00
|
|
|
FILE *file; /* The map file we have to read */
|
|
|
|
char *map_file; /* The name of the map file we have to
|
|
|
|
* read */
|
|
|
|
int bufsize;
|
1997-09-07 07:04:48 +02:00
|
|
|
|
|
|
|
/* put together the full pathname to the map file */
|
1999-05-10 17:17:17 +02:00
|
|
|
bufsize = (strlen(DataDir) + strlen(USERMAP_FILE) + 2) * sizeof(char);
|
1998-12-14 07:50:32 +01:00
|
|
|
map_file = (char *) palloc(bufsize);
|
1999-05-10 17:17:17 +02:00
|
|
|
snprintf(map_file, bufsize, "%s/%s", DataDir, USERMAP_FILE);
|
1997-09-07 07:04:48 +02:00
|
|
|
|
1999-01-17 07:20:06 +01:00
|
|
|
#ifndef __CYGWIN32__
|
1997-09-07 07:04:48 +02:00
|
|
|
file = AllocateFile(map_file, "r");
|
1999-01-17 07:20:06 +01:00
|
|
|
#else
|
|
|
|
file = AllocateFile(map_file, "rb");
|
|
|
|
#endif
|
1997-09-07 07:04:48 +02:00
|
|
|
if (file == NULL)
|
|
|
|
{
|
|
|
|
/* The open of the map file failed. */
|
|
|
|
|
|
|
|
*checks_out_p = false;
|
|
|
|
|
1999-10-23 05:13:33 +02:00
|
|
|
snprintf(PQerrormsg, PQERRORMSG_LENGTH,
|
1999-05-25 18:15:34 +02:00
|
|
|
"verify_against_usermap: usermap file for Ident-based "
|
|
|
|
"authentication "
|
|
|
|
"does not exist or permissions are not setup correctly! "
|
|
|
|
"Unable to open file \"%s\".\n",
|
|
|
|
map_file);
|
1997-09-07 07:04:48 +02:00
|
|
|
fputs(PQerrormsg, stderr);
|
|
|
|
pqdebug("%s", PQerrormsg);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
verify_against_open_usermap(file,
|
|
|
|
pguser, ident_username, usermap_name,
|
|
|
|
checks_out_p);
|
|
|
|
FreeFile(file);
|
|
|
|
}
|
1997-12-09 04:11:25 +01:00
|
|
|
pfree(map_file);
|
1997-09-07 07:04:48 +02:00
|
|
|
|
|
|
|
|
|
|
|
}
|
1996-10-12 09:47:12 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
1998-01-26 02:42:53 +01:00
|
|
|
int
|
1998-02-26 05:46:47 +01:00
|
|
|
authident(struct sockaddr_in * raddr, struct sockaddr_in * laddr,
|
1998-09-01 05:29:17 +02:00
|
|
|
const char *postgres_username,
|
|
|
|
const char *auth_arg)
|
1997-09-07 07:04:48 +02:00
|
|
|
{
|
1996-10-12 09:47:12 +02:00
|
|
|
/*---------------------------------------------------------------------------
|
1997-09-07 07:04:48 +02:00
|
|
|
Talk to the ident server on the remote host and find out who owns the
|
1996-10-12 09:47:12 +02:00
|
|
|
connection described by "port". Then look in the usermap file under
|
1998-09-01 05:29:17 +02:00
|
|
|
the usermap *auth_arg and see if that user is equivalent to
|
|
|
|
Postgres user *user.
|
1996-10-12 09:47:12 +02:00
|
|
|
|
1998-01-26 02:42:53 +01:00
|
|
|
Return STATUS_OK if yes.
|
1996-10-12 09:47:12 +02:00
|
|
|
---------------------------------------------------------------------------*/
|
1998-01-26 02:42:53 +01:00
|
|
|
bool checks_out;
|
1997-09-08 04:41:22 +02:00
|
|
|
bool ident_failed;
|
1997-09-07 07:04:48 +02:00
|
|
|
|
|
|
|
/* We were unable to get ident to give us a username */
|
1997-09-08 04:41:22 +02:00
|
|
|
char ident_username[IDENT_USERNAME_MAX + 1];
|
1997-09-07 07:04:48 +02:00
|
|
|
|
|
|
|
/* The username returned by ident */
|
|
|
|
|
1998-01-26 02:42:53 +01:00
|
|
|
ident(raddr->sin_addr, laddr->sin_addr,
|
|
|
|
raddr->sin_port, laddr->sin_port,
|
1997-09-07 07:04:48 +02:00
|
|
|
&ident_failed, ident_username);
|
|
|
|
|
|
|
|
if (ident_failed)
|
1998-01-26 02:42:53 +01:00
|
|
|
return STATUS_ERROR;
|
1997-09-07 07:04:48 +02:00
|
|
|
|
1998-01-26 02:42:53 +01:00
|
|
|
verify_against_usermap(postgres_username, ident_username, auth_arg,
|
1998-02-26 05:46:47 +01:00
|
|
|
&checks_out);
|
1998-01-26 02:42:53 +01:00
|
|
|
|
1998-09-01 05:29:17 +02:00
|
|
|
return checks_out ? STATUS_OK : STATUS_ERROR;
|
1996-10-12 09:47:12 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
1998-02-24 16:27:04 +01:00
|
|
|
#ifdef CYR_RECODE
|
|
|
|
#define CHARSET_FILE "charset.conf"
|
|
|
|
#define MAX_CHARSETS 10
|
1998-02-26 05:46:47 +01:00
|
|
|
#define KEY_HOST 1
|
|
|
|
#define KEY_BASE 2
|
|
|
|
#define KEY_TABLE 3
|
1998-02-24 16:27:04 +01:00
|
|
|
|
|
|
|
struct CharsetItem
|
|
|
|
{
|
1998-02-26 05:46:47 +01:00
|
|
|
char Orig[MAX_TOKEN];
|
|
|
|
char Dest[MAX_TOKEN];
|
|
|
|
char Table[MAX_TOKEN];
|
1998-02-24 16:27:04 +01:00
|
|
|
};
|
|
|
|
|
1998-02-26 05:46:47 +01:00
|
|
|
int
|
|
|
|
InRange(char *buf, int host)
|
1998-02-24 16:27:04 +01:00
|
|
|
{
|
1998-02-26 05:46:47 +01:00
|
|
|
int valid,
|
|
|
|
i,
|
|
|
|
FromAddr,
|
|
|
|
ToAddr,
|
|
|
|
tmp;
|
|
|
|
struct in_addr file_ip_addr;
|
|
|
|
char *p;
|
|
|
|
unsigned int one = 0x80000000,
|
|
|
|
NetMask = 0;
|
|
|
|
unsigned char mask;
|
|
|
|
|
|
|
|
p = strchr(buf, '/');
|
|
|
|
if (p)
|
|
|
|
{
|
|
|
|
*p++ = '\0';
|
|
|
|
valid = inet_aton(buf, &file_ip_addr);
|
|
|
|
if (valid)
|
|
|
|
{
|
|
|
|
mask = strtoul(p, 0, 0);
|
|
|
|
FromAddr = ntohl(file_ip_addr.s_addr);
|
|
|
|
ToAddr = ntohl(file_ip_addr.s_addr);
|
|
|
|
for (i = 0; i < mask; i++)
|
|
|
|
{
|
|
|
|
NetMask |= one;
|
|
|
|
one >>= 1;
|
|
|
|
}
|
|
|
|
FromAddr &= NetMask;
|
|
|
|
ToAddr = ToAddr | ~NetMask;
|
|
|
|
tmp = ntohl(host);
|
|
|
|
return ((unsigned) tmp >= (unsigned) FromAddr &&
|
|
|
|
(unsigned) tmp <= (unsigned) ToAddr);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
p = strchr(buf, '-');
|
|
|
|
if (p)
|
|
|
|
{
|
|
|
|
*p++ = '\0';
|
|
|
|
valid = inet_aton(buf, &file_ip_addr);
|
|
|
|
if (valid)
|
|
|
|
{
|
|
|
|
FromAddr = ntohl(file_ip_addr.s_addr);
|
|
|
|
valid = inet_aton(p, &file_ip_addr);
|
|
|
|
if (valid)
|
|
|
|
{
|
|
|
|
ToAddr = ntohl(file_ip_addr.s_addr);
|
|
|
|
tmp = ntohl(host);
|
|
|
|
return ((unsigned) tmp >= (unsigned) FromAddr &&
|
|
|
|
(unsigned) tmp <= (unsigned) ToAddr);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
valid = inet_aton(buf, &file_ip_addr);
|
|
|
|
if (valid)
|
|
|
|
{
|
|
|
|
FromAddr = file_ip_addr.s_addr;
|
1998-09-01 05:29:17 +02:00
|
|
|
return (unsigned) FromAddr == (unsigned) host;
|
1998-02-26 05:46:47 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return false;
|
1998-02-24 16:27:04 +01:00
|
|
|
}
|
|
|
|
|
1998-02-26 05:46:47 +01:00
|
|
|
void
|
1998-09-01 05:29:17 +02:00
|
|
|
GetCharSetByHost(char *TableName, int host, const char *DataDir)
|
1998-02-24 16:27:04 +01:00
|
|
|
{
|
1999-05-25 18:15:34 +02:00
|
|
|
FILE *file;
|
|
|
|
char buf[MAX_TOKEN],
|
1998-02-26 05:46:47 +01:00
|
|
|
BaseCharset[MAX_TOKEN],
|
|
|
|
OrigCharset[MAX_TOKEN],
|
|
|
|
DestCharset[MAX_TOKEN],
|
1998-12-14 07:50:32 +01:00
|
|
|
HostCharset[MAX_TOKEN],
|
|
|
|
c,
|
|
|
|
eof = false,
|
1999-05-25 18:15:34 +02:00
|
|
|
*map_file;
|
|
|
|
int key = 0,
|
1998-12-14 07:50:32 +01:00
|
|
|
ChIndex = 0,
|
|
|
|
i,
|
|
|
|
bufsize;
|
|
|
|
|
1999-05-25 18:15:34 +02:00
|
|
|
struct CharsetItem *ChArray[MAX_CHARSETS];
|
1998-02-26 05:46:47 +01:00
|
|
|
|
|
|
|
*TableName = '\0';
|
1998-12-14 07:50:32 +01:00
|
|
|
bufsize = (strlen(DataDir) + strlen(CHARSET_FILE) + 2) * sizeof(char);
|
|
|
|
map_file = (char *) palloc(bufsize);
|
|
|
|
snprintf(map_file, bufsize, "%s/%s", DataDir, CHARSET_FILE);
|
1999-01-17 07:20:06 +01:00
|
|
|
#ifndef __CYGWIN32__
|
1999-05-09 02:54:30 +02:00
|
|
|
file = AllocateFile(map_file, "r");
|
1999-01-17 07:20:06 +01:00
|
|
|
#else
|
1999-05-09 02:54:30 +02:00
|
|
|
file = AllocateFile(map_file, "rb");
|
1999-01-17 07:20:06 +01:00
|
|
|
#endif
|
1998-02-26 05:46:47 +01:00
|
|
|
if (file == NULL)
|
|
|
|
return;
|
|
|
|
while (!eof)
|
|
|
|
{
|
|
|
|
c = getc(file);
|
|
|
|
ungetc(c, file);
|
|
|
|
if (c == EOF)
|
|
|
|
eof = true;
|
|
|
|
else
|
|
|
|
{
|
|
|
|
if (c == '#')
|
|
|
|
read_through_eol(file);
|
|
|
|
else
|
|
|
|
{
|
|
|
|
/* Read the key */
|
|
|
|
next_token(file, buf, sizeof(buf));
|
|
|
|
if (buf[0] != '\0')
|
|
|
|
{
|
|
|
|
if (strcasecmp(buf, "HostCharset") == 0)
|
|
|
|
key = KEY_HOST;
|
|
|
|
if (strcasecmp(buf, "BaseCharset") == 0)
|
|
|
|
key = KEY_BASE;
|
|
|
|
if (strcasecmp(buf, "RecodeTable") == 0)
|
|
|
|
key = KEY_TABLE;
|
|
|
|
switch (key)
|
|
|
|
{
|
|
|
|
case KEY_HOST:
|
|
|
|
/* Read the host */
|
|
|
|
next_token(file, buf, sizeof(buf));
|
|
|
|
if (buf[0] != '\0')
|
|
|
|
{
|
|
|
|
if (InRange(buf, host))
|
|
|
|
{
|
|
|
|
/* Read the charset */
|
|
|
|
next_token(file, buf, sizeof(buf));
|
|
|
|
if (buf[0] != '\0')
|
|
|
|
strcpy(HostCharset, buf);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case KEY_BASE:
|
|
|
|
/* Read the base charset */
|
|
|
|
next_token(file, buf, sizeof(buf));
|
|
|
|
if (buf[0] != '\0')
|
|
|
|
strcpy(BaseCharset, buf);
|
|
|
|
break;
|
|
|
|
case KEY_TABLE:
|
|
|
|
/* Read the original charset */
|
|
|
|
next_token(file, buf, sizeof(buf));
|
|
|
|
if (buf[0] != '\0')
|
|
|
|
{
|
|
|
|
strcpy(OrigCharset, buf);
|
|
|
|
/* Read the destination charset */
|
|
|
|
next_token(file, buf, sizeof(buf));
|
|
|
|
if (buf[0] != '\0')
|
|
|
|
{
|
|
|
|
strcpy(DestCharset, buf);
|
|
|
|
/* Read the table filename */
|
|
|
|
next_token(file, buf, sizeof(buf));
|
|
|
|
if (buf[0] != '\0')
|
|
|
|
{
|
1999-05-25 18:15:34 +02:00
|
|
|
ChArray[ChIndex] =
|
|
|
|
(struct CharsetItem *) palloc(sizeof(struct CharsetItem));
|
1998-02-26 05:46:47 +01:00
|
|
|
strcpy(ChArray[ChIndex]->Orig, OrigCharset);
|
|
|
|
strcpy(ChArray[ChIndex]->Dest, DestCharset);
|
|
|
|
strcpy(ChArray[ChIndex]->Table, buf);
|
|
|
|
ChIndex++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
read_through_eol(file);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
1999-05-09 02:54:30 +02:00
|
|
|
FreeFile(file);
|
1998-12-14 07:50:32 +01:00
|
|
|
pfree(map_file);
|
1998-02-26 05:46:47 +01:00
|
|
|
|
|
|
|
for (i = 0; i < ChIndex; i++)
|
|
|
|
{
|
|
|
|
if (!strcasecmp(BaseCharset, ChArray[i]->Orig) &&
|
|
|
|
!strcasecmp(HostCharset, ChArray[i]->Dest))
|
|
|
|
strncpy(TableName, ChArray[i]->Table, 79);
|
1998-12-14 07:50:32 +01:00
|
|
|
pfree((struct CharsetItem *) ChArray[i]);
|
1998-02-26 05:46:47 +01:00
|
|
|
}
|
1998-02-24 16:27:04 +01:00
|
|
|
}
|
1998-02-26 05:46:47 +01:00
|
|
|
|
1998-02-24 16:27:04 +01:00
|
|
|
#endif
|
1996-10-12 09:47:12 +02:00
|
|
|
|
1999-04-16 06:59:03 +02:00
|
|
|
int
|
1999-09-27 05:13:16 +02:00
|
|
|
hba_getauthmethod(hbaPort *port)
|
1997-09-07 07:04:48 +02:00
|
|
|
{
|
1996-10-12 09:47:12 +02:00
|
|
|
/*---------------------------------------------------------------------------
|
1998-01-26 02:42:53 +01:00
|
|
|
Determine what authentication method should be used when accessing database
|
1999-04-16 06:59:03 +02:00
|
|
|
"database" from frontend "raddr", user "user". Return the method,
|
|
|
|
an optional argument, and STATUS_OK.
|
|
|
|
Note that STATUS_ERROR indicates a problem with the hba config file.
|
|
|
|
If the file is OK but does not contain any entry matching the request,
|
|
|
|
we return STATUS_OK and method = uaReject.
|
1997-09-07 07:04:48 +02:00
|
|
|
----------------------------------------------------------------------------*/
|
1999-04-16 06:59:03 +02:00
|
|
|
bool hba_ok = false;
|
1997-09-07 07:04:48 +02:00
|
|
|
|
1999-09-27 05:13:16 +02:00
|
|
|
find_hba_entry(port, &hba_ok);
|
1997-09-08 23:56:23 +02:00
|
|
|
|
1999-04-16 06:59:03 +02:00
|
|
|
return hba_ok ? STATUS_OK : STATUS_ERROR;
|
1996-10-12 09:47:12 +02:00
|
|
|
}
|