mirror of
https://github.com/postgres/postgres.git
synced 2025-07-30 11:03:19 +03:00
Reserve the "pg_" namespace for roles
This will prevent users from creating roles which begin with "pg_" and will check for those roles before allowing an upgrade using pg_upgrade. This will allow for default roles to be provided at initdb time. Reviews by José Luis Tallón and Robert Haas
This commit is contained in:
@ -1365,13 +1365,15 @@ testdb=>
|
|||||||
|
|
||||||
|
|
||||||
<varlistentry>
|
<varlistentry>
|
||||||
<term><literal>\dg[+] [ <link linkend="APP-PSQL-patterns"><replaceable class="parameter">pattern</replaceable></link> ]</literal></term>
|
<term><literal>\dg[S+] [ <link linkend="APP-PSQL-patterns"><replaceable class="parameter">pattern</replaceable></link> ]</literal></term>
|
||||||
<listitem>
|
<listitem>
|
||||||
<para>
|
<para>
|
||||||
Lists database roles.
|
Lists database roles.
|
||||||
(Since the concepts of <quote>users</> and <quote>groups</> have been
|
(Since the concepts of <quote>users</> and <quote>groups</> have been
|
||||||
unified into <quote>roles</>, this command is now equivalent to
|
unified into <quote>roles</>, this command is now equivalent to
|
||||||
<literal>\du</literal>.)
|
<literal>\du</literal>.)
|
||||||
|
By default, only user-created roles are shown; supply the
|
||||||
|
<literal>S</literal> modifier to include system roles.
|
||||||
If <replaceable class="parameter">pattern</replaceable> is specified,
|
If <replaceable class="parameter">pattern</replaceable> is specified,
|
||||||
only those roles whose names match the pattern are listed.
|
only those roles whose names match the pattern are listed.
|
||||||
If the form <literal>\dg+</literal> is used, additional information
|
If the form <literal>\dg+</literal> is used, additional information
|
||||||
@ -1525,13 +1527,15 @@ testdb=>
|
|||||||
</varlistentry>
|
</varlistentry>
|
||||||
|
|
||||||
<varlistentry>
|
<varlistentry>
|
||||||
<term><literal>\du[+] [ <link linkend="APP-PSQL-patterns"><replaceable class="parameter">pattern</replaceable></link> ]</literal></term>
|
<term><literal>\du[S+] [ <link linkend="APP-PSQL-patterns"><replaceable class="parameter">pattern</replaceable></link> ]</literal></term>
|
||||||
<listitem>
|
<listitem>
|
||||||
<para>
|
<para>
|
||||||
Lists database roles.
|
Lists database roles.
|
||||||
(Since the concepts of <quote>users</> and <quote>groups</> have been
|
(Since the concepts of <quote>users</> and <quote>groups</> have been
|
||||||
unified into <quote>roles</>, this command is now equivalent to
|
unified into <quote>roles</>, this command is now equivalent to
|
||||||
<literal>\dg</literal>.)
|
<literal>\dg</literal>.)
|
||||||
|
By default, only user-created roles are shown; supply the
|
||||||
|
<literal>S</literal> modifier to include system roles.
|
||||||
If <replaceable class="parameter">pattern</replaceable> is specified,
|
If <replaceable class="parameter">pattern</replaceable> is specified,
|
||||||
only those roles whose names match the pattern are listed.
|
only those roles whose names match the pattern are listed.
|
||||||
If the form <literal>\du+</literal> is used, additional information
|
If the form <literal>\du+</literal> is used, additional information
|
||||||
|
@ -423,6 +423,9 @@ ExecuteGrantStmt(GrantStmt *stmt)
|
|||||||
grantee_uid = ACL_ID_PUBLIC;
|
grantee_uid = ACL_ID_PUBLIC;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
|
if (!IsBootstrapProcessingMode())
|
||||||
|
check_rolespec_name((Node *) grantee,
|
||||||
|
"Cannot GRANT or REVOKE privileges to or from a reserved role.");
|
||||||
grantee_uid = get_rolespec_oid((Node *) grantee, false);
|
grantee_uid = get_rolespec_oid((Node *) grantee, false);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -918,6 +921,8 @@ ExecAlterDefaultPrivilegesStmt(AlterDefaultPrivilegesStmt *stmt)
|
|||||||
grantee_uid = ACL_ID_PUBLIC;
|
grantee_uid = ACL_ID_PUBLIC;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
|
check_rolespec_name((Node *) grantee,
|
||||||
|
"Cannot GRANT or REVOKE default privileges to or from a reserved role.");
|
||||||
grantee_uid = get_rolespec_oid((Node *) grantee, false);
|
grantee_uid = get_rolespec_oid((Node *) grantee, false);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -1008,6 +1013,8 @@ ExecAlterDefaultPrivilegesStmt(AlterDefaultPrivilegesStmt *stmt)
|
|||||||
{
|
{
|
||||||
RoleSpec *rolespec = lfirst(rolecell);
|
RoleSpec *rolespec = lfirst(rolecell);
|
||||||
|
|
||||||
|
check_rolespec_name((Node *) rolespec,
|
||||||
|
"Cannot alter default privileges for reserved role.");
|
||||||
iacls.roleid = get_rolespec_oid((Node *) rolespec, false);
|
iacls.roleid = get_rolespec_oid((Node *) rolespec, false);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -184,8 +184,9 @@ IsToastNamespace(Oid namespaceId)
|
|||||||
* True iff name starts with the pg_ prefix.
|
* True iff name starts with the pg_ prefix.
|
||||||
*
|
*
|
||||||
* For some classes of objects, the prefix pg_ is reserved for
|
* For some classes of objects, the prefix pg_ is reserved for
|
||||||
* system objects only. As of 8.0, this is only true for
|
* system objects only. As of 8.0, this was only true for
|
||||||
* schema and tablespace names.
|
* schema and tablespace names. With 9.6, this is also true
|
||||||
|
* for roles.
|
||||||
*/
|
*/
|
||||||
bool
|
bool
|
||||||
IsReservedName(const char *name)
|
IsReservedName(const char *name)
|
||||||
|
@ -747,6 +747,9 @@ ExecAlterOwnerStmt(AlterOwnerStmt *stmt)
|
|||||||
{
|
{
|
||||||
Oid newowner = get_rolespec_oid(stmt->newowner, false);
|
Oid newowner = get_rolespec_oid(stmt->newowner, false);
|
||||||
|
|
||||||
|
check_rolespec_name(stmt->newowner,
|
||||||
|
"Cannot make reserved roles owners of objects.");
|
||||||
|
|
||||||
switch (stmt->objectType)
|
switch (stmt->objectType)
|
||||||
{
|
{
|
||||||
case OBJECT_DATABASE:
|
case OBJECT_DATABASE:
|
||||||
|
@ -1148,6 +1148,10 @@ CreateUserMapping(CreateUserMappingStmt *stmt)
|
|||||||
else
|
else
|
||||||
useId = get_rolespec_oid(stmt->user, false);
|
useId = get_rolespec_oid(stmt->user, false);
|
||||||
|
|
||||||
|
/* Additional check to protect reserved role names */
|
||||||
|
check_rolespec_name(stmt->user,
|
||||||
|
"Cannot specify reserved role as mapping user.");
|
||||||
|
|
||||||
/* Check that the server exists. */
|
/* Check that the server exists. */
|
||||||
srv = GetForeignServerByName(stmt->servername, false);
|
srv = GetForeignServerByName(stmt->servername, false);
|
||||||
|
|
||||||
@ -1248,6 +1252,10 @@ AlterUserMapping(AlterUserMappingStmt *stmt)
|
|||||||
else
|
else
|
||||||
useId = get_rolespec_oid(stmt->user, false);
|
useId = get_rolespec_oid(stmt->user, false);
|
||||||
|
|
||||||
|
/* Additional check to protect reserved role names */
|
||||||
|
check_rolespec_name(stmt->user,
|
||||||
|
"Cannot alter reserved role mapping user.");
|
||||||
|
|
||||||
srv = GetForeignServerByName(stmt->servername, false);
|
srv = GetForeignServerByName(stmt->servername, false);
|
||||||
|
|
||||||
umId = GetSysCacheOid2(USERMAPPINGUSERSERVER,
|
umId = GetSysCacheOid2(USERMAPPINGUSERSERVER,
|
||||||
@ -1337,6 +1345,11 @@ RemoveUserMapping(DropUserMappingStmt *stmt)
|
|||||||
else
|
else
|
||||||
{
|
{
|
||||||
useId = get_rolespec_oid(stmt->user, stmt->missing_ok);
|
useId = get_rolespec_oid(stmt->user, stmt->missing_ok);
|
||||||
|
|
||||||
|
/* Additional check to protect reserved role names */
|
||||||
|
check_rolespec_name(stmt->user,
|
||||||
|
"Cannot remove reserved role mapping user.");
|
||||||
|
|
||||||
if (!OidIsValid(useId))
|
if (!OidIsValid(useId))
|
||||||
{
|
{
|
||||||
/*
|
/*
|
||||||
|
@ -176,8 +176,13 @@ policy_role_list_to_array(List *roles, int *num_roles)
|
|||||||
return role_oids;
|
return role_oids;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
{
|
||||||
|
/* Additional check to protect reserved role names */
|
||||||
|
check_rolespec_name((Node *) spec,
|
||||||
|
"Cannot specify reserved role as policy target");
|
||||||
role_oids[i++] =
|
role_oids[i++] =
|
||||||
ObjectIdGetDatum(get_rolespec_oid((Node *) spec, false));
|
ObjectIdGetDatum(get_rolespec_oid((Node *) spec, false));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return role_oids;
|
return role_oids;
|
||||||
|
@ -65,6 +65,10 @@ CreateSchemaCommand(CreateSchemaStmt *stmt, const char *queryString)
|
|||||||
else
|
else
|
||||||
owner_uid = saved_uid;
|
owner_uid = saved_uid;
|
||||||
|
|
||||||
|
/* Additional check to protect reserved role names */
|
||||||
|
check_rolespec_name(stmt->authrole,
|
||||||
|
"Cannot specify reserved role as owner.");
|
||||||
|
|
||||||
/* fill schema name with the user name if not specified */
|
/* fill schema name with the user name if not specified */
|
||||||
if (!schemaName)
|
if (!schemaName)
|
||||||
{
|
{
|
||||||
|
@ -3566,6 +3566,8 @@ ATExecCmd(List **wqueue, AlteredTableInfo *tab, Relation rel,
|
|||||||
(List *) cmd->def, lockmode);
|
(List *) cmd->def, lockmode);
|
||||||
break;
|
break;
|
||||||
case AT_ChangeOwner: /* ALTER OWNER */
|
case AT_ChangeOwner: /* ALTER OWNER */
|
||||||
|
check_rolespec_name(cmd->newowner,
|
||||||
|
"Cannot specify reserved role as owner.");
|
||||||
ATExecChangeOwner(RelationGetRelid(rel),
|
ATExecChangeOwner(RelationGetRelid(rel),
|
||||||
get_rolespec_oid(cmd->newowner, false),
|
get_rolespec_oid(cmd->newowner, false),
|
||||||
false, lockmode);
|
false, lockmode);
|
||||||
|
@ -256,6 +256,10 @@ CreateTableSpace(CreateTableSpaceStmt *stmt)
|
|||||||
else
|
else
|
||||||
ownerId = GetUserId();
|
ownerId = GetUserId();
|
||||||
|
|
||||||
|
/* Additional check to protect reserved role names */
|
||||||
|
check_rolespec_name(stmt->owner,
|
||||||
|
"Cannot specify reserved role as owner.");
|
||||||
|
|
||||||
/* Unix-ify the offered path, and strip any trailing slashes */
|
/* Unix-ify the offered path, and strip any trailing slashes */
|
||||||
location = pstrdup(stmt->location);
|
location = pstrdup(stmt->location);
|
||||||
canonicalize_path(location);
|
canonicalize_path(location);
|
||||||
|
@ -17,6 +17,7 @@
|
|||||||
#include "access/htup_details.h"
|
#include "access/htup_details.h"
|
||||||
#include "access/xact.h"
|
#include "access/xact.h"
|
||||||
#include "catalog/binary_upgrade.h"
|
#include "catalog/binary_upgrade.h"
|
||||||
|
#include "catalog/catalog.h"
|
||||||
#include "catalog/dependency.h"
|
#include "catalog/dependency.h"
|
||||||
#include "catalog/indexing.h"
|
#include "catalog/indexing.h"
|
||||||
#include "catalog/objectaccess.h"
|
#include "catalog/objectaccess.h"
|
||||||
@ -311,6 +312,17 @@ CreateRole(CreateRoleStmt *stmt)
|
|||||||
errmsg("permission denied to create role")));
|
errmsg("permission denied to create role")));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Check that the user is not trying to create a role in the reserved
|
||||||
|
* "pg_" namespace.
|
||||||
|
*/
|
||||||
|
if (IsReservedName(stmt->role))
|
||||||
|
ereport(ERROR,
|
||||||
|
(errcode(ERRCODE_RESERVED_NAME),
|
||||||
|
errmsg("role name \"%s\" is reserved",
|
||||||
|
stmt->role),
|
||||||
|
errdetail("Role names starting with \"pg_\" are reserved.")));
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Check the pg_authid relation to be certain the role doesn't already
|
* Check the pg_authid relation to be certain the role doesn't already
|
||||||
* exist.
|
* exist.
|
||||||
@ -507,6 +519,9 @@ AlterRole(AlterRoleStmt *stmt)
|
|||||||
DefElem *dbypassRLS = NULL;
|
DefElem *dbypassRLS = NULL;
|
||||||
Oid roleid;
|
Oid roleid;
|
||||||
|
|
||||||
|
check_rolespec_name(stmt->role,
|
||||||
|
"Cannot alter reserved roles.");
|
||||||
|
|
||||||
/* Extract options from the statement node tree */
|
/* Extract options from the statement node tree */
|
||||||
foreach(option, stmt->options)
|
foreach(option, stmt->options)
|
||||||
{
|
{
|
||||||
@ -857,6 +872,9 @@ AlterRoleSet(AlterRoleSetStmt *stmt)
|
|||||||
|
|
||||||
if (stmt->role)
|
if (stmt->role)
|
||||||
{
|
{
|
||||||
|
check_rolespec_name(stmt->role,
|
||||||
|
"Cannot alter reserved roles.");
|
||||||
|
|
||||||
roletuple = get_rolespec_tuple(stmt->role);
|
roletuple = get_rolespec_tuple(stmt->role);
|
||||||
roleid = HeapTupleGetOid(roletuple);
|
roleid = HeapTupleGetOid(roletuple);
|
||||||
|
|
||||||
@ -1117,6 +1135,7 @@ RenameRole(const char *oldname, const char *newname)
|
|||||||
int i;
|
int i;
|
||||||
Oid roleid;
|
Oid roleid;
|
||||||
ObjectAddress address;
|
ObjectAddress address;
|
||||||
|
Form_pg_authid authform;
|
||||||
|
|
||||||
rel = heap_open(AuthIdRelationId, RowExclusiveLock);
|
rel = heap_open(AuthIdRelationId, RowExclusiveLock);
|
||||||
dsc = RelationGetDescr(rel);
|
dsc = RelationGetDescr(rel);
|
||||||
@ -1136,6 +1155,7 @@ RenameRole(const char *oldname, const char *newname)
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
roleid = HeapTupleGetOid(oldtuple);
|
roleid = HeapTupleGetOid(oldtuple);
|
||||||
|
authform = (Form_pg_authid) GETSTRUCT(oldtuple);
|
||||||
|
|
||||||
if (roleid == GetSessionUserId())
|
if (roleid == GetSessionUserId())
|
||||||
ereport(ERROR,
|
ereport(ERROR,
|
||||||
@ -1146,6 +1166,24 @@ RenameRole(const char *oldname, const char *newname)
|
|||||||
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
|
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
|
||||||
errmsg("current user cannot be renamed")));
|
errmsg("current user cannot be renamed")));
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Check that the user is not trying to rename a system role and
|
||||||
|
* not trying to rename a role into the reserved "pg_" namespace.
|
||||||
|
*/
|
||||||
|
if (IsReservedName(NameStr(authform->rolname)))
|
||||||
|
ereport(ERROR,
|
||||||
|
(errcode(ERRCODE_RESERVED_NAME),
|
||||||
|
errmsg("role name \"%s\" is reserved",
|
||||||
|
NameStr(authform->rolname)),
|
||||||
|
errdetail("Role names starting with \"pg_\" are reserved.")));
|
||||||
|
|
||||||
|
if (IsReservedName(newname))
|
||||||
|
ereport(ERROR,
|
||||||
|
(errcode(ERRCODE_RESERVED_NAME),
|
||||||
|
errmsg("role name \"%s\" is reserved",
|
||||||
|
newname),
|
||||||
|
errdetail("Role names starting with \"pg_\" are reserved.")));
|
||||||
|
|
||||||
/* make sure the new name doesn't exist */
|
/* make sure the new name doesn't exist */
|
||||||
if (SearchSysCacheExists1(AUTHNAME, CStringGetDatum(newname)))
|
if (SearchSysCacheExists1(AUTHNAME, CStringGetDatum(newname)))
|
||||||
ereport(ERROR,
|
ereport(ERROR,
|
||||||
@ -1224,10 +1262,18 @@ GrantRole(GrantRoleStmt *stmt)
|
|||||||
ListCell *item;
|
ListCell *item;
|
||||||
|
|
||||||
if (stmt->grantor)
|
if (stmt->grantor)
|
||||||
|
{
|
||||||
|
check_rolespec_name(stmt->grantor,
|
||||||
|
"Cannot specify reserved role as grantor.");
|
||||||
grantor = get_rolespec_oid(stmt->grantor, false);
|
grantor = get_rolespec_oid(stmt->grantor, false);
|
||||||
|
}
|
||||||
else
|
else
|
||||||
grantor = GetUserId();
|
grantor = GetUserId();
|
||||||
|
|
||||||
|
foreach(item, stmt->grantee_roles)
|
||||||
|
check_rolespec_name(lfirst(item),
|
||||||
|
"Cannot GRANT roles to a reserved role.");
|
||||||
|
|
||||||
grantee_ids = roleSpecsToIds(stmt->grantee_roles);
|
grantee_ids = roleSpecsToIds(stmt->grantee_roles);
|
||||||
|
|
||||||
/* AccessShareLock is enough since we aren't modifying pg_authid */
|
/* AccessShareLock is enough since we aren't modifying pg_authid */
|
||||||
@ -1318,6 +1364,9 @@ ReassignOwnedObjects(ReassignOwnedStmt *stmt)
|
|||||||
errmsg("permission denied to reassign objects")));
|
errmsg("permission denied to reassign objects")));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
check_rolespec_name(stmt->newrole,
|
||||||
|
"Cannot specify reserved role as owner.");
|
||||||
|
|
||||||
/* Must have privileges on the receiving side too */
|
/* Must have privileges on the receiving side too */
|
||||||
newrole = get_rolespec_oid(stmt->newrole, false);
|
newrole = get_rolespec_oid(stmt->newrole, false);
|
||||||
|
|
||||||
|
@ -854,6 +854,9 @@ check_role(char **newval, void **extra, GucSource source)
|
|||||||
roleid = InvalidOid;
|
roleid = InvalidOid;
|
||||||
is_superuser = false;
|
is_superuser = false;
|
||||||
}
|
}
|
||||||
|
/* Do not allow setting role to a reserved role. */
|
||||||
|
else if (strncmp(*newval, "pg_", 3) == 0)
|
||||||
|
return false;
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if (!IsTransactionState())
|
if (!IsTransactionState())
|
||||||
|
@ -17,6 +17,7 @@
|
|||||||
#include <ctype.h>
|
#include <ctype.h>
|
||||||
|
|
||||||
#include "access/htup_details.h"
|
#include "access/htup_details.h"
|
||||||
|
#include "catalog/catalog.h"
|
||||||
#include "catalog/namespace.h"
|
#include "catalog/namespace.h"
|
||||||
#include "catalog/pg_authid.h"
|
#include "catalog/pg_authid.h"
|
||||||
#include "catalog/pg_auth_members.h"
|
#include "catalog/pg_auth_members.h"
|
||||||
@ -5247,3 +5248,41 @@ get_rolespec_name(const Node *node)
|
|||||||
|
|
||||||
return rolename;
|
return rolename;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Given a RoleSpec, throw an error if the name is reserved, using detail_msg,
|
||||||
|
* if provided.
|
||||||
|
*
|
||||||
|
* If node is NULL, no error is thrown. If detail_msg is NULL then no detail
|
||||||
|
* message is provided.
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
check_rolespec_name(const Node *node, const char *detail_msg)
|
||||||
|
{
|
||||||
|
RoleSpec *role;
|
||||||
|
|
||||||
|
if (!node)
|
||||||
|
return;
|
||||||
|
|
||||||
|
role = (RoleSpec *) node;
|
||||||
|
|
||||||
|
Assert(IsA(node, RoleSpec));
|
||||||
|
|
||||||
|
if (role->roletype != ROLESPEC_CSTRING)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (IsReservedName(role->rolename))
|
||||||
|
{
|
||||||
|
if (detail_msg)
|
||||||
|
ereport(ERROR,
|
||||||
|
(errcode(ERRCODE_RESERVED_NAME),
|
||||||
|
errmsg("role \"%s\" is reserved",
|
||||||
|
role->rolename),
|
||||||
|
errdetail("%s", detail_msg)));
|
||||||
|
else
|
||||||
|
ereport(ERROR,
|
||||||
|
(errcode(ERRCODE_RESERVED_NAME),
|
||||||
|
errmsg("role \"%s\" is reserved",
|
||||||
|
role->rolename)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -665,7 +665,7 @@ dumpRoles(PGconn *conn)
|
|||||||
int i;
|
int i;
|
||||||
|
|
||||||
/* note: rolconfig is dumped later */
|
/* note: rolconfig is dumped later */
|
||||||
if (server_version >= 90500)
|
if (server_version >= 90600)
|
||||||
printfPQExpBuffer(buf,
|
printfPQExpBuffer(buf,
|
||||||
"SELECT oid, rolname, rolsuper, rolinherit, "
|
"SELECT oid, rolname, rolsuper, rolinherit, "
|
||||||
"rolcreaterole, rolcreatedb, "
|
"rolcreaterole, rolcreatedb, "
|
||||||
@ -674,6 +674,7 @@ dumpRoles(PGconn *conn)
|
|||||||
"pg_catalog.shobj_description(oid, 'pg_authid') as rolcomment, "
|
"pg_catalog.shobj_description(oid, 'pg_authid') as rolcomment, "
|
||||||
"rolname = current_user AS is_current_user "
|
"rolname = current_user AS is_current_user "
|
||||||
"FROM pg_authid "
|
"FROM pg_authid "
|
||||||
|
"WHERE rolname !~ '^pg_' "
|
||||||
"ORDER BY 2");
|
"ORDER BY 2");
|
||||||
else if (server_version >= 90100)
|
else if (server_version >= 90100)
|
||||||
printfPQExpBuffer(buf,
|
printfPQExpBuffer(buf,
|
||||||
@ -771,6 +772,13 @@ dumpRoles(PGconn *conn)
|
|||||||
auth_oid = atooid(PQgetvalue(res, i, i_oid));
|
auth_oid = atooid(PQgetvalue(res, i, i_oid));
|
||||||
rolename = PQgetvalue(res, i, i_rolname);
|
rolename = PQgetvalue(res, i, i_rolname);
|
||||||
|
|
||||||
|
if (strncmp(rolename,"pg_",3) == 0)
|
||||||
|
{
|
||||||
|
fprintf(stderr, _("%s: role name starting with 'pg_' skipped (%s)\n"),
|
||||||
|
progname, rolename);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
resetPQExpBuffer(buf);
|
resetPQExpBuffer(buf);
|
||||||
|
|
||||||
if (binary_upgrade)
|
if (binary_upgrade)
|
||||||
@ -896,6 +904,7 @@ dumpRoleMembership(PGconn *conn)
|
|||||||
"LEFT JOIN pg_authid ur on ur.oid = a.roleid "
|
"LEFT JOIN pg_authid ur on ur.oid = a.roleid "
|
||||||
"LEFT JOIN pg_authid um on um.oid = a.member "
|
"LEFT JOIN pg_authid um on um.oid = a.member "
|
||||||
"LEFT JOIN pg_authid ug on ug.oid = a.grantor "
|
"LEFT JOIN pg_authid ug on ug.oid = a.grantor "
|
||||||
|
"WHERE NOT (ur.rolname ~ '^pg_' AND um.rolname ~ '^pg_')"
|
||||||
"ORDER BY 1,2,3");
|
"ORDER BY 1,2,3");
|
||||||
|
|
||||||
if (PQntuples(res) > 0)
|
if (PQntuples(res) > 0)
|
||||||
|
@ -24,6 +24,7 @@ static void check_for_prepared_transactions(ClusterInfo *cluster);
|
|||||||
static void check_for_isn_and_int8_passing_mismatch(ClusterInfo *cluster);
|
static void check_for_isn_and_int8_passing_mismatch(ClusterInfo *cluster);
|
||||||
static void check_for_reg_data_type_usage(ClusterInfo *cluster);
|
static void check_for_reg_data_type_usage(ClusterInfo *cluster);
|
||||||
static void check_for_jsonb_9_4_usage(ClusterInfo *cluster);
|
static void check_for_jsonb_9_4_usage(ClusterInfo *cluster);
|
||||||
|
static void check_for_pg_role_prefix(ClusterInfo *cluster);
|
||||||
static void get_bin_version(ClusterInfo *cluster);
|
static void get_bin_version(ClusterInfo *cluster);
|
||||||
static char *get_canonical_locale_name(int category, const char *locale);
|
static char *get_canonical_locale_name(int category, const char *locale);
|
||||||
|
|
||||||
@ -96,6 +97,11 @@ check_and_dump_old_cluster(bool live_check)
|
|||||||
check_for_prepared_transactions(&old_cluster);
|
check_for_prepared_transactions(&old_cluster);
|
||||||
check_for_reg_data_type_usage(&old_cluster);
|
check_for_reg_data_type_usage(&old_cluster);
|
||||||
check_for_isn_and_int8_passing_mismatch(&old_cluster);
|
check_for_isn_and_int8_passing_mismatch(&old_cluster);
|
||||||
|
|
||||||
|
/* 9.5 and below should not have roles starting with pg_ */
|
||||||
|
if (GET_MAJOR_VERSION(old_cluster.major_version) <= 905)
|
||||||
|
check_for_pg_role_prefix(&old_cluster);
|
||||||
|
|
||||||
if (GET_MAJOR_VERSION(old_cluster.major_version) == 904 &&
|
if (GET_MAJOR_VERSION(old_cluster.major_version) == 904 &&
|
||||||
old_cluster.controldata.cat_ver < JSONB_FORMAT_CHANGE_CAT_VER)
|
old_cluster.controldata.cat_ver < JSONB_FORMAT_CHANGE_CAT_VER)
|
||||||
check_for_jsonb_9_4_usage(&old_cluster);
|
check_for_jsonb_9_4_usage(&old_cluster);
|
||||||
@ -629,7 +635,8 @@ check_is_install_user(ClusterInfo *cluster)
|
|||||||
res = executeQueryOrDie(conn,
|
res = executeQueryOrDie(conn,
|
||||||
"SELECT rolsuper, oid "
|
"SELECT rolsuper, oid "
|
||||||
"FROM pg_catalog.pg_roles "
|
"FROM pg_catalog.pg_roles "
|
||||||
"WHERE rolname = current_user");
|
"WHERE rolname = current_user "
|
||||||
|
"AND rolname !~ '^pg_'");
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* We only allow the install user in the new cluster (see comment below)
|
* We only allow the install user in the new cluster (see comment below)
|
||||||
@ -645,7 +652,8 @@ check_is_install_user(ClusterInfo *cluster)
|
|||||||
|
|
||||||
res = executeQueryOrDie(conn,
|
res = executeQueryOrDie(conn,
|
||||||
"SELECT COUNT(*) "
|
"SELECT COUNT(*) "
|
||||||
"FROM pg_catalog.pg_roles ");
|
"FROM pg_catalog.pg_roles "
|
||||||
|
"WHERE rolname !~ '^pg_'");
|
||||||
|
|
||||||
if (PQntuples(res) != 1)
|
if (PQntuples(res) != 1)
|
||||||
pg_fatal("could not determine the number of users\n");
|
pg_fatal("could not determine the number of users\n");
|
||||||
@ -1033,6 +1041,34 @@ check_for_jsonb_9_4_usage(ClusterInfo *cluster)
|
|||||||
check_ok();
|
check_ok();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* check_for_pg_role_prefix()
|
||||||
|
*
|
||||||
|
* Versions older than 9.6 should not have any pg_* roles
|
||||||
|
*/
|
||||||
|
static void
|
||||||
|
check_for_pg_role_prefix(ClusterInfo *cluster)
|
||||||
|
{
|
||||||
|
PGresult *res;
|
||||||
|
PGconn *conn = connectToServer(cluster, "template1");
|
||||||
|
|
||||||
|
prep_status("Checking for roles starting with 'pg_'");
|
||||||
|
|
||||||
|
res = executeQueryOrDie(conn,
|
||||||
|
"SELECT * "
|
||||||
|
"FROM pg_catalog.pg_roles "
|
||||||
|
"WHERE rolname ~ '^pg_'");
|
||||||
|
|
||||||
|
if (PQntuples(res) != 0)
|
||||||
|
pg_fatal("The %s cluster contains roles starting with 'pg_'\n",
|
||||||
|
CLUSTER_NAME(cluster));
|
||||||
|
|
||||||
|
PQclear(res);
|
||||||
|
|
||||||
|
PQfinish(conn);
|
||||||
|
|
||||||
|
check_ok();
|
||||||
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
get_bin_version(ClusterInfo *cluster)
|
get_bin_version(ClusterInfo *cluster)
|
||||||
|
@ -429,7 +429,7 @@ exec_command(const char *cmd,
|
|||||||
break;
|
break;
|
||||||
case 'g':
|
case 'g':
|
||||||
/* no longer distinct from \du */
|
/* no longer distinct from \du */
|
||||||
success = describeRoles(pattern, show_verbose);
|
success = describeRoles(pattern, show_verbose, show_system);
|
||||||
break;
|
break;
|
||||||
case 'l':
|
case 'l':
|
||||||
success = do_lo_list();
|
success = do_lo_list();
|
||||||
@ -474,7 +474,7 @@ exec_command(const char *cmd,
|
|||||||
success = PSQL_CMD_UNKNOWN;
|
success = PSQL_CMD_UNKNOWN;
|
||||||
break;
|
break;
|
||||||
case 'u':
|
case 'u':
|
||||||
success = describeRoles(pattern, show_verbose);
|
success = describeRoles(pattern, show_verbose, show_system);
|
||||||
break;
|
break;
|
||||||
case 'F': /* text search subsystem */
|
case 'F': /* text search subsystem */
|
||||||
switch (cmd[2])
|
switch (cmd[2])
|
||||||
|
@ -2646,7 +2646,7 @@ add_tablespace_footer(printTableContent *const cont, char relkind,
|
|||||||
* Describes roles. Any schema portion of the pattern is ignored.
|
* Describes roles. Any schema portion of the pattern is ignored.
|
||||||
*/
|
*/
|
||||||
bool
|
bool
|
||||||
describeRoles(const char *pattern, bool verbose)
|
describeRoles(const char *pattern, bool verbose, bool showSystem)
|
||||||
{
|
{
|
||||||
PQExpBufferData buf;
|
PQExpBufferData buf;
|
||||||
PGresult *res;
|
PGresult *res;
|
||||||
@ -2691,6 +2691,9 @@ describeRoles(const char *pattern, bool verbose)
|
|||||||
|
|
||||||
appendPQExpBufferStr(&buf, "\nFROM pg_catalog.pg_roles r\n");
|
appendPQExpBufferStr(&buf, "\nFROM pg_catalog.pg_roles r\n");
|
||||||
|
|
||||||
|
if (!showSystem && !pattern)
|
||||||
|
appendPQExpBufferStr(&buf, "WHERE r.rolname !~ '^pg_'\n");
|
||||||
|
|
||||||
processSQLNamePattern(pset.db, &buf, pattern, false, false,
|
processSQLNamePattern(pset.db, &buf, pattern, false, false,
|
||||||
NULL, "r.rolname", NULL, NULL);
|
NULL, "r.rolname", NULL, NULL);
|
||||||
}
|
}
|
||||||
|
@ -25,7 +25,7 @@ extern bool describeTypes(const char *pattern, bool verbose, bool showSystem);
|
|||||||
extern bool describeOperators(const char *pattern, bool verbose, bool showSystem);
|
extern bool describeOperators(const char *pattern, bool verbose, bool showSystem);
|
||||||
|
|
||||||
/* \du, \dg */
|
/* \du, \dg */
|
||||||
extern bool describeRoles(const char *pattern, bool verbose);
|
extern bool describeRoles(const char *pattern, bool verbose, bool showSystem);
|
||||||
|
|
||||||
/* \drds */
|
/* \drds */
|
||||||
extern bool listDbRoleSettings(const char *pattern1, const char *pattern2);
|
extern bool listDbRoleSettings(const char *pattern1, const char *pattern2);
|
||||||
|
@ -229,7 +229,7 @@ slashUsage(unsigned short int pager)
|
|||||||
fprintf(output, _(" \\dFd[+] [PATTERN] list text search dictionaries\n"));
|
fprintf(output, _(" \\dFd[+] [PATTERN] list text search dictionaries\n"));
|
||||||
fprintf(output, _(" \\dFp[+] [PATTERN] list text search parsers\n"));
|
fprintf(output, _(" \\dFp[+] [PATTERN] list text search parsers\n"));
|
||||||
fprintf(output, _(" \\dFt[+] [PATTERN] list text search templates\n"));
|
fprintf(output, _(" \\dFt[+] [PATTERN] list text search templates\n"));
|
||||||
fprintf(output, _(" \\dg[+] [PATTERN] list roles\n"));
|
fprintf(output, _(" \\dg[S+] [PATTERN] list roles\n"));
|
||||||
fprintf(output, _(" \\di[S+] [PATTERN] list indexes\n"));
|
fprintf(output, _(" \\di[S+] [PATTERN] list indexes\n"));
|
||||||
fprintf(output, _(" \\dl list large objects, same as \\lo_list\n"));
|
fprintf(output, _(" \\dl list large objects, same as \\lo_list\n"));
|
||||||
fprintf(output, _(" \\dL[S+] [PATTERN] list procedural languages\n"));
|
fprintf(output, _(" \\dL[S+] [PATTERN] list procedural languages\n"));
|
||||||
@ -242,7 +242,7 @@ slashUsage(unsigned short int pager)
|
|||||||
fprintf(output, _(" \\ds[S+] [PATTERN] list sequences\n"));
|
fprintf(output, _(" \\ds[S+] [PATTERN] list sequences\n"));
|
||||||
fprintf(output, _(" \\dt[S+] [PATTERN] list tables\n"));
|
fprintf(output, _(" \\dt[S+] [PATTERN] list tables\n"));
|
||||||
fprintf(output, _(" \\dT[S+] [PATTERN] list data types\n"));
|
fprintf(output, _(" \\dT[S+] [PATTERN] list data types\n"));
|
||||||
fprintf(output, _(" \\du[+] [PATTERN] list roles\n"));
|
fprintf(output, _(" \\du[S+] [PATTERN] list roles\n"));
|
||||||
fprintf(output, _(" \\dv[S+] [PATTERN] list views\n"));
|
fprintf(output, _(" \\dv[S+] [PATTERN] list views\n"));
|
||||||
fprintf(output, _(" \\dE[S+] [PATTERN] list foreign tables\n"));
|
fprintf(output, _(" \\dE[S+] [PATTERN] list foreign tables\n"));
|
||||||
fprintf(output, _(" \\dx[+] [PATTERN] list extensions\n"));
|
fprintf(output, _(" \\dx[+] [PATTERN] list extensions\n"));
|
||||||
|
@ -231,6 +231,7 @@ extern void check_is_member_of_role(Oid member, Oid role);
|
|||||||
extern Oid get_role_oid(const char *rolename, bool missing_ok);
|
extern Oid get_role_oid(const char *rolename, bool missing_ok);
|
||||||
extern Oid get_role_oid_or_public(const char *rolename);
|
extern Oid get_role_oid_or_public(const char *rolename);
|
||||||
extern Oid get_rolespec_oid(const Node *node, bool missing_ok);
|
extern Oid get_rolespec_oid(const Node *node, bool missing_ok);
|
||||||
|
extern void check_rolespec_name(const Node *node, const char *detail_msg);
|
||||||
extern HeapTuple get_rolespec_tuple(const Node *node);
|
extern HeapTuple get_rolespec_tuple(const Node *node);
|
||||||
extern char *get_rolespec_name(const Node *node);
|
extern char *get_rolespec_name(const Node *node);
|
||||||
|
|
||||||
|
@ -78,6 +78,18 @@ CREATE ROLE "none"; -- error
|
|||||||
ERROR: role name "none" is reserved
|
ERROR: role name "none" is reserved
|
||||||
LINE 1: CREATE ROLE "none";
|
LINE 1: CREATE ROLE "none";
|
||||||
^
|
^
|
||||||
|
CREATE ROLE pg_abc; -- error
|
||||||
|
ERROR: role name "pg_abc" is reserved
|
||||||
|
DETAIL: Role names starting with "pg_" are reserved.
|
||||||
|
CREATE ROLE "pg_abc"; -- error
|
||||||
|
ERROR: role name "pg_abc" is reserved
|
||||||
|
DETAIL: Role names starting with "pg_" are reserved.
|
||||||
|
CREATE ROLE pg_abcdef; -- error
|
||||||
|
ERROR: role name "pg_abcdef" is reserved
|
||||||
|
DETAIL: Role names starting with "pg_" are reserved.
|
||||||
|
CREATE ROLE "pg_abcdef"; -- error
|
||||||
|
ERROR: role name "pg_abcdef" is reserved
|
||||||
|
DETAIL: Role names starting with "pg_" are reserved.
|
||||||
CREATE ROLE testrol0 SUPERUSER LOGIN;
|
CREATE ROLE testrol0 SUPERUSER LOGIN;
|
||||||
CREATE ROLE testrolx SUPERUSER LOGIN;
|
CREATE ROLE testrolx SUPERUSER LOGIN;
|
||||||
CREATE ROLE testrol2 SUPERUSER;
|
CREATE ROLE testrol2 SUPERUSER;
|
||||||
@ -804,6 +816,14 @@ LINE 1: DROP USER MAPPING IF EXISTS FOR CURRENT_ROLE SERVER sv9;
|
|||||||
DROP USER MAPPING IF EXISTS FOR nonexistent SERVER sv9; -- error
|
DROP USER MAPPING IF EXISTS FOR nonexistent SERVER sv9; -- error
|
||||||
NOTICE: role "nonexistent" does not exist, skipping
|
NOTICE: role "nonexistent" does not exist, skipping
|
||||||
-- GRANT/REVOKE
|
-- GRANT/REVOKE
|
||||||
|
GRANT testrol0 TO pg_abc; -- error
|
||||||
|
ERROR: role "pg_abc" is reserved
|
||||||
|
DETAIL: Cannot GRANT roles to a reserved role.
|
||||||
|
GRANT pg_abc TO pg_abcdef; -- error
|
||||||
|
ERROR: role "pg_abcdef" is reserved
|
||||||
|
DETAIL: Cannot GRANT roles to a reserved role.
|
||||||
|
SET ROLE pg_testrole; -- error
|
||||||
|
ERROR: invalid value for parameter "role": "pg_testrole"
|
||||||
UPDATE pg_proc SET proacl = null WHERE proname LIKE 'testagg_';
|
UPDATE pg_proc SET proacl = null WHERE proname LIKE 'testagg_';
|
||||||
SELECT proname, proacl FROM pg_proc WHERE proname LIKE 'testagg_';
|
SELECT proname, proacl FROM pg_proc WHERE proname LIKE 'testagg_';
|
||||||
proname | proacl
|
proname | proacl
|
||||||
|
@ -57,6 +57,11 @@ CREATE ROLE "public"; -- error
|
|||||||
CREATE ROLE none; -- error
|
CREATE ROLE none; -- error
|
||||||
CREATE ROLE "none"; -- error
|
CREATE ROLE "none"; -- error
|
||||||
|
|
||||||
|
CREATE ROLE pg_abc; -- error
|
||||||
|
CREATE ROLE "pg_abc"; -- error
|
||||||
|
CREATE ROLE pg_abcdef; -- error
|
||||||
|
CREATE ROLE "pg_abcdef"; -- error
|
||||||
|
|
||||||
CREATE ROLE testrol0 SUPERUSER LOGIN;
|
CREATE ROLE testrol0 SUPERUSER LOGIN;
|
||||||
CREATE ROLE testrolx SUPERUSER LOGIN;
|
CREATE ROLE testrolx SUPERUSER LOGIN;
|
||||||
CREATE ROLE testrol2 SUPERUSER;
|
CREATE ROLE testrol2 SUPERUSER;
|
||||||
@ -376,6 +381,11 @@ DROP USER MAPPING IF EXISTS FOR CURRENT_ROLE SERVER sv9; --error
|
|||||||
DROP USER MAPPING IF EXISTS FOR nonexistent SERVER sv9; -- error
|
DROP USER MAPPING IF EXISTS FOR nonexistent SERVER sv9; -- error
|
||||||
|
|
||||||
-- GRANT/REVOKE
|
-- GRANT/REVOKE
|
||||||
|
GRANT testrol0 TO pg_abc; -- error
|
||||||
|
GRANT pg_abc TO pg_abcdef; -- error
|
||||||
|
|
||||||
|
SET ROLE pg_testrole; -- error
|
||||||
|
|
||||||
UPDATE pg_proc SET proacl = null WHERE proname LIKE 'testagg_';
|
UPDATE pg_proc SET proacl = null WHERE proname LIKE 'testagg_';
|
||||||
SELECT proname, proacl FROM pg_proc WHERE proname LIKE 'testagg_';
|
SELECT proname, proacl FROM pg_proc WHERE proname LIKE 'testagg_';
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user