diff options
Diffstat (limited to 'src/backend/commands')
-rw-r--r-- | src/backend/commands/aggregatecmds.c | 8 | ||||
-rw-r--r-- | src/backend/commands/alter.c | 16 | ||||
-rw-r--r-- | src/backend/commands/conversioncmds.c | 8 | ||||
-rw-r--r-- | src/backend/commands/copy.c | 3 | ||||
-rw-r--r-- | src/backend/commands/dbcommands.c | 50 | ||||
-rw-r--r-- | src/backend/commands/functioncmds.c | 10 | ||||
-rw-r--r-- | src/backend/commands/opclasscmds.c | 10 | ||||
-rw-r--r-- | src/backend/commands/operatorcmds.c | 8 | ||||
-rw-r--r-- | src/backend/commands/schemacmds.c | 33 | ||||
-rw-r--r-- | src/backend/commands/tablecmds.c | 28 | ||||
-rw-r--r-- | src/backend/commands/tablespace.c | 30 | ||||
-rw-r--r-- | src/backend/commands/typecmds.c | 8 | ||||
-rw-r--r-- | src/backend/commands/user.c | 1335 | ||||
-rw-r--r-- | src/backend/commands/variable.c | 56 |
14 files changed, 711 insertions, 892 deletions
diff --git a/src/backend/commands/aggregatecmds.c b/src/backend/commands/aggregatecmds.c index 9833937b705..6335757981e 100644 --- a/src/backend/commands/aggregatecmds.c +++ b/src/backend/commands/aggregatecmds.c @@ -9,7 +9,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/commands/aggregatecmds.c,v 1.26 2005/04/14 20:03:23 tgl Exp $ + * $PostgreSQL: pgsql/src/backend/commands/aggregatecmds.c,v 1.27 2005/06/28 05:08:53 tgl Exp $ * * DESCRIPTION * The "DefineFoo" routines take the parse tree and pick out the @@ -295,7 +295,7 @@ RenameAggregate(List *name, TypeName *basetype, const char *newname) * Change aggregate owner */ void -AlterAggregateOwner(List *name, TypeName *basetype, AclId newOwnerSysId) +AlterAggregateOwner(List *name, TypeName *basetype, Oid newOwnerId) { Oid basetypeOid; Oid procOid; @@ -329,7 +329,7 @@ AlterAggregateOwner(List *name, TypeName *basetype, AclId newOwnerSysId) * If the new owner is the same as the existing owner, consider the * command to have succeeded. This is for dump restoration purposes. */ - if (procForm->proowner != newOwnerSysId) + if (procForm->proowner != newOwnerId) { /* Otherwise, must be superuser to change object ownership */ if (!superuser()) @@ -341,7 +341,7 @@ AlterAggregateOwner(List *name, TypeName *basetype, AclId newOwnerSysId) * Modify the owner --- okay to scribble on tup because it's a * copy */ - procForm->proowner = newOwnerSysId; + procForm->proowner = newOwnerId; simple_heap_update(rel, &tup->t_self, tup); CatalogUpdateIndexes(rel, tup); diff --git a/src/backend/commands/alter.c b/src/backend/commands/alter.c index 9bb40f35164..a19b500152d 100644 --- a/src/backend/commands/alter.c +++ b/src/backend/commands/alter.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/commands/alter.c,v 1.12 2004/12/31 21:59:41 pgsql Exp $ + * $PostgreSQL: pgsql/src/backend/commands/alter.c,v 1.13 2005/06/28 05:08:53 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -64,10 +64,6 @@ ExecRenameStmt(RenameStmt *stmt) RenameFunction(stmt->object, stmt->objarg, stmt->newname); break; - case OBJECT_GROUP: - RenameGroup(stmt->subname, stmt->newname); - break; - case OBJECT_LANGUAGE: RenameLanguage(stmt->subname, stmt->newname); break; @@ -76,6 +72,10 @@ ExecRenameStmt(RenameStmt *stmt) RenameOpClass(stmt->object, stmt->subname, stmt->newname); break; + case OBJECT_ROLE: + RenameRole(stmt->subname, stmt->newname); + break; + case OBJECT_SCHEMA: RenameSchema(stmt->subname, stmt->newname); break; @@ -84,10 +84,6 @@ ExecRenameStmt(RenameStmt *stmt) RenameTableSpace(stmt->subname, stmt->newname); break; - case OBJECT_USER: - RenameUser(stmt->subname, stmt->newname); - break; - case OBJECT_TABLE: case OBJECT_INDEX: case OBJECT_COLUMN: @@ -153,7 +149,7 @@ ExecRenameStmt(RenameStmt *stmt) void ExecAlterOwnerStmt(AlterOwnerStmt *stmt) { - AclId newowner = get_usesysid(stmt->newowner); + Oid newowner = get_roleid_checked(stmt->newowner); switch (stmt->objectType) { diff --git a/src/backend/commands/conversioncmds.c b/src/backend/commands/conversioncmds.c index fb71bf59f92..c2aa48614e6 100644 --- a/src/backend/commands/conversioncmds.c +++ b/src/backend/commands/conversioncmds.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/commands/conversioncmds.c,v 1.18 2005/05/03 19:17:59 tgl Exp $ + * $PostgreSQL: pgsql/src/backend/commands/conversioncmds.c,v 1.19 2005/06/28 05:08:53 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -175,7 +175,7 @@ RenameConversion(List *name, const char *newname) * Change conversion owner */ void -AlterConversionOwner(List *name, AclId newOwnerSysId) +AlterConversionOwner(List *name, Oid newOwnerId) { Oid conversionOid; HeapTuple tup; @@ -203,7 +203,7 @@ AlterConversionOwner(List *name, AclId newOwnerSysId) * If the new owner is the same as the existing owner, consider the * command to have succeeded. This is for dump restoration purposes. */ - if (convForm->conowner != newOwnerSysId) + if (convForm->conowner != newOwnerId) { /* Otherwise, must be superuser to change object ownership */ if (!superuser()) @@ -215,7 +215,7 @@ AlterConversionOwner(List *name, AclId newOwnerSysId) * Modify the owner --- okay to scribble on tup because it's a * copy */ - convForm->conowner = newOwnerSysId; + convForm->conowner = newOwnerId; simple_heap_update(rel, &tup->t_self, tup); diff --git a/src/backend/commands/copy.c b/src/backend/commands/copy.c index 30eeefded8e..10e68684b8e 100644 --- a/src/backend/commands/copy.c +++ b/src/backend/commands/copy.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/commands/copy.c,v 1.245 2005/06/02 01:21:22 momjian Exp $ + * $PostgreSQL: pgsql/src/backend/commands/copy.c,v 1.246 2005/06/28 05:08:53 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -25,7 +25,6 @@ #include "catalog/index.h" #include "catalog/namespace.h" #include "catalog/pg_index.h" -#include "catalog/pg_shadow.h" #include "catalog/pg_type.h" #include "commands/copy.h" #include "commands/trigger.h" diff --git a/src/backend/commands/dbcommands.c b/src/backend/commands/dbcommands.c index 6fa6aa5b44b..1dac14ead2e 100644 --- a/src/backend/commands/dbcommands.c +++ b/src/backend/commands/dbcommands.c @@ -15,7 +15,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/commands/dbcommands.c,v 1.161 2005/06/25 22:47:29 tgl Exp $ + * $PostgreSQL: pgsql/src/backend/commands/dbcommands.c,v 1.162 2005/06/28 05:08:53 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -28,10 +28,10 @@ #include "access/genam.h" #include "access/heapam.h" #include "catalog/catalog.h" +#include "catalog/indexing.h" +#include "catalog/pg_authid.h" #include "catalog/pg_database.h" -#include "catalog/pg_shadow.h" #include "catalog/pg_tablespace.h" -#include "catalog/indexing.h" #include "commands/comment.h" #include "commands/dbcommands.h" #include "commands/tablespace.h" @@ -52,7 +52,7 @@ /* non-export function prototypes */ -static bool get_db_info(const char *name, Oid *dbIdP, int4 *ownerIdP, +static bool get_db_info(const char *name, Oid *dbIdP, Oid *ownerIdP, int *encodingP, bool *dbIsTemplateP, bool *dbAllowConnP, Oid *dbLastSysOidP, TransactionId *dbVacuumXidP, TransactionId *dbFrozenXidP, @@ -70,7 +70,7 @@ createdb(const CreatedbStmt *stmt) HeapScanDesc scan; Relation rel; Oid src_dboid; - AclId src_owner; + Oid src_owner; int src_encoding; bool src_istemplate; bool src_allowconn; @@ -85,7 +85,7 @@ createdb(const CreatedbStmt *stmt) Datum new_record[Natts_pg_database]; char new_record_nulls[Natts_pg_database]; Oid dboid; - AclId datdba; + Oid datdba; ListCell *option; DefElem *dtablespacename = NULL; DefElem *downer = NULL; @@ -186,13 +186,13 @@ createdb(const CreatedbStmt *stmt) nodeTag(dencoding->arg)); } - /* obtain sysid of proposed owner */ + /* obtain OID of proposed owner */ if (dbowner) - datdba = get_usesysid(dbowner); /* will ereport if no such user */ + datdba = get_roleid_checked(dbowner); else datdba = GetUserId(); - if (datdba == GetUserId()) + if (is_member_of_role(GetUserId(), datdba)) { /* creating database for self: can be superuser or createdb */ if (!superuser() && !have_createdb_privilege()) @@ -243,7 +243,7 @@ createdb(const CreatedbStmt *stmt) */ if (!src_istemplate) { - if (!superuser() && GetUserId() != src_owner) + if (!pg_database_ownercheck(src_dboid, GetUserId())) ereport(ERROR, (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE), errmsg("permission denied to copy database \"%s\"", @@ -483,7 +483,7 @@ createdb(const CreatedbStmt *stmt) new_record[Anum_pg_database_datname - 1] = DirectFunctionCall1(namein, CStringGetDatum(dbname)); - new_record[Anum_pg_database_datdba - 1] = Int32GetDatum(datdba); + new_record[Anum_pg_database_datdba - 1] = ObjectIdGetDatum(datdba); new_record[Anum_pg_database_encoding - 1] = Int32GetDatum(encoding); new_record[Anum_pg_database_datistemplate - 1] = BoolGetDatum(false); new_record[Anum_pg_database_datallowconn - 1] = BoolGetDatum(true); @@ -557,9 +557,8 @@ createdb(const CreatedbStmt *stmt) void dropdb(const char *dbname) { - int4 db_owner; - bool db_istemplate; Oid db_id; + bool db_istemplate; Relation pgdbrel; SysScanDesc pgdbscan; ScanKeyData key; @@ -588,13 +587,13 @@ dropdb(const char *dbname) */ pgdbrel = heap_open(DatabaseRelationId, ExclusiveLock); - if (!get_db_info(dbname, &db_id, &db_owner, NULL, + if (!get_db_info(dbname, &db_id, NULL, NULL, &db_istemplate, NULL, NULL, NULL, NULL, NULL)) ereport(ERROR, (errcode(ERRCODE_UNDEFINED_DATABASE), errmsg("database \"%s\" does not exist", dbname))); - if (GetUserId() != db_owner && !superuser()) + if (!pg_database_ownercheck(db_id, GetUserId())) aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_DATABASE, dbname); @@ -818,8 +817,7 @@ AlterDatabaseSet(AlterDatabaseSetStmt *stmt) (errcode(ERRCODE_UNDEFINED_DATABASE), errmsg("database \"%s\" does not exist", stmt->dbname))); - if (!(superuser() - || ((Form_pg_database) GETSTRUCT(tuple))->datdba == GetUserId())) + if (!pg_database_ownercheck(HeapTupleGetOid(tuple), GetUserId())) aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_DATABASE, stmt->dbname); @@ -878,7 +876,7 @@ AlterDatabaseSet(AlterDatabaseSetStmt *stmt) * ALTER DATABASE name OWNER TO newowner */ void -AlterDatabaseOwner(const char *dbname, AclId newOwnerSysId) +AlterDatabaseOwner(const char *dbname, Oid newOwnerId) { HeapTuple tuple; Relation rel; @@ -910,7 +908,7 @@ AlterDatabaseOwner(const char *dbname, AclId newOwnerSysId) * command to have succeeded. This is to be consistent with other * objects. */ - if (datForm->datdba != newOwnerSysId) + if (datForm->datdba != newOwnerId) { Datum repl_val[Natts_pg_database]; char repl_null[Natts_pg_database]; @@ -930,7 +928,7 @@ AlterDatabaseOwner(const char *dbname, AclId newOwnerSysId) memset(repl_repl, ' ', sizeof(repl_repl)); repl_repl[Anum_pg_database_datdba - 1] = 'r'; - repl_val[Anum_pg_database_datdba - 1] = Int32GetDatum(newOwnerSysId); + repl_val[Anum_pg_database_datdba - 1] = ObjectIdGetDatum(newOwnerId); /* * Determine the modified ACL for the new owner. This is only @@ -943,7 +941,7 @@ AlterDatabaseOwner(const char *dbname, AclId newOwnerSysId) if (!isNull) { newAcl = aclnewowner(DatumGetAclP(aclDatum), - datForm->datdba, newOwnerSysId); + datForm->datdba, newOwnerId); repl_repl[Anum_pg_database_datacl - 1] = 'r'; repl_val[Anum_pg_database_datacl - 1] = PointerGetDatum(newAcl); } @@ -972,7 +970,7 @@ AlterDatabaseOwner(const char *dbname, AclId newOwnerSysId) */ static bool -get_db_info(const char *name, Oid *dbIdP, int4 *ownerIdP, +get_db_info(const char *name, Oid *dbIdP, Oid *ownerIdP, int *encodingP, bool *dbIsTemplateP, bool *dbAllowConnP, Oid *dbLastSysOidP, TransactionId *dbVacuumXidP, TransactionId *dbFrozenXidP, @@ -1007,7 +1005,7 @@ get_db_info(const char *name, Oid *dbIdP, int4 *ownerIdP, /* oid of the database */ if (dbIdP) *dbIdP = HeapTupleGetOid(tuple); - /* sysid of the owner */ + /* oid of the owner */ if (ownerIdP) *ownerIdP = dbform->datdba; /* character encoding */ @@ -1046,12 +1044,12 @@ have_createdb_privilege(void) bool result = false; HeapTuple utup; - utup = SearchSysCache(SHADOWSYSID, - Int32GetDatum(GetUserId()), + utup = SearchSysCache(AUTHOID, + ObjectIdGetDatum(GetUserId()), 0, 0, 0); if (HeapTupleIsValid(utup)) { - result = ((Form_pg_shadow) GETSTRUCT(utup))->usecreatedb; + result = ((Form_pg_authid) GETSTRUCT(utup))->rolcreatedb; ReleaseSysCache(utup); } return result; diff --git a/src/backend/commands/functioncmds.c b/src/backend/commands/functioncmds.c index ea3c3811837..3329822fe62 100644 --- a/src/backend/commands/functioncmds.c +++ b/src/backend/commands/functioncmds.c @@ -10,7 +10,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/commands/functioncmds.c,v 1.61 2005/04/14 20:03:23 tgl Exp $ + * $PostgreSQL: pgsql/src/backend/commands/functioncmds.c,v 1.62 2005/06/28 05:08:53 tgl Exp $ * * DESCRIPTION * These routines take the parse tree and pick out the @@ -853,7 +853,7 @@ RenameFunction(List *name, List *argtypes, const char *newname) * Change function owner */ void -AlterFunctionOwner(List *name, List *argtypes, AclId newOwnerSysId) +AlterFunctionOwner(List *name, List *argtypes, Oid newOwnerId) { Oid procOid; HeapTuple tup; @@ -882,7 +882,7 @@ AlterFunctionOwner(List *name, List *argtypes, AclId newOwnerSysId) * If the new owner is the same as the existing owner, consider the * command to have succeeded. This is for dump restoration purposes. */ - if (procForm->proowner != newOwnerSysId) + if (procForm->proowner != newOwnerId) { Datum repl_val[Natts_pg_proc]; char repl_null[Natts_pg_proc]; @@ -902,7 +902,7 @@ AlterFunctionOwner(List *name, List *argtypes, AclId newOwnerSysId) memset(repl_repl, ' ', sizeof(repl_repl)); repl_repl[Anum_pg_proc_proowner - 1] = 'r'; - repl_val[Anum_pg_proc_proowner - 1] = Int32GetDatum(newOwnerSysId); + repl_val[Anum_pg_proc_proowner - 1] = ObjectIdGetDatum(newOwnerId); /* * Determine the modified ACL for the new owner. This is only @@ -914,7 +914,7 @@ AlterFunctionOwner(List *name, List *argtypes, AclId newOwnerSysId) if (!isNull) { newAcl = aclnewowner(DatumGetAclP(aclDatum), - procForm->proowner, newOwnerSysId); + procForm->proowner, newOwnerId); repl_repl[Anum_pg_proc_proacl - 1] = 'r'; repl_val[Anum_pg_proc_proacl - 1] = PointerGetDatum(newAcl); } diff --git a/src/backend/commands/opclasscmds.c b/src/backend/commands/opclasscmds.c index e64924c43a7..3610269644a 100644 --- a/src/backend/commands/opclasscmds.c +++ b/src/backend/commands/opclasscmds.c @@ -9,7 +9,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/commands/opclasscmds.c,v 1.32 2005/04/14 20:03:23 tgl Exp $ + * $PostgreSQL: pgsql/src/backend/commands/opclasscmds.c,v 1.33 2005/06/28 05:08:53 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -321,7 +321,7 @@ DefineOpClass(CreateOpClassStmt *stmt) namestrcpy(&opcName, opcname); values[i++] = NameGetDatum(&opcName); /* opcname */ values[i++] = ObjectIdGetDatum(namespaceoid); /* opcnamespace */ - values[i++] = Int32GetDatum(GetUserId()); /* opcowner */ + values[i++] = ObjectIdGetDatum(GetUserId()); /* opcowner */ values[i++] = ObjectIdGetDatum(typeoid); /* opcintype */ values[i++] = BoolGetDatum(stmt->isDefault); /* opcdefault */ values[i++] = ObjectIdGetDatum(storageoid); /* opckeytype */ @@ -880,7 +880,7 @@ RenameOpClass(List *name, const char *access_method, const char *newname) * Change opclass owner */ void -AlterOpClassOwner(List *name, const char *access_method, AclId newOwnerSysId) +AlterOpClassOwner(List *name, const char *access_method, Oid newOwnerId) { Oid opcOid; Oid amOid; @@ -945,7 +945,7 @@ AlterOpClassOwner(List *name, const char *access_method, AclId newOwnerSysId) * If the new owner is the same as the existing owner, consider the * command to have succeeded. This is for dump restoration purposes. */ - if (opcForm->opcowner != newOwnerSysId) + if (opcForm->opcowner != newOwnerId) { /* Otherwise, must be superuser to change object ownership */ if (!superuser()) @@ -957,7 +957,7 @@ AlterOpClassOwner(List *name, const char *access_method, AclId newOwnerSysId) * Modify the owner --- okay to scribble on tup because it's a * copy */ - opcForm->opcowner = newOwnerSysId; + opcForm->opcowner = newOwnerId; simple_heap_update(rel, &tup->t_self, tup); diff --git a/src/backend/commands/operatorcmds.c b/src/backend/commands/operatorcmds.c index 45dc1eafeaa..adea1b2b5d7 100644 --- a/src/backend/commands/operatorcmds.c +++ b/src/backend/commands/operatorcmds.c @@ -9,7 +9,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/commands/operatorcmds.c,v 1.21 2005/04/14 20:03:24 tgl Exp $ + * $PostgreSQL: pgsql/src/backend/commands/operatorcmds.c,v 1.22 2005/06/28 05:08:54 tgl Exp $ * * DESCRIPTION * The "DefineFoo" routines take the parse tree and pick out the @@ -269,7 +269,7 @@ RemoveOperatorById(Oid operOid) */ void AlterOperatorOwner(List *name, TypeName *typeName1, TypeName *typeName2, - AclId newOwnerSysId) + Oid newOwnerId) { Oid operOid; HeapTuple tup; @@ -293,7 +293,7 @@ AlterOperatorOwner(List *name, TypeName *typeName1, TypeName *typeName2, * If the new owner is the same as the existing owner, consider the * command to have succeeded. This is for dump restoration purposes. */ - if (oprForm->oprowner != newOwnerSysId) + if (oprForm->oprowner != newOwnerId) { /* Otherwise, must be superuser to change object ownership */ if (!superuser()) @@ -305,7 +305,7 @@ AlterOperatorOwner(List *name, TypeName *typeName1, TypeName *typeName2, * Modify the owner --- okay to scribble on tup because it's a * copy */ - oprForm->oprowner = newOwnerSysId; + oprForm->oprowner = newOwnerId; simple_heap_update(rel, &tup->t_self, tup); diff --git a/src/backend/commands/schemacmds.c b/src/backend/commands/schemacmds.c index 5754c1dfcb4..d92812f1fcf 100644 --- a/src/backend/commands/schemacmds.c +++ b/src/backend/commands/schemacmds.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/commands/schemacmds.c,v 1.30 2005/06/21 00:58:15 neilc Exp $ + * $PostgreSQL: pgsql/src/backend/commands/schemacmds.c,v 1.31 2005/06/28 05:08:54 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -42,11 +42,11 @@ CreateSchemaCommand(CreateSchemaStmt *stmt) Oid namespaceId; List *parsetree_list; ListCell *parsetree_item; - AclId owner_userid; - AclId saved_userid; + Oid owner_uid; + Oid saved_uid; AclResult aclresult; - saved_userid = GetUserId(); + saved_uid = GetUserId(); /* * Figure out user identities. @@ -54,12 +54,11 @@ CreateSchemaCommand(CreateSchemaStmt *stmt) if (!authId) { - owner_userid = saved_userid; + owner_uid = saved_uid; } else if (superuser()) { - /* The following will error out if user does not exist */ - owner_userid = get_usesysid(authId); + owner_uid = get_roleid_checked(authId); /* * Set the current user to the requested authorization so that @@ -67,15 +66,15 @@ CreateSchemaCommand(CreateSchemaStmt *stmt) * (This will revert to session user on error or at the end of * this routine.) */ - SetUserId(owner_userid); + SetUserId(owner_uid); } else { const char *owner_name; /* not superuser */ - owner_userid = saved_userid; - owner_name = GetUserNameFromId(owner_userid); + owner_uid = saved_uid; + owner_name = GetUserNameFromId(owner_uid); if (strcmp(authId, owner_name) != 0) ereport(ERROR, (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE), @@ -87,7 +86,7 @@ CreateSchemaCommand(CreateSchemaStmt *stmt) /* * Permissions checks. */ - aclresult = pg_database_aclcheck(MyDatabaseId, saved_userid, ACL_CREATE); + aclresult = pg_database_aclcheck(MyDatabaseId, saved_uid, ACL_CREATE); if (aclresult != ACLCHECK_OK) aclcheck_error(aclresult, ACL_KIND_DATABASE, get_database_name(MyDatabaseId)); @@ -99,7 +98,7 @@ CreateSchemaCommand(CreateSchemaStmt *stmt) errdetail("The prefix \"pg_\" is reserved for system schemas."))); /* Create the schema's namespace */ - namespaceId = NamespaceCreate(schemaName, owner_userid); + namespaceId = NamespaceCreate(schemaName, owner_uid); /* Advance cmd counter to make the namespace visible */ CommandCounterIncrement(); @@ -149,7 +148,7 @@ CreateSchemaCommand(CreateSchemaStmt *stmt) PopSpecialNamespace(namespaceId); /* Reset current user */ - SetUserId(saved_userid); + SetUserId(saved_uid); } @@ -279,7 +278,7 @@ RenameSchema(const char *oldname, const char *newname) * Change schema owner */ void -AlterSchemaOwner(const char *name, AclId newOwnerSysId) +AlterSchemaOwner(const char *name, Oid newOwnerId) { HeapTuple tup; Relation rel; @@ -300,7 +299,7 @@ AlterSchemaOwner(const char *name, AclId newOwnerSysId) * If the new owner is the same as the existing owner, consider the * command to have succeeded. This is for dump restoration purposes. */ - if (nspForm->nspowner != newOwnerSysId) + if (nspForm->nspowner != newOwnerId) { Datum repl_val[Natts_pg_namespace]; char repl_null[Natts_pg_namespace]; @@ -320,7 +319,7 @@ AlterSchemaOwner(const char *name, AclId newOwnerSysId) memset(repl_repl, ' ', sizeof(repl_repl)); repl_repl[Anum_pg_namespace_nspowner - 1] = 'r'; - repl_val[Anum_pg_namespace_nspowner - 1] = Int32GetDatum(newOwnerSysId); + repl_val[Anum_pg_namespace_nspowner - 1] = ObjectIdGetDatum(newOwnerId); /* * Determine the modified ACL for the new owner. This is only @@ -332,7 +331,7 @@ AlterSchemaOwner(const char *name, AclId newOwnerSysId) if (!isNull) { newAcl = aclnewowner(DatumGetAclP(aclDatum), - nspForm->nspowner, newOwnerSysId); + nspForm->nspowner, newOwnerId); repl_repl[Anum_pg_namespace_nspacl - 1] = 'r'; repl_val[Anum_pg_namespace_nspacl - 1] = PointerGetDatum(newAcl); } diff --git a/src/backend/commands/tablecmds.c b/src/backend/commands/tablecmds.c index 9981129c0eb..dda9532baf8 100644 --- a/src/backend/commands/tablecmds.c +++ b/src/backend/commands/tablecmds.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/commands/tablecmds.c,v 1.161 2005/06/06 20:22:57 tgl Exp $ + * $PostgreSQL: pgsql/src/backend/commands/tablecmds.c,v 1.162 2005/06/28 05:08:54 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -231,9 +231,9 @@ static void ATExecAlterColumnType(AlteredTableInfo *tab, Relation rel, const char *colName, TypeName *typename); static void ATPostAlterTypeCleanup(List **wqueue, AlteredTableInfo *tab); static void ATPostAlterTypeParse(char *cmd, List **wqueue); -static void ATExecChangeOwner(Oid relationOid, int32 newOwnerSysId); +static void ATExecChangeOwner(Oid relationOid, Oid newOwnerId); static void change_owner_recurse_to_sequences(Oid relationOid, - int32 newOwnerSysId); + Oid newOwnerId); static void ATExecClusterOn(Relation rel, const char *indexName); static void ATExecDropCluster(Relation rel); static void ATPrepSetTableSpace(AlteredTableInfo *tab, Relation rel, @@ -2133,8 +2133,8 @@ ATExecCmd(AlteredTableInfo *tab, Relation rel, AlterTableCmd *cmd) AlterTableCreateToastTable(RelationGetRelid(rel), false); break; case AT_ChangeOwner: /* ALTER OWNER */ - /* get_usesysid raises an error if no such user */ - ATExecChangeOwner(RelationGetRelid(rel), get_usesysid(cmd->name)); + ATExecChangeOwner(RelationGetRelid(rel), + get_roleid_checked(cmd->name)); break; case AT_ClusterOn: /* CLUSTER ON */ ATExecClusterOn(rel, cmd->name); @@ -5233,7 +5233,7 @@ ATPostAlterTypeParse(char *cmd, List **wqueue) * ALTER TABLE OWNER */ static void -ATExecChangeOwner(Oid relationOid, int32 newOwnerSysId) +ATExecChangeOwner(Oid relationOid, Oid newOwnerId) { Relation target_rel; Relation class_rel; @@ -5277,7 +5277,7 @@ ATExecChangeOwner(Oid relationOid, int32 newOwnerSysId) * If the new owner is the same as the existing owner, consider the * command to have succeeded. This is for dump restoration purposes. */ - if (tuple_class->relowner != newOwnerSysId) + if (tuple_class->relowner != newOwnerId) { Datum repl_val[Natts_pg_class]; char repl_null[Natts_pg_class]; @@ -5297,7 +5297,7 @@ ATExecChangeOwner(Oid relationOid, int32 newOwnerSysId) memset(repl_repl, ' ', sizeof(repl_repl)); repl_repl[Anum_pg_class_relowner - 1] = 'r'; - repl_val[Anum_pg_class_relowner - 1] = Int32GetDatum(newOwnerSysId); + repl_val[Anum_pg_class_relowner - 1] = ObjectIdGetDatum(newOwnerId); /* * Determine the modified ACL for the new owner. This is only @@ -5309,7 +5309,7 @@ ATExecChangeOwner(Oid relationOid, int32 newOwnerSysId) if (!isNull) { newAcl = aclnewowner(DatumGetAclP(aclDatum), - tuple_class->relowner, newOwnerSysId); + tuple_class->relowner, newOwnerId); repl_repl[Anum_pg_class_relacl - 1] = 'r'; repl_val[Anum_pg_class_relacl - 1] = PointerGetDatum(newAcl); } @@ -5337,7 +5337,7 @@ ATExecChangeOwner(Oid relationOid, int32 newOwnerSysId) /* For each index, recursively change its ownership */ foreach(i, index_oid_list) - ATExecChangeOwner(lfirst_oid(i), newOwnerSysId); + ATExecChangeOwner(lfirst_oid(i), newOwnerId); list_free(index_oid_list); } @@ -5346,10 +5346,10 @@ ATExecChangeOwner(Oid relationOid, int32 newOwnerSysId) { /* If it has a toast table, recurse to change its ownership */ if (tuple_class->reltoastrelid != InvalidOid) - ATExecChangeOwner(tuple_class->reltoastrelid, newOwnerSysId); + ATExecChangeOwner(tuple_class->reltoastrelid, newOwnerId); /* If it has dependent sequences, recurse to change them too */ - change_owner_recurse_to_sequences(relationOid, newOwnerSysId); + change_owner_recurse_to_sequences(relationOid, newOwnerId); } } @@ -5366,7 +5366,7 @@ ATExecChangeOwner(Oid relationOid, int32 newOwnerSysId) * ownership. */ static void -change_owner_recurse_to_sequences(Oid relationOid, int32 newOwnerSysId) +change_owner_recurse_to_sequences(Oid relationOid, Oid newOwnerId) { Relation depRel; SysScanDesc scan; @@ -5416,7 +5416,7 @@ change_owner_recurse_to_sequences(Oid relationOid, int32 newOwnerSysId) } /* We don't need to close the sequence while we alter it. */ - ATExecChangeOwner(depForm->objid, newOwnerSysId); + ATExecChangeOwner(depForm->objid, newOwnerId); /* Now we can close it. Keep the lock till end of transaction. */ relation_close(seqRel, NoLock); diff --git a/src/backend/commands/tablespace.c b/src/backend/commands/tablespace.c index a469a8fa349..15a263b8efd 100644 --- a/src/backend/commands/tablespace.c +++ b/src/backend/commands/tablespace.c @@ -37,7 +37,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/commands/tablespace.c,v 1.22 2005/06/19 21:34:01 tgl Exp $ + * $PostgreSQL: pgsql/src/backend/commands/tablespace.c,v 1.23 2005/06/28 05:08:54 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -208,7 +208,7 @@ CreateTableSpace(CreateTableSpaceStmt *stmt) Oid tablespaceoid; char *location; char *linkloc; - AclId ownerid; + Oid ownerId; /* validate */ @@ -225,12 +225,9 @@ CreateTableSpace(CreateTableSpaceStmt *stmt) /* However, the eventual owner of the tablespace need not be */ if (stmt->owner) - { - /* No need to check result, get_usesysid() does that */ - ownerid = get_usesysid(stmt->owner); - } + ownerId = get_roleid_checked(stmt->owner); else - ownerid = GetUserId(); + ownerId = GetUserId(); /* Unix-ify the offered path, and strip any trailing slashes */ location = pstrdup(stmt->location); @@ -297,7 +294,7 @@ CreateTableSpace(CreateTableSpaceStmt *stmt) values[Anum_pg_tablespace_spcname - 1] = DirectFunctionCall1(namein, CStringGetDatum(stmt->tablespacename)); values[Anum_pg_tablespace_spcowner - 1] = - Int32GetDatum(ownerid); + ObjectIdGetDatum(ownerId); values[Anum_pg_tablespace_spclocation - 1] = DirectFunctionCall1(textin, CStringGetDatum(location)); nulls[Anum_pg_tablespace_spcacl - 1] = 'n'; @@ -426,9 +423,8 @@ DropTableSpace(DropTableSpaceStmt *stmt) tablespaceoid = HeapTupleGetOid(tuple); - /* Must be superuser or owner */ - if (GetUserId() != ((Form_pg_tablespace) GETSTRUCT(tuple))->spcowner && - !superuser()) + /* Must be tablespace owner */ + if (!pg_tablespace_ownercheck(tablespaceoid, GetUserId())) aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_TABLESPACE, tablespacename); @@ -711,8 +707,8 @@ RenameTableSpace(const char *oldname, const char *newname) heap_endscan(scan); - /* Must be owner or superuser */ - if (newform->spcowner != GetUserId() && !superuser()) + /* Must be owner */ + if (!pg_tablespace_ownercheck(HeapTupleGetOid(newtuple), GetUserId())) aclcheck_error(ACLCHECK_NO_PRIV, ACL_KIND_TABLESPACE, oldname); /* Validate new name */ @@ -750,7 +746,7 @@ RenameTableSpace(const char *oldname, const char *newname) * Change tablespace owner */ void -AlterTableSpaceOwner(const char *name, AclId newOwnerSysId) +AlterTableSpaceOwner(const char *name, Oid newOwnerId) { Relation rel; ScanKeyData entry[1]; @@ -778,7 +774,7 @@ AlterTableSpaceOwner(const char *name, AclId newOwnerSysId) * If the new owner is the same as the existing owner, consider the * command to have succeeded. This is for dump restoration purposes. */ - if (spcForm->spcowner != newOwnerSysId) + if (spcForm->spcowner != newOwnerId) { Datum repl_val[Natts_pg_tablespace]; char repl_null[Natts_pg_tablespace]; @@ -798,7 +794,7 @@ AlterTableSpaceOwner(const char *name, AclId newOwnerSysId) memset(repl_repl, ' ', sizeof(repl_repl)); repl_repl[Anum_pg_tablespace_spcowner - 1] = 'r'; - repl_val[Anum_pg_tablespace_spcowner - 1] = Int32GetDatum(newOwnerSysId); + repl_val[Anum_pg_tablespace_spcowner - 1] = ObjectIdGetDatum(newOwnerId); /* * Determine the modified ACL for the new owner. This is only @@ -811,7 +807,7 @@ AlterTableSpaceOwner(const char *name, AclId newOwnerSysId) if (!isNull) { newAcl = aclnewowner(DatumGetAclP(aclDatum), - spcForm->spcowner, newOwnerSysId); + spcForm->spcowner, newOwnerId); repl_repl[Anum_pg_tablespace_spcacl - 1] = 'r'; repl_val[Anum_pg_tablespace_spcacl - 1] = PointerGetDatum(newAcl); } diff --git a/src/backend/commands/typecmds.c b/src/backend/commands/typecmds.c index 280022feaa1..53570c77409 100644 --- a/src/backend/commands/typecmds.c +++ b/src/backend/commands/typecmds.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/commands/typecmds.c,v 1.72 2005/05/06 17:24:53 tgl Exp $ + * $PostgreSQL: pgsql/src/backend/commands/typecmds.c,v 1.73 2005/06/28 05:08:54 tgl Exp $ * * DESCRIPTION * The "DefineFoo" routines take the parse tree and pick out the @@ -2016,7 +2016,7 @@ GetDomainConstraints(Oid typeOid) * Change the owner of a type. */ void -AlterTypeOwner(List *names, AclId newOwnerSysId) +AlterTypeOwner(List *names, Oid newOwnerId) { TypeName *typename; Oid typeOid; @@ -2063,7 +2063,7 @@ AlterTypeOwner(List *names, AclId newOwnerSysId) * If the new owner is the same as the existing owner, consider the * command to have succeeded. This is for dump restoration purposes. */ - if (typTup->typowner != newOwnerSysId) + if (typTup->typowner != newOwnerId) { /* Otherwise, must be superuser to change object ownership */ if (!superuser()) @@ -2075,7 +2075,7 @@ AlterTypeOwner(List *names, AclId newOwnerSysId) * Modify the owner --- okay to scribble on typTup because it's a * copy */ - typTup->typowner = newOwnerSysId; + typTup->typowner = newOwnerId; simple_heap_update(rel, &tup->t_self, tup); diff --git a/src/backend/commands/user.c b/src/backend/commands/user.c index 3c70c579785..131f1896f92 100644 --- a/src/backend/commands/user.c +++ b/src/backend/commands/user.c @@ -1,12 +1,12 @@ /*------------------------------------------------------------------------- * * user.c - * Commands for manipulating users and groups. + * Commands for manipulating roles (formerly called users). * * Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * - * $PostgreSQL: pgsql/src/backend/commands/user.c,v 1.151 2005/04/14 20:03:24 tgl Exp $ + * $PostgreSQL: pgsql/src/backend/commands/user.c,v 1.152 2005/06/28 05:08:55 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -14,15 +14,14 @@ #include "access/heapam.h" #include "catalog/indexing.h" +#include "catalog/pg_auth_members.h" +#include "catalog/pg_authid.h" #include "catalog/pg_database.h" -#include "catalog/pg_group.h" -#include "catalog/pg_shadow.h" -#include "catalog/pg_type.h" #include "commands/user.h" #include "libpq/crypt.h" #include "miscadmin.h" -#include "utils/acl.h" #include "utils/builtins.h" +#include "utils/catcache.h" #include "utils/flatfiles.h" #include "utils/fmgroids.h" #include "utils/guc.h" @@ -32,46 +31,46 @@ extern bool Password_encryption; - -static void CheckPgUserAclNotNull(void); -static void UpdateGroupMembership(Relation group_rel, HeapTuple group_tuple, - List *members); -static IdList *IdListToArray(List *members); -static List *IdArrayToList(IdList *oldarray); +static List *roleNamesToIds(List *memberNames); +static void AddRoleMems(const char *rolename, Oid roleid, + List *memberNames, List *memberIds, + Oid grantorId, bool admin_opt); +static void DelRoleMems(const char *rolename, Oid roleid, + List *memberNames, List *memberIds, + bool admin_opt); /* - * CREATE USER + * CREATE ROLE */ void -CreateUser(CreateUserStmt *stmt) +CreateRole(CreateRoleStmt *stmt) { - Relation pg_shadow_rel; - TupleDesc pg_shadow_dsc; - HeapScanDesc scan; + Relation pg_authid_rel; + TupleDesc pg_authid_dsc; HeapTuple tuple; - Datum new_record[Natts_pg_shadow]; - char new_record_nulls[Natts_pg_shadow]; - bool user_exists = false, - sysid_exists = false, - havesysid = false; - int max_id; + Datum new_record[Natts_pg_authid]; + char new_record_nulls[Natts_pg_authid]; + Oid roleid; ListCell *item; ListCell *option; - char *password = NULL; /* PostgreSQL user password */ + char *password = NULL; /* user password */ bool encrypt_password = Password_encryption; /* encrypt password? */ char encrypted_password[MD5_PASSWD_LEN + 1]; - int sysid = 0; /* PgSQL system id (valid if havesysid) */ + bool issuper = false; /* Make the user a superuser? */ + bool createrole = false; /* Can this user create roles? */ bool createdb = false; /* Can the user create databases? */ - bool createuser = false; /* Can this user create users? */ - List *groupElts = NIL; /* The groups the user is a member of */ + bool canlogin = false; /* Can this user login? */ + List *roleElts = NIL; /* roles the user is a member of */ + List *rolememElts = NIL; /* roles which will be members of this role */ char *validUntil = NULL; /* The time the login is valid * until */ DefElem *dpassword = NULL; - DefElem *dsysid = NULL; DefElem *dcreatedb = NULL; - DefElem *dcreateuser = NULL; - DefElem *dgroupElts = NULL; + DefElem *dcreaterole = NULL; + DefElem *dcanlogin = NULL; + DefElem *droleElts = NULL; + DefElem *drolememElts = NULL; DefElem *dvalidUntil = NULL; /* Extract options from the statement node tree */ @@ -95,11 +94,16 @@ CreateUser(CreateUserStmt *stmt) } else if (strcmp(defel->defname, "sysid") == 0) { - if (dsysid) + ereport(WARNING, + (errmsg("SYSID can no longer be specified"))); + } + else if (strcmp(defel->defname, "createrole") == 0) + { + if (dcreaterole) ereport(ERROR, (errcode(ERRCODE_SYNTAX_ERROR), errmsg("conflicting or redundant options"))); - dsysid = defel; + dcreaterole = defel; } else if (strcmp(defel->defname, "createdb") == 0) { @@ -109,21 +113,29 @@ CreateUser(CreateUserStmt *stmt) errmsg("conflicting or redundant options"))); dcreatedb = defel; } - else if (strcmp(defel->defname, "createuser") == 0) + else if (strcmp(defel->defname, "canlogin") == 0) { - if (dcreateuser) + if (dcanlogin) ereport(ERROR, (errcode(ERRCODE_SYNTAX_ERROR), errmsg("conflicting or redundant options"))); - dcreateuser = defel; + dcanlogin = defel; } - else if (strcmp(defel->defname, "groupElts") == 0) + else if (strcmp(defel->defname, "roleElts") == 0) { - if (dgroupElts) + if (droleElts) ereport(ERROR, (errcode(ERRCODE_SYNTAX_ERROR), errmsg("conflicting or redundant options"))); - dgroupElts = defel; + droleElts = defel; + } + else if (strcmp(defel->defname, "rolememElts") == 0) + { + if (drolememElts) + ereport(ERROR, + (errcode(ERRCODE_SYNTAX_ERROR), + errmsg("conflicting or redundant options"))); + drolememElts = defel; } else if (strcmp(defel->defname, "validUntil") == 0) { @@ -140,83 +152,51 @@ CreateUser(CreateUserStmt *stmt) if (dcreatedb) createdb = intVal(dcreatedb->arg) != 0; - if (dcreateuser) - createuser = intVal(dcreateuser->arg) != 0; - if (dsysid) + if (dcreaterole) { - sysid = intVal(dsysid->arg); - if (sysid <= 0) - ereport(ERROR, - (errcode(ERRCODE_INVALID_PARAMETER_VALUE), - errmsg("user ID must be positive"))); - havesysid = true; + createrole = intVal(dcreaterole->arg) != 0; + /* XXX issuper is implied by createrole for now */ + issuper = createrole; } + if (dcanlogin) + canlogin = intVal(dcanlogin->arg) != 0; if (dvalidUntil) validUntil = strVal(dvalidUntil->arg); if (dpassword) password = strVal(dpassword->arg); - if (dgroupElts) - groupElts = (List *) dgroupElts->arg; + if (droleElts) + roleElts = (List *) droleElts->arg; + if (drolememElts) + rolememElts = (List *) drolememElts->arg; /* Check some permissions first */ - if (password) - CheckPgUserAclNotNull(); - if (!superuser()) ereport(ERROR, (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE), - errmsg("must be superuser to create users"))); + errmsg("must be superuser to create roles"))); - if (strcmp(stmt->user, "public") == 0) + if (strcmp(stmt->role, "public") == 0) ereport(ERROR, (errcode(ERRCODE_RESERVED_NAME), - errmsg("user name \"%s\" is reserved", - stmt->user))); + errmsg("role name \"%s\" is reserved", + stmt->role))); /* - * Scan the pg_shadow relation to be certain the user or id doesn't - * already exist. Note we secure exclusive lock, because we also need - * to be sure of what the next usesysid should be, and we need to - * protect our eventual update of the flat password file. + * Check the pg_authid relation to be certain the role doesn't + * already exist. Note we secure exclusive lock because + * we need to protect our eventual update of the flat auth file. */ - pg_shadow_rel = heap_open(ShadowRelationId, ExclusiveLock); - pg_shadow_dsc = RelationGetDescr(pg_shadow_rel); - - scan = heap_beginscan(pg_shadow_rel, SnapshotNow, 0, NULL); - max_id = 99; /* start auto-assigned ids at 100 */ - while (!user_exists && !sysid_exists && - (tuple = heap_getnext(scan, ForwardScanDirection)) != NULL) - { - Form_pg_shadow shadow_form = (Form_pg_shadow) GETSTRUCT(tuple); - int32 this_sysid; - - user_exists = (strcmp(NameStr(shadow_form->usename), stmt->user) == 0); - - this_sysid = shadow_form->usesysid; - if (havesysid) /* customized id wanted */ - sysid_exists = (this_sysid == sysid); - else - { - /* pick 1 + max */ - if (this_sysid > max_id) - max_id = this_sysid; - } - } - heap_endscan(scan); + pg_authid_rel = heap_open(AuthIdRelationId, ExclusiveLock); + pg_authid_dsc = RelationGetDescr(pg_authid_rel); - if (user_exists) - ereport(ERROR, - (errcode(ERRCODE_DUPLICATE_OBJECT), - errmsg("user \"%s\" already exists", - stmt->user))); - if (sysid_exists) + tuple = SearchSysCache(AUTHNAME, + PointerGetDatum(stmt->role), + 0, 0, 0); + if (HeapTupleIsValid(tuple)) ereport(ERROR, (errcode(ERRCODE_DUPLICATE_OBJECT), - errmsg("user ID %d is already assigned", sysid))); - - /* If no sysid given, use max existing id + 1 */ - if (!havesysid) - sysid = max_id + 1; + errmsg("role \"%s\" already exists", + stmt->role))); /* * Build a tuple to insert @@ -224,105 +204,123 @@ CreateUser(CreateUserStmt *stmt) MemSet(new_record, 0, sizeof(new_record)); MemSet(new_record_nulls, ' ', sizeof(new_record_nulls)); - new_record[Anum_pg_shadow_usename - 1] = - DirectFunctionCall1(namein, CStringGetDatum(stmt->user)); - new_record[Anum_pg_shadow_usesysid - 1] = Int32GetDatum(sysid); - AssertState(BoolIsValid(createdb)); - new_record[Anum_pg_shadow_usecreatedb - 1] = BoolGetDatum(createdb); - AssertState(BoolIsValid(createuser)); - new_record[Anum_pg_shadow_usesuper - 1] = BoolGetDatum(createuser); - /* superuser gets catupd right by default */ - new_record[Anum_pg_shadow_usecatupd - 1] = BoolGetDatum(createuser); + new_record[Anum_pg_authid_rolname - 1] = + DirectFunctionCall1(namein, CStringGetDatum(stmt->role)); + + new_record[Anum_pg_authid_rolsuper - 1] = BoolGetDatum(issuper); + new_record[Anum_pg_authid_rolcreaterole - 1] = BoolGetDatum(createrole); + new_record[Anum_pg_authid_rolcreatedb - 1] = BoolGetDatum(createdb); + /* superuser gets catupdate right by default */ + new_record[Anum_pg_authid_rolcatupdate - 1] = BoolGetDatum(issuper); + new_record[Anum_pg_authid_rolcanlogin - 1] = BoolGetDatum(canlogin); if (password) { if (!encrypt_password || isMD5(password)) - new_record[Anum_pg_shadow_passwd - 1] = + new_record[Anum_pg_authid_rolpassword - 1] = DirectFunctionCall1(textin, CStringGetDatum(password)); else { - if (!EncryptMD5(password, stmt->user, strlen(stmt->user), + if (!EncryptMD5(password, stmt->role, strlen(stmt->role), encrypted_password)) elog(ERROR, "password encryption failed"); - new_record[Anum_pg_shadow_passwd - 1] = + new_record[Anum_pg_authid_rolpassword - 1] = DirectFunctionCall1(textin, CStringGetDatum(encrypted_password)); } } else - new_record_nulls[Anum_pg_shadow_passwd - 1] = 'n'; + new_record_nulls[Anum_pg_authid_rolpassword - 1] = 'n'; if (validUntil) - new_record[Anum_pg_shadow_valuntil - 1] = - DirectFunctionCall1(abstimein, CStringGetDatum(validUntil)); + new_record[Anum_pg_authid_rolvaliduntil - 1] = + DirectFunctionCall3(timestamptz_in, + CStringGetDatum(validUntil), + ObjectIdGetDatum(InvalidOid), + Int32GetDatum(-1)); + else - new_record_nulls[Anum_pg_shadow_valuntil - 1] = 'n'; + new_record_nulls[Anum_pg_authid_rolvaliduntil - 1] = 'n'; - new_record_nulls[Anum_pg_shadow_useconfig - 1] = 'n'; + new_record_nulls[Anum_pg_authid_rolconfig - 1] = 'n'; - tuple = heap_formtuple(pg_shadow_dsc, new_record, new_record_nulls); + tuple = heap_formtuple(pg_authid_dsc, new_record, new_record_nulls); /* - * Insert new record in the pg_shadow table + * Insert new record in the pg_authid table */ - simple_heap_insert(pg_shadow_rel, tuple); + roleid = simple_heap_insert(pg_authid_rel, tuple); + Assert(OidIsValid(roleid)); /* Update indexes */ - CatalogUpdateIndexes(pg_shadow_rel, tuple); + CatalogUpdateIndexes(pg_authid_rel, tuple); /* - * Add the user to the groups specified. We'll just call the below - * AlterGroup for this. + * Add the new role to the specified existing roles. */ - foreach(item, groupElts) + foreach(item, roleElts) { - AlterGroupStmt ags; + char *oldrolename = strVal(lfirst(item)); + Oid oldroleid = get_roleid_checked(oldrolename); - ags.name = strVal(lfirst(item)); /* the group name to add - * this in */ - ags.action = +1; - ags.listUsers = list_make1(makeInteger(sysid)); - AlterGroup(&ags, "CREATE USER"); + AddRoleMems(oldrolename, oldroleid, + list_make1(makeString(stmt->role)), + list_make1_oid(roleid), + GetUserId(), false); } /* + * Add the specified members to this new role. + */ + AddRoleMems(stmt->role, roleid, + rolememElts, roleNamesToIds(rolememElts), + GetUserId(), false); + + /* * Now we can clean up; but keep lock until commit (to avoid possible * deadlock when commit code tries to acquire lock). */ - heap_close(pg_shadow_rel, NoLock); + heap_close(pg_authid_rel, NoLock); /* - * Set flag to update flat password file at commit. + * Set flag to update flat auth file at commit. */ - user_file_update_needed(); + auth_file_update_needed(); } - /* - * ALTER USER + * ALTER ROLE */ void -AlterUser(AlterUserStmt *stmt) +AlterRole(AlterRoleStmt *stmt) { - Datum new_record[Natts_pg_shadow]; - char new_record_nulls[Natts_pg_shadow]; - char new_record_repl[Natts_pg_shadow]; - Relation pg_shadow_rel; - TupleDesc pg_shadow_dsc; + Datum new_record[Natts_pg_authid]; + char new_record_nulls[Natts_pg_authid]; + char new_record_repl[Natts_pg_authid]; + Relation pg_authid_rel; + TupleDesc pg_authid_dsc; HeapTuple tuple, new_tuple; ListCell *option; - char *password = NULL; /* PostgreSQL user password */ + char *password = NULL; /* user password */ bool encrypt_password = Password_encryption; /* encrypt password? */ char encrypted_password[MD5_PASSWD_LEN + 1]; - int createdb = -1; /* Can the user create databases? */ - int createuser = -1; /* Can this user create users? */ + int issuper = -1; /* Make the user a superuser? */ + int createrole = -1; /* Can this user create roles? */ + int createdb = -1; /* Can the user create databases? */ + int canlogin = -1; /* Can this user login? */ + int adminopt = 0; /* Can this user grant this role to others? */ + List *rolememElts = NIL; /* The roles which will be added/removed to this role */ char *validUntil = NULL; /* The time the login is valid * until */ DefElem *dpassword = NULL; DefElem *dcreatedb = NULL; - DefElem *dcreateuser = NULL; + DefElem *dcreaterole = NULL; + DefElem *dcanlogin = NULL; + DefElem *dadminopt = NULL; DefElem *dvalidUntil = NULL; + DefElem *drolememElts = NULL; + Oid roleid; /* Extract options from the statement node tree */ foreach(option, stmt->options) @@ -351,13 +349,29 @@ AlterUser(AlterUserStmt *stmt) errmsg("conflicting or redundant options"))); dcreatedb = defel; } - else if (strcmp(defel->defname, "createuser") == 0) + else if (strcmp(defel->defname, "createrole") == 0) { - if (dcreateuser) + if (dcreaterole) ereport(ERROR, (errcode(ERRCODE_SYNTAX_ERROR), errmsg("conflicting or redundant options"))); - dcreateuser = defel; + dcreaterole = defel; + } + else if (strcmp(defel->defname, "canlogin") == 0) + { + if (dcanlogin) + ereport(ERROR, + (errcode(ERRCODE_SYNTAX_ERROR), + errmsg("conflicting or redundant options"))); + dcanlogin = defel; + } + else if (strcmp(defel->defname, "adminopt") == 0) + { + if (dadminopt) + ereport(ERROR, + (errcode(ERRCODE_SYNTAX_ERROR), + errmsg("conflicting or redundant options"))); + dadminopt = defel; } else if (strcmp(defel->defname, "validUntil") == 0) { @@ -367,6 +381,14 @@ AlterUser(AlterUserStmt *stmt) errmsg("conflicting or redundant options"))); dvalidUntil = defel; } + else if (strcmp(defel->defname, "rolememElts") == 0 && stmt->action != 0) + { + if (drolememElts) + ereport(ERROR, + (errcode(ERRCODE_SYNTAX_ERROR), + errmsg("conflicting or redundant options"))); + drolememElts = defel; + } else elog(ERROR, "option \"%s\" not recognized", defel->defname); @@ -374,42 +396,54 @@ AlterUser(AlterUserStmt *stmt) if (dcreatedb) createdb = intVal(dcreatedb->arg); - if (dcreateuser) - createuser = intVal(dcreateuser->arg); + if (dcreaterole) + { + createrole = intVal(dcreaterole->arg); + /* XXX createrole implies issuper for now */ + issuper = createrole; + } + if (dcanlogin) + canlogin = intVal(dcanlogin->arg); + if (dadminopt) + adminopt = intVal(dadminopt->arg); if (dvalidUntil) validUntil = strVal(dvalidUntil->arg); if (dpassword) password = strVal(dpassword->arg); - - if (password) - CheckPgUserAclNotNull(); + if (drolememElts) + rolememElts = (List *) drolememElts->arg; /* must be superuser or just want to change your own password */ if (!superuser() && - !(createdb < 0 && - createuser < 0 && + !(issuper < 0 && + createrole < 0 && + createdb < 0 && + canlogin < 0 && !validUntil && + !rolememElts && + !adminopt && password && - strcmp(GetUserNameFromId(GetUserId()), stmt->user) == 0)) + strcmp(GetUserNameFromId(GetUserId()), stmt->role) == 0)) ereport(ERROR, (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE), errmsg("permission denied"))); /* - * Scan the pg_shadow relation to be certain the user exists. Note we - * secure exclusive lock to protect our update of the flat password - * file. + * Scan the pg_authid relation to be certain the user exists. Note we + * secure exclusive lock to protect our update of the flat auth file. */ - pg_shadow_rel = heap_open(ShadowRelationId, ExclusiveLock); - pg_shadow_dsc = RelationGetDescr(pg_shadow_rel); + pg_authid_rel = heap_open(AuthIdRelationId, ExclusiveLock); + pg_authid_dsc = RelationGetDescr(pg_authid_rel); - tuple = SearchSysCache(SHADOWNAME, - PointerGetDatum(stmt->user), + tuple = SearchSysCache(AUTHNAME, + PointerGetDatum(stmt->role), 0, 0, 0); if (!HeapTupleIsValid(tuple)) ereport(ERROR, (errcode(ERRCODE_UNDEFINED_OBJECT), - errmsg("user \"%s\" does not exist", stmt->user))); + errmsg("role \"%s\" does not exist", stmt->role))); + + roleid = HeapTupleGetOid(tuple); /* * Build an updated tuple, perusing the information just obtained @@ -418,65 +452,79 @@ AlterUser(AlterUserStmt *stmt) MemSet(new_record_nulls, ' ', sizeof(new_record_nulls)); MemSet(new_record_repl, ' ', sizeof(new_record_repl)); - new_record[Anum_pg_shadow_usename - 1] = DirectFunctionCall1(namein, - CStringGetDatum(stmt->user)); - new_record_repl[Anum_pg_shadow_usename - 1] = 'r'; - - /* createdb */ - if (createdb >= 0) - { - new_record[Anum_pg_shadow_usecreatedb - 1] = BoolGetDatum(createdb > 0); - new_record_repl[Anum_pg_shadow_usecreatedb - 1] = 'r'; - } + new_record[Anum_pg_authid_rolname - 1] = DirectFunctionCall1(namein, + CStringGetDatum(stmt->role)); + new_record_repl[Anum_pg_authid_rolname - 1] = 'r'; /* - * createuser (superuser) and catupd + * issuper/createrole/catupdate/etc * - * XXX It's rather unclear how to handle catupd. It's probably best to + * XXX It's rather unclear how to handle catupdate. It's probably best to * keep it equal to the superuser status, otherwise you could end up * with a situation where no existing superuser can alter the - * catalogs, including pg_shadow! + * catalogs, including pg_authid! */ - if (createuser >= 0) + if (issuper >= 0) { - new_record[Anum_pg_shadow_usesuper - 1] = BoolGetDatum(createuser > 0); - new_record_repl[Anum_pg_shadow_usesuper - 1] = 'r'; + new_record[Anum_pg_authid_rolsuper - 1] = BoolGetDatum(issuper > 0); + new_record_repl[Anum_pg_authid_rolsuper - 1] = 'r'; - new_record[Anum_pg_shadow_usecatupd - 1] = BoolGetDatum(createuser > 0); - new_record_repl[Anum_pg_shadow_usecatupd - 1] = 'r'; + new_record[Anum_pg_authid_rolcatupdate - 1] = BoolGetDatum(issuper > 0); + new_record_repl[Anum_pg_authid_rolcatupdate - 1] = 'r'; + } + + if (createrole >= 0) + { + new_record[Anum_pg_authid_rolcreaterole - 1] = BoolGetDatum(createrole > 0); + new_record_repl[Anum_pg_authid_rolcreaterole - 1] = 'r'; + } + + if (createdb >= 0) + { + new_record[Anum_pg_authid_rolcreatedb - 1] = BoolGetDatum(createdb > 0); + new_record_repl[Anum_pg_authid_rolcreatedb - 1] = 'r'; + } + + if (canlogin >= 0) + { + new_record[Anum_pg_authid_rolcanlogin - 1] = BoolGetDatum(canlogin > 0); + new_record_repl[Anum_pg_authid_rolcanlogin - 1] = 'r'; } /* password */ if (password) { if (!encrypt_password || isMD5(password)) - new_record[Anum_pg_shadow_passwd - 1] = + new_record[Anum_pg_authid_rolpassword - 1] = DirectFunctionCall1(textin, CStringGetDatum(password)); else { - if (!EncryptMD5(password, stmt->user, strlen(stmt->user), + if (!EncryptMD5(password, stmt->role, strlen(stmt->role), encrypted_password)) elog(ERROR, "password encryption failed"); - new_record[Anum_pg_shadow_passwd - 1] = + new_record[Anum_pg_authid_rolpassword - 1] = DirectFunctionCall1(textin, CStringGetDatum(encrypted_password)); } - new_record_repl[Anum_pg_shadow_passwd - 1] = 'r'; + new_record_repl[Anum_pg_authid_rolpassword - 1] = 'r'; } /* valid until */ if (validUntil) { - new_record[Anum_pg_shadow_valuntil - 1] = - DirectFunctionCall1(abstimein, CStringGetDatum(validUntil)); - new_record_repl[Anum_pg_shadow_valuntil - 1] = 'r'; + new_record[Anum_pg_authid_rolvaliduntil - 1] = + DirectFunctionCall3(timestamptz_in, + CStringGetDatum(validUntil), + ObjectIdGetDatum(InvalidOid), + Int32GetDatum(-1)); + new_record_repl[Anum_pg_authid_rolvaliduntil - 1] = 'r'; } - new_tuple = heap_modifytuple(tuple, pg_shadow_dsc, new_record, + new_tuple = heap_modifytuple(tuple, pg_authid_dsc, new_record, new_record_nulls, new_record_repl); - simple_heap_update(pg_shadow_rel, &tuple->t_self, new_tuple); + simple_heap_update(pg_authid_rel, &tuple->t_self, new_tuple); /* Update indexes */ - CatalogUpdateIndexes(pg_shadow_rel, new_tuple); + CatalogUpdateIndexes(pg_authid_rel, new_tuple); ReleaseSysCache(tuple); heap_freetuple(new_tuple); @@ -485,59 +533,68 @@ AlterUser(AlterUserStmt *stmt) * Now we can clean up; but keep lock until commit (to avoid possible * deadlock when commit code tries to acquire lock). */ - heap_close(pg_shadow_rel, NoLock); + heap_close(pg_authid_rel, NoLock); + + if (stmt->action == +1) /* add members to role */ + AddRoleMems(stmt->role, roleid, + rolememElts, roleNamesToIds(rolememElts), + GetUserId(), adminopt); + else if (stmt->action == -1) /* drop members from role */ + DelRoleMems(stmt->role, roleid, + rolememElts, roleNamesToIds(rolememElts), + adminopt); /* - * Set flag to update flat password file at commit. + * Set flag to update flat auth file at commit. */ - user_file_update_needed(); + auth_file_update_needed(); } /* - * ALTER USER ... SET + * ALTER ROLE ... SET */ void -AlterUserSet(AlterUserSetStmt *stmt) +AlterRoleSet(AlterRoleSetStmt *stmt) { char *valuestr; HeapTuple oldtuple, newtuple; Relation rel; - Datum repl_val[Natts_pg_shadow]; - char repl_null[Natts_pg_shadow]; - char repl_repl[Natts_pg_shadow]; + Datum repl_val[Natts_pg_authid]; + char repl_null[Natts_pg_authid]; + char repl_repl[Natts_pg_authid]; int i; valuestr = flatten_set_variable_args(stmt->variable, stmt->value); /* * RowExclusiveLock is sufficient, because we don't need to update the - * flat password file. + * flat auth file. */ - rel = heap_open(ShadowRelationId, RowExclusiveLock); - oldtuple = SearchSysCache(SHADOWNAME, - PointerGetDatum(stmt->user), + rel = heap_open(AuthIdRelationId, RowExclusiveLock); + oldtuple = SearchSysCache(AUTHNAME, + PointerGetDatum(stmt->role), 0, 0, 0); if (!HeapTupleIsValid(oldtuple)) ereport(ERROR, (errcode(ERRCODE_UNDEFINED_OBJECT), - errmsg("user \"%s\" does not exist", stmt->user))); + errmsg("role \"%s\" does not exist", stmt->role))); if (!(superuser() || - ((Form_pg_shadow) GETSTRUCT(oldtuple))->usesysid == GetUserId())) + (HeapTupleGetOid(oldtuple) == GetUserId()))) ereport(ERROR, (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE), errmsg("permission denied"))); - for (i = 0; i < Natts_pg_shadow; i++) + for (i = 0; i < Natts_pg_authid; i++) repl_repl[i] = ' '; - repl_repl[Anum_pg_shadow_useconfig - 1] = 'r'; + repl_repl[Anum_pg_authid_rolconfig - 1] = 'r'; if (strcmp(stmt->variable, "all") == 0 && valuestr == NULL) { /* RESET ALL */ - repl_null[Anum_pg_shadow_useconfig - 1] = 'n'; + repl_null[Anum_pg_authid_rolconfig - 1] = 'n'; } else { @@ -545,10 +602,10 @@ AlterUserSet(AlterUserSetStmt *stmt) bool isnull; ArrayType *array; - repl_null[Anum_pg_shadow_useconfig - 1] = ' '; + repl_null[Anum_pg_authid_rolconfig - 1] = ' '; - datum = SysCacheGetAttr(SHADOWNAME, oldtuple, - Anum_pg_shadow_useconfig, &isnull); + datum = SysCacheGetAttr(AUTHNAME, oldtuple, + Anum_pg_authid_rolconfig, &isnull); array = isnull ? NULL : DatumGetArrayTypeP(datum); @@ -558,9 +615,9 @@ AlterUserSet(AlterUserSetStmt *stmt) array = GUCArrayDelete(array, stmt->variable); if (array) - repl_val[Anum_pg_shadow_useconfig - 1] = PointerGetDatum(array); + repl_val[Anum_pg_authid_rolconfig - 1] = PointerGetDatum(array); else - repl_null[Anum_pg_shadow_useconfig - 1] = 'n'; + repl_null[Anum_pg_authid_rolconfig - 1] = 'n'; } newtuple = heap_modifytuple(oldtuple, RelationGetDescr(rel), repl_val, repl_null, repl_repl); @@ -574,60 +631,61 @@ AlterUserSet(AlterUserSetStmt *stmt) /* - * DROP USER + * DROP ROLE */ void -DropUser(DropUserStmt *stmt) +DropRole(DropRoleStmt *stmt) { - Relation pg_shadow_rel; - TupleDesc pg_shadow_dsc; + Relation pg_authid_rel, pg_auth_members_rel; ListCell *item; if (!superuser()) ereport(ERROR, (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE), - errmsg("must be superuser to drop users"))); + errmsg("must be superuser to drop roles"))); /* - * Scan the pg_shadow relation to find the usesysid of the user to be + * Scan the pg_authid relation to find the Oid of the role to be * deleted. Note we secure exclusive lock, because we need to protect - * our update of the flat password file. + * our update of the flat auth file. */ - pg_shadow_rel = heap_open(ShadowRelationId, ExclusiveLock); - pg_shadow_dsc = RelationGetDescr(pg_shadow_rel); + pg_authid_rel = heap_open(AuthIdRelationId, ExclusiveLock); + pg_auth_members_rel = heap_open(AuthMemRelationId, ExclusiveLock); - foreach(item, stmt->users) + foreach(item, stmt->roles) { - const char *user = strVal(lfirst(item)); + const char *role = strVal(lfirst(item)); HeapTuple tuple, tmp_tuple; Relation pg_rel; TupleDesc pg_dsc; ScanKeyData scankey; HeapScanDesc scan; - AclId usesysid; + CatCList *auth_mem_list; + Oid roleid; + int i; - tuple = SearchSysCache(SHADOWNAME, - PointerGetDatum(user), + tuple = SearchSysCache(AUTHNAME, + PointerGetDatum(role), 0, 0, 0); if (!HeapTupleIsValid(tuple)) ereport(ERROR, (errcode(ERRCODE_UNDEFINED_OBJECT), - errmsg("user \"%s\" does not exist", user))); + errmsg("role \"%s\" does not exist", role))); - usesysid = ((Form_pg_shadow) GETSTRUCT(tuple))->usesysid; + roleid = HeapTupleGetOid(tuple); - if (usesysid == GetUserId()) + if (roleid == GetUserId()) ereport(ERROR, (errcode(ERRCODE_OBJECT_IN_USE), - errmsg("current user cannot be dropped"))); - if (usesysid == GetSessionUserId()) + errmsg("current role cannot be dropped"))); + if (roleid == GetSessionUserId()) ereport(ERROR, (errcode(ERRCODE_OBJECT_IN_USE), - errmsg("session user cannot be dropped"))); + errmsg("session role cannot be dropped"))); /* - * Check if user still owns a database. If so, error out. + * Check if role still owns a database. If so, error out. * * (It used to be that this function would drop the database * automatically. This is not only very dangerous for people that @@ -639,8 +697,8 @@ DropUser(DropUserStmt *stmt) ScanKeyInit(&scankey, Anum_pg_database_datdba, - BTEqualStrategyNumber, F_INT4EQ, - Int32GetDatum(usesysid)); + BTEqualStrategyNumber, F_OIDEQ, + roleid); scan = heap_beginscan(pg_rel, SnapshotNow, 1, &scankey); @@ -651,8 +709,8 @@ DropUser(DropUserStmt *stmt) dbname = NameStr(((Form_pg_database) GETSTRUCT(tmp_tuple))->datname); ereport(ERROR, (errcode(ERRCODE_OBJECT_IN_USE), - errmsg("user \"%s\" cannot be dropped", user), - errdetail("The user owns database \"%s\".", dbname))); + errmsg("role \"%s\" cannot be dropped", role), + errdetail("The role owns database \"%s\".", dbname))); } heap_endscan(scan); @@ -660,66 +718,64 @@ DropUser(DropUserStmt *stmt) /* * Somehow we'd have to check for tables, views, etc. owned by the - * user as well, but those could be spread out over all sorts of + * role as well, but those could be spread out over all sorts of * databases which we don't have access to (easily). */ /* - * Remove the user from the pg_shadow table + * Remove the role from the pg_authid table */ - simple_heap_delete(pg_shadow_rel, &tuple->t_self); + simple_heap_delete(pg_authid_rel, &tuple->t_self); ReleaseSysCache(tuple); /* - * Remove user from groups + * Remove role from roles * - * try calling alter group drop user for every group + * scan pg_auth_members and remove tuples which have + * roleid == member or roleid == role */ - pg_rel = heap_open(GroupRelationId, ExclusiveLock); - pg_dsc = RelationGetDescr(pg_rel); - scan = heap_beginscan(pg_rel, SnapshotNow, 0, NULL); - while ((tmp_tuple = heap_getnext(scan, ForwardScanDirection)) != NULL) - { - AlterGroupStmt ags; + auth_mem_list = SearchSysCacheList(AUTHMEMROLEMEM, 1, + ObjectIdGetDatum(roleid), + 0, 0, 0); - /* the group name from which to try to drop the user: */ - ags.name = pstrdup(NameStr(((Form_pg_group) GETSTRUCT(tmp_tuple))->groname)); - ags.action = -1; - ags.listUsers = list_make1(makeInteger(usesysid)); - AlterGroup(&ags, "DROP USER"); + for (i = 0; i < auth_mem_list->n_members; i++) + { + HeapTuple authmemtup = &auth_mem_list->members[i]->tuple; + simple_heap_delete(pg_auth_members_rel, &authmemtup->t_self); } - heap_endscan(scan); - heap_close(pg_rel, ExclusiveLock); + ReleaseSysCacheList(auth_mem_list); - /* - * Advance command counter so that later iterations of this loop - * will see the changes already made. This is essential if, for - * example, we are trying to drop two users who are members of the - * same group --- the AlterGroup for the second user had better - * see the tuple updated from the first one. - */ - CommandCounterIncrement(); + auth_mem_list = SearchSysCacheList(AUTHMEMMEMROLE, 1, + ObjectIdGetDatum(roleid), + 0, 0, 0); + + for (i = 0; i < auth_mem_list->n_members; i++) + { + HeapTuple authmemtup = &auth_mem_list->members[i]->tuple; + simple_heap_delete(pg_auth_members_rel, &authmemtup->t_self); + } + ReleaseSysCacheList(auth_mem_list); } /* * Now we can clean up; but keep lock until commit (to avoid possible * deadlock when commit code tries to acquire lock). */ - heap_close(pg_shadow_rel, NoLock); + heap_close(pg_auth_members_rel, NoLock); + heap_close(pg_authid_rel, NoLock); /* - * Set flag to update flat password file at commit. + * Set flag to update flat auth file at commit. */ - user_file_update_needed(); + auth_file_update_needed(); } - /* - * Rename user + * Rename role */ void -RenameUser(const char *oldname, const char *newname) +RenameRole(const char *oldname, const char *newname) { HeapTuple oldtuple, newtuple; @@ -727,22 +783,23 @@ RenameUser(const char *oldname, const char *newname) Relation rel; Datum datum; bool isnull; - Datum repl_val[Natts_pg_shadow]; - char repl_null[Natts_pg_shadow]; - char repl_repl[Natts_pg_shadow]; + Datum repl_val[Natts_pg_authid]; + char repl_null[Natts_pg_authid]; + char repl_repl[Natts_pg_authid]; int i; + Oid roleid; /* ExclusiveLock because we need to update the password file */ - rel = heap_open(ShadowRelationId, ExclusiveLock); + rel = heap_open(AuthIdRelationId, ExclusiveLock); dsc = RelationGetDescr(rel); - oldtuple = SearchSysCache(SHADOWNAME, + oldtuple = SearchSysCache(AUTHNAME, CStringGetDatum(oldname), 0, 0, 0); if (!HeapTupleIsValid(oldtuple)) ereport(ERROR, (errcode(ERRCODE_UNDEFINED_OBJECT), - errmsg("user \"%s\" does not exist", oldname))); + errmsg("role \"%s\" does not exist", oldname))); /* * XXX Client applications probably store the session user somewhere, @@ -750,43 +807,46 @@ RenameUser(const char *oldname, const char *newname) * not be an actual problem besides a little confusion, so think about * this and decide. */ - if (((Form_pg_shadow) GETSTRUCT(oldtuple))->usesysid == GetSessionUserId()) + + roleid = HeapTupleGetOid(oldtuple); + + if (roleid == GetSessionUserId()) ereport(ERROR, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), - errmsg("session user may not be renamed"))); + errmsg("session role may not be renamed"))); /* make sure the new name doesn't exist */ - if (SearchSysCacheExists(SHADOWNAME, + if (SearchSysCacheExists(AUTHNAME, CStringGetDatum(newname), 0, 0, 0)) ereport(ERROR, (errcode(ERRCODE_DUPLICATE_OBJECT), - errmsg("user \"%s\" already exists", newname))); + errmsg("role \"%s\" already exists", newname))); /* must be superuser */ if (!superuser()) ereport(ERROR, (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE), - errmsg("must be superuser to rename users"))); + errmsg("must be superuser to rename roles"))); - for (i = 0; i < Natts_pg_shadow; i++) + for (i = 0; i < Natts_pg_authid; i++) repl_repl[i] = ' '; - repl_repl[Anum_pg_shadow_usename - 1] = 'r'; - repl_val[Anum_pg_shadow_usename - 1] = DirectFunctionCall1(namein, + repl_repl[Anum_pg_authid_rolname - 1] = 'r'; + repl_val[Anum_pg_authid_rolname - 1] = DirectFunctionCall1(namein, CStringGetDatum(newname)); - repl_null[Anum_pg_shadow_usename - 1] = ' '; + repl_null[Anum_pg_authid_rolname - 1] = ' '; - datum = heap_getattr(oldtuple, Anum_pg_shadow_passwd, dsc, &isnull); + datum = heap_getattr(oldtuple, Anum_pg_authid_rolpassword, dsc, &isnull); if (!isnull && isMD5(DatumGetCString(DirectFunctionCall1(textout, datum)))) { /* MD5 uses the username as salt, so just clear it on a rename */ - repl_repl[Anum_pg_shadow_passwd - 1] = 'r'; - repl_null[Anum_pg_shadow_passwd - 1] = 'n'; + repl_repl[Anum_pg_authid_rolpassword - 1] = 'r'; + repl_null[Anum_pg_authid_rolpassword - 1] = 'n'; ereport(NOTICE, - (errmsg("MD5 password cleared because of user rename"))); + (errmsg("MD5 password cleared because of role rename"))); } newtuple = heap_modifytuple(oldtuple, dsc, repl_val, repl_null, repl_repl); @@ -797,551 +857,322 @@ RenameUser(const char *oldname, const char *newname) ReleaseSysCache(oldtuple); heap_close(rel, NoLock); - user_file_update_needed(); + auth_file_update_needed(); } - /* - * CheckPgUserAclNotNull + * GrantRoleStmt * - * check to see if there is an ACL on pg_shadow - */ -static void -CheckPgUserAclNotNull(void) -{ - HeapTuple htup; - - htup = SearchSysCache(RELOID, - ObjectIdGetDatum(ShadowRelationId), - 0, 0, 0); - if (!HeapTupleIsValid(htup)) /* should not happen, we hope */ - elog(ERROR, "cache lookup failed for relation %u", ShadowRelationId); - - if (heap_attisnull(htup, Anum_pg_class_relacl)) - { - Form_pg_class classForm = (Form_pg_class) GETSTRUCT(htup); - - ereport(ERROR, - (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE), - errmsg("before using passwords you must revoke privileges on %s", - NameStr(classForm->relname)), - errdetail("This restriction is to prevent unprivileged users from reading the passwords."), - errhint("Try REVOKE ALL ON \"%s\" FROM PUBLIC.", - NameStr(classForm->relname)))); - } - - ReleaseSysCache(htup); -} - - -/* - * CREATE GROUP + * Grant/Revoke roles to/from roles */ void -CreateGroup(CreateGroupStmt *stmt) +GrantRole(GrantRoleStmt *stmt) { - Relation pg_group_rel; - HeapScanDesc scan; - HeapTuple tuple; - TupleDesc pg_group_dsc; - bool group_exists = false, - sysid_exists = false, - havesysid = false; - int max_id; - Datum new_record[Natts_pg_group]; - char new_record_nulls[Natts_pg_group]; + Oid grantor; + List *grantee_ids; ListCell *item; - ListCell *option; - List *newlist = NIL; - IdList *grolist; - int sysid = 0; - List *userElts = NIL; - DefElem *dsysid = NULL; - DefElem *duserElts = NULL; - - foreach(option, stmt->options) - { - DefElem *defel = (DefElem *) lfirst(option); - if (strcmp(defel->defname, "sysid") == 0) - { - if (dsysid) - ereport(ERROR, - (errcode(ERRCODE_SYNTAX_ERROR), - errmsg("conflicting or redundant options"))); - dsysid = defel; - } - else if (strcmp(defel->defname, "userElts") == 0) - { - if (duserElts) - ereport(ERROR, - (errcode(ERRCODE_SYNTAX_ERROR), - errmsg("conflicting or redundant options"))); - duserElts = defel; - } - else - elog(ERROR, "option \"%s\" not recognized", - defel->defname); - } - - if (dsysid) - { - sysid = intVal(dsysid->arg); - if (sysid <= 0) - ereport(ERROR, - (errcode(ERRCODE_INVALID_PARAMETER_VALUE), - errmsg("group ID must be positive"))); - havesysid = true; - } + if (stmt->grantor) + grantor = get_roleid_checked(stmt->grantor); + else + grantor = GetUserId(); - if (duserElts) - userElts = (List *) duserElts->arg; + grantee_ids = roleNamesToIds(stmt->grantee_roles); /* - * Make sure the user can do this. - */ - if (!superuser()) - ereport(ERROR, - (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE), - errmsg("must be superuser to create groups"))); - - if (strcmp(stmt->name, "public") == 0) - ereport(ERROR, - (errcode(ERRCODE_RESERVED_NAME), - errmsg("group name \"%s\" is reserved", - stmt->name))); - - /* - * Scan the pg_group relation to be certain the group or id doesn't - * already exist. Note we secure exclusive lock, because we also need - * to be sure of what the next grosysid should be, and we need to - * protect our eventual update of the flat group file. + * Step through all of the granted roles and add/remove + * entries for the grantees, or, if admin_opt is set, then + * just add/remove the admin option. + * + * Note: Permissions checking is done by AddRoleMems/DelRoleMems */ - pg_group_rel = heap_open(GroupRelationId, ExclusiveLock); - pg_group_dsc = RelationGetDescr(pg_group_rel); - - scan = heap_beginscan(pg_group_rel, SnapshotNow, 0, NULL); - max_id = 99; /* start auto-assigned ids at 100 */ - while (!group_exists && !sysid_exists && - (tuple = heap_getnext(scan, ForwardScanDirection)) != NULL) + foreach(item, stmt->granted_roles) { - Form_pg_group group_form = (Form_pg_group) GETSTRUCT(tuple); - int32 this_sysid; + char *rolename = strVal(lfirst(item)); + Oid roleid = get_roleid_checked(rolename); - group_exists = (strcmp(NameStr(group_form->groname), stmt->name) == 0); - - this_sysid = group_form->grosysid; - if (havesysid) /* customized id wanted */ - sysid_exists = (this_sysid == sysid); + if (stmt->is_grant) + AddRoleMems(rolename, roleid, + stmt->grantee_roles, grantee_ids, + grantor, stmt->admin_opt); else - { - /* pick 1 + max */ - if (this_sysid > max_id) - max_id = this_sysid; - } + DelRoleMems(rolename, roleid, + stmt->grantee_roles, grantee_ids, + stmt->admin_opt); } - heap_endscan(scan); - - if (group_exists) - ereport(ERROR, - (errcode(ERRCODE_DUPLICATE_OBJECT), - errmsg("group \"%s\" already exists", - stmt->name))); - if (sysid_exists) - ereport(ERROR, - (errcode(ERRCODE_DUPLICATE_OBJECT), - errmsg("group ID %d is already assigned", sysid))); +} - /* If no sysid given, use max existing id + 1 */ - if (!havesysid) - sysid = max_id + 1; +/* + * roleNamesToIds + * + * Given a list of role names (as String nodes), generate a list of role OIDs + * in the same order. + */ +static List * +roleNamesToIds(List *memberNames) +{ + List *result = NIL; + ListCell *l; - /* - * Translate the given user names to ids - */ - foreach(item, userElts) + foreach(l, memberNames) { - const char *groupuser = strVal(lfirst(item)); - int32 userid = get_usesysid(groupuser); + char *rolename = strVal(lfirst(l)); + Oid roleid = get_roleid_checked(rolename); - if (!list_member_int(newlist, userid)) - newlist = lappend_int(newlist, userid); + result = lappend_oid(result, roleid); } - - /* build an array to insert */ - if (newlist) - grolist = IdListToArray(newlist); - else - grolist = NULL; - - /* - * Form a tuple to insert - */ - new_record[Anum_pg_group_groname - 1] = - DirectFunctionCall1(namein, CStringGetDatum(stmt->name)); - new_record[Anum_pg_group_grosysid - 1] = Int32GetDatum(sysid); - new_record[Anum_pg_group_grolist - 1] = PointerGetDatum(grolist); - - new_record_nulls[Anum_pg_group_groname - 1] = ' '; - new_record_nulls[Anum_pg_group_grosysid - 1] = ' '; - new_record_nulls[Anum_pg_group_grolist - 1] = grolist ? ' ' : 'n'; - - tuple = heap_formtuple(pg_group_dsc, new_record, new_record_nulls); - - /* - * Insert a new record in the pg_group table - */ - simple_heap_insert(pg_group_rel, tuple); - - /* Update indexes */ - CatalogUpdateIndexes(pg_group_rel, tuple); - - /* - * Now we can clean up; but keep lock until commit (to avoid possible - * deadlock when commit code tries to acquire lock). - */ - heap_close(pg_group_rel, NoLock); - - /* - * Set flag to update flat group file at commit. - */ - group_file_update_needed(); + return result; } - /* - * ALTER GROUP + * AddRoleMems -- Add given members to the specified role + * + * rolename: name of role to add to (used only for error messages) + * roleid: OID of role to add to + * memberNames: list of names of roles to add (used only for error messages) + * memberIds: OIDs of roles to add + * grantorId: who is granting the membership + * admin_opt: granting admin option? */ -void -AlterGroup(AlterGroupStmt *stmt, const char *tag) +static void +AddRoleMems(const char *rolename, Oid roleid, + List *memberNames, List *memberIds, + Oid grantorId, bool admin_opt) { - Relation pg_group_rel; - TupleDesc pg_group_dsc; - HeapTuple group_tuple; - IdList *oldarray; - Datum datum; - bool null; - List *newlist; - ListCell *item; + Relation pg_authmem_rel; + TupleDesc pg_authmem_dsc; + ListCell *nameitem; + ListCell *iditem; - /* - * Make sure the user can do this. - */ - if (!superuser()) - ereport(ERROR, - (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE), - errmsg("must be superuser to alter groups"))); + Assert(list_length(memberNames) == list_length(memberIds)); - /* - * Secure exclusive lock to protect our update of the flat group file. - */ - pg_group_rel = heap_open(GroupRelationId, ExclusiveLock); - pg_group_dsc = RelationGetDescr(pg_group_rel); + /* Skip permission check if nothing to do */ + if (!memberIds) + return; /* - * Fetch existing tuple for group. + * Check permissions: must be superuser or have admin option on the + * role to be changed. + * + * XXX: The admin option is not considered to be inherited through + * multiple roles, unlike normal 'is_member_of_role' privilege checks. */ - group_tuple = SearchSysCache(GRONAME, - PointerGetDatum(stmt->name), - 0, 0, 0); - if (!HeapTupleIsValid(group_tuple)) - ereport(ERROR, - (errcode(ERRCODE_UNDEFINED_OBJECT), - errmsg("group \"%s\" does not exist", stmt->name))); + if (!superuser()) + { + HeapTuple authmem_chk_tuple; + Form_pg_auth_members authmem_chk; - /* Fetch old group membership. */ - datum = heap_getattr(group_tuple, Anum_pg_group_grolist, - pg_group_dsc, &null); - oldarray = null ? NULL : DatumGetIdListP(datum); + if (grantorId != GetUserId()) + ereport(ERROR, + (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE), + errmsg("must be superuser to set grantor ID"))); + + authmem_chk_tuple = SearchSysCache(AUTHMEMROLEMEM, + ObjectIdGetDatum(roleid), + ObjectIdGetDatum(grantorId), + 0, 0); + if (!HeapTupleIsValid(authmem_chk_tuple)) + ereport(ERROR, + (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE), + errmsg("must be superuser or have admin option on role \"%s\"", + rolename))); - /* initialize list with old array contents */ - newlist = IdArrayToList(oldarray); + authmem_chk = (Form_pg_auth_members) GETSTRUCT(authmem_chk_tuple); + if (!authmem_chk->admin_option) + ereport(ERROR, + (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE), + errmsg("must be superuser or have admin option on role \"%s\"", + rolename))); + ReleaseSysCache(authmem_chk_tuple); + } /* - * Now decide what to do. + * Secure exclusive lock to protect our update of the flat auth file. */ - AssertState(stmt->action == +1 || stmt->action == -1); + pg_authmem_rel = heap_open(AuthMemRelationId, ExclusiveLock); + pg_authmem_dsc = RelationGetDescr(pg_authmem_rel); - if (stmt->action == +1) /* add users, might also be invoked by - * create user */ + forboth(nameitem, memberNames, iditem, memberIds) { + const char *membername = strVal(lfirst(nameitem)); + Oid memberid = lfirst_oid(iditem); + HeapTuple authmem_tuple; + HeapTuple tuple; + Datum new_record[Natts_pg_auth_members]; + char new_record_nulls[Natts_pg_auth_members]; + char new_record_repl[Natts_pg_auth_members]; + /* - * convert the to be added usernames to sysids and add them to the - * list + * Check if entry for this role/member already exists; + * if so, give warning unless we are adding admin option. */ - foreach(item, stmt->listUsers) + authmem_tuple = SearchSysCache(AUTHMEMROLEMEM, + ObjectIdGetDatum(roleid), + ObjectIdGetDatum(memberid), + 0, 0); + if (HeapTupleIsValid(authmem_tuple) && !admin_opt) { - int32 sysid; - - if (strcmp(tag, "ALTER GROUP") == 0) - { - /* Get the uid of the proposed user to add. */ - sysid = get_usesysid(strVal(lfirst(item))); - } - else if (strcmp(tag, "CREATE USER") == 0) - { - /* - * in this case we already know the uid and it wouldn't be - * in the cache anyway yet - */ - sysid = intVal(lfirst(item)); - } - else - { - elog(ERROR, "unexpected tag: \"%s\"", tag); - sysid = 0; /* keep compiler quiet */ - } - - if (!list_member_int(newlist, sysid)) - newlist = lappend_int(newlist, sysid); + ereport(NOTICE, + (errmsg("role \"%s\" is already a member of role \"%s\"", + membername, rolename))); + ReleaseSysCache(authmem_tuple); + continue; } - /* Do the update */ - UpdateGroupMembership(pg_group_rel, group_tuple, newlist); - } /* endif alter group add user */ + /* Build a tuple to insert or update */ + MemSet(new_record, 0, sizeof(new_record)); + MemSet(new_record_nulls, ' ', sizeof(new_record_nulls)); + MemSet(new_record_repl, ' ', sizeof(new_record_repl)); - else if (stmt->action == -1) /* drop users from group */ - { - bool is_dropuser = strcmp(tag, "DROP USER") == 0; + new_record[Anum_pg_auth_members_roleid - 1] = ObjectIdGetDatum(roleid); + new_record[Anum_pg_auth_members_member - 1] = ObjectIdGetDatum(memberid); + new_record[Anum_pg_auth_members_grantor - 1] = ObjectIdGetDatum(grantorId); + new_record[Anum_pg_auth_members_admin_option - 1] = BoolGetDatum(admin_opt); - if (newlist == NIL) + if (HeapTupleIsValid(authmem_tuple)) { - if (!is_dropuser) - ereport(WARNING, - (errcode(ERRCODE_WARNING), - errmsg("group \"%s\" does not have any members", - stmt->name))); + new_record_repl[Anum_pg_auth_members_grantor - 1] = 'r'; + new_record_repl[Anum_pg_auth_members_admin_option - 1] = 'r'; + tuple = heap_modifytuple(authmem_tuple, pg_authmem_dsc, + new_record, + new_record_nulls, new_record_repl); + simple_heap_update(pg_authmem_rel, &tuple->t_self, tuple); + CatalogUpdateIndexes(pg_authmem_rel, tuple); + ReleaseSysCache(authmem_tuple); } else { - /* - * convert the to be dropped usernames to sysids and remove - * them from the list - */ - foreach(item, stmt->listUsers) - { - int32 sysid; - - if (!is_dropuser) - { - /* Get the uid of the proposed user to drop. */ - sysid = get_usesysid(strVal(lfirst(item))); - } - else - { - /* for dropuser we already know the uid */ - sysid = intVal(lfirst(item)); - } - if (list_member_int(newlist, sysid)) - newlist = list_delete_int(newlist, sysid); - else if (!is_dropuser) - ereport(WARNING, - (errcode(ERRCODE_WARNING), - errmsg("user \"%s\" is not in group \"%s\"", - strVal(lfirst(item)), stmt->name))); - } - - /* Do the update */ - UpdateGroupMembership(pg_group_rel, group_tuple, newlist); - } /* endif group not null */ - } /* endif alter group drop user */ - - ReleaseSysCache(group_tuple); + tuple = heap_formtuple(pg_authmem_dsc, + new_record, new_record_nulls); + simple_heap_insert(pg_authmem_rel, tuple); + CatalogUpdateIndexes(pg_authmem_rel, tuple); + } + } /* * Now we can clean up; but keep lock until commit (to avoid possible * deadlock when commit code tries to acquire lock). */ - heap_close(pg_group_rel, NoLock); - - /* - * Set flag to update flat group file at commit. - */ - group_file_update_needed(); + heap_close(pg_authmem_rel, NoLock); } /* - * Subroutine for AlterGroup: given a pg_group tuple and a desired new - * membership (expressed as an integer list), form and write an updated tuple. - * The pg_group relation must be open and locked already. + * DelRoleMems -- Remove given members from the specified role + * + * rolename: name of role to del from (used only for error messages) + * roleid: OID of role to del from + * memberNames: list of names of roles to del (used only for error messages) + * memberIds: OIDs of roles to del + * admin_opt: remove admin option only? */ static void -UpdateGroupMembership(Relation group_rel, HeapTuple group_tuple, - List *members) +DelRoleMems(const char *rolename, Oid roleid, + List *memberNames, List *memberIds, + bool admin_opt) { - IdList *newarray; - Datum new_record[Natts_pg_group]; - char new_record_nulls[Natts_pg_group]; - char new_record_repl[Natts_pg_group]; - HeapTuple tuple; + Relation pg_authmem_rel; + TupleDesc pg_authmem_dsc; + ListCell *nameitem; + ListCell *iditem; - newarray = IdListToArray(members); + Assert(list_length(memberNames) == list_length(memberIds)); + + /* Skip permission check if nothing to do */ + if (!memberIds) + return; /* - * Form an updated tuple with the new array and write it back. + * Check permissions: must be superuser or have admin option on the + * role to be changed. + * + * XXX: The admin option is not considered to be inherited through + * multiple roles, unlike normal 'is_member_of_role' privilege checks. */ - MemSet(new_record, 0, sizeof(new_record)); - MemSet(new_record_nulls, ' ', sizeof(new_record_nulls)); - MemSet(new_record_repl, ' ', sizeof(new_record_repl)); - - new_record[Anum_pg_group_grolist - 1] = PointerGetDatum(newarray); - new_record_repl[Anum_pg_group_grolist - 1] = 'r'; - - tuple = heap_modifytuple(group_tuple, RelationGetDescr(group_rel), - new_record, new_record_nulls, new_record_repl); - - simple_heap_update(group_rel, &group_tuple->t_self, tuple); - - /* Update indexes */ - CatalogUpdateIndexes(group_rel, tuple); -} - - -/* - * Convert an integer list of sysids to an array. - */ -static IdList * -IdListToArray(List *members) -{ - int nmembers = list_length(members); - IdList *newarray; - ListCell *item; - int i; - - newarray = palloc(ARR_OVERHEAD(1) + nmembers * sizeof(int32)); - newarray->size = ARR_OVERHEAD(1) + nmembers * sizeof(int32); - newarray->flags = 0; - newarray->elemtype = INT4OID; - ARR_NDIM(newarray) = 1; /* one dimensional array */ - ARR_LBOUND(newarray)[0] = 1; /* axis starts at one */ - ARR_DIMS(newarray)[0] = nmembers; /* axis is this long */ - i = 0; - foreach(item, members) - ((int *) ARR_DATA_PTR(newarray))[i++] = lfirst_int(item); - - return newarray; -} - -/* - * Convert an array of sysids to an integer list. - */ -static List * -IdArrayToList(IdList *oldarray) -{ - List *newlist = NIL; - int hibound, - i; - - if (oldarray == NULL) - return NIL; - - Assert(ARR_NDIM(oldarray) == 1); - Assert(ARR_ELEMTYPE(oldarray) == INT4OID); - - hibound = ARR_DIMS(oldarray)[0]; - - for (i = 0; i < hibound; i++) + if (!superuser()) { - int32 sysid; + HeapTuple authmem_chk_tuple; + Form_pg_auth_members authmem_chk; + + authmem_chk_tuple = SearchSysCache(AUTHMEMROLEMEM, + ObjectIdGetDatum(roleid), + ObjectIdGetDatum(GetUserId()), + 0, 0); + if (!HeapTupleIsValid(authmem_chk_tuple)) + ereport(ERROR, + (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE), + errmsg("must be superuser or have admin option on role \"%s\"", + rolename))); - sysid = ((int32 *) ARR_DATA_PTR(oldarray))[i]; - /* filter out any duplicates --- probably a waste of time */ - if (!list_member_int(newlist, sysid)) - newlist = lappend_int(newlist, sysid); + authmem_chk = (Form_pg_auth_members) GETSTRUCT(authmem_chk_tuple); + if (!authmem_chk->admin_option) + ereport(ERROR, + (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE), + errmsg("must be superuser or have admin option on role \"%s\"", + rolename))); + ReleaseSysCache(authmem_chk_tuple); } - return newlist; -} - - -/* - * DROP GROUP - */ -void -DropGroup(DropGroupStmt *stmt) -{ - Relation pg_group_rel; - HeapTuple tuple; - /* - * Make sure the user can do this. + * Secure exclusive lock to protect our update of the flat auth file. */ - if (!superuser()) - ereport(ERROR, - (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE), - errmsg("must be superuser to drop groups"))); + pg_authmem_rel = heap_open(AuthMemRelationId, ExclusiveLock); + pg_authmem_dsc = RelationGetDescr(pg_authmem_rel); - /* - * Secure exclusive lock to protect our update of the flat group file. - */ - pg_group_rel = heap_open(GroupRelationId, ExclusiveLock); + forboth(nameitem, memberNames, iditem, memberIds) + { + const char *membername = strVal(lfirst(nameitem)); + Oid memberid = lfirst_oid(iditem); + HeapTuple authmem_tuple; - /* Find and delete the group. */ + /* + * Find entry for this role/member + */ + authmem_tuple = SearchSysCache(AUTHMEMROLEMEM, + ObjectIdGetDatum(roleid), + ObjectIdGetDatum(memberid), + 0, 0); + if (!HeapTupleIsValid(authmem_tuple)) + { + ereport(WARNING, + (errmsg("role \"%s\" is not a member of role \"%s\"", + membername, rolename))); + continue; + } - tuple = SearchSysCacheCopy(GRONAME, - PointerGetDatum(stmt->name), - 0, 0, 0); - if (!HeapTupleIsValid(tuple)) - ereport(ERROR, - (errcode(ERRCODE_UNDEFINED_OBJECT), - errmsg("group \"%s\" does not exist", stmt->name))); + if (!admin_opt) + { + /* Remove the entry altogether */ + simple_heap_delete(pg_authmem_rel, &authmem_tuple->t_self); + } + else + { + /* Just turn off the admin option */ + HeapTuple tuple; + Datum new_record[Natts_pg_auth_members]; + char new_record_nulls[Natts_pg_auth_members]; + char new_record_repl[Natts_pg_auth_members]; + + /* Build a tuple to update with */ + MemSet(new_record, 0, sizeof(new_record)); + MemSet(new_record_nulls, ' ', sizeof(new_record_nulls)); + MemSet(new_record_repl, ' ', sizeof(new_record_repl)); + + new_record[Anum_pg_auth_members_admin_option - 1] = BoolGetDatum(false); + new_record_repl[Anum_pg_auth_members_admin_option - 1] = 'r'; + + tuple = heap_modifytuple(authmem_tuple, pg_authmem_dsc, + new_record, + new_record_nulls, new_record_repl); + simple_heap_update(pg_authmem_rel, &tuple->t_self, tuple); + CatalogUpdateIndexes(pg_authmem_rel, tuple); + } - simple_heap_delete(pg_group_rel, &tuple->t_self); + ReleaseSysCache(authmem_tuple); + } /* * Now we can clean up; but keep lock until commit (to avoid possible * deadlock when commit code tries to acquire lock). */ - heap_close(pg_group_rel, NoLock); - - /* - * Set flag to update flat group file at commit. - */ - group_file_update_needed(); -} - - -/* - * Rename group - */ -void -RenameGroup(const char *oldname, const char *newname) -{ - HeapTuple tup; - Relation rel; - - /* ExclusiveLock because we need to update the flat group file */ - rel = heap_open(GroupRelationId, ExclusiveLock); - - tup = SearchSysCacheCopy(GRONAME, - CStringGetDatum(oldname), - 0, 0, 0); - if (!HeapTupleIsValid(tup)) - ereport(ERROR, - (errcode(ERRCODE_UNDEFINED_OBJECT), - errmsg("group \"%s\" does not exist", oldname))); - - /* make sure the new name doesn't exist */ - if (SearchSysCacheExists(GRONAME, - CStringGetDatum(newname), - 0, 0, 0)) - ereport(ERROR, - (errcode(ERRCODE_DUPLICATE_OBJECT), - errmsg("group \"%s\" already exists", newname))); - - /* must be superuser */ - if (!superuser()) - ereport(ERROR, - (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE), - errmsg("must be superuser to rename groups"))); - - /* rename */ - namestrcpy(&(((Form_pg_group) GETSTRUCT(tup))->groname), newname); - simple_heap_update(rel, &tup->t_self, tup); - CatalogUpdateIndexes(rel, tup); - - heap_close(rel, NoLock); - heap_freetuple(tup); - - group_file_update_needed(); + heap_close(pg_authmem_rel, NoLock); } diff --git a/src/backend/commands/variable.c b/src/backend/commands/variable.c index 048a3e41562..7df2a92a6c6 100644 --- a/src/backend/commands/variable.c +++ b/src/backend/commands/variable.c @@ -9,7 +9,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/commands/variable.c,v 1.108 2005/06/09 21:52:07 tgl Exp $ + * $PostgreSQL: pgsql/src/backend/commands/variable.c,v 1.109 2005/06/28 05:08:55 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -19,7 +19,7 @@ #include <ctype.h> #include "access/xact.h" -#include "catalog/pg_shadow.h" +#include "catalog/pg_authid.h" #include "commands/variable.h" #include "miscadmin.h" #include "parser/scansup.h" @@ -567,46 +567,46 @@ assign_client_encoding(const char *value, bool doit, GucSource source) * SET SESSION AUTHORIZATION * * When resetting session auth after an error, we can't expect to do catalog - * lookups. Hence, the stored form of the value must provide a numeric userid + * lookups. Hence, the stored form of the value must provide a numeric oid * that can be re-used directly. We store the string in the form of * NAMEDATALEN 'x's, followed by T or F to indicate superuserness, followed - * by the numeric userid, followed by a comma, followed by the user name. - * This cannot be confused with a plain user name because of the NAMEDATALEN + * by the numeric oid, followed by a comma, followed by the role name. + * This cannot be confused with a plain role name because of the NAMEDATALEN * limit on names, so we can tell whether we're being passed an initial - * username or a saved/restored value. + * role name or a saved/restored value. */ extern char *session_authorization_string; /* in guc.c */ const char * assign_session_authorization(const char *value, bool doit, GucSource source) { - AclId usesysid = 0; + Oid roleid = InvalidOid; bool is_superuser = false; - const char *actual_username = NULL; + const char *actual_rolename = NULL; char *result; if (strspn(value, "x") == NAMEDATALEN && (value[NAMEDATALEN] == 'T' || value[NAMEDATALEN] == 'F')) { /* might be a saved userid string */ - AclId savedsysid; + Oid savedoid; char *endptr; - savedsysid = (AclId) strtoul(value + NAMEDATALEN + 1, &endptr, 10); + savedoid = (Oid) strtoul(value + NAMEDATALEN + 1, &endptr, 10); if (endptr != value + NAMEDATALEN + 1 && *endptr == ',') { /* syntactically valid, so break out the data */ - usesysid = savedsysid; + roleid = savedoid; is_superuser = (value[NAMEDATALEN] == 'T'); - actual_username = endptr + 1; + actual_rolename = endptr + 1; } } - if (usesysid == 0) + if (roleid == InvalidOid) { /* not a saved ID, so look it up */ - HeapTuple userTup; + HeapTuple roleTup; if (!IsTransactionState()) { @@ -618,38 +618,38 @@ assign_session_authorization(const char *value, bool doit, GucSource source) return NULL; } - userTup = SearchSysCache(SHADOWNAME, + roleTup = SearchSysCache(AUTHNAME, PointerGetDatum(value), 0, 0, 0); - if (!HeapTupleIsValid(userTup)) + if (!HeapTupleIsValid(roleTup)) { if (source >= PGC_S_INTERACTIVE) ereport(ERROR, (errcode(ERRCODE_UNDEFINED_OBJECT), - errmsg("user \"%s\" does not exist", value))); + errmsg("role \"%s\" does not exist", value))); return NULL; } - usesysid = ((Form_pg_shadow) GETSTRUCT(userTup))->usesysid; - is_superuser = ((Form_pg_shadow) GETSTRUCT(userTup))->usesuper; - actual_username = value; + roleid = HeapTupleGetOid(roleTup); + is_superuser = ((Form_pg_authid) GETSTRUCT(roleTup))->rolsuper; + actual_rolename = value; - ReleaseSysCache(userTup); + ReleaseSysCache(roleTup); } if (doit) - SetSessionAuthorization(usesysid, is_superuser); + SetSessionAuthorization(roleid, is_superuser); - result = (char *) malloc(NAMEDATALEN + 32 + strlen(actual_username)); + result = (char *) malloc(NAMEDATALEN + 32 + strlen(actual_rolename)); if (!result) return NULL; memset(result, 'x', NAMEDATALEN); - sprintf(result + NAMEDATALEN, "%c%lu,%s", + sprintf(result + NAMEDATALEN, "%c%u,%s", is_superuser ? 'T' : 'F', - (unsigned long) usesysid, - actual_username); + roleid, + actual_rolename); return result; } @@ -662,13 +662,13 @@ show_session_authorization(void) * assign_session_authorization */ const char *value = session_authorization_string; - AclId savedsysid; + Oid savedoid; char *endptr; Assert(strspn(value, "x") == NAMEDATALEN && (value[NAMEDATALEN] == 'T' || value[NAMEDATALEN] == 'F')); - savedsysid = (AclId) strtoul(value + NAMEDATALEN + 1, &endptr, 10); + savedoid = (Oid) strtoul(value + NAMEDATALEN + 1, &endptr, 10); Assert(endptr != value + NAMEDATALEN + 1 && *endptr == ','); |