Commit c33d5758 authored by Tom Lane's avatar Tom Lane

More cleanup on roles patch. Allow admin option to be inherited through

role memberships; make superuser/createrole distinction do something
useful; fix some locking and CommandCounterIncrement issues; prevent
creation of loops in the membership graph.
parent 4523e0b6
...@@ -15,7 +15,7 @@ ...@@ -15,7 +15,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/commands/dbcommands.c,v 1.162 2005/06/28 05:08:53 tgl Exp $ * $PostgreSQL: pgsql/src/backend/commands/dbcommands.c,v 1.163 2005/06/29 20:34:13 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -194,8 +194,8 @@ createdb(const CreatedbStmt *stmt) ...@@ -194,8 +194,8 @@ createdb(const CreatedbStmt *stmt)
if (is_member_of_role(GetUserId(), datdba)) if (is_member_of_role(GetUserId(), datdba))
{ {
/* creating database for self: can be superuser or createdb */ /* creating database for self: createdb is required */
if (!superuser() && !have_createdb_privilege()) if (!have_createdb_privilege())
ereport(ERROR, ereport(ERROR,
(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE), (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
errmsg("permission denied to create database"))); errmsg("permission denied to create database")));
...@@ -759,7 +759,7 @@ RenameDatabase(const char *oldname, const char *newname) ...@@ -759,7 +759,7 @@ RenameDatabase(const char *oldname, const char *newname)
oldname); oldname);
/* must have createdb rights */ /* must have createdb rights */
if (!superuser() && !have_createdb_privilege()) if (!have_createdb_privilege())
ereport(ERROR, ereport(ERROR,
(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE), (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
errmsg("permission denied to rename database"))); errmsg("permission denied to rename database")));
...@@ -1044,6 +1044,10 @@ have_createdb_privilege(void) ...@@ -1044,6 +1044,10 @@ have_createdb_privilege(void)
bool result = false; bool result = false;
HeapTuple utup; HeapTuple utup;
/* Superusers can always do everything */
if (superuser())
return true;
utup = SearchSysCache(AUTHOID, utup = SearchSysCache(AUTHOID,
ObjectIdGetDatum(GetUserId()), ObjectIdGetDatum(GetUserId()),
0, 0, 0); 0, 0, 0);
......
This diff is collapsed.
...@@ -11,7 +11,7 @@ ...@@ -11,7 +11,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/parser/gram.y,v 2.500 2005/06/28 19:51:22 tgl Exp $ * $PostgreSQL: pgsql/src/backend/parser/gram.y,v 2.501 2005/06/29 20:34:13 tgl Exp $
* *
* HISTORY * HISTORY
* AUTHOR DATE MAJOR EVENT * AUTHOR DATE MAJOR EVENT
...@@ -376,7 +376,7 @@ static void doNegateFloat(Value *v); ...@@ -376,7 +376,7 @@ 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 NOT NOTHING NOTIFY NOCREATEROLE NOCREATEUSER NOLOGIN_P NONE NOSUPERUSER NOT NOTHING NOTIFY
NOTNULL NOWAIT NULL_P NULLIF NUMERIC 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
...@@ -395,7 +395,7 @@ static void doNegateFloat(Value *v); ...@@ -395,7 +395,7 @@ static void doNegateFloat(Value *v);
SAVEPOINT SCHEMA SCROLL SECOND_P SECURITY SELECT SEQUENCE SAVEPOINT SCHEMA SCROLL SECOND_P SECURITY SELECT SEQUENCE
SERIALIZABLE SESSION SESSION_USER SET SETOF SHARE SERIALIZABLE SESSION SESSION_USER SET SETOF SHARE
SHOW SIMILAR SIMPLE SMALLINT SOME STABLE START STATEMENT SHOW SIMILAR SIMPLE SMALLINT SOME STABLE START STATEMENT
STATISTICS STDIN STDOUT STORAGE STRICT_P SUBSTRING SYMMETRIC STATISTICS STDIN STDOUT STORAGE STRICT_P SUBSTRING SUPERUSER_P SYMMETRIC
SYSID SYSTEM_P SYSID SYSTEM_P
TABLE TABLESPACE TEMP TEMPLATE TEMPORARY THEN TIME TIMESTAMP TABLE TABLESPACE TEMP TEMPLATE TEMPORARY THEN TIME TIMESTAMP
...@@ -622,6 +622,14 @@ OptRoleElem: ...@@ -622,6 +622,14 @@ OptRoleElem:
{ {
$$ = makeDefElem("sysid", (Node *)makeInteger($2)); $$ = makeDefElem("sysid", (Node *)makeInteger($2));
} }
| SUPERUSER_P
{
$$ = makeDefElem("superuser", (Node *)makeInteger(TRUE));
}
| NOSUPERUSER
{
$$ = makeDefElem("superuser", (Node *)makeInteger(FALSE));
}
| CREATEDB | CREATEDB
{ {
$$ = makeDefElem("createdb", (Node *)makeInteger(TRUE)); $$ = makeDefElem("createdb", (Node *)makeInteger(TRUE));
...@@ -634,21 +642,22 @@ OptRoleElem: ...@@ -634,21 +642,22 @@ OptRoleElem:
{ {
$$ = makeDefElem("createrole", (Node *)makeInteger(TRUE)); $$ = makeDefElem("createrole", (Node *)makeInteger(TRUE));
} }
| CREATEUSER | NOCREATEROLE
{ {
$$ = makeDefElem("createrole", (Node *)makeInteger(TRUE)); $$ = makeDefElem("createrole", (Node *)makeInteger(FALSE));
} }
| LOGIN_P | CREATEUSER
{ {
$$ = makeDefElem("canlogin", (Node *)makeInteger(TRUE)); /* For backwards compatibility, synonym for SUPERUSER */
$$ = makeDefElem("superuser", (Node *)makeInteger(TRUE));
} }
| NOCREATEROLE | NOCREATEUSER
{ {
$$ = makeDefElem("createrole", (Node *)makeInteger(FALSE)); $$ = makeDefElem("superuser", (Node *)makeInteger(FALSE));
} }
| NOCREATEUSER | LOGIN_P
{ {
$$ = makeDefElem("createrole", (Node *)makeInteger(FALSE)); $$ = makeDefElem("canlogin", (Node *)makeInteger(TRUE));
} }
| NOLOGIN_P | NOLOGIN_P
{ {
...@@ -8013,6 +8022,7 @@ unreserved_keyword: ...@@ -8013,6 +8022,7 @@ unreserved_keyword:
| NOCREATEROLE | NOCREATEROLE
| NOCREATEUSER | NOCREATEUSER
| NOLOGIN_P | NOLOGIN_P
| NOSUPERUSER
| NOTHING | NOTHING
| NOTIFY | NOTIFY
| NOWAIT | NOWAIT
...@@ -8068,6 +8078,7 @@ unreserved_keyword: ...@@ -8068,6 +8078,7 @@ unreserved_keyword:
| STDIN | STDIN
| STDOUT | STDOUT
| STORAGE | STORAGE
| SUPERUSER_P
| SYSID | SYSID
| SYSTEM_P | SYSTEM_P
| STRICT_P | STRICT_P
......
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/parser/keywords.c,v 1.161 2005/06/28 19:51:22 tgl Exp $ * $PostgreSQL: pgsql/src/backend/parser/keywords.c,v 1.162 2005/06/29 20:34:14 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -221,6 +221,7 @@ static const ScanKeyword ScanKeywords[] = { ...@@ -221,6 +221,7 @@ static const ScanKeyword ScanKeywords[] = {
{"nocreateuser", NOCREATEUSER}, {"nocreateuser", NOCREATEUSER},
{"nologin", NOLOGIN_P}, {"nologin", NOLOGIN_P},
{"none", NONE}, {"none", NONE},
{"nosuperuser", NOSUPERUSER},
{"not", NOT}, {"not", NOT},
{"nothing", NOTHING}, {"nothing", NOTHING},
{"notify", NOTIFY}, {"notify", NOTIFY},
...@@ -308,6 +309,7 @@ static const ScanKeyword ScanKeywords[] = { ...@@ -308,6 +309,7 @@ static const ScanKeyword ScanKeywords[] = {
{"storage", STORAGE}, {"storage", STORAGE},
{"strict", STRICT_P}, {"strict", STRICT_P},
{"substring", SUBSTRING}, {"substring", SUBSTRING},
{"superuser", SUPERUSER_P},
{"symmetric", SYMMETRIC}, {"symmetric", SYMMETRIC},
{"sysid", SYSID}, {"sysid", SYSID},
{"system", SYSTEM_P}, {"system", SYSTEM_P},
......
This diff is collapsed.
...@@ -23,7 +23,7 @@ ...@@ -23,7 +23,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/utils/init/flatfiles.c,v 1.10 2005/06/28 22:16:45 tgl Exp $ * $PostgreSQL: pgsql/src/backend/utils/init/flatfiles.c,v 1.11 2005/06/29 20:34:15 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -295,7 +295,7 @@ write_database_file(Relation drel) ...@@ -295,7 +295,7 @@ write_database_file(Relation drel)
* "rolename" "password" "validuntil" "memberof" "memberof" ... * "rolename" "password" "validuntil" "memberof" "memberof" ...
* Only roles that are marked rolcanlogin are entered into the auth file. * Only roles that are marked rolcanlogin are entered into the auth file.
* Each role's line lists all the roles (groups) of which it is directly * Each role's line lists all the roles (groups) of which it is directly
* or indirectly a member. * or indirectly a member, except for itself.
* *
* The postmaster expects the file to be sorted by rolename. There is not * The postmaster expects the file to be sorted by rolename. There is not
* any special ordering of the membership lists. * any special ordering of the membership lists.
...@@ -538,28 +538,31 @@ write_auth_file(Relation rel_authid, Relation rel_authmem) ...@@ -538,28 +538,31 @@ write_auth_file(Relation rel_authid, Relation rel_authmem)
qsort(auth_info, total_roles, sizeof(auth_entry), oid_compar); qsort(auth_info, total_roles, sizeof(auth_entry), oid_compar);
qsort(authmem_info, total_mem, sizeof(authmem_entry), mem_compar); qsort(authmem_info, total_mem, sizeof(authmem_entry), mem_compar);
/* /*
* For each role, find what it belongs to. We can skip this for * For each role, find what it belongs to.
* non-login roles.
*/ */
for (curr_role = 0; curr_role < total_roles; curr_role++) for (curr_role = 0; curr_role < total_roles; curr_role++)
{ {
List *roles_list = NIL; List *roles_list;
List *roles_names_list = NIL; List *roles_names_list = NIL;
List *roles_list_hunt;
ListCell *mem; ListCell *mem;
/* We can skip this for non-login roles */
if (!auth_info[curr_role].rolcanlogin) if (!auth_info[curr_role].rolcanlogin)
continue; continue;
roles_list_hunt = list_make1_oid(auth_info[curr_role].roleid); /*
while (roles_list_hunt) * This search algorithm is the same as in is_member_of_role;
* we are just working with a different input data structure.
*/
roles_list = list_make1_oid(auth_info[curr_role].roleid);
foreach(mem, roles_list)
{ {
authmem_entry key; authmem_entry key;
authmem_entry *found_mem; authmem_entry *found_mem;
int first_found, last_found, curr_mem; int first_found, last_found, i;
key.memberid = linitial_oid(roles_list_hunt); key.memberid = lfirst_oid(mem);
roles_list_hunt = list_delete_first(roles_list_hunt);
found_mem = bsearch(&key, authmem_info, total_mem, found_mem = bsearch(&key, authmem_info, total_mem,
sizeof(authmem_entry), mem_compar); sizeof(authmem_entry), mem_compar);
if (!found_mem) if (!found_mem)
...@@ -577,26 +580,25 @@ write_auth_file(Relation rel_authid, Relation rel_authmem) ...@@ -577,26 +580,25 @@ write_auth_file(Relation rel_authid, Relation rel_authmem)
mem_compar(&key, &authmem_info[last_found + 1]) == 0) mem_compar(&key, &authmem_info[last_found + 1]) == 0)
last_found++; last_found++;
/* /*
* Now add all the new roles to roles_list, as well * Now add all the new roles to roles_list.
* as to our list of what remains to be searched.
*/ */
for (curr_mem = first_found; curr_mem <= last_found; curr_mem++) for (i = first_found; i <= last_found; i++)
{ {
Oid rolid = authmem_info[curr_mem].roleid; Oid rolid = authmem_info[i].roleid;
if (!list_member_oid(roles_list, rolid)) if (!list_member_oid(roles_list, rolid))
{
roles_list = lappend_oid(roles_list, rolid); roles_list = lappend_oid(roles_list, rolid);
roles_list_hunt = lappend_oid(roles_list_hunt, rolid);
}
} }
} }
/* /*
* Convert list of role Oids to list of role names. * Convert list of role Oids to list of role names.
* We must do this before re-sorting auth_info. * We must do this before re-sorting auth_info.
*
* We skip the first list element (curr_role itself) since there
* is no point in writing that a role is a member of itself.
*/ */
foreach(mem, roles_list) for_each_cell(mem, lnext(list_head(roles_list)))
{ {
auth_entry key_auth; auth_entry key_auth;
auth_entry *found_role; auth_entry *found_role;
...@@ -604,10 +606,12 @@ write_auth_file(Relation rel_authid, Relation rel_authmem) ...@@ -604,10 +606,12 @@ write_auth_file(Relation rel_authid, Relation rel_authmem)
key_auth.roleid = lfirst_oid(mem); key_auth.roleid = lfirst_oid(mem);
found_role = bsearch(&key_auth, auth_info, total_roles, found_role = bsearch(&key_auth, auth_info, total_roles,
sizeof(auth_entry), oid_compar); sizeof(auth_entry), oid_compar);
roles_names_list = lappend(roles_names_list, if (found_role) /* paranoia */
found_role->rolname); roles_names_list = lappend(roles_names_list,
found_role->rolname);
} }
auth_info[curr_role].member_of = roles_names_list; auth_info[curr_role].member_of = roles_names_list;
list_free(roles_list);
} }
} }
......
...@@ -7,7 +7,7 @@ ...@@ -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.79 2005/06/28 19:51:25 tgl Exp $ * $PostgreSQL: pgsql/src/include/utils/acl.h,v 1.80 2005/06/29 20:34:15 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, ...@@ -210,6 +210,7 @@ extern AclMode aclmask(const Acl *acl, Oid roleid, Oid ownerId,
AclMode mask, AclMaskHow how); AclMode mask, AclMaskHow how);
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 void initialize_acl(void); extern void initialize_acl(void);
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment