LCOV - code coverage report
Current view: top level - src/common - restricted_token.c (source / functions) Hit Total Coverage
Test: PostgreSQL 13devel Lines: 2 2 100.0 %
Date: 2019-09-19 16:06:56 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-2019, 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 NT4, or any other system not containing the required functions, will
      44             :  * NOT execute anything.
      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 = NULL;
      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             :         _CreateRestrictedToken = (__CreateRestrictedToken) GetProcAddress(Advapi32Handle, "CreateRestrictedToken");
      65             :     }
      66             : 
      67             :     if (_CreateRestrictedToken == NULL)
      68             :     {
      69             :         pg_log_warning("cannot create restricted tokens on this platform");
      70             :         if (Advapi32Handle != NULL)
      71             :             FreeLibrary(Advapi32Handle);
      72             :         return 0;
      73             :     }
      74             : 
      75             :     /* Open the current token to use as a base for the restricted one */
      76             :     if (!OpenProcessToken(GetCurrentProcess(), TOKEN_ALL_ACCESS, &origToken))
      77             :     {
      78             :         pg_log_error("could not open process token: error code %lu", GetLastError());
      79             :         return 0;
      80             :     }
      81             : 
      82             :     /* Allocate list of SIDs to remove */
      83             :     ZeroMemory(&dropSids, sizeof(dropSids));
      84             :     if (!AllocateAndInitializeSid(&NtAuthority, 2,
      85             :                                   SECURITY_BUILTIN_DOMAIN_RID, DOMAIN_ALIAS_RID_ADMINS, 0, 0, 0, 0, 0,
      86             :                                   0, &dropSids[0].Sid) ||
      87             :         !AllocateAndInitializeSid(&NtAuthority, 2,
      88             :                                   SECURITY_BUILTIN_DOMAIN_RID, DOMAIN_ALIAS_RID_POWER_USERS, 0, 0, 0, 0, 0,
      89             :                                   0, &dropSids[1].Sid))
      90             :     {
      91             :         pg_log_error("could not allocate SIDs: error code %lu", GetLastError());
      92             :         return 0;
      93             :     }
      94             : 
      95             :     b = _CreateRestrictedToken(origToken,
      96             :                                DISABLE_MAX_PRIVILEGE,
      97             :                                sizeof(dropSids) / sizeof(dropSids[0]),
      98             :                                dropSids,
      99             :                                0, NULL,
     100             :                                0, NULL,
     101             :                                &restrictedToken);
     102             : 
     103             :     FreeSid(dropSids[1].Sid);
     104             :     FreeSid(dropSids[0].Sid);
     105             :     CloseHandle(origToken);
     106             :     FreeLibrary(Advapi32Handle);
     107             : 
     108             :     if (!b)
     109             :     {
     110             :         pg_log_error("could not create restricted token: error code %lu", GetLastError());
     111             :         return 0;
     112             :     }
     113             : 
     114             : #ifndef __CYGWIN__
     115             :     AddUserToTokenDacl(restrictedToken);
     116             : #endif
     117             : 
     118             :     if (!CreateProcessAsUser(restrictedToken,
     119             :                              NULL,
     120             :                              cmd,
     121             :                              NULL,
     122             :                              NULL,
     123             :                              TRUE,
     124             :                              CREATE_SUSPENDED,
     125             :                              NULL,
     126             :                              NULL,
     127             :                              &si,
     128             :                              processInfo))
     129             : 
     130             :     {
     131             :         pg_log_error("could not start process for command \"%s\": error code %lu", cmd, GetLastError());
     132             :         return 0;
     133             :     }
     134             : 
     135             :     ResumeThread(processInfo->hThread);
     136             :     return restrictedToken;
     137             : }
     138             : #endif
     139             : 
     140             : /*
     141             :  * On Windows make sure that we are running with a restricted token,
     142             :  * On other platforms do nothing.
     143             :  */
     144             : void
     145         690 : get_restricted_token(void)
     146             : {
     147             : #ifdef WIN32
     148             :     HANDLE      restrictedToken;
     149             : 
     150             :     /*
     151             :      * Before we execute another program, make sure that we are running with a
     152             :      * restricted token. If not, re-execute ourselves with one.
     153             :      */
     154             : 
     155             :     if ((restrict_env = getenv("PG_RESTRICT_EXEC")) == NULL
     156             :         || strcmp(restrict_env, "1") != 0)
     157             :     {
     158             :         PROCESS_INFORMATION pi;
     159             :         char       *cmdline;
     160             : 
     161             :         ZeroMemory(&pi, sizeof(pi));
     162             : 
     163             :         cmdline = pg_strdup(GetCommandLine());
     164             : 
     165             :         putenv("PG_RESTRICT_EXEC=1");
     166             : 
     167             :         if ((restrictedToken = CreateRestrictedProcess(cmdline, &pi)) == 0)
     168             :         {
     169             :             pg_log_error("could not re-execute with restricted token: error code %lu", GetLastError());
     170             :         }
     171             :         else
     172             :         {
     173             :             /*
     174             :              * Successfully re-execed. Now wait for child process to capture
     175             :              * exitcode.
     176             :              */
     177             :             DWORD       x;
     178             : 
     179             :             CloseHandle(restrictedToken);
     180             :             CloseHandle(pi.hThread);
     181             :             WaitForSingleObject(pi.hProcess, INFINITE);
     182             : 
     183             :             if (!GetExitCodeProcess(pi.hProcess, &x))
     184             :             {
     185             :                 pg_log_error("could not get exit code from subprocess: error code %lu", GetLastError());
     186             :                 exit(1);
     187             :             }
     188             :             exit(x);
     189             :         }
     190             :     }
     191             : #endif
     192         690 : }

Generated by: LCOV version 1.13