|
|
//+---------------------------------------------------------------------------
//
// Microsoft Windows
// Copyright (C) Microsoft Corporation, 1996 - 1996.
//
// File: FILE.C
//
// Contents: Unit test for file propagation, issues
//
// History: 14-Sep-96 MacM Created
//
// Notes:
//
//----------------------------------------------------------------------------
#include <nt.h>
#include <ntrtl.h>
#include <nturtl.h>
#include <windows.h>
#include <stdlib.h>
#include <stdio.h>
#include <aclapi.h>
#include <seopaque.h>
#include <ntrtl.h>
#define FLAG_ON(flags,bit) ((flags) & (bit))
#define DEFAULT_ACCESS ACTRL_SVC_GET_INFO | ACTRL_SVC_SET_INFO | \
ACTRL_SVC_STATUS | ACTRL_SVC_LIST | \ ACTRL_SVC_START | ACTRL_SVC_STOP | \ ACTRL_SVC_PAUSE | ACTRL_SVC_INTERROGATE
#define HANDLE_CLOSE(h) if((h) != NULL) { CloseServiceHandle(h); (h) = NULL;}
//
// Flags for tests
//
#define STEST_READ 0x00000001
#define STEST_CACHE 0x00000002
DWORD AddAE ( IN PWSTR pwszUser, IN ACCESS_RIGHTS AccessRights, IN INHERIT_FLAGS Inherit, IN ULONG fAccess, IN PACTRL_ACCESS pExistingAccess, OUT PACTRL_ACCESS *ppNewAccess ) /*++
Routine Description:
Initialize an access entry
Arguments:
pwszUser - User to set AccessRights - Access rights to set Inherit - Any inheritance flags fAccess - Allowed or denied node? pExistingAccess - Access Entry to add to ppNewAccess - Where the new access is returned
Return Value:
ERROR_SUCCESS - Success
--*/ { DWORD dwErr = ERROR_SUCCESS; ACTRL_ACCESS_ENTRY AAE;
BuildTrusteeWithNameW(&(AAE.Trustee), pwszUser); AAE.fAccessFlags = fAccess; AAE.Access = AccessRights; AAE.ProvSpecificAccess = 0; AAE.Inheritance = Inherit; AAE.lpInheritProperty = NULL;
dwErr = SetEntriesInAccessListW(1, &AAE, GRANT_ACCESS, NULL, pExistingAccess, ppNewAccess); if(dwErr != ERROR_SUCCESS) { printf(" Failed to add new access entry: %lu\n", dwErr); }
return(dwErr); }
VOID Usage ( IN PSTR pszExe ) /*++
Routine Description:
Displays the usage
Arguments:
pszExe - Name of the exe
Return Value:
VOID
--*/ { printf("%s service user [/C] [/O] [/I] [/P] [/test] [/H]\n", pszExe); printf(" where services is the display name of the service\n"); printf(" user is the name of a user to set access for\n"); printf(" /test indicates which test to run:\n"); printf(" /READ (Simple read/write)\n"); printf(" /CACHE (Cache matching)\n"); printf(" if test is not specified, all variations are run\n"); printf(" /H indicates to use the handle version of the APIs\n"); printf(" /C is Container Inherit\n"); printf(" /O is Object Inherit\n"); printf(" /I is InheritOnly\n"); printf(" /P is Inherit No Propagate\n");
return; }
//
// Conceptually, this is a companion function for GetSecurityForPath
//
#define SetSecurityForService(svc,usehandle,handle,access) \
(usehandle == TRUE ? \ SetSecurityInfoExW(handle, \ SE_SERVICE, \ DACL_SECURITY_INFORMATION, \ NULL, \ access, \ NULL, \ NULL, \ NULL, \ NULL) : \ SetNamedSecurityInfoExW(svc, \ SE_SERVICE, \ DACL_SECURITY_INFORMATION, \ NULL, \ access, \ NULL, \ NULL, \ NULL, \ NULL))
DWORD GetSecurityForService ( IN PWSTR pwszService, IN BOOL fUseHandle, OUT HANDLE *phObj, OUT PACTRL_ACCESSW *ppAccess ) /*++
Routine Description:
Reads the dacl off the specified service object
Arguments:
pwszService -- Service to read fUseHandle -- Use handle or path based API phObj -- Handle to object ppAccess -- Where the access is returned
Return Value:
ERROR_SUCCESS -- Success
--*/ { DWORD dwErr = ERROR_SUCCESS; SC_HANDLE hSC;
if(fUseHandle == TRUE) { //
// Open the object
//
if(*phObj == NULL) { hSC = OpenSCManager(NULL, NULL, GENERIC_READ); if(hSC == NULL) { dwErr = GetLastError(); } else { //
// Open the service
//
*phObj = OpenService(hSC, pwszService, READ_CONTROL | WRITE_DAC); if(*phObj == NULL) { dwErr = GetLastError(); } } }
if(dwErr == ERROR_SUCCESS) { dwErr = GetSecurityInfoExW(*phObj, SE_SERVICE, DACL_SECURITY_INFORMATION, NULL, NULL, ppAccess, NULL, NULL, NULL); if(dwErr != ERROR_SUCCESS) { HANDLE_CLOSE(*phObj); }
}
} else { dwErr = GetNamedSecurityInfoExW(pwszService, SE_SERVICE, DACL_SECURITY_INFORMATION, NULL, NULL, ppAccess, NULL, NULL, NULL); if(phObj != NULL) { *phObj = NULL; } }
return(dwErr); }
DWORD DoReadTest ( IN PWSTR pwszService, IN PWSTR pwszUser, IN BOOL fDoHandle ) /*++
Routine Description:
Does the simple read test
Arguments:
pwszService -- Service name pwszUser -- User to run with fDoHandle -- If true, use the handle based APIs
Return Value:
ERROR_SUCCESS -- Success
--*/ { DWORD dwErr = ERROR_SUCCESS; PACTRL_ACCESS pCurrent; PACTRL_ACCESS pNew; HANDLE hObj;
printf("Simple read/write test\n");
printf(" Processing service %ws\n", pwszService); hObj = NULL;
dwErr = GetSecurityForService(pwszService, fDoHandle, &hObj, &pCurrent); if(dwErr != ERROR_SUCCESS) { printf(" Failed to read the DACL off %ws: %lu\n", pwszService, dwErr); } else { //
// Ok, now add the entry for our user
//
dwErr = AddAE(pwszUser, DEFAULT_ACCESS, 0, ACTRL_ACCESS_ALLOWED, pCurrent, &pNew); if(dwErr == ERROR_SUCCESS) { //
// Set it
//
dwErr = SetSecurityForService(pwszService, fDoHandle, hObj, pNew);
if(dwErr != ERROR_SUCCESS) { printf(" Set failed: %lu\n", dwErr); } LocalFree(pNew); }
//
// If that worked, reread the new security, and see if it's correct
//
if(dwErr == ERROR_SUCCESS) { HANDLE_CLOSE(hObj);
dwErr = GetSecurityForService(pwszService, fDoHandle, &hObj, &pNew); if(dwErr != ERROR_SUCCESS) { printf(" Failed to read the 2nd DACL off %ws: %lu\n", pwszService, dwErr); } else { //
// We should only have one property, so cheat...
//
ULONG cExpected = 1 + pCurrent->pPropertyAccessList[0]. pAccessEntryList->cEntries; ULONG cGot = pNew->pPropertyAccessList[0]. pAccessEntryList->cEntries; if(cExpected != cGot) { printf(" Expected %lu entries, got %lu\n", cExpected, cGot); dwErr = ERROR_INVALID_FUNCTION; }
LocalFree(pNew); }
//
// Restore the current security
//
SetNamedSecurityInfoExW(pwszService, SE_SERVICE, DACL_SECURITY_INFORMATION, NULL, pCurrent, NULL, NULL, NULL, NULL); }
LocalFree(pCurrent); }
HANDLE_CLOSE(hObj);
return(dwErr); }
DWORD DoCacheTest ( IN PWSTR pwszService, IN PWSTR pwszUser, IN BOOL fDoHandle ) /*++
Routine Description:
Does the marta cache matching test
Arguments:
pwszService -- Service name pwszUser -- User to run with fDoHandle -- If true, use the handle based APIs
Return Value:
ERROR_SUCCESS -- Success
--*/ { DWORD dwErr = ERROR_SUCCESS; PACTRL_ACCESS pCurrent; INT i; SE_OBJECT_TYPE SeList[] = {SE_FILE_OBJECT, SE_SERVICE, SE_PRINTER, SE_REGISTRY_KEY, SE_LMSHARE, SE_KERNEL_OBJECT, SE_WINDOW_OBJECT, SE_DS_OBJECT, SE_DS_OBJECT_ALL}; PSTR pszSeList[] = {"SE_FILE_OBJECT", "SE_SERVICE", "SE_PRINTER", "SE_REGISTRY_KEY", "SE_LMSHARE", "SE_KERNEL_OBJECT", "SE_WINDOW_OBJECT", "SE_DS_OBJECT", "SE_DS_OBJECT_ALL"};
ASSERT(sizeof(SeList) / sizeof(SE_OBJECT_TYPE) == sizeof(pszSeList) / sizeof(PSTR));
printf("Marta cache matching test\n");
printf(" Processing service %ws\n", pwszService);
//
// Prime the cache...
//
dwErr = GetNamedSecurityInfoExW(pwszService, SE_SERVICE, DACL_SECURITY_INFORMATION, NULL, NULL, &pCurrent, NULL, NULL, NULL); if(dwErr != ERROR_SUCCESS) { printf(" Failed to read the DACL off %ws: %lu\n", pwszService, dwErr); } else { LocalFree(pCurrent);
//
// Now, open it as an another object type...
//
for(i = 0; i < sizeof(pszSeList) / sizeof(PSTR); i++) { printf(" Processing %ws as a %s\n", pwszService, pszSeList[i]);
if(GetNamedSecurityInfoExW(pwszService, SeList[i], DACL_SECURITY_INFORMATION, NULL, NULL, &pCurrent, NULL, NULL, NULL) == ERROR_SUCCESS) { LocalFree(pCurrent); } }
//
// In order to check this, we'll set the debugger on NTMARTA, turn on cache tracing,
// and see how many hits we have. Tacky, no doubt, but we have little choice
//
}
//
// Now, create a file of the same name, and do the same code
//
if(dwErr == ERROR_SUCCESS) { HANDLE hFile; printf(" Processing file %ws\n", pwszService);
hFile = CreateFile(pwszService, GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); if(hFile == INVALID_HANDLE_VALUE) { dwErr = GetLastError(); printf(" CreateEvent on %ws failed with %lu\n", pwszService, dwErr); } else { for(i = 0; i < sizeof(pszSeList) / sizeof(PSTR); i++) { printf(" Processing %ws as a %s\n", pwszService, pszSeList[i]);
if(GetNamedSecurityInfoExW(pwszService, SeList[i], DACL_SECURITY_INFORMATION, NULL, NULL, &pCurrent, NULL, NULL, NULL) == ERROR_SUCCESS) { LocalFree(pCurrent); } }
if(GetNamedSecurityInfoExW(pwszService, SE_FILE_OBJECT, DACL_SECURITY_INFORMATION, NULL, NULL, &pCurrent, NULL, NULL, NULL) == ERROR_SUCCESS) { LocalFree(pCurrent); } CloseHandle(hFile); DeleteFile(pwszService); } }
return(dwErr); }
__cdecl main ( IN INT argc, IN CHAR *argv[]) /*++
Routine Description:
The main
Arguments:
argc -- Count of arguments argv -- List of arguments
Return Value:
0 -- Success non-0 -- Failure
--*/ {
DWORD dwErr = ERROR_SUCCESS; WCHAR wszService[MAX_PATH + 1]; WCHAR wszUser[MAX_PATH + 1]; INHERIT_FLAGS Inherit = 0; ULONG Tests = 0; INT i; BOOL fHandle = FALSE;
srand((ULONG)(GetTickCount() * GetCurrentThreadId()));
if(argc < 3) { Usage(argv[0]); exit(1); }
mbstowcs(wszService, argv[1], strlen(argv[1]) + 1); mbstowcs(wszUser, argv[2], strlen(argv[2]) + 1);
//
// process the command line
//
for(i = 3; i < argc; i++) { if(_stricmp(argv[i], "/h") == 0) { fHandle = TRUE; } else if(_stricmp(argv[i],"/C") == 0) { Inherit |= SUB_CONTAINERS_ONLY_INHERIT; } else if(_stricmp(argv[i],"/O") == 0) { Inherit |= SUB_OBJECTS_ONLY_INHERIT; } else if(_stricmp(argv[i],"/I") == 0) { Inherit |= INHERIT_ONLY; } else if(_stricmp(argv[i],"/P") == 0) { Inherit |= INHERIT_NO_PROPAGATE; } else if(_stricmp(argv[i],"/READ") == 0) { Tests |= STEST_READ; } else if(_stricmp(argv[i],"/CACHE") == 0) { Tests |= STEST_CACHE; } else { Usage(argv[0]); exit(1); break; } }
if(Tests == 0) { Tests = STEST_READ; }
//
// Build the tree
//
if(dwErr == ERROR_SUCCESS && FLAG_ON(Tests, STEST_READ)) { dwErr = DoReadTest(wszService, wszUser, fHandle); }
if(dwErr == ERROR_SUCCESS && FLAG_ON(Tests, STEST_CACHE)) { dwErr = DoCacheTest(wszService, wszUser, fHandle); }
printf("%s\n", dwErr == ERROR_SUCCESS ? "success" : "failed"); return(dwErr); }
|