mirror of
https://github.com/Ylianst/MeshCentral.git
synced 2024-12-26 07:05:52 -05:00
New command run dialog box can now run scripts that are stored on the server.
This commit is contained in:
parent
ab84719afe
commit
d171d2af82
161
meshuser.js
161
meshuser.js
@ -2784,92 +2784,111 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain, use
|
||||
{
|
||||
if (common.validateArray(command.nodeids, 1) == false) break; // Check nodeid's
|
||||
if (typeof command.type != 'number') break; // Check command type
|
||||
if (typeof command.cmds != 'string') break; // Check commands
|
||||
if (typeof command.runAsUser != 'number') { command.runAsUser = 0; } // Check runAsUser
|
||||
|
||||
for (i in command.nodeids) {
|
||||
var nodeid = command.nodeids[i], err = null;
|
||||
const processRunCommand = function (command) {
|
||||
for (i in command.nodeids) {
|
||||
var nodeid = command.nodeids[i], err = null;
|
||||
|
||||
// Argument validation
|
||||
if (common.validateString(nodeid, 1, 1024) == false) { err = 'Invalid nodeid'; } // Check nodeid
|
||||
else {
|
||||
if (nodeid.indexOf('/') == -1) { nodeid = 'node/' + domain.id + '/' + nodeid; }
|
||||
if ((nodeid.split('/').length != 3) || (nodeid.split('/')[1] != domain.id)) { err = 'Invalid domain'; } // Invalid domain, operation only valid for current domain
|
||||
}
|
||||
if (err != null) {
|
||||
if (command.responseid != null) { try { ws.send(JSON.stringify({ action: 'runcommands', responseid: command.responseid, result: err })); } catch (ex) { } }
|
||||
continue;
|
||||
}
|
||||
|
||||
// Get the node and the rights for this node
|
||||
parent.GetNodeWithRights(domain, user, nodeid, function (node, rights, visible) {
|
||||
// Check if this node was found
|
||||
if (node == null) {
|
||||
if (command.responseid != null) { try { ws.send(JSON.stringify({ action: 'runcommands', responseid: command.responseid, result: 'Invalid nodeid' })); } catch (ex) { } }
|
||||
return;
|
||||
// Argument validation
|
||||
if (common.validateString(nodeid, 1, 1024) == false) { err = 'Invalid nodeid'; } // Check nodeid
|
||||
else {
|
||||
if (nodeid.indexOf('/') == -1) { nodeid = 'node/' + domain.id + '/' + nodeid; }
|
||||
if ((nodeid.split('/').length != 3) || (nodeid.split('/')[1] != domain.id)) { err = 'Invalid domain'; } // Invalid domain, operation only valid for current domain
|
||||
}
|
||||
if (err != null) {
|
||||
if (command.responseid != null) { try { ws.send(JSON.stringify({ action: 'runcommands', responseid: command.responseid, result: err })); } catch (ex) { } }
|
||||
continue;
|
||||
}
|
||||
|
||||
if (command.type == 4) {
|
||||
// This is an agent console command
|
||||
|
||||
// Check we have the rights to run commands on this device, MESHRIGHT_REMOTECONTROL & MESHRIGHT_AGENTCONSOLE are needed
|
||||
if ((rights & 24) != 24) {
|
||||
if (command.responseid != null) { try { ws.send(JSON.stringify({ action: 'runcommands', responseid: command.responseid, result: 'Access denied' })); } catch (ex) { } }
|
||||
// Get the node and the rights for this node
|
||||
parent.GetNodeWithRights(domain, user, nodeid, function (node, rights, visible) {
|
||||
// Check if this node was found
|
||||
if (node == null) {
|
||||
if (command.responseid != null) { try { ws.send(JSON.stringify({ action: 'runcommands', responseid: command.responseid, result: 'Invalid nodeid' })); } catch (ex) { } }
|
||||
return;
|
||||
}
|
||||
|
||||
// Send the commands to the agent
|
||||
var agent = parent.wsagents[node._id];
|
||||
if ((agent != null) && (agent.authenticated == 2) && (agent.agentInfo != null)) {
|
||||
try { agent.send(JSON.stringify({ action: 'msg', type: 'console', value: command.cmds, rights: rights, sessionid: ws.sessionId })); } catch (ex) { }
|
||||
if (command.responseid != null) { try { ws.send(JSON.stringify({ action: 'runcommands', responseid: command.responseid, result: 'OK' })); } catch (ex) { } }
|
||||
} else {
|
||||
if (command.responseid != null) { try { ws.send(JSON.stringify({ action: 'runcommands', responseid: command.responseid, result: 'Agent not connected' })); } catch (ex) { } }
|
||||
}
|
||||
} else {
|
||||
// This is a standard (bash/shell/powershell) command.
|
||||
if (command.type == 4) {
|
||||
// This is an agent console command
|
||||
|
||||
// Check we have the rights to run commands on this device
|
||||
if ((rights & MESHRIGHT_REMOTECOMMAND) == 0) {
|
||||
if (command.responseid != null) { try { ws.send(JSON.stringify({ action: 'runcommands', responseid: command.responseid, result: 'Access denied' })); } catch (ex) { } }
|
||||
return;
|
||||
}
|
||||
|
||||
// Get the agent and run the commands
|
||||
var agent = parent.wsagents[node._id];
|
||||
if ((agent != null) && (agent.authenticated == 2) && (agent.agentInfo != null)) {
|
||||
// Check if this agent is correct for this command type
|
||||
// command.type 1 = Windows Command, 2 = Windows PowerShell, 3 = Linux/BSD/macOS
|
||||
var commandsOk = false;
|
||||
if ((agent.agentInfo.agentId > 0) && (agent.agentInfo.agentId < 5)) {
|
||||
// Windows Agent
|
||||
if ((command.type == 1) || (command.type == 2)) { commandsOk = true; }
|
||||
else if (command.type === 0) { command.type = 1; commandsOk = true; } // Set the default type of this agent
|
||||
} else {
|
||||
// Non-Windows Agent
|
||||
if (command.type == 3) { commandsOk = true; }
|
||||
else if (command.type === 0) { command.type = 3; commandsOk = true; } // Set the default type of this agent
|
||||
// Check we have the rights to run commands on this device, MESHRIGHT_REMOTECONTROL & MESHRIGHT_AGENTCONSOLE are needed
|
||||
if ((rights & 24) != 24) {
|
||||
if (command.responseid != null) { try { ws.send(JSON.stringify({ action: 'runcommands', responseid: command.responseid, result: 'Access denied' })); } catch (ex) { } }
|
||||
return;
|
||||
}
|
||||
if (commandsOk == true) {
|
||||
// Send the commands to the agent
|
||||
try { agent.send(JSON.stringify({ action: 'runcommands', type: command.type, cmds: command.cmds, runAsUser: command.runAsUser })); } catch (ex) { }
|
||||
|
||||
// Send the commands to the agent
|
||||
var agent = parent.wsagents[node._id];
|
||||
if ((agent != null) && (agent.authenticated == 2) && (agent.agentInfo != null)) {
|
||||
try { agent.send(JSON.stringify({ action: 'msg', type: 'console', value: command.cmds, rights: rights, sessionid: ws.sessionId })); } catch (ex) { }
|
||||
if (command.responseid != null) { try { ws.send(JSON.stringify({ action: 'runcommands', responseid: command.responseid, result: 'OK' })); } catch (ex) { } }
|
||||
|
||||
// Send out an event that these commands where run on this device
|
||||
var targets = parent.CreateNodeDispatchTargets(node.meshid, node._id, ['server-users', user._id]);
|
||||
var msgid = 24; // "Running commands"
|
||||
if (command.type == 1) { msgid = 99; } // "Running commands as user"
|
||||
if (command.type == 2) { msgid = 100; } // "Running commands as user if possible"
|
||||
var event = { etype: 'node', userid: user._id, username: user.name, nodeid: node._id, action: 'runcommands', msg: 'Running commands', msgid: msgid, cmds: command.cmds, cmdType: command.type, runAsUser: command.runAsUser, domain: domain.id };
|
||||
parent.parent.DispatchEvent(targets, obj, event);
|
||||
} else {
|
||||
if (command.responseid != null) { try { ws.send(JSON.stringify({ action: 'runcommands', responseid: command.responseid, result: 'Invalid command type' })); } catch (ex) { } }
|
||||
if (command.responseid != null) { try { ws.send(JSON.stringify({ action: 'runcommands', responseid: command.responseid, result: 'Agent not connected' })); } catch (ex) { } }
|
||||
}
|
||||
} else {
|
||||
if (command.responseid != null) { try { ws.send(JSON.stringify({ action: 'runcommands', responseid: command.responseid, result: 'Agent not connected' })); } catch (ex) { } }
|
||||
// This is a standard (bash/shell/powershell) command.
|
||||
|
||||
// Check we have the rights to run commands on this device
|
||||
if ((rights & MESHRIGHT_REMOTECOMMAND) == 0) {
|
||||
if (command.responseid != null) { try { ws.send(JSON.stringify({ action: 'runcommands', responseid: command.responseid, result: 'Access denied' })); } catch (ex) { } }
|
||||
return;
|
||||
}
|
||||
|
||||
// Get the agent and run the commands
|
||||
var agent = parent.wsagents[node._id];
|
||||
if ((agent != null) && (agent.authenticated == 2) && (agent.agentInfo != null)) {
|
||||
// Check if this agent is correct for this command type
|
||||
// command.type 1 = Windows Command, 2 = Windows PowerShell, 3 = Linux/BSD/macOS
|
||||
var commandsOk = false;
|
||||
if ((agent.agentInfo.agentId > 0) && (agent.agentInfo.agentId < 5)) {
|
||||
// Windows Agent
|
||||
if ((command.type == 1) || (command.type == 2)) { commandsOk = true; }
|
||||
else if (command.type === 0) { command.type = 1; commandsOk = true; } // Set the default type of this agent
|
||||
} else {
|
||||
// Non-Windows Agent
|
||||
if (command.type == 3) { commandsOk = true; }
|
||||
else if (command.type === 0) { command.type = 3; commandsOk = true; } // Set the default type of this agent
|
||||
}
|
||||
if (commandsOk == true) {
|
||||
// Send the commands to the agent
|
||||
try { agent.send(JSON.stringify({ action: 'runcommands', type: command.type, cmds: command.cmds, runAsUser: command.runAsUser })); } catch (ex) { }
|
||||
if (command.responseid != null) { try { ws.send(JSON.stringify({ action: 'runcommands', responseid: command.responseid, result: 'OK' })); } catch (ex) { } }
|
||||
|
||||
// Send out an event that these commands where run on this device
|
||||
var targets = parent.CreateNodeDispatchTargets(node.meshid, node._id, ['server-users', user._id]);
|
||||
var msgid = 24; // "Running commands"
|
||||
if (command.type == 1) { msgid = 99; } // "Running commands as user"
|
||||
if (command.type == 2) { msgid = 100; } // "Running commands as user if possible"
|
||||
var event = { etype: 'node', userid: user._id, username: user.name, nodeid: node._id, action: 'runcommands', msg: 'Running commands', msgid: msgid, cmds: command.cmds, cmdType: command.type, runAsUser: command.runAsUser, domain: domain.id };
|
||||
parent.parent.DispatchEvent(targets, obj, event);
|
||||
} else {
|
||||
if (command.responseid != null) { try { ws.send(JSON.stringify({ action: 'runcommands', responseid: command.responseid, result: 'Invalid command type' })); } catch (ex) { } }
|
||||
}
|
||||
} else {
|
||||
if (command.responseid != null) { try { ws.send(JSON.stringify({ action: 'runcommands', responseid: command.responseid, result: 'Agent not connected' })); } catch (ex) { } }
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
if (typeof command.cmdpath == 'string') {
|
||||
// If a server command path is used, load the script from the path
|
||||
var file = parent.getServerFilePath(user, domain, command.cmdpath);
|
||||
if (file != null) {
|
||||
fs.readFile(file.fullpath, function (err, data) {
|
||||
// If loaded correctly, run loaded commands
|
||||
if ((err != null) || (data == null) || (data.length == 0) || (data.length > 65535)) return;
|
||||
command.cmds = data.toString();
|
||||
delete command.cmdpath;
|
||||
processRunCommand(command);
|
||||
});
|
||||
}
|
||||
} else if (typeof command.cmds == 'string') {
|
||||
// Run provided commands
|
||||
if (command.cmds.length > 65535) return;
|
||||
processRunCommand(command);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
@ -591,14 +591,14 @@ body {
|
||||
width: 260px;
|
||||
}
|
||||
|
||||
#d3serveraction {
|
||||
#d3serveraction, #d2serveraction {
|
||||
width: 100%;
|
||||
background-color: #d3d9d6;
|
||||
text-align: left;
|
||||
padding: 3px;
|
||||
}
|
||||
|
||||
#d3serverfiles {
|
||||
#d3serverfiles, #d2serverfiles {
|
||||
width: 100%;
|
||||
height: 150px;
|
||||
background-color: white;
|
||||
|
@ -1281,7 +1281,7 @@
|
||||
</div>
|
||||
<div id=d3servermode>
|
||||
<div id=d3serveraction valign=bottom>
|
||||
<input type=button id=p3FolderUp disabled="disabled" onclick=d3folderup() value="Up" />
|
||||
<input type=button id=p3FolderUp disabled="disabled" onclick=d3folderup() value="Up" /> <span id=p3CurrentFolder></span>
|
||||
</div>
|
||||
<div id=d3serverfiles></div>
|
||||
</div>
|
||||
@ -5731,15 +5731,17 @@
|
||||
x += '</select>';
|
||||
x += '<select id=d2cmduser style=width:100%;margin-bottom:4px><option value=0' + ((runopt.runAs == 0)?' selected':'') + '>' + "Run as agent" + '</option><option value=1' + ((runopt.runAs == 1)?' selected':'') + '>' + "Run as user, agent if no user" + '</option><option value=2' + ((runopt.runAs == 2)?' selected':'') + '>' + "Must run as user" + '</option></select>';
|
||||
x += '<select id=d2cmdsource onclick=d2runCommandValidate() style=width:100%;margin-bottom:4px><option value=0' + ((runopt.source == 0)?' selected':'') + '>' + "Commands from text box" + '</option><option value=1' + ((runopt.source == 1)?' selected':'') + '>' + "Commands from file" + '</option>';
|
||||
//if (userinfo.siteadmin & 8) { x += '<option value=2' + ((runopt.source == 2)?' selected':'') + '>' + "Commands from file on server" + '</option>'; }
|
||||
if (userinfo.siteadmin & 8) { x += '<option value=2' + ((runopt.source == 2)?' selected':'') + '>' + "Commands from file on server" + '</option>'; }
|
||||
x += '</select><textarea id=d2runcmd onkeyup=d2runCommandValidate() style=background-color:#fcf3cf;width:100%;height:200px;resize:none;overflow-y:scroll>' + (runopt.cmd ? EscapeHtml(decodeURIComponent(runopt.cmd)) : '') + '</textarea>';
|
||||
x += '<div id=d2runfile style=display:none><input id=d2runfileex type=file onchange=d2runCommandValidate() id=d2localFile name=files onchange=d2runCommandValidate() /></div>';
|
||||
x += '<div id=d2runsfile style=display:none>bb</div>';
|
||||
if (userinfo.siteadmin & 8) { x += '<div id=d2runsfile style=display:none><div id=d2serveraction valign=bottom><input type=button id=p2FolderUp disabled="disabled" onclick=d3folderup() value="Up" /> <span id=p2CurrentFolder></span></div><div id=d2serverfiles></div></div>'; }
|
||||
setDialogMode(2, "Run Commands", 3, d2groupActionFunctionRunCommands, x, options);
|
||||
Q('d2runcmd').focus();
|
||||
d2runCommandValidate();
|
||||
if (userinfo.siteadmin & 8) { d3fileoptions = { dialog: 2, files: 'd2serverfiles', folderup: 'p2FolderUp', currentFolder: 'p2CurrentFolder', func: null }; d3updatefiles(); } // Update the server files
|
||||
}
|
||||
}
|
||||
|
||||
function d2runCommandValidate() {
|
||||
QV('d2cmduser', Q('d2cmdtype').value < 4);
|
||||
QV('d2runcmd', Q('d2cmdsource').value == 0);
|
||||
@ -5751,6 +5753,7 @@
|
||||
if (Q('d2cmdsource').value == 2) { ok = false; } // From server file
|
||||
QE('idx_dlgOkButton', ok);
|
||||
}
|
||||
|
||||
function d2groupActionFunctionRunCommands(b, options) {
|
||||
var type = 3;
|
||||
try { type = parseInt(Q('d2cmdtype').value); } catch (ex) { }
|
||||
@ -5770,7 +5773,11 @@
|
||||
}
|
||||
if (Q('d2cmdsource').value == 2) {
|
||||
// From server file
|
||||
cmd.cmds = '';
|
||||
var files = d3getFileSel();
|
||||
if (files.length != 1) return;
|
||||
cmd.cmdpath = d3filetreelocation.join('/') + '/' + files[0];
|
||||
meshserver.send(cmd);
|
||||
if (options.func) { options.func(); }
|
||||
}
|
||||
}
|
||||
|
||||
@ -16115,6 +16122,7 @@
|
||||
//
|
||||
|
||||
function d3init() {
|
||||
d3fileoptions = { dialog: 1, filter: 'd3filter', files: 'd3serverfiles', folderup: 'p3FolderUp', currentFolder: 'p3CurrentFolder', func: d3setActions };
|
||||
Q('d3localFile').value = '';
|
||||
Q('d3localFile').accept = Q('d3filter').value;
|
||||
d3modechange();
|
||||
@ -16129,10 +16137,11 @@
|
||||
|
||||
var d3filetreelinkpath;
|
||||
var d3filetreelocation = [];
|
||||
|
||||
var d3fileoptions = null;
|
||||
function d3updatefiles() {
|
||||
if (Q('d3uploadMode').value == 1) return;
|
||||
var html1 = '', html2 = '', filetreex = filetree, folderdepth = 1, publicPath = null;
|
||||
if (d3fileoptions == null) return;
|
||||
if ((d3fileoptions.filter == 'd3filter') && (Q('d3uploadMode').value == 1)) return;
|
||||
var html1 = '', html2 = '', filetreex = filetree, folderdepth = 1, publicPath = null, lastFolderName = '';
|
||||
|
||||
// Navigate to path location, build the paths at the same time
|
||||
var d3filetreelocation2 = [], oldlinkpath = d3filetreelinkpath, checkedBoxes = [], checkboxes = document.getElementsByName('fc');
|
||||
@ -16150,6 +16159,7 @@
|
||||
if (d3filetreelinkpath != '') { d3filetreelinkpath += '/' + d3filetreelocation[i]; if (folderdepth > 2) { publicPath += '/' + d3filetreelocation[i]; } }
|
||||
}
|
||||
filetreex = filetreex.f[d3filetreelocation[i]];
|
||||
lastFolderName = filetreex.n;
|
||||
folderdepth++;
|
||||
} else {
|
||||
break;
|
||||
@ -16161,7 +16171,8 @@
|
||||
var filetreexx = p5sort_files(filetreex.f);
|
||||
|
||||
// File filter
|
||||
var fileFilter = Q('d3filter').value
|
||||
var fileFilter = '';
|
||||
if (d3fileoptions.filter) { fileFilter = Q(d3fileoptions.filter).value };
|
||||
|
||||
// Display all files and folders at this location
|
||||
for (var i in filetreexx) {
|
||||
@ -16189,19 +16200,24 @@
|
||||
if (f.t < 3) { html1 += h; } else { html2 += h; }
|
||||
}
|
||||
|
||||
QH('d3serverfiles', html1 + html2);
|
||||
QE('p3FolderUp', d3filetreelocation.length > 0);
|
||||
d3setActions();
|
||||
if (d3fileoptions.currentFolder) { QH(d3fileoptions.currentFolder, lastFolderName); }
|
||||
QH(d3fileoptions.files, html1 + html2);
|
||||
QE(d3fileoptions.folderup, d3filetreelocation.length > 0);
|
||||
if (d3fileoptions.func) { d3fileoptions.func(); }
|
||||
}
|
||||
|
||||
function d3folderset(x) { d3filetreelocation.push(decodeURIComponent(x)); d3updatefiles(); return false; }
|
||||
function d3folderup(x) { if (x == null) { d3filetreelocation.pop(); } else { while (d3filetreelocation.length > x) { d3filetreelocation.pop(); } } d3updatefiles(); }
|
||||
function d3getFileSel() { var cc = []; var checkboxes = document.getElementsByName('fcx'); for (var i = 0; i < checkboxes.length; i++) { if (checkboxes[i].checked) { cc.push(checkboxes[i].value) } } return cc; }
|
||||
function d3setActions() {
|
||||
var mode = Q('d3uploadMode').value;
|
||||
if (mode == 1) {
|
||||
QE('idx_dlgOkButton', Q('d3localFile').value.length > 0);
|
||||
} else {
|
||||
if (d3fileoptions.dialog == 1) {
|
||||
var mode = Q('d3uploadMode').value;
|
||||
if (mode == 1) {
|
||||
QE('idx_dlgOkButton', Q('d3localFile').value.length > 0);
|
||||
} else {
|
||||
QE('idx_dlgOkButton', d3getFileSel().length == 1);
|
||||
}
|
||||
} else if (d3fileoptions.dialog == 2) {
|
||||
QE('idx_dlgOkButton', d3getFileSel().length == 1);
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user