Age Owner TLA Line data Source code
1 : /*-------------------------------------------------------------------------
2 : *
3 : * usercontext.c
4 : * Convenience functions for running code as a different database user.
5 : *
6 : * Portions Copyright (c) 1996-2023, 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
5 rhaas 33 GNC 147872 : SwitchToUntrustedUser(Oid userid, UserContext *context)
34 : {
35 : /* Get the current user ID and security context. */
36 147872 : GetUserIdAndSecContext(&context->save_userid,
37 : &context->save_sec_context);
38 :
39 : /* Check that we have sufficient privileges to assume the target role. */
40 147872 : if (!member_can_set_role(context->save_userid, userid))
41 2 : 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 147870 : 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 147844 : SetUserIdAndSecContext(userid, context->save_sec_context);
60 147844 : context->save_nestlevel = -1;
61 : }
62 : else
63 : {
64 26 : 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 roll
71 : * back any GUC changes that may be made by code running as the target
72 : * user, inasmuch as they could be malicious.
73 : */
74 26 : sec_context |= SECURITY_RESTRICTED_OPERATION;
75 26 : SetUserIdAndSecContext(userid, sec_context);
76 26 : context->save_nestlevel = NewGUCNestLevel();
77 : }
78 147870 : }
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
87 147855 : RestoreUserContext(UserContext *context)
88 : {
89 147855 : if (context->save_nestlevel != -1)
90 20 : AtEOXact_GUC(false, context->save_nestlevel);
91 147855 : SetUserIdAndSecContext(context->save_userid, context->save_sec_context);
92 147855 : }
|