==========
mswin32/S6_API-Base_Console #109607, from Rohan_Phillips, 9586 chars, 26-Sep-95  18:16:07
Comment to 109588.
----------
Subject: Am i a service?
Fm: Rohan Phillips 72420,3522
To: Dick Beck 74260,3034

Dick,

Try the code below.  It's given to you with the notice that there
is no support for it.  Just something a friend wrote.

 /* @comm CService::CheckSIDs() determines whether the current process is
executing as a console process or a service by enumerating the process
token.
If the process token contains a SECURITY_INTERACTIVE_RID SID, then the
process is running as a console process.  If the token contains a
SECURITY_SERVICE_RID SID, then the process is running as a service in a user
account.  If neither of these cases are true, then the process is running as
a service in the LOCAL_SYSTEM account.  If the service is running under the
LOCAL_SYSTEM account, it may have access to the desktop which is determined
by checking the service's service_type for SERVICE_INTERACTIVE_PROCESS.  If
the service is interactive, a console is allocated and stdout and stderr
redirected to it
 */

DWORD CService::CheckSIDs(void)
{
	HANDLE hProcessToken = NULL;
	DWORD groupLength = 50;
	PTOKEN_GROUPS groupInfo = NULL;

	SID_IDENTIFIER_AUTHORITY siaNt = SECURITY_NT_AUTHORITY;
	PSID pInteractiveSid = NULL;
	PSID pServiceSid = NULL;

	DWORD dwRet = NO_ERROR;

	DWORD ndx;

	// open the token
	if (!::OpenProcessToken(::GetCurrentProcess(),
		TOKEN_QUERY, &hProcessToken))
	{
		dwRet = ::GetLastError();
		goto closedown;
	}

	// allocate a buffer of default size
	groupInfo = (PTOKEN_GROUPS)::LocalAlloc(0, groupLength);
	if (groupInfo == NULL)
	{
		dwRet = ::GetLastError();
		goto closedown;
	}

	// try to get the info
	if (!::GetTokenInformation(hProcessToken, TokenGroups,
		groupInfo, groupLength, &groupLength))
	{
		// if buffer was too small, allocate to proper size, otherwise error
		if (::GetLastError() != ERROR_INSUFFICIENT_BUFFER)
		{
			dwRet = ::GetLastError();
			goto closedown;
		}

		::LocalFree(groupInfo);

		groupInfo = (PTOKEN_GROUPS)::LocalAlloc(0, groupLength);
		if (groupInfo == NULL)
		{
			dwRet = ::GetLastError();
			goto closedown;
		}

		if (!GetTokenInformation(hProcessToken, TokenGroups,
			groupInfo, groupLength, &groupLength))
		{
			dwRet = ::GetLastError();
			goto closedown;
		}
	}

	//
	//  We now know the groups associated with this token.  We want
	//  to look to see if the interactive group is active in the
	//  token, and if so, we know that this is an interactive process.
	//
	//  We also look for the "service" SID, and if it's present,
	//  we know we're a service.
	//
	//  The service SID will be present iff the service is running in a
	//  user account (and was invoked by the service controller).
	//

	// create comparison sids
	if (!AllocateAndInitializeSid(&siaNt, 1, SECURITY_INTERACTIVE_RID,
		0, 0, 0, 0, 0, 0, 0, &pInteractiveSid))
	{
		dwRet = ::GetLastError();
		goto closedown;
	}

	if (!AllocateAndInitializeSid(&siaNt, 1, SECURITY_SERVICE_RID,
		0, 0, 0, 0, 0, 0, 0, &pServiceSid))
	{
		dwRet = ::GetLastError();
		goto closedown;
	}


	// reset flags
	m_isInteractive = FALSE;
	m_isService = FALSE;

	// try to match sids
	for (ndx = 0; ndx < groupInfo->GroupCount ; ndx += 1)
	{
		SID_AND_ATTRIBUTES sanda = groupInfo->Groups[ndx];
		PSID pSid = sanda.Sid;

		//
		//	  Check to see if the group we're looking at is one of
		//	  the two groups we're interested in.
		//

		if (::EqualSid(pSid, pInteractiveSid))
		{
			//
			//  This process has the Interactive SID in its
			//  token.  This means that the process is running as
			//  a console process
			//
			m_isInteractive = TRUE;
			m_isService = FALSE;
			break;
		}
		else if (::EqualSid(pSid, pServiceSid))
		{
			//
			//  This process has the Service SID in its
			//  token.  This means that the process is running as
			//  a service running in a user account ( not local system ).
			//
			m_isService = TRUE;
			m_isInteractive = FALSE;
			break;
		}
	}

	if ( !( m_isService || m_isInteractive ) )
	{
		//
		//  Neither Interactive or Service was present in the current
		//  users token, This implies that the process is running as
		//  a service, most likely running as LocalSystem.
		//
		m_isService = TRUE;

		// determine if the local system service is interactive.  We
		// do this y looking in the service's registry and checking
		// the Type value for the SERVICE_INTERACTIVE_PROCESS bit

		HKEY  hkey = NULL;

		TCHAR szKey[256];

		SPRINTF( szKey, TEXT("SYSTEM\\CurrentControlSet\\Services\\%s"),
			m_pServiceName );
		if ( RegOpenKeyEx( HKEY_LOCAL_MACHINE,
						   szKey,
						   0,
						   KEY_READ,
						   &hkey ) == ERROR_SUCCESS )
		{
			DWORD dwType = 0;
			DWORD dwSize = sizeof(DWORD);
			if ( RegQueryValueEx(hkey,
								 TEXT("Type"),
								 NULL,
								 NULL,
								 (LPBYTE) &dwType,
								 &dwSize ) == ERROR_SUCCESS )
			{
				if ( dwType & SERVICE_INTERACTIVE_PROCESS )
				{
					m_isInteractive = TRUE;

					// service was given permission to interact with the
					// with the desktop, so allocate a console
					FreeConsole();
					if ( AllocConsole() )
					{
						// Now re-map the C Runtime STDIO handles
						int hCrt = ::_open_osfhandle((long)
							GetStdHandle(STD_OUTPUT_HANDLE), _O_TEXT);

						*stdout = *(::_fdopen(hCrt, "w"));
						::setvbuf(stdout, NULL, _IONBF, 0);

						*stderr = *(::_fdopen(hCrt, "w"));
						::setvbuf(stderr, NULL, _IONBF, 0);

					}

					DWORD dwDebug = 0;
					DWORD dwDbgSize = sizeof(dwDebug);
					TCHAR szWindbgPath[256];
					DWORD dwPathSize = sizeof(szWindbgPath);
					if (
					   ( RegQueryValueEx(hkey,
										 TEXT("Debug"),
										 NULL,
										 NULL,
										 (LPBYTE) &dwDebug,
										 &dwDbgSize ) == ERROR_SUCCESS )
					   &&
					   ( RegQueryValueEx(hkey,
										 TEXT("WindbgPath"),
										 NULL,
										 NULL,
										 (LPBYTE) szWindbgPath,
										 &dwPathSize ) == ERROR_SUCCESS )
					   )
					{
						if( dwDebug )  // 1 if debug
						{
							PROCESS_INFORMATION pi;
							STARTUPINFO		 si;		// startup info

							si.cb		  = sizeof( STARTUPINFO );
							si.lpReserved  = NULL;
							si.lpDesktop   = NULL;
							si.lpTitle	 = NULL;
							si.dwX		 = 0;
							si.dwY		 = 0;
							si.dwXSize	 = 0;
							si.dwYSize	 = 0;
							si.dwFlags	 = (DWORD) NULL;
							si.wShowWindow = SW_SHOWDEFAULT;
							si.cbReserved2 = 0;
							si.lpReserved2 = NULL;

							pi.hProcess  = NULL;

							TCHAR szCmd[300];
							_stprintf( szCmd, _T("%s -g -p 0x%x"),
								szWindbgPath, GetCurrentProcessId() );
							//-- now create the windbg process
							if( CreateProcess(
								   NULL, szCmd,
								   (LPSECURITY_ATTRIBUTES) NULL,
								   (LPSECURITY_ATTRIBUTES) NULL,
								   TRUE,
								   DETACHED_PROCESS,
								   (LPVOID) NULL,
								   (LPTSTR) NULL,
								   &si, &pi ) )
							{
								CloseHandle( pi.hThread );
								CloseHandle( pi.hProcess );
							}
						}
					}

				}
			}

			RegCloseKey( hkey );
		}


	}


	closedown:
		if ( pServiceSid )
			::FreeSid( pServiceSid );

		if ( pInteractiveSid )
			::FreeSid( pInteractiveSid );

		if ( groupInfo )
			::LocalFree( groupInfo );

		if ( hProcessToken )
			::CloseHandle( hProcessToken );

	return dwRet;
}


