1120 lines
23 KiB
C
1120 lines
23 KiB
C
#include "precomp.h"
|
|
#pragma hdrstop
|
|
/*++
|
|
|
|
Copyright (c) 1990 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
security.c
|
|
|
|
Abstract:
|
|
|
|
Security related functions in the setupdll
|
|
|
|
Detect Routines:
|
|
|
|
1. GetUserAccounts. Lists down all the user accounts in the system
|
|
2. GetComputerName. Finds the computer name.
|
|
|
|
Install Routines Workers:
|
|
|
|
1. CheckPrivilegeExistsWorker.
|
|
2. EnablePrivilegeWorker.
|
|
|
|
General Subroutines:
|
|
|
|
1. AdjustPrivilege.
|
|
2. RestorePrivilege.
|
|
|
|
Author:
|
|
|
|
Sunil Pai (sunilp) April 1992
|
|
|
|
--*/
|
|
|
|
|
|
//
|
|
// Routines which are used to force deletion of a file by taking ownership
|
|
// of the file
|
|
//
|
|
|
|
BOOL
|
|
AssertTakeOwnership(
|
|
HANDLE TokenHandle,
|
|
PTOKEN_PRIVILEGES OldPrivs
|
|
);
|
|
|
|
BOOL
|
|
GetTokenHandle(
|
|
PHANDLE TokenHandle
|
|
);
|
|
|
|
|
|
|
|
VOID
|
|
RestoreTakeOwnership(
|
|
HANDLE TokenHandle,
|
|
PTOKEN_PRIVILEGES OldPrivs
|
|
);
|
|
|
|
BOOL
|
|
FForceDeleteFile(
|
|
LPSTR szPath
|
|
);
|
|
|
|
|
|
|
|
//======================
|
|
// DETECT ROUTINES
|
|
//=======================
|
|
|
|
//
|
|
// Get current users account name
|
|
//
|
|
|
|
CB
|
|
GetMyUserName(
|
|
IN RGSZ Args,
|
|
IN USHORT cArgs,
|
|
OUT SZ ReturnBuffer,
|
|
IN CB cbReturnBuffer
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
DetectRoutine for GetUserName. This finds out the username of
|
|
the logged in account.
|
|
|
|
Arguments:
|
|
|
|
Args - C argument list to this detect routine (None exist)
|
|
|
|
cArgs - Number of arguments.
|
|
|
|
ReturnBuffer - Buffer in which detected value is returned.
|
|
|
|
cbReturnBuffer - Buffer Size.
|
|
|
|
|
|
Return value:
|
|
|
|
Returns length of detected value.
|
|
|
|
|
|
--*/
|
|
{
|
|
CHAR UserName[MAX_PATH];
|
|
CHAR DomainName[MAX_PATH];
|
|
DWORD cbUserName = MAX_PATH;
|
|
DWORD cbDomainName = MAX_PATH;
|
|
SID_NAME_USE peUse;
|
|
BOOL bStatus = FALSE;
|
|
HANDLE hToken = NULL;
|
|
|
|
TOKEN_USER *ptu = NULL;
|
|
DWORD cbTokenBuffer = 0;
|
|
|
|
CB Length;
|
|
|
|
#define DEFAULT_USERNAME ""
|
|
|
|
Unused(Args);
|
|
Unused(cArgs);
|
|
Unused(cbReturnBuffer);
|
|
|
|
|
|
if( !OpenProcessToken( GetCurrentProcess(), TOKEN_READ, &hToken ) ) {
|
|
goto err;
|
|
}
|
|
|
|
//
|
|
// Get space needed for process token information
|
|
//
|
|
|
|
if( !GetTokenInformation( hToken, TokenUser, (LPVOID)NULL, 0, &cbTokenBuffer) ) {
|
|
if (GetLastError() != ERROR_INSUFFICIENT_BUFFER) {
|
|
goto err;
|
|
}
|
|
}
|
|
|
|
//
|
|
// Allocate space for token user information
|
|
//
|
|
|
|
if ( (ptu = (TOKEN_USER *)SAlloc(cbTokenBuffer)) == NULL ) {
|
|
goto err;
|
|
}
|
|
|
|
//
|
|
// Query token user information again
|
|
//
|
|
|
|
if( !GetTokenInformation( hToken, TokenUser, (LPVOID)ptu, cbTokenBuffer, &cbTokenBuffer) ) {
|
|
goto err;
|
|
}
|
|
|
|
//
|
|
// Query the user name and return it
|
|
//
|
|
|
|
if( LookupAccountSid( NULL, ptu->User.Sid, UserName, &cbUserName , DomainName, &cbDomainName, &peUse) ) {
|
|
lstrcpy( ReturnBuffer, DomainName );
|
|
lstrcat( ReturnBuffer, "\\" );
|
|
lstrcat( ReturnBuffer, UserName );
|
|
Length = lstrlen( ReturnBuffer ) + 1;
|
|
bStatus = TRUE;
|
|
}
|
|
|
|
err:
|
|
|
|
if( !bStatus ) {
|
|
lstrcpy( ReturnBuffer, DEFAULT_USERNAME );
|
|
Length = lstrlen( DEFAULT_USERNAME ) + 1;
|
|
}
|
|
|
|
if( hToken != NULL ) {
|
|
CloseHandle( hToken );
|
|
}
|
|
|
|
if( ptu ) {
|
|
SFree( ptu );
|
|
}
|
|
|
|
return( Length );
|
|
|
|
}
|
|
|
|
|
|
//
|
|
// Get User Accounts
|
|
//
|
|
|
|
CB
|
|
GetUserAccounts(
|
|
IN RGSZ Args,
|
|
IN USHORT cArgs,
|
|
OUT SZ ReturnBuffer,
|
|
IN CB cbReturnBuffer
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
DetectRoutine for UserAccounts. This routine enumerates all the
|
|
user accounts under HKEY_USERS and returns the <sid-string key, username>
|
|
tuplet for every user found. The detected value will have the
|
|
following form:
|
|
|
|
{ {sid-string1, user-name1}, {sid-string2, user-name2} ... }
|
|
|
|
Arguments:
|
|
|
|
Args - C argument list to this detect routine (None exist)
|
|
|
|
cArgs - Number of arguments.
|
|
|
|
ReturnBuffer - Buffer in which detected value is returned.
|
|
|
|
cbReturnBuffer - Buffer Size.
|
|
|
|
|
|
Return value:
|
|
|
|
Returns length of detected value.
|
|
|
|
|
|
--*/
|
|
{
|
|
HKEY hProfile, hSubKey;
|
|
CHAR SubKeyName[MAX_PATH];
|
|
CHAR UserName[MAX_PATH];
|
|
CHAR DomainName[MAX_PATH];
|
|
CHAR ProfilePath[MAX_PATH];
|
|
CHAR Class[MAX_PATH];
|
|
DWORD cbSubKeyName;
|
|
DWORD cbUserName;
|
|
DWORD cbDomainName;
|
|
DWORD cbProfilePath;
|
|
DWORD cbClass;
|
|
FILETIME FileTime;
|
|
UINT Index;
|
|
LONG Status;
|
|
BOOL bStatus;
|
|
RGSZ rgszUsers, rgszCurrent;
|
|
SZ sz;
|
|
CB Length;
|
|
|
|
CHAR UnknownUser[MAX_PATH];
|
|
DWORD UnknownUserNum;
|
|
CHAR UnknownUserChar[10];
|
|
PSID pSid;
|
|
SID_NAME_USE peUse;
|
|
|
|
Unused(Args);
|
|
Unused(cArgs);
|
|
Unused(cbReturnBuffer);
|
|
|
|
#define NO_ACCOUNTS "{}"
|
|
|
|
|
|
//
|
|
// Load the string to use as the unknown user string. We will append
|
|
// it with numbers
|
|
//
|
|
LoadString( MyDllModuleHandle, IDS_STRING_UNKNOWN_USER, UnknownUser, MAX_PATH );
|
|
UnknownUserNum = 1;
|
|
|
|
//
|
|
// Enumerate keys under HKEY_USERS, for each user see if it is a
|
|
// a .Default (reject this), get the sid value and convert the
|
|
// sid to a user name. Add the subkey (this is a sid-string) and
|
|
// the username as an account.
|
|
//
|
|
|
|
//
|
|
// Intialise users list to no users
|
|
//
|
|
|
|
rgszUsers = RgszAlloc(1);
|
|
|
|
//
|
|
// open the key to the profile tree
|
|
//
|
|
|
|
Status = RegOpenKeyEx(
|
|
HKEY_LOCAL_MACHINE,
|
|
"Software\\Microsoft\\Windows NT\\CurrentVersion\\ProfileList",
|
|
0,
|
|
KEY_READ,
|
|
&hProfile
|
|
);
|
|
|
|
if (Status == ERROR_SUCCESS) {
|
|
|
|
//
|
|
// Profile key exists, enumerate the profiles under this key
|
|
//
|
|
|
|
for ( Index = 0 ; ; Index++ ) {
|
|
|
|
//
|
|
// Get the current sub-key
|
|
//
|
|
|
|
cbSubKeyName = MAX_PATH;
|
|
cbClass = MAX_PATH;
|
|
cbUserName = MAX_PATH;
|
|
cbDomainName = MAX_PATH;
|
|
cbProfilePath = MAX_PATH;
|
|
|
|
Status = RegEnumKeyEx(
|
|
hProfile,
|
|
Index,
|
|
SubKeyName,
|
|
&cbSubKeyName,
|
|
NULL,
|
|
Class,
|
|
&cbClass,
|
|
&FileTime
|
|
);
|
|
|
|
if ( Status != ERROR_SUCCESS ) {
|
|
break;
|
|
}
|
|
|
|
|
|
//
|
|
// Open the subkey
|
|
//
|
|
|
|
Status = RegOpenKeyEx(
|
|
hProfile,
|
|
SubKeyName,
|
|
0,
|
|
KEY_READ,
|
|
&hSubKey
|
|
);
|
|
|
|
if ( Status != ERROR_SUCCESS) {
|
|
continue;
|
|
}
|
|
|
|
if( !lstrcmpi( SubKeyName, "THE_USER" ) ) {
|
|
lstrcpy( UserName, "THE_USER" );
|
|
goto skip_1;
|
|
}
|
|
|
|
//
|
|
// Get the User name for this profile, by looking up the sid
|
|
// value in the user key and then looking up the sid.
|
|
//
|
|
|
|
pSid = (PSID)GetValueEntry(
|
|
hSubKey,
|
|
"Sid"
|
|
);
|
|
|
|
if (!pSid) {
|
|
RegCloseKey( hSubKey );
|
|
continue;
|
|
}
|
|
|
|
//
|
|
// Convert the Sid into Username
|
|
//
|
|
|
|
bStatus = LookupAccountSid(
|
|
NULL,
|
|
pSid,
|
|
UserName,
|
|
&cbUserName,
|
|
DomainName,
|
|
&cbDomainName,
|
|
&peUse
|
|
);
|
|
SFree( pSid );
|
|
|
|
if( !bStatus ) {
|
|
RegCloseKey( hSubKey );
|
|
continue;
|
|
}
|
|
|
|
lstrcat( DomainName, "\\" );
|
|
if(!lstrcmpi(UserName, "")) {
|
|
lstrcat(DomainName, UnknownUser);
|
|
_ultoa( UnknownUserNum, UnknownUserChar, 10 );
|
|
lstrcat(DomainName, UnknownUserChar);
|
|
UnknownUserNum++;
|
|
}
|
|
else {
|
|
lstrcat(DomainName, UserName);
|
|
}
|
|
|
|
skip_1:
|
|
|
|
//
|
|
// Get the profilepath for this subkey, check to see if profilepath
|
|
// exists
|
|
//
|
|
|
|
bStatus = HUserKeyToProfilePath(
|
|
hSubKey,
|
|
ProfilePath,
|
|
&cbProfilePath
|
|
);
|
|
|
|
if( !bStatus ) {
|
|
RegCloseKey( hSubKey );
|
|
continue;
|
|
}
|
|
|
|
RegCloseKey( hSubKey );
|
|
|
|
//
|
|
// Form the list entry for this user
|
|
//
|
|
|
|
rgszCurrent = RgszAlloc(4);
|
|
rgszCurrent[0] = SzDup ( SubKeyName );
|
|
rgszCurrent[1] = SzDup ( DomainName );
|
|
rgszCurrent[2] = SzDup ( ProfilePath );
|
|
rgszCurrent[3] = NULL;
|
|
|
|
//
|
|
// Add this user to the list of users
|
|
//
|
|
|
|
sz = SzListValueFromRgsz( rgszCurrent );
|
|
if ( sz ) {
|
|
if( !RgszAdd ( &rgszUsers, sz ) ) {
|
|
SFree( sz );
|
|
}
|
|
}
|
|
RgszFree ( rgszCurrent );
|
|
|
|
}
|
|
|
|
RegCloseKey( hProfile );
|
|
}
|
|
|
|
sz = SzListValueFromRgsz( rgszUsers );
|
|
RgszFree( rgszUsers );
|
|
|
|
if ( sz ) {
|
|
lstrcpy( ReturnBuffer, sz );
|
|
Length = lstrlen( sz ) + 1;
|
|
SFree ( sz );
|
|
}
|
|
else {
|
|
lstrcpy( ReturnBuffer, NO_ACCOUNTS );
|
|
Length = lstrlen( NO_ACCOUNTS ) + 1;
|
|
}
|
|
|
|
return ( Length );
|
|
}
|
|
|
|
|
|
|
|
|
|
//========================
|
|
// INSTALL ROUTINE WORKERS
|
|
//========================
|
|
|
|
BOOL
|
|
CheckPrivilegeExistsWorker(
|
|
IN LPSTR PrivilegeType
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Routine to determine whether we have a particular privilege
|
|
|
|
Arguments:
|
|
|
|
PrivilegeType - Name of the privilege to enable / disable
|
|
|
|
Return value:
|
|
|
|
TRUE if CheckTakeOwnerPrivilege succeeds, FALSE otherwise.
|
|
|
|
If TRUE: ReturnTextBuffer has "YES" if privilege exists, "NO" otherwise.
|
|
|
|
If FALSE: ReturnTextBuffer has error text.
|
|
|
|
|
|
--*/
|
|
{
|
|
LONG Privilege;
|
|
TOKEN_PRIVILEGES PrevState;
|
|
ULONG ReturnLength = sizeof( TOKEN_PRIVILEGES );
|
|
|
|
if ( !lstrcmpi( PrivilegeType, "SeTakeOwnershipPrivilege" ) ) {
|
|
Privilege = SE_TAKE_OWNERSHIP_PRIVILEGE;
|
|
}
|
|
else if ( !lstrcmpi( PrivilegeType, "SeSystemEnvironmentPrivilege" ) ) {
|
|
Privilege = SE_SYSTEM_ENVIRONMENT_PRIVILEGE;
|
|
}
|
|
else {
|
|
SetErrorText(IDS_ERROR_UNSUPPORTEDPRIV);
|
|
return ( FALSE );
|
|
}
|
|
|
|
if ( AdjustPrivilege(
|
|
Privilege,
|
|
ENABLE_PRIVILEGE,
|
|
&PrevState,
|
|
&ReturnLength
|
|
)
|
|
) {
|
|
SetReturnText( "YES" );
|
|
RestorePrivilege( &PrevState );
|
|
return ( TRUE );
|
|
}
|
|
else {
|
|
SetReturnText( "NO" );
|
|
return ( TRUE );
|
|
}
|
|
}
|
|
|
|
|
|
BOOL
|
|
EnablePrivilegeWorker(
|
|
LPSTR PrivilegeType,
|
|
LPSTR Action
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Install routine to enable / disable the SE_SYSTEM_ENVIRONMENT_PRIVILEGE
|
|
|
|
Arguments:
|
|
|
|
PrivilegeType - Name of the privilege to enable / disable
|
|
Action - Whether to enable / disable
|
|
|
|
Return value:
|
|
|
|
TRUE if Enable / Disable succeeds, FALSE otherwise. ReturnTextBuffer
|
|
gets initialised to error text if FALSE.
|
|
|
|
|
|
--*/
|
|
{
|
|
|
|
ULONG Privilege;
|
|
INT AdjustAction;
|
|
|
|
|
|
if ( !lstrcmpi( PrivilegeType, "SeTakeOwnershipPrivilege" ) ) {
|
|
Privilege = SE_TAKE_OWNERSHIP_PRIVILEGE;
|
|
}
|
|
else if ( !lstrcmpi( PrivilegeType, "SeSystemEnvironmentPrivilege" ) ) {
|
|
Privilege = SE_SYSTEM_ENVIRONMENT_PRIVILEGE;
|
|
}
|
|
else {
|
|
SetErrorText(IDS_ERROR_UNSUPPORTEDPRIV);
|
|
return ( FALSE );
|
|
}
|
|
|
|
//
|
|
// Check Arg[1] .. Whether to enable / disable
|
|
//
|
|
|
|
if (!lstrcmpi(Action, "ENABLE")) {
|
|
AdjustAction = ENABLE_PRIVILEGE;
|
|
}
|
|
else if (!lstrcmpi(Action, "DISABLE")) {
|
|
AdjustAction = DISABLE_PRIVILEGE;
|
|
}
|
|
else {
|
|
SetErrorText(IDS_ERROR_BADARGS);
|
|
return(FALSE);
|
|
}
|
|
|
|
if ( !AdjustPrivilege(
|
|
Privilege,
|
|
AdjustAction,
|
|
NULL,
|
|
NULL
|
|
)
|
|
) {
|
|
SetErrorText(IDS_ERROR_ADJUSTPRIVILEGE);
|
|
return ( FALSE );
|
|
}
|
|
else {
|
|
return ( TRUE );
|
|
}
|
|
}
|
|
|
|
|
|
//======================================================================
|
|
// General security subroutines
|
|
//======================================================================
|
|
|
|
BOOL
|
|
AdjustPrivilege(
|
|
IN LONG PrivilegeType,
|
|
IN INT Action,
|
|
IN PTOKEN_PRIVILEGES PrevState, OPTIONAL
|
|
IN PULONG ReturnLength OPTIONAL
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Routine to enable or disable a particular privilege
|
|
|
|
Arguments:
|
|
|
|
PrivilegeType - Name of the privilege to enable / disable
|
|
|
|
Action - ENABLE_PRIVILEGE | DISABLE_PRIVILEGE
|
|
|
|
PrevState - Optional pointer to TOKEN_PRIVILEGES structure
|
|
to receive the previous state of privilege.
|
|
|
|
ReturnLength - Optional pointer to a ULONG to receive the length
|
|
of the PrevState returned.
|
|
|
|
Return value:
|
|
|
|
TRUE if succeeded, FALSE otherwise.
|
|
|
|
--*/
|
|
{
|
|
NTSTATUS NtStatus;
|
|
HANDLE Token;
|
|
LUID Privilege;
|
|
TOKEN_PRIVILEGES NewState;
|
|
ULONG BufferLength = 0;
|
|
|
|
|
|
//
|
|
// Get Privilege LUID
|
|
//
|
|
|
|
Privilege = RtlConvertLongToLuid(PrivilegeType);
|
|
|
|
NewState.PrivilegeCount = 1;
|
|
NewState.Privileges[0].Luid = Privilege;
|
|
|
|
//
|
|
// Look at action and determine the attributes
|
|
//
|
|
|
|
switch( Action ) {
|
|
|
|
case ENABLE_PRIVILEGE:
|
|
NewState.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
|
|
break;
|
|
|
|
case DISABLE_PRIVILEGE:
|
|
NewState.Privileges[0].Attributes = 0;
|
|
break;
|
|
|
|
default:
|
|
return ( FALSE );
|
|
}
|
|
|
|
//
|
|
// Open our own token
|
|
//
|
|
|
|
NtStatus = NtOpenProcessToken(
|
|
NtCurrentProcess(),
|
|
TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY,
|
|
&Token
|
|
);
|
|
|
|
if (!NT_SUCCESS(NtStatus)) {
|
|
return( FALSE );
|
|
}
|
|
|
|
//
|
|
// See if return buffer is present and accordingly set the parameter
|
|
// of buffer length
|
|
//
|
|
|
|
if ( PrevState && ReturnLength ) {
|
|
BufferLength = *ReturnLength;
|
|
}
|
|
|
|
|
|
//
|
|
// Set the state of the privilege
|
|
//
|
|
|
|
NtStatus = NtAdjustPrivilegesToken(
|
|
Token, // TokenHandle
|
|
FALSE, // DisableAllPrivileges
|
|
&NewState, // NewState
|
|
BufferLength, // BufferLength
|
|
PrevState, // PreviousState (OPTIONAL)
|
|
ReturnLength // ReturnLength (OPTIONAL)
|
|
);
|
|
|
|
if ( NT_SUCCESS( NtStatus ) ) {
|
|
|
|
NtClose( Token );
|
|
return( TRUE );
|
|
|
|
}
|
|
else {
|
|
|
|
NtClose( Token );
|
|
return( FALSE );
|
|
|
|
}
|
|
}
|
|
|
|
|
|
BOOL
|
|
RestorePrivilege(
|
|
IN PTOKEN_PRIVILEGES PrevState
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
To restore a privilege to its previous state
|
|
|
|
Arguments:
|
|
|
|
PrevState - Pointer to token privileges returned from an earlier
|
|
AdjustPrivileges call.
|
|
|
|
Return value:
|
|
|
|
TRUE on success, FALSE otherwise
|
|
|
|
--*/
|
|
{
|
|
NTSTATUS NtStatus;
|
|
HANDLE Token;
|
|
|
|
//
|
|
// Parameter checking
|
|
//
|
|
|
|
if ( !PrevState ) {
|
|
return ( FALSE );
|
|
}
|
|
|
|
//
|
|
// Open our own token
|
|
//
|
|
|
|
NtStatus = NtOpenProcessToken(
|
|
NtCurrentProcess(),
|
|
TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY,
|
|
&Token
|
|
);
|
|
|
|
if (!NT_SUCCESS(NtStatus)) {
|
|
return( FALSE );
|
|
}
|
|
|
|
|
|
//
|
|
// Set the state of the privilege
|
|
//
|
|
|
|
NtStatus = NtAdjustPrivilegesToken(
|
|
Token, // TokenHandle
|
|
FALSE, // DisableAllPrivileges
|
|
PrevState, // NewState
|
|
0, // BufferLength
|
|
NULL, // PreviousState (OPTIONAL)
|
|
NULL // ReturnLength (OPTIONAL)
|
|
);
|
|
|
|
if ( NT_SUCCESS( NtStatus ) ) {
|
|
NtClose( Token );
|
|
return( TRUE );
|
|
}
|
|
else {
|
|
|
|
NtClose( Token );
|
|
return( FALSE );
|
|
}
|
|
}
|
|
|
|
|
|
BOOL
|
|
HUserKeyToProfilePath(
|
|
IN HKEY hUserKey,
|
|
OUT LPSTR lpProfilePath,
|
|
IN OUT LPDWORD lpcbProfilePath
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This finds out the ProfilePath corresponding to a user account key handle
|
|
sees if the file exists and then returns the path to the profile.
|
|
|
|
Arguments:
|
|
|
|
hUserKey - Handle to a user account profile key
|
|
|
|
lpProfilePath - Pointer to a profile path buffer which will receive the
|
|
queried path.
|
|
|
|
lpcbProfilePath - Pointer to the size of the profile path buffer. Input
|
|
value is the size of the name buffer. Output value is the
|
|
actual size of the username queried
|
|
|
|
Return value:
|
|
|
|
Returns TRUE for success, FALSE for failure. If TRUE lpProfilePath and
|
|
lpcbProfilePath are initialized.
|
|
|
|
--*/
|
|
{
|
|
LONG Status;
|
|
CHAR szValue[ MAX_PATH ];
|
|
DWORD dwSize = MAX_PATH;
|
|
|
|
//
|
|
// Get the profile path value
|
|
//
|
|
|
|
Status = RegQueryValueEx(
|
|
hUserKey,
|
|
"ProfileImagePath",
|
|
NULL,
|
|
NULL,
|
|
szValue,
|
|
&dwSize
|
|
);
|
|
|
|
if( Status != ERROR_SUCCESS ) {
|
|
return( FALSE );
|
|
}
|
|
|
|
*lpcbProfilePath = ExpandEnvironmentStrings(
|
|
(LPCSTR)szValue,
|
|
lpProfilePath,
|
|
*lpcbProfilePath
|
|
);
|
|
|
|
//
|
|
// Check if profile path exists
|
|
//
|
|
|
|
if ( FFileExist( lpProfilePath ) ) {
|
|
|
|
return( TRUE );
|
|
}
|
|
else {
|
|
|
|
return( FALSE );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
BOOL
|
|
FForceDeleteFile(
|
|
LPSTR szPath
|
|
)
|
|
{
|
|
BOOL Result;
|
|
SECURITY_DESCRIPTOR SecurityDescriptor;
|
|
HANDLE TokenHandle;
|
|
TOKEN_PRIVILEGES OldPrivs;
|
|
PSID AliasAdminsSid = NULL;
|
|
SID_IDENTIFIER_AUTHORITY SepNtAuthority = SECURITY_NT_AUTHORITY;
|
|
|
|
|
|
Result = AllocateAndInitializeSid(
|
|
&SepNtAuthority,
|
|
2,
|
|
SECURITY_BUILTIN_DOMAIN_RID,
|
|
DOMAIN_ALIAS_RID_ADMINS,
|
|
0,
|
|
0,
|
|
0,
|
|
0,
|
|
0,
|
|
0,
|
|
&AliasAdminsSid
|
|
);
|
|
|
|
if ( !Result ) {
|
|
return( FALSE );
|
|
}
|
|
|
|
Result = GetTokenHandle( &TokenHandle );
|
|
|
|
if ( !Result ) {
|
|
return( FALSE );
|
|
}
|
|
|
|
//
|
|
// Create the security descritor with NULL DACL and Administrator as owner
|
|
//
|
|
|
|
InitializeSecurityDescriptor( &SecurityDescriptor, SECURITY_DESCRIPTOR_REVISION );
|
|
|
|
|
|
Result = SetSecurityDescriptorDacl (
|
|
&SecurityDescriptor,
|
|
TRUE,
|
|
NULL,
|
|
FALSE
|
|
);
|
|
|
|
|
|
if ( !Result ) {
|
|
CloseHandle( TokenHandle );
|
|
return( FALSE );
|
|
}
|
|
|
|
Result = SetSecurityDescriptorOwner (
|
|
&SecurityDescriptor,
|
|
AliasAdminsSid,
|
|
FALSE
|
|
);
|
|
|
|
if ( !Result ) {
|
|
CloseHandle( TokenHandle );
|
|
return FALSE;
|
|
}
|
|
|
|
|
|
//
|
|
// Assert TakeOwnership privilege.
|
|
//
|
|
|
|
Result = AssertTakeOwnership( TokenHandle, &OldPrivs );
|
|
|
|
if ( !Result ) {
|
|
CloseHandle( TokenHandle );
|
|
return FALSE;
|
|
}
|
|
|
|
//
|
|
// Make Administrator the owner of the file.
|
|
//
|
|
|
|
Result = SetFileSecurity(
|
|
szPath,
|
|
OWNER_SECURITY_INFORMATION,
|
|
&SecurityDescriptor
|
|
);
|
|
|
|
RestoreTakeOwnership( TokenHandle, &OldPrivs );
|
|
|
|
if ( !Result ) {
|
|
CloseHandle( TokenHandle );
|
|
return( FALSE );
|
|
}
|
|
|
|
//
|
|
// We are now the owner, put a benign DACL onto the file
|
|
//
|
|
|
|
Result = SetFileSecurity(
|
|
szPath,
|
|
DACL_SECURITY_INFORMATION,
|
|
&SecurityDescriptor
|
|
);
|
|
|
|
if ( !Result ) {
|
|
CloseHandle( TokenHandle );
|
|
return( FALSE );
|
|
}
|
|
|
|
|
|
return( TRUE );
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
BOOL
|
|
GetTokenHandle(
|
|
PHANDLE TokenHandle
|
|
)
|
|
//
|
|
// This routine will open the current process and return
|
|
// a handle to its token.
|
|
//
|
|
// These handles will be closed for us when the process
|
|
// exits.
|
|
//
|
|
{
|
|
|
|
HANDLE ProcessHandle;
|
|
BOOL Result;
|
|
|
|
ProcessHandle = OpenProcess(
|
|
PROCESS_QUERY_INFORMATION,
|
|
FALSE,
|
|
GetCurrentProcessId()
|
|
);
|
|
|
|
if ( ProcessHandle == NULL ) {
|
|
|
|
//
|
|
// This should not happen
|
|
//
|
|
|
|
return( FALSE );
|
|
}
|
|
|
|
|
|
Result = OpenProcessToken (
|
|
ProcessHandle,
|
|
TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY,
|
|
TokenHandle
|
|
);
|
|
|
|
if ( !Result ) {
|
|
|
|
//
|
|
// This should not happen
|
|
//
|
|
|
|
return( FALSE );
|
|
|
|
}
|
|
|
|
return( TRUE );
|
|
}
|
|
|
|
|
|
BOOL
|
|
AssertTakeOwnership(
|
|
HANDLE TokenHandle,
|
|
PTOKEN_PRIVILEGES OldPrivs
|
|
)
|
|
//
|
|
// This routine turns on SeTakeOwnershipPrivilege in the current
|
|
// token. Once that has been accomplished, we can open the file
|
|
// for WRITE_OWNER even if we are denied that access by the ACL
|
|
// on the file.
|
|
|
|
{
|
|
LUID TakeOwnershipValue;
|
|
BOOL Result;
|
|
TOKEN_PRIVILEGES TokenPrivileges;
|
|
DWORD ReturnLength;
|
|
|
|
|
|
//
|
|
// First, find out the value of TakeOwnershipPrivilege
|
|
//
|
|
|
|
|
|
Result = LookupPrivilegeValue(
|
|
NULL,
|
|
"SeTakeOwnershipPrivilege",
|
|
&TakeOwnershipValue
|
|
);
|
|
|
|
if ( !Result ) {
|
|
|
|
//
|
|
// This should not happen
|
|
//
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
//
|
|
// Set up the privilege set we will need
|
|
//
|
|
|
|
TokenPrivileges.PrivilegeCount = 1;
|
|
TokenPrivileges.Privileges[0].Luid = TakeOwnershipValue;
|
|
TokenPrivileges.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
|
|
|
|
|
|
ReturnLength = sizeof( TOKEN_PRIVILEGES );
|
|
|
|
(VOID) AdjustTokenPrivileges (
|
|
TokenHandle,
|
|
FALSE,
|
|
&TokenPrivileges,
|
|
sizeof( TOKEN_PRIVILEGES ),
|
|
OldPrivs,
|
|
&ReturnLength
|
|
);
|
|
|
|
if ( GetLastError() != NO_ERROR ) {
|
|
|
|
return( FALSE );
|
|
|
|
} else {
|
|
|
|
return( TRUE );
|
|
}
|
|
|
|
}
|
|
|
|
VOID
|
|
RestoreTakeOwnership(
|
|
HANDLE TokenHandle,
|
|
PTOKEN_PRIVILEGES OldPrivs
|
|
)
|
|
{
|
|
(VOID) AdjustTokenPrivileges (
|
|
TokenHandle,
|
|
FALSE,
|
|
OldPrivs,
|
|
sizeof( TOKEN_PRIVILEGES ),
|
|
NULL,
|
|
NULL
|
|
);
|
|
|
|
}
|