mirror of
https://github.com/postgres/postgres.git
synced 2025-11-09 06:21:09 +03:00
Add SET ROLE. This is a partial commit of Stephen Frost's recent patch;
I'm still working on the has_role function and information_schema changes.
This commit is contained in:
@@ -6,7 +6,7 @@
|
||||
* Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group
|
||||
* Portions Copyright (c) 1994, Regents of the University of California
|
||||
*
|
||||
* $PostgreSQL: pgsql/src/backend/commands/user.c,v 1.156 2005/07/07 20:39:58 tgl Exp $
|
||||
* $PostgreSQL: pgsql/src/backend/commands/user.c,v 1.157 2005/07/25 22:12:31 tgl Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@@ -227,7 +227,8 @@ CreateRole(CreateRoleStmt *stmt)
|
||||
errmsg("permission denied to create role")));
|
||||
}
|
||||
|
||||
if (strcmp(stmt->role, "public") == 0)
|
||||
if (strcmp(stmt->role, "public") == 0 ||
|
||||
strcmp(stmt->role, "none") == 0)
|
||||
ereport(ERROR,
|
||||
(errcode(ERRCODE_RESERVED_NAME),
|
||||
errmsg("role name \"%s\" is reserved",
|
||||
@@ -760,11 +761,15 @@ DropRole(DropRoleStmt *stmt)
|
||||
if (roleid == GetUserId())
|
||||
ereport(ERROR,
|
||||
(errcode(ERRCODE_OBJECT_IN_USE),
|
||||
errmsg("current role cannot be dropped")));
|
||||
errmsg("current user cannot be dropped")));
|
||||
if (roleid == GetOuterUserId())
|
||||
ereport(ERROR,
|
||||
(errcode(ERRCODE_OBJECT_IN_USE),
|
||||
errmsg("current user cannot be dropped")));
|
||||
if (roleid == GetSessionUserId())
|
||||
ereport(ERROR,
|
||||
(errcode(ERRCODE_OBJECT_IN_USE),
|
||||
errmsg("session role cannot be dropped")));
|
||||
errmsg("session user cannot be dropped")));
|
||||
|
||||
/*
|
||||
* For safety's sake, we allow createrole holders to drop ordinary
|
||||
@@ -893,7 +898,8 @@ RenameRole(const char *oldname, const char *newname)
|
||||
* XXX Client applications probably store the session user somewhere,
|
||||
* so renaming it could cause confusion. On the other hand, there may
|
||||
* not be an actual problem besides a little confusion, so think about
|
||||
* this and decide.
|
||||
* this and decide. Same for SET ROLE ... we don't restrict renaming
|
||||
* the current effective userid, though.
|
||||
*/
|
||||
|
||||
roleid = HeapTupleGetOid(oldtuple);
|
||||
@@ -901,7 +907,11 @@ RenameRole(const char *oldname, const char *newname)
|
||||
if (roleid == GetSessionUserId())
|
||||
ereport(ERROR,
|
||||
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
|
||||
errmsg("session role may not be renamed")));
|
||||
errmsg("session user may not be renamed")));
|
||||
if (roleid == GetOuterUserId())
|
||||
ereport(ERROR,
|
||||
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
|
||||
errmsg("current user may not be renamed")));
|
||||
|
||||
/* make sure the new name doesn't exist */
|
||||
if (SearchSysCacheExists(AUTHNAME,
|
||||
@@ -911,6 +921,13 @@ RenameRole(const char *oldname, const char *newname)
|
||||
(errcode(ERRCODE_DUPLICATE_OBJECT),
|
||||
errmsg("role \"%s\" already exists", newname)));
|
||||
|
||||
if (strcmp(newname, "public") == 0 ||
|
||||
strcmp(newname, "none") == 0)
|
||||
ereport(ERROR,
|
||||
(errcode(ERRCODE_RESERVED_NAME),
|
||||
errmsg("role name \"%s\" is reserved",
|
||||
newname)));
|
||||
|
||||
/*
|
||||
* createrole is enough privilege unless you want to mess with a superuser
|
||||
*/
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $PostgreSQL: pgsql/src/backend/commands/variable.c,v 1.111 2005/07/21 03:56:10 momjian Exp $
|
||||
* $PostgreSQL: pgsql/src/backend/commands/variable.c,v 1.112 2005/07/25 22:12:32 tgl Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@@ -24,6 +24,7 @@
|
||||
#include "miscadmin.h"
|
||||
#include "parser/scansup.h"
|
||||
#include "pgtime.h"
|
||||
#include "utils/acl.h"
|
||||
#include "utils/builtins.h"
|
||||
#include "utils/guc.h"
|
||||
#include "utils/syscache.h"
|
||||
@@ -684,3 +685,142 @@ show_session_authorization(void)
|
||||
|
||||
return endptr + 1;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* SET ROLE
|
||||
*
|
||||
* When resetting session auth after an error, we can't expect to do catalog
|
||||
* lookups. Hence, the stored form of the value must provide a numeric oid
|
||||
* that can be re-used directly. We implement this exactly like SET
|
||||
* SESSION AUTHORIZATION.
|
||||
*
|
||||
* The SQL spec requires "SET ROLE NONE" to unset the role, so we hardwire
|
||||
* a translation of "none" to InvalidOid.
|
||||
*/
|
||||
extern char *role_string; /* in guc.c */
|
||||
|
||||
const char *
|
||||
assign_role(const char *value, bool doit, GucSource source)
|
||||
{
|
||||
Oid roleid = InvalidOid;
|
||||
bool is_superuser = false;
|
||||
const char *actual_rolename = value;
|
||||
char *result;
|
||||
|
||||
if (strspn(value, "x") == NAMEDATALEN &&
|
||||
(value[NAMEDATALEN] == 'T' || value[NAMEDATALEN] == 'F'))
|
||||
{
|
||||
/* might be a saved userid string */
|
||||
Oid savedoid;
|
||||
char *endptr;
|
||||
|
||||
savedoid = (Oid) strtoul(value + NAMEDATALEN + 1, &endptr, 10);
|
||||
|
||||
if (endptr != value + NAMEDATALEN + 1 && *endptr == ',')
|
||||
{
|
||||
/* syntactically valid, so break out the data */
|
||||
roleid = savedoid;
|
||||
is_superuser = (value[NAMEDATALEN] == 'T');
|
||||
actual_rolename = endptr + 1;
|
||||
}
|
||||
}
|
||||
|
||||
if (roleid == InvalidOid &&
|
||||
strcmp(actual_rolename, "none") != 0)
|
||||
{
|
||||
/* not a saved ID, so look it up */
|
||||
HeapTuple roleTup;
|
||||
|
||||
if (!IsTransactionState())
|
||||
{
|
||||
/*
|
||||
* Can't do catalog lookups, so fail. The upshot of this is
|
||||
* that role cannot be set in postgresql.conf, which seems
|
||||
* like a good thing anyway.
|
||||
*/
|
||||
return NULL;
|
||||
}
|
||||
|
||||
roleTup = SearchSysCache(AUTHNAME,
|
||||
PointerGetDatum(value),
|
||||
0, 0, 0);
|
||||
if (!HeapTupleIsValid(roleTup))
|
||||
{
|
||||
if (source >= PGC_S_INTERACTIVE)
|
||||
ereport(ERROR,
|
||||
(errcode(ERRCODE_UNDEFINED_OBJECT),
|
||||
errmsg("role \"%s\" does not exist", value)));
|
||||
return NULL;
|
||||
}
|
||||
|
||||
roleid = HeapTupleGetOid(roleTup);
|
||||
is_superuser = ((Form_pg_authid) GETSTRUCT(roleTup))->rolsuper;
|
||||
|
||||
ReleaseSysCache(roleTup);
|
||||
|
||||
/*
|
||||
* Verify that session user is allowed to become this role
|
||||
*/
|
||||
if (!is_member_of_role(GetSessionUserId(), roleid))
|
||||
{
|
||||
if (source >= PGC_S_INTERACTIVE)
|
||||
ereport(ERROR,
|
||||
(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
|
||||
errmsg("permission denied to set role \"%s\"",
|
||||
value)));
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
if (doit)
|
||||
SetCurrentRoleId(roleid, is_superuser);
|
||||
|
||||
result = (char *) malloc(NAMEDATALEN + 32 + strlen(actual_rolename));
|
||||
if (!result)
|
||||
return NULL;
|
||||
|
||||
memset(result, 'x', NAMEDATALEN);
|
||||
|
||||
sprintf(result + NAMEDATALEN, "%c%u,%s",
|
||||
is_superuser ? 'T' : 'F',
|
||||
roleid,
|
||||
actual_rolename);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
const char *
|
||||
show_role(void)
|
||||
{
|
||||
/*
|
||||
* Extract the role name from the stored string; see
|
||||
* assign_role
|
||||
*/
|
||||
const char *value = role_string;
|
||||
Oid savedoid;
|
||||
char *endptr;
|
||||
|
||||
/* This special case only applies if no SET ROLE has been done */
|
||||
if (value == NULL || strcmp(value, "none") == 0)
|
||||
return "none";
|
||||
|
||||
Assert(strspn(value, "x") == NAMEDATALEN &&
|
||||
(value[NAMEDATALEN] == 'T' || value[NAMEDATALEN] == 'F'));
|
||||
|
||||
savedoid = (Oid) strtoul(value + NAMEDATALEN + 1, &endptr, 10);
|
||||
|
||||
Assert(endptr != value + NAMEDATALEN + 1 && *endptr == ',');
|
||||
|
||||
/*
|
||||
* Check that the stored string still matches the effective setting,
|
||||
* else return "none". This is a kluge to deal with the fact that
|
||||
* SET SESSION AUTHORIZATION logically resets SET ROLE to NONE, but
|
||||
* we cannot set the GUC role variable from assign_session_authorization
|
||||
* (because we haven't got enough info to call set_config_option).
|
||||
*/
|
||||
if (savedoid != GetCurrentRoleId())
|
||||
return "none";
|
||||
|
||||
return endptr + 1;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user