|
|
//+-------------------------------------------------------------------------
//
// 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; }
|