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-2025, 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
20static 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 */
27static void
28log_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 */
48int
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 */
119int
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:186
#define pg_attribute_printf(f, a)
Definition: c.h:213
#define fprintf(file, fmt, msg)
Definition: cubescan.l:21
#define _(x)
Definition: elog.c:90
static void const char * fmt
va_end(args)
exit(1)
va_start(args, fmt)
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