pg.ddx.io  pgsql-bugs@postgresql.org mailing list archive  
help / color / mirror / Atom feed
From: MauMau <maumau307@gmail.com>
To: Michael Paquier <michael.paquier@gmail.com>
To: Breen Hagan <breen@rtda.com>
Cc: Heikki Linnakangas <hlinnaka@iki.fi>
Cc: Alvaro Herrera <alvherre@2ndquadrant.com>
Cc: PostgreSQL Hackers <pgsql-hackers@postgresql.org>
Subject: Re: BUG #13755: pgwin32_is_service not checking if SECURITY_SERVICE_SID is disabled
Date: Sun, 6 Nov 2016 18:30:41 +0900
Message-ID: <952A88FFCBDA419EB6D6556B6A8F29C1@tunaPC> (raw)
In-Reply-To: <CAB7nPqTMMFdzG5kcCjeC98rVJA+sKquowWDOu1=6w=OAkzRiSg@mail.gmail.com>
References: <CAB7nPqTAiB6+z=Cbqzt4KNNkynhP6D7_r_KaZBkmpt9mX7STuQ@mail.gmail.com>
	<20160404160801.GA186687@alvherre.pgsql>
	<CAB7nPqQjdCfny+SeF8mVehP+e1m4EwYxLBC2rhNHPwk5aTisPw@mail.gmail.com>
	<CAB7nPqSvfu=KpJ=NX+YAHmgAmQdzA7N5h31BjzXeMgczhGCC+Q@mail.gmail.com>
	<64a0ee81-2e30-c9b1-97b6-312772f89a2e@iki.fi>
	<CAC6pFPwwwufOHocFEbZimnd6-Mh3A2xYA=F9HmC_kxV1NTXhoA@mail.gmail.com>
	<CAB7nPqRzb4Fb9bJOttXHjh38hFxaN79hTNJEV0aBbgz=K52ASw@mail.gmail.com>
	<CAB7nPqTMMFdzG5kcCjeC98rVJA+sKquowWDOu1=6w=OAkzRiSg@mail.gmail.com>
List-Unsubscribe: <mailto:majordomo@postgresql.org?body=unsub%20pgsql-hackers>

Hello,

Sorry, I may have had to send this to pgsql-hackers.  I just replied
to all, which did not include pgsql-hackers but pgsql-bugs because
this discussion was on pgsql-bugs.  CommitFest app doesn't seem to
reflect the mails on pgsql-bugs, so I'm re-submitting this here on
pgsql-hackers.

From: Michael Paquier
(Moved to next CF, with same status "Ready for committer").

I reviewed and tested this patch after simplifying it like the
attached one.  The file could be reduced by about 110 lines.  Please
review and/or test it.  Though I kept the status "ready for
committer", feel free to change it back based on the result.

I tested as follows.  First, I confirmed that pg_is_admin() still
works by running postgres.exe from the Administrator command line:

--------------------------------------------------
G:\>postgres
Execution of PostgreSQL by a user with administrative permissions is
not
permitted.
The server must be started under an unprivileged user ID to prevent
possible system security compromises.  See the documentation for
more information on how to properly start the server.

G:\>
--------------------------------------------------



Then, I added the following two elog() calls in postmaster.c so that
pg_is_admin() and pg_is_service() works fine.


--------------------------------------------------
    maybe_start_bgworker();

    elog(LOG, "pgwin32_is_admin = %d", pgwin32_is_admin());
    elog(LOG, "pgwin32_is_service = %d", pgwin32_is_service());

    status = ServerLoop();
--------------------------------------------------


To reproduce the OP's problem, I modified pg_ctl.c to disable
SECURITY_SERVICE_RID when spawning postgres.exe.  Without the patch,
starting the Windows service emit the following log, showing that
pg_is_service() misjudged that postgres is running as a Windows
service:

LOG:  pgwin32_is_admin = 0
LOG:  pgwin32_is_service = 1

With the patch, the log became correct:

LOG:  pgwin32_is_admin = 0
LOG:  pgwin32_is_service = 0


Regards
Takayuki Tsunakawa

-- 
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers

Attachments:

win32-security_service-v3.patch (application/octet-stream, 12.7K) download ÿþdiff --git a/src/port/win32security.c b/src/port/win32security.c index 2c9ca15..3b22f16 100644 --- a/src/port/win32security.c +++ b/src/port/win32security.c @@ -18,11 +18,6 @@ #endif -static BOOL pgwin32_get_dynamic_tokeninfo(HANDLE token, - TOKEN_INFORMATION_CLASS class, - char **InfoBuffer, char *errbuf, int errsize); - - /* * Utility wrapper for frontend and backend when reporting an error * message. @@ -53,33 +48,11 @@ log_error(const char *fmt,...) 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)) - { - 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))) - { - log_error("%s", errbuf); - exit(1); - } - - Groups = (PTOKEN_GROUPS) InfoBuffer; - - CloseHandle(AccessToken); + BOOL IsAdministrators; + BOOL IsPowerUsers; if (!AllocateAndInitializeSid(&NtAuthority, 2, SECURITY_BUILTIN_DOMAIN_RID, @@ -101,24 +74,21 @@ pgwin32_is_admin(void) exit(1); } - success = FALSE; - - for (x = 0; x < Groups->GroupCount; x++) + if (!CheckTokenMembership(NULL, AdministratorsSid, &IsAdministrators) || + !CheckTokenMembership(NULL, PowerUsersSid, &IsPowerUsers)) { - 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; - } + log_error("could not check access token membership: error code %lu\n", + GetLastError()); + exit(1); } - free(InfoBuffer); FreeSid(AdministratorsSid); FreeSid(PowerUsersSid); - return success; + + if (IsAdministrators || IsPowerUsers) + return 1; + else + return 0; } /* @@ -143,140 +113,63 @@ int pgwin32_is_service(void) { static int _is_service = -1; - HANDLE AccessToken; - char *InfoBuffer = NULL; - char errbuf[256]; - PTOKEN_GROUPS Groups; - PTOKEN_USER User; + BOOL IsMember; 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; - + /* First check for Local System */ 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); + fprintf(stderr, "could not get SID for Local System account: error code %lu\n", + GetLastError()); return -1; } - if (EqualSid(LocalSystemSid, User->User.Sid)) + if (!CheckTokenMembership(NULL, LocalSystemSid, &IsMember)) { + fprintf(stderr, "could not check access token membership: error code %lu\n", + GetLastError()); FreeSid(LocalSystemSid); - free(InfoBuffer); - CloseHandle(AccessToken); - _is_service = 1; - return _is_service; + return -1; } - FreeSid(LocalSystemSid); - free(InfoBuffer); - /* Now check for group SID */ - if (!pgwin32_get_dynamic_tokeninfo(AccessToken, TokenGroups, &InfoBuffer, - errbuf, sizeof(errbuf))) + if (IsMember) { - fprintf(stderr, "%s", errbuf); - return -1; + _is_service = 1; + return _is_service; } - Groups = (PTOKEN_GROUPS) InfoBuffer; - + /* Next check for service group */ 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); + fprintf(stderr, "could not get SID for service group: error code %lu\n", + GetLastError()); return -1; } - _is_service = 0; - for (x = 0; x < Groups->GroupCount; x++) + if (!CheckTokenMembership(NULL, ServiceSid, &IsMember)) { - if (EqualSid(ServiceSid, Groups->Groups[x].Sid)) - { - _is_service = 1; - break; - } + fprintf(stderr, "could not check access token membership: error code %lu\n", + GetLastError()); + FreeSid(ServiceSid); + return -1; } - - free(InfoBuffer); FreeSid(ServiceSid); - CloseHandle(AccessToken); + if (IsMember) + _is_service = 1; + else + _is_service = 0; 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 buffer size: got zero size\n"); - return FALSE; - } - - if (GetLastError() != ERROR_INSUFFICIENT_BUFFER) - { - snprintf(errbuf, errsize, - "could not get token information buffer size: 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; -}

view thread (38+ messages)  latest in thread

Message-ID: <952A88FFCBDA419EB6D6556B6A8F29C1@tunaPC>
Permalink:  ../952A88FFCBDA419EB6D6556B6A8F29C1@tunaPC/
Also on:    postgresql.org/message-id/952A88FFCBDA419EB6D6556B6A8F29C1@tunaPC

 ·  · 

reply

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Reply to all the recipients using the --to and --cc options:
  reply via email

  To: pgsql-bugs@postgresql.org
  Cc: maumau307@gmail.com, michael.paquier@gmail.com, breen@rtda.com, hlinnaka@iki.fi, alvherre@2ndquadrant.com, pgsql-hackers@postgresql.org
  Subject: Re: BUG #13755: pgwin32_is_service not checking if SECURITY_SERVICE_SID is disabled
  In-Reply-To: <952A88FFCBDA419EB6D6556B6A8F29C1@tunaPC>

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

This inbox is served by DDX for PostgreSQL; see mirroring instructions
for how to clone and mirror all data and code used for this inbox