PostgreSQL Source Code  git master
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros
restricted_token.c
Go to the documentation of this file.
1 /*-------------------------------------------------------------------------
2  *
3  * restricted_token.c
4  * helper routine to ensure restricted token on Windows
5  *
6  *
7  * Portions Copyright (c) 1996-2017, 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 
24 
25 #ifdef WIN32
26 
27 /* internal vars */
28 char *restrict_env;
29 
30 typedef BOOL (WINAPI * __CreateRestrictedToken) (HANDLE, DWORD, DWORD, PSID_AND_ATTRIBUTES, DWORD, PLUID_AND_ATTRIBUTES, DWORD, PSID_AND_ATTRIBUTES, PHANDLE);
31 
32 /* Windows API define missing from some versions of MingW headers */
33 #ifndef DISABLE_MAX_PRIVILEGE
34 #define DISABLE_MAX_PRIVILEGE 0x1
35 #endif
36 
37 /*
38  * Create a restricted token and execute the specified process with it.
39  *
40  * Returns restricted token on success and 0 on failure.
41  *
42  * On NT4, or any other system not containing the required functions, will
43  * NOT execute anything.
44  */
45 HANDLE
46 CreateRestrictedProcess(char *cmd, PROCESS_INFORMATION *processInfo, const char *progname)
47 {
48  BOOL b;
49  STARTUPINFO si;
50  HANDLE origToken;
51  HANDLE restrictedToken;
52  SID_IDENTIFIER_AUTHORITY NtAuthority = {SECURITY_NT_AUTHORITY};
53  SID_AND_ATTRIBUTES dropSids[2];
54  __CreateRestrictedToken _CreateRestrictedToken = NULL;
55  HANDLE Advapi32Handle;
56 
57  ZeroMemory(&si, sizeof(si));
58  si.cb = sizeof(si);
59 
60  Advapi32Handle = LoadLibrary("ADVAPI32.DLL");
61  if (Advapi32Handle != NULL)
62  {
63  _CreateRestrictedToken = (__CreateRestrictedToken) GetProcAddress(Advapi32Handle, "CreateRestrictedToken");
64  }
65 
66  if (_CreateRestrictedToken == NULL)
67  {
68  fprintf(stderr, _("%s: WARNING: cannot create restricted tokens on this platform\n"), progname);
69  if (Advapi32Handle != NULL)
70  FreeLibrary(Advapi32Handle);
71  return 0;
72  }
73 
74  /* Open the current token to use as a base for the restricted one */
75  if (!OpenProcessToken(GetCurrentProcess(), TOKEN_ALL_ACCESS, &origToken))
76  {
77  fprintf(stderr, _("%s: could not open process token: error code %lu\n"), progname, GetLastError());
78  return 0;
79  }
80 
81  /* Allocate list of SIDs to remove */
82  ZeroMemory(&dropSids, sizeof(dropSids));
83  if (!AllocateAndInitializeSid(&NtAuthority, 2,
84  SECURITY_BUILTIN_DOMAIN_RID, DOMAIN_ALIAS_RID_ADMINS, 0, 0, 0, 0, 0,
85  0, &dropSids[0].Sid) ||
86  !AllocateAndInitializeSid(&NtAuthority, 2,
87  SECURITY_BUILTIN_DOMAIN_RID, DOMAIN_ALIAS_RID_POWER_USERS, 0, 0, 0, 0, 0,
88  0, &dropSids[1].Sid))
89  {
90  fprintf(stderr, _("%s: could not allocate SIDs: error code %lu\n"),
91  progname, 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  fprintf(stderr, _("%s: could not create restricted token: error code %lu\n"),
111  progname, GetLastError());
112  return 0;
113  }
114 
115 #ifndef __CYGWIN__
116  AddUserToTokenDacl(restrictedToken);
117 #endif
118 
119  if (!CreateProcessAsUser(restrictedToken,
120  NULL,
121  cmd,
122  NULL,
123  NULL,
124  TRUE,
125  CREATE_SUSPENDED,
126  NULL,
127  NULL,
128  &si,
129  processInfo))
130 
131  {
132  fprintf(stderr, _("%s: could not start process for command \"%s\": error code %lu\n"), progname, cmd, GetLastError());
133  return 0;
134  }
135 
136  ResumeThread(processInfo->hThread);
137  return restrictedToken;
138 }
139 #endif
140 
141 /*
142  * On Windows make sure that we are running with a restricted token,
143  * On other platforms do nothing.
144  */
145 void
146 get_restricted_token(const char *progname)
147 {
148 #ifdef WIN32
149  HANDLE restrictedToken;
150 
151  /*
152  * Before we execute another program, make sure that we are running with a
153  * restricted token. If not, re-execute ourselves with one.
154  */
155 
156  if ((restrict_env = getenv("PG_RESTRICT_EXEC")) == NULL
157  || strcmp(restrict_env, "1") != 0)
158  {
159  PROCESS_INFORMATION pi;
160  char *cmdline;
161 
162  ZeroMemory(&pi, sizeof(pi));
163 
164  cmdline = pg_strdup(GetCommandLine());
165 
166  putenv("PG_RESTRICT_EXEC=1");
167 
168  if ((restrictedToken = CreateRestrictedProcess(cmdline, &pi, progname)) == 0)
169  {
170  fprintf(stderr, _("%s: could not re-execute with restricted token: error code %lu\n"), progname, GetLastError());
171  }
172  else
173  {
174  /*
175  * Successfully re-execed. Now wait for child process to capture
176  * exitcode.
177  */
178  DWORD x;
179 
180  CloseHandle(restrictedToken);
181  CloseHandle(pi.hThread);
182  WaitForSingleObject(pi.hProcess, INFINITE);
183 
184  if (!GetExitCodeProcess(pi.hProcess, &x))
185  {
186  fprintf(stderr, _("%s: could not get exit code from subprocess: error code %lu\n"), progname, GetLastError());
187  exit(1);
188  }
189  exit(x);
190  }
191  }
192 #endif
193 }
#define putenv(x)
Definition: win32.h:421
const char * progname
Definition: pg_standby.c:37
void get_restricted_token(const char *progname)
char * pg_strdup(const char *in)
Definition: fe_memutils.c:85
#define NULL
Definition: c.h:229
#define TRUE
Definition: c.h:217
typedef BOOL(WINAPI *MINIDUMPWRITEDUMP)(HANDLE hProcess
#define _(x)
Definition: elog.c:84