diff options
-rw-r--r-- | doc/src/sgml/libpq.sgml | 39 | ||||
-rw-r--r-- | src/bin/psql/command.c | 20 | ||||
-rw-r--r-- | src/interfaces/libpq/exports.txt | 1 | ||||
-rw-r--r-- | src/interfaces/libpq/fe-auth.c | 81 | ||||
-rw-r--r-- | src/interfaces/libpq/libpq-fe.h | 1 |
5 files changed, 125 insertions, 17 deletions
diff --git a/doc/src/sgml/libpq.sgml b/doc/src/sgml/libpq.sgml index ed88ac001a1..21195e0e728 100644 --- a/doc/src/sgml/libpq.sgml +++ b/doc/src/sgml/libpq.sgml @@ -7116,6 +7116,45 @@ char *PQencryptPasswordConn(PGconn *conn, const char *passwd, const char *user, </listitem> </varlistentry> + <varlistentry id="libpq-PQchangePassword"> + <term><function>PQchangePassword</function><indexterm><primary>PQchangePassword</primary></indexterm></term> + + <listitem> + <para> + Changes a <productname>PostgreSQL</productname> password. +<synopsis> +PGresult *PQchangePassword(PGconn *conn, const char *user, const char *passwd); +</synopsis> + This function uses <function>PQencryptPasswordConn</function> + to build and execute the command <literal>ALTER USER ... PASSWORD + '...'</literal>, thereby changing the user's password. It exists for + the same reason as <function>PQencryptPasswordConn</function>, but + is more convenient as it both builds and runs the command for you. + <xref linkend="libpq-PQencryptPasswordConn"/> is passed a + <symbol>NULL</symbol> for the algorithm argument, hence encryption is + done according to the server's <xref linkend="guc-password-encryption"/> + setting. + </para> + + <para> + The <parameter>user</parameter> and <parameter>passwd</parameter> arguments + are the SQL name of the target user, and the new cleartext password. + </para> + + <para> + Returns a <structname>PGresult</structname> pointer representing + the result of the <literal>ALTER USER</literal> command, or + a null pointer if the routine failed before issuing any command. + The <xref linkend="libpq-PQresultStatus"/> function should be called + to check the return value for any errors (including the value of a null + pointer, in which case it will return + <symbol>PGRES_FATAL_ERROR</symbol>). Use + <xref linkend="libpq-PQerrorMessage"/> to get more information about + such errors. + </para> + </listitem> + </varlistentry> + <varlistentry id="libpq-PQencryptPassword"> <term><function>PQencryptPassword</function><indexterm><primary>PQencryptPassword</primary></indexterm></term> diff --git a/src/bin/psql/command.c b/src/bin/psql/command.c index 9103bc34657..eb216b7c09e 100644 --- a/src/bin/psql/command.c +++ b/src/bin/psql/command.c @@ -2158,29 +2158,15 @@ exec_command_password(PsqlScanState scan_state, bool active_branch) } else { - char *encrypted_password; + PGresult *res = PQchangePassword(pset.db, user, pw1); - encrypted_password = PQencryptPasswordConn(pset.db, pw1, user, NULL); - - if (!encrypted_password) + if (PQresultStatus(res) != PGRES_COMMAND_OK) { pg_log_info("%s", PQerrorMessage(pset.db)); success = false; } - else - { - PGresult *res; - printfPQExpBuffer(&buf, "ALTER USER %s PASSWORD ", - fmtId(user)); - appendStringLiteralConn(&buf, encrypted_password, pset.db); - res = PSQLexec(buf.data); - if (!res) - success = false; - else - PQclear(res); - PQfreemem(encrypted_password); - } + PQclear(res); } free(user); diff --git a/src/interfaces/libpq/exports.txt b/src/interfaces/libpq/exports.txt index 850734ac96c..28b861fd93b 100644 --- a/src/interfaces/libpq/exports.txt +++ b/src/interfaces/libpq/exports.txt @@ -191,3 +191,4 @@ PQclosePrepared 188 PQclosePortal 189 PQsendClosePrepared 190 PQsendClosePortal 191 +PQchangePassword 192 diff --git a/src/interfaces/libpq/fe-auth.c b/src/interfaces/libpq/fe-auth.c index da5ccd324d9..1a8e4f6fbfa 100644 --- a/src/interfaces/libpq/fe-auth.c +++ b/src/interfaces/libpq/fe-auth.c @@ -1372,3 +1372,84 @@ PQencryptPasswordConn(PGconn *conn, const char *passwd, const char *user, return crypt_pwd; } + +/* + * PQchangePassword -- exported routine to change a password + * + * This is intended to be used by client applications that wish to + * change the password for a user. The password is not sent in + * cleartext because it is encrypted on the client side. This is + * good because it ensures the cleartext password is never known by + * the server, and therefore won't end up in logs, pg_stat displays, + * etc. The password encryption is performed by PQencryptPasswordConn(), + * which is passed a NULL for the algorithm argument. Hence encryption + * is done according to the server's password_encryption + * setting. We export the function so that clients won't be dependent + * on the implementation specific details with respect to how the + * server changes passwords. + * + * Arguments are a connection object, the SQL name of the target user, + * and the cleartext password. + * + * Return value is the PGresult of the executed ALTER USER statement + * or NULL if we never get there. The caller is responsible to PQclear() + * the returned PGresult. + * + * PQresultStatus() should be called to check the return value for errors, + * and PQerrorMessage() used to get more information about such errors. + */ +PGresult * +PQchangePassword(PGconn *conn, const char *user, const char *passwd) +{ + char *encrypted_password = PQencryptPasswordConn(conn, passwd, + user, NULL); + + if (!encrypted_password) + { + /* PQencryptPasswordConn() already registered the error */ + return NULL; + } + else + { + char *fmtpw = PQescapeLiteral(conn, encrypted_password, + strlen(encrypted_password)); + + /* no longer needed, so clean up now */ + PQfreemem(encrypted_password); + + if (!fmtpw) + { + /* PQescapeLiteral() already registered the error */ + return NULL; + } + else + { + char *fmtuser = PQescapeIdentifier(conn, user, strlen(user)); + + if (!fmtuser) + { + /* PQescapeIdentifier() already registered the error */ + PQfreemem(fmtpw); + return NULL; + } + else + { + PQExpBufferData buf; + PGresult *res; + + initPQExpBuffer(&buf); + printfPQExpBuffer(&buf, "ALTER USER %s PASSWORD %s", + fmtuser, fmtpw); + + res = PQexec(conn, buf.data); + + /* clean up */ + termPQExpBuffer(&buf); + PQfreemem(fmtuser); + PQfreemem(fmtpw); + + return res; + } + } + } +} diff --git a/src/interfaces/libpq/libpq-fe.h b/src/interfaces/libpq/libpq-fe.h index 12eb72c1fef..f0ec660cb69 100644 --- a/src/interfaces/libpq/libpq-fe.h +++ b/src/interfaces/libpq/libpq-fe.h @@ -659,6 +659,7 @@ extern int PQenv2encoding(void); extern char *PQencryptPassword(const char *passwd, const char *user); extern char *PQencryptPasswordConn(PGconn *conn, const char *passwd, const char *user, const char *algorithm); +extern PGresult *PQchangePassword(PGconn *conn, const char *user, const char *passwd); /* === in encnames.c === */ |