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-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 33 297442 : SwitchToUntrustedUser(Oid userid, UserContext *context) 34 : { 35 : /* Get the current user ID and security context. */ 36 297442 : GetUserIdAndSecContext(&context->save_userid, 37 : &context->save_sec_context); 38 : 39 : /* Check that we have sufficient privileges to assume the target role. */ 40 297442 : 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 297440 : 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 297380 : SetUserIdAndSecContext(userid, context->save_sec_context); 60 297380 : context->save_nestlevel = -1; 61 : } 62 : else 63 : { 64 60 : 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 60 : sec_context |= SECURITY_RESTRICTED_OPERATION; 75 60 : SetUserIdAndSecContext(userid, sec_context); 76 60 : context->save_nestlevel = NewGUCNestLevel(); 77 : } 78 297440 : } 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 297396 : RestoreUserContext(UserContext *context) 88 : { 89 297396 : if (context->save_nestlevel != -1) 90 48 : AtEOXact_GUC(false, context->save_nestlevel); 91 297396 : SetUserIdAndSecContext(context->save_userid, context->save_sec_context); 92 297396 : }