LCOV - code coverage report
Current view: top level - src/common - restricted_token.c (source / functions) Hit Total Coverage
Test: PostgreSQL 18devel Lines: 2 2 100.0 %
Date: 2024-11-21 08:14:44 Functions: 1 1 100.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /*-------------------------------------------------------------------------
       2             :  *
       3             :  * restricted_token.c
       4             :  *      helper routine to ensure restricted token on Windows
       5             :  *
       6             :  *
       7             :  * Portions Copyright (c) 1996-2024, PostgreSQL Global Development Group
       8             :  * Portions Copyright (c) 1994, Regents of the University of California
       9             :  *
      10             :  *
      11             :  * IDENTIFICATION
      12             :  *    src/common/restricted_token.c
      13             :  *
      14             :  *-------------------------------------------------------------------------
      15             :  */
      16             : 
      17             : #ifndef FRONTEND
      18             : #error "This file is not expected to be compiled for backend code"
      19             : #endif
      20             : 
      21             : #include "postgres_fe.h"
      22             : 
      23             : #include "common/logging.h"
      24             : #include "common/restricted_token.h"
      25             : 
      26             : #ifdef WIN32
      27             : 
      28             : /* internal vars */
      29             : static char *restrict_env;
      30             : 
      31             : /* Windows API define missing from some versions of MingW headers */
      32             : #ifndef  DISABLE_MAX_PRIVILEGE
      33             : #define DISABLE_MAX_PRIVILEGE   0x1
      34             : #endif
      35             : 
      36             : /*
      37             :  * Create a restricted token and execute the specified process with it.
      38             :  *
      39             :  * Returns restricted token on success and 0 on failure.
      40             :  *
      41             :  * On any system not containing the required functions, do nothing
      42             :  * but still report an error.
      43             :  */
      44             : HANDLE
      45             : CreateRestrictedProcess(char *cmd, PROCESS_INFORMATION *processInfo)
      46             : {
      47             :     BOOL        b;
      48             :     STARTUPINFO si;
      49             :     HANDLE      origToken;
      50             :     HANDLE      restrictedToken;
      51             :     SID_IDENTIFIER_AUTHORITY NtAuthority = {SECURITY_NT_AUTHORITY};
      52             :     SID_AND_ATTRIBUTES dropSids[2];
      53             : 
      54             :     ZeroMemory(&si, sizeof(si));
      55             :     si.cb = sizeof(si);
      56             : 
      57             :     /* Open the current token to use as a base for the restricted one */
      58             :     if (!OpenProcessToken(GetCurrentProcess(), TOKEN_ALL_ACCESS, &origToken))
      59             :     {
      60             :         pg_log_error("could not open process token: error code %lu",
      61             :                      GetLastError());
      62             :         return 0;
      63             :     }
      64             : 
      65             :     /* Allocate list of SIDs to remove */
      66             :     ZeroMemory(&dropSids, sizeof(dropSids));
      67             :     if (!AllocateAndInitializeSid(&NtAuthority, 2,
      68             :                                   SECURITY_BUILTIN_DOMAIN_RID, DOMAIN_ALIAS_RID_ADMINS, 0, 0, 0, 0, 0,
      69             :                                   0, &dropSids[0].Sid) ||
      70             :         !AllocateAndInitializeSid(&NtAuthority, 2,
      71             :                                   SECURITY_BUILTIN_DOMAIN_RID, DOMAIN_ALIAS_RID_POWER_USERS, 0, 0, 0, 0, 0,
      72             :                                   0, &dropSids[1].Sid))
      73             :     {
      74             :         pg_log_error("could not allocate SIDs: error code %lu",
      75             :                      GetLastError());
      76             :         CloseHandle(origToken);
      77             :         return 0;
      78             :     }
      79             : 
      80             :     b = CreateRestrictedToken(origToken,
      81             :                               DISABLE_MAX_PRIVILEGE,
      82             :                               sizeof(dropSids) / sizeof(dropSids[0]),
      83             :                               dropSids,
      84             :                               0, NULL,
      85             :                               0, NULL,
      86             :                               &restrictedToken);
      87             : 
      88             :     FreeSid(dropSids[1].Sid);
      89             :     FreeSid(dropSids[0].Sid);
      90             :     CloseHandle(origToken);
      91             : 
      92             :     if (!b)
      93             :     {
      94             :         pg_log_error("could not create restricted token: error code %lu", GetLastError());
      95             :         return 0;
      96             :     }
      97             : 
      98             : #ifndef __CYGWIN__
      99             :     AddUserToTokenDacl(restrictedToken);
     100             : #endif
     101             : 
     102             :     if (!CreateProcessAsUser(restrictedToken,
     103             :                              NULL,
     104             :                              cmd,
     105             :                              NULL,
     106             :                              NULL,
     107             :                              TRUE,
     108             :                              CREATE_SUSPENDED,
     109             :                              NULL,
     110             :                              NULL,
     111             :                              &si,
     112             :                              processInfo))
     113             : 
     114             :     {
     115             :         pg_log_error("could not start process for command \"%s\": error code %lu", cmd, GetLastError());
     116             :         return 0;
     117             :     }
     118             : 
     119             :     ResumeThread(processInfo->hThread);
     120             :     return restrictedToken;
     121             : }
     122             : #endif
     123             : 
     124             : /*
     125             :  * On Windows make sure that we are running with a restricted token,
     126             :  * On other platforms do nothing.
     127             :  */
     128             : void
     129        1034 : get_restricted_token(void)
     130             : {
     131             : #ifdef WIN32
     132             :     HANDLE      restrictedToken;
     133             : 
     134             :     /*
     135             :      * Before we execute another program, make sure that we are running with a
     136             :      * restricted token. If not, re-execute ourselves with one.
     137             :      */
     138             : 
     139             :     if ((restrict_env = getenv("PG_RESTRICT_EXEC")) == NULL
     140             :         || strcmp(restrict_env, "1") != 0)
     141             :     {
     142             :         PROCESS_INFORMATION pi;
     143             :         char       *cmdline;
     144             : 
     145             :         ZeroMemory(&pi, sizeof(pi));
     146             : 
     147             :         cmdline = pg_strdup(GetCommandLine());
     148             : 
     149             :         setenv("PG_RESTRICT_EXEC", "1", 1);
     150             : 
     151             :         if ((restrictedToken = CreateRestrictedProcess(cmdline, &pi)) == 0)
     152             :         {
     153             :             pg_log_error("could not re-execute with restricted token: error code %lu", GetLastError());
     154             :         }
     155             :         else
     156             :         {
     157             :             /*
     158             :              * Successfully re-executed. Now wait for child process to capture
     159             :              * the exit code.
     160             :              */
     161             :             DWORD       x;
     162             : 
     163             :             CloseHandle(restrictedToken);
     164             :             CloseHandle(pi.hThread);
     165             :             WaitForSingleObject(pi.hProcess, INFINITE);
     166             : 
     167             :             if (!GetExitCodeProcess(pi.hProcess, &x))
     168             :                 pg_fatal("could not get exit code from subprocess: error code %lu", GetLastError());
     169             :             exit(x);
     170             :         }
     171             :         pg_free(cmdline);
     172             :     }
     173             : #endif
     174        1034 : }

Generated by: LCOV version 1.14