1 /*-------------------------------------------------------------------------
2 *
3 * win32security.c
4 * Microsoft Windows Win32 Security Support Functions
5 *
6 * Portions Copyright (c) 1996-2019, 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
21 /*
22 * Utility wrapper for frontend and backend when reporting an error
23 * message.
24 */
25 static
26 pg_attribute_printf(1, 2)
27 void
log_error(const char * fmt,...)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
pgwin32_is_admin(void)49 pgwin32_is_admin(void)
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) We are running as LocalSystem (only used by services)
99 * 2) Our token contains SECURITY_SERVICE_RID (automatically added to the
100 * process token by the SCM when starting a service)
101 *
102 * The check for LocalSystem is needed, because surprisingly, if a service
103 * is running as LocalSystem, it does not have SECURITY_SERVICE_RID in its
104 * process token.
105 *
106 * Return values:
107 * 0 = Not service
108 * 1 = Service
109 * -1 = Error
110 *
111 * Note: we can't report errors via either ereport (we're called too early
112 * in the backend) or write_stderr (because that calls this). We are
113 * therefore reduced to writing directly on stderr, which sucks, but we
114 * have few alternatives.
115 */
116 int
pgwin32_is_service(void)117 pgwin32_is_service(void)
118 {
119 static int _is_service = -1;
120 BOOL IsMember;
121 PSID ServiceSid;
122 PSID LocalSystemSid;
123 SID_IDENTIFIER_AUTHORITY NtAuthority = {SECURITY_NT_AUTHORITY};
124
125 /* Only check the first time */
126 if (_is_service != -1)
127 return _is_service;
128
129 /* First check for LocalSystem */
130 if (!AllocateAndInitializeSid(&NtAuthority, 1,
131 SECURITY_LOCAL_SYSTEM_RID, 0, 0, 0, 0, 0, 0, 0,
132 &LocalSystemSid))
133 {
134 fprintf(stderr, "could not get SID for local system account\n");
135 return -1;
136 }
137
138 if (!CheckTokenMembership(NULL, LocalSystemSid, &IsMember))
139 {
140 fprintf(stderr, "could not check access token membership: error code %lu\n",
141 GetLastError());
142 FreeSid(LocalSystemSid);
143 return -1;
144 }
145 FreeSid(LocalSystemSid);
146
147 if (IsMember)
148 {
149 _is_service = 1;
150 return _is_service;
151 }
152
153 /* Check for service group membership */
154 if (!AllocateAndInitializeSid(&NtAuthority, 1,
155 SECURITY_SERVICE_RID, 0, 0, 0, 0, 0, 0, 0,
156 &ServiceSid))
157 {
158 fprintf(stderr, "could not get SID for service group: error code %lu\n",
159 GetLastError());
160 return -1;
161 }
162
163 if (!CheckTokenMembership(NULL, ServiceSid, &IsMember))
164 {
165 fprintf(stderr, "could not check access token membership: error code %lu\n",
166 GetLastError());
167 FreeSid(ServiceSid);
168 return -1;
169 }
170 FreeSid(ServiceSid);
171
172 if (IsMember)
173 _is_service = 1;
174 else
175 _is_service = 0;
176
177 return _is_service;
178 }
179