diff --git a/src/common/backend/catalog/pg_shdepend.cpp b/src/common/backend/catalog/pg_shdepend.cpp index f56445846..8aa9a240e 100644 --- a/src/common/backend/catalog/pg_shdepend.cpp +++ b/src/common/backend/catalog/pg_shdepend.cpp @@ -57,6 +57,7 @@ #include "commands/sec_rls_cmds.h" #include "commands/tablecmds.h" #include "commands/typecmds.h" +#include "commands/directory.h" #include "storage/lmgr.h" #include "miscadmin.h" #include "utils/acl.h" @@ -1412,6 +1413,10 @@ void shdepReassignOwned(List* roleids, Oid newrole) AlterSubscriptionOwner_oid(sdepForm->objid, newrole); break; + case PgDirectoryRelationId: + AlterPgDirectoryOwner_oid(sdepForm->objid, newrole); + break; + default: ereport(ERROR, (errcode(ERRCODE_UNRECOGNIZED_NODE_TYPE), errmsg("unexpected classid %u", sdepForm->classid))); diff --git a/src/gausskernel/optimizer/commands/directory.cpp b/src/gausskernel/optimizer/commands/directory.cpp index 7c9871d28..e7f177167 100644 --- a/src/gausskernel/optimizer/commands/directory.cpp +++ b/src/gausskernel/optimizer/commands/directory.cpp @@ -389,6 +389,72 @@ void RemoveDirectoryById(Oid dirOid) heap_close(relation, RowExclusiveLock); } +static void AlterPgDirectoryOwner_internal(Relation rel, HeapTuple tuple, Oid newOwnerId) +{ + Form_pg_directory dirForm = (Form_pg_directory)GETSTRUCT(tuple); + /* + * If the new owner is the same as the existing owner, consider the + * command to have succeeded. This is to be consistent with other + * objects. + */ + if (dirForm->owner == newOwnerId) { + return; + } + + Datum repl_val[Natts_pg_directory]; + bool repl_null[Natts_pg_directory]; + bool repl_repl[Natts_pg_directory]; + Acl* newAcl = NULL; + Datum aclDatum; + bool isNull = false; + HeapTuple newtuple; + errno_t rc; + + if (u_sess->attr.attr_storage.enable_access_server_directory) { + /* must be sysadmin or owner of the existing object */ + if (!superuser() && !pg_directory_ownercheck(HeapTupleGetOid(tuple), GetUserId())) { + aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_DIRECTORY, NameStr(dirForm->dirname)); + } + } else { + if (!initialuser()) { + ereport(ERROR, (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE), + errmsg("permission denied to change owner of directory"), + errhint("must be initial user to change owner of a directory"))); + } + } + + /* Must be able to become new owner */ + check_is_member_of_role(GetUserId(), newOwnerId); + + rc = memset_s(repl_null, sizeof(repl_null), false, sizeof(repl_null)); + securec_check(rc, "\0", "\0"); + rc = memset_s(repl_repl, sizeof(repl_repl), false, sizeof(repl_repl)); + securec_check(rc, "\0", "\0"); + + repl_repl[Anum_pg_directory_owner - 1] = true; + repl_val[Anum_pg_directory_owner - 1] = ObjectIdGetDatum(newOwnerId); + + /* + * Determine the modified ACL for the new owner. This is only + * necessary when the ACL is non-null. + */ + aclDatum = tableam_tops_tuple_getattr(tuple, Anum_pg_directory_directory_acl, RelationGetDescr(rel), &isNull); + if (!isNull) { + newAcl = aclnewowner(DatumGetAclP(aclDatum), dirForm->owner, newOwnerId); + repl_repl[Anum_pg_directory_directory_acl - 1] = true; + repl_val[Anum_pg_directory_directory_acl - 1] = PointerGetDatum(newAcl); + } + + newtuple = (HeapTuple) tableam_tops_modify_tuple(tuple, RelationGetDescr(rel), repl_val, repl_null, repl_repl); + simple_heap_update(rel, &newtuple->t_self, newtuple); + CatalogUpdateIndexes(rel, newtuple); + + tableam_tops_free_tuple(newtuple); + + /* Update owner dependency reference */ + changeDependencyOnOwner(PgDirectoryRelationId, HeapTupleGetOid(tuple), newOwnerId); +} + /* * ALTER Directory name OWNER TO newowner */ @@ -398,7 +464,6 @@ void AlterDirectoryOwner(const char* dirname, Oid newOwnerId) Relation rel; ScanKeyData scankey; SysScanDesc scan = NULL; - Form_pg_directory dirForm = NULL; /* * Get the old tuple. We don't need a lock on the directory per se, @@ -413,69 +478,30 @@ void AlterDirectoryOwner(const char* dirname, Oid newOwnerId) heap_close(rel, RowExclusiveLock); ereport(ERROR, (errcode(ERRCODE_UNDEFINED_OBJECT), errmsg("directory \"%s\" does not exist", dirname))); } - dirForm = (Form_pg_directory)GETSTRUCT(tuple); - /* - * If the new owner is the same as the existing owner, consider the - * command to have succeeded. This is to be consistent with other - * objects. - */ - if (dirForm->owner != newOwnerId) { - Datum repl_val[Natts_pg_directory]; - bool repl_null[Natts_pg_directory]; - bool repl_repl[Natts_pg_directory]; - Acl* newAcl = NULL; - Datum aclDatum; - bool isNull = false; - HeapTuple newtuple; - errno_t rc; - if (u_sess->attr.attr_storage.enable_access_server_directory) { - /* must be sysadmin or owner of the existing object */ - if (!superuser() && !pg_directory_ownercheck(HeapTupleGetOid(tuple), GetUserId())) { - aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_DIRECTORY, dirname); - } - } else { - if (!initialuser()) { - ereport(ERROR, (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE), - errmsg("permission denied to change owner of directory"), - errhint("must be initial user to change owner of a directory"))); - } - } - - /* Must be able to become new owner */ - check_is_member_of_role(GetUserId(), newOwnerId); - - rc = memset_s(repl_null, sizeof(repl_null), false, sizeof(repl_null)); - securec_check(rc, "\0", "\0"); - rc = memset_s(repl_repl, sizeof(repl_repl), false, sizeof(repl_repl)); - securec_check(rc, "\0", "\0"); - - repl_repl[Anum_pg_directory_owner - 1] = true; - repl_val[Anum_pg_directory_owner - 1] = ObjectIdGetDatum(newOwnerId); - - /* - * Determine the modified ACL for the new owner. This is only - * necessary when the ACL is non-null. - */ - aclDatum = tableam_tops_tuple_getattr(tuple, Anum_pg_directory_directory_acl, RelationGetDescr(rel), &isNull); - if (!isNull) { - newAcl = aclnewowner(DatumGetAclP(aclDatum), dirForm->owner, newOwnerId); - repl_repl[Anum_pg_directory_directory_acl - 1] = true; - repl_val[Anum_pg_directory_directory_acl - 1] = PointerGetDatum(newAcl); - } - - newtuple = (HeapTuple) tableam_tops_modify_tuple(tuple, RelationGetDescr(rel), repl_val, repl_null, repl_repl); - simple_heap_update(rel, &newtuple->t_self, newtuple); - CatalogUpdateIndexes(rel, newtuple); - - tableam_tops_free_tuple(newtuple); - - /* Update owner dependency reference */ - changeDependencyOnOwner(PgDirectoryRelationId, HeapTupleGetOid(tuple), newOwnerId); - } + AlterPgDirectoryOwner_internal(rel, tuple, newOwnerId); systable_endscan(scan); /* Close pg_database, but keep lock till commit */ heap_close(rel, NoLock); } + + +void AlterPgDirectoryOwner_oid(Oid dirOid, Oid newOwnerId) +{ + Relation rel; + HeapTuple tup = NULL; + + rel = heap_open(PgDirectoryRelationId, RowExclusiveLock); + + tup = SearchSysCacheCopy1(DIRECTORYOID, ObjectIdGetDatum(dirOid)); + if (!HeapTupleIsValid(tup)) /* should not happen */ + ereport(ERROR, (errcode(ERRCODE_CACHE_LOOKUP_FAILED), errmsg("cache lookup failed for directory %u", dirOid))); + + AlterPgDirectoryOwner_internal(rel, tup, newOwnerId); + + heap_freetuple(tup); + heap_close(rel, NoLock); +} + diff --git a/src/include/commands/directory.h b/src/include/commands/directory.h index 03203782a..3e5a90c62 100644 --- a/src/include/commands/directory.h +++ b/src/include/commands/directory.h @@ -35,5 +35,6 @@ extern Oid get_directory_oid(const char* directoryname, bool missing_ok); extern char* get_directory_name(Oid dir_oid); extern void RemoveDirectoryById(Oid dirOid); extern void AlterDirectoryOwner(const char* dirname, Oid newOwnerId); +extern void AlterPgDirectoryOwner_oid(Oid dirOid, Oid newOwnerId); #endif /* DIRECTORY_H*/ diff --git a/src/test/regress/input/directory_test.source b/src/test/regress/input/directory_test.source index 47c8d58df..0ef2c62da 100644 --- a/src/test/regress/input/directory_test.source +++ b/src/test/regress/input/directory_test.source @@ -133,5 +133,19 @@ DROP DIRECTORY test_dir2; \! @abs_bindir@/gs_guc reload -Z datanode -D @abs_srcdir@/tmp_check/datanode1 -c "enable_access_server_directory=off" >/dev/null 2>&1 RESET ROLE; + +alter system set enable_access_server_directory=on; +create user u_reassign_owned_0008_1 sysadmin password 'test@123'; +create user u_reassign_owned_0008_2 sysadmin password 'test@123'; +SET ROLE u_reassign_owned_0008_1 PASSWORD 'test@123'; +show enable_access_server_directory; +create or replace directory dir_object_reassign_owned_0008 as '/tmp'; +select t1.dirname, t2.usename, t1.dirpath from pg_directory t1 inner join pg_user t2 on t2.usesysid=t1.owner where t1.dirname='dir_object_reassign_owned_0008'; +reassign owned by u_reassign_owned_0008_1 to u_reassign_owned_0008_2; + +RESET ROLE; +alter system set enable_access_server_directory=off; + DROP USER test_user1,test_user2,test_user3; DROP USER test_sysadmin,test_create,test_drop; +DROP USER u_reassign_owned_0008_1, u_reassign_owned_0008_2 cascade; diff --git a/src/test/regress/output/directory_test.source b/src/test/regress/output/directory_test.source index b98879d96..69dae3ccc 100644 --- a/src/test/regress/output/directory_test.source +++ b/src/test/regress/output/directory_test.source @@ -265,5 +265,26 @@ DROP DIRECTORY test_dir2; \! rm -rf @testtablespace@/dir2 \! @abs_bindir@/gs_guc reload -Z datanode -D @abs_srcdir@/tmp_check/datanode1 -c "enable_access_server_directory=off" >/dev/null 2>&1 RESET ROLE; +alter system set enable_access_server_directory=on; +create user u_reassign_owned_0008_1 sysadmin password 'test@123'; +create user u_reassign_owned_0008_2 sysadmin password 'test@123'; +SET ROLE u_reassign_owned_0008_1 PASSWORD 'test@123'; +show enable_access_server_directory; + enable_access_server_directory +-------------------------------- + on +(1 row) + +create or replace directory dir_object_reassign_owned_0008 as '/tmp'; +select t1.dirname, t2.usename, t1.dirpath from pg_directory t1 inner join pg_user t2 on t2.usesysid=t1.owner where t1.dirname='dir_object_reassign_owned_0008'; + dirname | usename | dirpath +--------------------------------+-------------------------+--------- + dir_object_reassign_owned_0008 | u_reassign_owned_0008_1 | /tmp +(1 row) + +reassign owned by u_reassign_owned_0008_1 to u_reassign_owned_0008_2; +RESET ROLE; +alter system set enable_access_server_directory=off; DROP USER test_user1,test_user2,test_user3; DROP USER test_sysadmin,test_create,test_drop; +DROP USER u_reassign_owned_0008_1, u_reassign_owned_0008_2 cascade;