@ -146,6 +146,10 @@ static void WINAPI pgwin32_ServiceHandler(DWORD);
static void WINAPI pgwin32_ServiceMain ( DWORD , LPTSTR * ) ;
static void WINAPI pgwin32_ServiceMain ( DWORD , LPTSTR * ) ;
static void pgwin32_doRunAsService ( void ) ;
static void pgwin32_doRunAsService ( void ) ;
static int CreateRestrictedProcess ( char * cmd , PROCESS_INFORMATION * processInfo , bool as_service ) ;
static int CreateRestrictedProcess ( char * cmd , PROCESS_INFORMATION * processInfo , bool as_service ) ;
static bool pgwin32_get_dynamic_tokeninfo ( HANDLE token ,
TOKEN_INFORMATION_CLASS class ,
char * * InfoBuffer , char * errbuf , int errsize ) ;
static int pgwin32_is_service ( void ) ;
# endif
# endif
static pgpid_t get_pgpid ( void ) ;
static pgpid_t get_pgpid ( void ) ;
@ -211,7 +215,7 @@ write_stderr(const char *fmt,...)
* On Win32 , we print to stderr if running on a console , or write to
* On Win32 , we print to stderr if running on a console , or write to
* eventlog if running as a service
* eventlog if running as a service
*/
*/
if ( ! isatty ( fileno ( stderr ) ) ) /* Running as a service */
if ( ! pgwin32_is_service ( ) ) /* Running as a service */
{
{
char errbuf [ 2048 ] ; /* Arbitrary size? */
char errbuf [ 2048 ] ; /* Arbitrary size? */
@ -1594,6 +1598,160 @@ pgwin32_doRunAsService(void)
}
}
}
}
/*
* 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: got zero size \n " ) ;
return false ;
}
if ( GetLastError ( ) ! = ERROR_INSUFFICIENT_BUFFER )
{
snprintf ( errbuf , errsize , " could not get token information: 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 ;
}
/*
* We consider ourselves running as a service if one of the following is
* true :
*
* 1 ) We are running as Local System ( only used by services )
* 2 ) Our token contains SECURITY_SERVICE_RID ( automatically added to the
* process token by the SCM when starting a service )
*
* Return values :
* 0 = Not service
* 1 = Service
* - 1 = Error
*
* Note : we can ' t report errors via 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 ;
HANDLE AccessToken ;
char * InfoBuffer = NULL ;
char errbuf [ 256 ] ;
PTOKEN_GROUPS Groups ;
PTOKEN_USER User ;
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 ;
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 ) ;
return - 1 ;
}
if ( EqualSid ( LocalSystemSid , User - > User . Sid ) )
{
FreeSid ( LocalSystemSid ) ;
free ( InfoBuffer ) ;
CloseHandle ( AccessToken ) ;
_is_service = 1 ;
return _is_service ;
}
FreeSid ( LocalSystemSid ) ;
free ( InfoBuffer ) ;
/* Now check for group SID */
if ( ! pgwin32_get_dynamic_tokeninfo ( AccessToken , TokenGroups , & InfoBuffer ,
errbuf , sizeof ( errbuf ) ) )
{
fprintf ( stderr , " %s " , errbuf ) ;
return - 1 ;
}
Groups = ( PTOKEN_GROUPS ) InfoBuffer ;
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 ) ;
return - 1 ;
}
_is_service = 0 ;
for ( x = 0 ; x < Groups - > GroupCount ; x + + )
{
if ( EqualSid ( ServiceSid , Groups - > Groups [ x ] . Sid ) )
{
_is_service = 1 ;
break ;
}
}
free ( InfoBuffer ) ;
FreeSid ( ServiceSid ) ;
CloseHandle ( AccessToken ) ;
return _is_service ;
}
/*
/*
* Mingw headers are incomplete , and so are the libraries . So we have to load
* Mingw headers are incomplete , and so are the libraries . So we have to load