diff options
Diffstat (limited to 'src/port/win32security.c')
-rw-r--r-- | src/port/win32security.c | 190 |
1 files changed, 190 insertions, 0 deletions
diff --git a/src/port/win32security.c b/src/port/win32security.c new file mode 100644 index 0000000..4d9d28c --- /dev/null +++ b/src/port/win32security.c @@ -0,0 +1,190 @@ +/*------------------------------------------------------------------------- + * + * win32security.c + * Microsoft Windows Win32 Security Support Functions + * + * Portions Copyright (c) 1996-2023, PostgreSQL Global Development Group + * + * IDENTIFICATION + * src/port/win32security.c + * + *------------------------------------------------------------------------- + */ + +#ifndef FRONTEND +#include "postgres.h" +#else +#include "postgres_fe.h" +#endif + +static void log_error(const char *fmt,...) pg_attribute_printf(1, 2); + + +/* + * Utility wrapper for frontend and backend when reporting an error + * message. + */ +static void +log_error(const char *fmt,...) +{ + va_list ap; + + va_start(ap, fmt); +#ifndef FRONTEND + write_stderr(fmt, ap); +#else + fprintf(stderr, fmt, ap); +#endif + va_end(ap); +} + +/* + * 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) +{ + PSID AdministratorsSid; + PSID PowerUsersSid; + SID_IDENTIFIER_AUTHORITY NtAuthority = {SECURITY_NT_AUTHORITY}; + BOOL IsAdministrators; + BOOL IsPowerUsers; + + if (!AllocateAndInitializeSid(&NtAuthority, 2, + SECURITY_BUILTIN_DOMAIN_RID, + DOMAIN_ALIAS_RID_ADMINS, 0, 0, 0, 0, 0, + 0, &AdministratorsSid)) + { + log_error(_("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)) + { + log_error(_("could not get SID for PowerUsers group: error code %lu\n"), + GetLastError()); + exit(1); + } + + if (!CheckTokenMembership(NULL, AdministratorsSid, &IsAdministrators) || + !CheckTokenMembership(NULL, PowerUsersSid, &IsPowerUsers)) + { + log_error(_("could not check access token membership: error code %lu\n"), + GetLastError()); + exit(1); + } + + FreeSid(AdministratorsSid); + FreeSid(PowerUsersSid); + + if (IsAdministrators || IsPowerUsers) + return 1; + else + return 0; +} + +/* + * We consider ourselves running as a service if one of the following is + * true: + * + * 1) Standard error is not valid (always the case for services, and pg_ctl + * running as a service "passes" that down to postgres, + * c.f. CreateRestrictedProcess()) + * 2) We are running as LocalSystem (only used by services) + * 3) Our token contains SECURITY_SERVICE_RID (automatically added to the + * process token by the SCM when starting a service) + * + * The check for LocalSystem is needed, because surprisingly, if a service + * is running as LocalSystem, it does not have SECURITY_SERVICE_RID in its + * process token. + * + * Return values: + * 0 = Not service + * 1 = Service + * -1 = Error + * + * 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. + */ +int +pgwin32_is_service(void) +{ + static int _is_service = -1; + BOOL IsMember; + PSID ServiceSid; + PSID LocalSystemSid; + SID_IDENTIFIER_AUTHORITY NtAuthority = {SECURITY_NT_AUTHORITY}; + HANDLE stderr_handle; + + /* Only check the first time */ + if (_is_service != -1) + return _is_service; + + /* Check if standard error is not valid */ + stderr_handle = GetStdHandle(STD_ERROR_HANDLE); + if (stderr_handle != INVALID_HANDLE_VALUE && stderr_handle != NULL) + { + _is_service = 0; + return _is_service; + } + + /* Check if running as LocalSystem */ + 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"); + return -1; + } + + if (!CheckTokenMembership(NULL, LocalSystemSid, &IsMember)) + { + fprintf(stderr, "could not check access token membership: error code %lu\n", + GetLastError()); + FreeSid(LocalSystemSid); + return -1; + } + FreeSid(LocalSystemSid); + + if (IsMember) + { + _is_service = 1; + return _is_service; + } + + /* Check for service group membership */ + if (!AllocateAndInitializeSid(&NtAuthority, 1, + SECURITY_SERVICE_RID, 0, 0, 0, 0, 0, 0, 0, + &ServiceSid)) + { + fprintf(stderr, "could not get SID for service group: error code %lu\n", + GetLastError()); + return -1; + } + + if (!CheckTokenMembership(NULL, ServiceSid, &IsMember)) + { + fprintf(stderr, "could not check access token membership: error code %lu\n", + GetLastError()); + FreeSid(ServiceSid); + return -1; + } + FreeSid(ServiceSid); + + if (IsMember) + _is_service = 1; + else + _is_service = 0; + + return _is_service; +} |