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:
Tom Lane 2005-07-25 22:12:34 +00:00
parent f5df006a04
commit e5d6b91220
17 changed files with 533 additions and 97 deletions

View File

@ -1,5 +1,5 @@
<!--
$PostgreSQL: pgsql/doc/src/sgml/func.sgml,v 1.269 2005/07/22 21:16:14 momjian Exp $
$PostgreSQL: pgsql/doc/src/sgml/func.sgml,v 1.270 2005/07/25 22:12:30 tgl Exp $
PostgreSQL documentation
-->
@ -8266,7 +8266,9 @@ select current_date + s.a as dates from generate_series(0,14,7) as s(a);
with <xref linkend="sql-set-session-authorization" endterm="sql-set-session-authorization-title">.
The <function>current_user</function> is the user identifier
that is applicable for permission checking. Normally, it is equal
to the session user, but it changes during the execution of
to the session user, but it can be changed with
<xref linkend="sql-set-role" endterm="sql-set-role-title">.
It also changes during the execution of
functions with the attribute <literal>SECURITY DEFINER</literal>.
In Unix parlance, the session user is the <quote>real user</quote> and
the current user is the <quote>effective user</quote>.

View File

@ -1,5 +1,5 @@
<!--
$PostgreSQL: pgsql/doc/src/sgml/ref/allfiles.sgml,v 1.63 2005/06/17 22:32:42 tgl Exp $
$PostgreSQL: pgsql/doc/src/sgml/ref/allfiles.sgml,v 1.64 2005/07/25 22:12:31 tgl Exp $
PostgreSQL documentation
Complete list of usable sgml source files in this directory.
-->
@ -102,6 +102,7 @@ Complete list of usable sgml source files in this directory.
<!entity selectInto system "select_into.sgml">
<!entity set system "set.sgml">
<!entity setConstraints system "set_constraints.sgml">
<!entity setRole system "set_role.sgml">
<!entity setSessionAuth system "set_session_auth.sgml">
<!entity setTransaction system "set_transaction.sgml">
<!entity show system "show.sgml">

View File

@ -1,5 +1,5 @@
<!--
$PostgreSQL: pgsql/doc/src/sgml/ref/pg_dump.sgml,v 1.79 2005/07/10 15:08:52 momjian Exp $
$PostgreSQL: pgsql/doc/src/sgml/ref/pg_dump.sgml,v 1.80 2005/07/25 22:12:31 tgl Exp $
PostgreSQL documentation
-->
@ -474,8 +474,8 @@ PostgreSQL documentation
<term><option>--use-set-session-authorization</></term>
<listitem>
<para>
Output SQL standard SET SESSION AUTHORIZATION commands instead
of OWNER TO commands. This makes the dump more standards compatible,
Output SQL standard SET SESSION AUTHORIZATION commands instead of
ALTER OWNER commands. This makes the dump more standards compatible,
but depending on the history of the objects in the dump, may not
restore properly.
</para>

View File

@ -1,5 +1,5 @@
<!--
$PostgreSQL: pgsql/doc/src/sgml/ref/pg_dumpall.sgml,v 1.51 2005/06/21 20:45:43 tgl Exp $
$PostgreSQL: pgsql/doc/src/sgml/ref/pg_dumpall.sgml,v 1.52 2005/07/25 22:12:31 tgl Exp $
PostgreSQL documentation
-->
@ -277,8 +277,8 @@ PostgreSQL documentation
<term><option>--use-set-session-authorization</></term>
<listitem>
<para>
Output SQL standard SET SESSION AUTHORIZATION commands instead
of OWNER TO commands. This makes the dump more standards compatible,
Output SQL standard SET SESSION AUTHORIZATION commands instead of
ALTER OWNER commands. This makes the dump more standards compatible,
but depending on the history of the objects in the dump, may not
restore properly.
</para>

View File

@ -1,4 +1,4 @@
<!-- $PostgreSQL: pgsql/doc/src/sgml/ref/pg_restore.sgml,v 1.53 2005/06/21 20:45:43 tgl Exp $ -->
<!-- $PostgreSQL: pgsql/doc/src/sgml/ref/pg_restore.sgml,v 1.54 2005/07/25 22:12:31 tgl Exp $ -->
<refentry id="APP-PGRESTORE">
<refmeta>
@ -361,8 +361,8 @@
<term><option>--use-set-session-authorization</option></term>
<listitem>
<para>
Output SQL standard SET SESSION AUTHORIZATION commands instead
of OWNER TO commands. This makes the dump more standards compatible,
Output SQL standard SET SESSION AUTHORIZATION commands instead of
ALTER OWNER commands. This makes the dump more standards compatible,
but depending on the history of the objects in the dump, may not
restore properly.
</para>

View File

@ -0,0 +1,116 @@
<!-- $PostgreSQL: pgsql/doc/src/sgml/ref/set_role.sgml,v 1.1 2005/07/25 22:12:31 tgl Exp $ -->
<refentry id="SQL-SET-ROLE">
<refmeta>
<refentrytitle id="sql-set-role-title">SET ROLE</refentrytitle>
<refmiscinfo>SQL - Language Statements</refmiscinfo>
</refmeta>
<refnamediv>
<refname>SET ROLE</refname>
<refpurpose>set the current user identifier of the current session</refpurpose>
</refnamediv>
<indexterm zone="sql-set-role">
<primary>SET ROLE</primary>
</indexterm>
<refsynopsisdiv>
<synopsis>
SET [ SESSION | LOCAL ] ROLE <replaceable class="parameter">rolename</replaceable>
SET [ SESSION | LOCAL ] ROLE NONE
RESET ROLE
</synopsis>
</refsynopsisdiv>
<refsect1>
<title>Description</title>
<para>
This command sets the current user
identifier of the current SQL-session context to be <replaceable
class="parameter">rolename</replaceable>. The role name may be
written as either an identifier or a string literal. Using this
command, it is possible to either add privileges or restrict one's
privileges.
</para>
<para>
The specified <replaceable class="parameter">rolename</replaceable>
must be a role that the current session user is a member of.
(If the session user is a superuser, any role can be selected.)
</para>
<para>
The <literal>SESSION</> and <literal>LOCAL</> modifiers act the same
as for the regular <xref linkend="SQL-SET" endterm="SQL-SET-title">
command.
</para>
<para>
The <literal>NONE</> and <literal>RESET</> forms reset the current
user identifier to be the current session user identifier.
These forms may be executed by any user.
</para>
</refsect1>
<refsect1>
<title>Examples</title>
<programlisting>
SELECT SESSION_USER, CURRENT_USER;
session_user | current_user
--------------+--------------
peter | peter
SET ROLE 'paul';
SELECT SESSION_USER, CURRENT_USER;
session_user | current_user
--------------+--------------
peter | paul
</programlisting>
</refsect1>
<refsect1>
<title>Compatibility</title>
<para>
<productname>PostgreSQL</productname>
allows identifier syntax (<literal>"rolename"</literal>), while
the SQL standard requires the role name to be written as a string
literal. SQL does not allow this command during a transaction;
<productname>PostgreSQL</productname> does not make this
restriction because there is no reason to.
The <literal>SESSION</> and <literal>LOCAL</> modifiers are a
<productname>PostgreSQL</productname> extension, as is the
<literal>RESET</> syntax.
</para>
</refsect1>
<refsect1>
<title>See Also</title>
<simplelist type="inline">
<member><xref linkend="sql-set-session-authorization" endterm="sql-set-session-authorization-title"></member>
</simplelist>
</refsect1>
</refentry>
<!-- Keep this comment at the end of the file
Local variables:
mode:sgml
sgml-omittag:nil
sgml-shorttag:t
sgml-minimize-attributes:nil
sgml-always-quote-attributes:t
sgml-indent-step:1
sgml-indent-data:t
sgml-parent-document:nil
sgml-default-dtd-file:"../reference.ced"
sgml-exposed-tags:nil
sgml-local-catalogs:("/usr/lib/sgml/catalog")
sgml-local-ecat-files:nil
End:
-->

View File

@ -1,4 +1,4 @@
<!-- $PostgreSQL: pgsql/doc/src/sgml/ref/set_session_auth.sgml,v 1.12 2003/11/29 19:51:39 pgsql Exp $ -->
<!-- $PostgreSQL: pgsql/doc/src/sgml/ref/set_session_auth.sgml,v 1.13 2005/07/25 22:12:31 tgl Exp $ -->
<refentry id="SQL-SET-SESSION-AUTHORIZATION">
<refmeta>
<refentrytitle id="sql-set-session-authorization-title">SET SESSION AUTHORIZATION</refentrytitle>
@ -31,7 +31,7 @@ RESET SESSION AUTHORIZATION
class="parameter">username</replaceable>. The user name may be
written as either an identifier or a string literal. Using this
command, it is possible, for example, to temporarily become an
unprivileged user and later switch back to become a superuser.
unprivileged user and later switch back to being a superuser.
</para>
<para>
@ -39,8 +39,9 @@ RESET SESSION AUTHORIZATION
authenticated) user name provided by the client. The current user
identifier is normally equal to the session user identifier, but
may change temporarily in the context of <quote>setuid</quote>
functions and similar mechanisms. The current user identifier is
relevant for permission checking.
functions and similar mechanisms; it can also be changed by
<xref linkend="sql-set-role" endterm="sql-set-role-title">.
The current user identifier is relevant for permission checking.
</para>
<para>
@ -93,10 +94,24 @@ SELECT SESSION_USER, CURRENT_USER;
allows identifier syntax (<literal>"username"</literal>), which SQL
does not. SQL does not allow this command during a transaction;
<productname>PostgreSQL</productname> does not make this
restriction because there is no reason to. The privileges
necessary to execute this command are left implementation-defined
by the standard.
restriction because there is no reason to.
The <literal>SESSION</> and <literal>LOCAL</> modifiers are a
<productname>PostgreSQL</productname> extension, as is the
<literal>RESET</> syntax.
</para>
<para>
The privileges necessary to execute this command are left
implementation-defined by the standard.
</para>
</refsect1>
<refsect1>
<title>See Also</title>
<simplelist type="inline">
<member><xref linkend="sql-set-role" endterm="sql-set-role-title"></member>
</simplelist>
</refsect1>
</refentry>

View File

@ -1,5 +1,5 @@
<!-- reference.sgml
$PostgreSQL: pgsql/doc/src/sgml/reference.sgml,v 1.53 2005/06/17 22:32:42 tgl Exp $
$PostgreSQL: pgsql/doc/src/sgml/reference.sgml,v 1.54 2005/07/25 22:12:30 tgl Exp $
PostgreSQL Reference Manual
-->
@ -134,6 +134,7 @@ PostgreSQL Reference Manual
&selectInto;
&set;
&setConstraints;
&setRole;
&setSessionAuth;
&setTransaction;
&show;

View File

@ -10,7 +10,7 @@
*
*
* IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/access/transam/xact.c,v 1.210 2005/07/13 22:46:09 tgl Exp $
* $PostgreSQL: pgsql/src/backend/access/transam/xact.c,v 1.211 2005/07/25 22:12:31 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@ -1865,7 +1865,7 @@ AbortTransaction(void)
/*
* Reset user id which might have been changed transiently. We cannot
* use s->currentUser, but must get the session userid from
* use s->currentUser, but must get the session outer-level userid from
* miscinit.c.
*
* (Note: it is not necessary to restore session authorization here
@ -1874,7 +1874,7 @@ AbortTransaction(void)
* DEFINER function could send control here with the wrong current
* userid.)
*/
SetUserId(GetSessionUserId());
SetUserId(GetOuterUserId());
/*
* do abort processing

View File

@ -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
*/

View File

@ -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;
}

View File

@ -11,7 +11,7 @@
*
*
* IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/parser/gram.y,v 2.501 2005/06/29 20:34:13 tgl Exp $
* $PostgreSQL: pgsql/src/backend/parser/gram.y,v 2.502 2005/07/25 22:12:32 tgl Exp $
*
* HISTORY
* AUTHOR DATE MAJOR EVENT
@ -1004,6 +1004,13 @@ set_rest: var_name TO var_list_or_default
n->args = list_make1(makeStringConst($2, NULL));
$$ = n;
}
| ROLE ColId_or_Sconst
{
VariableSetStmt *n = makeNode(VariableSetStmt);
n->name = "role";
n->args = list_make1(makeStringConst($2, NULL));
$$ = n;
}
| SESSION AUTHORIZATION ColId_or_Sconst
{
VariableSetStmt *n = makeNode(VariableSetStmt);

View File

@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/utils/init/miscinit.c,v 1.146 2005/07/14 05:13:41 tgl Exp $
* $PostgreSQL: pgsql/src/backend/utils/init/miscinit.c,v 1.147 2005/07/25 22:12:33 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@ -270,24 +270,44 @@ make_absolute_path(const char *path)
/* ----------------------------------------------------------------
* Role ID things
* User ID state
*
* The authenticated user is determined at connection start and never
* changes. The session user can be changed only by SET SESSION
* AUTHORIZATION. The current user may change when "setuid" functions
* are implemented. Conceptually there is a stack, whose bottom
* is the session user. You are yourself responsible to save and
* restore the current user id if you need to change it.
* We have to track several different values associated with the concept
* of "user ID".
*
* AuthenticatedUserId is determined at connection start and never changes.
*
* SessionUserId is initially the same as AuthenticatedUserId, but can be
* changed by SET SESSION AUTHORIZATION (if AuthenticatedUserIsSuperuser).
* This is the ID reported by the SESSION_USER SQL function.
*
* OuterUserId is the current user ID in effect at the "outer level" (outside
* any transaction or function). This is initially the same as SessionUserId,
* but can be changed by SET ROLE to any role that SessionUserId is a
* member of. We store this mainly so that AbortTransaction knows what to
* reset CurrentUserId to.
*
* CurrentUserId is the current effective user ID; this is the one to use
* for all normal permissions-checking purposes. At outer level this will
* be the same as OuterUserId, but it changes during calls to SECURITY
* DEFINER functions, as well as locally in some specialized commands.
* ----------------------------------------------------------------
*/
static Oid AuthenticatedUserId = InvalidOid;
static Oid SessionUserId = InvalidOid;
static Oid OuterUserId = InvalidOid;
static Oid CurrentUserId = InvalidOid;
/* We also have to remember the superuser state of some of these levels */
static bool AuthenticatedUserIsSuperuser = false;
static bool SessionUserIsSuperuser = false;
/* We also remember if a SET ROLE is currently active */
static bool SetRoleIsActive = false;
/*
* This function is relevant for all privilege checks.
* GetUserId/SetUserId - get/set the current effective user ID.
*/
Oid
GetUserId(void)
@ -298,15 +318,37 @@ GetUserId(void)
void
SetUserId(Oid roleid)
SetUserId(Oid userid)
{
AssertArg(OidIsValid(roleid));
CurrentUserId = roleid;
AssertArg(OidIsValid(userid));
CurrentUserId = userid;
}
/*
* This value is only relevant for informational purposes.
* GetOuterUserId/SetOuterUserId - get/set the outer-level user ID.
*/
Oid
GetOuterUserId(void)
{
AssertState(OidIsValid(OuterUserId));
return OuterUserId;
}
static void
SetOuterUserId(Oid userid)
{
AssertArg(OidIsValid(userid));
OuterUserId = userid;
/* We force the effective user ID to match, too */
CurrentUserId = userid;
}
/*
* GetSessionUserId/SetSessionUserId - get/set the session user ID.
*/
Oid
GetSessionUserId(void)
@ -316,17 +358,23 @@ GetSessionUserId(void)
}
void
SetSessionUserId(Oid roleid)
static void
SetSessionUserId(Oid userid, bool is_superuser)
{
AssertArg(OidIsValid(roleid));
SessionUserId = roleid;
/* Current user defaults to session user. */
if (!OidIsValid(CurrentUserId))
CurrentUserId = roleid;
AssertArg(OidIsValid(userid));
SessionUserId = userid;
SessionUserIsSuperuser = is_superuser;
SetRoleIsActive = false;
/* We force the effective user IDs to match, too */
OuterUserId = userid;
CurrentUserId = userid;
}
/*
* Initialize user identity during normal backend startup
*/
void
InitializeSessionUserId(const char *rolename)
{
@ -364,7 +412,8 @@ InitializeSessionUserId(const char *rolename)
AuthenticatedUserId = roleid;
AuthenticatedUserIsSuperuser = rform->rolsuper;
SetSessionUserId(roleid); /* sets CurrentUserId too */
/* This sets OuterUserId/CurrentUserId too */
SetSessionUserId(roleid, AuthenticatedUserIsSuperuser);
/* Record username and superuser status as GUC settings too */
SetConfigOption("session_authorization", rolename,
@ -391,6 +440,9 @@ InitializeSessionUserId(const char *rolename)
}
/*
* Initialize user identity during special backend startup
*/
void
InitializeSessionUserIdStandalone(void)
{
@ -403,7 +455,7 @@ InitializeSessionUserIdStandalone(void)
AuthenticatedUserId = BOOTSTRAP_SUPERUSERID;
AuthenticatedUserIsSuperuser = true;
SetSessionUserId(BOOTSTRAP_SUPERUSERID);
SetSessionUserId(BOOTSTRAP_SUPERUSERID, true);
}
@ -414,21 +466,82 @@ InitializeSessionUserIdStandalone(void)
* that in case of multiple SETs in a single session, the original userid's
* superuserness is what matters. But we set the GUC variable is_superuser
* to indicate whether the *current* session userid is a superuser.
*
* Note: this is not an especially clean place to do the permission check.
* It's OK because the check does not require catalog access and can't
* fail during an end-of-transaction GUC reversion, but we may someday
* have to push it up into assign_session_authorization.
*/
void
SetSessionAuthorization(Oid roleid, bool is_superuser)
SetSessionAuthorization(Oid userid, bool is_superuser)
{
/* Must have authenticated already, else can't make permission check */
AssertState(OidIsValid(AuthenticatedUserId));
if (roleid != AuthenticatedUserId &&
if (userid != AuthenticatedUserId &&
!AuthenticatedUserIsSuperuser)
ereport(ERROR,
(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
errmsg("permission denied to set session authorization")));
SetSessionUserId(roleid);
SetUserId(roleid);
SetSessionUserId(userid, is_superuser);
SetConfigOption("is_superuser",
is_superuser ? "on" : "off",
PGC_INTERNAL, PGC_S_OVERRIDE);
}
/*
* Report current role id
* This follows the semantics of SET ROLE, ie return the outer-level ID
* not the current effective ID, and return InvalidOid when the setting
* is logically SET ROLE NONE.
*/
Oid
GetCurrentRoleId(void)
{
if (SetRoleIsActive)
return OuterUserId;
else
return InvalidOid;
}
/*
* Change Role ID while running (SET ROLE)
*
* If roleid is InvalidOid, we are doing SET ROLE NONE: revert to the
* session user authorization. In this case the is_superuser argument
* is ignored.
*
* When roleid is not InvalidOid, the caller must have checked whether
* the session user has permission to become that role. (We cannot check
* here because this routine must be able to execute in a failed transaction
* to restore a prior value of the ROLE GUC variable.)
*/
void
SetCurrentRoleId(Oid roleid, bool is_superuser)
{
/*
* Get correct info if it's SET ROLE NONE
*
* If SessionUserId hasn't been set yet, just do nothing --- the eventual
* SetSessionUserId call will fix everything. This is needed since we
* will get called during GUC initialization.
*/
if (!OidIsValid(roleid))
{
if (!OidIsValid(SessionUserId))
return;
roleid = SessionUserId;
is_superuser = SessionUserIsSuperuser;
SetRoleIsActive = false;
}
else
SetRoleIsActive = true;
SetOuterUserId(roleid);
SetConfigOption("is_superuser",
is_superuser ? "on" : "off",

View File

@ -18,7 +18,7 @@
## can be ignored
INTENTIONALLY_NOT_INCLUDED="autocommit debug_deadlocks exit_on_error \
is_superuser lc_collate lc_ctype lc_messages lc_monetary lc_numeric lc_time \
pre_auth_delay seed server_encoding server_version session_authorization \
pre_auth_delay role seed server_encoding server_version session_authorization \
trace_lock_oidmin trace_lock_table trace_locks trace_lwlocks trace_notify \
trace_userlocks transaction_isolation transaction_read_only \
zero_damaged_pages"

View File

@ -10,7 +10,7 @@
* Written by Peter Eisentraut <peter_e@gmx.net>.
*
* IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/utils/misc/guc.c,v 1.277 2005/07/23 21:05:47 tgl Exp $
* $PostgreSQL: pgsql/src/backend/utils/misc/guc.c,v 1.278 2005/07/25 22:12:33 tgl Exp $
*
*--------------------------------------------------------------------
*/
@ -195,7 +195,8 @@ static int block_size;
static bool integer_datetimes;
static bool standard_compliant_strings;
/* should be static, but commands/variable.c needs to get at it */
/* should be static, but commands/variable.c needs to get at these */
char *role_string;
char *session_authorization_string;
@ -1828,6 +1829,17 @@ static struct config_string ConfigureNamesString[] =
PG_VERSION, NULL, NULL
},
{
/* Not for general use --- used by SET ROLE */
{"role", PGC_USERSET, UNGROUPED,
gettext_noop("Sets the current role."),
NULL,
GUC_NO_SHOW_ALL | GUC_NO_RESET_ALL | GUC_NOT_IN_SAMPLE | GUC_DISALLOW_IN_FILE
},
&role_string,
"none", assign_role, show_role
},
{
/* Not for general use --- used by SET SESSION AUTHORIZATION */
{"session_authorization", PGC_USERSET, UNGROUPED,
@ -2048,8 +2060,6 @@ static bool guc_dirty; /* TRUE if need to do commit/abort work */
static bool reporting_enabled; /* TRUE to enable GUC_REPORT */
static char *guc_string_workspace; /* for avoiding memory leaks */
static int guc_var_compare(const void *a, const void *b);
static int guc_name_compare(const char *namea, const char *nameb);
@ -2576,8 +2586,6 @@ InitializeGUCOptions(void)
reporting_enabled = false;
guc_string_workspace = NULL;
/*
* Prevent any attempt to override the transaction modes from
* non-interactive sources.
@ -2976,13 +2984,6 @@ AtEOXact_GUC(bool isCommit, bool isSubXact)
if (!guc_dirty)
return;
/* Prevent memory leak if ereport during an assign_hook */
if (guc_string_workspace)
{
free(guc_string_workspace);
guc_string_workspace = NULL;
}
my_level = GetCurrentTransactionNestLevel();
Assert(isSubXact ? (my_level > 1) : (my_level == 1));
@ -3389,6 +3390,33 @@ parse_real(const char *value, double *result)
}
/*
* Call a GucStringAssignHook function, being careful to free the
* "newval" string if the hook ereports.
*
* This is split out of set_config_option just to avoid the "volatile"
* qualifiers that would otherwise have to be plastered all over.
*/
static const char *
call_string_assign_hook(GucStringAssignHook assign_hook,
char *newval, bool doit, GucSource source)
{
const char *result;
PG_TRY();
{
result = (*assign_hook) (newval, doit, source);
}
PG_CATCH();
{
free(newval);
PG_RE_THROW();
}
PG_END_TRY();
return result;
}
/*
* Sets option `name' to given value. The value should be a string
@ -3833,21 +3861,18 @@ set_config_option(const char *name, const char *value,
break;
}
/*
* Remember string in workspace, so that we can free it
* and avoid a permanent memory leak if hook ereports.
*/
if (guc_string_workspace)
free(guc_string_workspace);
guc_string_workspace = newval;
if (conf->assign_hook)
{
const char *hookresult;
hookresult = (*conf->assign_hook) (newval,
changeVal, source);
guc_string_workspace = NULL;
/*
* If the hook ereports, we have to make sure we free
* newval, else it will be a permanent memory leak.
*/
hookresult = call_string_assign_hook(conf->assign_hook,
newval,
changeVal,
source);
if (hookresult == NULL)
{
free(newval);
@ -3874,8 +3899,6 @@ set_config_option(const char *name, const char *value,
}
}
guc_string_workspace = NULL;
if (changeVal || makeDefault)
{
/* Save old value to support transaction abort */
@ -4305,8 +4328,7 @@ init_custom_variable(struct config_generic * gen,
}
void
DefineCustomBoolVariable(
const char *name,
DefineCustomBoolVariable(const char *name,
const char *short_desc,
const char *long_desc,
bool *valueAddr,
@ -4328,8 +4350,7 @@ DefineCustomBoolVariable(
}
void
DefineCustomIntVariable(
const char *name,
DefineCustomIntVariable(const char *name,
const char *short_desc,
const char *long_desc,
int *valueAddr,
@ -4355,8 +4376,7 @@ DefineCustomIntVariable(
}
void
DefineCustomRealVariable(
const char *name,
DefineCustomRealVariable(const char *name,
const char *short_desc,
const char *long_desc,
double *valueAddr,
@ -4382,8 +4402,7 @@ DefineCustomRealVariable(
}
void
DefineCustomStringVariable(
const char *name,
DefineCustomStringVariable(const char *name,
const char *short_desc,
const char *long_desc,
char **valueAddr,

View File

@ -5,7 +5,7 @@
* Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
* $PostgreSQL: pgsql/src/include/commands/variable.h,v 1.25 2004/12/31 22:03:28 pgsql Exp $
* $PostgreSQL: pgsql/src/include/commands/variable.h,v 1.26 2005/07/25 22:12:34 tgl Exp $
*/
#ifndef VARIABLE_H
#define VARIABLE_H
@ -26,6 +26,9 @@ extern bool assign_random_seed(double value,
extern const char *show_random_seed(void);
extern const char *assign_client_encoding(const char *value,
bool doit, GucSource source);
extern const char *assign_role(const char *value,
bool doit, GucSource source);
extern const char *show_role(void);
extern const char *assign_session_authorization(const char *value,
bool doit, GucSource source);
extern const char *show_session_authorization(void);

View File

@ -13,7 +13,7 @@
* Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
* $PostgreSQL: pgsql/src/include/miscadmin.h,v 1.177 2005/07/04 04:51:52 tgl Exp $
* $PostgreSQL: pgsql/src/include/miscadmin.h,v 1.178 2005/07/25 22:12:34 tgl Exp $
*
* NOTES
* some of the information in this file should be moved to other files.
@ -230,12 +230,14 @@ extern void SetDatabasePath(const char *path);
extern char *GetUserNameFromId(Oid roleid);
extern Oid GetUserId(void);
extern void SetUserId(Oid roleid);
extern void SetUserId(Oid userid);
extern Oid GetOuterUserId(void);
extern Oid GetSessionUserId(void);
extern void SetSessionUserId(Oid roleid);
extern void InitializeSessionUserId(const char *rolename);
extern void InitializeSessionUserIdStandalone(void);
extern void SetSessionAuthorization(Oid roleid, bool is_superuser);
extern void SetSessionAuthorization(Oid userid, bool is_superuser);
extern Oid GetCurrentRoleId(void);
extern void SetCurrentRoleId(Oid roleid, bool is_superuser);
extern void SetDataDir(const char *dir);
extern void ChangeToDataDir(void);