diff options
author | Tom Lane <tgl@sss.pgh.pa.us> | 2001-11-02 18:39:57 +0000 |
---|---|---|
committer | Tom Lane <tgl@sss.pgh.pa.us> | 2001-11-02 18:39:57 +0000 |
commit | 8a069abd180250a5863160ed3b510a9d4c21c207 (patch) | |
tree | 359d39dceba0beeca39b8efe2e0c1dc236fdbdd8 /src/backend/libpq/crypt.c | |
parent | 6babf6eab7a09127f0425c168a9e1ddffe5b4808 (diff) |
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.
Diffstat (limited to 'src/backend/libpq/crypt.c')
-rw-r--r-- | src/backend/libpq/crypt.c | 184 |
1 files changed, 93 insertions, 91 deletions
diff --git a/src/backend/libpq/crypt.c b/src/backend/libpq/crypt.c index 8decc40d0ba..83921ee014f 100644 --- a/src/backend/libpq/crypt.c +++ b/src/backend/libpq/crypt.c @@ -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); - /* - * 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. + * 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_cache || result == 0) + if (!(pwd_file = crypt_openpwdfile())) + return; + + /* free any old data */ + if (pwd_cache) { - /* 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; - } + while (--pwd_cache_count >= 0) + pfree(pwd_cache[pwd_cache_count]); + pfree(pwd_cache); + pwd_cache = NULL; + pwd_cache_count = 0; + } - if (!(pwd_file = crypt_openpwdfile())) - return; + /* + * 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. + */ + while (fgets(buffer, sizeof(buffer), pwd_file) != NULL) + { + 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') |