security.c 5.17 KB
Newer Older
1 2 3
/*-------------------------------------------------------------------------
 *
 * security.c
Bruce Momjian's avatar
Bruce Momjian committed
4
 *	  Microsoft Windows Win32 Security Support Functions
5
 *
Bruce Momjian's avatar
Bruce Momjian committed
6
 * Portions Copyright (c) 1996-2004, PostgreSQL Global Development Group
7 8
 *
 * IDENTIFICATION
9
 *	  $PostgreSQL: pgsql/src/backend/port/win32/security.c,v 1.6 2004/11/09 13:01:25 petere Exp $
10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26
 *
 *-------------------------------------------------------------------------
 */

#include "postgres.h"


/*
 * Returns nonzero if the current user has administrative privileges,
 * or zero if not.
 *
 * Note: this cannot use ereport() because it's called too early during
 * startup.
 */
int
pgwin32_is_admin(void)
{
Bruce Momjian's avatar
Bruce Momjian committed
27 28
	HANDLE		AccessToken;
	char	   *InfoBuffer = NULL;
29
	PTOKEN_GROUPS Groups;
Bruce Momjian's avatar
Bruce Momjian committed
30 31 32 33 34 35 36 37
	DWORD		InfoBufferSize;
	PSID		AdministratorsSid;
	PSID		PowerUsersSid;
	SID_IDENTIFIER_AUTHORITY NtAuthority = {SECURITY_NT_AUTHORITY};
	UINT		x;
	BOOL		success;

	if (!OpenProcessToken(GetCurrentProcess(), TOKEN_READ, &AccessToken))
38
	{
39
		write_stderr("could not open process token: error code %d\n",
Bruce Momjian's avatar
Bruce Momjian committed
40
					 (int) GetLastError());
41 42 43
		exit(1);
	}

Bruce Momjian's avatar
Bruce Momjian committed
44
	if (GetTokenInformation(AccessToken, TokenGroups, NULL, 0, &InfoBufferSize))
45
	{
Peter Eisentraut's avatar
Peter Eisentraut committed
46
		write_stderr("could not get token information: got zero size\n");
47 48 49 50 51
		exit(1);
	}

	if (GetLastError() != ERROR_INSUFFICIENT_BUFFER)
	{
52
		write_stderr("could not get token information: error code %d\n",
Bruce Momjian's avatar
Bruce Momjian committed
53
					 (int) GetLastError());
54 55 56 57 58 59
		exit(1);
	}

	InfoBuffer = malloc(InfoBufferSize);
	if (!InfoBuffer)
	{
Peter Eisentraut's avatar
Peter Eisentraut committed
60
		write_stderr("could not allocate %i bytes for token information\n",
Bruce Momjian's avatar
Bruce Momjian committed
61
					 (int) InfoBufferSize);
62 63
		exit(1);
	}
Bruce Momjian's avatar
Bruce Momjian committed
64
	Groups = (PTOKEN_GROUPS) InfoBuffer;
65

Bruce Momjian's avatar
Bruce Momjian committed
66
	if (!GetTokenInformation(AccessToken, TokenGroups, InfoBuffer,
67
							 InfoBufferSize, &InfoBufferSize))
68
	{
69
		write_stderr("could not get token information: error code %d\n",
Bruce Momjian's avatar
Bruce Momjian committed
70
					 (int) GetLastError());
71 72 73 74 75
		exit(1);
	}

	CloseHandle(AccessToken);

Bruce Momjian's avatar
Bruce Momjian committed
76 77 78
	if (!AllocateAndInitializeSid(&NtAuthority, 2,
	 SECURITY_BUILTIN_DOMAIN_RID, DOMAIN_ALIAS_RID_ADMINS, 0, 0, 0, 0, 0,
								  0, &AdministratorsSid))
79
	{
80
		write_stderr("could not get SID for Administrators group: error code %d\n",
Bruce Momjian's avatar
Bruce Momjian committed
81
					 (int) GetLastError());
82 83 84 85
		exit(1);
	}

	if (!AllocateAndInitializeSid(&NtAuthority, 2,
Bruce Momjian's avatar
Bruce Momjian committed
86
								  SECURITY_BUILTIN_DOMAIN_RID, DOMAIN_ALIAS_RID_POWER_USERS, 0, 0, 0, 0, 0,
87 88
								  0, &PowerUsersSid))
	{
89
		write_stderr("could not get SID for PowerUsers group: error code %d\n",
Bruce Momjian's avatar
Bruce Momjian committed
90
					 (int) GetLastError());
91 92
		exit(1);
	}
Bruce Momjian's avatar
Bruce Momjian committed
93

94
	success = FALSE;
Bruce Momjian's avatar
Bruce Momjian committed
95 96

	for (x = 0; x < Groups->GroupCount; x++)
97 98 99 100 101 102 103 104
	{
		if (EqualSid(AdministratorsSid, Groups->Groups[x].Sid) ||
			EqualSid(PowerUsersSid, Groups->Groups[x].Sid))
		{
			success = TRUE;
			break;
		}
	}
Bruce Momjian's avatar
Bruce Momjian committed
105

106
	free(InfoBuffer);
107 108 109 110 111 112 113 114 115 116 117
	FreeSid(AdministratorsSid);
	FreeSid(PowerUsersSid);
	return success;
}

/*
 * We consider ourselves running as a service if one of the following is
 * true:
 *
 * 1) We are running as Local System (only used by services)
 * 2) Our token contains SECURITY_SERVICE_RID (automatically added to the
Bruce Momjian's avatar
Bruce Momjian committed
118
 *	  process token by the SCM when starting a service)
119 120
 *
 * Return values:
Bruce Momjian's avatar
Bruce Momjian committed
121 122 123
 *	 0 = Not service
 *	 1 = Service
 *	-1 = Error
124 125 126 127 128 129 130 131
 *
 * Note: we can't report errors via either ereport (we're called too early)
 * or write_stderr (because that calls this).  We are therefore reduced to
 * writing directly on stderr, which sucks, but we have few alternatives.
 */
int
pgwin32_is_service(void)
{
Bruce Momjian's avatar
Bruce Momjian committed
132 133 134 135 136 137 138 139 140 141
	static int	_is_service = -1;
	HANDLE		AccessToken;
	UCHAR		InfoBuffer[1024];
	PTOKEN_GROUPS Groups = (PTOKEN_GROUPS) InfoBuffer;
	PTOKEN_USER User = (PTOKEN_USER) InfoBuffer;
	DWORD		InfoBufferSize;
	PSID		ServiceSid;
	PSID		LocalSystemSid;
	SID_IDENTIFIER_AUTHORITY NtAuthority = {SECURITY_NT_AUTHORITY};
	UINT		x;
142 143 144 145

	/* Only check the first time */
	if (_is_service != -1)
		return _is_service;
Bruce Momjian's avatar
Bruce Momjian committed
146 147 148

	if (!OpenProcessToken(GetCurrentProcess(), TOKEN_READ, &AccessToken))
	{
149
		fprintf(stderr, "could not open process token: error code %d\n",
Bruce Momjian's avatar
Bruce Momjian committed
150
				(int) GetLastError());
151 152 153 154
		return -1;
	}

	/* First check for local system */
Bruce Momjian's avatar
Bruce Momjian committed
155 156
	if (!GetTokenInformation(AccessToken, TokenUser, InfoBuffer, 1024, &InfoBufferSize))
	{
157
		fprintf(stderr, "could not get token information: error code %d\n",
Bruce Momjian's avatar
Bruce Momjian committed
158
				(int) GetLastError());
159 160
		return -1;
	}
Bruce Momjian's avatar
Bruce Momjian committed
161 162 163 164 165

	if (!AllocateAndInitializeSid(&NtAuthority, 1,
						  SECURITY_LOCAL_SYSTEM_RID, 0, 0, 0, 0, 0, 0, 0,
								  &LocalSystemSid))
	{
Peter Eisentraut's avatar
Peter Eisentraut committed
166
		fprintf(stderr, "could not get SID for local system account\n");
167 168 169 170
		CloseHandle(AccessToken);
		return -1;
	}

Bruce Momjian's avatar
Bruce Momjian committed
171 172
	if (EqualSid(LocalSystemSid, User->User.Sid))
	{
173 174 175 176 177 178 179 180 181
		FreeSid(LocalSystemSid);
		CloseHandle(AccessToken);
		_is_service = 1;
		return _is_service;
	}

	FreeSid(LocalSystemSid);

	/* Now check for group SID */
Bruce Momjian's avatar
Bruce Momjian committed
182 183
	if (!GetTokenInformation(AccessToken, TokenGroups, InfoBuffer, 1024, &InfoBufferSize))
	{
184
		fprintf(stderr, "could not get token information: error code %d\n",
Bruce Momjian's avatar
Bruce Momjian committed
185
				(int) GetLastError());
186 187 188
		return -1;
	}

Bruce Momjian's avatar
Bruce Momjian committed
189 190 191 192
	if (!AllocateAndInitializeSid(&NtAuthority, 1,
							   SECURITY_SERVICE_RID, 0, 0, 0, 0, 0, 0, 0,
								  &ServiceSid))
	{
Peter Eisentraut's avatar
Peter Eisentraut committed
193
		fprintf(stderr, "could not get SID for service group\n");
194 195 196 197 198 199 200
		CloseHandle(AccessToken);
		return -1;
	}

	_is_service = 0;
	for (x = 0; x < Groups->GroupCount; x++)
	{
Bruce Momjian's avatar
Bruce Momjian committed
201
		if (EqualSid(ServiceSid, Groups->Groups[x].Sid))
202 203 204 205 206 207 208 209 210 211 212 213
		{
			_is_service = 1;
			break;
		}
	}

	FreeSid(ServiceSid);

	CloseHandle(AccessToken);

	return _is_service;
}