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.
438 lines
12 KiB
438 lines
12 KiB
//+---------------------------------------------------------------------------
|
|
//
|
|
// Microsoft Windows
|
|
// Copyright (C) Microsoft Corporation, 1992 - 1996.
|
|
//
|
|
// File: security.cxx
|
|
//
|
|
// Contents:
|
|
//
|
|
// Classes: None.
|
|
//
|
|
// Functions: None.
|
|
//
|
|
// History: 26-Jun-96 MarkBl Created
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
#include "..\pch\headers.hxx"
|
|
#pragma hdrstop
|
|
#include <common.hxx> // MAX_SID_SIZE
|
|
#include "..\inc\debug.hxx"
|
|
#include "..\inc\security.hxx"
|
|
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Function: CreateSecurityDescriptor
|
|
//
|
|
// Synopsis: Create a security descriptor with the ACE information
|
|
// specified.
|
|
//
|
|
// Arguments: [AceCount] -- ACE count (no. of rgMyAce and rgAce elements).
|
|
// [rgMyAce] -- ACE specification array.
|
|
// [rgAce] -- Caller allocated array of ptrs to ACEs so
|
|
// this function doesn't have to allocate it.
|
|
//
|
|
// Returns: TRUE -- Function succeeded,
|
|
// FALSE -- Otherwise.
|
|
//
|
|
// Notes: None.
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
PSECURITY_DESCRIPTOR
|
|
CreateSecurityDescriptor(
|
|
DWORD AceCount,
|
|
MYACE rgMyAce[],
|
|
PACCESS_ALLOWED_ACE rgAce[],
|
|
DWORD * pStatus)
|
|
{
|
|
PSECURITY_DESCRIPTOR pSecurityDescriptor = NULL;
|
|
PACL pAcl = NULL;
|
|
DWORD LengthAces = 0;
|
|
DWORD LengthAcl;
|
|
DWORD i;
|
|
DWORD Status;
|
|
|
|
for (i = 0; i < AceCount; i++)
|
|
{
|
|
rgAce[i] = CreateAccessAllowedAce(rgMyAce[i].pSid,
|
|
rgMyAce[i].AccessMask,
|
|
0,
|
|
rgMyAce[i].InheritFlags,
|
|
&Status);
|
|
|
|
if (rgAce[i] == NULL)
|
|
{
|
|
goto ErrorExit;
|
|
}
|
|
|
|
LengthAces += rgAce[i]->Header.AceSize;
|
|
}
|
|
|
|
//
|
|
// Calculate ACL and SD sizes
|
|
//
|
|
|
|
LengthAcl = sizeof(ACL) + LengthAces;
|
|
|
|
//
|
|
// Create the ACL.
|
|
//
|
|
|
|
pAcl = (PACL)LocalAlloc(LMEM_FIXED, LengthAcl);
|
|
|
|
if (pAcl == NULL)
|
|
{
|
|
Status = ERROR_NOT_ENOUGH_MEMORY;
|
|
schDebugOut((DEB_ERROR,
|
|
"CreateSecurityDescriptor, ACL allocation failed\n"));
|
|
goto ErrorExit;
|
|
}
|
|
|
|
if (!InitializeAcl(pAcl, LengthAcl, ACL_REVISION))
|
|
{
|
|
Status = GetLastError();
|
|
schDebugOut((DEB_ERROR,
|
|
"CreateSecurityDescriptor, InitializeAcl failed, " \
|
|
"status = 0x%lx\n",
|
|
Status));
|
|
goto ErrorExit;
|
|
}
|
|
|
|
for (i = 0; i < AceCount; i++)
|
|
{
|
|
if (!AddAce(pAcl,
|
|
ACL_REVISION,
|
|
0,
|
|
rgAce[i],
|
|
rgAce[i]->Header.AceSize))
|
|
{
|
|
Status = GetLastError();
|
|
schDebugOut((DEB_ERROR,
|
|
"CreateSecurityDescriptor, AddAce[%l] failed, " \
|
|
"status = 0x%lx\n", i, Status));
|
|
goto ErrorExit;
|
|
}
|
|
|
|
LocalFree(rgAce[i]);
|
|
rgAce[i] = NULL;
|
|
}
|
|
|
|
//
|
|
// Create the security descriptor.
|
|
//
|
|
|
|
pSecurityDescriptor = LocalAlloc(LMEM_FIXED,
|
|
SECURITY_DESCRIPTOR_MIN_LENGTH);
|
|
|
|
if (pSecurityDescriptor == NULL)
|
|
{
|
|
Status = ERROR_NOT_ENOUGH_MEMORY;
|
|
schDebugOut((DEB_ERROR,
|
|
"CreateSecurityDescriptor, SECURITY_DESCRIPTOR allocation " \
|
|
"failed\n"));
|
|
goto ErrorExit;
|
|
}
|
|
|
|
if (!InitializeSecurityDescriptor(pSecurityDescriptor,
|
|
SECURITY_DESCRIPTOR_REVISION))
|
|
{
|
|
Status = GetLastError();
|
|
schDebugOut((DEB_ERROR,
|
|
"CreateSecurityDescriptor, InitializeSecurityDescriptor " \
|
|
"failed, status = 0x%lx\n",
|
|
Status));
|
|
goto ErrorExit;
|
|
}
|
|
|
|
if (!SetSecurityDescriptorDacl(pSecurityDescriptor,
|
|
TRUE,
|
|
pAcl,
|
|
FALSE))
|
|
{
|
|
Status = GetLastError();
|
|
schDebugOut((DEB_ERROR,
|
|
"CreateSecurityDescriptor, SetSecurityDescriptorDacl " \
|
|
"failed, status = 0x%lx\n",
|
|
Status));
|
|
goto ErrorExit;
|
|
}
|
|
|
|
if (pStatus != NULL) *pStatus = ERROR_SUCCESS;
|
|
|
|
return(pSecurityDescriptor);
|
|
|
|
ErrorExit:
|
|
for (i = 0; i < AceCount; i++)
|
|
{
|
|
if (rgAce[i] != NULL)
|
|
{
|
|
LocalFree(rgAce[i]);
|
|
rgAce[i] = NULL;
|
|
}
|
|
}
|
|
if (pAcl != NULL) LocalFree(pAcl);
|
|
if (pSecurityDescriptor != NULL) LocalFree(pSecurityDescriptor);
|
|
|
|
if (pStatus != NULL) *pStatus = Status;
|
|
|
|
return(NULL);
|
|
}
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Function: DeleteSecurityDescriptor
|
|
//
|
|
// Synopsis: Deallocate the security descriptor allocated in
|
|
// CreateSecurityDescriptor.
|
|
//
|
|
// Arguments: [pSecurityDescriptor] -- SD returned from
|
|
// CreateSecurityDescriptor.
|
|
//
|
|
// Returns: None.
|
|
//
|
|
// Notes: None.
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
void
|
|
DeleteSecurityDescriptor(PSECURITY_DESCRIPTOR pSecurityDescriptor)
|
|
{
|
|
BOOL fPresent;
|
|
BOOL fDefaulted;
|
|
PACL pAcl;
|
|
|
|
schAssert(pSecurityDescriptor != NULL);
|
|
|
|
if (GetSecurityDescriptorDacl(pSecurityDescriptor,
|
|
&fPresent,
|
|
&pAcl,
|
|
&fDefaulted))
|
|
{
|
|
if (fPresent && pAcl != NULL)
|
|
{
|
|
LocalFree(pAcl);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
schDebugOut((DEB_ERROR,
|
|
"DeleteSecurityDescriptor, GetSecurityDescriptorDacl failed, " \
|
|
"status = 0x%lx\n",
|
|
GetLastError()));
|
|
}
|
|
|
|
LocalFree(pSecurityDescriptor);
|
|
}
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Function: CreateAccessAllowedAce
|
|
//
|
|
// Synopsis: Scavenged code from winlogon to create an access allowed ACE.
|
|
// Modified a bit to use Win32 vs. Rtl.
|
|
//
|
|
// Arguments: [pSid] -- Sid to which this ACE is applied.
|
|
// [AccessMask] -- ACE access mask value.
|
|
// [AceFlags] -- ACE flags value.
|
|
// [InheritFlags] -- ACE inherit flags value.
|
|
//
|
|
// Returns: Created ACE if successful.
|
|
// NULL on error.
|
|
//
|
|
// Notes: None.
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
PACCESS_ALLOWED_ACE
|
|
CreateAccessAllowedAce(
|
|
PSID pSid,
|
|
ACCESS_MASK AccessMask,
|
|
UCHAR AceFlags,
|
|
UCHAR InheritFlags,
|
|
DWORD * pStatus)
|
|
{
|
|
ULONG LengthSid = GetLengthSid(pSid);
|
|
ULONG LengthACE = sizeof(ACE_HEADER) + sizeof(ACCESS_MASK) + LengthSid;
|
|
PACCESS_ALLOWED_ACE Ace;
|
|
|
|
Ace = (PACCESS_ALLOWED_ACE)LocalAlloc(LMEM_FIXED, LengthACE);
|
|
|
|
if (Ace == NULL)
|
|
{
|
|
if (pStatus != NULL) *pStatus = ERROR_NOT_ENOUGH_MEMORY;
|
|
schDebugOut((DEB_ERROR,
|
|
"CreateAccessAllowedAce, ACE allocation failed\n"));
|
|
return(NULL);
|
|
}
|
|
|
|
Ace->Header.AceType = ACCESS_ALLOWED_ACE_TYPE;
|
|
Ace->Header.AceSize = (UCHAR)LengthACE;
|
|
Ace->Header.AceFlags = AceFlags | InheritFlags;
|
|
Ace->Mask = AccessMask;
|
|
CopySid(LengthSid, (PSID)(&(Ace->SidStart)), pSid);
|
|
|
|
if (pStatus != NULL) *pStatus = ERROR_SUCCESS;
|
|
|
|
return(Ace);
|
|
}
|
|
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Function: IsThreadCallerAnAdmin
|
|
//
|
|
// Synopsis: Determine if the user represented by the specified token is a
|
|
// member of the administrators group.
|
|
//
|
|
// Arguments: [hThreadToken] -- Token to check. If NULL, the current
|
|
// thread's token is used if there is one, or else the
|
|
// current process' token.
|
|
//
|
|
// Returns: TRUE -- Match
|
|
// FALSE -- Thread caller not an admin or an error occurred.
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
BOOL
|
|
IsThreadCallerAnAdmin(HANDLE hThreadToken)
|
|
{
|
|
//
|
|
// Create an admin SID to compare against.
|
|
//
|
|
#if 1
|
|
//
|
|
// Efficient way - relies on the format of the SID structure (which is
|
|
// published in winnt.h) - valid for at least NT 4 and NT 5
|
|
//
|
|
|
|
schAssert(sizeof SID == 12);
|
|
|
|
const struct
|
|
{
|
|
SID Sid;
|
|
DWORD SubAuthority1;
|
|
} AdminSid =
|
|
{
|
|
{ SID_REVISION, // Revision
|
|
2, // SubAuthorityCount
|
|
SECURITY_NT_AUTHORITY, // IdentifierAuthority
|
|
SECURITY_BUILTIN_DOMAIN_RID }, // SubAuthority[0]
|
|
DOMAIN_ALIAS_RID_ADMINS // SubAuthority[1]
|
|
};
|
|
#else
|
|
/*
|
|
#error SID structure has changed!
|
|
//
|
|
// Inefficient way, initialize at run time
|
|
//
|
|
BYTE AdminSid[MAX_SID_SIZE];
|
|
SID_IDENTIFIER_AUTHORITY IdentifierAuthority = SECURITY_NT_AUTHORITY;
|
|
|
|
if (! InitializeSid(rgbAdminSid, &IdentifierAuthority, 2))
|
|
{
|
|
schAssert(0);
|
|
CHECK_HRESULT(HRESULT_FROM_WIN32(GetLastError()));
|
|
return FALSE;
|
|
}
|
|
|
|
*GetSidSubAuthority(rgbAdminSid, 0) = SECURITY_BUILTIN_DOMAIN_RID;
|
|
*GetSidSubAuthority(rgbAdminSid, 1) = DOMAIN_ALIAS_RID_ADMINS;
|
|
*/
|
|
#endif
|
|
|
|
//
|
|
// See if the token is a member.
|
|
//
|
|
BOOL fIsCallerAdmin;
|
|
if (!CheckTokenMembership(hThreadToken,
|
|
(PSID) &AdminSid,
|
|
&fIsCallerAdmin))
|
|
{
|
|
CHECK_HRESULT(HRESULT_FROM_WIN32(GetLastError()));
|
|
return FALSE;
|
|
}
|
|
|
|
return fIsCallerAdmin;
|
|
}
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Function: EnablePrivilege
|
|
//
|
|
// Synopsis: Tries to enable / disable a privilege for the current process.
|
|
//
|
|
// Arguments: [pszPrivName] - name of privilege to enable / disable.
|
|
// [bEnable] - enable / disable switch.
|
|
// [pbWasEnabled] - optional pointer to receive the previous
|
|
// state of the privilege.
|
|
//
|
|
// Returns: win32 error code.
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
DWORD
|
|
EnablePrivilege(
|
|
IN PCWSTR pszPrivName,
|
|
IN BOOL bEnable,
|
|
OUT PBOOL pbWasEnabled OPTIONAL
|
|
)
|
|
{
|
|
DWORD dwError = ERROR_SUCCESS;
|
|
BOOL bSuccess;
|
|
HANDLE hToken = 0;
|
|
DWORD dwSize;
|
|
TOKEN_PRIVILEGES privNew;
|
|
TOKEN_PRIVILEGES privOld;
|
|
|
|
bSuccess = OpenProcessToken(
|
|
GetCurrentProcess(),
|
|
TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY,
|
|
&hToken);
|
|
|
|
if (!bSuccess)
|
|
{
|
|
dwError = GetLastError();
|
|
goto Cleanup;
|
|
}
|
|
|
|
bSuccess = LookupPrivilegeValue(
|
|
0,
|
|
pszPrivName,
|
|
&privNew.Privileges[0].Luid);
|
|
|
|
if (!bSuccess)
|
|
{
|
|
dwError = GetLastError();
|
|
goto Cleanup;
|
|
}
|
|
|
|
privNew.PrivilegeCount = 1;
|
|
privNew.Privileges[0].Attributes = bEnable ? SE_PRIVILEGE_ENABLED : 0;
|
|
|
|
bSuccess = AdjustTokenPrivileges(
|
|
hToken,
|
|
FALSE,
|
|
&privNew,
|
|
sizeof(privOld),
|
|
&privOld,
|
|
&dwSize);
|
|
|
|
if (!bSuccess)
|
|
{
|
|
dwError = GetLastError();
|
|
goto Cleanup;
|
|
}
|
|
|
|
if (pbWasEnabled)
|
|
{
|
|
*pbWasEnabled = (privOld.Privileges[0].Attributes & SE_PRIVILEGE_ENABLED)
|
|
? TRUE : FALSE;
|
|
}
|
|
|
|
Cleanup:
|
|
|
|
if (hToken)
|
|
{
|
|
CloseHandle(hToken);
|
|
}
|
|
|
|
return dwError;
|
|
}
|