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.
846 lines
25 KiB
846 lines
25 KiB
//+----------------------------------------------------------------------------
|
|
//
|
|
// Microsoft Windows
|
|
// Copyright (C) Microsoft Corporation, 1992 - 1993.
|
|
//
|
|
// File: setup.cxx
|
|
//
|
|
// Contents: Task Scheduler setup program
|
|
//
|
|
// Classes: None.
|
|
//
|
|
// Functions:
|
|
//
|
|
// History: 04-Apr-96 MarkBl Created
|
|
// 23-Sep-96 AnirudhS Added SetTaskFolderSecurity, etc.
|
|
// 30-Sep-96 AnirudhS Added /firstlogon and /logon options
|
|
// 15-Nov-96 AnirudhS Conditionally enable the service on NT too
|
|
// 01-09-97 DavidMun Add sysagent.exe path value under
|
|
// app paths, backup sysagent.exe
|
|
// 04-14-97 DavidMun Add DoMemphisSetup
|
|
// 03-03-01 JBenton Prefix BUG 333200 use of uninit memory
|
|
// 03-10-01 JBenton BUG 142333 tighten Tasks folder security
|
|
// October 01 Maxa Updated security on Tasks folder in preparation for addition of auditing.
|
|
//
|
|
//-----------------------------------------------------------------------------
|
|
|
|
#include <windows.h>
|
|
#include <tchar.h>
|
|
#include <sddl.h>
|
|
#include <StrSafe.h>
|
|
#include "security.hxx"
|
|
#include "setupids.h"
|
|
|
|
#define ARRAY_LEN(a) (sizeof(a)/sizeof((a)[0]))
|
|
#define ARG_DELIMITERS TEXT(" \t")
|
|
#define MINUTES_BEFORE_IDLE_DEFAULT 15
|
|
#define MAX_LOG_SIZE_DEFAULT (0x20)
|
|
|
|
//
|
|
// Note that the svchost registry keys to run schedule service as a part
|
|
// of netsvcs is set in hivesft.inx file.
|
|
//
|
|
#define SCHED_SETUP_SWITCH TEXT("/setup")
|
|
#define SCHED_SERVICE_EXE_PATH TEXT("%SystemRoot%\\System32\\svchost.exe -k netsvcs")
|
|
#define SCHED_SERVICE_DLL TEXT("MSTask.dll")
|
|
#define SCHED_SERVICE_NAME TEXT("Schedule")
|
|
#define SCHED_SERVICE_GROUP TEXT("SchedulerGroup")
|
|
#define MINUTESBEFOREIDLE TEXT("MinutesBeforeIdle")
|
|
#define MAXLOGSIZEKB TEXT("MaxLogSizeKB")
|
|
#define TASKSFOLDER TEXT("TasksFolder")
|
|
#define FIRSTBOOT TEXT("FirstBoot")
|
|
#define SM_SA_KEY TEXT("Software\\Microsoft\\SchedulingAgent")
|
|
|
|
//
|
|
// Entry points from mstask.dll
|
|
// Note they are used with GetProcAddress, which always wants an ANSI string.
|
|
//
|
|
#define CONVERT_AT_TASKS_API "ConvertAtJobsToTasks"
|
|
|
|
//
|
|
// Function pointer types used when loading above functions from mstask.dll
|
|
//
|
|
|
|
typedef HRESULT (__stdcall *PSTDAPI)(void);
|
|
typedef BOOL (__stdcall *PBOOLAPI)(void);
|
|
typedef VOID (__stdcall *PVOIDAPI)(void);
|
|
|
|
typedef struct _MYSIDINFO {
|
|
PSID_IDENTIFIER_AUTHORITY pIdentifierAuthority;
|
|
DWORD dwSubAuthority;
|
|
DWORD dwSubSubAuthority;
|
|
PSID pSid;
|
|
} MYSIDINFO;
|
|
|
|
DWORD SetTaskFolderSecurity(LPCWSTR pwszFolderPath);
|
|
DWORD AllocateAndInitializeDomainSid(
|
|
PSID pDomainSid,
|
|
MYSIDINFO * pDomainSidInfo);
|
|
|
|
void DoSetup(void);
|
|
void ErrorDialog(UINT ErrorFmtStringID, TCHAR * szRoutine, DWORD ErrorCode);
|
|
|
|
HINSTANCE ghInstance = NULL;
|
|
|
|
//+----------------------------------------------------------------------------
|
|
//
|
|
// Function: WinMainCRTStartup
|
|
//
|
|
// Synopsis: entry point
|
|
//
|
|
//-----------------------------------------------------------------------------
|
|
void _cdecl
|
|
main(int argc, char ** argv)
|
|
{
|
|
//
|
|
// Skip EXE name and find first parameter, if any
|
|
//
|
|
LPTSTR ptszStart;
|
|
LPTSTR szArg1 = _tcstok(ptszStart = GetCommandLine(), ARG_DELIMITERS);
|
|
szArg1 = _tcstok(NULL, ARG_DELIMITERS);
|
|
//
|
|
// Switch based on the first parameter
|
|
//
|
|
if (szArg1 == NULL)
|
|
{
|
|
; // Do nothing
|
|
}
|
|
else if (lstrcmpi(szArg1, SCHED_SETUP_SWITCH) == 0)
|
|
{
|
|
DoSetup();
|
|
}
|
|
}
|
|
|
|
//+----------------------------------------------------------------------------
|
|
//
|
|
// Function: DoSetup
|
|
//
|
|
// Synopsis: Performs the normal setup procedure
|
|
//
|
|
//-----------------------------------------------------------------------------
|
|
void
|
|
DoSetup(void)
|
|
{
|
|
#define SCHED_SERVICE_DEPENDENCY L"RpcSs\0"
|
|
#define SCC_AT_SVC_KEY L"System\\CurrentControlSet\\Services\\Schedule"
|
|
#define TASKS_FOLDER_DEFAULT L"%SystemRoot%\\Tasks"
|
|
|
|
TCHAR szTasksFolder[MAX_PATH + 1] = TEXT("");
|
|
TCHAR tszDisplayName[50]; // "Task Scheduler"
|
|
DWORD dwTmp;
|
|
HKEY hKey;
|
|
|
|
//
|
|
// Disable hard-error popups.
|
|
//
|
|
SetErrorMode(SEM_FAILCRITICALERRORS | SEM_NOOPENFILEERRORBOX);
|
|
|
|
ghInstance = GetModuleHandle(NULL);
|
|
|
|
//
|
|
// Load the service display name.
|
|
//
|
|
int cch = LoadString(ghInstance, IDS_SERVICE_DISPLAY_NAME, tszDisplayName,
|
|
ARRAY_LEN(tszDisplayName));
|
|
if (!(0 < cch && cch < ARRAY_LEN(tszDisplayName) - 1))
|
|
{
|
|
ErrorDialog(IDS_INSTALL_FAILURE,
|
|
TEXT("LoadString"),
|
|
GetLastError());
|
|
return;
|
|
}
|
|
|
|
//
|
|
// Create/open the Scheduling Agent key in Software\Microsoft.
|
|
//
|
|
LONG lErr = RegCreateKeyEx(HKEY_LOCAL_MACHINE,
|
|
SM_SA_KEY,
|
|
0,
|
|
NULL,
|
|
REG_OPTION_NON_VOLATILE,
|
|
KEY_ALL_ACCESS,
|
|
NULL,
|
|
&hKey,
|
|
&dwTmp);
|
|
|
|
if (ERROR_SUCCESS != lErr)
|
|
{
|
|
ErrorDialog(IDS_INSTALL_FAILURE, TEXT("RegCreateKeyEx"), lErr);
|
|
return;
|
|
}
|
|
|
|
// Creator/Owner, System, Builtin Admins: Full control,
|
|
// Authenticated users: generic read
|
|
WCHAR pwszSDDL[] = L"D:P(A;OICIIO;FA;;;CO)(A;OICI;FA;;;BA)(A;OICI;FA;;;SY)(A;OICI;GR;;;AU)";
|
|
PSECURITY_DESCRIPTOR pSD = NULL;
|
|
|
|
if (!ConvertStringSecurityDescriptorToSecurityDescriptorW(pwszSDDL, SDDL_REVISION_1, &pSD, NULL))
|
|
{
|
|
lErr = (GetLastError());
|
|
ErrorDialog(IDS_INSTALL_FAILURE, TEXT("ConvertStringSecurityDescriptorToSecurityDescriptorW"), lErr);
|
|
RegCloseKey(hKey);
|
|
return;
|
|
}
|
|
|
|
lErr = RegSetKeySecurity(hKey, DACL_SECURITY_INFORMATION, pSD);
|
|
LocalFree(pSD);
|
|
if (ERROR_SUCCESS != lErr)
|
|
{
|
|
ErrorDialog(IDS_INSTALL_FAILURE, TEXT("RegSetKeySecurity"), lErr);
|
|
RegCloseKey(hKey);
|
|
return;
|
|
}
|
|
|
|
// Set MinutesBeforeIdle to a default value of 15 mins.
|
|
//
|
|
dwTmp = MINUTES_BEFORE_IDLE_DEFAULT;
|
|
lErr = RegSetValueEx(hKey,
|
|
MINUTESBEFOREIDLE,
|
|
0,
|
|
REG_DWORD,
|
|
(CONST BYTE *)&dwTmp,
|
|
sizeof(dwTmp));
|
|
|
|
if (ERROR_SUCCESS != lErr)
|
|
{
|
|
ErrorDialog(IDS_INSTALL_FAILURE, TEXT("RegSetValueEx"), lErr);
|
|
RegCloseKey(hKey);
|
|
return;
|
|
}
|
|
|
|
// Set MaxLogSizeKB to 32K or 0x7FFF.
|
|
//
|
|
dwTmp = MAX_LOG_SIZE_DEFAULT;
|
|
lErr = RegSetValueEx(hKey,
|
|
MAXLOGSIZEKB,
|
|
0,
|
|
REG_DWORD,
|
|
(CONST BYTE *)&dwTmp,
|
|
sizeof(dwTmp));
|
|
|
|
if (ERROR_SUCCESS != lErr)
|
|
{
|
|
ErrorDialog(IDS_INSTALL_FAILURE, TEXT("RegSetValueEx"), lErr);
|
|
RegCloseKey(hKey);
|
|
return;
|
|
}
|
|
|
|
// Read the tasks folder location. The .INF should've set this.
|
|
// If not, default.
|
|
//
|
|
dwTmp = MAX_PATH * sizeof(TCHAR);
|
|
if (RegQueryValueEx(hKey,
|
|
TASKSFOLDER,
|
|
NULL,
|
|
NULL,
|
|
(LPBYTE)szTasksFolder,
|
|
&dwTmp) != ERROR_SUCCESS ||
|
|
szTasksFolder[0] == TEXT('\0'))
|
|
{
|
|
StringCchCopy(szTasksFolder, MAX_PATH + 1, TASKS_FOLDER_DEFAULT);
|
|
}
|
|
|
|
// Set FirstBoot to non-zero.
|
|
//
|
|
dwTmp = 1;
|
|
lErr = RegSetValueEx(hKey,
|
|
FIRSTBOOT,
|
|
0,
|
|
REG_DWORD,
|
|
(CONST BYTE *)&dwTmp,
|
|
sizeof(dwTmp));
|
|
|
|
RegCloseKey(hKey);
|
|
|
|
if (ERROR_SUCCESS != lErr)
|
|
{
|
|
ErrorDialog(IDS_INSTALL_FAILURE, TEXT("RegSetValueEx"), lErr);
|
|
return;
|
|
}
|
|
|
|
//
|
|
// Set the right permissions on the job folder.
|
|
// The default permissions allow anyone to delete any job, which we
|
|
// don't want.
|
|
//
|
|
{
|
|
TCHAR szTaskFolderPath[MAX_PATH + 1];
|
|
DWORD cch = ExpandEnvironmentStrings(szTasksFolder,
|
|
szTaskFolderPath,
|
|
ARRAY_LEN(szTaskFolderPath));
|
|
if (cch == 0 || cch > ARRAY_LEN(szTaskFolderPath))
|
|
{
|
|
//
|
|
// The job folder path is too long.
|
|
//
|
|
ErrorDialog(IDS_INSTALL_FAILURE,
|
|
TEXT("ExpandEnvironmentStrings"),
|
|
cch ? ERROR_BUFFER_OVERFLOW : GetLastError());
|
|
return;
|
|
}
|
|
|
|
DWORD dwError = SetTaskFolderSecurity(szTaskFolderPath);
|
|
if (dwError != ERROR_SUCCESS)
|
|
{
|
|
ErrorDialog(IDS_INSTALL_FAILURE,
|
|
TEXT("SetTaskFolderSecurity"),
|
|
dwError);
|
|
return;
|
|
}
|
|
}
|
|
|
|
HINSTANCE hinstMSTask = LoadLibrary(SCHED_SERVICE_DLL);
|
|
if (!hinstMSTask)
|
|
{
|
|
ErrorDialog(IDS_INSTALL_FAILURE,
|
|
SCHED_SERVICE_DLL,
|
|
GetLastError());
|
|
return;
|
|
}
|
|
|
|
PVOIDAPI pfnConvertLegacyJobsToTasks = (PVOIDAPI)
|
|
GetProcAddress(hinstMSTask, CONVERT_AT_TASKS_API);
|
|
|
|
if (!pfnConvertLegacyJobsToTasks)
|
|
{
|
|
ErrorDialog(IDS_INSTALL_FAILURE,
|
|
TEXT("GetProcAddress"),
|
|
GetLastError());
|
|
return;
|
|
}
|
|
|
|
pfnConvertLegacyJobsToTasks();
|
|
|
|
//
|
|
// Install the Win32 service.
|
|
//
|
|
|
|
SC_HANDLE hSCMgr = OpenSCManager(NULL, NULL, SC_MANAGER_CREATE_SERVICE);
|
|
|
|
if (hSCMgr == NULL)
|
|
{
|
|
//
|
|
// Yow, we're hosed.
|
|
//
|
|
|
|
ErrorDialog(IDS_INSTALL_FAILURE,
|
|
TEXT("OpenSCManager"),
|
|
GetLastError());
|
|
return;
|
|
}
|
|
|
|
|
|
//
|
|
// Is the service already installed? If so, change its parameters;
|
|
// otherwise, create it.
|
|
//
|
|
|
|
SC_HANDLE hSvc = OpenService(hSCMgr,
|
|
SCHED_SERVICE_NAME,
|
|
SERVICE_CHANGE_CONFIG | SERVICE_START);
|
|
|
|
if (hSvc == NULL)
|
|
{
|
|
hSvc = CreateService(hSCMgr,
|
|
SCHED_SERVICE_NAME,
|
|
tszDisplayName,
|
|
SERVICE_CHANGE_CONFIG | SERVICE_START,
|
|
SERVICE_WIN32_SHARE_PROCESS,
|
|
SERVICE_AUTO_START,
|
|
SERVICE_ERROR_NORMAL,
|
|
SCHED_SERVICE_EXE_PATH,
|
|
SCHED_SERVICE_GROUP,
|
|
NULL,
|
|
SCHED_SERVICE_DEPENDENCY,
|
|
NULL,
|
|
NULL);
|
|
|
|
if (hSvc == NULL)
|
|
{
|
|
ErrorDialog(IDS_INSTALL_FAILURE,
|
|
TEXT("CreateService"),
|
|
GetLastError());
|
|
CloseServiceHandle(hSCMgr);
|
|
return;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// This path will be followed when we upgrade the At service
|
|
// to the Scheduling Agent. The service name will remain the
|
|
// same, but the display name will be set to the new display
|
|
// name (the At service had no display name) and the image path
|
|
// will be changed to point to the new exe.
|
|
// (The old binary will be left on disk in order to make it easy
|
|
// to revert to it, in case of compatibility problems.)
|
|
//
|
|
if (!ChangeServiceConfig(
|
|
hSvc, // hService
|
|
SERVICE_WIN32_SHARE_PROCESS, // dwServiceType
|
|
SERVICE_AUTO_START, // dwStartType
|
|
SERVICE_ERROR_NORMAL, // dwErrorControl
|
|
SCHED_SERVICE_EXE_PATH, // lpBinaryPathName
|
|
SCHED_SERVICE_GROUP, // lpLoadOrderGroup
|
|
NULL, // lpdwTagId
|
|
SCHED_SERVICE_DEPENDENCY, // lpDependencies
|
|
L".\\LocalSystem", // lpServiceStartName
|
|
L"", // lpPassword
|
|
tszDisplayName // lpDisplayName
|
|
))
|
|
{
|
|
ErrorDialog(IDS_INSTALL_FAILURE,
|
|
TEXT("ChangeServiceConfig"),
|
|
GetLastError());
|
|
CloseServiceHandle(hSvc);
|
|
CloseServiceHandle(hSCMgr);
|
|
return;
|
|
}
|
|
}
|
|
|
|
// in either case, set the recovery options
|
|
// not checking return - it's a minor glitch, no need to upset the user
|
|
SC_ACTION actions[3] = {{SC_ACTION_RESTART, 6000},{SC_ACTION_RESTART, 60000},{SC_ACTION_NONE, 0}};
|
|
SERVICE_FAILURE_ACTIONS recoveryInfo = {24*60*60, NULL, NULL, 3, &(actions[0])};
|
|
ChangeServiceConfig2(hSvc,SERVICE_CONFIG_FAILURE_ACTIONS, (LPVOID)&recoveryInfo);
|
|
|
|
CloseServiceHandle(hSvc);
|
|
CloseServiceHandle(hSCMgr);
|
|
}
|
|
|
|
//+----------------------------------------------------------------------------
|
|
//
|
|
// Function: ErrorDialog
|
|
//
|
|
// Synopsis: Displays an error message.
|
|
//
|
|
//-----------------------------------------------------------------------------
|
|
void
|
|
ErrorDialog(UINT ErrorFmtStringID, TCHAR * szRoutine, DWORD ErrorCode)
|
|
{
|
|
#define ERROR_BUFFER_SIZE (MAX_PATH * 2)
|
|
|
|
TCHAR szErrorFmt[MAX_PATH + 1] = TEXT("");
|
|
TCHAR szError[ERROR_BUFFER_SIZE + 1];
|
|
TCHAR * pszError = szError;
|
|
|
|
LoadString(ghInstance, ErrorFmtStringID, szErrorFmt, MAX_PATH);
|
|
|
|
if (*szErrorFmt)
|
|
{
|
|
StringCchPrintf(szError, ERROR_BUFFER_SIZE + 1, szErrorFmt, szRoutine, ErrorCode);
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// Not a localizable string, but done just in case LoadString
|
|
// should fail for some reason.
|
|
//
|
|
|
|
StringCchCopy(szErrorFmt, MAX_PATH + 1, TEXT("Error installing Task Scheduler; error = 0x%x"));
|
|
StringCchPrintf(szError, ERROR_BUFFER_SIZE + 1, szErrorFmt, ErrorCode);
|
|
}
|
|
|
|
MessageBox(NULL, szError, NULL, MB_ICONSTOP | MB_OK);
|
|
}
|
|
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Function: SetTaskFolderSecurity
|
|
//
|
|
// Synopsis: Grant the following permissions to the task folder:
|
|
//
|
|
// LocalSystem All Access.
|
|
// Domain Administrators All Access.
|
|
// World RWX Access (no permission to delete
|
|
// child files).
|
|
//
|
|
// Arguments: [pwszFolderPath] -- Task folder path.
|
|
//
|
|
// Notes: None.
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
DWORD
|
|
SetTaskFolderSecurity(LPCWSTR pwszFolderPath)
|
|
{
|
|
DWORD dwError = ERROR_SUCCESS;
|
|
BOOL bSuccess;
|
|
BOOL bWasEnabled = FALSE;
|
|
BOOL bSetSacl = TRUE;
|
|
PSECURITY_DESCRIPTOR pSecurityDescriptor = 0;
|
|
DWORD i;
|
|
SECURITY_INFORMATION dwSecInfo = 0;
|
|
|
|
const DWORD c_dwBaseSidCount = 6;
|
|
const DWORD c_dwDomainSidCount = 3;
|
|
const DWORD c_dwDaclAceCountSrv = 5;
|
|
const DWORD c_dwDaclAceCountWks = 4;
|
|
const DWORD c_dwSaclAceCount = 2;
|
|
|
|
|
|
//
|
|
// Build the SIDs that will go in the security descriptor.
|
|
//
|
|
|
|
SID_IDENTIFIER_AUTHORITY NtAuth = SECURITY_NT_AUTHORITY;
|
|
SID_IDENTIFIER_AUTHORITY WorldAuth = SECURITY_WORLD_SID_AUTHORITY;
|
|
SID_IDENTIFIER_AUTHORITY CreatorAuth = SECURITY_CREATOR_SID_AUTHORITY;
|
|
|
|
MYSIDINFO rgBaseSidInfo[c_dwBaseSidCount] =
|
|
{
|
|
{
|
|
&NtAuth, // Local System.
|
|
SECURITY_LOCAL_SYSTEM_RID,
|
|
NULL
|
|
},
|
|
{
|
|
&NtAuth, // Built in domain. (Used for
|
|
SECURITY_BUILTIN_DOMAIN_RID, // domain admins SID.)
|
|
NULL
|
|
},
|
|
{
|
|
&NtAuth, // Authenticated user.
|
|
SECURITY_AUTHENTICATED_USER_RID,
|
|
NULL
|
|
},
|
|
{
|
|
&CreatorAuth, // Creator.
|
|
SECURITY_CREATOR_OWNER_RID,
|
|
NULL
|
|
},
|
|
{
|
|
&WorldAuth, // Everyone.
|
|
SECURITY_WORLD_RID,
|
|
NULL
|
|
},
|
|
{
|
|
&NtAuth, // Anonymous.
|
|
SECURITY_ANONYMOUS_LOGON_RID,
|
|
NULL
|
|
},
|
|
|
|
|
|
};
|
|
|
|
MYSIDINFO rgDomainSidInfo[c_dwDomainSidCount] =
|
|
{
|
|
{
|
|
NULL, // Domain administrators.
|
|
DOMAIN_ALIAS_RID_ADMINS,
|
|
NULL
|
|
},
|
|
{
|
|
NULL, // Server Operators.
|
|
DOMAIN_ALIAS_RID_SYSTEM_OPS,
|
|
NULL
|
|
},
|
|
{
|
|
NULL, // Backup Operators.
|
|
DOMAIN_ALIAS_RID_BACKUP_OPS,
|
|
NULL
|
|
}
|
|
};
|
|
|
|
|
|
//
|
|
// Create the base SIDs.
|
|
//
|
|
|
|
for (i = 0; i < c_dwBaseSidCount; i++)
|
|
{
|
|
if (!AllocateAndInitializeSid(
|
|
rgBaseSidInfo[i].pIdentifierAuthority,
|
|
1,
|
|
rgBaseSidInfo[i].dwSubAuthority,
|
|
0, 0, 0, 0, 0, 0, 0,
|
|
&rgBaseSidInfo[i].pSid))
|
|
{
|
|
dwError = GetLastError();
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (dwError == ERROR_SUCCESS)
|
|
{
|
|
//
|
|
// Create the domain SIDs.
|
|
//
|
|
|
|
for (i = 0; i < c_dwDomainSidCount; i++)
|
|
{
|
|
dwError = AllocateAndInitializeDomainSid(
|
|
rgBaseSidInfo[1].pSid,
|
|
&rgDomainSidInfo[i]);
|
|
|
|
if (dwError != ERROR_SUCCESS)
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
//
|
|
// Create the security descriptor.
|
|
//
|
|
|
|
ACE_DESC rgDaclAcesSrv[c_dwDaclAceCountSrv] =
|
|
{
|
|
{
|
|
FILE_ALL_ACCESS,
|
|
ACCESS_ALLOWED_ACE_TYPE,
|
|
OBJECT_INHERIT_ACE | CONTAINER_INHERIT_ACE,
|
|
rgBaseSidInfo[0].pSid // Local System
|
|
},
|
|
{
|
|
FILE_ALL_ACCESS,
|
|
ACCESS_ALLOWED_ACE_TYPE,
|
|
OBJECT_INHERIT_ACE | CONTAINER_INHERIT_ACE,
|
|
rgDomainSidInfo[0].pSid // Domain admins
|
|
},
|
|
{
|
|
FILE_GENERIC_READ | FILE_GENERIC_EXECUTE | FILE_WRITE_DATA,
|
|
ACCESS_ALLOWED_ACE_TYPE,
|
|
0,
|
|
rgDomainSidInfo[1].pSid // Backup Operators
|
|
},
|
|
{
|
|
FILE_GENERIC_READ | FILE_GENERIC_EXECUTE | FILE_WRITE_DATA,
|
|
ACCESS_ALLOWED_ACE_TYPE,
|
|
0,
|
|
rgDomainSidInfo[2].pSid // Server Operators
|
|
},
|
|
{
|
|
FILE_ALL_ACCESS,
|
|
ACCESS_ALLOWED_ACE_TYPE,
|
|
OBJECT_INHERIT_ACE | CONTAINER_INHERIT_ACE | INHERIT_ONLY_ACE,
|
|
rgBaseSidInfo[3].pSid // Creator
|
|
}
|
|
};
|
|
|
|
ACE_DESC rgDaclAcesWks[c_dwDaclAceCountWks] =
|
|
{
|
|
{
|
|
FILE_ALL_ACCESS,
|
|
ACCESS_ALLOWED_ACE_TYPE,
|
|
OBJECT_INHERIT_ACE | CONTAINER_INHERIT_ACE,
|
|
rgBaseSidInfo[0].pSid // Local System
|
|
},
|
|
{
|
|
FILE_ALL_ACCESS,
|
|
ACCESS_ALLOWED_ACE_TYPE,
|
|
OBJECT_INHERIT_ACE | CONTAINER_INHERIT_ACE,
|
|
rgDomainSidInfo[0].pSid // Domain admins
|
|
},
|
|
{
|
|
FILE_GENERIC_READ | FILE_GENERIC_EXECUTE | FILE_WRITE_DATA,
|
|
ACCESS_ALLOWED_ACE_TYPE,
|
|
0,
|
|
rgBaseSidInfo[2].pSid // Authenticated user
|
|
},
|
|
{
|
|
FILE_ALL_ACCESS,
|
|
ACCESS_ALLOWED_ACE_TYPE,
|
|
OBJECT_INHERIT_ACE | CONTAINER_INHERIT_ACE | INHERIT_ONLY_ACE,
|
|
rgBaseSidInfo[3].pSid // Creator
|
|
}
|
|
};
|
|
|
|
ACE_DESC rgSaclAces[c_dwSaclAceCount] =
|
|
{
|
|
{
|
|
FILE_WRITE_DATA | FILE_APPEND_DATA | FILE_DELETE_CHILD | DELETE | WRITE_DAC | WRITE_OWNER,
|
|
SYSTEM_AUDIT_ACE_TYPE,
|
|
SUCCESSFUL_ACCESS_ACE_FLAG | FAILED_ACCESS_ACE_FLAG | OBJECT_INHERIT_ACE | CONTAINER_INHERIT_ACE,
|
|
rgBaseSidInfo[4].pSid // Everyone
|
|
},
|
|
{
|
|
FILE_WRITE_DATA | FILE_APPEND_DATA | FILE_DELETE_CHILD | DELETE | WRITE_DAC | WRITE_OWNER,
|
|
SYSTEM_AUDIT_ACE_TYPE,
|
|
SUCCESSFUL_ACCESS_ACE_FLAG | FAILED_ACCESS_ACE_FLAG | OBJECT_INHERIT_ACE | CONTAINER_INHERIT_ACE,
|
|
rgBaseSidInfo[5].pSid // Anonymous
|
|
}
|
|
};
|
|
|
|
if (dwError != ERROR_SUCCESS)
|
|
{
|
|
goto Cleanup;
|
|
}
|
|
|
|
// different security on workstation vs server
|
|
|
|
OSVERSIONINFOEX verInfo;
|
|
verInfo.dwOSVersionInfoSize = sizeof(OSVERSIONINFOEX);
|
|
if (!GetVersionEx((LPOSVERSIONINFOW)&verInfo))
|
|
{
|
|
dwError = ERROR_NOT_SUPPORTED;
|
|
goto Cleanup;
|
|
}
|
|
|
|
|
|
if (verInfo.wProductType == VER_NT_WORKSTATION)
|
|
{
|
|
|
|
dwError = CreateSecurityDescriptor(
|
|
&pSecurityDescriptor,
|
|
c_dwDaclAceCountWks,
|
|
rgDaclAcesWks,
|
|
c_dwSaclAceCount,
|
|
rgSaclAces);
|
|
|
|
if (dwError != ERROR_SUCCESS)
|
|
{
|
|
goto Cleanup;
|
|
}
|
|
|
|
}
|
|
else
|
|
{
|
|
dwError = CreateSecurityDescriptor(
|
|
&pSecurityDescriptor,
|
|
c_dwDaclAceCountSrv,
|
|
rgDaclAcesSrv,
|
|
c_dwSaclAceCount,
|
|
rgSaclAces);
|
|
|
|
if (dwError != ERROR_SUCCESS)
|
|
{
|
|
goto Cleanup;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
//
|
|
// Enable SecurityPrivilege in order to be able
|
|
// to set the SACL.
|
|
//
|
|
|
|
dwError = EnablePrivilege(
|
|
SE_SECURITY_NAME,
|
|
TRUE,
|
|
&bWasEnabled);
|
|
|
|
if (dwError != ERROR_SUCCESS)
|
|
{
|
|
bSetSacl = FALSE;
|
|
}
|
|
|
|
|
|
//
|
|
// Finally, set permissions.
|
|
//
|
|
|
|
dwSecInfo |= DACL_SECURITY_INFORMATION;
|
|
|
|
if (bSetSacl && c_dwSaclAceCount)
|
|
{
|
|
dwSecInfo |= SACL_SECURITY_INFORMATION;
|
|
}
|
|
|
|
bSuccess = SetFileSecurity(
|
|
pwszFolderPath,
|
|
dwSecInfo,
|
|
pSecurityDescriptor);
|
|
|
|
|
|
|
|
if (!bWasEnabled)
|
|
{
|
|
EnablePrivilege(
|
|
SE_SECURITY_NAME,
|
|
FALSE,
|
|
0);
|
|
}
|
|
|
|
|
|
|
|
if (!bSuccess)
|
|
{
|
|
dwError = GetLastError();
|
|
goto Cleanup;
|
|
}
|
|
|
|
dwError = ERROR_SUCCESS;
|
|
|
|
Cleanup:
|
|
|
|
for (i = 0; i < c_dwBaseSidCount; i++)
|
|
{
|
|
if (rgBaseSidInfo[i].pSid != NULL)
|
|
{
|
|
FreeSid(rgBaseSidInfo[i].pSid);
|
|
}
|
|
}
|
|
for (i = 0; i < c_dwDomainSidCount; i++)
|
|
{
|
|
LocalFree(rgDomainSidInfo[i].pSid);
|
|
}
|
|
if (pSecurityDescriptor != NULL)
|
|
{
|
|
DeleteSecurityDescriptor(pSecurityDescriptor);
|
|
}
|
|
|
|
return dwError;
|
|
}
|
|
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Function: AllocateAndInitializeDomainSid
|
|
//
|
|
// Synopsis:
|
|
//
|
|
// Arguments: [pDomainSid] --
|
|
// [pDomainSidInfo] --
|
|
//
|
|
// Notes: None.
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
DWORD
|
|
AllocateAndInitializeDomainSid(
|
|
PSID pDomainSid,
|
|
MYSIDINFO * pDomainSidInfo)
|
|
{
|
|
UCHAR DomainIdSubAuthorityCount;
|
|
DWORD SidLength;
|
|
|
|
//
|
|
// Allocate a Sid which has one more sub-authority than the domain ID.
|
|
//
|
|
|
|
DomainIdSubAuthorityCount = *(GetSidSubAuthorityCount(pDomainSid));
|
|
SidLength = GetSidLengthRequired(DomainIdSubAuthorityCount + 1);
|
|
|
|
pDomainSidInfo->pSid = (PSID) LocalAlloc(0, SidLength);
|
|
|
|
if (pDomainSidInfo->pSid == NULL)
|
|
{
|
|
return(ERROR_NOT_ENOUGH_MEMORY);
|
|
}
|
|
|
|
//
|
|
// Initialize the new SID to have the same initial value as the
|
|
// domain ID.
|
|
//
|
|
|
|
if (!CopySid(SidLength, pDomainSidInfo->pSid, pDomainSid))
|
|
{
|
|
LocalFree(pDomainSidInfo->pSid);
|
|
pDomainSidInfo->pSid = NULL;
|
|
return(GetLastError());
|
|
}
|
|
|
|
//
|
|
// Adjust the sub-authority count and add the relative Id unique
|
|
// to the newly allocated SID
|
|
//
|
|
|
|
(*(GetSidSubAuthorityCount(pDomainSidInfo->pSid)))++;
|
|
*(GetSidSubAuthority(pDomainSidInfo->pSid,
|
|
DomainIdSubAuthorityCount)) =
|
|
pDomainSidInfo->dwSubAuthority;
|
|
|
|
return(ERROR_SUCCESS);
|
|
}
|
|
|