1
0
Fork 0
mirror of https://github.com/Ylianst/MeshCentral.git synced 2025-03-09 15:40:18 +00:00

New MeshCmd, fixes MeshAgent registry values

This commit is contained in:
Ylian Saint-Hilaire 2018-04-04 12:08:28 -07:00
parent 8287997b2d
commit 835e03225d
10 changed files with 142 additions and 279 deletions

View file

@ -1,22 +1,20 @@
var SERVICE_WIN32 = 0x00000010 | 0x00000020;
var SERVICE_STATE = { STOPPED: 0x00000001, SERVICE_START_PENDING: 0x00000002, SERVICE_STOP_PENDING: 0x00000003, RUNNING: 0x00000004 };
var SERVICE_ACCEPT = {SERVICE_ACCEPT_STOP: 0x00000001, SERVICE_ACCEPT_SHUTDOWN: 0x00000004};
var SERVICE_CONTROL = {SERVICE_CONTROL_SHUTDOWN: 0x00000005, SERVICE_CONTROL_STOP: 0x00000001};
var SERVICE_ACCEPT = { SERVICE_ACCEPT_STOP: 0x00000001, SERVICE_ACCEPT_SHUTDOWN: 0x00000004 };
var SERVICE_CONTROL = { SERVICE_CONTROL_SHUTDOWN: 0x00000005, SERVICE_CONTROL_STOP: 0x00000001 };
var NO_ERROR = 0;
var serviceManager = require('serviceManager');
function serviceHost(serviceName)
{
function serviceHost(serviceName) {
this._ObjectID = 'serviceHost';
var emitterUtils = require('events').inherits(this);
emitterUtils.createEvent('serviceStart');
emitterUtils.createEvent('serviceStop');
emitterUtils.createEvent('normalStart');
if (process.platform == 'win32')
{
if (process.platform == 'win32') {
this.GM = require('_GenericMarshal');
this.Advapi = this.GM.CreateNativeProxy('Advapi32.dll');
this.Advapi.CreateMethod({ method: 'StartServiceCtrlDispatcherA', threadDispatch: 1 });
@ -33,8 +31,7 @@ function serviceHost(serviceName)
this._ServiceMain = this.GM.GetGenericGlobalCallback(2);
this._ServiceMain.Parent = this;
this._ServiceMain.GM = this.GM;
this._ServiceMain.on('GlobalCallback', function onGlobalCallback(argc, argv)
{
this._ServiceMain.on('GlobalCallback', function onGlobalCallback(argc, argv) {
//ToDo: Check to make sure this is for us
this.Parent._ServiceStatus = this.GM.CreateVariable(28);
@ -52,8 +49,7 @@ function serviceHost(serviceName)
this.Parent._ServiceStatus.toBuffer().writeUInt32LE(SERVICE_WIN32);
this.Parent._ServiceStatus.toBuffer().writeUInt32LE(SERVICE_STATE.SERVICE_STOPPED, 4);
this.Parent._ServiceStatusHandle = this.Parent.Advapi.RegisterServiceCtrlHandlerA(this.Parent._ServiceName, this.Parent._ServiceControlHandler);
if(this.Parent._ServiceStatusHandle.Val == 0)
{
if (this.Parent._ServiceStatusHandle.Val == 0) {
process.exit(1);
}
@ -67,8 +63,7 @@ function serviceHost(serviceName)
this.Parent.Advapi.SetServiceStatus(this.Parent._ServiceStatusHandle, this.Parent._ServiceStatus);
this.Parent.Ole32.CoInitializeEx(0, 2);
this.Parent.on('~', function OnServiceHostFinalizer()
{
this.Parent.on('~', function OnServiceHostFinalizer() {
var GM = require('_GenericMarshal');
var Advapi = GM.CreateNativeProxy('Advapi32.dll');
Advapi.CreateMethod('SetServiceStatus');
@ -92,10 +87,8 @@ function serviceHost(serviceName)
this._ServiceControlHandler = this.GM.GetGenericGlobalCallback(1);
this._ServiceControlHandler.Parent = this;
this._ServiceControlHandler.GM = this.GM;
this._ServiceControlHandler.on('GlobalCallback', function onServiceControlHandler(code)
{
switch (code.Val)
{
this._ServiceControlHandler.on('GlobalCallback', function onServiceControlHandler(code) {
switch (code.Val) {
case SERVICE_CONTROL.SERVICE_CONTROL_SHUTDOWN:
case SERVICE_CONTROL.SERVICE_CONTROL_STOP:
this.Parent.emit('serviceStop');
@ -113,54 +106,42 @@ function serviceHost(serviceName)
{
throw ('Must specify either ServiceName or Options');
}
if (!this._ServiceOptions.servicePath)
{
if (!this._ServiceOptions.servicePath) {
this._ServiceOptions.servicePath = process.execPath;
}
this.run = function run()
{
this.run = function run() {
var serviceOperation = 0;
for(var i = 0; i<process.argv.length; ++i)
{
switch(process.argv[i])
{
case '-install':
for (var i = 0; i < process.argv.length; ++i) {
switch (process.argv[i].toLowerCase()) {
case 'install':
if (!this._svcManager) { this._svcManager = new serviceManager(); }
try
{
try {
this._svcManager.installService(this._ServiceOptions);
}
catch(e)
{
} catch (e) {
console.log(e);
process.exit();
}
if (process.platform == 'win32')
{
if (process.platform == 'win32') {
// Only do this on Windows, becuase Linux is async... It'll complete later
console.log(this._ServiceOptions.name + ' installed');
console.log(this._ServiceOptions.name + ' installed.');
process.exit();
}
i = process.argv.length;
serviceOperation = 1;
break;
case '-uninstall':
case 'uninstall':
if (!this._svcManager) { this._svcManager = new serviceManager(); }
try
{
try {
this._svcManager.uninstallService(this._ServiceOptions);
}
catch(e)
{
} catch (e) {
console.log(e);
process.exit();
}
if (process.platform == 'win32')
{
if (process.platform == 'win32') {
// Only do this on Windows, becuase Linux is async... It'll complete later
console.log(this._ServiceOptions.name + ' uninstalled');
console.log(this._ServiceOptions.name + ' uninstalled.');
process.exit();
}
i = process.argv.length;
@ -170,55 +151,46 @@ function serviceHost(serviceName)
case '-d':
if (!this._svcManager) { this._svcManager = new serviceManager(); }
this._svcManager.getService(this._ServiceOptions.name).start();
console.log(this._ServiceOptions.name + ' starting...');
console.log(this._ServiceOptions.name + ' starting.');
process.exit();
break;
case 'stop':
case '-s':
if (!this._svcManager) { this._svcManager = new serviceManager(); }
this._svcManager.getService(this._ServiceOptions.name).stop();
console.log(this._ServiceOptions.name + ' stopping...');
console.log(this._ServiceOptions.name + ' stopping.');
process.exit();
break;
}
}
if (process.platform == 'win32')
{
if (process.platform == 'win32') {
var serviceTable = this.GM.CreateVariable(4 * this.GM.PointerSize);
this._ServiceName.pointerBuffer().copy(serviceTable.toBuffer());
this._ServiceMain.pointerBuffer().copy(serviceTable.toBuffer(), this.GM.PointerSize);
this._sscd = this.Advapi.StartServiceCtrlDispatcherA(serviceTable);
this._sscd.parent = this;
this._sscd.on('done', function OnStartServiceCtrlDispatcherA(retVal) {
if (retVal.Val == 0)
{
this.parent.emit('normalStart');
}
if (retVal.Val == 0) { this.parent.emit('normalStart'); }
});
return;
}
var moduleName = this._ServiceOptions ? this._ServiceOptions.name : process.execPath.substring(1 + process.execPath.lastIndexOf('/'));
for (var i = 0; i < process.argv.length; ++i)
{
switch(process.argv[i])
{
for (var i = 0; i < process.argv.length; ++i) {
switch (process.argv[i].toLowerCase()) {
case 'start':
case '-d':
var child = require('child_process').execFile(process.execPath, [moduleName], { type: require('child_process').SpawnTypes.DETACHED });
var pstream = null;
try
{
try {
pstream = require('fs').createWriteStream('/var/run/' + moduleName + '.pid', { flags: 'w' });
}
catch(e)
{
catch (e) {
}
if (pstream == null)
{
if (pstream == null) {
pstream = require('fs').createWriteStream('.' + moduleName + '.pid', { flags: 'w' });
}
pstream.end(child.pid.toString());
@ -229,33 +201,26 @@ function serviceHost(serviceName)
case 'stop':
case '-s':
var pid = null;
try
{
try {
pid = parseInt(require('fs').readFileSync('/var/run/' + moduleName + '.pid', { flags: 'r' }));
require('fs').unlinkSync('/var/run/' + moduleName + '.pid');
}
catch(e)
{
catch (e) {
}
if(pid == null)
{
try
{
if (pid == null) {
try {
pid = parseInt(require('fs').readFileSync('.' + moduleName + '.pid', { flags: 'r' }));
require('fs').unlinkSync('.' + moduleName + '.pid');
}
catch(e)
{
catch (e) {
}
}
if(pid)
{
if (pid) {
process.kill(pid);
console.log(moduleName + ' stopped');
}
else
{
else {
console.log(moduleName + ' not running');
}
process.exit();
@ -263,56 +228,30 @@ function serviceHost(serviceName)
}
}
if(serviceOperation == 0)
{
if (serviceOperation == 0) {
// This is non-windows, so we need to check how this binary was started to determine if this was a service start
// Start by checking if we were started with start/stop
var pid = null;
try
{
pid = parseInt(require('fs').readFileSync('/var/run/' + moduleName + '.pid', { flags: 'r' }));
}
catch (e)
{
}
if (pid == null)
{
try
{
pid = parseInt(require('fs').readFileSync('.' + moduleName + '.pid', { flags: 'r' }));
}
catch (e)
{
}
}
if (pid != null && pid == process.pid)
{
try { pid = parseInt(require('fs').readFileSync('/var/run/' + moduleName + '.pid', { flags: 'r' })); } catch (e) { }
if (pid == null) { try { pid = parseInt(require('fs').readFileSync('.' + moduleName + '.pid', { flags: 'r' })); } catch (e) { } }
if (pid != null && pid == process.pid) {
this.emit('serviceStart');
}
else
{
} else {
// Now we need to check if we were started with systemd
if (require('processManager').getProcessInfo(1).Name == 'systemd')
{
if (require('processManager').getProcessInfo(1).Name == 'systemd') {
this._checkpid = require('child_process').execFile('/bin/sh', ['sh'], { type: require('child_process').SpawnTypes.TERM });
this._checkpid.result = '';
this._checkpid.parent = this;
this._checkpid.on('exit', function onCheckPIDExit()
{
this._checkpid.on('exit', function onCheckPIDExit() {
var lines = this.result.split('\r\n');
for (i in lines)
{
if(lines[i].startsWith(' Main PID:'))
{
for (i in lines) {
if (lines[i].startsWith(' Main PID:')) {
var tokens = lines[i].split(' ');
if (parseInt(tokens[3]) == process.pid)
{
if (parseInt(tokens[3]) == process.pid) {
this.parent.emit('serviceStart');
}
else
{
} else {
this.parent.emit('normalStart');
}
delete this.parent._checkpid;
@ -326,8 +265,7 @@ function serviceHost(serviceName)
this._checkpid.stdin.write("systemctl status " + moduleName + " | grep 'Main PID:'\n");
this._checkpid.stdin.write('exit\n');
}
else
{
else {
// This isn't even a systemd platform, so this couldn't have been a service start
this.emit('normalStart');
}

View file

@ -1,7 +1,6 @@
function parseServiceStatus(token)
{
function parseServiceStatus(token) {
var j = {};
var serviceType = token.Deref(0, 4).IntVal;
j.isFileSystemDriver = ((serviceType & 0x00000002) == 0x00000002);
@ -9,8 +8,7 @@ function parseServiceStatus(token)
j.isSharedProcess = ((serviceType & 0x00000020) == 0x00000020);
j.isOwnProcess = ((serviceType & 0x00000010) == 0x00000010);
j.isInteractive = ((serviceType & 0x00000100) == 0x00000100);
switch (token.Deref((1 * 4), 4).toBuffer().readUInt32LE())
{
switch (token.Deref((1 * 4), 4).toBuffer().readUInt32LE()) {
case 0x00000005:
j.state = 'CONTINUE_PENDING';
break;
@ -35,8 +33,7 @@ function parseServiceStatus(token)
}
var controlsAccepted = token.Deref((2 * 4), 4).toBuffer().readUInt32LE();
j.controlsAccepted = [];
if ((controlsAccepted & 0x00000010) == 0x00000010)
{
if ((controlsAccepted & 0x00000010) == 0x00000010) {
j.controlsAccepted.push('SERVICE_CONTROL_NETBINDADD');
j.controlsAccepted.push('SERVICE_CONTROL_NETBINDREMOVE');
j.controlsAccepted.push('SERVICE_CONTROL_NETBINDENABLE');
@ -54,10 +51,8 @@ function parseServiceStatus(token)
return (j);
}
function serviceManager()
{
if (process.platform == 'win32')
{
function serviceManager() {
if (process.platform == 'win32') {
this.GM = require('_GenericMarshal');
this.proxy = this.GM.CreateNativeProxy('Advapi32.dll');
this.proxy.CreateMethod('OpenSCManagerA');
@ -83,40 +78,31 @@ function serviceManager()
var AdministratorsGroup = this.GM.CreatePointer();
var admin = false;
if (this.proxy.AllocateAndInitializeSid(NTAuthority, 2, 32, 544, 0, 0, 0, 0, 0, 0, AdministratorsGroup).Val != 0)
{
if (this.proxy.AllocateAndInitializeSid(NTAuthority, 2, 32, 544, 0, 0, 0, 0, 0, 0, AdministratorsGroup).Val != 0) {
var member = this.GM.CreateInteger();
if (this.proxy.CheckTokenMembership(0, AdministratorsGroup.Deref(), member).Val != 0)
{
if (this.proxy.CheckTokenMembership(0, AdministratorsGroup.Deref(), member).Val != 0) {
if (member.toBuffer().readUInt32LE() != 0) { admin = true; }
}
this.proxy.FreeSid(AdministratorsGroup.Deref());
}
return admin;
};
this.getServiceFolder = function getServiceFolder()
{
this.getServiceFolder = function getServiceFolder() {
var destinationFolder = null;
if (require('os').arch() == 'x64')
{
if (require('os').arch() == 'x64') {
// 64 bit Windows
if (this.GM.PointerSize == 4)
{
if (this.GM.PointerSize == 4) {
// 32 Bit App
destinationFolder = process.env['ProgramFiles(x86)'];
}
else
{
} else {
// 64 bit App
destinationFolder = process.env['ProgramFiles'];
}
}
else
{
} else {
// 32 bit Windows
destinationFolder = process.env['ProgramFiles'];
}
return (destinationFolder + '\\mesh');
return (destinationFolder + '\\Open Source\\MeshCmd');
};
this.enumerateService = function () {
@ -129,9 +115,7 @@ function serviceManager()
var resumeHandle = this.GM.CreatePointer();
//var services = this.proxy.CreateVariable(262144);
var success = this.proxy.EnumServicesStatusExA(handle, 0, 0x00000030, 0x00000003, 0x00, 0x00, bytesNeeded, servicesReturned, resumeHandle, 0x00);
if (bytesNeeded.IntVal <= 0) {
throw ('error enumerating services');
}
if (bytesNeeded.IntVal <= 0) { throw('Error enumerating services'); }
var sz = bytesNeeded.IntVal;
var services = this.GM.CreateVariable(sz);
this.proxy.EnumServicesStatusExA(handle, 0, 0x00000030, 0x00000003, services, sz, bytesNeeded, servicesReturned, resumeHandle, 0x00);
@ -157,7 +141,7 @@ function serviceManager()
var ptr = this.GM.CreatePointer();
var bytesNeeded = this.GM.CreateVariable(ptr._size);
var handle = this.proxy.OpenSCManagerA(0x00, 0x00, 0x0001 | 0x0004 | 0x0020 | 0x0010);
if (handle.Val == 0) { throw ('could not open ServiceManager'); }
if (handle.Val == 0) { throw('Could not open ServiceManager'); }
var h = this.proxy.OpenServiceA(handle, serviceName, 0x0004 | 0x0020 | 0x0010 | 0x00010000);
if (h.Val != 0) {
var success = this.proxy.QueryServiceStatusEx(h, 0, 0, 0, bytesNeeded);
@ -182,51 +166,46 @@ function serviceManager()
}
}
else {
throw ('cannot call ' + this.name + '.stop(), when current state is: ' + this.status.state);
throw ('Cannot call ' + this.name + '.stop(), when current state is: ' + this.status.state);
}
}
retVal.start = function () {
if (this.status.state == 'STOPPED') {
var success = this._proxy.StartServiceA(this._service, 0, 0);
if (success == 0) {
throw (this.name + '.start() failed');
}
}
else {
throw ('cannot call ' + this.name + '.start(), when current state is: ' + this.status.state);
if (success == 0) { throw (this.name + '.start() failed'); }
} else {
throw ('Cannot call ' + this.name + '.start(), when current state is: ' + this.status.state);
}
}
return (retVal);
}
else {
} else {
}
}
this.proxy.CloseServiceHandle(handle);
throw ('could not find service: ' + name);
throw ('Could not find service: ' + name);
}
}
this.installService = function installService(options)
{
if (process.platform == 'win32')
{
if (!this.isAdmin()) { throw ('Installing as Service, requires admin'); }
this.installService = function installService(options) {
if (process.platform == 'win32') {
if (!this.isAdmin()) { throw ('Installing as Service, requires administrator permissions.'); }
// Before we start, we need to copy the binary to the right place
var folder = this.getServiceFolder();
if (!require('fs').existsSync(folder)) { require('fs').mkdirSync(folder); }
require('fs').copyFileSync(options.servicePath, folder + '\\' + options.name + '.exe');
options.servicePath = folder + '\\' + options.name + '.exe';
console.log('Installing to "' + options.servicePath + '"');
var servicePath = this.GM.CreateVariable('"' + options.servicePath + '"');
var handle = this.proxy.OpenSCManagerA(0x00, 0x00, 0x0002);
if (handle.Val == 0) { throw ('error opening SCManager'); }
if (handle.Val == 0) { throw ('Error opening SCManager'); }
var serviceName = this.GM.CreateVariable(options.name);
var displayName = this.GM.CreateVariable(options.name);
var allAccess = 0x000F01FF;
var serviceType;
switch (options.startType) {
case 'BOOT_START':
@ -264,13 +243,11 @@ function serviceManager()
this.proxy.CloseServiceHandle(handle);
return (this.getService(options.name));
}
if(process.platform == 'linux')
{
switch (this.getServiceType())
{
if (process.platform == 'linux') {
switch (this.getServiceType()) {
case 'init':
require('fs').copyFileSync(options.servicePath, '/etc/init.d/' + options.name);
console.log('copying ' + options.servicePath);
console.log('Copying ' + options.servicePath);
var m = require('fs').statSync('/etc/init.d/' + options.name).mode;
m |= (require('fs').CHMOD_MODES.S_IXUSR | require('fs').CHMOD_MODES.S_IXGRP);
require('fs').chmodSync('/etc/init.d/' + options.name, m);
@ -305,40 +282,25 @@ function serviceManager()
}
}
}
this.uninstallService = function uninstallService(name)
{
this.uninstallService = function uninstallService(name) {
if (typeof (name) == 'object') { name = name.name; }
if (process.platform == 'win32')
{
if (!this.isAdmin()) { throw ('Uninstalling a service, requires admin'); }
if (process.platform == 'win32') {
if (!this.isAdmin()) { throw ('Uninstalling a service, requires administrator permissions.'); }
var service = this.getService(name);
if (service.status.state == undefined || service.status.state == 'STOPPED')
{
if (this.proxy.DeleteService(service._service) == 0)
{
if (service.status.state == undefined || service.status.state == 'STOPPED') {
if (this.proxy.DeleteService(service._service) == 0) {
throw ('Uninstall Service for: ' + name + ', failed with error: ' + this.proxy2.GetLastError());
}
else
{
try
{
require('fs').unlinkSync(this.getServiceFolder() + '\\' + name + '.exe');
}
catch(e)
{
}
} else {
try { require('fs').unlinkSync(this.getServiceFolder() + '\\' + name + '.exe'); } catch (e) { }
}
}
else
{
else {
throw ('Cannot uninstall service: ' + name + ', because it is: ' + service.status.state);
}
}
else if(process.platform == 'linux')
{
switch (this.getServiceType())
{
else if (process.platform == 'linux') {
switch (this.getServiceType()) {
case 'init':
this._update = require('child_process').execFile('/bin/sh', ['sh'], { type: require('child_process').SpawnTypes.TERM });
this._update._svcname = name;
@ -346,11 +308,7 @@ function serviceManager()
try {
require('fs').unlinkSync('/etc/init.d/' + this._svcname);
console.log(this._svcname + ' uninstalled');
}
catch (e) {
console.log(this._svcname + ' could not be uninstalled')
}
} catch (e) { console.log(this._svcname + ' could not be uninstalled'); }
process.exit();
});
this._update.stdout.on('data', function (chunk) { });
@ -366,10 +324,7 @@ function serviceManager()
require('fs').unlinkSync('/usr/local/mesh/' + this._svcname);
require('fs').unlinkSync('/lib/systemd/system/' + this._svcname + '.service');
console.log(this._svcname + ' uninstalled');
}
catch (e) {
console.log(this._svcname + ' could not be uninstalled')
}
} catch (e) { console.log(this._svcname + ' could not be uninstalled'); }
process.exit();
});
this._update.stdout.on('data', function (chunk) { });
@ -382,10 +337,8 @@ function serviceManager()
}
}
}
if(process.platform == 'linux')
{
this.getServiceType = function getServiceType()
{
if (process.platform == 'linux') {
this.getServiceType = function getServiceType() {
return (require('processManager').getProcessInfo(1).Name);
};
}