447 lines
10 KiB
C++
447 lines
10 KiB
C++
/*++
|
|
|
|
Copyright (c) 2000 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
test.cpp
|
|
|
|
Abstract:
|
|
|
|
Utility which allows to dump a file DACL in ADL or set a file DACL from ADL
|
|
|
|
Author:
|
|
|
|
t-eugenz - August 2000
|
|
|
|
Environment:
|
|
|
|
User mode only.
|
|
|
|
Revision History:
|
|
|
|
Created - August 2000
|
|
|
|
--*/
|
|
|
|
|
|
#include "adl.h"
|
|
|
|
|
|
//
|
|
// Various file rights
|
|
// More general rights have priority
|
|
//
|
|
|
|
ADL_MASK_STRING MaskStringMap[] =
|
|
{
|
|
{ (FILE_GENERIC_READ | FILE_GENERIC_WRITE | FILE_GENERIC_EXECUTE | WRITE_DAC
|
|
| WRITE_OWNER | READ_CONTROL | DELETE) & ~SYNCHRONIZE , L"full control" },
|
|
{ FILE_GENERIC_READ & ~SYNCHRONIZE, L"read" },
|
|
{ FILE_GENERIC_WRITE & ~SYNCHRONIZE, L"write" },
|
|
{ FILE_GENERIC_EXECUTE & ~SYNCHRONIZE, L"execute" },
|
|
{ DELETE & ~SYNCHRONIZE, L"delete" },
|
|
{ READ_CONTROL, L"read control"},
|
|
{ WRITE_DAC, L"write dac"},
|
|
{ WRITE_OWNER, L"write owner" },
|
|
{ SYNCHRONIZE, L"synchronize" },
|
|
{ FILE_READ_DATA, L"read data" },
|
|
{ FILE_WRITE_DATA, L"write data" },
|
|
{ FILE_APPEND_DATA, L"append data" },
|
|
{ FILE_READ_EA, L"read extended attributes" },
|
|
{ FILE_WRITE_EA, L"write extended attributes" },
|
|
{ FILE_EXECUTE, L"file execute" },
|
|
{ FILE_READ_ATTRIBUTES, L"read attributes" },
|
|
{ FILE_WRITE_ATTRIBUTES, L"write attributes" },
|
|
{ 0, NULL }
|
|
};
|
|
|
|
|
|
//
|
|
// Representation of the English version of ADL
|
|
//
|
|
|
|
ADL_LANGUAGE_SPEC lEnglish =
|
|
{
|
|
TK_LANG_ENGLISH,
|
|
0,
|
|
L' ',
|
|
L'\t',
|
|
L'\n',
|
|
L'\r',
|
|
L'"',
|
|
L',',
|
|
L';',
|
|
L'(',
|
|
L')',
|
|
L'@',
|
|
L'\\',
|
|
L'.',
|
|
0,
|
|
L"and",
|
|
L"except",
|
|
L"on",
|
|
L"allowed",
|
|
L"as",
|
|
L"this file",
|
|
L"subfolders",
|
|
L"files",
|
|
L"subfolders and files",
|
|
L"noprop"
|
|
};
|
|
|
|
ADL_PARSER_CONTROL EnglishFileParser =
|
|
{
|
|
&lEnglish,
|
|
MaskStringMap,
|
|
ACCESS_SYSTEM_SECURITY | MAXIMUM_ALLOWED,
|
|
SYNCHRONIZE
|
|
};
|
|
|
|
|
|
|
|
//
|
|
// Error handler
|
|
//
|
|
|
|
void HandleError(AdlStatement::ADL_ERROR_TYPE adlErr, const AdlToken *pTok)
|
|
{
|
|
switch(adlErr)
|
|
{
|
|
|
|
//
|
|
// Errors that should not happen unless there is a problem with the
|
|
// system or the user makes a mistake
|
|
//
|
|
|
|
case AdlStatement::ERROR_FATAL_LEXER_ERROR:
|
|
case AdlStatement::ERROR_FATAL_PARSER_ERROR:
|
|
case AdlStatement::ERROR_FATAL_ACL_CONVERT_ERROR:
|
|
case AdlStatement::ERROR_OUT_OF_MEMORY:
|
|
case AdlStatement::ERROR_ACL_API_FAILED:
|
|
case AdlStatement::ERROR_NOT_INITIALIZED:
|
|
wprintf(L"\n\nFatal internal error, Errorcode %u, THIS IS BAD\n\n", adlErr);
|
|
break;
|
|
|
|
case AdlStatement::ERROR_LSA_FAILED:
|
|
wprintf(L"\n\nError: LSA failed. Unable to resolve user information\n\n");
|
|
break;
|
|
|
|
|
|
//
|
|
// Input-related grammar errors: no token supplied
|
|
//
|
|
|
|
case AdlStatement::ERROR_UNTERMINATED_STRING:
|
|
wprintf(L"\n\nError: unmatched quote in the input\n\n");
|
|
break;
|
|
|
|
case AdlStatement::ERROR_UNKNOWN_ACE_TYPE:
|
|
wprintf(L"\n\nError: Unknown ACE type encountered\n\n");
|
|
break;
|
|
|
|
case AdlStatement::ERROR_IMPERSONATION_UNSUPPORTED:
|
|
wprintf(L"\n\nError: Impersonation is currently not supported in ADL\n\n");
|
|
break;
|
|
|
|
case AdlStatement::ERROR_INVALID_PARSER_CONTROL:
|
|
wprintf(L"\n\nError: The specified laanguage type is not supported\n\n");
|
|
break;
|
|
|
|
//
|
|
// For this error, the last read token is supplied
|
|
//
|
|
|
|
case AdlStatement::ERROR_NOT_IN_LANGUAGE:
|
|
wprintf(L"\n\nError, invalid ADL statement, did not expect '%s',\n\
|
|
which was found between characters %u and %u\n\n", pTok->GetValue(),
|
|
pTok->GetStart(), pTok->GetEnd());
|
|
break;
|
|
|
|
|
|
//
|
|
// Input-related semantic errors
|
|
//
|
|
|
|
//
|
|
// For these errors, the offending token is supplied
|
|
//
|
|
|
|
case AdlStatement::ERROR_UNKNOWN_USER:
|
|
|
|
wprintf(L"\n\nError, unknown user: ");
|
|
if( pTok->GetOptValue() != NULL )
|
|
{
|
|
wprintf(L"'%s%c%s' ", pTok->GetValue(), lEnglish.CH_AT, pTok->GetOptValue());
|
|
}
|
|
else
|
|
{
|
|
wprintf(L"'%s' ", pTok->GetValue());
|
|
}
|
|
wprintf(L"found between characters %u and %u\n\n", pTok->GetStart(), pTok->GetEnd());
|
|
break;
|
|
|
|
|
|
case AdlStatement::ERROR_UNKNOWN_PERMISSION:
|
|
wprintf(L"\n\nError, unknown permission: '%s' \
|
|
found between characters %u and %u\n\n",
|
|
pTok->GetValue(), pTok->GetStart(), pTok->GetEnd());
|
|
break;
|
|
|
|
case AdlStatement::ERROR_INVALID_USERNAME:
|
|
wprintf(L"\n\nError, invalid username string: '%s' \
|
|
found between characters %u and %u\n\n",
|
|
pTok->GetValue(), pTok->GetStart(), pTok->GetEnd());
|
|
break;
|
|
|
|
case AdlStatement::ERROR_INVALID_DOMAIN:
|
|
wprintf(L"\n\nError, invalid domain name string: '%s' \
|
|
found between characters %u and %u\n\n",
|
|
pTok->GetValue(), pTok->GetStart(), pTok->GetEnd());
|
|
break;
|
|
|
|
case AdlStatement::ERROR_INVALID_OBJECT:
|
|
wprintf(L"\n\nError, invalid object specifier: '%s' \
|
|
found between characters %u and %u\n\n",
|
|
pTok->GetValue(), pTok->GetStart(), pTok->GetEnd());
|
|
break;
|
|
|
|
//
|
|
// Other errors with no token supplied
|
|
//
|
|
|
|
case AdlStatement::ERROR_UNKNOWN_SID:
|
|
wprintf(L"\n\nError: SID encountered which could not be resolved to a name\n\n");
|
|
break;
|
|
|
|
case AdlStatement::ERROR_UNKNOWN_ACCESS_MASK:
|
|
wprintf(L"\n\nError: Access mask contains unknown bit\n\n");
|
|
break;
|
|
|
|
case AdlStatement::ERROR_INEXPRESSIBLE_ACL:
|
|
wprintf(L"\n\nError: This DACL cannot be expressed in ADL\n\n");
|
|
break;
|
|
|
|
default:
|
|
wprintf(L"\n\nUNKNOWN Error code: %u, THIS IS VERY BAD\n\n", adlErr);
|
|
break;
|
|
}
|
|
|
|
}
|
|
|
|
//
|
|
// -dump Filename
|
|
//
|
|
|
|
void DumpDaclToAdl(int argc, WCHAR *argv[]) {
|
|
|
|
DWORD dwErr;
|
|
|
|
if(argc != 3)
|
|
{
|
|
wprintf(L"\nUsage:\n\n%s -dump <target>\n\n", argv[0]);
|
|
exit(1);
|
|
}
|
|
|
|
PSECURITY_DESCRIPTOR pSD;
|
|
SECURITY_INFORMATION SecInfo = DACL_SECURITY_INFORMATION;
|
|
|
|
DWORD dwLengthNeeded;
|
|
GetFileSecurity(
|
|
argv[2],
|
|
SecInfo,
|
|
NULL,
|
|
0,
|
|
&dwLengthNeeded);
|
|
|
|
pSD = (PSECURITY_DESCRIPTOR) new BYTE[dwLengthNeeded];
|
|
|
|
dwErr = GetFileSecurity(
|
|
argv[2],
|
|
SecInfo,
|
|
pSD,
|
|
dwLengthNeeded,
|
|
&dwLengthNeeded);
|
|
|
|
if( dwErr == 0)
|
|
{
|
|
dwErr = GetLastError();
|
|
wprintf(L"GetFileSecurity failed on file '%s' with error %u, 0x%x\n",
|
|
argv[2], dwErr, dwErr);
|
|
exit(5);
|
|
}
|
|
|
|
PACL pDacl;
|
|
|
|
BOOL fDaclPresent;
|
|
BOOL fDaclDefaulted;
|
|
GetSecurityDescriptorDacl(pSD, &fDaclPresent, &pDacl, &fDaclDefaulted);
|
|
|
|
if( !fDaclPresent || pDacl == NULL )
|
|
{
|
|
wprintf(L"Security descriptor of '%s' does not contain a DACL",argv[2]);
|
|
exit(6);
|
|
}
|
|
|
|
AdlStatement *stat;
|
|
|
|
try
|
|
{
|
|
stat = new AdlStatement(&EnglishFileParser);
|
|
wstring ws;
|
|
stat->ReadFromDacl(pDacl);
|
|
stat->WriteToString(&ws);
|
|
wprintf(L"%s", ws.c_str());
|
|
}
|
|
catch(AdlStatement::ADL_ERROR_TYPE adlErr)
|
|
{
|
|
HandleError(adlErr, stat->GetErrorToken());
|
|
}
|
|
|
|
if( stat != NULL )
|
|
{
|
|
delete stat;
|
|
}
|
|
|
|
delete[] (PBYTE)pSD;
|
|
}
|
|
|
|
|
|
//
|
|
// -set adlfile target
|
|
//
|
|
|
|
void WriteDaclFromAdl(int argc, WCHAR *argv[]) {
|
|
|
|
WCHAR buf[16384];
|
|
char buf3[16384];
|
|
DWORD i;
|
|
DWORD dwErr;
|
|
|
|
if(argc != 4)
|
|
{
|
|
wprintf(L"\nUsage:\n\n%s -set <adl rules file> <target>\n\n", argv[0]);
|
|
exit(1);
|
|
}
|
|
|
|
FILE *in = _wfopen(argv[2], L"rb");
|
|
if(in == NULL)
|
|
{
|
|
wprintf(L"Error: cannot open input ADL file '%s', exiting\n", argv[2]);
|
|
exit(2);
|
|
}
|
|
|
|
// skip top byte
|
|
if( fgetwc(in) != 0xFEFF)
|
|
{
|
|
fseek(in, 0, SEEK_SET);
|
|
for(i = 0; (buf3[i] = (char)fgetc(in)) != EOF && i < 16384; i++);
|
|
buf3[i] = 0;
|
|
MultiByteToWideChar(CP_ACP, 0, buf3, i+1, buf, 16384);
|
|
}
|
|
else
|
|
{
|
|
for(i = 0; (buf[i] = fgetwc(in)) != WEOF && i < 16384; i++);
|
|
buf[i] = 0;
|
|
}
|
|
|
|
AdlStatement * stat;
|
|
|
|
try
|
|
{
|
|
stat = new AdlStatement( &EnglishFileParser);
|
|
wstring ws;
|
|
stat->ReadFromString(buf);
|
|
stat->WriteToString(&ws);
|
|
wprintf(L"Setting permissions to:\n-------------\n%s\n-------------\n",
|
|
ws.c_str());
|
|
|
|
}
|
|
catch(AdlStatement::ADL_ERROR_TYPE adlErr)
|
|
{
|
|
HandleError(adlErr, stat->GetErrorToken());
|
|
if( stat != NULL )
|
|
{
|
|
delete stat;
|
|
}
|
|
exit(6);
|
|
}
|
|
|
|
//
|
|
// Initialize the security descriptor
|
|
//
|
|
|
|
SECURITY_DESCRIPTOR SD;
|
|
|
|
InitializeSecurityDescriptor(&SD, SECURITY_DESCRIPTOR_REVISION);
|
|
SetSecurityDescriptorGroup(&SD, NULL, FALSE);
|
|
SetSecurityDescriptorOwner(&SD, NULL, FALSE);
|
|
SetSecurityDescriptorSacl(&SD, FALSE, NULL, FALSE);
|
|
|
|
PACL pDacl = NULL;
|
|
|
|
try
|
|
{
|
|
stat->WriteToDacl(&pDacl);
|
|
}
|
|
catch(AdlStatement::ADL_ERROR_TYPE adlErr)
|
|
{
|
|
HandleError(adlErr, stat->GetErrorToken());
|
|
delete stat;
|
|
exit(7);
|
|
}
|
|
|
|
SetSecurityDescriptorDacl(&SD, TRUE, pDacl, FALSE);
|
|
|
|
//
|
|
// Set the file security
|
|
//
|
|
|
|
SECURITY_INFORMATION SecInfo = DACL_SECURITY_INFORMATION;
|
|
dwErr = SetFileSecurity(argv[3], SecInfo, &SD);
|
|
if(dwErr == 0)
|
|
{
|
|
dwErr = GetLastError();
|
|
wprintf(L"SetFileSecurity on %s failed with %d, 0x%x\n",
|
|
argv[3],
|
|
dwErr,
|
|
dwErr);
|
|
}
|
|
else
|
|
{
|
|
wprintf(L"Success, permissions set.\n");
|
|
}
|
|
|
|
AdlStatement::FreeMemory(pDacl);
|
|
|
|
delete stat;
|
|
}
|
|
|
|
|
|
void __cdecl wmain(int argc, WCHAR *argv[])
|
|
{
|
|
|
|
if(argc < 2)
|
|
{
|
|
wprintf(L"\nUsage:\n\n%s -set <adl rules file> <target>\n"
|
|
L"%s -dump <target>\n\n", argv[0], argv[0]);
|
|
}
|
|
else
|
|
{
|
|
if(!_wcsicmp(argv[1], L"-dump"))
|
|
{
|
|
DumpDaclToAdl(argc, argv);
|
|
}
|
|
else if(!_wcsicmp(argv[1], L"-set"))
|
|
{
|
|
WriteDaclFromAdl(argc, argv);
|
|
}
|
|
else
|
|
{
|
|
wprintf(L"\nUsage:\n\n%s -set <adl rules file> <target>\n"
|
|
L"%s -dump <target>\n\n", argv[0], argv[0]);
|
|
}
|
|
|
|
}
|
|
}
|