/*
 * Tool name   : WhoIsLoggedIn
 * Description : Tool to list all users that are currently loggedin
 *               on a system.
 * Version     : 0.1
 * OS          : Tested on Microsoft Windows XP
 * Todo        : -
 *
 * Changes     : - 
 * 
 *
 */

#include <windows.h>
#include <WtsApi32.h>
#include <Ntsecapi.h>
#include <shellapi.h>
#include <lm.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#define MAX_BUF_SIZE 1024
#define STATUS_SUCCESS ((NTSTATUS)0x00000000L)

#pragma comment(lib, "Secur32.lib")
#pragma comment(lib, "Advapi32.lib")



/*
 * Constants, data types and function forward declarations.
 *
 */


char *enumerateLoggedInUsers(void);
char *addDataToBuffer(char *pOldData, int *pOldDataSize, char *pNewData, int pNewDataSize);



/*
 * Program entry point
 *
 */

int main()
{
  int lRetVal = 0;
  char *lTempBuf = NULL;




  /*
   * Enumerate all logged in users.
   *
   */

  if ((lTempBuf = enumerateLoggedInUsers()) != NULL)
  {
    printf("\n\nLogged in users\n_______________\n\n%s\n\n\n", lTempBuf);
    HeapFree(GetProcessHeap(), 0, lTempBuf);
    lTempBuf = NULL;
  }

  printf("\n\nHit return to stop execution ...\n");
  getc(stdin);

  return(lRetVal);
}




/*
 * List all local user account information
 *
 */

char *enumerateLoggedInUsers()
{
  PSECURITY_LOGON_SESSION_DATA lSessionData = NULL;
  PLUID lSessions;
  ULONG lSessionCounter = 0;
  int lCounter = 0;
  WCHAR lBuffer[MAX_BUF_SIZE + 1];
  WCHAR *lUnicodeBuffer;
  int lUnicodeLength;
  char lTemp[MAX_BUF_SIZE + 1];
  char lUserName[MAX_BUF_SIZE + 1];
  char lLogonType[MAX_BUF_SIZE + 1];
  char lAuthPackage[MAX_BUF_SIZE + 1];
  char lLogonDomainName[MAX_BUF_SIZE + 1];
  char *lRetVal = NULL;
  int lBufSize = 0;
  

  ZeroMemory(lTemp, sizeof(lTemp));
  _snprintf(lTemp, sizeof(lTemp) - 1, "\n\n%-20s %-30s  %-15s  %-20s\n\n", "Username", "Logon type", "Auth. type", "Domain");
  lRetVal = addDataToBuffer(lRetVal, &lBufSize, lTemp, strlen(lTemp));


  if (LsaEnumerateLogonSessions(&lSessionCounter, &lSessions) == STATUS_SUCCESS)
  {

    /*
     * List logged in users and some more session details
     *
     */

    for (lCounter = 0; lCounter < (int) lSessionCounter; lCounter++)
    {
      /*
       * Buffer initialisation.
       * 
       */

      ZeroMemory(lUserName, sizeof(lUserName));
      ZeroMemory(lLogonType, sizeof(lLogonType));
      ZeroMemory(lAuthPackage, sizeof(lAuthPackage));
      ZeroMemory(lLogonDomainName, sizeof(lLogonDomainName));


      /*
       * Get the session information.
       *
       */
      if ((LsaGetLogonSessionData (&lSessions[lCounter], &lSessionData)) == STATUS_SUCCESS) 
      {

        /*
         * Determine user name.
         *
         */

        if ((lSessionData->UserName).Length <= 0 && lSessionData->UserName.Buffer != NULL)
        {
		  strncpy(lUserName, "NO USERNAME", sizeof(lUserName) - 1);
        } else if (lSessionData->UserName.Buffer != NULL) {
          // Get the user name.
          lUnicodeBuffer = (lSessionData->UserName).Buffer;
          lUnicodeLength = (lSessionData->UserName).Length;

          if(lUnicodeLength < 256)
          {
            lstrcpyn (lBuffer, lUnicodeBuffer, lUnicodeLength);
            lstrcat (lBuffer,L"");
          }

          wcstombs(lTemp, lUnicodeBuffer, sizeof(lTemp));
          strncpy(lUserName, lTemp, sizeof(lUserName) - 1);
        } // if ((lSessionData->UserNa...



        /*
         * Session type.
         *
         */

        if ((SECURITY_LOGON_TYPE) lSessionData->LogonType == Interactive)
          _snprintf(lLogonType, sizeof(lLogonType) - 1, "%-30s  ", "(local/interactive user) ");
        else if ((SECURITY_LOGON_TYPE) lSessionData->LogonType == RemoteInteractive)
          _snprintf(lLogonType, sizeof(lLogonType) - 1, "%-30s  ", "(remote interactive user) ");
        else if ((SECURITY_LOGON_TYPE) lSessionData->LogonType == Service)
          _snprintf(lLogonType, sizeof(lLogonType) - 1, "%-30s  ", "(local service) ");
        else if ((SECURITY_LOGON_TYPE) lSessionData->LogonType == NetworkCleartext)
          _snprintf(lLogonType, sizeof(lLogonType) - 1, "%-30s  ", "(via vetwork, cleartext) ");
        else if ((SECURITY_LOGON_TYPE) lSessionData->LogonType == Batch)
          _snprintf(lLogonType, sizeof(lLogonType) - 1, "%-30s  ", "(batch) ");
        else if ((SECURITY_LOGON_TYPE) lSessionData->LogonType == Proxy)
          _snprintf(lLogonType, sizeof(lLogonType) - 1, "%-30s  ", "(proxy) ");
        else if ((SECURITY_LOGON_TYPE) lSessionData->LogonType == Network)
          _snprintf(lLogonType, sizeof(lLogonType) - 1, "%-30s  ", "(network) ");
        else if ((SECURITY_LOGON_TYPE) lSessionData->LogonType == Unlock)
          _snprintf(lLogonType, sizeof(lLogonType) - 1, "%-30s  ", "(unlock) ");
        else if ((SECURITY_LOGON_TYPE) lSessionData->LogonType == NewCredentials)
          _snprintf(lLogonType, sizeof(lLogonType) - 1, "%-30s  ", "(newcredentials) ");
        else if ((SECURITY_LOGON_TYPE) lSessionData->LogonType == CachedInteractive)
          _snprintf(lLogonType, sizeof(lLogonType) - 1, "%-30s  ", "(cachedinteractive) ");
        else
          _snprintf(lLogonType, sizeof(lLogonType) - 1, "%-30s  ", "(unknown auth. type) ");


        /*
         * Authentication package.
         *
         */

        if (lSessionData->AuthenticationPackage.Buffer != NULL)
        {
          // Get the authentication package name.
          lUnicodeBuffer = (lSessionData->AuthenticationPackage).Buffer;
          lUnicodeLength = (lSessionData->AuthenticationPackage).Length;

          if(lUnicodeLength < 256)
          {
            lstrcpyn(lBuffer, lUnicodeBuffer, lUnicodeLength);
            lstrcat(lBuffer, L"");
          }

          wcstombs(lTemp, lUnicodeBuffer, sizeof(lTemp));
          strncpy(lAuthPackage, lTemp, sizeof(lAuthPackage));
        } // if (lSessionData->Authen...



        /*
         * Logon Domain name.
         *
         */

        if (lSessionData->LogonDomain.Buffer != NULL)
        {
          // Get the domain name.
          lUnicodeBuffer = (lSessionData->LogonDomain).Buffer;
          lUnicodeLength = (lSessionData->LogonDomain).Length;

          if(lUnicodeLength < MAX_BUF_SIZE)
          {
            lstrcpyn(lBuffer, lUnicodeBuffer, lUnicodeLength);
            lstrcat(lBuffer, L"");
          }

          if (Interactive == lSessionData->LogonType)
		  {
            wcstombs(lTemp, lUnicodeBuffer, sizeof(lTemp));
            strncpy(lLogonDomainName, lTemp, sizeof(lLogonDomainName));
		  }
        } // if (lSessionData->LogonDomain.B...





        // If session information was returned, free it.
        LsaFreeReturnBuffer(lSessionData);
	  } // if ((LsaGetLogonSessionD...

      ZeroMemory(lTemp, sizeof(lTemp));
      _snprintf(lTemp, sizeof(lTemp) - 1, "%-20s %-30s %-15s %-20s\n", lUserName, lLogonType, lAuthPackage, lLogonDomainName);
      lRetVal = addDataToBuffer(lRetVal, &lBufSize, lTemp, strlen(lTemp));
    } // for (lCounter = 0; lCou...
  } else {
    ZeroMemory(lTemp, sizeof(lTemp));
    _snprintf(lTemp, sizeof(lTemp) - 1, "LsaEnumerate failed %lu\n", LsaNtStatusToWinError(lRetVal));
    lRetVal = addDataToBuffer(lRetVal, &lBufSize, lTemp, strlen(lTemp));
  } // if ((lRetVal = LsaEnumerateL...

  return(lRetVal);
}




/*
 * 
 *
 */

char *addDataToBuffer(char *pOldData, int *pOldDataSize, char *pNewData, int pNewDataSize)
{
  char *lRetVal = NULL;


  /*
   * Allocate the Buffer on the heap.
   *
   */

  if (pOldData == NULL)
  {
    if ((lRetVal = (char *) HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, pNewDataSize + 1)) != NULL)
	{
      CopyMemory(lRetVal, pNewData, pNewDataSize);
	  *pOldDataSize = pNewDataSize;
	} // if (lRetVal = ...






  /*
   * Rellocate the Buffer on the heap. In case of failure
   * release all the allocated buffer area.
   *
   */

  } else {
    if ((lRetVal = (char *) HeapReAlloc(GetProcessHeap(), 0, pOldData, *pOldDataSize + pNewDataSize )) != NULL)
	{
      ZeroMemory(&lRetVal[*pOldDataSize], pNewDataSize);
	  CopyMemory(&lRetVal[*pOldDataSize], pNewData, pNewDataSize);
      *pOldDataSize += pNewDataSize;
	} else {
      HeapFree(GetProcessHeap(), 0, pOldData);
      lRetVal = NULL;
	}
  } // if (pOldBuffer == ...

  return(lRetVal);
}
