PostgreSQL Source Code  git master
crypt.h File Reference
Include dependency graph for crypt.h:
This graph shows which files directly or indirectly include this file:

Go to the source code of this file.

Typedefs

typedef enum PasswordType PasswordType
 

Enumerations

enum  PasswordType { PASSWORD_TYPE_PLAINTEXT = 0, PASSWORD_TYPE_MD5, PASSWORD_TYPE_SCRAM_SHA_256 }
 

Functions

PasswordType get_password_type (const char *shadow_pass)
 
char * encrypt_password (PasswordType target_type, const char *role, const char *password)
 
char * get_role_password (const char *role, char **logdetail)
 
int md5_crypt_verify (const char *role, const char *shadow_pass, const char *client_pass, const char *md5_salt, int md5_salt_len, char **logdetail)
 
int plain_crypt_verify (const char *role, const char *shadow_pass, const char *client_pass, char **logdetail)
 

Typedef Documentation

◆ PasswordType

typedef enum PasswordType PasswordType

Enumeration Type Documentation

◆ PasswordType

Enumerator
PASSWORD_TYPE_PLAINTEXT 
PASSWORD_TYPE_MD5 
PASSWORD_TYPE_SCRAM_SHA_256 

Definition at line 27 of file crypt.h.

Function Documentation

◆ encrypt_password()

char* encrypt_password ( PasswordType  target_type,
const char *  role,
const char *  password 
)

Definition at line 114 of file crypt.c.

References elog, ERROR, get_password_type(), MD5_PASSWD_LEN, palloc(), PASSWORD_TYPE_MD5, PASSWORD_TYPE_PLAINTEXT, PASSWORD_TYPE_SCRAM_SHA_256, pg_be_scram_build_secret(), pg_md5_encrypt(), and pstrdup().

Referenced by AlterRole(), and CreateRole().

116 {
117  PasswordType guessed_type = get_password_type(password);
118  char *encrypted_password;
119 
120  if (guessed_type != PASSWORD_TYPE_PLAINTEXT)
121  {
122  /*
123  * Cannot convert an already-encrypted password from one format to
124  * another, so return it as it is.
125  */
126  return pstrdup(password);
127  }
128 
129  switch (target_type)
130  {
131  case PASSWORD_TYPE_MD5:
132  encrypted_password = palloc(MD5_PASSWD_LEN + 1);
133 
134  if (!pg_md5_encrypt(password, role, strlen(role),
135  encrypted_password))
136  elog(ERROR, "password encryption failed");
137  return encrypted_password;
138 
141 
143  elog(ERROR, "cannot encrypt password with 'plaintext'");
144  }
145 
146  /*
147  * This shouldn't happen, because the above switch statements should
148  * handle every combination of source and target password types.
149  */
150  elog(ERROR, "cannot encrypt password to requested type");
151  return NULL; /* keep compiler quiet */
152 }
static char password[100]
Definition: streamutil.c:53
char * pstrdup(const char *in)
Definition: mcxt.c:1186
char * pg_be_scram_build_secret(const char *password)
Definition: auth-scram.c:451
bool pg_md5_encrypt(const char *passwd, const char *salt, size_t salt_len, char *buf)
Definition: md5.c:323
#define ERROR
Definition: elog.h:43
PasswordType
Definition: crypt.h:27
#define MD5_PASSWD_LEN
Definition: md5.h:20
void * palloc(Size size)
Definition: mcxt.c:949
PasswordType get_password_type(const char *shadow_pass)
Definition: crypt.c:89
#define elog(elevel,...)
Definition: elog.h:228

◆ get_password_type()

PasswordType get_password_type ( const char *  shadow_pass)

Definition at line 89 of file crypt.c.

References MD5_PASSWD_CHARSET, MD5_PASSWD_LEN, parse_scram_secret(), PASSWORD_TYPE_MD5, PASSWORD_TYPE_PLAINTEXT, PASSWORD_TYPE_SCRAM_SHA_256, and SCRAM_KEY_LEN.

Referenced by AlterRole(), CheckPWChallengeAuth(), CreateRole(), encrypt_password(), md5_crypt_verify(), pg_be_scram_init(), plain_crypt_verify(), and RenameRole().

90 {
91  char *encoded_salt;
92  int iterations;
93  uint8 stored_key[SCRAM_KEY_LEN];
94  uint8 server_key[SCRAM_KEY_LEN];
95 
96  if (strncmp(shadow_pass, "md5", 3) == 0 &&
97  strlen(shadow_pass) == MD5_PASSWD_LEN &&
98  strspn(shadow_pass + 3, MD5_PASSWD_CHARSET) == MD5_PASSWD_LEN - 3)
99  return PASSWORD_TYPE_MD5;
100  if (parse_scram_secret(shadow_pass, &iterations, &encoded_salt,
101  stored_key, server_key))
104 }
unsigned char uint8
Definition: c.h:357
#define MD5_PASSWD_CHARSET
Definition: md5.h:19
#define MD5_PASSWD_LEN
Definition: md5.h:20
bool parse_scram_secret(const char *secret, int *iterations, char **salt, uint8 *stored_key, uint8 *server_key)
Definition: auth-scram.c:556
#define SCRAM_KEY_LEN
Definition: scram-common.h:23

◆ get_role_password()

char* get_role_password ( const char *  role,
char **  logdetail 
)

Definition at line 37 of file crypt.c.

References _, AUTHNAME, DatumGetTimestampTz, GetCurrentTimestamp(), HeapTupleIsValid, PointerGetDatum, psprintf(), ReleaseSysCache(), SearchSysCache1(), SysCacheGetAttr(), and TextDatumGetCString.

Referenced by CheckPasswordAuth(), and CheckPWChallengeAuth().

38 {
39  TimestampTz vuntil = 0;
40  HeapTuple roleTup;
41  Datum datum;
42  bool isnull;
43  char *shadow_pass;
44 
45  /* Get role info from pg_authid */
46  roleTup = SearchSysCache1(AUTHNAME, PointerGetDatum(role));
47  if (!HeapTupleIsValid(roleTup))
48  {
49  *logdetail = psprintf(_("Role \"%s\" does not exist."),
50  role);
51  return NULL; /* no such user */
52  }
53 
54  datum = SysCacheGetAttr(AUTHNAME, roleTup,
55  Anum_pg_authid_rolpassword, &isnull);
56  if (isnull)
57  {
58  ReleaseSysCache(roleTup);
59  *logdetail = psprintf(_("User \"%s\" has no password assigned."),
60  role);
61  return NULL; /* user has no password */
62  }
63  shadow_pass = TextDatumGetCString(datum);
64 
65  datum = SysCacheGetAttr(AUTHNAME, roleTup,
66  Anum_pg_authid_rolvaliduntil, &isnull);
67  if (!isnull)
68  vuntil = DatumGetTimestampTz(datum);
69 
70  ReleaseSysCache(roleTup);
71 
72  /*
73  * Password OK, but check to be sure we are not past rolvaliduntil
74  */
75  if (!isnull && vuntil < GetCurrentTimestamp())
76  {
77  *logdetail = psprintf(_("User \"%s\" has an expired password."),
78  role);
79  return NULL;
80  }
81 
82  return shadow_pass;
83 }
TimestampTz GetCurrentTimestamp(void)
Definition: timestamp.c:1583
int64 TimestampTz
Definition: timestamp.h:39
#define PointerGetDatum(X)
Definition: postgres.h:556
char * psprintf(const char *fmt,...)
Definition: psprintf.c:46
#define DatumGetTimestampTz(X)
Definition: timestamp.h:28
HeapTuple SearchSysCache1(int cacheId, Datum key1)
Definition: syscache.c:1116
#define TextDatumGetCString(d)
Definition: builtins.h:84
uintptr_t Datum
Definition: postgres.h:367
void ReleaseSysCache(HeapTuple tuple)
Definition: syscache.c:1164
Datum SysCacheGetAttr(int cacheId, HeapTuple tup, AttrNumber attributeNumber, bool *isNull)
Definition: syscache.c:1377
#define HeapTupleIsValid(tuple)
Definition: htup.h:78
#define _(x)
Definition: elog.c:87

◆ md5_crypt_verify()

int md5_crypt_verify ( const char *  role,
const char *  shadow_pass,
const char *  client_pass,
const char *  md5_salt,
int  md5_salt_len,
char **  logdetail 
)

Definition at line 166 of file crypt.c.

References _, Assert, get_password_type(), MD5_PASSWD_LEN, PASSWORD_TYPE_MD5, pg_md5_encrypt(), psprintf(), STATUS_ERROR, and STATUS_OK.

Referenced by CheckMD5Auth().

170 {
171  int retval;
172  char crypt_pwd[MD5_PASSWD_LEN + 1];
173 
174  Assert(md5_salt_len > 0);
175 
176  if (get_password_type(shadow_pass) != PASSWORD_TYPE_MD5)
177  {
178  /* incompatible password hash format. */
179  *logdetail = psprintf(_("User \"%s\" has a password that cannot be used with MD5 authentication."),
180  role);
181  return STATUS_ERROR;
182  }
183 
184  /*
185  * Compute the correct answer for the MD5 challenge.
186  *
187  * We do not bother setting logdetail for any pg_md5_encrypt failure
188  * below: the only possible error is out-of-memory, which is unlikely, and
189  * if it did happen adding a psprintf call would only make things worse.
190  */
191  /* stored password already encrypted, only do salt */
192  if (!pg_md5_encrypt(shadow_pass + strlen("md5"),
193  md5_salt, md5_salt_len,
194  crypt_pwd))
195  {
196  return STATUS_ERROR;
197  }
198 
199  if (strcmp(client_pass, crypt_pwd) == 0)
200  retval = STATUS_OK;
201  else
202  {
203  *logdetail = psprintf(_("Password does not match for user \"%s\"."),
204  role);
205  retval = STATUS_ERROR;
206  }
207 
208  return retval;
209 }
char * psprintf(const char *fmt,...)
Definition: psprintf.c:46
#define STATUS_ERROR
Definition: c.h:1121
bool pg_md5_encrypt(const char *passwd, const char *salt, size_t salt_len, char *buf)
Definition: md5.c:323
#define STATUS_OK
Definition: c.h:1120
#define MD5_PASSWD_LEN
Definition: md5.h:20
#define Assert(condition)
Definition: c.h:739
PasswordType get_password_type(const char *shadow_pass)
Definition: crypt.c:89
#define _(x)
Definition: elog.c:87

◆ plain_crypt_verify()

int plain_crypt_verify ( const char *  role,
const char *  shadow_pass,
const char *  client_pass,
char **  logdetail 
)

Definition at line 222 of file crypt.c.

References _, get_password_type(), MD5_PASSWD_LEN, PASSWORD_TYPE_MD5, PASSWORD_TYPE_PLAINTEXT, PASSWORD_TYPE_SCRAM_SHA_256, pg_md5_encrypt(), psprintf(), scram_verify_plain_password(), STATUS_ERROR, and STATUS_OK.

Referenced by AlterRole(), check_password(), CheckPasswordAuth(), and CreateRole().

225 {
226  char crypt_client_pass[MD5_PASSWD_LEN + 1];
227 
228  /*
229  * Client sent password in plaintext. If we have an MD5 hash stored, hash
230  * the password the client sent, and compare the hashes. Otherwise
231  * compare the plaintext passwords directly.
232  */
233  switch (get_password_type(shadow_pass))
234  {
237  client_pass,
238  shadow_pass))
239  {
240  return STATUS_OK;
241  }
242  else
243  {
244  *logdetail = psprintf(_("Password does not match for user \"%s\"."),
245  role);
246  return STATUS_ERROR;
247  }
248  break;
249 
250  case PASSWORD_TYPE_MD5:
251  if (!pg_md5_encrypt(client_pass,
252  role,
253  strlen(role),
254  crypt_client_pass))
255  {
256  /*
257  * We do not bother setting logdetail for pg_md5_encrypt
258  * failure: the only possible error is out-of-memory, which is
259  * unlikely, and if it did happen adding a psprintf call would
260  * only make things worse.
261  */
262  return STATUS_ERROR;
263  }
264  if (strcmp(crypt_client_pass, shadow_pass) == 0)
265  return STATUS_OK;
266  else
267  {
268  *logdetail = psprintf(_("Password does not match for user \"%s\"."),
269  role);
270  return STATUS_ERROR;
271  }
272  break;
273 
275 
276  /*
277  * We never store passwords in plaintext, so this shouldn't
278  * happen.
279  */
280  break;
281  }
282 
283  /*
284  * This shouldn't happen. Plain "password" authentication is possible
285  * with any kind of stored password hash.
286  */
287  *logdetail = psprintf(_("Password of user \"%s\" is in unrecognized format."),
288  role);
289  return STATUS_ERROR;
290 }
char * psprintf(const char *fmt,...)
Definition: psprintf.c:46
#define STATUS_ERROR
Definition: c.h:1121
bool pg_md5_encrypt(const char *passwd, const char *salt, size_t salt_len, char *buf)
Definition: md5.c:323
bool scram_verify_plain_password(const char *username, const char *password, const char *secret)
Definition: auth-scram.c:488
#define STATUS_OK
Definition: c.h:1120
#define MD5_PASSWD_LEN
Definition: md5.h:20
PasswordType get_password_type(const char *shadow_pass)
Definition: crypt.c:89
#define _(x)
Definition: elog.c:87