More work on agent self-sharing.
Ylian Saint-Hilaire committed
Nov 10, 2021 at 15:19 UTC
6dceb842d721199af1752125e35992d8ef9b749b
1 file changed
+47
-28
meshdesktopmultiplex.js
+47
-28
@@ -138,7 +138,8 @@ function CreateDesktopMultiplexor(parent, domain, nodeid, func) {
138
if ((domain.sessionrecording.onlyselectedusers === true) && (peer.user != null) && (peer.user.flags != null) && ((peer.user.flags & 2) != 0)) { startRecord = true; }
139
else if (domain.sessionrecording.onlyselectedusergroups === true) {
140
// Check if there is a usergroup that requires recording of the session
141
- var user = parent.users[peer.user._id];
141
+ var user = null;
142
+ if (peer.user != null) { user = parent.users[peer.user._id]; }
143
if ((user != null) && (user.links != null) && (user.links[obj.meshid] == null) && (user.links[obj.nodeid] == null)) {
144
// This user does not have a direct link to the device group or device. Find all user groups the would cause the link.
145
for (var i in user.links) {
@@ -160,7 +161,7 @@ function CreateDesktopMultiplexor(parent, domain, nodeid, func) {
161
162
// Log joining the multiplex session
163
if (obj.startTime != null) {
163
- var event = { etype: 'relay', action: 'relaylog', domain: domain.id, nodeid: obj.nodeid, userid: peer.user._id, username: peer.user.name, msgid: 4, msg: "Joined desktop multiplex session", protocol: 2 };
164
+ var event = { etype: 'relay', action: 'relaylog', domain: domain.id, nodeid: obj.nodeid, userid: peer.user ? peer.user._id : null, username: peer.user.name, msgid: 4, msg: "Joined desktop multiplex session", protocol: 2 };
165
parent.parent.DispatchEvent(['*', obj.nodeid, peer.user._id, obj.meshid], obj, event);
166
}
167
@@ -188,8 +189,11 @@ function CreateDesktopMultiplexor(parent, domain, nodeid, func) {
189
190
// Log multiplex session start
191
if ((obj.agent != null) && (obj.viewers.length > 0) && (obj.startTime == null)) {
191
- var event = { etype: 'relay', action: 'relaylog', domain: domain.id, nodeid: obj.nodeid, userid: obj.viewers[0].user._id, username: obj.viewers[0].user.name, msgid: 6, msg: "Started desktop multiplex session", protocol: 2 };
192
- parent.parent.DispatchEvent(['*', obj.nodeid, obj.viewers[0].user._id, obj.meshid], obj, event);
192
+ var event = { etype: 'relay', action: 'relaylog', domain: domain.id, nodeid: obj.nodeid, msgid: 6, msg: "Started desktop multiplex session", protocol: 2 };
193
+ if (obj.viewers[0].user != null) { event.userid = obj.viewers[0].user._id; event.username = obj.viewers[0].user.name; }
194
+ const targets = ['*', obj.nodeid, obj.meshid];
195
+ if (obj.viewers[0].user != null) { targets.push(obj.viewers[0].user._id); }
196
+ parent.parent.DispatchEvent(targets, obj, event);
197
obj.startTime = Date.now();
198
}
199
return true;
@@ -265,9 +269,12 @@ function CreateDesktopMultiplexor(parent, domain, nodeid, func) {
269
270
//var event = { etype: 'relay', action: 'relaylog', domain: domain.id, nodeid: obj.nodeid, userid: peer.user._id, username: peer.user.name, msgid: 5, msg: "Left the desktop multiplex session", protocol: 2 };
271
const sessionSeconds = Math.floor((Date.now() - peer.startTime) / 1000);
268
- var event = { etype: 'relay', action: 'relaylog', domain: domain.id, nodeid: obj.nodeid, userid: peer.user._id, username: peer.user.name, msgid: 122, msgArgs: [sessionSeconds], msg: "Left the desktop multiplex session after " + sessionSeconds + " second(s).", protocol: 2, bytesin: inTraffc, bytesout: outTraffc };
272
+ var event = { etype: 'relay', action: 'relaylog', domain: domain.id, nodeid: obj.nodeid, msgid: 122, msgArgs: [sessionSeconds], msg: "Left the desktop multiplex session after " + sessionSeconds + " second(s).", protocol: 2, bytesin: inTraffc, bytesout: outTraffc };
273
+ if (peer.user != null) { event.userid = peer.user._id; event.username = peer.user.name; }
274
if (peer.guestName) { event.guestname = peer.guestName; }
270
- parent.parent.DispatchEvent(['*', obj.nodeid, peer.user._id, obj.meshid], obj, event);
275
+ const targets = ['*', obj.nodeid, obj.meshid];
276
+ if (peer.user != null) { targets.push(peer.user._id); }
277
+ parent.parent.DispatchEvent(targets, obj, event);
278
}
279
280
// Aggressive clean up of the viewer
@@ -997,6 +1004,7 @@ function CreateMeshRelayEx2(parent, ws, req, domain, user, cookie) {
1004
obj.ruserid = null;
1005
obj.req = req; // Used in multi-server.js
1006
obj.viewOnly = ((cookie != null) && (cookie.vo == 1)); // set view only mode
1007
+ if ((cookie != null) && (cookie.nouser == 1)) { obj.nouser = true; } // This is a relay without user authentication
1008
1009
// If the domain has remote desktop viewonly set, force everyone to be in viewonly mode.
1010
if ((typeof domain.desktop == 'object') && (domain.desktop.viewonly == true)) { obj.viewOnly = true; }
@@ -1018,12 +1026,12 @@ function CreateMeshRelayEx2(parent, ws, req, domain, user, cookie) {
1026
// Check relay authentication
1027
if ((user == null) && (obj.req.query != null) && (obj.req.query.rauth != null)) {
1028
const rcookie = parent.parent.decodeCookie(obj.req.query.rauth, parent.parent.loginCookieEncryptionKey, 240); // Cookie with 4 hour timeout
1021
- if (rcookie.ruserid != null) { obj.ruserid = rcookie.ruserid; }
1029
+ if (rcookie.ruserid != null) { obj.ruserid = rcookie.ruserid; } else if (rcookie.nouser === 1) { obj.rnouser = true; }
1030
if (rcookie.nodeid != null) { obj.nodeid = rcookie.nodeid; }
1031
}
1032
1033
// If there is no authentication, drop this connection
1026
- if ((obj.id != null) && (obj.user == null) && (obj.ruserid == null)) { try { ws.close(); parent.parent.debug('relay', 'DesktopRelay: Connection with no authentication (' + obj.req.clientIp + ')'); } catch (e) { console.log(e); } return; }
1034
+ if ((obj.id != null) && (obj.user == null) && (obj.ruserid == null) && (obj.nouser !== true) && (obj.rnouser !== true)) { try { ws.close(); parent.parent.debug('relay', 'DesktopRelay: Connection with no authentication (' + obj.req.clientIp + ')'); } catch (e) { console.log(e); } return; }
1035
1036
// Relay session count (we may remove this in the future)
1037
obj.relaySessionCounted = true;
@@ -1082,8 +1090,8 @@ function CreateMeshRelayEx2(parent, ws, req, domain, user, cookie) {
1090
obj.sendAgentMessage = function (command, userid, domainid) {
1091
var rights, mesh;
1092
if (command.nodeid == null) return false;
1085
- var user = parent.users[userid];
1086
- if (user == null) return false;
1093
+ var user = null;
1094
+ if (userid != null) { user = parent.users[userid]; if (user == null) return false; }
1095
var splitnodeid = command.nodeid.split('/');
1096
// Check that we are in the same domain and the user has rights over this node.
1097
if ((splitnodeid[0] == 'node') && (splitnodeid[1] == domainid)) {
@@ -1092,7 +1100,7 @@ function CreateMeshRelayEx2(parent, ws, req, domain, user, cookie) {
1100
var agent = parent.wsagents[command.nodeid];
1101
if (agent != null) {
1102
// Check if we have permission to send a message to that node
1095
- rights = parent.GetNodeRights(user, agent.dbMeshKey, agent.dbNodeKey);
1103
+ if (userid == null) { rights = MESHRIGHT_REMOTECONTROL; } else { rights = parent.GetNodeRights(user, routing.meshid, command.nodeid); }
1104
mesh = parent.meshes[agent.dbMeshKey];
1105
if ((rights != null) && (mesh != null) || ((rights & 16) != 0)) { // TODO: 16 is console permission, may need more gradular permission checking
1106
if (ws.sessionId) { command.sessionid = ws.sessionId; } // Set the session id, required for responses.
@@ -1100,8 +1108,10 @@ function CreateMeshRelayEx2(parent, ws, req, domain, user, cookie) {
1108
if ((command.rights != 0xFFFFFFFF) && ((command.rights & 0x100) != 0)) { command.rights -= 0x100; } // Since the multiplexor will enforce view-only, remove MESHRIGHT_REMOTEVIEWONLY
1109
if (typeof command.consent == 'number') { command.consent = command.consent | mesh.consent; } else { command.consent = mesh.consent; } // Add user consent
1110
if (typeof domain.userconsentflags == 'number') { command.consent |= domain.userconsentflags; } // Add server required consent flags
1103
- command.username = user.name; // Add user name
1104
- command.realname = user.realname; // Add real name
1111
+ if (user != null) {
1112
+ command.username = user.name; // Add user name
1113
+ command.realname = user.realname; // Add real name
1114
+ }
1115
if (typeof domain.desktopprivacybartext == 'string') { command.privacybartext = domain.desktopprivacybartext; } // Privacy bar text
1116
delete command.nodeid; // Remove the nodeid since it's implyed.
1117
agent.send(JSON.stringify(command));
@@ -1112,7 +1122,7 @@ function CreateMeshRelayEx2(parent, ws, req, domain, user, cookie) {
1122
var routing = parent.parent.GetRoutingServerIdNotSelf(command.nodeid, 1); // 1 = MeshAgent routing type
1123
if (routing != null) {
1124
// Check if we have permission to send a message to that node
1115
- rights = parent.GetNodeRights(user, routing.meshid, command.nodeid);
1125
+ if (userid == null) { rights = MESHRIGHT_REMOTECONTROL; } else { rights = parent.GetNodeRights(user, routing.meshid, command.nodeid); }
1126
mesh = parent.meshes[routing.meshid];
1127
if (rights != null || ((rights & 16) != 0)) { // TODO: 16 is console permission, may need more gradular permission checking
1128
if (ws.sessionId) { command.fromSessionid = ws.sessionId; } // Set the session id, required for responses.
@@ -1120,8 +1130,10 @@ function CreateMeshRelayEx2(parent, ws, req, domain, user, cookie) {
1130
if ((command.rights != 0xFFFFFFFF) && ((command.rights & 0x00000100) != 0)) { command.rights -= 0x00000100; } // Since the multiplexor will enforce view-only, remove MESHRIGHT_REMOTEVIEWONLY
1131
if (typeof command.consent == 'number') { command.consent = command.consent | mesh.consent; } else { command.consent = mesh.consent; } // Add user consent
1132
if (typeof domain.userconsentflags == 'number') { command.consent |= domain.userconsentflags; } // Add server required consent flags
1123
- command.username = user.name; // Add user name
1124
- command.realname = user.realname; // Add real name
1133
+ if (user != null) {
1134
+ command.username = user.name; // Add user name
1135
+ command.realname = user.realname; // Add real name
1136
+ }
1137
if (typeof domain.desktopprivacybartext == 'string') { command.privacybartext = domain.desktopprivacybartext; } // Privacy bar text
1138
parent.parent.multiServer.DispatchMessageSingleServer(command, routing.serverid);
1139
return true;
@@ -1233,7 +1245,7 @@ function CreateMeshRelayEx2(parent, ws, req, domain, user, cookie) {
1245
setExpireTimer();
1246
1247
// Mark this relay session as authenticated if this is the user end.
1236
- obj.authenticated = (user != null);
1248
+ obj.authenticated = ((user != null) || (obj.nouser === true));
1249
if (obj.authenticated) {
1250
// Kick off the routing, if we have agent routing instructions, process them here.
1251
// Routing instructions can only be given by a authenticated user
@@ -1245,14 +1257,16 @@ function CreateMeshRelayEx2(parent, ws, req, domain, user, cookie) {
1257
const node = docs[0];
1258
1259
// Check if this user has permission to manage this computer
1248
- if ((parent.GetNodeRights(user, node.meshid, node._id) & MESHRIGHT_REMOTECONTROL) == 0) { console.log('ERR: Access denied (1)'); try { obj.close(); } catch (e) { } return; }
1260
+ if ((obj.nouser !== true) && ((parent.GetNodeRights(user, node.meshid, node._id) & MESHRIGHT_REMOTECONTROL) == 0)) { console.log('ERR: Access denied (1)'); try { obj.close(); } catch (e) { } return; }
1261
1262
// Send connection request to agent
1251
- const rcookie = parent.parent.encodeCookie({ ruserid: user._id, nodeid: node._id }, parent.parent.loginCookieEncryptionKey);
1263
+ const rcookieData = { nodeid: node._id };
1264
+ if (user != null) { rcookieData.ruserid = user._id; } else if (obj.nouser === true) { rcookieData.nouser = 1; }
1265
+ const rcookie = parent.parent.encodeCookie(rcookieData, parent.parent.loginCookieEncryptionKey);
1266
if (obj.id == undefined) { obj.id = ('' + Math.random()).substring(2); } // If there is no connection id, generate one.
1267
const command = { nodeid: node._id, action: 'msg', type: 'tunnel', value: '*/meshrelay.ashx?id=' + obj.id + '&rauth=' + rcookie, tcpport: cookie.tcpport, tcpaddr: cookie.tcpaddr };
1268
parent.parent.debug('relay', 'Relay: Sending agent tunnel command: ' + JSON.stringify(command));
1255
- if (obj.sendAgentMessage(command, user._id, cookie.domainid) == false) { delete obj.id; parent.parent.debug('relay', 'Relay: Unable to contact this agent (' + obj.req.clientIp + ')'); }
1269
+ if (obj.sendAgentMessage(command, user ? user._id : null, cookie.domainid) == false) { delete obj.id; parent.parent.debug('relay', 'Relay: Unable to contact this agent (' + obj.req.clientIp + ')'); }
1270
performRelay(0);
1271
});
1272
return obj;
@@ -1264,20 +1278,22 @@ function CreateMeshRelayEx2(parent, ws, req, domain, user, cookie) {
1278
const node = docs[0];
1279
1280
// Check if this user has permission to manage this computer
1267
- if ((parent.GetNodeRights(user, node.meshid, node._id) & MESHRIGHT_REMOTECONTROL) == 0) { console.log('ERR: Access denied (2)'); try { obj.close(); } catch (e) { } return; }
1281
+ if ((obj.nouser !== true) && ((parent.GetNodeRights(user, node.meshid, node._id) & MESHRIGHT_REMOTECONTROL) == 0)) { console.log('ERR: Access denied (2)'); try { obj.close(); } catch (e) { } return; }
1282
1283
// Send connection request to agent
1284
if (obj.id == null) { obj.id = ('' + Math.random()).substring(2); } // If there is no connection id, generate one.
1271
- const rcookie = parent.parent.encodeCookie({ ruserid: user._id, nodeid: node._id }, parent.parent.loginCookieEncryptionKey);
1285
+ const rcookieData = { nodeid: node._id };
1286
+ if (user != null) { rcookieData.ruserid = user._id; } else if (obj.nouser === true) { rcookieData.nouser = 1; }
1287
+ const rcookie = parent.parent.encodeCookie(rcookieData, parent.parent.loginCookieEncryptionKey);
1288
1289
if (obj.req.query.tcpport != null) {
1290
const command = { nodeid: node._id, action: 'msg', type: 'tunnel', value: '*/meshrelay.ashx?id=' + obj.id + '&rauth=' + rcookie, tcpport: obj.req.query.tcpport, tcpaddr: ((obj.req.query.tcpaddr == null) ? '127.0.0.1' : obj.req.query.tcpaddr) };
1291
parent.parent.debug('relay', 'Relay: Sending agent TCP tunnel command: ' + JSON.stringify(command));
1276
- if (obj.sendAgentMessage(command, user._id, domain.id) == false) { delete obj.id; parent.parent.debug('relay', 'Relay: Unable to contact this agent (' + obj.req.clientIp + ')'); }
1292
+ if (obj.sendAgentMessage(command, user ? user._id : null, domain.id) == false) { delete obj.id; parent.parent.debug('relay', 'Relay: Unable to contact this agent (' + obj.req.clientIp + ')'); }
1293
} else if (obj.req.query.udpport != null) {
1294
const command = { nodeid: node._id, action: 'msg', type: 'tunnel', value: '*/meshrelay.ashx?id=' + obj.id + '&rauth=' + rcookie, udpport: obj.req.query.udpport, udpaddr: ((obj.req.query.udpaddr == null) ? '127.0.0.1' : obj.req.query.udpaddr) };
1295
parent.parent.debug('relay', 'Relay: Sending agent UDP tunnel command: ' + JSON.stringify(command));
1280
- if (obj.sendAgentMessage(command, user._id, domain.id) == false) { delete obj.id; parent.parent.debug('relay', 'Relay: Unable to contact this agent (' + obj.req.clientIp + ')'); }
1296
+ if (obj.sendAgentMessage(command, user ? user._id : null, domain.id) == false) { delete obj.id; parent.parent.debug('relay', 'Relay: Unable to contact this agent (' + obj.req.clientIp + ')'); }
1297
}
1298
performRelay(0);
1299
});
@@ -1290,12 +1306,15 @@ function CreateMeshRelayEx2(parent, ws, req, domain, user, cookie) {
1306
const node = docs[0];
1307
1308
// Check if this user has permission to manage this computer
1293
- if ((parent.GetNodeRights(user, node.meshid, node._id) & MESHRIGHT_REMOTECONTROL) == 0) { console.log('ERR: Access denied (2)'); try { obj.close(); } catch (e) { } return; }
1309
+ if ((obj.nouser !== true) && ((parent.GetNodeRights(user, node.meshid, node._id) & MESHRIGHT_REMOTECONTROL) == 0)) { console.log('ERR: Access denied (2)'); try { obj.close(); } catch (e) { } return; }
1310
1311
// Send connection request to agent
1312
if (obj.id == null) { obj.id = ('' + Math.random()).substring(2); }
1297
- const rcookie = parent.parent.encodeCookie({ ruserid: user._id, nodeid: node._id }, parent.parent.loginCookieEncryptionKey);
1298
- const command = { nodeid: node._id, action: 'msg', type: 'tunnel', userid: user._id, value: '*/meshrelay.ashx?p=2&id=' + obj.id + '&rauth=' + rcookie + '&nodeid=' + node._id, soptions: {}, usage: 2, rights: cookie.r, guestname: cookie.gn, consent: cookie.cf, remoteaddr: cleanRemoteAddr(obj.req.clientIp) };
1313
+ const rcookieData = { nodeid: node._id };
1314
+ if (user != null) { rcookieData.ruserid = user._id; } else if (obj.nouser === true) { rcookieData.nouser = 1; }
1315
+ const rcookie = parent.parent.encodeCookie(rcookieData, parent.parent.loginCookieEncryptionKey);
1316
+ const command = { nodeid: node._id, action: 'msg', type: 'tunnel', value: '*/meshrelay.ashx?p=2&id=' + obj.id + '&rauth=' + rcookie + '&nodeid=' + node._id, soptions: {}, usage: 2, rights: cookie.r, guestname: cookie.gn, consent: cookie.cf, remoteaddr: cleanRemoteAddr(obj.req.clientIp) };
1317
+ if (user != null) { command.userid = user._id; }
1318
if (typeof domain.consentmessages == 'object') {
1319
if (typeof domain.consentmessages.title == 'string') { command.soptions.consentTitle = domain.consentmessages.title; }
1320
if (typeof domain.consentmessages.desktop == 'string') { command.soptions.consentMsgDesktop = domain.consentmessages.desktop; }
@@ -1309,7 +1328,7 @@ function CreateMeshRelayEx2(parent, ws, req, domain, user, cookie) {
1328
if (typeof domain.notificationmessages.files == 'string') { command.soptions.notifyMsgFiles = domain.notificationmessages.files; }
1329
}
1330
parent.parent.debug('relay', 'Relay: Sending agent tunnel command: ' + JSON.stringify(command));
1312
- if (obj.sendAgentMessage(command, user._id, domain.id) == false) { delete obj.id; parent.parent.debug('relay', 'Relay: Unable to contact this agent (' + obj.req.clientIp + ')'); }
1331
+ if (obj.sendAgentMessage(command, user ? user._id : null, domain.id) == false) { delete obj.id; parent.parent.debug('relay', 'Relay: Unable to contact this agent (' + obj.req.clientIp + ')'); }
1332
1333
performRelay(0);
1334
});