diff options
Diffstat (limited to 'src/interfaces/libpq/fe-auth.c')
-rw-r--r-- | src/interfaces/libpq/fe-auth.c | 125 |
1 files changed, 113 insertions, 12 deletions
diff --git a/src/interfaces/libpq/fe-auth.c b/src/interfaces/libpq/fe-auth.c index d81ee4f9447..daa7cc95858 100644 --- a/src/interfaces/libpq/fe-auth.c +++ b/src/interfaces/libpq/fe-auth.c @@ -1077,7 +1077,33 @@ pg_fe_getauthname(PQExpBuffer errorMessage) /* - * PQencryptPassword -- exported routine to encrypt a password + * PQencryptPassword -- exported routine to encrypt a password with MD5 + * + * This function is equivalent to calling PQencryptPasswordConn with + * "md5" as the encryption method, except that this doesn't require + * a connection object. This function is deprecated, use + * PQencryptPasswordConn instead. + */ +char * +PQencryptPassword(const char *passwd, const char *user) +{ + char *crypt_pwd; + + crypt_pwd = malloc(MD5_PASSWD_LEN + 1); + if (!crypt_pwd) + return NULL; + + if (!pg_md5_encrypt(passwd, user, strlen(user), crypt_pwd)) + { + free(crypt_pwd); + return NULL; + } + + return crypt_pwd; +} + +/* + * PQencryptPasswordConn -- exported routine to encrypt a password * * This is intended to be used by client applications that wish to send * commands like ALTER USER joe PASSWORD 'pwd'. The password need not @@ -1087,27 +1113,102 @@ 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 a connection object, the cleartext password, the SQL + * name of the user it is for, and a string indicating the algorithm to + * use for encrypting the password. If algorithm is NULL, this queries + * the server for the current 'password_encryption' value. If you wish + * to avoid that, e.g. to avoid blocking, you can execute + * 'show password_encryption' yourself before calling this function, and + * pass it as the algorithm. * - * 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. The client may assume the string + * doesn't contain any special characters that would require escaping. + * On error, an error message is stored in the connection object, and + * returns NULL. */ char * -PQencryptPassword(const char *passwd, const char *user) +PQencryptPasswordConn(PGconn *conn, const char *passwd, const char *user, + const char *algorithm) { - char *crypt_pwd; +#define MAX_ALGORITHM_NAME_LEN 50 + char algobuf[MAX_ALGORITHM_NAME_LEN + 1]; + char *crypt_pwd = NULL; - crypt_pwd = malloc(MD5_PASSWD_LEN + 1); - if (!crypt_pwd) + if (!conn) return NULL; - if (!pg_md5_encrypt(passwd, user, strlen(user), crypt_pwd)) + /* If no algorithm was given, ask the server. */ + if (algorithm == NULL) { - free(crypt_pwd); + PGresult *res; + char *val; + + res = PQexec(conn, "show password_encryption"); + if (res == NULL) + { + /* PQexec() should've set conn->errorMessage already */ + return NULL; + } + if (PQresultStatus(res) != PGRES_TUPLES_OK) + { + /* PQexec() should've set conn->errorMessage already */ + PQclear(res); + return NULL; + } + if (PQntuples(res) != 1 || PQnfields(res) != 1) + { + PQclear(res); + printfPQExpBuffer(&conn->errorMessage, + libpq_gettext("unexpected shape of result set returned for SHOW\n")); + return NULL; + } + val = PQgetvalue(res, 0, 0); + + if (strlen(val) > MAX_ALGORITHM_NAME_LEN) + { + PQclear(res); + printfPQExpBuffer(&conn->errorMessage, + libpq_gettext("password_encryption value too long\n")); + return NULL; + } + strcpy(algobuf, val); + PQclear(res); + + algorithm = algobuf; + } + + /* Ok, now we know what algorithm to use */ + + if (strcmp(algorithm, "scram-sha-256") == 0) + { + crypt_pwd = pg_fe_scram_build_verifier(passwd); + } + else if (strcmp(algorithm, "md5") == 0) + { + crypt_pwd = malloc(MD5_PASSWD_LEN + 1); + if (crypt_pwd) + { + if (!pg_md5_encrypt(passwd, user, strlen(user), crypt_pwd)) + { + free(crypt_pwd); + crypt_pwd = NULL; + } + } + } + else if (strcmp(algorithm, "plain") == 0) + { + crypt_pwd = strdup(passwd); + } + else + { + printfPQExpBuffer(&conn->errorMessage, + libpq_gettext("unknown password encryption algorithm\n")); return NULL; } + if (!crypt_pwd) + printfPQExpBuffer(&conn->errorMessage, + libpq_gettext("out of memory\n")); + return crypt_pwd; } |