From adae944146da0630be05b0573068565662ee6b5a Mon Sep 17 00:00:00 2001 From: Ylian Saint-Hilaire Date: Thu, 19 Aug 2021 14:10:03 -0700 Subject: [PATCH] Added terminal start command option --- agents/meshcore.js | 30 +++++++++++------------------- db.js | 6 +++--- meshagent.js | 13 +++++++++++++ meshcentral-config-schema.json | 12 ++++++++++-- sample-config-advanced.json | 8 ++++++++ 5 files changed, 45 insertions(+), 24 deletions(-) diff --git a/agents/meshcore.js b/agents/meshcore.js index ed1d612d..187aced3 100644 --- a/agents/meshcore.js +++ b/agents/meshcore.js @@ -87,7 +87,7 @@ if (require('MeshAgent').ARCHID == null) { } if (id != null) { Object.defineProperty(require('MeshAgent'), 'ARCHID', { value: id }); } } -var obj = {}; +var obj = { serverInfo: {} }; var agentFileHttpRequests = {}; // Currently active agent HTTPS GET requests from the server. var agentFileHttpPendingRequests = []; // Pending HTTPS GET requests from the server. var debugConsole = (global._MSH && (_MSH().debugConsole == 1)); @@ -1375,6 +1375,10 @@ function handleServerCommand(data) { agentFileHttpPendingRequests.push(data); serverFetchFile(); break; + case 'serverInfo': // Server information + obj.serverInfo = data; + delete obj.serverInfo.action; + break; case 'errorlog': // Return agent error log try { mesh.SendCommand(JSON.stringify({ action: 'errorlog', log: require('util-agentlog').read(data.startTime) })); } catch (ex) { } break; @@ -1922,14 +1926,7 @@ function onTunnelData(data) { // The above line is commented out, because there is a bug with ClosePseudoConsole() API, so this is the workaround this.httprequest._dispatcher = require('win-dispatcher').dispatch({ modules: [{ name: 'win-virtual-terminal', script: getJSModule('win-virtual-terminal') }], launch: { module: 'win-virtual-terminal', method: (this.httprequest.protocol == 6 ? 'StartPowerShell' : 'Start'), args: [cols, rows] } }); this.httprequest._dispatcher.httprequest = this.httprequest; - this.httprequest._dispatcher.on('connection', function (c) { - if (this.httprequest.connectionPromise.completed) { - c.end(); - } - else { - this.httprequest.connectionPromise._res(c); - } - }); + this.httprequest._dispatcher.on('connection', function (c) { if (this.httprequest.connectionPromise.completed) { c.end(); } else { this.httprequest.connectionPromise._res(c); } }); } else { // Legacy Terminal @@ -1954,14 +1951,7 @@ function onTunnelData(data) { that.httprequest._dispatcher = require('win-dispatcher').dispatch({ user: username, modules: [{ name: 'win-terminal', script: getJSModule('win-terminal') }], launch: { module: 'win-terminal', method: (that.httprequest.protocol == 9 ? 'StartPowerShell' : 'Start'), args: [cols, rows] } }); } that.httprequest._dispatcher.ws = that; - that.httprequest._dispatcher.on('connection', function (c) { - if (this.ws.httprequest.connectionPromise.completed) { - c.end(); - } - else { - this.ws.httprequest.connectionPromise._res(c); - } - }); + that.httprequest._dispatcher.on('connection', function (c) { if (this.ws.httprequest.connectionPromise.completed) { c.end(); } else { this.ws.httprequest.connectionPromise._res(c); } }); } }); } @@ -1992,13 +1982,15 @@ function onTunnelData(data) { else if (bash) { var p = childProcess.execFile(bash, ['bash'], options); // Start bash // Spaces at the beginning of lines are needed to hide commands from the command history - if (process.platform == 'linux') { p.stdin.write(' alias ls=\'ls --color=auto\';clear\n'); } + if ((obj.serverInfo.termlaunchcommand != null) && (typeof obj.serverInfo.termlaunchcommand[process.platform] == 'string')) { p.stdin.write(obj.serverInfo.termlaunchcommand[process.platform]); } + else if (process.platform == 'linux') { p.stdin.write(' alias ls=\'ls --color=auto\';clear\n'); } this.httprequest.connectionPromise._res(p); } else if (sh) { var p = childProcess.execFile(sh, ['sh'], options); // Start sh // Spaces at the beginning of lines are needed to hide commands from the command history - if (process.platform == 'linux') { p.stdin.write(' alias ls=\'ls --color=auto\';clear\n'); } + if ((obj.serverInfo.termlaunchcommand != null) && (typeof obj.serverInfo.termlaunchcommand[process.platform] == 'string')) { p.stdin.write(obj.serverInfo.termlaunchcommand[process.platform]); } + else if (process.platform == 'linux') { p.stdin.write(' alias ls=\'ls --color=auto\';clear\n'); } this.httprequest.connectionPromise._res(p); } else { diff --git a/db.js b/db.js index a6c333de..d51467c3 100644 --- a/db.js +++ b/db.js @@ -1970,7 +1970,7 @@ module.exports.CreateDB = function (parent, func) { var output = parent.fs.createWriteStream(newAutoBackupPath + '.zip'); var archive = null; if (parent.config.settings.autobackup && (typeof parent.config.settings.autobackup.zippassword == 'string')) { - try { archiver.registerFormat('zip-encrypted', require("archiver-zip-encrypted")); } catch (ex) { } + try { archiver.registerFormat('zip-encrypted', require('archiver-zip-encrypted')); } catch (ex) { } archive = archiver.create('zip-encrypted', { zlib: { level: 9 }, encryptionMethod: 'aes256', password: parent.config.settings.autobackup.zippassword }); } else { archive = archiver('zip', { zlib: { level: 9 } }); @@ -2009,7 +2009,7 @@ module.exports.CreateDB = function (parent, func) { var output = parent.fs.createWriteStream(newAutoBackupPath + '.zip'); var archive = null; if (parent.config.settings.autobackup && (typeof parent.config.settings.autobackup.zippassword == 'string')) { - try { archiver.registerFormat('zip-encrypted', require("archiver-zip-encrypted")); } catch (ex) { } + try { archiver.registerFormat('zip-encrypted', require('archiver-zip-encrypted')); } catch (ex) { } archive = archiver.create('zip-encrypted', { zlib: { level: 9 }, encryptionMethod: 'aes256', password: parent.config.settings.autobackup.zippassword }); } else { archive = archiver('zip', { zlib: { level: 9 } }); @@ -2036,7 +2036,7 @@ module.exports.CreateDB = function (parent, func) { var output = parent.fs.createWriteStream(newAutoBackupPath + '.zip'); var archive = null; if (parent.config.settings.autobackup && (typeof parent.config.settings.autobackup.zippassword == 'string')) { - try { archiver.registerFormat('zip-encrypted', require("archiver-zip-encrypted")); } catch (ex) { } + try { archiver.registerFormat('zip-encrypted', require('archiver-zip-encrypted')); } catch (ex) { } archive = archiver.create('zip-encrypted', { zlib: { level: 9 }, encryptionMethod: 'aes256', password: parent.config.settings.autobackup.zippassword }); } else { archive = archiver('zip', { zlib: { level: 9 } }); diff --git a/meshagent.js b/meshagent.js index d8aaffb0..e732d4bb 100644 --- a/meshagent.js +++ b/meshagent.js @@ -1076,6 +1076,19 @@ module.exports.CreateMeshAgent = function (parent, db, ws, req, args, domain) { } }); } + + // Indicate server information to the agent. + var serverInfo = { action: 'serverInfo' }; + if ((typeof domain.terminal == 'object') && (typeof domain.terminal.launchcommand == 'object')) { + // Send terminal starting command + serverInfo.termlaunchcommand = {}; + if (typeof domain.terminal.launchcommand.linux == 'string') { serverInfo.termlaunchcommand.linux = domain.terminal.launchcommand.linux; } + if (typeof domain.terminal.launchcommand.darwin == 'string') { serverInfo.termlaunchcommand.darwin = domain.terminal.launchcommand.darwin; } + if (typeof domain.terminal.launchcommand.freebsd == 'string') { serverInfo.termlaunchcommand.freebsd = domain.terminal.launchcommand.freebsd; } + } + obj.send(JSON.stringify(serverInfo)); + + // Plug in handler if (parent.parent.pluginHandler != null) { parent.parent.pluginHandler.callHook('hook_agentCoreIsStable', obj, parent); } diff --git a/meshcentral-config-schema.json b/meshcentral-config-schema.json index 819c5aed..eb4b7bd9 100644 --- a/meshcentral-config-schema.json +++ b/meshcentral-config-schema.json @@ -507,10 +507,18 @@ "type": "object", "description": "Values that affect the terminal feature", "properties": { - "linuxshell": { + "linuxShell": { "type": "string", "enum": [ "any", "root", "user", "login" ], - "default": "any" + "default": "any", + "description": "Indicate what terminal options are available when the user clicks the right mouse button on the terminal connect button." + }, + "launchCommand": { + "type": "object", + "description": "Indicate what string the agent must write to the shell after starting a terminal session", + "linux": { "type": "string", "default": " alias ls=\\'ls --color=auto\\';clear\\n", "description": "String to write after opening a Linux terminal." }, + "darwin": { "type": "string", "default": null, "description": "String to write after opening a macOS terminal." }, + "freebsd": { "type": "string", "default": null, "description": "String to write after opening a FreeBSD terminal." }, } } }, diff --git a/sample-config-advanced.json b/sample-config-advanced.json index 7fb43aee..49e89b86 100644 --- a/sample-config-advanced.json +++ b/sample-config-advanced.json @@ -262,6 +262,14 @@ "_maxAgentSessions": 100, "maxSingleUserSessions": 10 }, + "_terminal": { + "_linuxshell": "login", + "launchCommand": { + "linux": "clear\necho \"Hello Linux\"\n", + "darwin": "clear\necho \"Hello MacOS\"\n", + "freebsd": "clear\necho \"Hello FreeBSD\"\n" + } + }, "_amtScanOptions": [ "LabNetwork 192.168.15.0/23", "SalesNetwork 192.168.8.0/24"