@@ -149,6 +149,10 @@ static void WINAPI pgwin32_ServiceHandler(DWORD);
149149static void WINAPI pgwin32_ServiceMain (DWORD ,LPTSTR * );
150150static void pgwin32_doRunAsService (void );
151151static int CreateRestrictedProcess (char * cmd ,PROCESS_INFORMATION * processInfo ,bool as_service );
152+ static bool pgwin32_get_dynamic_tokeninfo (HANDLE token ,
153+ TOKEN_INFORMATION_CLASS class ,
154+ char * * InfoBuffer ,char * errbuf ,int errsize );
155+ static int pgwin32_is_service (void );
152156#endif
153157
154158static pgpid_t get_pgpid (bool is_status_request );
@@ -216,7 +220,7 @@ write_stderr(const char *fmt,...)
216220 * On Win32, we print to stderr if running on a console, or write to
217221 * eventlog if running as a service
218222 */
219- if (!isatty ( fileno ( stderr ) ))/* Running as a service */
223+ if (!pgwin32_is_service ( ))/* Running as a service */
220224{
221225char errbuf [2048 ];/* Arbitrary size? */
222226
@@ -1689,6 +1693,160 @@ pgwin32_doRunAsService(void)
16891693}
16901694}
16911695
1696+ /*
1697+ * Call GetTokenInformation() on a token and return a dynamically sized
1698+ * buffer with the information in it. This buffer must be free():d by
1699+ * the calling function!
1700+ */
1701+ static bool
1702+ pgwin32_get_dynamic_tokeninfo (HANDLE token ,TOKEN_INFORMATION_CLASS class ,
1703+ char * * InfoBuffer ,char * errbuf ,int errsize )
1704+ {
1705+ DWORD InfoBufferSize ;
1706+
1707+ if (GetTokenInformation (token ,class ,NULL ,0 ,& InfoBufferSize ))
1708+ {
1709+ snprintf (errbuf ,errsize ,"could not get token information: got zero size\n" );
1710+ return false;
1711+ }
1712+
1713+ if (GetLastError ()!= ERROR_INSUFFICIENT_BUFFER )
1714+ {
1715+ snprintf (errbuf ,errsize ,"could not get token information: error code %lu\n" ,
1716+ GetLastError ());
1717+ return false;
1718+ }
1719+
1720+ * InfoBuffer = malloc (InfoBufferSize );
1721+ if (* InfoBuffer == NULL )
1722+ {
1723+ snprintf (errbuf ,errsize ,"could not allocate %d bytes for token information\n" ,
1724+ (int )InfoBufferSize );
1725+ return false;
1726+ }
1727+
1728+ if (!GetTokenInformation (token ,class ,* InfoBuffer ,
1729+ InfoBufferSize ,& InfoBufferSize ))
1730+ {
1731+ snprintf (errbuf ,errsize ,"could not get token information: error code %lu\n" ,
1732+ GetLastError ());
1733+ return false;
1734+ }
1735+
1736+ return true;
1737+ }
1738+
1739+ /*
1740+ * We consider ourselves running as a service if one of the following is
1741+ * true:
1742+ *
1743+ * 1) We are running as Local System (only used by services)
1744+ * 2) Our token contains SECURITY_SERVICE_RID (automatically added to the
1745+ * process token by the SCM when starting a service)
1746+ *
1747+ * Return values:
1748+ * 0 = Not service
1749+ * 1 = Service
1750+ *-1 = Error
1751+ *
1752+ * Note: we can't report errors via write_stderr (because that calls this)
1753+ * We are therefore reduced to writing directly on stderr, which sucks, but
1754+ * we have few alternatives.
1755+ */
1756+ int
1757+ pgwin32_is_service (void )
1758+ {
1759+ static int _is_service = -1 ;
1760+ HANDLE AccessToken ;
1761+ char * InfoBuffer = NULL ;
1762+ char errbuf [256 ];
1763+ PTOKEN_GROUPS Groups ;
1764+ PTOKEN_USER User ;
1765+ PSID ServiceSid ;
1766+ PSID LocalSystemSid ;
1767+ SID_IDENTIFIER_AUTHORITY NtAuthority = {SECURITY_NT_AUTHORITY };
1768+ UINT x ;
1769+
1770+ /* Only check the first time */
1771+ if (_is_service != -1 )
1772+ return _is_service ;
1773+
1774+ if (!OpenProcessToken (GetCurrentProcess (),TOKEN_READ ,& AccessToken ))
1775+ {
1776+ fprintf (stderr ,"could not open process token: error code %lu\n" ,
1777+ GetLastError ());
1778+ return -1 ;
1779+ }
1780+
1781+ /* First check for local system */
1782+ if (!pgwin32_get_dynamic_tokeninfo (AccessToken ,TokenUser ,& InfoBuffer ,
1783+ errbuf ,sizeof (errbuf )))
1784+ {
1785+ fprintf (stderr ,"%s" ,errbuf );
1786+ return -1 ;
1787+ }
1788+
1789+ User = (PTOKEN_USER )InfoBuffer ;
1790+
1791+ if (!AllocateAndInitializeSid (& NtAuthority ,1 ,
1792+ SECURITY_LOCAL_SYSTEM_RID ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,
1793+ & LocalSystemSid ))
1794+ {
1795+ fprintf (stderr ,"could not get SID for local system account\n" );
1796+ CloseHandle (AccessToken );
1797+ return -1 ;
1798+ }
1799+
1800+ if (EqualSid (LocalSystemSid ,User -> User .Sid ))
1801+ {
1802+ FreeSid (LocalSystemSid );
1803+ free (InfoBuffer );
1804+ CloseHandle (AccessToken );
1805+ _is_service = 1 ;
1806+ return _is_service ;
1807+ }
1808+
1809+ FreeSid (LocalSystemSid );
1810+ free (InfoBuffer );
1811+
1812+ /* Now check for group SID */
1813+ if (!pgwin32_get_dynamic_tokeninfo (AccessToken ,TokenGroups ,& InfoBuffer ,
1814+ errbuf ,sizeof (errbuf )))
1815+ {
1816+ fprintf (stderr ,"%s" ,errbuf );
1817+ return -1 ;
1818+ }
1819+
1820+ Groups = (PTOKEN_GROUPS )InfoBuffer ;
1821+
1822+ if (!AllocateAndInitializeSid (& NtAuthority ,1 ,
1823+ SECURITY_SERVICE_RID ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,
1824+ & ServiceSid ))
1825+ {
1826+ fprintf (stderr ,"could not get SID for service group\n" );
1827+ free (InfoBuffer );
1828+ CloseHandle (AccessToken );
1829+ return -1 ;
1830+ }
1831+
1832+ _is_service = 0 ;
1833+ for (x = 0 ;x < Groups -> GroupCount ;x ++ )
1834+ {
1835+ if (EqualSid (ServiceSid ,Groups -> Groups [x ].Sid ))
1836+ {
1837+ _is_service = 1 ;
1838+ break ;
1839+ }
1840+ }
1841+
1842+ free (InfoBuffer );
1843+ FreeSid (ServiceSid );
1844+
1845+ CloseHandle (AccessToken );
1846+
1847+ return _is_service ;
1848+ }
1849+
16921850
16931851/*
16941852 * Mingw headers are incomplete, and so are the libraries. So we have to load