Add a role property 'rolinherit' which, when false, denotes that the role
doesn't automatically inherit the privileges of roles it is a member of; for such a role, membership in another role can be exploited only by doing explicit SET ROLE. The default inherit setting is TRUE, so by default the behavior doesn't change, but creating a user with NOINHERIT gives closer adherence to our current reading of SQL99. Documentation still lacking, and I think the information schema needs another look.
This commit is contained in:
parent
f9fd176461
commit
af019fb9ae
@ -1,6 +1,6 @@
|
|||||||
<!--
|
<!--
|
||||||
Documentation of the system catalogs, directed toward PostgreSQL developers
|
Documentation of the system catalogs, directed toward PostgreSQL developers
|
||||||
$PostgreSQL: pgsql/doc/src/sgml/catalogs.sgml,v 2.108 2005/07/14 05:13:38 tgl Exp $
|
$PostgreSQL: pgsql/doc/src/sgml/catalogs.sgml,v 2.109 2005/07/26 16:38:25 tgl Exp $
|
||||||
-->
|
-->
|
||||||
|
|
||||||
<chapter id="catalogs">
|
<chapter id="catalogs">
|
||||||
@ -976,6 +976,14 @@
|
|||||||
<entry>Role has superuser privileges</entry>
|
<entry>Role has superuser privileges</entry>
|
||||||
</row>
|
</row>
|
||||||
|
|
||||||
|
<row>
|
||||||
|
<entry><structfield>rolinherit</structfield></entry>
|
||||||
|
<entry><type>bool</type></entry>
|
||||||
|
<entry></entry>
|
||||||
|
<entry>Role automatically inherits privileges of roles it is a
|
||||||
|
member of</entry>
|
||||||
|
</row>
|
||||||
|
|
||||||
<row>
|
<row>
|
||||||
<entry><structfield>rolcreaterole</structfield></entry>
|
<entry><structfield>rolcreaterole</structfield></entry>
|
||||||
<entry><type>bool</type></entry>
|
<entry><type>bool</type></entry>
|
||||||
@ -4728,6 +4736,11 @@
|
|||||||
that blanks out the password field.
|
that blanks out the password field.
|
||||||
</para>
|
</para>
|
||||||
|
|
||||||
|
<para>
|
||||||
|
This view explicitly exposes the OID column of the underlying table,
|
||||||
|
since that is needed to do joins to other catalogs.
|
||||||
|
</para>
|
||||||
|
|
||||||
<table>
|
<table>
|
||||||
<title><structname>pg_roles</> Columns</title>
|
<title><structname>pg_roles</> Columns</title>
|
||||||
|
|
||||||
@ -4756,6 +4769,14 @@
|
|||||||
<entry>Role has superuser privileges</entry>
|
<entry>Role has superuser privileges</entry>
|
||||||
</row>
|
</row>
|
||||||
|
|
||||||
|
<row>
|
||||||
|
<entry><structfield>rolinherit</structfield></entry>
|
||||||
|
<entry><type>bool</type></entry>
|
||||||
|
<entry></entry>
|
||||||
|
<entry>Role automatically inherits privileges of roles it is a
|
||||||
|
member of</entry>
|
||||||
|
</row>
|
||||||
|
|
||||||
<row>
|
<row>
|
||||||
<entry><structfield>rolcreaterole</structfield></entry>
|
<entry><structfield>rolcreaterole</structfield></entry>
|
||||||
<entry><type>bool</type></entry>
|
<entry><type>bool</type></entry>
|
||||||
@ -4811,6 +4832,13 @@
|
|||||||
<entry></entry>
|
<entry></entry>
|
||||||
<entry>Session defaults for run-time configuration variables</entry>
|
<entry>Session defaults for run-time configuration variables</entry>
|
||||||
</row>
|
</row>
|
||||||
|
|
||||||
|
<row>
|
||||||
|
<entry><structfield>oid</structfield></entry>
|
||||||
|
<entry><type>oid</type></entry>
|
||||||
|
<entry><literal><link linkend="catalog-pg-authid"><structname>pg_authid</structname></link>.oid</literal></entry>
|
||||||
|
<entry>ID of role</entry>
|
||||||
|
</row>
|
||||||
</tbody>
|
</tbody>
|
||||||
</tgroup>
|
</tgroup>
|
||||||
</table>
|
</table>
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
<!--
|
<!--
|
||||||
$PostgreSQL: pgsql/doc/src/sgml/func.sgml,v 1.271 2005/07/26 00:04:17 tgl Exp $
|
$PostgreSQL: pgsql/doc/src/sgml/func.sgml,v 1.272 2005/07/26 16:38:25 tgl Exp $
|
||||||
PostgreSQL documentation
|
PostgreSQL documentation
|
||||||
-->
|
-->
|
||||||
|
|
||||||
@ -8559,7 +8559,12 @@ SELECT has_function_privilege('joeuser', 'myfunc(int, text)', 'execute');
|
|||||||
can access a role in a particular way. The possibilities for its
|
can access a role in a particular way. The possibilities for its
|
||||||
arguments are analogous to <function>has_table_privilege</function>.
|
arguments are analogous to <function>has_table_privilege</function>.
|
||||||
The desired access privilege type must evaluate to
|
The desired access privilege type must evaluate to
|
||||||
<literal>MEMBER</literal>.
|
<literal>MEMBER</literal> or
|
||||||
|
<literal>USAGE</literal>.
|
||||||
|
<literal>MEMBER</literal> denotes direct or indirect membership in
|
||||||
|
the role (that is, the right to do <literal>SET ROLE</>), while
|
||||||
|
<literal>USAGE</literal> denotes whether the privileges of the role
|
||||||
|
are immediately available without doing <literal>SET ROLE</>.
|
||||||
</para>
|
</para>
|
||||||
|
|
||||||
<para>
|
<para>
|
||||||
|
@ -8,7 +8,7 @@
|
|||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $PostgreSQL: pgsql/src/backend/catalog/aclchk.c,v 1.115 2005/07/07 20:39:57 tgl Exp $
|
* $PostgreSQL: pgsql/src/backend/catalog/aclchk.c,v 1.116 2005/07/26 16:38:26 tgl Exp $
|
||||||
*
|
*
|
||||||
* NOTES
|
* NOTES
|
||||||
* See acl.h.
|
* See acl.h.
|
||||||
@ -1984,7 +1984,7 @@ pg_class_ownercheck(Oid class_oid, Oid roleid)
|
|||||||
|
|
||||||
ReleaseSysCache(tuple);
|
ReleaseSysCache(tuple);
|
||||||
|
|
||||||
return is_member_of_role(roleid, ownerId);
|
return has_privs_of_role(roleid, ownerId);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -2012,7 +2012,7 @@ pg_type_ownercheck(Oid type_oid, Oid roleid)
|
|||||||
|
|
||||||
ReleaseSysCache(tuple);
|
ReleaseSysCache(tuple);
|
||||||
|
|
||||||
return is_member_of_role(roleid, ownerId);
|
return has_privs_of_role(roleid, ownerId);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -2040,7 +2040,7 @@ pg_oper_ownercheck(Oid oper_oid, Oid roleid)
|
|||||||
|
|
||||||
ReleaseSysCache(tuple);
|
ReleaseSysCache(tuple);
|
||||||
|
|
||||||
return is_member_of_role(roleid, ownerId);
|
return has_privs_of_role(roleid, ownerId);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -2068,7 +2068,7 @@ pg_proc_ownercheck(Oid proc_oid, Oid roleid)
|
|||||||
|
|
||||||
ReleaseSysCache(tuple);
|
ReleaseSysCache(tuple);
|
||||||
|
|
||||||
return is_member_of_role(roleid, ownerId);
|
return has_privs_of_role(roleid, ownerId);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -2096,7 +2096,7 @@ pg_namespace_ownercheck(Oid nsp_oid, Oid roleid)
|
|||||||
|
|
||||||
ReleaseSysCache(tuple);
|
ReleaseSysCache(tuple);
|
||||||
|
|
||||||
return is_member_of_role(roleid, ownerId);
|
return has_privs_of_role(roleid, ownerId);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -2135,7 +2135,7 @@ pg_tablespace_ownercheck(Oid spc_oid, Oid roleid)
|
|||||||
heap_endscan(scan);
|
heap_endscan(scan);
|
||||||
heap_close(pg_tablespace, AccessShareLock);
|
heap_close(pg_tablespace, AccessShareLock);
|
||||||
|
|
||||||
return is_member_of_role(roleid, spcowner);
|
return has_privs_of_role(roleid, spcowner);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -2164,7 +2164,7 @@ pg_opclass_ownercheck(Oid opc_oid, Oid roleid)
|
|||||||
|
|
||||||
ReleaseSysCache(tuple);
|
ReleaseSysCache(tuple);
|
||||||
|
|
||||||
return is_member_of_role(roleid, ownerId);
|
return has_privs_of_role(roleid, ownerId);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -2203,7 +2203,7 @@ pg_database_ownercheck(Oid db_oid, Oid roleid)
|
|||||||
heap_endscan(scan);
|
heap_endscan(scan);
|
||||||
heap_close(pg_database, AccessShareLock);
|
heap_close(pg_database, AccessShareLock);
|
||||||
|
|
||||||
return is_member_of_role(roleid, dba);
|
return has_privs_of_role(roleid, dba);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -2231,5 +2231,5 @@ pg_conversion_ownercheck(Oid conv_oid, Oid roleid)
|
|||||||
|
|
||||||
ReleaseSysCache(tuple);
|
ReleaseSysCache(tuple);
|
||||||
|
|
||||||
return is_member_of_role(roleid, ownerId);
|
return has_privs_of_role(roleid, ownerId);
|
||||||
}
|
}
|
||||||
|
@ -3,20 +3,22 @@
|
|||||||
*
|
*
|
||||||
* Copyright (c) 1996-2005, PostgreSQL Global Development Group
|
* Copyright (c) 1996-2005, PostgreSQL Global Development Group
|
||||||
*
|
*
|
||||||
* $PostgreSQL: pgsql/src/backend/catalog/system_views.sql,v 1.16 2005/06/28 05:08:52 tgl Exp $
|
* $PostgreSQL: pgsql/src/backend/catalog/system_views.sql,v 1.17 2005/07/26 16:38:26 tgl Exp $
|
||||||
*/
|
*/
|
||||||
|
|
||||||
CREATE VIEW pg_roles AS
|
CREATE VIEW pg_roles AS
|
||||||
SELECT
|
SELECT
|
||||||
rolname,
|
rolname,
|
||||||
rolsuper,
|
rolsuper,
|
||||||
|
rolinherit,
|
||||||
rolcreaterole,
|
rolcreaterole,
|
||||||
rolcreatedb,
|
rolcreatedb,
|
||||||
rolcatupdate,
|
rolcatupdate,
|
||||||
rolcanlogin,
|
rolcanlogin,
|
||||||
'********'::text as rolpassword,
|
'********'::text as rolpassword,
|
||||||
rolvaliduntil,
|
rolvaliduntil,
|
||||||
rolconfig
|
rolconfig,
|
||||||
|
oid
|
||||||
FROM pg_authid;
|
FROM pg_authid;
|
||||||
|
|
||||||
CREATE VIEW pg_shadow AS
|
CREATE VIEW pg_shadow AS
|
||||||
|
@ -6,7 +6,7 @@
|
|||||||
* Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group
|
* Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group
|
||||||
* Portions Copyright (c) 1994, Regents of the University of California
|
* Portions Copyright (c) 1994, Regents of the University of California
|
||||||
*
|
*
|
||||||
* $PostgreSQL: pgsql/src/backend/commands/user.c,v 1.157 2005/07/25 22:12:31 tgl Exp $
|
* $PostgreSQL: pgsql/src/backend/commands/user.c,v 1.158 2005/07/26 16:38:26 tgl Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
@ -82,6 +82,7 @@ CreateRole(CreateRoleStmt *stmt)
|
|||||||
bool encrypt_password = Password_encryption; /* encrypt password? */
|
bool encrypt_password = Password_encryption; /* encrypt password? */
|
||||||
char encrypted_password[MD5_PASSWD_LEN + 1];
|
char encrypted_password[MD5_PASSWD_LEN + 1];
|
||||||
bool issuper = false; /* Make the user a superuser? */
|
bool issuper = false; /* Make the user a superuser? */
|
||||||
|
bool inherit = true; /* Auto inherit privileges? */
|
||||||
bool createrole = false; /* Can this user create roles? */
|
bool createrole = false; /* Can this user create roles? */
|
||||||
bool createdb = false; /* Can the user create databases? */
|
bool createdb = false; /* Can the user create databases? */
|
||||||
bool canlogin = false; /* Can this user login? */
|
bool canlogin = false; /* Can this user login? */
|
||||||
@ -91,6 +92,7 @@ CreateRole(CreateRoleStmt *stmt)
|
|||||||
char *validUntil = NULL; /* time the login is valid until */
|
char *validUntil = NULL; /* time the login is valid until */
|
||||||
DefElem *dpassword = NULL;
|
DefElem *dpassword = NULL;
|
||||||
DefElem *dissuper = NULL;
|
DefElem *dissuper = NULL;
|
||||||
|
DefElem *dinherit = NULL;
|
||||||
DefElem *dcreaterole = NULL;
|
DefElem *dcreaterole = NULL;
|
||||||
DefElem *dcreatedb = NULL;
|
DefElem *dcreatedb = NULL;
|
||||||
DefElem *dcanlogin = NULL;
|
DefElem *dcanlogin = NULL;
|
||||||
@ -99,6 +101,19 @@ CreateRole(CreateRoleStmt *stmt)
|
|||||||
DefElem *dadminmembers = NULL;
|
DefElem *dadminmembers = NULL;
|
||||||
DefElem *dvalidUntil = NULL;
|
DefElem *dvalidUntil = NULL;
|
||||||
|
|
||||||
|
/* The defaults can vary depending on the original statement type */
|
||||||
|
switch (stmt->stmt_type)
|
||||||
|
{
|
||||||
|
case ROLESTMT_ROLE:
|
||||||
|
break;
|
||||||
|
case ROLESTMT_USER:
|
||||||
|
canlogin = true;
|
||||||
|
/* may eventually want inherit to default to false here */
|
||||||
|
break;
|
||||||
|
case ROLESTMT_GROUP:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
/* Extract options from the statement node tree */
|
/* Extract options from the statement node tree */
|
||||||
foreach(option, stmt->options)
|
foreach(option, stmt->options)
|
||||||
{
|
{
|
||||||
@ -120,7 +135,7 @@ CreateRole(CreateRoleStmt *stmt)
|
|||||||
}
|
}
|
||||||
else if (strcmp(defel->defname, "sysid") == 0)
|
else if (strcmp(defel->defname, "sysid") == 0)
|
||||||
{
|
{
|
||||||
ereport(WARNING,
|
ereport(NOTICE,
|
||||||
(errmsg("SYSID can no longer be specified")));
|
(errmsg("SYSID can no longer be specified")));
|
||||||
}
|
}
|
||||||
else if (strcmp(defel->defname, "superuser") == 0)
|
else if (strcmp(defel->defname, "superuser") == 0)
|
||||||
@ -131,6 +146,14 @@ CreateRole(CreateRoleStmt *stmt)
|
|||||||
errmsg("conflicting or redundant options")));
|
errmsg("conflicting or redundant options")));
|
||||||
dissuper = defel;
|
dissuper = defel;
|
||||||
}
|
}
|
||||||
|
else if (strcmp(defel->defname, "inherit") == 0)
|
||||||
|
{
|
||||||
|
if (dinherit)
|
||||||
|
ereport(ERROR,
|
||||||
|
(errcode(ERRCODE_SYNTAX_ERROR),
|
||||||
|
errmsg("conflicting or redundant options")));
|
||||||
|
dinherit = defel;
|
||||||
|
}
|
||||||
else if (strcmp(defel->defname, "createrole") == 0)
|
else if (strcmp(defel->defname, "createrole") == 0)
|
||||||
{
|
{
|
||||||
if (dcreaterole)
|
if (dcreaterole)
|
||||||
@ -196,6 +219,8 @@ CreateRole(CreateRoleStmt *stmt)
|
|||||||
password = strVal(dpassword->arg);
|
password = strVal(dpassword->arg);
|
||||||
if (dissuper)
|
if (dissuper)
|
||||||
issuper = intVal(dissuper->arg) != 0;
|
issuper = intVal(dissuper->arg) != 0;
|
||||||
|
if (dinherit)
|
||||||
|
inherit = intVal(dinherit->arg) != 0;
|
||||||
if (dcreaterole)
|
if (dcreaterole)
|
||||||
createrole = intVal(dcreaterole->arg) != 0;
|
createrole = intVal(dcreaterole->arg) != 0;
|
||||||
if (dcreatedb)
|
if (dcreatedb)
|
||||||
@ -261,6 +286,7 @@ CreateRole(CreateRoleStmt *stmt)
|
|||||||
DirectFunctionCall1(namein, CStringGetDatum(stmt->role));
|
DirectFunctionCall1(namein, CStringGetDatum(stmt->role));
|
||||||
|
|
||||||
new_record[Anum_pg_authid_rolsuper - 1] = BoolGetDatum(issuper);
|
new_record[Anum_pg_authid_rolsuper - 1] = BoolGetDatum(issuper);
|
||||||
|
new_record[Anum_pg_authid_rolinherit - 1] = BoolGetDatum(inherit);
|
||||||
new_record[Anum_pg_authid_rolcreaterole - 1] = BoolGetDatum(createrole);
|
new_record[Anum_pg_authid_rolcreaterole - 1] = BoolGetDatum(createrole);
|
||||||
new_record[Anum_pg_authid_rolcreatedb - 1] = BoolGetDatum(createdb);
|
new_record[Anum_pg_authid_rolcreatedb - 1] = BoolGetDatum(createdb);
|
||||||
/* superuser gets catupdate right by default */
|
/* superuser gets catupdate right by default */
|
||||||
@ -367,6 +393,7 @@ AlterRole(AlterRoleStmt *stmt)
|
|||||||
bool encrypt_password = Password_encryption; /* encrypt password? */
|
bool encrypt_password = Password_encryption; /* encrypt password? */
|
||||||
char encrypted_password[MD5_PASSWD_LEN + 1];
|
char encrypted_password[MD5_PASSWD_LEN + 1];
|
||||||
int issuper = -1; /* Make the user a superuser? */
|
int issuper = -1; /* Make the user a superuser? */
|
||||||
|
int inherit = -1; /* Auto inherit privileges? */
|
||||||
int createrole = -1; /* Can this user create roles? */
|
int createrole = -1; /* Can this user create roles? */
|
||||||
int createdb = -1; /* Can the user create databases? */
|
int createdb = -1; /* Can the user create databases? */
|
||||||
int canlogin = -1; /* Can this user login? */
|
int canlogin = -1; /* Can this user login? */
|
||||||
@ -374,6 +401,7 @@ AlterRole(AlterRoleStmt *stmt)
|
|||||||
char *validUntil = NULL; /* time the login is valid until */
|
char *validUntil = NULL; /* time the login is valid until */
|
||||||
DefElem *dpassword = NULL;
|
DefElem *dpassword = NULL;
|
||||||
DefElem *dissuper = NULL;
|
DefElem *dissuper = NULL;
|
||||||
|
DefElem *dinherit = NULL;
|
||||||
DefElem *dcreaterole = NULL;
|
DefElem *dcreaterole = NULL;
|
||||||
DefElem *dcreatedb = NULL;
|
DefElem *dcreatedb = NULL;
|
||||||
DefElem *dcanlogin = NULL;
|
DefElem *dcanlogin = NULL;
|
||||||
@ -408,6 +436,14 @@ AlterRole(AlterRoleStmt *stmt)
|
|||||||
errmsg("conflicting or redundant options")));
|
errmsg("conflicting or redundant options")));
|
||||||
dissuper = defel;
|
dissuper = defel;
|
||||||
}
|
}
|
||||||
|
else if (strcmp(defel->defname, "inherit") == 0)
|
||||||
|
{
|
||||||
|
if (dinherit)
|
||||||
|
ereport(ERROR,
|
||||||
|
(errcode(ERRCODE_SYNTAX_ERROR),
|
||||||
|
errmsg("conflicting or redundant options")));
|
||||||
|
dinherit = defel;
|
||||||
|
}
|
||||||
else if (strcmp(defel->defname, "createrole") == 0)
|
else if (strcmp(defel->defname, "createrole") == 0)
|
||||||
{
|
{
|
||||||
if (dcreaterole)
|
if (dcreaterole)
|
||||||
@ -458,6 +494,8 @@ AlterRole(AlterRoleStmt *stmt)
|
|||||||
password = strVal(dpassword->arg);
|
password = strVal(dpassword->arg);
|
||||||
if (dissuper)
|
if (dissuper)
|
||||||
issuper = intVal(dissuper->arg);
|
issuper = intVal(dissuper->arg);
|
||||||
|
if (dinherit)
|
||||||
|
inherit = intVal(dinherit->arg);
|
||||||
if (dcreaterole)
|
if (dcreaterole)
|
||||||
createrole = intVal(dcreaterole->arg);
|
createrole = intVal(dcreaterole->arg);
|
||||||
if (dcreatedb)
|
if (dcreatedb)
|
||||||
@ -497,10 +535,10 @@ AlterRole(AlterRoleStmt *stmt)
|
|||||||
(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
|
(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
|
||||||
errmsg("must be superuser to alter superusers")));
|
errmsg("must be superuser to alter superusers")));
|
||||||
}
|
}
|
||||||
else
|
else if (!have_createrole_privilege())
|
||||||
{
|
{
|
||||||
if (!have_createrole_privilege() &&
|
if (!(inherit < 0 &&
|
||||||
!(createrole < 0 &&
|
createrole < 0 &&
|
||||||
createdb < 0 &&
|
createdb < 0 &&
|
||||||
canlogin < 0 &&
|
canlogin < 0 &&
|
||||||
!rolemembers &&
|
!rolemembers &&
|
||||||
@ -536,6 +574,12 @@ AlterRole(AlterRoleStmt *stmt)
|
|||||||
new_record_repl[Anum_pg_authid_rolcatupdate - 1] = 'r';
|
new_record_repl[Anum_pg_authid_rolcatupdate - 1] = 'r';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (inherit >= 0)
|
||||||
|
{
|
||||||
|
new_record[Anum_pg_authid_rolinherit - 1] = BoolGetDatum(inherit > 0);
|
||||||
|
new_record_repl[Anum_pg_authid_rolinherit - 1] = 'r';
|
||||||
|
}
|
||||||
|
|
||||||
if (createrole >= 0)
|
if (createrole >= 0)
|
||||||
{
|
{
|
||||||
new_record[Anum_pg_authid_rolcreaterole - 1] = BoolGetDatum(createrole > 0);
|
new_record[Anum_pg_authid_rolcreaterole - 1] = BoolGetDatum(createrole > 0);
|
||||||
|
@ -15,7 +15,7 @@
|
|||||||
* Portions Copyright (c) 1994, Regents of the University of California
|
* Portions Copyright (c) 1994, Regents of the University of California
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $PostgreSQL: pgsql/src/backend/nodes/copyfuncs.c,v 1.311 2005/07/02 23:00:39 tgl Exp $
|
* $PostgreSQL: pgsql/src/backend/nodes/copyfuncs.c,v 1.312 2005/07/26 16:38:27 tgl Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
@ -2392,6 +2392,7 @@ _copyCreateRoleStmt(CreateRoleStmt *from)
|
|||||||
{
|
{
|
||||||
CreateRoleStmt *newnode = makeNode(CreateRoleStmt);
|
CreateRoleStmt *newnode = makeNode(CreateRoleStmt);
|
||||||
|
|
||||||
|
COPY_SCALAR_FIELD(stmt_type);
|
||||||
COPY_STRING_FIELD(role);
|
COPY_STRING_FIELD(role);
|
||||||
COPY_NODE_FIELD(options);
|
COPY_NODE_FIELD(options);
|
||||||
|
|
||||||
|
@ -18,7 +18,7 @@
|
|||||||
* Portions Copyright (c) 1994, Regents of the University of California
|
* Portions Copyright (c) 1994, Regents of the University of California
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $PostgreSQL: pgsql/src/backend/nodes/equalfuncs.c,v 1.248 2005/07/02 23:00:39 tgl Exp $
|
* $PostgreSQL: pgsql/src/backend/nodes/equalfuncs.c,v 1.249 2005/07/26 16:38:27 tgl Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
@ -1308,6 +1308,7 @@ _equalDropPLangStmt(DropPLangStmt *a, DropPLangStmt *b)
|
|||||||
static bool
|
static bool
|
||||||
_equalCreateRoleStmt(CreateRoleStmt *a, CreateRoleStmt *b)
|
_equalCreateRoleStmt(CreateRoleStmt *a, CreateRoleStmt *b)
|
||||||
{
|
{
|
||||||
|
COMPARE_SCALAR_FIELD(stmt_type);
|
||||||
COMPARE_STRING_FIELD(role);
|
COMPARE_STRING_FIELD(role);
|
||||||
COMPARE_NODE_FIELD(options);
|
COMPARE_NODE_FIELD(options);
|
||||||
|
|
||||||
|
@ -11,7 +11,7 @@
|
|||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $PostgreSQL: pgsql/src/backend/parser/gram.y,v 2.502 2005/07/25 22:12:32 tgl Exp $
|
* $PostgreSQL: pgsql/src/backend/parser/gram.y,v 2.503 2005/07/26 16:38:27 tgl Exp $
|
||||||
*
|
*
|
||||||
* HISTORY
|
* HISTORY
|
||||||
* AUTHOR DATE MAJOR EVENT
|
* AUTHOR DATE MAJOR EVENT
|
||||||
@ -361,7 +361,7 @@ static void doNegateFloat(Value *v);
|
|||||||
HANDLER HAVING HEADER HOLD HOUR_P
|
HANDLER HAVING HEADER HOLD HOUR_P
|
||||||
|
|
||||||
ILIKE IMMEDIATE IMMUTABLE IMPLICIT_P IN_P INCLUDING INCREMENT
|
ILIKE IMMEDIATE IMMUTABLE IMPLICIT_P IN_P INCLUDING INCREMENT
|
||||||
INDEX INHERITS INITIALLY INNER_P INOUT INPUT_P
|
INDEX INHERIT INHERITS INITIALLY INNER_P INOUT INPUT_P
|
||||||
INSENSITIVE INSERT INSTEAD INT_P INTEGER INTERSECT
|
INSENSITIVE INSERT INSTEAD INT_P INTEGER INTERSECT
|
||||||
INTERVAL INTO INVOKER IS ISNULL ISOLATION
|
INTERVAL INTO INVOKER IS ISNULL ISOLATION
|
||||||
|
|
||||||
@ -376,8 +376,8 @@ static void doNegateFloat(Value *v);
|
|||||||
MATCH MAXVALUE MINUTE_P MINVALUE MODE MONTH_P MOVE
|
MATCH MAXVALUE MINUTE_P MINVALUE MODE MONTH_P MOVE
|
||||||
|
|
||||||
NAMES NATIONAL NATURAL NCHAR NEW NEXT NO NOCREATEDB
|
NAMES NATIONAL NATURAL NCHAR NEW NEXT NO NOCREATEDB
|
||||||
NOCREATEROLE NOCREATEUSER NOLOGIN_P NONE NOSUPERUSER NOT NOTHING NOTIFY
|
NOCREATEROLE NOCREATEUSER NOINHERIT NOLOGIN_P NONE NOSUPERUSER
|
||||||
NOTNULL NOWAIT NULL_P NULLIF NUMERIC
|
NOT NOTHING NOTIFY NOTNULL NOWAIT NULL_P NULLIF NUMERIC
|
||||||
|
|
||||||
OBJECT_P OF OFF OFFSET OIDS OLD ON ONLY OPERATOR OPTION OR
|
OBJECT_P OF OFF OFFSET OIDS OLD ON ONLY OPERATOR OPTION OR
|
||||||
ORDER OUT_P OUTER_P OVERLAPS OVERLAY OWNER
|
ORDER OUT_P OUTER_P OVERLAPS OVERLAY OWNER
|
||||||
@ -581,6 +581,7 @@ CreateRoleStmt:
|
|||||||
CREATE ROLE RoleId opt_with OptRoleList
|
CREATE ROLE RoleId opt_with OptRoleList
|
||||||
{
|
{
|
||||||
CreateRoleStmt *n = makeNode(CreateRoleStmt);
|
CreateRoleStmt *n = makeNode(CreateRoleStmt);
|
||||||
|
n->stmt_type = ROLESTMT_ROLE;
|
||||||
n->role = $3;
|
n->role = $3;
|
||||||
n->options = $5;
|
n->options = $5;
|
||||||
$$ = (Node *)n;
|
$$ = (Node *)n;
|
||||||
@ -630,6 +631,14 @@ OptRoleElem:
|
|||||||
{
|
{
|
||||||
$$ = makeDefElem("superuser", (Node *)makeInteger(FALSE));
|
$$ = makeDefElem("superuser", (Node *)makeInteger(FALSE));
|
||||||
}
|
}
|
||||||
|
| INHERIT
|
||||||
|
{
|
||||||
|
$$ = makeDefElem("inherit", (Node *)makeInteger(TRUE));
|
||||||
|
}
|
||||||
|
| NOINHERIT
|
||||||
|
{
|
||||||
|
$$ = makeDefElem("inherit", (Node *)makeInteger(FALSE));
|
||||||
|
}
|
||||||
| CREATEDB
|
| CREATEDB
|
||||||
{
|
{
|
||||||
$$ = makeDefElem("createdb", (Node *)makeInteger(TRUE));
|
$$ = makeDefElem("createdb", (Node *)makeInteger(TRUE));
|
||||||
@ -700,10 +709,9 @@ CreateUserStmt:
|
|||||||
CREATE USER RoleId opt_with OptRoleList
|
CREATE USER RoleId opt_with OptRoleList
|
||||||
{
|
{
|
||||||
CreateRoleStmt *n = makeNode(CreateRoleStmt);
|
CreateRoleStmt *n = makeNode(CreateRoleStmt);
|
||||||
|
n->stmt_type = ROLESTMT_USER;
|
||||||
n->role = $3;
|
n->role = $3;
|
||||||
n->options = lappend($5,
|
n->options = $5;
|
||||||
makeDefElem("canlogin",
|
|
||||||
(Node *)makeInteger(TRUE)));
|
|
||||||
$$ = (Node *)n;
|
$$ = (Node *)n;
|
||||||
}
|
}
|
||||||
;
|
;
|
||||||
@ -829,6 +837,7 @@ CreateGroupStmt:
|
|||||||
CREATE GROUP_P RoleId opt_with OptRoleList
|
CREATE GROUP_P RoleId opt_with OptRoleList
|
||||||
{
|
{
|
||||||
CreateRoleStmt *n = makeNode(CreateRoleStmt);
|
CreateRoleStmt *n = makeNode(CreateRoleStmt);
|
||||||
|
n->stmt_type = ROLESTMT_GROUP;
|
||||||
n->role = $3;
|
n->role = $3;
|
||||||
n->options = $5;
|
n->options = $5;
|
||||||
$$ = (Node *)n;
|
$$ = (Node *)n;
|
||||||
@ -7996,6 +8005,7 @@ unreserved_keyword:
|
|||||||
| INCLUDING
|
| INCLUDING
|
||||||
| INCREMENT
|
| INCREMENT
|
||||||
| INDEX
|
| INDEX
|
||||||
|
| INHERIT
|
||||||
| INHERITS
|
| INHERITS
|
||||||
| INPUT_P
|
| INPUT_P
|
||||||
| INSENSITIVE
|
| INSENSITIVE
|
||||||
@ -8028,6 +8038,7 @@ unreserved_keyword:
|
|||||||
| NOCREATEDB
|
| NOCREATEDB
|
||||||
| NOCREATEROLE
|
| NOCREATEROLE
|
||||||
| NOCREATEUSER
|
| NOCREATEUSER
|
||||||
|
| NOINHERIT
|
||||||
| NOLOGIN_P
|
| NOLOGIN_P
|
||||||
| NOSUPERUSER
|
| NOSUPERUSER
|
||||||
| NOTHING
|
| NOTHING
|
||||||
|
@ -8,7 +8,7 @@
|
|||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $PostgreSQL: pgsql/src/backend/parser/keywords.c,v 1.162 2005/06/29 20:34:14 tgl Exp $
|
* $PostgreSQL: pgsql/src/backend/parser/keywords.c,v 1.163 2005/07/26 16:38:27 tgl Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
@ -165,6 +165,7 @@ static const ScanKeyword ScanKeywords[] = {
|
|||||||
{"including", INCLUDING},
|
{"including", INCLUDING},
|
||||||
{"increment", INCREMENT},
|
{"increment", INCREMENT},
|
||||||
{"index", INDEX},
|
{"index", INDEX},
|
||||||
|
{"inherit", INHERIT},
|
||||||
{"inherits", INHERITS},
|
{"inherits", INHERITS},
|
||||||
{"initially", INITIALLY},
|
{"initially", INITIALLY},
|
||||||
{"inner", INNER_P},
|
{"inner", INNER_P},
|
||||||
@ -219,6 +220,7 @@ static const ScanKeyword ScanKeywords[] = {
|
|||||||
{"nocreatedb", NOCREATEDB},
|
{"nocreatedb", NOCREATEDB},
|
||||||
{"nocreaterole", NOCREATEROLE},
|
{"nocreaterole", NOCREATEROLE},
|
||||||
{"nocreateuser", NOCREATEUSER},
|
{"nocreateuser", NOCREATEUSER},
|
||||||
|
{"noinherit", NOINHERIT},
|
||||||
{"nologin", NOLOGIN_P},
|
{"nologin", NOLOGIN_P},
|
||||||
{"none", NONE},
|
{"none", NONE},
|
||||||
{"nosuperuser", NOSUPERUSER},
|
{"nosuperuser", NOSUPERUSER},
|
||||||
|
@ -8,7 +8,7 @@
|
|||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $PostgreSQL: pgsql/src/backend/utils/adt/acl.c,v 1.121 2005/07/26 00:04:18 tgl Exp $
|
* $PostgreSQL: pgsql/src/backend/utils/adt/acl.c,v 1.122 2005/07/26 16:38:27 tgl Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
@ -39,15 +39,29 @@
|
|||||||
* all the roles the "given role" is a member of, directly or indirectly.
|
* all the roles the "given role" is a member of, directly or indirectly.
|
||||||
* The cache is flushed whenever we detect a change in pg_auth_members.
|
* The cache is flushed whenever we detect a change in pg_auth_members.
|
||||||
*
|
*
|
||||||
* Possibly this mechanism should be generalized to allow caching membership
|
* There are actually two caches, one computed under "has_privs" rules
|
||||||
* info for more than one role?
|
* (do not recurse where rolinherit isn't true) and one computed under
|
||||||
|
* "is_member" rules (recurse regardless of rolinherit).
|
||||||
*
|
*
|
||||||
* cached_role is the role OID the cache is for.
|
* Possibly this mechanism should be generalized to allow caching membership
|
||||||
* cached_memberships is an OID list of roles that cached_role is a member of.
|
* info for multiple roles?
|
||||||
* The cache is valid if cached_role is not InvalidOid.
|
*
|
||||||
|
* The has_privs cache is:
|
||||||
|
* cached_privs_role is the role OID the cache is for.
|
||||||
|
* cached_privs_roles is an OID list of roles that cached_privs_role
|
||||||
|
* has the privileges of (always including itself).
|
||||||
|
* The cache is valid if cached_privs_role is not InvalidOid.
|
||||||
|
*
|
||||||
|
* The is_member cache is similarly:
|
||||||
|
* cached_member_role is the role OID the cache is for.
|
||||||
|
* cached_membership_roles is an OID list of roles that cached_member_role
|
||||||
|
* is a member of (always including itself).
|
||||||
|
* The cache is valid if cached_member_role is not InvalidOid.
|
||||||
*/
|
*/
|
||||||
static Oid cached_role = InvalidOid;
|
static Oid cached_privs_role = InvalidOid;
|
||||||
static List *cached_memberships = NIL;
|
static List *cached_privs_roles = NIL;
|
||||||
|
static Oid cached_member_role = InvalidOid;
|
||||||
|
static List *cached_membership_roles = NIL;
|
||||||
|
|
||||||
|
|
||||||
static const char *getid(const char *s, char *n);
|
static const char *getid(const char *s, char *n);
|
||||||
@ -999,7 +1013,7 @@ aclmask(const Acl *acl, Oid roleid, Oid ownerId,
|
|||||||
result = 0;
|
result = 0;
|
||||||
|
|
||||||
/* Owner always implicitly has all grant options */
|
/* Owner always implicitly has all grant options */
|
||||||
if (is_member_of_role(roleid, ownerId))
|
if (has_privs_of_role(roleid, ownerId))
|
||||||
{
|
{
|
||||||
result = mask & ACLITEM_ALL_GOPTION_BITS;
|
result = mask & ACLITEM_ALL_GOPTION_BITS;
|
||||||
if (result == mask)
|
if (result == mask)
|
||||||
@ -1042,7 +1056,7 @@ aclmask(const Acl *acl, Oid roleid, Oid ownerId,
|
|||||||
continue; /* already checked it */
|
continue; /* already checked it */
|
||||||
|
|
||||||
if ((aidata->ai_privs & remaining) &&
|
if ((aidata->ai_privs & remaining) &&
|
||||||
is_member_of_role(roleid, aidata->ai_grantee))
|
has_privs_of_role(roleid, aidata->ai_grantee))
|
||||||
{
|
{
|
||||||
result |= aidata->ai_privs & mask;
|
result |= aidata->ai_privs & mask;
|
||||||
if ((how == ACLMASK_ALL) ? (result == mask) : (result != 0))
|
if ((how == ACLMASK_ALL) ? (result == mask) : (result != 0))
|
||||||
@ -2653,8 +2667,10 @@ pg_has_role_id_id(PG_FUNCTION_ARGS)
|
|||||||
* convert_role_priv_string
|
* convert_role_priv_string
|
||||||
* Convert text string to AclMode value.
|
* Convert text string to AclMode value.
|
||||||
*
|
*
|
||||||
* There is only one interesting option, MEMBER, which we represent by
|
* We use USAGE to denote whether the privileges of the role are accessible
|
||||||
* ACL_USAGE since no formal ACL bit is defined for it. This convention
|
* (has_privs), MEMBER to denote is_member, and MEMBER WITH GRANT OPTION
|
||||||
|
* (or ADMIN OPTION) to denote is_admin. There is no ACL bit corresponding
|
||||||
|
* to MEMBER so we cheat and use ACL_CREATE for that. This convention
|
||||||
* is shared only with pg_role_aclcheck, below.
|
* is shared only with pg_role_aclcheck, below.
|
||||||
*/
|
*/
|
||||||
static AclMode
|
static AclMode
|
||||||
@ -2668,12 +2684,15 @@ convert_role_priv_string(text *priv_type_text)
|
|||||||
/*
|
/*
|
||||||
* Return mode from priv_type string
|
* Return mode from priv_type string
|
||||||
*/
|
*/
|
||||||
if (pg_strcasecmp(priv_type, "MEMBER") == 0)
|
if (pg_strcasecmp(priv_type, "USAGE") == 0)
|
||||||
return ACL_USAGE;
|
return ACL_USAGE;
|
||||||
if (pg_strcasecmp(priv_type, "MEMBER WITH GRANT OPTION") == 0)
|
if (pg_strcasecmp(priv_type, "MEMBER") == 0)
|
||||||
return ACL_GRANT_OPTION_FOR(ACL_USAGE);
|
return ACL_CREATE;
|
||||||
if (pg_strcasecmp(priv_type, "MEMBER WITH ADMIN OPTION") == 0)
|
if (pg_strcasecmp(priv_type, "USAGE WITH GRANT OPTION") == 0 ||
|
||||||
return ACL_GRANT_OPTION_FOR(ACL_USAGE);
|
pg_strcasecmp(priv_type, "USAGE WITH ADMIN OPTION") == 0 ||
|
||||||
|
pg_strcasecmp(priv_type, "MEMBER WITH GRANT OPTION") == 0 ||
|
||||||
|
pg_strcasecmp(priv_type, "MEMBER WITH ADMIN OPTION") == 0)
|
||||||
|
return ACL_GRANT_OPTION_FOR(ACL_CREATE);
|
||||||
|
|
||||||
ereport(ERROR,
|
ereport(ERROR,
|
||||||
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
|
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
|
||||||
@ -2688,20 +2707,22 @@ convert_role_priv_string(text *priv_type_text)
|
|||||||
static AclResult
|
static AclResult
|
||||||
pg_role_aclcheck(Oid role_oid, Oid roleid, AclMode mode)
|
pg_role_aclcheck(Oid role_oid, Oid roleid, AclMode mode)
|
||||||
{
|
{
|
||||||
if (mode & ACL_GRANT_OPTION_FOR(ACL_USAGE))
|
if (mode & ACL_GRANT_OPTION_FOR(ACL_CREATE))
|
||||||
{
|
{
|
||||||
if (is_admin_of_role(roleid, role_oid))
|
if (is_admin_of_role(roleid, role_oid))
|
||||||
return ACLCHECK_OK;
|
return ACLCHECK_OK;
|
||||||
else
|
|
||||||
return ACLCHECK_NO_PRIV;
|
|
||||||
}
|
}
|
||||||
else
|
if (mode & ACL_CREATE)
|
||||||
{
|
{
|
||||||
if (is_member_of_role(roleid, role_oid))
|
if (is_member_of_role(roleid, role_oid))
|
||||||
return ACLCHECK_OK;
|
return ACLCHECK_OK;
|
||||||
else
|
|
||||||
return ACLCHECK_NO_PRIV;
|
|
||||||
}
|
}
|
||||||
|
if (mode & ACL_USAGE)
|
||||||
|
{
|
||||||
|
if (has_privs_of_role(roleid, role_oid))
|
||||||
|
return ACLCHECK_OK;
|
||||||
|
}
|
||||||
|
return ACLCHECK_NO_PRIV;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -2730,23 +2751,47 @@ initialize_acl(void)
|
|||||||
static void
|
static void
|
||||||
RoleMembershipCacheCallback(Datum arg, Oid relid)
|
RoleMembershipCacheCallback(Datum arg, Oid relid)
|
||||||
{
|
{
|
||||||
/* Force membership cache to be recomputed on next use */
|
/* Force membership caches to be recomputed on next use */
|
||||||
cached_role = InvalidOid;
|
cached_privs_role = InvalidOid;
|
||||||
|
cached_member_role = InvalidOid;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* Check if specified role has rolinherit set */
|
||||||
|
static bool
|
||||||
|
has_rolinherit(Oid roleid)
|
||||||
|
{
|
||||||
|
bool result = false;
|
||||||
|
HeapTuple utup;
|
||||||
|
|
||||||
|
utup = SearchSysCache(AUTHOID,
|
||||||
|
ObjectIdGetDatum(roleid),
|
||||||
|
0, 0, 0);
|
||||||
|
if (HeapTupleIsValid(utup))
|
||||||
|
{
|
||||||
|
result = ((Form_pg_authid) GETSTRUCT(utup))->rolinherit;
|
||||||
|
ReleaseSysCache(utup);
|
||||||
|
}
|
||||||
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Is member a member of role (directly or indirectly)?
|
* Does member have the privileges of role (directly or indirectly)?
|
||||||
|
*
|
||||||
|
* This is defined not to recurse through roles that don't have rolinherit
|
||||||
|
* set; for such roles, membership implies the ability to do SET ROLE, but
|
||||||
|
* the privileges are not available until you've done so.
|
||||||
*
|
*
|
||||||
* Since indirect membership testing is relatively expensive, we cache
|
* Since indirect membership testing is relatively expensive, we cache
|
||||||
* a list of memberships.
|
* a list of memberships.
|
||||||
*/
|
*/
|
||||||
bool
|
bool
|
||||||
is_member_of_role(Oid member, Oid role)
|
has_privs_of_role(Oid member, Oid role)
|
||||||
{
|
{
|
||||||
List *roles_list;
|
List *roles_list;
|
||||||
ListCell *l;
|
ListCell *l;
|
||||||
List *new_cached_memberships;
|
List *new_cached_privs_roles;
|
||||||
MemoryContext oldctx;
|
MemoryContext oldctx;
|
||||||
|
|
||||||
/* Fast path for simple case */
|
/* Fast path for simple case */
|
||||||
@ -2758,8 +2803,100 @@ is_member_of_role(Oid member, Oid role)
|
|||||||
return true;
|
return true;
|
||||||
|
|
||||||
/* If cache is already valid, just use the list */
|
/* If cache is already valid, just use the list */
|
||||||
if (OidIsValid(cached_role) && cached_role == member)
|
if (OidIsValid(cached_privs_role) && cached_privs_role == member)
|
||||||
return list_member_oid(cached_memberships, role);
|
return list_member_oid(cached_privs_roles, role);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Find all the roles that member is a member of,
|
||||||
|
* including multi-level recursion. The role itself will always
|
||||||
|
* be the first element of the resulting list.
|
||||||
|
*
|
||||||
|
* Each element of the list is scanned to see if it adds any indirect
|
||||||
|
* memberships. We can use a single list as both the record of
|
||||||
|
* already-found memberships and the agenda of roles yet to be scanned.
|
||||||
|
* This is a bit tricky but works because the foreach() macro doesn't
|
||||||
|
* fetch the next list element until the bottom of the loop.
|
||||||
|
*/
|
||||||
|
roles_list = list_make1_oid(member);
|
||||||
|
|
||||||
|
foreach(l, roles_list)
|
||||||
|
{
|
||||||
|
Oid memberid = lfirst_oid(l);
|
||||||
|
CatCList *memlist;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
/* Ignore non-inheriting roles */
|
||||||
|
if (!has_rolinherit(memberid))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
/* Find roles that memberid is directly a member of */
|
||||||
|
memlist = SearchSysCacheList(AUTHMEMMEMROLE, 1,
|
||||||
|
ObjectIdGetDatum(memberid),
|
||||||
|
0, 0, 0);
|
||||||
|
for (i = 0; i < memlist->n_members; i++)
|
||||||
|
{
|
||||||
|
HeapTuple tup = &memlist->members[i]->tuple;
|
||||||
|
Oid otherid = ((Form_pg_auth_members) GETSTRUCT(tup))->roleid;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Even though there shouldn't be any loops in the membership
|
||||||
|
* graph, we must test for having already seen this role.
|
||||||
|
* It is legal for instance to have both A->B and A->C->B.
|
||||||
|
*/
|
||||||
|
if (!list_member_oid(roles_list, otherid))
|
||||||
|
roles_list = lappend_oid(roles_list, otherid);
|
||||||
|
}
|
||||||
|
ReleaseSysCacheList(memlist);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Copy the completed list into TopMemoryContext so it will persist.
|
||||||
|
*/
|
||||||
|
oldctx = MemoryContextSwitchTo(TopMemoryContext);
|
||||||
|
new_cached_privs_roles = list_copy(roles_list);
|
||||||
|
MemoryContextSwitchTo(oldctx);
|
||||||
|
list_free(roles_list);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Now safe to assign to state variable
|
||||||
|
*/
|
||||||
|
cached_privs_role = InvalidOid; /* just paranoia */
|
||||||
|
list_free(cached_privs_roles);
|
||||||
|
cached_privs_roles = new_cached_privs_roles;
|
||||||
|
cached_privs_role = member;
|
||||||
|
|
||||||
|
/* And now we can return the answer */
|
||||||
|
return list_member_oid(cached_privs_roles, role);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Is member a member of role (directly or indirectly)?
|
||||||
|
*
|
||||||
|
* This is defined to recurse through roles regardless of rolinherit.
|
||||||
|
*
|
||||||
|
* Since indirect membership testing is relatively expensive, we cache
|
||||||
|
* a list of memberships.
|
||||||
|
*/
|
||||||
|
bool
|
||||||
|
is_member_of_role(Oid member, Oid role)
|
||||||
|
{
|
||||||
|
List *roles_list;
|
||||||
|
ListCell *l;
|
||||||
|
List *new_cached_membership_roles;
|
||||||
|
MemoryContext oldctx;
|
||||||
|
|
||||||
|
/* Fast path for simple case */
|
||||||
|
if (member == role)
|
||||||
|
return true;
|
||||||
|
|
||||||
|
/* Superusers have every privilege, so are part of every role */
|
||||||
|
if (superuser_arg(member))
|
||||||
|
return true;
|
||||||
|
|
||||||
|
/* If cache is already valid, just use the list */
|
||||||
|
if (OidIsValid(cached_member_role) && cached_member_role == member)
|
||||||
|
return list_member_oid(cached_membership_roles, role);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Find all the roles that member is a member of,
|
* Find all the roles that member is a member of,
|
||||||
@ -2804,20 +2941,20 @@ is_member_of_role(Oid member, Oid role)
|
|||||||
* Copy the completed list into TopMemoryContext so it will persist.
|
* Copy the completed list into TopMemoryContext so it will persist.
|
||||||
*/
|
*/
|
||||||
oldctx = MemoryContextSwitchTo(TopMemoryContext);
|
oldctx = MemoryContextSwitchTo(TopMemoryContext);
|
||||||
new_cached_memberships = list_copy(roles_list);
|
new_cached_membership_roles = list_copy(roles_list);
|
||||||
MemoryContextSwitchTo(oldctx);
|
MemoryContextSwitchTo(oldctx);
|
||||||
list_free(roles_list);
|
list_free(roles_list);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Now safe to assign to state variable
|
* Now safe to assign to state variable
|
||||||
*/
|
*/
|
||||||
cached_role = InvalidOid; /* just paranoia */
|
cached_member_role = InvalidOid; /* just paranoia */
|
||||||
list_free(cached_memberships);
|
list_free(cached_membership_roles);
|
||||||
cached_memberships = new_cached_memberships;
|
cached_membership_roles = new_cached_membership_roles;
|
||||||
cached_role = member;
|
cached_member_role = member;
|
||||||
|
|
||||||
/* And now we can return the answer */
|
/* And now we can return the answer */
|
||||||
return list_member_oid(cached_memberships, role);
|
return list_member_oid(cached_membership_roles, role);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -37,7 +37,7 @@
|
|||||||
* Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group
|
* Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group
|
||||||
* Portions Copyright (c) 1994, Regents of the University of California
|
* Portions Copyright (c) 1994, Regents of the University of California
|
||||||
*
|
*
|
||||||
* $PostgreSQL: pgsql/src/include/catalog/catversion.h,v 1.291 2005/07/26 00:04:18 tgl Exp $
|
* $PostgreSQL: pgsql/src/include/catalog/catversion.h,v 1.292 2005/07/26 16:38:28 tgl Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
@ -53,6 +53,6 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
/* yyyymmddN */
|
/* yyyymmddN */
|
||||||
#define CATALOG_VERSION_NO 200507251
|
#define CATALOG_VERSION_NO 200507261
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@ -10,7 +10,7 @@
|
|||||||
* Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group
|
* Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group
|
||||||
* Portions Copyright (c) 1994, Regents of the University of California
|
* Portions Copyright (c) 1994, Regents of the University of California
|
||||||
*
|
*
|
||||||
* $PostgreSQL: pgsql/src/include/catalog/pg_authid.h,v 1.1 2005/06/28 05:09:05 tgl Exp $
|
* $PostgreSQL: pgsql/src/include/catalog/pg_authid.h,v 1.2 2005/07/26 16:38:28 tgl Exp $
|
||||||
*
|
*
|
||||||
* NOTES
|
* NOTES
|
||||||
* the genbki.sh script reads this file and generates .bki
|
* the genbki.sh script reads this file and generates .bki
|
||||||
@ -44,6 +44,7 @@ CATALOG(pg_authid,1260) BKI_SHARED_RELATION
|
|||||||
{
|
{
|
||||||
NameData rolname; /* name of role */
|
NameData rolname; /* name of role */
|
||||||
bool rolsuper; /* read this field via superuser() only! */
|
bool rolsuper; /* read this field via superuser() only! */
|
||||||
|
bool rolinherit; /* inherit privileges from other roles? */
|
||||||
bool rolcreaterole; /* allowed to create more roles? */
|
bool rolcreaterole; /* allowed to create more roles? */
|
||||||
bool rolcreatedb; /* allowed to create databases? */
|
bool rolcreatedb; /* allowed to create databases? */
|
||||||
bool rolcatupdate; /* allowed to alter catalogs manually? */
|
bool rolcatupdate; /* allowed to alter catalogs manually? */
|
||||||
@ -69,16 +70,17 @@ typedef FormData_pg_authid *Form_pg_authid;
|
|||||||
* compiler constants for pg_authid
|
* compiler constants for pg_authid
|
||||||
* ----------------
|
* ----------------
|
||||||
*/
|
*/
|
||||||
#define Natts_pg_authid 9
|
#define Natts_pg_authid 10
|
||||||
#define Anum_pg_authid_rolname 1
|
#define Anum_pg_authid_rolname 1
|
||||||
#define Anum_pg_authid_rolsuper 2
|
#define Anum_pg_authid_rolsuper 2
|
||||||
#define Anum_pg_authid_rolcreaterole 3
|
#define Anum_pg_authid_rolinherit 3
|
||||||
#define Anum_pg_authid_rolcreatedb 4
|
#define Anum_pg_authid_rolcreaterole 4
|
||||||
#define Anum_pg_authid_rolcatupdate 5
|
#define Anum_pg_authid_rolcreatedb 5
|
||||||
#define Anum_pg_authid_rolcanlogin 6
|
#define Anum_pg_authid_rolcatupdate 6
|
||||||
#define Anum_pg_authid_rolpassword 7
|
#define Anum_pg_authid_rolcanlogin 7
|
||||||
#define Anum_pg_authid_rolvaliduntil 8
|
#define Anum_pg_authid_rolpassword 8
|
||||||
#define Anum_pg_authid_rolconfig 9
|
#define Anum_pg_authid_rolvaliduntil 9
|
||||||
|
#define Anum_pg_authid_rolconfig 10
|
||||||
|
|
||||||
/* ----------------
|
/* ----------------
|
||||||
* initial contents of pg_authid
|
* initial contents of pg_authid
|
||||||
@ -87,7 +89,7 @@ typedef FormData_pg_authid *Form_pg_authid;
|
|||||||
* user choices.
|
* user choices.
|
||||||
* ----------------
|
* ----------------
|
||||||
*/
|
*/
|
||||||
DATA(insert OID = 10 ( "POSTGRES" t t t t t _null_ _null_ _null_ ));
|
DATA(insert OID = 10 ( "POSTGRES" t t t t t t _null_ _null_ _null_ ));
|
||||||
|
|
||||||
#define BOOTSTRAP_SUPERUSERID 10
|
#define BOOTSTRAP_SUPERUSERID 10
|
||||||
|
|
||||||
|
@ -7,7 +7,7 @@
|
|||||||
* Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group
|
* Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group
|
||||||
* Portions Copyright (c) 1994, Regents of the University of California
|
* Portions Copyright (c) 1994, Regents of the University of California
|
||||||
*
|
*
|
||||||
* $PostgreSQL: pgsql/src/include/nodes/parsenodes.h,v 1.285 2005/06/28 19:51:24 tgl Exp $
|
* $PostgreSQL: pgsql/src/include/nodes/parsenodes.h,v 1.286 2005/07/26 16:38:28 tgl Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
@ -1139,11 +1139,24 @@ typedef struct DropPLangStmt
|
|||||||
|
|
||||||
/* ----------------------
|
/* ----------------------
|
||||||
* Create/Alter/Drop Role Statements
|
* Create/Alter/Drop Role Statements
|
||||||
|
*
|
||||||
|
* Note: these node types are also used for the backwards-compatible
|
||||||
|
* Create/Alter/Drop User/Group statements. In the ALTER and DROP cases
|
||||||
|
* there's really no need to distinguish what the original spelling was,
|
||||||
|
* but for CREATE we mark the type because the defaults vary.
|
||||||
* ----------------------
|
* ----------------------
|
||||||
*/
|
*/
|
||||||
|
typedef enum RoleStmtType
|
||||||
|
{
|
||||||
|
ROLESTMT_ROLE,
|
||||||
|
ROLESTMT_USER,
|
||||||
|
ROLESTMT_GROUP
|
||||||
|
} RoleStmtType;
|
||||||
|
|
||||||
typedef struct CreateRoleStmt
|
typedef struct CreateRoleStmt
|
||||||
{
|
{
|
||||||
NodeTag type;
|
NodeTag type;
|
||||||
|
RoleStmtType stmt_type; /* ROLE/USER/GROUP */
|
||||||
char *role; /* role name */
|
char *role; /* role name */
|
||||||
List *options; /* List of DefElem nodes */
|
List *options; /* List of DefElem nodes */
|
||||||
} CreateRoleStmt;
|
} CreateRoleStmt;
|
||||||
|
@ -7,7 +7,7 @@
|
|||||||
* Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group
|
* Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group
|
||||||
* Portions Copyright (c) 1994, Regents of the University of California
|
* Portions Copyright (c) 1994, Regents of the University of California
|
||||||
*
|
*
|
||||||
* $PostgreSQL: pgsql/src/include/utils/acl.h,v 1.82 2005/07/14 21:46:30 tgl Exp $
|
* $PostgreSQL: pgsql/src/include/utils/acl.h,v 1.83 2005/07/26 16:38:29 tgl Exp $
|
||||||
*
|
*
|
||||||
* NOTES
|
* NOTES
|
||||||
* An ACL array is simply an array of AclItems, representing the union
|
* An ACL array is simply an array of AclItems, representing the union
|
||||||
@ -210,6 +210,7 @@ extern AclMode aclmask(const Acl *acl, Oid roleid, Oid ownerId,
|
|||||||
AclMode mask, AclMaskHow how);
|
AclMode mask, AclMaskHow how);
|
||||||
extern int aclmembers(const Acl *acl, Oid **roleids);
|
extern int aclmembers(const Acl *acl, Oid **roleids);
|
||||||
|
|
||||||
|
extern bool has_privs_of_role(Oid member, Oid role);
|
||||||
extern bool is_member_of_role(Oid member, Oid role);
|
extern bool is_member_of_role(Oid member, Oid role);
|
||||||
extern bool is_admin_of_role(Oid member, Oid role);
|
extern bool is_admin_of_role(Oid member, Oid role);
|
||||||
extern void check_is_member_of_role(Oid member, Oid role);
|
extern void check_is_member_of_role(Oid member, Oid role);
|
||||||
|
@ -1281,7 +1281,7 @@ SELECT viewname, definition FROM pg_views WHERE schemaname <> 'information_schem
|
|||||||
pg_indexes | SELECT n.nspname AS schemaname, c.relname AS tablename, i.relname AS indexname, t.spcname AS "tablespace", pg_get_indexdef(i.oid) AS indexdef FROM ((((pg_index x JOIN pg_class c ON ((c.oid = x.indrelid))) JOIN pg_class i ON ((i.oid = x.indexrelid))) LEFT JOIN pg_namespace n ON ((n.oid = c.relnamespace))) LEFT JOIN pg_tablespace t ON ((t.oid = i.reltablespace))) WHERE ((c.relkind = 'r'::"char") AND (i.relkind = 'i'::"char"));
|
pg_indexes | SELECT n.nspname AS schemaname, c.relname AS tablename, i.relname AS indexname, t.spcname AS "tablespace", pg_get_indexdef(i.oid) AS indexdef FROM ((((pg_index x JOIN pg_class c ON ((c.oid = x.indrelid))) JOIN pg_class i ON ((i.oid = x.indexrelid))) LEFT JOIN pg_namespace n ON ((n.oid = c.relnamespace))) LEFT JOIN pg_tablespace t ON ((t.oid = i.reltablespace))) WHERE ((c.relkind = 'r'::"char") AND (i.relkind = 'i'::"char"));
|
||||||
pg_locks | SELECT l.locktype, l."database", l.relation, l.page, l.tuple, l.transactionid, l.classid, l.objid, l.objsubid, l."transaction", l.pid, l."mode", l."granted" FROM pg_lock_status() l(locktype text, "database" oid, relation oid, page integer, tuple smallint, transactionid xid, classid oid, objid oid, objsubid smallint, "transaction" xid, pid integer, "mode" text, "granted" boolean);
|
pg_locks | SELECT l.locktype, l."database", l.relation, l.page, l.tuple, l.transactionid, l.classid, l.objid, l.objsubid, l."transaction", l.pid, l."mode", l."granted" FROM pg_lock_status() l(locktype text, "database" oid, relation oid, page integer, tuple smallint, transactionid xid, classid oid, objid oid, objsubid smallint, "transaction" xid, pid integer, "mode" text, "granted" boolean);
|
||||||
pg_prepared_xacts | SELECT p."transaction", p.gid, p."prepared", u.rolname AS "owner", d.datname AS "database" FROM ((pg_prepared_xact() p("transaction" xid, gid text, "prepared" timestamp with time zone, ownerid oid, dbid oid) LEFT JOIN pg_authid u ON ((p.ownerid = u.oid))) LEFT JOIN pg_database d ON ((p.dbid = d.oid)));
|
pg_prepared_xacts | SELECT p."transaction", p.gid, p."prepared", u.rolname AS "owner", d.datname AS "database" FROM ((pg_prepared_xact() p("transaction" xid, gid text, "prepared" timestamp with time zone, ownerid oid, dbid oid) LEFT JOIN pg_authid u ON ((p.ownerid = u.oid))) LEFT JOIN pg_database d ON ((p.dbid = d.oid)));
|
||||||
pg_roles | SELECT pg_authid.rolname, pg_authid.rolsuper, pg_authid.rolcreaterole, pg_authid.rolcreatedb, pg_authid.rolcatupdate, pg_authid.rolcanlogin, '********'::text AS rolpassword, pg_authid.rolvaliduntil, pg_authid.rolconfig FROM pg_authid;
|
pg_roles | SELECT pg_authid.rolname, pg_authid.rolsuper, pg_authid.rolinherit, pg_authid.rolcreaterole, pg_authid.rolcreatedb, pg_authid.rolcatupdate, pg_authid.rolcanlogin, '********'::text AS rolpassword, pg_authid.rolvaliduntil, pg_authid.rolconfig, pg_authid.oid FROM pg_authid;
|
||||||
pg_rules | SELECT n.nspname AS schemaname, c.relname AS tablename, r.rulename, pg_get_ruledef(r.oid) AS definition FROM ((pg_rewrite r JOIN pg_class c ON ((c.oid = r.ev_class))) LEFT JOIN pg_namespace n ON ((n.oid = c.relnamespace))) WHERE (r.rulename <> '_RETURN'::name);
|
pg_rules | SELECT n.nspname AS schemaname, c.relname AS tablename, r.rulename, pg_get_ruledef(r.oid) AS definition FROM ((pg_rewrite r JOIN pg_class c ON ((c.oid = r.ev_class))) LEFT JOIN pg_namespace n ON ((n.oid = c.relnamespace))) WHERE (r.rulename <> '_RETURN'::name);
|
||||||
pg_settings | SELECT a.name, a.setting, a.category, a.short_desc, a.extra_desc, a.context, a.vartype, a.source, a.min_val, a.max_val FROM pg_show_all_settings() a(name text, setting text, category text, short_desc text, extra_desc text, context text, vartype text, source text, min_val text, max_val text);
|
pg_settings | SELECT a.name, a.setting, a.category, a.short_desc, a.extra_desc, a.context, a.vartype, a.source, a.min_val, a.max_val FROM pg_show_all_settings() a(name text, setting text, category text, short_desc text, extra_desc text, context text, vartype text, source text, min_val text, max_val text);
|
||||||
pg_shadow | SELECT pg_authid.rolname AS usename, pg_authid.oid AS usesysid, pg_authid.rolcreatedb AS usecreatedb, pg_authid.rolsuper AS usesuper, pg_authid.rolcatupdate AS usecatupd, pg_authid.rolpassword AS passwd, (pg_authid.rolvaliduntil)::abstime AS valuntil, pg_authid.rolconfig AS useconfig FROM pg_authid WHERE pg_authid.rolcanlogin;
|
pg_shadow | SELECT pg_authid.rolname AS usename, pg_authid.oid AS usesysid, pg_authid.rolcreatedb AS usecreatedb, pg_authid.rolsuper AS usesuper, pg_authid.rolcatupdate AS usecatupd, pg_authid.rolpassword AS passwd, (pg_authid.rolvaliduntil)::abstime AS valuntil, pg_authid.rolconfig AS useconfig FROM pg_authid WHERE pg_authid.rolcanlogin;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user