Skip to content

Commit 9aa3a0d

Browse files
committed
ext/pgsql: adding pg_change_password functionality.
handy call to change an user password while taking care transparently of the password's encryption. close GH-14262
1 parent 1d38656 commit 9aa3a0d

File tree

7 files changed

+123
-1
lines changed

7 files changed

+123
-1
lines changed

NEWS

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -186,6 +186,7 @@ PHP NEWS
186186
(David Carlier)
187187
. Added pg_result_memory_size to get the query result memory usage.
188188
(KentarouTakeda)
189+
. Added pg_change_password to alter an user's password. (David Carlier)
189190

190191
- Phar:
191192
. Fixed bug GH-12532 (PharData created from zip has incorrect timestamp).

UPGRADING

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -513,6 +513,10 @@ PHP 8.4 UPGRADE NOTES
513513
. Added pcntl_getqos_class to get the QoS level (aka performance and related
514514
energy consumption) of the current process and pcntl_setqos_class to set it.
515515

516+
- PGSQL:
517+
. Added pg_change_password to alter a given user's password. It handles
518+
transparently the password encryption from the database settings.
519+
516520
- Sodium:
517521
. Added the sodium_crypto_aead_aegis128l_*() and sodium_crypto_aead_aegis256l_*()
518522
functions to support the AEGIS family of authenticated encryption algorithms,

ext/pgsql/config.m4

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,7 @@ if test "$PHP_PGSQL" != "no"; then
6767
AC_CHECK_LIB(pq, lo_truncate64, AC_DEFINE(HAVE_PG_LO64,1,[PostgreSQL 9.3 or later]))
6868
AC_CHECK_LIB(pq, PQsetErrorContextVisibility, AC_DEFINE(HAVE_PG_CONTEXT_VISIBILITY,1,[PostgreSQL 9.6 or later]))
6969
AC_CHECK_LIB(pq, PQresultMemorySize, AC_DEFINE(HAVE_PG_RESULT_MEMORY_SIZE,1,[PostgreSQL 12 or later]))
70+
AC_CHECK_LIB(pq, PQchangePassword, AC_DEFINE(HAVE_PG_CHANGE_PASSWORD,1,[PostgreSQL 17 or later]))
7071
LIBS=$old_LIBS
7172
LDFLAGS=$old_LDFLAGS
7273

ext/pgsql/pgsql.c

Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@
3939
#include "php_pgsql.h"
4040
#include "php_globals.h"
4141
#include "zend_exceptions.h"
42+
#include "zend_attributes.h"
4243

4344
#ifdef HAVE_PGSQL
4445

@@ -401,6 +402,47 @@ static bool _php_pgsql_identifier_is_escaped(const char *identifier, size_t len)
401402
return true;
402403
}
403404

405+
#ifndef HAVE_PG_CHANGE_PASSWORD
406+
static PGresult *PQchangePassword(PGconn *conn, const char *user, const char *passwd)
407+
{
408+
/**
409+
* It is more appropriate to let the configured password encryption algorithm
410+
* being picked up, so we pass NULL
411+
*/
412+
char *enc = PQencryptPasswordConn(conn, passwd, user, NULL);
413+
414+
if (!enc) {
415+
return NULL;
416+
}
417+
418+
char *fmtenc = PQescapeLiteral(conn, enc, strlen(enc));
419+
PQfreemem(enc);
420+
421+
if (!fmtenc) {
422+
return NULL;
423+
}
424+
425+
char *fmtuser = PQescapeIdentifier(conn, user, strlen(user));
426+
427+
if (!fmtuser) {
428+
PQfreemem(fmtenc);
429+
return NULL;
430+
}
431+
432+
char *query;
433+
434+
spprintf(&query, 0, "ALTER USER %s PASSWORD %s", fmtuser, fmtenc);
435+
436+
PGresult *pg_result = PQexec(conn, query);
437+
438+
efree(query);
439+
PQfreemem(fmtuser);
440+
PQfreemem(fmtenc);
441+
442+
return pg_result;
443+
}
444+
#endif
445+
404446
/* {{{ PHP_INI */
405447
PHP_INI_BEGIN()
406448
STD_PHP_INI_BOOLEAN( "pgsql.allow_persistent", "1", PHP_INI_SYSTEM, OnUpdateBool, allow_persistent, zend_pgsql_globals, pgsql_globals)
@@ -6048,4 +6090,36 @@ PHP_FUNCTION(pg_select)
60486090
}
60496091
/* }}} */
60506092

6093+
PHP_FUNCTION(pg_change_password)
6094+
{
6095+
zval *pgsql_link;
6096+
pgsql_link_handle *link;
6097+
PGresult *pg_result;
6098+
zend_string *user, *passwd;
6099+
6100+
ZEND_PARSE_PARAMETERS_START(3, 3)
6101+
Z_PARAM_OBJECT_OF_CLASS(pgsql_link, pgsql_link_ce)
6102+
Z_PARAM_STR(user)
6103+
Z_PARAM_STR(passwd)
6104+
ZEND_PARSE_PARAMETERS_END();
6105+
6106+
if (ZSTR_LEN(user) == 0) {
6107+
zend_argument_value_error(2, "cannot be empty");
6108+
RETURN_THROWS();
6109+
}
6110+
6111+
/* it is technically possible, but better to disallow it */
6112+
if (ZSTR_LEN(passwd) == 0) {
6113+
zend_argument_value_error(3, "cannot be empty");
6114+
RETURN_THROWS();
6115+
}
6116+
6117+
link = Z_PGSQL_LINK_P(pgsql_link);
6118+
CHECK_PGSQL_LINK(link);
6119+
6120+
pg_result = PQchangePassword(link->conn, ZSTR_VAL(user), ZSTR_VAL(passwd));
6121+
RETVAL_BOOL(PQresultStatus(pg_result) == PGRES_COMMAND_OK);
6122+
PQclear(pg_result);
6123+
}
6124+
60516125
#endif

ext/pgsql/pgsql.stub.php

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -947,6 +947,8 @@ function pg_set_error_context_visibility(PgSql\Connection $connection, int $visi
947947
#ifdef HAVE_PG_RESULT_MEMORY_SIZE
948948
function pg_result_memory_size(PgSql\Result $result): int {}
949949
#endif
950+
951+
function pg_change_password(PgSql\Connection $connection, string $user, #[\SensitiveParameter] string $password): bool {}
950952
}
951953

952954
namespace PgSql {

ext/pgsql/pgsql_arginfo.h

Lines changed: 12 additions & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
--TEST--
2+
Changing user password with pg_change_password
3+
--EXTENSIONS--
4+
pgsql
5+
--SKIPIF--
6+
<?php include("inc/skipif.inc"); ?>
7+
--FILE--
8+
<?php
9+
include('inc/config.inc');
10+
11+
$conn = pg_connect($conn_str);
12+
13+
try {
14+
pg_change_password($conn, "", "pass");
15+
} catch (\ValueError $e) {
16+
echo $e->getMessage() . PHP_EOL;
17+
}
18+
try {
19+
pg_change_password($conn, "user", "");
20+
} catch (\ValueError $e) {
21+
echo $e->getMessage() . PHP_EOL;
22+
}
23+
24+
var_dump(pg_change_password($conn, "inexistent_user", "postitpwd"));
25+
?>
26+
--EXPECT--
27+
pg_change_password(): Argument #2 ($user) cannot be empty
28+
pg_change_password(): Argument #3 ($password) cannot be empty
29+
bool(false)

0 commit comments

Comments
 (0)