mirror of https://github.com/tongzx/nt5src
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.
1066 lines
30 KiB
1066 lines
30 KiB
/*++
|
|
|
|
Copyright (c) 1994 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
aclfuncs.c
|
|
|
|
Abstract:
|
|
|
|
This module contians the functions to process the items from the files
|
|
containing the ACL entries for registry keys and files
|
|
|
|
Author:
|
|
|
|
Bob Watson (a-robw) Dec-94
|
|
|
|
Revision History:
|
|
|
|
--*/
|
|
#ifdef TEST_MODE
|
|
#undef TEST_MODE
|
|
#endif
|
|
//#define TEST_MODE 1
|
|
|
|
#include <windows.h>
|
|
#include <stdio.h>
|
|
#include <c2inc.h>
|
|
#include <c2dll.h>
|
|
#include <c2utils.h>
|
|
#include "c2acls.h"
|
|
#include "c2aclres.h"
|
|
#include "strings.h"
|
|
|
|
#define FILE_ENTRY 1
|
|
#define DIR_ENTRY 2
|
|
|
|
// internal flag
|
|
#define FILE_PATH_SUBDIRS 8
|
|
|
|
#define NTFS_NOT_STANDARD 0x00000000
|
|
#define NTFS_FULL_CONTROL 0x00010001
|
|
#define NTFS_CHANGE 0x00010002
|
|
#define NTFS_ADD_READ 0x00010003
|
|
#define NTFS_READ 0x00010004
|
|
#define NTFS_ADD 0x00010005
|
|
#define NTFS_LIST 0x00010006
|
|
#define NTFS_NO_ACCESS 0x00010007
|
|
#define NTFS_NONE 0x00000008
|
|
#define NTFS_ALL 0x00000009
|
|
|
|
#define NTFS_FILE_ALL_ACCESS (FILE_ALL_ACCESS)
|
|
#define NTFS_FILE_CHANGE (FILE_GENERIC_READ | FILE_GENERIC_WRITE | \
|
|
FILE_GENERIC_EXECUTE | DELETE)
|
|
#define NTFS_FILE_ADD_READ (FILE_GENERIC_READ | FILE_GENERIC_WRITE | \
|
|
FILE_GENERIC_EXECUTE)
|
|
#define NTFS_FILE_READ (FILE_GENERIC_READ | FILE_GENERIC_EXECUTE)
|
|
#define NTFS_FILE_ADD (FILE_GENERIC_WRITE | FILE_GENERIC_EXECUTE)
|
|
#define NTFS_FILE_LIST (FILE_GENERIC_READ | FILE_GENERIC_EXECUTE)
|
|
#define NTFS_FILE_NO_ACCESS (FILE_ALL_ACCESS) /* access denied ace */
|
|
|
|
#define NTFS_DIR_ALL_ACCESS (GENERIC_ALL)
|
|
#define NTFS_DIR_CHANGE (GENERIC_READ | GENERIC_WRITE | \
|
|
GENERIC_EXECUTE | DELETE)
|
|
#define NTFS_DIR_ADD_READ (GENERIC_READ | GENERIC_EXECUTE)
|
|
#define NTFS_DIR_READ (GENERIC_READ | GENERIC_EXECUTE)
|
|
#define NTFS_DIR_ADD (GENERIC_WRITE | GENERIC_EXECUTE)
|
|
#define NTFS_DIR_LIST (GENERIC_READ | GENERIC_EXECUTE)
|
|
#define NTFS_DIR_NO_ACCESS (GENERIC_ALL) /* access denied ace */
|
|
|
|
#define NTFS_DIR_DIR_FLAGS (INHERIT_ONLY_ACE | OBJECT_INHERIT_ACE)
|
|
#define NTFS_DIR_FILE_FLAGS (CONTAINER_INHERIT_ACE)
|
|
#define NTFS_FILE_FILE_FLAGS 0x00
|
|
|
|
typedef struct _ACCESS_DECODE {
|
|
LPTSTR szString;
|
|
DWORD dwMask;
|
|
} ACCESS_DECODE, *PACCESS_DECODE;
|
|
|
|
#ifdef TEST_MODE
|
|
LONG
|
|
DumpAclData (
|
|
IN LPCTSTR szFileName,
|
|
IN PSECURITY_DESCRIPTOR psdFile
|
|
);
|
|
#endif
|
|
|
|
static ACCESS_DECODE adRegistryDecodeList[] = {
|
|
// specific access
|
|
{TEXT("QV"), (DWORD)KEY_QUERY_VALUE},
|
|
{TEXT("SV"), (DWORD)KEY_SET_VALUE},
|
|
{TEXT("CS"), (DWORD)KEY_CREATE_SUB_KEY},
|
|
{TEXT("ES"), (DWORD)KEY_ENUMERATE_SUB_KEYS},
|
|
{TEXT("NT"), (DWORD)KEY_NOTIFY},
|
|
{TEXT("CL"), (DWORD)KEY_CREATE_LINK},
|
|
// standard rights
|
|
{TEXT("DE"), (DWORD)DELETE},
|
|
{TEXT("RC"), (DWORD)READ_CONTROL},
|
|
{TEXT("WD"), (DWORD)WRITE_DAC},
|
|
{TEXT("WO"), (DWORD)WRITE_OWNER},
|
|
// predefined groups
|
|
{TEXT("NONE"), (DWORD)0},
|
|
{TEXT("FULL"), (DWORD)KEY_ALL_ACCESS},
|
|
{TEXT("READ"), (DWORD)KEY_READ},
|
|
// terminating entry
|
|
{NULL, (DWORD)0}
|
|
};
|
|
|
|
static ACCESS_DECODE adNtfsDecodeList[] = {
|
|
// predefined "combination" access keywords
|
|
{TEXT("FullControl"), (DWORD)NTFS_FULL_CONTROL},
|
|
{TEXT("Change"), (DWORD)NTFS_CHANGE},
|
|
{TEXT("AddRead"), (DWORD)NTFS_ADD_READ},
|
|
{TEXT("Read"), (DWORD)NTFS_READ},
|
|
{TEXT("Add"), (DWORD)NTFS_ADD},
|
|
{TEXT("List"), (DWORD)NTFS_LIST},
|
|
{TEXT("NoAccess"), (DWORD)NTFS_NO_ACCESS},
|
|
// predefined single ACE entries
|
|
{TEXT("NONE"), (DWORD)NTFS_NONE},
|
|
{TEXT("ALL"), (DWORD)NTFS_ALL},
|
|
// terminating entry
|
|
{NULL, (DWORD)0}
|
|
};
|
|
|
|
static
|
|
BOOL
|
|
DotOrDotDotDir (
|
|
IN LPCTSTR szFileName
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
examines the filename in the parameter list to see if it is one
|
|
of the default subdirectories (e.g. the . or the .. dirs). This
|
|
routine assumes that the argument is a filename only. (i.e. NO
|
|
PATH!)
|
|
|
|
Arguments:
|
|
|
|
Filename to compare
|
|
|
|
Return Value:
|
|
|
|
TRUE if filename is either the . or the .. dir
|
|
FALSE if it is any other string
|
|
|
|
--*/
|
|
{
|
|
if (szFileName != NULL) { // check for null parameter
|
|
if (lstrcmp(szFileName, cszDot) == 0) {
|
|
return TRUE; // it's the . dir
|
|
} else if (lstrcmp(szFileName, cszDotDot) == 0) {
|
|
return TRUE; // it's the .. dir
|
|
} else {
|
|
return FALSE; // it's neither
|
|
}
|
|
} else {
|
|
return FALSE; // null filename, so not a . or .. dir
|
|
}
|
|
}
|
|
|
|
static
|
|
BOOL
|
|
IsDirectory (
|
|
IN LPCTSTR szFilePath
|
|
)
|
|
{
|
|
DWORD dwAttrib;
|
|
|
|
dwAttrib = QuietGetFileAttributes (szFilePath);
|
|
|
|
if (dwAttrib != 0xFFFFFFFF) {
|
|
return ((dwAttrib & FILE_ATTRIBUTE_DIRECTORY) == FILE_ATTRIBUTE_DIRECTORY);
|
|
} else {
|
|
return FALSE;
|
|
}
|
|
}
|
|
|
|
static
|
|
ACCESS_MASK
|
|
ReadNtfsPermissionString (
|
|
IN LPCTSTR szPerms,
|
|
IN BOOL bDirectory
|
|
)
|
|
{
|
|
LPCTSTR szThisChar;
|
|
ACCESS_MASK amReturn = 0;
|
|
|
|
for (szThisChar = szPerms; *szThisChar != 0; szThisChar++) {
|
|
switch (*szThisChar) {
|
|
case TEXT('R'):
|
|
case TEXT('r'):
|
|
amReturn |= (bDirectory ? GENERIC_READ : FILE_GENERIC_READ);
|
|
break;
|
|
|
|
case TEXT('W'):
|
|
case TEXT('w'):
|
|
amReturn |= (bDirectory ? GENERIC_WRITE : FILE_GENERIC_WRITE);
|
|
break;
|
|
|
|
case TEXT('X'):
|
|
case TEXT('x'):
|
|
amReturn |= (bDirectory ? GENERIC_EXECUTE : FILE_GENERIC_EXECUTE);
|
|
break;
|
|
|
|
case TEXT('D'):
|
|
case TEXT('d'):
|
|
amReturn |= DELETE;
|
|
break;
|
|
|
|
case TEXT('P'):
|
|
case TEXT('p'):
|
|
amReturn |= WRITE_DAC;
|
|
break;
|
|
|
|
case TEXT('O'):
|
|
case TEXT('o'):
|
|
amReturn |= WRITE_OWNER;
|
|
break;
|
|
|
|
default:
|
|
// no change if unrecognized
|
|
break;
|
|
}
|
|
}
|
|
return amReturn;
|
|
}
|
|
|
|
HKEY
|
|
GetRootKey (
|
|
IN LPCTSTR szKeyPath
|
|
)
|
|
{
|
|
TCHAR szLocalPath[MAX_PATH];
|
|
LPTSTR szEndOfRoot;
|
|
|
|
lstrcpy (szLocalPath, szKeyPath);
|
|
szEndOfRoot = _tcschr(szLocalPath, cBackslash);
|
|
if (szEndOfRoot != NULL) {
|
|
*szEndOfRoot = 0; // null terminate here and use just the chars to the left
|
|
if (lstrcmpi(szLocalPath, cszLocalMachine) == 0) {
|
|
return HKEY_LOCAL_MACHINE;
|
|
} else if (lstrcmpi(szLocalPath, cszClassesRoot) == 0) {
|
|
return HKEY_CLASSES_ROOT;
|
|
} else if (lstrcmpi(szLocalPath, cszCurrentUser) == 0) {
|
|
return HKEY_CURRENT_USER;
|
|
} else if (lstrcmpi(szLocalPath, cszUsers) == 0) {
|
|
return HKEY_USERS;
|
|
} else {
|
|
return NULL;
|
|
}
|
|
} else {
|
|
return NULL;
|
|
}
|
|
}
|
|
|
|
LPCTSTR
|
|
GetKeyPath (
|
|
IN LPCTSTR szKeyPath,
|
|
OUT LPBOOL pbDoSubKeys
|
|
)
|
|
{
|
|
static TCHAR szLocalPath[MAX_PATH];
|
|
LPTSTR szEndOfRoot;
|
|
BOOL bReturn = FALSE;
|
|
|
|
szEndOfRoot = _tcschr(szKeyPath, cBackslash);
|
|
if (szEndOfRoot != NULL) {
|
|
// path found
|
|
szEndOfRoot++; // go to first char after '\'
|
|
// save in local static buffer
|
|
lstrcpy (szLocalPath, szEndOfRoot);
|
|
// now see if this is a recursive key
|
|
szEndOfRoot = _tcschr(szLocalPath, cAsterisk);
|
|
if (szEndOfRoot != NULL) {
|
|
// then this is a recursive path
|
|
bReturn = TRUE;
|
|
szEndOfRoot--; // go back to backslash
|
|
*szEndOfRoot = 0; // and terminate there
|
|
}
|
|
if (pbDoSubKeys != NULL) {
|
|
*pbDoSubKeys = bReturn;
|
|
}
|
|
return szLocalPath;
|
|
} else {
|
|
// unable to find correct syntax so just return entire string
|
|
if (pbDoSubKeys != NULL) {
|
|
*pbDoSubKeys = FALSE;
|
|
}
|
|
return szKeyPath; // or beginning of path after ROOT key
|
|
}
|
|
}
|
|
|
|
LPCTSTR
|
|
GetFilePathFromHeader (
|
|
IN LPCTSTR szHeaderPath,
|
|
OUT LPDWORD pdwFlags
|
|
)
|
|
{
|
|
static TCHAR szLocalPath[MAX_PATH];
|
|
TCHAR szLocalWorkPath[MAX_PATH];
|
|
LPTSTR szEndOfPath;
|
|
DWORD dwLastError = ERROR_SUCCESS;
|
|
DWORD dwReturn = FILE_PATH_NORMAL;
|
|
|
|
lstrcpy (szLocalWorkPath, szHeaderPath);
|
|
szEndOfPath = _tcsrchr(szLocalWorkPath, cBang);
|
|
if (szEndOfPath != NULL) {
|
|
// wild card found so remember this and truncate
|
|
szEndOfPath--; // go to first char before *
|
|
*szEndOfPath = 0; // and terminate there
|
|
dwReturn = FILE_PATH_ALL; // remember to do sub-dirs
|
|
} else {
|
|
// check for wildcard path syntax characters
|
|
szEndOfPath = _tcschr (szLocalWorkPath, cAsterisk);
|
|
if (szEndOfPath == NULL) {
|
|
// check for the other wild card char
|
|
szEndOfPath = _tcschr (szLocalWorkPath, cAsterisk);
|
|
}
|
|
if (szEndOfPath != NULL) {
|
|
// keep the path intact but set the flag
|
|
dwReturn = FILE_PATH_WILD;
|
|
}
|
|
// no wildcard, so assume the path is in the valid syntax
|
|
}
|
|
dwLastError = GetExpandedFileName(
|
|
szLocalWorkPath,
|
|
sizeof(szLocalPath)/sizeof(TCHAR),
|
|
szLocalPath,
|
|
NULL);
|
|
|
|
if (dwLastError != ERROR_SUCCESS) {
|
|
SetLastError (dwLastError); // record error
|
|
szLocalPath[0] = 0; // and clear buffer
|
|
}
|
|
|
|
if (pdwFlags != NULL) {
|
|
*pdwFlags = dwReturn; // update the sub dir flag
|
|
}
|
|
|
|
return (LPCTSTR)&szLocalPath[0];
|
|
}
|
|
|
|
static
|
|
DWORD
|
|
DecodeRegAccessEntry (
|
|
IN LPCTSTR szAccessEntry
|
|
)
|
|
{
|
|
PACCESS_DECODE pEnt;
|
|
|
|
for (pEnt = &adRegistryDecodeList[0];
|
|
pEnt->szString != NULL;
|
|
pEnt++) {
|
|
if (lstrcmpi (szAccessEntry, pEnt->szString) == 0) {
|
|
return pEnt->dwMask;
|
|
}
|
|
}
|
|
return 0; // no entry found
|
|
}
|
|
|
|
static
|
|
DWORD
|
|
DecodeNtfsAccessEntry (
|
|
IN LPCTSTR szAccessEntry
|
|
)
|
|
{
|
|
PACCESS_DECODE pEnt;
|
|
|
|
for (pEnt = &adNtfsDecodeList[0];
|
|
pEnt->szString != NULL;
|
|
pEnt++) {
|
|
if (lstrcmpi (szAccessEntry, pEnt->szString) == 0) {
|
|
return pEnt->dwMask;
|
|
}
|
|
}
|
|
return NTFS_NOT_STANDARD; // no entry found
|
|
}
|
|
|
|
static
|
|
BOOL
|
|
FillAce (
|
|
IN PACCESS_ALLOWED_ACE paaAce,
|
|
IN ACCESS_MASK amAccess,
|
|
IN BYTE Type,
|
|
IN BYTE Flags,
|
|
IN PSID pSid
|
|
)
|
|
{
|
|
paaAce->Header.AceType = Type;
|
|
paaAce->Header.AceFlags = Flags;
|
|
paaAce->Mask = amAccess;
|
|
CopySid (
|
|
(DWORD)(paaAce->Header.AceSize - (sizeof (ACCESS_ALLOWED_ACE) - sizeof(DWORD))),
|
|
(PSID)(&paaAce->SidStart),
|
|
pSid);
|
|
paaAce->Header.AceSize = (WORD)(GetLengthSid(pSid) +
|
|
(sizeof (ACCESS_ALLOWED_ACE) - sizeof(DWORD)));
|
|
return TRUE;
|
|
}
|
|
|
|
static
|
|
BOOL
|
|
MakeAccessDeniedAce (
|
|
IN PACCESS_DENIED_ACE padAce,
|
|
IN ACCESS_MASK amAccess,
|
|
IN BYTE Flags,
|
|
IN PSID pSid
|
|
)
|
|
{
|
|
padAce->Header.AceType = ACCESS_DENIED_ACE_TYPE;
|
|
padAce->Header.AceFlags = Flags;
|
|
padAce->Mask = amAccess;
|
|
CopySid (
|
|
(DWORD)(padAce->Header.AceSize - (sizeof (ACCESS_ALLOWED_ACE) - sizeof(DWORD))),
|
|
(PSID)(&padAce->SidStart),
|
|
pSid);
|
|
padAce->Header.AceSize = (WORD)(GetLengthSid(pSid) +
|
|
(sizeof (ACCESS_ALLOWED_ACE) - sizeof(DWORD)));
|
|
return TRUE;
|
|
}
|
|
|
|
static
|
|
LONG
|
|
MakeAceFromRegEntry (
|
|
IN LPCTSTR szAccessList,
|
|
IN PSID psidUser,
|
|
IN OUT PACCESS_ALLOWED_ACE pAce
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
interprets the access string list and returns the corresponding
|
|
access mask
|
|
|
|
Arguments:
|
|
|
|
list of access strings to include:
|
|
|
|
|
|
--*/
|
|
{
|
|
DWORD dwIndex = 1;
|
|
LPCTSTR szItem;
|
|
|
|
// see if this is an "inherit" ACE or not
|
|
|
|
if (lstrcmpi ((LPTSTR)GetItemFromIniEntry(szAccessList, dwIndex),
|
|
cszInherit) == 0) {
|
|
pAce->Header.AceFlags = CONTAINER_INHERIT_ACE | INHERIT_ONLY_ACE;
|
|
dwIndex++; // go to next entry
|
|
} else {
|
|
pAce->Header.AceFlags = 0;
|
|
}
|
|
|
|
// walk down the list to set bits as they are defined.
|
|
szItem = GetItemFromIniEntry (szAccessList, dwIndex);
|
|
while (lstrlen(szItem) > 0) {
|
|
pAce->Mask |= DecodeRegAccessEntry(szItem);
|
|
dwIndex++;
|
|
szItem = (LPTSTR)GetItemFromIniEntry (szAccessList, dwIndex);
|
|
}
|
|
|
|
// now to add the sid and set the ace size
|
|
|
|
CopySid (
|
|
(DWORD)(pAce->Header.AceSize - sizeof(ACE_HEADER) - sizeof (ACCESS_MASK)),
|
|
(PSID)(&pAce->SidStart),
|
|
psidUser);
|
|
|
|
pAce->Header.AceSize = (WORD)GetLengthSid(psidUser) +
|
|
sizeof(ACE_HEADER) +
|
|
sizeof(ACCESS_MASK);
|
|
|
|
return ERROR_SUCCESS;
|
|
}
|
|
|
|
LONG
|
|
MakeAclFromRegSection (
|
|
IN LPTSTR mszSection,
|
|
OUT PACL pAcl
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
interprets the section string as a list of ACE information in the form
|
|
of:
|
|
DOMAIN\ACCOUNT = Access information
|
|
and adds the ACE information to the initialized ACL passed in
|
|
|
|
Arguments:
|
|
|
|
mszSection msz Buffer of ACE information
|
|
pAcl pointer to intialized ACL buffer
|
|
|
|
Return Value:
|
|
|
|
WIN32 Error status of function
|
|
|
|
--*/
|
|
{
|
|
LPTSTR szThisEntry;
|
|
TCHAR szDomain[MAX_PATH];
|
|
DWORD dwSidBuffSize;
|
|
DWORD dwDomainSize;
|
|
SID_NAME_USE snu;
|
|
PSID psidAccount = NULL;
|
|
PACCESS_ALLOWED_ACE pAce = NULL;
|
|
LONG lStatus;
|
|
|
|
for (szThisEntry = mszSection;
|
|
*szThisEntry != 0;
|
|
szThisEntry += lstrlen(szThisEntry)+1) {
|
|
psidAccount = GLOBAL_ALLOC (SMALL_BUFFER_SIZE);
|
|
pAce = GLOBAL_ALLOC (MAX_PATH); // this should be plenty big
|
|
if ((psidAccount != NULL) && (pAce != NULL)){
|
|
dwSidBuffSize = SMALL_BUFFER_SIZE;
|
|
dwDomainSize = sizeof(szDomain) / sizeof(TCHAR);
|
|
if (LookupAccountName (
|
|
NULL, // look up on local machine
|
|
GetKeyFromIniEntry(szThisEntry),
|
|
psidAccount,
|
|
&dwSidBuffSize,
|
|
szDomain,
|
|
&dwDomainSize,
|
|
&snu)) {
|
|
|
|
// account found so make an ACE with it
|
|
pAce->Header.AceType = ACCESS_ALLOWED_ACE_TYPE;
|
|
pAce->Header.AceFlags = 0;
|
|
pAce->Header.AceSize = MAX_PATH; // initial buffer size
|
|
pAce->Mask = 0; // the mask will be added in the next fn.
|
|
pAce->SidStart = 0; // the sid will be added in the next fn.
|
|
|
|
lStatus = MakeAceFromRegEntry (
|
|
szThisEntry,
|
|
psidAccount,
|
|
pAce);
|
|
|
|
AddAce (
|
|
pAcl,
|
|
ACL_REVISION,
|
|
MAXDWORD, // append this ACE to the end of the list
|
|
(LPVOID)pAce,
|
|
(DWORD)pAce->Header.AceSize);
|
|
} else {
|
|
// unable to look up name
|
|
}
|
|
} else {
|
|
// unable to allocate SID buffer
|
|
}
|
|
GLOBAL_FREE_IF_ALLOC (psidAccount);
|
|
GLOBAL_FREE_IF_ALLOC (pAce);
|
|
} // end of entry loop
|
|
return ERROR_SUCCESS;
|
|
}
|
|
|
|
static
|
|
BOOL
|
|
MakeDirAce (
|
|
IN PACCESS_ALLOWED_ACE pAce,
|
|
IN PSID pSid,
|
|
IN DWORD dwAccessValue
|
|
)
|
|
{
|
|
BOOL bAddAce = TRUE;
|
|
ACCESS_MASK amAce = 0;
|
|
BYTE bType = ACCESS_ALLOWED_ACE_TYPE;
|
|
|
|
switch (dwAccessValue) {
|
|
case NTFS_FULL_CONTROL:
|
|
amAce = NTFS_DIR_ALL_ACCESS;
|
|
break;
|
|
|
|
case NTFS_CHANGE:
|
|
amAce = NTFS_DIR_CHANGE;
|
|
break;
|
|
|
|
case NTFS_ADD_READ:
|
|
amAce = NTFS_DIR_ADD_READ;
|
|
break;
|
|
|
|
case NTFS_READ:
|
|
amAce = NTFS_DIR_READ;
|
|
break;
|
|
|
|
case NTFS_ADD:
|
|
bAddAce = FALSE;
|
|
break;
|
|
|
|
case NTFS_LIST:
|
|
bAddAce = FALSE;
|
|
break;
|
|
|
|
case NTFS_NO_ACCESS:
|
|
amAce = NTFS_DIR_NO_ACCESS;
|
|
bType = ACCESS_DENIED_ACE_TYPE;
|
|
break;
|
|
|
|
default:
|
|
bAddAce = FALSE;
|
|
break;
|
|
}
|
|
|
|
if (bAddAce) {
|
|
bAddAce = FillAce (
|
|
pAce,
|
|
amAce,
|
|
bType,
|
|
NTFS_DIR_DIR_FLAGS,
|
|
pSid);
|
|
}
|
|
|
|
return bAddAce;
|
|
}
|
|
|
|
static
|
|
BOOL
|
|
MakeFileAce (
|
|
IN PACCESS_ALLOWED_ACE pAce,
|
|
IN PSID pSid,
|
|
IN DWORD dwAccessValue,
|
|
IN BOOL bDirectory
|
|
)
|
|
{
|
|
BOOL bAddAce = TRUE;
|
|
ACCESS_MASK amAce = 0;
|
|
BYTE bType = ACCESS_ALLOWED_ACE_TYPE;
|
|
|
|
switch (dwAccessValue) {
|
|
case NTFS_FULL_CONTROL:
|
|
amAce = NTFS_FILE_ALL_ACCESS;
|
|
break;
|
|
|
|
case NTFS_CHANGE:
|
|
amAce = NTFS_FILE_CHANGE;
|
|
break;
|
|
|
|
case NTFS_ADD_READ:
|
|
if (bDirectory) {
|
|
amAce = NTFS_FILE_ADD_READ;
|
|
} else {
|
|
bAddAce = FALSE; // not allowed for files
|
|
}
|
|
break;
|
|
|
|
case NTFS_READ:
|
|
amAce = NTFS_FILE_READ;
|
|
break;
|
|
|
|
case NTFS_ADD:
|
|
amAce = NTFS_FILE_ADD;
|
|
break;
|
|
|
|
case NTFS_LIST:
|
|
amAce = NTFS_FILE_LIST;
|
|
break;
|
|
|
|
case NTFS_NO_ACCESS:
|
|
amAce = NTFS_FILE_NO_ACCESS;
|
|
bType = ACCESS_DENIED_ACE_TYPE;
|
|
break;
|
|
|
|
default:
|
|
bAddAce = FALSE;
|
|
break;
|
|
}
|
|
|
|
if (bAddAce) {
|
|
bAddAce = FillAce (
|
|
pAce,
|
|
amAce,
|
|
bType,
|
|
(BYTE)(bDirectory ? NTFS_DIR_FILE_FLAGS : NTFS_FILE_FILE_FLAGS),
|
|
pSid);
|
|
}
|
|
|
|
return bAddAce;
|
|
}
|
|
|
|
static
|
|
LONG
|
|
InterpretNtfsAccessEntry (
|
|
IN LPCTSTR szThisEntry,
|
|
IN BOOL bDirectory,
|
|
IN PSID psidAccount,
|
|
OUT PACL pAcl
|
|
)
|
|
{
|
|
LONG lStatus = ERROR_SUCCESS;
|
|
LPCTSTR szAccessString;
|
|
DWORD dwAccessValue;
|
|
BOOL bCombinationEntry; // true if access string makes 2 ace's
|
|
PACCESS_ALLOWED_ACE pAce;
|
|
ACCESS_MASK amAce;
|
|
BYTE bAceType;
|
|
BYTE bAceFlags;
|
|
DWORD dwAllowedEntries;
|
|
DWORD dwThisEntry = 1;
|
|
|
|
szAccessString = GetItemFromIniEntry (szThisEntry, dwThisEntry);
|
|
dwAccessValue = DecodeNtfsAccessEntry (szAccessString);
|
|
bCombinationEntry = (BOOL)(HIWORD(dwAccessValue) == 1);
|
|
|
|
if (bCombinationEntry) {
|
|
// this is a combination entry so if this is a directory
|
|
// we'll make 2 ACE's one for dir access and one to be inherited
|
|
// for file access. If this is a file, then only the file access
|
|
// ace will be created.
|
|
if (bDirectory) {
|
|
// make the directory access ACE for the directory entry
|
|
pAce = (PACCESS_ALLOWED_ACE)GLOBAL_ALLOC(MAX_PATH);
|
|
if (pAce != NULL) {
|
|
if (MakeDirAce (pAce, psidAccount, dwAccessValue)) {
|
|
// then add ace to acl
|
|
AddAce (
|
|
pAcl,
|
|
ACL_REVISION,
|
|
MAXDWORD,
|
|
(LPVOID)pAce,
|
|
(DWORD)pAce->Header.AceSize);
|
|
}
|
|
}
|
|
GLOBAL_FREE_IF_ALLOC (pAce); // free this one
|
|
}
|
|
// create the File Access entry
|
|
pAce = (PACCESS_ALLOWED_ACE)GLOBAL_ALLOC(MAX_PATH);
|
|
if (pAce != NULL) {
|
|
if (MakeFileAce (pAce, psidAccount, dwAccessValue, bDirectory)) {
|
|
// then add ace to acl
|
|
AddAce (
|
|
pAcl,
|
|
ACL_REVISION,
|
|
MAXDWORD,
|
|
(LPVOID)pAce,
|
|
(DWORD)pAce->Header.AceSize);
|
|
}
|
|
}
|
|
GLOBAL_FREE_IF_ALLOC (pAce); // free this one
|
|
} else {
|
|
// specific permissions have been specified so process them
|
|
// this is the first entry in the list so it's either the "dir"
|
|
// entry of a directory or a File entry.
|
|
|
|
dwAllowedEntries = (bDirectory ? 2 : 1);
|
|
while (dwThisEntry <= dwAllowedEntries) {
|
|
if (lstrlen(szAccessString) > 0) {
|
|
bAceFlags = (bDirectory ? (dwThisEntry == DIR_ENTRY ?
|
|
NTFS_DIR_DIR_FLAGS : NTFS_DIR_FILE_FLAGS) : NTFS_FILE_FILE_FLAGS);
|
|
bAceType = ACCESS_ALLOWED_ACE_TYPE;
|
|
switch (dwAccessValue) {
|
|
case NTFS_NONE:
|
|
amAce = (bDirectory ? NTFS_DIR_NO_ACCESS : NTFS_FILE_NO_ACCESS);
|
|
bAceType = ACCESS_DENIED_ACE_TYPE;
|
|
break;
|
|
|
|
case NTFS_ALL:
|
|
amAce = (bDirectory ? NTFS_DIR_NO_ACCESS : NTFS_FILE_ALL_ACCESS);
|
|
break;
|
|
|
|
default:
|
|
amAce = ReadNtfsPermissionString (szAccessString, bDirectory);
|
|
break;
|
|
}
|
|
pAce = (PACCESS_ALLOWED_ACE)GLOBAL_ALLOC(MAX_PATH);
|
|
if (pAce != NULL) {
|
|
FillAce (
|
|
pAce,
|
|
amAce,
|
|
bAceType,
|
|
bAceFlags,
|
|
psidAccount);
|
|
|
|
AddAce (
|
|
pAcl,
|
|
ACL_REVISION,
|
|
MAXDWORD,
|
|
(LPVOID)pAce,
|
|
(DWORD)pAce->Header.AceSize);
|
|
}
|
|
GLOBAL_FREE_IF_ALLOC (pAce);
|
|
}
|
|
if (++dwThisEntry <= dwAllowedEntries) {
|
|
// get next entry from string
|
|
szAccessString = GetItemFromIniEntry (szThisEntry, dwThisEntry);
|
|
}
|
|
}
|
|
}
|
|
return lStatus;
|
|
}
|
|
|
|
LONG
|
|
MakeAclFromNtfsSection (
|
|
IN LPTSTR mszSection,
|
|
IN BOOL bDirectory, // true if this is for a directory
|
|
OUT PACL pAcl
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
interprets the section string as a list of ACE information in the form
|
|
of:
|
|
DOMAIN\ACCOUNT = Access information
|
|
and adds the ACE information to the initialized ACL passed in
|
|
|
|
Arguments:
|
|
|
|
mszSection msz Buffer of ACE information
|
|
pAcl pointer to intialized ACL buffer
|
|
|
|
Return Value:
|
|
|
|
WIN32 Error status of function
|
|
|
|
--*/
|
|
{
|
|
LPTSTR szThisEntry;
|
|
TCHAR szDomain[MAX_PATH];
|
|
DWORD dwSidBuffSize;
|
|
DWORD dwDomainSize;
|
|
SID_NAME_USE snu;
|
|
PSID psidAccount = NULL;
|
|
LONG lStatus;
|
|
|
|
for (szThisEntry = mszSection;
|
|
*szThisEntry != 0;
|
|
szThisEntry += lstrlen(szThisEntry)+1) {
|
|
psidAccount = GLOBAL_ALLOC (SMALL_BUFFER_SIZE);
|
|
if (psidAccount != NULL) {
|
|
dwSidBuffSize = SMALL_BUFFER_SIZE;
|
|
dwDomainSize = sizeof(szDomain) / sizeof(TCHAR);
|
|
if (LookupAccountName (
|
|
NULL, // look up on local machine
|
|
GetKeyFromIniEntry(szThisEntry),
|
|
psidAccount,
|
|
&dwSidBuffSize,
|
|
szDomain,
|
|
&dwDomainSize,
|
|
&snu)) {
|
|
|
|
lStatus = InterpretNtfsAccessEntry (
|
|
szThisEntry,
|
|
bDirectory,
|
|
psidAccount,
|
|
pAcl);
|
|
|
|
} else {
|
|
// unable to look up name
|
|
}
|
|
} else {
|
|
// unable to allocate SID buffer
|
|
}
|
|
GLOBAL_FREE_IF_ALLOC (psidAccount);
|
|
} // end of entry loop
|
|
return ERROR_SUCCESS;
|
|
}
|
|
|
|
LONG
|
|
SetRegistryKeySecurity (
|
|
IN HKEY hkeyRootKey,
|
|
IN LPCTSTR szKeyPath,
|
|
IN BOOL bDoSubKeys,
|
|
IN PSECURITY_DESCRIPTOR psdSecurity
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
opens the key in "KeyPath" and set's the key's security. If the
|
|
"bDoSubKeys" flag is set, then all sub keys are set to the same
|
|
security using this routine recursively.
|
|
|
|
Return Value:
|
|
|
|
WIN32 status value of function
|
|
|
|
--*/
|
|
{
|
|
LONG lStatus;
|
|
HKEY hkeyThisKey;
|
|
DWORD dwKeyIndex;
|
|
DWORD dwSubKeyLen;
|
|
TCHAR szSubKeyName[MAX_PATH];
|
|
FILETIME FileTime;
|
|
|
|
lStatus = RegOpenKeyEx (
|
|
hkeyRootKey,
|
|
szKeyPath,
|
|
0L,
|
|
KEY_ALL_ACCESS,
|
|
&hkeyThisKey);
|
|
|
|
if (lStatus == ERROR_SUCCESS) {
|
|
_tprintf (GetStringResource (GetDllInstance(), IDS_REG_DISPLAY_FORMAT),
|
|
szKeyPath);
|
|
lStatus = RegSetKeySecurity (
|
|
hkeyThisKey,
|
|
DACL_SECURITY_INFORMATION,
|
|
psdSecurity);
|
|
|
|
if (bDoSubKeys) {
|
|
dwKeyIndex = 0;
|
|
dwSubKeyLen = sizeof(szSubKeyName) / sizeof(TCHAR);
|
|
|
|
while (RegEnumKeyEx (
|
|
hkeyThisKey,
|
|
dwKeyIndex,
|
|
szSubKeyName,
|
|
&dwSubKeyLen,
|
|
NULL,
|
|
NULL, // don't care about the class
|
|
NULL, // no class buffer
|
|
&FileTime) == ERROR_SUCCESS) {
|
|
// subkey found so set subkey security
|
|
lStatus = SetRegistryKeySecurity (
|
|
hkeyThisKey,
|
|
szSubKeyName,
|
|
bDoSubKeys,
|
|
psdSecurity);
|
|
// set variables for next call
|
|
dwKeyIndex++;
|
|
dwSubKeyLen = sizeof(szSubKeyName) / sizeof(TCHAR);
|
|
}
|
|
}
|
|
RegCloseKey (hkeyThisKey);
|
|
} else {
|
|
// unable to open key so return ERROR
|
|
}
|
|
return lStatus;
|
|
}
|
|
|
|
LONG
|
|
SetNtfsFileSecurity (
|
|
IN LPCTSTR szPath,
|
|
IN DWORD dwFlags,
|
|
IN PSECURITY_DESCRIPTOR pSdDir,
|
|
IN PSECURITY_DESCRIPTOR pSdFile
|
|
)
|
|
{
|
|
LONG lReturn = ERROR_SUCCESS;
|
|
LONG lStatus = ERROR_SUCCESS;
|
|
WIN32_FIND_DATA fdThisFile;
|
|
HANDLE hFileSearch;
|
|
BOOL bFileFound = FALSE;
|
|
DWORD dwFlagsToPass;
|
|
LPTSTR szWildPath;
|
|
TCHAR szWildFilePath[MAX_PATH];
|
|
LPTSTR szWildFileName;
|
|
|
|
if ((dwFlags & FILE_PATH_NORMAL) == FILE_PATH_NORMAL) {
|
|
// then just set the security on this path
|
|
if (FileExists(szPath)) {
|
|
if (IsDirectory(szPath)) {
|
|
// then apply directory SD
|
|
#ifdef TEST_MODE
|
|
_tprintf (TEXT("\n_DIR: %s"), szPath);
|
|
DumpAclData (szPath, pSdDir);
|
|
lReturn = ERROR_SUCCESS;
|
|
#else
|
|
if (!SetFileSecurity(szPath, DACL_SECURITY_INFORMATION, pSdDir)) {
|
|
lReturn = GetLastError();
|
|
}
|
|
#endif
|
|
} else {
|
|
// it's not a dir so apply file SD
|
|
#ifdef TEST_MODE
|
|
_tprintf (TEXT("\nFILE: %s"), szPath);
|
|
DumpAclData (szPath, pSdFile);
|
|
lReturn = ERROR_SUCCESS;
|
|
#else
|
|
if (!SetFileSecurity(szPath, DACL_SECURITY_INFORMATION, pSdFile)) {
|
|
lReturn = GetLastError();
|
|
}
|
|
#endif
|
|
}
|
|
} else {
|
|
#ifdef TEST_MODE
|
|
_tprintf (TEXT("\n_ERR: %s"), szPath);
|
|
#endif
|
|
lReturn = ERROR_FILE_NOT_FOUND;
|
|
}
|
|
} else if ((dwFlags & FILE_PATH_WILD) == FILE_PATH_WILD) {
|
|
// the path is (presumably) a wild-card path spec so walk the list
|
|
// of matching files
|
|
// make a local copy of the path preceeding the wildcard chars
|
|
// to build local paths with
|
|
lstrcpy (szWildFilePath, szPath);
|
|
szWildFileName = _tcsrchr(szWildFilePath, cBackslash); // find last backslash char
|
|
if (szWildFileName == NULL) {
|
|
// no backslash found so add one to the end of the path string
|
|
lstrcat (szWildFilePath, cszBackslash);
|
|
szWildFileName = szWildFilePath + lstrlen(szWildFilePath);
|
|
} else {
|
|
// backslash found so move pointer past it.
|
|
szWildFileName++;
|
|
}
|
|
hFileSearch = FindFirstFile (szPath, &fdThisFile);
|
|
if (hFileSearch != INVALID_HANDLE_VALUE) bFileFound = TRUE;
|
|
while (bFileFound) {
|
|
if (fdThisFile.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
|
|
if (!DotOrDotDotDir (fdThisFile.cFileName)) {
|
|
// then if this is dir, do see if we should do all the sub dirs
|
|
if ((dwFlags & FILE_PATH_SUBDIRS) == FILE_PATH_SUBDIRS) {
|
|
dwFlagsToPass = FILE_PATH_ALL;
|
|
} else {
|
|
dwFlagsToPass = 0; // do not do in this case
|
|
}
|
|
} else {
|
|
// this is a . or a .. dir so ignore
|
|
dwFlagsToPass = 0;
|
|
}
|
|
} else {
|
|
// just a file so process as a normal file
|
|
dwFlagsToPass = FILE_PATH_NORMAL;
|
|
}
|
|
if (dwFlagsToPass != 0) {
|
|
// make into a full path string
|
|
lstrcpy (szWildFileName, fdThisFile.cFileName);
|
|
// set the file security of this and any other files
|
|
lStatus = SetNtfsFileSecurity (szWildFilePath, dwFlagsToPass,
|
|
pSdDir, pSdFile);
|
|
if (lStatus != ERROR_SUCCESS) {
|
|
// save last "non-success" error for return
|
|
lReturn = lStatus;
|
|
}
|
|
}
|
|
bFileFound = FindNextFile (hFileSearch, &fdThisFile);
|
|
}
|
|
FindClose (hFileSearch);
|
|
} else if ((dwFlags & FILE_PATH_ALL) == FILE_PATH_ALL) {
|
|
// set the security of this path
|
|
lStatus = SetNtfsFileSecurity (szPath, FILE_PATH_NORMAL,
|
|
pSdDir, pSdFile);
|
|
if (IsDirectory(szPath)) {
|
|
// make a wild card path an pass it do all the files and sub-dirs
|
|
// of this path
|
|
szWildPath = (LPTSTR)GLOBAL_ALLOC(MAX_PATH_BYTES);
|
|
if (szWildPath != NULL) {
|
|
lstrcpy (szWildPath, szPath);
|
|
if (szWildPath[lstrlen(szWildPath)-1] != cBackslash) {
|
|
lstrcat (szWildPath, cszBackslash);
|
|
}
|
|
lstrcat (szWildPath, cszStarDotStar); // make wild
|
|
// call this routine with both WILD and ALL flags set
|
|
// so all files and sub-dirs will get set.
|
|
lStatus = SetNtfsFileSecurity (szWildPath,
|
|
(FILE_PATH_WILD | FILE_PATH_SUBDIRS),
|
|
pSdDir, pSdFile);
|
|
lReturn = lStatus;
|
|
} else {
|
|
lReturn = ERROR_OUTOFMEMORY;
|
|
}
|
|
GLOBAL_FREE_IF_ALLOC (szWildPath);
|
|
} else {
|
|
// path not a dir so just skip the wildcard stuff
|
|
}
|
|
} else {
|
|
// unrecognized flag
|
|
lReturn = ERROR_INVALID_PARAMETER;
|
|
}
|
|
return lReturn;
|
|
}
|