mirror of
https://github.com/Ylianst/MeshCentral.git
synced 2025-01-13 16:03:20 -05:00
Added agent time stamping when signing a Windows agent.
This commit is contained in:
parent
de3d47e948
commit
18c11a344c
@ -486,7 +486,7 @@ function createAuthenticodeHandler(path) {
|
|||||||
fs.closeSync(output);
|
fs.closeSync(output);
|
||||||
|
|
||||||
// Indicate we are done
|
// Indicate we are done
|
||||||
func(null);
|
func(null, written);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -1372,7 +1372,7 @@ function createAuthenticodeHandler(path) {
|
|||||||
|
|
||||||
// Close the file
|
// Close the file
|
||||||
fs.closeSync(output);
|
fs.closeSync(output);
|
||||||
func(null);
|
func(null, written);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Save an executable without the signature
|
// Save an executable without the signature
|
||||||
@ -1635,7 +1635,7 @@ function createAuthenticodeHandler(path) {
|
|||||||
fs.closeSync(output);
|
fs.closeSync(output);
|
||||||
|
|
||||||
// Indicate success
|
// Indicate success
|
||||||
func(null);
|
func(null, written);
|
||||||
}
|
}
|
||||||
|
|
||||||
function writeExecutableEx(output, p7signature, written, func) {
|
function writeExecutableEx(output, p7signature, written, func) {
|
||||||
@ -1669,7 +1669,7 @@ function createAuthenticodeHandler(path) {
|
|||||||
fs.closeSync(output);
|
fs.closeSync(output);
|
||||||
|
|
||||||
// Indicate success
|
// Indicate success
|
||||||
func(null);
|
func(null, written);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Return null if we could not open the file
|
// Return null if we could not open the file
|
||||||
|
@ -101,6 +101,7 @@
|
|||||||
"agentCoreDump": { "type": "boolean", "default": false, "description": "Automatically activates and transfers any agent crash dump files to the server in meshcentral-data/coredumps." },
|
"agentCoreDump": { "type": "boolean", "default": false, "description": "Automatically activates and transfers any agent crash dump files to the server in meshcentral-data/coredumps." },
|
||||||
"agentCoreDumpUsers": { "type": "array", "description": "List of non-administrator users that have access to mesh agent crash dumps." },
|
"agentCoreDumpUsers": { "type": "array", "description": "List of non-administrator users that have access to mesh agent crash dumps." },
|
||||||
"agentSignLock": { "type": "boolean", "default": false, "description": "When code signing an agent using authenticode, lock the agent to only allow connection to this server. (This is in testing, the default value will change to true in the future)." },
|
"agentSignLock": { "type": "boolean", "default": false, "description": "When code signing an agent using authenticode, lock the agent to only allow connection to this server. (This is in testing, the default value will change to true in the future)." },
|
||||||
|
"agentTimeStampServer": { "type": [ "boolean", "string" ], "default": "http://timestamp.comodoca.com/authenticode", "description": "The time stamping server to use when code signing Windows executables. When set to false, the executables are not time stamped." },
|
||||||
"ignoreAgentHashCheck": { "type": [ "boolean", "string" ], "default": false, "description": "When true, the agent no longer checked the TLS certificate of the server. This should be used for debugging only. You can also set this to a comma seperated list of IP addresses to ignore, for example: \"192.168.2.100,192.168.1.0/24\"." },
|
"ignoreAgentHashCheck": { "type": [ "boolean", "string" ], "default": false, "description": "When true, the agent no longer checked the TLS certificate of the server. This should be used for debugging only. You can also set this to a comma seperated list of IP addresses to ignore, for example: \"192.168.2.100,192.168.1.0/24\"." },
|
||||||
"exactPorts": { "type": "boolean", "default": false, "description": "When set to true, MeshCentral will only grab the required TCP listening ports or fail. It will not try to use the next available port of it's busy." },
|
"exactPorts": { "type": "boolean", "default": false, "description": "When set to true, MeshCentral will only grab the required TCP listening ports or fail. It will not try to use the next available port of it's busy." },
|
||||||
"allowLoginToken": { "type": "boolean", "default": false },
|
"allowLoginToken": { "type": "boolean", "default": false },
|
||||||
|
599
meshcentral.js
599
meshcentral.js
@ -1617,275 +1617,277 @@ function CreateMeshCentralServer(config, args) {
|
|||||||
|
|
||||||
// Load the list of mesh agents and install scripts
|
// 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; } }
|
if ((obj.args.noagentupdate == 1) || (obj.args.noagentupdate == true)) { for (i in obj.meshAgentsArchitectureNumbers) { obj.meshAgentsArchitectureNumbers[i].update = false; } }
|
||||||
obj.updateMeshAgentsTable(obj.config.domains[''], function () {
|
obj.signMeshAgents(obj.config.domains[''], function () {
|
||||||
obj.updateMeshAgentInstallScripts();
|
obj.updateMeshAgentsTable(obj.config.domains[''], function () {
|
||||||
|
obj.updateMeshAgentInstallScripts();
|
||||||
|
|
||||||
// Setup and start the web server
|
// Setup and start the web server
|
||||||
obj.crypto.randomBytes(48, function (err, buf) {
|
obj.crypto.randomBytes(48, function (err, buf) {
|
||||||
// Setup Mesh Multi-Server if needed
|
// Setup Mesh Multi-Server if needed
|
||||||
obj.multiServer = require('./multiserver.js').CreateMultiServer(obj, obj.args);
|
obj.multiServer = require('./multiserver.js').CreateMultiServer(obj, obj.args);
|
||||||
if (obj.multiServer != null) {
|
if (obj.multiServer != null) {
|
||||||
if ((obj.db.databaseType != 3) || (obj.db.changeStream != true)) { console.log("ERROR: Multi-server support requires use of MongoDB with ReplicaSet and ChangeStream enabled."); process.exit(0); return; }
|
if ((obj.db.databaseType != 3) || (obj.db.changeStream != true)) { console.log("ERROR: Multi-server support requires use of MongoDB with ReplicaSet and ChangeStream enabled."); process.exit(0); return; }
|
||||||
if (typeof obj.args.sessionkey != 'string') { console.log("ERROR: Multi-server support requires \"SessionKey\" be set in the settings section of config.json, same key for all servers."); process.exit(0); return; }
|
if (typeof obj.args.sessionkey != 'string') { console.log("ERROR: Multi-server support requires \"SessionKey\" be set in the settings section of config.json, same key for all servers."); process.exit(0); return; }
|
||||||
obj.serverId = obj.multiServer.serverid;
|
obj.serverId = obj.multiServer.serverid;
|
||||||
for (var serverid in obj.config.peers.servers) { obj.peerConnectivityByNode[serverid] = {}; }
|
for (var serverid in obj.config.peers.servers) { obj.peerConnectivityByNode[serverid] = {}; }
|
||||||
}
|
}
|
||||||
|
|
||||||
// If the server is set to "nousers", allow only loopback unless IP filter is set
|
// If the server is set to "nousers", allow only loopback unless IP filter is set
|
||||||
if ((obj.args.nousers == true) && (obj.args.userallowedip == null)) { obj.args.userallowedip = "::1,127.0.0.1"; }
|
if ((obj.args.nousers == true) && (obj.args.userallowedip == null)) { obj.args.userallowedip = "::1,127.0.0.1"; }
|
||||||
|
|
||||||
// Set the session length to 60 minutes if not set and set a random key if needed
|
// Set the session length to 60 minutes if not set and set a random key if needed
|
||||||
if ((obj.args.sessiontime != null) && ((typeof obj.args.sessiontime != 'number') || (obj.args.sessiontime < 1))) { delete obj.args.sessiontime; }
|
if ((obj.args.sessiontime != null) && ((typeof obj.args.sessiontime != 'number') || (obj.args.sessiontime < 1))) { delete obj.args.sessiontime; }
|
||||||
if (typeof obj.args.sessionkey != 'string') { obj.args.sessionkey = buf.toString('hex').toUpperCase(); }
|
if (typeof obj.args.sessionkey != 'string') { obj.args.sessionkey = buf.toString('hex').toUpperCase(); }
|
||||||
|
|
||||||
// Create MQTT Broker to hook into webserver and mpsserver
|
// Create MQTT Broker to hook into webserver and mpsserver
|
||||||
if ((typeof obj.config.settings.mqtt == 'object') && (typeof obj.config.settings.mqtt.auth == 'object') && (typeof obj.config.settings.mqtt.auth.keyid == 'string') && (typeof obj.config.settings.mqtt.auth.key == 'string')) { obj.mqttbroker = require("./mqttbroker.js").CreateMQTTBroker(obj, obj.db, obj.args); }
|
if ((typeof obj.config.settings.mqtt == 'object') && (typeof obj.config.settings.mqtt.auth == 'object') && (typeof obj.config.settings.mqtt.auth.keyid == 'string') && (typeof obj.config.settings.mqtt.auth.key == 'string')) { obj.mqttbroker = require("./mqttbroker.js").CreateMQTTBroker(obj, obj.db, obj.args); }
|
||||||
|
|
||||||
// Start the web server and if needed, the redirection web server.
|
// Start the web server and if needed, the redirection web server.
|
||||||
obj.webserver = require('./webserver.js').CreateWebServer(obj, obj.db, obj.args, obj.certificates, obj.StartEx5);
|
obj.webserver = require('./webserver.js').CreateWebServer(obj, obj.db, obj.args, obj.certificates, obj.StartEx5);
|
||||||
if (obj.redirserver != null) { obj.redirserver.hookMainWebServer(obj.certificates); }
|
if (obj.redirserver != null) { obj.redirserver.hookMainWebServer(obj.certificates); }
|
||||||
|
|
||||||
// Update proxy certificates
|
// Update proxy certificates
|
||||||
if (obj.supportsProxyCertificatesRequest == true) { obj.updateProxyCertificates(true); }
|
if (obj.supportsProxyCertificatesRequest == true) { obj.updateProxyCertificates(true); }
|
||||||
|
|
||||||
// Setup the Intel AMT event handler
|
// Setup the Intel AMT event handler
|
||||||
obj.amtEventHandler = require('./amtevents.js').CreateAmtEventsHandler(obj);
|
obj.amtEventHandler = require('./amtevents.js').CreateAmtEventsHandler(obj);
|
||||||
|
|
||||||
// Setup the Intel AMT local network scanner
|
// Setup the Intel AMT local network scanner
|
||||||
if (obj.args.wanonly != true) {
|
if (obj.args.wanonly != true) {
|
||||||
if (obj.args.amtscanner != false) { obj.amtScanner = require('./amtscanner.js').CreateAmtScanner(obj).start(); }
|
if (obj.args.amtscanner != false) { obj.amtScanner = require('./amtscanner.js').CreateAmtScanner(obj).start(); }
|
||||||
if (obj.args.meshscanner != false) { obj.meshScanner = require('./meshscanner.js').CreateMeshScanner(obj).start(); }
|
if (obj.args.meshscanner != false) { obj.meshScanner = require('./meshscanner.js').CreateMeshScanner(obj).start(); }
|
||||||
}
|
}
|
||||||
|
|
||||||
// Setup and start the MPS server
|
// Setup and start the MPS server
|
||||||
obj.mpsserver = require('./mpsserver.js').CreateMpsServer(obj, obj.db, obj.args, obj.certificates);
|
obj.mpsserver = require('./mpsserver.js').CreateMpsServer(obj, obj.db, obj.args, obj.certificates);
|
||||||
|
|
||||||
// Setup the Intel AMT manager
|
// Setup the Intel AMT manager
|
||||||
if (obj.args.amtmanager !== false) {
|
if (obj.args.amtmanager !== false) {
|
||||||
obj.amtManager = require('./amtmanager.js').CreateAmtManager(obj);
|
obj.amtManager = require('./amtmanager.js').CreateAmtManager(obj);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Setup and start the legacy swarm server
|
// Setup and start the legacy swarm server
|
||||||
if ((obj.certificates.swarmserver != null) && (obj.args.swarmport != null) && (obj.args.swarmport !== 0)) {
|
if ((obj.certificates.swarmserver != null) && (obj.args.swarmport != null) && (obj.args.swarmport !== 0)) {
|
||||||
obj.swarmserver = require('./swarmserver.js').CreateSwarmServer(obj, obj.db, obj.args, obj.certificates);
|
obj.swarmserver = require('./swarmserver.js').CreateSwarmServer(obj, obj.db, obj.args, obj.certificates);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Setup the main email server
|
// Setup the main email server
|
||||||
if (obj.config.sendgrid != null) {
|
if (obj.config.sendgrid != null) {
|
||||||
// Sendgrid server
|
|
||||||
obj.mailserver = require('./meshmail.js').CreateMeshMail(obj);
|
|
||||||
obj.mailserver.verify();
|
|
||||||
if (obj.args.lanonly == true) { addServerWarning("SendGrid server has limited use in LAN mode.", 17); }
|
|
||||||
} else if (obj.config.smtp != null) {
|
|
||||||
// SMTP server
|
|
||||||
obj.mailserver = require('./meshmail.js').CreateMeshMail(obj);
|
|
||||||
obj.mailserver.verify();
|
|
||||||
if (obj.args.lanonly == true) { addServerWarning("SMTP server has limited use in LAN mode.", 18); }
|
|
||||||
} else if (obj.config.sendmail != null) {
|
|
||||||
// Sendmail server
|
|
||||||
obj.mailserver = require('./meshmail.js').CreateMeshMail(obj);
|
|
||||||
obj.mailserver.verify();
|
|
||||||
if (obj.args.lanonly == true) { addServerWarning("SMTP server has limited use in LAN mode.", 18); }
|
|
||||||
}
|
|
||||||
|
|
||||||
// Setup the email server for each domain
|
|
||||||
for (i in obj.config.domains) {
|
|
||||||
if (obj.config.domains[i].sendgrid != null) {
|
|
||||||
// Sendgrid server
|
// Sendgrid server
|
||||||
obj.config.domains[i].mailserver = require('./meshmail.js').CreateMeshMail(obj, obj.config.domains[i]);
|
obj.mailserver = require('./meshmail.js').CreateMeshMail(obj);
|
||||||
obj.config.domains[i].mailserver.verify();
|
obj.mailserver.verify();
|
||||||
if (obj.args.lanonly == true) { addServerWarning("SendGrid server has limited use in LAN mode.", 17); }
|
if (obj.args.lanonly == true) { addServerWarning("SendGrid server has limited use in LAN mode.", 17); }
|
||||||
} else if ((obj.config.domains[i].smtp != null) && (obj.config.domains[i].smtp.host != null) && (obj.config.domains[i].smtp.from != null)) {
|
} else if (obj.config.smtp != null) {
|
||||||
// SMTP server
|
// SMTP server
|
||||||
obj.config.domains[i].mailserver = require('./meshmail.js').CreateMeshMail(obj, obj.config.domains[i]);
|
obj.mailserver = require('./meshmail.js').CreateMeshMail(obj);
|
||||||
obj.config.domains[i].mailserver.verify();
|
obj.mailserver.verify();
|
||||||
if (obj.args.lanonly == true) { addServerWarning("SMTP server has limited use in LAN mode.", 18); }
|
if (obj.args.lanonly == true) { addServerWarning("SMTP server has limited use in LAN mode.", 18); }
|
||||||
} else if (obj.config.domains[i].sendmail != null) {
|
} else if (obj.config.sendmail != null) {
|
||||||
// Sendmail server
|
// Sendmail server
|
||||||
obj.config.domains[i].mailserver = require('./meshmail.js').CreateMeshMail(obj, obj.config.domains[i]);
|
obj.mailserver = require('./meshmail.js').CreateMeshMail(obj);
|
||||||
obj.config.domains[i].mailserver.verify();
|
obj.mailserver.verify();
|
||||||
if (obj.args.lanonly == true) { addServerWarning("SMTP server has limited use in LAN mode.", 18); }
|
if (obj.args.lanonly == true) { addServerWarning("SMTP server has limited use in LAN mode.", 18); }
|
||||||
} else {
|
|
||||||
// Setup the parent mail server for this domain
|
|
||||||
if (obj.mailserver != null) { obj.config.domains[i].mailserver = obj.mailserver; }
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
// Setup SMS gateway
|
// Setup the email server for each domain
|
||||||
if (config.sms != null) {
|
for (i in obj.config.domains) {
|
||||||
obj.smsserver = require('./meshsms.js').CreateMeshSMS(obj);
|
if (obj.config.domains[i].sendgrid != null) {
|
||||||
if ((obj.smsserver != null) && (obj.args.lanonly == true)) { addServerWarning("SMS gateway has limited use in LAN mode.", 19); }
|
// Sendgrid server
|
||||||
}
|
obj.config.domains[i].mailserver = require('./meshmail.js').CreateMeshMail(obj, obj.config.domains[i]);
|
||||||
|
obj.config.domains[i].mailserver.verify();
|
||||||
// Setup web based push notifications
|
if (obj.args.lanonly == true) { addServerWarning("SendGrid server has limited use in LAN mode.", 17); }
|
||||||
if ((typeof config.settings.webpush == 'object') && (typeof config.settings.webpush.email == 'string')) {
|
} else if ((obj.config.domains[i].smtp != null) && (obj.config.domains[i].smtp.host != null) && (obj.config.domains[i].smtp.from != null)) {
|
||||||
obj.webpush = require('web-push');
|
// SMTP server
|
||||||
var vapidKeys = null;
|
obj.config.domains[i].mailserver = require('./meshmail.js').CreateMeshMail(obj, obj.config.domains[i]);
|
||||||
try { vapidKeys = JSON.parse(obj.fs.readFileSync(obj.path.join(obj.datapath, 'vapid.json')).toString()); } catch (ex) { }
|
obj.config.domains[i].mailserver.verify();
|
||||||
if ((vapidKeys == null) || (typeof vapidKeys.publicKey != 'string') || (typeof vapidKeys.privateKey != 'string')) {
|
if (obj.args.lanonly == true) { addServerWarning("SMTP server has limited use in LAN mode.", 18); }
|
||||||
console.log("Generating web push VAPID keys...");
|
} else if (obj.config.domains[i].sendmail != null) {
|
||||||
vapidKeys = obj.webpush.generateVAPIDKeys();
|
// Sendmail server
|
||||||
obj.fs.writeFileSync(obj.path.join(obj.datapath, 'vapid.json'), JSON.stringify(vapidKeys));
|
obj.config.domains[i].mailserver = require('./meshmail.js').CreateMeshMail(obj, obj.config.domains[i]);
|
||||||
}
|
obj.config.domains[i].mailserver.verify();
|
||||||
obj.webpush.vapidPublicKey = vapidKeys.publicKey;
|
if (obj.args.lanonly == true) { addServerWarning("SMTP server has limited use in LAN mode.", 18); }
|
||||||
obj.webpush.setVapidDetails('mailto:' + config.settings.webpush.email, vapidKeys.publicKey, vapidKeys.privateKey);
|
|
||||||
if (typeof config.settings.webpush.gcmapi == 'string') { webpush.setGCMAPIKey(config.settings.webpush.gcmapi); }
|
|
||||||
}
|
|
||||||
|
|
||||||
// Setup Firebase
|
|
||||||
if ((config.firebase != null) && (typeof config.firebase.senderid == 'string') && (typeof config.firebase.serverkey == 'string')) {
|
|
||||||
obj.firebase = require('./firebase').CreateFirebase(obj, config.firebase.senderid, config.firebase.serverkey);
|
|
||||||
} else if ((typeof config.firebaserelay == 'object') && (typeof config.firebaserelay.url == 'string')) {
|
|
||||||
// Setup the push messaging relay
|
|
||||||
obj.firebase = require('./firebase').CreateFirebaseRelay(obj, config.firebaserelay.url, config.firebaserelay.key);
|
|
||||||
} else if (obj.config.settings.publicpushnotifications === true) {
|
|
||||||
// Setup the Firebase push messaging relay using https://meshcentral.com, this is the public push notification server.
|
|
||||||
obj.firebase = require('./firebase').CreateFirebaseRelay(obj, 'https://meshcentral.com/firebaserelay.aspx');
|
|
||||||
}
|
|
||||||
|
|
||||||
// Start periodic maintenance
|
|
||||||
obj.maintenanceTimer = setInterval(obj.maintenanceActions, 1000 * 60 * 60); // Run this every hour
|
|
||||||
|
|
||||||
// Dispatch an event that the server is now running
|
|
||||||
obj.DispatchEvent(['*'], obj, { etype: 'server', action: 'started', msg: 'Server started' });
|
|
||||||
|
|
||||||
// Plugin hook. Need to run something at server startup? This is the place.
|
|
||||||
if (obj.pluginHandler) { obj.pluginHandler.callHook('server_startup'); }
|
|
||||||
|
|
||||||
// Setup the login cookie encryption key
|
|
||||||
if ((obj.config) && (obj.config.settings) && (typeof obj.config.settings.logincookieencryptionkey == 'string')) {
|
|
||||||
// We have a string, hash it and use that as a key
|
|
||||||
try { obj.loginCookieEncryptionKey = Buffer.from(obj.config.settings.logincookieencryptionkey, 'hex'); } catch (ex) { }
|
|
||||||
if ((obj.loginCookieEncryptionKey == null) || (obj.loginCookieEncryptionKey.length != 80)) { addServerWarning("Invalid \"LoginCookieEncryptionKey\" in config.json.", 20); obj.loginCookieEncryptionKey = null; }
|
|
||||||
}
|
|
||||||
|
|
||||||
// Login cookie encryption key not set, use one from the database
|
|
||||||
if (obj.loginCookieEncryptionKey == null) {
|
|
||||||
obj.db.Get('LoginCookieEncryptionKey', function (err, docs) {
|
|
||||||
if ((docs != null) && (docs.length > 0) && (docs[0].key != null) && (obj.args.logintokengen == null) && (docs[0].key.length >= 160)) {
|
|
||||||
obj.loginCookieEncryptionKey = Buffer.from(docs[0].key, 'hex');
|
|
||||||
} else {
|
} else {
|
||||||
obj.loginCookieEncryptionKey = obj.generateCookieKey(); obj.db.Set({ _id: 'LoginCookieEncryptionKey', key: obj.loginCookieEncryptionKey.toString('hex'), time: Date.now() });
|
// Setup the parent mail server for this domain
|
||||||
|
if (obj.mailserver != null) { obj.config.domains[i].mailserver = obj.mailserver; }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Setup SMS gateway
|
||||||
|
if (config.sms != null) {
|
||||||
|
obj.smsserver = require('./meshsms.js').CreateMeshSMS(obj);
|
||||||
|
if ((obj.smsserver != null) && (obj.args.lanonly == true)) { addServerWarning("SMS gateway has limited use in LAN mode.", 19); }
|
||||||
|
}
|
||||||
|
|
||||||
|
// Setup web based push notifications
|
||||||
|
if ((typeof config.settings.webpush == 'object') && (typeof config.settings.webpush.email == 'string')) {
|
||||||
|
obj.webpush = require('web-push');
|
||||||
|
var vapidKeys = null;
|
||||||
|
try { vapidKeys = JSON.parse(obj.fs.readFileSync(obj.path.join(obj.datapath, 'vapid.json')).toString()); } catch (ex) { }
|
||||||
|
if ((vapidKeys == null) || (typeof vapidKeys.publicKey != 'string') || (typeof vapidKeys.privateKey != 'string')) {
|
||||||
|
console.log("Generating web push VAPID keys...");
|
||||||
|
vapidKeys = obj.webpush.generateVAPIDKeys();
|
||||||
|
obj.fs.writeFileSync(obj.path.join(obj.datapath, 'vapid.json'), JSON.stringify(vapidKeys));
|
||||||
|
}
|
||||||
|
obj.webpush.vapidPublicKey = vapidKeys.publicKey;
|
||||||
|
obj.webpush.setVapidDetails('mailto:' + config.settings.webpush.email, vapidKeys.publicKey, vapidKeys.privateKey);
|
||||||
|
if (typeof config.settings.webpush.gcmapi == 'string') { webpush.setGCMAPIKey(config.settings.webpush.gcmapi); }
|
||||||
|
}
|
||||||
|
|
||||||
|
// Setup Firebase
|
||||||
|
if ((config.firebase != null) && (typeof config.firebase.senderid == 'string') && (typeof config.firebase.serverkey == 'string')) {
|
||||||
|
obj.firebase = require('./firebase').CreateFirebase(obj, config.firebase.senderid, config.firebase.serverkey);
|
||||||
|
} else if ((typeof config.firebaserelay == 'object') && (typeof config.firebaserelay.url == 'string')) {
|
||||||
|
// Setup the push messaging relay
|
||||||
|
obj.firebase = require('./firebase').CreateFirebaseRelay(obj, config.firebaserelay.url, config.firebaserelay.key);
|
||||||
|
} else if (obj.config.settings.publicpushnotifications === true) {
|
||||||
|
// Setup the Firebase push messaging relay using https://meshcentral.com, this is the public push notification server.
|
||||||
|
obj.firebase = require('./firebase').CreateFirebaseRelay(obj, 'https://meshcentral.com/firebaserelay.aspx');
|
||||||
|
}
|
||||||
|
|
||||||
|
// Start periodic maintenance
|
||||||
|
obj.maintenanceTimer = setInterval(obj.maintenanceActions, 1000 * 60 * 60); // Run this every hour
|
||||||
|
|
||||||
|
// Dispatch an event that the server is now running
|
||||||
|
obj.DispatchEvent(['*'], obj, { etype: 'server', action: 'started', msg: 'Server started' });
|
||||||
|
|
||||||
|
// Plugin hook. Need to run something at server startup? This is the place.
|
||||||
|
if (obj.pluginHandler) { obj.pluginHandler.callHook('server_startup'); }
|
||||||
|
|
||||||
|
// Setup the login cookie encryption key
|
||||||
|
if ((obj.config) && (obj.config.settings) && (typeof obj.config.settings.logincookieencryptionkey == 'string')) {
|
||||||
|
// We have a string, hash it and use that as a key
|
||||||
|
try { obj.loginCookieEncryptionKey = Buffer.from(obj.config.settings.logincookieencryptionkey, 'hex'); } catch (ex) { }
|
||||||
|
if ((obj.loginCookieEncryptionKey == null) || (obj.loginCookieEncryptionKey.length != 80)) { addServerWarning("Invalid \"LoginCookieEncryptionKey\" in config.json.", 20); obj.loginCookieEncryptionKey = null; }
|
||||||
|
}
|
||||||
|
|
||||||
|
// Login cookie encryption key not set, use one from the database
|
||||||
|
if (obj.loginCookieEncryptionKey == null) {
|
||||||
|
obj.db.Get('LoginCookieEncryptionKey', function (err, docs) {
|
||||||
|
if ((docs != null) && (docs.length > 0) && (docs[0].key != null) && (obj.args.logintokengen == null) && (docs[0].key.length >= 160)) {
|
||||||
|
obj.loginCookieEncryptionKey = Buffer.from(docs[0].key, 'hex');
|
||||||
|
} else {
|
||||||
|
obj.loginCookieEncryptionKey = obj.generateCookieKey(); obj.db.Set({ _id: 'LoginCookieEncryptionKey', key: obj.loginCookieEncryptionKey.toString('hex'), time: Date.now() });
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// Load the invitation link encryption key from the database
|
||||||
|
obj.db.Get('InvitationLinkEncryptionKey', function (err, docs) {
|
||||||
|
if ((docs != null) && (docs.length > 0) && (docs[0].key != null) && (docs[0].key.length >= 160)) {
|
||||||
|
obj.invitationLinkEncryptionKey = Buffer.from(docs[0].key, 'hex');
|
||||||
|
} else {
|
||||||
|
obj.invitationLinkEncryptionKey = obj.generateCookieKey(); obj.db.Set({ _id: 'InvitationLinkEncryptionKey', key: obj.invitationLinkEncryptionKey.toString('hex'), time: Date.now() });
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
|
||||||
|
|
||||||
// Load the invitation link encryption key from the database
|
// Setup Intel AMT hello server
|
||||||
obj.db.Get('InvitationLinkEncryptionKey', function (err, docs) {
|
if ((typeof config.settings.amtprovisioningserver == 'object') && (typeof config.settings.amtprovisioningserver.devicegroup == 'string') && (typeof config.settings.amtprovisioningserver.newmebxpassword == 'string') && (typeof config.settings.amtprovisioningserver.trustedfqdn == 'string') && (typeof config.settings.amtprovisioningserver.ip == 'string')) {
|
||||||
if ((docs != null) && (docs.length > 0) && (docs[0].key != null) && (docs[0].key.length >= 160)) {
|
obj.amtProvisioningServer = require('./amtprovisioningserver').CreateAmtProvisioningServer(obj, config.settings.amtprovisioningserver);
|
||||||
obj.invitationLinkEncryptionKey = Buffer.from(docs[0].key, 'hex');
|
|
||||||
} else {
|
|
||||||
obj.invitationLinkEncryptionKey = obj.generateCookieKey(); obj.db.Set({ _id: 'InvitationLinkEncryptionKey', key: obj.invitationLinkEncryptionKey.toString('hex'), time: Date.now() });
|
|
||||||
}
|
}
|
||||||
});
|
|
||||||
|
|
||||||
// Setup Intel AMT hello server
|
// Start collecting server stats every 5 minutes
|
||||||
if ((typeof config.settings.amtprovisioningserver == 'object') && (typeof config.settings.amtprovisioningserver.devicegroup == 'string') && (typeof config.settings.amtprovisioningserver.newmebxpassword == 'string') && (typeof config.settings.amtprovisioningserver.trustedfqdn == 'string') && (typeof config.settings.amtprovisioningserver.ip == 'string')) {
|
obj.trafficStats = obj.webserver.getTrafficStats();
|
||||||
obj.amtProvisioningServer = require('./amtprovisioningserver').CreateAmtProvisioningServer(obj, config.settings.amtprovisioningserver);
|
setInterval(function () {
|
||||||
}
|
obj.serverStatsCounter++;
|
||||||
|
var hours = 720; // Start with all events lasting 30 days.
|
||||||
|
if (((obj.serverStatsCounter) % 2) == 1) { hours = 3; } // Half of the event get removed after 3 hours.
|
||||||
|
else if ((Math.floor(obj.serverStatsCounter / 2) % 2) == 1) { hours = 8; } // Another half of the event get removed after 8 hours.
|
||||||
|
else if ((Math.floor(obj.serverStatsCounter / 4) % 2) == 1) { hours = 24; } // Another half of the event get removed after 24 hours.
|
||||||
|
else if ((Math.floor(obj.serverStatsCounter / 8) % 2) == 1) { hours = 48; } // Another half of the event get removed after 48 hours.
|
||||||
|
else if ((Math.floor(obj.serverStatsCounter / 16) % 2) == 1) { hours = 72; } // Another half of the event get removed after 72 hours.
|
||||||
|
const expire = new Date();
|
||||||
|
expire.setTime(expire.getTime() + (60 * 60 * 1000 * hours));
|
||||||
|
|
||||||
// Start collecting server stats every 5 minutes
|
// Get traffic data
|
||||||
obj.trafficStats = obj.webserver.getTrafficStats();
|
var trafficStats = obj.webserver.getTrafficDelta(obj.trafficStats);
|
||||||
setInterval(function () {
|
obj.trafficStats = trafficStats.current;
|
||||||
obj.serverStatsCounter++;
|
|
||||||
var hours = 720; // Start with all events lasting 30 days.
|
|
||||||
if (((obj.serverStatsCounter) % 2) == 1) { hours = 3; } // Half of the event get removed after 3 hours.
|
|
||||||
else if ((Math.floor(obj.serverStatsCounter / 2) % 2) == 1) { hours = 8; } // Another half of the event get removed after 8 hours.
|
|
||||||
else if ((Math.floor(obj.serverStatsCounter / 4) % 2) == 1) { hours = 24; } // Another half of the event get removed after 24 hours.
|
|
||||||
else if ((Math.floor(obj.serverStatsCounter / 8) % 2) == 1) { hours = 48; } // Another half of the event get removed after 48 hours.
|
|
||||||
else if ((Math.floor(obj.serverStatsCounter / 16) % 2) == 1) { hours = 72; } // Another half of the event get removed after 72 hours.
|
|
||||||
const expire = new Date();
|
|
||||||
expire.setTime(expire.getTime() + (60 * 60 * 1000 * hours));
|
|
||||||
|
|
||||||
// Get traffic data
|
var data = {
|
||||||
var trafficStats = obj.webserver.getTrafficDelta(obj.trafficStats);
|
time: new Date(),
|
||||||
obj.trafficStats = trafficStats.current;
|
expire: expire,
|
||||||
|
mem: process.memoryUsage(),
|
||||||
|
conn: {
|
||||||
|
ca: Object.keys(obj.webserver.wsagents).length,
|
||||||
|
cu: Object.keys(obj.webserver.wssessions).length,
|
||||||
|
us: Object.keys(obj.webserver.wssessions2).length,
|
||||||
|
rs: obj.webserver.relaySessionCount
|
||||||
|
},
|
||||||
|
traffic: trafficStats.delta
|
||||||
|
};
|
||||||
|
try { data.cpu = require('os').loadavg(); } catch (ex) { }
|
||||||
|
if (obj.mpsserver != null) {
|
||||||
|
data.conn.am = 0;
|
||||||
|
for (var i in obj.mpsserver.ciraConnections) { data.conn.am += obj.mpsserver.ciraConnections[i].length; }
|
||||||
|
}
|
||||||
|
if (obj.firstStats === true) { delete obj.firstStats; data.first = true; }
|
||||||
|
if (obj.multiServer != null) { data.s = obj.multiServer.serverid; }
|
||||||
|
obj.db.SetServerStats(data); // Save the stats to the database
|
||||||
|
obj.DispatchEvent(['*'], obj, { action: 'servertimelinestats', data: data }); // Event the server stats
|
||||||
|
}, 300000);
|
||||||
|
|
||||||
var data = {
|
obj.debug('main', "Server started");
|
||||||
time: new Date(),
|
if (obj.args.nousers == true) { obj.updateServerState('nousers', '1'); }
|
||||||
expire: expire,
|
obj.updateServerState('state', "running");
|
||||||
mem: process.memoryUsage(),
|
|
||||||
conn: {
|
// Setup auto-backup defaults
|
||||||
ca: Object.keys(obj.webserver.wsagents).length,
|
if (obj.config.settings.autobackup == null) { obj.config.settings.autobackup = { backupintervalhours: 24, keeplastdaysbackup: 10 }; }
|
||||||
cu: Object.keys(obj.webserver.wssessions).length,
|
else if (obj.config.settings.autobackup === false) { delete obj.config.settings.autobackup; }
|
||||||
us: Object.keys(obj.webserver.wssessions2).length,
|
|
||||||
rs: obj.webserver.relaySessionCount
|
// Check that autobackup path is not within the "meshcentral-data" folder.
|
||||||
},
|
if ((typeof obj.config.settings.autobackup == 'object') && (typeof obj.config.settings.autobackup.backuppath == 'string') && (obj.path.normalize(obj.config.settings.autobackup.backuppath).startsWith(obj.path.normalize(obj.datapath)))) {
|
||||||
traffic: trafficStats.delta
|
addServerWarning("Backup path can't be set within meshcentral-data folder, backup settings ignored.", 21);
|
||||||
};
|
delete obj.config.settings.autobackup;
|
||||||
try { data.cpu = require('os').loadavg(); } catch (ex) { }
|
|
||||||
if (obj.mpsserver != null) {
|
|
||||||
data.conn.am = 0;
|
|
||||||
for (var i in obj.mpsserver.ciraConnections) { data.conn.am += obj.mpsserver.ciraConnections[i].length; }
|
|
||||||
}
|
}
|
||||||
if (obj.firstStats === true) { delete obj.firstStats; data.first = true; }
|
|
||||||
if (obj.multiServer != null) { data.s = obj.multiServer.serverid; }
|
|
||||||
obj.db.SetServerStats(data); // Save the stats to the database
|
|
||||||
obj.DispatchEvent(['*'], obj, { action: 'servertimelinestats', data: data }); // Event the server stats
|
|
||||||
}, 300000);
|
|
||||||
|
|
||||||
obj.debug('main', "Server started");
|
// Load Intel AMT passwords from the "amtactivation.log" file
|
||||||
if (obj.args.nousers == true) { obj.updateServerState('nousers', '1'); }
|
obj.loadAmtActivationLogPasswords(function (amtPasswords) {
|
||||||
obj.updateServerState('state', "running");
|
obj.amtPasswords = amtPasswords;
|
||||||
|
});
|
||||||
|
|
||||||
// Setup auto-backup defaults
|
// Setup users that can see all device groups
|
||||||
if (obj.config.settings.autobackup == null) { obj.config.settings.autobackup = { backupintervalhours: 24, keeplastdaysbackup: 10 }; }
|
if (typeof obj.config.settings.managealldevicegroups == 'string') { obj.config.settings.managealldevicegroups = obj.config.settings.managealldevicegroups.split(','); }
|
||||||
else if (obj.config.settings.autobackup === false) { delete obj.config.settings.autobackup; }
|
else if (Array.isArray(obj.config.settings.managealldevicegroups) == false) { obj.config.settings.managealldevicegroups = []; }
|
||||||
|
for (i in obj.config.domains) {
|
||||||
// Check that autobackup path is not within the "meshcentral-data" folder.
|
if (Array.isArray(obj.config.domains[i].managealldevicegroups)) {
|
||||||
if ((typeof obj.config.settings.autobackup == 'object') && (typeof obj.config.settings.autobackup.backuppath == 'string') && (obj.path.normalize(obj.config.settings.autobackup.backuppath).startsWith(obj.path.normalize(obj.datapath)))) {
|
for (var j in obj.config.domains[i].managealldevicegroups) {
|
||||||
addServerWarning("Backup path can't be set within meshcentral-data folder, backup settings ignored.", 21);
|
if (typeof obj.config.domains[i].managealldevicegroups[j] == 'string') {
|
||||||
delete obj.config.settings.autobackup;
|
const u = 'user/' + i + '/' + obj.config.domains[i].managealldevicegroups[j];
|
||||||
}
|
if (obj.config.settings.managealldevicegroups.indexOf(u) == -1) { obj.config.settings.managealldevicegroups.push(u); }
|
||||||
|
}
|
||||||
// Load Intel AMT passwords from the "amtactivation.log" file
|
|
||||||
obj.loadAmtActivationLogPasswords(function (amtPasswords) {
|
|
||||||
obj.amtPasswords = amtPasswords;
|
|
||||||
});
|
|
||||||
|
|
||||||
// Setup users that can see all device groups
|
|
||||||
if (typeof obj.config.settings.managealldevicegroups == 'string') { obj.config.settings.managealldevicegroups = obj.config.settings.managealldevicegroups.split(','); }
|
|
||||||
else if (Array.isArray(obj.config.settings.managealldevicegroups) == false) { obj.config.settings.managealldevicegroups = []; }
|
|
||||||
for (i in obj.config.domains) {
|
|
||||||
if (Array.isArray(obj.config.domains[i].managealldevicegroups)) {
|
|
||||||
for (var j in obj.config.domains[i].managealldevicegroups) {
|
|
||||||
if (typeof obj.config.domains[i].managealldevicegroups[j] == 'string') {
|
|
||||||
const u = 'user/' + i + '/' + obj.config.domains[i].managealldevicegroups[j];
|
|
||||||
if (obj.config.settings.managealldevicegroups.indexOf(u) == -1) { obj.config.settings.managealldevicegroups.push(u); }
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
obj.config.settings.managealldevicegroups.sort();
|
||||||
obj.config.settings.managealldevicegroups.sort();
|
|
||||||
|
|
||||||
// Start watchdog timer if needed
|
// Start watchdog timer if needed
|
||||||
// This is used to monitor if NodeJS is servicing IO correctly or getting held up a lot. Add this line to the settings section of config.json
|
// This is used to monitor if NodeJS is servicing IO correctly or getting held up a lot. Add this line to the settings section of config.json
|
||||||
// "watchDog": { "interval": 100, "timeout": 150 }
|
// "watchDog": { "interval": 100, "timeout": 150 }
|
||||||
// This will check every 100ms, if the timer is more than 150ms late, it will warn.
|
// This will check every 100ms, if the timer is more than 150ms late, it will warn.
|
||||||
if ((typeof config.settings.watchdog == 'object') && (typeof config.settings.watchdog.interval == 'number') && (typeof config.settings.watchdog.timeout == 'number') && (config.settings.watchdog.interval >= 50) && (config.settings.watchdog.timeout >= 50)) {
|
if ((typeof config.settings.watchdog == 'object') && (typeof config.settings.watchdog.interval == 'number') && (typeof config.settings.watchdog.timeout == 'number') && (config.settings.watchdog.interval >= 50) && (config.settings.watchdog.timeout >= 50)) {
|
||||||
obj.watchdogtime = Date.now();
|
obj.watchdogtime = Date.now();
|
||||||
obj.watchdogmax = 0;
|
obj.watchdogmax = 0;
|
||||||
obj.watchdogmaxtime = null;
|
obj.watchdogmaxtime = null;
|
||||||
obj.watchdogtable = [];
|
obj.watchdogtable = [];
|
||||||
obj.watchdog = setInterval(function () {
|
obj.watchdog = setInterval(function () {
|
||||||
const now = Date.now(), delta = now - obj.watchdogtime - config.settings.watchdog.interval;
|
const now = Date.now(), delta = now - obj.watchdogtime - config.settings.watchdog.interval;
|
||||||
if (delta > obj.watchdogmax) { obj.watchdogmax = delta; obj.watchdogmaxtime = new Date().toLocaleString(); }
|
if (delta > obj.watchdogmax) { obj.watchdogmax = delta; obj.watchdogmaxtime = new Date().toLocaleString(); }
|
||||||
if (delta > config.settings.watchdog.timeout) {
|
if (delta > config.settings.watchdog.timeout) {
|
||||||
const msg = obj.common.format("Watchdog timer timeout, {0}ms.", delta);
|
const msg = obj.common.format("Watchdog timer timeout, {0}ms.", delta);
|
||||||
obj.watchdogtable.push(new Date().toLocaleString() + ', ' + delta + 'ms');
|
obj.watchdogtable.push(new Date().toLocaleString() + ', ' + delta + 'ms');
|
||||||
while (obj.watchdogtable.length > 10) { obj.watchdogtable.shift(); }
|
while (obj.watchdogtable.length > 10) { obj.watchdogtable.shift(); }
|
||||||
obj.debug('main', msg);
|
obj.debug('main', msg);
|
||||||
try {
|
try {
|
||||||
var errlogpath = null;
|
var errlogpath = null;
|
||||||
if (typeof obj.args.mesherrorlogpath == 'string') { errlogpath = obj.path.join(obj.args.mesherrorlogpath, 'mesherrors.txt'); } else { errlogpath = obj.getConfigFilePath('mesherrors.txt'); }
|
if (typeof obj.args.mesherrorlogpath == 'string') { errlogpath = obj.path.join(obj.args.mesherrorlogpath, 'mesherrors.txt'); } else { errlogpath = obj.getConfigFilePath('mesherrors.txt'); }
|
||||||
obj.fs.appendFileSync(errlogpath, new Date().toLocaleString() + ': ' + msg + '\r\n');
|
obj.fs.appendFileSync(errlogpath, new Date().toLocaleString() + ': ' + msg + '\r\n');
|
||||||
} catch (ex) { console.log('ERROR: Unable to write to mesherrors.txt.'); }
|
} catch (ex) { console.log('ERROR: Unable to write to mesherrors.txt.'); }
|
||||||
}
|
}
|
||||||
obj.watchdogtime = now;
|
obj.watchdogtime = now;
|
||||||
}, config.settings.watchdog.interval);
|
}, config.settings.watchdog.interval);
|
||||||
obj.debug('main', "Started watchdog timer.");
|
obj.debug('main', "Started watchdog timer.");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
@ -2841,24 +2843,29 @@ function CreateMeshCentralServer(config, args) {
|
|||||||
10006: { id: 10006, localname: 'MeshCentralAssistant.exe', rname: 'MeshCentralAssistant.exe', desc: 'MeshCentral Assistant for Windows', update: false, amt: false, platform: 'win32' } // MeshCentral Assistant
|
10006: { id: 10006, localname: 'MeshCentralAssistant.exe', rname: 'MeshCentralAssistant.exe', desc: 'MeshCentral Assistant for Windows', update: false, amt: false, platform: 'win32' } // MeshCentral Assistant
|
||||||
};
|
};
|
||||||
|
|
||||||
// Update the list of available mesh agents
|
// Sign windows agents
|
||||||
obj.updateMeshAgentsTable = function (domain, func) {
|
obj.signMeshAgents = function (domain, func) {
|
||||||
// Setup the domain is specified
|
// Setup the domain is specified
|
||||||
var objx = domain, suffix = '';
|
var objx = domain, suffix = '';
|
||||||
if (domain.id == '') { objx = obj; } else { suffix = '-' + domain.id; objx.meshAgentBinaries = {}; }
|
if (domain.id == '') { objx = obj; } else { suffix = '-' + domain.id; objx.meshAgentBinaries = {}; }
|
||||||
|
|
||||||
// Check if a custom agent signing certificate is available
|
// Check if a custom agent signing certificate is available
|
||||||
var agentSignCertInfo = require('./authenticode.js').loadCertificates([ obj.path.join(obj.datapath, 'agentsigningcert.pem') ]);
|
var agentSignCertInfo = require('./authenticode.js').loadCertificates([obj.path.join(obj.datapath, 'agentsigningcert.pem')]);
|
||||||
|
if (agentSignCertInfo == null) { func(); return; } // No code signing certificate, nothing to do.
|
||||||
|
|
||||||
// If not using a custom signing cert, get agent code signature certificate ready with the full cert chain
|
// If not using a custom signing cert, get agent code signature certificate ready with the full cert chain
|
||||||
if ((agentSignCertInfo == null) && (obj.certificates.codesign != null)) {
|
if ((agentSignCertInfo == null) && (obj.certificates.codesign != null)) {
|
||||||
agentSignCertInfo = {
|
agentSignCertInfo = {
|
||||||
cert: obj.certificateOperations.forge.pki.certificateFromPem(obj.certificates.codesign.cert),
|
cert: obj.certificateOperations.forge.pki.certificateFromPem(obj.certificates.codesign.cert),
|
||||||
key: obj.certificateOperations.forge.pki.privateKeyFromPem(obj.certificates.codesign.key),
|
key: obj.certificateOperations.forge.pki.privateKeyFromPem(obj.certificates.codesign.key),
|
||||||
extraCerts: [obj.certificateOperations.forge.pki.certificateFromPem(obj.certificates.root.cert) ]
|
extraCerts: [obj.certificateOperations.forge.pki.certificateFromPem(obj.certificates.root.cert)]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Setup the domain is specified
|
||||||
|
var objx = domain, suffix = '';
|
||||||
|
if (domain.id == '') { objx = obj; } else { suffix = '-' + domain.id; objx.meshAgentBinaries = {}; }
|
||||||
|
|
||||||
// Generate the agent signature description and URL
|
// Generate the agent signature description and URL
|
||||||
var serverSignedAgentsPath, signDesc, signUrl;
|
var serverSignedAgentsPath, signDesc, signUrl;
|
||||||
if (agentSignCertInfo != null) {
|
if (agentSignCertInfo != null) {
|
||||||
@ -2877,12 +2884,17 @@ function CreateMeshCentralServer(config, args) {
|
|||||||
if (obj.config.settings.agentsignlock) { signUrl += '?ServerID=' + obj.certificateOperations.getPublicKeyHash(obj.certificates.agent.cert).toUpperCase(); }
|
if (obj.config.settings.agentsignlock) { signUrl += '?ServerID=' + obj.certificateOperations.getPublicKeyHash(obj.certificates.agent.cert).toUpperCase(); }
|
||||||
}
|
}
|
||||||
|
|
||||||
// Load agent information file. This includes the data & time of the agent.
|
// Setup the time server
|
||||||
const agentInfo = [];
|
var timeStampUrl = 'http://timestamp.comodoca.com/authenticode';
|
||||||
try { agentInfo = JSON.parse(obj.fs.readFileSync(obj.path.join(__dirname, 'agents', 'hashagents.json'), 'utf8')); } catch (ex) { }
|
if (args.agenttimestampserver === false) { timeStampUrl = null; }
|
||||||
|
else if (typeof args.agenttimestampserver == 'string') { timeStampUrl = args.agenttimestampserver; }
|
||||||
|
|
||||||
|
// Setup the pending operations counter
|
||||||
|
var pendingOperations = 1;
|
||||||
|
|
||||||
var archcount = 0;
|
|
||||||
for (var archid in obj.meshAgentsArchitectureNumbers) {
|
for (var archid in obj.meshAgentsArchitectureNumbers) {
|
||||||
|
if (obj.meshAgentsArchitectureNumbers[archid].codesign !== true) continue;
|
||||||
|
|
||||||
var agentpath;
|
var agentpath;
|
||||||
if (domain.id == '') {
|
if (domain.id == '') {
|
||||||
// Load all agents when processing the default domain
|
// Load all agents when processing the default domain
|
||||||
@ -2895,46 +2907,83 @@ function CreateMeshCentralServer(config, args) {
|
|||||||
if (obj.fs.existsSync(agentpath)) { delete obj.meshAgentsArchitectureNumbers[archid].codesign; } else { continue; } // If the agent is not present in "meshcentral-data/agents" skip.
|
if (obj.fs.existsSync(agentpath)) { delete obj.meshAgentsArchitectureNumbers[archid].codesign; } else { continue; } // If the agent is not present in "meshcentral-data/agents" skip.
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Open the original agent with authenticode
|
||||||
|
var signeedagentpath = obj.path.join(serverSignedAgentsPath, obj.meshAgentsArchitectureNumbers[archid].localname);
|
||||||
|
const originalAgent = require('./authenticode.js').createAuthenticodeHandler(agentpath);
|
||||||
|
if (originalAgent != null) {
|
||||||
|
// Check if the agent is already signed correctly
|
||||||
|
const destinationAgent = require('./authenticode.js').createAuthenticodeHandler(signeedagentpath);
|
||||||
|
var destinationAgentOk = (
|
||||||
|
(destinationAgent != null) &&
|
||||||
|
(destinationAgent.fileHashSigned != null) &&
|
||||||
|
(Buffer.compare(destinationAgent.fileHashSigned, destinationAgent.fileHashActual) == 0) &&
|
||||||
|
((Buffer.compare(destinationAgent.fileHashSigned, originalAgent.getHash(destinationAgent.fileHashAlgo))) == 0) &&
|
||||||
|
(destinationAgent.signingAttribs.indexOf(signUrl) >= 0) &&
|
||||||
|
(destinationAgent.signingAttribs.indexOf(signDesc) >= 0)
|
||||||
|
);
|
||||||
|
if (destinationAgent != null) { destinationAgent.close(); }
|
||||||
|
if (destinationAgentOk == false) {
|
||||||
|
// If not signed correctly, sign it. First, create the server signed agent folder if needed
|
||||||
|
try { obj.fs.mkdirSync(serverSignedAgentsPath); } catch (ex) { }
|
||||||
|
const xagentSignedFunc = function agentSignedFunc(err, size) {
|
||||||
|
if (err == null) {
|
||||||
|
// Agent was signed succesfuly
|
||||||
|
console.log(obj.common.format('Code signed agent {0}.', agentSignedFunc.objx.meshAgentsArchitectureNumbers[agentSignedFunc.archid].localname));
|
||||||
|
} else {
|
||||||
|
console.log(obj.common.format('Failed to sign agent {0}: ' + err, agentSignedFunc.objx.meshAgentsArchitectureNumbers[agentSignedFunc.archid].localname));
|
||||||
|
}
|
||||||
|
if (--pendingOperations === 0) { agentSignedFunc.func(); }
|
||||||
|
}
|
||||||
|
pendingOperations++;
|
||||||
|
xagentSignedFunc.func = func;
|
||||||
|
xagentSignedFunc.objx = objx;
|
||||||
|
xagentSignedFunc.archid = archid;
|
||||||
|
xagentSignedFunc.signeedagentpath = signeedagentpath;
|
||||||
|
originalAgent.sign(agentSignCertInfo, { out: signeedagentpath, desc: signDesc, url: signUrl, time: timeStampUrl }, xagentSignedFunc);
|
||||||
|
} else {
|
||||||
|
// Signed agent is already ok, use it.
|
||||||
|
originalAgent.close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (--pendingOperations === 0) { func(); }
|
||||||
|
}
|
||||||
|
|
||||||
|
// Update the list of available mesh agents
|
||||||
|
obj.updateMeshAgentsTable = function (domain, func) {
|
||||||
|
// Check if a custom agent signing certificate is available
|
||||||
|
var agentSignCertInfo = require('./authenticode.js').loadCertificates([obj.path.join(obj.datapath, 'agentsigningcert.pem')]);
|
||||||
|
|
||||||
|
// Setup the domain is specified
|
||||||
|
var objx = domain, suffix = '';
|
||||||
|
if (domain.id == '') { objx = obj; } else { suffix = '-' + domain.id; objx.meshAgentBinaries = {}; }
|
||||||
|
|
||||||
|
// Load agent information file. This includes the data & time of the agent.
|
||||||
|
const 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;
|
||||||
|
if (domain.id == '') {
|
||||||
|
// Load all agents when processing the default domain
|
||||||
|
agentpath = obj.path.join(__dirname, 'agents' + suffix, obj.meshAgentsArchitectureNumbers[archid].localname);
|
||||||
|
const agentpath2 = obj.path.join(obj.datapath, 'signedagents' + suffix, obj.meshAgentsArchitectureNumbers[archid].localname);
|
||||||
|
if (obj.fs.existsSync(agentpath2)) { agentpath = agentpath2; } // If the agent is present in "meshcentral-data/signedagents", use that one instead.
|
||||||
|
const agentpath3 = obj.path.join(obj.datapath, 'agents' + suffix, obj.meshAgentsArchitectureNumbers[archid].localname);
|
||||||
|
if (obj.fs.existsSync(agentpath3)) { agentpath = agentpath3; } // If the agent is present in "meshcentral-data/agents", use that one instead.
|
||||||
|
} else {
|
||||||
|
// When processing an extra domain, only load agents that are specific to that domain
|
||||||
|
var agentpath = obj.path.join(obj.datapath, 'agents' + suffix, obj.meshAgentsArchitectureNumbers[archid].localname);
|
||||||
|
if (obj.fs.existsSync(agentpath)) { delete obj.meshAgentsArchitectureNumbers[archid].codesign; } else { continue; } // If the agent is not present in "meshcentral-data/agents" skip.
|
||||||
|
}
|
||||||
|
|
||||||
// Fetch agent binary information
|
// Fetch agent binary information
|
||||||
var stats = null;
|
var stats = null;
|
||||||
try { stats = obj.fs.statSync(agentpath); } catch (ex) { }
|
try { stats = obj.fs.statSync(agentpath); } catch (ex) { }
|
||||||
if ((stats == null)) continue; // If this agent does not exist, skip it.
|
if ((stats == null)) continue; // If this agent does not exist, skip it.
|
||||||
|
|
||||||
// Check if we need to sign this agent, if so, check if it's already been signed
|
|
||||||
if ((obj.meshAgentsArchitectureNumbers[archid].codesign === true) && (agentSignCertInfo != null)) {
|
|
||||||
// Open the original agent with authenticode
|
|
||||||
var signeedagentpath = obj.path.join(serverSignedAgentsPath, obj.meshAgentsArchitectureNumbers[archid].localname);
|
|
||||||
const originalAgent = require('./authenticode.js').createAuthenticodeHandler(agentpath);
|
|
||||||
if (originalAgent != null) {
|
|
||||||
// Check if the agent is already signed correctly
|
|
||||||
const destinationAgent = require('./authenticode.js').createAuthenticodeHandler(signeedagentpath);
|
|
||||||
var destinationAgentOk = (
|
|
||||||
(destinationAgent != null) &&
|
|
||||||
(destinationAgent.fileHashSigned != null) &&
|
|
||||||
(Buffer.compare(destinationAgent.fileHashSigned, destinationAgent.fileHashActual) == 0) &&
|
|
||||||
((Buffer.compare(destinationAgent.fileHashSigned, originalAgent.getHash(destinationAgent.fileHashAlgo))) == 0) &&
|
|
||||||
(destinationAgent.signingAttribs.indexOf(signUrl) >= 0) &&
|
|
||||||
(destinationAgent.signingAttribs.indexOf(signDesc) >= 0)
|
|
||||||
);
|
|
||||||
if (destinationAgent != null) { destinationAgent.close(); }
|
|
||||||
if (destinationAgentOk == false) {
|
|
||||||
// If not signed correctly, sign it. First, create the server signed agent folder if needed
|
|
||||||
try { obj.fs.mkdirSync(serverSignedAgentsPath); } catch (ex) { }
|
|
||||||
if (originalAgent.sign(agentSignCertInfo, { out: signeedagentpath, desc: signDesc, url: signUrl }) == true) {
|
|
||||||
// Agent was signed succesfuly
|
|
||||||
agentpath = signeedagentpath;
|
|
||||||
console.log(obj.common.format('Code signed agent {0}.', obj.meshAgentsArchitectureNumbers[archid].localname));
|
|
||||||
} else {
|
|
||||||
console.log(obj.common.format('Failed to sign agent {0}.', obj.meshAgentsArchitectureNumbers[archid].localname));
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// Signed agent is already ok, use it.
|
|
||||||
agentpath = signeedagentpath;
|
|
||||||
}
|
|
||||||
originalAgent.close();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Setup agent information
|
// Setup agent information
|
||||||
archcount++;
|
archcount++;
|
||||||
objx.meshAgentBinaries[archid] = Object.assign({}, obj.meshAgentsArchitectureNumbers[archid]);
|
objx.meshAgentBinaries[archid] = Object.assign({}, obj.meshAgentsArchitectureNumbers[archid]);
|
||||||
|
@ -38,6 +38,7 @@
|
|||||||
"_agentCoreDump": true,
|
"_agentCoreDump": true,
|
||||||
"_agentCoreDumpUsers": "user1,user2",
|
"_agentCoreDumpUsers": "user1,user2",
|
||||||
"_agentSignLock": true,
|
"_agentSignLock": true,
|
||||||
|
"_agentTimeStampServer": "http://timestamp.digicert.com",
|
||||||
"_ignoreAgentHashCheck": true,
|
"_ignoreAgentHashCheck": true,
|
||||||
"_exactPorts": true,
|
"_exactPorts": true,
|
||||||
"_allowLoginToken": true,
|
"_allowLoginToken": true,
|
||||||
|
Loading…
Reference in New Issue
Block a user