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 }
 

Functions

PasswordType get_password_type (const char *shadow_pass)
 
char * encrypt_password (PasswordType target_type, const char *role, const char *password)
 
int get_role_password (const char *role, char **shadow_pass, 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 

Definition at line 24 of file crypt.h.

Function Documentation

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

Definition at line 126 of file crypt.c.

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

Referenced by AlterRole(), and CreateRole().

128 {
129  PasswordType guessed_type = get_password_type(password);
130  char *encrypted_password;
131 
132  switch (target_type)
133  {
135 
136  /*
137  * We cannot convert a hashed password back to plaintext, so just
138  * store the password as it was, whether it was hashed or not.
139  */
140  return pstrdup(password);
141 
142  case PASSWORD_TYPE_MD5:
143  switch (guessed_type)
144  {
146  encrypted_password = palloc(MD5_PASSWD_LEN + 1);
147 
148  if (!pg_md5_encrypt(password, role, strlen(role),
149  encrypted_password))
150  elog(ERROR, "password encryption failed");
151  return encrypted_password;
152 
153  case PASSWORD_TYPE_MD5:
154  return pstrdup(password);
155  }
156  }
157 
158  /*
159  * This shouldn't happen, because the above switch statements should
160  * handle every combination of source and target password types.
161  */
162  elog(ERROR, "cannot encrypt password to requested type");
163  return NULL; /* keep compiler quiet */
164 }
static char password[100]
Definition: streamutil.c:44
char * pstrdup(const char *in)
Definition: mcxt.c:1165
PasswordType get_password_type(const char *shadow_pass)
Definition: crypt.c:110
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:24
#define MD5_PASSWD_LEN
Definition: md5.h:19
#define NULL
Definition: c.h:226
void * palloc(Size size)
Definition: mcxt.c:891
#define elog
Definition: elog.h:219
PasswordType get_password_type ( const char *  shadow_pass)

Definition at line 110 of file crypt.c.

References MD5_PASSWD_LEN, PASSWORD_TYPE_MD5, and PASSWORD_TYPE_PLAINTEXT.

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

111 {
112  if (strncmp(shadow_pass, "md5", 3) == 0 && strlen(shadow_pass) == MD5_PASSWD_LEN)
113  return PASSWORD_TYPE_MD5;
115 }
#define MD5_PASSWD_LEN
Definition: md5.h:19
int get_role_password ( const char *  role,
char **  shadow_pass,
char **  logdetail 
)

Definition at line 43 of file crypt.c.

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

Referenced by CheckMD5Auth(), and CheckPasswordAuth().

44 {
45  int retval = STATUS_ERROR;
46  TimestampTz vuntil = 0;
47  HeapTuple roleTup;
48  Datum datum;
49  bool isnull;
50 
51  *shadow_pass = NULL;
52 
53  /* Get role info from pg_authid */
54  roleTup = SearchSysCache1(AUTHNAME, PointerGetDatum(role));
55  if (!HeapTupleIsValid(roleTup))
56  {
57  *logdetail = psprintf(_("Role \"%s\" does not exist."),
58  role);
59  return STATUS_ERROR; /* no such user */
60  }
61 
62  datum = SysCacheGetAttr(AUTHNAME, roleTup,
64  if (isnull)
65  {
66  ReleaseSysCache(roleTup);
67  *logdetail = psprintf(_("User \"%s\" has no password assigned."),
68  role);
69  return STATUS_ERROR; /* user has no password */
70  }
71  *shadow_pass = TextDatumGetCString(datum);
72 
73  datum = SysCacheGetAttr(AUTHNAME, roleTup,
75  if (!isnull)
76  vuntil = DatumGetTimestampTz(datum);
77 
78  ReleaseSysCache(roleTup);
79 
80  if (**shadow_pass == '\0')
81  {
82  *logdetail = psprintf(_("User \"%s\" has an empty password."),
83  role);
84  pfree(*shadow_pass);
85  *shadow_pass = NULL;
86  return STATUS_ERROR; /* empty password */
87  }
88 
89  /*
90  * Password OK, now check to be sure we are not past rolvaliduntil
91  */
92  if (isnull)
93  retval = STATUS_OK;
94  else if (vuntil < GetCurrentTimestamp())
95  {
96  *logdetail = psprintf(_("User \"%s\" has an expired password."),
97  role);
98  retval = STATUS_ERROR;
99  }
100  else
101  retval = STATUS_OK;
102 
103  return retval;
104 }
TimestampTz GetCurrentTimestamp(void)
Definition: timestamp.c:1569
int64 TimestampTz
Definition: timestamp.h:39
#define PointerGetDatum(X)
Definition: postgres.h:564
char * psprintf(const char *fmt,...)
Definition: psprintf.c:46
#define STATUS_ERROR
Definition: c.h:972
#define Anum_pg_authid_rolpassword
Definition: pg_authid.h:88
#define SearchSysCache1(cacheId, key1)
Definition: syscache.h:149
void pfree(void *pointer)
Definition: mcxt.c:992
#define Anum_pg_authid_rolvaliduntil
Definition: pg_authid.h:89
#define DatumGetTimestampTz(X)
Definition: timestamp.h:28
#define STATUS_OK
Definition: c.h:971
#define TextDatumGetCString(d)
Definition: builtins.h:91
uintptr_t Datum
Definition: postgres.h:374
void ReleaseSysCache(HeapTuple tuple)
Definition: syscache.c:1083
Datum SysCacheGetAttr(int cacheId, HeapTuple tup, AttrNumber attributeNumber, bool *isNull)
Definition: syscache.c:1245
#define HeapTupleIsValid(tuple)
Definition: htup.h:77
#define NULL
Definition: c.h:226
#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 178 of file crypt.c.

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

Referenced by CheckMD5Auth().

182 {
183  int retval;
184  char crypt_pwd[MD5_PASSWD_LEN + 1];
185  char crypt_pwd2[MD5_PASSWD_LEN + 1];
186 
187  Assert(md5_salt_len > 0);
188 
189  /*
190  * Compute the correct answer for the MD5 challenge.
191  *
192  * We do not bother setting logdetail for any pg_md5_encrypt failure
193  * below: the only possible error is out-of-memory, which is unlikely, and
194  * if it did happen adding a psprintf call would only make things worse.
195  */
196  switch (get_password_type(shadow_pass))
197  {
198  case PASSWORD_TYPE_MD5:
199  /* stored password already encrypted, only do salt */
200  if (!pg_md5_encrypt(shadow_pass + strlen("md5"),
201  md5_salt, md5_salt_len,
202  crypt_pwd))
203  {
204  return STATUS_ERROR;
205  }
206  break;
207 
209  /* stored password is plain, double-encrypt */
210  if (!pg_md5_encrypt(shadow_pass,
211  role,
212  strlen(role),
213  crypt_pwd2))
214  {
215  return STATUS_ERROR;
216  }
217  if (!pg_md5_encrypt(crypt_pwd2 + strlen("md5"),
218  md5_salt, md5_salt_len,
219  crypt_pwd))
220  {
221  return STATUS_ERROR;
222  }
223  break;
224 
225  default:
226  /* unknown password hash format. */
227  *logdetail = psprintf(_("User \"%s\" has a password that cannot be used with MD5 authentication."),
228  role);
229  return STATUS_ERROR;
230  }
231 
232  if (strcmp(client_pass, crypt_pwd) == 0)
233  retval = STATUS_OK;
234  else
235  {
236  *logdetail = psprintf(_("Password does not match for user \"%s\"."),
237  role);
238  retval = STATUS_ERROR;
239  }
240 
241  return retval;
242 }
PasswordType get_password_type(const char *shadow_pass)
Definition: crypt.c:110
char * psprintf(const char *fmt,...)
Definition: psprintf.c:46
#define STATUS_ERROR
Definition: c.h:972
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:971
#define MD5_PASSWD_LEN
Definition: md5.h:19
#define Assert(condition)
Definition: c.h:671
#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 255 of file crypt.c.

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

Referenced by check_password(), and CheckPasswordAuth().

258 {
259  int retval;
260  char crypt_client_pass[MD5_PASSWD_LEN + 1];
261 
262  /*
263  * Client sent password in plaintext. If we have an MD5 hash stored, hash
264  * the password the client sent, and compare the hashes. Otherwise
265  * compare the plaintext passwords directly.
266  */
267  switch (get_password_type(shadow_pass))
268  {
269  case PASSWORD_TYPE_MD5:
270  if (!pg_md5_encrypt(client_pass,
271  role,
272  strlen(role),
273  crypt_client_pass))
274  {
275  /*
276  * We do not bother setting logdetail for pg_md5_encrypt
277  * failure: the only possible error is out-of-memory, which is
278  * unlikely, and if it did happen adding a psprintf call would
279  * only make things worse.
280  */
281  return STATUS_ERROR;
282  }
283  client_pass = crypt_client_pass;
284  break;
286  break;
287 
288  default:
289 
290  /*
291  * This shouldn't happen. Plain "password" authentication should
292  * be possible with any kind of stored password hash.
293  */
294  *logdetail = psprintf(_("Password of user \"%s\" is in unrecognized format."),
295  role);
296  return STATUS_ERROR;
297  }
298 
299  if (strcmp(client_pass, shadow_pass) == 0)
300  retval = STATUS_OK;
301  else
302  {
303  *logdetail = psprintf(_("Password does not match for user \"%s\"."),
304  role);
305  retval = STATUS_ERROR;
306  }
307 
308  return retval;
309 }
PasswordType get_password_type(const char *shadow_pass)
Definition: crypt.c:110
char * psprintf(const char *fmt,...)
Definition: psprintf.c:46
#define STATUS_ERROR
Definition: c.h:972
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:971
#define MD5_PASSWD_LEN
Definition: md5.h:19
#define _(x)
Definition: elog.c:84