/*++ Copyright (c) Microsoft Corporation Module Name: wssid.cpp Abstract: This file gets the security identifier (SID) for respective user name and groups in the current access token on a local system or a remote system. Authors: Christophe Robert Revision History: 02-July-2001 : Updated by Wipro Technologies. --*/ //common header files needed for this file #include "pch.h" #include "CommonHeaderFiles.h" WsSid::WsSid ( VOID ) /*++ Routine Description: This function intializes the members of WsSid class. Arguments: None Return Value: None --*/ { // initializing member variables pSid = NULL ; bToBeFreed = FALSE ; } WsSid::~WsSid ( VOID ) /*++ Routine Description: This function deallocates the members of WsSid class. Arguments: None Return Value: None --*/ { // release memory if ( bToBeFreed && pSid ){ FreeMemory ( (LPVOID *) &pSid ) ; } } DWORD WsSid::DisplayAccountName ( IN DWORD dwFormatType , IN DWORD dwNameFormat ) /*++ Routine Description: This function displays the user name and SID. Arguments: [IN] DWORD dwFormatType : Format type i.,e LIST, CSV or TABLE [IN] DWORD dwNameFormat : Name Format either UPN or FQDN Return Value: EXIT_SUCCESS : On success EXIT_FAILURE : On failure --*/ { // sub-local variables WCHAR wszUserName[ MAX_STRING_LENGTH ]; WCHAR wszSid [ MAX_STRING_LENGTH ]; WCHAR wszGroup[MAX_STRING_LENGTH]; DWORD dwErr = 0 ; DWORD dwColCount = 0 ; DWORD dw = 0 ; DWORD dwCount = 0 ; DWORD dwArrSize = 0 ; DWORD dwSize = 0; DWORD dwUserLen = 0; DWORD dwSidLen = 0; DWORD dwUserColLen = 0; DWORD dwSidColLen = 0; DWORD dwSidUse = 0; LPWSTR wszBuffer = NULL; //initialize memory SecureZeroMemory ( wszUserName, SIZE_OF_ARRAY(wszUserName) ); SecureZeroMemory ( wszSid, SIZE_OF_ARRAY(wszSid) ); SecureZeroMemory ( wszGroup, SIZE_OF_ARRAY(wszGroup) ); // create a dynamic array TARRAY pColData = CreateDynamicArray(); if ( NULL == pColData) { // set last error and display an error message with respect //to ERROR_NOT_ENOUGH_MEMORY SetLastError((DWORD)E_OUTOFMEMORY); SaveLastError(); ShowLastErrorEx (stderr, SLE_TYPE_ERROR | SLE_SYSTEM); return EXIT_FAILURE; } dwSize = SIZE_OF_ARRAY(wszGroup); //if /FQDN is specified if ( (FQDN_FORMAT == dwNameFormat) ) { //Get the username in FQDN format if (GetUserNameEx ( NameFullyQualifiedDN, wszGroup, &dwSize) == FALSE ) { // GetUserNameEx() got failed due to small size specified for username. // allocate the actual size (dwSize) of username and call the same // function again... wszBuffer = (LPWSTR) AllocateMemory(dwSize * sizeof(WCHAR)); if ( NULL == wszBuffer ) { // display system error message with respect to GetLastError() ShowLastErrorEx ( stderr, SLE_TYPE_ERROR | SLE_SYSTEM ); return EXIT_FAILURE; } if (GetUserNameEx ( NameFullyQualifiedDN, wszBuffer, &dwSize) == FALSE ) { // display an error messaga as.. unable to get FQDN name // as logged-on user is not a domain user ShowMessage ( stderr, GetResString (IDS_ERROR_FQDN) ); DestroyDynamicArray(&pColData); FreeMemory ((LPVOID*) &wszBuffer); return EXIT_FAILURE ; } ShowMessage ( stdout, _X(wszBuffer)); ShowMessage ( stdout, L"\n"); FreeMemory ((LPVOID*) &wszBuffer); DestroyDynamicArray(&pColData); // return success return EXIT_SUCCESS; } ShowMessage ( stdout, _X(wszGroup)); ShowMessage ( stdout, L"\n"); DestroyDynamicArray(&pColData); // return success return EXIT_SUCCESS; } else if ( (UPN_FORMAT == dwNameFormat ) ) { // get the user name in UPN format if ( GetUserNameEx ( NameUserPrincipal, wszGroup, &dwSize) == FALSE ) { // GetUserNameEx() got failed due to small size specified for username // allocate the actual size(dwSize) of username and call the same // function again... wszBuffer = (LPWSTR) AllocateMemory(dwSize * sizeof(WCHAR)); if ( NULL == wszBuffer ) { // display system error message with respect to GetLastError() ShowLastErrorEx ( stderr, SLE_TYPE_ERROR | SLE_SYSTEM ); return EXIT_FAILURE; } // get the user name in UPN format if ( GetUserNameEx ( NameUserPrincipal, wszBuffer, &dwSize) == FALSE ) { // display an error messaga as.. unable to get UPN name // as logged-on user is not a domain user ShowMessage ( stderr, GetResString (IDS_ERROR_UPN) ); // release memory DestroyDynamicArray(&pColData); FreeMemory ((LPVOID*) &wszBuffer); return EXIT_FAILURE ; } // convert UPN name in lower case letters CharLower ( wszBuffer ); // display UPN name ShowMessage ( stdout, _X(wszBuffer) ); ShowMessage ( stdout, L"\n"); // release memory DestroyDynamicArray(&pColData); FreeMemory ((LPVOID*) &wszBuffer); //return success return EXIT_SUCCESS; } // convert UPN name in lower case letters CharLower ( wszGroup ); // display UPN name ShowMessage ( stdout, _X(wszGroup) ); ShowMessage ( stdout, L"\n"); DestroyDynamicArray(&pColData); //return success return EXIT_SUCCESS; } // get user name if ( (dwErr = GetAccountName ( wszUserName, &dwSidUse)) != EXIT_SUCCESS ){ // display an error message with respect to Win32 error code ShowLastErrorEx(stderr, SLE_TYPE_ERROR | SLE_SYSTEM); DestroyDynamicArray(&pColData); return dwErr ; } // convery user name in lower case letters CharLower ( wszUserName ); // if /USER specified if ( USER_ONLY != dwNameFormat) { // display SID with respect to username if ( (dwErr = DisplaySid ( wszSid ) ) != EXIT_SUCCESS ){ DestroyDynamicArray(&pColData); return dwErr ; } } // get the length of user name dwUserLen = StringLengthInBytes (wszUserName); // get the length of SID dwSidLen = StringLengthInBytes (wszSid); // //To avoid localization problems, get the maximum length of column name and // values of respective columns // // Get the maximum length of a column name "UserName" dwUserColLen = StringLengthInBytes( GetResString(IDS_COL_USERNAME) ); if ( dwUserColLen > dwUserLen ) { dwUserLen = dwUserColLen; } // Get the maximum length of a column name "SID" dwSidColLen = StringLengthInBytes( GetResString(IDS_COL_SID) ); if ( dwSidColLen > dwSidLen ) { dwSidLen = dwSidColLen; } // defining verbose columns with the actual size TCOLUMNS pVerboseCols[] = { {L"\0",dwUserLen, SR_TYPE_STRING, COL_FORMAT_STRING, NULL, NULL}, {L"\0",dwSidLen,SR_TYPE_STRING,COL_FORMAT_STRING,NULL,NULL} }; // if /USER is specified if ( USER_ONLY == dwNameFormat ) { // display the user name StringCopy (pVerboseCols[dw].szColumn , GetResString(IDS_COL_USERNAME), MAX_RES_STRING); ShowMessage ( stdout, _X(wszUserName) ); ShowMessage ( stdout, L"\n"); // release memory DestroyDynamicArray(&pColData); return EXIT_SUCCESS; } else { //Load the column names for verbose mode for( dwColCount = IDS_COL_USERNAME , dw = 0 ; dwColCount <= IDS_COL_SID; dwColCount++, dw++) { StringCopy(pVerboseCols[dw].szColumn , GetResString(dwColCount), MAX_RES_STRING ); } // get the number of columns dwArrSize = SIZE_OF_ARRAY( pVerboseCols ); } //Start appending to the 2D array DynArrayAppendRow(pColData, dwArrSize); //Insert the user name DynArraySetString2(pColData, dwCount, USERNAME_COL_NUMBER, _X(wszUserName), 0); //Insert the SID string DynArraySetString2(pColData, dwCount, SID_COL_NUMBER, _X(wszSid), 0); // 1) If the display format is CSV.. then we should not display column headings.. // 2) If /NH is specified ...then we should not display column headings.. if ( !(( SR_FORMAT_CSV == dwFormatType ) || ((dwFormatType & SR_HIDECOLUMN) == SR_HIDECOLUMN))) { // display the headings before displaying the username and SID ShowMessage ( stdout, L"\n" ); ShowMessage ( stdout, GetResString ( IDS_LIST_USER_NAMES ) ); ShowMessage ( stdout, GetResString ( IDS_DISPLAY_USER_DASH ) ); } // display the actual values for user name and SID ShowResults(dwArrSize, pVerboseCols, dwFormatType, pColData); // release memory DestroyDynamicArray(&pColData); // return success return EXIT_SUCCESS; } DWORD WsSid::DisplayGroupName ( OUT LPWSTR wszGroupName, OUT LPWSTR wszGroupSid, IN DWORD *dwSidUseName) /*++ Routine Description: This function gets the group name and SID to display. Arguments: [OUT] LPWSTR wszGroupName : Stores group name [OUT] LPWSTR wszGroupSid : Stores group SID [IN] DWORD dwSidUseName : stores Sid use name Return Value: EXIT_SUCCESS : On success EXIT_FAILURE : On failure --*/ { // sub-local variables DWORD dwErr = 0 ; DWORD dwSidUse = 0; // display the user name if ( (dwErr = GetAccountName ( wszGroupName, &dwSidUse) ) != EXIT_SUCCESS ){ // display an error message with respect to Win32 error code ShowLastErrorEx(stderr, SLE_TYPE_ERROR | SLE_SYSTEM); return dwErr ; } // display SID if ( (dwErr = DisplaySid ( wszGroupSid ) ) != EXIT_SUCCESS ){ return dwErr ; } *dwSidUseName = dwSidUse; // return success return EXIT_SUCCESS; } DWORD WsSid::DisplaySid ( OUT LPWSTR wszSid ) /*++ Routine Description: This function gets the SID . Arguments: [OUT] LPWSTR wszSid : Stores SID string Return Value: EXIT_SUCCESS : On success EXIT_FAILURE : On failure --*/ { // sub-local variable DWORD dwErr = 0 ; // Get SID string if ( (dwErr = GetSidString (wszSid)) != EXIT_SUCCESS ) { return dwErr ; } // return success return EXIT_SUCCESS; } DWORD WsSid::GetAccountName ( OUT LPWSTR wszAccountName, OUT DWORD *dwSidType ) /*++ Routine Description: This function gets the account name and SID Arguments: [OUT] szAccountName : Stores user name [OUT] dwSidType : Stores Sid use name Return Value: EXIT_SUCCESS : On success EXIT_FAILURE : On failure --*/ { // sub-local variables SID_NAME_USE SidUse ; WCHAR wszUserName[ MAX_RES_STRING ]; WCHAR wszDomainName [ MAX_RES_STRING ]; DWORD dwUserLen = 0; DWORD dwDomainLen = 0; BOOL bNotResolved = FALSE; // initialize the variables SecureZeroMemory ( wszUserName, SIZE_OF_ARRAY(wszUserName) ); SecureZeroMemory ( wszDomainName, SIZE_OF_ARRAY(wszDomainName) ); // get the length of user name and group name dwUserLen = SIZE_OF_ARRAY ( wszUserName ); dwDomainLen = SIZE_OF_ARRAY ( wszDomainName ); // enable debug privileges if ( FALSE == EnableDebugPriv() ) { // return WIN32 error code return GetLastError () ; } // get user name and domain name with respective to SID if ( FALSE == LookupAccountSid ( NULL, // Local System pSid, wszUserName, &dwUserLen, wszDomainName, &dwDomainLen, &SidUse ) ){ if ( 0 == StringLength (wszUserName, 0)) { bNotResolved = TRUE; StringCopy ( wszAccountName, L" ", MAX_RES_STRING ); } else if ( ( 0 != StringLength (wszDomainName, 0) ) && ( 0 != StringLength (wszUserName, 0) ) ) { // return WIN32 error code return GetLastError () ; } } if ( FALSE == bNotResolved) { // check for empty domain name if ( 0 != StringLength ( wszDomainName, 0 ) ) { StringCopy ( wszAccountName, wszDomainName, MAX_RES_STRING ); StringConcat ( wszAccountName, SLASH , MAX_RES_STRING); StringConcat ( wszAccountName, wszUserName, MAX_RES_STRING ); } else { StringCopy ( wszAccountName, wszUserName, MAX_RES_STRING ); } } *dwSidType = (DWORD)SidUse; // return success return EXIT_SUCCESS ; } DWORD WsSid::GetSidString ( OUT LPWSTR wszSid ) /*++ Routine Description: This function gets the SID string. Arguments: [OUT] LPWSTR wszSid : Stores SID string Return Value: EXIT_SUCCESS : On success EXIT_FAILURE : On failure --*/ { // sub-local variables PSID_IDENTIFIER_AUTHORITY Auth ; PUCHAR lpNbSubAuth ; LPDWORD lpSubAuth = 0 ; UCHAR uloop ; WCHAR wszTmp[MAX_RES_STRING] ; WCHAR wszStr[ MAX_RES_STRING ] ; // initialize the variables SecureZeroMemory ( wszTmp, SIZE_OF_ARRAY(wszTmp) ); SecureZeroMemory ( wszStr, SIZE_OF_ARRAY(wszStr) ); //check for empty if ( NULL == pSid ) { return EXIT_FAILURE ; } //Is it a valid SID if ( FALSE == IsValidSid ( pSid ) ) { ShowMessage ( stderr, GetResString ( IDS_INVALID_SID ) ); return EXIT_FAILURE ; } //Add the revision StringCopy ( wszStr, SID_STRING, MAX_RES_STRING ); //Get identifier authority Auth = GetSidIdentifierAuthority ( pSid ) ; if ( NULL == Auth ) { // return WIN32 error code return GetLastError () ; } // format authority value if ( (Auth->Value[0] != 0) || (Auth->Value[1] != 0) ) { StringCchPrintf ( wszTmp, SIZE_OF_ARRAY(wszTmp), AUTH_FORMAT_STR1 , (ULONG)Auth->Value[0], (ULONG)Auth->Value[1], (ULONG)Auth->Value[2], (ULONG)Auth->Value[3], (ULONG)Auth->Value[4], (ULONG)Auth->Value[5] ); } else { StringCchPrintf ( wszTmp, SIZE_OF_ARRAY(wszTmp), AUTH_FORMAT_STR2 , (ULONG)(Auth->Value[5] ) + (ULONG)(Auth->Value[4] << 8) + (ULONG)(Auth->Value[3] << 16) + (ULONG)(Auth->Value[2] << 24) ); } StringConcat (wszStr, DASH , SIZE_OF_ARRAY(wszStr)); StringConcat (wszStr, wszTmp, SIZE_OF_ARRAY(wszStr)); //Get sub authorities lpNbSubAuth = GetSidSubAuthorityCount ( pSid ) ; if ( NULL == lpNbSubAuth ) { return GetLastError () ; } // loop through and get sub authority for ( uloop = 0 ; uloop < *lpNbSubAuth ; uloop++ ) { lpSubAuth = GetSidSubAuthority ( pSid,(DWORD)uloop ) ; if ( NULL == lpSubAuth ) { return GetLastError () ; } // convert long integer to a string _ultot (*lpSubAuth, wszTmp, BASE_TEN) ; StringConcat ( wszStr, DASH, SIZE_OF_ARRAY(wszStr) ) ; StringConcat (wszStr, wszTmp, SIZE_OF_ARRAY(wszStr) ) ; } StringCopy ( wszSid, wszStr, MAX_RES_STRING ); // retunr success return EXIT_SUCCESS ; } DWORD WsSid::Init ( OUT PSID pOtherSid ) /*++ Routine Description: This function Initializes the SID Arguments: [OUT] PSID pOtherSid : Stores SID string Return Value: EXIT_SUCCESS : On success EXIT_FAILURE : On failure --*/ { // sub-local variable DWORD dwSize ; // get the length of SID dwSize = GetLengthSid ( pOtherSid ) ; // allocate the memory with the actual size pSid = (PSID) AllocateMemory ( dwSize ) ; if ( NULL == pSid ) { // return WIN32 error code return GetLastError () ; } bToBeFreed = TRUE ; // copy SID if ( FALSE == CopySid ( dwSize, pSid, pOtherSid ) ){ return GetLastError () ; } // return success return EXIT_SUCCESS ; } BOOL WsSid::EnableDebugPriv() /*++ Routine Description: Enables the debug privliges for the current process so that this utility can terminate the processes on local system without any problem Arguments: NONE Return Value: TRUE upon successfull and FALSE if failed --*/ { // local variables LUID luidValue; BOOL bResult = FALSE; HANDLE hToken = NULL; TOKEN_PRIVILEGES tkp; // Retrieve a handle of the access token bResult = OpenProcessToken( GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES | TOKEN_ADJUST_GROUPS | TOKEN_QUERY, &hToken ); if ( bResult == FALSE ) { // save the error messaage and return SaveLastError(); return FALSE; } // Enable the SE_DEBUG_NAME privilege or disable // all privileges, depends on this flag. bResult = LookupPrivilegeValue( NULL, SE_DEBUG_NAME, &luidValue ); if ( bResult == FALSE ) { // save the error messaage and return SaveLastError(); CloseHandle( hToken ); return FALSE; } // prepare the token privileges structure tkp.PrivilegeCount = 1; tkp.Privileges[ 0 ].Luid = luidValue; tkp.Privileges[ 0 ].Attributes = SE_PRIVILEGE_ENABLED; // now enable the debug privileges in the token bResult = AdjustTokenPrivileges( hToken, FALSE, &tkp, sizeof( TOKEN_PRIVILEGES ), ( PTOKEN_PRIVILEGES ) NULL, ( PDWORD ) NULL ); if ( bResult == FALSE ) { // The return value of AdjustTokenPrivileges be texted SaveLastError(); CloseHandle( hToken ); return FALSE; } // close the opened handle object CloseHandle( hToken ); // enabled ... inform success return TRUE; }