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.
8648 lines
212 KiB
8648 lines
212 KiB
/*++
|
|
|
|
Copyright (c) 1996 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
server.cpp
|
|
|
|
Abstract:
|
|
|
|
Server (main) module
|
|
|
|
Author:
|
|
|
|
Jin Huang (jinhuang) 28-Jan-1998
|
|
|
|
Revision History:
|
|
|
|
--*/
|
|
#include "serverp.h"
|
|
#include "service.h"
|
|
#include "ntrpcp.h"
|
|
#include "pfp.h"
|
|
#include "infp.h"
|
|
#include "sceutil.h"
|
|
#include "queue.h"
|
|
#include <io.h>
|
|
#include <lm.h>
|
|
#include <lmapibuf.h>
|
|
//
|
|
// thread global variables
|
|
//
|
|
|
|
DWORD Thread gCurrentTicks=0;
|
|
DWORD Thread gTotalTicks=0;
|
|
BYTE Thread cbClientFlag=0;
|
|
DWORD Thread gWarningCode=0;
|
|
BOOL Thread gbInvalidData=FALSE;
|
|
BOOL Thread bLogOn=TRUE;
|
|
INT Thread gDebugLevel=-1;
|
|
|
|
extern DWORD gdwMaxPDCWait;
|
|
extern DWORD gdwPDCRetry;
|
|
extern DWORD gdwRequirePDCSync;
|
|
extern BOOL gbCheckSync;
|
|
|
|
NT_PRODUCT_TYPE Thread ProductType=NtProductWinNt;
|
|
PSID Thread AdminsSid=NULL;
|
|
|
|
extern DWORD Thread t_pebSize;
|
|
extern LPVOID Thread t_pebClient;
|
|
extern LSA_HANDLE Thread LsaPrivatePolicy;
|
|
extern HINSTANCE MyModuleHandle;
|
|
|
|
static PPOLICY_DNS_DOMAIN_INFO DnsDomainInfo=NULL;
|
|
static BOOL gbSystemShutdown=FALSE;
|
|
static HANDLE hTimerQueue=NULL;
|
|
|
|
//
|
|
// database context list to keep tracking all client requested context
|
|
// so that they can be freed properly.
|
|
// if yes, we do not need to do this.
|
|
//
|
|
|
|
typedef struct _SCESRV_CONTEXT_LIST_ {
|
|
|
|
PSCECONTEXT Context;
|
|
struct _SCESRV_CONTEXT_LIST_ *Next;
|
|
struct _SCESRV_CONTEXT_LIST_ *Prior;
|
|
|
|
} SCESRV_CONTEXT_LIST, *PSCESRV_CONTEXT_LIST;
|
|
|
|
static PSCESRV_CONTEXT_LIST pOpenContexts=NULL;
|
|
static CRITICAL_SECTION ContextSync;
|
|
|
|
//
|
|
// database task list to control simultaneous database operations under
|
|
// the same context (jet session)
|
|
//
|
|
|
|
typedef struct _SCESRV_DBTASK_ {
|
|
|
|
PSCECONTEXT Context;
|
|
CRITICAL_SECTION Sync;
|
|
DWORD dInUsed;
|
|
BOOL bCloseReq;
|
|
struct _SCESRV_DBTASK_ *Next;
|
|
struct _SCESRV_DBTASK_ *Prior;
|
|
|
|
} SCESRV_DBTASK, *PSCESRV_DBTASK;
|
|
|
|
static PSCESRV_DBTASK pDbTask=NULL;
|
|
static CRITICAL_SECTION TaskSync;
|
|
|
|
#define SCE_TASK_LOCK 0x01L
|
|
#define SCE_TASK_CLOSE 0x02L
|
|
|
|
//
|
|
// engine task list to control simultaneous configuration/analysis engines
|
|
//
|
|
|
|
typedef struct _SCESRV_ENGINE_ {
|
|
|
|
LPTSTR Database;
|
|
struct _SCESRV_ENGINE_ *Next;
|
|
struct _SCESRV_ENGINE_ *Prior;
|
|
|
|
} SCESRV_ENGINE, *PSCESRV_ENGINE;
|
|
|
|
static PSCESRV_ENGINE pEngines=NULL;
|
|
static CRITICAL_SECTION EngSync;
|
|
|
|
//
|
|
// jet enigne synchronization
|
|
//
|
|
|
|
CRITICAL_SECTION JetSync;
|
|
|
|
//
|
|
// flag for stop request
|
|
//
|
|
static BOOL bStopRequest=FALSE;
|
|
static BOOL bDbStopped=FALSE;
|
|
static BOOL bEngStopped=FALSE;
|
|
|
|
static CRITICAL_SECTION RpcSync;
|
|
static BOOL RpcStarted = FALSE;
|
|
static BOOL ServerInited = FALSE;
|
|
|
|
static CRITICAL_SECTION CloseSync;
|
|
|
|
static HINSTANCE hSceCliDll=NULL;
|
|
static PFSCEINFWRITEINFO pfSceInfWriteInfo=NULL;
|
|
static PFSCEGETINFO pfSceGetInfo=NULL;
|
|
|
|
extern PSCESRV_POLQUEUE pNotificationQHead;
|
|
#define SCE_POLICY_MAX_WAIT 24
|
|
static DWORD gPolicyWaitCount=0;
|
|
|
|
#define SERVICE_SAMSS TEXT("SamSS")
|
|
|
|
SCESTATUS
|
|
ScepGenerateAttachmentSections(
|
|
IN PSCECONTEXT hProfile,
|
|
IN SCESVC_INFO_TYPE InfoType,
|
|
IN LPTSTR InfFileName,
|
|
IN SCE_ATTACHMENT_TYPE aType
|
|
);
|
|
|
|
SCESTATUS
|
|
ScepGenerateWMIAttachmentSections(
|
|
IN PSCECONTEXT hProfile,
|
|
IN SCESVC_INFO_TYPE InfoType,
|
|
IN LPTSTR InfFileName
|
|
);
|
|
|
|
SCESTATUS
|
|
ScepGenerateOneAttachmentSection(
|
|
IN PSCECONTEXT hProfile,
|
|
IN SCESVC_INFO_TYPE InfoType,
|
|
IN LPTSTR InfFileName,
|
|
IN LPTSTR SectionName,
|
|
IN BOOL bWMISection
|
|
);
|
|
|
|
VOID
|
|
ScepWaitForSamSS(
|
|
IN PVOID pContext
|
|
);
|
|
|
|
SCESTATUS
|
|
ScepConvertServices(
|
|
IN OUT PVOID *ppServices,
|
|
IN BOOL bSRForm
|
|
);
|
|
|
|
SCESTATUS
|
|
ScepFreeConvertedServices(
|
|
IN PVOID pServices,
|
|
IN BOOL bSRForm
|
|
);
|
|
|
|
DWORD
|
|
ScepConfigureConvertedFileSecurityImmediate(
|
|
IN PWSTR pszDriveName
|
|
);
|
|
|
|
DWORD
|
|
ScepWaitForSynchronizeWithPDC(
|
|
IN UNICODE_STRING DnsDomainName,
|
|
IN PWSTR LocalTemplateName,
|
|
OUT BOOL *pbTimeout
|
|
);
|
|
|
|
DWORD
|
|
ScepVerifyPDCRole(
|
|
IN PWSTR pComputerName,
|
|
OUT BOOL *pbIsPDC
|
|
);
|
|
|
|
////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// Server Control APIs
|
|
//
|
|
////////////////////////////////////////////////////////////////////////
|
|
|
|
VOID
|
|
ScepInitServerData()
|
|
/*
|
|
Routine Description:
|
|
|
|
Initialize global data for the server
|
|
|
|
Arguments:
|
|
|
|
None
|
|
|
|
Return Value:
|
|
|
|
None
|
|
*/
|
|
{
|
|
//
|
|
// initialize RPC server controls
|
|
//
|
|
|
|
InitializeCriticalSection(&RpcSync);
|
|
RpcStarted = FALSE;
|
|
ServerInited = FALSE;
|
|
//
|
|
// flag to indicate if the server is requested to stop.
|
|
//
|
|
bStopRequest = TRUE; // will be reset when server is started up so this will
|
|
// block all RPC calls before server is ready
|
|
|
|
//
|
|
// database operation pending tasks control
|
|
//
|
|
pDbTask=NULL;
|
|
InitializeCriticalSection(&TaskSync);
|
|
|
|
//
|
|
// configuration/analysis engine task control
|
|
//
|
|
pEngines=NULL;
|
|
InitializeCriticalSection(&EngSync);
|
|
|
|
//
|
|
// should also remember all created database context so that
|
|
// resource can be freed when server is shutting down
|
|
//
|
|
|
|
InitializeCriticalSection(&CloseSync);
|
|
|
|
pOpenContexts = NULL;
|
|
InitializeCriticalSection(&ContextSync);
|
|
|
|
bEngStopped = FALSE;
|
|
bDbStopped = FALSE;
|
|
|
|
//
|
|
// jet engine synchronization
|
|
//
|
|
InitializeCriticalSection(&JetSync);
|
|
|
|
//
|
|
// initialize jet engine globals
|
|
//
|
|
SceJetInitializeData();
|
|
|
|
//
|
|
// initialize queue related stuff
|
|
//
|
|
ScepNotificationQInitialize();
|
|
|
|
return;
|
|
}
|
|
|
|
|
|
VOID
|
|
ScepUninitServerData()
|
|
/*
|
|
Routine Description:
|
|
|
|
UnInitialize global data for the server
|
|
|
|
Arguments:
|
|
|
|
None
|
|
|
|
Return Value:
|
|
|
|
None
|
|
*/
|
|
{
|
|
//
|
|
// delete the critical sections
|
|
//
|
|
|
|
DeleteCriticalSection(&RpcSync);
|
|
|
|
DeleteCriticalSection(&TaskSync);
|
|
|
|
DeleteCriticalSection(&EngSync);
|
|
|
|
DeleteCriticalSection(&CloseSync);
|
|
|
|
DeleteCriticalSection(&ContextSync);
|
|
|
|
DeleteCriticalSection(&JetSync);
|
|
|
|
return;
|
|
}
|
|
|
|
|
|
NTSTATUS
|
|
ScepStartServerServices()
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
It starts the server services.
|
|
|
|
Arguments:
|
|
|
|
None.
|
|
|
|
Return Value:
|
|
|
|
NT status.
|
|
|
|
--*/
|
|
{
|
|
NTSTATUS Status = STATUS_SUCCESS;
|
|
RPC_STATUS RpcStatus;
|
|
|
|
//
|
|
// start RPC server
|
|
//
|
|
|
|
EnterCriticalSection(&RpcSync);
|
|
|
|
if ( !RpcStarted ) {
|
|
|
|
//
|
|
// use secure RPC
|
|
//
|
|
Status = RpcServerRegisterAuthInfo(
|
|
NULL,
|
|
RPC_C_AUTHN_WINNT,
|
|
NULL,
|
|
NULL
|
|
);
|
|
|
|
if ( NT_SUCCESS(Status) ) {
|
|
|
|
RpcStatus = RpcpAddInterface( L"scerpc",
|
|
scerpc_ServerIfHandle);
|
|
|
|
if ( RpcStatus != RPC_S_OK ) {
|
|
//
|
|
// can't add RPC interface
|
|
//
|
|
Status = I_RpcMapWin32Status(RpcStatus);
|
|
|
|
} else {
|
|
|
|
//
|
|
// The first argument specifies the minimum number of threads to
|
|
// be created to handle calls; the second argument specifies the
|
|
// maximum number of concurrent calls allowed. The last argument
|
|
// indicates not to wait.
|
|
//
|
|
|
|
RpcStatus = RpcServerListen(1,12345, 1);
|
|
|
|
if ( RpcStatus == RPC_S_ALREADY_LISTENING ) {
|
|
RpcStatus = RPC_S_OK;
|
|
}
|
|
|
|
Status = I_RpcMapWin32Status(RpcStatus);
|
|
|
|
if ( RpcStatus == RPC_S_OK ) {
|
|
RpcStarted = TRUE;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if ( NT_SUCCESS(Status) ) {
|
|
|
|
//
|
|
// RPC server started
|
|
// jet engine will be initialized when a database call comes in
|
|
//
|
|
|
|
intptr_t hFile;
|
|
struct _wfinddata_t FileInfo;
|
|
|
|
PWSTR szCompLog=NULL, szCompSav=NULL;
|
|
|
|
SafeAllocaAllocate(szCompLog, (MAX_PATH+50)*sizeof(WCHAR));
|
|
SafeAllocaAllocate(szCompSav, (MAX_PATH*2+20)*sizeof(WCHAR));
|
|
|
|
//
|
|
// delete the component log file
|
|
//
|
|
|
|
if ( szCompLog && szCompSav ) {
|
|
|
|
szCompLog[0] = L'\0';
|
|
GetSystemWindowsDirectory(szCompLog, MAX_PATH);
|
|
szCompLog[MAX_PATH-1] = L'\0';
|
|
|
|
DWORD WindirLen = wcslen(szCompLog);
|
|
|
|
wcscpy(szCompSav, szCompLog);
|
|
|
|
wcscat(szCompLog, L"\\security\\logs\\scecomp.log\0");
|
|
wcscat(szCompSav, L"\\security\\logs\\scecomp.old\0");
|
|
|
|
CopyFile(szCompLog, szCompSav, FALSE);
|
|
|
|
DeleteFile(szCompLog);
|
|
|
|
//
|
|
// clean up temp files
|
|
//
|
|
|
|
wcscpy(szCompLog+WindirLen, L"\\security\\sce*.tmp");
|
|
|
|
|
|
hFile = _wfindfirst(szCompLog, &FileInfo);
|
|
|
|
if ( hFile != -1 ) {
|
|
|
|
do {
|
|
|
|
wcscpy(szCompSav+WindirLen, L"\\security\\");
|
|
wcscat(szCompSav, FileInfo.name);
|
|
|
|
DeleteFile(szCompSav);
|
|
|
|
} while ( _wfindnext(hFile, &FileInfo) == 0 );
|
|
|
|
_findclose(hFile);
|
|
}
|
|
|
|
//
|
|
// reset the stop request flag
|
|
//
|
|
|
|
bEngStopped = FALSE;
|
|
bDbStopped = FALSE;
|
|
bStopRequest = FALSE;
|
|
|
|
} else {
|
|
Status = STATUS_NO_MEMORY;
|
|
}
|
|
|
|
SafeAllocaFree(szCompLog);
|
|
SafeAllocaFree(szCompSav);
|
|
}
|
|
|
|
pEngines = NULL;
|
|
pOpenContexts = NULL;
|
|
pDbTask = NULL;
|
|
|
|
//
|
|
// start a system thread to handle notifications
|
|
// if the thread can't be started, return failure to services.exe
|
|
// which will reboot.
|
|
//
|
|
if ( NT_SUCCESS(Status) ) {
|
|
Status = ScepQueueStartSystemThread();
|
|
}
|
|
|
|
LeaveCriticalSection(&RpcSync);
|
|
|
|
if ( NT_SUCCESS(Status) ) {
|
|
//
|
|
// launch a worker thread to wait for SAMSS service
|
|
// the only failure case would be out of memory, in which case,
|
|
// return the error to initialize code (to shutdown the system).
|
|
//
|
|
Status = RtlQueueWorkItem(
|
|
ScepWaitForSamSS,
|
|
NULL,
|
|
WT_EXECUTEONLYONCE | WT_EXECUTELONGFUNCTION
|
|
) ;
|
|
}
|
|
|
|
return(Status);
|
|
}
|
|
|
|
VOID
|
|
ScepWaitForSamSS(
|
|
IN PVOID pContext
|
|
)
|
|
{
|
|
//
|
|
// make sure this function handles server temination
|
|
// If for some reason, the wait times out, set ServerInited to TRUE
|
|
// and let RPC threads continue to perform the task (and may fail later on)
|
|
//
|
|
|
|
DWORD rc = ERROR_SUCCESS;
|
|
SC_HANDLE ScManagerHandle = NULL;
|
|
SC_HANDLE ServiceHandle = NULL;
|
|
ULONG Timeout;
|
|
ULONG TimeSleep;
|
|
SERVICE_STATUS ServiceStatus;
|
|
|
|
Timeout = 600; // 600 second timeout
|
|
|
|
//
|
|
// Open a handle to the Netlogon Service.
|
|
//
|
|
|
|
ScManagerHandle = OpenSCManager(
|
|
NULL,
|
|
NULL,
|
|
SC_MANAGER_CONNECT );
|
|
|
|
if (ScManagerHandle == NULL) {
|
|
rc = ERROR_NOT_SUPPORTED;
|
|
goto Cleanup;
|
|
}
|
|
|
|
ServiceHandle = OpenService(
|
|
ScManagerHandle,
|
|
SERVICE_SAMSS,
|
|
SERVICE_QUERY_STATUS );
|
|
|
|
if ( ServiceHandle == NULL ) {
|
|
rc = ERROR_NOT_SUPPORTED;
|
|
goto Cleanup;
|
|
}
|
|
|
|
//
|
|
// Loop waiting for the SamSS service to start.
|
|
//
|
|
|
|
for (;;) {
|
|
|
|
//
|
|
// Query the status of the SamSS service.
|
|
//
|
|
if (! QueryServiceStatus( ServiceHandle, &ServiceStatus )) {
|
|
|
|
rc = GetLastError();
|
|
goto Cleanup;
|
|
}
|
|
|
|
//
|
|
// Return or continue waiting depending on the state of
|
|
// the netlogon service.
|
|
//
|
|
|
|
switch( ServiceStatus.dwCurrentState) {
|
|
case SERVICE_RUNNING:
|
|
rc = ERROR_SUCCESS;
|
|
ServerInited = TRUE;
|
|
goto Cleanup;
|
|
|
|
case SERVICE_STOPPED:
|
|
|
|
//
|
|
// If Netlogon failed to start,
|
|
// error out now. The caller has waited long enough to start.
|
|
//
|
|
if ( ServiceStatus.dwWin32ExitCode != ERROR_SERVICE_NEVER_STARTED ){
|
|
rc = ERROR_NOT_SUPPORTED;
|
|
goto Cleanup;
|
|
}
|
|
|
|
//
|
|
// If SamSs has never been started on this boot,
|
|
// continue waiting for it to start.
|
|
//
|
|
|
|
break;
|
|
|
|
//
|
|
// If SamSS is trying to start up now,
|
|
// continue waiting for it to start.
|
|
//
|
|
case SERVICE_START_PENDING:
|
|
break;
|
|
|
|
//
|
|
// Any other state is bogus.
|
|
//
|
|
default:
|
|
rc = ERROR_NOT_SUPPORTED;
|
|
goto Cleanup;
|
|
|
|
}
|
|
|
|
//
|
|
// if server is shutting down, break this loop
|
|
//
|
|
|
|
if ( bStopRequest ) {
|
|
break;
|
|
}
|
|
|
|
//
|
|
// sleep for ten seconds;
|
|
//
|
|
if ( Timeout > 5 ) {
|
|
TimeSleep = 5;
|
|
} else {
|
|
TimeSleep = Timeout;
|
|
}
|
|
|
|
Sleep(TimeSleep*1000);
|
|
|
|
Timeout -= TimeSleep;
|
|
|
|
if ( Timeout == 0 ) {
|
|
rc = ERROR_NOT_SUPPORTED;
|
|
goto Cleanup;
|
|
}
|
|
|
|
}
|
|
|
|
ServerInited = TRUE;
|
|
|
|
Cleanup:
|
|
if ( ScManagerHandle != NULL ) {
|
|
(VOID) CloseServiceHandle(ScManagerHandle);
|
|
}
|
|
if ( ServiceHandle != NULL ) {
|
|
(VOID) CloseServiceHandle(ServiceHandle);
|
|
}
|
|
|
|
if ( ERROR_SUCCESS != rc ) {
|
|
|
|
//
|
|
// even if it failed to wait for SAMSS service
|
|
// still set the init flag to let RPC threads go through
|
|
// after sleep for the timeout
|
|
//
|
|
|
|
if ( Timeout > 0 ) {
|
|
Sleep(Timeout*1000); // timeout second
|
|
}
|
|
|
|
ServerInited = TRUE;
|
|
}
|
|
|
|
}
|
|
|
|
|
|
NTSTATUS
|
|
ScepStopServerServices(
|
|
IN BOOL bShutDown
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
It stops the server services. This include:
|
|
Blocking all new RPC requests
|
|
Stop RPC server
|
|
wait for all active database operations to finish
|
|
Close all context handles
|
|
Terminate jet engine
|
|
|
|
Arguments:
|
|
|
|
bShutdown - if the server is shutting down.
|
|
|
|
Return Value:
|
|
|
|
NT status.
|
|
|
|
--*/
|
|
{
|
|
NTSTATUS Status=STATUS_SUCCESS;
|
|
RPC_STATUS RpcStatus;
|
|
LARGE_INTEGER StartTime;
|
|
LARGE_INTEGER CurrentTime;
|
|
DWORD dStartSeconds;
|
|
DWORD dCurrentSeconds;
|
|
|
|
//
|
|
// no need to critical section this one because there
|
|
// should be only one writer to this variable and I
|
|
// don't care the readers
|
|
//
|
|
gbSystemShutdown = bShutDown;
|
|
|
|
EnterCriticalSection(&RpcSync);
|
|
|
|
//
|
|
// block new RPC requests
|
|
//
|
|
|
|
bStopRequest = TRUE;
|
|
|
|
ScepServerCancelTimer();
|
|
|
|
//
|
|
// stop RPC server
|
|
//
|
|
|
|
if ( RpcStarted ) {
|
|
|
|
//
|
|
// use secure RPC
|
|
//
|
|
RpcStatus = RpcServerUnregisterIf(scerpc_ServerIfHandle,
|
|
0,
|
|
1);
|
|
|
|
if ( RpcStatus == RPC_S_OK ) {
|
|
|
|
RpcStatus = RpcMgmtStopServerListening(NULL);
|
|
}
|
|
|
|
if ( RpcStatus == RPC_S_OK ) {
|
|
|
|
RpcStatus = RpcMgmtWaitServerListen();
|
|
}
|
|
|
|
Status = I_RpcMapWin32Status(RpcStatus);
|
|
|
|
if ( RpcStatus == RPC_S_OK ) {
|
|
//
|
|
// reset the flag
|
|
//
|
|
RpcStarted = FALSE;
|
|
}
|
|
}
|
|
|
|
// db task
|
|
EnterCriticalSection(&TaskSync);
|
|
|
|
if ( pDbTask ) {
|
|
|
|
bDbStopped = FALSE;
|
|
LeaveCriticalSection(&TaskSync);
|
|
|
|
NtQuerySystemTime(&StartTime);
|
|
RtlTimeToSecondsSince1980 (&StartTime, &dStartSeconds);
|
|
|
|
while ( !bDbStopped ) {
|
|
//
|
|
// wait until remove task routine removes everything
|
|
// wait maximum 1 minutes in case some tasks are dead or looping
|
|
//
|
|
NtQuerySystemTime(&CurrentTime);
|
|
RtlTimeToSecondsSince1980 (&CurrentTime, &dCurrentSeconds);
|
|
|
|
if ( dCurrentSeconds - dStartSeconds > 60 ) {
|
|
//
|
|
// too long, break it
|
|
//
|
|
break;
|
|
}
|
|
}
|
|
|
|
} else {
|
|
//
|
|
// new tasks are already blocked by bStopRequest
|
|
// so pDbTask won't be !NULL again
|
|
//
|
|
LeaveCriticalSection(&TaskSync);
|
|
}
|
|
|
|
// engine task
|
|
EnterCriticalSection(&EngSync);
|
|
|
|
if ( pEngines ) {
|
|
|
|
bEngStopped = FALSE;
|
|
LeaveCriticalSection(&EngSync);
|
|
|
|
NtQuerySystemTime(&StartTime);
|
|
RtlTimeToSecondsSince1980 (&StartTime, &dStartSeconds);
|
|
|
|
while ( !bEngStopped ) {
|
|
//
|
|
// wait until remove task routine removes everything
|
|
// wait maximum 1 minutes in case some tasks are dead or looping
|
|
//
|
|
NtQuerySystemTime(&CurrentTime);
|
|
RtlTimeToSecondsSince1980 (&CurrentTime, &dCurrentSeconds);
|
|
|
|
if ( dCurrentSeconds - dStartSeconds > 60 ) {
|
|
//
|
|
// too long, break it
|
|
//
|
|
break;
|
|
}
|
|
}
|
|
|
|
} else {
|
|
//
|
|
// new tasks are already blocked by bStopRequest
|
|
// so pEngines won't be !NULL again
|
|
//
|
|
LeaveCriticalSection(&EngSync);
|
|
|
|
}
|
|
|
|
//
|
|
// close all client's contexts
|
|
//
|
|
|
|
EnterCriticalSection(&ContextSync);
|
|
|
|
PSCESRV_CONTEXT_LIST pList=pOpenContexts;
|
|
PSCESRV_CONTEXT_LIST pTemp;
|
|
|
|
while ( pList ) {
|
|
|
|
__try {
|
|
if ( pList->Context && ScepIsValidContext(pList->Context) ) {
|
|
|
|
ScepCloseDatabase(pList->Context);
|
|
|
|
pTemp = pList;
|
|
pList = pList->Next;
|
|
|
|
ScepFree(pTemp);
|
|
|
|
} else {
|
|
// it's already freed
|
|
break;
|
|
}
|
|
} __except (EXCEPTION_EXECUTE_HANDLER) {
|
|
break;
|
|
}
|
|
}
|
|
|
|
pOpenContexts = NULL;
|
|
|
|
LeaveCriticalSection(&ContextSync);
|
|
|
|
//
|
|
// check policy tasks
|
|
//
|
|
ScepQueuePrepareShutdown();
|
|
|
|
if ( DnsDomainInfo ) {
|
|
|
|
//
|
|
// there is no other threads, free DnsDomainInfo
|
|
//
|
|
|
|
LsaFreeMemory( DnsDomainInfo );
|
|
DnsDomainInfo = NULL;
|
|
}
|
|
|
|
//
|
|
// terminate jet engine
|
|
//
|
|
|
|
SceJetTerminate(TRUE);
|
|
|
|
SceJetDeleteJetFiles(NULL);
|
|
|
|
LeaveCriticalSection(&RpcSync);
|
|
|
|
return(Status);
|
|
}
|
|
|
|
SCESTATUS
|
|
ScepRsopLog(
|
|
IN AREA_INFORMATION Area,
|
|
IN DWORD dwConfigStatus,
|
|
IN wchar_t *pStatusInfo OPTIONAL,
|
|
IN DWORD dwPrivLow OPTIONAL,
|
|
IN DWORD dwPrivHigh OPTIONAL
|
|
)
|
|
/*
|
|
Routine Description:
|
|
|
|
Call back to client for logging RSOP diagnosis mode data
|
|
|
|
Arguments:
|
|
|
|
Area - the area being logged (used in client side in conjunction with last parameter pStatusInfo)
|
|
|
|
dwConfigStatus - error/success code of the particular setting in question
|
|
|
|
pStatusInfo - finer information regarding the above area (specific setting name etc.)
|
|
*/
|
|
{
|
|
//
|
|
// call back to client
|
|
//
|
|
__try {
|
|
|
|
SceClientCallbackRsopLog(Area, dwConfigStatus, pStatusInfo, dwPrivLow, dwPrivHigh);
|
|
|
|
} __except(EXCEPTION_EXECUTE_HANDLER) {
|
|
|
|
return(SCESTATUS_INVALID_PARAMETER);
|
|
}
|
|
|
|
return(SCESTATUS_SUCCESS);
|
|
}
|
|
|
|
SCESTATUS
|
|
ScepPostProgress(
|
|
IN DWORD Delta,
|
|
IN AREA_INFORMATION Area,
|
|
IN LPTSTR szName OPTIONAL
|
|
)
|
|
/*
|
|
Routine Description:
|
|
|
|
Call back to client for the progress of current thread, if client set
|
|
the callback flag.
|
|
|
|
Arguments:
|
|
|
|
Delta - Ticks changes since last callback
|
|
|
|
szName - the current item name
|
|
*/
|
|
{
|
|
|
|
if ( cbClientFlag ) {
|
|
|
|
//
|
|
// callback is requested
|
|
//
|
|
|
|
gCurrentTicks += Delta;
|
|
|
|
//
|
|
// call back to client
|
|
//
|
|
__try {
|
|
|
|
switch (cbClientFlag ) {
|
|
case SCE_CALLBACK_DELTA:
|
|
SceClientCallback(Delta,0,0,(wchar_t *)szName);
|
|
break;
|
|
|
|
case SCE_CALLBACK_TOTAL:
|
|
if ( Area ) {
|
|
SceClientCallback(gCurrentTicks, gTotalTicks, Area, (wchar_t *)szName);
|
|
}
|
|
break;
|
|
}
|
|
|
|
} __except(EXCEPTION_EXECUTE_HANDLER) {
|
|
|
|
return(SCESTATUS_INVALID_PARAMETER);
|
|
}
|
|
}
|
|
|
|
return(SCESTATUS_SUCCESS);
|
|
|
|
}
|
|
|
|
|
|
SCESTATUS
|
|
ScepValidateAndLockContext(
|
|
IN PSCECONTEXT Context,
|
|
IN BYTE LockFlag,
|
|
IN BOOL bRequireWrite,
|
|
OUT PSCESRV_DBTASK *ppTask OPTIONAL
|
|
)
|
|
/*
|
|
Routine Description:
|
|
|
|
Validate the context handle is SCE context handle.
|
|
If the same context (same session) is already used for another
|
|
database operation, this operation will be in waiting (a critical
|
|
section pointer is returned)
|
|
|
|
Arguments:
|
|
|
|
Context - the context handle
|
|
|
|
bLock - TRUE=perform the lock
|
|
|
|
ppTask - the output task pointer
|
|
|
|
Return Value:
|
|
|
|
SCESTATUS
|
|
*/
|
|
{
|
|
|
|
SCESTATUS rc = SCESTATUS_INVALID_PARAMETER;
|
|
|
|
if ( (LockFlag & SCE_TASK_LOCK) && !ppTask ) {
|
|
//
|
|
// if willing to lock, ppTask must NOT be NULL
|
|
//
|
|
return(rc);
|
|
}
|
|
|
|
if ( !Context ) {
|
|
//
|
|
// contents of the context will be checked within the critical section
|
|
// because other threads might free the context within there.
|
|
//
|
|
return(rc);
|
|
}
|
|
|
|
if ( ppTask ) {
|
|
*ppTask = NULL;
|
|
}
|
|
|
|
//
|
|
// lock the task list and verify the context
|
|
//
|
|
|
|
EnterCriticalSection(&TaskSync);
|
|
|
|
if ( bStopRequest ) {
|
|
LeaveCriticalSection(&TaskSync);
|
|
return(SCESTATUS_SERVICE_NOT_SUPPORT);
|
|
}
|
|
|
|
if ( ScepIsValidContext(Context) &&
|
|
( Context->JetSessionID != JET_sesidNil ) &&
|
|
( Context->JetDbID != JET_dbidNil) ) {
|
|
|
|
rc = SCESTATUS_SUCCESS;
|
|
|
|
if ( bRequireWrite &&
|
|
( SCEJET_OPEN_READ_ONLY == Context->OpenFlag ) ) {
|
|
//
|
|
// write operation is requested but the database is only granted
|
|
// read only access to this context.
|
|
//
|
|
rc = SCESTATUS_ACCESS_DENIED;
|
|
} else {
|
|
//
|
|
// check if esent delay load successful
|
|
//
|
|
DWORD dbVersion;
|
|
|
|
__try {
|
|
JetGetDatabaseInfo(Context->JetSessionID,
|
|
Context->JetDbID,
|
|
(void *)&dbVersion,
|
|
sizeof(DWORD),
|
|
JET_DbInfoVersion
|
|
);
|
|
} __except (EXCEPTION_EXECUTE_HANDLER) {
|
|
//
|
|
// esent.dll is not loaded (delay) successfully
|
|
//
|
|
rc = SCESTATUS_MOD_NOT_FOUND;
|
|
}
|
|
}
|
|
|
|
} else {
|
|
rc = SCESTATUS_INVALID_PARAMETER;
|
|
}
|
|
|
|
if ( SCESTATUS_SUCCESS == rc && LockFlag ) {
|
|
|
|
PSCESRV_DBTASK pdb = pDbTask;
|
|
|
|
while ( pdb ) {
|
|
if ( pdb->Context &&
|
|
pdb->Context->JetSessionID == Context->JetSessionID &&
|
|
pdb->Context->JetDbID == Context->JetDbID ) {
|
|
break;
|
|
}
|
|
pdb = pdb->Next;
|
|
}
|
|
|
|
if ( pdb && pdb->Context ) {
|
|
|
|
//
|
|
// find the same context address and same session
|
|
// critical section is in pdb->Sync
|
|
//
|
|
|
|
if ( pdb->bCloseReq ) {
|
|
|
|
//
|
|
// error this thread out because another thread is closing the
|
|
// same context
|
|
//
|
|
|
|
rc = SCESTATUS_ACCESS_DENIED;
|
|
|
|
} else if ( LockFlag & SCE_TASK_CLOSE ) {
|
|
|
|
//
|
|
// close on this context is requested but there are other
|
|
// thread running under this context, so just turn on the flag
|
|
// and the context will be closed when all pending tasks
|
|
// are done
|
|
//
|
|
|
|
pdb->bCloseReq = TRUE;
|
|
|
|
} else {
|
|
|
|
//
|
|
// request a lock, it's ok for this task to continue
|
|
//
|
|
|
|
pdb->dInUsed++;
|
|
*ppTask = pdb;
|
|
}
|
|
|
|
} else {
|
|
|
|
//
|
|
// did not find the same context, this operation is ok to go
|
|
// but need to add itself to the list
|
|
//
|
|
|
|
if ( LockFlag & SCE_TASK_CLOSE ) {
|
|
|
|
//
|
|
// a close context is requested, other threads using
|
|
// the same context will be invalidated after this context
|
|
// is freed
|
|
//
|
|
|
|
rc = ScepCloseDatabase(Context);
|
|
|
|
} else if ( LockFlag & SCE_TASK_LOCK ) {
|
|
|
|
PSCESRV_DBTASK NewDbTask = (PSCESRV_DBTASK)ScepAlloc(0, sizeof(SCESRV_DBTASK));
|
|
|
|
if ( NewDbTask ) {
|
|
//
|
|
// new node is created
|
|
//
|
|
NewDbTask->Context = Context;
|
|
NewDbTask->Prior = NULL;
|
|
NewDbTask->dInUsed = 1;
|
|
NewDbTask->bCloseReq = FALSE;
|
|
|
|
InitializeCriticalSection(&(NewDbTask->Sync));
|
|
|
|
//
|
|
// link it to the db task list
|
|
//
|
|
|
|
NewDbTask->Next = pDbTask;
|
|
|
|
if ( pDbTask ) {
|
|
pDbTask->Prior = NewDbTask;
|
|
}
|
|
|
|
pDbTask = NewDbTask;
|
|
|
|
*ppTask = NewDbTask;
|
|
|
|
} else {
|
|
|
|
rc = SCESTATUS_NOT_ENOUGH_RESOURCE;
|
|
}
|
|
|
|
} else {
|
|
//
|
|
// no lock, no close, just return
|
|
//
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
LeaveCriticalSection(&TaskSync);
|
|
|
|
return(rc);
|
|
}
|
|
|
|
|
|
SCESTATUS
|
|
ScepRemoveTask(
|
|
PSCESRV_DBTASK pTask
|
|
)
|
|
/*
|
|
Routine Description:
|
|
|
|
Remove the task (context) from dbtask table if there is no other
|
|
thread running in the same context.
|
|
|
|
Arguments:
|
|
|
|
|
|
pTask - the task node containing context and critical section
|
|
|
|
Return Value:
|
|
|
|
SCESTATUS
|
|
*/
|
|
{
|
|
|
|
if ( !pTask ) {
|
|
return(SCESTATUS_SUCCESS);
|
|
}
|
|
|
|
SCESTATUS rc=SCESTATUS_SUCCESS;
|
|
|
|
EnterCriticalSection(&TaskSync);
|
|
|
|
//
|
|
// find the task pointer in the task list for verification
|
|
//
|
|
|
|
PSCESRV_DBTASK pdb = pDbTask;
|
|
|
|
while ( pdb && (ULONG_PTR)pdb != (ULONG_PTR)pTask ) {
|
|
|
|
pdb = pdb->Next;
|
|
}
|
|
|
|
if ( pdb ) {
|
|
|
|
//
|
|
// find the same task node
|
|
//
|
|
|
|
pdb->dInUsed--;
|
|
|
|
if ( 0 == pdb->dInUsed ) {
|
|
|
|
//
|
|
// nobody is using this task node
|
|
// remove it
|
|
//
|
|
|
|
if ( pdb->Prior ) {
|
|
|
|
pdb->Prior->Next = pdb->Next;
|
|
|
|
} else {
|
|
//
|
|
// no parent node, set the static variable
|
|
//
|
|
pDbTask = pdb->Next;
|
|
|
|
}
|
|
|
|
//
|
|
// this is a double link list, remember to remove the Prior link
|
|
//
|
|
|
|
if ( pdb->Next ) {
|
|
pdb->Next->Prior = pdb->Prior;
|
|
}
|
|
|
|
//
|
|
// if close request is send, close this database
|
|
//
|
|
|
|
if ( pdb->bCloseReq && pdb->Context ) {
|
|
|
|
ScepCloseDatabase(pdb->Context);
|
|
}
|
|
|
|
//
|
|
// delete the critical section
|
|
//
|
|
DeleteCriticalSection(&(pdb->Sync));
|
|
|
|
//
|
|
// free the memory used by this node
|
|
//
|
|
|
|
ScepFree(pdb);
|
|
|
|
} else {
|
|
|
|
//
|
|
// other thread is using this task node for database operation
|
|
// do nothing
|
|
//
|
|
}
|
|
|
|
} else {
|
|
|
|
//
|
|
// can't find the task node in global the task list
|
|
//
|
|
rc = SCESTATUS_INVALID_PARAMETER;
|
|
|
|
}
|
|
|
|
//
|
|
// if stop is requested, notify the server that db task is done
|
|
//
|
|
if ( bStopRequest && !pDbTask ) {
|
|
bDbStopped = TRUE;
|
|
}
|
|
|
|
LeaveCriticalSection(&TaskSync);
|
|
|
|
return(rc);
|
|
}
|
|
|
|
|
|
SCESTATUS
|
|
ScepLockEngine(
|
|
IN LPTSTR DatabaseName
|
|
)
|
|
/*
|
|
Routine Description:
|
|
|
|
Lock the database for configuration/analysis.
|
|
|
|
Only one engine can run on the same database for configuration or
|
|
analysis because first it's meaningless to have multiple engines
|
|
running toward the same system, and second, the database is changed
|
|
by the engine (table may be deleted, so on...)
|
|
|
|
OpenDatabase is not locked by this lock, because each OpenDatabase
|
|
has its own session and cursor and no operations such as delete the
|
|
database or delete a table can be done with that context.
|
|
|
|
Arguments:
|
|
|
|
DefProfile - the database name
|
|
|
|
Return Value:
|
|
|
|
SCESTATUS
|
|
*/
|
|
{
|
|
|
|
SCESTATUS rc;
|
|
|
|
if ( !DatabaseName ) {
|
|
//
|
|
// if willing to lock, ppTask must NOT be NULL
|
|
//
|
|
return(SCESTATUS_INVALID_PARAMETER);
|
|
}
|
|
|
|
EnterCriticalSection(&EngSync);
|
|
|
|
if ( bStopRequest ) {
|
|
LeaveCriticalSection(&EngSync);
|
|
return(SCESTATUS_SERVICE_NOT_SUPPORT);
|
|
}
|
|
|
|
PSCESRV_ENGINE pe = pEngines;
|
|
|
|
while ( pe ) {
|
|
if ( pe->Database &&
|
|
0 == _wcsicmp(pe->Database, DatabaseName) ) {
|
|
break;
|
|
}
|
|
pe = pe->Next;
|
|
}
|
|
|
|
if ( pe ) {
|
|
|
|
//
|
|
// find the same database running by other threads
|
|
//
|
|
|
|
rc = SCESTATUS_ALREADY_RUNNING;
|
|
|
|
} else {
|
|
|
|
//
|
|
// did not find the same database, this operation is ok to go
|
|
// but need to add itself to the list
|
|
//
|
|
|
|
PSCESRV_ENGINE NewEng = (PSCESRV_ENGINE)ScepAlloc(0, sizeof(SCESRV_ENGINE));
|
|
|
|
if ( NewEng ) {
|
|
|
|
//
|
|
// new node is created
|
|
//
|
|
NewEng->Database = (LPTSTR)ScepAlloc(LPTR, (wcslen(DatabaseName)+1)*sizeof(TCHAR));
|
|
|
|
if ( NewEng->Database ) {
|
|
|
|
wcscpy(NewEng->Database, DatabaseName);
|
|
|
|
NewEng->Next = pEngines;
|
|
NewEng->Prior = NULL;
|
|
|
|
if ( pEngines ) {
|
|
pEngines->Prior = NewEng;
|
|
}
|
|
|
|
pEngines = NewEng;
|
|
|
|
rc = SCESTATUS_SUCCESS;
|
|
|
|
} else {
|
|
|
|
ScepFree(NewEng);
|
|
rc = SCESTATUS_NOT_ENOUGH_RESOURCE;
|
|
}
|
|
|
|
} else {
|
|
|
|
rc = SCESTATUS_NOT_ENOUGH_RESOURCE;
|
|
}
|
|
}
|
|
|
|
LeaveCriticalSection(&EngSync);
|
|
|
|
return(rc);
|
|
|
|
}
|
|
|
|
SCESTATUS
|
|
ScepUnlockEngine(
|
|
IN LPTSTR DatabaseName
|
|
)
|
|
/*
|
|
Routine Description:
|
|
|
|
Unlock the database.
|
|
|
|
Arguments:
|
|
|
|
DatabaseName - the database name
|
|
|
|
Return Value:
|
|
|
|
SCESTATUS
|
|
*/
|
|
{
|
|
if ( !DatabaseName ) {
|
|
//
|
|
// if no database name, just return
|
|
//
|
|
return(SCESTATUS_SUCCESS);
|
|
}
|
|
|
|
EnterCriticalSection(&EngSync);
|
|
|
|
PSCESRV_ENGINE pe = pEngines;
|
|
|
|
while ( pe && pe->Database &&
|
|
0 != _wcsicmp(pe->Database, DatabaseName) ) {
|
|
pe = pe->Next;
|
|
}
|
|
|
|
if ( pe ) {
|
|
|
|
//
|
|
// find the database, unlock it.
|
|
//
|
|
if ( pe->Prior ) {
|
|
|
|
pe->Prior->Next = pe->Next;
|
|
|
|
} else {
|
|
|
|
//
|
|
// no parent node, set the static variable
|
|
//
|
|
|
|
pEngines = pe->Next;
|
|
|
|
}
|
|
|
|
//
|
|
// this is a double link list, remember to remove the Prior link
|
|
//
|
|
|
|
if ( pe->Next ) {
|
|
pe->Next->Prior = pe->Prior;
|
|
}
|
|
|
|
//
|
|
// free the node
|
|
//
|
|
|
|
if ( pe->Database ) {
|
|
ScepFree(pe->Database);
|
|
}
|
|
|
|
ScepFree(pe);
|
|
}
|
|
|
|
//
|
|
// if stop is requested, notify the server that engine are done
|
|
//
|
|
if ( bStopRequest && !pEngines ) {
|
|
bEngStopped = TRUE;
|
|
}
|
|
|
|
LeaveCriticalSection(&EngSync);
|
|
|
|
return(SCESTATUS_SUCCESS);
|
|
|
|
}
|
|
|
|
|
|
SCESTATUS
|
|
ScepAddToOpenContext(
|
|
IN PSCECONTEXT Context
|
|
)
|
|
{
|
|
if ( !Context ) {
|
|
return(SCESTATUS_INVALID_PARAMETER);
|
|
}
|
|
|
|
SCESTATUS rc=SCESTATUS_SUCCESS;
|
|
|
|
__try {
|
|
if ( ScepIsValidContext(Context) ) {
|
|
|
|
PSCESRV_CONTEXT_LIST pList=pOpenContexts;
|
|
|
|
//
|
|
// note, ContextSync is already entered before this function is called
|
|
//
|
|
|
|
while ( pList ) {
|
|
|
|
if ( pList->Context &&
|
|
pList->Context->JetSessionID == Context->JetSessionID &&
|
|
pList->Context->JetDbID == Context->JetDbID ) {
|
|
// 0 == memcmp(pList->Context, Context, sizeof(SCECONTEXT)) ) {
|
|
break;
|
|
}
|
|
pList = pList->Next;
|
|
}
|
|
|
|
if ( !pList ) {
|
|
|
|
//
|
|
// did not find this open context, add it
|
|
//
|
|
pList = (PSCESRV_CONTEXT_LIST)ScepAlloc(0, sizeof(SCESRV_CONTEXT_LIST));
|
|
|
|
if ( pList ) {
|
|
pList->Context = Context;
|
|
pList->Prior = NULL;
|
|
pList->Next = pOpenContexts;
|
|
|
|
if ( pOpenContexts ) {
|
|
pOpenContexts->Prior = pList;
|
|
}
|
|
pOpenContexts = pList;
|
|
|
|
} else {
|
|
|
|
rc = SCESTATUS_NOT_ENOUGH_RESOURCE;
|
|
}
|
|
|
|
}
|
|
|
|
} else {
|
|
rc = SCESTATUS_INVALID_PARAMETER;
|
|
}
|
|
|
|
} __except(EXCEPTION_EXECUTE_HANDLER) {
|
|
|
|
rc = SCESTATUS_INVALID_PARAMETER;
|
|
}
|
|
|
|
return(rc);
|
|
}
|
|
|
|
BOOL
|
|
ScepNoActiveContexts()
|
|
{
|
|
|
|
BOOL bExist=FALSE;
|
|
|
|
//
|
|
// any active task ?
|
|
//
|
|
EnterCriticalSection(&TaskSync);
|
|
|
|
if ( pDbTask ) {
|
|
bExist = TRUE;
|
|
}
|
|
|
|
LeaveCriticalSection(&TaskSync);
|
|
|
|
if ( bExist ) {
|
|
return FALSE;
|
|
}
|
|
|
|
//
|
|
// any active db engine task ?
|
|
//
|
|
EnterCriticalSection(&EngSync);
|
|
|
|
if ( pEngines ) {
|
|
bExist = TRUE;
|
|
}
|
|
|
|
LeaveCriticalSection(&EngSync);
|
|
|
|
if ( bExist ) {
|
|
return FALSE;
|
|
}
|
|
|
|
//
|
|
// any open contexts ?
|
|
//
|
|
EnterCriticalSection(&ContextSync);
|
|
|
|
if ( pOpenContexts ) {
|
|
bExist = TRUE;
|
|
}
|
|
|
|
LeaveCriticalSection(&ContextSync);
|
|
|
|
return !bExist;
|
|
}
|
|
|
|
|
|
VOID
|
|
pDelayShutdownFunc(
|
|
IN PVOID Context,
|
|
IN UCHAR Timeout
|
|
)
|
|
{
|
|
|
|
if ( TryEnterCriticalSection(&JetSync) ) {
|
|
|
|
if ( hTimerQueue ) {
|
|
//
|
|
// it's necessary to do this check because there might be another thread
|
|
// cancelled this timer (after it's fired)
|
|
//
|
|
if ( ScepNoActiveContexts() ) {
|
|
|
|
SceJetTerminateNoCritical(TRUE); // clean version store (FALSE);
|
|
}
|
|
|
|
//
|
|
// 4. Note that UNLIKE before, EVERY timer needs to be deleted by calling
|
|
// RtlDeleteTimer even if they are one shot objects and have fired.
|
|
//
|
|
DeleteTimerQueueTimer( NULL, hTimerQueue, NULL );
|
|
|
|
//
|
|
// do not call CloseHandle because the handle will be closed by the
|
|
// timer function.
|
|
|
|
hTimerQueue = NULL;
|
|
}
|
|
|
|
LeaveCriticalSection(&JetSync);
|
|
|
|
} else {
|
|
//
|
|
// there is other thread holding off this one.
|
|
// This means there is still active clients, or a new client
|
|
// coming in, just return. htimerQueue will be reset by another thread
|
|
//
|
|
}
|
|
}
|
|
|
|
|
|
BOOL
|
|
ScepIfTerminateEngine()
|
|
{
|
|
//
|
|
// if system is requesting a shutdown, don't do
|
|
// anything, because the active clients and jet engine will be shutdown
|
|
//
|
|
if ( ScepIsSystemShutDown() ) {
|
|
return TRUE;
|
|
}
|
|
|
|
if ( ScepNoActiveContexts() ) {
|
|
//
|
|
// use JetSync to control timer queue
|
|
//
|
|
EnterCriticalSection(&JetSync);
|
|
|
|
DWORD Interval = 6*60*1000 ; // 6 minutes
|
|
|
|
if ( !CreateTimerQueueTimer(
|
|
&hTimerQueue,
|
|
NULL,
|
|
pDelayShutdownFunc,
|
|
NULL,
|
|
Interval,
|
|
0,
|
|
0 ) ) {
|
|
hTimerQueue = NULL;
|
|
}
|
|
|
|
LeaveCriticalSection(&JetSync);
|
|
|
|
return TRUE;
|
|
|
|
} else {
|
|
return FALSE;
|
|
}
|
|
}
|
|
|
|
SCESTATUS
|
|
ScepServerCancelTimer()
|
|
{
|
|
|
|
EnterCriticalSection(&JetSync);
|
|
|
|
if (hTimerQueue ) {
|
|
|
|
DeleteTimerQueueTimer(
|
|
NULL,
|
|
hTimerQueue,
|
|
(HANDLE)-1
|
|
);
|
|
hTimerQueue = NULL;
|
|
}
|
|
|
|
LeaveCriticalSection(&JetSync);
|
|
|
|
return(SCESTATUS_SUCCESS);
|
|
|
|
}
|
|
|
|
|
|
SCESTATUS
|
|
ScepValidateAndCloseDatabase(
|
|
IN PSCECONTEXT Context
|
|
)
|
|
{
|
|
SCESTATUS rc;
|
|
|
|
|
|
EnterCriticalSection(&CloseSync);
|
|
|
|
if ( ScepIsValidContext(Context) ) {
|
|
|
|
rc = SCESTATUS_SUCCESS;
|
|
|
|
} else {
|
|
|
|
rc = SCESTATUS_INVALID_PARAMETER;
|
|
}
|
|
|
|
if ( rc != SCESTATUS_SUCCESS ) {
|
|
LeaveCriticalSection(&CloseSync);
|
|
return(rc);
|
|
}
|
|
|
|
//
|
|
// be able to access the first byte
|
|
//
|
|
|
|
EnterCriticalSection(&ContextSync);
|
|
|
|
|
|
PSCESRV_CONTEXT_LIST pList=pOpenContexts;
|
|
|
|
while ( pList && ((ULONG_PTR)(pList->Context) != (ULONG_PTR)Context ||
|
|
pList->Context->JetSessionID != Context->JetSessionID ||
|
|
pList->Context->JetDbID != Context->JetDbID) ) {
|
|
pList = pList->Next;
|
|
}
|
|
|
|
if ( pList ) {
|
|
//
|
|
// find the open context, remove it from the open context list
|
|
// NOTE: both Prior and Next should be handled
|
|
//
|
|
|
|
if ( pList->Prior ) {
|
|
|
|
pList->Prior->Next = pList->Next;
|
|
} else {
|
|
|
|
pOpenContexts = pList->Next;
|
|
}
|
|
|
|
if ( pList->Next ) {
|
|
pList->Next->Prior = pList->Prior;
|
|
}
|
|
|
|
//
|
|
// free pList, do not call CloseDatabase because it will
|
|
// be closed in the following call.
|
|
//
|
|
ScepFree(pList);
|
|
|
|
}
|
|
|
|
LeaveCriticalSection(&ContextSync);
|
|
|
|
//
|
|
// if there are other threads running using the
|
|
// same database context, the close request is
|
|
// turned on. When all threads using the context
|
|
// finish, the context is closed.
|
|
//
|
|
// this client calling close won't have to wait
|
|
// for other threads using the same context
|
|
//
|
|
|
|
rc = ScepValidateAndLockContext(
|
|
(PSCECONTEXT)Context,
|
|
SCE_TASK_CLOSE,
|
|
FALSE,
|
|
NULL);
|
|
|
|
LeaveCriticalSection(&CloseSync);
|
|
|
|
//
|
|
// start a timer queue to check to see if there is active tasks/contexts
|
|
// if not, terminate jet engine
|
|
//
|
|
ScepIfTerminateEngine();
|
|
|
|
return(rc);
|
|
}
|
|
|
|
|
|
SCEPR_STATUS
|
|
SceSvcRpcQueryInfo(
|
|
IN SCEPR_CONTEXT Context,
|
|
IN SCEPR_SVCINFO_TYPE SceSvcType,
|
|
IN wchar_t *ServiceName,
|
|
IN wchar_t *Prefix OPTIONAL,
|
|
IN BOOL bExact,
|
|
OUT PSCEPR_SVCINFO __RPC_FAR *ppvInfo,
|
|
IN OUT PSCEPR_ENUM_CONTEXT psceEnumHandle
|
|
)
|
|
/*
|
|
Routine Description:
|
|
|
|
Retrieve information for the service from the database. If there are
|
|
more than the maximum allowed records for the service, only maximum
|
|
allowed records are returned. Client must use the enumeration handle
|
|
to make next query.
|
|
|
|
If during the enumeration, another client using the same context (which
|
|
is wired but it's possible) to change the information for this service,
|
|
the first client may get incorrect information.
|
|
|
|
The recommend solution is to use another context handle when doing the
|
|
update.
|
|
|
|
Arguments:
|
|
|
|
Context - the context handle
|
|
|
|
SceSvcType - the info type requested
|
|
|
|
ServiceName - the service name for which info is requested
|
|
|
|
Prefix - optional key prefix
|
|
|
|
bExact - TRUE = exact match on key
|
|
|
|
ppvInfo - output buffer
|
|
|
|
psceEnumHandle - the enumeration handle (used for next enumeration)
|
|
|
|
Return Value:
|
|
|
|
SCEPR_STATUS
|
|
*/
|
|
{
|
|
SCESTATUS rc;
|
|
BOOL bAdminSidInToken = FALSE;
|
|
|
|
UINT ClientLocalFlag = 0;
|
|
|
|
if ( !ServiceName || !ppvInfo || !psceEnumHandle ) {
|
|
return(SCESTATUS_INVALID_PARAMETER);
|
|
}
|
|
|
|
if ( RPC_S_OK != I_RpcBindingIsClientLocal( NULL, &ClientLocalFlag) ||
|
|
0 == ClientLocalFlag ){
|
|
|
|
//
|
|
// to prevent denial-of-service type attacks,
|
|
// do not allow remote RPC
|
|
//
|
|
|
|
return SCESTATUS_ACCESS_DENIED;
|
|
|
|
}
|
|
|
|
//
|
|
// impersonate the client
|
|
//
|
|
|
|
rc = RpcImpersonateClient( NULL );
|
|
|
|
if (rc != RPC_S_OK) {
|
|
return( rc );
|
|
}
|
|
|
|
rc = ScepDosErrorToSceStatus(ScepIsAdminLoggedOn(&bAdminSidInToken, TRUE));
|
|
|
|
if (SCESTATUS_SUCCESS != rc || FALSE == bAdminSidInToken) {
|
|
RpcRevertToSelf();
|
|
return SCESTATUS_SPECIAL_ACCOUNT;
|
|
|
|
}
|
|
|
|
|
|
//
|
|
// validate the context handle is a SCE context
|
|
// Only one database operation per context
|
|
//
|
|
|
|
PSCESRV_DBTASK pTask=NULL;
|
|
|
|
rc = ScepValidateAndLockContext((PSCECONTEXT)Context,
|
|
SCE_TASK_LOCK,
|
|
FALSE,
|
|
&pTask);
|
|
|
|
if (SCESTATUS_SUCCESS == rc ) {
|
|
|
|
//
|
|
// lock the context
|
|
//
|
|
|
|
if ( pTask ) {
|
|
EnterCriticalSection(&(pTask->Sync));
|
|
}
|
|
|
|
//
|
|
// query the information now
|
|
//
|
|
#ifdef SCE_JET_TRAN
|
|
rc = SceJetJetErrorToSceStatus(
|
|
JetSetSessionContext(
|
|
((PSCECONTEXT)Context)->JetSessionID,
|
|
(ULONG_PTR)Context
|
|
));
|
|
|
|
if ( SCESTATUS_SUCCESS == rc ) {
|
|
#endif
|
|
__try {
|
|
|
|
rc = SceSvcpQueryInfo(
|
|
(PSCECONTEXT)Context,
|
|
(SCESVC_INFO_TYPE)SceSvcType,
|
|
(PCWSTR)ServiceName,
|
|
(PWSTR)Prefix,
|
|
bExact,
|
|
(PVOID *)ppvInfo,
|
|
(PSCE_ENUMERATION_CONTEXT)psceEnumHandle
|
|
);
|
|
|
|
} __except (EXCEPTION_EXECUTE_HANDLER) {
|
|
|
|
//
|
|
// free ppvInfo if it's allocated
|
|
//
|
|
SceSvcpFreeMemory(*ppvInfo);
|
|
|
|
rc = SCESTATUS_EXCEPTION_IN_SERVER;
|
|
}
|
|
|
|
#ifdef SCE_JET_TRAN
|
|
JetResetSessionContext(((PSCECONTEXT)Context)->JetSessionID);
|
|
|
|
}
|
|
#endif
|
|
//
|
|
// unlock the context
|
|
//
|
|
|
|
if ( pTask ) {
|
|
LeaveCriticalSection(&(pTask->Sync));
|
|
}
|
|
|
|
//
|
|
// remove the context from task table
|
|
//
|
|
|
|
ScepRemoveTask(pTask);
|
|
|
|
}
|
|
|
|
RpcRevertToSelf();
|
|
|
|
return((SCEPR_STATUS)rc);
|
|
}
|
|
|
|
|
|
SCEPR_STATUS
|
|
SceSvcRpcSetInfo(
|
|
IN SCEPR_CONTEXT Context,
|
|
IN SCEPR_SVCINFO_TYPE SceSvcType,
|
|
IN wchar_t *ServiceName,
|
|
IN wchar_t *Prefix OPTIONAL,
|
|
IN BOOL bExact,
|
|
IN PSCEPR_SVCINFO pvInfo
|
|
)
|
|
/*
|
|
Routine Description:
|
|
|
|
Write information for the service to the database.
|
|
|
|
Arguments:
|
|
|
|
Context - the context handle
|
|
|
|
SceSvcType - the info type requested
|
|
|
|
ServiceName - the service name for which info is requested
|
|
|
|
Prefix - optional key prefix
|
|
|
|
bExact - TRUE = exact match on key
|
|
|
|
pvInfo - output buffer
|
|
|
|
Return Value:
|
|
|
|
SCEPR_STATUS
|
|
*/
|
|
{
|
|
SCESTATUS rc;
|
|
BOOL bAdminSidInToken = FALSE;
|
|
|
|
UINT ClientLocalFlag = 0;
|
|
|
|
if ( !ServiceName || !pvInfo ) {
|
|
return(SCESTATUS_INVALID_PARAMETER);
|
|
}
|
|
|
|
if ( RPC_S_OK != I_RpcBindingIsClientLocal( NULL, &ClientLocalFlag) ||
|
|
0 == ClientLocalFlag ){
|
|
|
|
//
|
|
// to prevent denial-of-service type attacks,
|
|
// do not allow remote RPC
|
|
//
|
|
|
|
return SCESTATUS_ACCESS_DENIED;
|
|
|
|
}
|
|
|
|
//
|
|
// impersonate the client
|
|
//
|
|
|
|
rc = RpcImpersonateClient( NULL );
|
|
|
|
if (rc != RPC_S_OK) {
|
|
return( rc );
|
|
}
|
|
|
|
rc = ScepDosErrorToSceStatus(ScepIsAdminLoggedOn(&bAdminSidInToken, TRUE));
|
|
|
|
if (SCESTATUS_SUCCESS != rc || FALSE == bAdminSidInToken) {
|
|
RpcRevertToSelf();
|
|
return SCESTATUS_SPECIAL_ACCOUNT;
|
|
}
|
|
|
|
//
|
|
// validate the context handle is a SCE context
|
|
// Only one database operation per context
|
|
//
|
|
|
|
PSCESRV_DBTASK pTask=NULL;
|
|
|
|
rc = ScepValidateAndLockContext((PSCECONTEXT)Context,
|
|
SCE_TASK_LOCK,
|
|
TRUE,
|
|
&pTask);
|
|
|
|
if (SCESTATUS_SUCCESS == rc ) {
|
|
|
|
//
|
|
// lock the context
|
|
//
|
|
|
|
if ( pTask ) {
|
|
EnterCriticalSection(&(pTask->Sync));
|
|
}
|
|
|
|
#ifdef SCE_JET_TRAN
|
|
rc = SceJetJetErrorToSceStatus(
|
|
JetSetSessionContext(
|
|
((PSCECONTEXT)Context)->JetSessionID,
|
|
(ULONG_PTR)Context
|
|
));
|
|
|
|
if ( SCESTATUS_SUCCESS == rc ) {
|
|
#endif
|
|
//
|
|
// set the information now
|
|
//
|
|
|
|
__try {
|
|
|
|
rc = SceSvcpSetInfo(
|
|
(PSCECONTEXT)Context,
|
|
(SCESVC_INFO_TYPE)SceSvcType,
|
|
(LPTSTR)ServiceName,
|
|
(LPTSTR)Prefix,
|
|
bExact,
|
|
0,
|
|
(PVOID)pvInfo
|
|
);
|
|
|
|
} __except (EXCEPTION_EXECUTE_HANDLER) {
|
|
|
|
rc = SCESTATUS_EXCEPTION_IN_SERVER;
|
|
}
|
|
|
|
#ifdef SCE_JET_TRAN
|
|
JetResetSessionContext(((PSCECONTEXT)Context)->JetSessionID);
|
|
|
|
}
|
|
#endif
|
|
//
|
|
// unlock the context
|
|
//
|
|
|
|
if ( pTask ) {
|
|
LeaveCriticalSection(&(pTask->Sync));
|
|
}
|
|
|
|
//
|
|
// remove the context from task table
|
|
//
|
|
|
|
ScepRemoveTask(pTask);
|
|
|
|
}
|
|
|
|
RpcRevertToSelf();
|
|
|
|
return((SCEPR_STATUS)rc);
|
|
}
|
|
|
|
|
|
DWORD
|
|
SceRpcSetupUpdateObject(
|
|
IN SCEPR_CONTEXT Context,
|
|
IN wchar_t *ObjectFullName,
|
|
IN DWORD ObjectType,
|
|
IN UINT nFlag,
|
|
IN wchar_t *SDText
|
|
)
|
|
/*
|
|
Routine Description:
|
|
|
|
Update object's security settings.
|
|
|
|
Arguments:
|
|
|
|
Context - the context handle
|
|
|
|
ObjectFullName - the object's full path name
|
|
|
|
ObjectType - the object type
|
|
|
|
nFlag - the update flag
|
|
|
|
SDText - the SDDL text for the object
|
|
|
|
Return Value:
|
|
|
|
DWORD
|
|
*/
|
|
{
|
|
if ( !ObjectFullName || !SDText ) {
|
|
return(SCESTATUS_INVALID_PARAMETER);
|
|
}
|
|
|
|
DWORD rc;
|
|
|
|
UINT ClientLocalFlag = 0;
|
|
|
|
if ( RPC_S_OK != I_RpcBindingIsClientLocal( NULL, &ClientLocalFlag) ||
|
|
0 == ClientLocalFlag ){
|
|
|
|
//
|
|
// to prevent denial-of-service type attacks,
|
|
// do not allow remote RPC
|
|
//
|
|
|
|
return SCESTATUS_ACCESS_DENIED;
|
|
|
|
}
|
|
|
|
//
|
|
// impersonate the client
|
|
//
|
|
|
|
rc = RpcImpersonateClient( NULL );
|
|
|
|
if (rc != RPC_S_OK) {
|
|
return( rc );
|
|
}
|
|
|
|
BOOL bAdminSidInToken = FALSE;
|
|
|
|
rc = ScepDosErrorToSceStatus(ScepIsAdminLoggedOn(&bAdminSidInToken, TRUE));
|
|
|
|
if (SCESTATUS_SUCCESS != rc || FALSE == bAdminSidInToken) {
|
|
RpcRevertToSelf();
|
|
return SCESTATUS_SPECIAL_ACCOUNT;
|
|
|
|
}
|
|
|
|
//
|
|
// validate the context handle is a SCE context
|
|
// Only one database operation per context
|
|
//
|
|
|
|
PSCESRV_DBTASK pTask=NULL;
|
|
|
|
rc = ScepValidateAndLockContext((PSCECONTEXT)Context,
|
|
SCE_TASK_LOCK,
|
|
TRUE,
|
|
&pTask);
|
|
|
|
if (SCESTATUS_SUCCESS == rc ) {
|
|
|
|
//
|
|
// lock the context
|
|
//
|
|
|
|
if ( pTask ) {
|
|
EnterCriticalSection(&(pTask->Sync));
|
|
}
|
|
|
|
__try {
|
|
|
|
#ifdef SCE_JET_TRAN
|
|
rc = SceJetJetErrorToSceStatus(
|
|
JetSetSessionContext(
|
|
((PSCECONTEXT)Context)->JetSessionID,
|
|
(ULONG_PTR)Context
|
|
));
|
|
|
|
if ( SCESTATUS_SUCCESS == rc ) {
|
|
#endif
|
|
//
|
|
// update object, return code is DWORD
|
|
//
|
|
rc = ScepSetupUpdateObject(
|
|
(PSCECONTEXT)Context,
|
|
(LPTSTR)ObjectFullName,
|
|
(SE_OBJECT_TYPE)ObjectType,
|
|
nFlag,
|
|
(LPTSTR)SDText
|
|
);
|
|
|
|
#ifdef SCE_JET_TRAN
|
|
JetResetSessionContext(((PSCECONTEXT)Context)->JetSessionID);
|
|
|
|
}
|
|
#endif
|
|
} __except(EXCEPTION_EXECUTE_HANDLER) {
|
|
|
|
rc = ERROR_EXCEPTION_IN_SERVICE;
|
|
}
|
|
|
|
//
|
|
// unlock the context
|
|
//
|
|
|
|
if ( pTask ) {
|
|
LeaveCriticalSection(&(pTask->Sync));
|
|
}
|
|
|
|
//
|
|
// remove the context from task table
|
|
//
|
|
|
|
ScepRemoveTask(pTask);
|
|
|
|
} else {
|
|
|
|
rc = ScepSceStatusToDosError(rc);
|
|
}
|
|
|
|
RpcRevertToSelf();
|
|
|
|
return(rc);
|
|
}
|
|
|
|
|
|
|
|
DWORD
|
|
SceRpcSetupMoveFile(
|
|
IN SCEPR_CONTEXT Context,
|
|
IN wchar_t *OldName,
|
|
IN wchar_t *NewName OPTIONAL,
|
|
IN wchar_t *SDText OPTIONAL
|
|
)
|
|
/*
|
|
Routine Description:
|
|
|
|
Rename or delete a object in the section.
|
|
|
|
Arguments:
|
|
|
|
Context - the context handle
|
|
|
|
SectionName - the object's section name
|
|
|
|
OldName - existing name
|
|
|
|
NewName - new name to rename to, if NULL, the existing object is deleted
|
|
|
|
Return Value:
|
|
|
|
DWORD
|
|
*/
|
|
{
|
|
if ( !OldName ) {
|
|
return(SCESTATUS_INVALID_PARAMETER);
|
|
}
|
|
|
|
UINT ClientLocalFlag = 0;
|
|
|
|
if ( RPC_S_OK != I_RpcBindingIsClientLocal( NULL, &ClientLocalFlag) ||
|
|
0 == ClientLocalFlag ){
|
|
|
|
//
|
|
// to prevent denial-of-service type attacks,
|
|
// do not allow remote RPC
|
|
//
|
|
|
|
return SCESTATUS_ACCESS_DENIED;
|
|
|
|
}
|
|
|
|
DWORD rc;
|
|
|
|
//
|
|
// impersonate the client
|
|
//
|
|
|
|
rc = RpcImpersonateClient( NULL );
|
|
|
|
if (rc != RPC_S_OK) {
|
|
return( rc );
|
|
}
|
|
|
|
BOOL bAdminSidInToken = FALSE;
|
|
|
|
rc = ScepDosErrorToSceStatus(ScepIsAdminLoggedOn(&bAdminSidInToken, TRUE));
|
|
|
|
if (SCESTATUS_SUCCESS != rc || FALSE == bAdminSidInToken) {
|
|
RpcRevertToSelf();
|
|
return SCESTATUS_SPECIAL_ACCOUNT;
|
|
|
|
}
|
|
|
|
//
|
|
// validate the context handle is a SCE context
|
|
// Only one database operation per context
|
|
//
|
|
|
|
PSCESRV_DBTASK pTask=NULL;
|
|
|
|
rc = ScepValidateAndLockContext((PSCECONTEXT)Context,
|
|
SCE_TASK_LOCK,
|
|
TRUE,
|
|
&pTask);
|
|
|
|
if (SCESTATUS_SUCCESS == rc ) {
|
|
|
|
//
|
|
// lock the context
|
|
//
|
|
|
|
if ( pTask ) {
|
|
EnterCriticalSection(&(pTask->Sync));
|
|
}
|
|
|
|
__try {
|
|
|
|
#ifdef SCE_JET_TRAN
|
|
rc = SceJetJetErrorToSceStatus(
|
|
JetSetSessionContext(
|
|
((PSCECONTEXT)Context)->JetSessionID,
|
|
(ULONG_PTR)Context
|
|
));
|
|
|
|
if ( SCESTATUS_SUCCESS == rc ) {
|
|
#endif
|
|
//
|
|
// update object, return code is DWORD
|
|
//
|
|
|
|
rc = ScepSetupMoveFile(
|
|
(PSCECONTEXT)Context,
|
|
(LPTSTR)OldName,
|
|
(LPTSTR)NewName,
|
|
(LPTSTR)SDText
|
|
);
|
|
|
|
#ifdef SCE_JET_TRAN
|
|
JetResetSessionContext(((PSCECONTEXT)Context)->JetSessionID);
|
|
|
|
}
|
|
#endif
|
|
|
|
} __except(EXCEPTION_EXECUTE_HANDLER) {
|
|
|
|
rc = ERROR_EXCEPTION_IN_SERVICE;
|
|
}
|
|
|
|
//
|
|
// unlock the context
|
|
//
|
|
|
|
if ( pTask ) {
|
|
LeaveCriticalSection(&(pTask->Sync));
|
|
}
|
|
|
|
//
|
|
// remove the context from task table
|
|
//
|
|
|
|
ScepRemoveTask(pTask);
|
|
|
|
} else {
|
|
|
|
rc = ScepSceStatusToDosError(rc);
|
|
}
|
|
|
|
RpcRevertToSelf();
|
|
|
|
return(rc);
|
|
}
|
|
|
|
|
|
DWORD
|
|
SceRpcGenerateTemplate(
|
|
IN handle_t binding_h,
|
|
IN wchar_t *JetDbName OPTIONAL,
|
|
IN wchar_t *LogFileName OPTIONAL,
|
|
OUT SCEPR_CONTEXT __RPC_FAR *pContext
|
|
)
|
|
/*
|
|
Routine Description:
|
|
|
|
Request a context handle to generate a template from the
|
|
database. If database name is not provided, the default database
|
|
used.
|
|
|
|
Arguments:
|
|
|
|
JetDbName - optional database name, if NULL, the default is used.
|
|
|
|
LogFileName - the log file name
|
|
|
|
pContext - the output context handle
|
|
|
|
Return Value:
|
|
|
|
DWORD
|
|
*/
|
|
{
|
|
if ( !pContext ) {
|
|
return(SCESTATUS_INVALID_PARAMETER);
|
|
}
|
|
|
|
UINT ClientLocalFlag = 0;
|
|
|
|
if ( RPC_S_OK != I_RpcBindingIsClientLocal( NULL, &ClientLocalFlag) ||
|
|
0 == ClientLocalFlag ){
|
|
|
|
//
|
|
// to prevent denial-of-service type attacks,
|
|
// do not allow remote RPC
|
|
//
|
|
|
|
return SCESTATUS_ACCESS_DENIED;
|
|
|
|
}
|
|
|
|
DWORD rc;
|
|
|
|
if ( bStopRequest ) {
|
|
return(SCESTATUS_SERVICE_NOT_SUPPORT);
|
|
}
|
|
|
|
//
|
|
// there is no need to check delay loaded DLLs since now we have a exception hander
|
|
// (defined in sources)
|
|
// initialize jet engine in system context
|
|
//
|
|
|
|
rc = ScepSceStatusToDosError( SceJetInitialize(NULL) );
|
|
|
|
if ( ERROR_SUCCESS != rc ) {
|
|
return(rc);
|
|
}
|
|
|
|
//
|
|
// impersonate the client
|
|
//
|
|
|
|
rc = RpcImpersonateClient( NULL );
|
|
|
|
if (rc != RPC_S_OK) {
|
|
*pContext = NULL;
|
|
//
|
|
// terminate jet engine if there is no other clients
|
|
//
|
|
ScepIfTerminateEngine();
|
|
|
|
return( rc );
|
|
}
|
|
|
|
BOOL bAdminSidInToken = FALSE;
|
|
|
|
rc = ScepDosErrorToSceStatus(ScepIsAdminLoggedOn(&bAdminSidInToken, TRUE));
|
|
|
|
if (SCESTATUS_SUCCESS != rc || FALSE == bAdminSidInToken) {
|
|
RpcRevertToSelf();
|
|
return SCESTATUS_SPECIAL_ACCOUNT;
|
|
}
|
|
|
|
//
|
|
// get the default database name if needed
|
|
// and call open database on it.
|
|
//
|
|
// OpenDatabase is not blocked by any task.
|
|
//
|
|
|
|
EnterCriticalSection(&ContextSync);
|
|
|
|
PWSTR DefProfile=NULL;
|
|
|
|
__try {
|
|
//
|
|
// figure out the default database name
|
|
// catch exception if the input buffer are bogus
|
|
//
|
|
rc = ScepGetDefaultDatabase(
|
|
JetDbName,
|
|
0,
|
|
LogFileName,
|
|
NULL,
|
|
&DefProfile
|
|
);
|
|
|
|
} __except(EXCEPTION_EXECUTE_HANDLER) {
|
|
|
|
rc = ERROR_EXCEPTION_IN_SERVICE;
|
|
}
|
|
|
|
if ( NO_ERROR == rc && DefProfile ) {
|
|
|
|
//
|
|
// initialize to open the database
|
|
//
|
|
|
|
ScepLogOutput3(0,0, SCEDLL_BEGIN_INIT);
|
|
|
|
ScepLogOutput3(2,0, SCEDLL_FIND_DBLOCATION, DefProfile);
|
|
|
|
//
|
|
// open the database
|
|
//
|
|
|
|
rc = ScepOpenDatabase((PCWSTR)DefProfile,
|
|
0, // do not require analysis info,
|
|
SCEJET_OPEN_READ_ONLY,
|
|
(PSCECONTEXT *)pContext);
|
|
|
|
rc = ScepSceStatusToDosError(rc);
|
|
|
|
if ( ERROR_SUCCESS != rc ) {
|
|
ScepLogOutput3(1, rc, SCEDLL_ERROR_OPEN, DefProfile);
|
|
}
|
|
}
|
|
|
|
if (DefProfile != NULL && DefProfile != JetDbName ) {
|
|
|
|
ScepFree( DefProfile );
|
|
}
|
|
|
|
ScepLogClose();
|
|
|
|
if ( *pContext ) {
|
|
//
|
|
// if a context is to be returned, add it to the open context list
|
|
//
|
|
ScepAddToOpenContext((PSCECONTEXT)(*pContext));
|
|
rc = ERROR_SUCCESS;
|
|
|
|
} else {
|
|
|
|
rc = ERROR_FILE_NOT_FOUND;
|
|
}
|
|
|
|
LeaveCriticalSection(&ContextSync);
|
|
|
|
RpcRevertToSelf();
|
|
|
|
if ( ERROR_SUCCESS != rc ) {
|
|
//
|
|
// terminate jet engine if no other clients
|
|
//
|
|
ScepIfTerminateEngine();
|
|
}
|
|
|
|
return(rc);
|
|
}
|
|
|
|
|
|
|
|
SCEPR_STATUS
|
|
SceRpcConfigureSystem(
|
|
IN handle_t binding_h,
|
|
IN wchar_t *InfFileName OPTIONAL,
|
|
IN wchar_t *DatabaseName OPTIONAL,
|
|
IN wchar_t *LogFileName OPTIONAL,
|
|
IN DWORD ConfigOptions,
|
|
IN AREAPR Area,
|
|
IN DWORD pebSize,
|
|
IN UCHAR *pebClient OPTIONAL,
|
|
OUT PDWORD pdWarning OPTIONAL
|
|
)
|
|
/*
|
|
Routine Description:
|
|
|
|
Configure the system using the Inf template and/or existing
|
|
database info
|
|
|
|
Arguments:
|
|
|
|
See ScepConfigureSystem
|
|
|
|
Return Value:
|
|
|
|
SCEPR_STATUS
|
|
*/
|
|
{
|
|
SCESTATUS rc;
|
|
|
|
UINT ClientLocalFlag = 0;
|
|
|
|
if ( RPC_S_OK != I_RpcBindingIsClientLocal( NULL, &ClientLocalFlag) ||
|
|
0 == ClientLocalFlag ){
|
|
|
|
//
|
|
// to prevent denial-of-service type attacks,
|
|
// do not allow remote RPC
|
|
//
|
|
|
|
return SCESTATUS_ACCESS_DENIED;
|
|
|
|
}
|
|
|
|
|
|
//
|
|
// impersonate the client
|
|
//
|
|
|
|
rc = RpcImpersonateClient( NULL );
|
|
|
|
if (rc != RPC_S_OK) {
|
|
return( rc );
|
|
}
|
|
|
|
BOOL bAdminSidInToken = FALSE;
|
|
|
|
rc = ScepDosErrorToSceStatus(ScepIsAdminLoggedOn(&bAdminSidInToken, TRUE));
|
|
|
|
if (SCESTATUS_SUCCESS != rc || FALSE == bAdminSidInToken) {
|
|
RpcRevertToSelf();
|
|
return SCESTATUS_SPECIAL_ACCOUNT;
|
|
|
|
}
|
|
|
|
RpcRevertToSelf();
|
|
|
|
|
|
if ( bStopRequest ) {
|
|
|
|
if ( !ServerInited ) {
|
|
//
|
|
// server is in the middle of initialization
|
|
// client calls to server too early, should wait for some time
|
|
// (maximum 3 seconds)
|
|
//
|
|
INT cnt=0;
|
|
while (cnt < 6) {
|
|
Sleep(500); // .5 second
|
|
if ( ServerInited ) {
|
|
break;
|
|
}
|
|
cnt++;
|
|
}
|
|
|
|
if ( bStopRequest ) {
|
|
//
|
|
// if it's still in stop mode, return failure
|
|
//
|
|
return(SCESTATUS_SERVICE_NOT_SUPPORT);
|
|
}
|
|
} else {
|
|
|
|
return(SCESTATUS_SERVICE_NOT_SUPPORT);
|
|
}
|
|
}
|
|
|
|
//
|
|
// initialize jet engine in system context
|
|
//
|
|
JET_ERR JetErr=0;
|
|
BOOL bAdminLogon=FALSE;
|
|
|
|
rc = SceJetInitialize(&JetErr);
|
|
|
|
if ( rc != SCESTATUS_SUCCESS ) {
|
|
|
|
if ( ((JetErr > JET_errUnicodeTranslationBufferTooSmall) &&
|
|
(JetErr < JET_errInvalidLoggedOperation) &&
|
|
(JetErr != JET_errLogDiskFull)) ||
|
|
(JetErr == JET_errFileNotFound) ) {
|
|
//
|
|
// something is wrong with Jet log files or with other temparary databases
|
|
// if I am in setup and using system database (admin logon) or
|
|
// am in dcpromo, delete the Jet log files and try again
|
|
//
|
|
//
|
|
// impersonate the client, return DWORD error code
|
|
//
|
|
|
|
if ( RPC_S_OK == RpcImpersonateClient( NULL ) ) {
|
|
|
|
ScepIsAdminLoggedOn(&bAdminLogon, TRUE);
|
|
|
|
RpcRevertToSelf();
|
|
|
|
if ( bAdminLogon &&
|
|
(DatabaseName == NULL || SceIsSystemDatabase(DatabaseName) )) {
|
|
//
|
|
// system database and admin logon
|
|
// delete the Jet log files now.
|
|
//
|
|
SceJetDeleteJetFiles(NULL);
|
|
|
|
//
|
|
// try to initialize again (in system context)
|
|
//
|
|
rc = SceJetInitialize(&JetErr);
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
if ( rc != SCESTATUS_SUCCESS )
|
|
return(rc);
|
|
}
|
|
|
|
//
|
|
// impersonate the client, return DWORD error code
|
|
//
|
|
|
|
rc = RpcImpersonateClient( NULL );
|
|
|
|
if (rc != RPC_S_OK) {
|
|
|
|
ScepIfTerminateEngine();
|
|
|
|
return( ScepDosErrorToSceStatus(rc) );
|
|
}
|
|
|
|
|
|
//
|
|
// get the database name
|
|
//
|
|
|
|
LPTSTR DefProfile=NULL;
|
|
|
|
__try {
|
|
//
|
|
// catch exception if the input parameters are bogus
|
|
//
|
|
rc = ScepGetDefaultDatabase(
|
|
(LPCTSTR)DatabaseName,
|
|
ConfigOptions,
|
|
(LPCTSTR)LogFileName,
|
|
&bAdminLogon,
|
|
&DefProfile
|
|
);
|
|
|
|
} __except(EXCEPTION_EXECUTE_HANDLER) {
|
|
|
|
rc = ERROR_EXCEPTION_IN_SERVICE;
|
|
}
|
|
|
|
if ( ERROR_SUCCESS == rc && DefProfile ) {
|
|
|
|
//
|
|
// validate access to the database
|
|
//
|
|
rc = ScepDatabaseAccessGranted( DefProfile,
|
|
FILE_GENERIC_READ | FILE_GENERIC_WRITE,
|
|
TRUE
|
|
);
|
|
}
|
|
|
|
rc = ScepDosErrorToSceStatus(rc);
|
|
|
|
if ( SCESTATUS_SUCCESS == rc && DefProfile ) {
|
|
|
|
//
|
|
// validate the database to see if there is any configuration/
|
|
// analysis running on other threads
|
|
//
|
|
|
|
rc = ScepLockEngine(DefProfile);
|
|
|
|
if ( SCESTATUS_ALREADY_RUNNING == rc &&
|
|
(ConfigOptions & SCE_DCPROMO_WAIT ) ) {
|
|
//
|
|
// will wait for max one minute
|
|
//
|
|
DWORD DcpromoWaitCount = 0;
|
|
|
|
while ( TRUE ) {
|
|
|
|
Sleep(5000); // 5 seconds
|
|
|
|
rc = ScepLockEngine(DefProfile);
|
|
|
|
DcpromoWaitCount++;
|
|
|
|
if ( SCESTATUS_SUCCESS == rc ||
|
|
DcpromoWaitCount >= 12 ) {
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
if ( SCESTATUS_SUCCESS == rc ) {
|
|
|
|
t_pebClient = (LPVOID)pebClient;
|
|
t_pebSize = pebSize;
|
|
|
|
//
|
|
// it's ok to continue this operation
|
|
// no other threads are running configuration/analysis
|
|
// based on the same database
|
|
//
|
|
|
|
DWORD dOptions = ConfigOptions;
|
|
if ( !DatabaseName ||
|
|
( bAdminLogon && SceIsSystemDatabase(DatabaseName)) ) {
|
|
|
|
dOptions |= SCE_SYSTEM_DB;
|
|
}
|
|
|
|
__try {
|
|
//
|
|
// catch exception if InfFileName, or pebClient/pdWarning are bogus
|
|
//
|
|
rc = ScepConfigureSystem(
|
|
(LPCTSTR)InfFileName,
|
|
DefProfile,
|
|
dOptions,
|
|
bAdminLogon,
|
|
(AREA_INFORMATION)Area,
|
|
pdWarning
|
|
);
|
|
} __except(EXCEPTION_EXECUTE_HANDLER) {
|
|
|
|
rc = SCESTATUS_EXCEPTION_IN_SERVER;
|
|
}
|
|
|
|
//
|
|
// make sure private LSA handle is closed (to avoid deadlock)
|
|
//
|
|
if ( LsaPrivatePolicy ) {
|
|
|
|
ScepNotifyLogPolicy(0, TRUE, L"Policy Prop: Private LSA handle is to be released", 0, 0, NULL );
|
|
|
|
LsaClose(LsaPrivatePolicy);
|
|
LsaPrivatePolicy = NULL;
|
|
|
|
}
|
|
|
|
//
|
|
// unlock the engine for this database
|
|
//
|
|
|
|
ScepUnlockEngine(DefProfile);
|
|
}
|
|
}
|
|
|
|
if ( DefProfile && DefProfile != DatabaseName ) {
|
|
ScepFree(DefProfile);
|
|
|
|
}
|
|
|
|
ScepLogClose();
|
|
|
|
//
|
|
// change context back
|
|
//
|
|
|
|
RpcRevertToSelf();
|
|
|
|
//
|
|
// start a timer queue to check to see if there is active tasks/contexts
|
|
// if not, terminate jet engine
|
|
//
|
|
ScepIfTerminateEngine();
|
|
|
|
return((SCEPR_STATUS)rc);
|
|
}
|
|
|
|
|
|
SCEPR_STATUS
|
|
SceRpcGetDatabaseInfo(
|
|
IN SCEPR_CONTEXT Context,
|
|
IN SCEPR_TYPE ProfileType,
|
|
IN AREAPR Area,
|
|
OUT PSCEPR_PROFILE_INFO __RPC_FAR *ppInfoBuffer,
|
|
OUT PSCEPR_ERROR_LOG_INFO __RPC_FAR *Errlog OPTIONAL
|
|
)
|
|
/*
|
|
Routine Description:
|
|
|
|
Get information from the context database.
|
|
|
|
Arguments:
|
|
|
|
Note: the InfoBuffer will always be the output buffer. Client site will
|
|
pass in a address of NULL buffer to start with for any area information
|
|
then merge this output buffer with the one clients called in.
|
|
|
|
Have to marshlling security descriptor data to add a length in pServices
|
|
|
|
See ScepGetDatabaseInfo
|
|
|
|
Return Value:
|
|
|
|
SCEPR_STATUS
|
|
*/
|
|
{
|
|
if ( !ppInfoBuffer ) {
|
|
return(SCESTATUS_INVALID_PARAMETER);
|
|
}
|
|
|
|
UINT ClientLocalFlag = 0;
|
|
|
|
if ( RPC_S_OK != I_RpcBindingIsClientLocal( NULL, &ClientLocalFlag) ||
|
|
0 == ClientLocalFlag ){
|
|
|
|
//
|
|
// to prevent denial-of-service type attacks,
|
|
// do not allow remote RPC
|
|
//
|
|
|
|
return SCESTATUS_ACCESS_DENIED;
|
|
|
|
}
|
|
|
|
SCESTATUS rc;
|
|
|
|
//
|
|
// impersonate the client
|
|
//
|
|
|
|
rc = RpcImpersonateClient( NULL );
|
|
|
|
if (rc != RPC_S_OK) {
|
|
return( ScepDosErrorToSceStatus(rc) );
|
|
}
|
|
|
|
BOOL bAdminSidInToken = FALSE;
|
|
|
|
rc = ScepDosErrorToSceStatus(ScepIsAdminLoggedOn(&bAdminSidInToken, TRUE));
|
|
|
|
if (SCESTATUS_SUCCESS != rc || FALSE == bAdminSidInToken) {
|
|
RpcRevertToSelf();
|
|
return SCESTATUS_SPECIAL_ACCOUNT;
|
|
}
|
|
|
|
//
|
|
// validate the context handle is a SCE context
|
|
// Only one database operation per context
|
|
//
|
|
|
|
PSCESRV_DBTASK pTask=NULL;
|
|
|
|
rc = ScepValidateAndLockContext((PSCECONTEXT)Context,
|
|
SCE_TASK_LOCK,
|
|
FALSE,
|
|
&pTask);
|
|
|
|
if (SCESTATUS_SUCCESS == rc ) {
|
|
|
|
//
|
|
// lock the context
|
|
//
|
|
|
|
if ( pTask ) {
|
|
EnterCriticalSection(&(pTask->Sync));
|
|
}
|
|
|
|
__try {
|
|
//
|
|
// catch exception if Context, ppInfoBuffer, Errlog are bogus pointers
|
|
//
|
|
#ifdef SCE_JET_TRAN
|
|
rc = SceJetJetErrorToSceStatus(
|
|
JetSetSessionContext(
|
|
((PSCECONTEXT)Context)->JetSessionID,
|
|
(ULONG_PTR)Context
|
|
));
|
|
|
|
if ( SCESTATUS_SUCCESS == rc ) {
|
|
#endif
|
|
//
|
|
// query the information now
|
|
//
|
|
|
|
rc = ScepGetDatabaseInfo(
|
|
(PSCECONTEXT)Context,
|
|
(SCETYPE)ProfileType,
|
|
(AREA_INFORMATION)Area,
|
|
0,
|
|
(PSCE_PROFILE_INFO *)ppInfoBuffer,
|
|
(PSCE_ERROR_LOG_INFO *)Errlog
|
|
);
|
|
|
|
#ifdef SCE_JET_TRAN
|
|
JetResetSessionContext(((PSCECONTEXT)Context)->JetSessionID);
|
|
|
|
}
|
|
#endif
|
|
|
|
} __except(EXCEPTION_EXECUTE_HANDLER) {
|
|
|
|
//
|
|
// free ppInfoBuffer if it's allocated
|
|
//
|
|
SceFreeProfileMemory( (PSCE_PROFILE_INFO)(*ppInfoBuffer));
|
|
*ppInfoBuffer = NULL;
|
|
|
|
rc = SCESTATUS_EXCEPTION_IN_SERVER;
|
|
}
|
|
|
|
//
|
|
// unlock the context
|
|
//
|
|
|
|
if ( pTask ) {
|
|
LeaveCriticalSection(&(pTask->Sync));
|
|
}
|
|
|
|
//
|
|
// remove the context from task table
|
|
//
|
|
|
|
ScepRemoveTask(pTask);
|
|
|
|
__try {
|
|
|
|
if ( *ppInfoBuffer && (*ppInfoBuffer)->pServices ) {
|
|
//
|
|
// marshell the SCEPR_SERVICES structure for the security
|
|
// descriptor
|
|
//
|
|
for ( PSCE_SERVICES ps=(PSCE_SERVICES)((*ppInfoBuffer)->pServices);
|
|
ps != NULL; ps = ps->Next ) {
|
|
|
|
if ( ps->General.pSecurityDescriptor ) {
|
|
//
|
|
// if there is a security descriptor, it must be self relative
|
|
// because the SD is returned from SDDL apis.
|
|
//
|
|
ULONG nLen = RtlLengthSecurityDescriptor (
|
|
ps->General.pSecurityDescriptor);
|
|
|
|
if ( nLen > 0 ) {
|
|
//
|
|
// create a wrapper node to contain the security descriptor
|
|
//
|
|
|
|
PSCEPR_SR_SECURITY_DESCRIPTOR pNewWrap;
|
|
pNewWrap = (PSCEPR_SR_SECURITY_DESCRIPTOR)ScepAlloc(0, sizeof(SCEPR_SR_SECURITY_DESCRIPTOR));
|
|
if ( pNewWrap ) {
|
|
|
|
//
|
|
// assign the wrap to the structure
|
|
//
|
|
pNewWrap->SecurityDescriptor = (UCHAR *)(ps->General.pSecurityDescriptor);
|
|
pNewWrap->Length = nLen;
|
|
|
|
ps->General.pSecurityDescriptor = (PSECURITY_DESCRIPTOR)pNewWrap;
|
|
|
|
} else {
|
|
//
|
|
// no memory is available, but still continue to parse all nodes
|
|
//
|
|
nLen = 0;
|
|
}
|
|
}
|
|
|
|
if ( nLen == 0 ) {
|
|
//
|
|
// something wrong with this security descriptor
|
|
// free the buffer
|
|
//
|
|
ScepFree(ps->General.pSecurityDescriptor);
|
|
ps->General.pSecurityDescriptor = NULL;
|
|
ps->SeInfo = 0;
|
|
}
|
|
|
|
}
|
|
}
|
|
}
|
|
|
|
} __except(EXCEPTION_EXECUTE_HANDLER) {
|
|
|
|
rc = SCESTATUS_EXCEPTION_IN_SERVER;
|
|
}
|
|
}
|
|
|
|
RpcRevertToSelf();
|
|
|
|
return((SCEPR_STATUS)rc);
|
|
}
|
|
|
|
|
|
SCEPR_STATUS
|
|
SceRpcGetObjectChildren(
|
|
IN SCEPR_CONTEXT Context,
|
|
IN SCEPR_TYPE ProfileType,
|
|
IN AREAPR Area,
|
|
IN wchar_t *ObjectPrefix,
|
|
OUT PSCEPR_OBJECT_CHILDREN __RPC_FAR *Buffer,
|
|
OUT PSCEPR_ERROR_LOG_INFO __RPC_FAR *Errlog OPTIONAL
|
|
)
|
|
/*
|
|
Routine Description:
|
|
|
|
Get immediate children of the object from the context database
|
|
|
|
Arguments:
|
|
|
|
See ScepGetObjectChildren
|
|
|
|
Return Value:
|
|
|
|
SCEPR_STATUS
|
|
*/
|
|
{
|
|
if ( !ObjectPrefix || !Buffer ) {
|
|
return(SCESTATUS_INVALID_PARAMETER);
|
|
}
|
|
|
|
UINT ClientLocalFlag = 0;
|
|
|
|
if ( RPC_S_OK != I_RpcBindingIsClientLocal( NULL, &ClientLocalFlag) ||
|
|
0 == ClientLocalFlag ){
|
|
|
|
//
|
|
// to prevent denial-of-service type attacks,
|
|
// do not allow remote RPC
|
|
//
|
|
|
|
return SCESTATUS_ACCESS_DENIED;
|
|
|
|
}
|
|
|
|
//
|
|
// prevent empty strings
|
|
//
|
|
if ( ObjectPrefix[0] == L'\0' ) {
|
|
return(SCESTATUS_INVALID_PARAMETER);
|
|
}
|
|
|
|
SCESTATUS rc;
|
|
|
|
//
|
|
// impersonate the client
|
|
//
|
|
|
|
rc = RpcImpersonateClient( NULL );
|
|
|
|
if (rc != RPC_S_OK) {
|
|
return( ScepDosErrorToSceStatus(rc) );
|
|
}
|
|
|
|
BOOL bAdminSidInToken = FALSE;
|
|
|
|
rc = ScepDosErrorToSceStatus(ScepIsAdminLoggedOn(&bAdminSidInToken, TRUE));
|
|
|
|
if (SCESTATUS_SUCCESS != rc || FALSE == bAdminSidInToken) {
|
|
RpcRevertToSelf();
|
|
return SCESTATUS_SPECIAL_ACCOUNT;
|
|
}
|
|
|
|
//
|
|
// validate the context handle is a SCE context
|
|
// Only one database operation per context
|
|
//
|
|
|
|
PSCESRV_DBTASK pTask=NULL;
|
|
|
|
rc = ScepValidateAndLockContext((PSCECONTEXT)Context,
|
|
SCE_TASK_LOCK,
|
|
FALSE,
|
|
&pTask);
|
|
|
|
if (SCESTATUS_SUCCESS == rc ) {
|
|
|
|
//
|
|
// lock the context
|
|
//
|
|
|
|
if ( pTask ) {
|
|
EnterCriticalSection(&(pTask->Sync));
|
|
}
|
|
|
|
__try {
|
|
|
|
#ifdef SCE_JET_TRAN
|
|
rc = SceJetJetErrorToSceStatus(
|
|
JetSetSessionContext(
|
|
((PSCECONTEXT)Context)->JetSessionID,
|
|
(ULONG_PTR)Context
|
|
));
|
|
|
|
if ( SCESTATUS_SUCCESS == rc ) {
|
|
#endif
|
|
//
|
|
// query the information now
|
|
//
|
|
|
|
rc = ScepGetObjectChildren(
|
|
(PSCECONTEXT)Context,
|
|
(SCETYPE)ProfileType,
|
|
(AREA_INFORMATION)Area,
|
|
(PWSTR)ObjectPrefix,
|
|
SCE_IMMEDIATE_CHILDREN,
|
|
(PVOID *)Buffer,
|
|
(PSCE_ERROR_LOG_INFO *)Errlog
|
|
);
|
|
|
|
#ifdef SCE_JET_TRAN
|
|
JetResetSessionContext(((PSCECONTEXT)Context)->JetSessionID);
|
|
|
|
}
|
|
#endif
|
|
|
|
} __except (EXCEPTION_EXECUTE_HANDLER) {
|
|
|
|
//
|
|
// free Buffer if already allocated
|
|
//
|
|
SceFreeMemory( (PVOID)(*Buffer), SCE_STRUCT_OBJECT_CHILDREN);
|
|
*Buffer = NULL;
|
|
|
|
rc = SCESTATUS_EXCEPTION_IN_SERVER;
|
|
}
|
|
//
|
|
// unlock the context
|
|
//
|
|
|
|
if ( pTask ) {
|
|
LeaveCriticalSection(&(pTask->Sync));
|
|
}
|
|
|
|
//
|
|
// remove the context from task table
|
|
//
|
|
|
|
ScepRemoveTask(pTask);
|
|
|
|
}
|
|
|
|
RpcRevertToSelf();
|
|
|
|
return((SCEPR_STATUS)rc);
|
|
|
|
}
|
|
|
|
|
|
|
|
SCEPR_STATUS
|
|
SceRpcOpenDatabase(
|
|
IN handle_t binding_h,
|
|
IN wchar_t *DatabaseName,
|
|
IN DWORD OpenOption,
|
|
OUT SCEPR_CONTEXT __RPC_FAR *pContext
|
|
)
|
|
/*
|
|
Routine Description:
|
|
|
|
Request a context handle for the database. If bAnalysisRequired is set
|
|
to TRUE, this routine also checks if there is analysis information
|
|
in the database and return error is no analysis info is available.
|
|
|
|
Arguments:
|
|
|
|
DatabaseName - database name
|
|
|
|
OpenOption - SCE_OPEN_OPTION_REQUIRE_ANALYSIS
|
|
require analysis information in the database
|
|
SCE_OPEN_OPTION_TATTOO
|
|
open the tattoo table instead (in system database)
|
|
|
|
pContext - the output context handle
|
|
|
|
Return Value:
|
|
|
|
SCEPR_STATUS
|
|
*/
|
|
{
|
|
if ( !pContext || !DatabaseName ) {
|
|
return(SCESTATUS_INVALID_PARAMETER);
|
|
}
|
|
|
|
UINT ClientLocalFlag = 0;
|
|
|
|
if ( RPC_S_OK != I_RpcBindingIsClientLocal( NULL, &ClientLocalFlag) ||
|
|
0 == ClientLocalFlag ){
|
|
|
|
//
|
|
// to prevent denial-of-service type attacks,
|
|
// do not allow remote RPC
|
|
//
|
|
|
|
return SCESTATUS_ACCESS_DENIED;
|
|
|
|
}
|
|
|
|
if ( bStopRequest ) {
|
|
return(SCESTATUS_SERVICE_NOT_SUPPORT);
|
|
}
|
|
|
|
SCESTATUS rc;
|
|
|
|
//
|
|
// initialize jet engine in system context
|
|
//
|
|
rc = SceJetInitialize(NULL);
|
|
|
|
if ( SCESTATUS_SUCCESS != rc ) {
|
|
return(rc);
|
|
}
|
|
|
|
//
|
|
// impersonate the client
|
|
//
|
|
|
|
rc = RpcImpersonateClient( NULL );
|
|
|
|
if (rc != RPC_S_OK) {
|
|
|
|
*pContext = NULL;
|
|
rc = ScepDosErrorToSceStatus(rc);
|
|
|
|
} else {
|
|
|
|
|
|
BOOL bAdminSidInToken = FALSE;
|
|
|
|
rc = ScepDosErrorToSceStatus(ScepIsAdminLoggedOn(&bAdminSidInToken, TRUE));
|
|
|
|
if (SCESTATUS_SUCCESS != rc || FALSE == bAdminSidInToken) {
|
|
RpcRevertToSelf();
|
|
return SCESTATUS_SPECIAL_ACCOUNT;
|
|
}
|
|
|
|
|
|
//
|
|
// OpenDatabase is not blocked by any task.
|
|
//
|
|
|
|
EnterCriticalSection(&ContextSync);
|
|
|
|
__try {
|
|
|
|
rc = ScepOpenDatabase(
|
|
(PCWSTR)DatabaseName,
|
|
OpenOption,
|
|
SCEJET_OPEN_READ_WRITE,
|
|
(PSCECONTEXT *)pContext
|
|
);
|
|
|
|
} __except (EXCEPTION_EXECUTE_HANDLER) {
|
|
|
|
rc = SCESTATUS_EXCEPTION_IN_SERVER;
|
|
}
|
|
|
|
if ( *pContext && SCESTATUS_SUCCESS == rc ) {
|
|
//
|
|
// if a context is to be returned, add it to the open context list
|
|
//
|
|
ScepAddToOpenContext((PSCECONTEXT)(*pContext));
|
|
}
|
|
|
|
LeaveCriticalSection(&ContextSync);
|
|
|
|
RpcRevertToSelf();
|
|
}
|
|
|
|
if ( rc != SCESTATUS_SUCCESS ) {
|
|
//
|
|
// make sure jet engine is terminated if no other acitve clients
|
|
//
|
|
ScepIfTerminateEngine();
|
|
}
|
|
|
|
return(rc);
|
|
}
|
|
|
|
|
|
SCEPR_STATUS
|
|
SceRpcCloseDatabase(
|
|
IN OUT SCEPR_CONTEXT *pContext
|
|
)
|
|
/*
|
|
Routine Description:
|
|
|
|
Request to close the context. If other threads on working under the
|
|
same context, the close request is send to the task list and when
|
|
all pending tasks on the same context are done, the context is freed.
|
|
|
|
This API does not wait for the closure of the database.
|
|
|
|
Arguments:
|
|
|
|
Context - the database context
|
|
|
|
Return Value:
|
|
|
|
SCEPR_STATUS
|
|
*/
|
|
{
|
|
SCESTATUS rc;
|
|
|
|
//
|
|
// impersonate the client
|
|
//
|
|
|
|
UINT ClientLocalFlag = 0;
|
|
|
|
if ( RPC_S_OK != I_RpcBindingIsClientLocal( NULL, &ClientLocalFlag) ||
|
|
0 == ClientLocalFlag ){
|
|
|
|
//
|
|
// to prevent denial-of-service type attacks,
|
|
// do not allow remote RPC
|
|
//
|
|
|
|
return SCESTATUS_ACCESS_DENIED;
|
|
|
|
}
|
|
|
|
rc = RpcImpersonateClient( NULL );
|
|
|
|
if (rc != RPC_S_OK) {
|
|
return( ScepDosErrorToSceStatus(rc) );
|
|
}
|
|
|
|
BOOL bAdminSidInToken = FALSE;
|
|
|
|
rc = ScepDosErrorToSceStatus(ScepIsAdminLoggedOn(&bAdminSidInToken, TRUE));
|
|
|
|
if (SCESTATUS_SUCCESS != rc || FALSE == bAdminSidInToken) {
|
|
RpcRevertToSelf();
|
|
return SCESTATUS_SPECIAL_ACCOUNT;
|
|
}
|
|
//
|
|
// remove this from the open context too
|
|
//
|
|
|
|
|
|
if ( pContext && *pContext ) {
|
|
|
|
rc = ScepValidateAndCloseDatabase((PSCECONTEXT)(*pContext));
|
|
|
|
*pContext = NULL;
|
|
|
|
}
|
|
|
|
RpcRevertToSelf();
|
|
|
|
return((SCEPR_STATUS)rc);
|
|
}
|
|
|
|
|
|
|
|
SCEPR_STATUS
|
|
SceRpcGetDatabaseDescription(
|
|
IN SCEPR_CONTEXT Context,
|
|
OUT wchar_t __RPC_FAR **Description
|
|
)
|
|
/*
|
|
Routine Description:
|
|
|
|
Query database description from the context
|
|
|
|
Arguments:
|
|
|
|
Context - the database context
|
|
|
|
Description - the output buffer of description
|
|
|
|
Return Value:
|
|
|
|
SCEPR_STATUS
|
|
*/
|
|
{
|
|
if ( !Context || !Description ) {
|
|
|
|
return(SCESTATUS_INVALID_PARAMETER);
|
|
}
|
|
|
|
UINT ClientLocalFlag = 0;
|
|
|
|
if ( RPC_S_OK != I_RpcBindingIsClientLocal( NULL, &ClientLocalFlag) ||
|
|
0 == ClientLocalFlag ){
|
|
|
|
//
|
|
// to prevent denial-of-service type attacks,
|
|
// do not allow remote RPC
|
|
//
|
|
|
|
return SCESTATUS_ACCESS_DENIED;
|
|
|
|
}
|
|
|
|
SCESTATUS rc;
|
|
|
|
//
|
|
// impersonate the client
|
|
//
|
|
|
|
rc = RpcImpersonateClient( NULL );
|
|
|
|
if (rc != RPC_S_OK) {
|
|
return( ScepDosErrorToSceStatus(rc) );
|
|
}
|
|
|
|
BOOL bAdminSidInToken = FALSE;
|
|
|
|
rc = ScepDosErrorToSceStatus(ScepIsAdminLoggedOn(&bAdminSidInToken, TRUE));
|
|
|
|
if (SCESTATUS_SUCCESS != rc || FALSE == bAdminSidInToken) {
|
|
RpcRevertToSelf();
|
|
return SCESTATUS_SPECIAL_ACCOUNT;
|
|
}
|
|
|
|
//
|
|
// the context needs to be locked in case another thread
|
|
// is calling close database on it
|
|
//
|
|
|
|
PSCESRV_DBTASK pTask=NULL;
|
|
|
|
rc = ScepValidateAndLockContext((PSCECONTEXT)Context,
|
|
SCE_TASK_LOCK,
|
|
FALSE,
|
|
&pTask);
|
|
|
|
if (SCESTATUS_SUCCESS == rc ) {
|
|
|
|
#ifdef SCE_JET_TRAN
|
|
rc = SceJetJetErrorToSceStatus(
|
|
JetSetSessionContext(
|
|
((PSCECONTEXT)Context)->JetSessionID,
|
|
(ULONG_PTR)Context
|
|
));
|
|
|
|
if ( SCESTATUS_SUCCESS == rc ) {
|
|
#endif
|
|
//
|
|
// do not need to lock the context because
|
|
// it's reading information from one record table
|
|
//
|
|
|
|
rc = SceJetGetDescription(
|
|
(PSCECONTEXT)Context,
|
|
(PWSTR *)Description
|
|
);
|
|
|
|
#ifdef SCE_JET_TRAN
|
|
JetResetSessionContext(((PSCECONTEXT)Context)->JetSessionID);
|
|
|
|
}
|
|
#endif
|
|
//
|
|
// remove the context from task table
|
|
//
|
|
|
|
ScepRemoveTask(pTask);
|
|
|
|
}
|
|
|
|
RpcRevertToSelf();
|
|
|
|
return((SCEPR_STATUS)rc);
|
|
}
|
|
|
|
|
|
SCEPR_STATUS
|
|
SceRpcGetDBTimeStamp(
|
|
IN SCEPR_CONTEXT Context,
|
|
OUT PLARGE_INTEGER ptsConfig,
|
|
OUT PLARGE_INTEGER ptsAnalysis
|
|
)
|
|
/*
|
|
Routine Description:
|
|
|
|
Query the last configuration and analysis time stamp from the context.
|
|
|
|
Arguments:
|
|
|
|
Context - the database context
|
|
|
|
ptsConfig - the last configuration time stamp
|
|
|
|
ptsAnalysis - the last analysis time stamp
|
|
|
|
Return Value:
|
|
|
|
SCEPR_STATUS
|
|
*/
|
|
{
|
|
if ( !Context || !ptsConfig || !ptsAnalysis ) {
|
|
return(SCESTATUS_INVALID_PARAMETER);
|
|
}
|
|
|
|
UINT ClientLocalFlag = 0;
|
|
|
|
if ( RPC_S_OK != I_RpcBindingIsClientLocal( NULL, &ClientLocalFlag) ||
|
|
0 == ClientLocalFlag ){
|
|
|
|
//
|
|
// to prevent denial-of-service type attacks,
|
|
// do not allow remote RPC
|
|
//
|
|
|
|
return SCESTATUS_ACCESS_DENIED;
|
|
|
|
}
|
|
|
|
SCESTATUS rc;
|
|
|
|
//
|
|
// impersonate the client
|
|
//
|
|
|
|
rc = RpcImpersonateClient( NULL );
|
|
|
|
if (rc != RPC_S_OK) {
|
|
return( ScepDosErrorToSceStatus(rc) );
|
|
}
|
|
|
|
BOOL bAdminSidInToken = FALSE;
|
|
|
|
rc = ScepDosErrorToSceStatus(ScepIsAdminLoggedOn(&bAdminSidInToken, TRUE));
|
|
|
|
if (SCESTATUS_SUCCESS != rc || FALSE == bAdminSidInToken) {
|
|
RpcRevertToSelf();
|
|
return SCESTATUS_SPECIAL_ACCOUNT;
|
|
}
|
|
|
|
//
|
|
// the context needs to be locked in case another thread
|
|
// is calling close database on it
|
|
//
|
|
|
|
PSCESRV_DBTASK pTask=NULL;
|
|
|
|
rc = ScepValidateAndLockContext((PSCECONTEXT)Context,
|
|
SCE_TASK_LOCK,
|
|
FALSE,
|
|
&pTask);
|
|
|
|
if (SCESTATUS_SUCCESS == rc ) {
|
|
|
|
#ifdef SCE_JET_TRAN
|
|
rc = SceJetJetErrorToSceStatus(
|
|
JetSetSessionContext(
|
|
((PSCECONTEXT)Context)->JetSessionID,
|
|
(ULONG_PTR)Context
|
|
));
|
|
|
|
if ( SCESTATUS_SUCCESS == rc ) {
|
|
#endif
|
|
//
|
|
// do not need to lock the context because
|
|
// it's reading information from one record table
|
|
//
|
|
|
|
rc = SceJetGetTimeStamp(
|
|
(PSCECONTEXT)Context,
|
|
ptsConfig,
|
|
ptsAnalysis
|
|
);
|
|
|
|
#ifdef SCE_JET_TRAN
|
|
JetResetSessionContext(((PSCECONTEXT)Context)->JetSessionID);
|
|
|
|
}
|
|
#endif
|
|
//
|
|
// remove the context from task table
|
|
//
|
|
|
|
ScepRemoveTask(pTask);
|
|
|
|
}
|
|
|
|
RpcRevertToSelf();
|
|
|
|
return((SCEPR_STATUS)rc);
|
|
|
|
}
|
|
|
|
|
|
SCEPR_STATUS
|
|
SceRpcGetObjectSecurity(
|
|
IN SCEPR_CONTEXT Context,
|
|
IN SCEPR_TYPE DbProfileType,
|
|
IN AREAPR Area,
|
|
IN wchar_t *ObjectName,
|
|
OUT PSCEPR_OBJECT_SECURITY __RPC_FAR *ObjSecurity
|
|
)
|
|
/*
|
|
Routine Description:
|
|
|
|
Query security settings for an object from the context database.
|
|
|
|
Arguments:
|
|
|
|
Context - the database context
|
|
|
|
DbProfileType - the database table type
|
|
|
|
Area - the security area (file, registry, so on.)
|
|
|
|
ObjectName - the object's full name
|
|
|
|
ObjSecurity - object security settings structure
|
|
|
|
Return Value:
|
|
|
|
SCEPR_STATUS
|
|
*/
|
|
{
|
|
if ( !Context || !ObjSecurity || !ObjectName ) {
|
|
return(SCESTATUS_INVALID_PARAMETER);
|
|
}
|
|
|
|
UINT ClientLocalFlag = 0;
|
|
|
|
if ( RPC_S_OK != I_RpcBindingIsClientLocal( NULL, &ClientLocalFlag) ||
|
|
0 == ClientLocalFlag ){
|
|
|
|
//
|
|
// to prevent denial-of-service type attacks,
|
|
// do not allow remote RPC
|
|
//
|
|
|
|
return SCESTATUS_ACCESS_DENIED;
|
|
|
|
}
|
|
|
|
SCESTATUS rc;
|
|
|
|
|
|
//
|
|
// impersonate the client
|
|
//
|
|
|
|
rc = RpcImpersonateClient( NULL );
|
|
|
|
if (rc != RPC_S_OK) {
|
|
return( ScepDosErrorToSceStatus(rc) );
|
|
}
|
|
|
|
BOOL bAdminSidInToken = FALSE;
|
|
|
|
rc = ScepDosErrorToSceStatus(ScepIsAdminLoggedOn(&bAdminSidInToken, TRUE));
|
|
|
|
if (SCESTATUS_SUCCESS != rc || FALSE == bAdminSidInToken) {
|
|
RpcRevertToSelf();
|
|
return SCESTATUS_SPECIAL_ACCOUNT;
|
|
}
|
|
|
|
//
|
|
// validate the context handle is a SCE context
|
|
// Only one database operation per context
|
|
//
|
|
|
|
PSCESRV_DBTASK pTask=NULL;
|
|
|
|
rc = ScepValidateAndLockContext((PSCECONTEXT)Context,
|
|
SCE_TASK_LOCK,
|
|
FALSE,
|
|
&pTask);
|
|
|
|
if (SCESTATUS_SUCCESS == rc ) {
|
|
|
|
//
|
|
// lock the context
|
|
//
|
|
|
|
if ( pTask ) {
|
|
EnterCriticalSection(&(pTask->Sync));
|
|
}
|
|
|
|
#ifdef SCE_JET_TRAN
|
|
rc = SceJetJetErrorToSceStatus(
|
|
JetSetSessionContext(
|
|
((PSCECONTEXT)Context)->JetSessionID,
|
|
(ULONG_PTR)Context
|
|
));
|
|
|
|
if ( SCESTATUS_SUCCESS == rc ) {
|
|
#endif
|
|
//
|
|
// query the information now
|
|
//
|
|
|
|
rc = ScepGetObjectSecurity(
|
|
(PSCECONTEXT)Context,
|
|
(SCETYPE)DbProfileType,
|
|
(AREA_INFORMATION)Area,
|
|
(PWSTR)ObjectName,
|
|
(PSCE_OBJECT_SECURITY *)ObjSecurity
|
|
);
|
|
|
|
#ifdef SCE_JET_TRAN
|
|
JetResetSessionContext(((PSCECONTEXT)Context)->JetSessionID);
|
|
|
|
}
|
|
#endif
|
|
//
|
|
// unlock the context
|
|
//
|
|
|
|
if ( pTask ) {
|
|
LeaveCriticalSection(&(pTask->Sync));
|
|
}
|
|
|
|
//
|
|
// remove the context from task table
|
|
//
|
|
|
|
ScepRemoveTask(pTask);
|
|
|
|
//
|
|
// convert the security descriptor
|
|
//
|
|
if ( ( SCESTATUS_SUCCESS == rc ) &&
|
|
*ObjSecurity &&
|
|
(*ObjSecurity)->pSecurityDescriptor ) {
|
|
|
|
//
|
|
// there is a security descriptor, it must be self relative
|
|
// because it's returned from the SDDL api.
|
|
//
|
|
ULONG nLen = RtlLengthSecurityDescriptor (
|
|
(PSECURITY_DESCRIPTOR)((*ObjSecurity)->pSecurityDescriptor));
|
|
|
|
if ( nLen > 0 ) {
|
|
//
|
|
// create a wrapper node to contain the security descriptor
|
|
//
|
|
|
|
PSCEPR_SR_SECURITY_DESCRIPTOR pNewWrap;
|
|
pNewWrap = (PSCEPR_SR_SECURITY_DESCRIPTOR)ScepAlloc(0, sizeof(SCEPR_SR_SECURITY_DESCRIPTOR));
|
|
if ( pNewWrap ) {
|
|
|
|
//
|
|
// assign the wrap to the structure
|
|
//
|
|
pNewWrap->SecurityDescriptor = (UCHAR *)((*ObjSecurity)->pSecurityDescriptor);
|
|
pNewWrap->Length = nLen;
|
|
|
|
(*ObjSecurity)->pSecurityDescriptor = (SCEPR_SR_SECURITY_DESCRIPTOR *)pNewWrap;
|
|
|
|
} else {
|
|
//
|
|
// no memory is available, but still continue to parse all nodes
|
|
//
|
|
nLen = 0;
|
|
}
|
|
}
|
|
|
|
if ( nLen == 0 ) {
|
|
//
|
|
// something wrong with this security descriptor
|
|
// free the buffer
|
|
//
|
|
ScepFree((*ObjSecurity)->pSecurityDescriptor);
|
|
(*ObjSecurity)->pSecurityDescriptor = NULL;
|
|
(*ObjSecurity)->SeInfo = 0;
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
RpcRevertToSelf();
|
|
|
|
return((SCEPR_STATUS)rc);
|
|
}
|
|
|
|
|
|
|
|
SCEPR_STATUS
|
|
SceRpcGetAnalysisSummary(
|
|
IN SCEPR_CONTEXT Context,
|
|
IN AREAPR Area,
|
|
OUT PDWORD pCount
|
|
)
|
|
/*
|
|
Routine Description:
|
|
|
|
Query security settings for an object from the context database.
|
|
|
|
Arguments:
|
|
|
|
Context - the database context
|
|
|
|
Area - the security area (file, registry, so on.)
|
|
|
|
pCount - the output count
|
|
|
|
Return Value:
|
|
|
|
SCEPR_STATUS
|
|
*/
|
|
{
|
|
if ( !Context || !pCount ) {
|
|
return(SCESTATUS_INVALID_PARAMETER);
|
|
}
|
|
|
|
UINT ClientLocalFlag = 0;
|
|
|
|
if ( RPC_S_OK != I_RpcBindingIsClientLocal( NULL, &ClientLocalFlag) ||
|
|
0 == ClientLocalFlag ){
|
|
|
|
//
|
|
// to prevent denial-of-service type attacks,
|
|
// do not allow remote RPC
|
|
//
|
|
|
|
return SCESTATUS_ACCESS_DENIED;
|
|
|
|
}
|
|
|
|
SCESTATUS rc;
|
|
|
|
//
|
|
// impersonate the client
|
|
//
|
|
|
|
rc = RpcImpersonateClient( NULL );
|
|
|
|
if (rc != RPC_S_OK) {
|
|
return( ScepDosErrorToSceStatus(rc) );
|
|
}
|
|
|
|
BOOL bAdminSidInToken = FALSE;
|
|
|
|
rc = ScepDosErrorToSceStatus(ScepIsAdminLoggedOn(&bAdminSidInToken, TRUE));
|
|
|
|
if (SCESTATUS_SUCCESS != rc || FALSE == bAdminSidInToken) {
|
|
RpcRevertToSelf();
|
|
return SCESTATUS_SPECIAL_ACCOUNT;
|
|
}
|
|
|
|
//
|
|
// validate the context handle is a SCE context
|
|
// Only one database operation per context
|
|
//
|
|
|
|
PSCESRV_DBTASK pTask=NULL;
|
|
|
|
rc = ScepValidateAndLockContext((PSCECONTEXT)Context,
|
|
SCE_TASK_LOCK,
|
|
FALSE,
|
|
&pTask);
|
|
|
|
if (SCESTATUS_SUCCESS == rc ) {
|
|
|
|
//
|
|
// lock the context
|
|
//
|
|
|
|
if ( pTask ) {
|
|
EnterCriticalSection(&(pTask->Sync));
|
|
}
|
|
|
|
#ifdef SCE_JET_TRAN
|
|
rc = SceJetJetErrorToSceStatus(
|
|
JetSetSessionContext(
|
|
((PSCECONTEXT)Context)->JetSessionID,
|
|
(ULONG_PTR)Context
|
|
));
|
|
|
|
if ( SCESTATUS_SUCCESS == rc ) {
|
|
#endif
|
|
//
|
|
// query the information now
|
|
//
|
|
|
|
rc = ScepGetAnalysisSummary(
|
|
(PSCECONTEXT)Context,
|
|
(AREA_INFORMATION)Area,
|
|
pCount
|
|
);
|
|
|
|
#ifdef SCE_JET_TRAN
|
|
JetResetSessionContext(((PSCECONTEXT)Context)->JetSessionID);
|
|
|
|
}
|
|
#endif
|
|
//
|
|
// unlock the context
|
|
//
|
|
|
|
if ( pTask ) {
|
|
LeaveCriticalSection(&(pTask->Sync));
|
|
}
|
|
|
|
//
|
|
// remove the context from task table
|
|
//
|
|
|
|
ScepRemoveTask(pTask);
|
|
|
|
}
|
|
|
|
RpcRevertToSelf();
|
|
|
|
return((SCEPR_STATUS)rc);
|
|
}
|
|
|
|
|
|
|
|
SCEPR_STATUS
|
|
SceRpcAnalyzeSystem(
|
|
IN handle_t binding_h,
|
|
IN wchar_t *InfFileName OPTIONAL,
|
|
IN wchar_t *DatabaseName OPTIONAL,
|
|
IN wchar_t *LogFileName OPTIONAL,
|
|
IN AREAPR Area,
|
|
IN DWORD AnalyzeOptions,
|
|
IN DWORD pebSize,
|
|
IN UCHAR *pebClient OPTIONAL,
|
|
OUT PDWORD pdWarning OPTIONAL
|
|
)
|
|
/*
|
|
Routine Description:
|
|
|
|
Analyze the system using the Inf template and/or existing
|
|
database info
|
|
|
|
Arguments:
|
|
|
|
See ScepAnalyzeSystem
|
|
|
|
Return Value:
|
|
|
|
SCEPR_STATUS
|
|
*/
|
|
{
|
|
SCESTATUS rc;
|
|
|
|
if ( bStopRequest ) {
|
|
return(SCESTATUS_SERVICE_NOT_SUPPORT);
|
|
}
|
|
|
|
UINT ClientLocalFlag = 0;
|
|
|
|
if ( RPC_S_OK != I_RpcBindingIsClientLocal( NULL, &ClientLocalFlag) ||
|
|
0 == ClientLocalFlag ){
|
|
|
|
//
|
|
// to prevent denial-of-service type attacks,
|
|
// do not allow remote RPC
|
|
//
|
|
|
|
return SCESTATUS_ACCESS_DENIED;
|
|
|
|
}
|
|
|
|
//
|
|
// initialize jet engine in system context
|
|
//
|
|
rc = SceJetInitialize(NULL);
|
|
|
|
if ( rc != SCESTATUS_SUCCESS ) {
|
|
return(rc);
|
|
}
|
|
|
|
//
|
|
// impersonate the client, return DWORD error code
|
|
//
|
|
|
|
rc = RpcImpersonateClient( NULL );
|
|
|
|
if (rc != RPC_S_OK) {
|
|
|
|
ScepIfTerminateEngine();
|
|
|
|
return( ScepDosErrorToSceStatus(rc) );
|
|
}
|
|
|
|
BOOL bAdminSidInToken = FALSE;
|
|
|
|
rc = ScepDosErrorToSceStatus(ScepIsAdminLoggedOn(&bAdminSidInToken, TRUE));
|
|
|
|
if (SCESTATUS_SUCCESS != rc || FALSE == bAdminSidInToken) {
|
|
RpcRevertToSelf();
|
|
return SCESTATUS_SPECIAL_ACCOUNT;
|
|
}
|
|
|
|
//
|
|
// get the database name
|
|
//
|
|
|
|
BOOL bAdminLogon=FALSE;
|
|
LPTSTR DefProfile=NULL;
|
|
|
|
__try {
|
|
|
|
rc = ScepGetDefaultDatabase(
|
|
(AnalyzeOptions & SCE_GENERATE_ROLLBACK) ? NULL : (LPCTSTR)DatabaseName,
|
|
AnalyzeOptions,
|
|
(LPCTSTR)LogFileName,
|
|
&bAdminLogon,
|
|
&DefProfile
|
|
);
|
|
|
|
} __except (EXCEPTION_EXECUTE_HANDLER) {
|
|
|
|
rc = ERROR_EXCEPTION_IN_SERVICE;
|
|
}
|
|
|
|
if ( (AnalyzeOptions & SCE_GENERATE_ROLLBACK)
|
|
&& !bAdminLogon ) {
|
|
//
|
|
// only allow admin to use system database to generate rollback
|
|
// is this the correct design?
|
|
//
|
|
rc = ERROR_ACCESS_DENIED;
|
|
}
|
|
|
|
if ( ERROR_SUCCESS == rc && DefProfile ) {
|
|
|
|
//
|
|
// validate access to the database
|
|
//
|
|
rc = ScepDatabaseAccessGranted( DefProfile,
|
|
FILE_GENERIC_READ | FILE_GENERIC_WRITE,
|
|
TRUE
|
|
);
|
|
}
|
|
|
|
rc = ScepDosErrorToSceStatus(rc);
|
|
|
|
if ( SCESTATUS_SUCCESS == rc && DefProfile ) {
|
|
|
|
//
|
|
// validate the database to see if there is any configuration/
|
|
// analysis running on other threads
|
|
//
|
|
|
|
rc = ScepLockEngine(DefProfile);
|
|
|
|
if ( SCESTATUS_SUCCESS == rc ) {
|
|
|
|
t_pebClient = (LPVOID)pebClient;
|
|
t_pebSize = pebSize;
|
|
|
|
//
|
|
// it's ok to continue this operation
|
|
// no other threads are running configuration/analysis
|
|
// based on the same database
|
|
//
|
|
|
|
DWORD dOptions = AnalyzeOptions;
|
|
if ( !(AnalyzeOptions & SCE_GENERATE_ROLLBACK) ) {
|
|
if ( !DatabaseName ||
|
|
( bAdminLogon && SceIsSystemDatabase(DatabaseName)) ) {
|
|
|
|
dOptions |= SCE_SYSTEM_DB;
|
|
}
|
|
}
|
|
|
|
__try {
|
|
|
|
rc = ScepAnalyzeSystem(
|
|
(LPCTSTR)InfFileName,
|
|
DefProfile,
|
|
dOptions,
|
|
bAdminLogon,
|
|
(AREA_INFORMATION)Area,
|
|
pdWarning,
|
|
(AnalyzeOptions & SCE_GENERATE_ROLLBACK) ? DatabaseName : NULL
|
|
);
|
|
|
|
} __except (EXCEPTION_EXECUTE_HANDLER) {
|
|
|
|
rc = SCESTATUS_EXCEPTION_IN_SERVER;
|
|
}
|
|
|
|
//
|
|
// unlock the engine for this database
|
|
//
|
|
|
|
ScepUnlockEngine(DefProfile);
|
|
}
|
|
}
|
|
|
|
if ( DefProfile && DefProfile != DatabaseName ) {
|
|
ScepFree(DefProfile);
|
|
|
|
}
|
|
|
|
ScepLogClose();
|
|
|
|
//
|
|
// change context back
|
|
//
|
|
|
|
RpcRevertToSelf();
|
|
|
|
//
|
|
// start a timer queue to check to see if there is active tasks/contexts
|
|
// if not, terminate jet engine
|
|
//
|
|
ScepIfTerminateEngine();
|
|
|
|
return((SCEPR_STATUS)rc);
|
|
}
|
|
|
|
|
|
SCEPR_STATUS
|
|
SceRpcUpdateDatabaseInfo(
|
|
IN SCEPR_CONTEXT Context,
|
|
IN SCEPR_TYPE ProfileType,
|
|
IN AREAPR Area,
|
|
IN PSCEPR_PROFILE_INFO pInfo,
|
|
IN DWORD dwMode
|
|
)
|
|
/*
|
|
Routine Description:
|
|
|
|
Update database in the context using pInfo
|
|
|
|
Arguments:
|
|
|
|
Context - the database context
|
|
|
|
ProfileType - the database table type
|
|
|
|
Area - the security area (security policy... except objects's area)
|
|
|
|
pInfo - the info to update
|
|
|
|
Return Value:
|
|
|
|
SCEPR_STATUS
|
|
*/
|
|
{
|
|
if ( !Context || !pInfo ) {
|
|
return(SCESTATUS_INVALID_PARAMETER);
|
|
}
|
|
|
|
UINT ClientLocalFlag = 0;
|
|
|
|
if ( RPC_S_OK != I_RpcBindingIsClientLocal( NULL, &ClientLocalFlag) ||
|
|
0 == ClientLocalFlag ){
|
|
|
|
//
|
|
// to prevent denial-of-service type attacks,
|
|
// do not allow remote RPC
|
|
//
|
|
|
|
return SCESTATUS_ACCESS_DENIED;
|
|
|
|
}
|
|
|
|
SCESTATUS rc;
|
|
|
|
//
|
|
// impersonate the client
|
|
//
|
|
|
|
rc = RpcImpersonateClient( NULL );
|
|
|
|
if (rc != RPC_S_OK) {
|
|
return( ScepDosErrorToSceStatus(rc) );
|
|
}
|
|
|
|
|
|
BOOL bAdminSidInToken = FALSE;
|
|
|
|
rc = ScepDosErrorToSceStatus(ScepIsAdminLoggedOn(&bAdminSidInToken, TRUE));
|
|
|
|
if (SCESTATUS_SUCCESS != rc || FALSE == bAdminSidInToken) {
|
|
RpcRevertToSelf();
|
|
return SCESTATUS_SPECIAL_ACCOUNT;
|
|
}
|
|
|
|
//
|
|
// validate the context handle is a SCE context
|
|
// Only one database operation per context
|
|
//
|
|
|
|
PSCESRV_DBTASK pTask=NULL;
|
|
|
|
rc = ScepValidateAndLockContext((PSCECONTEXT)Context,
|
|
SCE_TASK_LOCK,
|
|
TRUE,
|
|
&pTask);
|
|
|
|
if (SCESTATUS_SUCCESS == rc ) {
|
|
|
|
PSCEPR_SERVICES pOldServices = pInfo->pServices;
|
|
|
|
//
|
|
// Convert SCEPR_PROFILE_INFO into SCE_PROFILE_INFO
|
|
//
|
|
if ( (Area & AREA_SYSTEM_SERVICE) &&
|
|
pOldServices ) {
|
|
|
|
rc = ScepConvertServices( (PVOID *)&(pInfo->pServices), TRUE );
|
|
|
|
} else {
|
|
pInfo->pServices = NULL;
|
|
}
|
|
|
|
|
|
if ( SCESTATUS_SUCCESS == rc ) {
|
|
|
|
//
|
|
// lock the context
|
|
//
|
|
|
|
if ( pTask ) {
|
|
EnterCriticalSection(&(pTask->Sync));
|
|
}
|
|
|
|
__try {
|
|
|
|
#ifdef SCE_JET_TRAN
|
|
rc = SceJetJetErrorToSceStatus(
|
|
JetSetSessionContext(
|
|
((PSCECONTEXT)Context)->JetSessionID,
|
|
(ULONG_PTR)Context
|
|
));
|
|
|
|
if ( SCESTATUS_SUCCESS == rc ) {
|
|
#endif
|
|
//
|
|
// update the information now
|
|
//
|
|
|
|
if ( dwMode & SCE_UPDATE_LOCAL_POLICY ) {
|
|
|
|
//
|
|
// update local policy only
|
|
//
|
|
rc = ScepUpdateLocalTable(
|
|
(PSCECONTEXT)Context,
|
|
(AREA_INFORMATION)Area,
|
|
(PSCE_PROFILE_INFO)pInfo,
|
|
dwMode
|
|
);
|
|
} else {
|
|
//
|
|
// update the database (SMP and SAP)
|
|
//
|
|
rc = ScepUpdateDatabaseInfo(
|
|
(PSCECONTEXT)Context,
|
|
(AREA_INFORMATION)Area,
|
|
(PSCE_PROFILE_INFO)pInfo
|
|
);
|
|
}
|
|
|
|
#ifdef SCE_JET_TRAN
|
|
JetResetSessionContext(((PSCECONTEXT)Context)->JetSessionID);
|
|
|
|
}
|
|
#endif
|
|
|
|
} __except (EXCEPTION_EXECUTE_HANDLER) {
|
|
|
|
rc = SCESTATUS_EXCEPTION_IN_SERVER;
|
|
}
|
|
|
|
//
|
|
// unlock the context
|
|
//
|
|
|
|
if ( pTask ) {
|
|
LeaveCriticalSection(&(pTask->Sync));
|
|
}
|
|
|
|
ScepFreeConvertedServices( pInfo->pServices, FALSE );
|
|
|
|
}
|
|
|
|
pInfo->pServices = pOldServices;
|
|
|
|
//
|
|
// remove the context from task table
|
|
//
|
|
|
|
ScepRemoveTask(pTask);
|
|
|
|
}
|
|
|
|
RpcRevertToSelf();
|
|
|
|
return((SCEPR_STATUS)rc);
|
|
}
|
|
|
|
|
|
|
|
SCEPR_STATUS
|
|
SceRpcUpdateObjectInfo(
|
|
IN SCEPR_CONTEXT Context,
|
|
IN AREAPR Area,
|
|
IN wchar_t *ObjectName,
|
|
IN DWORD NameLen,
|
|
IN BYTE ConfigStatus,
|
|
IN BOOL IsContainer,
|
|
IN SCEPR_SR_SECURITY_DESCRIPTOR *pSD OPTIONAL,
|
|
IN SECURITY_INFORMATION SeInfo,
|
|
OUT PBYTE pAnalysisStatus
|
|
)
|
|
/*
|
|
Routine Description:
|
|
|
|
Update object's security settings in the database.
|
|
|
|
Arguments:
|
|
|
|
See ScepUpdateObjectInfo
|
|
|
|
Return Value:
|
|
|
|
SCEPR_STATUS
|
|
*/
|
|
{
|
|
if ( !Context || !ObjectName ) {
|
|
return(SCESTATUS_INVALID_PARAMETER);
|
|
}
|
|
|
|
SCESTATUS rc;
|
|
|
|
UINT ClientLocalFlag = 0;
|
|
|
|
if ( RPC_S_OK != I_RpcBindingIsClientLocal( NULL, &ClientLocalFlag) ||
|
|
0 == ClientLocalFlag ){
|
|
|
|
//
|
|
// to prevent denial-of-service type attacks,
|
|
// do not allow remote RPC
|
|
//
|
|
|
|
return SCESTATUS_ACCESS_DENIED;
|
|
|
|
}
|
|
|
|
//
|
|
// impersonate the client
|
|
//
|
|
|
|
rc = RpcImpersonateClient( NULL );
|
|
|
|
if (rc != RPC_S_OK) {
|
|
return( ScepDosErrorToSceStatus(rc) );
|
|
}
|
|
|
|
BOOL bAdminSidInToken = FALSE;
|
|
|
|
rc = ScepDosErrorToSceStatus(ScepIsAdminLoggedOn(&bAdminSidInToken, TRUE));
|
|
|
|
if (SCESTATUS_SUCCESS != rc || FALSE == bAdminSidInToken) {
|
|
RpcRevertToSelf();
|
|
return SCESTATUS_SPECIAL_ACCOUNT;
|
|
}
|
|
|
|
//
|
|
// validate the context handle is a SCE context
|
|
// Only one database operation per context
|
|
//
|
|
|
|
PSCESRV_DBTASK pTask=NULL;
|
|
|
|
rc = ScepValidateAndLockContext((PSCECONTEXT)Context,
|
|
SCE_TASK_LOCK,
|
|
TRUE,
|
|
&pTask);
|
|
|
|
if (SCESTATUS_SUCCESS == rc ) {
|
|
|
|
//
|
|
// lock the context
|
|
//
|
|
|
|
if ( pTask ) {
|
|
EnterCriticalSection(&(pTask->Sync));
|
|
}
|
|
#ifdef SCE_JET_TRAN
|
|
rc = SceJetJetErrorToSceStatus(
|
|
JetSetSessionContext(
|
|
((PSCECONTEXT)Context)->JetSessionID,
|
|
(ULONG_PTR)Context
|
|
));
|
|
|
|
if ( SCESTATUS_SUCCESS == rc ) {
|
|
#endif
|
|
//
|
|
// update the object info now
|
|
//
|
|
|
|
__try {
|
|
|
|
rc = ScepUpdateObjectInfo(
|
|
(PSCECONTEXT)Context,
|
|
(AREA_INFORMATION)Area,
|
|
(PWSTR)ObjectName,
|
|
NameLen,
|
|
ConfigStatus,
|
|
IsContainer,
|
|
pSD ? (PSECURITY_DESCRIPTOR)(pSD->SecurityDescriptor) : NULL,
|
|
SeInfo,
|
|
pAnalysisStatus
|
|
);
|
|
|
|
} __except (EXCEPTION_EXECUTE_HANDLER) {
|
|
|
|
rc = SCESTATUS_EXCEPTION_IN_SERVER;
|
|
}
|
|
|
|
#ifdef SCE_JET_TRAN
|
|
JetResetSessionContext(((PSCECONTEXT)Context)->JetSessionID);
|
|
|
|
}
|
|
#endif
|
|
//
|
|
// unlock the context
|
|
//
|
|
|
|
if ( pTask ) {
|
|
LeaveCriticalSection(&(pTask->Sync));
|
|
}
|
|
|
|
//
|
|
// remove the context from task table
|
|
//
|
|
|
|
ScepRemoveTask(pTask);
|
|
|
|
}
|
|
|
|
RpcRevertToSelf();
|
|
|
|
return((SCEPR_STATUS)rc);
|
|
}
|
|
|
|
|
|
|
|
SCEPR_STATUS
|
|
SceRpcStartTransaction(
|
|
IN SCEPR_CONTEXT Context
|
|
)
|
|
/*
|
|
Routine Description:
|
|
|
|
Start a transaction on the context. If other threads sharing the same
|
|
context, their changes will also be controlled by this transaction.
|
|
|
|
It's the caller's responsible to not share the same context for
|
|
transactioning.
|
|
|
|
Arguments:
|
|
|
|
See SceJetStartTransaction
|
|
|
|
Return Value:
|
|
|
|
SCEPR_STATUS
|
|
*/
|
|
{
|
|
if ( !Context ) {
|
|
return(SCESTATUS_INVALID_PARAMETER);
|
|
}
|
|
|
|
SCESTATUS rc;
|
|
|
|
UINT ClientLocalFlag = 0;
|
|
|
|
if ( RPC_S_OK != I_RpcBindingIsClientLocal( NULL, &ClientLocalFlag) ||
|
|
0 == ClientLocalFlag ){
|
|
|
|
//
|
|
// to prevent denial-of-service type attacks,
|
|
// do not allow remote RPC
|
|
//
|
|
|
|
return SCESTATUS_ACCESS_DENIED;
|
|
|
|
}
|
|
|
|
//
|
|
// impersonate the client
|
|
//
|
|
|
|
rc = RpcImpersonateClient( NULL );
|
|
|
|
if (rc != RPC_S_OK) {
|
|
return( ScepDosErrorToSceStatus(rc) );
|
|
}
|
|
|
|
BOOL bAdminSidInToken = FALSE;
|
|
|
|
rc = ScepDosErrorToSceStatus(ScepIsAdminLoggedOn(&bAdminSidInToken, TRUE));
|
|
|
|
if (SCESTATUS_SUCCESS != rc || FALSE == bAdminSidInToken) {
|
|
RpcRevertToSelf();
|
|
return SCESTATUS_SPECIAL_ACCOUNT;
|
|
}
|
|
|
|
//
|
|
// validate the context handle is a SCE context
|
|
// Only one database operation per context
|
|
//
|
|
|
|
PSCESRV_DBTASK pTask=NULL;
|
|
|
|
rc = ScepValidateAndLockContext((PSCECONTEXT)Context,
|
|
SCE_TASK_LOCK,
|
|
TRUE,
|
|
&pTask);
|
|
|
|
if (SCESTATUS_SUCCESS == rc ) {
|
|
|
|
//
|
|
// lock the context
|
|
//
|
|
|
|
if ( pTask ) {
|
|
EnterCriticalSection(&(pTask->Sync));
|
|
}
|
|
|
|
//
|
|
// start transaction on this context
|
|
//
|
|
#ifdef SCE_JET_TRAN
|
|
rc = SceJetJetErrorToSceStatus(
|
|
JetSetSessionContext(
|
|
((PSCECONTEXT)Context)->JetSessionID,
|
|
(ULONG_PTR)Context
|
|
));
|
|
|
|
if ( SCESTATUS_SUCCESS == rc ) {
|
|
#endif
|
|
rc = SceJetStartTransaction(
|
|
(PSCECONTEXT)Context
|
|
);
|
|
|
|
#ifdef SCE_JET_TRAN
|
|
JetResetSessionContext(((PSCECONTEXT)Context)->JetSessionID);
|
|
|
|
}
|
|
#endif
|
|
|
|
//
|
|
// unlock the context
|
|
//
|
|
|
|
if ( pTask ) {
|
|
LeaveCriticalSection(&(pTask->Sync));
|
|
}
|
|
|
|
//
|
|
// remove the context from task table
|
|
//
|
|
|
|
ScepRemoveTask(pTask);
|
|
|
|
}
|
|
|
|
RpcRevertToSelf();
|
|
|
|
return((SCEPR_STATUS)rc);
|
|
}
|
|
|
|
|
|
|
|
SCEPR_STATUS
|
|
SceRpcCommitTransaction(
|
|
IN SCEPR_CONTEXT Context
|
|
)
|
|
/*
|
|
Routine Description:
|
|
|
|
Commit a transaction on the context. If other threads sharing the same
|
|
context, their changes will also be controlled by this transaction.
|
|
|
|
It's the caller's responsible to not share the same context for
|
|
transactioning.
|
|
|
|
Arguments:
|
|
|
|
See SceJetCommitTransaction
|
|
|
|
Return Value:
|
|
|
|
SCEPR_STATUS
|
|
*/
|
|
{
|
|
if ( !Context ) {
|
|
return(SCESTATUS_INVALID_PARAMETER);
|
|
}
|
|
|
|
SCESTATUS rc;
|
|
|
|
UINT ClientLocalFlag = 0;
|
|
|
|
if ( RPC_S_OK != I_RpcBindingIsClientLocal( NULL, &ClientLocalFlag) ||
|
|
0 == ClientLocalFlag ){
|
|
|
|
//
|
|
// to prevent denial-of-service type attacks,
|
|
// do not allow remote RPC
|
|
//
|
|
|
|
return SCESTATUS_ACCESS_DENIED;
|
|
|
|
}
|
|
|
|
//
|
|
// impersonate the client
|
|
//
|
|
|
|
rc = RpcImpersonateClient( NULL );
|
|
|
|
if (rc != RPC_S_OK) {
|
|
return( ScepDosErrorToSceStatus(rc) );
|
|
}
|
|
|
|
BOOL bAdminSidInToken = FALSE;
|
|
|
|
rc = ScepDosErrorToSceStatus(ScepIsAdminLoggedOn(&bAdminSidInToken, TRUE));
|
|
|
|
if (SCESTATUS_SUCCESS != rc || FALSE == bAdminSidInToken) {
|
|
RpcRevertToSelf();
|
|
return SCESTATUS_SPECIAL_ACCOUNT;
|
|
}
|
|
|
|
//
|
|
// validate the context handle is a SCE context
|
|
// Only one database operation per context
|
|
//
|
|
|
|
PSCESRV_DBTASK pTask=NULL;
|
|
|
|
rc = ScepValidateAndLockContext((PSCECONTEXT)Context,
|
|
SCE_TASK_LOCK,
|
|
TRUE,
|
|
&pTask);
|
|
|
|
if (SCESTATUS_SUCCESS == rc ) {
|
|
|
|
//
|
|
// lock the context
|
|
//
|
|
|
|
if ( pTask ) {
|
|
EnterCriticalSection(&(pTask->Sync));
|
|
}
|
|
|
|
//
|
|
// set the context to the jet session so thread id is not used for this
|
|
// operation.
|
|
//
|
|
#ifdef SCE_JET_TRAN
|
|
rc = SceJetJetErrorToSceStatus(
|
|
JetSetSessionContext(
|
|
((PSCECONTEXT)Context)->JetSessionID,
|
|
(ULONG_PTR)Context
|
|
));
|
|
|
|
if ( SCESTATUS_SUCCESS == rc ) {
|
|
#endif
|
|
//
|
|
// commit transaction on this context
|
|
//
|
|
|
|
rc = SceJetCommitTransaction(
|
|
(PSCECONTEXT)Context,
|
|
0
|
|
);
|
|
|
|
#ifdef SCE_JET_TRAN
|
|
JetResetSessionContext(((PSCECONTEXT)Context)->JetSessionID);
|
|
|
|
}
|
|
#endif
|
|
//
|
|
// unlock the context
|
|
//
|
|
|
|
if ( pTask ) {
|
|
LeaveCriticalSection(&(pTask->Sync));
|
|
}
|
|
|
|
//
|
|
// remove the context from task table
|
|
//
|
|
|
|
ScepRemoveTask(pTask);
|
|
|
|
}
|
|
|
|
RpcRevertToSelf();
|
|
|
|
return((SCEPR_STATUS)rc);
|
|
}
|
|
|
|
|
|
|
|
SCEPR_STATUS
|
|
SceRpcRollbackTransaction(
|
|
IN SCEPR_CONTEXT Context
|
|
)
|
|
/*
|
|
Routine Description:
|
|
|
|
Rollback a transaction on the context. If other threads sharing the same
|
|
context, their changes will also be controlled by this transaction.
|
|
|
|
It's the caller's responsible to not share the same context for
|
|
transactioning.
|
|
|
|
Arguments:
|
|
|
|
See SceJetRollback
|
|
|
|
Return Value:
|
|
|
|
SCEPR_STATUS
|
|
*/
|
|
{
|
|
if ( !Context ) {
|
|
return(SCESTATUS_INVALID_PARAMETER);
|
|
}
|
|
|
|
SCESTATUS rc;
|
|
|
|
UINT ClientLocalFlag = 0;
|
|
|
|
if ( RPC_S_OK != I_RpcBindingIsClientLocal( NULL, &ClientLocalFlag) ||
|
|
0 == ClientLocalFlag ){
|
|
|
|
//
|
|
// to prevent denial-of-service type attacks,
|
|
// do not allow remote RPC
|
|
//
|
|
|
|
return SCESTATUS_ACCESS_DENIED;
|
|
|
|
}
|
|
|
|
//
|
|
// impersonate the client
|
|
//
|
|
|
|
rc = RpcImpersonateClient( NULL );
|
|
|
|
if (rc != RPC_S_OK) {
|
|
return( ScepDosErrorToSceStatus(rc) );
|
|
}
|
|
|
|
BOOL bAdminSidInToken = FALSE;
|
|
|
|
rc = ScepDosErrorToSceStatus(ScepIsAdminLoggedOn(&bAdminSidInToken, TRUE));
|
|
|
|
if (SCESTATUS_SUCCESS != rc || FALSE == bAdminSidInToken) {
|
|
RpcRevertToSelf();
|
|
return SCESTATUS_SPECIAL_ACCOUNT;
|
|
}
|
|
|
|
//
|
|
// validate the context handle is a SCE context
|
|
// Only one database operation per context
|
|
//
|
|
|
|
PSCESRV_DBTASK pTask=NULL;
|
|
|
|
rc = ScepValidateAndLockContext((PSCECONTEXT)Context,
|
|
SCE_TASK_LOCK,
|
|
TRUE,
|
|
&pTask);
|
|
|
|
if (SCESTATUS_SUCCESS == rc ) {
|
|
|
|
//
|
|
// lock the context
|
|
//
|
|
|
|
if ( pTask ) {
|
|
EnterCriticalSection(&(pTask->Sync));
|
|
}
|
|
|
|
//
|
|
// set the context to the jet session so thread id is not used for this
|
|
// operation.
|
|
//
|
|
|
|
#ifdef SCE_JET_TRAN
|
|
rc = SceJetJetErrorToSceStatus(
|
|
JetSetSessionContext(
|
|
((PSCECONTEXT)Context)->JetSessionID,
|
|
(ULONG_PTR)Context
|
|
));
|
|
|
|
if ( SCESTATUS_SUCCESS == rc ) {
|
|
#endif
|
|
//
|
|
// rollback transaction on this context
|
|
//
|
|
|
|
rc = SceJetRollback(
|
|
(PSCECONTEXT)Context,
|
|
0
|
|
);
|
|
|
|
#ifdef SCE_JET_TRAN
|
|
JetResetSessionContext(((PSCECONTEXT)Context)->JetSessionID);
|
|
}
|
|
#endif
|
|
//
|
|
// unlock the context
|
|
//
|
|
|
|
if ( pTask ) {
|
|
LeaveCriticalSection(&(pTask->Sync));
|
|
}
|
|
|
|
//
|
|
// remove the context from task table
|
|
//
|
|
|
|
ScepRemoveTask(pTask);
|
|
|
|
}
|
|
|
|
RpcRevertToSelf();
|
|
|
|
return((SCEPR_STATUS)rc);
|
|
}
|
|
|
|
|
|
SCEPR_STATUS
|
|
SceRpcGetServerProductType(
|
|
IN handle_t binding_h,
|
|
OUT PSCEPR_SERVER_TYPE srvProduct
|
|
)
|
|
/*
|
|
Routine Description:
|
|
|
|
Get SCE server's product type
|
|
|
|
Arguments:
|
|
|
|
Return Value:
|
|
|
|
*/
|
|
{
|
|
if ( !srvProduct ) {
|
|
return(SCESTATUS_INVALID_PARAMETER);
|
|
}
|
|
|
|
UINT ClientLocalFlag = 0;
|
|
|
|
if ( RPC_S_OK != I_RpcBindingIsClientLocal( NULL, &ClientLocalFlag) ||
|
|
0 == ClientLocalFlag ){
|
|
|
|
//
|
|
// to prevent denial-of-service type attacks,
|
|
// do not allow remote RPC
|
|
//
|
|
|
|
return SCESTATUS_ACCESS_DENIED;
|
|
|
|
}
|
|
|
|
if ( bStopRequest ) {
|
|
return(SCESTATUS_SERVICE_NOT_SUPPORT);
|
|
}
|
|
|
|
//
|
|
// impersonate the client
|
|
//
|
|
|
|
BOOL bAdminSidInToken = FALSE;
|
|
DWORD rc = RpcImpersonateClient( NULL );
|
|
|
|
if (rc != RPC_S_OK) {
|
|
return( ScepDosErrorToSceStatus(rc) );
|
|
}
|
|
|
|
rc = ScepDosErrorToSceStatus(ScepIsAdminLoggedOn(&bAdminSidInToken, TRUE));
|
|
|
|
if (SCESTATUS_SUCCESS != rc || FALSE == bAdminSidInToken) {
|
|
RpcRevertToSelf();
|
|
return SCESTATUS_SPECIAL_ACCOUNT;
|
|
|
|
}
|
|
|
|
ScepGetProductType((PSCE_SERVER_TYPE)srvProduct);
|
|
|
|
RpcRevertToSelf();
|
|
|
|
return(SCESTATUS_SUCCESS);
|
|
}
|
|
|
|
|
|
|
|
SCEPR_STATUS
|
|
SceSvcRpcUpdateInfo(
|
|
IN SCEPR_CONTEXT Context,
|
|
IN wchar_t *ServiceName,
|
|
IN PSCEPR_SVCINFO Info
|
|
)
|
|
/*
|
|
Routine Description:
|
|
|
|
Update information for the service to the database.
|
|
|
|
Arguments:
|
|
|
|
Context - the context handle
|
|
|
|
ServiceName - the service name for which info is requested
|
|
|
|
Info - output buffer
|
|
|
|
Return Value:
|
|
|
|
SCEPR_STATUS
|
|
*/
|
|
{
|
|
if ( !Context || !ServiceName || !Info ) {
|
|
return(SCESTATUS_INVALID_PARAMETER);
|
|
}
|
|
|
|
SCESTATUS rc;
|
|
|
|
UINT ClientLocalFlag = 0;
|
|
|
|
if ( RPC_S_OK != I_RpcBindingIsClientLocal( NULL, &ClientLocalFlag) ||
|
|
0 == ClientLocalFlag ){
|
|
|
|
//
|
|
// to prevent denial-of-service type attacks,
|
|
// do not allow remote RPC
|
|
//
|
|
|
|
return SCESTATUS_ACCESS_DENIED;
|
|
|
|
}
|
|
|
|
//
|
|
// impersonate the client
|
|
//
|
|
|
|
rc = RpcImpersonateClient( NULL );
|
|
|
|
if (rc != RPC_S_OK) {
|
|
return( ScepDosErrorToSceStatus(rc) );
|
|
}
|
|
|
|
BOOL bAdminSidInToken = FALSE;
|
|
|
|
rc = ScepDosErrorToSceStatus(ScepIsAdminLoggedOn(&bAdminSidInToken, TRUE));
|
|
|
|
if (SCESTATUS_SUCCESS != rc || FALSE == bAdminSidInToken) {
|
|
RpcRevertToSelf();
|
|
return SCESTATUS_SPECIAL_ACCOUNT;
|
|
}
|
|
|
|
//
|
|
// validate the context handle is a SCE context
|
|
// Only one database operation per context
|
|
//
|
|
|
|
PSCESRV_DBTASK pTask=NULL;
|
|
|
|
rc = ScepValidateAndLockContext((PSCECONTEXT)Context,
|
|
SCE_TASK_LOCK,
|
|
TRUE,
|
|
&pTask);
|
|
|
|
if (SCESTATUS_SUCCESS == rc ) {
|
|
|
|
//
|
|
// lock the context
|
|
//
|
|
|
|
if ( pTask ) {
|
|
EnterCriticalSection(&(pTask->Sync));
|
|
}
|
|
|
|
#ifdef SCE_JET_TRAN
|
|
rc = SceJetJetErrorToSceStatus(
|
|
JetSetSessionContext(
|
|
((PSCECONTEXT)Context)->JetSessionID,
|
|
(ULONG_PTR)Context
|
|
));
|
|
|
|
if ( SCESTATUS_SUCCESS == rc ) {
|
|
#endif
|
|
//
|
|
// update the service info now
|
|
//
|
|
|
|
__try {
|
|
|
|
rc = SceSvcpUpdateInfo(
|
|
(PSCECONTEXT)Context,
|
|
(LPCTSTR)ServiceName,
|
|
(PSCESVC_CONFIGURATION_INFO)Info
|
|
);
|
|
|
|
} __except (EXCEPTION_EXECUTE_HANDLER) {
|
|
|
|
rc = SCESTATUS_EXCEPTION_IN_SERVER;
|
|
}
|
|
|
|
#ifdef SCE_JET_TRAN
|
|
JetResetSessionContext(((PSCECONTEXT)Context)->JetSessionID);
|
|
|
|
}
|
|
#endif
|
|
//
|
|
// unlock the context
|
|
//
|
|
|
|
if ( pTask ) {
|
|
LeaveCriticalSection(&(pTask->Sync));
|
|
}
|
|
|
|
//
|
|
// remove the context from task table
|
|
//
|
|
|
|
ScepRemoveTask(pTask);
|
|
|
|
}
|
|
|
|
RpcRevertToSelf();
|
|
|
|
return((SCEPR_STATUS)rc);
|
|
}
|
|
|
|
|
|
|
|
SCEPR_STATUS
|
|
SceRpcCopyObjects(
|
|
IN SCEPR_CONTEXT Context,
|
|
IN SCEPR_TYPE ProfileType,
|
|
IN wchar_t *InfFileName,
|
|
IN AREAPR Area,
|
|
OUT PSCEPR_ERROR_LOG_INFO *pErrlog OPTIONAL
|
|
)
|
|
/*
|
|
Routine Description:
|
|
|
|
Update information for the service to the database.
|
|
|
|
Arguments:
|
|
|
|
Context - the context handle
|
|
|
|
InfFileName - the inf template name to copy to
|
|
|
|
Area - which area(s) to copy
|
|
|
|
pErrlog - the error log buffer
|
|
|
|
Return Value:
|
|
|
|
SCEPR_STATUS
|
|
*/
|
|
{
|
|
if ( !Context || !InfFileName ) {
|
|
return(SCESTATUS_INVALID_PARAMETER);
|
|
}
|
|
|
|
UINT ClientLocalFlag = 0;
|
|
|
|
if ( RPC_S_OK != I_RpcBindingIsClientLocal( NULL, &ClientLocalFlag) ||
|
|
0 == ClientLocalFlag ){
|
|
|
|
//
|
|
// to prevent denial-of-service type attacks,
|
|
// do not allow remote RPC
|
|
//
|
|
|
|
return SCESTATUS_ACCESS_DENIED;
|
|
|
|
}
|
|
|
|
if ( !Area ) {
|
|
//
|
|
// nothing to copy
|
|
//
|
|
return(SCESTATUS_SUCCESS);
|
|
}
|
|
|
|
if ( ProfileType != SCE_ENGINE_SCP &&
|
|
ProfileType != SCE_ENGINE_SMP ) {
|
|
return(SCESTATUS_INVALID_PARAMETER);
|
|
}
|
|
|
|
//
|
|
// impersonate the client
|
|
//
|
|
|
|
SCESTATUS rc;
|
|
|
|
rc = RpcImpersonateClient( NULL );
|
|
|
|
if (rc != RPC_S_OK) {
|
|
return( ScepDosErrorToSceStatus(rc) );
|
|
}
|
|
|
|
BOOL bAdminSidInToken = FALSE;
|
|
|
|
rc = ScepDosErrorToSceStatus(ScepIsAdminLoggedOn(&bAdminSidInToken, TRUE));
|
|
|
|
if (SCESTATUS_SUCCESS != rc || FALSE == bAdminSidInToken) {
|
|
RpcRevertToSelf();
|
|
return SCESTATUS_SPECIAL_ACCOUNT;
|
|
}
|
|
|
|
//
|
|
// validate the context handle is a SCE context
|
|
// Only one database operation per context
|
|
//
|
|
|
|
PSCESRV_DBTASK pTask=NULL;
|
|
|
|
rc = ScepValidateAndLockContext((PSCECONTEXT)Context,
|
|
SCE_TASK_LOCK,
|
|
FALSE,
|
|
&pTask);
|
|
|
|
if (SCESTATUS_SUCCESS == rc ) {
|
|
|
|
//
|
|
// lock the context
|
|
//
|
|
|
|
if ( pTask ) {
|
|
EnterCriticalSection(&(pTask->Sync));
|
|
}
|
|
|
|
#ifdef SCE_JET_TRAN
|
|
rc = SceJetJetErrorToSceStatus(
|
|
JetSetSessionContext(
|
|
((PSCECONTEXT)Context)->JetSessionID,
|
|
(ULONG_PTR)Context
|
|
));
|
|
|
|
if ( SCESTATUS_SUCCESS == rc ) {
|
|
#endif
|
|
|
|
//
|
|
// query the information now
|
|
//
|
|
|
|
if ( Area & AREA_REGISTRY_SECURITY ) {
|
|
|
|
rc = ScepCopyObjects(
|
|
(PSCECONTEXT)Context,
|
|
(SCETYPE)ProfileType,
|
|
(LPTSTR)InfFileName,
|
|
szRegistryKeys,
|
|
AREA_REGISTRY_SECURITY,
|
|
(PSCE_ERROR_LOG_INFO *)pErrlog
|
|
);
|
|
}
|
|
|
|
if ( SCESTATUS_SUCCESS == rc &&
|
|
Area & AREA_FILE_SECURITY ) {
|
|
|
|
rc = ScepCopyObjects(
|
|
(PSCECONTEXT)Context,
|
|
(SCETYPE)ProfileType,
|
|
(LPTSTR)InfFileName,
|
|
szFileSecurity,
|
|
AREA_FILE_SECURITY,
|
|
(PSCE_ERROR_LOG_INFO *)pErrlog
|
|
);
|
|
}
|
|
#if 0
|
|
if ( SCESTATUS_SUCCESS == rc &&
|
|
Area & AREA_DS_OBJECTS ) {
|
|
|
|
rc = ScepCopyObjects(
|
|
(PSCECONTEXT)Context,
|
|
(SCETYPE)ProfileType,
|
|
(LPTSTR)InfFileName,
|
|
szDSSecurity,
|
|
AREA_DS_OBJECTS,
|
|
(PSCE_ERROR_LOG_INFO *)pErrlog
|
|
);
|
|
}
|
|
#endif
|
|
if ( SCESTATUS_SUCCESS == rc &&
|
|
Area & AREA_SYSTEM_SERVICE ) {
|
|
|
|
rc = ScepCopyObjects(
|
|
(PSCECONTEXT)Context,
|
|
(SCETYPE)ProfileType,
|
|
(LPTSTR)InfFileName,
|
|
szServiceGeneral,
|
|
AREA_SYSTEM_SERVICE,
|
|
(PSCE_ERROR_LOG_INFO *)pErrlog
|
|
);
|
|
}
|
|
|
|
SCESVC_INFO_TYPE iType;
|
|
switch ( ProfileType ) {
|
|
case SCE_ENGINE_SCP:
|
|
iType = SceSvcMergedPolicyInfo;
|
|
break;
|
|
case SCE_ENGINE_SMP:
|
|
iType = SceSvcConfigurationInfo;
|
|
break;
|
|
}
|
|
|
|
if ( SCESTATUS_SUCCESS == rc &&
|
|
( Area & AREA_SYSTEM_SERVICE) ) {
|
|
|
|
rc = ScepGenerateAttachmentSections(
|
|
(PSCECONTEXT)Context,
|
|
iType,
|
|
(LPTSTR)InfFileName,
|
|
SCE_ATTACHMENT_SERVICE
|
|
);
|
|
}
|
|
if ( SCESTATUS_SUCCESS == rc &&
|
|
(Area & AREA_SECURITY_POLICY) ) {
|
|
|
|
rc = ScepGenerateAttachmentSections(
|
|
(PSCECONTEXT)Context,
|
|
iType,
|
|
(LPTSTR)InfFileName,
|
|
SCE_ATTACHMENT_POLICY
|
|
);
|
|
}
|
|
if ( SCESTATUS_SUCCESS == rc &&
|
|
( Area & AREA_ATTACHMENTS) ) {
|
|
|
|
rc = ScepGenerateWMIAttachmentSections(
|
|
(PSCECONTEXT)Context,
|
|
iType,
|
|
(LPTSTR)InfFileName
|
|
);
|
|
}
|
|
|
|
#ifdef SCE_JET_TRAN
|
|
JetResetSessionContext(((PSCECONTEXT)Context)->JetSessionID);
|
|
|
|
}
|
|
#endif
|
|
|
|
//
|
|
// unlock the context
|
|
//
|
|
|
|
if ( pTask ) {
|
|
LeaveCriticalSection(&(pTask->Sync));
|
|
}
|
|
|
|
//
|
|
// remove the context from task table
|
|
//
|
|
|
|
ScepRemoveTask(pTask);
|
|
|
|
}
|
|
|
|
RpcRevertToSelf();
|
|
|
|
return((SCEPR_STATUS)rc);
|
|
}
|
|
|
|
SCEPR_STATUS
|
|
SceRpcSetupResetLocalPolicy(
|
|
IN SCEPR_CONTEXT Context,
|
|
IN AREAPR Area,
|
|
IN wchar_t *OneSectionName OPTIONAL,
|
|
IN DWORD PolicyOptions
|
|
)
|
|
{
|
|
SCESTATUS rc;
|
|
|
|
UINT ClientLocalFlag = 0;
|
|
|
|
if ( RPC_S_OK != I_RpcBindingIsClientLocal( NULL, &ClientLocalFlag) ||
|
|
0 == ClientLocalFlag ){
|
|
|
|
//
|
|
// to prevent denial-of-service type attacks,
|
|
// do not allow remote RPC
|
|
//
|
|
|
|
return SCESTATUS_ACCESS_DENIED;
|
|
|
|
}
|
|
|
|
//
|
|
// impersonate the client
|
|
//
|
|
|
|
rc = RpcImpersonateClient( NULL );
|
|
|
|
if (rc != RPC_S_OK) {
|
|
return( ScepDosErrorToSceStatus(rc) );
|
|
}
|
|
|
|
BOOL bAdminSidInToken = FALSE;
|
|
|
|
rc = ScepDosErrorToSceStatus(ScepIsAdminLoggedOn(&bAdminSidInToken, TRUE));
|
|
|
|
if (SCESTATUS_SUCCESS != rc || FALSE == bAdminSidInToken) {
|
|
RpcRevertToSelf();
|
|
return SCESTATUS_SPECIAL_ACCOUNT;
|
|
}
|
|
|
|
//
|
|
// validate the context handle is a SCE context
|
|
// Only one database operation per context
|
|
//
|
|
|
|
PSCESRV_DBTASK pTask=NULL;
|
|
|
|
rc = ScepValidateAndLockContext((PSCECONTEXT)Context,
|
|
SCE_TASK_LOCK,
|
|
TRUE,
|
|
&pTask);
|
|
|
|
if (SCESTATUS_SUCCESS == rc ) {
|
|
|
|
//
|
|
// lock the context
|
|
//
|
|
|
|
if ( pTask ) {
|
|
EnterCriticalSection(&(pTask->Sync));
|
|
}
|
|
|
|
#ifdef SCE_JET_TRAN
|
|
rc = SceJetJetErrorToSceStatus(
|
|
JetSetSessionContext(
|
|
((PSCECONTEXT)Context)->JetSessionID,
|
|
(ULONG_PTR)Context
|
|
));
|
|
|
|
if ( SCESTATUS_SUCCESS == rc ) {
|
|
#endif
|
|
//
|
|
// remove policies from the local table
|
|
//
|
|
if ( PolicyOptions & SCE_RESET_POLICY_SYSPREP ) {
|
|
|
|
ScepSetupResetLocalPolicy((PSCECONTEXT)Context,
|
|
(AREA_INFORMATION)Area,
|
|
NULL,
|
|
SCE_ENGINE_SMP,
|
|
FALSE
|
|
);
|
|
ScepSetupResetLocalPolicy((PSCECONTEXT)Context,
|
|
(AREA_INFORMATION)Area,
|
|
NULL,
|
|
SCE_ENGINE_SCP,
|
|
FALSE
|
|
);
|
|
|
|
rc = ScepSetupResetLocalPolicy((PSCECONTEXT)Context,
|
|
(AREA_INFORMATION)Area,
|
|
NULL,
|
|
SCE_ENGINE_SAP, // for the tattoo table
|
|
FALSE
|
|
);
|
|
} else {
|
|
|
|
if ( PolicyOptions & SCE_RESET_POLICY_TATTOO ) {
|
|
// after dcpromo, we need to reset the tattoo values
|
|
rc = ScepSetupResetLocalPolicy((PSCECONTEXT)Context,
|
|
(AREA_INFORMATION)Area,
|
|
(PCWSTR)OneSectionName,
|
|
SCE_ENGINE_SAP, // for the tattoo table
|
|
FALSE
|
|
);
|
|
}
|
|
|
|
rc = ScepSetupResetLocalPolicy((PSCECONTEXT)Context,
|
|
(AREA_INFORMATION)Area,
|
|
(PCWSTR)OneSectionName,
|
|
SCE_ENGINE_SMP,
|
|
(PolicyOptions & SCE_RESET_POLICY_KEEP_LOCAL)
|
|
);
|
|
|
|
if ( (PolicyOptions & SCE_RESET_POLICY_ENFORCE_ATREBOOT ) &&
|
|
( (((PSCECONTEXT)Context)->Type & 0xF0L) == SCEJET_MERGE_TABLE_1 ||
|
|
(((PSCECONTEXT)Context)->Type & 0xF0L) == SCEJET_MERGE_TABLE_2 ) &&
|
|
((PSCECONTEXT)Context)->JetScpID != ((PSCECONTEXT)Context)->JetSmpID ) {
|
|
//
|
|
// there is effective policy table already in the database
|
|
// (and this is in setup upgrade)
|
|
// update local group policy table to trigger a policy prop at reboot
|
|
//
|
|
|
|
ScepEnforcePolicyPropagation();
|
|
}
|
|
}
|
|
|
|
#ifdef SCE_JET_TRAN
|
|
JetResetSessionContext(((PSCECONTEXT)Context)->JetSessionID);
|
|
|
|
}
|
|
#endif
|
|
//
|
|
// unlock the context
|
|
//
|
|
|
|
if ( pTask ) {
|
|
LeaveCriticalSection(&(pTask->Sync));
|
|
}
|
|
|
|
//
|
|
// remove the context from task table
|
|
//
|
|
|
|
ScepRemoveTask(pTask);
|
|
|
|
}
|
|
|
|
RpcRevertToSelf();
|
|
|
|
return((SCEPR_STATUS)rc);
|
|
|
|
}
|
|
|
|
|
|
|
|
SCESTATUS
|
|
ScepGenerateAttachmentSections(
|
|
IN PSCECONTEXT hProfile,
|
|
IN SCESVC_INFO_TYPE InfoType,
|
|
IN LPTSTR InfFileName,
|
|
IN SCE_ATTACHMENT_TYPE aType
|
|
)
|
|
{
|
|
SCESTATUS rc;
|
|
PSCE_SERVICES pServiceList=NULL, pNode;
|
|
|
|
rc = ScepEnumServiceEngines( &pServiceList, aType );
|
|
|
|
if ( rc == SCESTATUS_SUCCESS ) {
|
|
|
|
for ( pNode=pServiceList; pNode != NULL; pNode=pNode->Next) {
|
|
//
|
|
// generate section for one attachment
|
|
//
|
|
rc = ScepGenerateOneAttachmentSection(hProfile,
|
|
InfoType,
|
|
InfFileName,
|
|
pNode->ServiceName,
|
|
FALSE
|
|
);
|
|
|
|
if ( rc != SCESTATUS_SUCCESS ) {
|
|
ScepLogOutput3(1, ScepSceStatusToDosError(rc),
|
|
SCEDLL_ERROR_CONVERT_SECTION, pNode->ServiceName );
|
|
break;
|
|
}
|
|
}
|
|
|
|
SceFreePSCE_SERVICES(pServiceList);
|
|
|
|
}
|
|
|
|
if ( rc == SCESTATUS_PROFILE_NOT_FOUND ||
|
|
rc == SCESTATUS_RECORD_NOT_FOUND ) {
|
|
// if no service exist, just ignore
|
|
rc = SCESTATUS_SUCCESS;
|
|
}
|
|
|
|
return(rc);
|
|
|
|
}
|
|
|
|
SCESTATUS
|
|
ScepGenerateWMIAttachmentSections(
|
|
IN PSCECONTEXT hProfile,
|
|
IN SCESVC_INFO_TYPE InfoType,
|
|
IN LPTSTR InfFileName
|
|
)
|
|
{
|
|
SCESTATUS rc;
|
|
PSCE_NAME_LIST pList=NULL, pNode;
|
|
|
|
rc = ScepEnumAttachmentSections( hProfile, &pList);
|
|
|
|
if ( rc == SCESTATUS_SUCCESS ) {
|
|
|
|
for ( pNode=pList; pNode != NULL; pNode=pNode->Next) {
|
|
|
|
//
|
|
// generate section for one attachment
|
|
//
|
|
rc = ScepGenerateOneAttachmentSection(hProfile,
|
|
InfoType,
|
|
InfFileName,
|
|
pNode->Name,
|
|
TRUE
|
|
);
|
|
|
|
if ( rc != SCESTATUS_SUCCESS ) {
|
|
ScepLogOutput3(1, ScepSceStatusToDosError(rc),
|
|
SCEDLL_ERROR_CONVERT_SECTION, pNode->Name );
|
|
break;
|
|
}
|
|
}
|
|
|
|
ScepFreeNameList(pList);
|
|
|
|
}
|
|
|
|
if ( rc == SCESTATUS_PROFILE_NOT_FOUND ||
|
|
rc == SCESTATUS_RECORD_NOT_FOUND ) {
|
|
// if no service exist, just ignore
|
|
rc = SCESTATUS_SUCCESS;
|
|
}
|
|
|
|
return(rc);
|
|
|
|
}
|
|
|
|
SCESTATUS
|
|
ScepGenerateOneAttachmentSection(
|
|
IN PSCECONTEXT hProfile,
|
|
IN SCESVC_INFO_TYPE InfoType,
|
|
IN LPTSTR InfFileName,
|
|
IN LPTSTR SectionName,
|
|
IN BOOL bWMISection
|
|
)
|
|
{
|
|
//
|
|
// read inf info for the section
|
|
//
|
|
SCESTATUS rc;
|
|
SCE_ENUMERATION_CONTEXT sceEnumHandle=0;
|
|
DWORD CountReturned;
|
|
PSCESVC_CONFIGURATION_INFO pAttachInfo=NULL;
|
|
|
|
do {
|
|
|
|
CountReturned = 0;
|
|
|
|
rc = SceSvcpQueryInfo(
|
|
hProfile,
|
|
InfoType,
|
|
SectionName,
|
|
NULL,
|
|
FALSE,
|
|
(PVOID *)&pAttachInfo,
|
|
&sceEnumHandle
|
|
);
|
|
|
|
if ( rc == SCESTATUS_SUCCESS && pAttachInfo != NULL &&
|
|
pAttachInfo->Count > 0 ) {
|
|
//
|
|
// got something
|
|
//
|
|
CountReturned = pAttachInfo->Count;
|
|
|
|
//
|
|
// copy each line
|
|
//
|
|
for ( DWORD i=0; i<pAttachInfo->Count; i++ ) {
|
|
|
|
if ( pAttachInfo->Lines[i].Key == NULL ||
|
|
pAttachInfo->Lines[i].Value == NULL ) {
|
|
continue;
|
|
}
|
|
|
|
if ( !WritePrivateProfileString(
|
|
SectionName,
|
|
pAttachInfo->Lines[i].Key,
|
|
pAttachInfo->Lines[i].Value,
|
|
InfFileName
|
|
) ) {
|
|
|
|
rc = ScepDosErrorToSceStatus(GetLastError());
|
|
break;
|
|
}
|
|
}
|
|
|
|
if ( bWMISection ) {
|
|
|
|
//
|
|
// make sure to create the szAttachments section
|
|
//
|
|
if ( !WritePrivateProfileString(
|
|
szAttachments,
|
|
SectionName,
|
|
L"Include",
|
|
InfFileName
|
|
) ) {
|
|
|
|
rc = ScepDosErrorToSceStatus(GetLastError());
|
|
}
|
|
}
|
|
}
|
|
|
|
SceSvcpFreeMemory((PVOID)pAttachInfo);
|
|
pAttachInfo = NULL;
|
|
|
|
} while ( rc == SCESTATUS_SUCCESS && CountReturned > 0 );
|
|
|
|
if ( SCESTATUS_RECORD_NOT_FOUND == rc ) {
|
|
rc = SCESTATUS_SUCCESS;
|
|
}
|
|
|
|
return rc;
|
|
|
|
}
|
|
|
|
void __RPC_USER
|
|
SCEPR_CONTEXT_rundown( SCEPR_CONTEXT Context)
|
|
{
|
|
|
|
SCESTATUS rc;
|
|
|
|
//
|
|
// impersonate the client
|
|
//
|
|
|
|
rc = RpcImpersonateClient( NULL );
|
|
|
|
if (rc != RPC_S_OK) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
// this client is shutting down
|
|
//
|
|
|
|
rc = ScepValidateAndCloseDatabase((PSCECONTEXT)Context);
|
|
|
|
RpcRevertToSelf();
|
|
|
|
return;
|
|
}
|
|
|
|
|
|
|
|
SCESTATUS
|
|
ScepOpenDatabase(
|
|
IN PCWSTR DatabaseName,
|
|
IN DWORD OpenOption,
|
|
IN SCEJET_OPEN_TYPE OpenType,
|
|
OUT PSCECONTEXT *pContext
|
|
)
|
|
/*
|
|
Routine Description:
|
|
|
|
This routine opens the database and returns a context handle.
|
|
OpenDatabase can be called by multiple clients for the same database
|
|
and we do not block multiple access because each client will get
|
|
a duplicate database cursor and have their own working tables.
|
|
|
|
When a database is changed by other clients, all cursors will be
|
|
synchronized. Clients who had retrived "old" data are responsible
|
|
to refresh their data buffer. No notification is provided at this
|
|
point.
|
|
|
|
Arguments:
|
|
|
|
Return Value:
|
|
|
|
|
|
*/
|
|
{
|
|
if ( !DatabaseName || !pContext ) {
|
|
return(SCESTATUS_INVALID_PARAMETER);
|
|
}
|
|
|
|
SCESTATUS rc;
|
|
//
|
|
// check access of the database (with current client token)
|
|
//
|
|
DWORD Access=0;
|
|
|
|
if ( SCEJET_OPEN_READ_ONLY == OpenType ) {
|
|
|
|
// BUG in ESENT
|
|
// Even ask for read only, ESENT still writes to the database
|
|
// Access = FILE_GENERIC_READ;
|
|
Access = FILE_GENERIC_READ | FILE_GENERIC_WRITE;
|
|
} else {
|
|
Access = FILE_GENERIC_READ | FILE_GENERIC_WRITE;
|
|
}
|
|
|
|
rc = ScepDatabaseAccessGranted((LPTSTR)DatabaseName,
|
|
Access,
|
|
FALSE
|
|
);
|
|
|
|
if ( rc != ERROR_SUCCESS ) {
|
|
|
|
ScepLogOutput2(1,rc,L"%s", DatabaseName);
|
|
|
|
return( ScepDosErrorToSceStatus(rc) );
|
|
}
|
|
|
|
DWORD Len;
|
|
DWORD MBLen=0;
|
|
PCHAR FileName=NULL;
|
|
NTSTATUS NtStatus;
|
|
|
|
//
|
|
// convert WCHAR into ANSI
|
|
//
|
|
|
|
Len = wcslen( DatabaseName );
|
|
|
|
NtStatus = RtlUnicodeToMultiByteSize(&MBLen, (PWSTR)DatabaseName, Len*sizeof(WCHAR));
|
|
|
|
if ( !NT_SUCCESS(NtStatus) ) {
|
|
//
|
|
// cannot get the length, set default to 512
|
|
//
|
|
MBLen = 512;
|
|
}
|
|
|
|
FileName = (PCHAR)ScepAlloc( LPTR, MBLen+2);
|
|
|
|
if ( FileName == NULL ) {
|
|
rc = SCESTATUS_NOT_ENOUGH_RESOURCE;
|
|
} else {
|
|
|
|
NtStatus = RtlUnicodeToMultiByteN(
|
|
FileName,
|
|
MBLen+1,
|
|
NULL,
|
|
(PWSTR)DatabaseName,
|
|
Len*sizeof(WCHAR)
|
|
);
|
|
|
|
if ( !NT_SUCCESS(NtStatus) ) {
|
|
rc = SCESTATUS_PROFILE_NOT_FOUND;
|
|
|
|
} else {
|
|
|
|
//
|
|
// make sure the context buffer is initialized
|
|
//
|
|
|
|
*pContext = NULL;
|
|
|
|
rc = SceJetOpenFile(
|
|
(LPSTR)FileName,
|
|
OpenType, //SCEJET_OPEN_READ_WRITE,
|
|
(OpenOption == SCE_OPEN_OPTION_TATTOO ) ? SCE_TABLE_OPTION_TATTOO : 0,
|
|
pContext
|
|
);
|
|
|
|
if ( (OpenOption == SCE_OPEN_OPTION_REQUIRE_ANALYSIS ) &&
|
|
SCESTATUS_SUCCESS == rc &&
|
|
*pContext ) {
|
|
|
|
if ( (*pContext)->JetSapID == JET_tableidNil ) {
|
|
|
|
//
|
|
// no analysis information is available
|
|
//
|
|
|
|
rc = SCESTATUS_PROFILE_NOT_FOUND;
|
|
|
|
//
|
|
// free handle
|
|
//
|
|
|
|
SceJetCloseFile(
|
|
*pContext,
|
|
TRUE,
|
|
FALSE
|
|
);
|
|
*pContext = NULL;
|
|
}
|
|
|
|
}
|
|
}
|
|
ScepFree( FileName );
|
|
|
|
}
|
|
|
|
return(rc);
|
|
}
|
|
|
|
|
|
SCESTATUS
|
|
ScepCloseDatabase(
|
|
IN PSCECONTEXT Context
|
|
)
|
|
{
|
|
SCESTATUS rc;
|
|
|
|
if ( !Context ) {
|
|
return(SCESTATUS_INVALID_PARAMETER);
|
|
}
|
|
|
|
__try {
|
|
|
|
if ( ScepIsValidContext(Context) ) {
|
|
|
|
//
|
|
// be able to access the first byte
|
|
//
|
|
|
|
rc = SceJetCloseFile(
|
|
Context,
|
|
TRUE,
|
|
FALSE
|
|
);
|
|
} else {
|
|
//
|
|
// this context is not our context or already be freed
|
|
//
|
|
rc = SCESTATUS_INVALID_PARAMETER;
|
|
}
|
|
|
|
} __except (EXCEPTION_EXECUTE_HANDLER) {
|
|
|
|
rc = SCESTATUS_INVALID_PARAMETER;
|
|
}
|
|
|
|
return(rc);
|
|
|
|
}
|
|
|
|
DWORD
|
|
SceRpcControlNotificationQProcess(
|
|
IN handle_t binding_h,
|
|
IN DWORD Flag
|
|
)
|
|
/*
|
|
Description:
|
|
|
|
This function should be called by a system thread to control that policy
|
|
notification queue process should be suspended or resumed.
|
|
|
|
The purpose of this function is to protect policy changes being overwritten
|
|
by policy proapgation when the GPO file is copied/imported into the database
|
|
|
|
*/
|
|
{
|
|
UINT ClientLocalFlag = 0;
|
|
|
|
if ( RPC_S_OK != I_RpcBindingIsClientLocal( NULL, &ClientLocalFlag) ||
|
|
0 == ClientLocalFlag ){
|
|
|
|
//
|
|
// to prevent denial-of-service type attacks,
|
|
// do not allow remote RPC
|
|
//
|
|
|
|
return SCESTATUS_ACCESS_DENIED;
|
|
|
|
}
|
|
|
|
DWORD rc=ERROR_SUCCESS;
|
|
|
|
//
|
|
// impersonate the client
|
|
//
|
|
|
|
rc = RpcImpersonateClient( NULL );
|
|
|
|
if (rc != RPC_S_OK) {
|
|
|
|
ScepNotifyLogPolicy(rc, FALSE, L"Impersonation Failed", 0, 0, NULL );
|
|
return( rc );
|
|
}
|
|
|
|
//
|
|
// perform access check to make sure that only
|
|
// system thread can make the call
|
|
//
|
|
HANDLE hToken = NULL;
|
|
|
|
if (!OpenThreadToken( GetCurrentThread(),
|
|
TOKEN_QUERY,
|
|
TRUE,
|
|
&hToken)) {
|
|
|
|
rc = GetLastError();
|
|
|
|
ScepNotifyLogPolicy(rc, FALSE, L"Fail to query token", 0, 0, NULL );
|
|
|
|
RpcRevertToSelf();
|
|
|
|
return( rc );
|
|
}
|
|
|
|
BOOL b=FALSE;
|
|
|
|
rc = RtlNtStatusToDosError( ScepIsSystemContext(hToken, &b) );
|
|
|
|
if ( rc != ERROR_SUCCESS || !b ) {
|
|
|
|
CloseHandle(hToken);
|
|
|
|
ScepNotifyLogPolicy(rc, FALSE, L"Not system context", 0, 0, NULL );
|
|
|
|
RpcRevertToSelf();
|
|
|
|
return( rc ? rc : ERROR_ACCESS_DENIED );
|
|
}
|
|
|
|
CloseHandle(hToken);
|
|
|
|
//
|
|
// even though there might be a shutdown request
|
|
// we need to let the control go through
|
|
//
|
|
|
|
if ( Flag ) {
|
|
|
|
ScepNotifyLogPolicy(0, TRUE, L"RPC enter Suspend queue.", 0, 0, NULL );
|
|
//
|
|
// this thread is called from policy propagation which is guaranteed to
|
|
// run by one thread (system context). No need to protect the global buffer
|
|
//
|
|
gPolicyWaitCount++;
|
|
|
|
if ( pNotificationQHead ) {
|
|
|
|
if ( gPolicyWaitCount < SCE_POLICY_MAX_WAIT ) {
|
|
//
|
|
// queue is not empty, should not propagate policy
|
|
//
|
|
ScepNotifyLogPolicy(0, FALSE, L"Queue is not empty, abort.", 0, 0, NULL );
|
|
|
|
RpcRevertToSelf();
|
|
|
|
return (ERROR_OVERRIDE_NOCHANGES);
|
|
|
|
} else {
|
|
|
|
ScepNotifyLogPolicy(0, FALSE, L"Resetting policy wait count.", 0, 0, NULL );
|
|
gPolicyWaitCount = 0;
|
|
|
|
}
|
|
} else {
|
|
gPolicyWaitCount = 0;
|
|
}
|
|
|
|
} else {
|
|
|
|
ScepNotifyLogPolicy(0, TRUE, L"RPC enter Resume queue.", 0, 0, NULL );
|
|
}
|
|
|
|
//
|
|
// now set the control flag
|
|
//
|
|
|
|
ScepNotificationQControl(Flag);
|
|
|
|
RpcRevertToSelf();
|
|
|
|
return(rc);
|
|
}
|
|
|
|
DWORD
|
|
SceRpcNotifySaveChangesInGP(
|
|
IN handle_t binding_h,
|
|
IN DWORD DbType,
|
|
IN DWORD DeltaType,
|
|
IN DWORD ObjectType,
|
|
IN PSCEPR_SID ObjectSid OPTIONAL,
|
|
IN DWORD ExplicitLowRight,
|
|
IN DWORD ExplicitHighRight
|
|
)
|
|
/*
|
|
Description:
|
|
|
|
This function should be called by a system thread to notify that policy
|
|
in LSA/SAM databases are changed programmatically by other applications.
|
|
The purpose of this function is to synchronize policy store with LSA/SAM
|
|
databases so that application changes won't be overwritten by next
|
|
policy propagation.
|
|
|
|
This function will add the notification to a queue for server to process.
|
|
Only system context can add a node to the queue.
|
|
|
|
*/
|
|
{
|
|
|
|
UINT ClientLocalFlag = 0;
|
|
|
|
if ( RPC_S_OK != I_RpcBindingIsClientLocal( NULL, &ClientLocalFlag) ||
|
|
0 == ClientLocalFlag ){
|
|
|
|
//
|
|
// to prevent denial-of-service type attacks,
|
|
// do not allow remote RPC
|
|
//
|
|
|
|
return SCESTATUS_ACCESS_DENIED;
|
|
|
|
}
|
|
|
|
//
|
|
// even though there might be a shutdown request
|
|
// we need to let notification saved before allowing shutdown
|
|
//
|
|
|
|
DWORD rc=ERROR_SUCCESS;
|
|
|
|
ScepNotifyLogPolicy(0, TRUE, L"Notified DC", DbType, ObjectType, NULL );
|
|
|
|
if ( ObjectSid ) {
|
|
|
|
__try {
|
|
|
|
if ( !RtlValidSid(ObjectSid) ) {
|
|
rc = GetLastError();
|
|
}
|
|
|
|
} __except (EXCEPTION_EXECUTE_HANDLER) {
|
|
// objectsid buffer is invalid
|
|
rc = ERROR_EXCEPTION_IN_SERVICE;
|
|
}
|
|
|
|
if ( rc != ERROR_SUCCESS ) {
|
|
ScepNotifyLogPolicy(0, FALSE, L"Invalid Sid", DbType, ObjectType, NULL );
|
|
return(rc);
|
|
}
|
|
}
|
|
|
|
//
|
|
// impersonate the client
|
|
//
|
|
|
|
rc = RpcImpersonateClient( NULL );
|
|
|
|
if (rc != RPC_S_OK) {
|
|
|
|
ScepNotifyLogPolicy(rc, FALSE, L"Impersonation Failed", DbType, ObjectType, NULL );
|
|
return( rc );
|
|
}
|
|
|
|
//
|
|
// perform access check to make sure that only
|
|
// system thread can make the call
|
|
//
|
|
HANDLE hToken = NULL;
|
|
|
|
if (!OpenThreadToken( GetCurrentThread(),
|
|
TOKEN_QUERY,
|
|
TRUE,
|
|
&hToken)) {
|
|
|
|
rc = GetLastError();
|
|
|
|
ScepNotifyLogPolicy(rc, FALSE, L"Fail to query token", DbType, ObjectType, NULL );
|
|
|
|
RpcRevertToSelf();
|
|
|
|
return( rc );
|
|
}
|
|
|
|
BOOL b=FALSE;
|
|
|
|
rc = RtlNtStatusToDosError( ScepIsSystemContext(hToken, &b) );
|
|
|
|
if ( rc != ERROR_SUCCESS || !b ) {
|
|
|
|
CloseHandle(hToken);
|
|
|
|
ScepNotifyLogPolicy(rc, FALSE, L"Not system context", DbType, ObjectType, NULL );
|
|
|
|
RpcRevertToSelf();
|
|
|
|
return( rc ? rc : ERROR_ACCESS_DENIED );
|
|
}
|
|
|
|
CloseHandle(hToken);
|
|
|
|
//
|
|
// Add the request to the "queue" for further process
|
|
//
|
|
rc = ScepNotificationQEnqueue((SECURITY_DB_TYPE)DbType,
|
|
(SECURITY_DB_DELTA_TYPE)DeltaType,
|
|
(SECURITY_DB_OBJECT_TYPE)ObjectType,
|
|
(PSID)ObjectSid,
|
|
ExplicitLowRight,
|
|
ExplicitHighRight,
|
|
NULL
|
|
);
|
|
|
|
RpcRevertToSelf();
|
|
|
|
return(rc);
|
|
}
|
|
|
|
DWORD
|
|
ScepNotifyProcessOneNodeDC(
|
|
IN SECURITY_DB_TYPE DbType,
|
|
IN SECURITY_DB_OBJECT_TYPE ObjectType,
|
|
IN SECURITY_DB_DELTA_TYPE DeltaType,
|
|
IN PSID ObjectSid,
|
|
IN DWORD ExplicitLowRight,
|
|
IN DWORD ExplicitHighRight,
|
|
OUT BOOL *pbTimeout
|
|
)
|
|
/*
|
|
Description:
|
|
|
|
This function is called by the queue management thread to process one
|
|
notification node in the queue. This function will determine which group
|
|
policy template to save to and what are the differences between current
|
|
state of LSA/SAM and group policy.
|
|
|
|
Group policy is only modified when there is a difference detected. Group
|
|
policy version # is updated on save. This function is always called in a
|
|
single system thread.
|
|
|
|
if scecli.dll fails to be loaded, ERROR_MOD_NOT_FOUND will be returned.
|
|
|
|
if sysvol share is not ready, the error returned will be ERROR_FILE_NOT_FOUND.
|
|
However if the template file doesn't exist (deleted), ERROR_FILE_NOT_FOUND will
|
|
also be returned. This case is handled the same way as the share/path doesn't
|
|
exist (error logged and retried) because the GPOs are required to be there for
|
|
replication purpose. But in the future, when the dependency is removed from
|
|
domain controllers GPO, we might need to separate the two cases (one success,
|
|
one failure).
|
|
|
|
If disk is full, the error returned will be ERROR_EXTENDED_ERROR.
|
|
|
|
*/
|
|
{
|
|
|
|
//
|
|
// query if I am in setup
|
|
//
|
|
DWORD dwInSetup = 0;
|
|
DWORD rc=0;
|
|
|
|
*pbTimeout = FALSE;
|
|
|
|
ScepRegQueryIntValue(HKEY_LOCAL_MACHINE,
|
|
TEXT("System\\Setup"),
|
|
TEXT("SystemSetupInProgress"),
|
|
&dwInSetup
|
|
);
|
|
|
|
PWSTR TemplateName=NULL;
|
|
BOOL bAccountGPO=FALSE;
|
|
|
|
if ( DbType == SecurityDbSam &&
|
|
!SCEP_IS_SAM_OBJECT(ObjectType) ) {
|
|
//
|
|
// if it's for deleted account, should update user right GPO
|
|
// otherwise, update the account GPO
|
|
//
|
|
bAccountGPO = TRUE;
|
|
}
|
|
|
|
if ( dwInSetup && !IsNT5()) {
|
|
|
|
//
|
|
// if it's in setup, group policy templates are not available (DS is down)
|
|
// save the notifications to a temperaory store and process the
|
|
// store at next system start up.
|
|
//
|
|
ScepNotifyLogPolicy(0, FALSE, L"In setup", DbType, ObjectType, NULL );
|
|
|
|
UNICODE_STRING tmp;
|
|
tmp.Length = 0;
|
|
tmp.Buffer = NULL;
|
|
|
|
//
|
|
// get the default template name
|
|
//
|
|
rc = ScepNotifyGetDefaultGPOTemplateName(
|
|
tmp,
|
|
NULL,
|
|
bAccountGPO,
|
|
SCEGPO_INSETUP_NT4,
|
|
&TemplateName
|
|
);
|
|
|
|
if ( ERROR_SUCCESS == rc && TemplateName ) {
|
|
|
|
//
|
|
// save the transaction in this temp file
|
|
//
|
|
rc = ScepNotifySaveNotifications(TemplateName,
|
|
(SECURITY_DB_TYPE)DbType,
|
|
(SECURITY_DB_OBJECT_TYPE)ObjectType,
|
|
(SECURITY_DB_DELTA_TYPE)DeltaType,
|
|
(PSID)ObjectSid
|
|
);
|
|
|
|
ScepNotifyLogPolicy(rc, FALSE, L"Notification Saved", DbType, ObjectType, TemplateName );
|
|
|
|
} else {
|
|
|
|
ScepNotifyLogPolicy(rc, FALSE, L"Error get file path", DbType, ObjectType, NULL );
|
|
}
|
|
|
|
//
|
|
// free TemplateName
|
|
//
|
|
LocalFree(TemplateName);
|
|
|
|
return rc;
|
|
}
|
|
|
|
//
|
|
// let's check if scecli is loaded in the process
|
|
// once it's loaded, it will stay loaded.
|
|
//
|
|
if ( hSceCliDll == NULL )
|
|
hSceCliDll = LoadLibrary(TEXT("scecli.dll"));
|
|
|
|
if ( hSceCliDll ) {
|
|
if ( pfSceInfWriteInfo == NULL ) {
|
|
pfSceInfWriteInfo = (PFSCEINFWRITEINFO)GetProcAddress(
|
|
hSceCliDll,
|
|
"SceWriteSecurityProfileInfo");
|
|
}
|
|
|
|
if ( pfSceGetInfo == NULL ) {
|
|
pfSceGetInfo = (PFSCEGETINFO)GetProcAddress(
|
|
hSceCliDll,
|
|
"SceGetSecurityProfileInfo");
|
|
}
|
|
}
|
|
|
|
//
|
|
// if shutdown/stop service is requested, or client functions can't be found
|
|
// quit now
|
|
//
|
|
|
|
if ( bStopRequest || !hSceCliDll ||
|
|
!pfSceInfWriteInfo || !pfSceGetInfo ) {
|
|
|
|
if ( bStopRequest ) {
|
|
ScepNotifyLogPolicy(0, FALSE, L"Leave - Stop Requested", DbType, ObjectType, NULL );
|
|
} else {
|
|
rc = ERROR_MOD_NOT_FOUND;
|
|
ScepNotifyLogPolicy(0, FALSE, L"Leave - Can't load scecli.dll or GetProcAddr", DbType, ObjectType, NULL );
|
|
}
|
|
|
|
return(rc);
|
|
}
|
|
|
|
//
|
|
// domain DNS name is required to access the sysvol portion of group policy
|
|
// templates.
|
|
//
|
|
// This information is only queried once and saved in the static global buffer.
|
|
//
|
|
if ( (DnsDomainInfo == NULL) ||
|
|
(DnsDomainInfo->DnsDomainName.Buffer == NULL) ) {
|
|
|
|
//
|
|
// free the old buffer
|
|
//
|
|
if ( DnsDomainInfo ) {
|
|
LsaFreeMemory(DnsDomainInfo);
|
|
DnsDomainInfo = NULL;
|
|
}
|
|
|
|
OBJECT_ATTRIBUTES ObjectAttributes;
|
|
LSA_HANDLE LsaPolicyHandle;
|
|
|
|
InitializeObjectAttributes( &ObjectAttributes, NULL, 0, NULL, NULL );
|
|
|
|
NTSTATUS Status = LsaOpenPolicy( NULL,
|
|
&ObjectAttributes,
|
|
POLICY_VIEW_LOCAL_INFORMATION,
|
|
&LsaPolicyHandle );
|
|
|
|
if ( NT_SUCCESS(Status) ) {
|
|
|
|
Status = LsaQueryInformationPolicy( LsaPolicyHandle,
|
|
PolicyDnsDomainInformation,
|
|
( PVOID * )&DnsDomainInfo );
|
|
|
|
LsaClose( LsaPolicyHandle );
|
|
}
|
|
|
|
rc = RtlNtStatusToDosError(Status);
|
|
}
|
|
|
|
//
|
|
// get the template name (full UNC path) in sysvol
|
|
//
|
|
if ( ERROR_SUCCESS == rc &&
|
|
DnsDomainInfo &&
|
|
(DnsDomainInfo->DnsDomainName.Buffer) ) {
|
|
|
|
rc = ScepNotifyGetDefaultGPOTemplateName(
|
|
(UNICODE_STRING)(DnsDomainInfo->DnsDomainName),
|
|
NULL,
|
|
bAccountGPO,
|
|
dwInSetup ? SCEGPO_INSETUP_NT5 : 0,
|
|
&TemplateName
|
|
);
|
|
}
|
|
|
|
ScepNotifyLogPolicy(rc, FALSE, L"Get template name", DbType, ObjectType, TemplateName);
|
|
|
|
if ( ERROR_SUCCESS == rc && TemplateName ) {
|
|
|
|
//
|
|
// Check to see if the current DC is advertised to be a DC and
|
|
// and synchronized with the PDC policy
|
|
//
|
|
// Note, this check is bypassed in setup, is only done for the
|
|
// domain controller GPO, and for every 10 nodes processed
|
|
//
|
|
|
|
if ( gdwRequirePDCSync && (dwInSetup == 0) && !bAccountGPO &&
|
|
!gbCheckSync ) {
|
|
|
|
if ( ERROR_SUCCESS != ( rc = ScepWaitForSynchronizeWithPDC(
|
|
(UNICODE_STRING)(DnsDomainInfo->DnsDomainName),
|
|
TemplateName,
|
|
pbTimeout)) ) {
|
|
|
|
if ( *pbTimeout ) {
|
|
//
|
|
// we ran into maximum time out, must return and drop all nodes
|
|
// free TemplateName
|
|
//
|
|
LocalFree(TemplateName);
|
|
|
|
return rc;
|
|
|
|
} else {
|
|
|
|
//
|
|
// logs an event and let the change go through
|
|
//
|
|
LogEvent(MyModuleHandle,
|
|
STATUS_SEVERITY_ERROR,
|
|
SCEEVENT_ERROR_POLICY_PDCVERIFY,
|
|
SCESRV_POLICY_ERROR_VERIFY_SYNC,
|
|
rc
|
|
);
|
|
}
|
|
}
|
|
|
|
//
|
|
// PDC is already checked, set the flag now
|
|
//
|
|
gbCheckSync = TRUE;
|
|
}
|
|
|
|
AREA_INFORMATION Area;
|
|
PSCE_PROFILE_INFO pSceInfo=NULL;
|
|
|
|
//
|
|
// open template to get the existing template info
|
|
//
|
|
|
|
SCE_HINF hProfile;
|
|
|
|
hProfile.Type = (BYTE)SCE_INF_FORMAT;
|
|
|
|
rc = SceInfpOpenProfile(
|
|
TemplateName,
|
|
&(hProfile.hInf)
|
|
);
|
|
|
|
rc = ScepSceStatusToDosError(rc);
|
|
|
|
if ( ERROR_SUCCESS == rc ) {
|
|
|
|
if ( (DbType == SecurityDbLsa &&
|
|
ObjectType == SecurityDbObjectLsaAccount) ||
|
|
(DbType == SecurityDbSam &&
|
|
(ObjectType == SecurityDbObjectSamUser ||
|
|
ObjectType == SecurityDbObjectSamGroup ||
|
|
ObjectType == SecurityDbObjectSamAlias )) ) {
|
|
Area = AREA_ATTACHMENTS; // just create the buffer;
|
|
} else {
|
|
Area = AREA_SECURITY_POLICY;
|
|
}
|
|
|
|
//
|
|
// load informatin from the template (GP)
|
|
//
|
|
rc = (*pfSceGetInfo)(
|
|
(PVOID)&hProfile,
|
|
SCE_ENGINE_SCP,
|
|
Area,
|
|
&pSceInfo,
|
|
NULL
|
|
);
|
|
|
|
rc = ScepSceStatusToDosError(rc);
|
|
|
|
if ( ERROR_SUCCESS != rc ) {
|
|
|
|
ScepNotifyLogPolicy(rc, FALSE, L"Error read inf", DbType, ObjectType, TemplateName);
|
|
}
|
|
|
|
if ( Area == AREA_ATTACHMENTS ) {
|
|
//
|
|
// now get the real settings for user rights
|
|
//
|
|
Area = AREA_PRIVILEGES;
|
|
|
|
if ( pSceInfo ) {
|
|
|
|
rc = SceInfpGetPrivileges(
|
|
hProfile.hInf,
|
|
FALSE,
|
|
&(pSceInfo->OtherInfo.smp.pPrivilegeAssignedTo),
|
|
NULL
|
|
);
|
|
|
|
rc = ScepSceStatusToDosError(rc);
|
|
|
|
if ( ERROR_SUCCESS != rc ) {
|
|
ScepNotifyLogPolicy(rc, FALSE, L"Error read privileges from template", DbType, ObjectType, TemplateName);
|
|
}
|
|
}
|
|
}
|
|
|
|
SceInfpCloseProfile(hProfile.hInf);
|
|
|
|
} else {
|
|
|
|
ScepNotifyLogPolicy(rc, FALSE, L"Error open inf", DbType, ObjectType, TemplateName);
|
|
}
|
|
|
|
if ( ERROR_SUCCESS == rc && pSceInfo ) {
|
|
|
|
//
|
|
// SMP and INF takes the same structure
|
|
//
|
|
pSceInfo->Type = SCE_ENGINE_SMP;
|
|
|
|
BOOL bChanged = FALSE;
|
|
|
|
ScepIsDomainLocal(NULL);
|
|
|
|
//
|
|
// check if there is difference between current state of LSA
|
|
// and group policy templates.
|
|
//
|
|
rc = ScepNotifyGetChangedPolicies(
|
|
(SECURITY_DB_TYPE)DbType,
|
|
(SECURITY_DB_DELTA_TYPE)DeltaType,
|
|
(SECURITY_DB_OBJECT_TYPE)ObjectType,
|
|
(PSID)ObjectSid,
|
|
pSceInfo,
|
|
NULL,
|
|
FALSE, // not save to DB
|
|
ExplicitLowRight,
|
|
ExplicitHighRight,
|
|
&bChanged
|
|
);
|
|
|
|
if ( ERROR_SUCCESS == rc && bChanged ) {
|
|
//
|
|
// no error, get the policy for the area changed
|
|
// now, write it back to the template
|
|
//
|
|
|
|
ScepNotifyLogPolicy(0, FALSE, L"Save", DbType, ObjectType, NULL );
|
|
|
|
ScepCheckAndWaitPolicyPropFinish();
|
|
|
|
PSCE_ERROR_LOG_INFO pErrList=NULL;
|
|
|
|
rc = (*pfSceInfWriteInfo)(
|
|
TemplateName,
|
|
Area,
|
|
(PSCE_PROFILE_INFO)pSceInfo,
|
|
&pErrList
|
|
);
|
|
|
|
ScepNotifyLogPolicy(rc, FALSE, L"Save operation", DbType, ObjectType, NULL );
|
|
|
|
for (PSCE_ERROR_LOG_INFO pErr = pErrList; pErr != NULL; pErr = pErr->next) {
|
|
|
|
ScepNotifyLogPolicy(pErr->rc, FALSE, L"Save operation error", DbType, ObjectType, pErr->buffer );
|
|
}
|
|
|
|
ScepFreeErrorLog(pErrList);
|
|
|
|
rc = ScepSceStatusToDosError(rc);
|
|
|
|
//
|
|
// only update version # of the GPO if it's not access denied or file not found
|
|
// if verion # failed to update, still continue but in which case
|
|
// the change will probably not get replicated and applied on
|
|
// other DCs right away
|
|
//
|
|
|
|
if ( ERROR_ACCESS_DENIED != rc &&
|
|
ERROR_FILE_NOT_FOUND != rc ) {
|
|
|
|
DWORD rc2 = ScepNotifyUpdateGPOVersion( TemplateName,
|
|
bAccountGPO );
|
|
|
|
ScepNotifyLogPolicy(rc2, FALSE, L"GPO Version updated", DbType, ObjectType, NULL );
|
|
}
|
|
|
|
} else if ( ERROR_SUCCESS == rc ) {
|
|
//
|
|
// nothing changed
|
|
//
|
|
ScepNotifyLogPolicy(0, FALSE, L"No change", DbType, ObjectType, NULL );
|
|
}
|
|
|
|
}
|
|
|
|
//
|
|
// free any memory allocated
|
|
//
|
|
SceFreeMemory( (PVOID)pSceInfo, Area);
|
|
ScepFree(pSceInfo);
|
|
|
|
} else {
|
|
|
|
ScepNotifyLogPolicy(rc, FALSE, L"Error get file path", DbType, ObjectType, NULL );
|
|
}
|
|
|
|
//
|
|
// free TemplateName
|
|
//
|
|
LocalFree(TemplateName);
|
|
|
|
return rc;
|
|
}
|
|
|
|
DWORD
|
|
ScepWaitForSynchronizeWithPDC(
|
|
IN UNICODE_STRING DnsDomainName,
|
|
IN PWSTR LocalTemplateName,
|
|
OUT BOOL *pbTimeout
|
|
)
|
|
/*
|
|
Description:
|
|
|
|
Wait and verify that local DC is advertised and PDC is available.
|
|
|
|
When PDC is available, check the last modified time of local policy
|
|
template is equal or newer than the one on PDC. If the local copy is
|
|
too old, wait and check again until timeout.
|
|
|
|
Arguments:
|
|
|
|
DnsDomainName - the dns domain name which may be needed in template path
|
|
|
|
LocalTemplateName - the template full path name on the local DC.
|
|
|
|
pbTimeout - output to indicate if maximum wait has been reached.
|
|
|
|
*/
|
|
{
|
|
|
|
WCHAR SysName[MAX_COMPUTERNAME_LENGTH+1];
|
|
DWORD Len;
|
|
DWORD rc=ERROR_SUCCESS;
|
|
|
|
DWORD dwDCWait = 0;
|
|
DWORD dwMaxWaitCount = gdwMaxPDCWait / gdwPDCRetry + 1;
|
|
|
|
//
|
|
// make sure current DC is advertised
|
|
//
|
|
|
|
PDOMAIN_CONTROLLER_INFOW DCInfo=NULL;
|
|
PDOMAIN_CONTROLLER_INFOW PDCInfo=NULL;
|
|
PWSTR pComputerName=NULL;
|
|
PWSTR pTemp=NULL;
|
|
|
|
WIN32_FIND_DATA *LocalFileData=NULL;
|
|
WIN32_FIND_DATA *PDCFileData=NULL;
|
|
LARGE_INTEGER FileTime1;
|
|
LARGE_INTEGER FileTime2;
|
|
|
|
HANDLE hLocal=INVALID_HANDLE_VALUE;
|
|
HANDLE hPDC = INVALID_HANDLE_VALUE;
|
|
PWSTR PDCTemplateName=NULL;
|
|
|
|
//
|
|
// dynamic allocate stack buffer
|
|
//
|
|
SafeAllocaAllocate(LocalFileData, sizeof(WIN32_FIND_DATA));
|
|
if ( LocalFileData == NULL ) {
|
|
return (ERROR_NOT_ENOUGH_MEMORY);
|
|
}
|
|
|
|
SafeAllocaAllocate(PDCFileData, sizeof(WIN32_FIND_DATA));
|
|
|
|
if ( PDCFileData == NULL ) {
|
|
SafeAllocaFree(LocalFileData);
|
|
return (ERROR_NOT_ENOUGH_MEMORY);
|
|
}
|
|
|
|
do {
|
|
|
|
ScepNotifyLogPolicy(0, TRUE, L"Verify Sync: Check synchronization with PDC", 0, 0, NULL );
|
|
|
|
SysName[0] = L'\0';
|
|
Len = MAX_COMPUTERNAME_LENGTH;
|
|
|
|
if ( !GetComputerName(SysName, &Len) ) {
|
|
rc = GetLastError();
|
|
|
|
ScepNotifyLogPolicy(rc, FALSE, L"Verify Sync: Failed to get computer name", 0, 0, NULL );
|
|
|
|
//
|
|
// do not return, let it fail in DsGetDcName so we can get the maximum wait
|
|
//
|
|
}
|
|
|
|
//
|
|
// get local DC status
|
|
//
|
|
rc = DsGetDcName(SysName,
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
DS_IS_DNS_NAME,
|
|
&DCInfo
|
|
);
|
|
|
|
if ( ERROR_SUCCESS == rc ) {
|
|
|
|
//
|
|
// current DC is available, check the DS role
|
|
// local DC role should be accurate
|
|
//
|
|
|
|
if ( 0 == (DCInfo->Flags & DS_PDC_FLAG) ) {
|
|
|
|
//
|
|
// local DC is not a PDC, check PDC role
|
|
// get the PDC name first
|
|
//
|
|
|
|
rc = DsGetDcName(NULL,
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
DS_IS_FLAT_NAME | DS_PDC_REQUIRED,
|
|
&PDCInfo
|
|
);
|
|
|
|
if ( ERROR_SUCCESS == rc ) {
|
|
|
|
//
|
|
// Even though DsGetDcName tells the DS role is a PDC,
|
|
// it may not be (e.g., FSMO is transferred).
|
|
//
|
|
// Talk to the DC remotely to confirm. If the DC is not
|
|
// hosting a PDC role, let the code wait and retry
|
|
// since DsGetDcName cache will be eventually updated with
|
|
// the correct PDC info
|
|
//
|
|
|
|
pComputerName = PDCInfo->DomainControllerName;
|
|
//
|
|
// skip the backslashes
|
|
//
|
|
while ( *pComputerName == L'\\' ) pComputerName++;
|
|
|
|
//
|
|
// search for . to extract the computer name
|
|
//
|
|
pTemp = wcschr(pComputerName, L'.');
|
|
if ( pTemp ) *pTemp = L'\0';
|
|
|
|
|
|
BOOL bIsPDC = TRUE;
|
|
|
|
rc = ScepVerifyPDCRole(pComputerName, &bIsPDC);
|
|
|
|
//
|
|
// verify that the PDC name returned is indeed a PDC
|
|
//
|
|
if ( ERROR_SUCCESS != rc ) {
|
|
|
|
ScepNotifyLogPolicy(rc, FALSE, L"Verify Sync: Fail to verify PDC role for ", 0, 0, pComputerName );
|
|
rc = ERROR_INVALID_DOMAIN_ROLE;
|
|
|
|
} else if ( !bIsPDC ) {
|
|
|
|
ScepNotifyLogPolicy(0, FALSE, L"Verify Sync: Computer is not really in PDC role.", 0, 0, pComputerName );
|
|
rc = ERROR_INVALID_DOMAIN_ROLE;
|
|
|
|
} else {
|
|
|
|
//
|
|
// get the timestamp of gpttmpl.inf from the PDC
|
|
//
|
|
PDCTemplateName=NULL;
|
|
|
|
rc = ScepNotifyGetDefaultGPOTemplateName(DnsDomainName,
|
|
pComputerName,
|
|
FALSE,
|
|
SCEGPO_NOCHECK_EXISTENCE,
|
|
&PDCTemplateName
|
|
);
|
|
|
|
ScepNotifyLogPolicy(rc, FALSE, L"Verify Sync: Get template name on PDC", 0, 0, PDCTemplateName );
|
|
|
|
if ( ERROR_SUCCESS != rc ) {
|
|
//
|
|
// if failed to build a template name, it must because of out of memory
|
|
// no need to loop for this kind of failure
|
|
//
|
|
break;
|
|
|
|
} else {
|
|
|
|
if ( 0xFFFFFFFF == GetFileAttributes(PDCTemplateName) ) {
|
|
|
|
//
|
|
// current PDC template is not reachable, try again
|
|
// this could be become of network problem.
|
|
//
|
|
rc = GetLastError();
|
|
ScepNotifyLogPolicy(rc, FALSE, L"Verify Sync: PDC template is not accessible. Try again later", 0, 0, NULL );
|
|
|
|
} else {
|
|
|
|
//
|
|
// get local timestamp
|
|
//
|
|
memset(LocalFileData, '\0', sizeof(WIN32_FIND_DATA));
|
|
memset(PDCFileData, '\0', sizeof(WIN32_FIND_DATA));
|
|
|
|
hLocal=INVALID_HANDLE_VALUE;
|
|
hPDC = INVALID_HANDLE_VALUE;
|
|
|
|
hLocal = FindFirstFile(LocalTemplateName, LocalFileData);
|
|
if ( hLocal != INVALID_HANDLE_VALUE ) {
|
|
|
|
FindClose(hLocal);
|
|
hLocal = NULL;
|
|
|
|
//
|
|
// get PDC time stamp
|
|
//
|
|
|
|
hPDC = FindFirstFile(PDCTemplateName, PDCFileData);
|
|
|
|
if ( hPDC != INVALID_HANDLE_VALUE ) {
|
|
|
|
FindClose(hPDC);
|
|
hPDC = NULL;
|
|
|
|
FileTime1.LowPart = LocalFileData->ftLastWriteTime.dwLowDateTime;
|
|
FileTime1.HighPart = LocalFileData->ftLastWriteTime.dwHighDateTime;
|
|
|
|
FileTime2.LowPart = PDCFileData->ftLastWriteTime.dwLowDateTime;
|
|
FileTime2.HighPart = PDCFileData->ftLastWriteTime.dwHighDateTime;
|
|
|
|
//
|
|
// get time difference in minutes
|
|
//
|
|
LONG lDiff = 0;
|
|
|
|
if ( FileTime2.QuadPart != FileTime1.QuadPart ) {
|
|
lDiff = (LONG) ((FileTime2.QuadPart - FileTime1.QuadPart) / 10000000);
|
|
lDiff /= 60;
|
|
|
|
if ( lDiff >= 0 ) lDiff ++;
|
|
else lDiff --;
|
|
}
|
|
|
|
WCHAR szTime[32];
|
|
swprintf(szTime, L"%d minutes\0", lDiff);
|
|
|
|
if ( lDiff <= 0 ) {
|
|
//
|
|
// the local copy is newer or within the allowed delta window
|
|
// so this check is passed
|
|
//
|
|
ScepNotifyLogPolicy(0, FALSE, L"Verify Sync: Local copy is within range from PDC", 0, 0, szTime );
|
|
break;
|
|
|
|
} else {
|
|
|
|
ScepNotifyLogPolicy(0, FALSE, L"Verify Sync: Local copy is out of range from PDC", 0, 0, szTime );
|
|
rc = WAIT_TIMEOUT;
|
|
}
|
|
|
|
} else {
|
|
|
|
rc = GetLastError();
|
|
ScepNotifyLogPolicy(rc, FALSE, L"Verify Sync: Failed to get PDC file time", 0, 0, PDCTemplateName );
|
|
}
|
|
|
|
} else {
|
|
|
|
//
|
|
// if it cannot query file time on the local box
|
|
// something is wrong locally, do not retry
|
|
//
|
|
rc = GetLastError();
|
|
ScepNotifyLogPolicy(rc, FALSE, L"Verify Sync: Failed to get local file time", 0, 0, LocalTemplateName );
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
//
|
|
// mask the error so that caller knows if it reaches maximum wait
|
|
//
|
|
if ( ERROR_SUCCESS != rc ) {
|
|
|
|
rc = WAIT_TIMEOUT;
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
//
|
|
// current PDC is not available, try again
|
|
//
|
|
|
|
ScepNotifyLogPolicy(rc, FALSE, L"Verify Sync: Fail to get PDC info. Try again later", 0, 0, NULL );
|
|
rc = ERROR_INVALID_DOMAIN_ROLE;
|
|
}
|
|
|
|
} else {
|
|
|
|
//
|
|
// local DC is already a PDC, no need to check
|
|
// break the loop
|
|
//
|
|
ScepNotifyLogPolicy(0, FALSE, L"Verify Sync: Local DC is a PDC", 0, 0, NULL );
|
|
|
|
break;
|
|
}
|
|
|
|
|
|
} else {
|
|
|
|
ScepNotifyLogPolicy(rc, FALSE, L"Verify Sync: Fail to get local DC info. Try again later", 0, 0, NULL );
|
|
|
|
rc = ERROR_DOMAIN_CONTROLLER_NOT_FOUND;
|
|
}
|
|
|
|
//
|
|
// restore the name
|
|
//
|
|
if ( pTemp ) {
|
|
*pTemp = L'.';
|
|
pTemp=NULL;
|
|
}
|
|
|
|
//
|
|
// free buffers
|
|
//
|
|
|
|
if ( PDCInfo ) {
|
|
NetApiBufferFree(PDCInfo);
|
|
PDCInfo = NULL;
|
|
}
|
|
pComputerName = NULL;
|
|
|
|
if ( DCInfo ) {
|
|
NetApiBufferFree(DCInfo);
|
|
DCInfo = NULL;
|
|
}
|
|
|
|
if ( PDCTemplateName ) {
|
|
ScepFree(PDCTemplateName);
|
|
PDCTemplateName = NULL;
|
|
}
|
|
|
|
//
|
|
// sleep for some time and try again
|
|
//
|
|
Sleep(gdwPDCRetry*60*1000);
|
|
dwDCWait++;
|
|
|
|
} while ( dwDCWait < dwMaxWaitCount );
|
|
|
|
|
|
if ( dwDCWait >= dwMaxWaitCount &&
|
|
ERROR_SUCCESS != rc ) {
|
|
|
|
//
|
|
// something fails/times out when verifying the PDC, log a message
|
|
//
|
|
|
|
switch ( rc ) {
|
|
case ERROR_DOMAIN_CONTROLLER_NOT_FOUND:
|
|
|
|
ScepNotifyLogPolicy(0, TRUE, L"Verify Sync: Local DC is not advertised", 0, 0, NULL );
|
|
*pbTimeout = TRUE;
|
|
break;
|
|
case ERROR_INVALID_DOMAIN_ROLE:
|
|
|
|
ScepNotifyLogPolicy(0, TRUE, L"Verify Sync: PDC role cannot be found", 0, 0, NULL );
|
|
*pbTimeout = TRUE;
|
|
break;
|
|
case WAIT_TIMEOUT:
|
|
|
|
ScepNotifyLogPolicy(0, TRUE, L"Verify Sync: Local policy is not or may not be synchronized with PDC", 0, 0, NULL );
|
|
*pbTimeout = TRUE;
|
|
break;
|
|
}
|
|
}
|
|
|
|
|
|
//
|
|
// restore the name
|
|
//
|
|
if ( pTemp ) {
|
|
*pTemp = L'.';
|
|
}
|
|
|
|
//
|
|
// free buffers
|
|
//
|
|
|
|
if ( PDCInfo ) {
|
|
NetApiBufferFree(PDCInfo);
|
|
}
|
|
|
|
if ( DCInfo ) {
|
|
NetApiBufferFree(DCInfo);
|
|
}
|
|
|
|
if ( PDCTemplateName )
|
|
ScepFree(PDCTemplateName);
|
|
|
|
|
|
SafeAllocaFree(PDCFileData);
|
|
SafeAllocaFree(LocalFileData);
|
|
|
|
return rc;
|
|
|
|
}
|
|
|
|
DWORD
|
|
ScepVerifyPDCRole(
|
|
IN PWSTR pComputerName,
|
|
OUT BOOL *pbIsPDC
|
|
)
|
|
/*
|
|
Description:
|
|
|
|
For the given computer name (returned from DsGetDcName for PDC role),
|
|
verify that it's indeed hold a PDC FSMO at the current time.
|
|
|
|
DsGetDcName may returned cached name for the PDC which may not be
|
|
in function, or PDC FSMO may be transferred.
|
|
|
|
This is to guarantee that we always compare with PDC policy
|
|
|
|
Arguments:
|
|
|
|
pComputerName - the computer name for the proposed PDC
|
|
|
|
pbIsPDC - When return code is success, TRUE = PDC, FALSE = non PDC
|
|
|
|
Return Value:
|
|
|
|
Win32 error
|
|
*/
|
|
|
|
{
|
|
if ( pComputerName == NULL || pbIsPDC == NULL ) {
|
|
return(ERROR_INVALID_PARAMETER);
|
|
}
|
|
|
|
|
|
NTSTATUS NtStatus;
|
|
LSA_OBJECT_ATTRIBUTES attributes;
|
|
SECURITY_QUALITY_OF_SERVICE service;
|
|
LSA_HANDLE PolicyHandle=NULL;
|
|
DWORD rc=0;
|
|
|
|
memset( &attributes, 0, sizeof(attributes) );
|
|
attributes.Length = sizeof(attributes);
|
|
attributes.SecurityQualityOfService = &service;
|
|
service.Length = sizeof(service);
|
|
service.ImpersonationLevel= SecurityImpersonation;
|
|
service.ContextTrackingMode = SECURITY_DYNAMIC_TRACKING;
|
|
service.EffectiveOnly = TRUE;
|
|
|
|
LSA_UNICODE_STRING SystemName;
|
|
|
|
SystemName.Buffer = pComputerName;
|
|
SystemName.Length = wcslen(pComputerName)*sizeof(WCHAR);
|
|
SystemName.MaximumLength = SystemName.Length + 2;
|
|
|
|
//
|
|
// open the remote lsa
|
|
//
|
|
|
|
NtStatus = LsaOpenPolicy(
|
|
&SystemName,
|
|
&attributes,
|
|
POLICY_VIEW_LOCAL_INFORMATION,
|
|
&PolicyHandle
|
|
);
|
|
|
|
rc = RtlNtStatusToDosError(NtStatus);
|
|
|
|
if ( NT_SUCCESS(NtStatus) ) {
|
|
|
|
//
|
|
// query LSA server role from the remote computer
|
|
//
|
|
PPOLICY_LSA_SERVER_ROLE_INFO pServerRole=NULL;
|
|
|
|
NtStatus = LsaQueryInformationPolicy(PolicyHandle,
|
|
PolicyLsaServerRoleInformation,
|
|
(PVOID *)&pServerRole
|
|
);
|
|
|
|
rc = RtlNtStatusToDosError(NtStatus);
|
|
|
|
if ( NT_SUCCESS(NtStatus) ) {
|
|
|
|
//
|
|
// check the role and set output appropriately
|
|
//
|
|
if ( PolicyServerRolePrimary == pServerRole->LsaServerRole ) {
|
|
*pbIsPDC = TRUE;
|
|
} else {
|
|
*pbIsPDC = FALSE;
|
|
}
|
|
|
|
LsaFreeMemory(pServerRole);
|
|
|
|
rc = ERROR_SUCCESS;
|
|
}
|
|
|
|
LsaClose(PolicyHandle);
|
|
}
|
|
|
|
return(rc);
|
|
}
|
|
|
|
|
|
SCEPR_STATUS
|
|
SceRpcBrowseDatabaseTable(
|
|
IN handle_t binding_h,
|
|
IN wchar_t *DatabaseName OPTIONAL,
|
|
IN SCEPR_TYPE ProfileType,
|
|
IN AREAPR Area,
|
|
IN BOOL bDomainPolicyOnly
|
|
)
|
|
{
|
|
|
|
UINT ClientLocalFlag = 0;
|
|
|
|
if ( RPC_S_OK != I_RpcBindingIsClientLocal( NULL, &ClientLocalFlag) ||
|
|
0 == ClientLocalFlag ){
|
|
|
|
//
|
|
// to prevent denial-of-service type attacks,
|
|
// do not allow remote RPC
|
|
//
|
|
|
|
return SCESTATUS_ACCESS_DENIED;
|
|
|
|
}
|
|
|
|
SCESTATUS rc;
|
|
|
|
if ( bStopRequest ) {
|
|
return(SCESTATUS_SERVICE_NOT_SUPPORT);
|
|
}
|
|
|
|
//
|
|
// initialize jet engine in system context
|
|
//
|
|
rc = SceJetInitialize(NULL);
|
|
|
|
if ( SCESTATUS_SUCCESS != rc ) {
|
|
return(rc);
|
|
}
|
|
|
|
//
|
|
// impersonate the client, return DWORD error code
|
|
//
|
|
|
|
rc = RpcImpersonateClient( NULL );
|
|
|
|
if (rc != RPC_S_OK) {
|
|
//
|
|
// if no other active clients, terminate jet engine
|
|
//
|
|
ScepIfTerminateEngine();
|
|
|
|
return( ScepDosErrorToSceStatus(rc) );
|
|
|
|
}
|
|
|
|
|
|
BOOL bAdminSidInToken = FALSE;
|
|
|
|
rc = ScepDosErrorToSceStatus(ScepIsAdminLoggedOn(&bAdminSidInToken, TRUE));
|
|
|
|
if (SCESTATUS_SUCCESS != rc || FALSE == bAdminSidInToken) {
|
|
RpcRevertToSelf();
|
|
return SCESTATUS_SPECIAL_ACCOUNT;
|
|
}
|
|
|
|
|
|
//
|
|
// get the database name
|
|
//
|
|
|
|
BOOL bAdminLogon=FALSE;
|
|
LPTSTR DefProfile=NULL;
|
|
PSCECONTEXT hProfile=NULL;
|
|
|
|
__try {
|
|
|
|
rc = ScepGetDefaultDatabase(
|
|
(LPCTSTR)DatabaseName,
|
|
0,
|
|
NULL,
|
|
&bAdminLogon,
|
|
&DefProfile
|
|
);
|
|
|
|
} __except (EXCEPTION_EXECUTE_HANDLER) {
|
|
|
|
rc = ERROR_EXCEPTION_IN_SERVICE;
|
|
}
|
|
|
|
rc = ScepDosErrorToSceStatus(rc);
|
|
|
|
if ( SCESTATUS_SUCCESS == rc && DefProfile ) {
|
|
|
|
//
|
|
// OpenDatabase is not blocked by any task.
|
|
//
|
|
|
|
EnterCriticalSection(&ContextSync);
|
|
|
|
DWORD Option=0;
|
|
if ( ProfileType == SCE_ENGINE_SAP ) {
|
|
if ( bDomainPolicyOnly )
|
|
Option = SCE_OPEN_OPTION_TATTOO;
|
|
else
|
|
Option = SCE_OPEN_OPTION_REQUIRE_ANALYSIS;
|
|
}
|
|
|
|
rc = ScepOpenDatabase(
|
|
(PCWSTR)DefProfile,
|
|
Option,
|
|
SCEJET_OPEN_READ_ONLY,
|
|
&hProfile
|
|
);
|
|
|
|
if ( SCESTATUS_SUCCESS == rc ) {
|
|
//
|
|
// a new context is opened, add it to the open context list
|
|
//
|
|
|
|
if ( (ProfileType != SCE_ENGINE_SAP) && bDomainPolicyOnly &&
|
|
( (hProfile->Type & 0xF0L) != SCEJET_MERGE_TABLE_1 ) &&
|
|
( (hProfile->Type & 0xF0L) != SCEJET_MERGE_TABLE_2 ) ) {
|
|
//
|
|
// there is no merged policy table
|
|
//
|
|
rc = SceJetCloseFile(
|
|
hProfile,
|
|
TRUE,
|
|
FALSE
|
|
);
|
|
|
|
rc = SCESTATUS_PROFILE_NOT_FOUND;
|
|
hProfile = NULL;
|
|
|
|
} else {
|
|
|
|
ScepAddToOpenContext(hProfile);
|
|
}
|
|
} else {
|
|
ScepLogOutput3(1, ScepSceStatusToDosError(rc),
|
|
SCEDLL_ERROR_OPEN, DefProfile);
|
|
}
|
|
|
|
LeaveCriticalSection(&ContextSync);
|
|
|
|
if ( DefProfile != DatabaseName )
|
|
ScepFree(DefProfile);
|
|
DefProfile = NULL;
|
|
}
|
|
|
|
if ( SCESTATUS_SUCCESS == rc ) {
|
|
|
|
if ( ProfileType == SCE_ENGINE_SCP ) {
|
|
switch ( (hProfile->Type & 0xF0L) ) {
|
|
case SCEJET_MERGE_TABLE_1:
|
|
SceClientBrowseCallback(
|
|
0,
|
|
L"Merged Policy Table 1",
|
|
NULL,
|
|
NULL
|
|
);
|
|
break;
|
|
case SCEJET_MERGE_TABLE_2:
|
|
SceClientBrowseCallback(
|
|
0,
|
|
L"Merged Policy Table 2",
|
|
NULL,
|
|
NULL
|
|
);
|
|
break;
|
|
default:
|
|
|
|
SceClientBrowseCallback(
|
|
0,
|
|
L"There is no merged policy table. Local policy table is used.",
|
|
NULL,
|
|
NULL
|
|
);
|
|
break;
|
|
}
|
|
|
|
}
|
|
//
|
|
// browse the information now
|
|
//
|
|
DWORD dwBrowseOptions;
|
|
|
|
if ( (ProfileType != SCE_ENGINE_SAP) && bDomainPolicyOnly ) {
|
|
dwBrowseOptions = SCEBROWSE_DOMAIN_POLICY;
|
|
} else {
|
|
dwBrowseOptions = 0;
|
|
}
|
|
|
|
if ( Area & AREA_SECURITY_POLICY ) {
|
|
|
|
rc = ScepBrowseTableSection(
|
|
hProfile,
|
|
(SCETYPE)ProfileType,
|
|
szSystemAccess,
|
|
dwBrowseOptions
|
|
);
|
|
|
|
if ( SCESTATUS_SUCCESS == rc ) {
|
|
|
|
rc = ScepBrowseTableSection(
|
|
hProfile,
|
|
(SCETYPE)ProfileType,
|
|
szKerberosPolicy,
|
|
dwBrowseOptions
|
|
);
|
|
}
|
|
|
|
if ( SCESTATUS_SUCCESS == rc ) {
|
|
|
|
rc = ScepBrowseTableSection(
|
|
hProfile,
|
|
(SCETYPE)ProfileType,
|
|
szAuditEvent,
|
|
dwBrowseOptions
|
|
);
|
|
}
|
|
|
|
if ( SCESTATUS_SUCCESS == rc ) {
|
|
|
|
rc = ScepBrowseTableSection(
|
|
hProfile,
|
|
(SCETYPE)ProfileType,
|
|
szAuditSystemLog,
|
|
dwBrowseOptions
|
|
);
|
|
}
|
|
|
|
if ( SCESTATUS_SUCCESS == rc ) {
|
|
|
|
rc = ScepBrowseTableSection(
|
|
hProfile,
|
|
(SCETYPE)ProfileType,
|
|
szAuditSecurityLog,
|
|
dwBrowseOptions
|
|
);
|
|
}
|
|
if ( SCESTATUS_SUCCESS == rc ) {
|
|
|
|
rc = ScepBrowseTableSection(
|
|
hProfile,
|
|
(SCETYPE)ProfileType,
|
|
szAuditApplicationLog,
|
|
dwBrowseOptions
|
|
);
|
|
}
|
|
if ( SCESTATUS_SUCCESS == rc ) {
|
|
|
|
rc = ScepBrowseTableSection(
|
|
hProfile,
|
|
(SCETYPE)ProfileType,
|
|
szRegistryValues,
|
|
dwBrowseOptions | SCEBROWSE_MULTI_SZ
|
|
);
|
|
}
|
|
}
|
|
|
|
if ( (Area & AREA_PRIVILEGES) &&
|
|
(SCESTATUS_SUCCESS == rc) ) {
|
|
|
|
rc = ScepBrowseTableSection(
|
|
hProfile,
|
|
(SCETYPE)ProfileType,
|
|
szPrivilegeRights,
|
|
dwBrowseOptions | SCEBROWSE_MULTI_SZ
|
|
);
|
|
}
|
|
if ( (Area & AREA_GROUP_MEMBERSHIP) &&
|
|
(SCESTATUS_SUCCESS == rc) ) {
|
|
|
|
rc = ScepBrowseTableSection(
|
|
hProfile,
|
|
(SCETYPE)ProfileType,
|
|
szGroupMembership,
|
|
dwBrowseOptions | SCEBROWSE_MULTI_SZ
|
|
);
|
|
}
|
|
if ( (Area & AREA_SYSTEM_SERVICE) &&
|
|
(SCESTATUS_SUCCESS == rc) ) {
|
|
|
|
rc = ScepBrowseTableSection(
|
|
hProfile,
|
|
(SCETYPE)ProfileType,
|
|
szServiceGeneral,
|
|
dwBrowseOptions
|
|
);
|
|
}
|
|
|
|
if ( (Area & AREA_REGISTRY_SECURITY) &&
|
|
(SCESTATUS_SUCCESS == rc) ) {
|
|
|
|
rc = ScepBrowseTableSection(
|
|
hProfile,
|
|
(SCETYPE)ProfileType,
|
|
szRegistryKeys,
|
|
dwBrowseOptions
|
|
);
|
|
}
|
|
if ( (Area & AREA_FILE_SECURITY) &&
|
|
(SCESTATUS_SUCCESS == rc) ) {
|
|
|
|
rc = ScepBrowseTableSection(
|
|
hProfile,
|
|
(SCETYPE)ProfileType,
|
|
szFileSecurity,
|
|
dwBrowseOptions
|
|
);
|
|
}
|
|
|
|
if ( (Area & AREA_ATTACHMENTS) &&
|
|
(SCESTATUS_SUCCESS == rc) ) {
|
|
|
|
PSCE_NAME_LIST pList=NULL;
|
|
|
|
rc = ScepEnumAttachmentSections( hProfile, &pList);
|
|
|
|
if ( rc == SCESTATUS_SUCCESS ) {
|
|
|
|
for ( PSCE_NAME_LIST pNode=pList; pNode != NULL; pNode=pNode->Next) {
|
|
|
|
rc = ScepBrowseTableSection(
|
|
hProfile,
|
|
(SCETYPE)ProfileType,
|
|
pNode->Name,
|
|
dwBrowseOptions
|
|
);
|
|
if ( SCESTATUS_SUCCESS != rc ) {
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
ScepFreeNameList(pList);
|
|
}
|
|
|
|
ScepValidateAndCloseDatabase(hProfile);
|
|
hProfile = NULL;
|
|
|
|
} else {
|
|
|
|
//
|
|
// start a timer queue to check to see if there is active tasks/contexts
|
|
// if not, terminate jet engine
|
|
//
|
|
ScepIfTerminateEngine();
|
|
|
|
}
|
|
|
|
ScepLogClose();
|
|
|
|
RpcRevertToSelf();
|
|
|
|
return((SCEPR_STATUS)rc);
|
|
}
|
|
|
|
BOOL
|
|
ScepIsSystemShutDown()
|
|
{
|
|
|
|
return(gbSystemShutdown);
|
|
|
|
}
|
|
|
|
SCESTATUS
|
|
ScepConvertServices(
|
|
IN OUT PVOID *ppServices,
|
|
IN BOOL bSRForm
|
|
)
|
|
{
|
|
if ( !ppServices ) {
|
|
return(SCESTATUS_INVALID_PARAMETER);
|
|
}
|
|
|
|
PSCE_SERVICES pTemp = (PSCE_SERVICES)(*ppServices);
|
|
SCESTATUS rc=SCESTATUS_SUCCESS;
|
|
|
|
PSCE_SERVICES pNewNode;
|
|
PSCE_SERVICES pNewServices=NULL;
|
|
|
|
while ( pTemp ) {
|
|
|
|
pNewNode = (PSCE_SERVICES)ScepAlloc(0,sizeof(SCE_SERVICES));
|
|
|
|
if ( pNewNode ) {
|
|
|
|
pNewNode->ServiceName = pTemp->ServiceName;
|
|
pNewNode->DisplayName = pTemp->DisplayName;
|
|
pNewNode->Status = pTemp->Status;
|
|
pNewNode->Startup = pTemp->Startup;
|
|
pNewNode->SeInfo = pTemp->SeInfo;
|
|
|
|
pNewNode->General.pSecurityDescriptor = NULL;
|
|
|
|
pNewNode->Next = pNewServices;
|
|
pNewServices = pNewNode;
|
|
|
|
if ( bSRForm ) {
|
|
//
|
|
// Service node is in SCEPR_SERVICES structure
|
|
// convert it to SCE_SERVICES structure
|
|
// in this case, just use the self relative security descriptor
|
|
//
|
|
if ( pTemp->General.pSecurityDescriptor) {
|
|
pNewNode->General.pSecurityDescriptor = ((PSCEPR_SERVICES)pTemp)->pSecurityDescriptor->SecurityDescriptor;
|
|
}
|
|
|
|
} else {
|
|
|
|
//
|
|
// Service node is in SCE_SERVICES strucutre
|
|
// convert it to SCEPR_SERVICES structure
|
|
//
|
|
// make the SD to self relative format and PSCEPR_SR_SECURITY_DESCRIPTOR
|
|
//
|
|
|
|
if ( pTemp->General.pSecurityDescriptor ) {
|
|
|
|
if ( !RtlValidSid ( pTemp->General.pSecurityDescriptor ) ) {
|
|
rc = SCESTATUS_INVALID_PARAMETER;
|
|
break;
|
|
}
|
|
|
|
//
|
|
// get the length
|
|
//
|
|
DWORD nLen = 0;
|
|
DWORD NewLen;
|
|
PSECURITY_DESCRIPTOR pSD;
|
|
PSCEPR_SR_SECURITY_DESCRIPTOR pNewWrap;
|
|
|
|
RtlMakeSelfRelativeSD( pTemp->General.pSecurityDescriptor,
|
|
NULL,
|
|
&nLen
|
|
);
|
|
|
|
if ( nLen > 0 ) {
|
|
|
|
pSD = (PSECURITY_DESCRIPTOR)ScepAlloc(LMEM_ZEROINIT, nLen);
|
|
|
|
if ( !pSD ) {
|
|
rc = SCESTATUS_NOT_ENOUGH_RESOURCE;
|
|
break;
|
|
}
|
|
|
|
NewLen = nLen;
|
|
|
|
rc = ScepDosErrorToSceStatus(
|
|
RtlNtStatusToDosError(
|
|
RtlMakeSelfRelativeSD( pTemp->General.pSecurityDescriptor,
|
|
pSD,
|
|
&NewLen
|
|
) ) );
|
|
|
|
if ( SCESTATUS_SUCCESS == rc ) {
|
|
|
|
//
|
|
// create a wrapper node to contain the security descriptor
|
|
//
|
|
|
|
pNewWrap = (PSCEPR_SR_SECURITY_DESCRIPTOR)ScepAlloc(0, sizeof(SCEPR_SR_SECURITY_DESCRIPTOR));
|
|
if ( pNewWrap ) {
|
|
|
|
//
|
|
// assign the wrap to the structure
|
|
//
|
|
pNewWrap->SecurityDescriptor = (UCHAR *)pSD;
|
|
pNewWrap->Length = nLen;
|
|
|
|
} else {
|
|
rc = SCESTATUS_NOT_ENOUGH_RESOURCE;
|
|
}
|
|
}
|
|
|
|
if ( SCESTATUS_SUCCESS != rc ) {
|
|
ScepFree(pSD);
|
|
break;
|
|
}
|
|
|
|
//
|
|
// now link the SR_SD to the list
|
|
//
|
|
((PSCEPR_SERVICES)pNewNode)->pSecurityDescriptor = pNewWrap;
|
|
|
|
} else {
|
|
//
|
|
// something is wrong with the SD
|
|
//
|
|
rc = SCESTATUS_INVALID_PARAMETER;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
} else {
|
|
//
|
|
// all allocated buffer are in the list of pNewServices
|
|
//
|
|
rc = SCESTATUS_NOT_ENOUGH_RESOURCE;
|
|
break;
|
|
}
|
|
|
|
pTemp = pTemp->Next;
|
|
}
|
|
|
|
if ( SCESTATUS_SUCCESS != rc ) {
|
|
|
|
//
|
|
// free pNewServices
|
|
//
|
|
ScepFreeConvertedServices( (PVOID)pNewServices, !bSRForm );
|
|
pNewServices = NULL;
|
|
}
|
|
|
|
*ppServices = (PVOID)pNewServices;
|
|
|
|
return(rc);
|
|
}
|
|
|
|
|
|
SCESTATUS
|
|
ScepFreeConvertedServices(
|
|
IN PVOID pServices,
|
|
IN BOOL bSRForm
|
|
)
|
|
{
|
|
|
|
if ( pServices == NULL ) {
|
|
return(SCESTATUS_SUCCESS);
|
|
}
|
|
|
|
PSCEPR_SERVICES pNewNode = (PSCEPR_SERVICES)pServices;
|
|
|
|
PSCEPR_SERVICES pTempNode;
|
|
|
|
while ( pNewNode ) {
|
|
|
|
if ( bSRForm && pNewNode->pSecurityDescriptor ) {
|
|
|
|
//
|
|
// free this allocated buffer (PSCEPR_SR_SECURITY_DESCRIPTOR)
|
|
//
|
|
if ( pNewNode->pSecurityDescriptor->SecurityDescriptor ) {
|
|
ScepFree( pNewNode->pSecurityDescriptor->SecurityDescriptor);
|
|
}
|
|
ScepFree(pNewNode->pSecurityDescriptor);
|
|
}
|
|
|
|
//
|
|
// also free the PSCEPR_SERVICE node (but not the names referenced by this node)
|
|
//
|
|
pTempNode = pNewNode;
|
|
pNewNode = pNewNode->Next;
|
|
|
|
ScepFree(pTempNode);
|
|
}
|
|
|
|
return(SCESTATUS_SUCCESS);
|
|
}
|
|
|
|
|
|
SCESTATUS
|
|
SceRpcGetSystemSecurity(
|
|
IN handle_t binding_h,
|
|
IN AREAPR Area,
|
|
IN DWORD Options,
|
|
OUT PSCEPR_PROFILE_INFO __RPC_FAR *ppInfoBuffer,
|
|
OUT PSCEPR_ERROR_LOG_INFO __RPC_FAR *Errlog OPTIONAL
|
|
)
|
|
/*
|
|
Routine Description:
|
|
|
|
Query system security settings)
|
|
|
|
Only password, account lockout, kerberos, audit, user rights, and
|
|
SCE registry values are queried.
|
|
|
|
multile threads doing get/set system security are not blocked. In
|
|
other words, system security settings are not exclusive.
|
|
*/
|
|
|
|
{
|
|
UINT ClientLocalFlag = 0;
|
|
|
|
if ( RPC_S_OK != I_RpcBindingIsClientLocal( NULL, &ClientLocalFlag) ||
|
|
0 == ClientLocalFlag ){
|
|
|
|
//
|
|
// to prevent denial-of-service type attacks,
|
|
// do not allow remote RPC
|
|
//
|
|
|
|
return SCESTATUS_ACCESS_DENIED;
|
|
|
|
}
|
|
|
|
DWORD rc;
|
|
|
|
if ( bStopRequest ) {
|
|
return(SCESTATUS_SERVICE_NOT_SUPPORT);
|
|
}
|
|
|
|
//
|
|
// impersonate the client
|
|
//
|
|
|
|
rc = RpcImpersonateClient( NULL );
|
|
|
|
if (rc != RPC_S_OK) {
|
|
|
|
return( rc );
|
|
}
|
|
|
|
BOOL bAdminSidInToken = FALSE;
|
|
|
|
rc = ScepDosErrorToSceStatus(ScepIsAdminLoggedOn(&bAdminSidInToken, TRUE));
|
|
|
|
if (SCESTATUS_SUCCESS != rc || FALSE == bAdminSidInToken) {
|
|
RpcRevertToSelf();
|
|
return SCESTATUS_SPECIAL_ACCOUNT;
|
|
}
|
|
|
|
__try {
|
|
//
|
|
// catch exception if InfFileName, or pebClient/pdWarning are bogus
|
|
//
|
|
rc = ScepGetSystemSecurity(
|
|
(AREA_INFORMATION)Area,
|
|
Options,
|
|
(PSCE_PROFILE_INFO *)ppInfoBuffer,
|
|
(PSCE_ERROR_LOG_INFO *)Errlog
|
|
);
|
|
|
|
} __except(EXCEPTION_EXECUTE_HANDLER) {
|
|
|
|
rc = SCESTATUS_EXCEPTION_IN_SERVER;
|
|
}
|
|
|
|
RpcRevertToSelf();
|
|
|
|
return(rc);
|
|
}
|
|
|
|
SCESTATUS
|
|
SceRpcGetSystemSecurityFromHandle(
|
|
IN SCEPR_CONTEXT Context, // must be a context point to system db
|
|
IN AREAPR Area,
|
|
IN DWORD Options,
|
|
OUT PSCEPR_PROFILE_INFO __RPC_FAR *ppInfoBuffer,
|
|
OUT PSCEPR_ERROR_LOG_INFO __RPC_FAR *Errlog OPTIONAL
|
|
)
|
|
/*
|
|
Routine Description:
|
|
|
|
Query local security policy from the system (directly)
|
|
|
|
Only password, account lockout, kerberos, audit, user rights, and
|
|
SCE registry values are queried.
|
|
|
|
multile threads doing get/set system security are not blocked. In
|
|
other words, system security settings are not exclusive.
|
|
*/
|
|
{
|
|
UINT ClientLocalFlag = 0;
|
|
|
|
if ( RPC_S_OK != I_RpcBindingIsClientLocal( NULL, &ClientLocalFlag) ||
|
|
0 == ClientLocalFlag ){
|
|
|
|
//
|
|
// to prevent denial-of-service type attacks,
|
|
// do not allow remote RPC
|
|
//
|
|
|
|
return SCESTATUS_ACCESS_DENIED;
|
|
|
|
}
|
|
|
|
DWORD rc;
|
|
|
|
if ( bStopRequest ) {
|
|
return(SCESTATUS_SERVICE_NOT_SUPPORT);
|
|
}
|
|
|
|
//
|
|
// should we validate the profile handle?
|
|
// it's not used here so it's not validated now.
|
|
//
|
|
|
|
//
|
|
// impersonate the client
|
|
//
|
|
|
|
rc = RpcImpersonateClient( NULL );
|
|
|
|
if (rc != RPC_S_OK) {
|
|
|
|
return( rc );
|
|
}
|
|
|
|
BOOL bAdminSidInToken = FALSE;
|
|
|
|
rc = ScepDosErrorToSceStatus(ScepIsAdminLoggedOn(&bAdminSidInToken, TRUE));
|
|
|
|
if (SCESTATUS_SUCCESS != rc || FALSE == bAdminSidInToken) {
|
|
RpcRevertToSelf();
|
|
return SCESTATUS_SPECIAL_ACCOUNT;
|
|
}
|
|
|
|
__try {
|
|
//
|
|
// catch exception if InfFileName, or pebClient/pdWarning are bogus
|
|
//
|
|
rc = ScepGetSystemSecurity(
|
|
(AREA_INFORMATION)Area,
|
|
Options,
|
|
(PSCE_PROFILE_INFO *)ppInfoBuffer,
|
|
(PSCE_ERROR_LOG_INFO *)Errlog
|
|
);
|
|
|
|
} __except(EXCEPTION_EXECUTE_HANDLER) {
|
|
|
|
rc = SCESTATUS_EXCEPTION_IN_SERVER;
|
|
}
|
|
|
|
RpcRevertToSelf();
|
|
|
|
return(rc);
|
|
}
|
|
|
|
SCEPR_STATUS
|
|
SceRpcSetSystemSecurityFromHandle(
|
|
IN SCEPR_CONTEXT Context, // must be a context point to system db
|
|
IN AREAPR Area,
|
|
IN DWORD Options,
|
|
IN PSCEPR_PROFILE_INFO __RPC_FAR pInfoBuffer,
|
|
OUT PSCEPR_ERROR_LOG_INFO __RPC_FAR *Errlog OPTIONAL
|
|
)
|
|
/*
|
|
Routine Description:
|
|
|
|
Set local security policy to the system (directly)
|
|
|
|
Only password, account lockout, kerberos, audit, user rights, and
|
|
SCE registry values are set.
|
|
|
|
*/
|
|
{
|
|
UINT ClientLocalFlag = 0;
|
|
|
|
if ( RPC_S_OK != I_RpcBindingIsClientLocal( NULL, &ClientLocalFlag) ||
|
|
0 == ClientLocalFlag ){
|
|
|
|
//
|
|
// to prevent denial-of-service type attacks,
|
|
// do not allow remote RPC
|
|
//
|
|
|
|
return SCESTATUS_ACCESS_DENIED;
|
|
|
|
}
|
|
|
|
DWORD rc;
|
|
|
|
if ( bStopRequest ) {
|
|
return(SCESTATUS_SERVICE_NOT_SUPPORT);
|
|
}
|
|
|
|
//
|
|
// should we validate the profile handle?
|
|
// it's not used here so it's not validated now.
|
|
//
|
|
|
|
//
|
|
// impersonate the client
|
|
//
|
|
|
|
rc = RpcImpersonateClient( NULL );
|
|
|
|
if (rc != RPC_S_OK) {
|
|
|
|
return( rc );
|
|
}
|
|
|
|
BOOL bAdminSidInToken = FALSE;
|
|
|
|
rc = ScepDosErrorToSceStatus(ScepIsAdminLoggedOn(&bAdminSidInToken, TRUE));
|
|
|
|
if (SCESTATUS_SUCCESS != rc || FALSE == bAdminSidInToken) {
|
|
RpcRevertToSelf();
|
|
return SCESTATUS_SPECIAL_ACCOUNT;
|
|
}
|
|
|
|
__try {
|
|
//
|
|
// catch exception if InfFileName, or pebClient/pdWarning are bogus
|
|
//
|
|
rc = ScepSetSystemSecurity(
|
|
(AREA_INFORMATION)Area,
|
|
Options,
|
|
(PSCE_PROFILE_INFO)pInfoBuffer,
|
|
(PSCE_ERROR_LOG_INFO *)Errlog
|
|
);
|
|
|
|
} __except(EXCEPTION_EXECUTE_HANDLER) {
|
|
|
|
rc = SCESTATUS_EXCEPTION_IN_SERVER;
|
|
}
|
|
|
|
RpcRevertToSelf();
|
|
|
|
return(rc);
|
|
}
|
|
|
|
|
|
SCEPR_STATUS
|
|
SceRpcSetSystemSecurity(
|
|
IN handle_t binding_h,
|
|
IN AREAPR Area,
|
|
IN DWORD Options,
|
|
IN PSCEPR_PROFILE_INFO __RPC_FAR pInfoBuffer,
|
|
OUT PSCEPR_ERROR_LOG_INFO __RPC_FAR *Errlog OPTIONAL
|
|
)
|
|
/*
|
|
Routine Description:
|
|
|
|
Set local security policy to the system (directly)
|
|
|
|
Only password, account lockout, kerberos, audit, user rights, and
|
|
SCE registry values are set.
|
|
|
|
*/
|
|
{
|
|
UINT ClientLocalFlag = 0;
|
|
|
|
if ( RPC_S_OK != I_RpcBindingIsClientLocal( NULL, &ClientLocalFlag) ||
|
|
0 == ClientLocalFlag ){
|
|
|
|
//
|
|
// to prevent denial-of-service type attacks,
|
|
// do not allow remote RPC
|
|
//
|
|
|
|
return SCESTATUS_ACCESS_DENIED;
|
|
|
|
}
|
|
|
|
DWORD rc;
|
|
|
|
if ( bStopRequest ) {
|
|
return(SCESTATUS_SERVICE_NOT_SUPPORT);
|
|
}
|
|
|
|
//
|
|
// impersonate the client
|
|
//
|
|
|
|
rc = RpcImpersonateClient( NULL );
|
|
|
|
if (rc != RPC_S_OK) {
|
|
|
|
return( rc );
|
|
}
|
|
|
|
BOOL bAdminSidInToken = FALSE;
|
|
|
|
rc = ScepDosErrorToSceStatus(ScepIsAdminLoggedOn(&bAdminSidInToken, TRUE));
|
|
|
|
if (SCESTATUS_SUCCESS != rc || FALSE == bAdminSidInToken) {
|
|
RpcRevertToSelf();
|
|
return SCESTATUS_SPECIAL_ACCOUNT;
|
|
}
|
|
|
|
__try {
|
|
//
|
|
// catch exception if InfFileName, or pebClient/pdWarning are bogus
|
|
//
|
|
rc = ScepSetSystemSecurity(
|
|
(AREA_INFORMATION)Area,
|
|
Options,
|
|
(PSCE_PROFILE_INFO)pInfoBuffer,
|
|
(PSCE_ERROR_LOG_INFO *)Errlog
|
|
);
|
|
|
|
} __except(EXCEPTION_EXECUTE_HANDLER) {
|
|
|
|
rc = SCESTATUS_EXCEPTION_IN_SERVER;
|
|
}
|
|
|
|
RpcRevertToSelf();
|
|
|
|
return(rc);
|
|
}
|
|
|
|
|
|
SCEPR_STATUS
|
|
SceRpcSetDatabaseSetting(
|
|
IN SCEPR_CONTEXT Context,
|
|
IN SCEPR_TYPE ProfileType,
|
|
IN wchar_t *SectionName,
|
|
IN wchar_t *KeyName,
|
|
IN PSCEPR_VALUEINFO pValueInfo OPTIONAL
|
|
)
|
|
/*
|
|
Set or delete value from the given key
|
|
|
|
if pValueInfo is NULL, delete the key
|
|
|
|
*/
|
|
{
|
|
UINT ClientLocalFlag = 0;
|
|
|
|
if ( RPC_S_OK != I_RpcBindingIsClientLocal( NULL, &ClientLocalFlag) ||
|
|
0 == ClientLocalFlag ){
|
|
|
|
//
|
|
// to prevent denial-of-service type attacks,
|
|
// do not allow remote RPC
|
|
//
|
|
|
|
return SCESTATUS_ACCESS_DENIED;
|
|
|
|
}
|
|
|
|
if ( SCEPR_SMP != ProfileType ) {
|
|
return SCESTATUS_INVALID_PARAMETER;
|
|
}
|
|
|
|
SCESTATUS rc;
|
|
|
|
//
|
|
// impersonate the client
|
|
//
|
|
|
|
rc = RpcImpersonateClient( NULL );
|
|
|
|
if (rc != RPC_S_OK) {
|
|
return( ScepDosErrorToSceStatus(rc) );
|
|
}
|
|
|
|
BOOL bAdminSidInToken = FALSE;
|
|
|
|
rc = ScepDosErrorToSceStatus(ScepIsAdminLoggedOn(&bAdminSidInToken, TRUE));
|
|
|
|
if (SCESTATUS_SUCCESS != rc || FALSE == bAdminSidInToken) {
|
|
RpcRevertToSelf();
|
|
return SCESTATUS_SPECIAL_ACCOUNT;
|
|
}
|
|
|
|
//
|
|
// validate the context handle is a SCE context
|
|
// Only one database operation per context
|
|
//
|
|
|
|
PSCESRV_DBTASK pTask=NULL;
|
|
PSCESECTION hSection=NULL;
|
|
|
|
rc = ScepValidateAndLockContext((PSCECONTEXT)Context,
|
|
SCE_TASK_LOCK,
|
|
FALSE,
|
|
&pTask);
|
|
|
|
if (SCESTATUS_SUCCESS == rc ) {
|
|
|
|
//
|
|
// lock the context
|
|
//
|
|
|
|
if ( pTask ) {
|
|
EnterCriticalSection(&(pTask->Sync));
|
|
}
|
|
|
|
__try {
|
|
//
|
|
// catch exception if Context, ppInfoBuffer, Errlog are bogus pointers
|
|
//
|
|
#ifdef SCE_JET_TRAN
|
|
rc = SceJetJetErrorToSceStatus(
|
|
JetSetSessionContext(
|
|
((PSCECONTEXT)Context)->JetSessionID,
|
|
(ULONG_PTR)Context
|
|
));
|
|
|
|
if ( SCESTATUS_SUCCESS == rc ) {
|
|
#endif
|
|
//
|
|
// query the information now
|
|
//
|
|
|
|
rc = ScepOpenSectionForName(
|
|
(PSCECONTEXT)Context,
|
|
(SCETYPE)ProfileType,
|
|
SectionName,
|
|
&hSection
|
|
);
|
|
|
|
if ( SCESTATUS_SUCCESS == rc ) {
|
|
|
|
if ( pValueInfo == NULL || pValueInfo->Value == NULL ) {
|
|
// delete the key
|
|
rc = SceJetDelete(
|
|
hSection,
|
|
KeyName,
|
|
FALSE,
|
|
SCEJET_DELETE_LINE_NO_CASE
|
|
);
|
|
|
|
} else {
|
|
// set the value
|
|
rc = SceJetSetLine(
|
|
hSection,
|
|
KeyName,
|
|
FALSE,
|
|
(PWSTR)pValueInfo->Value,
|
|
pValueInfo->ValueLen,
|
|
0
|
|
);
|
|
}
|
|
|
|
SceJetCloseSection(&hSection, TRUE);
|
|
}
|
|
|
|
#ifdef SCE_JET_TRAN
|
|
JetResetSessionContext(((PSCECONTEXT)Context)->JetSessionID);
|
|
|
|
}
|
|
#endif
|
|
|
|
} __except(EXCEPTION_EXECUTE_HANDLER) {
|
|
|
|
//
|
|
// free ppInfoBuffer if it's allocated
|
|
//
|
|
|
|
if ( hSection )
|
|
SceJetCloseSection(&hSection, TRUE);
|
|
|
|
rc = SCESTATUS_EXCEPTION_IN_SERVER;
|
|
}
|
|
|
|
//
|
|
// unlock the context
|
|
//
|
|
|
|
if ( pTask ) {
|
|
LeaveCriticalSection(&(pTask->Sync));
|
|
}
|
|
|
|
//
|
|
// remove the context from task table
|
|
//
|
|
|
|
ScepRemoveTask(pTask);
|
|
|
|
}
|
|
|
|
RpcRevertToSelf();
|
|
|
|
return((SCEPR_STATUS)rc);
|
|
|
|
}
|
|
|
|
SCEPR_STATUS
|
|
SceRpcGetDatabaseSetting(
|
|
IN SCEPR_CONTEXT Context,
|
|
IN SCEPR_TYPE ProfileType,
|
|
IN wchar_t *SectionName,
|
|
IN wchar_t *KeyName,
|
|
OUT PSCEPR_VALUEINFO *pValueInfo
|
|
)
|
|
/*
|
|
Routine Description:
|
|
|
|
Get information for the particular key from the context database.
|
|
|
|
Arguments:
|
|
|
|
Return Value:
|
|
|
|
*/
|
|
{
|
|
UINT ClientLocalFlag = 0;
|
|
|
|
if ( RPC_S_OK != I_RpcBindingIsClientLocal( NULL, &ClientLocalFlag) ||
|
|
0 == ClientLocalFlag ){
|
|
|
|
//
|
|
// to prevent denial-of-service type attacks,
|
|
// do not allow remote RPC
|
|
//
|
|
|
|
return SCESTATUS_ACCESS_DENIED;
|
|
|
|
}
|
|
|
|
if ( !pValueInfo ) {
|
|
return(SCESTATUS_INVALID_PARAMETER);
|
|
}
|
|
|
|
if ( SCEPR_SMP != ProfileType ) {
|
|
return SCESTATUS_INVALID_PARAMETER;
|
|
}
|
|
|
|
SCESTATUS rc;
|
|
|
|
//
|
|
// impersonate the client
|
|
//
|
|
|
|
rc = RpcImpersonateClient( NULL );
|
|
|
|
if (rc != RPC_S_OK) {
|
|
return( ScepDosErrorToSceStatus(rc) );
|
|
}
|
|
|
|
BOOL bAdminSidInToken = FALSE;
|
|
|
|
rc = ScepDosErrorToSceStatus(ScepIsAdminLoggedOn(&bAdminSidInToken, TRUE));
|
|
|
|
if (SCESTATUS_SUCCESS != rc || FALSE == bAdminSidInToken) {
|
|
RpcRevertToSelf();
|
|
return SCESTATUS_SPECIAL_ACCOUNT;
|
|
}
|
|
|
|
//
|
|
// validate the context handle is a SCE context
|
|
// Only one database operation per context
|
|
//
|
|
|
|
PSCESRV_DBTASK pTask=NULL;
|
|
PSCESECTION hSection=NULL;
|
|
PWSTR Value=NULL;
|
|
|
|
rc = ScepValidateAndLockContext((PSCECONTEXT)Context,
|
|
SCE_TASK_LOCK,
|
|
FALSE,
|
|
&pTask);
|
|
|
|
if (SCESTATUS_SUCCESS == rc ) {
|
|
|
|
//
|
|
// lock the context
|
|
//
|
|
|
|
if ( pTask ) {
|
|
EnterCriticalSection(&(pTask->Sync));
|
|
}
|
|
|
|
__try {
|
|
//
|
|
// catch exception if Context, ppInfoBuffer, Errlog are bogus pointers
|
|
//
|
|
#ifdef SCE_JET_TRAN
|
|
rc = SceJetJetErrorToSceStatus(
|
|
JetSetSessionContext(
|
|
((PSCECONTEXT)Context)->JetSessionID,
|
|
(ULONG_PTR)Context
|
|
));
|
|
|
|
if ( SCESTATUS_SUCCESS == rc ) {
|
|
#endif
|
|
//
|
|
// query the information now
|
|
//
|
|
|
|
rc = ScepOpenSectionForName(
|
|
(PSCECONTEXT)Context,
|
|
(SCETYPE)ProfileType,
|
|
SectionName,
|
|
&hSection
|
|
);
|
|
|
|
if ( SCESTATUS_SUCCESS == rc ) {
|
|
|
|
DWORD ValueLen=0;
|
|
DWORD NewLen=0;
|
|
|
|
rc = SceJetGetValue(
|
|
hSection,
|
|
SCEJET_EXACT_MATCH_NO_CASE,
|
|
KeyName,
|
|
NULL,
|
|
0,
|
|
NULL,
|
|
NULL,
|
|
0,
|
|
&ValueLen
|
|
);
|
|
|
|
// allocate output buffer
|
|
if ( SCESTATUS_SUCCESS == rc ) {
|
|
Value = (PWSTR)ScepAlloc(LPTR, ValueLen+2);
|
|
|
|
if ( !Value )
|
|
rc = SCESTATUS_NOT_ENOUGH_RESOURCE;
|
|
else {
|
|
*pValueInfo = (PSCEPR_VALUEINFO)ScepAlloc(0,sizeof(SCEPR_VALUEINFO));
|
|
|
|
if ( *pValueInfo == NULL ) {
|
|
rc = SCESTATUS_NOT_ENOUGH_RESOURCE;
|
|
}
|
|
}
|
|
}
|
|
|
|
// query the value
|
|
if ( SCESTATUS_SUCCESS == rc ) {
|
|
|
|
rc = SceJetGetValue(
|
|
hSection,
|
|
SCEJET_CURRENT,
|
|
KeyName,
|
|
NULL,
|
|
0,
|
|
NULL,
|
|
Value,
|
|
ValueLen,
|
|
&NewLen
|
|
);
|
|
if ( SCESTATUS_SUCCESS == rc ) {
|
|
(*pValueInfo)->ValueLen = ValueLen+2;
|
|
(*pValueInfo)->Value = (byte *)Value;
|
|
}
|
|
}
|
|
|
|
// free buffer
|
|
if ( SCESTATUS_SUCCESS != rc ) {
|
|
|
|
if ( Value ) ScepFree(Value);
|
|
if ( *pValueInfo ) {
|
|
ScepFree(*pValueInfo);
|
|
*pValueInfo = NULL;
|
|
}
|
|
}
|
|
|
|
SceJetCloseSection(&hSection, TRUE);
|
|
}
|
|
|
|
#ifdef SCE_JET_TRAN
|
|
JetResetSessionContext(((PSCECONTEXT)Context)->JetSessionID);
|
|
|
|
}
|
|
#endif
|
|
|
|
} __except(EXCEPTION_EXECUTE_HANDLER) {
|
|
|
|
//
|
|
// free ppInfoBuffer if it's allocated
|
|
//
|
|
|
|
if ( Value ) ScepFree(Value);
|
|
if ( *pValueInfo ) {
|
|
ScepFree(*pValueInfo);
|
|
*pValueInfo = NULL;
|
|
}
|
|
|
|
if ( hSection )
|
|
SceJetCloseSection(&hSection, TRUE);
|
|
|
|
rc = SCESTATUS_EXCEPTION_IN_SERVER;
|
|
}
|
|
|
|
//
|
|
// unlock the context
|
|
//
|
|
|
|
if ( pTask ) {
|
|
LeaveCriticalSection(&(pTask->Sync));
|
|
}
|
|
|
|
//
|
|
// remove the context from task table
|
|
//
|
|
|
|
ScepRemoveTask(pTask);
|
|
|
|
}
|
|
|
|
RpcRevertToSelf();
|
|
|
|
return((SCEPR_STATUS)rc);
|
|
|
|
}
|
|
|
|
DWORD
|
|
SceRpcConfigureConvertedFileSecurityImmediately(
|
|
IN handle_t binding_h,
|
|
IN wchar_t *pszDriveName
|
|
)
|
|
/*
|
|
Routine Description:
|
|
|
|
RPC interface called by SCE client (only when conversion of security is immediate)
|
|
|
|
Arguments:
|
|
|
|
binding_h - binding handle
|
|
pszDriveName - name of the volume for which setup-style security is to be applied
|
|
|
|
Return:
|
|
|
|
win32 error code
|
|
|
|
*/
|
|
|
|
{
|
|
UINT ClientLocalFlag = 0;
|
|
|
|
if ( RPC_S_OK != I_RpcBindingIsClientLocal( NULL, &ClientLocalFlag) ||
|
|
0 == ClientLocalFlag ){
|
|
|
|
//
|
|
// to prevent denial-of-service type attacks,
|
|
// do not allow remote RPC
|
|
//
|
|
|
|
return SCESTATUS_ACCESS_DENIED;
|
|
|
|
}
|
|
|
|
DWORD rc = ERROR_SUCCESS;
|
|
NTSTATUS Status = NO_ERROR;
|
|
|
|
if ( pszDriveName == NULL ) {
|
|
return ERROR_INVALID_PARAMETER;
|
|
}
|
|
|
|
//
|
|
// impersonate the client
|
|
//
|
|
|
|
rc = RpcImpersonateClient( NULL );
|
|
|
|
if (rc != RPC_S_OK) {
|
|
|
|
return( rc );
|
|
}
|
|
|
|
BOOL bAdminSidInToken = FALSE;
|
|
|
|
rc = ScepDosErrorToSceStatus(ScepIsAdminLoggedOn(&bAdminSidInToken, TRUE));
|
|
|
|
if (SCESTATUS_SUCCESS != rc || FALSE == bAdminSidInToken) {
|
|
RpcRevertToSelf();
|
|
return SCESTATUS_SPECIAL_ACCOUNT;
|
|
}
|
|
|
|
rc = ScepConfigureConvertedFileSecurityImmediate( pszDriveName );
|
|
|
|
RpcRevertToSelf();
|
|
|
|
return(rc);
|
|
}
|
|
|
|
|
|
DWORD
|
|
ScepServerConfigureSystem(
|
|
IN PWSTR InfFileName,
|
|
IN PWSTR DatabaseName,
|
|
IN PWSTR LogFileName,
|
|
IN DWORD ConfigOptions,
|
|
IN AREA_INFORMATION Area
|
|
)
|
|
/*
|
|
Routine Description:
|
|
|
|
Configure the system using the Inf template. This routine is similar to the RPC interface
|
|
SceRpcConfigureSystem except that the configuration is initiated by the server itself.
|
|
|
|
Since this routine is called by the server only (system context) and not by sce client,
|
|
there is no need to do impersonate etc.
|
|
Log file initialization etc. is done outside of this routine
|
|
|
|
Arguments:
|
|
|
|
InfFileName - name of inf file to import configuration information from
|
|
DatabaseName - name of database to import into
|
|
LogFileName - name of log file to log errors
|
|
ConfigOptions - configuration options ()
|
|
Area - security area to configure
|
|
|
|
Return Value:
|
|
|
|
win32 error code
|
|
*/
|
|
{
|
|
DWORD rc = ERROR_SUCCESS;
|
|
|
|
if (InfFileName == NULL || DatabaseName == NULL || LogFileName == NULL)
|
|
return ERROR_INVALID_PARAMETER;
|
|
|
|
//
|
|
// initialize jet engine in system context if not already initialized
|
|
//
|
|
rc = SceJetInitialize(NULL);
|
|
|
|
if ( rc != SCESTATUS_SUCCESS ) {
|
|
return(ScepSceStatusToDosError(rc));
|
|
}
|
|
|
|
//
|
|
// no one else can use convert.sdb - lock access to it
|
|
//
|
|
|
|
rc = ScepLockEngine(DatabaseName);
|
|
|
|
if ( SCESTATUS_ALREADY_RUNNING == rc ) {
|
|
//
|
|
// will wait for max one minute
|
|
//
|
|
DWORD dwWaitCount = 0;
|
|
|
|
while ( TRUE ) {
|
|
|
|
Sleep(5000); // 5 seconds
|
|
|
|
rc = ScepLockEngine(DatabaseName);
|
|
|
|
dwWaitCount++;
|
|
|
|
if ( SCESTATUS_SUCCESS == rc ||
|
|
dwWaitCount >= 12 ) {
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
if ( SCESTATUS_SUCCESS == rc ) {
|
|
|
|
|
|
__try {
|
|
//
|
|
// catch exception if InfFileName, or pebClient/pdWarning are bogus
|
|
//
|
|
rc = ScepConfigureSystem(
|
|
(LPCTSTR)InfFileName,
|
|
DatabaseName,
|
|
ConfigOptions,
|
|
TRUE,
|
|
(AREA_INFORMATION)Area,
|
|
NULL
|
|
);
|
|
|
|
} __except(EXCEPTION_EXECUTE_HANDLER) {
|
|
|
|
rc = SCESTATUS_EXCEPTION_IN_SERVER;
|
|
}
|
|
|
|
ScepUnlockEngine(DatabaseName);
|
|
|
|
}
|
|
//
|
|
// start a timer queue to check to see if there is active tasks/contexts
|
|
// if not, terminate jet engine
|
|
//
|
|
ScepIfTerminateEngine();
|
|
|
|
return(ScepSceStatusToDosError(rc));
|
|
}
|
|
|