From 2c06cfea054dab44b8df393700e052ff01e3bd22 Mon Sep 17 00:00:00 2001 From: Michael Paquier Date: Fri, 7 Apr 2017 10:39:27 +0900 Subject: [PATCH 4/5] Extend PQencryptPassword with a hashing method This extra argument can use the following values when hashing the password: - scram, for SCRAM-SHA-256 hashing. - md5, for MD5 hashing. - plain, for cleartext. --- doc/src/sgml/libpq.sgml | 6 ++++- src/bin/psql/command.c | 2 +- src/bin/scripts/createuser.c | 3 ++- src/interfaces/libpq/fe-auth.c | 54 ++++++++++++++++++++++++++++++++--------- src/interfaces/libpq/libpq-fe.h | 3 ++- 5 files changed, 52 insertions(+), 16 deletions(-) diff --git a/doc/src/sgml/libpq.sgml b/doc/src/sgml/libpq.sgml index 4bc5bf3192..fc1aa4b5e5 100644 --- a/doc/src/sgml/libpq.sgml +++ b/doc/src/sgml/libpq.sgml @@ -5887,7 +5887,8 @@ void PQconninfoFree(PQconninfoOption *connOptions); Prepares the encrypted form of a PostgreSQL password. -char * PQencryptPassword(const char *passwd, const char *user); +char * PQencryptPassword(const char *passwd, const char *user, + const char *method); This function is intended to be used by client applications that wish to send commands like ALTER USER joe PASSWORD @@ -5901,6 +5902,9 @@ char * PQencryptPassword(const char *passwd, const char *user); memory. The caller can assume the string doesn't contain any special characters that would require escaping. Use PQfreemem to free the result when done with it. + The encryption method of the password can be specified as + md5 for hashing with MD5, scram for + hashing with SCRAM-SHA-256 and plain for cleartext. diff --git a/src/bin/psql/command.c b/src/bin/psql/command.c index 494f468575..9716c98fc2 100644 --- a/src/bin/psql/command.c +++ b/src/bin/psql/command.c @@ -1882,7 +1882,7 @@ exec_command_password(PsqlScanState scan_state, bool active_branch) else user = PQuser(pset.db); - encrypted_password = PQencryptPassword(pw1, user); + encrypted_password = PQencryptPassword(pw1, user, "md5"); if (!encrypted_password) { diff --git a/src/bin/scripts/createuser.c b/src/bin/scripts/createuser.c index 3d74797a8f..5af263e34a 100644 --- a/src/bin/scripts/createuser.c +++ b/src/bin/scripts/createuser.c @@ -275,7 +275,8 @@ main(int argc, char *argv[]) char *encrypted_password; encrypted_password = PQencryptPassword(newpassword, - newuser); + newuser, + "md5"); if (!encrypted_password) { fprintf(stderr, _("Password encryption failed.\n")); diff --git a/src/interfaces/libpq/fe-auth.c b/src/interfaces/libpq/fe-auth.c index 5fe7e565a0..40d4be3ca6 100644 --- a/src/interfaces/libpq/fe-auth.c +++ b/src/interfaces/libpq/fe-auth.c @@ -39,6 +39,7 @@ #endif #include "common/md5.h" +#include "common/scram-common.h" #include "libpq-fe.h" #include "libpq/scram.h" #include "fe-auth.h" @@ -919,27 +920,56 @@ pg_fe_getauthname(PQExpBuffer errorMessage) * be dependent on low-level details like whether the encryption is MD5 * or something else. * - * Arguments are the cleartext password, and the SQL name of the user it - * is for. + * Arguments are the cleartext password, the SQL name of the user it + * is for, and the name of password hashing method: + * - "scram", to hash password using SCRAM-SHA-256. + * - "md5", to hash password using MD5. + * - "plain", to get a cleartext value of password. * - * Return value is a malloc'd string, or NULL if out-of-memory. The client - * may assume the string doesn't contain any special characters that would - * require escaping. + * Return value is a malloc'd string, or NULL if out-of-memory or in + * the event of an error. The client may assume the string doesn't + * contain any special characters that would require escaping. */ char * -PQencryptPassword(const char *passwd, const char *user) +PQencryptPassword(const char *passwd, const char *user, const char *method) { char *crypt_pwd; - crypt_pwd = malloc(MD5_PASSWD_LEN + 1); - if (!crypt_pwd) - return NULL; + if (strcmp(method, "md5") == 0) + { + crypt_pwd = malloc(MD5_PASSWD_LEN + 1); + if (!crypt_pwd) + return NULL; - if (!pg_md5_encrypt(passwd, user, strlen(user), crypt_pwd)) + if (!pg_md5_encrypt(passwd, user, strlen(user), crypt_pwd)) + { + free(crypt_pwd); + return NULL; + } + } + else if (strcmp(method, "scram") == 0) { - free(crypt_pwd); - return NULL; + char salt[SCRAM_SALT_LEN]; + + crypt_pwd = malloc(SCRAM_VERIFIER_LEN + 1); + if (!crypt_pwd) + return NULL; + + if (!pg_frontend_random(salt, SCRAM_SALT_LEN)) + return NULL; + + if (!scram_build_verifier(user, passwd, salt, 0, crypt_pwd)) + { + free(crypt_pwd); + return NULL; + } } + else if (strcmp(method, "plain") == 0) + { + crypt_pwd = strdup(passwd); + } + else + return NULL; return crypt_pwd; } diff --git a/src/interfaces/libpq/libpq-fe.h b/src/interfaces/libpq/libpq-fe.h index 635af5b50e..c312dd0152 100644 --- a/src/interfaces/libpq/libpq-fe.h +++ b/src/interfaces/libpq/libpq-fe.h @@ -596,7 +596,8 @@ extern int PQenv2encoding(void); /* === in fe-auth.c === */ -extern char *PQencryptPassword(const char *passwd, const char *user); +extern char *PQencryptPassword(const char *passwd, const char *user, + const char *method); /* === in encnames.c === */ -- 2.12.2