/fcp
This commit is contained in:
parent
965110e4b2
commit
f5c5224a26
|
@ -11,6 +11,7 @@ This project adheres to [Semantic Versioning](http://semver.org/).
|
||||||
### Added
|
### Added
|
||||||
- Add option to limit the memory of sandboxed process and the number of process in single sandbox through job object. (thanks Yeyixiao)
|
- Add option to limit the memory of sandboxed process and the number of process in single sandbox through job object. (thanks Yeyixiao)
|
||||||
- Add ability to modified sandboxed process logic speed (reduced fixed latency, modified single-player speed, etc.) (thanks Yeyixiao)
|
- Add ability to modified sandboxed process logic speed (reduced fixed latency, modified single-player speed, etc.) (thanks Yeyixiao)
|
||||||
|
- Added /fcp /force_children commandline option to start.exe it allows to start a program unsandboxed but have all its children sandboxed
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -28,6 +28,7 @@
|
||||||
#include "core/svc/SbieIniWire.h"
|
#include "core/svc/SbieIniWire.h"
|
||||||
#include "common/my_version.h"
|
#include "common/my_version.h"
|
||||||
#include "msgs/msgs.h"
|
#include "msgs/msgs.h"
|
||||||
|
#include "core/drv/api_defs.h"
|
||||||
|
|
||||||
|
|
||||||
//---------------------------------------------------------------------------
|
//---------------------------------------------------------------------------
|
||||||
|
@ -88,6 +89,7 @@ BOOL execute_auto_run = FALSE;
|
||||||
BOOL execute_open_with = FALSE;
|
BOOL execute_open_with = FALSE;
|
||||||
BOOL run_elevated_2 = FALSE;
|
BOOL run_elevated_2 = FALSE;
|
||||||
BOOL disable_force_on_this_program = FALSE;
|
BOOL disable_force_on_this_program = FALSE;
|
||||||
|
BOOL force_children_on_this_program = FALSE;
|
||||||
BOOL auto_select_default_box = FALSE;
|
BOOL auto_select_default_box = FALSE;
|
||||||
WCHAR *StartMenuSectionName = NULL;
|
WCHAR *StartMenuSectionName = NULL;
|
||||||
BOOL run_silent = FALSE;
|
BOOL run_silent = FALSE;
|
||||||
|
@ -716,6 +718,17 @@ BOOL Parse_Command_Line(void)
|
||||||
|
|
||||||
disable_force_on_this_program = TRUE;
|
disable_force_on_this_program = TRUE;
|
||||||
|
|
||||||
|
//
|
||||||
|
// Command line switch /force_children or /fcp
|
||||||
|
//
|
||||||
|
|
||||||
|
} else if (_wcsnicmp(cmd, L"force_children", 14) == 0 ||
|
||||||
|
_wcsnicmp(cmd, L"fcp", 3) == 0) {
|
||||||
|
|
||||||
|
cmd = Eat_String(cmd);
|
||||||
|
|
||||||
|
force_children_on_this_program = TRUE;
|
||||||
|
|
||||||
//
|
//
|
||||||
// Command line switch /hide_window
|
// Command line switch /hide_window
|
||||||
//
|
//
|
||||||
|
@ -1193,7 +1206,7 @@ int Program_Start(void)
|
||||||
shExecInfo.cbSize = sizeof(SHELLEXECUTEINFO);
|
shExecInfo.cbSize = sizeof(SHELLEXECUTEINFO);
|
||||||
shExecInfo.fMask = SEE_MASK_FLAG_NO_UI | SEE_MASK_DOENVSUBST
|
shExecInfo.fMask = SEE_MASK_FLAG_NO_UI | SEE_MASK_DOENVSUBST
|
||||||
| SEE_MASK_FLAG_DDEWAIT | SEE_MASK_NOZONECHECKS;
|
| SEE_MASK_FLAG_DDEWAIT | SEE_MASK_NOZONECHECKS;
|
||||||
if (wait_for_process || keep_alive)
|
if (wait_for_process || keep_alive || force_children_on_this_program)
|
||||||
shExecInfo.fMask |= SEE_MASK_NOCLOSEPROCESS;
|
shExecInfo.fMask |= SEE_MASK_NOCLOSEPROCESS;
|
||||||
shExecInfo.hwnd = NULL;
|
shExecInfo.hwnd = NULL;
|
||||||
shExecInfo.lpVerb = NULL;
|
shExecInfo.lpVerb = NULL;
|
||||||
|
@ -1337,6 +1350,8 @@ int Program_Start(void)
|
||||||
|
|
||||||
if (ok && (wait_for_process || keep_alive))
|
if (ok && (wait_for_process || keep_alive))
|
||||||
hNewProcess = shExecInfo.hProcess;
|
hNewProcess = shExecInfo.hProcess;
|
||||||
|
else if(ok && force_children_on_this_program)
|
||||||
|
pi.dwProcessId = GetProcessId(shExecInfo.hProcess);
|
||||||
|
|
||||||
if (! ok) {
|
if (! ok) {
|
||||||
|
|
||||||
|
@ -1364,9 +1379,16 @@ int Program_Start(void)
|
||||||
// we know for sure that SandboxieRpcSs has opened it
|
// we know for sure that SandboxieRpcSs has opened it
|
||||||
//
|
//
|
||||||
|
|
||||||
if (ok && (! disable_force_on_this_program)) {
|
if (ok) {
|
||||||
|
|
||||||
SbieDll_StartCOM(FALSE);
|
if (force_children_on_this_program) {
|
||||||
|
|
||||||
|
SbieApi_Call(API_FORCE_CHILDREN, 2, pi.dwProcessId, BoxName);
|
||||||
|
|
||||||
|
} else if (!disable_force_on_this_program) {
|
||||||
|
|
||||||
|
SbieDll_StartCOM(FALSE);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//
|
//
|
||||||
|
@ -1395,7 +1417,9 @@ int Program_Start(void)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
} else if (GetModuleHandle(L"protect.dll")) {
|
}
|
||||||
|
// $Workaround$ - 3rd party fix
|
||||||
|
else if (GetModuleHandle(L"protect.dll")) {
|
||||||
|
|
||||||
//
|
//
|
||||||
// hack for FortKnox firewall -- keep Start.exe around for a few
|
// hack for FortKnox firewall -- keep Start.exe around for a few
|
||||||
|
@ -1833,8 +1857,9 @@ int __stdcall WinMainCRTStartup(
|
||||||
|
|
||||||
ULONG NewState = DISABLE_JUST_THIS_PROCESS;
|
ULONG NewState = DISABLE_JUST_THIS_PROCESS;
|
||||||
SbieApi_DisableForceProcess(&NewState, NULL);
|
SbieApi_DisableForceProcess(&NewState, NULL);
|
||||||
return die(Program_Start());
|
|
||||||
}
|
}
|
||||||
|
if (disable_force_on_this_program || force_children_on_this_program)
|
||||||
|
return die(Program_Start());
|
||||||
}
|
}
|
||||||
|
|
||||||
return die(RestartInSandbox());
|
return die(RestartInSandbox());
|
||||||
|
|
|
@ -162,6 +162,7 @@ enum {
|
||||||
API_PROTECT_ROOT,
|
API_PROTECT_ROOT,
|
||||||
API_UNPROTECT_ROOT,
|
API_UNPROTECT_ROOT,
|
||||||
API_KILL_PROCESS,
|
API_KILL_PROCESS,
|
||||||
|
API_FORCE_CHILDREN,
|
||||||
|
|
||||||
API_LAST
|
API_LAST
|
||||||
};
|
};
|
||||||
|
|
|
@ -101,9 +101,11 @@ static NTSTATUS Process_CreateUserProcess(
|
||||||
#ifdef USE_PROCESS_MAP
|
#ifdef USE_PROCESS_MAP
|
||||||
HASH_MAP Process_Map;
|
HASH_MAP Process_Map;
|
||||||
HASH_MAP Process_MapDfp;
|
HASH_MAP Process_MapDfp;
|
||||||
|
HASH_MAP Process_MapFcp;
|
||||||
#else
|
#else
|
||||||
LIST Process_List;
|
LIST Process_List;
|
||||||
LIST Process_ListDfp;
|
LIST Process_ListDfp;
|
||||||
|
LIST Process_ListFcp;
|
||||||
#endif
|
#endif
|
||||||
PERESOURCE Process_ListLock = NULL;
|
PERESOURCE Process_ListLock = NULL;
|
||||||
|
|
||||||
|
@ -136,9 +138,13 @@ _FX BOOLEAN Process_Init(void)
|
||||||
|
|
||||||
map_init(&Process_MapDfp, Driver_Pool);
|
map_init(&Process_MapDfp, Driver_Pool);
|
||||||
map_resize(&Process_MapDfp, 128); // prepare some buckets for better performance
|
map_resize(&Process_MapDfp, 128); // prepare some buckets for better performance
|
||||||
|
|
||||||
|
map_init(&Process_MapFcp, Driver_Pool);
|
||||||
|
map_resize(&Process_MapFcp, 128); // prepare some buckets for better performance
|
||||||
#else
|
#else
|
||||||
List_Init(&Process_List);
|
List_Init(&Process_List);
|
||||||
List_Init(&Process_ListDfp);
|
List_Init(&Process_ListDfp);
|
||||||
|
List_Init(&Process_ListFcp);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
if (! Mem_GetLockResource(&Process_ListLock, TRUE))
|
if (! Mem_GetLockResource(&Process_ListLock, TRUE))
|
||||||
|
@ -1537,6 +1543,8 @@ _FX void Process_Delete(HANDLE ProcessId)
|
||||||
|
|
||||||
Process_DfpDelete(ProcessId);
|
Process_DfpDelete(ProcessId);
|
||||||
|
|
||||||
|
Process_FcpDelete(ProcessId);
|
||||||
|
|
||||||
ExReleaseResourceLite(Process_ListLock);
|
ExReleaseResourceLite(Process_ListLock);
|
||||||
KeLowerIrql(irql);
|
KeLowerIrql(irql);
|
||||||
|
|
||||||
|
|
|
@ -447,6 +447,11 @@ void Process_DfpDelete(HANDLE ProcessId);
|
||||||
|
|
||||||
BOOLEAN Process_DfpCheck(HANDLE ProcessId, BOOLEAN *silent);
|
BOOLEAN Process_DfpCheck(HANDLE ProcessId, BOOLEAN *silent);
|
||||||
|
|
||||||
|
// Force Child Processes
|
||||||
|
|
||||||
|
VOID Process_FcpInsert(HANDLE ProcessId, const WCHAR* boxname);
|
||||||
|
void Process_FcpDelete(HANDLE ProcessId);
|
||||||
|
BOOLEAN Process_FcpCheck(HANDLE ProcessId, WCHAR* boxname);
|
||||||
|
|
||||||
// Enumerate or count processes in a sandbox
|
// Enumerate or count processes in a sandbox
|
||||||
|
|
||||||
|
@ -533,9 +538,11 @@ NTSTATUS Process_Api_Kill(PROCESS *proc, ULONG64 *parms);
|
||||||
#ifdef USE_PROCESS_MAP
|
#ifdef USE_PROCESS_MAP
|
||||||
extern HASH_MAP Process_Map;
|
extern HASH_MAP Process_Map;
|
||||||
extern HASH_MAP Process_MapDfp;
|
extern HASH_MAP Process_MapDfp;
|
||||||
|
extern HASH_MAP Process_MapFcp;
|
||||||
#else
|
#else
|
||||||
extern LIST Process_List;
|
extern LIST Process_List;
|
||||||
extern LIST Process_ListDfp;
|
extern LIST Process_ListDfp;
|
||||||
|
extern LIST Process_ListFcp;
|
||||||
#endif
|
#endif
|
||||||
extern PERESOURCE Process_ListLock;
|
extern PERESOURCE Process_ListLock;
|
||||||
|
|
||||||
|
|
|
@ -79,6 +79,16 @@ typedef struct _FORCE_PROCESS_2 {
|
||||||
} FORCE_PROCESS_2;
|
} FORCE_PROCESS_2;
|
||||||
|
|
||||||
|
|
||||||
|
typedef struct _FORCE_PROCESS_3 {
|
||||||
|
|
||||||
|
#ifndef USE_PROCESS_MAP
|
||||||
|
LIST_ELEM list_elem;
|
||||||
|
#endif
|
||||||
|
HANDLE pid;
|
||||||
|
WCHAR boxname[BOXNAME_COUNT];
|
||||||
|
|
||||||
|
} FORCE_PROCESS_3;
|
||||||
|
|
||||||
//---------------------------------------------------------------------------
|
//---------------------------------------------------------------------------
|
||||||
// Functions
|
// Functions
|
||||||
//---------------------------------------------------------------------------
|
//---------------------------------------------------------------------------
|
||||||
|
@ -274,6 +284,23 @@ _FX BOX *Process_GetForcedStartBox(
|
||||||
Process_DfpInsert(PROCESS_TERMINATED, ProcessId);
|
Process_DfpInsert(PROCESS_TERMINATED, ProcessId);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!box) {
|
||||||
|
|
||||||
|
WCHAR boxname[BOXNAME_COUNT];
|
||||||
|
|
||||||
|
if (Process_FcpCheck(ParentId, boxname)) {
|
||||||
|
|
||||||
|
ULONG boxname_len = (wcslen(boxname) + 1) * sizeof(WCHAR);
|
||||||
|
for (FORCE_BOX* cur_box = List_Head(&boxes); cur_box; cur_box = List_Next(cur_box)) {
|
||||||
|
if (cur_box->box->name_len == boxname_len
|
||||||
|
&& _wcsicmp(cur_box->box->name, boxname) == 0) {
|
||||||
|
box = cur_box->box;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (alert != 1)
|
if (alert != 1)
|
||||||
force_alert = FALSE;
|
force_alert = FALSE;
|
||||||
|
|
||||||
|
@ -794,7 +821,6 @@ _FX BOOLEAN Process_IsProcessParent(HANDLE ParentId, WCHAR* Name)
|
||||||
|
|
||||||
_FX BOOLEAN Process_IsWindowsExplorerParent(HANDLE ParentId)
|
_FX BOOLEAN Process_IsWindowsExplorerParent(HANDLE ParentId)
|
||||||
{
|
{
|
||||||
|
|
||||||
return Process_IsProcessParent(ParentId,L"explorer.exe");
|
return Process_IsProcessParent(ParentId,L"explorer.exe");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1399,10 +1425,12 @@ _FX BOX *Process_CheckForceProcess(
|
||||||
|
|
||||||
return box->box;
|
return box->box;
|
||||||
}
|
}
|
||||||
//if (Process_IsWindowsExplorerParent(ParentId) && Conf_Get_Boolean(box->box->name, L"ForceExplorerChild", FALSE)) {
|
|
||||||
|
//if (Process_IsWindowsExplorerParent(ParentId) && Conf_Get_Boolean(box->box->name, L"ForceExplorerChild", 0, FALSE)) {
|
||||||
// if(_wcsicmp(name,L"Sandman.exe")!=0)
|
// if(_wcsicmp(name,L"Sandman.exe")!=0)
|
||||||
// return box->box;
|
// return box->box;
|
||||||
//}
|
//}
|
||||||
|
|
||||||
box = List_Next(box);
|
box = List_Next(box);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1758,3 +1786,112 @@ _FX BOOLEAN Process_DfpCheck(HANDLE ProcessId, BOOLEAN *silent)
|
||||||
|
|
||||||
return found;
|
return found;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//---------------------------------------------------------------------------
|
||||||
|
// Process_FcpInsert
|
||||||
|
//---------------------------------------------------------------------------
|
||||||
|
|
||||||
|
|
||||||
|
_FX VOID Process_FcpInsert(HANDLE ProcessId, const WCHAR* boxname)
|
||||||
|
{
|
||||||
|
FORCE_PROCESS_3 *proc;
|
||||||
|
KIRQL irql;
|
||||||
|
|
||||||
|
//
|
||||||
|
// called by Session_Api_ForceChildren, process list not locked
|
||||||
|
//
|
||||||
|
|
||||||
|
KeRaiseIrql(APC_LEVEL, &irql);
|
||||||
|
ExAcquireResourceExclusiveLite(Process_ListLock, TRUE);
|
||||||
|
|
||||||
|
Process_FcpDelete(ProcessId);
|
||||||
|
|
||||||
|
proc = Mem_Alloc(Driver_Pool, sizeof(FORCE_PROCESS_3));
|
||||||
|
proc->pid = ProcessId;
|
||||||
|
wmemcpy(proc->boxname, boxname, BOXNAME_COUNT);
|
||||||
|
|
||||||
|
#ifdef USE_PROCESS_MAP
|
||||||
|
map_insert(&Process_MapFcp, ProcessId, proc, 0);
|
||||||
|
#else
|
||||||
|
List_Insert_After(&Process_ListFcp, NULL, proc);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
ExReleaseResourceLite(Process_ListLock);
|
||||||
|
KeLowerIrql(irql);
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//---------------------------------------------------------------------------
|
||||||
|
// Process_FcpDelete
|
||||||
|
//---------------------------------------------------------------------------
|
||||||
|
|
||||||
|
|
||||||
|
_FX void Process_FcpDelete(HANDLE ProcessId)
|
||||||
|
{
|
||||||
|
FORCE_PROCESS_3 *proc;
|
||||||
|
|
||||||
|
#ifdef USE_PROCESS_MAP
|
||||||
|
if(map_take(&Process_MapFcp, ProcessId, &proc, 0))
|
||||||
|
Mem_Free(proc, sizeof(FORCE_PROCESS_3));
|
||||||
|
#else
|
||||||
|
proc = List_Head(&Process_ListFcp);
|
||||||
|
while (proc) {
|
||||||
|
|
||||||
|
if (proc->pid == ProcessId) {
|
||||||
|
|
||||||
|
List_Remove(&Process_ListFcp, proc);
|
||||||
|
|
||||||
|
Mem_Free(proc, sizeof(FORCE_PROCESS_3));
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
proc = List_Next(proc);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//---------------------------------------------------------------------------
|
||||||
|
// Process_FcpCheck
|
||||||
|
//---------------------------------------------------------------------------
|
||||||
|
|
||||||
|
|
||||||
|
_FX BOOLEAN Process_FcpCheck(HANDLE ProcessId, WCHAR* boxname)
|
||||||
|
{
|
||||||
|
FORCE_PROCESS_3 *proc;
|
||||||
|
KIRQL irql;
|
||||||
|
BOOLEAN found = FALSE;
|
||||||
|
|
||||||
|
KeRaiseIrql(APC_LEVEL, &irql);
|
||||||
|
ExAcquireResourceExclusiveLite(Process_ListLock, TRUE);
|
||||||
|
|
||||||
|
#ifdef USE_PROCESS_MAP
|
||||||
|
proc = map_get(&Process_MapFcp, ProcessId);
|
||||||
|
if (proc) {
|
||||||
|
#else
|
||||||
|
proc = List_Head(&Process_ListFcp);
|
||||||
|
while (proc) {
|
||||||
|
|
||||||
|
if (proc->pid == ProcessId) {
|
||||||
|
#endif
|
||||||
|
if(boxname)
|
||||||
|
wmemcpy(boxname, proc->boxname, BOXNAME_COUNT);
|
||||||
|
|
||||||
|
found = TRUE;
|
||||||
|
#ifndef USE_PROCESS_MAP
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
proc = List_Next(proc);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
ExReleaseResourceLite(Process_ListLock);
|
||||||
|
KeLowerIrql(irql);
|
||||||
|
|
||||||
|
return found;
|
||||||
|
}
|
|
@ -104,6 +104,8 @@ static NTSTATUS Session_Api_Leader(PROCESS *proc, ULONG64 *parms);
|
||||||
|
|
||||||
static NTSTATUS Session_Api_DisableForce(PROCESS *proc, ULONG64 *parms);
|
static NTSTATUS Session_Api_DisableForce(PROCESS *proc, ULONG64 *parms);
|
||||||
|
|
||||||
|
static NTSTATUS Session_Api_ForceChildren(PROCESS *proc, ULONG64 *parms);
|
||||||
|
|
||||||
static NTSTATUS Session_Api_MonitorControl(PROCESS *proc, ULONG64 *parms);
|
static NTSTATUS Session_Api_MonitorControl(PROCESS *proc, ULONG64 *parms);
|
||||||
|
|
||||||
//static NTSTATUS Session_Api_MonitorPut(PROCESS *proc, ULONG64 *parms);
|
//static NTSTATUS Session_Api_MonitorPut(PROCESS *proc, ULONG64 *parms);
|
||||||
|
@ -141,6 +143,7 @@ _FX BOOLEAN Session_Init(void)
|
||||||
|
|
||||||
Api_SetFunction(API_SESSION_LEADER, Session_Api_Leader);
|
Api_SetFunction(API_SESSION_LEADER, Session_Api_Leader);
|
||||||
Api_SetFunction(API_DISABLE_FORCE_PROCESS, Session_Api_DisableForce);
|
Api_SetFunction(API_DISABLE_FORCE_PROCESS, Session_Api_DisableForce);
|
||||||
|
Api_SetFunction(API_FORCE_CHILDREN, Session_Api_ForceChildren);
|
||||||
Api_SetFunction(API_MONITOR_CONTROL, Session_Api_MonitorControl);
|
Api_SetFunction(API_MONITOR_CONTROL, Session_Api_MonitorControl);
|
||||||
//Api_SetFunction(API_MONITOR_PUT, Session_Api_MonitorPut);
|
//Api_SetFunction(API_MONITOR_PUT, Session_Api_MonitorPut);
|
||||||
Api_SetFunction(API_MONITOR_PUT2, Session_Api_MonitorPut2);
|
Api_SetFunction(API_MONITOR_PUT2, Session_Api_MonitorPut2);
|
||||||
|
@ -496,6 +499,38 @@ _FX BOOLEAN Session_IsForceDisabled(ULONG SessionId)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//---------------------------------------------------------------------------
|
||||||
|
// Session_Api_ForceChildren
|
||||||
|
//---------------------------------------------------------------------------
|
||||||
|
|
||||||
|
|
||||||
|
_FX NTSTATUS Session_Api_ForceChildren(PROCESS *proc, ULONG64 *parms)
|
||||||
|
{
|
||||||
|
HANDLE process_id;
|
||||||
|
WCHAR *user_boxname;
|
||||||
|
WCHAR boxname[BOXNAME_COUNT];
|
||||||
|
|
||||||
|
if (proc)
|
||||||
|
return STATUS_NOT_IMPLEMENTED;
|
||||||
|
|
||||||
|
process_id = (HANDLE)parms[1];
|
||||||
|
|
||||||
|
memzero(boxname, sizeof(boxname));
|
||||||
|
user_boxname = (WCHAR *)parms[2];
|
||||||
|
if (user_boxname) {
|
||||||
|
ProbeForRead(user_boxname, sizeof(WCHAR) * (BOXNAME_COUNT - 2), sizeof(UCHAR));
|
||||||
|
if (user_boxname[0])
|
||||||
|
wcsncpy(boxname, user_boxname, (BOXNAME_COUNT - 2));
|
||||||
|
}
|
||||||
|
if(!process_id || process_id == (HANDLE)-1 || !boxname[0])
|
||||||
|
return STATUS_INVALID_PARAMETER;
|
||||||
|
|
||||||
|
Process_FcpInsert(process_id, boxname);
|
||||||
|
|
||||||
|
return STATUS_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
//---------------------------------------------------------------------------
|
//---------------------------------------------------------------------------
|
||||||
// Session_IsLeader
|
// Session_IsLeader
|
||||||
//---------------------------------------------------------------------------
|
//---------------------------------------------------------------------------
|
||||||
|
|
Loading…
Reference in New Issue