diff --git a/MeshCentralServer.njsproj b/MeshCentralServer.njsproj index 3f50007e..d2d0cf3f 100644 --- a/MeshCentralServer.njsproj +++ b/MeshCentralServer.njsproj @@ -271,20 +271,17 @@ + + - - - - - diff --git a/agents/MeshCmd-signed.exe b/agents/MeshCmd-signed.exe index e2a53826..fab6f6fb 100644 Binary files a/agents/MeshCmd-signed.exe and b/agents/MeshCmd-signed.exe differ diff --git a/agents/MeshCmd64-signed.exe b/agents/MeshCmd64-signed.exe index 9f2e6505..3c0f7ddb 100644 Binary files a/agents/MeshCmd64-signed.exe and b/agents/MeshCmd64-signed.exe differ diff --git a/agents/meshcmd.js b/agents/meshcmd.js index 3dfb676d..01e82364 100644 --- a/agents/meshcmd.js +++ b/agents/meshcmd.js @@ -141,6 +141,7 @@ function run(argv) { if ((typeof args.serverid) == 'string') { settings.serverid = args.serverid; } if ((typeof args.serverhttpshash) == 'string') { settings.serverhttpshash = args.serverhttpshash; } if ((typeof args.remoteport) == 'string') { settings.remoteport = parseInt(args.remoteport); } + if ((typeof args.remotetarget) == 'string') { settings.remotetarget = args.remotetarget; } if ((typeof args.out) == 'string') { settings.output = args.out; } if ((typeof args.output) == 'string') { settings.output = args.output; } if ((typeof args.debug) == 'string') { settings.debuglevel = parseInt(args.debug); } @@ -2049,10 +2050,10 @@ function startRouter() { tcpserver.on('error', function (e) { console.log('ERROR: ' + JSON.stringify(e)); exit(0); return; }); tcpserver.listen(settings.localport, function () { // We started listening. - if (settings.remotename == null) { + if (settings.remotetarget == null) { console.log('Redirecting local port ' + settings.localport + ' to remote port ' + settings.remoteport + '.'); } else { - console.log('Redirecting local port ' + settings.localport + ' to ' + settings.remotename + ':' + settings.remoteport + '.'); + console.log('Redirecting local port ' + settings.localport + ' to ' + settings.remotetarget + ':' + settings.remoteport + '.'); } console.log('Press ctrl-c to exit.'); @@ -2069,7 +2070,7 @@ function OnTcpClientConnected(c) { c.on('end', function () { disconnectTunnel(this, this.websocket, 'Client closed'); }); c.pause(); try { - options = http.parseUri(settings.serverurl + '?user=' + settings.username + '&pass=' + settings.password + '&nodeid=' + settings.remotenodeid + '&tcpport=' + settings.remoteport); + options = http.parseUri(settings.serverurl + '?user=' + settings.username + '&pass=' + settings.password + '&nodeid=' + settings.remotenodeid + '&tcpport=' + settings.remoteport + (settings.remotetarget == null ? '' : '&tcpaddr=' + settings.remotetarget)); } catch (e) { console.log('Unable to parse \"serverUrl\".'); process.exit(1); return; } options.checkServerIdentity = onVerifyServer; options.rejectUnauthorized = false; @@ -2564,46 +2565,53 @@ function removeItemFromArray(array, element) { } // Run MeshCmd, but before we do, we need to see if what type of service we are going to be -var serviceName = null; -var serviceOpSpecified = 0; -var serviceInstall = 0; - +var serviceName = null, serviceDisplayName = null, serviceDesc = null; for (var i in process.argv) { - if (process.argv[i].toLowerCase() == 'install') { serviceInstall = 1 } else if (process.argv[i].toLowerCase() == 'uninstall') { serviceInstall = -1 } - if ((process.argv[i].toLowerCase() == 'microlms') || (process.argv[i].toLowerCase() == 'amtlms') || (process.argv[i].toLowerCase() == 'lms')) { serviceName = 'MicroLMS'; break; } - if ((process.argv[i].toLowerCase() == 'meshcommander') || (process.argv[i].toLowerCase() == 'commander')) { serviceName = 'MeshCommander'; break; } + if (process.argv[i].toLowerCase() == 'install') { process.argv[i] = '-install'; } + if (process.argv[i].toLowerCase() == 'uninstall') { process.argv[i] = '-uninstall'; } + if ((process.argv[i].toLowerCase() == 'microlms') || (process.argv[i].toLowerCase() == 'amtlms') || (process.argv[i].toLowerCase() == 'lms')) { + serviceName = 'MicroLMS'; + serviceDisplayName = 'MicroLMS Service for Intel(R) AMT'; + serviceDesc = 'Intel AMT Micro Local Manageability Service (MicroLMS)'; + } else if ((process.argv[i].toLowerCase() == 'intellms')) { + serviceName = 'LMS'; + serviceDisplayName = 'Intel(R) Management and Security Application Local Management Service'; + serviceDesc = 'Intel(R) Management and Security Application Local Management Service - Provides OS-related Intel(R) ME functionality.'; + } else if ((process.argv[i].toLowerCase() == 'meshcommander') || (process.argv[i].toLowerCase() == 'commander')) { + serviceName = 'MeshCommander'; + serviceDisplayName = 'MeshCommander, Intel AMT Management console'; + serviceDesc = 'MeshCommander is a Intel AMT management console.'; + } } if (serviceName == null) { - for (var i in process.argv) { - if ((process.argv[i].toLowerCase() == 'install') || (process.argv[i].toLowerCase() == 'uninstall')) { - console.log('In order to install/uninstall, a service type must be specified.'); - process.exit(); - } - } if (process.execPath.includes('MicroLMS')) { serviceName = 'MicroLMS'; } + else if (process.execPath.includes('LMS')) { serviceName = 'LMS'; } else if (process.execPath.includes('MeshCommander')) { serviceName = 'MeshCommander'; } - else { serviceName = 'not_a_service'; } + if (serviceName == null) { for (var i in process.argv) { if ((process.argv[i].toLowerCase() == '-install') || (process.argv[i].toLowerCase() == '-uninstall')) { console.log('In order to install/uninstall, a service type must be specified.'); process.exit(); } } } + if (serviceName == null) { try { run(process.argv); } catch (e) { console.log('ERROR: ' + e); } process.exit(); } } -if (serviceInstall == 0) { - run(process.argv); -} else { - var serviceHost = require('service-host'); - var meshcmdService = new serviceHost({ name: serviceName, startType: 'AUTO_START' }); +var serviceHost = require('service-host'); +var meshcmdService = new serviceHost({ name: serviceName, displayName: serviceDisplayName, startType: 'AUTO_START', description: serviceDesc }); - // Called when the background service is started. - meshcmdService.on('serviceStart', function onStart() { - console.setDestination(console.Destinations.DISABLED); // Disable console.log(). - if (process.execPath.includes('MicroLMS')) { run([process.execPath, 'microlms']); } // - else if (process.execPath.includes('MeshCommander')) { run([process.execPath, 'meshcommander']); } - else { console.log('Aborting Service Start, because unknown binary: ' + process.execPath); process.exit(1); } - }); +// Called when the background service is started. +meshcmdService.on('serviceStart', function onStart() { + //process.coreDumpLocation = 'C:\\tmp\\meshcommander.dmp'; + //process.on('exit', function () { console.log('exit3'); _debugCrash(); }); + console.setDestination(console.Destinations.DISABLED); // Disable console.log(). + //console.setDestination(console.Destinations.LOGFILE); + //attachDebuger({ webport: 0, wait: 1 }).then(console.log, console.log); - // Called when the background service is stopping - meshcmdService.on('serviceStop', function onStop() { console.log('Stopping service'); process.exit(); }); // The console.log() is for debugging, will be ignored unless "console.setDestination()" is set. + if (process.execPath.includes('MicroLMS')) { run([process.execPath, 'microlms']); } // Start MicroLMS + else if (process.execPath.includes('LMS')) { run([process.execPath, 'microlms']); } // Start MicroLMS + else if (process.execPath.includes('MeshCommander')) { run([process.execPath, 'meshcommander']); } // Start MeshCommander + else { console.log('Aborting Service Start, because unknown binary: ' + process.execPath); process.exit(1); } +}); - // Called when the executable is not running as a service, run normally. - meshcmdService.on('normalStart', function onNormalStart() { try { run(process.argv); } catch (e) { console.log('ERROR: ' + e); } }); - meshcmdService.run(); -} +// Called when the background service is stopping +meshcmdService.on('serviceStop', function onStop() { console.log('Stopping service'); process.exit(); }); // The console.log() is for debugging, will be ignored unless "console.setDestination()" is set. + +// Called when the executable is not running as a service, run normally. +meshcmdService.on('normalStart', function onNormalStart() { try { run(process.argv); } catch (e) { console.log('ERROR: ' + e); } }); +meshcmdService.run(); diff --git a/agents/meshcmd.min.js b/agents/meshcmd.min.js index 3dfb676d..01e82364 100644 --- a/agents/meshcmd.min.js +++ b/agents/meshcmd.min.js @@ -141,6 +141,7 @@ function run(argv) { if ((typeof args.serverid) == 'string') { settings.serverid = args.serverid; } if ((typeof args.serverhttpshash) == 'string') { settings.serverhttpshash = args.serverhttpshash; } if ((typeof args.remoteport) == 'string') { settings.remoteport = parseInt(args.remoteport); } + if ((typeof args.remotetarget) == 'string') { settings.remotetarget = args.remotetarget; } if ((typeof args.out) == 'string') { settings.output = args.out; } if ((typeof args.output) == 'string') { settings.output = args.output; } if ((typeof args.debug) == 'string') { settings.debuglevel = parseInt(args.debug); } @@ -2049,10 +2050,10 @@ function startRouter() { tcpserver.on('error', function (e) { console.log('ERROR: ' + JSON.stringify(e)); exit(0); return; }); tcpserver.listen(settings.localport, function () { // We started listening. - if (settings.remotename == null) { + if (settings.remotetarget == null) { console.log('Redirecting local port ' + settings.localport + ' to remote port ' + settings.remoteport + '.'); } else { - console.log('Redirecting local port ' + settings.localport + ' to ' + settings.remotename + ':' + settings.remoteport + '.'); + console.log('Redirecting local port ' + settings.localport + ' to ' + settings.remotetarget + ':' + settings.remoteport + '.'); } console.log('Press ctrl-c to exit.'); @@ -2069,7 +2070,7 @@ function OnTcpClientConnected(c) { c.on('end', function () { disconnectTunnel(this, this.websocket, 'Client closed'); }); c.pause(); try { - options = http.parseUri(settings.serverurl + '?user=' + settings.username + '&pass=' + settings.password + '&nodeid=' + settings.remotenodeid + '&tcpport=' + settings.remoteport); + options = http.parseUri(settings.serverurl + '?user=' + settings.username + '&pass=' + settings.password + '&nodeid=' + settings.remotenodeid + '&tcpport=' + settings.remoteport + (settings.remotetarget == null ? '' : '&tcpaddr=' + settings.remotetarget)); } catch (e) { console.log('Unable to parse \"serverUrl\".'); process.exit(1); return; } options.checkServerIdentity = onVerifyServer; options.rejectUnauthorized = false; @@ -2564,46 +2565,53 @@ function removeItemFromArray(array, element) { } // Run MeshCmd, but before we do, we need to see if what type of service we are going to be -var serviceName = null; -var serviceOpSpecified = 0; -var serviceInstall = 0; - +var serviceName = null, serviceDisplayName = null, serviceDesc = null; for (var i in process.argv) { - if (process.argv[i].toLowerCase() == 'install') { serviceInstall = 1 } else if (process.argv[i].toLowerCase() == 'uninstall') { serviceInstall = -1 } - if ((process.argv[i].toLowerCase() == 'microlms') || (process.argv[i].toLowerCase() == 'amtlms') || (process.argv[i].toLowerCase() == 'lms')) { serviceName = 'MicroLMS'; break; } - if ((process.argv[i].toLowerCase() == 'meshcommander') || (process.argv[i].toLowerCase() == 'commander')) { serviceName = 'MeshCommander'; break; } + if (process.argv[i].toLowerCase() == 'install') { process.argv[i] = '-install'; } + if (process.argv[i].toLowerCase() == 'uninstall') { process.argv[i] = '-uninstall'; } + if ((process.argv[i].toLowerCase() == 'microlms') || (process.argv[i].toLowerCase() == 'amtlms') || (process.argv[i].toLowerCase() == 'lms')) { + serviceName = 'MicroLMS'; + serviceDisplayName = 'MicroLMS Service for Intel(R) AMT'; + serviceDesc = 'Intel AMT Micro Local Manageability Service (MicroLMS)'; + } else if ((process.argv[i].toLowerCase() == 'intellms')) { + serviceName = 'LMS'; + serviceDisplayName = 'Intel(R) Management and Security Application Local Management Service'; + serviceDesc = 'Intel(R) Management and Security Application Local Management Service - Provides OS-related Intel(R) ME functionality.'; + } else if ((process.argv[i].toLowerCase() == 'meshcommander') || (process.argv[i].toLowerCase() == 'commander')) { + serviceName = 'MeshCommander'; + serviceDisplayName = 'MeshCommander, Intel AMT Management console'; + serviceDesc = 'MeshCommander is a Intel AMT management console.'; + } } if (serviceName == null) { - for (var i in process.argv) { - if ((process.argv[i].toLowerCase() == 'install') || (process.argv[i].toLowerCase() == 'uninstall')) { - console.log('In order to install/uninstall, a service type must be specified.'); - process.exit(); - } - } if (process.execPath.includes('MicroLMS')) { serviceName = 'MicroLMS'; } + else if (process.execPath.includes('LMS')) { serviceName = 'LMS'; } else if (process.execPath.includes('MeshCommander')) { serviceName = 'MeshCommander'; } - else { serviceName = 'not_a_service'; } + if (serviceName == null) { for (var i in process.argv) { if ((process.argv[i].toLowerCase() == '-install') || (process.argv[i].toLowerCase() == '-uninstall')) { console.log('In order to install/uninstall, a service type must be specified.'); process.exit(); } } } + if (serviceName == null) { try { run(process.argv); } catch (e) { console.log('ERROR: ' + e); } process.exit(); } } -if (serviceInstall == 0) { - run(process.argv); -} else { - var serviceHost = require('service-host'); - var meshcmdService = new serviceHost({ name: serviceName, startType: 'AUTO_START' }); +var serviceHost = require('service-host'); +var meshcmdService = new serviceHost({ name: serviceName, displayName: serviceDisplayName, startType: 'AUTO_START', description: serviceDesc }); - // Called when the background service is started. - meshcmdService.on('serviceStart', function onStart() { - console.setDestination(console.Destinations.DISABLED); // Disable console.log(). - if (process.execPath.includes('MicroLMS')) { run([process.execPath, 'microlms']); } // - else if (process.execPath.includes('MeshCommander')) { run([process.execPath, 'meshcommander']); } - else { console.log('Aborting Service Start, because unknown binary: ' + process.execPath); process.exit(1); } - }); +// Called when the background service is started. +meshcmdService.on('serviceStart', function onStart() { + //process.coreDumpLocation = 'C:\\tmp\\meshcommander.dmp'; + //process.on('exit', function () { console.log('exit3'); _debugCrash(); }); + console.setDestination(console.Destinations.DISABLED); // Disable console.log(). + //console.setDestination(console.Destinations.LOGFILE); + //attachDebuger({ webport: 0, wait: 1 }).then(console.log, console.log); - // Called when the background service is stopping - meshcmdService.on('serviceStop', function onStop() { console.log('Stopping service'); process.exit(); }); // The console.log() is for debugging, will be ignored unless "console.setDestination()" is set. + if (process.execPath.includes('MicroLMS')) { run([process.execPath, 'microlms']); } // Start MicroLMS + else if (process.execPath.includes('LMS')) { run([process.execPath, 'microlms']); } // Start MicroLMS + else if (process.execPath.includes('MeshCommander')) { run([process.execPath, 'meshcommander']); } // Start MeshCommander + else { console.log('Aborting Service Start, because unknown binary: ' + process.execPath); process.exit(1); } +}); - // Called when the executable is not running as a service, run normally. - meshcmdService.on('normalStart', function onNormalStart() { try { run(process.argv); } catch (e) { console.log('ERROR: ' + e); } }); - meshcmdService.run(); -} +// Called when the background service is stopping +meshcmdService.on('serviceStop', function onStop() { console.log('Stopping service'); process.exit(); }); // The console.log() is for debugging, will be ignored unless "console.setDestination()" is set. + +// Called when the executable is not running as a service, run normally. +meshcmdService.on('normalStart', function onNormalStart() { try { run(process.argv); } catch (e) { console.log('ERROR: ' + e); } }); +meshcmdService.run(); diff --git a/agents/meshcore.js b/agents/meshcore.js index de3d377b..7800b72f 100644 --- a/agents/meshcore.js +++ b/agents/meshcore.js @@ -754,6 +754,15 @@ function createMeshCore(agent) { for (var i in data.macs) { sendWakeOnLan(data.macs[i]); } break; } + case 'uninstallagent': + // Uninstall this agent + var agentName = process.platform == 'win32' ? 'Mesh Agent' : 'meshagent'; + if (require('service-manager').manager.getService(agentName).isMe()) { + try { diagnosticAgent_uninstall(); } catch (x) { } + var js = "require('service-manager').manager.getService('" + agentName + "').stop(); require('service-manager').manager.uninstallService('" + agentName + "'); process.exit();"; + this.child = require('child_process').execFile(process.execPath, [process.platform == 'win32' ? (process.execPath.split('\\').pop()) : (process.execPath.split('/').pop()), '-b64exec', Buffer.from(js).toString('base64')], { type: 4, detached: true }); + } + break; case 'poweraction': { // Server telling us to execute a power action if ((mesh.ExecPowerState != undefined) && (data.actiontype)) { @@ -810,15 +819,7 @@ function createMeshCore(agent) { case 'ping': { mesh.SendCommand('{"action":"pong"}'); break; } case 'pong': { break; } case 'plugin': { - if (typeof data.pluginaction == 'string') { - try { - MeshServerLog('Plugin called', data); - // Not yet implemented - // require(data.plugin.name).serveraction(data); - } catch (e) { - MeshServerLog('Error calling plugin', data); - } - } + try { require(data.plugin).consoleaction(data, data.rights, data.sessionid, this); } catch (e) { throw e; } break; } default: @@ -1998,17 +1999,12 @@ function createMeshCore(agent) { } break; } - case 'uninstallagent': + case 'uninstallagent': // Uninstall this agent var agentName = process.platform == 'win32' ? 'Mesh Agent' : 'meshagent'; if (!require('service-manager').manager.getService(agentName).isMe()) { response = 'Uininstall failed, this instance is not the service instance'; - } - else { - try { - diagnosticAgent_uninstall(); - } - catch (x) { - } + } else { + try { diagnosticAgent_uninstall(); } catch (x) { } var js = "require('service-manager').manager.getService('" + agentName + "').stop(); require('service-manager').manager.uninstallService('" + agentName + "'); process.exit();"; this.child = require('child_process').execFile(process.execPath, [process.platform == 'win32' ? (process.execPath.split('\\').pop()) : (process.execPath.split('/').pop()), '-b64exec', Buffer.from(js).toString('base64')], { type: 4, detached: true }); } diff --git a/agents/meshcore.min.js b/agents/meshcore.min.js index 4413c3aa..c64e8a59 100644 --- a/agents/meshcore.min.js +++ b/agents/meshcore.min.js @@ -754,6 +754,15 @@ function createMeshCore(agent) { for (var i in data.macs) { sendWakeOnLan(data.macs[i]); } break; } + case 'uninstallagent': + // Uninstall this agent + var agentName = process.platform == 'win32' ? 'Mesh Agent' : 'meshagent'; + if (require('service-manager').manager.getService(agentName).isMe()) { + try { diagnosticAgent_uninstall(); } catch (x) { } + var js = "require('service-manager').manager.getService('" + agentName + "').stop(); require('service-manager').manager.uninstallService('" + agentName + "'); process.exit();"; + this.child = require('child_process').execFile(process.execPath, [process.platform == 'win32' ? (process.execPath.split('\\').pop()) : (process.execPath.split('/').pop()), '-b64exec', Buffer.from(js).toString('base64')], { type: 4, detached: true }); + } + break; case 'poweraction': { // Server telling us to execute a power action if ((mesh.ExecPowerState != undefined) && (data.actiontype)) { @@ -810,15 +819,7 @@ function createMeshCore(agent) { case 'ping': { mesh.SendCommand('{"action":"pong"}'); break; } case 'pong': { break; } case 'plugin': { - if (typeof data.pluginaction == 'string') { - try { - MeshServerLog('Plugin called', data); - // Not yet implemented - // require(data.plugin.name).serveraction(data); - } catch (e) { - MeshServerLog('Error calling plugin', data); - } - } + try { require(data.plugin).consoleaction(data, data.rights, data.sessionid, this); } catch (e) { throw e; } break; } default: @@ -1942,17 +1943,12 @@ function createMeshCore(agent) { } break; } - case 'uninstallagent': + case 'uninstallagent': // Uninstall this agent var agentName = process.platform == 'win32' ? 'Mesh Agent' : 'meshagent'; if (!require('service-manager').manager.getService(agentName).isMe()) { response = 'Uininstall failed, this instance is not the service instance'; - } - else { - try { - diagnosticAgent_uninstall(); - } - catch (x) { - } + } else { + try { diagnosticAgent_uninstall(); } catch (x) { } var js = "require('service-manager').manager.getService('" + agentName + "').stop(); require('service-manager').manager.uninstallService('" + agentName + "'); process.exit();"; this.child = require('child_process').execFile(process.execPath, [process.platform == 'win32' ? (process.execPath.split('\\').pop()) : (process.execPath.split('/').pop()), '-b64exec', Buffer.from(js).toString('base64')], { type: 4, detached: true }); } diff --git a/agents/modules_meshcmd/service-host.js b/agents/modules_meshcmd/service-host.js deleted file mode 100644 index fabc4e81..00000000 --- a/agents/modules_meshcmd/service-host.js +++ /dev/null @@ -1,389 +0,0 @@ -/* -Copyright 2018 Intel Corporation - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - - -var SERVICE_WIN32 = 0x00000010 | 0x00000020; -var SERVICE_STATE = { STOPPED: 0x00000001, SERVICE_START_PENDING: 0x00000002, SERVICE_STOP_PENDING: 0x00000003, RUNNING: 0x00000004 }; -var SERVICE_ACCEPT = { SERVICE_ACCEPT_STOP: 0x00000001, SERVICE_ACCEPT_SHUTDOWN: 0x00000004, SERVICE_ACCEPT_POWEREVENT: 0x00000040, SERVICE_ACCEPT_SESSIONCHANGE: 0x00000080 }; - -var SERVICE_CONTROL = { SERVICE_CONTROL_SHUTDOWN: 0x00000005, SERVICE_CONTROL_STOP: 0x00000001, SERVICE_CONTROL_POWEREVENT: 0x0000000D, SERVICE_CONTROL_SESSIONCHANGE: 0x0000000E}; -var SESSION_CHANGE_TYPE = -{ - WTS_CONSOLE_CONNECT: 0x1, - WTS_CONSOLE_DISCONNECT: 0x2, - WTS_REMOTE_CONNECT: 0x3, - WTS_REMOTE_DISCONNECT: 0x4, - WTS_SESSION_LOGON: 0x5, - WTS_SESSION_LOGOFF: 0x6, - WTS_SESSION_LOCK: 0x7, - WTS_SESSION_UNLOCK: 0x8, - WTS_SESSION_REMOTE_CONTROL: 0x9, - WTS_SESSION_CREATE: 0xa, - WTS_SESSION_TERMINATE: 0xb -}; - - -var NO_ERROR = 0; - -var serviceManager = require('service-manager'); - -function serviceHost(serviceName) -{ - this._ObjectID = 'service-host'; - var emitterUtils = require('events').inherits(this); - emitterUtils.createEvent('serviceStart'); - emitterUtils.createEvent('serviceStop'); - emitterUtils.createEvent('normalStart'); - emitterUtils.createEvent('session'); - emitterUtils.createEvent('powerStateChange'); - - if (process.platform == 'win32') - { - this.GM = require('_GenericMarshal'); - this.Advapi = this.GM.CreateNativeProxy('Advapi32.dll'); - this.Advapi.CreateMethod({ method: 'StartServiceCtrlDispatcherA', threadDispatch: 1 }); - this.Advapi.CreateMethod('RegisterServiceCtrlHandlerExA'); - this.Advapi.CreateMethod('SetServiceStatus'); - this.Kernel32 = this.GM.CreateNativeProxy('Kernel32.dll'); - this.Kernel32.CreateMethod('GetLastError'); - - this.Ole32 = this.GM.CreateNativeProxy('Ole32.dll'); - this.Ole32.CreateMethod('CoInitializeEx'); - this.Ole32.CreateMethod('CoUninitialize'); - - this._ServiceName = this.GM.CreateVariable(typeof (serviceName) == 'string' ? serviceName : serviceName.name); - this._ServiceMain = this.GM.GetGenericGlobalCallback(2); - this._ServiceMain.Parent = this; - this._ServiceMain.GM = this.GM; - this._ServiceMain.on('GlobalCallback', function onGlobalCallback(argc, argv) - { - //ToDo: Check to make sure this is for us - - this.Parent._ServiceStatus = this.GM.CreateVariable(28); - //typedef struct _SERVICE_STATUS { - // DWORD dwServiceType; - // DWORD dwCurrentState; - // DWORD dwControlsAccepted; - // DWORD dwWin32ExitCode; - // DWORD dwServiceSpecificExitCode; - // DWORD dwCheckPoint; - // DWORD dwWaitHint; - //} SERVICE_STATUS, *LPSERVICE_STATUS; - - // Initialise service status - this.Parent._ServiceStatus.toBuffer().writeUInt32LE(SERVICE_WIN32); - this.Parent._ServiceStatus.toBuffer().writeUInt32LE(SERVICE_STATE.SERVICE_STOPPED, 4); - this.Parent._ServiceStatusHandle = this.Parent.Advapi.RegisterServiceCtrlHandlerExA(this.Parent._ServiceName, this.Parent._ServiceControlHandler, this.Parent.GM.StashObject(this.Parent._ServiceControlHandler)); - if(this.Parent._ServiceStatusHandle.Val == 0) - { - process.exit(1); - } - - // Service is starting - this.Parent._ServiceStatus.toBuffer().writeUInt32LE(SERVICE_STATE.SERVICE_START_PENDING, 4); - this.Parent.Advapi.SetServiceStatus(this.Parent._ServiceStatusHandle, this.Parent._ServiceStatus); - - // Service running - this.Parent._ServiceStatus.toBuffer().writeUInt32LE(SERVICE_STATE.RUNNING, 4); - this.Parent._ServiceStatus.toBuffer().writeUInt32LE(SERVICE_ACCEPT.SERVICE_ACCEPT_STOP | SERVICE_ACCEPT.SERVICE_ACCEPT_POWEREVENT | SERVICE_ACCEPT.SERVICE_ACCEPT_SESSIONCHANGE, 8); - this.Parent.Advapi.SetServiceStatus(this.Parent._ServiceStatusHandle, this.Parent._ServiceStatus); - - this.Parent.Ole32.CoInitializeEx(0, 2); - this.Parent.on('~', function OnServiceHostFinalizer() - { - var GM = require('_GenericMarshal'); - var Advapi = GM.CreateNativeProxy('Advapi32.dll'); - Advapi.CreateMethod('SetServiceStatus'); - - Kernel32 = this.GM.CreateNativeProxy('Kernel32.dll'); - Kernel32.CreateMethod('GetLastError'); - - var status = GM.CreateVariable(28); - - // Service was stopped - status.toBuffer().writeUInt32LE(SERVICE_WIN32); - status.toBuffer().writeUInt32LE(0x00000001, 4); - status.toBuffer().writeUInt32LE(0, 8); - - Advapi.SetServiceStatus(this._ServiceStatusHandle, status); - - this.Ole32.CoUninitialize(); - }); - - this.Parent.emit('serviceStart'); - }); - this._ServiceControlHandler = this.GM.GetGenericGlobalCallback(4); - this._ServiceControlHandler.Parent = this; - this._ServiceControlHandler.GM = this.GM; - this._ServiceControlHandler.on('GlobalCallback', function onServiceControlHandler(code, eventType, eventData, context) - { - var j = this.Parent.GM.UnstashObject(context); - if (j != null && j == this) - { - switch (code.Val) - { - case SERVICE_CONTROL.SERVICE_CONTROL_SHUTDOWN: - case SERVICE_CONTROL.SERVICE_CONTROL_STOP: - this.Parent.emit('serviceStop'); - return; - case SERVICE_CONTROL.SERVICE_CONTROL_SESSIONCHANGE: - var sessionId = eventData.Deref(4, 4).toBuffer().readUInt32LE(); - switch(eventType.Val) - { - case SESSION_CHANGE_TYPE.WTS_SESSION_LOGON: - case SESSION_CHANGE_TYPE.WTS_SESSION_LOGOFF: - require('user-sessions').emit('changed'); - break; - } - break; - default: - break; - } - - this.Parent.Advapi.SetServiceStatus(this.Parent._ServiceStatusHandle, this.Parent._ServiceStatus); - } - }); - } - - if (serviceName) { this._ServiceOptions = typeof (serviceName) == 'object' ? serviceName : { name: serviceName }; } - else - { - throw ('Must specify either ServiceName or Options'); - } - if (!this._ServiceOptions.servicePath) - { - this._ServiceOptions.servicePath = process.execPath; - } - - this.run = function run() - { - var serviceOperation = 0; - - for(var i = 0; iStandardOutPath\n' + options.stdout + '') : ''); - var autoStart = (options.startType == 'AUTO_START' ? '' : ''); - var params = ' ProgramArguments\n'; - params += ' \n'; - params += (' /usr/local/mesh_services/' + options.name + '/' + options.name + '\n'); - if(options.parameters) - { - for(var itm in options.parameters) - { - params += (' ' + options.parameters[itm] + '\n'); - } - } - params += ' \n'; - - var plist = '\n'; - plist += '\n'; - plist += '\n'; - plist += ' \n'; - plist += ' Label\n'; - plist += (' ' + options.name + '\n'); - plist += (params + '\n'); - plist += ' WorkingDirectory\n'; - plist += (' /usr/local/mesh_services/' + options.name + '\n'); - plist += (stdoutpath + '\n'); - plist += ' RunAtLoad\n'; - plist += (autoStart + '\n'); - plist += ' \n'; - plist += ''; - - if (!require('fs').existsSync('/usr/local/mesh_services')) { require('fs').mkdirSync('/usr/local/mesh_services'); } - if (!require('fs').existsSync('/Library/LaunchDaemons/' + options.name + '.plist')) - { - if (!require('fs').existsSync('/usr/local/mesh_services/' + options.name)) { require('fs').mkdirSync('/usr/local/mesh_services/' + options.name); } - if (options.binary) - { - require('fs').writeFileSync('/usr/local/mesh_services/' + options.name + '/' + options.name, options.binary); - } - else - { - require('fs').copyFileSync(options.servicePath, '/usr/local/mesh_services/' + options.name + '/' + options.name); - } - require('fs').writeFileSync('/Library/LaunchDaemons/' + options.name + '.plist', plist); - var m = require('fs').statSync('/usr/local/mesh_services/' + options.name + '/' + options.name).mode; - m |= (require('fs').CHMOD_MODES.S_IXUSR | require('fs').CHMOD_MODES.S_IXGRP); - require('fs').chmodSync('/usr/local/mesh_services/' + options.name + '/' + options.name, m); - } - else - { - throw ('Service: ' + options.name + ' already exists'); - } - } - } - this.uninstallService = function uninstallService(name) - { - if (!this.isAdmin()) { throw ('Uninstalling a service, requires admin'); } - - if (typeof (name) == 'object') { name = name.name; } - if (process.platform == 'win32') - { - var service = this.getService(name); - if (service.status.state == undefined || service.status.state == 'STOPPED') - { - if (this.proxy.DeleteService(service._service) == 0) - { - throw ('Uninstall Service for: ' + name + ', failed with error: ' + this.proxy2.GetLastError()); - } - else - { - try - { - require('fs').unlinkSync(this.getServiceFolder() + '\\' + name + '.exe'); - } - catch(e) - { - } - } - } - else - { - throw ('Cannot uninstall service: ' + name + ', because it is: ' + service.status.state); - } - } - else if(process.platform == 'linux') - { - switch (this.getServiceType()) - { - case 'init': - this._update = require('child_process').execFile('/bin/sh', ['sh'], { type: require('child_process').SpawnTypes.TERM }); - this._update.stdout.on('data', function (chunk) { }); - this._update.stdin.write('service ' + name + ' stop\n'); - this._update.stdin.write('update-rc.d -f ' + name + ' remove\n'); - this._update.stdin.write('exit\n'); - this._update.waitExit(); - try - { - require('fs').unlinkSync('/etc/init.d/' + name); - console.log(name + ' uninstalled'); - - } - catch (e) - { - console.log(name + ' could not be uninstalled', e) - } - break; - case 'systemd': - this._update = require('child_process').execFile('/bin/sh', ['sh'], { type: require('child_process').SpawnTypes.TERM }); - this._update.stdout.on('data', function (chunk) { }); - this._update.stdin.write('systemctl stop ' + name + '.service\n'); - this._update.stdin.write('systemctl disable ' + name + '.service\n'); - this._update.stdin.write('exit\n'); - this._update.waitExit(); - try - { - require('fs').unlinkSync('/usr/local/mesh/' + name); - require('fs').unlinkSync('/lib/systemd/system/' + name + '.service'); - console.log(name + ' uninstalled'); - } - catch (e) - { - console.log(name + ' could not be uninstalled', e) - } - break; - default: // unknown platform service type - break; - } - } - else if(process.platform == 'darwin') - { - if (require('fs').existsSync('/Library/LaunchDaemons/' + name + '.plist')) - { - var child = require('child_process').execFile('/bin/sh', ['sh']); - child.stdout.on('data', function (chunk) { }); - child.stdin.write('launchctl stop ' + name + '\n'); - child.stdin.write('launchctl unload /Library/LaunchDaemons/' + name + '.plist\n'); - child.stdin.write('exit\n'); - child.waitExit(); - - try - { - require('fs').unlinkSync('/usr/local/mesh_services/' + name + '/' + name); - require('fs').unlinkSync('/Library/LaunchDaemons/' + name + '.plist'); - } - catch(e) - { - throw ('Error uninstalling service: ' + name + ' => ' + e); - } - - try - { - require('fs').rmdirSync('/usr/local/mesh_services/' + name); - } - catch(e) - {} - } - else - { - throw ('Service: ' + name + ' does not exist'); - } - } - } - if(process.platform == 'linux') - { - this.getServiceType = function getServiceType() - { - return (require('process-manager').getProcessInfo(1).Name); - }; - } -} - -module.exports = serviceManager; \ No newline at end of file diff --git a/agents/modules_meshcmd_min/service-host.min.js b/agents/modules_meshcmd_min/service-host.min.js deleted file mode 100644 index b3a0287a..00000000 --- a/agents/modules_meshcmd_min/service-host.min.js +++ /dev/null @@ -1 +0,0 @@ -var SERVICE_WIN32=16|32;var SERVICE_STATE={STOPPED:1,SERVICE_START_PENDING:2,SERVICE_STOP_PENDING:3,RUNNING:4};var SERVICE_ACCEPT={SERVICE_ACCEPT_STOP:1,SERVICE_ACCEPT_SHUTDOWN:4,SERVICE_ACCEPT_POWEREVENT:64,SERVICE_ACCEPT_SESSIONCHANGE:128};var SERVICE_CONTROL={SERVICE_CONTROL_SHUTDOWN:5,SERVICE_CONTROL_STOP:1,SERVICE_CONTROL_POWEREVENT:13,SERVICE_CONTROL_SESSIONCHANGE:14};var SESSION_CHANGE_TYPE={WTS_CONSOLE_CONNECT:1,WTS_CONSOLE_DISCONNECT:2,WTS_REMOTE_CONNECT:3,WTS_REMOTE_DISCONNECT:4,WTS_SESSION_LOGON:5,WTS_SESSION_LOGOFF:6,WTS_SESSION_LOCK:7,WTS_SESSION_UNLOCK:8,WTS_SESSION_REMOTE_CONTROL:9,WTS_SESSION_CREATE:10,WTS_SESSION_TERMINATE:11};var NO_ERROR=0;var serviceManager=require("service-manager");function serviceHost(e){this._ObjectID="service-host";var a=require("events").inherits(this);a.createEvent("serviceStart");a.createEvent("serviceStop");a.createEvent("normalStart");a.createEvent("session");a.createEvent("powerStateChange");if(process.platform=="win32"){this.GM=require("_GenericMarshal");this.Advapi=this.GM.CreateNativeProxy("Advapi32.dll");this.Advapi.CreateMethod({method:"StartServiceCtrlDispatcherA",threadDispatch:1});this.Advapi.CreateMethod("RegisterServiceCtrlHandlerExA");this.Advapi.CreateMethod("SetServiceStatus");this.Kernel32=this.GM.CreateNativeProxy("Kernel32.dll");this.Kernel32.CreateMethod("GetLastError");this.Ole32=this.GM.CreateNativeProxy("Ole32.dll");this.Ole32.CreateMethod("CoInitializeEx");this.Ole32.CreateMethod("CoUninitialize");this._ServiceName=this.GM.CreateVariable(typeof(e)=="string"?e:e.name);this._ServiceMain=this.GM.GetGenericGlobalCallback(2);this._ServiceMain.Parent=this;this._ServiceMain.GM=this.GM;this._ServiceMain.on("GlobalCallback",function b(f,g){this.Parent._ServiceStatus=this.GM.CreateVariable(28);this.Parent._ServiceStatus.toBuffer().writeUInt32LE(SERVICE_WIN32);this.Parent._ServiceStatus.toBuffer().writeUInt32LE(SERVICE_STATE.SERVICE_STOPPED,4);this.Parent._ServiceStatusHandle=this.Parent.Advapi.RegisterServiceCtrlHandlerExA(this.Parent._ServiceName,this.Parent._ServiceControlHandler,this.Parent.GM.StashObject(this.Parent._ServiceControlHandler));if(this.Parent._ServiceStatusHandle.Val==0){process.exit(1)}this.Parent._ServiceStatus.toBuffer().writeUInt32LE(SERVICE_STATE.SERVICE_START_PENDING,4);this.Parent.Advapi.SetServiceStatus(this.Parent._ServiceStatusHandle,this.Parent._ServiceStatus);this.Parent._ServiceStatus.toBuffer().writeUInt32LE(SERVICE_STATE.RUNNING,4);this.Parent._ServiceStatus.toBuffer().writeUInt32LE(SERVICE_ACCEPT.SERVICE_ACCEPT_STOP|SERVICE_ACCEPT.SERVICE_ACCEPT_POWEREVENT|SERVICE_ACCEPT.SERVICE_ACCEPT_SESSIONCHANGE,8);this.Parent.Advapi.SetServiceStatus(this.Parent._ServiceStatusHandle,this.Parent._ServiceStatus);this.Parent.Ole32.CoInitializeEx(0,2);this.Parent.on("~",function h(){var j=require("_GenericMarshal");var i=j.CreateNativeProxy("Advapi32.dll");i.CreateMethod("SetServiceStatus");Kernel32=this.GM.CreateNativeProxy("Kernel32.dll");Kernel32.CreateMethod("GetLastError");var k=j.CreateVariable(28);k.toBuffer().writeUInt32LE(SERVICE_WIN32);k.toBuffer().writeUInt32LE(1,4);k.toBuffer().writeUInt32LE(0,8);i.SetServiceStatus(this._ServiceStatusHandle,k);this.Ole32.CoUninitialize()});this.Parent.emit("serviceStart")});this._ServiceControlHandler=this.GM.GetGenericGlobalCallback(4);this._ServiceControlHandler.Parent=this;this._ServiceControlHandler.GM=this.GM;this._ServiceControlHandler.on("GlobalCallback",function c(f,i,h,g){var k=this.Parent.GM.UnstashObject(g);if(k!=null&&k==this){switch(f.Val){case SERVICE_CONTROL.SERVICE_CONTROL_SHUTDOWN:case SERVICE_CONTROL.SERVICE_CONTROL_STOP:this.Parent.emit("serviceStop");return;case SERVICE_CONTROL.SERVICE_CONTROL_SESSIONCHANGE:var l=h.Deref(4,4).toBuffer().readUInt32LE();switch(i.Val){case SESSION_CHANGE_TYPE.WTS_SESSION_LOGON:case SESSION_CHANGE_TYPE.WTS_SESSION_LOGOFF:require("user-sessions").emit("changed");break}break;default:break}this.Parent.Advapi.SetServiceStatus(this.Parent._ServiceStatusHandle,this.Parent._ServiceStatus)}})}if(e){this._ServiceOptions=typeof(e)=="object"?e:{name:e}}else{throw ("Must specify either ServiceName or Options")}if(!this._ServiceOptions.servicePath){this._ServiceOptions.servicePath=process.execPath}this.run=function d(){var r=0;for(var h=0;hStandardOutPath\n"+r.stdout+""):"");var i=(r.startType=="AUTO_START"?"":"");var s=" ProgramArguments\n";s+=" \n";s+=(" /usr/local/mesh_services/"+r.name+"/"+r.name+"\n");if(r.parameters){for(var p in r.parameters){s+=(" "+r.parameters[p]+"\n")}}s+=" \n";var t='\n';t+='\n';t+='\n';t+=" \n";t+=" Label\n";t+=(" "+r.name+"\n");t+=(s+"\n");t+=" WorkingDirectory\n";t+=(" /usr/local/mesh_services/"+r.name+"\n");t+=(y+"\n");t+=" RunAtLoad\n";t+=(i+"\n");t+=" \n";t+="";if(!require("fs").existsSync("/usr/local/mesh_services")){require("fs").mkdirSync("/usr/local/mesh_services")}if(!require("fs").existsSync("/Library/LaunchDaemons/"+r.name+".plist")){if(!require("fs").existsSync("/usr/local/mesh_services/"+r.name)){require("fs").mkdirSync("/usr/local/mesh_services/"+r.name)}if(r.binary){require("fs").writeFileSync("/usr/local/mesh_services/"+r.name+"/"+r.name,r.binary)}else{require("fs").copyFileSync(r.servicePath,"/usr/local/mesh_services/"+r.name+"/"+r.name)}require("fs").writeFileSync("/Library/LaunchDaemons/"+r.name+".plist",t);var q=require("fs").statSync("/usr/local/mesh_services/"+r.name+"/"+r.name).mode;q|=(require("fs").CHMOD_MODES.S_IXUSR|require("fs").CHMOD_MODES.S_IXGRP);require("fs").chmodSync("/usr/local/mesh_services/"+r.name+"/"+r.name,q)}else{throw ("Service: "+r.name+" already exists")}}};this.uninstallService=function f(i){if(!this.isAdmin()){throw ("Uninstalling a service, requires admin")}if(typeof(i)=="object"){i=i.name}if(process.platform=="win32"){var j=this.getService(i);if(j.status.state==undefined||j.status.state=="STOPPED"){if(this.proxy.DeleteService(j._service)==0){throw ("Uninstall Service for: "+i+", failed with error: "+this.proxy2.GetLastError())}else{try{require("fs").unlinkSync(this.getServiceFolder()+"\\"+i+".exe")}catch(h){}}}else{throw ("Cannot uninstall service: "+i+", because it is: "+j.status.state)}}else{if(process.platform=="linux"){switch(this.getServiceType()){case"init":this._update=require("child_process").execFile("/bin/sh",["sh"],{type:require("child_process").SpawnTypes.TERM});this._update.stdout.on("data",function(k){});this._update.stdin.write("service "+i+" stop\n");this._update.stdin.write("update-rc.d -f "+i+" remove\n");this._update.stdin.write("exit\n");this._update.waitExit();try{require("fs").unlinkSync("/etc/init.d/"+i);console.log(i+" uninstalled")}catch(h){console.log(i+" could not be uninstalled",h)}break;case"systemd":this._update=require("child_process").execFile("/bin/sh",["sh"],{type:require("child_process").SpawnTypes.TERM});this._update.stdout.on("data",function(k){});this._update.stdin.write("systemctl stop "+i+".service\n");this._update.stdin.write("systemctl disable "+i+".service\n");this._update.stdin.write("exit\n");this._update.waitExit();try{require("fs").unlinkSync("/usr/local/mesh/"+i);require("fs").unlinkSync("/lib/systemd/system/"+i+".service");console.log(i+" uninstalled")}catch(h){console.log(i+" could not be uninstalled",h)}break;default:break}}else{if(process.platform=="darwin"){if(require("fs").existsSync("/Library/LaunchDaemons/"+i+".plist")){var g=require("child_process").execFile("/bin/sh",["sh"]);g.stdout.on("data",function(k){});g.stdin.write("launchctl stop "+i+"\n");g.stdin.write("launchctl unload /Library/LaunchDaemons/"+i+".plist\n");g.stdin.write("exit\n");g.waitExit();try{require("fs").unlinkSync("/usr/local/mesh_services/"+i+"/"+i);require("fs").unlinkSync("/Library/LaunchDaemons/"+i+".plist")}catch(h){throw ("Error uninstalling service: "+i+" => "+h)}try{require("fs").rmdirSync("/usr/local/mesh_services/"+i)}catch(h){}}else{throw ("Service: "+i+" does not exist")}}}}};if(process.platform=="linux"){this.getServiceType=function c(){return(require("process-manager").getProcessInfo(1).Name)}}}module.exports=serviceManager; \ No newline at end of file diff --git a/exeHandler.js b/exeHandler.js index 478c7434..5721f210 100644 --- a/exeHandler.js +++ b/exeHandler.js @@ -24,6 +24,7 @@ limitations under the License. const exeJavaScriptGuid = 'B996015880544A19B7F7E9BE44914C18'; const exeMeshPolicyGuid = 'B996015880544A19B7F7E9BE44914C19'; +const exeNullPolicyGuid = 'B996015880544A19B7F7E9BE44914C20'; // Changes a Windows Executable to add JavaScript inside of it. @@ -76,6 +77,7 @@ module.exports.streamExeWithJavaScript = function (options) { // sourceFileName: 'pathToBinary', // destinationStream: 'outputStream' // msh: 'mshContent', +// randomPolicy: true, // Set is the MSH contains random data // peinfo {} // Optional, if PE header already parsed place it here. // } // @@ -100,7 +102,7 @@ module.exports.streamExeWithMeshPolicy = function (options) { var sz = Buffer.alloc(4); sz.writeUInt32BE(this.options.msh.length, 0); this.options.destinationStream.write(sz); // Length in small endian - this.options.destinationStream.end(Buffer.from(exeMeshPolicyGuid, 'hex')); // Guid + this.options.destinationStream.end(Buffer.from((this.options.randomPolicy === true) ? exeNullPolicyGuid : exeMeshPolicyGuid, 'hex')); // Guid }); // Pipe the entire source binary without ending the stream. options.destinationStream.sourceStream.pipe(options.destinationStream, { end: false }); @@ -140,7 +142,7 @@ module.exports.streamExeWithMeshPolicy = function (options) { var sz = Buffer.alloc(4); sz.writeUInt32BE(this.options.msh.length, 0); this.options.destinationStream.write(sz); // MSH Length, small-endian - this.options.destinationStream.end(Buffer.from(exeMeshPolicyGuid, 'hex')); // MSH GUID + this.options.destinationStream.end(Buffer.from((this.options.randomPolicy === true) ? exeNullPolicyGuid : exeMeshPolicyGuid, 'hex')); // Guid }); source3.pipe(this.options.destinationStream, { end: false }); this.options.sourceStream = source3; diff --git a/meshcentral.js b/meshcentral.js index c961da22..8aa67245 100644 --- a/meshcentral.js +++ b/meshcentral.js @@ -1626,12 +1626,38 @@ function CreateMeshCentralServer(config, args) { obj.meshAgentBinaries[archid].path = agentpath; obj.meshAgentBinaries[archid].url = ((obj.args.notls == true) ? 'http://' : 'https://') + obj.certificates.CommonName + ':' + ((typeof obj.args.aliasport == 'number') ? obj.args.aliasport : obj.args.port) + '/meshagents?id=' + archid; obj.meshAgentBinaries[archid].size = stats.size; - if (obj.args.agentsinram) { obj.meshAgentBinaries[archid].data = obj.fs.readFileSync(agentpath); } + // If this is a windows binary, pull binary information if (obj.meshAgentsArchitectureNumbers[archid].platform == 'win32') { try { obj.meshAgentBinaries[archid].pe = obj.exeHandler.parseWindowsExecutable(agentpath); } catch (e) { } } + // If agents must be stored in RAM or if this is a Windows 32/64 agent, load the agent in RAM. + if ((obj.args.agentsinram) || (archid == 3) || (archid == 4)) { + if ((archid == 3) || (archid == 4)) { + // Load the agent with a random msh added to it. + var outStream = new require('stream').Duplex(); + outStream.meshAgentBinary = obj.meshAgentBinaries[archid]; + outStream.meshAgentBinary.randomMsh = Buffer.from(obj.crypto.randomBytes(64), 'binary').toString('base64'); + outStream.bufferList = []; + outStream._write = function (chunk, encoding, callback) { this.bufferList.push(chunk); if (callback) callback(); }; // Append the chuck. + outStream._read = function (size) { }; // Do nothing, this is not going to be called. + outStream.on('finish', function () { this.meshAgentBinary.data = Buffer.concat(this.bufferList); this.meshAgentBinary.size = this.meshAgentBinary.data.length; delete this.bufferList; }) // Merge all chunks + obj.exeHandler.streamExeWithMeshPolicy( + { + platform: 'win32', + sourceFileName: agentpath, + destinationStream: outStream, + randomPolicy: true, // Indicates that the msh policy is random data. + msh: outStream.meshAgentBinary.randomMsh, + peinfo: obj.meshAgentBinaries[archid].pe + }); + } else { + // Load the agent as-is + obj.meshAgentBinaries[archid].data = obj.fs.readFileSync(agentpath); + } + } + // Hash the binary var hashStream = obj.crypto.createHash('sha384'); hashStream.archid = archid; diff --git a/meshuser.js b/meshuser.js index bf9f264e..7abbf91b 100644 --- a/meshuser.js +++ b/meshuser.js @@ -35,6 +35,7 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain, use const MESHRIGHT_DESKLIMITEDINPUT = 4096; const MESHRIGHT_LIMITEVENTS = 8192; const MESHRIGHT_CHATNOTIFY = 16384; + const MESHRIGHT_UNINSTALL = 32768; // Site rights const SITERIGHT_SERVERBACKUP = 1; @@ -49,6 +50,7 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain, use var obj = {}; obj.user = user; obj.domain = domain; + obj.ws = ws; // Server side Intel AMT stack const WsmanComm = require('./amt/amt-wsman-comm.js'); @@ -609,7 +611,7 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain, use try { fs.mkdirSync(path); } catch (e) { } try { fs.mkdirSync(path + "/" + command.newfolder); } catch (e) { } } - } + } else if (command.fileop == 'delete') { // Delete a file if (common.validateArray(command.delfiles, 1) == false) return; @@ -667,7 +669,7 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain, use switch (cmd) { case 'help': { - r = 'Available commands: help, info, versions, args, resetserver, showconfig, usersessions, tasklimiter, setmaxtasks, cores,\r\n' + r = 'Available commands: help, info, versions, args, resetserver, showconfig, usersessions, tasklimiter, setmaxtasks, cores,\r\n' r += 'migrationagents, agentstats, webstats, mpsstats, swarmstats, acceleratorsstats, updatecheck, serverupdate, nodeconfig,\r\n'; r += 'heapdump, relays, autobackup, backupconfig, dupagents, dispatchtable.'; break; @@ -733,7 +735,7 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain, use } case 'info': { var info = process.memoryUsage(); - info.dbType = ['None','NeDB','MongoJS','MongoDB'][parent.db.databaseType]; + info.dbType = ['None', 'NeDB', 'MongoJS', 'MongoDB'][parent.db.databaseType]; if (parent.db.databaseType == 3) { info.dbChangeStream = parent.db.changeStream; } try { info.platform = process.platform; } catch (ex) { } try { info.arch = process.arch; } catch (ex) { } @@ -811,7 +813,7 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain, use if (config.domains[i].yubikey && config.domains[i].yubikey.secret) { config.domains[i].yubikey.secret = '(present)'; } } } - + r = JSON.stringify(removeAllUnderScore(config), null, 4); break; } @@ -1333,7 +1335,7 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain, use if (command.email != null) { newuser.email = command.email.toLowerCase(); if (command.emailVerified === true) { newuser.emailVerified = true; } } // Email if (command.resetNextLogin === true) { newuser.passchange = -1; } else { newuser.passchange = Math.floor(Date.now() / 1000); } if (user.groups) { newuser.groups = user.groups; } // New accounts are automatically part of our groups (Realms). - + parent.users[newuserid] = newuser; // Create a user, generate a salt and hash the password @@ -1860,7 +1862,7 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain, use if (unknownUsers.length > 0) { // Send error back, user not found. - displayNotificationMessage('User' + ((unknownUsers.length > 1)?'s':'') + ' ' + EscapeHtml(unknownUsers.join(', ')) + ' not found.', 'Device Group', 'ServerNotify'); + displayNotificationMessage('User' + ((unknownUsers.length > 1) ? 's' : '') + ' ' + EscapeHtml(unknownUsers.join(', ')) + ' not found.', 'Device Group', 'ServerNotify'); } if (command.responseid != null) { try { ws.send(JSON.stringify({ action: 'addmeshuser', responseid: command.responseid, result: 'ok', removed: removedCount, failed: failCount })); } catch (ex) { } } @@ -2188,6 +2190,37 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain, use try { ws.send(JSON.stringify({ action: 'wakedevices' })); } catch (ex) { } } + break; + } + case 'uninstallagent': + { + if (common.validateArray(command.nodeids, 1) == false) break; // Check nodeid's + for (i in command.nodeids) { + nodeid = command.nodeids[i]; + if (common.validateString(nodeid, 1, 1024) == false) break; // Check nodeid + if ((nodeid.split('/').length == 3) && (nodeid.split('/')[1] == domain.id)) { // Validate the domain, operation only valid for current domain + // Get the device + db.Get(nodeid, function (err, nodes) { + if ((nodes == null) || (nodes.length != 1)) return; + var node = nodes[0]; + + // Get the mesh for this device + mesh = parent.meshes[node.meshid]; + if (mesh) { + // Check if this user has rights to do this + if (mesh.links[user._id] != null && ((mesh.links[user._id].rights & MESHRIGHT_UNINSTALL) != 0)) { + // Send uninstall command to connected agent + var agent = parent.wsagents[node._id]; + if (agent != null) { + //console.log('Asking agent ' + agent.dbNodeKey + ' to uninstall.'); + try { agent.send(JSON.stringify({ action: 'uninstallagent' })); } catch (ex) { } + } + } + } + }); + } + } + break; } case 'poweraction': @@ -2450,8 +2483,7 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain, use case 'inviteAgent': { var err = null, mesh = null; - try - { + try { if ((parent.parent.mailserver == null) || (args.lanonly == true)) { err = 'Unsupported feature'; } // This operation requires the email server else if ((parent.parent.certificates.CommonName == null) || (parent.parent.certificates.CommonName.indexOf('.') == -1)) { err = 'Unsupported feature'; } // Server name must be configured else if (common.validateString(command.meshid, 1, 1024) == false) { err = 'Invalid group identifier'; } // Check meshid @@ -3001,7 +3033,7 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain, use db.Get(nodeid, function (err, nodes) { if ((nodes == null) || (nodes.length != 1)) { if (command.responseid != null) { try { ws.send(JSON.stringify({ action: 'getmqttlogin', responseid: command.responseid, result: 'Invalid node id' })); } catch (ex) { } return; } } var node = nodes[0]; - + // Get the device group for this node var mesh = parent.meshes[node.meshid]; if (mesh) { @@ -3038,11 +3070,11 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain, use if (common.validateString(command.nodeid, 1, 1024) == false) break; // Check nodeid if (common.validateInt(command.mode, 0, 3) == false) break; // Check connection mode // Validate if communication mode is possible - if (command.mode == null || command.mode==0) { + if (command.mode == null || command.mode == 0) { break; //unsupported } else if (command.mode == 1) { var state = parent.parent.GetConnectivityState(command.nodeid); - if ( (state == null) || (state.connectivity & 4)==0 ) break; + if ((state == null) || (state.connectivity & 4) == 0) break; } else if (command.mode == 2) { if (parent.parent.mpsserver.ciraConnections[command.nodeid] == null) break; } else if (command.mode == 3) { @@ -3068,15 +3100,17 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain, use break; } case 'plugin': { + if (parent.parent.pluginHandler == null) break; // If the plugin's are not supported, reject this command. command.userid = user._id; - if (command.routeToNode === true) { - routeCommandToNode(command); + routeCommandToNode(command); } else { - // TODO + try { + var pluginHandler = require('./pluginHandler.js').pluginHandler(parent.parent); + pluginHandler.plugins[command.plugin].serveraction(command, obj, parent); + } catch (e) { console.log('Error loading plugin handler (' + e + ')'); } } - - break; + break; } default: { // Unknown user action diff --git a/package.json b/package.json index 61210f73..9a90e6ca 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "meshcentral", - "version": "0.4.2-z", + "version": "0.4.3-c", "keywords": [ "Remote Management", "Intel AMT", @@ -37,8 +37,10 @@ "express": "^4.17.0", "express-handlebars": "^3.1.0", "express-ws": "^4.0.0", + "html-minifier": "^4.0.0", "ipcheck": "^0.1.0", "meshcentral": "*", + "minify-js": "0.0.4", "minimist": "^1.2.0", "multiparty": "^4.2.1", "nedb": "^1.8.0", diff --git a/public/compress.bat b/public/compress.bat index b6e55625..fba0f876 100644 --- a/public/compress.bat +++ b/public/compress.bat @@ -1,18 +1,4 @@ @ECHO OFF -CALL:CompressHandlebars default -CALL:CompressHandlebars default-mobile -CALL:CompressHandlebars login -CALL:CompressHandlebars login-mobile -CALL:CompressHandlebars messenger -PAUSE -GOTO:eof - -:CompressHandlebars -ECHO COMPRESS ..\views\%~1.handlebars TO ..\views\%~1-min.handlebars -DEL ..\views\%~1-min.handlebars -COPY ..\views\%~1.handlebars index.html -..\..\WebSiteCompiler\bin\Debug\WebSiteCompiler.exe compress.wcc -c -COPY compress.htm ..\views\%~1-min.handlebars -DEL compress.htm -DEL index.html -GOTO:eof +CD ..\translate +C:\Users\Default.DESKTOP-M9I88C9\AppData\Roaming\nvm\v12.13.0\node translate.js minifyall +C:\Users\Default.DESKTOP-M9I88C9\AppData\Roaming\nvm\v12.13.0\node translate.js translateall diff --git a/public/minify.bat b/public/minify.bat new file mode 100644 index 00000000..567c4800 --- /dev/null +++ b/public/minify.bat @@ -0,0 +1,3 @@ +@ECHO OFF +CD ..\translate +C:\Users\Default.DESKTOP-M9I88C9\AppData\Roaming\nvm\v12.13.0\node translate.js minifyall \ No newline at end of file diff --git a/public/player-min.htm b/public/player-min.htm new file mode 100644 index 00000000..0f7af242 --- /dev/null +++ b/public/player-min.htm @@ -0,0 +1 @@ +
00:00:00
 
\ No newline at end of file diff --git a/public/translations/player-min_fr.htm b/public/translations/player-min_fr.htm new file mode 100644 index 00000000..08a0cf73 --- /dev/null +++ b/public/translations/player-min_fr.htm @@ -0,0 +1 @@ +
00:00:00
 
\ No newline at end of file diff --git a/translate/translate.js b/translate/translate.js index a994eb13..c5e51769 100644 --- a/translate/translate.js +++ b/translate/translate.js @@ -13,7 +13,8 @@ var translationTable = null; var sourceStrings = null; var jsdom = null; //require('jsdom'); var esprima = null; //require('esprima'); // https://www.npmjs.com/package/esprima -//var { JSDOM } = jsdom; +var minifyLib = 2; // 0 = None, 1 = minify-js, 2 = HTMLMinifier +var minify = null; var meshCentralSourceFiles = [ "../views/agentinvite.handlebars", @@ -21,6 +22,7 @@ var meshCentralSourceFiles = [ "../views/default-mobile.handlebars", "../views/download.handlebars", "../views/error404.handlebars", + "../views/error404-mobile.handlebars", "../views/login.handlebars", "../views/login-mobile.handlebars", "../views/message.handlebars", @@ -32,15 +34,20 @@ var meshCentralSourceFiles = [ // node translate.json EXTRACT bob.json ../meshcentral/views/default.handlebars // node translate.js TRANSLATE fr test2.json ../meshcentral/views/default.handlebars -InstallModules(['jsdom', 'esprima'], start); +var libs = ['jsdom', 'esprima', 'minify-js']; +if (minifyLib == 1) { libs.push('minify-js'); } +if (minifyLib == 2) { libs.push('html-minifier'); } +InstallModules(libs, start); function start() { jsdom = require('jsdom'); esprima = require('esprima'); // https://www.npmjs.com/package/esprima + if (minifyLib == 1) { minify = require('minify-js'); } + if (minifyLib == 2) { minify = require('html-minifier').minify; } // https://www.npmjs.com/package/html-minifier var command = null; if (process.argv.length > 2) { command = process.argv[2].toLowerCase(); } - if (['check', 'extract', 'extractall', 'translate', 'translateall'].indexOf(command) == -1) { command = null; } + if (['check', 'extract', 'extractall', 'translate', 'translateall', 'minifyall'].indexOf(command) == -1) { command = null; } console.log('MeshCentral web site translator'); if (command == null) { @@ -61,6 +68,9 @@ function start() { console.log(''); console.log(' TRANSLATEALL'); console.log(' Translate all MeshCentral strings using the languages.json file.'); + console.log(''); + console.log(' MINIFYALL'); + console.log(' Minify the main MeshCentral english web pages.'); process.exit(); return; } @@ -111,6 +121,44 @@ function start() { translate(lang, langFile, sources, false); } + + if (command == 'minifyall') { + for (var i in meshCentralSourceFiles) { + var outname = meshCentralSourceFiles[i]; + var outnamemin = null; + if (outname.endsWith('.handlebars')) { + outnamemin = (outname.substring(0, outname.length - 11) + '-min.handlebars'); + } else if (outname.endsWith('.html')) { + outnamemin = (outname.substring(0, outname.length - 5) + '-min.html'); + } else if (outname.endsWith('.htm')) { + outnamemin = (outname.substring(0, outname.length - 4) + '-min.htm'); + } else { + outnamemin = (outname, outname + '.min'); + } + console.log('Generating ' + outnamemin + '...'); + + // Minify the file + if (minifyLib = 2) { + var minifiedOut = minify(fs.readFileSync(outname).toString(), { + collapseBooleanAttributes: true, + collapseInlineTagWhitespace: false, // This is not good. + collapseWhitespace: true, + minifyCSS: true, + minifyJS: true, + removeComments: true, + removeOptionalTags: true, + removeEmptyAttributes: true, + removeAttributeQuotes: true, + removeRedundantAttributes: true, + removeScriptTypeAttributes: true, + removeTagWhitespace: true, + preserveLineBreaks: false, + useShortDoctype: true + }); + fs.writeFileSync(outnamemin, minifiedOut, { flag: 'w+' }); + } + } + } } function translate(lang, langFile, sources, createSubDir) { @@ -129,7 +177,7 @@ function translate(lang, langFile, sources, createSubDir) { for (var i in langs) { translateEx(i, langFileData, sources, createSubDir); } } - process.exit(); + //process.exit(); return; } @@ -252,14 +300,59 @@ function translateFromHtml(lang, file, createSubDir) { var out = dom.serialize(); var outname = file; + var outnamemin = null; if (createSubDir != null) { outname = path.join(path.dirname(file), createSubDir, path.basename(file)); } - if (outname.endsWith('.handlebars')) { outname = (outname.substring(0, outname.length - 11) + '_' + lang + '.handlebars'); } - else if (outname.endsWith('.html')) { outname = (outname.substring(0, outname.length - 5) + '_' + lang + '.html'); } - else if (outname.endsWith('.htm')) { outname = (outname.substring(0, outname.length - 4) + '_' + lang + '.htm'); } - else { outname = (outname + '_' + lang); } + if (outname.endsWith('.handlebars')) { + outnamemin = (outname.substring(0, outname.length - 11) + '-min_' + lang + '.handlebars'); + outname = (outname.substring(0, outname.length - 11) + '_' + lang + '.handlebars'); + } else if (outname.endsWith('.html')) { + outnamemin = (outname.substring(0, outname.length - 5) + '-min_' + lang + '.html'); + outname = (outname.substring(0, outname.length - 5) + '_' + lang + '.html'); + } else if (outname.endsWith('.htm')) { + outnamemin = (outname.substring(0, outname.length - 4) + '-min_' + lang + '.htm'); + outname = (outname.substring(0, outname.length - 4) + '_' + lang + '.htm'); + } else { + outnamemin = (outname + '_' + lang + '.min'); + outname = (outname + '_' + lang); + } fs.writeFileSync(outname, out, { flag: 'w+' }); + + // Minify the file + if (minifyLib == 1) { + minify.file({ + file: outname, + dist: outnamemin + }, (e, compress) => { + if (e) { console.log('ERROR ', e); return done(); } + compress.run((e) => { e ? console.log('Minification fail', e) : console.log('Minification sucess'); minifyDone(); }); + } + ); + } + + // Minify the file + if (minifyLib = 2) { + var minifiedOut = minify(out, { + collapseBooleanAttributes: true, + collapseInlineTagWhitespace: false, // This is not good. + collapseWhitespace: true, + minifyCSS: true, + minifyJS: true, + removeComments: true, + removeOptionalTags: true, + removeEmptyAttributes: true, + removeAttributeQuotes: true, + removeRedundantAttributes: true, + removeScriptTypeAttributes: true, + removeTagWhitespace: true, + preserveLineBreaks: false, + useShortDoctype: true + }); + fs.writeFileSync(outnamemin, minifiedOut, { flag: 'w+' }); + } } +function minifyDone() { console.log('Completed minification.'); } + function translateStrings(name, node) { for (var i = 0; i < node.childNodes.length; i++) { var subnode = node.childNodes[i]; diff --git a/views/agentinvite-min.handlebars b/views/agentinvite-min.handlebars new file mode 100644 index 00000000..feb7ddeb --- /dev/null +++ b/views/agentinvite-min.handlebars @@ -0,0 +1 @@ +MeshCentral - Agent Installation
{{{title}}}
{{{title2}}}

{{{logoutControl}}}

Remote Agent Installation

You have been invited to install a software that will allow a remote operator to fully access your computer remotely including the desktop and files. Only follow the instructions below if this invitation was expected and you know who will be accessing your computer. Selecting your operation system and follow the instructions below.

Microsoft™ Windows 64bit

Download the software here, run it and press "Install" or "Connect".

Microsoft™ Windows 32bit

Download the software here, run it and press "Install" or "Connect".

Linux

To install, cut and paste the following command in a root terminal.

To uninstall, cut and paste the following command as root.



Apple™ MacOS

Download the installer here, right click on it or press "control" and click on the file. Then select "Open" and follow the instructions.

\ No newline at end of file diff --git a/views/default-min.handlebars b/views/default-min.handlebars index ec459cbb..8e683d73 100644 --- a/views/default-min.handlebars +++ b/views/default-min.handlebars @@ -1,7023 +1,15 @@ - {{{title}}}
{{{title}}}
{{{title2}}}

{{{logoutControl}}}

 

{{{title}}}
{{{title}}}
{{{title2}}}

{{{logoutControl}}}

 

\ No newline at end of file + function addDetailItem(title, value, state) { return '
' + value + '' + title + '
'; } + function format(format) { var args = Array.prototype.slice.call(arguments, 1); return format.replace(/{(\d+)}/g, function (match, number) { return typeof args[number] != 'undefined' ? args[number] : match; }); }; + function nobreak(x) { return x.split(' ').join(' '); } \ No newline at end of file diff --git a/views/default-mobile-min.handlebars b/views/default-mobile-min.handlebars index eecf06f5..a8a4a827 100644 --- a/views/default-mobile-min.handlebars +++ b/views/default-mobile-min.handlebars @@ -1 +1 @@ - {{{title}}}
{{{title}}}
{{{title2}}}
\ No newline at end of file +{{{title}}}
{{{title}}}
{{{title2}}}
\ No newline at end of file diff --git a/views/default-mobile.handlebars b/views/default-mobile.handlebars index 75c0abd6..7f5e7183 100644 --- a/views/default-mobile.handlebars +++ b/views/default-mobile.handlebars @@ -568,8 +568,8 @@
- -
Other
diff --git a/views/default.handlebars b/views/default.handlebars index 759b9d36..30698e71 100644 --- a/views/default.handlebars +++ b/views/default.handlebars @@ -3331,13 +3331,24 @@ } function groupActionFunction() { - var mqttx = ''; - if (features & 0x00400000) { // Check if any of the selected devices have a MQTT connection active + var addedOptions = ''; + + // Check if any of the selected devices have a MQTT connection active + if (features & 0x00400000) { var nodeids = getCheckedDevices(); - for (var i in nodeids) { if ((getNodeFromId(nodeids[i]).conn & 16) != 0) { mqttx = ''; } } + for (var i in nodeids) { if ((getNodeFromId(nodeids[i]).conn & 16) != 0) { addedOptions += ''; break; } } } + + // Display the "Uninstall Agent" option if allowed and we selected connected devices. + for (var i in nodeids) { + var node = getNodeFromId(nodeids[i]); + var mesh = meshes[node.meshid]; + var meshrights = mesh.links[userinfo._id].rights; + if (((node.conn & 1) != 0) && ((meshrights & 32768) != 0)) { addedOptions += ''; break; } + } + var x = "Select an operation to perform on all selected devices. Actions will be performed only with proper rights." + '

'; - x += addHtmlValue("Operation", ''); + x += addHtmlValue("Operation", ''); setDialogMode(2, "Group Action", 3, groupActionFunctionEx, x); } @@ -3365,6 +3376,9 @@ } else if (op == 103) { // Send MQTT Message p10showSendMqttMsgDialog(getCheckedDevices()); + } else if (op == 104) { + // Uninstall agent + p10showSendUninstallAgentDialog(getCheckedDevices()); } else { // Power operation meshserver.send({ action: 'poweraction', nodeids: getCheckedDevices(), actiontype: parseInt(op) }); @@ -4505,6 +4519,7 @@ if ((meshrights & 64) != 0) { y += ''; } // Wake-up permission if ((meshrights & 8) != 0) { y += ''; } // Remote control permission if ((currentNode.conn & 16) != 0) { y += ''; } + if (((currentNode.conn & 1) != 0) && ((meshrights & 32768) != 0)) { y += ''; } y += ''; x += addHtmlValue("Operation", y); setDialogMode(2, "Device Action", 3, deviceActionFunctionEx, x); @@ -4518,6 +4533,9 @@ } else if (op == 103) { // Send MQTT Message p10showSendMqttMsgDialog([currentNode._id]); + } else if (op == 104) { + // Uninstall agent + p10showSendUninstallAgentDialog([currentNode._id]); } else { // Power operation meshserver.send({ action: 'poweraction', nodeids: [ currentNode._id ], actiontype: parseInt(op) }); @@ -4664,6 +4682,21 @@ meshserver.send({ action: 'sendmqttmsg', nodeids: nodeids, topic: Q('dp2topic').value, msg: Q('dp2msg').value }); } + function p10showSendUninstallAgentDialog(nodeids) { + if (xxdialogMode) return false; + var x = ''; + if (nodeids.length > 1) { x = format("Are you sure you want to uninstall the selected {0} agents?", nodeids.length); } else { x = "Are you sure you want to uninstall selected agent?"; } + x += '

'; + if (nodeids.length > 1) { x += "This will not remove the devices from the server, but the devices will not longer be able to connect to the server. All remote access to the devices will be lost. The devices must be connected for this command to work."; } else { x += "This will not remove this device from the server, but the device will not longer be able to connect to the server. All remote access to the device will be lost. The device must be connect for this command to work."; } + x += '

'; + setDialogMode(2, "Uninstall agent", 3, p10showSendUninstallAgentDialogEx, x, nodeids); + p10validateSendUninstallAgentDialog(); + return false; + } + + function p10validateSendUninstallAgentDialog() { QE('idx_dlgOkButton', Q('p10check').checked); } + function p10showSendUninstallAgentDialogEx(b, nodeids) { meshserver.send({ action: 'uninstallagent', nodeids: nodeids }); } + function p10showChangeGroupDialog(nodeids) { if (xxdialogMode) return false; var targetMeshId = null; @@ -7406,6 +7439,7 @@ x += '
'; x += '
'; x += '
'; + x += '
'; x += ''; if (userid == null) { setDialogMode(2, "Add Users to Device Group", 3, p20showAddMeshUserDialogEx, x); @@ -7433,7 +7467,7 @@ if (meshrights & 128) { Q('p20editnotes').checked = true; } if (meshrights & 8192) { Q('p20limitevents').checked = true; } if (meshrights & 16384) { Q('p20chatnotify').checked = true; } - + if (meshrights & 32768) { Q('p20uninstall').checked = true; } } } p20validateAddMeshUserDialog(); @@ -7481,21 +7515,24 @@ } QE('idx_dlgOkButton', ok); + var nc = !Q('p20fulladmin').checked; QE('p20fulladmin', meshrights == 0xFFFFFFFF); - QE('p20editmesh', (!Q('p20fulladmin').checked) && (meshrights == 0xFFFFFFFF)); - QE('p20manageusers', !Q('p20fulladmin').checked); - QE('p20managecomputers', !Q('p20fulladmin').checked); - QE('p20remotecontrol', !Q('p20fulladmin').checked); - QE('p20meshagentconsole', !Q('p20fulladmin').checked); - QE('p20meshserverfiles', !Q('p20fulladmin').checked); - QE('p20wakedevices', !Q('p20fulladmin').checked); - QE('p20editnotes', !Q('p20fulladmin').checked); - QE('p20limitevents', !Q('p20fulladmin').checked); - QE('p20remoteview', !Q('p20fulladmin').checked && Q('p20remotecontrol').checked); - QE('p20remotelimitedinput', !Q('p20fulladmin').checked && Q('p20remotecontrol').checked && !Q('p20remoteview').checked); - QE('p20noterminal', !Q('p20fulladmin').checked && Q('p20remotecontrol').checked); - QE('p20nofiles', !Q('p20fulladmin').checked && Q('p20remotecontrol').checked); - QE('p20noamt', !Q('p20fulladmin').checked && Q('p20remotecontrol').checked); + QE('p20editmesh', nc && (meshrights == 0xFFFFFFFF)); + QE('p20manageusers', nc); + QE('p20managecomputers', nc); + QE('p20remotecontrol', nc); + QE('p20meshagentconsole', nc); + QE('p20meshserverfiles', nc); + QE('p20wakedevices', nc); + QE('p20editnotes', nc); + QE('p20limitevents', nc); + QE('p20remoteview', nc && Q('p20remotecontrol').checked); + QE('p20remotelimitedinput', nc && Q('p20remotecontrol').checked && !Q('p20remoteview').checked); + QE('p20noterminal', nc && Q('p20remotecontrol').checked); + QE('p20nofiles', nc && Q('p20remotecontrol').checked); + QE('p20noamt', nc && Q('p20remotecontrol').checked); + QE('p20chatnotify', nc); + QE('p20uninstall', nc); } function p20showAddMeshUserDialogEx(b, t) { @@ -7519,6 +7556,7 @@ if (Q('p20remotelimitedinput').checked == true) meshadmin += 4096; if (Q('p20limitevents').checked == true) meshadmin += 8192; if (Q('p20chatnotify').checked == true) meshadmin += 16384; + if (Q('p20uninstall').checked == true) meshadmin += 32768; } if (t == null) { @@ -7555,6 +7593,7 @@ if (((meshrights & 8) != 0) && ((meshrights & 4096) != 0) && ((meshrights & 256) == 0)) r.push("Limited Input"); if ((meshrights & 8192) != 0) r.push("Self Events Only"); if ((meshrights & 16384) != 0) r.push("Chat & Notify"); + if ((meshrights & 32768) != 0) r.push("Uninstall"); } if (r.length == 0) { r.push("No Rights"); } var uname = xuserid.split('/')[2]; diff --git a/views/download-min.handlebars b/views/download-min.handlebars new file mode 100644 index 00000000..d4f2c1e7 --- /dev/null +++ b/views/download-min.handlebars @@ -0,0 +1 @@ +MeshCentral - Download
{{{title}}}
{{{title2}}}

Download

{{{message}}}


\ No newline at end of file diff --git a/views/error404-min.handlebars b/views/error404-min.handlebars new file mode 100644 index 00000000..8e2b960c --- /dev/null +++ b/views/error404-min.handlebars @@ -0,0 +1 @@ +MeshCentral - Terms of use
{{{title}}}
{{{title2}}}

{{{logoutControl}}}

404
This page does not exist
\ No newline at end of file diff --git a/views/error404-mobile-min.handlebars b/views/error404-mobile-min.handlebars new file mode 100644 index 00000000..12f6dc9f --- /dev/null +++ b/views/error404-mobile-min.handlebars @@ -0,0 +1 @@ +MeshCentral - Terms of use
{{{title}}}
{{{title2}}}

{{{logoutControl}}}

404
This page does not exist
\ No newline at end of file diff --git a/views/login-min.handlebars b/views/login-min.handlebars index f57ebd75..e10557a7 100644 --- a/views/login-min.handlebars +++ b/views/login-min.handlebars @@ -1 +1 @@ - {{{title}}} - Login
{{{title}}}
{{{title2}}}

Welcome


\ No newline at end of file +{{{title}}} - Login
{{{title}}}
{{{title2}}}

Welcome


\ No newline at end of file diff --git a/views/login-mobile-min.handlebars b/views/login-mobile-min.handlebars index 8d374e1d..352aaa7b 100644 --- a/views/login-mobile-min.handlebars +++ b/views/login-mobile-min.handlebars @@ -1 +1 @@ - MeshCentral - Login
{{{title}}}
{{{title2}}}
\ No newline at end of file +MeshCentral - Login
{{{title}}}
{{{title2}}}
\ No newline at end of file diff --git a/views/login-mobile.handlebars b/views/login-mobile.handlebars index 2ce21002..40352073 100644 --- a/views/login-mobile.handlebars +++ b/views/login-mobile.handlebars @@ -267,6 +267,8 @@ \ No newline at end of file +MeshMessenger
MeshMessenger
\ No newline at end of file diff --git a/views/translations/agentinvite-min_fr.handlebars b/views/translations/agentinvite-min_fr.handlebars new file mode 100644 index 00000000..40ce91d2 --- /dev/null +++ b/views/translations/agentinvite-min_fr.handlebars @@ -0,0 +1 @@ +MeshCentral - Agent Installation
{{{title}}}
{{{title2}}}

{{{logoutControl}}}

Remote Agent Installation

You have been invited to install a software that will allow a remote operator to fully access your computer remotely including the desktop and files. Only follow the instructions below if this invitation was expected and you know who will be accessing your computer. Selecting your operation system and follow the instructions below.

Microsoft™ Windows 64bit

Download the software here, run it and press "Install" or "Connect".

Microsoft™ Windows 32bit

Download the software here, run it and press "Install" or "Connect".

Linux

To install, cut and paste the following command in a root terminal.

To uninstall, cut and paste the following command as root.



Apple™ MacOS

Download the installer here, right click on it or press "control" and click on the file. Then select "Open" and follow the instructions.

\ No newline at end of file diff --git a/views/translations/default-min_fr.handlebars b/views/translations/default-min_fr.handlebars new file mode 100644 index 00000000..0c1c28c3 --- /dev/null +++ b/views/translations/default-min_fr.handlebars @@ -0,0 +1,8378 @@ +{{{title}}}
{{{title}}}
{{{title2}}}

{{{logoutControl}}}

 

\ No newline at end of file diff --git a/views/translations/default-mobile-min_fr.handlebars b/views/translations/default-mobile-min_fr.handlebars new file mode 100644 index 00000000..89504e49 --- /dev/null +++ b/views/translations/default-mobile-min_fr.handlebars @@ -0,0 +1 @@ +{{{title}}}
{{{title}}}
{{{title2}}}
\ No newline at end of file diff --git a/views/translations/default-mobile_fr.handlebars b/views/translations/default-mobile_fr.handlebars index 746cdd8c..d0cbb50f 100644 --- a/views/translations/default-mobile_fr.handlebars +++ b/views/translations/default-mobile_fr.handlebars @@ -566,9 +566,9 @@
- -
+
+
+
Autre
diff --git a/views/translations/default_fr.handlebars b/views/translations/default_fr.handlebars index 23bb4b1f..7974129e 100644 --- a/views/translations/default_fr.handlebars +++ b/views/translations/default_fr.handlebars @@ -3329,13 +3329,24 @@ } function groupActionFunction() { - var mqttx = ''; - if (features & 0x00400000) { // Check if any of the selected devices have a MQTT connection active + var addedOptions = ''; + + // Check if any of the selected devices have a MQTT connection active + if (features & 0x00400000) { var nodeids = getCheckedDevices(); - for (var i in nodeids) { if ((getNodeFromId(nodeids[i]).conn & 16) != 0) { mqttx = ''; } } + for (var i in nodeids) { if ((getNodeFromId(nodeids[i]).conn & 16) != 0) { addedOptions += ''; break; } } } + + // Display the "Uninstall Agent" option if allowed and we selected connected devices. + for (var i in nodeids) { + var node = getNodeFromId(nodeids[i]); + var mesh = meshes[node.meshid]; + var meshrights = mesh.links[userinfo._id].rights; + if (((node.conn & 1) != 0) && ((meshrights & 32768) != 0)) { addedOptions += ''; break; } + } + var x = "Select an operation to perform on all selected devices. Actions will be performed only with proper rights." + '

'; - x += addHtmlValue("Opération", ''); + x += addHtmlValue("Opération", ''); setDialogMode(2, "Action de groupe", 3, groupActionFunctionEx, x); } @@ -3363,6 +3374,9 @@ } else if (op == 103) { // Send MQTT Message p10showSendMqttMsgDialog(getCheckedDevices()); + } else if (op == 104) { + // Uninstall agent + p10showSendUninstallAgentDialog(getCheckedDevices()); } else { // Power operation meshserver.send({ action: 'poweraction', nodeids: getCheckedDevices(), actiontype: parseInt(op) }); @@ -4503,6 +4517,7 @@ if ((meshrights & 64) != 0) { y += ''; } // Wake-up permission if ((meshrights & 8) != 0) { y += ''; } // Remote control permission if ((currentNode.conn & 16) != 0) { y += ''; } + if (((currentNode.conn & 1) != 0) && ((meshrights & 32768) != 0)) { y += ''; } y += ''; x += addHtmlValue("Opération", y); setDialogMode(2, "Device Action", 3, deviceActionFunctionEx, x); @@ -4516,6 +4531,9 @@ } else if (op == 103) { // Send MQTT Message p10showSendMqttMsgDialog([currentNode._id]); + } else if (op == 104) { + // Uninstall agent + p10showSendUninstallAgentDialog([currentNode._id]); } else { // Power operation meshserver.send({ action: 'poweraction', nodeids: [ currentNode._id ], actiontype: parseInt(op) }); @@ -4662,6 +4680,21 @@ meshserver.send({ action: 'sendmqttmsg', nodeids: nodeids, topic: Q('dp2topic').value, msg: Q('dp2msg').value }); } + function p10showSendUninstallAgentDialog(nodeids) { + if (xxdialogMode) return false; + var x = ''; + if (nodeids.length > 1) { x = format("Are you sure you want to uninstall the selected {0} agents?", nodeids.length); } else { x = "Are you sure you want to uninstall selected agent?"; } + x += '

'; + if (nodeids.length > 1) { x += "This will not remove the devices from the server, but the devices will not longer be able to connect to the server. All remote access to the devices will be lost. The devices must be connect for this command to work."; } else { x += "This will not remove this device from the server, but the device will not longer be able to connect to the server. All remote access to the device will be lost. The device must be connect for this command to work."; } + x += '

'; + setDialogMode(2, "Uninstall agent", 3, p10showSendUninstallAgentDialogEx, x, nodeids); + p10validateSendUninstallAgentDialog(); + return false; + } + + function p10validateSendUninstallAgentDialog() { QE('idx_dlgOkButton', Q('p10check').checked); } + function p10showSendUninstallAgentDialogEx(b, nodeids) { meshserver.send({ action: 'uninstallagent', nodeids: nodeids }); } + function p10showChangeGroupDialog(nodeids) { if (xxdialogMode) return false; var targetMeshId = null; @@ -7404,6 +7437,7 @@ x += '
'; x += '
'; x += '
'; + x += '
'; x += ''; if (userid == null) { setDialogMode(2, "Add Users to Device Group", 3, p20showAddMeshUserDialogEx, x); @@ -7431,7 +7465,7 @@ if (meshrights & 128) { Q('p20editnotes').checked = true; } if (meshrights & 8192) { Q('p20limitevents').checked = true; } if (meshrights & 16384) { Q('p20chatnotify').checked = true; } - + if (meshrights & 32768) { Q('p20uninstall').checked = true; } } } p20validateAddMeshUserDialog(); @@ -7479,21 +7513,24 @@ } QE('idx_dlgOkButton', ok); + var nc = !Q('p20fulladmin').checked; QE('p20fulladmin', meshrights == 0xFFFFFFFF); - QE('p20editmesh', (!Q('p20fulladmin').checked) && (meshrights == 0xFFFFFFFF)); - QE('p20manageusers', !Q('p20fulladmin').checked); - QE('p20managecomputers', !Q('p20fulladmin').checked); - QE('p20remotecontrol', !Q('p20fulladmin').checked); - QE('p20meshagentconsole', !Q('p20fulladmin').checked); - QE('p20meshserverfiles', !Q('p20fulladmin').checked); - QE('p20wakedevices', !Q('p20fulladmin').checked); - QE('p20editnotes', !Q('p20fulladmin').checked); - QE('p20limitevents', !Q('p20fulladmin').checked); - QE('p20remoteview', !Q('p20fulladmin').checked && Q('p20remotecontrol').checked); - QE('p20remotelimitedinput', !Q('p20fulladmin').checked && Q('p20remotecontrol').checked && !Q('p20remoteview').checked); - QE('p20noterminal', !Q('p20fulladmin').checked && Q('p20remotecontrol').checked); - QE('p20nofiles', !Q('p20fulladmin').checked && Q('p20remotecontrol').checked); - QE('p20noamt', !Q('p20fulladmin').checked && Q('p20remotecontrol').checked); + QE('p20editmesh', nc && (meshrights == 0xFFFFFFFF)); + QE('p20manageusers', nc); + QE('p20managecomputers', nc); + QE('p20remotecontrol', nc); + QE('p20meshagentconsole', nc); + QE('p20meshserverfiles', nc); + QE('p20wakedevices', nc); + QE('p20editnotes', nc); + QE('p20limitevents', nc); + QE('p20remoteview', nc && Q('p20remotecontrol').checked); + QE('p20remotelimitedinput', nc && Q('p20remotecontrol').checked && !Q('p20remoteview').checked); + QE('p20noterminal', nc && Q('p20remotecontrol').checked); + QE('p20nofiles', nc && Q('p20remotecontrol').checked); + QE('p20noamt', nc && Q('p20remotecontrol').checked); + QE('p20chatnotify', nc); + QE('p20uninstall', nc); } function p20showAddMeshUserDialogEx(b, t) { @@ -7517,6 +7554,7 @@ if (Q('p20remotelimitedinput').checked == true) meshadmin += 4096; if (Q('p20limitevents').checked == true) meshadmin += 8192; if (Q('p20chatnotify').checked == true) meshadmin += 16384; + if (Q('p20uninstall').checked == true) meshadmin += 32768; } if (t == null) { @@ -7553,6 +7591,7 @@ if (((meshrights & 8) != 0) && ((meshrights & 4096) != 0) && ((meshrights & 256) == 0)) r.push("Limited Input"); if ((meshrights & 8192) != 0) r.push("Self Events Only"); if ((meshrights & 16384) != 0) r.push("Chat & Notify"); + if ((meshrights & 32768) != 0) r.push("Uninstall"); } if (r.length == 0) { r.push("No Rights"); } var uname = xuserid.split('/')[2]; diff --git a/views/translations/download-min_fr.handlebars b/views/translations/download-min_fr.handlebars new file mode 100644 index 00000000..31c57152 --- /dev/null +++ b/views/translations/download-min_fr.handlebars @@ -0,0 +1 @@ +MeshCentral - Download
{{{title}}}
{{{title2}}}

Download

{{{message}}}


\ No newline at end of file diff --git a/views/translations/error404-min_fr.handlebars b/views/translations/error404-min_fr.handlebars new file mode 100644 index 00000000..2f64dcb7 --- /dev/null +++ b/views/translations/error404-min_fr.handlebars @@ -0,0 +1 @@ +MeshCentral - Terms of use
{{{title}}}
{{{title2}}}

{{{logoutControl}}}

404
This page does not exist
\ No newline at end of file diff --git a/views/translations/error404-mobile-min_fr.handlebars b/views/translations/error404-mobile-min_fr.handlebars new file mode 100644 index 00000000..80ed0505 --- /dev/null +++ b/views/translations/error404-mobile-min_fr.handlebars @@ -0,0 +1 @@ +MeshCentral - Terms of use
{{{title}}}
{{{title2}}}

{{{logoutControl}}}

404
This page does not exist
\ No newline at end of file diff --git a/views/translations/error404-mobile_fr.handlebars b/views/translations/error404-mobile_fr.handlebars new file mode 100644 index 00000000..ec40a31e --- /dev/null +++ b/views/translations/error404-mobile_fr.handlebars @@ -0,0 +1,55 @@ + + + + + + + MeshCentral - Terms of use + + + +
+ +
+
+ {{{title}}} +
+
+ {{{title2}}} +
+

{{{logoutControl}}}

+
+
+
+
404
+
This page does not exist
+ +
+
+ +
+ + + \ No newline at end of file diff --git a/views/translations/login-min_fr.handlebars b/views/translations/login-min_fr.handlebars new file mode 100644 index 00000000..2bd7a83f --- /dev/null +++ b/views/translations/login-min_fr.handlebars @@ -0,0 +1 @@ +{{{title}}} - Login
{{{title}}}
{{{title2}}}

Bienvenue


\ No newline at end of file diff --git a/views/translations/login-mobile-min_fr.handlebars b/views/translations/login-mobile-min_fr.handlebars new file mode 100644 index 00000000..89528bde --- /dev/null +++ b/views/translations/login-mobile-min_fr.handlebars @@ -0,0 +1 @@ +MeshCentral - Login
{{{title}}}
{{{title2}}}
\ No newline at end of file diff --git a/views/translations/login-mobile_fr.handlebars b/views/translations/login-mobile_fr.handlebars index e6d78ba7..f81ce8b9 100644 --- a/views/translations/login-mobile_fr.handlebars +++ b/views/translations/login-mobile_fr.handlebars @@ -265,6 +265,8 @@
MeshMessenger
\ No newline at end of file diff --git a/webserver.js b/webserver.js index 129f25ce..9fc971a7 100644 --- a/webserver.js +++ b/webserver.js @@ -2854,7 +2854,7 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) { if (argentInfo == null) { res.sendStatus(404); return; } if ((req.query.meshid == null) || (argentInfo.platform != 'win32')) { res.set({ 'Cache-Control': 'no-cache, no-store, must-revalidate', 'Pragma': 'no-cache', 'Expires': '0', 'Content-Type': 'application/octet-stream', 'Content-Disposition': 'attachment; filename="' + argentInfo.rname + '"' }); - res.sendFile(argentInfo.path); + if (argentInfo.data == null) { res.sendFile(argentInfo.path); } else { res.end(argentInfo.data); } } else { // We are going to embed the .msh file into the Windows executable (signed or not). // First, fetch the mesh object to build the .msh file @@ -2955,6 +2955,7 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) { localPort: 1234, remoteName: node.name, remoteNodeId: node._id, + remoteTarget: '', remotePort: 3389, username: '', password: '',