mirror of
				https://github.com/Ylianst/MeshCentral.git
				synced 2025-03-09 15:40:18 +00: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
					
				
					 3 changed files with 123 additions and 88 deletions
				
			
		
							
								
								
									
										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…
	
	Add table
		Add a link
		
	
		Reference in a new issue