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 @@
*
*
* 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)
if (is_member_of_role(GetUserId(), datdba))
{
/* creating database for self: can be superuser or createdb */
if (!superuser() && !have_createdb_privilege())
/* creating database for self: createdb is required */
if (!have_createdb_privilege())
ereport(ERROR,
(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
errmsg("permission denied to create database")));
......@@ -759,7 +759,7 @@ RenameDatabase(const char *oldname, const char *newname)
oldname);
/* must have createdb rights */
if (!superuser() && !have_createdb_privilege())
if (!have_createdb_privilege())
ereport(ERROR,
(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
errmsg("permission denied to rename database")));
......@@ -1044,6 +1044,10 @@ have_createdb_privilege(void)
bool result = false;
HeapTuple utup;
/* Superusers can always do everything */
if (superuser())
return true;
utup = SearchSysCache(AUTHOID,
ObjectIdGetDatum(GetUserId()),
0, 0, 0);
......
This diff is collapsed.
......@@ -11,7 +11,7 @@
*
*
* 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
* AUTHOR DATE MAJOR EVENT
......@@ -376,7 +376,7 @@ static void doNegateFloat(Value *v);
MATCH MAXVALUE MINUTE_P MINVALUE MODE MONTH_P MOVE
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
OBJECT_P OF OFF OFFSET OIDS OLD ON ONLY OPERATOR OPTION OR
......@@ -395,7 +395,7 @@ static void doNegateFloat(Value *v);
SAVEPOINT SCHEMA SCROLL SECOND_P SECURITY SELECT SEQUENCE
SERIALIZABLE SESSION SESSION_USER SET SETOF SHARE
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
TABLE TABLESPACE TEMP TEMPLATE TEMPORARY THEN TIME TIMESTAMP
......@@ -622,6 +622,14 @@ OptRoleElem:
{
$$ = makeDefElem("sysid", (Node *)makeInteger($2));
}
| SUPERUSER_P
{
$$ = makeDefElem("superuser", (Node *)makeInteger(TRUE));
}
| NOSUPERUSER
{
$$ = makeDefElem("superuser", (Node *)makeInteger(FALSE));
}
| CREATEDB
{
$$ = makeDefElem("createdb", (Node *)makeInteger(TRUE));
......@@ -634,21 +642,22 @@ OptRoleElem:
{
$$ = 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
{
......@@ -8013,6 +8022,7 @@ unreserved_keyword:
| NOCREATEROLE
| NOCREATEUSER
| NOLOGIN_P
| NOSUPERUSER
| NOTHING
| NOTIFY
| NOWAIT
......@@ -8068,6 +8078,7 @@ unreserved_keyword:
| STDIN
| STDOUT
| STORAGE
| SUPERUSER_P
| SYSID
| SYSTEM_P
| STRICT_P
......
......@@ -8,7 +8,7 @@
*
*
* 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[] = {
{"nocreateuser", NOCREATEUSER},
{"nologin", NOLOGIN_P},
{"none", NONE},
{"nosuperuser", NOSUPERUSER},
{"not", NOT},
{"nothing", NOTHING},
{"notify", NOTIFY},
......@@ -308,6 +309,7 @@ static const ScanKeyword ScanKeywords[] = {
{"storage", STORAGE},
{"strict", STRICT_P},
{"substring", SUBSTRING},
{"superuser", SUPERUSER_P},
{"symmetric", SYMMETRIC},
{"sysid", SYSID},
{"system", SYSTEM_P},
......
This diff is collapsed.
......@@ -23,7 +23,7 @@
* Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group
* 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)
* "rolename" "password" "validuntil" "memberof" "memberof" ...
* 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
* or indirectly a member.
* or indirectly a member, except for itself.
*
* The postmaster expects the file to be sorted by rolename. There is not
* any special ordering of the membership lists.
......@@ -538,28 +538,31 @@ write_auth_file(Relation rel_authid, Relation rel_authmem)
qsort(auth_info, total_roles, sizeof(auth_entry), oid_compar);
qsort(authmem_info, total_mem, sizeof(authmem_entry), mem_compar);
/*
* For each role, find what it belongs to. We can skip this for
* non-login roles.
* For each role, find what it belongs to.
*/
for (curr_role = 0; curr_role < total_roles; curr_role++)
{
List *roles_list = NIL;
List *roles_list;
List *roles_names_list = NIL;
List *roles_list_hunt;
ListCell *mem;
/* We can skip this for non-login roles */
if (!auth_info[curr_role].rolcanlogin)
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 *found_mem;
int first_found, last_found, curr_mem;
int first_found, last_found, i;
key.memberid = linitial_oid(roles_list_hunt);
roles_list_hunt = list_delete_first(roles_list_hunt);
key.memberid = lfirst_oid(mem);
found_mem = bsearch(&key, authmem_info, total_mem,
sizeof(authmem_entry), mem_compar);
if (!found_mem)
......@@ -577,26 +580,25 @@ write_auth_file(Relation rel_authid, Relation rel_authmem)
mem_compar(&key, &authmem_info[last_found + 1]) == 0)
last_found++;
/*
* Now add all the new roles to roles_list, as well
* as to our list of what remains to be searched.
* Now add all the new roles to roles_list.
*/
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))
{
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.
* 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 *found_role;
......@@ -604,10 +606,12 @@ write_auth_file(Relation rel_authid, Relation rel_authmem)
key_auth.roleid = lfirst_oid(mem);
found_role = bsearch(&key_auth, auth_info, total_roles,
sizeof(auth_entry), oid_compar);
if (found_role) /* paranoia */
roles_names_list = lappend(roles_names_list,
found_role->rolname);
}
auth_info[curr_role].member_of = roles_names_list;
list_free(roles_list);
}
}
......
......@@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group
* 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
* 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);
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);
......
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