aboutsummaryrefslogtreecommitdiff
path: root/src/backend/libpq/crypt.c
diff options
context:
space:
mode:
authorTom Lane <tgl@sss.pgh.pa.us>2009-08-29 19:26:52 +0000
committerTom Lane <tgl@sss.pgh.pa.us>2009-08-29 19:26:52 +0000
commite710b65c1c56ca7b91f662c63d37ff2e72862a94 (patch)
tree35f0571a317a0f6d9a0e50a84d7d4157a811807d /src/backend/libpq/crypt.c
parent585806cb9fa0deeec94c8d76c20316ad0dfdd7eb (diff)
downloadpostgresql-e710b65c1c56ca7b91f662c63d37ff2e72862a94.tar.gz
postgresql-e710b65c1c56ca7b91f662c63d37ff2e72862a94.zip
Remove the use of the pg_auth flat file for client authentication.
(That flat file is now completely useless, but removal will come later.) To do this, postpone client authentication into the startup transaction that's run by InitPostgres. We still collect the startup packet and do SSL initialization (if needed) at the same time we did before. The AuthenticationTimeout is applied separately to startup packet collection and the actual authentication cycle. (This is a bit annoying, since it means a couple extra syscalls; but the signal handling requirements inside and outside a transaction are sufficiently different that it seems best to treat the timeouts as completely independent.) A small security disadvantage is that if the given database name is invalid, this will be reported to the client before any authentication happens. We could work around that by connecting to database "postgres" instead, but consensus seems to be that it's not worth introducing such surprising behavior. Processing of all command-line switches and GUC options received from the client is now postponed until after authentication. This means that PostAuthDelay is much less useful than it used to be --- if you need to investigate problems during InitPostgres you'll have to set PreAuthDelay instead. However, allowing an unauthenticated user to set any GUC options whatever seems a bit too risky, so we'll live with that.
Diffstat (limited to 'src/backend/libpq/crypt.c')
-rw-r--r--src/backend/libpq/crypt.c83
1 files changed, 49 insertions, 34 deletions
diff --git a/src/backend/libpq/crypt.c b/src/backend/libpq/crypt.c
index e230d53577e..77250b40310 100644
--- a/src/backend/libpq/crypt.c
+++ b/src/backend/libpq/crypt.c
@@ -9,7 +9,7 @@
* Portions Copyright (c) 1996-2009, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
- * $PostgreSQL: pgsql/src/backend/libpq/crypt.c,v 1.77 2009/01/01 17:23:42 momjian Exp $
+ * $PostgreSQL: pgsql/src/backend/libpq/crypt.c,v 1.78 2009/08/29 19:26:51 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -20,38 +20,63 @@
#include <crypt.h>
#endif
+#include "catalog/pg_authid.h"
#include "libpq/crypt.h"
#include "libpq/md5.h"
+#include "miscadmin.h"
+#include "utils/builtins.h"
+#include "utils/syscache.h"
int
md5_crypt_verify(const Port *port, const char *role, char *client_pass)
{
- char *shadow_pass = NULL,
- *valuntil = NULL,
- *crypt_pwd;
int retval = STATUS_ERROR;
- List **line;
- ListCell *token;
+ char *shadow_pass,
+ *crypt_pwd;
+ TimestampTz vuntil = 0;
char *crypt_client_pass = client_pass;
+ HeapTuple roleTup;
+ Datum datum;
+ bool isnull;
+
+ /*
+ * Disable immediate interrupts while doing database access. (Note
+ * we don't bother to turn this back on if we hit one of the failure
+ * conditions, since we can expect we'll just exit right away anyway.)
+ */
+ ImmediateInterruptOK = false;
- if ((line = get_role_line(role)) == NULL)
- return STATUS_ERROR;
+ /* Get role info from pg_authid */
+ roleTup = SearchSysCache(AUTHNAME,
+ PointerGetDatum(role),
+ 0, 0, 0);
+ if (!HeapTupleIsValid(roleTup))
+ return STATUS_ERROR; /* no such user */
- /* Skip over rolename */
- token = list_head(*line);
- if (token)
- token = lnext(token);
- if (token)
+ datum = SysCacheGetAttr(AUTHNAME, roleTup,
+ Anum_pg_authid_rolpassword, &isnull);
+ if (isnull)
{
- shadow_pass = (char *) lfirst(token);
- token = lnext(token);
- if (token)
- valuntil = (char *) lfirst(token);
+ ReleaseSysCache(roleTup);
+ return STATUS_ERROR; /* user has no password */
}
+ shadow_pass = TextDatumGetCString(datum);
+
+ datum = SysCacheGetAttr(AUTHNAME, roleTup,
+ Anum_pg_authid_rolvaliduntil, &isnull);
+ if (!isnull)
+ vuntil = DatumGetTimestampTz(datum);
- if (shadow_pass == NULL || *shadow_pass == '\0')
- return STATUS_ERROR;
+ ReleaseSysCache(roleTup);
+
+ if (*shadow_pass == '\0')
+ return STATUS_ERROR; /* empty password */
+
+ /* Re-enable immediate response to SIGTERM/SIGINT/timeout interrupts */
+ ImmediateInterruptOK = true;
+ /* And don't forget to detect one that already arrived */
+ CHECK_FOR_INTERRUPTS();
/*
* Compare with the encrypted or plain password depending on the
@@ -119,24 +144,14 @@ md5_crypt_verify(const Port *port, const char *role, char *client_pass)
if (strcmp(crypt_client_pass, crypt_pwd) == 0)
{
/*
- * Password OK, now check to be sure we are not past valuntil
+ * Password OK, now check to be sure we are not past rolvaliduntil
*/
- if (valuntil == NULL || *valuntil == '\0')
+ if (isnull)
retval = STATUS_OK;
+ else if (vuntil < GetCurrentTimestamp())
+ retval = STATUS_ERROR;
else
- {
- TimestampTz vuntil;
-
- vuntil = DatumGetTimestampTz(DirectFunctionCall3(timestamptz_in,
- CStringGetDatum(valuntil),
- ObjectIdGetDatum(InvalidOid),
- Int32GetDatum(-1)));
-
- if (vuntil < GetCurrentTimestamp())
- retval = STATUS_ERROR;
- else
- retval = STATUS_OK;
- }
+ retval = STATUS_OK;
}
if (port->hba->auth_method == uaMD5)