diff options
Diffstat (limited to 'src/backend/commands')
-rw-r--r-- | src/backend/commands/user.c | 29 | ||||
-rw-r--r-- | src/backend/commands/variable.c | 142 |
2 files changed, 164 insertions, 7 deletions
diff --git a/src/backend/commands/user.c b/src/backend/commands/user.c index 4a46343d5d8..5f8eeae30df 100644 --- a/src/backend/commands/user.c +++ b/src/backend/commands/user.c @@ -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 */ diff --git a/src/backend/commands/variable.c b/src/backend/commands/variable.c index 494ab6b491e..9254d57e345 100644 --- a/src/backend/commands/variable.c +++ b/src/backend/commands/variable.c @@ -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; +} |