From ea9b028dc77e961b290087972b9bfbe8e91ce82f Mon Sep 17 00:00:00 2001 From: Tom Lane Date: Fri, 23 Dec 2005 01:16:38 +0000 Subject: [PATCH] Add an officially exported libpq function to encrypt passwords, and modify the previous \password patch to use it instead of depending on a not-officially-exported function. Per discussion. --- doc/src/sgml/libpq.sgml | 36 ++++++++++++++++++++++++++++- src/bin/psql/command.c | 13 ++++++----- src/bin/scripts/createuser.c | 10 ++++---- src/interfaces/libpq/exports.txt | 3 ++- src/interfaces/libpq/fe-auth.c | 39 +++++++++++++++++++++++++++++++- src/interfaces/libpq/libpq-fe.h | 6 ++++- 6 files changed, 93 insertions(+), 14 deletions(-) diff --git a/doc/src/sgml/libpq.sgml b/doc/src/sgml/libpq.sgml index 5b0444190c..df0ad527ae 100644 --- a/doc/src/sgml/libpq.sgml +++ b/doc/src/sgml/libpq.sgml @@ -1,5 +1,5 @@ @@ -3565,6 +3565,40 @@ void PQuntrace(PGconn *conn); + +Miscellaneous Functions + + +As always, there are some functions that just don't fit anywhere. + + + + +pg_make_encrypted_passwordpg_make_encrypted_password + + +Prepares the encrypted form of a PostgreSQL password. + +char *pg_make_encrypted_password(const char *passwd, const char *user); + +pg_make_encrypted_password is intended to be used by client +applications that wish to send commands like +ALTER USER joe PASSWORD 'pwd'. +It is good practice not to send the original cleartext password in such a +command, because it might be exposed in command logs, activity displays, +and so on. Instead, use this function to convert the password to encrypted +form before it is sent. The arguments are the cleartext password, and the SQL +name of the user it is for. The return value is a malloc'd string, or NULL if +out-of-memory. The caller may assume the string doesn't contain any weird +characters that would require escaping. Use PQfreemem to free +the result when done with it. + + + + + + + Notice Processing diff --git a/src/bin/psql/command.c b/src/bin/psql/command.c index 35da9cdf82..6e5ddf5369 100644 --- a/src/bin/psql/command.c +++ b/src/bin/psql/command.c @@ -3,7 +3,7 @@ * * Copyright (c) 2000-2005, PostgreSQL Global Development Group * - * $PostgreSQL: pgsql/src/bin/psql/command.c,v 1.156 2005/12/18 02:17:16 petere Exp $ + * $PostgreSQL: pgsql/src/bin/psql/command.c,v 1.157 2005/12/23 01:16:38 tgl Exp $ */ #include "postgres_fe.h" #include "command.h" @@ -12,7 +12,6 @@ #undef mkdir #endif -#include #include #ifdef HAVE_PWD_H #include @@ -35,7 +34,6 @@ #include "libpq-fe.h" #include "pqexpbuffer.h" -#include "libpq/crypt.h" #include "dumputils.h" #include "common.h" @@ -638,14 +636,16 @@ exec_command(const char *cmd, { char *opt0 = psql_scan_slash_option(scan_state, OT_SQLID, NULL, true); char *user; - char encrypted_password[MD5_PASSWD_LEN + 1]; + char *encrypted_password; if (opt0) user = opt0; else user = PQuser(pset.db); - if (!pg_md5_encrypt(pw1, user, strlen(user), encrypted_password)) + encrypted_password = pg_make_encrypted_password(pw1, user); + + if (!encrypted_password) { fprintf(stderr, _("Password encryption failed.\n")); success = false; @@ -656,7 +656,7 @@ exec_command(const char *cmd, PGresult *res; initPQExpBuffer(&buf); - printfPQExpBuffer(&buf, "ALTER ROLE %s PASSWORD '%s';", + printfPQExpBuffer(&buf, "ALTER USER %s PASSWORD '%s';", fmtId(user), encrypted_password); res = PSQLexec(buf.data, false); termPQExpBuffer(&buf); @@ -664,6 +664,7 @@ exec_command(const char *cmd, success = false; else PQclear(res); + PQfreemem(encrypted_password); } } diff --git a/src/bin/scripts/createuser.c b/src/bin/scripts/createuser.c index adf9c41b3a..9bd7d8d873 100644 --- a/src/bin/scripts/createuser.c +++ b/src/bin/scripts/createuser.c @@ -5,7 +5,7 @@ * Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * - * $PostgreSQL: pgsql/src/bin/scripts/createuser.c,v 1.24 2005/12/18 02:17:16 petere Exp $ + * $PostgreSQL: pgsql/src/bin/scripts/createuser.c,v 1.25 2005/12/23 01:16:38 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -13,7 +13,6 @@ #include "postgres_fe.h" #include "common.h" #include "dumputils.h" -#include "libpq/crypt.h" static void help(const char *progname); @@ -250,14 +249,17 @@ main(int argc, char *argv[]) if (encrypted != TRI_NO) { - char encrypted_password[MD5_PASSWD_LEN + 1]; + char *encrypted_password; - if (!pg_md5_encrypt(newpassword, newuser, strlen(newuser), encrypted_password)) + encrypted_password = pg_make_encrypted_password(newpassword, + newuser); + if (!encrypted_password) { fprintf(stderr, _("Password encryption failed.\n")); exit(1); } appendStringLiteral(&sql, encrypted_password, false); + PQfreemem(encrypted_password); } else appendStringLiteral(&sql, newpassword, false); diff --git a/src/interfaces/libpq/exports.txt b/src/interfaces/libpq/exports.txt index bcb18f829c..3b95bccb46 100644 --- a/src/interfaces/libpq/exports.txt +++ b/src/interfaces/libpq/exports.txt @@ -1,4 +1,4 @@ -# $PostgreSQL: pgsql/src/interfaces/libpq/exports.txt,v 1.5 2005/10/21 15:21:21 tgl Exp $ +# $PostgreSQL: pgsql/src/interfaces/libpq/exports.txt,v 1.6 2005/12/23 01:16:38 tgl Exp $ # Functions to be exported by libpq DLLs PQconnectdb 1 PQsetdbLogin 2 @@ -125,3 +125,4 @@ PQcancel 122 lo_create 123 PQinitSSL 124 PQregisterThreadLock 125 +pg_make_encrypted_password 126 diff --git a/src/interfaces/libpq/fe-auth.c b/src/interfaces/libpq/fe-auth.c index 95609114f9..039964a9fe 100644 --- a/src/interfaces/libpq/fe-auth.c +++ b/src/interfaces/libpq/fe-auth.c @@ -10,7 +10,7 @@ * exceed INITIAL_EXPBUFFER_SIZE (currently 256 bytes). * * IDENTIFICATION - * $PostgreSQL: pgsql/src/interfaces/libpq/fe-auth.c,v 1.108 2005/11/22 18:17:32 momjian Exp $ + * $PostgreSQL: pgsql/src/interfaces/libpq/fe-auth.c,v 1.109 2005/12/23 01:16:38 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -531,3 +531,40 @@ pg_fe_getauthname(char *PQerrormsg) return authn; } + + +/* + * pg_make_encrypted_password -- 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 + * be sent in cleartext if it is encrypted on the client side. This is + * good because it ensures the cleartext password won't end up in logs, + * pg_stat displays, etc. We export the function so that clients won't + * be dependent on low-level details like whether the enceyption is MD5 + * or something else. + * + * Arguments are the cleartext password, and the SQL name of the user it + * is for. + * + * Return value is a malloc'd string, or NULL if out-of-memory. The client + * may assume the string doesn't contain any weird characters that would + * require escaping. + */ +char * +pg_make_encrypted_password(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; +} diff --git a/src/interfaces/libpq/libpq-fe.h b/src/interfaces/libpq/libpq-fe.h index f0f0cede54..fc42c2b28a 100644 --- a/src/interfaces/libpq/libpq-fe.h +++ b/src/interfaces/libpq/libpq-fe.h @@ -7,7 +7,7 @@ * Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * - * $PostgreSQL: pgsql/src/interfaces/libpq/libpq-fe.h,v 1.122 2005/11/23 04:23:28 momjian Exp $ + * $PostgreSQL: pgsql/src/interfaces/libpq/libpq-fe.h,v 1.123 2005/12/23 01:16:38 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -495,6 +495,10 @@ extern int PQdsplen(const char *s, int encoding); /* Get encoding id from environment variable PGCLIENTENCODING */ extern int PQenv2encoding(void); +/* === in fe-auth.c === */ + +extern char *pg_make_encrypted_password(const char *passwd, const char *user); + #ifdef __cplusplus } #endif