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.
3267 lines
82 KiB
3267 lines
82 KiB
/*
|
|
|
|
Copyright (c) 1997 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
ui.c
|
|
|
|
Abstract:
|
|
|
|
This file contains the mainloop for the Client Side Caching agent. The code has to mesh
|
|
with the system startup, logon and logoff and these are different on NT and win9x.
|
|
This file and all others in the reint directory have been written such that for NT they
|
|
call the wide character win32 APIs while for win9x they call ANSI APIs.
|
|
|
|
The agent runs as a thread in the context of winlogon.exe. CSCDLL.DLL resgisters itself
|
|
to recieve a call from winlogon when a user logs on. The call is on a separate thread and
|
|
is impersonated as the logged on user. This thread eventually calls reint_winmain which
|
|
loops for ever, till the system is about to shutdown.
|
|
|
|
file ntstuff.c contains the interface which is exposed to winlogon. On every logon
|
|
this interface gets called, at which point, all the info necessary to impersonate the
|
|
logged on user is obtained and kept in an in memory list of logged on users. The list
|
|
also contains the SID for Local System.
|
|
|
|
For doing sparse filling and Inode, the agent looks in the database to see which of
|
|
the users on the list have read access right for the given file and uses that to fill
|
|
the file.
|
|
|
|
|
|
Author(s):
|
|
|
|
Trent Gray Donald/Felix Andrews/Shishir Pardikar
|
|
|
|
1-9-1994
|
|
|
|
Environment:
|
|
|
|
Win32 (user-mode) DLL
|
|
|
|
Revision History:
|
|
|
|
NT source formatting
|
|
|
|
Shishir Pardikar 2-19-97
|
|
|
|
Winlogon Integration
|
|
|
|
Shishir Pardikar 10-19-97
|
|
|
|
|
|
|
|
--*/
|
|
|
|
#include "pch.h"
|
|
#pragma hdrstop
|
|
|
|
#include "resource.h"
|
|
#include "traynoti.h"
|
|
#include <dbt.h>
|
|
#include "lib3.h"
|
|
#include "reint.h"
|
|
#include "utils.h"
|
|
#include "strings.h"
|
|
#include "cscuiext.h"
|
|
#include <userenv.h>
|
|
#include <safeboot.h>
|
|
|
|
//
|
|
// defines/macros useed in this file
|
|
//
|
|
|
|
|
|
#if (_TCHAR != wchar_t)
|
|
#error "Bad _TCHAR definition"
|
|
#endif
|
|
|
|
#if (_TEXT != L)
|
|
#error "BAD _Text definiton"
|
|
#endif
|
|
|
|
// Timer to deal with double clicks and stuff like that.
|
|
#define TRAY_ID 100
|
|
|
|
// timer ID to make sure the Tray icon appears!
|
|
#define TIMER_ADD_TRAY 101
|
|
|
|
#define minOfFour(one,two,three,four) (min(min(one,two),min(three,four)))
|
|
|
|
#define FILE_OPEN_THRESHOLD 16
|
|
#define CI_LOGON 1
|
|
#define CI_LOGOFF 2
|
|
// #define STWM_CSCCLOSEDIALOGS (WM_USER + 212)
|
|
|
|
typedef HWND (WINAPI *CSCUIINITIALIZE)(HANDLE hToken, DWORD dwFlags);
|
|
typedef LRESULT (WINAPI *CSCUISETSTATE)(UINT uMsg, WPARAM wParam, LPARAM lParam);
|
|
|
|
#define REG_VALUE_NT_BUILD_NUMBER _TEXT("NTBuildNumber")
|
|
#define REG_VALUE_DISABLE_AUTOCHECK _TEXT("DisableAutoCheck")
|
|
#define REG_KEY_NETCACHE_SETTINGS _TEXT("Software\\Microsoft\\Windows\\CurrentVersion\\NetCache")
|
|
|
|
#define AGENT_ALIVE (vfCSCEnabled && !vfStopRecieved)
|
|
#define AGENT_ALIVE_AND_ACTIVE (AGENT_ALIVE && !vfAgentQuiet)
|
|
#define AGENT_ALIVE_AND_HAVE_NET (AGENT_ALIVE && vcntNetDevices)
|
|
#define FIVE_MINUTES (5 * 1000 * 60)
|
|
|
|
|
|
#define MAX_LIST_SIZE 1024
|
|
|
|
#define PI_LITELOAD 0x00000004 // Lite load of the profile (for system use only)
|
|
|
|
//
|
|
// Data declarations/definitions
|
|
//
|
|
|
|
|
|
#pragma data_seg(DATASEG_READONLY)
|
|
|
|
_TCHAR vszKernel32[] = _TEXT("KERNEL32.DLL");
|
|
_TCHAR vszOpenVxDHandle[]=_TEXT("OpenVxDHandle");
|
|
|
|
static const _TCHAR szWkssvcToAgentStartEvent[] = _T("WkssvcToAgentStartEvent");
|
|
static const _TCHAR szWkssvcToAgentStopEvent[] = _T("WkssvcToAgentStopEvent");
|
|
static const _TCHAR szAgentToWkssvcEvent[] = _T("AgentToWkssvcEvent");
|
|
static const _TCHAR szAgentExistsEvent[] = _T("AgentExistsEvent");
|
|
|
|
static const _TCHAR vtzCSCUI[] = _TEXT("cscui.dll");
|
|
static const char vszCSCUIInitialize[] = "CSCUIInitialize";
|
|
static const char vszCSCUISetState[] = "CSCUISetState";
|
|
static const _TCHAR vtzDefaultExclusionList[] = L" *.SLM *.MDB *.LDB *.MDW *.MDE *.PST *.DB?";
|
|
|
|
DWORD vdwManualFileDetectionCount = 0;
|
|
|
|
#pragma data_seg()
|
|
|
|
#pragma data_seg(DATASEG_PERINSTANCE)
|
|
|
|
static _TCHAR vrgchBuff[1024], vrwBuff[4096], vrgchSrcName[350], vrgchDstName[300];
|
|
static HMENU g_MainMenu;
|
|
char vszDBDir[MAX_PATH]={0};
|
|
DWORD vdwDBCapacity = 0, vdwClusterSize = 0;
|
|
DWORD vdwRedirStartTime = 0;
|
|
AssertData;
|
|
AssertError;
|
|
|
|
#pragma data_seg()
|
|
|
|
HWND vhwndMain = NULL; // main window
|
|
|
|
BOOL vfAgentEnabledCSC=FALSE; // this is used to detect whether the remoteboot enabled CSC
|
|
BOOL vfCSCEnabled=FALSE; // csc is enabled
|
|
BOOL vfOKToEnableCSC = FALSE;
|
|
HANDLE vhProfile = NULL;
|
|
#pragma data_seg()
|
|
|
|
BOOL vfFormatDatabase = FALSE; // set at init time
|
|
|
|
#ifdef DEBUG
|
|
ULONG ReintKdPrintVector = REINT_KDP_GOOD_DEFAULT;
|
|
ULONG ReintKdPrintVectorDef = REINT_KDP_GOOD_DEFAULT;
|
|
#endif
|
|
|
|
unsigned ulFreePercent=30; // Amount of % cache freeing to be attempted
|
|
// if the cache is full
|
|
|
|
UINT vcntNetDevices = 0; // count of net devices
|
|
BOOL g_bShowMergeIcon; // menu icon
|
|
BOOL vfAgentRegistered = FALSE;
|
|
BOOL vfClassRegistered = TRUE;
|
|
BOOL vfMerging = FALSE;
|
|
|
|
BOOL vfAgentQuiet = FALSE;
|
|
DWORD vdwAgentThreadId = 0;
|
|
DWORD vdwAgentSessionId = 0xffff;
|
|
GLOBALSTATUS vsGS;
|
|
BOOL allowAttempt; // set if we want to allow AttemptCacheFill now
|
|
|
|
//
|
|
// event handles of named events shared between usermode and kernel mode
|
|
//
|
|
HANDLE heventPerSess = NULL;
|
|
HANDLE heventSharedFill = NULL;
|
|
HANDLE vhMutex = NULL;
|
|
DWORD dwVxDEvent = 0; // handle for VxD event obtained from heventShared
|
|
HANDLE vhShadowDBForEvent = INVALID_HANDLE_VALUE;
|
|
|
|
extern LPCONNECTINFO vlpLogonConnectList;
|
|
extern _TCHAR * vrgchCRLF;
|
|
HWND vhdlgShdLogon=NULL;
|
|
|
|
// net start-stop vars
|
|
HANDLE heventWkssvcToAgentStart = NULL;// event set by Workstation service on redir start
|
|
HANDLE heventWkssvcToAgentStop = NULL; // event set by Workstation service on redir stop
|
|
HANDLE heventAgentToWkssvc = NULL; // event used by agent to respond to wkssvc to tell it that
|
|
// it is OK to stop the redir
|
|
HANDLE heventShutDownAgent = NULL;
|
|
HANDLE heventShutDownThread = NULL;
|
|
HANDLE hCopyChunkThread = NULL;
|
|
DWORD vdwCopyChunkThreadId = 0;
|
|
BOOL vfRedirStarted = -1;
|
|
|
|
BOOL vfStartRecieved = FALSE;
|
|
BOOL vfStopRecieved = FALSE;
|
|
|
|
BOOL fAgentShutDownRequested = FALSE;
|
|
BOOL fAgentShutDown = FALSE;
|
|
|
|
|
|
// CSCUI related
|
|
|
|
HANDLE vhlibCSCUI = NULL;
|
|
CSCUIINITIALIZE vlpfnCSCUIInitialize = NULL;
|
|
CSCUISETSTATE vlpfnCSCUISetState = NULL;
|
|
BOOL vfShowingOfflineDlg = FALSE;
|
|
ULONG uOldDatabaseErrorFlags = 0;
|
|
|
|
|
|
//
|
|
// Function Prototypes
|
|
//
|
|
|
|
|
|
|
|
|
|
LRESULT
|
|
CALLBACK
|
|
ReInt_WndProc(
|
|
HWND hwnd,
|
|
UINT message,
|
|
WPARAM wParam,
|
|
LPARAM lParam
|
|
);
|
|
|
|
DWORD ReInt_AttemptCacheFill(
|
|
LPVOID lpContext
|
|
);
|
|
|
|
BOOL
|
|
ReInt_RefreshTray(
|
|
BOOL bHide
|
|
);
|
|
|
|
BOOL
|
|
ReInt_AnythingToMerge(
|
|
VOID
|
|
);
|
|
|
|
int InitMaint(
|
|
VOID
|
|
); // Initialize the maintenance subsystem
|
|
|
|
BOOL
|
|
CheckCSCDatabaseVersion(
|
|
BOOL *lpfWasDirty
|
|
);
|
|
|
|
BOOL
|
|
UpgradeCSCDatabase(
|
|
LPSTR lpszDir
|
|
);
|
|
|
|
BOOL
|
|
IsNetConnected(
|
|
VOID
|
|
);
|
|
|
|
int
|
|
ExtractSpaceStats(
|
|
IN GLOBALSTATUS *lpsGS,
|
|
OUT unsigned long *lpulMaxSpace,
|
|
OUT unsigned long *lpulCurSpace,
|
|
OUT unsigned long *lpulFreeSpace
|
|
);
|
|
|
|
int
|
|
InitCacheSize(
|
|
VOID
|
|
);
|
|
|
|
int
|
|
SetDefaultSpace(
|
|
LPSTR lpShadowDir
|
|
);
|
|
|
|
BOOL
|
|
NEAR
|
|
PASCAL
|
|
ReInt_InitApp(
|
|
HANDLE hInstance
|
|
);
|
|
|
|
BOOL
|
|
NEAR
|
|
PASCAL
|
|
ReInt_InitInstance(
|
|
HANDLE hInstance,
|
|
HANDLE hPrevInstance,
|
|
int cmdShow);
|
|
|
|
BOOL
|
|
NEAR
|
|
PASCAL
|
|
ReInt_TermInstance(
|
|
VOID
|
|
);
|
|
|
|
int
|
|
DoEventProcessing(
|
|
VOID
|
|
);
|
|
|
|
BOOL
|
|
FindCreateDBDir(
|
|
BOOL *lpfCreated,
|
|
BOOL fCleanup // empty the directory if found
|
|
);
|
|
|
|
BOOL
|
|
CreatePerSessSyncObjects(
|
|
VOID
|
|
);
|
|
|
|
BOOL
|
|
CreateSharedFillSyncObjects(
|
|
VOID
|
|
);
|
|
|
|
BOOL
|
|
EnableCSC(
|
|
VOID
|
|
);
|
|
BOOL
|
|
DisableCSC(
|
|
VOID
|
|
);
|
|
BOOL
|
|
IsCSCOn(
|
|
VOID
|
|
);
|
|
|
|
VOID
|
|
ProcessStartStopAgent(
|
|
VOID
|
|
);
|
|
|
|
BOOL
|
|
FStartAgent(
|
|
VOID
|
|
);
|
|
|
|
int
|
|
StartStopCheck(
|
|
VOID
|
|
);
|
|
|
|
BOOL
|
|
Reint_RegisterAgent(
|
|
VOID
|
|
);
|
|
|
|
VOID
|
|
Reint_UnregisterAgent(
|
|
VOID
|
|
);
|
|
|
|
BOOL
|
|
QueryEnableCSC(
|
|
VOID
|
|
);
|
|
|
|
VOID
|
|
QueryMiscRegistryValues(
|
|
VOID
|
|
);
|
|
|
|
|
|
BOOL
|
|
CreateStartStopEvents(
|
|
VOID
|
|
);
|
|
|
|
VOID
|
|
DestroyStartStopEvents(
|
|
VOID
|
|
);
|
|
|
|
|
|
BOOL
|
|
ProcessNetArrivalMessage(
|
|
VOID
|
|
);
|
|
|
|
BOOL
|
|
ProcessNetDepartureMessage(
|
|
BOOL fInvokeAutoDial
|
|
);
|
|
|
|
BOOL
|
|
WINAPI
|
|
CheckCSC(
|
|
LPSTR,
|
|
BOOL
|
|
);
|
|
|
|
BOOL
|
|
ReportShareNetArrivalDeparture(
|
|
BOOL fOneServer,
|
|
HSHARE hShare,
|
|
BOOL fInvokeAutoDial,
|
|
BOOL fArrival
|
|
);
|
|
|
|
LRESULT
|
|
ReportEventsToSystray(
|
|
DWORD dwMessage,
|
|
WPARAM dwWParam,
|
|
LPARAM dwLParam
|
|
);
|
|
|
|
BOOL
|
|
CheckServerOnline(
|
|
VOID
|
|
);
|
|
|
|
VOID
|
|
SetAgentShutDown(
|
|
VOID
|
|
);
|
|
|
|
|
|
BOOL
|
|
IsAgentShutDownRequested(
|
|
VOID
|
|
);
|
|
|
|
BOOL
|
|
LaunchSystrayForLoggedonUser(
|
|
VOID
|
|
);
|
|
|
|
BOOL
|
|
ImpersonateALoggedOnUser(
|
|
VOID
|
|
);
|
|
|
|
VOID
|
|
ReportCreateDelete(
|
|
HSHADOW hDir,
|
|
HSHADOW hShadow,
|
|
BOOL fCreated
|
|
);
|
|
|
|
BOOL
|
|
GetNameOfServerGoingOfflineEx(
|
|
HANDLE hShadowDB,
|
|
_TCHAR **lplptzServerName,
|
|
DWORD *lpdwSize,
|
|
BOOL *lpfAllocated
|
|
);
|
|
|
|
BOOL
|
|
AreAnyServersOffline(
|
|
VOID);
|
|
|
|
BOOL
|
|
IsPersonal(
|
|
VOID);
|
|
|
|
BOOL
|
|
IsMultipleUsersEnabled(
|
|
void);
|
|
|
|
BOOL
|
|
IsFastUserSwitchingEnabled(
|
|
VOID);
|
|
|
|
BOOL
|
|
AreConnectionsAllowed (
|
|
VOID);
|
|
|
|
BOOL
|
|
CanCSCLivewithTS(
|
|
VOID);
|
|
|
|
BOOL
|
|
IsWorkstation(
|
|
VOID);
|
|
|
|
//
|
|
// Functions
|
|
//
|
|
|
|
int
|
|
PASCAL
|
|
ReInt_WinMain(
|
|
HANDLE hInstance,
|
|
HANDLE hPrevInstance,
|
|
LPSTR lpszCommandLine,
|
|
int cmdShow)
|
|
/*++
|
|
Routine Description:
|
|
This is the mainloop for the agent processing. It "schedules" different agent activities
|
|
based on either an event set by the rdr or by predefined time intervals for these
|
|
activities. The activities include
|
|
|
|
a) Filling partially filled files
|
|
b) checking for stale files
|
|
c) maintaining space within limits
|
|
d) reducing reference priority of all files for every FILE_OPEN_THRESHOLD fileopens
|
|
--*/
|
|
{
|
|
MSG msg;
|
|
DWORD result; // result from Wait...
|
|
BOOL done = FALSE; // to detect a quit message.
|
|
BOOL staleInited = FALSE; // ensure that Staleness code runs
|
|
DWORD timeToWait;
|
|
DWORD nextGlobalStatusTime;
|
|
DWORD newTick;
|
|
DWORD nextSkipPurgeTime; // to figure out if we should perform an action.
|
|
HANDLE hT[4];
|
|
|
|
if (hPrevInstance) {
|
|
return FALSE;
|
|
}
|
|
|
|
|
|
vdwAgentThreadId = GetCurrentThreadId();
|
|
|
|
ReintKdPrint(MAINLOOP, ("Agent(1):----------ReInt_WinMain----------\n"));
|
|
|
|
if (ReInt_InitApp(hInstance) && ReInt_InitInstance(hInstance, hPrevInstance, cmdShow)) {
|
|
if (!AnyActiveNets(NULL))
|
|
vcntNetDevices = 1;
|
|
newTick = GetTickCount();
|
|
nextGlobalStatusTime = newTick + WAIT_INTERVAL_GLOBALSTATUS_MS;
|
|
nextSkipPurgeTime = newTick + WAIT_INTERVAL_SKIP_MS;
|
|
hT[0] = heventPerSess;
|
|
hT[1] = heventWkssvcToAgentStart;
|
|
hT[2] = heventWkssvcToAgentStop;
|
|
hT[3] = heventShutDownAgent;
|
|
StartStopCheck();
|
|
ProcessStartStopAgent();
|
|
while (!done) {
|
|
timeToWait = INFINITE;
|
|
ReintKdPrint(MAINLOOP, ("Agent(1): Wait INFINITE\n"));
|
|
result = WaitForMultipleObjects(4, hT, FALSE, timeToWait);
|
|
newTick=GetTickCount();
|
|
if ((result == WAIT_OBJECT_0) || (result == (WAIT_OBJECT_0+4))) {
|
|
ReintKdPrint(MAINLOOP, ("Agent(1):Event %d was fired or ReadGlobalStatus set\n",
|
|
result));
|
|
DoEventProcessing();
|
|
// During event processing, we also do globalstatus check and
|
|
// any other maintenance tasks. So let us restart the timer for
|
|
// globalstatus
|
|
nextGlobalStatusTime = newTick + WAIT_INTERVAL_GLOBALSTATUS_MS;
|
|
} else if ((result == (WAIT_OBJECT_0+1)) || (result == (WAIT_OBJECT_0+2))) {
|
|
ReintKdPrint(MAINLOOP, ("Agent(1): Received startstop \r\n"));
|
|
vfStartRecieved = (result == (WAIT_OBJECT_0+1));
|
|
vfStopRecieved = (result == (WAIT_OBJECT_0+2));
|
|
ProcessStartStopAgent();
|
|
continue;
|
|
} else if (result == (WAIT_OBJECT_0+3)) {
|
|
ReintKdPrint(MAINLOOP, ("Agent(1):Agent ShutdownRequested, terminating agent\r\n"));
|
|
SetAgentShutDown();
|
|
goto AllDone;
|
|
}
|
|
// do work only if CSC enabled
|
|
if (vfCSCEnabled && AGENT_ALIVE_AND_ACTIVE) {
|
|
// reset the staleness check time interval
|
|
if(((int)(newTick - nextSkipPurgeTime)) >= 0) {
|
|
// Unmark failures for servers that are known to be
|
|
// disconnected and connection has not been attempted on them
|
|
// for the last WAIT_INTERVAL_SKIP_MS milliseconds
|
|
PurgeSkipQueue(FALSE, 0, 0, 0);
|
|
vhcursor = NULL;
|
|
nextSkipPurgeTime = newTick + WAIT_INTERVAL_SKIP_MS;
|
|
ReintKdPrint(MAINLOOP, ("Agent(1):nextSkipPurgeTime = %d\n", nextSkipPurgeTime));
|
|
}
|
|
if(((int)(newTick - nextGlobalStatusTime)) >= 0) {
|
|
nextGlobalStatusTime = newTick + WAIT_INTERVAL_GLOBALSTATUS_MS;
|
|
ReintKdPrint(MAINLOOP,("Agent(1):nextGlobalStatusTime = %d\n", nextGlobalStatusTime));
|
|
// We haven't gotten an event for sometime now from the
|
|
// rdr, so let us go look what is up with him
|
|
DoEventProcessing();
|
|
// reset the globalstatus time interval
|
|
nextGlobalStatusTime = newTick + WAIT_INTERVAL_GLOBALSTATUS_MS;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
AllDone:
|
|
// do termination processing
|
|
ReintKdPrint(MAINLOOP, ("Agent(1):Exiting mainloop \r\n"));
|
|
ReInt_TermInstance();
|
|
return 0;
|
|
}
|
|
|
|
BOOL
|
|
NEAR
|
|
PASCAL
|
|
ReInt_InitApp(
|
|
HANDLE hInstance
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Parameters:
|
|
|
|
Return Value:
|
|
|
|
Notes:
|
|
|
|
--*/
|
|
{
|
|
if (
|
|
CreateSharedFillSyncObjects()
|
|
&&
|
|
CreatePerSessSyncObjects()
|
|
) {
|
|
if (!CreateStartStopEvents()) {
|
|
ReintKdPrint(BADERRORS, ("Agent:Failed to create Sync events \r\n"));
|
|
return FALSE;
|
|
}
|
|
if (!(hCopyChunkThread = CreateThread(
|
|
NULL,
|
|
8192,
|
|
ReInt_AttemptCacheFill,
|
|
NULL,
|
|
0,
|
|
&vdwCopyChunkThreadId))
|
|
) {
|
|
ReintKdPrint(BADERRORS, ("Agent:Failed to create copychunk thread\r\n"));
|
|
return FALSE;
|
|
}
|
|
return TRUE;
|
|
} else {
|
|
ReintKdPrint(BADERRORS, ("Failed to Create shared events\n"));
|
|
return FALSE;
|
|
}
|
|
}
|
|
|
|
BOOL
|
|
NEAR
|
|
PASCAL
|
|
ReInt_InitInstance(
|
|
HANDLE hInstance,
|
|
HANDLE hPrevInstance,
|
|
int cmdShow)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Parameters:
|
|
|
|
Return Value:
|
|
|
|
Notes:
|
|
|
|
--*/
|
|
{
|
|
BOOL fRet;
|
|
|
|
fRet = InitValues(vszDBDir, sizeof(vszDBDir), &vdwDBCapacity, &vdwClusterSize);
|
|
|
|
Assert(fRet);
|
|
|
|
fAgentShutDown = FALSE;
|
|
fAgentShutDownRequested = FALSE;
|
|
|
|
if (!(vfOKToEnableCSC = QueryEnableCSC()))
|
|
{
|
|
ReintKdPrint(INIT, ("cscdll: Registry says disable CSC, not enabling\r\n"));
|
|
}
|
|
|
|
vfFormatDatabase = QueryFormatDatabase();
|
|
|
|
ReintKdPrint(INIT, ("Format=%d\n", vfFormatDatabase));
|
|
|
|
return (TRUE);
|
|
}
|
|
|
|
/*--------------------------------------------------------------------------*/
|
|
BOOL
|
|
NEAR
|
|
PASCAL
|
|
ReInt_TermInstance(
|
|
VOID
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Parameters:
|
|
|
|
Return Value:
|
|
|
|
Notes:
|
|
|
|
--*/
|
|
{
|
|
|
|
DisableCSC();
|
|
|
|
if (heventPerSess) {
|
|
CloseHandle(heventPerSess);
|
|
heventPerSess = NULL;
|
|
}
|
|
|
|
if (heventSharedFill) {
|
|
CloseHandle(heventSharedFill);
|
|
heventSharedFill = NULL;
|
|
}
|
|
|
|
PurgeSkipQueue(TRUE, 0, 0, 0);
|
|
|
|
if (vhMutex) {
|
|
ReleaseMutex(vhMutex);
|
|
vhMutex = NULL;
|
|
}
|
|
|
|
// tell the workstation service that the agent is
|
|
// going away
|
|
if (heventAgentToWkssvc) {
|
|
SetEvent(heventAgentToWkssvc);
|
|
}
|
|
|
|
if (heventShutDownThread) {
|
|
DWORD dwRet;
|
|
|
|
//Assert(hCopyChunkThread);
|
|
SetEvent(heventShutDownThread);
|
|
|
|
//If CopyChunk thread was created then cleanup - bug 562543
|
|
if (hCopyChunkThread) {
|
|
dwRet = WaitForSingleObject(hCopyChunkThread, WAIT_INTERVAL_ATTEMPT_MS);
|
|
ReintKdPrint(MAINLOOP, ("wait on thread handle %d \r\n", dwRet));
|
|
CloseHandle(hCopyChunkThread);
|
|
}
|
|
}
|
|
|
|
DestroyStartStopEvents();
|
|
|
|
if (vfClassRegistered) {
|
|
UnregisterClass(vszReintClass, vhinstCur);
|
|
vfClassRegistered = FALSE;
|
|
|
|
}
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
DWORD
|
|
ReInt_AttemptCacheFill(
|
|
LPVOID lpParams
|
|
)
|
|
/*++
|
|
Routine Description:
|
|
|
|
A wrapper for AttemptCacheFill. On NT many agent threads can do copychunk
|
|
simultaneously, so there is no need to do mutual exclusion.
|
|
--*/
|
|
{
|
|
DWORD nextCheckServerOnlineTime;
|
|
DWORD dwWaitResult;
|
|
DWORD dwWaitResult2;
|
|
DWORD dwWaitTime;
|
|
DWORD newTick;
|
|
ULONG nFiles = 0;
|
|
ULONG nYoungFiles = 0;
|
|
HANDLE hT[2];
|
|
DWORD dwManualFileDetectionCount = 0xffff;
|
|
|
|
// on NT we run as a winlogon thread which has a very high process priority
|
|
// so we have to get to the lowest
|
|
if(!SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_LOWEST)) {
|
|
ReintKdPrint(BADERRORS, ("RE: SetTheadPriority failed, reason: 0x%08x\n", GetLastError()));
|
|
}
|
|
|
|
ReintKdPrint(MAINLOOP, ("Agent(2): Launched.\n"));
|
|
|
|
hT[0] = heventShutDownThread;
|
|
hT[1] = heventSharedFill;
|
|
|
|
nextCheckServerOnlineTime = GetTickCount() +
|
|
WAIT_INTERVAL_CHECK_SERVER_ONLINE_MS +
|
|
WAIT_INTERVAL_FILL_THROTTLE_MS;
|
|
for (;;) {
|
|
ReintKdPrint(MAINLOOP, ("Agent(2): nYoungFiles=%d\n", nYoungFiles));
|
|
if (nYoungFiles > 0 || AreAnyServersOffline() == TRUE) {
|
|
dwWaitTime = WAIT_INTERVAL_CHECK_SERVER_ONLINE_MS;
|
|
ReintKdPrint(MAINLOOP, ("Agent(2): Wait 8 min\n"));
|
|
} else {
|
|
dwWaitTime = INFINITE;
|
|
ReintKdPrint(MAINLOOP, ("Agent(2): Wait INFINITE\n"));
|
|
}
|
|
dwWaitResult = WaitForMultipleObjects(2, hT, FALSE, dwWaitTime);
|
|
if (dwWaitResult == (WAIT_OBJECT_0+0)) { // shutdown event
|
|
ReintKdPrint(MAINLOOP, ("Agent(2): Termination event...\n"));
|
|
if (AGENT_ALIVE && vdwAgentSessionId == 0)
|
|
CSCPurgeUnpinnedFiles(100, &nFiles, &nYoungFiles);
|
|
goto AllDone;
|
|
}
|
|
ReintKdPrint(MAINLOOP, ("Agent(2): Wait 2 min\n"));
|
|
dwWaitResult2 = WaitForSingleObject(heventShutDownThread, WAIT_INTERVAL_FILL_THROTTLE_MS);
|
|
if (dwWaitResult2 == (WAIT_OBJECT_0+0)) { // shutdown event
|
|
ReintKdPrint(MAINLOOP, ("Agent(2): Termination event...\n"));
|
|
if (AGENT_ALIVE && vdwAgentSessionId == 0)
|
|
CSCPurgeUnpinnedFiles(100, &nFiles, &nYoungFiles);
|
|
goto AllDone;
|
|
}
|
|
if (dwWaitResult == WAIT_TIMEOUT) { // timeout
|
|
if (AGENT_ALIVE) {
|
|
ReintKdPrint(MAINLOOP, ("Agent(2): Timeout...\n"));
|
|
AttemptCacheFill(0, DO_ONE_OBJECT, FALSE, CSC_INVALID_PRINCIPAL_ID, NULL, 0);
|
|
if (vdwAgentSessionId == 0) {
|
|
GetManualFileDetectionCounter(INVALID_HANDLE_VALUE,&dwManualFileDetectionCount);
|
|
vdwManualFileDetectionCount = dwManualFileDetectionCount;
|
|
CSCPurgeUnpinnedFiles(100, &nFiles, &nYoungFiles);
|
|
}
|
|
}
|
|
} else if (dwWaitResult == (WAIT_OBJECT_0+1)) { // kernel told us to run
|
|
if (AGENT_ALIVE) {
|
|
ReintKdPrint(MAINLOOP, ("Agent(2): Shared Event signal...\n"));
|
|
AttemptCacheFill(0, DO_ONE_OBJECT, FALSE, CSC_INVALID_PRINCIPAL_ID, NULL, 0);
|
|
GetManualFileDetectionCounter(INVALID_HANDLE_VALUE,&dwManualFileDetectionCount);
|
|
if (dwManualFileDetectionCount != vdwManualFileDetectionCount) {
|
|
vdwManualFileDetectionCount = dwManualFileDetectionCount;
|
|
CSCPurgeUnpinnedFiles(100, &nFiles, &nYoungFiles);
|
|
}
|
|
}
|
|
}
|
|
newTick = GetTickCount();
|
|
if(((int)(newTick - nextCheckServerOnlineTime)) >= 0) {
|
|
if (AGENT_ALIVE) {
|
|
// check whether one or more shares that are presently in
|
|
// disconnected state have come online.
|
|
// If they are, report them to the UI
|
|
CheckServerOnline();
|
|
nextCheckServerOnlineTime = newTick +
|
|
WAIT_INTERVAL_CHECK_SERVER_ONLINE_MS +
|
|
WAIT_INTERVAL_FILL_THROTTLE_MS;
|
|
}
|
|
}
|
|
}
|
|
AllDone:
|
|
ReintKdPrint(MAINLOOP, ("Agent(2):Thread exit\n"));
|
|
return 0;
|
|
}
|
|
|
|
VOID
|
|
ReInt_DoFreeShadowSpace(
|
|
GLOBALSTATUS *lpsGS,
|
|
int fForce
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
The function is called from the main
|
|
loop every "n" minutes to see if we are running out of space.
|
|
If so, it tries to free up some percentage of the shadow cache.
|
|
|
|
Parameters:
|
|
fForce: 0 => do it only if we don't have space and we are
|
|
on the net
|
|
1 => do it if we are on the net
|
|
|
|
2 => just do it
|
|
|
|
|
|
Return Value:
|
|
|
|
Notes:
|
|
|
|
--*/
|
|
{
|
|
ULONG ulMax;
|
|
ULONG ulCur;
|
|
ULONG ulFree;
|
|
WIN32_FIND_DATA sFind32;
|
|
LPCOPYPARAMS lpCP = NULL;
|
|
|
|
if (!lpsGS) {
|
|
lpsGS = &vsGS;
|
|
}
|
|
|
|
ReintKdPrint(MERGE, ("ReInt_DoFreeShadowSpace(1)\r\n"));
|
|
|
|
// Get space stats
|
|
if (ExtractSpaceStats(lpsGS, &ulMax, &ulCur, &ulFree) >= 0){
|
|
ReintKdPrint(MERGE, ("ReInt_DoFreeShadowSpace(2)\r\n"));
|
|
// do we have space and are not forced to free up?
|
|
if ((fForce < 1) && (ulFree > 0)){
|
|
ReintKdPrint(MERGE, ("ReInt_DoFreeShadowSpace(3)\r\n"));
|
|
return;
|
|
}
|
|
//
|
|
// We are forced or there is no space
|
|
//
|
|
// NB!!!! We check for a net device and if it exists we assume that
|
|
// it is OK to freespace on all shares.
|
|
if ((fForce < 2) && !vcntNetDevices){
|
|
ReintKdPrint(MERGE, ("ReInt_DoFreeShadowSpace: No net, aborting \r\n"));
|
|
return;
|
|
}
|
|
|
|
// Maximum force, or all conditions for freeing are being met
|
|
// ie. there is no space and we are on the net
|
|
memset(&sFind32, 0, sizeof(sFind32));
|
|
|
|
// NB the math below is done to avoid overflow.
|
|
// The consequence is that the resulting value is less than
|
|
// the percentage of cache space to be freed.
|
|
ulFree = (ulMax/100) * ulFreePercent;
|
|
|
|
// if the cached data is more than the earmarked space
|
|
// then add the extra too.
|
|
if (ulCur > ulMax) {
|
|
ulFree += (ulCur - ulMax);
|
|
}
|
|
DosToWin32FileSize(ulFree, &sFind32.nFileSizeHigh, &sFind32.nFileSizeLow);
|
|
ReintKdPrint(MERGE, ("ReInt_DoFreeShadowSpace(): freeing %d\n", ulFree));
|
|
ReintKdPrint(MERGE, (" nFileSizeLow=%d\n", sFind32.nFileSizeLow));
|
|
FreeShadowSpace(INVALID_HANDLE_VALUE,
|
|
sFind32.nFileSizeHigh,
|
|
sFind32.nFileSizeLow,
|
|
FALSE); // don't clear all
|
|
ReintKdPrint(MERGE, ("ReInt_DoFreeShadowSpace(): ending.\n"));
|
|
}
|
|
}
|
|
|
|
/*********************** Merging related routines **************************/
|
|
|
|
//
|
|
// DoubleClick/Menu handler.
|
|
//
|
|
VOID
|
|
ReInt_DoNetProp(
|
|
VOID
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Parameters:
|
|
|
|
Return Value:
|
|
|
|
Notes:
|
|
|
|
--*/
|
|
{
|
|
HINSTANCE hLib=LoadLibrary(_TEXT("shhndl.dll"));
|
|
ReintKdPrint(BADERRORS, ("LoadLibrary of shhndl returned %d\n",hLib));
|
|
if(hLib)
|
|
{
|
|
FARPROC lpFn=GetProcAddress(hLib,"NetProp_Create");
|
|
ReintKdPrint(BADERRORS, ("NetProp_Create is 0x%x\n",lpFn));
|
|
if(lpFn)
|
|
lpFn();
|
|
FreeLibrary(hLib);
|
|
}
|
|
|
|
}
|
|
|
|
//
|
|
// Command Handler
|
|
//
|
|
BOOL
|
|
NEAR
|
|
PASCAL
|
|
ReInt_CommandHandler(
|
|
HWND hwnd,
|
|
WPARAM wParam,
|
|
LPARAM lParam
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Parameters:
|
|
|
|
Return Value:
|
|
|
|
Notes:
|
|
|
|
--*/
|
|
{
|
|
unsigned long ulSwitch, ulSav;
|
|
switch (wParam)
|
|
{
|
|
case IDM_PROPERTIES:
|
|
ReInt_DoNetProp();
|
|
break;
|
|
|
|
case IDM_SHADOW_LOG:
|
|
{
|
|
if(ShadowSwitches(INVALID_HANDLE_VALUE, &ulSwitch, SHADOW_SWITCH_GET_STATE))
|
|
{
|
|
ulSav = (ulSwitch & SHADOW_SWITCH_LOGGING);
|
|
ulSwitch = SHADOW_SWITCH_LOGGING;
|
|
if (ShadowSwitches(INVALID_HANDLE_VALUE, &ulSwitch, (ulSav)?SHADOW_SWITCH_OFF:SHADOW_SWITCH_ON))
|
|
CheckMenuItem(GetMenu(hwnd), IDM_SHADOW_LOG , MF_BYCOMMAND|((ulSav)?MF_UNCHECKED:MF_CHECKED));
|
|
}
|
|
}
|
|
break;
|
|
|
|
case IDM_LOG_COPYING:
|
|
{
|
|
#ifdef TEST
|
|
HKEY hKey=0;
|
|
_TCHAR szDoCopy[MAX_NAME_LEN];
|
|
|
|
|
|
|
|
vfLogCopying = vfLogCopying?0:1;
|
|
CheckMenuItem(GetMenu(hwnd), IDM_LOG_COPYING , MF_BYCOMMAND|((vfLogCopying)?MF_UNCHECKED:MF_CHECKED));
|
|
|
|
if(RegOpenKey(HKEY_LOCAL_MACHINE, REG_KEY_CSC_SETTINGS, &hKey) != ERROR_SUCCESS)
|
|
{
|
|
ReintKdPrint(BADERRORS, ("IDM_LOG_COPYING: RegOpenKey failed\n"));
|
|
goto done;
|
|
}
|
|
|
|
if(vfLogCopying)
|
|
strcpy(szDoCopy, SZ_TRUE);
|
|
else
|
|
strcpy(szDoCopy, SZ_FALSE);
|
|
|
|
if(RegSetValueEx(hKey, vszDoLogCopy, (DWORD) 0, REG_SZ, szDoCopy, strlen(szDoCopy)+1) != ERROR_SUCCESS)
|
|
{
|
|
ReintKdPrint(BADERRORS, ("IDM_LOG_COPYING: RegSetValueEx failed\n"));
|
|
}
|
|
done:
|
|
if(hKey)
|
|
RegCloseKey(hKey);
|
|
#endif //TEST
|
|
}
|
|
break;
|
|
|
|
case IDM_SHADOWING:
|
|
break;
|
|
|
|
case IDM_SPEED_OPT:
|
|
break;
|
|
|
|
case IDM_TRAY_FILL_SHADOW:
|
|
break;
|
|
|
|
|
|
case IDM_TRAY_MERGE:
|
|
break;
|
|
|
|
case IDM_TRAY_FREE_SPACE:
|
|
break;
|
|
|
|
case IDM_TRAY_FORCE_LOG:
|
|
break;
|
|
|
|
case IDM_REFRESH_CONNECTIONS:
|
|
break;
|
|
|
|
case IDM_BREAK_CONNECTIONS:
|
|
break;
|
|
|
|
case IDM_LOGON:
|
|
if (lParam)
|
|
{
|
|
vfStartRecieved = TRUE;
|
|
// logon is done, try enabling CSC
|
|
// if CSC is already enabled, the routine will do the right thing
|
|
//
|
|
EnableCSC();
|
|
|
|
}
|
|
break;
|
|
case IDM_LOGOFF:
|
|
// no need to trap this, we get WM_QUERYENDSESSION and WM_ENDSESSION
|
|
break;
|
|
|
|
default:
|
|
return FALSE;
|
|
}
|
|
return TRUE;
|
|
}
|
|
|
|
LRESULT
|
|
CALLBACK
|
|
ReInt_WndProc(
|
|
HWND hwnd,
|
|
UINT message,
|
|
WPARAM wParam,
|
|
LPARAM lParam
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Parameters:
|
|
|
|
Return Value:
|
|
|
|
Notes:
|
|
|
|
--*/
|
|
{
|
|
LPARAM lRet = 0L;
|
|
|
|
switch (message)
|
|
{
|
|
case RWM_UPDATE:
|
|
ReintKdPrint(BADERRORS, ("Update hShare:%0x hWnd=%0x\n",wParam, lParam));
|
|
PurgeSkipQueue(TRUE, (HSHARE)wParam, 0, 0);
|
|
// return ReintOneShare((HSHARE)wParam,(HWND)lParam);
|
|
break;
|
|
|
|
case RWM_UPDATEALL:
|
|
break;
|
|
|
|
case WM_TIMER:
|
|
break;
|
|
|
|
case TRAY_NOTIFY:
|
|
break;
|
|
|
|
case WM_DEVICECHANGE:
|
|
{
|
|
switch (wParam)
|
|
{
|
|
case DBT_DEVICEARRIVAL:
|
|
if (((DEV_BROADCAST_NET *)lParam)->dbcn_devicetype == DBT_DEVTYP_NET)
|
|
{
|
|
// ProcessNetArrivalMessage();
|
|
|
|
}
|
|
break;
|
|
case DBT_DEVICEREMOVECOMPLETE:
|
|
if (((DEV_BROADCAST_NET *)lParam)->dbcn_devicetype == DBT_DEVTYP_NET)
|
|
{
|
|
// ProcessNetDepartureMessage(FALSE);
|
|
|
|
}
|
|
break;
|
|
}
|
|
break;
|
|
}
|
|
|
|
case WM_INITMENU:
|
|
return TRUE;
|
|
break;
|
|
|
|
case WM_INITMENUPOPUP:
|
|
break;
|
|
|
|
case WM_COMMAND:
|
|
if(lRet = ReInt_CommandHandler(hwnd, wParam, lParam))
|
|
return lRet;
|
|
break;
|
|
|
|
case WM_CLOSE:
|
|
ReintKdPrint(BADERRORS, ("WM_CLOSE hit.\n"));
|
|
break;
|
|
|
|
case WM_DESTROY:
|
|
ReintKdPrint(BADERRORS, ("WM_DESTROY hit.\n"));
|
|
PostQuitMessage((int)wParam);
|
|
return 1L;
|
|
|
|
case WM_SETCURSOR:
|
|
break;
|
|
case WM_QUERYENDSESSION:
|
|
return TRUE;
|
|
case WM_ENDSESSION:
|
|
ReintKdPrint(BADERRORS, ("Turning off shadowing on WM_ENDSESSION\r\n"));
|
|
DisableCSC();
|
|
break;
|
|
case WM_FILE_OPENS:
|
|
break;
|
|
|
|
case WM_SHADOW_ADDED:
|
|
case WM_SHADOW_DELETED:
|
|
ReintKdPrint(BADERRORS, ("allowAttempt = TRUE\n"));
|
|
allowAttempt = TRUE;
|
|
break;
|
|
|
|
case WM_SHARE_DISCONNECTED:
|
|
ReintKdPrint(BADERRORS, ("REINT: VxD notification(0x%08x)\n",message));
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
|
|
return DefWindowProc(hwnd, message, wParam, lParam);
|
|
}
|
|
|
|
BOOL ReInt_AnythingToMerge(
|
|
VOID
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Parameters:
|
|
|
|
Return Value:
|
|
|
|
Notes:
|
|
|
|
--*/
|
|
{
|
|
return (CheckDirtyShares() != 0);
|
|
}
|
|
|
|
//
|
|
//
|
|
BOOL
|
|
ReInt_RefreshTray(
|
|
BOOL bHide
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
Called to update the tray ICON to reflect the merge status.
|
|
|
|
Parameters:
|
|
|
|
bHide = TRUE means hide it
|
|
= FALSE means work it out.
|
|
|
|
Return Value:
|
|
|
|
Notes:
|
|
|
|
--*/
|
|
{
|
|
return TRUE;
|
|
}
|
|
|
|
// See if shadfowing is ON
|
|
// Returns: TRUE=> ON, FALSE=> OFF, -1 => soem error happened
|
|
BOOL
|
|
IsCSCOn(
|
|
VOID
|
|
)
|
|
{
|
|
|
|
if (vfCSCEnabled)
|
|
{
|
|
#ifdef DEBUG
|
|
unsigned ulSwitch = SHADOW_SWITCH_SHADOWING;
|
|
if(ShadowSwitches(INVALID_HANDLE_VALUE, &ulSwitch, SHADOW_SWITCH_GET_STATE))
|
|
{
|
|
Assert((ulSwitch & SHADOW_SWITCH_SHADOWING)!=0);
|
|
}
|
|
#endif
|
|
return (TRUE);
|
|
}
|
|
return (FALSE);
|
|
}
|
|
|
|
// Disable Shadowing
|
|
// Returns: 1 => done, -1 => some error happened
|
|
int
|
|
DisableCSC()
|
|
{
|
|
unsigned ulSwitch = SHADOW_SWITCH_SHADOWING;
|
|
|
|
if (vfCSCEnabled && vfAgentEnabledCSC) {
|
|
|
|
if(ShadowSwitches(INVALID_HANDLE_VALUE, &ulSwitch, SHADOW_SWITCH_OFF))
|
|
{
|
|
vfCSCEnabled = FALSE;
|
|
if (vhShadowDBForEvent != INVALID_HANDLE_VALUE)
|
|
{
|
|
CloseHandle(vhShadowDBForEvent);
|
|
vhShadowDBForEvent = INVALID_HANDLE_VALUE;
|
|
}
|
|
|
|
Reint_UnregisterAgent();
|
|
// SetDisabledReg();
|
|
return (1);
|
|
}
|
|
}
|
|
return (-1);
|
|
}
|
|
|
|
BOOL
|
|
EnableCSC(
|
|
VOID
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Parameters:
|
|
|
|
Return Value:
|
|
|
|
Notes:
|
|
|
|
|
|
--*/
|
|
{
|
|
char szBuff[MAX_PATH];
|
|
DWORD dwBuffSize;
|
|
BOOL fDirCreated=FALSE, fRedirCSCEnabled=TRUE, fWasDirty = FALSE;
|
|
unsigned uShadowSwitches;
|
|
|
|
ReintKdPrint(INIT, ("CSC Enabled %d \r\n", vfCSCEnabled));
|
|
if (vfCSCEnabled==FALSE)
|
|
{
|
|
|
|
dwBuffSize = sizeof(szBuff);
|
|
if(!GetUserNameA(szBuff, &dwBuffSize))
|
|
{
|
|
// not logged on yet
|
|
return FALSE;
|
|
}
|
|
|
|
if(ShadowSwitches(INVALID_HANDLE_VALUE, &uShadowSwitches, SHADOW_SWITCH_GET_STATE))
|
|
{
|
|
if (uShadowSwitches & SHADOW_SWITCH_SHADOWING)
|
|
{
|
|
ReintKdPrint(INIT, ("cscdll: CSC already started\r\n"));
|
|
}
|
|
else
|
|
{
|
|
ReintKdPrint(INIT, ("cscdll: redir is not doing CSC yet, OK\r\n"));
|
|
fRedirCSCEnabled = FALSE;
|
|
|
|
if (!vfOKToEnableCSC)
|
|
{
|
|
return FALSE;
|
|
}
|
|
|
|
vfAgentEnabledCSC = TRUE;
|
|
|
|
}
|
|
}
|
|
else
|
|
{
|
|
ReintKdPrint(BADERRORS, ("cscdll: couldn't get the CSC state from the redir\r\n"));
|
|
}
|
|
|
|
if (Reint_RegisterAgent())
|
|
{
|
|
|
|
SetFileAttributesA(vszDBDir, FILE_ATTRIBUTE_SYSTEM|FILE_ATTRIBUTE_HIDDEN);
|
|
|
|
ReintKdPrint(INIT,
|
|
("cscdll: enabling CSC at %s for %s with capacity %d and clustersize %d\r\n",
|
|
vszDBDir, szBuff, vdwDBCapacity, vdwClusterSize));
|
|
if (EnableShadowing(
|
|
INVALID_HANDLE_VALUE,
|
|
vszDBDir,
|
|
szBuff,
|
|
0,
|
|
vdwDBCapacity,
|
|
vdwClusterSize,
|
|
vfFormatDatabase))
|
|
{
|
|
vfCSCEnabled = TRUE;
|
|
if (vhShadowDBForEvent == INVALID_HANDLE_VALUE)
|
|
{
|
|
vhShadowDBForEvent = OpenShadowDatabaseIO();
|
|
}
|
|
}
|
|
else
|
|
{
|
|
ReintKdPrint(BADERRORS, ("cscdll: EnableShadowing failed, CSC not enabled!!!!\r\n"));
|
|
}
|
|
|
|
if (vfCSCEnabled==FALSE)
|
|
{
|
|
Reint_UnregisterAgent();
|
|
}
|
|
}
|
|
else
|
|
{
|
|
ReintKdPrint(BADERRORS, ("cscdll: EnableCSC.Agent registration failed, CSC not enabled!!!!\r\n"));
|
|
}
|
|
}
|
|
if (!vfCSCEnabled)
|
|
{
|
|
// NTRAID-455253-1/31/2000-shishirp need to add it to the event log with the right error
|
|
ReintKdPrint(BADERRORS, ("cscdll: CSC not enabled \r\n"));
|
|
}
|
|
|
|
return (vfCSCEnabled);
|
|
}
|
|
|
|
BOOL
|
|
IsNetConnected(
|
|
VOID
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
The function checks to see whether at this moment
|
|
we are connected to any resources on the real net.
|
|
|
|
Parameters:
|
|
|
|
Return Value:
|
|
|
|
Notes:
|
|
This is used to decide whether to start purging stuff from the
|
|
cache. If we are in a completely disconnected state then we
|
|
may not want to purge data that is potentially useful.
|
|
|
|
--*/
|
|
{
|
|
CSC_ENUMCOOKIE ulEnumCookie=NULL;
|
|
WIN32_FIND_DATA sFind32;
|
|
BOOL fConnected = FALSE;
|
|
SHADOWINFO sSI;
|
|
HANDLE hShadowDB;
|
|
|
|
memset(&sFind32, 0, sizeof(sFind32));
|
|
lstrcpy(sFind32.cFileName, _TEXT("*.*"));
|
|
|
|
if ((hShadowDB = OpenShadowDatabaseIO()) == INVALID_HANDLE_VALUE)
|
|
{
|
|
return FALSE;
|
|
}
|
|
|
|
if(FindOpenShadow(hShadowDB, 0, FINDOPEN_SHADOWINFO_ALL, &sFind32, &sSI))
|
|
{
|
|
ulEnumCookie = sSI.uEnumCookie;
|
|
|
|
do
|
|
{
|
|
if (sSI.uStatus & SHARE_CONNECTED) {
|
|
if (!(sSI.uStatus & SHARE_DISCONNECTED_OP)) {
|
|
fConnected = TRUE;
|
|
break;
|
|
}
|
|
}
|
|
} while(FindNextShadow(hShadowDB, ulEnumCookie, &sFind32, &sSI));
|
|
|
|
FindCloseShadow(hShadowDB, ulEnumCookie);
|
|
}
|
|
|
|
CloseShadowDatabaseIO(hShadowDB);
|
|
|
|
return fConnected;
|
|
}
|
|
|
|
|
|
int
|
|
ExtractSpaceStats(
|
|
GLOBALSTATUS *lpsGS,
|
|
unsigned long *lpulMaxSpace,
|
|
unsigned long *lpulCurSpace,
|
|
unsigned long *lpulFreeSpace
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
The function returns the max, current and free
|
|
space as known by the shadow cache.
|
|
|
|
Parameters:
|
|
|
|
Return Value:
|
|
1 if there is any free space
|
|
0 if there is no free space
|
|
-1 if there is some error
|
|
|
|
Notes:
|
|
|
|
--*/
|
|
{
|
|
int iRet = 1;
|
|
|
|
if (!lpsGS)
|
|
{
|
|
lpsGS = &vsGS;
|
|
}
|
|
|
|
if (lpulMaxSpace){
|
|
*lpulMaxSpace = lpsGS->sST.sMax.ulSize;
|
|
}
|
|
|
|
if (lpulCurSpace){
|
|
*lpulCurSpace = lpsGS->sST.sCur.ulSize;
|
|
}
|
|
|
|
if (lpulFreeSpace){
|
|
*lpulFreeSpace = 0;
|
|
}
|
|
|
|
// do we have any space?
|
|
if (lpsGS->sST.sMax.ulSize > lpsGS->sST.sCur.ulSize){
|
|
if (lpulFreeSpace){
|
|
*lpulFreeSpace = (lpsGS->sST.sMax.ulSize - lpsGS->sST.sCur.ulSize);
|
|
}
|
|
iRet = 1;
|
|
}
|
|
else{
|
|
iRet = 0;
|
|
}
|
|
|
|
return iRet;
|
|
}
|
|
|
|
|
|
int
|
|
InitCacheSize(
|
|
VOID
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
The function returns the max, current and free
|
|
space as known by the shadow cache.
|
|
|
|
Parameters:
|
|
|
|
Return Value:
|
|
1 if there is any free space
|
|
0 if there is no free space
|
|
-1 if there is some error
|
|
|
|
Notes:
|
|
|
|
--*/
|
|
{
|
|
unsigned ulMaxStore;
|
|
int iRet = 0;
|
|
|
|
if(!GetGlobalStatus(INVALID_HANDLE_VALUE, &vsGS))
|
|
{
|
|
return -1;
|
|
}
|
|
|
|
if (ExtractSpaceStats(&vsGS, &ulMaxStore, NULL, NULL)>=0){
|
|
|
|
if (ulMaxStore==0xffffffff){
|
|
|
|
ReintKdPrint(BADERRORS, ("Agent: Found newly created cache, setting cache size \r\n"));
|
|
|
|
Assert(vszDBDir[0]);
|
|
|
|
iRet = SetDefaultSpace(vszDBDir);
|
|
}
|
|
}
|
|
return iRet;
|
|
}
|
|
|
|
int
|
|
SetDefaultSpace(
|
|
LPSTR lpShadowDir
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Parameters:
|
|
|
|
Return Value:
|
|
|
|
Notes:
|
|
|
|
--*/
|
|
{
|
|
DWORD dwSPC, dwBPS, dwFreeC, dwTotalC, dwCapacity;
|
|
_TCHAR szDrive[4];
|
|
int iRet = 0;
|
|
|
|
Assert(lpShadowDir[1]==':');
|
|
memset(szDrive, 0, sizeof(szDrive));
|
|
memcpy(szDrive, lpShadowDir, 3);
|
|
if(GetDiskFreeSpace(szDrive, &dwSPC, &dwBPS, &dwFreeC, &dwTotalC )){
|
|
dwCapacity = ((dwSPC * dwBPS * 10)/100)*dwTotalC;
|
|
SetMaxShadowSpace(INVALID_HANDLE_VALUE, 0, dwCapacity);
|
|
iRet = 1;
|
|
}
|
|
return (iRet);
|
|
}
|
|
|
|
int
|
|
DoEventProcessing(
|
|
VOID
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
When the named event is triggered by the kernel mode component, this routine
|
|
looks to see what needs to be taken care of and does the job.
|
|
|
|
Parameters:
|
|
|
|
Return Value:
|
|
|
|
Notes:
|
|
|
|
This routine is called from various places in the mailoop and other loops such as
|
|
AttemptCacheFill. It may end up showing up dialog boxes and such, so care has to be taken
|
|
while invoking it.
|
|
|
|
--*/
|
|
{
|
|
int iRet;
|
|
GLOBALSTATUS sGS;
|
|
|
|
ReintKdPrint(
|
|
INIT,
|
|
("CSC Agent: CSC Enabled=%d vhShadowDBForEvent \n",
|
|
vfCSCEnabled,
|
|
vhShadowDBForEvent));
|
|
|
|
ReintKdPrint(MAINLOOP, ("Agent(1):DoEventProcessing()\n"));
|
|
|
|
if (iRet = GetGlobalStatus(vhShadowDBForEvent, &sGS)) {
|
|
ReintKdPrint(MAINLOOP, (
|
|
"Agent(1):uFlagsEvents:0x%x\n"
|
|
" uDatabaseErrorFlags:0x%x\n"
|
|
" hShadowAdded:0x%x\n"
|
|
" hDirAdded:0x%x\n"
|
|
" hShadowDeleted:0x%x\n"
|
|
" hDirDeleted:0x%x\n"
|
|
" cntFileOpen:%d\n"
|
|
" hShareDisconnected:0x%x\n",
|
|
sGS.uFlagsEvents,
|
|
sGS.uDatabaseErrorFlags,
|
|
sGS.hShadowAdded,
|
|
sGS.hDirAdded,
|
|
sGS.hShadowDeleted,
|
|
sGS.hDirDeleted,
|
|
sGS.cntFileOpen,
|
|
sGS.hShareDisconnected,
|
|
sGS.uFlagsEvents));
|
|
if (sGS.uFlagsEvents & FLAG_GLOBALSTATUS_START)
|
|
ReintKdPrint(MAINLOOP, ("Agent(1):FLAG_GLOBALSTATUS_START received\r\n"));
|
|
if (sGS.uFlagsEvents & FLAG_GLOBALSTATUS_STOP)
|
|
ReintKdPrint(MAINLOOP, ("Agent(1):FLAG_GLOBALSTATUS_STOP received\r\n"));
|
|
if (sGS.uFlagsEvents & FLAG_GLOBALSTATUS_NO_NET)
|
|
ReintKdPrint(MAINLOOP, ("Agent(1):FLAG_GLOBALSTATUS_NO_NET received\r\n"));
|
|
if (sGS.uFlagsEvents & FLAG_GLOBALSTATUS_GOT_NET)
|
|
ReintKdPrint(MAINLOOP, ("Agent(1):FLAG_GLOBALSTATUS_GOT_NET received\r\n"));
|
|
if (sGS.uFlagsEvents & FLAG_GLOBALSTATUS_INVOKE_FREESPACE)
|
|
ReintKdPrint(MAINLOOP, ("Agent(1):FLAG_GLOBALSTATUS_INVOKE_FREESPACE received\r\n"));
|
|
if (sGS.uFlagsEvents & FLAG_GLOBALSTATUS_SHARE_DISCONNECTED)
|
|
ReintKdPrint(
|
|
MAINLOOP,
|
|
("Agent(1):FLAG_GLOBALSTATUS_SHARE_DISCONNECTED (share=%d) received\r\n",
|
|
sGS.hShareDisconnected));
|
|
if (sGS.uFlagsEvents & FLAG_GLOBALSTATUS_START) {
|
|
vfCSCEnabled = TRUE;
|
|
if (vhShadowDBForEvent == INVALID_HANDLE_VALUE) {
|
|
vhShadowDBForEvent = OpenShadowDatabaseIO();
|
|
}
|
|
Reint_RegisterAgent();
|
|
} else if (sGS.uFlagsEvents & FLAG_GLOBALSTATUS_STOP) {
|
|
vfCSCEnabled = FALSE;
|
|
if (vhShadowDBForEvent != INVALID_HANDLE_VALUE) {
|
|
CloseHandle(vhShadowDBForEvent);
|
|
vhShadowDBForEvent = INVALID_HANDLE_VALUE;
|
|
}
|
|
Reint_UnregisterAgent();
|
|
}
|
|
if (AGENT_ALIVE) {
|
|
if (sGS.uFlagsEvents & FLAG_GLOBALSTATUS_GOT_NET) {
|
|
ProcessNetArrivalMessage();
|
|
} else if (sGS.uFlagsEvents & FLAG_GLOBALSTATUS_NO_NET) {
|
|
ProcessNetDepartureMessage(
|
|
((sGS.uFlagsEvents & FLAG_GLOBALSTATUS_INVOKE_AUTODIAL)!=0));
|
|
}
|
|
if (sGS.uFlagsEvents & FLAG_GLOBALSTATUS_SHARE_DISCONNECTED) {
|
|
ReportShareNetArrivalDeparture(
|
|
1,
|
|
sGS.hShareDisconnected,
|
|
((sGS.uFlagsEvents & FLAG_GLOBALSTATUS_INVOKE_AUTODIAL)!=0),
|
|
FALSE); // departed
|
|
}
|
|
if (uOldDatabaseErrorFlags != sGS.uDatabaseErrorFlags) {
|
|
ReportEventsToSystray(STWM_CACHE_CORRUPTED, 0, 0);
|
|
uOldDatabaseErrorFlags = sGS.uDatabaseErrorFlags;
|
|
}
|
|
// see if space needs freeing
|
|
if (sGS.uFlagsEvents & FLAG_GLOBALSTATUS_INVOKE_FREESPACE) {
|
|
ReintKdPrint(MAINLOOP, ("Agent(1): Calling DoFreeShadowSpace(1)\r\n"));
|
|
ReInt_DoFreeShadowSpace(&sGS, 0);
|
|
} else {
|
|
ReintKdPrint(MAINLOOP, ("Agent(1): Calling DoFreeShadowSpace(2)\r\n"));
|
|
ReInt_DoFreeShadowSpace(&sGS, 0);
|
|
}
|
|
} else {
|
|
if (sGS.uFlagsEvents & FLAG_GLOBALSTATUS_SHARE_DISCONNECTED) {
|
|
ReintKdPrint(MAINLOOP, ("Agent(1): Calling ReportShareNetArrivalDeparture\r\n"));
|
|
ReportShareNetArrivalDeparture(
|
|
1,
|
|
0,
|
|
((sGS.uFlagsEvents & FLAG_GLOBALSTATUS_INVOKE_AUTODIAL)!=0),
|
|
FALSE); // departed
|
|
}
|
|
}
|
|
vsGS = sGS;
|
|
vsGS.uFlagsEvents = 0; // clear all event indicators
|
|
}
|
|
return iRet;
|
|
}
|
|
|
|
BOOL
|
|
CreatePerSessSyncObjects(
|
|
VOID
|
|
)
|
|
{
|
|
NTSTATUS Status;
|
|
UNICODE_STRING EventName;
|
|
OBJECT_ATTRIBUTES ObjectAttributes;
|
|
WCHAR SessEventName[100];
|
|
|
|
// DbgPrint("CreatePerSessSyncObjects:vdwAgentSessionId = %d\n", vdwAgentSessionId);
|
|
|
|
Assert(heventPerSess == NULL);
|
|
|
|
wsprintf(SessEventName, L"%ws_%d", SESSION_EVENT_NAME_NT, vdwAgentSessionId);
|
|
|
|
// DbgPrint("CreatePerSessSyncObjects:SessEventName = [%ws]\n", SessEventName);
|
|
|
|
RtlInitUnicodeString(&EventName, SessEventName);
|
|
|
|
InitializeObjectAttributes( &ObjectAttributes,
|
|
&EventName,
|
|
OBJ_OPENIF, //got this const from base\client\support.c
|
|
(HANDLE) NULL,
|
|
(PSECURITY_DESCRIPTOR) NULL );
|
|
|
|
Status = NtCreateEvent(
|
|
&heventPerSess,
|
|
EVENT_ALL_ACCESS,
|
|
&ObjectAttributes,
|
|
SynchronizationEvent,
|
|
FALSE
|
|
);
|
|
|
|
if (!NT_SUCCESS(Status)) {
|
|
DbgPrint("CreatePerSessSyncObjects:NtCreateEvent returned %08lx\n",Status);
|
|
}
|
|
|
|
|
|
return (heventPerSess==0)?FALSE:TRUE;
|
|
|
|
}
|
|
|
|
BOOL
|
|
CreateSharedFillSyncObjects(
|
|
VOID
|
|
)
|
|
{
|
|
NTSTATUS Status;
|
|
UNICODE_STRING EventName;
|
|
OBJECT_ATTRIBUTES ObjectAttributes;
|
|
|
|
Assert(heventSharedFill == NULL);
|
|
|
|
RtlInitUnicodeString(&EventName,SHARED_FILL_EVENT_NAME_NT);
|
|
|
|
InitializeObjectAttributes( &ObjectAttributes,
|
|
&EventName,
|
|
OBJ_OPENIF, //got this const from base\client\support.c
|
|
(HANDLE) NULL,
|
|
(PSECURITY_DESCRIPTOR) NULL );
|
|
|
|
Status = NtCreateEvent(
|
|
&heventSharedFill,
|
|
EVENT_ALL_ACCESS,
|
|
&ObjectAttributes,
|
|
SynchronizationEvent,
|
|
FALSE
|
|
);
|
|
|
|
if (!NT_SUCCESS(Status)) {
|
|
DbgPrint("ntcreateeventstatus=%08lx\n",Status);
|
|
}
|
|
|
|
|
|
return (heventSharedFill==0)?FALSE:TRUE;
|
|
|
|
}
|
|
|
|
|
|
VOID
|
|
ProcessStartStopAgent(
|
|
VOID
|
|
)
|
|
{
|
|
if (vfStartRecieved)
|
|
{
|
|
|
|
ReintKdPrint(MAINLOOP, ("Agent(1): start received, enabling CSC\r\n"));
|
|
|
|
|
|
if (EnableCSC() == FALSE)
|
|
{
|
|
ReintKdPrint(ALWAYS, ("Ageint(1):Couldn't turn CSC ON!!!!!!!!! \n"));
|
|
}
|
|
else
|
|
{
|
|
UpdateExclusionList();
|
|
UpdateBandwidthConservationList();
|
|
}
|
|
|
|
|
|
// set the event to indicate to wkssvc that we are alive
|
|
if (heventAgentToWkssvc)
|
|
{
|
|
SetEvent(heventAgentToWkssvc);
|
|
}
|
|
|
|
vfStartRecieved = FALSE;
|
|
vfRedirStarted = TRUE;
|
|
}
|
|
else if (vfStopRecieved)
|
|
{
|
|
ReintKdPrint(MAINLOOP, ("Agent(1):Stop recieved \r\n"));
|
|
|
|
DisableCSC();
|
|
|
|
if(heventAgentToWkssvc)
|
|
{
|
|
SetEvent(heventAgentToWkssvc);
|
|
}
|
|
|
|
vcntNetDevices = 0;
|
|
vfStopRecieved = FALSE;
|
|
vfRedirStarted = FALSE;
|
|
}
|
|
}
|
|
|
|
BOOL
|
|
FStopAgent(
|
|
VOID
|
|
)
|
|
{
|
|
|
|
if (StartStopCheck() && vfStopRecieved)
|
|
{
|
|
return TRUE;
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
BOOL
|
|
StartStopCheck(
|
|
VOID
|
|
)
|
|
{
|
|
DWORD dwError;
|
|
BOOL fRet = FALSE;
|
|
HANDLE hT[2];
|
|
unsigned ulSwitch=0;
|
|
|
|
// the way we are finding out about the start makes the start event
|
|
// redundant, but we will leave it, because it is generically the right thing to have a
|
|
// start event and a stop event.
|
|
|
|
if ((vfRedirStarted == -1) && // if newly launched agent
|
|
(ShadowSwitches(INVALID_HANDLE_VALUE, &ulSwitch, SHADOW_SWITCH_GET_STATE)))
|
|
{
|
|
ReintKdPrint(INIT, ("Agent: redir already started\r\n"));
|
|
vfStartRecieved = TRUE;
|
|
}
|
|
else if (heventWkssvcToAgentStart)
|
|
{
|
|
// we know that when it comes to events it is all or nothing
|
|
Assert(heventWkssvcToAgentStop);
|
|
|
|
hT[0] = heventWkssvcToAgentStart;
|
|
hT[1] = heventWkssvcToAgentStop;
|
|
|
|
dwError = MsgWaitForMultipleObjects(2, hT, FALSE, 0, QS_ALLINPUT);
|
|
|
|
if (vfRedirStarted == TRUE)
|
|
{
|
|
vfStopRecieved = (dwError == WAIT_OBJECT_0+1);
|
|
if (vfStopRecieved)
|
|
{
|
|
ReintKdPrint(INIT, ("Agent: stop recieved\r\n"));
|
|
}
|
|
}
|
|
else
|
|
{
|
|
vfStartRecieved = (dwError == WAIT_OBJECT_0);
|
|
|
|
if (vfStartRecieved)
|
|
{
|
|
ReintKdPrint(INIT, ("Agent: start recieved\r\n"));
|
|
}
|
|
}
|
|
}
|
|
|
|
return fRet;
|
|
}
|
|
|
|
BOOL
|
|
Reint_RegisterAgent(
|
|
VOID
|
|
)
|
|
{
|
|
|
|
if (!vfAgentRegistered)
|
|
{
|
|
if (!RegisterAgent(INVALID_HANDLE_VALUE, vhwndMain, LongToHandle(dwVxDEvent)))
|
|
{
|
|
ReintKdPrint(BADERRORS, ("Agent registration failed \n"));
|
|
return FALSE;
|
|
}
|
|
|
|
else
|
|
{
|
|
vfAgentRegistered = TRUE;
|
|
}
|
|
}
|
|
return vfAgentRegistered;
|
|
}
|
|
|
|
VOID
|
|
Reint_UnregisterAgent(
|
|
VOID
|
|
)
|
|
{
|
|
if (vfAgentRegistered)
|
|
{
|
|
// don't do any checking
|
|
UnregisterAgent(INVALID_HANDLE_VALUE, vhwndMain);
|
|
vfAgentRegistered = FALSE;
|
|
}
|
|
|
|
}
|
|
|
|
BOOL
|
|
QueryEnableCSC(
|
|
VOID
|
|
)
|
|
{
|
|
|
|
DWORD dwDisposition, dwSize, dwEnabled=0;
|
|
HKEY hKey = NULL;
|
|
BOOL fRet = TRUE;
|
|
int i;
|
|
_TCHAR *lpKey;
|
|
NT_PRODUCT_TYPE productType;
|
|
|
|
if( !RtlGetNtProductType( &productType ) ) {
|
|
productType = NtProductWinNt;
|
|
}
|
|
|
|
switch ( productType ) {
|
|
case NtProductWinNt:
|
|
/* WORKSTATION */
|
|
ReintKdPrint(INIT, ("Agent:CSC running workstation\r\n"));
|
|
break;
|
|
default:
|
|
ReintKdPrint(INIT, ("Agent:CSC NOT running workstation\r\n"));
|
|
fRet = FALSE; // default is fail
|
|
}
|
|
|
|
|
|
//Check if CSC can work with current settings for TS
|
|
//Test for TS added by Navjot as per Bug#468391
|
|
if (IsPersonal() == TRUE || !CanCSCLivewithTS() )
|
|
return FALSE;
|
|
|
|
for (i=0; i<2; ++i)
|
|
{
|
|
if (i==0)
|
|
{
|
|
lpKey = REG_STRING_POLICY_NETCACHE_KEY;
|
|
}
|
|
else
|
|
{
|
|
lpKey = REG_STRING_NETCACHE_KEY;
|
|
}
|
|
|
|
if (RegOpenKeyEx( HKEY_LOCAL_MACHINE,
|
|
lpKey,
|
|
0,
|
|
KEY_READ | KEY_WRITE,
|
|
&hKey
|
|
) == ERROR_SUCCESS)
|
|
{
|
|
dwSize = sizeof(dwEnabled);
|
|
|
|
if (RegQueryValueEx(hKey, REG_VALUE_ENABLED, NULL, NULL, (void *)&dwEnabled, &dwSize) == ERROR_SUCCESS)
|
|
{
|
|
fRet = (dwEnabled != 0);
|
|
break;
|
|
}
|
|
|
|
|
|
RegCloseKey(hKey);
|
|
hKey = NULL;
|
|
}
|
|
else
|
|
{
|
|
hKey = NULL;
|
|
}
|
|
}
|
|
|
|
if(hKey)
|
|
{
|
|
RegCloseKey(hKey);
|
|
}
|
|
|
|
return (fRet);
|
|
}
|
|
|
|
|
|
|
|
|
|
BOOL
|
|
CreateStartStopEvents(
|
|
VOID
|
|
)
|
|
{
|
|
BOOL fOK = FALSE;
|
|
|
|
// ensure that there are thre named autoreset events
|
|
if (!heventWkssvcToAgentStart)
|
|
{
|
|
heventWkssvcToAgentStart = CreateEvent(NULL, FALSE, FALSE, szWkssvcToAgentStartEvent);
|
|
|
|
if (!heventWkssvcToAgentStart)
|
|
{
|
|
ReintKdPrint(BADERRORS, ("CSC.Agent: Failed to create heventWkssvcToAgentStart, error = %d\n", GetLastError()));
|
|
goto bailout;
|
|
}
|
|
|
|
Assert(!heventAgentToWkssvc);
|
|
|
|
heventWkssvcToAgentStop = CreateEvent(NULL, FALSE, FALSE, szWkssvcToAgentStopEvent);
|
|
|
|
if (!heventWkssvcToAgentStop)
|
|
{
|
|
ReintKdPrint(BADERRORS, ("CSC.Agent: Failed to create heventWkssvcToAgentStop, error = %d\n", GetLastError()));
|
|
goto bailout;
|
|
}
|
|
|
|
heventAgentToWkssvc = CreateEvent(NULL, FALSE, FALSE, szAgentToWkssvcEvent);
|
|
|
|
if (!heventAgentToWkssvc)
|
|
{
|
|
ReintKdPrint(BADERRORS, ("CSC.Agent: Failed to create heventAgentToWkssvc, error = %d\n", GetLastError()));
|
|
goto bailout;
|
|
}
|
|
|
|
// event to detect whether the agent is alive (used by wkssvc) and
|
|
// to signal termination (used by winlogon)
|
|
heventShutDownAgent = CreateEvent(NULL, FALSE, FALSE, szAgentExistsEvent);
|
|
|
|
if (!heventShutDownAgent)
|
|
{
|
|
ReintKdPrint(BADERRORS, ("CSC.Agent: Failed to create heventShutDownAgent, error = %d\n", GetLastError()));
|
|
goto bailout;
|
|
}
|
|
|
|
heventShutDownThread = CreateEvent(NULL, FALSE, FALSE, NULL);
|
|
|
|
if (!heventShutDownThread)
|
|
{
|
|
ReintKdPrint(BADERRORS, ("CSC.Agent: Failed to create heventShutDownThread, error = %d\n", GetLastError()));
|
|
goto bailout;
|
|
}
|
|
}
|
|
|
|
fOK = TRUE;
|
|
|
|
bailout:
|
|
|
|
if (!fOK)
|
|
{
|
|
DestroyStartStopEvents();
|
|
}
|
|
return fOK;
|
|
}
|
|
|
|
VOID
|
|
DestroyStartStopEvents(
|
|
VOID
|
|
)
|
|
{
|
|
|
|
if (heventWkssvcToAgentStart)
|
|
{
|
|
CloseHandle(heventWkssvcToAgentStart);
|
|
heventWkssvcToAgentStart = NULL;
|
|
}
|
|
|
|
if (heventWkssvcToAgentStop)
|
|
{
|
|
CloseHandle(heventWkssvcToAgentStop);
|
|
heventWkssvcToAgentStop = NULL;
|
|
}
|
|
|
|
if (heventAgentToWkssvc)
|
|
{
|
|
CloseHandle(heventAgentToWkssvc);
|
|
heventAgentToWkssvc = NULL;
|
|
}
|
|
|
|
if (heventShutDownAgent)
|
|
{
|
|
CloseHandle(heventShutDownAgent);
|
|
heventShutDownAgent = NULL;
|
|
}
|
|
if (heventShutDownThread)
|
|
{
|
|
CloseHandle(heventShutDownThread);
|
|
heventShutDownThread = NULL;
|
|
}
|
|
}
|
|
|
|
BOOL
|
|
UpdateExclusionList(
|
|
VOID
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Tell the kernel mode code about the exclusion list. If there is none set in the registry
|
|
then we set the default one
|
|
|
|
Parameters:
|
|
|
|
Return Value:
|
|
|
|
Notes:
|
|
|
|
|
|
--*/
|
|
{
|
|
LPWSTR lpwExclusionList = NULL;
|
|
DWORD cbSize = 0;
|
|
char buff[MAX_LIST_SIZE]; // max exclusion list
|
|
BOOL fRet = FALSE;
|
|
|
|
if (!vfCSCEnabled)
|
|
{
|
|
|
|
ReintKdPrint(INIT, ("CSC not enabled \r\n"));
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
ReintKdPrint(INIT, ("Getting ExclusionList \r\n"));
|
|
|
|
// get the exclusion list from the policy key.
|
|
// if that doesn't work then try the one from the netcache key
|
|
|
|
if (GetWideStringFromRegistryString(REG_STRING_POLICY_NETCACHE_KEY_A,
|
|
REG_STRING_EXCLUSION_LIST_A,
|
|
&lpwExclusionList,
|
|
&cbSize) ||
|
|
GetWideStringFromRegistryString(REG_STRING_NETCACHE_KEY_A,
|
|
REG_STRING_EXCLUSION_LIST_A,
|
|
&lpwExclusionList,
|
|
&cbSize)
|
|
)
|
|
{
|
|
ReintKdPrint(INIT, ("Got ExclusionList \r\n"));
|
|
|
|
if (cbSize < sizeof(buff))
|
|
{
|
|
memcpy(buff, lpwExclusionList, cbSize);
|
|
|
|
ReintKdPrint(INIT, ("Setting User defined exclusion list %ls size=%d\r\n", buff, cbSize));
|
|
if (SetExclusionList(INVALID_HANDLE_VALUE, (USHORT *)buff, cbSize))
|
|
{
|
|
fRet = TRUE;
|
|
}
|
|
}
|
|
|
|
}
|
|
else
|
|
{
|
|
// set the default
|
|
// take the string and it's terminating null char
|
|
cbSize = sizeof(vtzDefaultExclusionList);
|
|
Assert(cbSize < MAX_LIST_SIZE);
|
|
memcpy(buff, vtzDefaultExclusionList, cbSize);
|
|
ReintKdPrint(INIT, ("Setting default exclusion list %ls size=%d\r\n", buff, cbSize));
|
|
|
|
if (SetExclusionList(INVALID_HANDLE_VALUE, (USHORT *)buff, cbSize))
|
|
{
|
|
fRet = TRUE;
|
|
}
|
|
}
|
|
|
|
if (lpwExclusionList)
|
|
{
|
|
LocalFree(lpwExclusionList);
|
|
}
|
|
return fRet;
|
|
}
|
|
|
|
|
|
BOOL
|
|
UpdateBandwidthConservationList(
|
|
VOID
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Update the list of extensions on which bitcopy should be turned ON. We do not set any default
|
|
|
|
Parameters:
|
|
|
|
Return Value:
|
|
|
|
Notes:
|
|
|
|
|
|
--*/
|
|
{
|
|
LPWSTR lpwBandwidthConservationList = NULL;
|
|
DWORD cbSize = 0;
|
|
char buff[MAX_LIST_SIZE]; // max exclusion list
|
|
BOOL fRet = FALSE;
|
|
|
|
if (!vfCSCEnabled)
|
|
{
|
|
|
|
ReintKdPrint(INIT, ("CSC not enabled \r\n"));
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
ReintKdPrint(INIT, ("Getting BandwidthConservationList \r\n"));
|
|
|
|
// get the exclusion list from the policy key.
|
|
// if that doesn't work then try the one from the netcache key
|
|
|
|
if (GetWideStringFromRegistryString(REG_STRING_POLICY_NETCACHE_KEY_A,
|
|
REG_STRING_BANDWIDTH_CONSERVATION_LIST_A,
|
|
&lpwBandwidthConservationList,
|
|
&cbSize) ||
|
|
GetWideStringFromRegistryString(REG_STRING_NETCACHE_KEY_A,
|
|
REG_STRING_BANDWIDTH_CONSERVATION_LIST_A,
|
|
&lpwBandwidthConservationList,
|
|
&cbSize)
|
|
)
|
|
{
|
|
ReintKdPrint(INIT, ("Got BandwidthConservationList \r\n"));
|
|
|
|
if (cbSize < sizeof(buff))
|
|
{
|
|
memcpy(buff, lpwBandwidthConservationList, cbSize);
|
|
|
|
ReintKdPrint(INIT, ("Setting User defined bandwidth conservation list %ls size=%d\r\n", buff, cbSize));
|
|
if (SetBandwidthConservationList(INVALID_HANDLE_VALUE, (USHORT *)buff, cbSize))
|
|
{
|
|
fRet = TRUE;
|
|
}
|
|
}
|
|
|
|
}
|
|
else
|
|
{
|
|
fRet = FALSE;
|
|
#if 0
|
|
// set the default
|
|
// take the string and it's terminating null char
|
|
cbSize = sizeof(vtzDefaultBandwidthConservationList);
|
|
Assert(cbSize < MAX_LIST_SIZE);
|
|
memcpy(buff, vtzDefaultBandwidthConservationList, cbSize);
|
|
ReintKdPrint(INIT, ("Setting default exclusion list %ls size=%d\r\n", buff, cbSize));
|
|
|
|
if (SetBandwidthConservationList(INVALID_HANDLE_VALUE, (USHORT *)buff, cbSize))
|
|
{
|
|
fRet = TRUE;
|
|
}
|
|
#endif
|
|
}
|
|
|
|
if (lpwBandwidthConservationList)
|
|
{
|
|
LocalFree(lpwBandwidthConservationList);
|
|
}
|
|
return fRet;
|
|
}
|
|
|
|
|
|
|
|
BOOL
|
|
ProcessNetArrivalMessage(
|
|
VOID
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
|
|
Parameters:
|
|
|
|
Return Value:
|
|
|
|
Notes:
|
|
|
|
--*/
|
|
{
|
|
|
|
vcntNetDevices = 1;
|
|
ReportShareNetArrivalDeparture( 0, // all shares
|
|
0,
|
|
FALSE, // don't invoke autodial
|
|
TRUE // arrived
|
|
);
|
|
|
|
ReintKdPrint(INIT, ("WM_DEVICECHANGE:Net arrived, %d nets so far\r\n", vcntNetDevices));
|
|
|
|
return (TRUE);
|
|
}
|
|
|
|
BOOL
|
|
ProcessNetDepartureMessage(
|
|
BOOL fInvokeAutodial
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
|
|
Parameters:
|
|
|
|
Return Value:
|
|
|
|
Notes:
|
|
|
|
--*/
|
|
{
|
|
ReintKdPrint(MAINLOOP, ("WM_DEVICECHANGE:Net removed, %d nets so far\r\n", vcntNetDevices));
|
|
|
|
vcntNetDevices = 0;
|
|
|
|
ReportShareNetArrivalDeparture( 0, // all shares
|
|
0,
|
|
fInvokeAutodial, // invoke auto dial
|
|
FALSE // departed
|
|
);
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
BOOL
|
|
ReportShareNetArrivalDeparture(
|
|
BOOL fOneServer,
|
|
HSHARE hShare,
|
|
BOOL fInvokeAutoDial,
|
|
BOOL fArrival
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Parameters:
|
|
|
|
Return Value:
|
|
|
|
Notes:
|
|
|
|
--*/
|
|
{
|
|
SHAREINFO sSR;
|
|
_TCHAR *lptzServerName;
|
|
unsigned ulStatus;
|
|
DWORD dwSize;
|
|
BOOL fGotName = FALSE;
|
|
BOOL fAllocated = FALSE;
|
|
BOOL fRet = FALSE;
|
|
LRESULT lResult = LRESULT_CSCFAIL;
|
|
LPTSTR lp = NULL;
|
|
DWORD dwMessage = 0;
|
|
WPARAM dwWParam = (WPARAM) 0;
|
|
LPARAM dwLParam = (LPARAM) 0;
|
|
|
|
lptzServerName = sSR.rgSharePath;
|
|
|
|
if (fOneServer) {
|
|
if (fArrival) {
|
|
if(GetShareInfo(vhShadowDBForEvent, hShare, &sSR, &ulStatus)<= 0) {
|
|
PrintFn("ReportShareNetArrivalDeparture: couldn't get status for server 0x%x\r\n",
|
|
hShare);
|
|
ReintKdPrint(
|
|
BADERRORS,
|
|
("ReportShareNetArrivalDeparture: couldn't get status for server 0x%x\r\n",
|
|
hShare));
|
|
return FALSE;
|
|
}
|
|
lp = MyStrChr(sSR.rgSharePath+2, _T('\\'));
|
|
if (!lp) {
|
|
ReintKdPrint(
|
|
BADERRORS,
|
|
("ReportShareNetArrivalDeparture: Invalid server name %ls\r\n",
|
|
sSR.rgSharePath));
|
|
Assert(FALSE);
|
|
return FALSE;
|
|
}
|
|
*lp = 0;
|
|
} else { // A share departure
|
|
int i;
|
|
|
|
dwSize = sizeof(sSR.rgSharePath);
|
|
fGotName = GetNameOfServerGoingOfflineEx(
|
|
vhShadowDBForEvent,
|
|
&lptzServerName,
|
|
&dwSize,
|
|
&fAllocated);
|
|
if(!fGotName) {
|
|
TransitionShareToOffline(vhShadowDBForEvent, fOneServer, 0xffffffff);
|
|
goto bailout;
|
|
}
|
|
}
|
|
}
|
|
|
|
fRet = TRUE;
|
|
|
|
ReintKdPrint(
|
|
INIT,
|
|
("ReportShareNetArrivalDeparture: reporting %s to the systray\r\n",
|
|
(fArrival) ? "arrival" : "departure"));
|
|
|
|
dwMessage = (fArrival) ? STWM_CSCNETUP : STWM_CSCQUERYNETDOWN;
|
|
dwWParam = (fInvokeAutoDial)
|
|
? ((hShare != 0)
|
|
? CSCUI_AUTODIAL_FOR_CACHED_SHARE
|
|
: CSCUI_AUTODIAL_FOR_UNCACHED_SHARE)
|
|
: CSCUI_NO_AUTODIAL;
|
|
dwLParam = (fOneServer) ? (DWORD_PTR)(lptzServerName) : 0;
|
|
|
|
lResult = ReportEventsToSystray(dwMessage, dwWParam, dwLParam);
|
|
|
|
// if the redir is stuck waiting to be told whether to go offline on a share
|
|
// tell him yes or no
|
|
if (!fArrival) {
|
|
if (fOneServer) {
|
|
TransitionShareToOffline(
|
|
vhShadowDBForEvent,
|
|
fOneServer,
|
|
(lResult == LRESULT_CSCWORKOFFLINE)
|
|
? 1
|
|
: ((lResult == LRESULT_CSCRETRY)
|
|
? 0
|
|
: 0xffffffff)
|
|
);
|
|
|
|
if (lResult == LRESULT_CSCWORKOFFLINE) {
|
|
dwMessage = STWM_CSCNETDOWN;
|
|
dwWParam = fInvokeAutoDial;
|
|
dwLParam = (fOneServer)
|
|
? ((hShare != 0)
|
|
? (DWORD_PTR)(lptzServerName)
|
|
: 0xffffffff)
|
|
: 0;
|
|
ReportEventsToSystray(dwMessage, dwWParam, dwLParam);
|
|
ReportTransitionToDfs(lptzServerName, TRUE, 0xffffffff);
|
|
}
|
|
}
|
|
}
|
|
|
|
bailout:
|
|
if (fAllocated) {
|
|
LocalFree(lptzServerName);
|
|
}
|
|
return (fRet);
|
|
}
|
|
|
|
|
|
BOOL
|
|
CheckServerOnline(
|
|
VOID
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
|
|
Parameters:
|
|
|
|
Return Value:
|
|
|
|
Notes:
|
|
|
|
--*/
|
|
{
|
|
unsigned long ulStatus;
|
|
WIN32_FIND_DATA sFind32;
|
|
int cntReconnected=0;
|
|
SHADOWINFO sSI;
|
|
HANDLE hShadowDB;
|
|
_TCHAR tzDriveMap[4];
|
|
CSC_ENUMCOOKIE ulEnumCookie=NULL;
|
|
DWORD dwError;
|
|
|
|
if (!ImpersonateALoggedOnUser())
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
if ((hShadowDB = OpenShadowDatabaseIO()) ==INVALID_HANDLE_VALUE)
|
|
{
|
|
ResetAgentThreadImpersonation();
|
|
return 0;
|
|
}
|
|
|
|
memset(&sFind32, 0, sizeof(sFind32));
|
|
lstrcpy(sFind32.cFileName, _TEXT("*"));
|
|
|
|
if(FindOpenShadow( hShadowDB, 0, FINDOPEN_SHADOWINFO_ALL,
|
|
&sFind32, &sSI))
|
|
{
|
|
ulEnumCookie = sSI.uEnumCookie;
|
|
|
|
do {
|
|
if(GetShareStatus(hShadowDB, sSI.hShare, &ulStatus)) {
|
|
|
|
if(ulStatus & SHARE_DISCONNECTED_OP){
|
|
|
|
dwError = DWConnectNet(sFind32.cFileName, tzDriveMap, NULL, NULL, NULL, 0, NULL);
|
|
|
|
if ((dwError == NO_ERROR)||(dwError == ERROR_ACCESS_DENIED)||(dwError==WN_CONNECTED_OTHER_PASSWORD_DEFAULT))
|
|
{
|
|
if (sSI.ulHintFlags & FLAG_CSC_HINT_PIN_SYSTEM)
|
|
{
|
|
TransitionShareToOnline(INVALID_HANDLE_VALUE, 0);
|
|
}
|
|
else
|
|
{
|
|
ReportShareNetArrivalDeparture( TRUE,
|
|
sSI.hShare, // this share
|
|
FALSE, // don't autodial
|
|
TRUE); // Arrived
|
|
}
|
|
|
|
++cntReconnected;
|
|
if (dwError == NO_ERROR || dwError == WN_CONNECTED_OTHER_PASSWORD_DEFAULT)
|
|
{
|
|
DWDisconnectDriveMappedNet(tzDriveMap, TRUE); // force disconnect
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
Sleep(200);
|
|
|
|
} while(FindNextShadow(hShadowDB, ulEnumCookie, &sFind32, &sSI));
|
|
|
|
FindCloseShadow(hShadowDB, ulEnumCookie);
|
|
}
|
|
|
|
|
|
CloseShadowDatabaseIO(hShadowDB);
|
|
|
|
ResetAgentThreadImpersonation();
|
|
|
|
return (cntReconnected?TRUE:FALSE);
|
|
|
|
}
|
|
|
|
BOOL
|
|
AreAnyServersOffline(
|
|
VOID)
|
|
{
|
|
ULONG ulStatus;
|
|
WIN32_FIND_DATA sFind32 = {0};
|
|
SHADOWINFO sSI;
|
|
HANDLE hShadowDB;
|
|
CSC_ENUMCOOKIE ulEnumCookie = NULL;
|
|
BOOL bFoundOne = FALSE;
|
|
|
|
if ((hShadowDB = OpenShadowDatabaseIO()) ==INVALID_HANDLE_VALUE)
|
|
return FALSE;
|
|
|
|
wcscpy(sFind32.cFileName, L"*");
|
|
if (FindOpenShadow(hShadowDB, 0, FINDOPEN_SHADOWINFO_ALL, &sFind32, &sSI)) {
|
|
ulEnumCookie = sSI.uEnumCookie;
|
|
do {
|
|
if (GetShareStatus(hShadowDB, sSI.hShare, &ulStatus)) {
|
|
if ((ulStatus & SHARE_DISCONNECTED_OP) != 0) {
|
|
bFoundOne = TRUE;
|
|
break;
|
|
}
|
|
}
|
|
} while(FindNextShadow(hShadowDB, ulEnumCookie, &sFind32, &sSI));
|
|
FindCloseShadow(hShadowDB, ulEnumCookie);
|
|
}
|
|
CloseShadowDatabaseIO(hShadowDB);
|
|
return bFoundOne;
|
|
}
|
|
|
|
BOOL
|
|
FAbortOperation(
|
|
VOID
|
|
)
|
|
{
|
|
|
|
if (!vdwAgentThreadId)
|
|
{
|
|
return FALSE;
|
|
}
|
|
|
|
if (IsAgentShutDownRequested() || HasAgentShutDown())
|
|
{
|
|
ReintKdPrint(MAINLOOP, ("CSC.FAbortOperation: Agentshutdown detected aborting \r\n"));
|
|
return TRUE;
|
|
}
|
|
return (FStopAgent());
|
|
}
|
|
|
|
VOID
|
|
SetAgentShutDownRequest(
|
|
VOID
|
|
)
|
|
{
|
|
fAgentShutDownRequested = TRUE;
|
|
SetEvent(heventShutDownAgent);
|
|
}
|
|
|
|
BOOL
|
|
IsAgentShutDownRequested(
|
|
VOID
|
|
)
|
|
{
|
|
return (fAgentShutDownRequested == TRUE);
|
|
}
|
|
|
|
VOID
|
|
SetAgentShutDown(
|
|
VOID
|
|
)
|
|
{
|
|
fAgentShutDown = TRUE;
|
|
}
|
|
|
|
BOOL
|
|
HasAgentShutDown(
|
|
VOID
|
|
)
|
|
{
|
|
return (fAgentShutDown == TRUE );
|
|
|
|
}
|
|
|
|
|
|
// HWND CSCUIInitialize(HANDLE hToken, DWORD dwFlags)
|
|
BOOL
|
|
InitCSCUI(
|
|
HANDLE hToken
|
|
)
|
|
{
|
|
|
|
ReintKdPrint(INIT, (" Initializing cscui\r\n"));
|
|
|
|
EnterAgentCrit();
|
|
if (!vhlibCSCUI)
|
|
{
|
|
vhlibCSCUI = LoadLibrary(vtzCSCUI);
|
|
|
|
if (vhlibCSCUI)
|
|
{
|
|
if (vlpfnCSCUIInitialize = (CSCUIINITIALIZE)GetProcAddress(vhlibCSCUI, (const char *)vszCSCUIInitialize))
|
|
{
|
|
if(!(vlpfnCSCUISetState = (CSCUISETSTATE)GetProcAddress(vhlibCSCUI, (const char *)vszCSCUISetState)))
|
|
{
|
|
ReintKdPrint(BADERRORS, ("Failed to get proc addres for %s, Error = %d \r\n", vszCSCUISetState, GetLastError()));
|
|
}
|
|
else
|
|
{
|
|
(*vlpfnCSCUIInitialize)(hToken, CI_INITIALIZE);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
ReintKdPrint(BADERRORS, ("Failed to get proc addres for %s, Error = %d \r\n", vszCSCUIInitialize, GetLastError()));
|
|
}
|
|
}
|
|
else
|
|
{
|
|
ReintKdPrint(BADERRORS, ("Failed to load %ls, Error = %d \r\n", vtzCSCUI, GetLastError()));
|
|
}
|
|
}
|
|
LeaveAgentCrit();
|
|
|
|
return (vlpfnCSCUISetState != NULL);
|
|
}
|
|
|
|
|
|
|
|
VOID
|
|
TerminateCSCUI(
|
|
VOID
|
|
)
|
|
{
|
|
|
|
BOOL fShowing;
|
|
|
|
// snapshot the state of the showing dialog
|
|
// if we are about to show an offline dialog, ReportEventsToSystray
|
|
// will also do the action below but will try to set the vfShowingOfflineDlg
|
|
// variable to 1
|
|
// If fShowing was not set to 1, then we know that we are not showing UI
|
|
// and we set vfShowingOfflineDlg to 0xffffffff. This will make ReportEventsToSystray
|
|
// to not show the offline popup, so we will be free to do FreeLibrary
|
|
|
|
fShowing = (BOOL)InterlockedExchange((PLONG)&vfShowingOfflineDlg, 0xffffffff);
|
|
|
|
if (fShowing==1)
|
|
{
|
|
Assert(vhlibCSCUI && vlpfnCSCUISetState);
|
|
|
|
(vlpfnCSCUISetState)(STWM_CSCCLOSEDIALOGS, 0, 0);
|
|
|
|
while (vfShowingOfflineDlg != 0xfffffffe)
|
|
{
|
|
Sleep(10);
|
|
}
|
|
}
|
|
|
|
if (vhlibCSCUI)
|
|
{
|
|
(*vlpfnCSCUIInitialize)(0, CI_TERMINATE);
|
|
vlpfnCSCUIInitialize = NULL;
|
|
vlpfnCSCUISetState = NULL;
|
|
FreeLibrary(vhlibCSCUI);
|
|
vhlibCSCUI = NULL;
|
|
}
|
|
|
|
vfShowingOfflineDlg = 0;
|
|
|
|
}
|
|
|
|
LRESULT
|
|
ReportEventsToSystray(
|
|
DWORD dwMessage,
|
|
WPARAM dwWParam,
|
|
LPARAM dwLParam
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
|
|
Parameters:
|
|
|
|
Return Value:
|
|
|
|
Notes:
|
|
|
|
--*/
|
|
{
|
|
LRESULT lResult = LRESULT_CSCFAIL;
|
|
BOOL fOk;
|
|
|
|
HWND hwnd;
|
|
extern HDESK hdesktopUser, hdesktopCur;
|
|
|
|
EnterAgentCrit();
|
|
|
|
// is there a currently logged on user?
|
|
if (!hdesktopUser)
|
|
{
|
|
LeaveAgentCrit();
|
|
|
|
ReintKdPrint(INIT, ("ReportEventsToSystray: no-user logged, not-reporting\r\n"));
|
|
return lResult;
|
|
}
|
|
else
|
|
{
|
|
if(!SetThreadDesktop(hdesktopUser))
|
|
{
|
|
LeaveAgentCrit();
|
|
PrintFn("ReportEventsToSystray: failed to set desktop for agent thread error=%d\r\n", GetLastError());
|
|
ReintKdPrint(BADERRORS, ("ReportEventsToSystray: failed to set desktop for agent thread error=%d\r\n", GetLastError()));
|
|
return lResult;
|
|
}
|
|
|
|
// set our desktop to be that of the loggedon users desktop
|
|
hdesktopCur = hdesktopUser;
|
|
|
|
}
|
|
|
|
|
|
LeaveAgentCrit();
|
|
|
|
ReintKdPrint(INIT, ("ReportEventsToSystray: reporting message dwMessage=0x%x to the systray\r\n", dwMessage));
|
|
|
|
// snapshot the state of the showing dialog
|
|
// if we are about to terminate, the the terminateCSCUI will have
|
|
// will also do the action below but will try to set the vfShowingOfflineDlg
|
|
// variable to 0xffffffff
|
|
// If fOk was not set to 0xffffffff, then we know that we are not terminating
|
|
// and we set vfShowingOfflineDlg to 1. This will block the terminating guy
|
|
// and he will not free the library till thei variable gets set to FALSE;
|
|
|
|
fOk = (BOOL)InterlockedExchange((PLONG)&vfShowingOfflineDlg, 1);
|
|
|
|
if (fOk == 0)
|
|
{
|
|
if (vlpfnCSCUISetState)
|
|
{
|
|
|
|
lResult = (vlpfnCSCUISetState)(dwMessage, dwWParam, dwLParam);
|
|
|
|
// change the value of vfShowingOfflineDlg to 0 only if it is 1 right now
|
|
// it can be something other than 1 if we are about to terminate
|
|
|
|
if((DWORD)InterlockedCompareExchange(&vfShowingOfflineDlg, 0, 1) == 0xffffffff)
|
|
{
|
|
// if we came here then we are terminating, set a termination value
|
|
// so that the logoff thread will stop doing a sleep loop
|
|
// and if we came here again fOk will never be 0
|
|
vfShowingOfflineDlg = 0xfffffffe;
|
|
}
|
|
|
|
}
|
|
else
|
|
{
|
|
// Not showing any dialog, restore the variable back to what it should be
|
|
vfShowingOfflineDlg = 0;
|
|
PrintFn("ReportEventsToSystray: CSCUI not initalized\r\n");
|
|
}
|
|
}
|
|
|
|
return lResult;
|
|
}
|
|
|
|
BOOL
|
|
GetNameOfServerGoingOfflineEx(
|
|
HANDLE hShadowDB,
|
|
_TCHAR **lplptzServerName,
|
|
DWORD *lpdwSize,
|
|
BOOL *lpfAllocated
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine is called in winlogon thread to findout which server is about to go offline
|
|
The routine may allocate memory, which must be freed by the caller
|
|
|
|
Parameters:
|
|
|
|
Return Value:
|
|
|
|
Notes:
|
|
|
|
--*/
|
|
{
|
|
DWORD dwSize, i;
|
|
BOOL fRet = FALSE;
|
|
|
|
dwSize = *lpdwSize;
|
|
*lpfAllocated = FALSE;
|
|
|
|
for (i=0;i<2;++i)
|
|
{
|
|
|
|
if(!GetNameOfServerGoingOffline(
|
|
hShadowDB,
|
|
(LPBYTE)(*lplptzServerName), &dwSize))
|
|
{
|
|
// if we need a bigger buffer go get one
|
|
if (GetLastError() == ERROR_INSUFFICIENT_BUFFER)
|
|
{
|
|
// we shouldn't be trying to get a bigger buffer twice
|
|
// it should have been sufficient the first time around
|
|
|
|
if (i==1)
|
|
{
|
|
Assert(FALSE);
|
|
break;
|
|
}
|
|
|
|
ReintKdPrint(MAINLOOP, ("GetNameOfServerGoingOfflineEx: Need %d sized Buffer \n", dwSize));
|
|
*lplptzServerName = LocalAlloc(LPTR, dwSize);
|
|
|
|
if (!*lplptzServerName)
|
|
{
|
|
return FALSE;
|
|
}
|
|
|
|
*lpfAllocated = TRUE;
|
|
*lpdwSize = dwSize;
|
|
|
|
continue;
|
|
}
|
|
else
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// ReintKdPrint(MAINLOOP,("GetNameOfServerGoingOfflineEx:name=%ws\n", *lplptzServerName));
|
|
fRet = TRUE;
|
|
break;
|
|
}
|
|
}
|
|
|
|
// cleanup on error
|
|
if (!fRet && *lpfAllocated)
|
|
{
|
|
LocalFree(*lplptzServerName);
|
|
*lpfAllocated = FALSE;
|
|
}
|
|
|
|
return fRet;
|
|
}
|
|
|
|
BOOL
|
|
IsWinlogonRegValueSet(HKEY hKey, LPSTR pszKeyName, LPSTR pszPolicyKeyName, LPSTR pszValueName)
|
|
{
|
|
BOOL bRet = FALSE;
|
|
DWORD dwType;
|
|
DWORD dwSize;
|
|
HKEY hkey;
|
|
|
|
//
|
|
// first check the per-machine location.
|
|
//
|
|
if (RegOpenKeyExA(hKey, pszKeyName, 0, KEY_QUERY_VALUE, &hkey) == ERROR_SUCCESS)
|
|
{
|
|
dwSize = sizeof(bRet);
|
|
if (RegQueryValueExA(hkey, pszValueName, NULL, &dwType, (LPBYTE)&bRet, &dwSize) == ERROR_SUCCESS)
|
|
{
|
|
if (dwType != REG_DWORD)
|
|
{
|
|
bRet = FALSE;
|
|
}
|
|
}
|
|
RegCloseKey(hkey);
|
|
}
|
|
//
|
|
// then let the policy value override
|
|
//
|
|
if (RegOpenKeyExA(hKey, pszPolicyKeyName, 0, KEY_QUERY_VALUE, &hkey) == ERROR_SUCCESS)
|
|
{
|
|
dwSize = sizeof(bRet);
|
|
if (RegQueryValueExA(hkey, pszValueName, NULL, &dwType, (LPBYTE)&bRet, &dwSize) == ERROR_SUCCESS)
|
|
{
|
|
if (dwType != REG_DWORD)
|
|
{
|
|
bRet = FALSE;
|
|
}
|
|
}
|
|
RegCloseKey(hkey);
|
|
}
|
|
|
|
return bRet;
|
|
}
|
|
|
|
|
|
|
|
BOOL
|
|
CheckIsSafeModeType(DWORD dwSafeModeType)
|
|
{
|
|
|
|
BOOL bResult = FALSE;
|
|
HKEY hkey;
|
|
if (ERROR_SUCCESS == RegOpenKeyEx(HKEY_LOCAL_MACHINE,
|
|
TEXT("SYSTEM\\CurrentControlSet\\Control\\SafeBoot\\Option"),
|
|
0,
|
|
KEY_QUERY_VALUE,
|
|
&hkey))
|
|
{
|
|
DWORD dwType;
|
|
DWORD dwValue;
|
|
DWORD cbValue = sizeof(dwValue);
|
|
|
|
if (ERROR_SUCCESS == RegQueryValueEx(hkey,
|
|
TEXT("OptionValue"),
|
|
NULL,
|
|
&dwType,
|
|
(LPBYTE)&dwValue,
|
|
&cbValue))
|
|
{
|
|
bResult = (dwValue == dwSafeModeType);
|
|
}
|
|
RegCloseKey(hkey);
|
|
}
|
|
return bResult;
|
|
}
|
|
|
|
|
|
|
|
|
|
BOOL
|
|
AllowMultipleTsSessions(void)
|
|
{
|
|
return IsWinlogonRegValueSet(HKEY_LOCAL_MACHINE,
|
|
"SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Winlogon",
|
|
"SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\policies\\system",
|
|
"AllowMultipleTSSessions");
|
|
}
|
|
|
|
|
|
|
|
BOOL
|
|
IsSafeMode(void)
|
|
{
|
|
return CheckIsSafeModeType(SAFEBOOT_MINIMAL) ||
|
|
CheckIsSafeModeType(SAFEBOOT_NETWORK);
|
|
}
|
|
|
|
|
|
|
|
BOOL
|
|
IsTerminalServicesEnabled(void)
|
|
|
|
{
|
|
OSVERSIONINFOEX osVersionInfo;
|
|
DWORDLONG dwlConditionMask;
|
|
|
|
dwlConditionMask = 0;
|
|
ZeroMemory(&osVersionInfo, sizeof(osVersionInfo));
|
|
osVersionInfo.dwOSVersionInfoSize = sizeof(osVersionInfo);
|
|
osVersionInfo.wSuiteMask = VER_SUITE_TERMINAL | VER_SUITE_SINGLEUSERTS;
|
|
VER_SET_CONDITION(dwlConditionMask, VER_SUITENAME, VER_OR);
|
|
return(VerifyVersionInfo(&osVersionInfo, VER_SUITENAME, dwlConditionMask) != FALSE);
|
|
}
|
|
|
|
|
|
|
|
BOOL
|
|
IsMultipleUsersEnabled(void)
|
|
{
|
|
return IsTerminalServicesEnabled() &&
|
|
!IsSafeMode() &&
|
|
AllowMultipleTsSessions();
|
|
}
|
|
|
|
|
|
BOOL CanCSCLivewithTS(
|
|
VOID)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
Checks if TS settings are ok to turn on csc.
|
|
|
|
Arguments:
|
|
None
|
|
|
|
Return Value:
|
|
TRUE - Enable CSC
|
|
FALSE - Disable CSC
|
|
|
|
--*/
|
|
{
|
|
|
|
if (IsWorkstation ()) // for pro and per
|
|
{
|
|
|
|
// csc does not work with Fast user switching.
|
|
return !IsFastUserSwitchingEnabled();
|
|
}
|
|
else // for servers
|
|
{
|
|
//Both conditions have to be true
|
|
return !(IsTerminalServicesEnabled() && AreConnectionsAllowed());
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
BOOL AreConnectionsAllowed (
|
|
VOID)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
Checks if TS accepts connections.
|
|
|
|
Arguments:
|
|
None
|
|
|
|
Return Value:
|
|
TRUE - Accepts connections
|
|
FALSE - Denys connections
|
|
|
|
--*/
|
|
|
|
{
|
|
DWORD dwError;
|
|
HKEY hkey;
|
|
|
|
dwError = RegOpenKeyEx(HKEY_LOCAL_MACHINE,
|
|
TEXT("SYSTEM\\CurrentControlSet\\Control\\Terminal Server"),
|
|
0,
|
|
KEY_QUERY_VALUE,
|
|
&hkey);
|
|
|
|
if (ERROR_SUCCESS == dwError)
|
|
{
|
|
DWORD dwType;
|
|
DWORD dwValue;
|
|
DWORD cbValue = sizeof(dwValue);
|
|
|
|
if (ERROR_SUCCESS == RegQueryValueEx(hkey,
|
|
TEXT("fDenyTSConnections"),
|
|
NULL,
|
|
&dwType,
|
|
(LPBYTE)&dwValue,
|
|
&cbValue))
|
|
|
|
{
|
|
return !dwValue;
|
|
}
|
|
}
|
|
|
|
//
|
|
// could not read registry, this means connections were allowed.
|
|
//
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
BOOL
|
|
IsFastUserSwitchingEnabled(
|
|
VOID)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Checks to see if Terminal Services Fast User Switching is enabled. This is
|
|
to check if we should use the physical console session for UI dialogs, or
|
|
always use session 0.
|
|
|
|
Fast User Switching exists only on workstation product version, where terminal
|
|
services are available, when AllowMultipleTSSessions is set.
|
|
|
|
On server and above, or when multiple TS users are not allowed, session 0
|
|
can only be attached remotely be special request, in which case it should be
|
|
considered the "Console" session.
|
|
|
|
Arguments:
|
|
|
|
None.
|
|
|
|
Return Value:
|
|
|
|
Returns TRUE if Fast User Switching is currently enabled, FALSE otherwise.
|
|
|
|
--*/
|
|
|
|
{
|
|
static BOOL bVerified = FALSE;
|
|
static BOOL bIsTSWorkstation = FALSE;
|
|
|
|
HKEY hKey;
|
|
ULONG ulSize, ulValue;
|
|
BOOL bFusEnabled;
|
|
|
|
//
|
|
// Verify the product version if we haven't already.
|
|
//
|
|
if (!bVerified) {
|
|
OSVERSIONINFOEX osvix;
|
|
DWORDLONG dwlConditionMask = 0;
|
|
|
|
ZeroMemory(&osvix, sizeof(OSVERSIONINFOEX));
|
|
osvix.dwOSVersionInfoSize = sizeof(OSVERSIONINFOEX);
|
|
|
|
osvix.wProductType = VER_NT_WORKSTATION;
|
|
VER_SET_CONDITION(dwlConditionMask, VER_PRODUCT_TYPE, VER_LESS_EQUAL);
|
|
|
|
osvix.wSuiteMask = VER_SUITE_TERMINAL | VER_SUITE_SINGLEUSERTS;
|
|
VER_SET_CONDITION(dwlConditionMask, VER_SUITENAME, VER_OR);
|
|
|
|
if (VerifyVersionInfo(&osvix,
|
|
VER_PRODUCT_TYPE | VER_SUITENAME,
|
|
dwlConditionMask)) {
|
|
bIsTSWorkstation = TRUE;
|
|
}
|
|
|
|
bVerified = TRUE;
|
|
}
|
|
|
|
//
|
|
// Fast user switching (FUS) only applies to the Workstation product where
|
|
// Terminal Services are enabled (i.e. Personal, Professional).
|
|
//
|
|
if (!bIsTSWorkstation) {
|
|
return FALSE;
|
|
}
|
|
|
|
//
|
|
// Check if multiple TS sessions are currently allowed. We can't make this
|
|
// info static because it can change dynamically.
|
|
//
|
|
if (RegOpenKeyEx(HKEY_LOCAL_MACHINE,
|
|
TEXT("SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Winlogon"),
|
|
0,
|
|
KEY_READ,
|
|
&hKey) != ERROR_SUCCESS) {
|
|
return FALSE;
|
|
}
|
|
|
|
ulValue = 0;
|
|
ulSize = sizeof(ulValue);
|
|
bFusEnabled = FALSE;
|
|
|
|
if (RegQueryValueEx(hKey,
|
|
TEXT("AllowMultipleTSSessions"),
|
|
NULL,
|
|
NULL,
|
|
(LPBYTE)&ulValue,
|
|
&ulSize) == ERROR_SUCCESS) {
|
|
bFusEnabled = (ulValue != 0);
|
|
}
|
|
RegCloseKey(hKey);
|
|
|
|
return bFusEnabled;
|
|
|
|
} // IsFastUserSwitchingEnabled
|
|
|
|
|
|
|
|
BOOL
|
|
IsWorkstation(
|
|
VOID)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
Checks if the machine is a workstation.
|
|
|
|
Arguments:
|
|
None
|
|
|
|
Return Value:
|
|
TRUE - is workstation.
|
|
FALSE - is not a workstation.
|
|
|
|
--*/
|
|
{
|
|
|
|
|
|
OSVERSIONINFOEX osvix;
|
|
DWORDLONG dwlConditionMask = 0;
|
|
|
|
ZeroMemory(&osvix, sizeof(OSVERSIONINFOEX));
|
|
osvix.dwOSVersionInfoSize = sizeof(OSVERSIONINFOEX);
|
|
|
|
osvix.wProductType = VER_NT_WORKSTATION;
|
|
VER_SET_CONDITION(dwlConditionMask, VER_PRODUCT_TYPE, VER_LESS_EQUAL);
|
|
|
|
|
|
if (VerifyVersionInfo(&osvix,
|
|
VER_PRODUCT_TYPE,
|
|
dwlConditionMask)) {
|
|
return TRUE;
|
|
}
|
|
return FALSE;
|
|
|
|
|
|
|
|
}
|