@@ -1452,62 +1452,76 @@ AlterRole(AlterRoleStmt *stmt)
14521452 {
14531453 char * shadow_pass ;
14541454 char * logdetail ;
1455+
1456+ /* Like in CREATE USER, don't allow an empty password. */
1457+ if (password [0 ] == '\0' ||
1458+ plain_crypt_verify (rolename , password , "" , & logdetail ) == STATUS_OK )
1459+ {
1460+ ereport (NOTICE ,
1461+ (errmsg ("empty string is not a valid password, clearing password" )));
1462+ new_record_nulls [Anum_pg_authid_rolpassword - 1 ] = true;
1463+ }
1464+ else
1465+ {
1466+ /* Encrypt the password to the requested format. */
1467+ shadow_pass = encrypt_password (Password_encryption , rolename ,
1468+ password );
1469+ new_record [Anum_pg_authid_rolpassword - 1 ] =
1470+ CStringGetTextDatum (shadow_pass );
1471+ }
1472+ new_record_repl [Anum_pg_authid_rolpassword - 1 ] = true;
1473+ }
1474+
1475+ /* unset password */
1476+ if (dpassword && dpassword -> arg == NULL )
1477+ {
1478+ new_record_repl [Anum_pg_authid_rolpassword - 1 ] = true;
1479+ new_record_nulls [Anum_pg_authid_rolpassword - 1 ] = true;
1480+ }
1481+
1482+
1483+ if ((password || (dpassword && dpassword -> arg == NULL )) &&
1484+ (authform -> rolenableprofile || enable_profile ) && enable_password_profile )
1485+ {
14551486 Datum datum ;
14561487 bool isnull ;
14571488 bool setat_isnull ;
14581489 TimestampTz password_set_at = 0 ;
14591490 int32 profile_reuse_max = 0 ;
14601491 SysScanDesc password_history_scan ;
14611492 HeapTuple profiletuple ;
1493+ char * logdetail ;
1494+ bool ignore_password_history = false;
14621495
14631496 pg_profile_rel = table_open (ProfileRelationId , AccessShareLock );
14641497 pg_profile_dsc = RelationGetDescr (pg_profile_rel );
14651498
14661499 datum = SysCacheGetAttr (AUTHNAME , tuple ,
1467- Anum_pg_authid_rolprofile , & isnull );
1500+ Anum_pg_authid_rolprofile , & isnull );
14681501 Assert (!isnull );
14691502
14701503 profileid = DatumGetObjectId (datum );
14711504 profiletuple = SearchSysCache1 (PROFILEID , ObjectIdGetDatum (profileid ));
14721505 if (!HeapTupleIsValid (profiletuple ))
14731506 ereport (ERROR ,
1474- (errcode (ERRCODE_UNDEFINED_OBJECT ),
1475- errmsg ("profile \"%d\" does not exist" , profileid )));
1507+ (errcode (ERRCODE_UNDEFINED_OBJECT ),
1508+ errmsg ("profile \"%d\" does not exist" , profileid )));
14761509
14771510 /* Get PASSWORD_REUSE_MAX from profile tuple and transform it to normal value */
14781511 profileform = (Form_pg_profile ) GETSTRUCT (profiletuple );
14791512 profile_reuse_max = tranformProfileValueToNormal (profileform -> prfpasswordreusemax ,
1480- Anum_pg_profile_prfpasswordreusemax );
1513+ Anum_pg_profile_prfpasswordreusemax );
14811514
14821515 ReleaseSysCache (profiletuple );
14831516
14841517 if (profile_reuse_max == 0 )
1485- ereport (ERROR ,
1486- (errcode (ERRCODE_INVALID_PASSWORD ),
1487- errmsg ("can't alter user password for profile's password_reuse_max is zero." )));
1518+ ignore_password_history = true;
14881519
14891520 /*
14901521 * Get shadow password from pg_authid
14911522 */
14921523 datum = SysCacheGetAttr (AUTHNAME , tuple ,
1493- Anum_pg_authid_rolpassword , & isnull );
1494-
1495- /* Like in CREATE USER, don't allow an empty password. */
1496- if (password [0 ] == '\0' ||
1497- plain_crypt_verify (rolename , password , "" , & logdetail ) == STATUS_OK )
1498- {
1499- ereport (NOTICE ,
1500- (errmsg ("empty string is not a valid password, clearing password" )));
1501- new_record_nulls [Anum_pg_authid_rolpassword - 1 ] = true;
1502- }
1503- else
1504- {
1505- /* Encrypt the password to the requested format. */
1506- shadow_pass = encrypt_password (Password_encryption , rolename ,
1507- password );
1508- new_record [Anum_pg_authid_rolpassword - 1 ] =
1509- CStringGetTextDatum (shadow_pass );
1510- }
1524+ Anum_pg_authid_rolpassword , & isnull );
15111525
15121526 /*
15131527 * Disallow to use recently passwords which controlled by
@@ -1536,7 +1550,7 @@ AlterRole(AlterRoleStmt *stmt)
15361550 history_shadow_pass = TextDatumGetCString (datum );
15371551
15381552 datum = SysCacheGetAttr (AUTHNAME , tuple ,
1539- Anum_pg_authid_rolpasswordsetat , & setat_isnull );
1553+ Anum_pg_authid_rolpasswordsetat , & setat_isnull );
15401554 Assert (!setat_isnull );
15411555 history_password_set_at = DatumGetInt64 (datum );
15421556
@@ -1553,26 +1567,26 @@ AlterRole(AlterRoleStmt *stmt)
15531567
15541568 /* Form the insert tuple */
15551569 password_history_tuple = heap_form_tuple (pg_password_history_dsc ,
1556- password_history_record , password_nulls );
1570+ password_history_record , password_nulls );
15571571
1558- /* Insert new record into the pg_password_history table */
1572+ /* Insert new record into the pg_password_history table */
15591573 CatalogTupleInsert (pg_password_history_rel , password_history_tuple );
15601574
15611575 /* Advance command counter so we can see new record */
15621576 CommandCounterIncrement ();
15631577
15641578 /* form a scan key */
15651579 ScanKeyInit (& skey ,
1566- Anum_pg_password_history_passhistroleid ,
1567- BTEqualStrategyNumber , F_OIDEQ ,
1568- ObjectIdGetDatum (roleid ));
1580+ Anum_pg_password_history_passhistroleid ,
1581+ BTEqualStrategyNumber , F_OIDEQ ,
1582+ ObjectIdGetDatum (roleid ));
15691583
15701584 /*
15711585 * Get only recently PASSWORD_REUSE_MAX tuples.
15721586 */
15731587 password_history_scan = systable_beginscan_ordered (pg_password_history_rel ,
1574- pg_password_history_passwordsetat_idx ,
1575- NULL , 1 , & skey );
1588+ pg_password_history_passwordsetat_idx ,
1589+ NULL , 1 , & skey );
15761590 for (i = 0 ; i < profile_reuse_max ; i ++ )
15771591 {
15781592 password_history_tuple = systable_getnext_ordered (password_history_scan , BackwardScanDirection );
@@ -1581,19 +1595,20 @@ AlterRole(AlterRoleStmt *stmt)
15811595 break ;
15821596
15831597 datum = heap_getattr (password_history_tuple , Anum_pg_password_history_passhistpassword ,
1584- pg_password_history_dsc , & isnull );
1598+ pg_password_history_dsc , & isnull );
15851599 Assert (!isnull );
15861600 history_shadow_pass = text_to_cstring (DatumGetTextP (datum ));
15871601
15881602 /*
15891603 * Use password verify function to check whether password
15901604 * has been recorded in pg_password_history.
15911605 */
1592- if (plain_crypt_verify (rolename , history_shadow_pass , password , & logdetail ) == STATUS_OK )
1606+ if (!ignore_password_history && password &&
1607+ plain_crypt_verify (rolename , history_shadow_pass , password , & logdetail ) == STATUS_OK )
15931608 ereport (ERROR ,
1594- (errcode (ERRCODE_INVALID_PASSWORD ),
1595- errmsg ("The new password should not be the same with latest %d history password" ,
1596- profile_reuse_max )));
1609+ (errcode (ERRCODE_INVALID_PASSWORD ),
1610+ errmsg ("The new password should not be the same with latest %d history password" ,
1611+ profile_reuse_max )));
15971612 }
15981613
15991614 systable_endscan_ordered (password_history_scan );
@@ -1606,18 +1621,10 @@ AlterRole(AlterRoleStmt *stmt)
16061621 new_record [Anum_pg_authid_rolpasswordsetat - 1 ] =
16071622 Int64GetDatum (password_set_at );
16081623 new_record_repl [Anum_pg_authid_rolpasswordsetat - 1 ] = true;
1609- new_record_repl [Anum_pg_authid_rolpassword - 1 ] = true;
16101624
16111625 table_close (pg_profile_rel , NoLock );
16121626 }
16131627
1614- /* unset password */
1615- if (dpassword && dpassword -> arg == NULL )
1616- {
1617- new_record_repl [Anum_pg_authid_rolpassword - 1 ] = true;
1618- new_record_nulls [Anum_pg_authid_rolpassword - 1 ] = true;
1619- }
1620-
16211628 /* valid until */
16221629 new_record [Anum_pg_authid_rolvaliduntil - 1 ] = validUntil_datum ;
16231630 new_record_nulls [Anum_pg_authid_rolvaliduntil - 1 ] = validUntil_null ;
0 commit comments