LCOV - code coverage report
Current view: top level - src/common - restricted_token.c (source / functions) Hit Total Coverage
Test: PostgreSQL 13beta1 Lines: 2 2 100.0 %
Date: 2020-05-29 01:06:25 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-2020, 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             : char       *restrict_env;
      30             : 
      31             : typedef BOOL (WINAPI * __CreateRestrictedToken) (HANDLE, DWORD, DWORD, PSID_AND_ATTRIBUTES, DWORD, PLUID_AND_ATTRIBUTES, DWORD, PSID_AND_ATTRIBUTES, PHANDLE);
      32             : 
      33             : /* Windows API define missing from some versions of MingW headers */
      34             : #ifndef  DISABLE_MAX_PRIVILEGE
      35             : #define DISABLE_MAX_PRIVILEGE   0x1
      36             : #endif
      37             : 
      38             : /*
      39             :  * Create a restricted token and execute the specified process with it.
      40             :  *
      41             :  * Returns restricted token on success and 0 on failure.
      42             :  *
      43             :  * On any system not containing the required functions, do nothing
      44             :  * but still report an error.
      45             :  */
      46             : HANDLE
      47             : CreateRestrictedProcess(char *cmd, PROCESS_INFORMATION *processInfo)
      48             : {
      49             :     BOOL        b;
      50             :     STARTUPINFO si;
      51             :     HANDLE      origToken;
      52             :     HANDLE      restrictedToken;
      53             :     SID_IDENTIFIER_AUTHORITY NtAuthority = {SECURITY_NT_AUTHORITY};
      54             :     SID_AND_ATTRIBUTES dropSids[2];
      55             :     __CreateRestrictedToken _CreateRestrictedToken;
      56             :     HANDLE      Advapi32Handle;
      57             : 
      58             :     ZeroMemory(&si, sizeof(si));
      59             :     si.cb = sizeof(si);
      60             : 
      61             :     Advapi32Handle = LoadLibrary("ADVAPI32.DLL");
      62             :     if (Advapi32Handle == NULL)
      63             :     {
      64             :         pg_log_error("could not load library \"%s\": error code %lu",
      65             :                      "ADVAPI32.DLL", GetLastError());
      66             :         return 0;
      67             :     }
      68             : 
      69             :     _CreateRestrictedToken = (__CreateRestrictedToken) GetProcAddress(Advapi32Handle, "CreateRestrictedToken");
      70             : 
      71             :     if (_CreateRestrictedToken == NULL)
      72             :     {
      73             :         pg_log_error("cannot create restricted tokens on this platform: error code %lu",
      74             :                      GetLastError());
      75             :         FreeLibrary(Advapi32Handle);
      76             :         return 0;
      77             :     }
      78             : 
      79             :     /* Open the current token to use as a base for the restricted one */
      80             :     if (!OpenProcessToken(GetCurrentProcess(), TOKEN_ALL_ACCESS, &origToken))
      81             :     {
      82             :         pg_log_error("could not open process token: error code %lu",
      83             :                      GetLastError());
      84             :         FreeLibrary(Advapi32Handle);
      85             :         return 0;
      86             :     }
      87             : 
      88             :     /* Allocate list of SIDs to remove */
      89             :     ZeroMemory(&dropSids, sizeof(dropSids));
      90             :     if (!AllocateAndInitializeSid(&NtAuthority, 2,
      91             :                                   SECURITY_BUILTIN_DOMAIN_RID, DOMAIN_ALIAS_RID_ADMINS, 0, 0, 0, 0, 0,
      92             :                                   0, &dropSids[0].Sid) ||
      93             :         !AllocateAndInitializeSid(&NtAuthority, 2,
      94             :                                   SECURITY_BUILTIN_DOMAIN_RID, DOMAIN_ALIAS_RID_POWER_USERS, 0, 0, 0, 0, 0,
      95             :                                   0, &dropSids[1].Sid))
      96             :     {
      97             :         pg_log_error("could not allocate SIDs: error code %lu",
      98             :                      GetLastError());
      99             :         CloseHandle(origToken);
     100             :         FreeLibrary(Advapi32Handle);
     101             :         return 0;
     102             :     }
     103             : 
     104             :     b = _CreateRestrictedToken(origToken,
     105             :                                DISABLE_MAX_PRIVILEGE,
     106             :                                sizeof(dropSids) / sizeof(dropSids[0]),
     107             :                                dropSids,
     108             :                                0, NULL,
     109             :                                0, NULL,
     110             :                                &restrictedToken);
     111             : 
     112             :     FreeSid(dropSids[1].Sid);
     113             :     FreeSid(dropSids[0].Sid);
     114             :     CloseHandle(origToken);
     115             :     FreeLibrary(Advapi32Handle);
     116             : 
     117             :     if (!b)
     118             :     {
     119             :         pg_log_error("could not create restricted token: error code %lu", GetLastError());
     120             :         return 0;
     121             :     }
     122             : 
     123             : #ifndef __CYGWIN__
     124             :     AddUserToTokenDacl(restrictedToken);
     125             : #endif
     126             : 
     127             :     if (!CreateProcessAsUser(restrictedToken,
     128             :                              NULL,
     129             :                              cmd,
     130             :                              NULL,
     131             :                              NULL,
     132             :                              TRUE,
     133             :                              CREATE_SUSPENDED,
     134             :                              NULL,
     135             :                              NULL,
     136             :                              &si,
     137             :                              processInfo))
     138             : 
     139             :     {
     140             :         pg_log_error("could not start process for command \"%s\": error code %lu", cmd, GetLastError());
     141             :         return 0;
     142             :     }
     143             : 
     144             :     ResumeThread(processInfo->hThread);
     145             :     return restrictedToken;
     146             : }
     147             : #endif
     148             : 
     149             : /*
     150             :  * On Windows make sure that we are running with a restricted token,
     151             :  * On other platforms do nothing.
     152             :  */
     153             : void
     154         776 : get_restricted_token(void)
     155             : {
     156             : #ifdef WIN32
     157             :     HANDLE      restrictedToken;
     158             : 
     159             :     /*
     160             :      * Before we execute another program, make sure that we are running with a
     161             :      * restricted token. If not, re-execute ourselves with one.
     162             :      */
     163             : 
     164             :     if ((restrict_env = getenv("PG_RESTRICT_EXEC")) == NULL
     165             :         || strcmp(restrict_env, "1") != 0)
     166             :     {
     167             :         PROCESS_INFORMATION pi;
     168             :         char       *cmdline;
     169             : 
     170             :         ZeroMemory(&pi, sizeof(pi));
     171             : 
     172             :         cmdline = pg_strdup(GetCommandLine());
     173             : 
     174             :         putenv("PG_RESTRICT_EXEC=1");
     175             : 
     176             :         if ((restrictedToken = CreateRestrictedProcess(cmdline, &pi)) == 0)
     177             :         {
     178             :             pg_log_error("could not re-execute with restricted token: error code %lu", GetLastError());
     179             :         }
     180             :         else
     181             :         {
     182             :             /*
     183             :              * Successfully re-executed. Now wait for child process to capture
     184             :              * the exit code.
     185             :              */
     186             :             DWORD       x;
     187             : 
     188             :             CloseHandle(restrictedToken);
     189             :             CloseHandle(pi.hThread);
     190             :             WaitForSingleObject(pi.hProcess, INFINITE);
     191             : 
     192             :             if (!GetExitCodeProcess(pi.hProcess, &x))
     193             :             {
     194             :                 pg_log_error("could not get exit code from subprocess: error code %lu", GetLastError());
     195             :                 exit(1);
     196             :             }
     197             :             exit(x);
     198             :         }
     199             :         pg_free(cmdline);
     200             :     }
     201             : #endif
     202         776 : }

Generated by: LCOV version 1.13