Added basic auth.log support.

Ylian Saint-Hilaire committed Feb 17, 2020 at 10:24 UTC 2cb3df77c52abb5239669519b9aae64af023a38e
5 files changed +38 -6
meshcentral.js
+16
@@ -861,6 +861,13 @@ function CreateMeshCentralServer(config, args) {
861 obj.StartEx1b = function () {
862 var i;
863
864 + // Linux format /var/log/auth.log
865 + if (obj.config.settings.authlog != null) {
866 + obj.fs.open(obj.config.settings.authlog, 'a', function (err, fd) {
867 + if (err == null) { obj.authlog = fd; } else { console.log('ERROR: Unable to open: ' + obj.config.settings.authlog); }
868 + })
869 + }
870 +
871 // Check if self update is allowed. If running as a Windows service, self-update is not possible.
872 if (obj.fs.existsSync(obj.path.join(__dirname, 'daemon'))) { obj.serverSelfWriteAllowed = false; }
873
@@ -2181,6 +2188,15 @@ function CreateMeshCentralServer(config, args) {
2188 obj.getServerWarnings = function () { return serverWarnings; }
2189 obj.addServerWarning = function(msg, print) { serverWarnings.push(msg); if (print !== false) { console.log("WARNING: " + msg); } }
2190
2191 + // auth.log functions
2192 + obj.authLog = function(server, msg) {
2193 + if (obj.authlog == null) return;
2194 + var d = new Date();
2195 + var month = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'][d.getMonth()];
2196 + var msg = month + ' ' + d.getDate() + ' ' + obj.common.zeroPad(d.getHours(),2) + ':' + obj.common.zeroPad(d.getMinutes(),2) + ':' + d.getSeconds() + ' meshcentral ' + server + '[' + process.pid + ']: ' + msg + ((obj.platform == 'win32')?'\r\n':'\n');
2197 + obj.fs.write(obj.authlog, msg, function (err, written, string) { });
2198 + }
2199 +
2200 // Return the path of a file into the meshcentral-data path
2201 obj.getConfigFilePath = function (filename) {
2202 if ((obj.config != null) && (obj.config.configfiles != null) && (obj.config.configfiles[filename] != null) && (typeof obj.config.configfiles[filename] == 'string')) {
mpsserver.js
+5 -1
@@ -40,7 +40,11 @@ module.exports.CreateMpsServer = function (parent, db, args, certificates) {
40 obj.server.on('resumeSession', function (id, cb) { cb(null, tlsSessionStore[id.toString('hex')] || null); });
41 }
42
43 - obj.server.listen(args.mpsport, function () { console.log("MeshCentral Intel(R) AMT server running on " + certificates.AmtMpsName + ":" + args.mpsport + ((args.mpsaliasport != null) ? (", alias port " + args.mpsaliasport) : "") + "."); }).on("error", function (err) { console.error("ERROR: MeshCentral Intel(R) AMT server port " + args.mpsport + " is not available."); if (args.exactports) { process.exit(); } });
43 + obj.server.listen(args.mpsport, function () {
44 + console.log("MeshCentral Intel(R) AMT server running on " + certificates.AmtMpsName + ":" + args.mpsport + ((args.mpsaliasport != null) ? (", alias port " + args.mpsaliasport) : "") + ".");
45 + obj.parent.authLog('mps', 'Server listening on 0.0.0.0 port ' + args.mpsport + '.');
46 + }).on("error", function (err) { console.error("ERROR: MeshCentral Intel(R) AMT server port " + args.mpsport + " is not available."); if (args.exactports) { process.exit(); } });
47 +
48 obj.server.on('tlsClientError', function (err, tlssocket) { if (args.mpsdebug) { var remoteAddress = tlssocket.remoteAddress; if (tlssocket.remoteFamily == 'IPv6') { remoteAddress = '[' + remoteAddress + ']'; } console.log('MPS:Invalid TLS connection from ' + remoteAddress + ':' + tlssocket.remotePort + '.'); } });
49 obj.parent.updateServerState('mps-port', args.mpsport);
50 obj.parent.updateServerState('mps-name', certificates.AmtMpsName);
redirserver.js
+4 -3
@@ -127,10 +127,11 @@ module.exports.CreateRedirServer = function (parent, db, args, func) {
127 obj.tcpServer = obj.app.listen(port, function () {
128 obj.port = port;
129 console.log("MeshCentral HTTP redirection server running on port " + port + ".");
130 - obj.parent.updateServerState("redirect-port", port);
130 + obj.parent.authLog('http', 'Server listening on 0.0.0.0 port ' + port + '.');
131 + obj.parent.updateServerState('redirect-port', port);
132 func(obj.port);
132 - }).on("error", function (err) {
133 - if ((err.code == "EACCES") && (port < 65535)) { StartRedirServer(port + 1); } else { console.log(err); func(obj.port); }
133 + }).on('error', function (err) {
134 + if ((err.code == 'EACCES') && (port < 65535)) { StartRedirServer(port + 1); } else { console.log(err); func(obj.port); }
135 });
136 }
137
sample-config.json
+1
@@ -37,6 +37,7 @@
37 "_UserBlockedIP": "127.0.0.1,::1,192.168.0.100",
38 "_AgentAllowedIP": "192.168.0.100/24",
39 "_AgentBlockedIP": "127.0.0.1,::1",
40 + "_AuthLog": "c:\\temp\\auth.log",
41 "_LocalDiscovery": {
42 "name": "Local server name",
43 "info": "Information about this server"
webserver.js
+12 -2
@@ -695,6 +695,7 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) {
695 if ((req.body.token != null) || (req.body.hwtoken != null)) {
696 randomWaitTime = 2000 + (obj.crypto.randomBytes(2).readUInt16BE(0) % 4095); // This is a fail, wait a random time. 2 to 6 seconds.
697 req.session.messageid = 108; // Invalid token, try again.
698 + if (obj.parent.authlog) { obj.parent.authLog('https', 'Failed 2FA for ' + xusername + ' from ' + cleanRemoteAddr(req.ip) + ' port ' + req.port); }
699 parent.debug('web', 'handleLoginRequest: invalid 2FA token');
700 obj.parent.DispatchEvent(['*', 'server-users', 'user/' + domain.id + '/' + user.name], obj, { action: 'authfail', username: user.name, userid: 'user/' + domain.id + '/' + user.name, domain: domain.id, msg: 'User login attempt with incorrect 2nd factor from ' + cleanRemoteAddr(req.ip) });
701 obj.setbadLogin(req);
@@ -717,6 +718,7 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) {
718 }
719
720 // Login successful
721 + if (obj.parent.authlog) { obj.parent.authLog('https', 'Accepted password for ' + xusername + ' from ' + cleanRemoteAddr(req.ip) + ' port ' + req.connection.remotePort); }
722 parent.debug('web', 'handleLoginRequest: successful 2FA login');
723 completeLoginRequest(req, res, domain, user, userid, xusername, xpassword, direct);
724 }
@@ -725,10 +727,14 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) {
727 }
728
729 // Login successful
730 + if (obj.parent.authlog) { obj.parent.authLog('https', 'Accepted password for ' + xusername + ' from ' + cleanRemoteAddr(req.ip) + ' port ' + req.connection.remotePort); }
731 parent.debug('web', 'handleLoginRequest: successful login');
732 completeLoginRequest(req, res, domain, user, userid, xusername, xpassword, direct);
733 } else {
731 - // Login failed, wait a random delay
734 + // Login failed, log the error
735 + if (obj.parent.authlog) { obj.parent.authLog('https', 'Failed password for ' + xusername + ' from ' + cleanRemoteAddr(req.ip) + ' port ' + req.connection.remotePort); }
736 +
737 + // Wait a random delay
738 setTimeout(function () {
739 // If the account is locked, display that.
740 if (typeof xusername == 'string') {
@@ -1377,16 +1383,19 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) {
1383 // Login using SSPI
1384 domain.sspi.authenticate(req, res, function (err) {
1385 if ((err != null) || (req.connection.user == null)) {
1386 + if (obj.parent.authlog) { obj.parent.authLog('https', 'Failed SSPI-auth for ' + req.connection.user + ' from ' + cleanRemoteAddr(req.ip) + ' port ' + req.connection.remotePort); }
1387 parent.debug('web', 'handleRootRequest: SSPI auth required.');
1388 res.end('Authentication Required...');
1389 } else {
1390 + if (obj.parent.authlog) { obj.parent.authLog('https', 'Accepted SSPI-auth for ' + req.connection.user + ' from ' + cleanRemoteAddr(req.ip) + ' port ' + req.connection.remotePort); }
1391 parent.debug('web', 'handleRootRequest: SSPI auth ok.');
1392 handleRootRequestEx(req, res, domain, direct);
1393 }
1394 });
1395 } else if (req.query.user && req.query.pass) {
1388 - // User credentials are being passed in the URL. WARNING: Putting credentials in a URL is not good security... but people are requesting this option.
1396 + // User credentials are being passed in the URL. WARNING: Putting credentials in a URL is bad security... but people are requesting this option.
1397 obj.authenticate(req.query.user, req.query.pass, domain, function (err, userid) {
1398 + if (obj.parent.authlog) { obj.parent.authLog('https', 'Accepted password for ' + req.connection.user + ' from ' + cleanRemoteAddr(req.ip) + ' port ' + req.connection.remotePort); }
1399 parent.debug('web', 'handleRootRequest: user/pass in URL auth ok.');
1400 req.session.userid = userid;
1401 req.session.domainid = domain.id;
@@ -3804,6 +3813,7 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) {
3813 obj.tcpServer = obj.tlsServer.listen(port, function () { console.log('MeshCentral HTTPS server running on ' + certificates.CommonName + ':' + port + ((args.aliasport != null) ? (', alias port ' + args.aliasport) : '') + '.'); });
3814 obj.parent.updateServerState('servername', certificates.CommonName);
3815 }
3816 + if (obj.parent.authlog) { obj.parent.authLog('https', 'Server listening on 0.0.0.0 port ' + port + '.'); }
3817 obj.parent.updateServerState('https-port', port);
3818 if (args.aliasport != null) { obj.parent.updateServerState('https-aliasport', args.aliasport); }
3819 } else {