1 /*-------------------------------------------------------------------------
2  *
3  * win32security.c
4  *	  Microsoft Windows Win32 Security Support Functions
5  *
6  * Portions Copyright (c) 1996-2017, 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