From e65fb3a4d6729d2a2739b1138548b3b7923b2338 Mon Sep 17 00:00:00 2001 From: Michael Paquier Date: Thu, 3 Sep 2015 18:26:23 -0700 Subject: [PATCH] Switch pgwin32_is_service to src/port and make pg_ctl use it --- src/backend/port/win32/Makefile | 2 +- src/backend/port/win32/security.c | 248 --------------------- src/bin/pg_ctl/pg_ctl.c | 2 +- src/include/port/win32.h | 7 +- .../port/win32/security.c => port/win32security.c} | 53 +++-- src/tools/msvc/Mkvcbuild.pm | 2 +- 6 files changed, 47 insertions(+), 267 deletions(-) copy src/{backend/port/win32/security.c => port/win32security.c} (83%) diff --git a/src/backend/port/win32/Makefile b/src/backend/port/win32/Makefile index 820a3b3..a6ace93 100644 --- a/src/backend/port/win32/Makefile +++ b/src/backend/port/win32/Makefile @@ -12,7 +12,7 @@ subdir = src/backend/port/win32 top_builddir = ../../../.. include $(top_builddir)/src/Makefile.global -OBJS = timer.o socket.o signal.o security.o mingwcompat.o +OBJS = timer.o socket.o signal.o mingwcompat.o ifeq ($(have_win32_dbghelp), yes) OBJS += crashdump.o endif diff --git a/src/backend/port/win32/security.c b/src/backend/port/win32/security.c index e9cfe15..e69de29 100644 --- a/src/backend/port/win32/security.c +++ b/src/backend/port/win32/security.c @@ -1,248 +0,0 @@ -/*------------------------------------------------------------------------- - * - * security.c - * Microsoft Windows Win32 Security Support Functions - * - * Portions Copyright (c) 1996-2015, PostgreSQL Global Development Group - * - * IDENTIFICATION - * src/backend/port/win32/security.c - * - *------------------------------------------------------------------------- - */ - -#include "postgres.h" - - -static BOOL pgwin32_get_dynamic_tokeninfo(HANDLE token, - TOKEN_INFORMATION_CLASS class, char **InfoBuffer, - char *errbuf, int errsize); - -/* - * 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) -{ - HANDLE AccessToken; - char *InfoBuffer = NULL; - char errbuf[256]; - PTOKEN_GROUPS Groups; - PSID AdministratorsSid; - PSID PowerUsersSid; - SID_IDENTIFIER_AUTHORITY NtAuthority = {SECURITY_NT_AUTHORITY}; - UINT x; - BOOL success; - - if (!OpenProcessToken(GetCurrentProcess(), TOKEN_READ, &AccessToken)) - { - write_stderr("could not open process token: error code %lu\n", - GetLastError()); - exit(1); - } - - if (!pgwin32_get_dynamic_tokeninfo(AccessToken, TokenGroups, - &InfoBuffer, errbuf, sizeof(errbuf))) - { - write_stderr("%s", errbuf); - exit(1); - } - - Groups = (PTOKEN_GROUPS) InfoBuffer; - - CloseHandle(AccessToken); - - if (!AllocateAndInitializeSid(&NtAuthority, 2, - SECURITY_BUILTIN_DOMAIN_RID, DOMAIN_ALIAS_RID_ADMINS, 0, 0, 0, 0, 0, - 0, &AdministratorsSid)) - { - write_stderr("could not get SID for Administrators group: error code %lu\n", - GetLastError()); - exit(1); - } - - if (!AllocateAndInitializeSid(&NtAuthority, 2, - SECURITY_BUILTIN_DOMAIN_RID, DOMAIN_ALIAS_RID_POWER_USERS, 0, 0, 0, 0, 0, - 0, &PowerUsersSid)) - { - write_stderr("could not get SID for PowerUsers group: error code %lu\n", - GetLastError()); - exit(1); - } - - success = FALSE; - - for (x = 0; x < Groups->GroupCount; x++) - { - if ((EqualSid(AdministratorsSid, Groups->Groups[x].Sid) && (Groups->Groups[x].Attributes & SE_GROUP_ENABLED)) || - (EqualSid(PowerUsersSid, Groups->Groups[x].Sid) && (Groups->Groups[x].Attributes & SE_GROUP_ENABLED))) - { - success = TRUE; - break; - } - } - - free(InfoBuffer); - 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 - * process token by the SCM when starting a service) - * - * Return values: - * 0 = Not service - * 1 = Service - * -1 = Error - * - * 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) -{ - static int _is_service = -1; - HANDLE AccessToken; - char *InfoBuffer = NULL; - char errbuf[256]; - PTOKEN_GROUPS Groups; - PTOKEN_USER User; - PSID ServiceSid; - PSID LocalSystemSid; - SID_IDENTIFIER_AUTHORITY NtAuthority = {SECURITY_NT_AUTHORITY}; - UINT x; - - /* Only check the first time */ - if (_is_service != -1) - return _is_service; - - if (!OpenProcessToken(GetCurrentProcess(), TOKEN_READ, &AccessToken)) - { - fprintf(stderr, "could not open process token: error code %lu\n", - GetLastError()); - return -1; - } - - /* First check for local system */ - if (!pgwin32_get_dynamic_tokeninfo(AccessToken, TokenUser, &InfoBuffer, - errbuf, sizeof(errbuf))) - { - fprintf(stderr, "%s", errbuf); - return -1; - } - - User = (PTOKEN_USER) InfoBuffer; - - if (!AllocateAndInitializeSid(&NtAuthority, 1, - SECURITY_LOCAL_SYSTEM_RID, 0, 0, 0, 0, 0, 0, 0, - &LocalSystemSid)) - { - fprintf(stderr, "could not get SID for local system account\n"); - CloseHandle(AccessToken); - return -1; - } - - if (EqualSid(LocalSystemSid, User->User.Sid)) - { - FreeSid(LocalSystemSid); - free(InfoBuffer); - CloseHandle(AccessToken); - _is_service = 1; - return _is_service; - } - - FreeSid(LocalSystemSid); - free(InfoBuffer); - - /* Now check for group SID */ - if (!pgwin32_get_dynamic_tokeninfo(AccessToken, TokenGroups, &InfoBuffer, - errbuf, sizeof(errbuf))) - { - fprintf(stderr, "%s", errbuf); - return -1; - } - - Groups = (PTOKEN_GROUPS) InfoBuffer; - - if (!AllocateAndInitializeSid(&NtAuthority, 1, - SECURITY_SERVICE_RID, 0, 0, 0, 0, 0, 0, 0, - &ServiceSid)) - { - fprintf(stderr, "could not get SID for service group\n"); - free(InfoBuffer); - CloseHandle(AccessToken); - return -1; - } - - _is_service = 0; - for (x = 0; x < Groups->GroupCount; x++) - { - if (EqualSid(ServiceSid, Groups->Groups[x].Sid)) - { - _is_service = 1; - break; - } - } - - free(InfoBuffer); - FreeSid(ServiceSid); - - CloseHandle(AccessToken); - - return _is_service; -} - - -/* - * Call GetTokenInformation() on a token and return a dynamically sized - * buffer with the information in it. This buffer must be free():d by - * the calling function! - */ -static BOOL -pgwin32_get_dynamic_tokeninfo(HANDLE token, TOKEN_INFORMATION_CLASS class, - char **InfoBuffer, char *errbuf, int errsize) -{ - DWORD InfoBufferSize; - - if (GetTokenInformation(token, class, NULL, 0, &InfoBufferSize)) - { - snprintf(errbuf, errsize, "could not get token information: got zero size\n"); - return FALSE; - } - - if (GetLastError() != ERROR_INSUFFICIENT_BUFFER) - { - snprintf(errbuf, errsize, "could not get token information: error code %lu\n", - GetLastError()); - return FALSE; - } - - *InfoBuffer = malloc(InfoBufferSize); - if (*InfoBuffer == NULL) - { - snprintf(errbuf, errsize, "could not allocate %d bytes for token information\n", - (int) InfoBufferSize); - return FALSE; - } - - if (!GetTokenInformation(token, class, *InfoBuffer, - InfoBufferSize, &InfoBufferSize)) - { - snprintf(errbuf, errsize, "could not get token information: error code %lu\n", - GetLastError()); - return FALSE; - } - - return TRUE; -} diff --git a/src/bin/pg_ctl/pg_ctl.c b/src/bin/pg_ctl/pg_ctl.c index 6a36d29..d9eca37 100644 --- a/src/bin/pg_ctl/pg_ctl.c +++ b/src/bin/pg_ctl/pg_ctl.c @@ -215,7 +215,7 @@ write_stderr(const char *fmt,...) * On Win32, we print to stderr if running on a console, or write to * eventlog if running as a service */ - if (!isatty(fileno(stderr))) /* Running as a service */ + if (!pgwin32_is_service()) /* Running as a service */ { char errbuf[2048]; /* Arbitrary size? */ diff --git a/src/include/port/win32.h b/src/include/port/win32.h index 4cb51ec..69cd1c4 100644 --- a/src/include/port/win32.h +++ b/src/include/port/win32.h @@ -382,9 +382,6 @@ int pgwin32_waitforsinglesocket(SOCKET s, int what, int timeout); extern int pgwin32_noblock; -/* in backend/port/win32/security.c */ -extern int pgwin32_is_admin(void); -extern int pgwin32_is_service(void); #endif /* in backend/port/win32_shmem.c */ @@ -400,6 +397,10 @@ extern void _dosmaperr(unsigned long); extern int pgwin32_putenv(const char *); extern void pgwin32_unsetenv(const char *); +/* in port/win32security.c */ +extern int pgwin32_is_service(void); +extern int pgwin32_is_admin(void); + #define putenv(x) pgwin32_putenv(x) #define unsetenv(x) pgwin32_unsetenv(x) diff --git a/src/backend/port/win32/security.c b/src/port/win32security.c similarity index 83% copy from src/backend/port/win32/security.c copy to src/port/win32security.c index e9cfe15..59c2a67 100644 --- a/src/backend/port/win32/security.c +++ b/src/port/win32security.c @@ -1,22 +1,47 @@ /*------------------------------------------------------------------------- * - * security.c + * win32security.c * Microsoft Windows Win32 Security Support Functions * * Portions Copyright (c) 1996-2015, PostgreSQL Global Development Group * * IDENTIFICATION - * src/backend/port/win32/security.c + * src/port/win32security.c * *------------------------------------------------------------------------- */ +#ifndef FRONTEND #include "postgres.h" +#else +#include "postgres_fe.h" +#endif static BOOL pgwin32_get_dynamic_tokeninfo(HANDLE token, - TOKEN_INFORMATION_CLASS class, char **InfoBuffer, - char *errbuf, int errsize); + TOKEN_INFORMATION_CLASS class, + char **InfoBuffer, char *errbuf, int errsize); + + +/* + * Utility wrapper for frontend and backend when reporting an error + * message. + */ +static +pg_attribute_printf(1, 2) +void +log_error(const char *fmt,...) +{ + va_list ap; + + va_start(fmt, ap); +#ifndef FRONTEND + write_stderr(fmt, ap); +#else + fprintf(stderr, fmt, ap); +#endif + va_end(ap); +} /* * Returns nonzero if the current user has administrative privileges, @@ -40,15 +65,15 @@ pgwin32_is_admin(void) if (!OpenProcessToken(GetCurrentProcess(), TOKEN_READ, &AccessToken)) { - write_stderr("could not open process token: error code %lu\n", - GetLastError()); + log_error("could not open process token: error code %lu\n", + GetLastError()); exit(1); } if (!pgwin32_get_dynamic_tokeninfo(AccessToken, TokenGroups, &InfoBuffer, errbuf, sizeof(errbuf))) { - write_stderr("%s", errbuf); + log_error("%s", errbuf); exit(1); } @@ -60,8 +85,8 @@ pgwin32_is_admin(void) SECURITY_BUILTIN_DOMAIN_RID, DOMAIN_ALIAS_RID_ADMINS, 0, 0, 0, 0, 0, 0, &AdministratorsSid)) { - write_stderr("could not get SID for Administrators group: error code %lu\n", - GetLastError()); + log_error("could not get SID for Administrators group: error code %lu\n", + GetLastError()); exit(1); } @@ -69,7 +94,7 @@ pgwin32_is_admin(void) SECURITY_BUILTIN_DOMAIN_RID, DOMAIN_ALIAS_RID_POWER_USERS, 0, 0, 0, 0, 0, 0, &PowerUsersSid)) { - write_stderr("could not get SID for PowerUsers group: error code %lu\n", + log_error("could not get SID for PowerUsers group: error code %lu\n", GetLastError()); exit(1); } @@ -105,9 +130,11 @@ pgwin32_is_admin(void) * 1 = Service * -1 = Error * - * 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. + * Note: we can't report errors via either ereport (we're called too early + * in the backend) or write_stderr (because that calls this). We are + * therefore reduced to writing directly on stderr, which sucks, but we + * have few alternatives. Backend-side code needs as well calls to write + * directly to stderr, so that's not something to worry about in this case. */ int pgwin32_is_service(void) diff --git a/src/tools/msvc/Mkvcbuild.pm b/src/tools/msvc/Mkvcbuild.pm index 3abbb4c..224fdcd 100644 --- a/src/tools/msvc/Mkvcbuild.pm +++ b/src/tools/msvc/Mkvcbuild.pm @@ -89,7 +89,7 @@ sub mkvcbuild pgcheckdir.c pgmkdirp.c pgsleep.c pgstrcasecmp.c pqsignal.c mkdtemp.c qsort.c qsort_arg.c quotes.c system.c sprompt.c tar.c thread.c getopt.c getopt_long.c dirent.c - win32env.c win32error.c win32setlocale.c); + win32env.c win32error.c win32security.c win32setlocale.c); push(@pgportfiles, 'rint.c') if ($vsVersion < '12.00'); -- 1.9.2.msysgit.0