diff --git a/meshagent.js b/meshagent.js index 0b6543e7..2836e494 100644 --- a/meshagent.js +++ b/meshagent.js @@ -927,6 +927,7 @@ module.exports.CreateMeshAgent = function (parent, db, ws, req, args, domain) { // Not sure why, but in rare cases, obj.agentInfo is undefined here. if ((obj.agentInfo == null) || (typeof obj.agentInfo.capabilities != 'number')) { return; } // This is an odd case. obj.agentExeInfo = parent.parent.meshAgentBinaries[obj.agentInfo.agentId]; + if (domain.meshAgentBinaries && domain.meshAgentBinaries[obj.agentInfo.agentId]) { obj.agentExeInfo = domain.meshAgentBinaries[obj.agentInfo.agentId]; } // Check if this agent is reconnecting too often. if (disconnectCount > 4) { @@ -2093,7 +2094,13 @@ module.exports.CreateMeshAgent = function (parent, db, ws, req, args, domain) { // If the hash matches or is null, no update required. if ((agentExeInfo.hash == agentHash) || (agentHash == '\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0')) return 0; // If this is a macOS x86 or ARM agent type and it matched the universal binary, no update required. - if (((agentExeInfo.id == 16) || (agentExeInfo.id == 29)) && (parent.parent.meshAgentBinaries[10005].hash == agentHash)) return 0; + if ((agentExeInfo.id == 16) || (agentExeInfo.id == 29)) { + if (domain.meshAgentBinaries[10005]) { + if (domain.meshAgentBinaries[10005].hash == agentHash) return 0; + } else { + if (parent.parent.meshAgentBinaries[10005].hash == agentHash) return 0; + } + } // No match, update the agent. if (args.agentupdatesystem === 2) return 2; // If set, force a meshcore update. diff --git a/meshcentral.js b/meshcentral.js index c6b13451..efc6abe5 100644 --- a/meshcentral.js +++ b/meshcentral.js @@ -1572,9 +1572,12 @@ function CreateMeshCentralServer(config, args) { } } catch (ex) { } + // Load any domain specific agents + for (var i in obj.config.domains) { if (i != '') { obj.updateMeshAgentsTable(obj.config.domains[i], function () { }); } } + // Load the list of mesh agents and install scripts if ((obj.args.noagentupdate == 1) || (obj.args.noagentupdate == true)) { for (i in obj.meshAgentsArchitectureNumbers) { obj.meshAgentsArchitectureNumbers[i].update = false; } } - obj.updateMeshAgentsTable(function () { + obj.updateMeshAgentsTable(null, function () { obj.updateMeshAgentInstallScripts(); // Setup and start the web server @@ -2791,16 +2794,26 @@ function CreateMeshCentralServer(config, args) { }; // Update the list of available mesh agents - obj.updateMeshAgentsTable = function (func) { + obj.updateMeshAgentsTable = function (domain, func) { + // Setup the domain is specified + var objx = domain, suffix = ''; + if (objx == null) { objx = obj; } else { suffix = '-' + domain.id; objx.meshAgentBinaries = {}; } + // Load agent information file. This includes the data & time of the agent. var agentInfo = []; try { agentInfo = JSON.parse(obj.fs.readFileSync(obj.path.join(__dirname, 'agents', 'hashagents.json'), 'utf8')); } catch (ex) { } var archcount = 0; for (var archid in obj.meshAgentsArchitectureNumbers) { - var agentpath = obj.path.join(__dirname, 'agents', obj.meshAgentsArchitectureNumbers[archid].localname); - var agentpath2 = obj.path.join(obj.datapath, 'agents', obj.meshAgentsArchitectureNumbers[archid].localname); - if (obj.fs.existsSync(agentpath2)) { agentpath = agentpath2; } // If the agent is present in "meshcentral-data/agents", use that one instead. + var agentpath; + if (domain == null) { + agentpath = obj.path.join(__dirname, 'agents' + suffix, obj.meshAgentsArchitectureNumbers[archid].localname); + var agentpath2 = obj.path.join(obj.datapath, 'agents' + suffix, obj.meshAgentsArchitectureNumbers[archid].localname); + if (obj.fs.existsSync(agentpath2)) { agentpath = agentpath2; } // If the agent is present in "meshcentral-data/agents", use that one instead. + } else { + var agentpath = obj.path.join(obj.datapath, 'agents' + suffix, obj.meshAgentsArchitectureNumbers[archid].localname); + if (!obj.fs.existsSync(agentpath)) continue; // If the agent is not present in "meshcentral-data/agents" skip. + } // Fetch all the agent binary information var stats = null; @@ -2808,15 +2821,15 @@ function CreateMeshCentralServer(config, args) { if ((stats != null)) { // If file exists archcount++; - obj.meshAgentBinaries[archid] = Object.assign({}, obj.meshAgentsArchitectureNumbers[archid]); - obj.meshAgentBinaries[archid].path = agentpath; - obj.meshAgentBinaries[archid].url = 'http://' + obj.certificates.CommonName + ':' + ((typeof obj.args.aliasport == 'number') ? obj.args.aliasport : obj.args.port) + '/meshagents?id=' + archid; - obj.meshAgentBinaries[archid].size = stats.size; - if ((agentInfo[archid] != null) && (agentInfo[archid].mtime != null)) { obj.meshAgentBinaries[archid].mtime = new Date(agentInfo[archid].mtime); } // Set agent time if available + objx.meshAgentBinaries[archid] = Object.assign({}, obj.meshAgentsArchitectureNumbers[archid]); + objx.meshAgentBinaries[archid].path = agentpath; + objx.meshAgentBinaries[archid].url = 'http://' + obj.certificates.CommonName + ':' + ((typeof obj.args.aliasport == 'number') ? obj.args.aliasport : obj.args.port) + '/meshagents?id=' + archid; + objx.meshAgentBinaries[archid].size = stats.size; + if ((agentInfo[archid] != null) && (agentInfo[archid].mtime != null)) { objx.meshAgentBinaries[archid].mtime = new Date(agentInfo[archid].mtime); } // Set agent time if available // 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 (ex) { } + try { objx.meshAgentBinaries[archid].pe = obj.exeHandler.parseWindowsExecutable(agentpath); } catch (ex) { } } // If agents must be stored in RAM or if this is a Windows 32/64 agent, load the agent in RAM. @@ -2824,7 +2837,7 @@ function CreateMeshCentralServer(config, args) { 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 = objx.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. @@ -2883,11 +2896,11 @@ function CreateMeshCentralServer(config, args) { destinationStream: outStream, randomPolicy: true, // Indicates that the msh policy is random data. msh: outStream.meshAgentBinary.randomMsh, - peinfo: obj.meshAgentBinaries[archid].pe + peinfo: objx.meshAgentBinaries[archid].pe }); } else { // Load the agent as-is - obj.meshAgentBinaries[archid].data = obj.fs.readFileSync(agentpath); + objx.meshAgentBinaries[archid].data = obj.fs.readFileSync(agentpath); // Compress the agent using ZIP var archive = require('archiver')('zip', { level: 9 }); // Sets the compression method. @@ -2910,14 +2923,14 @@ function CreateMeshCentralServer(config, args) { //console.log('Packed', onZipData.x.size, onZipData.x.zsize); } const onZipError = function onZipError() { delete onZipData.x.zacc; } - obj.meshAgentBinaries[archid].zacc = []; - onZipData.x = obj.meshAgentBinaries[archid]; - onZipEnd.x = obj.meshAgentBinaries[archid]; - onZipError.x = obj.meshAgentBinaries[archid]; + objx.meshAgentBinaries[archid].zacc = []; + onZipData.x = objx.meshAgentBinaries[archid]; + onZipEnd.x = objx.meshAgentBinaries[archid]; + onZipError.x = objx.meshAgentBinaries[archid]; archive.on('data', onZipData); archive.on('end', onZipEnd); archive.on('error', onZipError); - archive.append(obj.meshAgentBinaries[archid].data, { name: 'meshagent' }); + archive.append(objx.meshAgentBinaries[archid].data, { name: 'meshagent' }); archive.finalize(); } } @@ -2926,24 +2939,24 @@ function CreateMeshCentralServer(config, args) { var hashStream = obj.crypto.createHash('sha384'); hashStream.archid = archid; hashStream.on('data', function (data) { - obj.meshAgentBinaries[this.archid].hash = data.toString('binary'); - obj.meshAgentBinaries[this.archid].hashhex = data.toString('hex'); + objx.meshAgentBinaries[this.archid].hash = data.toString('binary'); + objx.meshAgentBinaries[this.archid].hashhex = data.toString('hex'); if ((--archcount == 0) && (func != null)) { func(); } }); var options = { sourcePath: agentpath, targetStream: hashStream, platform: obj.meshAgentsArchitectureNumbers[archid].platform }; - if (obj.meshAgentBinaries[archid].pe != null) { options.peinfo = obj.meshAgentBinaries[archid].pe; } + if (objx.meshAgentBinaries[archid].pe != null) { options.peinfo = objx.meshAgentBinaries[archid].pe; } obj.exeHandler.hashExecutableFile(options); // If we are not loading Windows binaries to RAM, compute the RAW file hash of the signed binaries here. if ((obj.args.agentsinram === false) && ((archid == 3) || (archid == 4))) { var hash = obj.crypto.createHash('sha384').update(obj.fs.readFileSync(agentpath)); - obj.meshAgentBinaries[archid].fileHash = hash.digest('binary'); - obj.meshAgentBinaries[archid].fileHashHex = Buffer.from(obj.meshAgentBinaries[archid].fileHash, 'binary').toString('hex'); + objx.meshAgentBinaries[archid].fileHash = hash.digest('binary'); + objx.meshAgentBinaries[archid].fileHashHex = Buffer.from(objx.meshAgentBinaries[archid].fileHash, 'binary').toString('hex'); } } } - if ((obj.meshAgentBinaries[3] == null) && (obj.meshAgentBinaries[10003] != null)) { obj.meshAgentBinaries[3] = obj.meshAgentBinaries[10003]; } // If only the unsigned windows binaries are present, use them. - if ((obj.meshAgentBinaries[4] == null) && (obj.meshAgentBinaries[10004] != null)) { obj.meshAgentBinaries[4] = obj.meshAgentBinaries[10004]; } // If only the unsigned windows binaries are present, use them. + if ((objx.meshAgentBinaries[3] == null) && (objx.meshAgentBinaries[10003] != null)) { objx.meshAgentBinaries[3] = objx.meshAgentBinaries[10003]; } // If only the unsigned windows binaries are present, use them. + if ((objx.meshAgentBinaries[4] == null) && (objx.meshAgentBinaries[10004] != null)) { objx.meshAgentBinaries[4] = objx.meshAgentBinaries[10004]; } // If only the unsigned windows binaries are present, use them. }; // Generate a time limited user login token diff --git a/webserver.js b/webserver.js index c801e963..fe6863c6 100644 --- a/webserver.js +++ b/webserver.js @@ -4864,6 +4864,7 @@ module.exports.CreateWebServer = function (parent, db, args, certificates, doneF // Get the interactive install script, this only works for non-Windows agents var agentid = parseInt(req.query.meshinstall); var argentInfo = obj.parent.meshAgentBinaries[agentid]; + if (domain.meshAgentBinaries && domain.meshAgentBinaries[agentid]) { argentInfo = domain.meshAgentBinaries[agentid]; } var scriptInfo = obj.parent.meshAgentInstallScripts[6]; if ((argentInfo == null) || (scriptInfo == null) || (argentInfo.platform == 'win32')) { try { res.sendStatus(404); } catch (ex) { } return; } @@ -4883,6 +4884,7 @@ module.exports.CreateWebServer = function (parent, db, args, certificates, doneF } else if (req.query.id != null) { // Send a specific mesh agent back var argentInfo = obj.parent.meshAgentBinaries[req.query.id]; + if (domain.meshAgentBinaries && domain.meshAgentBinaries[req.query.id]) { argentInfo = domain.meshAgentBinaries[req.query.id]; } if (argentInfo == null) { try { res.sendStatus(404); } catch (ex) { } return; } // Download PDB debug files, only allowed for administrator or accounts with agent dump access @@ -4998,7 +5000,11 @@ module.exports.CreateWebServer = function (parent, db, args, certificates, doneF } setContentDispositionHeader(res, 'application/octet-stream', meshfilename, null, argentInfo.rname); if (argentInfo.mtime != null) { res.setHeader('Last-Modified', argentInfo.mtime.toUTCString()); } - obj.parent.exeHandler.streamExeWithMeshPolicy({ platform: 'win32', sourceFileName: obj.parent.meshAgentBinaries[req.query.id].path, destinationStream: res, msh: meshsettings, peinfo: obj.parent.meshAgentBinaries[req.query.id].pe }); + if (domain.meshAgentBinaries && domain.meshAgentBinaries[req.query.id]) { + obj.parent.exeHandler.streamExeWithMeshPolicy({ platform: 'win32', sourceFileName: domain.meshAgentBinaries[req.query.id].path, destinationStream: res, msh: meshsettings, peinfo: domain.meshAgentBinaries[req.query.id].pe }); + } else { + obj.parent.exeHandler.streamExeWithMeshPolicy({ platform: 'win32', sourceFileName: obj.parent.meshAgentBinaries[req.query.id].path, destinationStream: res, msh: meshsettings, peinfo: obj.parent.meshAgentBinaries[req.query.id].pe }); + } return; } } else if (req.query.script != null) { @@ -5048,6 +5054,7 @@ module.exports.CreateWebServer = function (parent, db, args, certificates, doneF // No signed agents, we are going to merge a new MeshCmd. if (((agentid == 3) || (agentid == 4)) && (obj.parent.meshAgentBinaries[agentid + 10000] != null)) { agentid += 10000; } // Avoid merging javascript to a signed mesh agent. var argentInfo = obj.parent.meshAgentBinaries[agentid]; + if (domain.meshAgentBinaries && domain.meshAgentBinaries[agentid]) { argentInfo = domain.meshAgentBinaries[agentid]; } if ((argentInfo == null) || (obj.parent.defaultMeshCmd == null)) { try { res.sendStatus(404); } catch (ex) { } return; } setContentDispositionHeader(res, 'application/octet-stream', 'meshcmd' + ((req.query.meshcmd <= 4) ? '.exe' : ''), null, 'meshcmd'); res.statusCode = 200; @@ -5216,6 +5223,7 @@ module.exports.CreateWebServer = function (parent, db, args, certificates, doneF var agentid = parseInt(fileSplit[0]); if ((isNaN(agentid) == false) && (obj.parent.meshAgentBinaries[agentid] != null)) { var agentinfo = obj.parent.meshAgentBinaries[agentid]; + if (domain.meshAgentBinaries && domain.meshAgentBinaries[agentid]) { argentInfo = domain.meshAgentBinaries[agentid]; } var filestats = obj.fs.statSync(obj.path.join(parent.datapath, '..', 'meshcentral-coredumps', file)); coredumps.push({ fileSplit: fileSplit, @@ -5283,6 +5291,7 @@ module.exports.CreateWebServer = function (parent, db, args, certificates, doneF for (var agentid in obj.parent.meshAgentBinaries) { if ((agentid >= 10000) && (agentid != 10005)) continue; var agentinfo = obj.parent.meshAgentBinaries[agentid]; + if (domain.meshAgentBinaries && domain.meshAgentBinaries[agentid]) { argentInfo = domain.meshAgentBinaries[agentid]; } response += '' + agentinfo.id + '' + agentinfo.desc.split(' ').join(' ') + ''; response += '' + agentinfo.rname + ''; if ((user.siteadmin == 0xFFFFFFFF) || ((Array.isArray(obj.parent.config.settings.agentcoredumpusers)) && (obj.parent.config.settings.agentcoredumpusers.indexOf(user._id) >= 0))) { @@ -5319,6 +5328,7 @@ module.exports.CreateWebServer = function (parent, db, args, certificates, doneF // Send a specific mesh agent back var argentInfo = obj.parent.meshAgentBinaries[req.query.id]; + if (domain.meshAgentBinaries && domain.meshAgentBinaries[req.query.id]) { argentInfo = domain.meshAgentBinaries[req.query.id]; } if ((argentInfo == null) || (req.query.meshid == null)) { res.sendStatus(404); return; } // Check if the meshid is a time limited, encrypted cookie