From c6ba7cbe81253d848d0c38d1b8bf5c7a34dc1e43 Mon Sep 17 00:00:00 2001 From: Michael Paquier Date: Mon, 25 Jul 2016 14:40:15 +0900 Subject: [PATCH 5/8] Create generic routine to fetch password and valid until values for a role This is used now for the MD5-encrypted case and the plain text, and this is going to be used as well for SCRAM-SHA256. That's as well useful for any new password-based protocols. --- src/backend/libpq/crypt.c | 59 +++++++++++++++++++++++++++++++++++------------ src/include/libpq/crypt.h | 2 ++ 2 files changed, 46 insertions(+), 15 deletions(-) diff --git a/src/backend/libpq/crypt.c b/src/backend/libpq/crypt.c index d84a180..1c41c57 100644 --- a/src/backend/libpq/crypt.c +++ b/src/backend/libpq/crypt.c @@ -1,8 +1,8 @@ /*------------------------------------------------------------------------- * * crypt.c - * Look into the password file and check the encrypted password with - * the one passed in from the frontend. + * Set of routines to look into the password file and check the + * encrypted password with the one passed in from the frontend. * * Original coding by Todd A. Brandys * @@ -30,23 +30,25 @@ /* - * Check given password for given user, and return STATUS_OK or STATUS_ERROR. - * In the error case, optionally store a palloc'd string at *logdetail - * that will be sent to the postmaster log (but not the client). + * Fetch information of a given role necessary to check password data, + * and return STATUS_OK or STATUS_ERROR. In the case of an error, + * optionally store a palloc'd string at *logdetail that will be sent + * to the postmaster log (but not the client). */ int -md5_crypt_verify(const Port *port, const char *role, char *client_pass, +get_role_details(const char *role, + char **password, + TimestampTz *vuntil, + bool *vuntil_null, char **logdetail) { - int retval = STATUS_ERROR; - char *shadow_pass, - *crypt_pwd; - TimestampTz vuntil = 0; - char *crypt_client_pass = client_pass; HeapTuple roleTup; Datum datum; bool isnull; + *vuntil = 0; + *vuntil_null = true; + /* Get role info from pg_authid */ roleTup = SearchSysCache1(AUTHNAME, PointerGetDatum(role)); if (!HeapTupleIsValid(roleTup)) @@ -65,22 +67,49 @@ md5_crypt_verify(const Port *port, const char *role, char *client_pass, role); return STATUS_ERROR; /* user has no password */ } - shadow_pass = TextDatumGetCString(datum); + *password = TextDatumGetCString(datum); datum = SysCacheGetAttr(AUTHNAME, roleTup, Anum_pg_authid_rolvaliduntil, &isnull); if (!isnull) - vuntil = DatumGetTimestampTz(datum); + { + *vuntil = DatumGetTimestampTz(datum); + *vuntil_null = false; + } ReleaseSysCache(roleTup); - if (*shadow_pass == '\0') + if (**password == '\0') { *logdetail = psprintf(_("User \"%s\" has an empty password."), role); return STATUS_ERROR; /* empty password */ } + return STATUS_OK; +} + +/* + * Check given password for given user, and return STATUS_OK or STATUS_ERROR. + * In the error case, optionally store a palloc'd string at *logdetail + * that will be sent to the postmaster log (but not the client). + */ +int +md5_crypt_verify(const Port *port, const char *role, char *client_pass, + char **logdetail) +{ + int retval = STATUS_ERROR; + char *shadow_pass, + *crypt_pwd; + TimestampTz vuntil; + char *crypt_client_pass = client_pass; + bool vuntil_null; + + /* fetch details about role needed for password checks */ + if (get_role_details(role, &shadow_pass, &vuntil, &vuntil_null, + logdetail) != STATUS_OK) + return STATUS_ERROR; + /* * Compare with the encrypted or plain password depending on the * authentication method being used for this connection. (We do not @@ -152,7 +181,7 @@ md5_crypt_verify(const Port *port, const char *role, char *client_pass, /* * Password OK, now check to be sure we are not past rolvaliduntil */ - if (isnull) + if (vuntil_null) retval = STATUS_OK; else if (vuntil < GetCurrentTimestamp()) { diff --git a/src/include/libpq/crypt.h b/src/include/libpq/crypt.h index 5725bb4..856c451 100644 --- a/src/include/libpq/crypt.h +++ b/src/include/libpq/crypt.h @@ -15,6 +15,8 @@ #include "libpq/libpq-be.h" +extern int get_role_details(const char *role, char **password, + TimestampTz *vuntil, bool *vuntil_null, char **logdetail); extern int md5_crypt_verify(const Port *port, const char *role, char *client_pass, char **logdetail); -- 2.10.1