#include<Windows.h>
#include<tchar.h>
#include<WtsApi32.h>
#include<sddl.h>
#include"Header.h"

#pragma comment(lib, "wtsapi32")
#pragma	comment(lib, "Advapi32")

#define	MAX_ACCOUNTNAME_LEN	1024
#define MAX_DOMAINNAME_LEN	1024


int main(void) {


	// Can you believe we are using the Remote Desktop API to list local processes? :-)  
	// WTSEnumerateProcessesEx https://msdn.microsoft.com/en-us/library/windows/desktop/ee621013(v=vs.85).aspx
	//  WTS_PROCESS_INFO_EX:  https://msdn.microsoft.com/en-us/library/windows/desktop/ee621026(v=vs.85).aspx
	// Important to remember:
	// The caller must be a member of the Administrators group to enumerate processes that are running under 
	// another user session.

	

	DWORD	level = 1; // As we want a  WTS_PROCESS_INFO_EX structure
	PWTS_PROCESS_INFO_EX processListing = NULL;
	DWORD	processCount = 0;

	if (!WTSEnumerateProcessesEx(
				WTS_CURRENT_SERVER_HANDLE, 
				&level, 
				WTS_ANY_SESSION, 
				(LPTSTR *)&processListing, 
				&processCount) )
	{

		ErrorDetails(_T("WTSEnumerateProcessesEx"), false);
	}

	// Parse the process information

	_tprintf(_T("Processes Found: %d\n\n"), processCount);
	LPTSTR stringSID = NULL;
	PWTS_PROCESS_INFO_EX originalPtr = processListing;

	_tprintf(_T("#\tPID\tHandles\tThreads\tProcess Name\tSID\tAccount\n\n"));

	for (DWORD counter = 1; counter <= processCount; counter++) {

		_tprintf(_T("%d\t"), counter);
		_tprintf(_T("%d\t"), processListing->ProcessId);
		_tprintf(_T("%d\t"), processListing->HandleCount);
		_tprintf(_T("%d\t"), processListing->NumberOfThreads);
		_tprintf(_T("%s\t"), processListing->pProcessName);

		// Let's try and print the SID and the associated accounts
		// Well known: https://support.microsoft.com/en-in/help/243330/well-known-security-identifiers-in-windows-operating-systems

		// Convert SID to string 

		if (!ConvertSidToStringSid(processListing->pUserSid, &stringSID)) {

			ErrorDetails(_T("ConvertSidToStringSid"), false);
			//_tprintf(_T("-\t"));
		}
		else {

			_tprintf(_T("%s\t"), stringSID);
			LocalFree((HLOCAL)stringSID);  // Our job to free this chap!
		}

		// Let's also try and get the account name with the SID
		// LookupAccountSid https://msdn.microsoft.com/en-us/library/windows/desktop/aa379166(v=vs.85).aspx

		TCHAR accountName[MAX_ACCOUNTNAME_LEN];
		DWORD bufferLen = MAX_ACCOUNTNAME_LEN;
		TCHAR domainName[MAX_DOMAINNAME_LEN];
		DWORD domainNameBufferLen = MAX_DOMAINNAME_LEN;
		SID_NAME_USE peUse;

		if (!LookupAccountSid(
					NULL, 
					processListing->pUserSid, 
					accountName, 
					&bufferLen,
					domainName,
					&domainNameBufferLen,
					&peUse)
			) 
		{

			ErrorDetails(_T("LookupAccountSid"), false);
			//_tprintf(_T("\n"));

		}
		else {
			// Print the account name 
			//_tprintf(_T("%s\t%s\n"), accountName, domainName);
			_tprintf(_T("%s\\%s\n"), domainName, accountName);

		}

		// move on to the next entry!
		processListing++;

	}


	// Free the memory!
	// WTSFreeMemoryEx https://msdn.microsoft.com/en-us/library/ee621015(v=vs.85).aspx 

	if (!WTSFreeMemoryEx(WTSTypeProcessInfoLevel1, originalPtr, processCount)) {

		ErrorDetails(_T("WTSFreeMemoryEx"), false);
	}
	processListing = NULL;

	_tprintf(_T("\n\nDone! Please any key to exit()\n"));

	getchar();
	return	0;

}