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 });