PostgreSQL Source Code  git master
win32security.c
Go to the documentation of this file.
1 /*-------------------------------------------------------------------------
2  *
3  * win32security.c
4  * Microsoft Windows Win32 Security Support Functions
5  *
6  * Portions Copyright (c) 1996-2024, PostgreSQL Global Development Group
7  *
8  * IDENTIFICATION
9  * src/port/win32security.c
10  *
11  *-------------------------------------------------------------------------
12  */
13 
14 #ifndef FRONTEND
15 #include "postgres.h"
16 #else
17 #include "postgres_fe.h"
18 #endif
19 
20 static void log_error(const char *fmt,...) pg_attribute_printf(1, 2);
21 
22 
23 /*
24  * Utility wrapper for frontend and backend when reporting an error
25  * message.
26  */
27 static void
28 log_error(const char *fmt,...)
29 {
30  va_list ap;
31 
32  va_start(ap, fmt);
33 #ifndef FRONTEND
34  write_stderr(fmt, ap);
35 #else
36  fprintf(stderr, fmt, ap);
37 #endif
38  va_end(ap);
39 }
40 
41 /*
42  * Returns nonzero if the current user has administrative privileges,
43  * or zero if not.
44  *
45  * Note: this cannot use ereport() because it's called too early during
46  * startup.
47  */
48 int
50 {
51  PSID AdministratorsSid;
52  PSID PowerUsersSid;
53  SID_IDENTIFIER_AUTHORITY NtAuthority = {SECURITY_NT_AUTHORITY};
54  BOOL IsAdministrators;
55  BOOL IsPowerUsers;
56 
57  if (!AllocateAndInitializeSid(&NtAuthority, 2,
58  SECURITY_BUILTIN_DOMAIN_RID,
59  DOMAIN_ALIAS_RID_ADMINS, 0, 0, 0, 0, 0,
60  0, &AdministratorsSid))
61  {
62  log_error(_("could not get SID for Administrators group: error code %lu\n"),
63  GetLastError());
64  exit(1);
65  }
66 
67  if (!AllocateAndInitializeSid(&NtAuthority, 2,
68  SECURITY_BUILTIN_DOMAIN_RID,
69  DOMAIN_ALIAS_RID_POWER_USERS, 0, 0, 0, 0, 0,
70  0, &PowerUsersSid))
71  {
72  log_error(_("could not get SID for PowerUsers group: error code %lu\n"),
73  GetLastError());
74  exit(1);
75  }
76 
77  if (!CheckTokenMembership(NULL, AdministratorsSid, &IsAdministrators) ||
78  !CheckTokenMembership(NULL, PowerUsersSid, &IsPowerUsers))
79  {
80  log_error(_("could not check access token membership: error code %lu\n"),
81  GetLastError());
82  exit(1);
83  }
84 
85  FreeSid(AdministratorsSid);
86  FreeSid(PowerUsersSid);
87 
88  if (IsAdministrators || IsPowerUsers)
89  return 1;
90  else
91  return 0;
92 }
93 
94 /*
95  * We consider ourselves running as a service if one of the following is
96  * true:
97  *
98  * 1) Standard error is not valid (always the case for services, and pg_ctl
99  * running as a service "passes" that down to postgres,
100  * c.f. CreateRestrictedProcess())
101  * 2) We are running as LocalSystem (only used by services)
102  * 3) Our token contains SECURITY_SERVICE_RID (automatically added to the
103  * process token by the SCM when starting a service)
104  *
105  * The check for LocalSystem is needed, because surprisingly, if a service
106  * is running as LocalSystem, it does not have SECURITY_SERVICE_RID in its
107  * process token.
108  *
109  * Return values:
110  * 0 = Not service
111  * 1 = Service
112  * -1 = Error
113  *
114  * Note: we can't report errors via either ereport (we're called too early
115  * in the backend) or write_stderr (because that calls this). We are
116  * therefore reduced to writing directly on stderr, which sucks, but we
117  * have few alternatives.
118  */
119 int
121 {
122  static int _is_service = -1;
123  BOOL IsMember;
124  PSID ServiceSid;
125  PSID LocalSystemSid;
126  SID_IDENTIFIER_AUTHORITY NtAuthority = {SECURITY_NT_AUTHORITY};
127  HANDLE stderr_handle;
128 
129  /* Only check the first time */
130  if (_is_service != -1)
131  return _is_service;
132 
133  /* Check if standard error is not valid */
134  stderr_handle = GetStdHandle(STD_ERROR_HANDLE);
135  if (stderr_handle != INVALID_HANDLE_VALUE && stderr_handle != NULL)
136  {
137  _is_service = 0;
138  return _is_service;
139  }
140 
141  /* Check if running as LocalSystem */
142  if (!AllocateAndInitializeSid(&NtAuthority, 1,
143  SECURITY_LOCAL_SYSTEM_RID, 0, 0, 0, 0, 0, 0, 0,
144  &LocalSystemSid))
145  {
146  fprintf(stderr, "could not get SID for local system account\n");
147  return -1;
148  }
149 
150  if (!CheckTokenMembership(NULL, LocalSystemSid, &IsMember))
151  {
152  fprintf(stderr, "could not check access token membership: error code %lu\n",
153  GetLastError());
154  FreeSid(LocalSystemSid);
155  return -1;
156  }
157  FreeSid(LocalSystemSid);
158 
159  if (IsMember)
160  {
161  _is_service = 1;
162  return _is_service;
163  }
164 
165  /* Check for service group membership */
166  if (!AllocateAndInitializeSid(&NtAuthority, 1,
167  SECURITY_SERVICE_RID, 0, 0, 0, 0, 0, 0, 0,
168  &ServiceSid))
169  {
170  fprintf(stderr, "could not get SID for service group: error code %lu\n",
171  GetLastError());
172  return -1;
173  }
174 
175  if (!CheckTokenMembership(NULL, ServiceSid, &IsMember))
176  {
177  fprintf(stderr, "could not check access token membership: error code %lu\n",
178  GetLastError());
179  FreeSid(ServiceSid);
180  return -1;
181  }
182  FreeSid(ServiceSid);
183 
184  if (IsMember)
185  _is_service = 1;
186  else
187  _is_service = 0;
188 
189  return _is_service;
190 }
#define write_stderr(str)
Definition: parallel.c:184
#define pg_attribute_printf(f, a)
Definition: c.h:191
#define _(x)
Definition: elog.c:90
static void const char * fmt
va_end(args)
exit(1)
va_start(args, fmt)
#define fprintf
Definition: port.h:242
int pgwin32_is_service(void)
static void log_error(const char *fmt,...) pg_attribute_printf(1
Definition: win32security.c:28
int pgwin32_is_admin(void)
Definition: win32security.c:49