Added 2FA support in MeshCMD.
Ylian Saint-Hilaire committed
Apr 3, 2020 at 16:06 UTC
459540f7427e734d0d283793d1b333ff920abe06
7 files changed
+81
-18
agents/MeshCmd-signed.exe
Binary files a/agents/MeshCmd-signed.exe and b/agents/MeshCmd-signed.exe differ
agents/MeshCmd64-signed.exe
Binary files a/agents/MeshCmd64-signed.exe and b/agents/MeshCmd64-signed.exe differ
agents/MeshService-signed.exe
Binary files a/agents/MeshService-signed.exe and b/agents/MeshService-signed.exe differ
agents/MeshService64-signed.exe
Binary files a/agents/MeshService64-signed.exe and b/agents/MeshService64-signed.exe differ
agents/meshcmd.js
+77
-14
@@ -153,8 +153,10 @@ function run(argv) {
153
if ((typeof args.cdrom) == 'string') { settings.cdrom = args.cdrom; }
154
if ((typeof args.tag) == 'string') { settings.tag = args.tag; }
155
if ((typeof args.scan) == 'string') { settings.scan = args.scan; }
156
+ if ((typeof args.token) == 'string') { settings.token = args.token; }
157
if ((typeof args.timeout) == 'string') { settings.timeout = parseInt(args.timeout); }
158
if ((typeof args.uuidoutput) == 'string' || args.uuidoutput) { settings.uuidoutput = args.uuidoutput; }
159
+ if (args.emailtoken) { settings.emailtoken = true; }
160
if (args.debug === true) { settings.debuglevel = 1; }
161
if (args.debug) { try { waitForDebugger(); } catch (e) { } }
162
if (args.noconsole) { settings.noconsole = true; }
@@ -2048,20 +2050,80 @@ function processLmsControlData(data) {
2050
//
2051
2052
function startRouter() {
2053
+ // Start by requesting a login token, this is needed because of 2FA and check that we have correct credentials from the start
2054
+ var options;
2055
+ try {
2056
+ var url = settings.serverurl.split('meshrelay.ashx').join('control.ashx') + '?user=' + settings.username + '&pass=' + settings.password;
2057
+ if (settings.emailtoken) { url += '&token=**email**'; } else if (settings.token != null) { url += '&token=' + settings.token; }
2058
+ options = http.parseUri(url);
2059
+ } catch (e) { console.log("Unable to parse \"serverUrl\"."); process.exit(1); return; }
2060
+ options.checkServerIdentity = onVerifyServer;
2061
+ options.rejectUnauthorized = false;
2062
+ settings.websocket = http.request(options);
2063
+ settings.websocket.upgrade = OnServerWebSocket;
2064
+ settings.websocket.on('error', function (e) { console.log("ERROR: " + JSON.stringify(e)); });
2065
+ settings.websocket.end();
2066
+}
2067
+
2068
+function OnServerWebSocket(msg, s, head) {
2069
+ settings.webchannel = s;
2070
+ s.on('data', function (msg) {
2071
+ var command = JSON.parse(msg);
2072
+ switch (command.action) {
2073
+ case 'close': {
2074
+ if (command.cause == 'noauth') {
2075
+ if (command.msg == 'tokenrequired') {
2076
+ if (command.email2fasent === true) {
2077
+ console.log("Login token email sent.");
2078
+ } else if (command.email2fa === true) {
2079
+ console.log("Login token required, use --token [token], or --emailtoken get a token.");
2080
+ } else {
2081
+ console.log("Login token required, use --token [token].");
2082
+ }
2083
+ } else { console.log("Invalid username or password."); }
2084
+ } else { console.log("Server disconnected: " + command.msg); }
2085
+ process.exit(1);
2086
+ return;
2087
+ }
2088
+ case 'serverinfo': {
2089
+ s.write("{\"action\":\"authcookie\"}"); // Ask for our first authentication cookie
2090
+ break;
2091
+ }
2092
+ case 'authcookie': {
2093
+ if (settings.acookie == null) {
2094
+ settings.acookie = command.cookie;
2095
+ settings.rcookie = command.rcookie;
2096
+ settings.renewCookieTimer = setInterval(function () { settings.webchannel.write("{\"action\":\"authcookie\"}"); }, 600000); // Ask for new cookie every 10 minutes
2097
+ startRouterEx();
2098
+ } else {
2099
+ settings.acookie = command.cookie;
2100
+ settings.rcookie = command.rcookie;
2101
+ }
2102
+ break;
2103
+ }
2104
+ }
2105
+ });
2106
+ s.on('error', function () { console.log("Server connection error."); process.exit(1); return; });
2107
+ s.on('close', function () { console.log("Server closed the connection."); process.exit(1); return; });
2108
+}
2109
+
2110
+function startRouterEx() {
2111
tcpserver = net.createServer(OnTcpClientConnected);
2112
tcpserver.on('error', function (e) { console.log("ERROR: " + JSON.stringify(e)); exit(0); return; });
2053
- tcpserver.listen(settings.localport, function () {
2054
- // We started listening.
2055
- if (settings.remotetarget == null) {
2056
- console.log('Redirecting local port ' + settings.localport + ' to remote port ' + settings.remoteport + '.');
2057
- } else {
2058
- console.log('Redirecting local port ' + settings.localport + ' to ' + settings.remotetarget + ':' + settings.remoteport + '.');
2059
- }
2060
- console.log("Press ctrl-c to exit.");
2113
+ try {
2114
+ tcpserver.listen(settings.localport, function () {
2115
+ // We started listening.
2116
+ if (settings.remotetarget == null) {
2117
+ console.log('Redirecting local port ' + settings.localport + ' to remote port ' + settings.remoteport + '.');
2118
+ } else {
2119
+ console.log('Redirecting local port ' + settings.localport + ' to ' + settings.remotetarget + ':' + settings.remoteport + '.');
2120
+ }
2121
+ console.log("Press ctrl-c to exit.");
2122
2062
- // If settings has a "cmd", run it now.
2063
- //process.exec("notepad.exe");
2064
- });
2123
+ // If settings has a "cmd", run it now.
2124
+ //process.exec("notepad.exe");
2125
+ });
2126
+ } catch (ex) { console.log("Unable to bind to local TCP port " + settings.localport + "."); exit(1); return; }
2127
}
2128
2129
// Called when a TCP connect is received on the local port. Launch a tunnel.
@@ -2071,8 +2133,9 @@ function OnTcpClientConnected(c) {
2133
debug(1, "Client connected");
2134
c.on('end', function () { disconnectTunnel(this, this.websocket, "Client closed"); });
2135
c.pause();
2136
+ var options;
2137
try {
2075
- options = http.parseUri(settings.serverurl + '?user=' + settings.username + '&pass=' + settings.password + '&nodeid=' + settings.remotenodeid + '&tcpport=' + settings.remoteport + (settings.remotetarget == null ? '' : '&tcpaddr=' + settings.remotetarget));
2138
+ options = http.parseUri(settings.serverurl + '?auth=' + settings.acookie + '&nodeid=' + settings.remotenodeid + '&tcpport=' + settings.remoteport + (settings.remotetarget == null ? '' : '&tcpaddr=' + settings.remotetarget));
2139
} catch (e) { console.log("Unable to parse \"serverUrl\"."); process.exit(1); return; }
2140
options.checkServerIdentity = onVerifyServer;
2141
options.rejectUnauthorized = false;
@@ -2106,8 +2169,8 @@ function OnWebSocket(msg, s, head) {
2169
}
2170
}
2171
});
2109
- s.on('error', function (msg) { disconnectTunnel(this.tcp, this, 'Websocket error'); });
2110
- s.on('close', function (msg) { disconnectTunnel(this.tcp, this, 'Websocket closed'); });
2172
+ s.on('error', function () { disconnectTunnel(this.tcp, this, 'Websocket error'); });
2173
+ s.on('close', function () { disconnectTunnel(this.tcp, this, 'Websocket closed'); });
2174
s.parent = this;
2175
}
2176
package.json
+1
-1
@@ -1,6 +1,6 @@
1
{
2
"name": "meshcentral",
3
- "version": "0.5.1-b",
3
+ "version": "0.5.1-c",
4
"keywords": [
5
"Remote Management",
6
"Intel AMT",
webserver.js
+3
-3
@@ -3352,9 +3352,9 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) {
3352
localPort: 1234,
3353
remoteName: node.name,
3354
remoteNodeId: node._id,
3355
- remoteTarget: '',
3355
+ remoteTarget: null,
3356
remotePort: 3389,
3357
- username: '',
3357
+ username: user.name,
3358
password: '',
3359
serverId: obj.agentCertificateHashHex.toUpperCase(), // SHA384 of server HTTPS public key
3360
serverHttpsHash: Buffer.from(obj.webCertificateHashs[domain.id], 'binary').toString('hex').toUpperCase(), // SHA384 of server HTTPS certificate
@@ -3368,7 +3368,7 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) {
3368
});
3369
} else if (req.query.meshaction == 'generic') {
3370
var meshaction = {
3371
- username: '',
3371
+ username: user.name,
3372
password: '',
3373
serverId: obj.agentCertificateHashHex.toUpperCase(), // SHA384 of server HTTPS public key
3374
serverHttpsHash: Buffer.from(obj.webCertificateHashs[domain.id], 'binary').toString('hex').toUpperCase(), // SHA384 of server HTTPS certificate