You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
1206 lines
24 KiB
1206 lines
24 KiB
//
|
|
// systemsecurity.cpp
|
|
//
|
|
// Copyright (c) Microsoft Corp, 1998
|
|
//
|
|
// This file contains source code for logging as Local System
|
|
//
|
|
// History:
|
|
//
|
|
// Todds 8/15/98 Created
|
|
// Modified by Rohanp 4/26/2002
|
|
//
|
|
//
|
|
|
|
#include <nt.h>
|
|
#include <ntrtl.h>
|
|
#include <nturtl.h>
|
|
|
|
#include <windows.h>
|
|
#include <winbase.h>
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <wincrypt.h>
|
|
#include <userenv.h>
|
|
#include <lm.h>
|
|
#include <psapi.h>
|
|
|
|
#define MyAlloc(cb) HeapAlloc(GetProcessHeap(), 0, cb)
|
|
#define MyFree(pv) HeapFree(GetProcessHeap(), 0, pv)
|
|
#define WSZ_BYTECOUNT(s) (2 * wcslen(s) + 2)
|
|
|
|
#define MAX_BLOBS 20
|
|
#define MAX_PROCESSES 200
|
|
#define MAX_SD 2048
|
|
#define BLOB_INCREMENT 0x4001 // 1 page + 1 byte...
|
|
|
|
|
|
DWORD
|
|
GetSystemProcessId(LPWSTR ProcessNameToFind,
|
|
DWORD * ProcessId);
|
|
|
|
|
|
|
|
//
|
|
// SetSidOnAcl
|
|
//
|
|
|
|
|
|
BOOL
|
|
SetSidOnAcl(
|
|
PSID pSid,
|
|
PACL pAclSource,
|
|
PACL *pAclDestination,
|
|
DWORD AccessMask,
|
|
BYTE AceFlags,
|
|
BOOL bAddSid
|
|
)
|
|
{
|
|
DWORD dwNewAclSize = 0, dwErr = 0;
|
|
LPVOID pAce = NULL;
|
|
DWORD AceCounter = 0;
|
|
BOOL bSuccess = FALSE; // assume this function will fail
|
|
ACL_SIZE_INFORMATION AclInfo;
|
|
|
|
//
|
|
// If we were given a NULL Acl, just provide a NULL Acl
|
|
//
|
|
if(pAclSource == NULL)
|
|
{
|
|
*pAclDestination = NULL;
|
|
return TRUE;
|
|
}
|
|
|
|
if(!IsValidSid(pSid))
|
|
{
|
|
return FALSE;
|
|
}
|
|
|
|
if(!GetAclInformation(
|
|
pAclSource,
|
|
&AclInfo,
|
|
sizeof(ACL_SIZE_INFORMATION),
|
|
AclSizeInformation
|
|
))
|
|
{
|
|
return FALSE;
|
|
}
|
|
|
|
//
|
|
// compute size for new Acl, based on addition or subtraction of Ace
|
|
//
|
|
if(bAddSid)
|
|
{
|
|
dwNewAclSize=AclInfo.AclBytesInUse +
|
|
sizeof(ACCESS_ALLOWED_ACE) +
|
|
GetLengthSid(pSid) -
|
|
sizeof(DWORD) ;
|
|
}
|
|
else
|
|
{
|
|
dwNewAclSize=AclInfo.AclBytesInUse -
|
|
sizeof(ACCESS_ALLOWED_ACE) -
|
|
GetLengthSid(pSid) +
|
|
sizeof(DWORD) ;
|
|
}
|
|
|
|
*pAclDestination = (PACL)MyAlloc(dwNewAclSize);
|
|
if(*pAclDestination == NULL)
|
|
{
|
|
return FALSE;
|
|
}
|
|
|
|
|
|
//
|
|
// initialize new Acl
|
|
//
|
|
if(!InitializeAcl(
|
|
*pAclDestination,
|
|
dwNewAclSize,
|
|
ACL_REVISION
|
|
))
|
|
{
|
|
dwErr = GetLastError();
|
|
goto ret;
|
|
}
|
|
|
|
//
|
|
// if appropriate, add ace representing pSid
|
|
//
|
|
if(bAddSid)
|
|
{
|
|
PACCESS_ALLOWED_ACE pNewAce = NULL;
|
|
|
|
if(!AddAccessAllowedAce(
|
|
*pAclDestination,
|
|
ACL_REVISION,
|
|
AccessMask,
|
|
pSid
|
|
))
|
|
{
|
|
dwErr = GetLastError();
|
|
goto ret;
|
|
}
|
|
|
|
//
|
|
// get pointer to ace we just added, so we can change the AceFlags
|
|
//
|
|
if(!GetAce(
|
|
*pAclDestination,
|
|
0, // this is the first ace in the Acl
|
|
(void**) &pNewAce
|
|
))
|
|
{
|
|
|
|
dwErr = GetLastError();
|
|
goto ret;
|
|
}
|
|
|
|
pNewAce->Header.AceFlags = AceFlags;
|
|
}
|
|
|
|
//
|
|
// copy existing aces to new Acl
|
|
//
|
|
for(AceCounter = 0 ; AceCounter < AclInfo.AceCount ; AceCounter++)
|
|
{
|
|
//
|
|
// fetch existing ace
|
|
//
|
|
if(!GetAce(pAclSource, AceCounter, &pAce))
|
|
{
|
|
dwErr = GetLastError();
|
|
goto ret;
|
|
}
|
|
|
|
//
|
|
// check to see if we are removing the Ace
|
|
//
|
|
if(!bAddSid)
|
|
{
|
|
//
|
|
// we only care about ACCESS_ALLOWED aces
|
|
//
|
|
if((((PACE_HEADER)pAce)->AceType) == ACCESS_ALLOWED_ACE_TYPE)
|
|
{
|
|
PSID pTempSid=(PSID)&((PACCESS_ALLOWED_ACE)pAce)->SidStart;
|
|
//
|
|
// if the Sid matches, skip adding this Sid
|
|
//
|
|
if(EqualSid(pSid, pTempSid)) continue;
|
|
}
|
|
}
|
|
|
|
//
|
|
// append ace to Acl
|
|
//
|
|
if(!AddAce(
|
|
*pAclDestination,
|
|
ACL_REVISION,
|
|
0xFFFF, // maintain Ace order //MAXDWORD
|
|
pAce,
|
|
((PACE_HEADER)pAce)->AceSize
|
|
))
|
|
{
|
|
|
|
dwErr = GetLastError();
|
|
goto ret;
|
|
}
|
|
}
|
|
|
|
bSuccess=TRUE; // indicate success
|
|
|
|
|
|
ret:
|
|
|
|
//
|
|
// free memory if an error occurred
|
|
//
|
|
if(!bSuccess)
|
|
{
|
|
if(*pAclDestination != NULL)
|
|
MyFree(*pAclDestination);
|
|
}
|
|
|
|
|
|
return bSuccess;
|
|
}
|
|
|
|
//
|
|
// AddSIDToKernelObject()
|
|
//
|
|
// This function takes a given SID and dwAccess and adds it to a given token.
|
|
//
|
|
// ** Be sure to restore old kernel object
|
|
// ** using call to GetKernelObjectSecurity()
|
|
//
|
|
BOOL
|
|
AddSIDToKernelObjectDacl(PSID pSid,
|
|
DWORD dwAccess,
|
|
HANDLE OriginalToken,
|
|
PSECURITY_DESCRIPTOR* ppSDOld)
|
|
{
|
|
|
|
PSECURITY_DESCRIPTOR pSD = NULL;
|
|
DWORD cbByte = MAX_SD, cbNeeded = 0, dwErr = 0;
|
|
PACL pOldDacl = NULL, pNewDacl = NULL;
|
|
BOOL fDaclPresent = FALSE, fDaclDefaulted = FALSE, fRet = FALSE;
|
|
SECURITY_DESCRIPTOR sdNew;
|
|
|
|
pSD = (PSECURITY_DESCRIPTOR) MyAlloc(cbByte);
|
|
if (NULL == pSD)
|
|
{
|
|
return FALSE;
|
|
}
|
|
|
|
if (!InitializeSecurityDescriptor(
|
|
&sdNew,
|
|
SECURITY_DESCRIPTOR_REVISION
|
|
))
|
|
{
|
|
|
|
dwErr = GetLastError();
|
|
goto ret;
|
|
}
|
|
|
|
if (!GetKernelObjectSecurity(
|
|
OriginalToken,
|
|
DACL_SECURITY_INFORMATION,
|
|
pSD,
|
|
cbByte,
|
|
&cbNeeded
|
|
))
|
|
{
|
|
|
|
dwErr = GetLastError();
|
|
if((cbNeeded > MAX_SD) && (dwErr == ERROR_MORE_DATA))
|
|
{
|
|
|
|
MyFree(pSD);
|
|
pSD = NULL;
|
|
pSD = (PSECURITY_DESCRIPTOR) MyAlloc(cbNeeded);
|
|
if (NULL == pSD)
|
|
{
|
|
dwErr = GetLastError();
|
|
goto ret;
|
|
}
|
|
|
|
dwErr = ERROR_SUCCESS;
|
|
if (!GetKernelObjectSecurity(
|
|
OriginalToken,
|
|
DACL_SECURITY_INFORMATION,
|
|
pSD,
|
|
cbNeeded,
|
|
&cbNeeded
|
|
))
|
|
{
|
|
dwErr = GetLastError();
|
|
}
|
|
|
|
}
|
|
|
|
if (dwErr != ERROR_SUCCESS)
|
|
{
|
|
goto ret;
|
|
}
|
|
}
|
|
|
|
if (!GetSecurityDescriptorDacl(
|
|
pSD,
|
|
&fDaclPresent,
|
|
&pOldDacl,
|
|
&fDaclDefaulted
|
|
))
|
|
{
|
|
dwErr = GetLastError();
|
|
goto ret;
|
|
}
|
|
|
|
if (!SetSidOnAcl(
|
|
pSid,
|
|
pOldDacl,
|
|
&pNewDacl,
|
|
dwAccess,
|
|
0,
|
|
TRUE
|
|
))
|
|
{
|
|
dwErr = GetLastError();
|
|
goto ret;
|
|
}
|
|
|
|
if (!SetSecurityDescriptorDacl(
|
|
&sdNew,
|
|
TRUE,
|
|
pNewDacl,
|
|
FALSE
|
|
))
|
|
{
|
|
dwErr = GetLastError();
|
|
goto ret;
|
|
}
|
|
|
|
if (!SetKernelObjectSecurity(
|
|
OriginalToken,
|
|
DACL_SECURITY_INFORMATION,
|
|
&sdNew
|
|
))
|
|
{
|
|
|
|
dwErr = GetLastError();
|
|
goto ret;
|
|
}
|
|
|
|
*ppSDOld = pSD;
|
|
fRet = TRUE;
|
|
|
|
ret:
|
|
|
|
if (NULL != pNewDacl)
|
|
{
|
|
MyFree(pNewDacl);
|
|
}
|
|
|
|
if (!fRet)
|
|
{
|
|
if (NULL != pSD)
|
|
{
|
|
MyFree(pSD);
|
|
*ppSDOld = NULL;
|
|
}
|
|
}
|
|
|
|
return fRet;
|
|
}
|
|
|
|
|
|
|
|
BOOL
|
|
SetPrivilege(
|
|
HANDLE hToken, // token handle
|
|
LPCTSTR Privilege, // Privilege to enable/disable
|
|
BOOL bEnablePrivilege // to enable or disable privilege
|
|
)
|
|
{
|
|
TOKEN_PRIVILEGES tp;
|
|
LUID luid;
|
|
TOKEN_PRIVILEGES tpPrevious;
|
|
DWORD cbPrevious=sizeof(TOKEN_PRIVILEGES);
|
|
|
|
if(!LookupPrivilegeValue( NULL, Privilege, &luid ))
|
|
{
|
|
return FALSE;
|
|
}
|
|
|
|
//
|
|
// first pass. get current privilege setting
|
|
//
|
|
tp.PrivilegeCount = 1;
|
|
tp.Privileges[0].Luid = luid;
|
|
tp.Privileges[0].Attributes = 0;
|
|
|
|
AdjustTokenPrivileges(
|
|
hToken,
|
|
FALSE,
|
|
&tp,
|
|
sizeof(TOKEN_PRIVILEGES),
|
|
&tpPrevious,
|
|
&cbPrevious
|
|
);
|
|
|
|
if (GetLastError() != ERROR_SUCCESS)
|
|
{
|
|
return FALSE;
|
|
}
|
|
|
|
//
|
|
// second pass. set privilege based on previous setting
|
|
//
|
|
tpPrevious.PrivilegeCount = 1;
|
|
tpPrevious.Privileges[0].Luid = luid;
|
|
|
|
if(bEnablePrivilege)
|
|
{
|
|
tpPrevious.Privileges[0].Attributes |= (SE_PRIVILEGE_ENABLED);
|
|
}
|
|
else
|
|
{
|
|
tpPrevious.Privileges[0].Attributes ^= (SE_PRIVILEGE_ENABLED &
|
|
tpPrevious.Privileges[0].Attributes);
|
|
}
|
|
|
|
AdjustTokenPrivileges(
|
|
hToken,
|
|
FALSE,
|
|
&tpPrevious,
|
|
cbPrevious,
|
|
NULL,
|
|
NULL
|
|
);
|
|
|
|
if (GetLastError() != ERROR_SUCCESS)
|
|
{
|
|
return FALSE;
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
BOOL
|
|
SetCurrentPrivilege(
|
|
LPCTSTR Privilege, // Privilege to enable/disable
|
|
BOOL bEnablePrivilege // to enable or disable privilege
|
|
)
|
|
{
|
|
BOOL bSuccess=FALSE; // assume failure
|
|
HANDLE hToken = NULL;
|
|
|
|
if (!OpenThreadToken(
|
|
GetCurrentThread(),
|
|
TOKEN_QUERY | TOKEN_ADJUST_PRIVILEGES,
|
|
FALSE,
|
|
&hToken))
|
|
{
|
|
|
|
if(!OpenProcessToken(
|
|
GetCurrentProcess(),
|
|
TOKEN_QUERY | TOKEN_ADJUST_PRIVILEGES,
|
|
&hToken
|
|
))
|
|
{
|
|
return FALSE;
|
|
}
|
|
}
|
|
|
|
if(SetPrivilege(hToken, Privilege, bEnablePrivilege))
|
|
{
|
|
bSuccess=TRUE;
|
|
}
|
|
|
|
CloseHandle(hToken);
|
|
|
|
return bSuccess;
|
|
}
|
|
|
|
|
|
//
|
|
// GetUserSid
|
|
//
|
|
// This function takes a token, and returns the user SID from that token.
|
|
//
|
|
// Note: SID must be freed by MyFree()
|
|
// hToken is optional... NULL means we'll grab it.
|
|
//
|
|
BOOL
|
|
GetUserSid(HANDLE hClientToken,
|
|
PSID* ppSid,
|
|
DWORD* lpcbSid)
|
|
{
|
|
DWORD cbUserInfo = 0;
|
|
PTOKEN_USER pUserInfo = NULL;
|
|
PUCHAR pnSubAuthorityCount = 0;
|
|
DWORD cbSid = 0;
|
|
BOOL fRet = FALSE;
|
|
HANDLE hToken = hClientToken;
|
|
|
|
*ppSid = NULL;
|
|
|
|
if (NULL == hClientToken)
|
|
{
|
|
|
|
if (!OpenThreadToken(
|
|
GetCurrentThread(),
|
|
TOKEN_QUERY,
|
|
FALSE,
|
|
&hToken
|
|
))
|
|
{
|
|
|
|
// not impersonating, use process token...
|
|
if (!OpenProcessToken(
|
|
GetCurrentProcess(),
|
|
TOKEN_QUERY,
|
|
&hToken
|
|
))
|
|
{
|
|
|
|
return FALSE;
|
|
}
|
|
}
|
|
}
|
|
|
|
// this will fail, usually w/ ERROR_INSUFFICIENT_BUFFER
|
|
GetTokenInformation(
|
|
hToken,
|
|
TokenUser,
|
|
NULL,
|
|
0,
|
|
&cbUserInfo
|
|
);
|
|
|
|
pUserInfo = (PTOKEN_USER) MyAlloc(cbUserInfo);
|
|
if (NULL == pUserInfo)
|
|
{
|
|
return FALSE;
|
|
}
|
|
|
|
if (!GetTokenInformation(
|
|
hToken,
|
|
TokenUser,
|
|
pUserInfo,
|
|
cbUserInfo,
|
|
&cbUserInfo
|
|
))
|
|
{
|
|
|
|
goto ret;
|
|
}
|
|
|
|
//
|
|
// Now that we've got the SID AND ATTRIBUTES struct, get the SID lenght,
|
|
// alloc room, and return *just the SID*
|
|
//
|
|
if (!IsValidSid(pUserInfo->User.Sid))
|
|
{
|
|
goto ret;
|
|
}
|
|
|
|
pnSubAuthorityCount = GetSidSubAuthorityCount(pUserInfo->User.Sid);
|
|
cbSid = GetSidLengthRequired(*pnSubAuthorityCount);
|
|
|
|
*ppSid = (PSID) MyAlloc(cbSid);
|
|
if (NULL == *ppSid )
|
|
{
|
|
goto ret;
|
|
}
|
|
|
|
if (!CopySid(
|
|
cbSid,
|
|
*ppSid,
|
|
pUserInfo->User.Sid
|
|
))
|
|
{
|
|
|
|
goto copyerr;
|
|
}
|
|
|
|
*lpcbSid = cbSid; // may be useful later on...
|
|
fRet = TRUE;
|
|
|
|
ret:
|
|
|
|
if (NULL == hClientToken && NULL != hToken)
|
|
{ // supplied our own
|
|
CloseHandle(hToken);
|
|
}
|
|
|
|
if (NULL != pUserInfo)
|
|
{
|
|
MyFree(pUserInfo);
|
|
}
|
|
|
|
return fRet;
|
|
|
|
copyerr:
|
|
|
|
if (NULL != *ppSid)
|
|
{
|
|
MyFree(*ppSid);
|
|
*ppSid = NULL;
|
|
}
|
|
|
|
goto ret;
|
|
}
|
|
|
|
//
|
|
// IsLocalSystem()
|
|
// This function makes the determination if the given process token
|
|
// is running as local system.
|
|
//
|
|
BOOL
|
|
IsLocalSystem(HANDLE hToken)
|
|
{
|
|
|
|
|
|
PSID pLocalSid = NULL, pTokenSid = NULL;
|
|
SID_IDENTIFIER_AUTHORITY IDAuthorityNT = SECURITY_NT_AUTHORITY;
|
|
DWORD cbSid = 0;
|
|
BOOL fRet = FALSE;
|
|
|
|
if (!GetUserSid(
|
|
hToken,
|
|
&pTokenSid,
|
|
&cbSid
|
|
))
|
|
{
|
|
goto ret;
|
|
}
|
|
|
|
if (!AllocateAndInitializeSid(
|
|
&IDAuthorityNT,
|
|
1,
|
|
SECURITY_LOCAL_SYSTEM_RID,
|
|
0,0,0,0,0,0,0,
|
|
&pLocalSid
|
|
))
|
|
{
|
|
|
|
goto ret;
|
|
}
|
|
|
|
if (EqualSid(pLocalSid, pTokenSid))
|
|
{
|
|
fRet = TRUE; // got one!
|
|
}
|
|
|
|
ret:
|
|
|
|
if (NULL != pTokenSid)
|
|
{
|
|
MyFree(pTokenSid);
|
|
}
|
|
|
|
if (NULL != pLocalSid)
|
|
{
|
|
FreeSid(pLocalSid);
|
|
}
|
|
|
|
return fRet;
|
|
}
|
|
|
|
|
|
|
|
|
|
//
|
|
// GetLocalSystemToken()
|
|
//
|
|
// This function grabs a process token from a LOCAL SYSTEM process and uses it
|
|
// to run as local system for the duration of the test
|
|
//
|
|
// RevertToSelf() must be called to restore original token
|
|
//
|
|
//
|
|
DWORD
|
|
GetLocalSystemToken(
|
|
IN ULONG ProcessId,
|
|
OUT HANDLE *hPDupToken
|
|
)
|
|
{
|
|
|
|
HANDLE hProcess = NULL;
|
|
HANDLE hPToken = NULL, hPTokenNew = NULL;
|
|
PSECURITY_DESCRIPTOR pSD = NULL;
|
|
DWORD cbNeeded = 0, dwErr = S_OK, i = 0;
|
|
DWORD cbrgPIDs = sizeof(DWORD) * MAX_PROCESSES;
|
|
|
|
PSID pSid = NULL;
|
|
DWORD cbSid = 0;
|
|
BOOL fSet = FALSE;
|
|
|
|
DWORD cbByte = MAX_SD, cbByte2 = MAX_SD;
|
|
|
|
|
|
//
|
|
// Enable debug privilege
|
|
//
|
|
if(!SetCurrentPrivilege(SE_DEBUG_NAME, TRUE))
|
|
{
|
|
return GetLastError();
|
|
}
|
|
|
|
if(!SetCurrentPrivilege(SE_TAKE_OWNERSHIP_NAME, TRUE))
|
|
{
|
|
return GetLastError();
|
|
}
|
|
|
|
if(ProcessId == 0)
|
|
{
|
|
GetSystemProcessId(L"System",
|
|
&ProcessId);
|
|
}
|
|
|
|
|
|
//
|
|
// Get current user's sid for use in expanding SD.
|
|
//
|
|
if (!GetUserSid(
|
|
NULL,
|
|
&pSid,
|
|
&cbSid
|
|
))
|
|
{
|
|
goto ret;
|
|
}
|
|
|
|
//
|
|
// Walk processes until we find one that's running as
|
|
// local system
|
|
//
|
|
do {
|
|
|
|
hProcess = OpenProcess(
|
|
PROCESS_ALL_ACCESS,
|
|
FALSE,
|
|
ProcessId
|
|
);
|
|
|
|
if (NULL == hProcess)
|
|
{
|
|
dwErr = GetLastError();
|
|
goto ret;
|
|
}
|
|
|
|
if (!OpenProcessToken(
|
|
hProcess,
|
|
READ_CONTROL | WRITE_DAC,
|
|
&hPToken
|
|
))
|
|
{
|
|
|
|
dwErr = GetLastError();
|
|
goto ret;
|
|
}
|
|
|
|
//
|
|
// We've got a token, but we can't use it for
|
|
// TOKEN_DUPLICATE access. So, instead, we'll go
|
|
// ahead and whack the DACL on the object to grant us
|
|
// this access, and get a new token.
|
|
// **** BE SURE TO RESTORE hProcess to Original SD!!! ****
|
|
//
|
|
if (!AddSIDToKernelObjectDacl(
|
|
pSid,
|
|
TOKEN_DUPLICATE,
|
|
hPToken,
|
|
&pSD
|
|
))
|
|
{
|
|
goto ret;
|
|
}
|
|
|
|
fSet = TRUE;
|
|
|
|
if (!OpenProcessToken(
|
|
hProcess,
|
|
TOKEN_DUPLICATE,
|
|
&hPTokenNew
|
|
))
|
|
{
|
|
|
|
dwErr = GetLastError();
|
|
goto ret;
|
|
}
|
|
|
|
//
|
|
// Duplicate the token
|
|
//
|
|
if (!DuplicateTokenEx(
|
|
hPTokenNew,
|
|
TOKEN_ALL_ACCESS,
|
|
NULL,
|
|
SecurityImpersonation,
|
|
TokenPrimary,
|
|
hPDupToken
|
|
))
|
|
{
|
|
|
|
dwErr = GetLastError();
|
|
goto ret;
|
|
}
|
|
|
|
if (IsLocalSystem(*hPDupToken))
|
|
{
|
|
break; // found a local system token
|
|
}
|
|
|
|
// Loop cleanup
|
|
if (!SetKernelObjectSecurity(
|
|
hPToken,
|
|
DACL_SECURITY_INFORMATION,
|
|
pSD
|
|
))
|
|
{
|
|
|
|
dwErr = GetLastError();
|
|
goto ret;
|
|
}
|
|
|
|
fSet = FALSE;
|
|
|
|
|
|
if (NULL != pSD)
|
|
{
|
|
MyFree(pSD);
|
|
pSD = NULL;
|
|
}
|
|
|
|
if (NULL != hPToken)
|
|
{
|
|
CloseHandle(hPToken);
|
|
hPToken = NULL;
|
|
}
|
|
|
|
if (NULL != hProcess)
|
|
{
|
|
CloseHandle(hProcess);
|
|
hProcess = NULL;
|
|
}
|
|
|
|
} while(FALSE);
|
|
|
|
|
|
if (!ImpersonateLoggedOnUser(*hPDupToken))
|
|
{
|
|
dwErr = GetLastError();
|
|
goto ret;
|
|
}
|
|
|
|
ret:
|
|
|
|
|
|
//***** REMEMBER TO RESTORE ORIGINAL SD TO OBJECT*****
|
|
|
|
if (fSet)
|
|
{
|
|
|
|
if (!SetKernelObjectSecurity(
|
|
hPToken,
|
|
DACL_SECURITY_INFORMATION,
|
|
pSD
|
|
))
|
|
{
|
|
|
|
dwErr = GetLastError();
|
|
}
|
|
}
|
|
|
|
if (NULL != pSid)
|
|
{
|
|
MyFree(pSid);
|
|
}
|
|
|
|
if (NULL != hPToken)
|
|
{
|
|
CloseHandle(hPToken);
|
|
}
|
|
|
|
if (NULL != pSD)
|
|
{
|
|
MyFree(pSD);
|
|
}
|
|
|
|
if (NULL != hProcess)
|
|
{
|
|
CloseHandle(hProcess);
|
|
}
|
|
|
|
return dwErr;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
//
|
|
// LogoffAndRevert()
|
|
//
|
|
// This function simply RevertsToSelf(), and then closes the logon token
|
|
//
|
|
// Params:
|
|
//
|
|
// hToken - Logon token from LogonUserW
|
|
//
|
|
// Returns:
|
|
//
|
|
// dwErr from last failure, S_OK otherwise.
|
|
//
|
|
DWORD
|
|
LogoffAndRevert(void)
|
|
{
|
|
|
|
HANDLE hThread = INVALID_HANDLE_VALUE;
|
|
DWORD dwErr = 0;
|
|
|
|
//
|
|
// Verify impersonation, and revert
|
|
//
|
|
if (OpenThreadToken(
|
|
GetCurrentThread(),
|
|
TOKEN_QUERY,
|
|
TRUE,
|
|
&hThread
|
|
))
|
|
{
|
|
|
|
CloseHandle(hThread);
|
|
RevertToSelf();
|
|
}
|
|
|
|
return dwErr;
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#if 0
|
|
|
|
extern "C"
|
|
int __cdecl wmain(
|
|
int argc,
|
|
WCHAR* argv[]
|
|
)
|
|
{
|
|
|
|
LPWSTR wszUPN = NULL;
|
|
LPWSTR wszOldPwd = NULL;
|
|
LPWSTR wszNewPwd = NULL;
|
|
|
|
DATA_BLOB* arCipherData = NULL;
|
|
|
|
INT i = 1;
|
|
DWORD dwErr = S_OK;
|
|
DWORD dwCleanupErrors = S_OK;
|
|
HANDLE hToken = INVALID_HANDLE_VALUE;
|
|
HANDLE hLocalSystem = NULL;
|
|
HANDLE hProfile = INVALID_HANDLE_VALUE;
|
|
BOOL fTest = TRUE;
|
|
|
|
PSECURITY_DESCRIPTOR pSD = NULL;
|
|
|
|
ULONG ProcessId = 8;
|
|
|
|
#if 0
|
|
while (i < carg) {
|
|
|
|
if (!_wcsicmp(rgwszarg[i], L"-?")) {
|
|
|
|
Usage();
|
|
return 0;
|
|
}
|
|
|
|
if (!_wcsicmp(rgwszarg[i], L"-reset")) {
|
|
|
|
ResetTestUser();
|
|
return 0;
|
|
|
|
}
|
|
|
|
if (!_wcsicmp(rgwszarg[i], L"-create")) {
|
|
|
|
CreateTestUser();
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
if (!_wcsicmp(rgwszarg[i], L"-user")) {
|
|
|
|
if (carg < 4) {
|
|
Usage();
|
|
}
|
|
|
|
fTest = TRUE;
|
|
}
|
|
|
|
|
|
i++;
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
if( argc == 2 )
|
|
{
|
|
ProcessId = _wtoi( argv[1] );
|
|
}
|
|
|
|
//
|
|
// Enable debug privilege
|
|
//
|
|
if(!SetCurrentPrivilege(SE_DEBUG_NAME, TRUE)) {
|
|
TERROR(L"SetCurrentPrivilege (debug) failed!");
|
|
return E_FAIL;
|
|
}
|
|
|
|
if(!SetCurrentPrivilege(SE_TAKE_OWNERSHIP_NAME, TRUE)) {
|
|
TERROR(L"SetCurrentPrivilege (TCB) failed!");
|
|
return E_FAIL;
|
|
}
|
|
|
|
|
|
//
|
|
// Run as local system
|
|
//
|
|
dwErr = GetLocalSystemToken(ProcessId, &hLocalSystem);
|
|
if (NULL == hLocalSystem || dwErr != S_OK) {
|
|
goto Ret;
|
|
}
|
|
|
|
|
|
// dwErr = LogoffAndRevert(hToken, pSD);
|
|
|
|
{
|
|
STARTUPINFO si;
|
|
PROCESS_INFORMATION pi;
|
|
|
|
ZeroMemory( &si, sizeof(si) );
|
|
ZeroMemory( &pi, sizeof(pi) );
|
|
|
|
si.cb = sizeof(si);
|
|
si.lpTitle = "NT AUTHORITY\\SYSTEM";
|
|
|
|
|
|
if(!CreateProcessAsUserA(
|
|
hLocalSystem,
|
|
NULL,
|
|
"cmd.exe",
|
|
NULL,
|
|
NULL,
|
|
FALSE,
|
|
CREATE_NEW_CONSOLE,
|
|
NULL,
|
|
NULL,
|
|
&si,
|
|
&pi
|
|
))
|
|
{
|
|
TERRORVAL(L"CreateProcessAsUser", GetLastError());
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (NULL != pSD) {
|
|
MyFree(pSD);
|
|
pSD = NULL;
|
|
}
|
|
|
|
if (hToken != INVALID_HANDLE_VALUE) {
|
|
CloseHandle(hToken);
|
|
hToken = INVALID_HANDLE_VALUE;
|
|
}
|
|
|
|
|
|
Ret:
|
|
|
|
|
|
|
|
if (hToken != INVALID_HANDLE_VALUE) {
|
|
CloseHandle(hToken);
|
|
}
|
|
|
|
if (NULL != hLocalSystem) {
|
|
RevertToSelf();
|
|
CloseHandle(hLocalSystem);
|
|
}
|
|
|
|
return dwErr;
|
|
|
|
}
|
|
#endif
|
|
|
|
|
|
DWORD
|
|
GetSystemProcessId(LPWSTR ProcessNameToFind,
|
|
DWORD * ProcessId)
|
|
{
|
|
PSYSTEM_PROCESS_INFORMATION ProcessInfo =NULL;
|
|
NTSTATUS NtStatus = 0;
|
|
DWORD WinError = 0;
|
|
ULONG TotalOffset = 0;
|
|
ULONG NumRetry = 0;
|
|
ULONG totalTasks = 0;
|
|
LONG TheSame = 0;
|
|
PUCHAR LargeBuffer = NULL;
|
|
ULONG LargeBufferSize = 64*1024;
|
|
UNICODE_STRING ProcessName;
|
|
|
|
retry:
|
|
|
|
if(NumRetry == 5)
|
|
{
|
|
WinError = RtlNtStatusToDosError(NtStatus);
|
|
return WinError;
|
|
}
|
|
|
|
if (LargeBuffer == NULL)
|
|
{
|
|
LargeBuffer = (PUCHAR)MyAlloc (LargeBufferSize);
|
|
if (LargeBuffer == NULL)
|
|
{
|
|
return GetLastError ();
|
|
}
|
|
}
|
|
|
|
NtStatus = NtQuerySystemInformation(
|
|
SystemProcessInformation,
|
|
LargeBuffer,
|
|
LargeBufferSize,
|
|
NULL
|
|
);
|
|
|
|
if (NtStatus == STATUS_INFO_LENGTH_MISMATCH)
|
|
{
|
|
LargeBufferSize += 8192;
|
|
MyFree(LargeBuffer);
|
|
LargeBuffer = NULL;
|
|
NumRetry++;
|
|
goto retry;
|
|
}
|
|
|
|
if(NtStatus != STATUS_SUCCESS)
|
|
{
|
|
WinError = RtlNtStatusToDosError(NtStatus);
|
|
return WinError;
|
|
}
|
|
|
|
NtStatus = RtlInitUnicodeStringEx( &ProcessName, ProcessNameToFind);
|
|
if(NtStatus != STATUS_SUCCESS)
|
|
{
|
|
WinError = RtlNtStatusToDosError(NtStatus);
|
|
return WinError;
|
|
}
|
|
|
|
ProcessInfo = (PSYSTEM_PROCESS_INFORMATION) LargeBuffer;
|
|
TotalOffset = 0;
|
|
while (TRUE)
|
|
{
|
|
if ( ProcessInfo->ImageName.Buffer )
|
|
{
|
|
TheSame = RtlCompareUnicodeString((PUNICODE_STRING)&ProcessInfo->ImageName, &ProcessName, TRUE );
|
|
if(TheSame == 0)
|
|
{
|
|
*ProcessId = (DWORD)(DWORD_PTR)ProcessInfo->UniqueProcessId;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (ProcessInfo->NextEntryOffset == 0)
|
|
{
|
|
break;
|
|
}
|
|
|
|
TotalOffset += ProcessInfo->NextEntryOffset;
|
|
ProcessInfo = (PSYSTEM_PROCESS_INFORMATION)&LargeBuffer[TotalOffset];
|
|
}
|
|
|
|
if(LargeBuffer)
|
|
{
|
|
MyFree (LargeBuffer);
|
|
}
|
|
|
|
return ERROR_SUCCESS;
|
|
}
|