1 /*-------------------------------------------------------------------------
4 * Look into the password file and check the encrypted password with
5 * the one passed in from the frontend.
7 * Original coding by Todd A. Brandys
9 * Portions Copyright (c) 1996-2012, PostgreSQL Global Development Group
10 * Portions Copyright (c) 1994, Regents of the University of California
12 * src/backend/libpq/crypt.c
14 *-------------------------------------------------------------------------
23 #include "catalog/pg_authid.h"
24 #include "libpq/crypt.h"
25 #include "libpq/md5.h"
26 #include "miscadmin.h"
27 #include "utils/builtins.h"
28 #include "utils/syscache.h"
29 #include "utils/timestamp.h"
33 md5_crypt_verify(const Port *port, const char *role, char *client_pass)
35 int retval = STATUS_ERROR;
38 TimestampTz vuntil = 0;
39 char *crypt_client_pass = client_pass;
45 * Disable immediate interrupts while doing database access. (Note we
46 * don't bother to turn this back on if we hit one of the failure
47 * conditions, since we can expect we'll just exit right away anyway.)
49 ImmediateInterruptOK = false;
51 /* Get role info from pg_authid */
52 roleTup = SearchSysCache1(AUTHNAME, PointerGetDatum(role));
53 if (!HeapTupleIsValid(roleTup))
54 return STATUS_ERROR; /* no such user */
56 datum = SysCacheGetAttr(AUTHNAME, roleTup,
57 Anum_pg_authid_rolpassword, &isnull);
60 ReleaseSysCache(roleTup);
61 return STATUS_ERROR; /* user has no password */
63 shadow_pass = TextDatumGetCString(datum);
65 datum = SysCacheGetAttr(AUTHNAME, roleTup,
66 Anum_pg_authid_rolvaliduntil, &isnull);
68 vuntil = DatumGetTimestampTz(datum);
70 ReleaseSysCache(roleTup);
72 if (*shadow_pass == '\0')
73 return STATUS_ERROR; /* empty password */
75 /* Re-enable immediate response to SIGTERM/SIGINT/timeout interrupts */
76 ImmediateInterruptOK = true;
77 /* And don't forget to detect one that already arrived */
78 CHECK_FOR_INTERRUPTS();
81 * Compare with the encrypted or plain password depending on the
82 * authentication method being used for this connection.
84 switch (port->hba->auth_method)
87 crypt_pwd = palloc(MD5_PASSWD_LEN + 1);
88 if (isMD5(shadow_pass))
90 /* stored password already encrypted, only do salt */
91 if (!pg_md5_encrypt(shadow_pass + strlen("md5"),
93 sizeof(port->md5Salt), crypt_pwd))
101 /* stored password is plain, double-encrypt */
102 char *crypt_pwd2 = palloc(MD5_PASSWD_LEN + 1);
104 if (!pg_md5_encrypt(shadow_pass,
106 strlen(port->user_name),
113 if (!pg_md5_encrypt(crypt_pwd2 + strlen("md5"),
115 sizeof(port->md5Salt),
126 if (isMD5(shadow_pass))
128 /* Encrypt user-supplied password to match stored MD5 */
129 crypt_client_pass = palloc(MD5_PASSWD_LEN + 1);
130 if (!pg_md5_encrypt(client_pass,
132 strlen(port->user_name),
135 pfree(crypt_client_pass);
139 crypt_pwd = shadow_pass;
143 if (strcmp(crypt_client_pass, crypt_pwd) == 0)
146 * Password OK, now check to be sure we are not past rolvaliduntil
150 else if (vuntil < GetCurrentTimestamp())
151 retval = STATUS_ERROR;
156 if (port->hba->auth_method == uaMD5)
158 if (crypt_client_pass != client_pass)
159 pfree(crypt_client_pass);