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.
1511 lines
41 KiB
1511 lines
41 KiB
//+-------------------------------------------------------------------------
|
|
//
|
|
// Microsoft Windows
|
|
//
|
|
// Copyright (C) Microsoft Corporation, 1996 - 1999
|
|
//
|
|
// File: misc.cpp
|
|
//
|
|
// This file contains miscellaneous helper functions.
|
|
//
|
|
//--------------------------------------------------------------------------
|
|
|
|
#include "aclpriv.h"
|
|
|
|
/*******************************************************************
|
|
|
|
NAME: GetAceSid
|
|
|
|
SYNOPSIS: Gets pointer to SID from an ACE
|
|
|
|
ENTRY: pAce - pointer to ACE
|
|
|
|
EXIT:
|
|
|
|
RETURNS: Pointer to SID if successful, NULL otherwise
|
|
|
|
NOTES:
|
|
|
|
HISTORY:
|
|
JeffreyS 08-Oct-1996 Created
|
|
|
|
********************************************************************/
|
|
|
|
PSID
|
|
GetAceSid(PACE_HEADER pAce)
|
|
{
|
|
switch (pAce->AceType)
|
|
{
|
|
case ACCESS_ALLOWED_ACE_TYPE:
|
|
case ACCESS_DENIED_ACE_TYPE:
|
|
case SYSTEM_AUDIT_ACE_TYPE:
|
|
case SYSTEM_ALARM_ACE_TYPE:
|
|
return (PSID)&((PKNOWN_ACE)pAce)->SidStart;
|
|
|
|
case ACCESS_ALLOWED_COMPOUND_ACE_TYPE:
|
|
return (PSID)&((PKNOWN_COMPOUND_ACE)pAce)->SidStart;
|
|
|
|
case ACCESS_ALLOWED_OBJECT_ACE_TYPE:
|
|
case ACCESS_DENIED_OBJECT_ACE_TYPE:
|
|
case SYSTEM_AUDIT_OBJECT_ACE_TYPE:
|
|
case SYSTEM_ALARM_OBJECT_ACE_TYPE:
|
|
return RtlObjectAceSid(pAce);
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
|
|
|
|
/*******************************************************************
|
|
|
|
NAME: LocalAllocSid
|
|
|
|
SYNOPSIS: Copies a SID
|
|
|
|
ENTRY: pOriginal - pointer to SID to copy
|
|
|
|
EXIT:
|
|
|
|
RETURNS: Pointer to SID if successful, NULL otherwise
|
|
|
|
NOTES: Caller must free the returned SID with LocalFree
|
|
|
|
HISTORY:
|
|
JeffreyS 12-Apr-1999 Created
|
|
|
|
********************************************************************/
|
|
|
|
PSID
|
|
LocalAllocSid(PSID pOriginal)
|
|
{
|
|
PSID pCopy = NULL;
|
|
if (pOriginal && IsValidSid(pOriginal))
|
|
{
|
|
DWORD dwLength = GetLengthSid(pOriginal);
|
|
pCopy = (PSID)LocalAlloc(LMEM_FIXED, dwLength);
|
|
if (NULL != pCopy)
|
|
CopyMemory(pCopy, pOriginal, dwLength);
|
|
}
|
|
return pCopy;
|
|
}
|
|
|
|
|
|
/*******************************************************************
|
|
|
|
NAME: DestroyDPA
|
|
|
|
SYNOPSIS: LocalFree's all pointers in a Dynamic Pointer
|
|
Array and then frees the DPA.
|
|
|
|
ENTRY: hList - handle of list to destroy
|
|
|
|
EXIT:
|
|
|
|
RETURNS: nothing
|
|
|
|
NOTES:
|
|
|
|
HISTORY:
|
|
JeffreyS 08-Oct-1996 Created
|
|
|
|
********************************************************************/
|
|
|
|
int CALLBACK
|
|
_LocalFreeCB(LPVOID pVoid, LPVOID /*pData*/)
|
|
{
|
|
if (pVoid)
|
|
LocalFree(pVoid);
|
|
return 1;
|
|
}
|
|
|
|
void
|
|
DestroyDPA(HDPA hList)
|
|
{
|
|
if (hList != NULL)
|
|
DPA_DestroyCallback(hList, _LocalFreeCB, 0);
|
|
}
|
|
|
|
|
|
|
|
/*******************************************************************
|
|
|
|
NAME: GetLSAConnection
|
|
|
|
SYNOPSIS: Wrapper for LsaOpenPolicy
|
|
|
|
ENTRY: pszServer - the server on which to make the connection
|
|
|
|
EXIT:
|
|
|
|
RETURNS: LSA_HANDLE if successful, NULL otherwise
|
|
|
|
NOTES:
|
|
|
|
HISTORY:
|
|
JeffreyS 08-Oct-1996 Created
|
|
|
|
********************************************************************/
|
|
|
|
LSA_HANDLE
|
|
GetLSAConnection(LPCTSTR pszServer, DWORD dwAccessDesired)
|
|
{
|
|
LSA_HANDLE hPolicy = NULL;
|
|
LSA_UNICODE_STRING uszServer = {0};
|
|
LSA_UNICODE_STRING *puszServer = NULL;
|
|
LSA_OBJECT_ATTRIBUTES oa;
|
|
SECURITY_QUALITY_OF_SERVICE sqos;
|
|
|
|
sqos.Length = SIZEOF(sqos);
|
|
sqos.ImpersonationLevel = SecurityImpersonation;
|
|
sqos.ContextTrackingMode = SECURITY_DYNAMIC_TRACKING;
|
|
sqos.EffectiveOnly = FALSE;
|
|
|
|
InitializeObjectAttributes(&oa, NULL, 0, NULL, NULL);
|
|
oa.SecurityQualityOfService = &sqos;
|
|
|
|
if (pszServer &&
|
|
*pszServer &&
|
|
RtlCreateUnicodeString(&uszServer, pszServer))
|
|
{
|
|
puszServer = &uszServer;
|
|
}
|
|
|
|
LsaOpenPolicy(puszServer, &oa, dwAccessDesired, &hPolicy);
|
|
|
|
if (puszServer)
|
|
RtlFreeUnicodeString(puszServer);
|
|
|
|
return hPolicy;
|
|
}
|
|
|
|
|
|
/*******************************************************************
|
|
|
|
NAME: LookupSid
|
|
|
|
SYNOPSIS: Gets the qualified account name for a given SID
|
|
|
|
ENTRY: pszServer - the server on which to do the lookup
|
|
pSid - the SID to lookup
|
|
|
|
EXIT: *ppszName contains the account name. This buffer
|
|
must be freed by the caller with LocalFree.
|
|
|
|
*pSidType contains the SID type. pSidType is optional.
|
|
|
|
RETURNS: TRUE if successful, FALSE otherwise
|
|
|
|
NOTES:
|
|
|
|
HISTORY:
|
|
JeffreyS 08-Oct-1996 Created
|
|
JeffreyS 16-Jan-1998 Converted to HDPA (multiple lookup)
|
|
|
|
********************************************************************/
|
|
|
|
BOOL
|
|
LookupSids(HDPA hSids, LPCTSTR pszServer, LPSECURITYINFO2 psi2, PUSER_LIST *ppUserList)
|
|
{
|
|
PSIDCACHE pSidCache;
|
|
|
|
if (NULL == hSids)
|
|
return FALSE;
|
|
|
|
if (ppUserList != NULL)
|
|
*ppUserList = NULL;
|
|
|
|
pSidCache = GetSidCache();
|
|
|
|
if (NULL != pSidCache)
|
|
{
|
|
BOOL bRet = pSidCache->LookupSids(hSids, pszServer, psi2, ppUserList);
|
|
pSidCache->Release();
|
|
return bRet;
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
BOOL
|
|
LookupSid(PSID pSid, LPCTSTR pszServer, LPSECURITYINFO2 psi2, PUSER_LIST *ppUserList)
|
|
{
|
|
BOOL fResult;
|
|
HDPA hSids = NULL;
|
|
|
|
if (NULL == pSid)
|
|
return FALSE;
|
|
|
|
hSids = DPA_Create(1);
|
|
|
|
if (NULL == hSids)
|
|
return FALSE;
|
|
|
|
DPA_AppendPtr(hSids, pSid);
|
|
|
|
fResult = LookupSids(hSids, pszServer, psi2, ppUserList);
|
|
|
|
if (NULL != hSids)
|
|
DPA_Destroy(hSids);
|
|
|
|
return fResult;
|
|
}
|
|
|
|
// Private data structure used by LookupSidsAsync to pass
|
|
// data needed by the thread
|
|
typedef struct _LOOKUPSIDSDATA
|
|
{
|
|
HDPA hSids;
|
|
LPTSTR pszServer;
|
|
HWND hWndNotify;
|
|
UINT uMsgNotify;
|
|
} LOOKUPSIDSDATA, *PLOOKUPSIDSDATA;
|
|
|
|
|
|
DWORD WINAPI
|
|
_LookupSidsAsyncProc(LPVOID pv)
|
|
{
|
|
PLOOKUPSIDSDATA pdata = (PLOOKUPSIDSDATA)pv;
|
|
|
|
if (pdata)
|
|
{
|
|
PSIDCACHE pSidCache = GetSidCache();
|
|
|
|
if (NULL != pSidCache)
|
|
{
|
|
pSidCache->LookupSidsAsync(pdata->hSids,
|
|
pdata->pszServer,
|
|
NULL,
|
|
pdata->hWndNotify,
|
|
pdata->uMsgNotify);
|
|
pSidCache->Release();
|
|
}
|
|
|
|
PostMessage(pdata->hWndNotify, pdata->uMsgNotify, 0, 0);
|
|
|
|
DestroyDPA(pdata->hSids);
|
|
LocalFreeString(&pdata->pszServer);
|
|
LocalFree(pdata);
|
|
}
|
|
|
|
FreeLibraryAndExitThread(GetModuleHandle(c_szDllName), 0);
|
|
return 0;
|
|
}
|
|
|
|
BOOL
|
|
LookupSidsAsync(HDPA hSids,
|
|
LPCTSTR pszServer,
|
|
LPSECURITYINFO2 psi2,
|
|
HWND hWndNotify,
|
|
UINT uMsgNotify,
|
|
PHANDLE phThread)
|
|
{
|
|
PLOOKUPSIDSDATA pdata;
|
|
|
|
if (phThread)
|
|
*phThread = NULL;
|
|
|
|
if (NULL == hSids)
|
|
return FALSE;
|
|
|
|
if (psi2)
|
|
{
|
|
// Should marshal psi2 into a stream and do this on the
|
|
// other thread. Well No one has implemented psi2 so its fine.
|
|
BOOL bResult = LookupSids(hSids, pszServer, psi2, NULL);
|
|
PostMessage(hWndNotify, uMsgNotify, 0, 0);
|
|
return bResult;
|
|
}
|
|
|
|
//
|
|
// Copy all of the data so the thread can be abandoned if necessary
|
|
//
|
|
pdata = (PLOOKUPSIDSDATA)LocalAlloc(LPTR, SIZEOF(LOOKUPSIDSDATA));
|
|
if (pdata)
|
|
{
|
|
int cSids;
|
|
int i;
|
|
HINSTANCE hInstThisDll;
|
|
DWORD dwThreadId;
|
|
HANDLE hThread;
|
|
|
|
cSids = DPA_GetPtrCount(hSids);
|
|
pdata->hSids = DPA_Create(cSids);
|
|
|
|
if (!pdata->hSids)
|
|
{
|
|
LocalFree(pdata);
|
|
return FALSE;
|
|
}
|
|
|
|
for (i = 0; i < cSids; i++)
|
|
{
|
|
PSID p2 = LocalAllocSid((PSID)DPA_FastGetPtr(hSids, i));
|
|
if (p2)
|
|
{
|
|
DPA_AppendPtr(pdata->hSids, p2);
|
|
}
|
|
}
|
|
|
|
if (pszServer)
|
|
LocalAllocString(&pdata->pszServer, pszServer);
|
|
|
|
pdata->hWndNotify = hWndNotify;
|
|
pdata->uMsgNotify = uMsgNotify;
|
|
|
|
// Give the thread we are about to create a ref to the dll,
|
|
// so that the dll will remain for the lifetime of the thread
|
|
hInstThisDll = LoadLibrary(c_szDllName);
|
|
|
|
hThread = CreateThread(NULL,
|
|
0,
|
|
_LookupSidsAsyncProc,
|
|
pdata,
|
|
NULL,
|
|
&dwThreadId);
|
|
if (hThread != NULL)
|
|
{
|
|
if (phThread)
|
|
*phThread = hThread;
|
|
else
|
|
CloseHandle(hThread);
|
|
return TRUE;
|
|
}
|
|
else
|
|
{
|
|
// Thread creation has failed; clean up
|
|
DestroyDPA(pdata->hSids);
|
|
LocalFreeString(&pdata->pszServer);
|
|
LocalFree(pdata);
|
|
FreeLibrary(hInstThisDll);
|
|
}
|
|
}
|
|
return FALSE;
|
|
}
|
|
|
|
BOOL
|
|
BuildUserDisplayName(LPTSTR *ppszDisplayName,
|
|
LPCTSTR pszName,
|
|
LPCTSTR pszLogonName)
|
|
{
|
|
TCHAR szDisplayName[MAX_PATH];
|
|
|
|
if (NULL == ppszDisplayName || NULL == pszName)
|
|
return FALSE;
|
|
|
|
*ppszDisplayName = NULL;
|
|
|
|
if (NULL != pszLogonName && *pszLogonName)
|
|
{
|
|
return (BOOL)FormatStringID(ppszDisplayName,
|
|
::hModule,
|
|
IDS_FMT_USER_DISPLAY,
|
|
pszName,
|
|
pszLogonName);
|
|
}
|
|
|
|
return SUCCEEDED(LocalAllocString(ppszDisplayName, pszName));
|
|
}
|
|
|
|
|
|
/*******************************************************************
|
|
|
|
NAME: LoadImageList
|
|
|
|
SYNOPSIS: Creates an image list from a bitmap resource
|
|
|
|
ENTRY: hInstance - the bitmap lives here
|
|
pszBitmapID - resource ID of the bitmap
|
|
|
|
EXIT:
|
|
|
|
RETURNS: HIMAGELIST if successful, NULL otherwise
|
|
|
|
NOTES:
|
|
In order to calculate the number of images, it is assumed
|
|
that the width and height of a single image are the same.
|
|
|
|
HISTORY:
|
|
JeffreyS 08-Oct-1996 Created
|
|
|
|
********************************************************************/
|
|
|
|
HIMAGELIST
|
|
LoadImageList(HINSTANCE hInstance, LPCTSTR pszBitmapID)
|
|
{
|
|
HIMAGELIST himl = NULL;
|
|
HBITMAP hbm = LoadBitmap(hInstance, pszBitmapID);
|
|
|
|
if (hbm != NULL)
|
|
{
|
|
BITMAP bm;
|
|
GetObject(hbm, SIZEOF(bm), &bm);
|
|
|
|
himl = ImageList_Create(bm.bmHeight, // height == width
|
|
bm.bmHeight,
|
|
ILC_COLOR | ILC_MASK,
|
|
bm.bmWidth / bm.bmHeight,
|
|
0); // don't need to grow
|
|
if (himl != NULL)
|
|
ImageList_AddMasked(himl, hbm, CLR_DEFAULT);
|
|
|
|
DeleteObject(hbm);
|
|
}
|
|
|
|
return himl;
|
|
}
|
|
|
|
|
|
/*******************************************************************
|
|
|
|
NAME: GetSidImageIndex
|
|
|
|
SYNOPSIS: Gets the image index for the given SID type
|
|
|
|
ENTRY: sidType - type of SID
|
|
sidSys - well-known group type
|
|
fRemoteUser - TRUE if SID is a user on a remote system
|
|
|
|
EXIT:
|
|
|
|
RETURNS: index into image list
|
|
|
|
NOTES:
|
|
|
|
HISTORY:
|
|
JeffreyS 08-Oct-1996 Created
|
|
|
|
********************************************************************/
|
|
|
|
SID_IMAGE_INDEX
|
|
GetSidImageIndex(PSID psid,
|
|
SID_NAME_USE sidType)
|
|
{
|
|
SID_IMAGE_INDEX idBitmap;
|
|
|
|
switch (sidType)
|
|
{
|
|
case SidTypeUser:
|
|
idBitmap = SID_IMAGE_USER;
|
|
break;
|
|
|
|
case SidTypeAlias:
|
|
case SidTypeGroup:
|
|
case SidTypeWellKnownGroup:
|
|
idBitmap = SID_IMAGE_GROUP;
|
|
break;
|
|
|
|
case SidTypeComputer:
|
|
idBitmap = SID_IMAGE_COMPUTER;
|
|
break;
|
|
|
|
default:
|
|
idBitmap = SID_IMAGE_UNKNOWN;
|
|
break;
|
|
}
|
|
|
|
return idBitmap;
|
|
}
|
|
|
|
|
|
#include <dsrole.h>
|
|
BOOL IsStandalone(LPCTSTR pszMachine, PBOOL pbIsDC)
|
|
{
|
|
BOOL bStandalone = TRUE;
|
|
PDSROLE_PRIMARY_DOMAIN_INFO_BASIC pDsRole = NULL;
|
|
|
|
//
|
|
// Find out if target machine is a standalone machine or joined to
|
|
// an NT domain.
|
|
//
|
|
|
|
__try
|
|
{
|
|
if (pbIsDC)
|
|
*pbIsDC = FALSE;
|
|
|
|
DsRoleGetPrimaryDomainInformation(pszMachine,
|
|
DsRolePrimaryDomainInfoBasic,
|
|
(PBYTE*)&pDsRole);
|
|
}
|
|
__finally
|
|
{
|
|
}
|
|
|
|
if (NULL != pDsRole)
|
|
{
|
|
if (pDsRole->MachineRole == DsRole_RoleStandaloneWorkstation ||
|
|
pDsRole->MachineRole == DsRole_RoleStandaloneServer)
|
|
{
|
|
bStandalone = TRUE;
|
|
}
|
|
else
|
|
bStandalone = FALSE;
|
|
|
|
if (pbIsDC)
|
|
{
|
|
if (pDsRole->MachineRole == DsRole_RolePrimaryDomainController ||
|
|
pDsRole->MachineRole == DsRole_RoleBackupDomainController)
|
|
{
|
|
*pbIsDC = TRUE;
|
|
}
|
|
}
|
|
|
|
DsRoleFreeMemory(pDsRole);
|
|
}
|
|
|
|
return bStandalone;
|
|
}
|
|
|
|
|
|
|
|
/*******************************************************************
|
|
|
|
NAME: IsDACLCanonical
|
|
|
|
SYNOPSIS: Checks a DACL for canonical ordering
|
|
|
|
ENTRY: pDacl - points to DACL to check
|
|
|
|
EXIT:
|
|
|
|
RETURNS: Nonzero if DACL is in canonical order, zero otherwise
|
|
|
|
NOTES:
|
|
|
|
HISTORY:
|
|
JeffreyS 08-Oct-1996 Created
|
|
JeffreyS 03-Oct-1997 Make object aces same as non-object aces
|
|
|
|
********************************************************************/
|
|
|
|
enum ACELEVEL
|
|
{
|
|
alNonInheritAccessDenied,
|
|
alNonInheritAccessAllowed,
|
|
alInheritedAces,
|
|
};
|
|
|
|
BOOL
|
|
IsDACLCanonical(PACL pDacl)
|
|
{
|
|
PACE_HEADER pAce;
|
|
ACELEVEL currentAceLevel;
|
|
DWORD dwAceCount;
|
|
|
|
if (pDacl == NULL)
|
|
return TRUE;
|
|
|
|
currentAceLevel = alNonInheritAccessDenied;
|
|
dwAceCount = pDacl->AceCount;
|
|
|
|
if (dwAceCount == 0)
|
|
return TRUE;
|
|
|
|
for (pAce = (PACE_HEADER)FirstAce(pDacl);
|
|
dwAceCount > 0;
|
|
--dwAceCount, pAce = (PACE_HEADER)NextAce(pAce))
|
|
{
|
|
ACELEVEL aceLevel;
|
|
|
|
//
|
|
// NOTE: We do not skip INHERIT_ONLY aces because we want them in
|
|
// canonical order too.
|
|
//
|
|
|
|
if (pAce->AceFlags & INHERITED_ACE)
|
|
{
|
|
aceLevel = alInheritedAces; // don't check order here
|
|
}
|
|
else
|
|
{
|
|
switch(pAce->AceType)
|
|
{
|
|
case ACCESS_DENIED_ACE_TYPE:
|
|
case ACCESS_DENIED_OBJECT_ACE_TYPE:
|
|
aceLevel = alNonInheritAccessDenied;
|
|
break;
|
|
|
|
case ACCESS_ALLOWED_ACE_TYPE:
|
|
case ACCESS_ALLOWED_COMPOUND_ACE_TYPE:
|
|
case ACCESS_ALLOWED_OBJECT_ACE_TYPE:
|
|
aceLevel = alNonInheritAccessAllowed;
|
|
break;
|
|
|
|
default:
|
|
return FALSE;
|
|
}
|
|
}
|
|
|
|
//
|
|
// If the ace type is less than the level we are currently at,
|
|
// then it is not canonical.
|
|
//
|
|
if (aceLevel < currentAceLevel)
|
|
return FALSE;
|
|
|
|
//
|
|
// Update the current ace level.
|
|
//
|
|
currentAceLevel = aceLevel;
|
|
}
|
|
|
|
//
|
|
// If we get here, then the DACL is in canonical order.
|
|
//
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
/*******************************************************************
|
|
|
|
NAME: IsDenyACL
|
|
|
|
SYNOPSIS: Checks a DACL for Deny ACEs. Also looks for "Deny
|
|
All" ACEs.
|
|
|
|
ENTRY: pDacl - points to DACL to check
|
|
|
|
EXIT: *pdwWarning is 0, IDS_PERM_DENY, or IDS_PERM_DENY_ALL
|
|
|
|
RETURNS: Nonzero if DACL contains any Deny ACEs, zero otherwise
|
|
|
|
NOTES:
|
|
|
|
HISTORY:
|
|
JeffreyS 05-Sep-1997 Created
|
|
|
|
********************************************************************/
|
|
|
|
BOOL
|
|
IsDenyACL(PACL pDacl,
|
|
BOOL fProtected,
|
|
DWORD dwFullControlMask,
|
|
LPDWORD pdwWarning)
|
|
{
|
|
DWORD dwWarning = 0;
|
|
|
|
TraceEnter(TRACE_MISC, "IsDenyACL");
|
|
|
|
// NULL DACL implies "Allow Everyone Full Control"
|
|
if (pDacl == NULL)
|
|
goto exit_gracefully;
|
|
|
|
// Check for empty DACL (no access to anyone)
|
|
if (pDacl->AceCount == 0)
|
|
{
|
|
if (fProtected)
|
|
dwWarning = IDS_PERM_DENY_EMPTY_DACL;
|
|
// else the object will inherit permissions from the parent.
|
|
}
|
|
else
|
|
{
|
|
PACE_HEADER pAce;
|
|
int iEntry;
|
|
|
|
// Iterate through the ACL looking for "Deny All"
|
|
for (iEntry = 0, pAce = (PACE_HEADER)FirstAce(pDacl);
|
|
iEntry < pDacl->AceCount;
|
|
iEntry++, pAce = (PACE_HEADER)NextAce(pAce))
|
|
{
|
|
if (pAce->AceType != ACCESS_DENIED_ACE_TYPE &&
|
|
pAce->AceType != ACCESS_DENIED_OBJECT_ACE_TYPE)
|
|
{
|
|
// Assuming the ACL is in canonical order, we can
|
|
// stop as soon as we find something that isn't
|
|
// a Deny ACE. (Deny ACEs come first)
|
|
break;
|
|
}
|
|
|
|
// Found a Deny ACE
|
|
dwWarning = IDS_PERM_DENY;
|
|
|
|
// Check for "Deny Everyone Full Control". Don't look
|
|
// for ACCESS_DENIED_OBJECT_ACE_TYPE here since Object
|
|
// aces don't have as wide an effect as normal aces.
|
|
if (pAce->AceType == ACCESS_DENIED_ACE_TYPE &&
|
|
((PKNOWN_ACE)pAce)->Mask == dwFullControlMask &&
|
|
EqualSid(GetAceSid(pAce), QuerySystemSid(UI_SID_World)))
|
|
{
|
|
// Found "Deny All"
|
|
dwWarning = IDS_PERM_DENY_EVERYONE_GROUP;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
exit_gracefully:
|
|
|
|
if (pdwWarning != NULL)
|
|
*pdwWarning = dwWarning;
|
|
|
|
TraceLeaveValue(dwWarning != 0);
|
|
}
|
|
|
|
|
|
/*******************************************************************
|
|
|
|
NAME: QuerySystemSid
|
|
|
|
SYNOPSIS: Retrieves the requested SID
|
|
|
|
ENTRY: SystemSidType - Which SID to retrieve
|
|
|
|
EXIT:
|
|
|
|
RETURNS: PSID if successful, NULL otherwise
|
|
|
|
HISTORY:
|
|
JeffreyS 08-Oct-1996 Created
|
|
|
|
********************************************************************/
|
|
|
|
//
|
|
// Global array of static system SIDs, corresponding to UI_SystemSid
|
|
//
|
|
const struct
|
|
{
|
|
SID sid; // contains 1 subauthority
|
|
DWORD dwSubAuth[1]; // we currently need at most 2 subauthorities
|
|
} g_StaticSids[COUNT_SYSTEM_SID_TYPES] =
|
|
{
|
|
{{SID_REVISION,1,SECURITY_WORLD_SID_AUTHORITY, {SECURITY_WORLD_RID}}, {0} },
|
|
{{SID_REVISION,1,SECURITY_CREATOR_SID_AUTHORITY,{SECURITY_CREATOR_OWNER_RID}}, {0} },
|
|
{{SID_REVISION,1,SECURITY_CREATOR_SID_AUTHORITY,{SECURITY_CREATOR_GROUP_RID}}, {0} },
|
|
{{SID_REVISION,1,SECURITY_NT_AUTHORITY, {SECURITY_DIALUP_RID}}, {0} },
|
|
{{SID_REVISION,1,SECURITY_NT_AUTHORITY, {SECURITY_NETWORK_RID}}, {0} },
|
|
{{SID_REVISION,1,SECURITY_NT_AUTHORITY, {SECURITY_BATCH_RID}}, {0} },
|
|
{{SID_REVISION,1,SECURITY_NT_AUTHORITY, {SECURITY_INTERACTIVE_RID}}, {0} },
|
|
{{SID_REVISION,1,SECURITY_NT_AUTHORITY, {SECURITY_SERVICE_RID}}, {0} },
|
|
{{SID_REVISION,1,SECURITY_NT_AUTHORITY, {SECURITY_ANONYMOUS_LOGON_RID}}, {0} },
|
|
{{SID_REVISION,1,SECURITY_NT_AUTHORITY, {SECURITY_PROXY_RID}}, {0} },
|
|
{{SID_REVISION,1,SECURITY_NT_AUTHORITY, {SECURITY_ENTERPRISE_CONTROLLERS_RID}},{0} },
|
|
{{SID_REVISION,1,SECURITY_NT_AUTHORITY, {SECURITY_PRINCIPAL_SELF_RID}}, {0} },
|
|
{{SID_REVISION,1,SECURITY_NT_AUTHORITY, {SECURITY_AUTHENTICATED_USER_RID}}, {0} },
|
|
{{SID_REVISION,1,SECURITY_NT_AUTHORITY, {SECURITY_RESTRICTED_CODE_RID}}, {0} },
|
|
{{SID_REVISION,1,SECURITY_NT_AUTHORITY, {SECURITY_TERMINAL_SERVER_RID}}, {0} },
|
|
{{SID_REVISION,1,SECURITY_NT_AUTHORITY, {SECURITY_LOCAL_SYSTEM_RID}}, {0} },
|
|
{{SID_REVISION,2,SECURITY_NT_AUTHORITY, {SECURITY_BUILTIN_DOMAIN_RID}}, {DOMAIN_ALIAS_RID_ADMINS} },
|
|
// {{SID_REVISION,2,SECURITY_NT_AUTHORITY, {SECURITY_BUILTIN_DOMAIN_RID}}, {DOMAIN_ALIAS_RID_USERS} },
|
|
// {{SID_REVISION,2,SECURITY_NT_AUTHORITY, {SECURITY_BUILTIN_DOMAIN_RID}}, {DOMAIN_ALIAS_RID_GUESTS} },
|
|
// {{SID_REVISION,2,SECURITY_NT_AUTHORITY, {SECURITY_BUILTIN_DOMAIN_RID}}, {DOMAIN_ALIAS_RID_POWER_USERS} },
|
|
// {{SID_REVISION,2,SECURITY_NT_AUTHORITY, {SECURITY_BUILTIN_DOMAIN_RID}}, {DOMAIN_ALIAS_RID_ACCOUNT_OPS} },
|
|
// {{SID_REVISION,2,SECURITY_NT_AUTHORITY, {SECURITY_BUILTIN_DOMAIN_RID}}, {DOMAIN_ALIAS_RID_SYSTEM_OPS} },
|
|
// {{SID_REVISION,2,SECURITY_NT_AUTHORITY, {SECURITY_BUILTIN_DOMAIN_RID}}, {DOMAIN_ALIAS_RID_PRINT_OPS} },
|
|
// {{SID_REVISION,2,SECURITY_NT_AUTHORITY, {SECURITY_BUILTIN_DOMAIN_RID}}, {DOMAIN_ALIAS_RID_BACKUP_OPS} },
|
|
// {{SID_REVISION,2,SECURITY_NT_AUTHORITY, {SECURITY_BUILTIN_DOMAIN_RID}}, {DOMAIN_ALIAS_RID_REPLICATOR} },
|
|
// {{SID_REVISION,2,SECURITY_NT_AUTHORITY, {SECURITY_BUILTIN_DOMAIN_RID}}, {DOMAIN_ALIAS_RID_RAS_SERVERS} },
|
|
};
|
|
|
|
PSID
|
|
QuerySystemSid(UI_SystemSid SystemSidType)
|
|
{
|
|
if (SystemSidType == UI_SID_Invalid || SystemSidType >= UI_SID_Count)
|
|
return NULL;
|
|
|
|
return (PSID)&g_StaticSids[SystemSidType];
|
|
}
|
|
|
|
|
|
//
|
|
// Global array of cached token SIDs
|
|
//
|
|
struct
|
|
{
|
|
SID sid; // SID contains 1 subauthority
|
|
DWORD dwSubAuth[SID_MAX_SUB_AUTHORITIES - 1];
|
|
} g_TokenSids[COUNT_TOKEN_SID_TYPES] = {0};
|
|
|
|
PSID
|
|
QueryTokenSid(UI_TokenSid TokenSidType)
|
|
{
|
|
if (TokenSidType == UI_TSID_Invalid || TokenSidType >= UI_TSID_Count)
|
|
return NULL;
|
|
|
|
if (0 == *GetSidSubAuthorityCount((PSID)&g_TokenSids[TokenSidType]))
|
|
{
|
|
HANDLE hProcessToken;
|
|
|
|
// Get the current process's user's SID
|
|
if (OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY, &hProcessToken))
|
|
{
|
|
BYTE buffer[sizeof(TOKEN_USER) + sizeof(g_TokenSids[0])];
|
|
ULONG cbBuffer = sizeof(buffer);
|
|
|
|
switch (TokenSidType)
|
|
{
|
|
case UI_TSID_CurrentProcessUser:
|
|
if (GetTokenInformation(hProcessToken,
|
|
TokenUser,
|
|
buffer,
|
|
cbBuffer,
|
|
&cbBuffer))
|
|
{
|
|
PTOKEN_USER ptu = (PTOKEN_USER)buffer;
|
|
CopyMemory(&g_TokenSids[UI_TSID_CurrentProcessUser],
|
|
ptu->User.Sid,
|
|
GetLengthSid(ptu->User.Sid));
|
|
}
|
|
break;
|
|
|
|
case UI_TSID_CurrentProcessOwner:
|
|
if (GetTokenInformation(hProcessToken,
|
|
TokenOwner,
|
|
buffer,
|
|
cbBuffer,
|
|
&cbBuffer))
|
|
{
|
|
PTOKEN_OWNER pto = (PTOKEN_OWNER)buffer;
|
|
CopyMemory(&g_TokenSids[UI_TSID_CurrentProcessOwner],
|
|
pto->Owner,
|
|
GetLengthSid(pto->Owner));
|
|
}
|
|
break;
|
|
|
|
case UI_TSID_CurrentProcessPrimaryGroup:
|
|
if (GetTokenInformation(hProcessToken,
|
|
TokenPrimaryGroup,
|
|
buffer,
|
|
cbBuffer,
|
|
&cbBuffer))
|
|
{
|
|
PTOKEN_PRIMARY_GROUP ptg = (PTOKEN_PRIMARY_GROUP)buffer;
|
|
CopyMemory(&g_TokenSids[UI_TSID_CurrentProcessPrimaryGroup],
|
|
ptg->PrimaryGroup,
|
|
GetLengthSid(ptg->PrimaryGroup));
|
|
}
|
|
break;
|
|
}
|
|
CloseHandle(hProcessToken);
|
|
}
|
|
|
|
if (0 == *GetSidSubAuthorityCount((PSID)&g_TokenSids[TokenSidType]))
|
|
return NULL;
|
|
}
|
|
|
|
return (PSID)&g_TokenSids[TokenSidType];
|
|
}
|
|
|
|
|
|
/*******************************************************************
|
|
|
|
NAME: GetAuthenticationID
|
|
|
|
SYNOPSIS: Retrieves the SID associated with the credentials
|
|
currently being used for network access.
|
|
(runas /netonly credentials)
|
|
|
|
ENTRY: pszServer = server on which to lookup the account.
|
|
NULL indicates local system.
|
|
|
|
EXIT:
|
|
|
|
RETURNS: PSID if successful, NULL otherwise. Caller must
|
|
free with LocalFree.
|
|
|
|
HISTORY:
|
|
JeffreyS 05-Aug-1999 Created
|
|
|
|
********************************************************************/
|
|
PSID
|
|
GetAuthenticationID(LPCWSTR pszServer)
|
|
{
|
|
PSID pSid = NULL;
|
|
HANDLE hLsa;
|
|
NTSTATUS Status;
|
|
|
|
//
|
|
// These LSA calls are delay-loaded from secur32.dll using the linker's
|
|
// delay-load mechanism. Therefore, wrap with an exception handler.
|
|
//
|
|
__try
|
|
{
|
|
Status = LsaConnectUntrusted(&hLsa);
|
|
|
|
if (Status == 0)
|
|
{
|
|
NEGOTIATE_CALLER_NAME_REQUEST Req = {0};
|
|
PNEGOTIATE_CALLER_NAME_RESPONSE pResp;
|
|
ULONG cbSize;
|
|
NTSTATUS SubStatus;
|
|
|
|
Req.MessageType = NegGetCallerName;
|
|
|
|
Status = LsaCallAuthenticationPackage(
|
|
hLsa,
|
|
0,
|
|
&Req,
|
|
sizeof(Req),
|
|
(void**)&pResp,
|
|
&cbSize,
|
|
&SubStatus);
|
|
|
|
if ((Status == 0) && (SubStatus == 0))
|
|
{
|
|
BYTE sid[sizeof(SID) + (SID_MAX_SUB_AUTHORITIES - 1)*sizeof(DWORD)];
|
|
PSID psid = (PSID)sid;
|
|
DWORD cbSid = sizeof(sid);
|
|
WCHAR szDomain[MAX_PATH];
|
|
DWORD cchDomain = ARRAYSIZE(szDomain);
|
|
SID_NAME_USE sidType;
|
|
|
|
if (LookupAccountNameW(pszServer,
|
|
pResp->CallerName,
|
|
psid,
|
|
&cbSid,
|
|
szDomain,
|
|
&cchDomain,
|
|
&sidType))
|
|
{
|
|
pSid = LocalAllocSid(psid);
|
|
}
|
|
|
|
LsaFreeReturnBuffer(pResp);
|
|
}
|
|
|
|
LsaDeregisterLogonProcess(hLsa);
|
|
}
|
|
}
|
|
__except(EXCEPTION_EXECUTE_HANDLER)
|
|
{
|
|
}
|
|
|
|
return pSid;
|
|
}
|
|
|
|
|
|
/*******************************************************************
|
|
|
|
NAME: CopyUnicodeString
|
|
|
|
SYNOPSIS: Allocates a buffer and copies a string from
|
|
a UNICODE_STRING sources.
|
|
|
|
ENTRY: pszDest - pointer to destination buffer
|
|
cchDest - # of chars in pszDest (bytes for MBCS)
|
|
pSrc - pointer to UNICODE_STRING to copy
|
|
|
|
EXIT: pszDest - containing copy of string
|
|
|
|
RETURNS: # of chars copied, or 0 if not successful.
|
|
|
|
NOTES:
|
|
|
|
HISTORY:
|
|
JeffreyS 22-Jan-1998 Created
|
|
|
|
********************************************************************/
|
|
|
|
int
|
|
CopyUnicodeString(LPTSTR pszDest, ULONG cchDest, PLSA_UNICODE_STRING pSrc)
|
|
{
|
|
int nResult;
|
|
ULONG cchSrc;
|
|
|
|
// If UNICODE, cchDest is size of destination buffer in chars
|
|
// Else (MBCS) cchDest is size of destination buffer in bytes
|
|
|
|
if (pszDest == NULL || 0 == cchDest)
|
|
return 0;
|
|
|
|
*pszDest = TEXT('\0');
|
|
|
|
if (pSrc == NULL || pSrc->Buffer == NULL)
|
|
return 0;
|
|
|
|
// Get # of chars in source (not including NULL)
|
|
cchSrc = pSrc->Length/sizeof(WCHAR);
|
|
|
|
|
|
//
|
|
// Note that pSrc->Buffer may not be NULL terminated so we can't just
|
|
// call lstrcpynW with cchDest. Also, if we call lstrcpynW with cchSrc,
|
|
// it copies the correct # of chars, but then overwrites the last char
|
|
// with NULL giving an incorrect result. If we call lstrcpynW with
|
|
// (cchSrc+1) it reads past the end of the buffer, which may fault (360251)
|
|
// causing lstrcpynW's exception handler to return 0 without NULL-
|
|
// terminating the resulting string.
|
|
//
|
|
// So let's just copy the bits.
|
|
//
|
|
nResult = min(cchSrc, cchDest);
|
|
CopyMemory(pszDest, pSrc->Buffer, sizeof(WCHAR)*nResult);
|
|
if (nResult == (int)cchDest)
|
|
--nResult;
|
|
pszDest[nResult] = L'\0';
|
|
|
|
return nResult;
|
|
}
|
|
|
|
|
|
/*******************************************************************
|
|
|
|
NAME: CopyUnicodeString
|
|
|
|
SYNOPSIS: Allocates a buffer and copies a string from
|
|
a UNICODE_STRING sources.
|
|
|
|
ENTRY: pSrc - pointer to UNICODE_STRING to copy
|
|
|
|
EXIT: *ppszResult - points to LocalAlloc'd buffer containing copy.
|
|
|
|
RETURNS: # of chars copied, or 0 if not successful.
|
|
|
|
NOTES:
|
|
|
|
HISTORY:
|
|
JeffreyS 22-Jan-1998 Created
|
|
|
|
********************************************************************/
|
|
|
|
int
|
|
CopyUnicodeString(LPTSTR *ppszResult, PLSA_UNICODE_STRING pSrc)
|
|
{
|
|
int nResult = 0;
|
|
|
|
if (NULL == ppszResult)
|
|
return 0;
|
|
|
|
*ppszResult = NULL;
|
|
|
|
if (NULL != pSrc)
|
|
{
|
|
ULONG cchResult;
|
|
|
|
*ppszResult = NULL;
|
|
|
|
// Get # of chars in source (including NULL)
|
|
cchResult = pSrc->Length/SIZEOF(WCHAR) + 1;
|
|
|
|
// Allocate buffer big enough for either UNICODE or MBCS result
|
|
*ppszResult = (LPTSTR)LocalAlloc(LPTR, cchResult * 2);
|
|
|
|
if (*ppszResult)
|
|
{
|
|
nResult = CopyUnicodeString(*ppszResult, cchResult, pSrc);
|
|
|
|
if (0 == nResult)
|
|
{
|
|
LocalFree(*ppszResult);
|
|
*ppszResult = NULL;
|
|
}
|
|
}
|
|
}
|
|
|
|
return nResult;
|
|
}
|
|
|
|
|
|
//
|
|
// Test GUIDs safely
|
|
//
|
|
BOOL IsSameGUID(const GUID *p1, const GUID *p2)
|
|
{
|
|
BOOL bResult = FALSE;
|
|
|
|
if (!p1) p1 = &GUID_NULL;
|
|
if (!p2) p2 = &GUID_NULL;
|
|
|
|
__try
|
|
{
|
|
bResult = InlineIsEqualGUID(*p1, *p2);
|
|
}
|
|
__except(EXCEPTION_EXECUTE_HANDLER)
|
|
{
|
|
}
|
|
|
|
return bResult;
|
|
}
|
|
|
|
/*******************************************************************
|
|
|
|
NAME: GetCountOfInheritableAces
|
|
|
|
SYNOPSIS: Get the count of aces in ACL which can be
|
|
inherited to child objects
|
|
|
|
RETURNS: Count of Aces
|
|
|
|
********************************************************************/
|
|
DWORD GetCountOfInheritableAces(PACL pAcl)
|
|
{
|
|
if(!pAcl)
|
|
return 0;
|
|
|
|
DWORD dwCount = 0;
|
|
PACE_HEADER pAce = NULL;
|
|
int iEntry = 0;
|
|
for (iEntry = 0, pAce = (PACE_HEADER)FirstAce(pAcl);
|
|
iEntry < pAcl->AceCount;
|
|
iEntry++, pAce = (PACE_HEADER)NextAce(pAce))
|
|
{
|
|
//
|
|
//Consider only explicit aces
|
|
//
|
|
if((!(pAce->AceFlags & INHERITED_ACE))&&(pAce->AceFlags & (OBJECT_INHERIT_ACE|CONTAINER_INHERIT_ACE)))
|
|
dwCount++;
|
|
}
|
|
|
|
return dwCount;
|
|
}
|
|
/*******************************************************************
|
|
|
|
NAME: GetCountOfInheritableAces
|
|
|
|
SYNOPSIS: Get the count of aces in SACL or DACL which can be
|
|
inherited to child objects
|
|
|
|
RETURNS: Count of Aces
|
|
|
|
********************************************************************/
|
|
DWORD GetCountOfInheritableAces(SECURITY_INFORMATION si, PSECURITY_DESCRIPTOR pSD)
|
|
{
|
|
if(!pSD)
|
|
return 0;
|
|
|
|
PACL pAcl = NULL;
|
|
BOOL bPresent;
|
|
BOOL bDefault;
|
|
|
|
if(si & DACL_SECURITY_INFORMATION)
|
|
{
|
|
if(GetSecurityDescriptorDacl(pSD, &bPresent, &pAcl, &bDefault))
|
|
{
|
|
return GetCountOfInheritableAces(pAcl);
|
|
}
|
|
}
|
|
else if(si & SACL_SECURITY_INFORMATION)
|
|
{
|
|
if(GetSecurityDescriptorSacl(pSD, &bPresent, &pAcl, &bDefault))
|
|
{
|
|
return GetCountOfInheritableAces(pAcl);
|
|
}
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
typedef struct AclBloatInfo{
|
|
DWORD dwInheriteAceCount;
|
|
SECURITY_INFORMATION si;
|
|
HFONT hFont;
|
|
BOOL bShowHelp;
|
|
}ACL_BLOAT_INFO;
|
|
|
|
INT_PTR CALLBACK
|
|
AclBloatDialogProc(HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam)
|
|
{
|
|
switch (uMsg)
|
|
{
|
|
case WM_INITDIALOG:
|
|
{
|
|
ACL_BLOAT_INFO * pInfo= (ACL_BLOAT_INFO*)lParam;
|
|
ASSERT(pInfo);
|
|
SetWindowLongPtr(hDlg, DWLP_USER, (LONG_PTR)pInfo);
|
|
|
|
//
|
|
//Add a warning icon
|
|
//
|
|
// add the warning icon
|
|
HICON hWarn = LoadIcon(NULL, IDI_WARNING);
|
|
SendDlgItemMessage(hDlg, // dialog box window handle
|
|
IDC_BLOAT_WARN_ICON, // icon identifier
|
|
STM_SETIMAGE, // message to send
|
|
(WPARAM) IMAGE_ICON, // image type
|
|
(LPARAM) hWarn); // icon handle
|
|
|
|
|
|
//
|
|
//Set the title of dialog box
|
|
//
|
|
LPTSTR pszCaption = NULL;
|
|
if(FormatStringID(&pszCaption,
|
|
::hModule,
|
|
pInfo->si & DACL_SECURITY_INFORMATION ? IDS_PERMISSIONS : IDS_AUDITING))
|
|
{
|
|
SetWindowText(hDlg, pszCaption);
|
|
LocalFreeString(&pszCaption);
|
|
}
|
|
|
|
//
|
|
//Set the warning message
|
|
//
|
|
UINT cItem = pInfo->dwInheriteAceCount;
|
|
WCHAR buffer[34];
|
|
_itow(cItem,buffer,10);
|
|
if(FormatStringID(&pszCaption,
|
|
::hModule,
|
|
pInfo->si & DACL_SECURITY_INFORMATION ? IDS_ACLBLOAT_NO_LIST_LINE1:IDS_ACLBLOAT_NO_LIST_SACL_LINE1,
|
|
buffer))
|
|
{
|
|
SetDlgItemText(hDlg, IDC_ACLBLOAT_LINE1, pszCaption);
|
|
LocalFreeString(&pszCaption);
|
|
}
|
|
|
|
//
|
|
//make warning bold
|
|
//
|
|
MakeBold(GetDlgItem(hDlg,IDC_ACLB_WARNING), &(pInfo->hFont));
|
|
|
|
//
|
|
//Set the line2, hide the Help button and move other buttons.
|
|
//
|
|
if(!pInfo->bShowHelp)
|
|
{
|
|
if(FormatStringID(&pszCaption,
|
|
::hModule,
|
|
pInfo->si & DACL_SECURITY_INFORMATION ? IDS_BLOAT_PERM_LINE2_NOHELP : IDS_BLOAT_AUDIT_LINE2_NOHELP))
|
|
{
|
|
SetDlgItemText(hDlg, IDC_ACLB_LINE3, pszCaption);
|
|
LocalFreeString(&pszCaption);
|
|
}
|
|
|
|
RECT rcHelp, rcCancel;
|
|
GetWindowRect(GetDlgItem(hDlg, IDHELP), &rcHelp);
|
|
MapWindowPoints(NULL, hDlg, (LPPOINT)&rcHelp, 2);
|
|
GetWindowRect(GetDlgItem(hDlg, IDCANCEL), &rcCancel);
|
|
MapWindowPoints(NULL, hDlg, (LPPOINT)&rcCancel, 2);
|
|
|
|
//
|
|
//Hide the Help button, Move Cancel to help position
|
|
//and Ok to Cancel positon.
|
|
//
|
|
ShowWindow(GetDlgItem(hDlg, IDHELP),FALSE);
|
|
SetWindowPos(GetDlgItem(hDlg, IDCANCEL),
|
|
NULL,
|
|
rcHelp.left,
|
|
rcHelp.top,
|
|
0,
|
|
0,
|
|
SWP_NOACTIVATE | SWP_NOSIZE | SWP_NOZORDER);
|
|
|
|
SetWindowPos(GetDlgItem(hDlg, IDOK),
|
|
NULL,
|
|
rcCancel.left,
|
|
rcCancel.top,
|
|
0,
|
|
0,
|
|
SWP_NOACTIVATE | SWP_NOSIZE | SWP_NOZORDER);
|
|
|
|
}
|
|
|
|
break;
|
|
}
|
|
|
|
case WM_COMMAND:
|
|
{
|
|
WORD wControlID = GET_WM_COMMAND_ID(wParam, lParam);
|
|
switch (wControlID)
|
|
{
|
|
case IDOK:
|
|
{
|
|
ACL_BLOAT_INFO * pInfo = (ACL_BLOAT_INFO *)GetWindowLongPtr(hDlg, DWLP_USER);
|
|
if(pInfo->hFont)
|
|
DeleteObject(pInfo->hFont);
|
|
pInfo->hFont = NULL;
|
|
EndDialog(hDlg, FALSE);
|
|
break;
|
|
}
|
|
case IDCANCEL:
|
|
{
|
|
ACL_BLOAT_INFO * pInfo = (ACL_BLOAT_INFO *)GetWindowLongPtr(hDlg, DWLP_USER);
|
|
if(pInfo->hFont)
|
|
DeleteObject(pInfo->hFont);
|
|
pInfo->hFont = NULL;
|
|
|
|
EndDialog(hDlg, TRUE);
|
|
break;
|
|
}
|
|
|
|
case IDHELP:
|
|
HtmlHelp(NULL,
|
|
L"aclui.chm::/ACLUI_acl_BP.htm",
|
|
HH_DISPLAY_TOPIC,
|
|
0);
|
|
return TRUE;
|
|
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
return FALSE;
|
|
}
|
|
|
|
//
|
|
// This function displays the "An error has occured [Continue] [Cancel]" message
|
|
//
|
|
// Returns IDOK or IDCANCEL
|
|
//
|
|
BOOL
|
|
IsAclBloated(HWND hWndParent, SECURITY_INFORMATION si, DWORD dwInheritAceCount, int idd, BOOL bShowHelp)
|
|
{
|
|
AclBloatInfo info;
|
|
info.dwInheriteAceCount = dwInheritAceCount;
|
|
info.si = si;
|
|
info.hFont = NULL;
|
|
info.bShowHelp = bShowHelp;
|
|
return (BOOL)DialogBoxParam(::hModule,
|
|
MAKEINTRESOURCE(idd),
|
|
hWndParent,
|
|
AclBloatDialogProc,
|
|
(LPARAM)(&info));
|
|
}
|
|
|
|
BOOL IsAclBloated(HWND hDlg, SECURITY_INFORMATION si, PSECURITY_DESCRIPTOR pSD, DWORD dwOrgInheritAceCount, BOOL bShowHelp)
|
|
{
|
|
ASSERT(pSD);
|
|
BOOL fReturn = FALSE;
|
|
|
|
DWORD dwNewInheritAceCount = GetCountOfInheritableAces(si, pSD);
|
|
if( ((int)dwNewInheritAceCount - (int)dwOrgInheritAceCount) > ACL_BLOAT_LIMIT )
|
|
fReturn = IsAclBloated(hDlg,
|
|
si,
|
|
dwNewInheritAceCount - dwOrgInheritAceCount,
|
|
si & DACL_SECURITY_INFORMATION ? IDD_BLOAT_NO_LIST : IDD_BLOAT_NO_LIST_SACL,
|
|
bShowHelp);
|
|
|
|
return fReturn;
|
|
}
|
|
|
|
//
|
|
//Sets the font style to bold for the hwnd.
|
|
//phNewFont gets handle to newFont which
|
|
//is to freed after hwnd is destroyed.
|
|
//
|
|
HRESULT MakeBold (HWND hwnd, HFONT *phNewFont)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
HFONT hFont = NULL;
|
|
*phNewFont = NULL;
|
|
LOGFONT LogFont;
|
|
|
|
if(!hwnd || !phNewFont)
|
|
return E_POINTER;
|
|
|
|
|
|
hFont = (HFONT)SendMessage(hwnd,WM_GETFONT,0,0);
|
|
if (!hFont)
|
|
{
|
|
hr = HRESULT_FROM_WIN32(GetLastError());
|
|
return hr;
|
|
}
|
|
|
|
|
|
if (!GetObject(hFont,sizeof(LOGFONT),(LPVOID)(&LogFont)))
|
|
{
|
|
hr = HRESULT_FROM_WIN32(GetLastError());
|
|
return hr;
|
|
}
|
|
|
|
LogFont.lfWeight = FW_BOLD;
|
|
|
|
if (!(*phNewFont = CreateFontIndirect(&LogFont)))
|
|
{
|
|
hr = HRESULT_FROM_WIN32(GetLastError());
|
|
return hr;
|
|
}
|
|
|
|
SendMessage(hwnd,WM_SETFONT,(WPARAM)(*phNewFont),MAKELPARAM(FALSE,0));
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
//+----------------------------------------------------------------------------
|
|
// Function:DoDisabledCheck
|
|
// Synopsis:Check if any of the object in pDsSelList is disabled. if yes,
|
|
// function displays a dialog box to user.
|
|
// Returns: TRUE if to add objects in list to acl else no.
|
|
//-----------------------------------------------------------------------------
|
|
BOOL
|
|
DoDisabledCheck(IN HWND hWnd,
|
|
IN PDS_SELECTION_LIST pDsSelList)
|
|
{
|
|
if(!pDsSelList)
|
|
{
|
|
return FALSE;
|
|
}
|
|
|
|
HRESULT hr = S_OK;
|
|
int cNames = pDsSelList->cItems;
|
|
BOOL bDisabled = FALSE;
|
|
|
|
//
|
|
//Check if account of any of the object in the list is disbled
|
|
//
|
|
for (int i = 0; i < cNames; i++)
|
|
{
|
|
//Second element in the array is pointer to UserAccountControl
|
|
LPVARIANT pvarUAC = pDsSelList->aDsSelection[i].pvarFetchedAttributes + 1;
|
|
|
|
if (NULL == pvarUAC || (VT_I4 != V_VT(pvarUAC)))
|
|
{
|
|
continue;
|
|
}
|
|
if(bDisabled = V_I4(pvarUAC) & UF_ACCOUNTDISABLE)
|
|
break;
|
|
}
|
|
|
|
BOOL bReturn = TRUE;
|
|
if(bDisabled)
|
|
{
|
|
WCHAR szBuffer[1024];
|
|
WCHAR szCaption[1024];
|
|
LoadString(::hModule, IDS_DISABLED_USER, szBuffer, ARRAYSIZE(szBuffer));
|
|
LoadString(::hModule, IDS_SECURITY, szCaption, ARRAYSIZE(szCaption));
|
|
if(IDCANCEL == MessageBox(hWnd,
|
|
szBuffer,
|
|
szCaption,
|
|
MB_OKCANCEL | MB_ICONWARNING | MB_APPLMODAL ))
|
|
{
|
|
bReturn = FALSE;
|
|
}
|
|
}
|
|
|
|
return bReturn;
|
|
}
|
|
|
|
|
|
BOOL
|
|
IsCallBackAcePresentInSD(PSECURITY_DESCRIPTOR pSD)
|
|
{
|
|
if (pSD == NULL || !IsValidSecurityDescriptor(pSD))
|
|
return FALSE;
|
|
|
|
PACL pAcl = NULL;
|
|
BOOL bDefaulted = FALSE;
|
|
BOOL bPresent = FALSE;
|
|
|
|
if(!GetSecurityDescriptorDacl(pSD, &bPresent, &pAcl, &bDefaulted))
|
|
return FALSE;
|
|
|
|
if(!bPresent || !pAcl)
|
|
return FALSE;
|
|
|
|
return IsCallBackAcePresentInAcl(pAcl);
|
|
}
|
|
|
|
BOOL
|
|
IsCallBackAcePresentInAcl(PACL pAcl)
|
|
{
|
|
if(!pAcl)
|
|
return FALSE;
|
|
|
|
DWORD dwAceCount = pAcl->AceCount;
|
|
|
|
if (dwAceCount == 0)
|
|
return FALSE;
|
|
|
|
PACE_HEADER pAce;
|
|
for (pAce = (PACE_HEADER)FirstAce(pAcl);
|
|
dwAceCount > 0;
|
|
--dwAceCount, pAce = (PACE_HEADER)NextAce(pAce))
|
|
{
|
|
if(pAce->AceType >= ACCESS_ALLOWED_CALLBACK_ACE_TYPE &&
|
|
pAce->AceType <= SYSTEM_ALARM_CALLBACK_OBJECT_ACE_TYPE)
|
|
{
|
|
return TRUE;
|
|
}
|
|
}
|
|
return FALSE;
|
|
}
|
|
|
|
|