PostgreSQL Source Code  git master
usercontext.c
Go to the documentation of this file.
1 /*-------------------------------------------------------------------------
2  *
3  * usercontext.c
4  * Convenience functions for running code as a different database user.
5  *
6  * Portions Copyright (c) 1996-2024, PostgreSQL Global Development Group
7  * Portions Copyright (c) 1994, Regents of the University of California
8  *
9  *
10  * IDENTIFICATION
11  * src/backend/utils/init/usercontext.c
12  *
13  *-------------------------------------------------------------------------
14  */
15 #include "postgres.h"
16 
17 #include "miscadmin.h"
18 #include "utils/acl.h"
19 #include "utils/guc.h"
20 #include "utils/usercontext.h"
21 
22 /*
23  * Temporarily switch to a new user ID.
24  *
25  * If the current user doesn't have permission to SET ROLE to the new user,
26  * an ERROR occurs.
27  *
28  * If the new user doesn't have permission to SET ROLE to the current user,
29  * SECURITY_RESTRICTED_OPERATION is imposed and a new GUC nest level is
30  * created so that any settings changes can be rolled back.
31  */
32 void
34 {
35  /* Get the current user ID and security context. */
36  GetUserIdAndSecContext(&context->save_userid,
37  &context->save_sec_context);
38 
39  /* Check that we have sufficient privileges to assume the target role. */
40  if (!member_can_set_role(context->save_userid, userid))
41  ereport(ERROR,
42  (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
43  errmsg("role \"%s\" cannot SET ROLE to \"%s\"",
44  GetUserNameFromId(context->save_userid, false),
45  GetUserNameFromId(userid, false))));
46 
47  /*
48  * Try to prevent the user to which we're switching from assuming the
49  * privileges of the current user, unless they can SET ROLE to that user
50  * anyway.
51  */
52  if (member_can_set_role(userid, context->save_userid))
53  {
54  /*
55  * Each user can SET ROLE to the other, so there's no point in
56  * imposing any security restrictions. Just let the user do whatever
57  * they want.
58  */
59  SetUserIdAndSecContext(userid, context->save_sec_context);
60  context->save_nestlevel = -1;
61  }
62  else
63  {
64  int sec_context = context->save_sec_context;
65 
66  /*
67  * This user can SET ROLE to the target user, but not the other way
68  * around, so protect ourselves against the target user by setting
69  * SECURITY_RESTRICTED_OPERATION to prevent certain changes to the
70  * session state. Also set up a new GUC nest level, so that we can
71  * roll back any GUC changes that may be made by code running as the
72  * target user, inasmuch as they could be malicious.
73  */
74  sec_context |= SECURITY_RESTRICTED_OPERATION;
75  SetUserIdAndSecContext(userid, sec_context);
76  context->save_nestlevel = NewGUCNestLevel();
77  }
78 }
79 
80 /*
81  * Switch back to the original user ID.
82  *
83  * If we created a new GUC nest level, also roll back any changes that were
84  * made within it.
85  */
86 void
88 {
89  if (context->save_nestlevel != -1)
90  AtEOXact_GUC(false, context->save_nestlevel);
91  SetUserIdAndSecContext(context->save_userid, context->save_sec_context);
92 }
bool member_can_set_role(Oid member, Oid role)
Definition: acl.c:5162
int errcode(int sqlerrcode)
Definition: elog.c:859
int errmsg(const char *fmt,...)
Definition: elog.c:1072
#define ERROR
Definition: elog.h:39
#define ereport(elevel,...)
Definition: elog.h:149
int NewGUCNestLevel(void)
Definition: guc.c:2237
void AtEOXact_GUC(bool isCommit, int nestLevel)
Definition: guc.c:2264
#define SECURITY_RESTRICTED_OPERATION
Definition: miscadmin.h:315
char * GetUserNameFromId(Oid roleid, bool noerr)
Definition: miscinit.c:980
void GetUserIdAndSecContext(Oid *userid, int *sec_context)
Definition: miscinit.c:635
void SetUserIdAndSecContext(Oid userid, int sec_context)
Definition: miscinit.c:642
unsigned int Oid
Definition: postgres_ext.h:31
tree context
Definition: radixtree.h:1833
void SwitchToUntrustedUser(Oid userid, UserContext *context)
Definition: usercontext.c:33
void RestoreUserContext(UserContext *context)
Definition: usercontext.c:87