Coverage Report

Created: 2025-09-27 06:52

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/postgres/src/backend/utils/init/usercontext.c
Line
Count
Source
1
/*-------------------------------------------------------------------------
2
 *
3
 * usercontext.c
4
 *    Convenience functions for running code as a different database user.
5
 *
6
 * Portions Copyright (c) 1996-2025, 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
SwitchToUntrustedUser(Oid userid, UserContext *context)
34
0
{
35
  /* Get the current user ID and security context. */
36
0
  GetUserIdAndSecContext(&context->save_userid,
37
0
               &context->save_sec_context);
38
39
  /* Check that we have sufficient privileges to assume the target role. */
40
0
  if (!member_can_set_role(context->save_userid, userid))
41
0
    ereport(ERROR,
42
0
        (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
43
0
         errmsg("role \"%s\" cannot SET ROLE to \"%s\"",
44
0
            GetUserNameFromId(context->save_userid, false),
45
0
            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
0
  if (member_can_set_role(userid, context->save_userid))
53
0
  {
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
0
    SetUserIdAndSecContext(userid, context->save_sec_context);
60
0
    context->save_nestlevel = -1;
61
0
  }
62
0
  else
63
0
  {
64
0
    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
0
    sec_context |= SECURITY_RESTRICTED_OPERATION;
75
0
    SetUserIdAndSecContext(userid, sec_context);
76
0
    context->save_nestlevel = NewGUCNestLevel();
77
0
  }
78
0
}
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
RestoreUserContext(UserContext *context)
88
0
{
89
0
  if (context->save_nestlevel != -1)
90
0
    AtEOXact_GUC(false, context->save_nestlevel);
91
0
  SetUserIdAndSecContext(context->save_userid, context->save_sec_context);
92
0
}