@@ -149,6 +149,10 @@ static void WINAPI pgwin32_ServiceHandler(DWORD);
149
149
static void WINAPI pgwin32_ServiceMain (DWORD ,LPTSTR * );
150
150
static void pgwin32_doRunAsService (void );
151
151
static 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 );
152
156
#endif
153
157
154
158
static pgpid_t get_pgpid (bool is_status_request );
@@ -216,7 +220,7 @@ write_stderr(const char *fmt,...)
216
220
* On Win32, we print to stderr if running on a console, or write to
217
221
* eventlog if running as a service
218
222
*/
219
- if (!isatty ( fileno ( stderr ) ))/* Running as a service */
223
+ if (!pgwin32_is_service ( ))/* Running as a service */
220
224
{
221
225
char errbuf [2048 ];/* Arbitrary size? */
222
226
@@ -1689,6 +1693,160 @@ pgwin32_doRunAsService(void)
1689
1693
}
1690
1694
}
1691
1695
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
+
1692
1850
1693
1851
/*
1694
1852
* Mingw headers are incomplete, and so are the libraries. So we have to load