Skip to content

Commit c6305a9

Browse files
committed
Allow plaintext 'password' authentication when user has a SCRAM verifier.
Oversight in the main SCRAM patch.
1 parent ff30aec commit c6305a9

File tree

3 files changed

+87
-22
lines changed

3 files changed

+87
-22
lines changed

src/backend/libpq/auth-scram.c

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -364,6 +364,52 @@ scram_build_verifier(const char *username, const char *password,
364364
return psprintf("scram-sha-256:%s:%d:%s:%s", encoded_salt, iterations, storedkey_hex, serverkey_hex);
365365
}
366366

367+
/*
368+
* Verify a plaintext password against a SCRAM verifier. This is used when
369+
* performing plaintext password authentication for a user that has a SCRAM
370+
* verifier stored in pg_authid.
371+
*/
372+
bool
373+
scram_verify_plain_password(const char *username, const char *password,
374+
const char *verifier)
375+
{
376+
char *encoded_salt;
377+
char *salt;
378+
int saltlen;
379+
int iterations;
380+
uint8 stored_key[SCRAM_KEY_LEN];
381+
uint8 server_key[SCRAM_KEY_LEN];
382+
uint8 computed_key[SCRAM_KEY_LEN];
383+
384+
if (!parse_scram_verifier(verifier, &encoded_salt, &iterations,
385+
stored_key, server_key))
386+
{
387+
/*
388+
* The password looked like a SCRAM verifier, but could not be
389+
* parsed.
390+
*/
391+
elog(LOG, "invalid SCRAM verifier for user \"%s\"", username);
392+
return false;
393+
}
394+
395+
salt = palloc(pg_b64_dec_len(strlen(encoded_salt)));
396+
saltlen = pg_b64_decode(encoded_salt, strlen(encoded_salt), salt);
397+
if (saltlen == -1)
398+
{
399+
elog(LOG, "invalid SCRAM verifier for user \"%s\"", username);
400+
return false;
401+
}
402+
403+
/* Compute Server key based on the user-supplied plaintext password */
404+
scram_ClientOrServerKey(password, salt, saltlen, iterations,
405+
SCRAM_SERVER_KEY_NAME, computed_key);
406+
407+
/*
408+
* Compare the verifier's Server Key with the one computed from the
409+
* user-supplied password.
410+
*/
411+
return memcmp(computed_key, server_key, SCRAM_KEY_LEN) == 0;
412+
}
367413

368414
/*
369415
* Check if given verifier can be used for SCRAM authentication.

src/backend/libpq/crypt.c

Lines changed: 39 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -283,7 +283,6 @@ plain_crypt_verify(const char *role, const char *shadow_pass,
283283
const char *client_pass,
284284
char **logdetail)
285285
{
286-
int retval;
287286
char crypt_client_pass[MD5_PASSWD_LEN + 1];
288287

289288
/*
@@ -293,6 +292,21 @@ plain_crypt_verify(const char *role, const char *shadow_pass,
293292
*/
294293
switch (get_password_type(shadow_pass))
295294
{
295+
case PASSWORD_TYPE_SCRAM:
296+
if (scram_verify_plain_password(role,
297+
client_pass,
298+
shadow_pass))
299+
{
300+
return STATUS_OK;
301+
}
302+
else
303+
{
304+
*logdetail = psprintf(_("Password does not match for user \"%s\"."),
305+
role);
306+
return STATUS_ERROR;
307+
}
308+
break;
309+
296310
case PASSWORD_TYPE_MD5:
297311
if (!pg_md5_encrypt(client_pass,
298312
role,
@@ -307,30 +321,33 @@ plain_crypt_verify(const char *role, const char *shadow_pass,
307321
*/
308322
return STATUS_ERROR;
309323
}
310-
client_pass = crypt_client_pass;
324+
if (strcmp(crypt_client_pass, shadow_pass) == 0)
325+
return STATUS_OK;
326+
else
327+
{
328+
*logdetail = psprintf(_("Password does not match for user \"%s\"."),
329+
role);
330+
return STATUS_ERROR;
331+
}
311332
break;
333+
312334
case PASSWORD_TYPE_PLAINTEXT:
335+
if (strcmp(client_pass, shadow_pass) == 0)
336+
return STATUS_OK;
337+
else
338+
{
339+
*logdetail = psprintf(_("Password does not match for user \"%s\"."),
340+
role);
341+
return STATUS_ERROR;
342+
}
313343
break;
314-
315-
default:
316-
317-
/*
318-
* This shouldn't happen. Plain "password" authentication should
319-
* be possible with any kind of stored password hash.
320-
*/
321-
*logdetail = psprintf(_("Password of user \"%s\" is in unrecognized format."),
322-
role);
323-
return STATUS_ERROR;
324344
}
325345

326-
if (strcmp(client_pass, shadow_pass) == 0)
327-
retval = STATUS_OK;
328-
else
329-
{
330-
*logdetail = psprintf(_("Password does not match for user \"%s\"."),
331-
role);
332-
retval = STATUS_ERROR;
333-
}
334-
335-
return retval;
346+
/*
347+
* This shouldn't happen. Plain "password" authentication is possible
348+
* with any kind of stored password hash.
349+
*/
350+
*logdetail = psprintf(_("Password of user \"%s\" is in unrecognized format."),
351+
role);
352+
return STATUS_ERROR;
336353
}

src/include/libpq/scram.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,5 +31,7 @@ extern char *scram_build_verifier(const char *username,
3131
const char *password,
3232
int iterations);
3333
extern bool is_scram_verifier(const char *verifier);
34+
extern bool scram_verify_plain_password(const char *username,
35+
const char *password, const char *verifier);
3436

3537
#endif /* PG_SCRAM_H */

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy