PostgreSQL Source Code  git master
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros
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

Enumeration Type Documentation

Enumerator
PASSWORD_TYPE_PLAINTEXT 
PASSWORD_TYPE_MD5 
PASSWORD_TYPE_SCRAM_SHA_256 

Definition at line 27 of file crypt.h.

Function Documentation

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

Definition at line 116 of file crypt.c.

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

Referenced by AlterRole(), and CreateRole().

118 {
119  PasswordType guessed_type = get_password_type(password);
120  char *encrypted_password;
121 
122  if (guessed_type != PASSWORD_TYPE_PLAINTEXT)
123  {
124  /*
125  * Cannot convert an already-encrypted password from one format to
126  * another, so return it as it is.
127  */
128  return pstrdup(password);
129  }
130 
131  switch (target_type)
132  {
133  case PASSWORD_TYPE_MD5:
134  encrypted_password = palloc(MD5_PASSWD_LEN + 1);
135 
136  if (!pg_md5_encrypt(password, role, strlen(role),
137  encrypted_password))
138  elog(ERROR, "password encryption failed");
139  return encrypted_password;
140 
143 
145  elog(ERROR, "cannot encrypt password with 'plaintext'");
146  }
147 
148  /*
149  * This shouldn't happen, because the above switch statements should
150  * handle every combination of source and target password types.
151  */
152  elog(ERROR, "cannot encrypt password to requested type");
153  return NULL; /* keep compiler quiet */
154 }
static char password[100]
Definition: streamutil.c:41
char * pstrdup(const char *in)
Definition: mcxt.c:1077
PasswordType get_password_type(const char *shadow_pass)
Definition: crypt.c:99
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:19
#define NULL
Definition: c.h:229
void * palloc(Size size)
Definition: mcxt.c:849
#define elog
Definition: elog.h:219
char * pg_be_scram_build_verifier(const char *password)
Definition: auth-scram.c:376
PasswordType get_password_type ( const char *  shadow_pass)

Definition at line 99 of file crypt.c.

References MD5_PASSWD_LEN, PASSWORD_TYPE_MD5, PASSWORD_TYPE_PLAINTEXT, and PASSWORD_TYPE_SCRAM_SHA_256.

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

100 {
101  if (strncmp(shadow_pass, "md5", 3) == 0 && strlen(shadow_pass) == MD5_PASSWD_LEN)
102  return PASSWORD_TYPE_MD5;
103  if (strncmp(shadow_pass, "SCRAM-SHA-256$", strlen("SCRAM-SHA-256$")) == 0)
106 }
#define MD5_PASSWD_LEN
Definition: md5.h:19
char* get_role_password ( const char *  role,
char **  logdetail 
)

Definition at line 39 of file crypt.c.

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

Referenced by CheckPasswordAuth(), and CheckPWChallengeAuth().

40 {
41  TimestampTz vuntil = 0;
42  HeapTuple roleTup;
43  Datum datum;
44  bool isnull;
45  char *shadow_pass;
46 
47  /* Get role info from pg_authid */
48  roleTup = SearchSysCache1(AUTHNAME, PointerGetDatum(role));
49  if (!HeapTupleIsValid(roleTup))
50  {
51  *logdetail = psprintf(_("Role \"%s\" does not exist."),
52  role);
53  return NULL; /* no such user */
54  }
55 
56  datum = SysCacheGetAttr(AUTHNAME, roleTup,
58  if (isnull)
59  {
60  ReleaseSysCache(roleTup);
61  *logdetail = psprintf(_("User \"%s\" has no password assigned."),
62  role);
63  return NULL; /* user has no password */
64  }
65  shadow_pass = TextDatumGetCString(datum);
66 
67  datum = SysCacheGetAttr(AUTHNAME, roleTup,
69  if (!isnull)
70  vuntil = DatumGetTimestampTz(datum);
71 
72  ReleaseSysCache(roleTup);
73 
74  if (*shadow_pass == '\0')
75  {
76  *logdetail = psprintf(_("User \"%s\" has an empty password."),
77  role);
78  pfree(shadow_pass);
79  return NULL; /* empty password */
80  }
81 
82  /*
83  * Password OK, but check to be sure we are not past rolvaliduntil
84  */
85  if (!isnull && vuntil < GetCurrentTimestamp())
86  {
87  *logdetail = psprintf(_("User \"%s\" has an expired password."),
88  role);
89  return NULL;
90  }
91 
92  return shadow_pass;
93 }
TimestampTz GetCurrentTimestamp(void)
Definition: timestamp.c:1570
int64 TimestampTz
Definition: timestamp.h:39
#define PointerGetDatum(X)
Definition: postgres.h:562
char * psprintf(const char *fmt,...)
Definition: psprintf.c:46
#define Anum_pg_authid_rolpassword
Definition: pg_authid.h:88
#define SearchSysCache1(cacheId, key1)
Definition: syscache.h:156
void pfree(void *pointer)
Definition: mcxt.c:950
#define Anum_pg_authid_rolvaliduntil
Definition: pg_authid.h:89
#define DatumGetTimestampTz(X)
Definition: timestamp.h:28
#define TextDatumGetCString(d)
Definition: builtins.h:92
uintptr_t Datum
Definition: postgres.h:372
void ReleaseSysCache(HeapTuple tuple)
Definition: syscache.c:1117
Datum SysCacheGetAttr(int cacheId, HeapTuple tup, AttrNumber attributeNumber, bool *isNull)
Definition: syscache.c:1279
#define HeapTupleIsValid(tuple)
Definition: htup.h:77
#define NULL
Definition: c.h:229
#define _(x)
Definition: elog.c:84
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 168 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().

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

Definition at line 224 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 check_password(), and CheckPasswordAuth().

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