Improved MeshCmd error messages.
Ylian Saint-Hilaire committed
May 25, 2021 at 22:30 UTC
f73c5d2a123351626ee87cb144db96e5fc866053
4 files changed
+100
-81
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/meshcmd.js
+7
-1
@@ -2034,7 +2034,13 @@ function OnServerWebSocket(msg, s, head) {
2034
} else {
2035
console.log("Login token required, use --token [token].");
2036
}
2037
- } else { console.log("Invalid username or password."); }
2037
+ } else if (command.msg == 'badtlscert') {
2038
+ console.log("Invalid TLS certificate detected.");
2039
+ } else if (command.msg == 'badargs') {
2040
+ console.log("Invalid protocol arguments.");
2041
+ } else {
2042
+ console.log("Invalid username/password.");
2043
+ }
2044
} else { console.log("Server disconnected: " + command.msg); }
2045
process.exit(1);
2046
return;
webserver.js
+93
-80
@@ -6048,12 +6048,20 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) {
6048
6049
switch (command.action) {
6050
case 'serverAuth': { // This command is used to perform server "inner" authentication.
6051
- if (obj.common.validateString(command.cnonce, 1, 256) == false) break; // Check the client nonce
6052
- if (obj.common.validateString(command.tlshash, 1, 512) == false) break; // Check the TLS hash
6051
+ // Check the client nonce and TLS hash
6052
+ if ((obj.common.validateString(command.cnonce, 1, 256) == false) || (obj.common.validateString(command.tlshash, 1, 512) == false)) {
6053
+ try { ws.send(JSON.stringify({ action: 'close', cause: 'noauth', msg: 'badargs' })); } catch (ex) { }
6054
+ try { ws.close(); } catch (ex) { }
6055
+ break;
6056
+ }
6057
6058
// Check that the TLS hash is an acceptable one.
6059
var h = Buffer.from(command.tlshash, 'hex').toString('binary');
6056
- if ((obj.webCertificateHashs[domain.id] != h) && (obj.webCertificateFullHashs[domain.id] != h) && (obj.defaultWebCertificateHash != h) && (obj.defaultWebCertificateFullHash != h)) { try { ws.close(); } catch (ex) { } return; }
6060
+ if ((obj.webCertificateHashs[domain.id] != h) && (obj.webCertificateFullHashs[domain.id] != h) && (obj.defaultWebCertificateHash != h) && (obj.defaultWebCertificateFullHash != h)) {
6061
+ try { ws.send(JSON.stringify({ action: 'close', cause: 'noauth', msg: 'badtlscert' })); } catch (ex) { }
6062
+ try { ws.close(); } catch (ex) { }
6063
+ return;
6064
+ }
6065
6066
// TLS hash check is a success, sign the request.
6067
// Perform the hash signature using the server agent certificate
@@ -6069,89 +6077,94 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) {
6077
// Check username and password authentication
6078
if ((typeof command.username == 'string') && (typeof command.password == 'string')) {
6079
obj.authenticate(Buffer.from(command.username, 'base64').toString(), Buffer.from(command.password, 'base64').toString(), domain, function (err, userid, passhint, loginOptions) {
6072
- var user = obj.users[userid];
6073
- if ((err == null) && (user)) {
6074
- // Check if a 2nd factor is needed
6075
- var emailcheck = ((domain.mailserver != null) && (obj.parent.certificates.CommonName != null) && (obj.parent.certificates.CommonName.indexOf('.') != -1) && (obj.args.lanonly != true) && (domain.auth != 'sspi') && (domain.auth != 'ldap'))
6076
-
6077
- // See if we support two-factor trusted cookies
6078
- var twoFactorCookieDays = 30;
6079
- if (typeof domain.twofactorcookiedurationdays == 'number') { twoFactorCookieDays = domain.twofactorcookiedurationdays; }
6080
-
6081
- if (checkUserOneTimePasswordRequired(domain, user, req, loginOptions) == true) {
6082
- // Figure out if email 2FA is allowed
6083
- var email2fa = (((typeof domain.passwordrequirements != 'object') || (domain.passwordrequirements.email2factor != false)) && (domain.mailserver != null) && (user.otpekey != null));
6084
- var sms2fa = (((typeof domain.passwordrequirements != 'object') || (domain.passwordrequirements.sms2factor != false)) && (parent.smsserver != null) && (user.phone != null));
6085
- //var push2fa = ((parent.firebase != null) && (user.otpdev != null));
6086
- if ((typeof command.token != 'string') || (command.token == '**email**') || (command.token == '**sms**')/* || (command.token == '**push**')*/) {
6087
- if ((command.token == '**email**') && (email2fa == true)) {
6088
- // Cause a token to be sent to the user's registered email
6089
- user.otpekey = { k: obj.common.zeroPad(getRandomEightDigitInteger(), 8), d: Date.now() };
6090
- obj.db.SetUser(user);
6091
- parent.debug('web', 'Sending 2FA email to: ' + user.email);
6092
- domain.mailserver.sendAccountLoginMail(domain, user.email, user.otpekey.k, obj.getLanguageCodes(req), req.query.key);
6093
- // Ask for a login token & confirm email was sent
6094
- try { ws.send(JSON.stringify({ action: 'close', cause: 'noauth', msg: 'tokenrequired', email2fa: email2fa, sms2fa: sms2fa, email2fasent: true, twoFactorCookieDays: twoFactorCookieDays })); ws.close(); } catch (e) { }
6095
- } else if ((command.token == '**sms**') && (sms2fa == true)) {
6096
- // Cause a token to be sent to the user's phone number
6097
- user.otpsms = { k: obj.common.zeroPad(getRandomSixDigitInteger(), 6), d: Date.now() };
6098
- obj.db.SetUser(user);
6099
- parent.debug('web', 'Sending 2FA SMS to: ' + user.phone);
6100
- parent.smsserver.sendToken(domain, user.phone, user.otpsms.k, obj.getLanguageCodes(req));
6101
- // Ask for a login token & confirm sms was sent
6102
- try { ws.send(JSON.stringify({ action: 'close', cause: 'noauth', msg: 'tokenrequired', email2fa: email2fa, sms2fa: sms2fa, sms2fasent: true, twoFactorCookieDays: twoFactorCookieDays })); ws.close(); } catch (e) { }
6103
- /*
6104
- } else if ((command.token == '**push**') && (push2fa == true)) {
6105
- // Cause push notification to device
6106
- const code = Buffer.from(obj.common.zeroPad(getRandomSixDigitInteger(), 6)).toString('base64');
6107
- const authCookie = parent.encodeCookie({ a: 'checkAuth', c: code, u: user._id, n: user.otpdev });
6108
- var payload = { notification: { title: "MeshCentral", body: user.name + " authentication" }, data: { url: '2fa://auth?code=' + code + '&c=' + authCookie } };
6109
- var options = { priority: 'High', timeToLive: 60 }; // TTL: 1 minute
6110
- parent.firebase.sendToDevice(user.otpdev, payload, options, function (id, err, errdesc) {
6111
- if (err == null) { parent.debug('email', 'Successfully auth check send push message to device'); } else { parent.debug('email', 'Failed auth check push message to device, error: ' + errdesc); }
6112
- });
6113
- */
6114
- } else {
6115
- // Ask for a login token
6116
- parent.debug('web', 'Asking for login token');
6117
- try { ws.send(JSON.stringify({ action: 'close', cause: 'noauth', msg: 'tokenrequired', email2fa: email2fa, sms2fa: sms2fa, twoFactorCookieDays: twoFactorCookieDays })); ws.close(); } catch (ex) { console.log(ex); }
6118
- }
6119
- } else {
6120
- checkUserOneTimePassword(req, domain, user, command.token, null, function (result) {
6121
- if (result == false) {
6122
- // Failed, ask for a login token again
6123
- parent.debug('web', 'Invalid login token, asking again');
6124
- try { ws.send(JSON.stringify({ action: 'close', cause: 'noauth', msg: 'tokenrequired', email2fa: email2fa, sms2fa: sms2fa, twoFactorCookieDays: twoFactorCookieDays })); ws.close(); } catch (e) { }
6080
+ if ((err != null) || (userid == null)) {
6081
+ // Invalid authentication
6082
+ try { ws.send(JSON.stringify({ action: 'close', cause: 'noauth', msg: 'noauth-2c' })); } catch (ex) { }
6083
+ try { ws.close(); } catch (ex) { }
6084
+ } else {
6085
+ var user = obj.users[userid];
6086
+ if ((err == null) && (user)) {
6087
+ // Check if a 2nd factor is needed
6088
+ var emailcheck = ((domain.mailserver != null) && (obj.parent.certificates.CommonName != null) && (obj.parent.certificates.CommonName.indexOf('.') != -1) && (obj.args.lanonly != true) && (domain.auth != 'sspi') && (domain.auth != 'ldap'))
6089
+
6090
+ // See if we support two-factor trusted cookies
6091
+ var twoFactorCookieDays = 30;
6092
+ if (typeof domain.twofactorcookiedurationdays == 'number') { twoFactorCookieDays = domain.twofactorcookiedurationdays; }
6093
+
6094
+ if (checkUserOneTimePasswordRequired(domain, user, req, loginOptions) == true) {
6095
+ // Figure out if email 2FA is allowed
6096
+ var email2fa = (((typeof domain.passwordrequirements != 'object') || (domain.passwordrequirements.email2factor != false)) && (domain.mailserver != null) && (user.otpekey != null));
6097
+ var sms2fa = (((typeof domain.passwordrequirements != 'object') || (domain.passwordrequirements.sms2factor != false)) && (parent.smsserver != null) && (user.phone != null));
6098
+ //var push2fa = ((parent.firebase != null) && (user.otpdev != null));
6099
+ if ((typeof command.token != 'string') || (command.token == '**email**') || (command.token == '**sms**')/* || (command.token == '**push**')*/) {
6100
+ if ((command.token == '**email**') && (email2fa == true)) {
6101
+ // Cause a token to be sent to the user's registered email
6102
+ user.otpekey = { k: obj.common.zeroPad(getRandomEightDigitInteger(), 8), d: Date.now() };
6103
+ obj.db.SetUser(user);
6104
+ parent.debug('web', 'Sending 2FA email to: ' + user.email);
6105
+ domain.mailserver.sendAccountLoginMail(domain, user.email, user.otpekey.k, obj.getLanguageCodes(req), req.query.key);
6106
+ // Ask for a login token & confirm email was sent
6107
+ try { ws.send(JSON.stringify({ action: 'close', cause: 'noauth', msg: 'tokenrequired', email2fa: email2fa, sms2fa: sms2fa, email2fasent: true, twoFactorCookieDays: twoFactorCookieDays })); ws.close(); } catch (e) { }
6108
+ } else if ((command.token == '**sms**') && (sms2fa == true)) {
6109
+ // Cause a token to be sent to the user's phone number
6110
+ user.otpsms = { k: obj.common.zeroPad(getRandomSixDigitInteger(), 6), d: Date.now() };
6111
+ obj.db.SetUser(user);
6112
+ parent.debug('web', 'Sending 2FA SMS to: ' + user.phone);
6113
+ parent.smsserver.sendToken(domain, user.phone, user.otpsms.k, obj.getLanguageCodes(req));
6114
+ // Ask for a login token & confirm sms was sent
6115
+ try { ws.send(JSON.stringify({ action: 'close', cause: 'noauth', msg: 'tokenrequired', email2fa: email2fa, sms2fa: sms2fa, sms2fasent: true, twoFactorCookieDays: twoFactorCookieDays })); ws.close(); } catch (e) { }
6116
+ /*
6117
+ } else if ((command.token == '**push**') && (push2fa == true)) {
6118
+ // Cause push notification to device
6119
+ const code = Buffer.from(obj.common.zeroPad(getRandomSixDigitInteger(), 6)).toString('base64');
6120
+ const authCookie = parent.encodeCookie({ a: 'checkAuth', c: code, u: user._id, n: user.otpdev });
6121
+ var payload = { notification: { title: "MeshCentral", body: user.name + " authentication" }, data: { url: '2fa://auth?code=' + code + '&c=' + authCookie } };
6122
+ var options = { priority: 'High', timeToLive: 60 }; // TTL: 1 minute
6123
+ parent.firebase.sendToDevice(user.otpdev, payload, options, function (id, err, errdesc) {
6124
+ if (err == null) { parent.debug('email', 'Successfully auth check send push message to device'); } else { parent.debug('email', 'Failed auth check push message to device, error: ' + errdesc); }
6125
+ });
6126
+ */
6127
} else {
6126
- // We are authenticated with 2nd factor.
6127
- // Check email verification
6128
- if (emailcheck && (user.email != null) && (user.emailVerified !== true)) {
6129
- parent.debug('web', 'Invalid login, asking for email validation');
6130
- try { ws.send(JSON.stringify({ action: 'close', cause: 'emailvalidation', msg: 'emailvalidationrequired', email2fa: email2fa, sms2fa: sms2fa, email2fasent: true })); ws.close(); } catch (e) { }
6128
+ // Ask for a login token
6129
+ parent.debug('web', 'Asking for login token');
6130
+ try { ws.send(JSON.stringify({ action: 'close', cause: 'noauth', msg: 'tokenrequired', email2fa: email2fa, sms2fa: sms2fa, twoFactorCookieDays: twoFactorCookieDays })); ws.close(); } catch (ex) { console.log(ex); }
6131
+ }
6132
+ } else {
6133
+ checkUserOneTimePassword(req, domain, user, command.token, null, function (result) {
6134
+ if (result == false) {
6135
+ // Failed, ask for a login token again
6136
+ parent.debug('web', 'Invalid login token, asking again');
6137
+ try { ws.send(JSON.stringify({ action: 'close', cause: 'noauth', msg: 'tokenrequired', email2fa: email2fa, sms2fa: sms2fa, twoFactorCookieDays: twoFactorCookieDays })); ws.close(); } catch (e) { }
6138
} else {
6132
- // We are authenticated
6133
- ws._socket.pause();
6134
- ws.removeAllListeners(['message', 'close', 'error']);
6135
- func(ws, req, domain, user);
6139
+ // We are authenticated with 2nd factor.
6140
+ // Check email verification
6141
+ if (emailcheck && (user.email != null) && (user.emailVerified !== true)) {
6142
+ parent.debug('web', 'Invalid login, asking for email validation');
6143
+ try { ws.send(JSON.stringify({ action: 'close', cause: 'emailvalidation', msg: 'emailvalidationrequired', email2fa: email2fa, sms2fa: sms2fa, email2fasent: true })); ws.close(); } catch (e) { }
6144
+ } else {
6145
+ // We are authenticated
6146
+ ws._socket.pause();
6147
+ ws.removeAllListeners(['message', 'close', 'error']);
6148
+ func(ws, req, domain, user);
6149
+ }
6150
}
6137
- }
6138
- });
6139
- }
6140
- } else {
6141
- // Check email verification
6142
- if (emailcheck && (user.email != null) && (user.emailVerified !== true)) {
6143
- parent.debug('web', 'Invalid login, asking for email validation');
6144
- var email2fa = (((typeof domain.passwordrequirements != 'object') || (domain.passwordrequirements.email2factor != false)) && (domain.mailserver != null) && (user.otpekey != null));
6145
- var sms2fa = (((typeof domain.passwordrequirements != 'object') || (domain.passwordrequirements.sms2factor != false)) && (parent.smsserver != null) && (user.phone != null));
6146
- try { ws.send(JSON.stringify({ action: 'close', cause: 'emailvalidation', msg: 'emailvalidationrequired', email2fa: email2fa, sms2fa: sms2fa, email2fasent: true })); ws.close(); } catch (e) { }
6151
+ });
6152
+ }
6153
} else {
6148
- // We are authenticated
6149
- ws._socket.pause();
6150
- ws.removeAllListeners(['message', 'close', 'error']);
6151
- func(ws, req, domain, user);
6154
+ // Check email verification
6155
+ if (emailcheck && (user.email != null) && (user.emailVerified !== true)) {
6156
+ parent.debug('web', 'Invalid login, asking for email validation');
6157
+ var email2fa = (((typeof domain.passwordrequirements != 'object') || (domain.passwordrequirements.email2factor != false)) && (domain.mailserver != null) && (user.otpekey != null));
6158
+ var sms2fa = (((typeof domain.passwordrequirements != 'object') || (domain.passwordrequirements.sms2factor != false)) && (parent.smsserver != null) && (user.phone != null));
6159
+ try { ws.send(JSON.stringify({ action: 'close', cause: 'emailvalidation', msg: 'emailvalidationrequired', email2fa: email2fa, sms2fa: sms2fa, email2fasent: true })); ws.close(); } catch (e) { }
6160
+ } else {
6161
+ // We are authenticated
6162
+ ws._socket.pause();
6163
+ ws.removeAllListeners(['message', 'close', 'error']);
6164
+ func(ws, req, domain, user);
6165
+ }
6166
}
6167
}
6154
-
6168
}
6169
});
6170
} else {