1
0
mirror of https://github.com/postgres/postgres.git synced 2025-07-23 03:21:12 +03:00
Files
postgres/src/backend/libpq/crypt.c
Robert Haas e26c539e9f Wrap calls to SearchSysCache and related functions using macros.
The purpose of this change is to eliminate the need for every caller
of SearchSysCache, SearchSysCacheCopy, SearchSysCacheExists,
GetSysCacheOid, and SearchSysCacheList to know the maximum number
of allowable keys for a syscache entry (currently 4).  This will
make it far easier to increase the maximum number of keys in a
future release should we choose to do so, and it makes the code
shorter, too.

Design and review by Tom Lane.
2010-02-14 18:42:19 +00:00

162 lines
4.0 KiB
C

/*-------------------------------------------------------------------------
*
* crypt.c
* Look into the password file and check the encrypted password with
* the one passed in from the frontend.
*
* Original coding by Todd A. Brandys
*
* Portions Copyright (c) 1996-2010, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
* $PostgreSQL: pgsql/src/backend/libpq/crypt.c,v 1.80 2010/02/14 18:42:15 rhaas Exp $
*
*-------------------------------------------------------------------------
*/
#include "postgres.h"
#include <unistd.h>
#ifdef HAVE_CRYPT_H
#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)
{
int retval = STATUS_ERROR;
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;
/* Get role info from pg_authid */
roleTup = SearchSysCache1(AUTHNAME, PointerGetDatum(role));
if (!HeapTupleIsValid(roleTup))
return STATUS_ERROR; /* no such user */
datum = SysCacheGetAttr(AUTHNAME, roleTup,
Anum_pg_authid_rolpassword, &isnull);
if (isnull)
{
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);
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
* authentication method being used for this connection.
*/
switch (port->hba->auth_method)
{
case uaMD5:
crypt_pwd = palloc(MD5_PASSWD_LEN + 1);
if (isMD5(shadow_pass))
{
/* stored password already encrypted, only do salt */
if (!pg_md5_encrypt(shadow_pass + strlen("md5"),
(char *) port->md5Salt,
sizeof(port->md5Salt), crypt_pwd))
{
pfree(crypt_pwd);
return STATUS_ERROR;
}
}
else
{
/* stored password is plain, double-encrypt */
char *crypt_pwd2 = palloc(MD5_PASSWD_LEN + 1);
if (!pg_md5_encrypt(shadow_pass,
port->user_name,
strlen(port->user_name),
crypt_pwd2))
{
pfree(crypt_pwd);
pfree(crypt_pwd2);
return STATUS_ERROR;
}
if (!pg_md5_encrypt(crypt_pwd2 + strlen("md5"),
port->md5Salt,
sizeof(port->md5Salt),
crypt_pwd))
{
pfree(crypt_pwd);
pfree(crypt_pwd2);
return STATUS_ERROR;
}
pfree(crypt_pwd2);
}
break;
default:
if (isMD5(shadow_pass))
{
/* Encrypt user-supplied password to match stored MD5 */
crypt_client_pass = palloc(MD5_PASSWD_LEN + 1);
if (!pg_md5_encrypt(client_pass,
port->user_name,
strlen(port->user_name),
crypt_client_pass))
{
pfree(crypt_client_pass);
return STATUS_ERROR;
}
}
crypt_pwd = shadow_pass;
break;
}
if (strcmp(crypt_client_pass, crypt_pwd) == 0)
{
/*
* Password OK, now check to be sure we are not past rolvaliduntil
*/
if (isnull)
retval = STATUS_OK;
else if (vuntil < GetCurrentTimestamp())
retval = STATUS_ERROR;
else
retval = STATUS_OK;
}
if (port->hba->auth_method == uaMD5)
pfree(crypt_pwd);
if (crypt_client_pass != client_pass)
pfree(crypt_client_pass);
return retval;
}