Header And Logo

PostgreSQL
| The world's most advanced open source database.

Functions

crypt.c File Reference

#include "postgres.h"
#include <unistd.h>
#include "catalog/pg_authid.h"
#include "libpq/crypt.h"
#include "libpq/md5.h"
#include "miscadmin.h"
#include "utils/builtins.h"
#include "utils/syscache.h"
#include "utils/timestamp.h"
Include dependency graph for crypt.c:

Go to the source code of this file.

Functions

int md5_crypt_verify (const Port *port, const char *role, char *client_pass)

Function Documentation

int md5_crypt_verify ( const Port port,
const char *  role,
char *  client_pass 
)

Definition at line 33 of file crypt.c.

References Anum_pg_authid_rolpassword, Anum_pg_authid_rolvaliduntil, HbaLine::auth_method, AUTHNAME, CHECK_FOR_INTERRUPTS, DatumGetTimestampTz, GetCurrentTimestamp(), Port::hba, HeapTupleIsValid, ImmediateInterruptOK, isMD5, MD5_PASSWD_LEN, Port::md5Salt, palloc(), pfree(), pg_md5_encrypt(), PointerGetDatum, ReleaseSysCache(), SearchSysCache1, SysCacheGetAttr(), TextDatumGetCString, uaMD5, and Port::user_name.

Referenced by recv_and_check_password_packet().

{
    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"),
                                    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;
}