From 41ecece9a9f172bbafa68ded5209f372af0c3713 Mon Sep 17 00:00:00 2001 From: Ylian Saint-Hilaire Date: Fri, 27 Aug 2021 14:42:28 -0700 Subject: [PATCH] Completed user access rights removal feature, #3065 --- agents/meshcore.js | 1 + agents/recoverycore.js | 1 + meshuser.js | 4 +-- views/default-mobile.handlebars | 41 +++++++++++++++++++++------ views/default.handlebars | 38 ++++++++++++++++++++----- webserver.js | 49 +++++++++++++++++++++++++-------- 6 files changed, 104 insertions(+), 30 deletions(-) diff --git a/agents/meshcore.js b/agents/meshcore.js index 09075d04..1a668e1e 100644 --- a/agents/meshcore.js +++ b/agents/meshcore.js @@ -874,6 +874,7 @@ function handleServerCommand(data) { case 'msg': { switch (data.type) { case 'console': { // Process a console command + if ((typeof data.rights != 'number') || ((data.rights & 16) == 0)) break; // Check console rights if (data.value && data.sessionid) { MeshServerLogEx(17, [data.value], "Processing console command: " + data.value, data); var args = splitArgs(data.value); diff --git a/agents/recoverycore.js b/agents/recoverycore.js index ce22ff04..215e14c8 100644 --- a/agents/recoverycore.js +++ b/agents/recoverycore.js @@ -911,6 +911,7 @@ require('MeshAgent').AddCommandHandler(function (data) { { switch (data.type) { case 'console': { // Process a console command + if ((typeof data.rights != 'number') || ((data.rights & 16) == 0)) break; // Check console rights if (data.value && data.sessionid) { var args = splitArgs(data.value); processConsoleCommand(args[0].toLowerCase(), parseArgs(args), data.rights, data.sessionid); diff --git a/meshuser.js b/meshuser.js index 5621b5f5..cf6fdce1 100644 --- a/meshuser.js +++ b/meshuser.js @@ -4313,7 +4313,7 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain, use // Get the node and the rights for this node parent.GetNodeWithRights(domain, user, command.nodeid, function (node, rights, visible) { - if ((rights & MESHRIGHT_AGENTCONSOLE) == 0) return; + if ((rights & MESHRIGHT_REMOTECONTROL) == 0) return; // Ask for clipboard data from agent var agent = parent.wsagents[node._id]; @@ -4326,7 +4326,7 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain, use // Get the node and the rights for this node parent.GetNodeWithRights(domain, user, command.nodeid, function (node, rights, visible) { - if ((rights & MESHRIGHT_AGENTCONSOLE) == 0) return; + if ((rights & MESHRIGHT_REMOTECONTROL) == 0) return; // Send clipboard data to the agent var agent = parent.wsagents[node._id]; diff --git a/views/default-mobile.handlebars b/views/default-mobile.handlebars index 51653130..d7df88ad 100644 --- a/views/default-mobile.handlebars +++ b/views/default-mobile.handlebars @@ -3549,7 +3549,7 @@ if ((currentDevicePanel != 5) && (currentNode != null) && - ((meshrights & 8) || (meshrights & 256)) && ((meshrights == 0xFFFFFFFF) || ((meshrights & 65536) == 0)) && + ((meshrights & 8) || (meshrights & 256)) && ((meshrights == 0xFFFFFFFF) || ((meshrights & 512) == 0)) && (((currentNode.agent == null) && ((typeof currentNode.intelamt.sku !== 'number') || ((currentNode.intelamt.sku & 8) != 0))) || (currentNode.agent && (currentNode.agent.caps & 2))) ) { menus.push({ n: "Terminal", f: 'setupDeviceMenu(5)' }); } @@ -6359,6 +6359,28 @@ // These must match server // + // Remove user rights + function removeUserRights(rights, userid) { + if ((userid != userinfo._id) || (userinfo.removeRights == null)) return rights; + var add = 0, substract = 0; + if ((userinfo.removeRights & 0x00010000) != 0) { add += 0x00010000; } // No Desktop + if ((userinfo.removeRights & 0x00000100) != 0) { add += 0x00000100; } // Desktop View Only + if ((userinfo.removeRights & 0x00000200) != 0) { add += 0x00000200; } // No Terminal + if ((userinfo.removeRights & 0x00000400) != 0) { add += 0x00000400; } // No Files + if ((userinfo.removeRights & 0x00000010) != 0) { substract += 0x00000010; } // No Console + if (rights != 0xFFFFFFFF) { + // If not administrator, add and subsctract restrictions + rights |= add; + rights &= (0xFFFFFFFF - substract); + } else { + // If administrator for a device group, start with permissions and add and subsctract restrictions + rights = 1 + 2 + 4 + 8 + 32 + 64 + 128 + 16384 + 32768 + 131072 + 262144 + 524288 + 1048576; + rights |= add; + rights &= (0xFFFFFFFF - substract); + } + return rights; + } + // Get the right of a user on a given device group function GetMeshRights(mesh, userid) { if (mesh == null) { return 0; } @@ -6367,12 +6389,12 @@ if ((mesh == null) || (mesh.links == null)) { return 0; } // Check if super user - if (userinfo.manageAllDeviceGroups && (userid == userinfo._id)) return 0xFFFFFFFF; + if (serverinfo.manageAllDeviceGroups && (userid == userinfo._id)) return removeUserRights(0xFFFFFFFF, userid); // Check device group link permission var rights = 0, r = mesh.links[userid]; if (r != null) { - if (r.rights == 0xFFFFFFFF) { return 0xFFFFFFFF; } // User has full rights thru a device group link, stop here. + if (r.rights == 0xFFFFFFFF) { return removeUserRights(0xFFFFFFFF, userid); } // User has full rights thru a device group link, stop here. rights = r.rights; } @@ -6384,14 +6406,14 @@ if (i.startsWith('ugrp/')) { r = mesh.links[i]; if (r != null) { - if (r.rights == 0xFFFFFFFF) { return 0xFFFFFFFF; } // User has full rights thru a user group, stop here. + if (r.rights == 0xFFFFFFFF) { return removeUserRights(0xFFFFFFFF, userid); } // User has full rights thru a user group, stop here. rights |= r.rights; // TODO: Deal with reverse permissions } } } } - return rights; + return removeUserRights(rights, userid); } // Returns true if the user can view the given device group @@ -6403,7 +6425,7 @@ if (mesh.links[userid] != null) { return true; } // User has visilibity thru a direct link // Check if user user - if (userinfo.manageAllDeviceGroups && (userid == userinfo._id)) return true; + if (serverinfo.manageAllDeviceGroups && (userid == userinfo._id)) return true; // Check permissions thru user groups var user = null; @@ -6423,8 +6445,7 @@ if (userid == null) { userid = userinfo._id; } if (typeof node == 'string') { node = getNodeFromId(node); if (node == null) { return 0; } } var r = GetMeshRights(node.meshid, userid); - if (r == 0xFFFFFFFF) return r; - var user = null; + if (r == 0xFFFFFFFF) return removeUserRights(r, userid); // Check direct device rights using device data if ((node.links != null) && (node.links[userid] != null)) { r |= node.links[userid].rights; } // TODO: Deal with reverse permissions @@ -6438,6 +6459,7 @@ // Check direct device rights using user data /* + var user = null; if (userid == userinfo._id) { user = userinfo; } else { if (users != null) { user = users[userid]; } } if ((user != null) && (user.links != null)) { var r2 = user.links[node._id]; @@ -6447,7 +6469,7 @@ } } */ - return r; + return removeUserRights(r, userid); } // Return true if the device is visible to the user @@ -6468,6 +6490,7 @@ return false; } + // // Generic Methods // diff --git a/views/default.handlebars b/views/default.handlebars index 9118790f..8ef7d90d 100644 --- a/views/default.handlebars +++ b/views/default.handlebars @@ -2807,10 +2807,12 @@ if (userinfo._id == message.event.account._id) { var newsiteadmin = message.event.account.siteadmin?message.event.account.siteadmin:0; var oldsiteadmin = userinfo.siteadmin?userinfo.siteadmin:0; + var newRemoveRights = message.event.account.removeRights?message.event.account.removeRights:0; + var oldRemoveRights = userinfo.removeRights?userinfo.removeRights:0; if ((message.event.account.quota != userinfo.quota) || (((userinfo.siteadmin & 8) == 0) && ((message.event.account.siteadmin & 8) != 0))) { meshserver.send({ action: 'files' }); } var oldgroups = userinfo.groups; userinfo = message.event.account; - if ((oldsiteadmin != newsiteadmin) || (message.event.accountImageChange == 1)) { // If the site admin permission or user image has changed... + if ((oldsiteadmin != newsiteadmin) || (oldRemoveRights != newRemoveRights) || (message.event.accountImageChange == 1)) { // If the site admin permission or user image has changed... if (message.event.accountImageChange == 1) { userinfo.accountImageRnd = Math.floor(Math.random() * 9999999999); } updateSiteAdmin(); } @@ -15819,6 +15821,28 @@ // These must match server // + // Remove user rights + function removeUserRights(rights, userid) { + if ((userid != userinfo._id) || (userinfo.removeRights == null)) return rights; + var add = 0, substract = 0; + if ((userinfo.removeRights & 0x00010000) != 0) { add += 0x00010000; } // No Desktop + if ((userinfo.removeRights & 0x00000100) != 0) { add += 0x00000100; } // Desktop View Only + if ((userinfo.removeRights & 0x00000200) != 0) { add += 0x00000200; } // No Terminal + if ((userinfo.removeRights & 0x00000400) != 0) { add += 0x00000400; } // No Files + if ((userinfo.removeRights & 0x00000010) != 0) { substract += 0x00000010; } // No Console + if (rights != 0xFFFFFFFF) { + // If not administrator, add and subsctract restrictions + rights |= add; + rights &= (0xFFFFFFFF - substract); + } else { + // If administrator for a device group, start with permissions and add and subsctract restrictions + rights = 1 + 2 + 4 + 8 + 32 + 64 + 128 + 16384 + 32768 + 131072 + 262144 + 524288 + 1048576; + rights |= add; + rights &= (0xFFFFFFFF - substract); + } + return rights; + } + // Get the right of a user on a given device group function GetMeshRights(mesh, userid) { if (mesh == null) { return 0; } @@ -15827,12 +15851,12 @@ if ((mesh == null) || (mesh.links == null)) { return 0; } // Check if super user - if (serverinfo.manageAllDeviceGroups && (userid == userinfo._id)) return 0xFFFFFFFF; + if (serverinfo.manageAllDeviceGroups && (userid == userinfo._id)) return removeUserRights(0xFFFFFFFF, userid); // Check device group link permission var rights = 0, r = mesh.links[userid]; if (r != null) { - if (r.rights == 0xFFFFFFFF) { return 0xFFFFFFFF; } // User has full rights thru a device group link, stop here. + if (r.rights == 0xFFFFFFFF) { return removeUserRights(0xFFFFFFFF, userid); } // User has full rights thru a device group link, stop here. rights = r.rights; } @@ -15844,14 +15868,14 @@ if (i.startsWith('ugrp/')) { r = mesh.links[i]; if (r != null) { - if (r.rights == 0xFFFFFFFF) { return 0xFFFFFFFF; } // User has full rights thru a user group, stop here. + if (r.rights == 0xFFFFFFFF) { return removeUserRights(0xFFFFFFFF, userid); } // User has full rights thru a user group, stop here. rights |= r.rights; // TODO: Deal with reverse permissions } } } } - return rights; + return removeUserRights(rights, userid); } // Returns true if the user can view the given device group @@ -15883,7 +15907,7 @@ if (userid == null) { userid = userinfo._id; } if (typeof node == 'string') { node = getNodeFromId(node); if (node == null) { return 0; } } var r = GetMeshRights(node.meshid, userid); - if (r == 0xFFFFFFFF) return r; + if (r == 0xFFFFFFFF) return removeUserRights(r, userid); // Check direct device rights using device data if ((node.links != null) && (node.links[userid] != null)) { r |= node.links[userid].rights; } // TODO: Deal with reverse permissions @@ -15907,7 +15931,7 @@ } } */ - return r; + return removeUserRights(r, userid); } // Return true if the device is visible to the user diff --git a/webserver.js b/webserver.js index 27297713..3e52599c 100644 --- a/webserver.js +++ b/webserver.js @@ -6799,6 +6799,28 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) { // Access Control Functions // + // Remove user rights + function removeUserRights(rights, user) { + if (user.removeRights == null) return rights; + var add = 0, substract = 0; + if ((user.removeRights & 0x00010000) != 0) { add += 0x00010000; } // No Desktop + if ((user.removeRights & 0x00000100) != 0) { add += 0x00000100; } // Desktop View Only + if ((user.removeRights & 0x00000200) != 0) { add += 0x00000200; } // No Terminal + if ((user.removeRights & 0x00000400) != 0) { add += 0x00000400; } // No Files + if ((user.removeRights & 0x00000010) != 0) { substract += 0x00000010; } // No Console + if (rights != 0xFFFFFFFF) { + // If not administrator, add and subsctract restrictions + rights |= add; + rights &= (0xFFFFFFFF - substract); + } else { + // If administrator for a device group, start with permissions and add and subsctract restrictions + rights = 1 + 2 + 4 + 8 + 32 + 64 + 128 + 16384 + 32768 + 131072 + 262144 + 524288 + 1048576; + rights |= add; + rights &= (0xFFFFFFFF - substract); + } + return rights; + } + // Return the node and rights for a given nodeid obj.GetNodeWithRights = function (domain, user, nodeid, func) { // Perform user pre-validation @@ -6818,7 +6840,7 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) { // This is a super user that can see all device groups for a given domain if ((user.siteadmin == 0xFFFFFFFF) && (parent.config.settings.managealldevicegroups.indexOf(user._id) >= 0) && (nodes[0].domain == user.domain)) { - func(nodes[0], 0xFFFFFFFF, true); return; + func(nodes[0], removeUserRights(0xFFFFFFFF, user), true); return; } // If no links, stop here. @@ -6827,7 +6849,7 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) { // Check device link var rights = 0, visible = false, r = user.links[nodeid]; if (r != null) { - if (r.rights == 0xFFFFFFFF) { func(nodes[0], 0xFFFFFFFF, true); return; } // User has full rights thru a device link, stop here. + if (r.rights == 0xFFFFFFFF) { func(nodes[0], removeUserRights(0xFFFFFFFF, user), true); return; } // User has full rights thru a device link, stop here. rights |= r.rights; visible = true; } @@ -6835,7 +6857,7 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) { // Check device group link r = user.links[nodes[0].meshid]; if (r != null) { - if (r.rights == 0xFFFFFFFF) { func(nodes[0], 0xFFFFFFFF, true); return; } // User has full rights thru a device group link, stop here. + if (r.rights == 0xFFFFFFFF) { func(nodes[0], removeUserRights(0xFFFFFFFF, user), true); return; } // User has full rights thru a device group link, stop here. rights |= r.rights; visible = true; } @@ -6847,13 +6869,13 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) { if (g && (g.links != null)) { r = g.links[nodes[0].meshid]; if (r != null) { - if (r.rights == 0xFFFFFFFF) { func(nodes[0], 0xFFFFFFFF, true); return; } // User has full rights thru a user group link, stop here. + if (r.rights == 0xFFFFFFFF) { func(nodes[0], removeUserRights(0xFFFFFFFF, user), true); return; } // User has full rights thru a user group link, stop here. rights |= r.rights; // TODO: Deal with reverse rights visible = true; } r = g.links[nodeid]; if (r != null) { - if (r.rights == 0xFFFFFFFF) { func(nodes[0], 0xFFFFFFFF, true); return; } // User has full rights thru a user group direct link, stop here. + if (r.rights == 0xFFFFFFFF) { func(nodes[0], removeUserRights(0xFFFFFFFF, user), true); return; } // User has full rights thru a user group direct link, stop here. rights |= r.rights; // TODO: Deal with reverse rights visible = true; } @@ -6861,6 +6883,9 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) { } } + // Remove any user rights + rights = removeUserRights(rights, user); + // Return the rights we found func(nodes[0], rights, visible); }); @@ -6954,7 +6979,7 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) { } else return 0; // Check if this is a super user that can see all device groups for a given domain - if ((user.siteadmin == 0xFFFFFFFF) && (parent.config.settings.managealldevicegroups.indexOf(user._id) >= 0) && (meshid.startsWith('mesh/' + user.domain + '/'))) { return 0xFFFFFFFF; } + if ((user.siteadmin == 0xFFFFFFFF) && (parent.config.settings.managealldevicegroups.indexOf(user._id) >= 0) && (meshid.startsWith('mesh/' + user.domain + '/'))) { return removeUserRights(0xFFFFFFFF, user); } // Check direct user to device group permissions if (user.links == null) return 0; @@ -6962,7 +6987,7 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) { r = user.links[meshid]; if (r != null) { var rights = r.rights; - if (rights == 0xFFFFFFFF) { return rights; } // If the user has full access thru direct link, stop here. + if (rights == 0xFFFFFFFF) { return removeUserRights(rights, user); } // If the user has full access thru direct link, stop here. } // Check if we are part of any user groups that would give this user more access. @@ -6973,7 +6998,7 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) { r = g.links[meshid]; if (r != null) { if (r.rights == 0xFFFFFFFF) { - return r.rights; // If the user hash full access thru a user group link, stop here. + return removeUserRights(r.rights, user); // If the user hash full access thru a user group link, stop here. } else { rights |= r.rights; // Add to existing rights (TODO: Deal with reverse rights) } @@ -6983,7 +7008,7 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) { } } - return rights; + return removeUserRights(rights, user); } // Returns true if the user can view the given device group @@ -7022,11 +7047,11 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) { if (typeof user == 'string') { user = obj.users[user]; } if (user == null) { return 0; } var r = obj.GetMeshRights(user, mesh); - if (r == 0xFFFFFFFF) return r; + if (r == 0xFFFFFFFF) return removeUserRights(r, user); // Check direct device rights using device data if ((user.links != null) && (user.links[nodeid] != null)) { r |= user.links[nodeid].rights; } // TODO: Deal with reverse permissions - if (r == 0xFFFFFFFF) return r; + if (r == 0xFFFFFFFF) return removeUserRights(r, user); // Check direct device rights thru a user group for (var i in user.links) { @@ -7036,7 +7061,7 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) { } } - return r; + return removeUserRights(r, user); } // Returns a list of displatch targets for a given mesh