1
0
mirror of https://github.com/postgres/postgres.git synced 2025-07-17 06:41:09 +03:00

Fix pg_pwd caching mechanism, which was broken by changes to fork

postmaster children before client auth step.  Postmaster now rereads
pg_pwd on receipt of SIGHUP, the same way that pg_hba.conf is handled.
No cycles need be expended to validate password cache validity during
connection startup.
This commit is contained in:
Tom Lane
2001-11-02 18:39:57 +00:00
parent 6babf6eab7
commit 8a069abd18
6 changed files with 187 additions and 146 deletions

View File

@ -9,7 +9,7 @@
* Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
* $Header: /cvsroot/pgsql/src/backend/libpq/crypt.c,v 1.40 2001/11/01 18:10:48 tgl Exp $
* $Header: /cvsroot/pgsql/src/backend/libpq/crypt.c,v 1.41 2001/11/02 18:39:57 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@ -17,6 +17,9 @@
#include <errno.h>
#include <unistd.h>
#ifdef HAVE_CRYPT_H
#include <crypt.h>
#endif
#include "libpq/crypt.h"
#include "libpq/libpq.h"
@ -24,15 +27,15 @@
#include "storage/fd.h"
#include "utils/nabstime.h"
#ifdef HAVE_CRYPT_H
#include <crypt.h>
#endif
char **pwd_cache = NULL;
int pwd_cache_count = 0;
#define CRYPT_PWD_FILE "pg_pwd"
static char **pwd_cache = NULL;
static int pwd_cache_count = 0;
/*
* crypt_getpwdfilename --- get name of password file
* crypt_getpwdfilename --- get full pathname of password file
*
* Note that result string is palloc'd, and should be freed by the caller.
*/
@ -50,28 +53,8 @@ crypt_getpwdfilename(void)
}
/*
* crypt_getpwdreloadfilename --- get name of password-reload-needed flag file
*
* Note that result string is palloc'd, and should be freed by the caller.
* Open the password file if possible (return NULL if not)
*/
char *
crypt_getpwdreloadfilename(void)
{
char *pwdfilename;
int bufsize;
char *rpfnam;
pwdfilename = crypt_getpwdfilename();
bufsize = strlen(pwdfilename) + strlen(CRYPT_PWD_RELOAD_SUFX) + 1;
rpfnam = (char *) palloc(bufsize);
snprintf(rpfnam, bufsize, "%s%s", pwdfilename, CRYPT_PWD_RELOAD_SUFX);
pfree(pwdfilename);
return rpfnam;
}
/*-------------------------------------------------------------------------*/
static FILE *
crypt_openpwdfile(void)
{
@ -123,107 +106,128 @@ compar_user(const void *user_a, const void *user_b)
return result;
}
/*-------------------------------------------------------------------------*/
static void
crypt_loadpwdfile(void)
/*
* Load or reload the password-file cache
*/
void
load_password_cache(void)
{
char *filename;
int result;
FILE *pwd_file;
char buffer[1024];
filename = crypt_getpwdreloadfilename();
result = unlink(filename);
pfree(filename);
/*
* If for some reason we fail to open the password file, preserve the
* old cache contents; this seems better than dropping the cache if,
* say, we are temporarily out of filetable slots.
*/
if (!(pwd_file = crypt_openpwdfile()))
return;
/* free any old data */
if (pwd_cache)
{
while (--pwd_cache_count >= 0)
pfree(pwd_cache[pwd_cache_count]);
pfree(pwd_cache);
pwd_cache = NULL;
pwd_cache_count = 0;
}
/*
* We want to delete the flag file before reading the contents of the
* pg_pwd file. If result == 0 then the unlink of the reload file was
* successful. This means that a backend performed a COPY of the
* pg_shadow file to pg_pwd. Therefore we must now do a reload.
* Read the file and store its lines in current memory context,
* which we expect will be PostmasterContext. That context will
* live as long as we need the cache to live, ie, until just after
* each postmaster child has completed client authentication.
*/
if (!pwd_cache || result == 0)
while (fgets(buffer, sizeof(buffer), pwd_file) != NULL)
{
/* free the old data only if this is a reload */
if (pwd_cache)
{
while (pwd_cache_count--)
free((void *) pwd_cache[pwd_cache_count]);
free((void *) pwd_cache);
pwd_cache = NULL;
pwd_cache_count = 0;
}
if (!(pwd_file = crypt_openpwdfile()))
return;
int blen;
/*
* Here is where we load the data from pg_pwd.
* We must remove the return char at the end of the string, as
* this will affect the correct parsing of the password entry.
*/
while (fgets(buffer, sizeof(buffer), pwd_file) != NULL)
{
/*
* We must remove the return char at the end of the string, as
* this will affect the correct parsing of the password entry.
*/
if (buffer[(result = strlen(buffer) - 1)] == '\n')
buffer[result] = '\0';
if (buffer[(blen = strlen(buffer) - 1)] == '\n')
buffer[blen] = '\0';
if (pwd_cache == NULL)
pwd_cache = (char **)
realloc((void *) pwd_cache,
sizeof(char *) * (pwd_cache_count + 1));
pwd_cache[pwd_cache_count++] = strdup(buffer);
}
FreeFile(pwd_file);
/*
* Now sort the entries in the cache for faster searching later.
*/
qsort((void *) pwd_cache, pwd_cache_count, sizeof(char *), compar_user);
palloc(sizeof(char *) * (pwd_cache_count + 1));
else
pwd_cache = (char **)
repalloc((void *) pwd_cache,
sizeof(char *) * (pwd_cache_count + 1));
pwd_cache[pwd_cache_count++] = pstrdup(buffer);
}
FreeFile(pwd_file);
/*
* Now sort the entries in the cache for faster searching later.
*/
qsort((void *) pwd_cache, pwd_cache_count, sizeof(char *), compar_user);
}
/*-------------------------------------------------------------------------*/
static void
/*
* Parse a line of the password file to extract password and valid-until date.
*/
static bool
crypt_parsepwdentry(char *buffer, char **pwd, char **valdate)
{
char *parse = buffer;
int count,
i;
*pwd = NULL;
*valdate = NULL;
/*
* skip to the password field
*/
for (i = 0; i < 6; i++)
parse += (strcspn(parse, CRYPT_PWD_FILE_SEPSTR) + 1);
{
parse += strcspn(parse, CRYPT_PWD_FILE_SEPSTR);
if (*parse == '\0')
return false;
parse++;
}
/*
* store a copy of user password to return
*/
count = strcspn(parse, CRYPT_PWD_FILE_SEPSTR);
*pwd = (char *) palloc(count + 1);
strncpy(*pwd, parse, count);
memcpy(*pwd, parse, count);
(*pwd)[count] = '\0';
parse += (count + 1);
parse += count;
if (*parse == '\0')
{
pfree(*pwd);
*pwd = NULL;
return false;
}
parse++;
/*
* store a copy of the date login becomes invalid
*/
count = strcspn(parse, CRYPT_PWD_FILE_SEPSTR);
*valdate = (char *) palloc(count + 1);
strncpy(*valdate, parse, count);
memcpy(*valdate, parse, count);
(*valdate)[count] = '\0';
parse += (count + 1);
return true;
}
/*-------------------------------------------------------------------------*/
static int
/*
* Lookup a username in the password-file cache,
* return his password and valid-until date.
*/
static bool
crypt_getloginfo(const char *user, char **passwd, char **valuntil)
{
crypt_loadpwdfile();
*passwd = NULL;
*valuntil = NULL;
if (pwd_cache)
{
@ -236,14 +240,12 @@ crypt_getloginfo(const char *user, char **passwd, char **valuntil)
compar_user);
if (pwd_entry)
{
crypt_parsepwdentry(*pwd_entry, passwd, valuntil);
return STATUS_OK;
if (crypt_parsepwdentry(*pwd_entry, passwd, valuntil))
return true;
}
}
*passwd = NULL;
*valuntil = NULL;
return STATUS_ERROR;
return false;
}
/*-------------------------------------------------------------------------*/
@ -256,7 +258,7 @@ md5_crypt_verify(const Port *port, const char *user, const char *pgpass)
*crypt_pwd;
int retval = STATUS_ERROR;
if (crypt_getloginfo(user, &passwd, &valuntil) == STATUS_ERROR)
if (!crypt_getloginfo(user, &passwd, &valuntil))
return STATUS_ERROR;
if (passwd == NULL || *passwd == '\0')