/*------------------------------------------------------------------------- * * 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; }