diff --git a/src/interfaces/libpq/exports.txt b/src/interfaces/libpq/exports.txt index 850734a..28b861f 100644 *** a/src/interfaces/libpq/exports.txt --- b/src/interfaces/libpq/exports.txt *************** PQclosePrepared 188 *** 191,193 **** --- 191,194 ---- 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 912aa14..a6897f8 100644 *** a/src/interfaces/libpq/fe-auth.c --- b/src/interfaces/libpq/fe-auth.c *************** PQencryptPasswordConn(PGconn *conn, cons *** 1372,1374 **** --- 1372,1459 ---- 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. 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 = NULL; + PQExpBufferData buf; + + encrypted_password = PQencryptPasswordConn(conn, passwd, user, NULL); + + if (!encrypted_password) + { + /* PQencryptPasswordConn() already registered the error */ + return NULL; + } + else + { + char *fmtpw = NULL; + + 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 = NULL; + + fmtuser = PQescapeIdentifier(conn, user, strlen(user)); + if (!fmtuser) + { + /* PQescapeIdentifier() already registered the error */ + PQfreemem(fmtpw); + return NULL; + } + else + { + 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); + + if (!res) + return NULL; + else + return res; + } + } + } + } diff --git a/src/interfaces/libpq/libpq-fe.h b/src/interfaces/libpq/libpq-fe.h index 97762d5..bc8e6de 100644 *** a/src/interfaces/libpq/libpq-fe.h --- b/src/interfaces/libpq/libpq-fe.h *************** extern int PQenv2encoding(void); *** 659,664 **** --- 659,665 ---- 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 === */