First working MacOS mesh agent

This commit is contained in:
Ylian Saint-Hilaire 2018-11-14 15:44:28 -08:00
parent cf63f78564
commit 35245805fb
10 changed files with 676 additions and 328 deletions

Binary file not shown.

View File

@ -631,7 +631,7 @@ function createMeshCore(agent) {
this.removeAllListeners('data'); this.removeAllListeners('data');
this.on('data', onTunnelControlData); this.on('data', onTunnelControlData);
//this.write('MeshCore Terminal Hello'); //this.write('MeshCore Terminal Hello');
if (process.platform != 'win32') { this.httprequest.process.stdin.write("stty erase ^H\nalias ls='ls --color=auto'\nclear\n"); } if (process.platform == 'linux') { this.httprequest.process.stdin.write("stty erase ^H\nalias ls='ls --color=auto'\nclear\n"); }
} else if (this.httprequest.protocol == 2) } else if (this.httprequest.protocol == 2)
{ {
// Remote desktop using native pipes // Remote desktop using native pipes

View File

@ -187,9 +187,9 @@ function serviceHost(serviceName)
console.log(e); console.log(e);
process.exit(); process.exit();
} }
if (process.platform == 'win32') if (process.platform == 'win32' || process.platform == 'darwin')
{ {
// Only do this on Windows, becuase Linux is async... It'll complete later // Only do this on Windows/MacOS, becuase Linux is async... It'll complete later
console.log(this._ServiceOptions.name + ' installed'); console.log(this._ServiceOptions.name + ' installed');
process.exit(); process.exit();
} }
@ -207,9 +207,9 @@ function serviceHost(serviceName)
console.log(e); console.log(e);
process.exit(); process.exit();
} }
if (process.platform == 'win32') if (process.platform == 'win32' || process.platform == 'darwin')
{ {
// Only do this on Windows, becuase Linux is async... It'll complete later // Only do this on Windows/MacOS, becuase Linux is async... It'll complete later
console.log(this._ServiceOptions.name + ' uninstalled'); console.log(this._ServiceOptions.name + ' uninstalled');
process.exit(); process.exit();
} }
@ -251,138 +251,141 @@ function serviceHost(serviceName)
}); });
return; return;
} }
else if (process.platform == 'linux')
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]) var moduleName = this._ServiceOptions ? this._ServiceOptions.name : process.execPath.substring(1 + process.execPath.lastIndexOf('/'));
{
case 'start':
case '-d':
var child = require('child_process').execFile(process.execPath, [moduleName], { type: require('child_process').SpawnTypes.DETACHED });
var pstream = null;
try
{
pstream = require('fs').createWriteStream('/var/run/' + moduleName + '.pid', { flags: 'w' });
}
catch(e)
{
}
if (pstream == null)
{
pstream = require('fs').createWriteStream('.' + moduleName + '.pid', { flags: 'w' });
}
pstream.end(child.pid.toString());
console.log(moduleName + ' started!'); for (var i = 0; i < process.argv.length; ++i) {
process.exit(); switch (process.argv[i]) {
break; case 'start':
case 'stop': case '-d':
case '-s': var child = require('child_process').execFile(process.execPath, [moduleName], { type: require('child_process').SpawnTypes.DETACHED });
var pid = null; var pstream = null;
try try {
{ pstream = require('fs').createWriteStream('/var/run/' + moduleName + '.pid', { flags: 'w' });
pid = parseInt(require('fs').readFileSync('/var/run/' + moduleName + '.pid', { flags: 'r' }));
require('fs').unlinkSync('/var/run/' + moduleName + '.pid');
}
catch(e)
{
}
if(pid == null)
{
try
{
pid = parseInt(require('fs').readFileSync('.' + moduleName + '.pid', { flags: 'r' }));
require('fs').unlinkSync('.' + moduleName + '.pid');
} }
catch(e) catch (e) {
{
} }
} if (pstream == null) {
pstream = require('fs').createWriteStream('.' + moduleName + '.pid', { flags: 'w' });
}
pstream.end(child.pid.toString());
if(pid) console.log(moduleName + ' started!');
{ process.exit();
process.kill(pid); break;
console.log(moduleName + ' stopped'); case 'stop':
case '-s':
var pid = null;
try {
pid = parseInt(require('fs').readFileSync('/var/run/' + moduleName + '.pid', { flags: 'r' }));
require('fs').unlinkSync('/var/run/' + moduleName + '.pid');
}
catch (e) {
}
if (pid == null) {
try {
pid = parseInt(require('fs').readFileSync('.' + moduleName + '.pid', { flags: 'r' }));
require('fs').unlinkSync('.' + moduleName + '.pid');
}
catch (e) {
}
}
if (pid) {
process.kill(pid);
console.log(moduleName + ' stopped');
}
else {
console.log(moduleName + ' not running');
}
process.exit();
break;
}
}
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' }));
} }
else catch (e) {
{
console.log(moduleName + ' not running');
} }
process.exit(); }
break;
if (pid != null && pid == process.pid) {
this.emit('serviceStart');
}
else {
// Now we need to check if we were started with systemd
if (require('process-manager').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() {
var lines = this.result.split('\r\n');
for (i in lines) {
if (lines[i].startsWith(' Main PID:')) {
var tokens = lines[i].split(' ');
if (parseInt(tokens[3]) == process.pid) {
this.parent.emit('serviceStart');
}
else {
this.parent.emit('normalStart');
}
delete this.parent._checkpid;
return;
}
}
this.parent.emit('normalStart');
delete this.parent._checkpid;
});
this._checkpid.stdout.on('data', function (chunk) { this.parent.result += chunk.toString(); });
this._checkpid.stdin.write("systemctl status " + moduleName + " | grep 'Main PID:'\n");
this._checkpid.stdin.write('exit\n');
}
else {
// This isn't even a systemd platform, so this couldn't have been a service start
this.emit('normalStart');
}
}
} }
} }
else if(process.platform == 'darwin')
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 // First let's fetch all the PIDs of running services
var child = require('child_process').execFile('/bin/sh', ['sh']);
child.stdout.str = '';
child.stdout.on('data', function (chunk) { this.str += chunk.toString(); });
child.stdin.write('launchctl list\nexit\n');
child.waitExit();
// Start by checking if we were started with start/stop var lines = child.stdout.str.split('\n');
var pid = null; var tokens, i;
try var p = {};
for (i = 1; i < lines.length; ++i)
{ {
pid = parseInt(require('fs').readFileSync('/var/run/' + moduleName + '.pid', { flags: 'r' })); tokens = lines[i].split('\t');
if (tokens[0] && tokens[0] != '-') { p[tokens[0]] = tokens[0]; }
} }
catch (e)
{ if(p[process.pid.toString()])
}
if (pid == null)
{
try
{
pid = parseInt(require('fs').readFileSync('.' + moduleName + '.pid', { flags: 'r' }));
}
catch (e)
{
}
}
if (pid != null && pid == process.pid)
{ {
// We are a service!
this.emit('serviceStart'); this.emit('serviceStart');
} }
else else
{ {
// Now we need to check if we were started with systemd this.emit('normalStart');
if (require('process-manager').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()
{
var lines = this.result.split('\r\n');
for (i in lines)
{
if(lines[i].startsWith(' Main PID:'))
{
var tokens = lines[i].split(' ');
if (parseInt(tokens[3]) == process.pid)
{
this.parent.emit('serviceStart');
}
else
{
this.parent.emit('normalStart');
}
delete this.parent._checkpid;
return;
}
}
this.parent.emit('normalStart');
delete this.parent._checkpid;
});
this._checkpid.stdout.on('data', function (chunk) { this.parent.result += chunk.toString(); });
this._checkpid.stdin.write("systemctl status " + moduleName + " | grep 'Main PID:'\n");
this._checkpid.stdin.write('exit\n');
}
else
{
// This isn't even a systemd platform, so this couldn't have been a service start
this.emit('normalStart');
}
} }
} }
}; };

View File

@ -214,6 +214,13 @@ function serviceManager()
throw ('could not find service: ' + name); throw ('could not find service: ' + name);
} }
} }
else
{
this.isAdmin = function isAdmin()
{
return (require('user-sessions').isRoot());
}
}
this.installService = function installService(options) this.installService = function installService(options)
{ {
if (process.platform == 'win32') if (process.platform == 'win32')
@ -273,6 +280,8 @@ function serviceManager()
} }
if(process.platform == 'linux') if(process.platform == 'linux')
{ {
if (!this.isAdmin()) { throw ('Installing as Service, requires root'); }
switch (this.getServiceType()) switch (this.getServiceType())
{ {
case 'init': case 'init':
@ -311,14 +320,70 @@ function serviceManager()
break; break;
} }
} }
if(process.platform == 'darwin')
{
if (!this.isAdmin()) { throw ('Installing as Service, requires root'); }
// Mac OS
var stdoutpath = (options.stdout ? ('<key>StandardOutPath</key>\n<string>' + options.stdout + '</string>') : '');
var autoStart = (options.startType == 'AUTO_START' ? '<true/>' : '<false/>');
var params = ' <key>ProgramArguments</key>\n';
params += ' <array>\n';
params += (' <string>/usr/local/mesh_services/' + options.name + '/' + options.name + '</string>\n');
if(options.parameters)
{
for(var itm in options.parameters)
{
params += (' <string>' + options.parameters[itm] + '</string>\n');
}
}
params += ' </array>\n';
var plist = '<?xml version="1.0" encoding="UTF-8"?>\n';
plist += '<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">\n';
plist += '<plist version="1.0">\n';
plist += ' <dict>\n';
plist += ' <key>Label</key>\n';
plist += (' <string>' + options.name + '</string>\n');
plist += (params + '\n');
plist += ' <key>WorkingDirectory</key>\n';
plist += (' <string>/usr/local/mesh_services/' + options.name + '</string>\n');
plist += (stdoutpath + '\n');
plist += ' <key>RunAtLoad</key>\n';
plist += (autoStart + '\n');
plist += ' </dict>\n';
plist += '</plist>';
if (!require('fs').existsSync('/usr/local/mesh_services')) { require('fs').mkdirSync('/usr/local/mesh_services'); }
if (!require('fs').existsSync('/Library/LaunchDaemons/' + options.name + '.plist'))
{
if (!require('fs').existsSync('/usr/local/mesh_services/' + options.name)) { require('fs').mkdirSync('/usr/local/mesh_services/' + options.name); }
if (options.binary)
{
require('fs').writeFileSync('/usr/local/mesh_services/' + options.name + '/' + options.name, options.binary);
}
else
{
require('fs').copyFileSync(options.servicePath, '/usr/local/mesh_services/' + options.name + '/' + options.name);
}
require('fs').writeFileSync('/Library/LaunchDaemons/' + options.name + '.plist', plist);
var m = require('fs').statSync('/usr/local/mesh_services/' + options.name + '/' + options.name).mode;
m |= (require('fs').CHMOD_MODES.S_IXUSR | require('fs').CHMOD_MODES.S_IXGRP);
require('fs').chmodSync('/usr/local/mesh_services/' + options.name + '/' + options.name, m);
}
else
{
throw ('Service: ' + options.name + ' already exists');
}
}
} }
this.uninstallService = function uninstallService(name) this.uninstallService = function uninstallService(name)
{ {
if (!this.isAdmin()) { throw ('Uninstalling a service, requires admin'); }
if (typeof (name) == 'object') { name = name.name; } if (typeof (name) == 'object') { name = name.name; }
if (process.platform == 'win32') if (process.platform == 'win32')
{ {
if (!this.isAdmin()) { throw ('Uninstalling a service, requires admin'); }
var service = this.getService(name); var service = this.getService(name);
if (service.status.state == undefined || service.status.state == 'STOPPED') if (service.status.state == undefined || service.status.state == 'STOPPED')
{ {
@ -388,6 +453,39 @@ function serviceManager()
break; break;
} }
} }
else if(process.platform == 'darwin')
{
if (require('fs').existsSync('/Library/LaunchDaemons/' + name + '.plist'))
{
var child = require('child_process').execFile('/bin/sh', ['sh']);
child.stdout.on('data', function (chunk) { });
child.stdin.write('launchctl stop ' + name + '\n');
child.stdin.write('launchctl unload /Library/LaunchDaemons/' + name + '.plist\n');
child.stdin.write('exit\n');
child.waitExit();
try
{
require('fs').unlinkSync('/usr/local/mesh_services/' + name + '/' + name);
require('fs').unlinkSync('/Library/LaunchDaemons/' + name + '.plist');
}
catch(e)
{
throw ('Error uninstalling service: ' + name + ' => ' + e);
}
try
{
require('fs').rmdirSync('/usr/local/mesh_services/' + name);
}
catch(e)
{}
}
else
{
throw ('Service: ' + name + ' does not exist');
}
}
} }
if(process.platform == 'linux') if(process.platform == 'linux')
{ {

View File

@ -78,12 +78,20 @@ function UserSessions()
this._marshal = require('_GenericMarshal'); this._marshal = require('_GenericMarshal');
this._kernel32 = this._marshal.CreateNativeProxy('Kernel32.dll'); this._kernel32 = this._marshal.CreateNativeProxy('Kernel32.dll');
this._kernel32.CreateMethod('GetLastError'); this._kernel32.CreateMethod('GetLastError');
this._wts = this._marshal.CreateNativeProxy('Wtsapi32.dll');
this._wts.CreateMethod('WTSEnumerateSessionsA'); try
this._wts.CreateMethod('WTSQuerySessionInformationA'); {
this._wts.CreateMethod('WTSRegisterSessionNotification'); this._wts = this._marshal.CreateNativeProxy('Wtsapi32.dll');
this._wts.CreateMethod('WTSUnRegisterSessionNotification'); this._wts.CreateMethod('WTSEnumerateSessionsA');
this._wts.CreateMethod('WTSFreeMemory'); this._wts.CreateMethod('WTSQuerySessionInformationA');
this._wts.CreateMethod('WTSRegisterSessionNotification');
this._wts.CreateMethod('WTSUnRegisterSessionNotification');
this._wts.CreateMethod('WTSFreeMemory');
}
catch(exc)
{
}
this._user32 = this._marshal.CreateNativeProxy('user32.dll'); this._user32 = this._marshal.CreateNativeProxy('user32.dll');
this._user32.CreateMethod('RegisterPowerSettingNotification'); this._user32.CreateMethod('RegisterPowerSettingNotification');
this._user32.CreateMethod('UnregisterPowerSettingNotification'); this._user32.CreateMethod('UnregisterPowerSettingNotification');
@ -203,7 +211,7 @@ function UserSessions()
this.immediate = setImmediate(function (self) this.immediate = setImmediate(function (self)
{ {
// Now that we have a window handle, we can register it to receive Windows Messages // Now that we have a window handle, we can register it to receive Windows Messages
self.parent._wts.WTSRegisterSessionNotification(self.parent.hwnd, NOTIFY_FOR_ALL_SESSIONS); if (self.parent._wts) { self.parent._wts.WTSRegisterSessionNotification(self.parent.hwnd, NOTIFY_FOR_ALL_SESSIONS); }
self.parent._user32.ACDC_H = self.parent._user32.RegisterPowerSettingNotification(self.parent.hwnd, GUID_ACDC_POWER_SOURCE, 0); self.parent._user32.ACDC_H = self.parent._user32.RegisterPowerSettingNotification(self.parent.hwnd, GUID_ACDC_POWER_SOURCE, 0);
self.parent._user32.BATT_H = self.parent._user32.RegisterPowerSettingNotification(self.parent.hwnd, GUID_BATTERY_PERCENTAGE_REMAINING, 0); self.parent._user32.BATT_H = self.parent._user32.RegisterPowerSettingNotification(self.parent.hwnd, GUID_BATTERY_PERCENTAGE_REMAINING, 0);
self.parent._user32.DISP_H = self.parent._user32.RegisterPowerSettingNotification(self.parent.hwnd, GUID_CONSOLE_DISPLAY_STATE, 0); self.parent._user32.DISP_H = self.parent._user32.RegisterPowerSettingNotification(self.parent.hwnd, GUID_CONSOLE_DISPLAY_STATE, 0);
@ -307,6 +315,38 @@ function UserSessions()
{ {
this.user_session.emit('changed'); this.user_session.emit('changed');
}); });
this._users = function _users()
{
var child = require('child_process').execFile('/bin/sh', ['sh']);
child.stdout.str = '';
child.stdout.on('data', function (chunk) { this.str += chunk.toString(); });
child.stdin.write('awk -F: \'($3 >= 0) {printf "%s:%s\\n", $1, $3}\' /etc/passwd\nexit\n');
child.waitExit();
var lines = child.stdout.str.split('\n');
var ret = {}, tokens;
for (var ln in lines)
{
tokens = lines[ln].split(':');
if (tokens[0]) { ret[tokens[0]] = tokens[1]; }
}
return (ret);
}
this._uids = function _uids() {
var child = require('child_process').execFile('/bin/sh', ['sh']);
child.stdout.str = '';
child.stdout.on('data', function (chunk) { this.str += chunk.toString(); });
child.stdin.write('awk -F: \'($3 >= 0) {printf "%s:%s\\n", $1, $3}\' /etc/passwd\nexit\n');
child.waitExit();
var lines = child.stdout.str.split('\n');
var ret = {}, tokens;
for (var ln in lines) {
tokens = lines[ln].split(':');
if (tokens[0]) { ret[tokens[1]] = tokens[0]; }
}
return (ret);
}
this.Self = function Self() this.Self = function Self()
{ {
var promise = require('promise'); var promise = require('promise');
@ -501,6 +541,43 @@ function UserSessions()
} }
else if(process.platform == 'darwin') else if(process.platform == 'darwin')
{ {
this._users = function ()
{
var child = require('child_process').execFile('/usr/bin/dscl', ['dscl', '.', 'list', '/Users', 'UniqueID']);
child.stdout.str = '';
child.stdout.on('data', function (chunk) { this.str += chunk.toString(); });
child.stdin.write('exit\n');
child.waitExit();
var lines = child.stdout.str.split('\n');
var tokens, i;
var users = {};
for (i = 0; i < lines.length; ++i) {
tokens = lines[i].split(' ');
if (tokens[0]) { users[tokens[0]] = tokens[tokens.length - 1]; }
}
return (users);
}
this._uids = function () {
var child = require('child_process').execFile('/usr/bin/dscl', ['dscl', '.', 'list', '/Users', 'UniqueID']);
child.stdout.str = '';
child.stdout.on('data', function (chunk) { this.str += chunk.toString(); });
child.stdin.write('exit\n');
child.waitExit();
var lines = child.stdout.str.split('\n');
var tokens, i;
var users = {};
for (i = 0; i < lines.length; ++i) {
tokens = lines[i].split(' ');
if (tokens[0]) { users[tokens[tokens.length - 1]] = tokens[0]; }
}
return (users);
}
this._idTable = function() this._idTable = function()
{ {
var table = {}; var table = {};
@ -559,6 +636,48 @@ function UserSessions()
if (cb) { cb.call(this, users); } if (cb) { cb.call(this, users); }
} }
} }
if(process.platform == 'linux' || process.platform == 'darwin')
{
this._self = function _self()
{
var child = require('child_process').execFile('/usr/bin/id', ['id', '-u']);
child.stdout.str = '';
child.stdout.on('data', function (chunk) { this.str += chunk.toString(); });
child.waitExit();
return (parseInt(child.stdout.str));
}
this.isRoot = function isRoot()
{
return (this._self() == 0);
}
this.consoleUid = function consoleUid()
{
var checkstr = process.platform == 'darwin' ? 'console' : ':0';
var child = require('child_process').execFile('/bin/sh', ['sh']);
child.stdout.str = '';
child.stdout.on('data', function (chunk) { this.str += chunk.toString(); });
child.stdin.write('who\nexit\n');
child.waitExit();
var lines = child.stdout.str.split('\n');
var tokens, i, j;
for (i in lines)
{
tokens = lines[i].split(' ');
for (j = 1; j < tokens.length; ++j)
{
if (tokens[j].length > 0 && tokens[j] == checkstr)
{
return (parseInt(this._users()[tokens[0]]));
}
}
}
throw ('nobody logged into console');
}
}
} }
function showActiveOnly(source) function showActiveOnly(source)
{ {

View File

@ -78,12 +78,20 @@ function UserSessions()
this._marshal = require('_GenericMarshal'); this._marshal = require('_GenericMarshal');
this._kernel32 = this._marshal.CreateNativeProxy('Kernel32.dll'); this._kernel32 = this._marshal.CreateNativeProxy('Kernel32.dll');
this._kernel32.CreateMethod('GetLastError'); this._kernel32.CreateMethod('GetLastError');
this._wts = this._marshal.CreateNativeProxy('Wtsapi32.dll');
this._wts.CreateMethod('WTSEnumerateSessionsA'); try
this._wts.CreateMethod('WTSQuerySessionInformationA'); {
this._wts.CreateMethod('WTSRegisterSessionNotification'); this._wts = this._marshal.CreateNativeProxy('Wtsapi32.dll');
this._wts.CreateMethod('WTSUnRegisterSessionNotification'); this._wts.CreateMethod('WTSEnumerateSessionsA');
this._wts.CreateMethod('WTSFreeMemory'); this._wts.CreateMethod('WTSQuerySessionInformationA');
this._wts.CreateMethod('WTSRegisterSessionNotification');
this._wts.CreateMethod('WTSUnRegisterSessionNotification');
this._wts.CreateMethod('WTSFreeMemory');
}
catch(exc)
{
}
this._user32 = this._marshal.CreateNativeProxy('user32.dll'); this._user32 = this._marshal.CreateNativeProxy('user32.dll');
this._user32.CreateMethod('RegisterPowerSettingNotification'); this._user32.CreateMethod('RegisterPowerSettingNotification');
this._user32.CreateMethod('UnregisterPowerSettingNotification'); this._user32.CreateMethod('UnregisterPowerSettingNotification');
@ -203,7 +211,7 @@ function UserSessions()
this.immediate = setImmediate(function (self) this.immediate = setImmediate(function (self)
{ {
// Now that we have a window handle, we can register it to receive Windows Messages // Now that we have a window handle, we can register it to receive Windows Messages
self.parent._wts.WTSRegisterSessionNotification(self.parent.hwnd, NOTIFY_FOR_ALL_SESSIONS); if (self.parent._wts) { self.parent._wts.WTSRegisterSessionNotification(self.parent.hwnd, NOTIFY_FOR_ALL_SESSIONS); }
self.parent._user32.ACDC_H = self.parent._user32.RegisterPowerSettingNotification(self.parent.hwnd, GUID_ACDC_POWER_SOURCE, 0); self.parent._user32.ACDC_H = self.parent._user32.RegisterPowerSettingNotification(self.parent.hwnd, GUID_ACDC_POWER_SOURCE, 0);
self.parent._user32.BATT_H = self.parent._user32.RegisterPowerSettingNotification(self.parent.hwnd, GUID_BATTERY_PERCENTAGE_REMAINING, 0); self.parent._user32.BATT_H = self.parent._user32.RegisterPowerSettingNotification(self.parent.hwnd, GUID_BATTERY_PERCENTAGE_REMAINING, 0);
self.parent._user32.DISP_H = self.parent._user32.RegisterPowerSettingNotification(self.parent.hwnd, GUID_CONSOLE_DISPLAY_STATE, 0); self.parent._user32.DISP_H = self.parent._user32.RegisterPowerSettingNotification(self.parent.hwnd, GUID_CONSOLE_DISPLAY_STATE, 0);
@ -307,6 +315,38 @@ function UserSessions()
{ {
this.user_session.emit('changed'); this.user_session.emit('changed');
}); });
this._users = function _users()
{
var child = require('child_process').execFile('/bin/sh', ['sh']);
child.stdout.str = '';
child.stdout.on('data', function (chunk) { this.str += chunk.toString(); });
child.stdin.write('awk -F: \'($3 >= 0) {printf "%s:%s\\n", $1, $3}\' /etc/passwd\nexit\n');
child.waitExit();
var lines = child.stdout.str.split('\n');
var ret = {}, tokens;
for (var ln in lines)
{
tokens = lines[ln].split(':');
if (tokens[0]) { ret[tokens[0]] = tokens[1]; }
}
return (ret);
}
this._uids = function _uids() {
var child = require('child_process').execFile('/bin/sh', ['sh']);
child.stdout.str = '';
child.stdout.on('data', function (chunk) { this.str += chunk.toString(); });
child.stdin.write('awk -F: \'($3 >= 0) {printf "%s:%s\\n", $1, $3}\' /etc/passwd\nexit\n');
child.waitExit();
var lines = child.stdout.str.split('\n');
var ret = {}, tokens;
for (var ln in lines) {
tokens = lines[ln].split(':');
if (tokens[0]) { ret[tokens[1]] = tokens[0]; }
}
return (ret);
}
this.Self = function Self() this.Self = function Self()
{ {
var promise = require('promise'); var promise = require('promise');
@ -501,6 +541,43 @@ function UserSessions()
} }
else if(process.platform == 'darwin') else if(process.platform == 'darwin')
{ {
this._users = function ()
{
var child = require('child_process').execFile('/usr/bin/dscl', ['dscl', '.', 'list', '/Users', 'UniqueID']);
child.stdout.str = '';
child.stdout.on('data', function (chunk) { this.str += chunk.toString(); });
child.stdin.write('exit\n');
child.waitExit();
var lines = child.stdout.str.split('\n');
var tokens, i;
var users = {};
for (i = 0; i < lines.length; ++i) {
tokens = lines[i].split(' ');
if (tokens[0]) { users[tokens[0]] = tokens[tokens.length - 1]; }
}
return (users);
}
this._uids = function () {
var child = require('child_process').execFile('/usr/bin/dscl', ['dscl', '.', 'list', '/Users', 'UniqueID']);
child.stdout.str = '';
child.stdout.on('data', function (chunk) { this.str += chunk.toString(); });
child.stdin.write('exit\n');
child.waitExit();
var lines = child.stdout.str.split('\n');
var tokens, i;
var users = {};
for (i = 0; i < lines.length; ++i) {
tokens = lines[i].split(' ');
if (tokens[0]) { users[tokens[tokens.length - 1]] = tokens[0]; }
}
return (users);
}
this._idTable = function() this._idTable = function()
{ {
var table = {}; var table = {};
@ -559,6 +636,48 @@ function UserSessions()
if (cb) { cb.call(this, users); } if (cb) { cb.call(this, users); }
} }
} }
if(process.platform == 'linux' || process.platform == 'darwin')
{
this._self = function _self()
{
var child = require('child_process').execFile('/usr/bin/id', ['id', '-u']);
child.stdout.str = '';
child.stdout.on('data', function (chunk) { this.str += chunk.toString(); });
child.waitExit();
return (parseInt(child.stdout.str));
}
this.isRoot = function isRoot()
{
return (this._self() == 0);
}
this.consoleUid = function consoleUid()
{
var checkstr = process.platform == 'darwin' ? 'console' : ':0';
var child = require('child_process').execFile('/bin/sh', ['sh']);
child.stdout.str = '';
child.stdout.on('data', function (chunk) { this.str += chunk.toString(); });
child.stdin.write('who\nexit\n');
child.waitExit();
var lines = child.stdout.str.split('\n');
var tokens, i, j;
for (i in lines)
{
tokens = lines[i].split(' ');
for (j = 1; j < tokens.length; ++j)
{
if (tokens[j].length > 0 && tokens[j] == checkstr)
{
return (parseInt(this._users()[tokens[0]]));
}
}
}
throw ('nobody logged into console');
}
}
} }
function showActiveOnly(source) function showActiveOnly(source)
{ {

View File

@ -1,6 +1,6 @@
{ {
"name": "meshcentral", "name": "meshcentral",
"version": "0.2.3-a", "version": "0.2.3-c",
"keywords": [ "keywords": [
"Remote Management", "Remote Management",
"Intel AMT", "Intel AMT",

File diff suppressed because one or more lines are too long

View File

@ -1936,6 +1936,10 @@
for (var i in multiDesktop) { for (var i in multiDesktop) {
// If a device is no longer viewed, disconnect it. // If a device is no longer viewed, disconnect it.
if (multiDesktop[i].xxdelete == true) { multiDesktop[i].Stop(); delete multiDesktop[i]; } if (multiDesktop[i].xxdelete == true) { multiDesktop[i].Stop(); delete multiDesktop[i]; }
else if (debugmode && multiDesktop[i].m && multiDesktop[i].m.onScreenSizeChange) {
// Adjust screen size change (JOKO) - This is not good.
multiDesktop[i].m.onScreenSizeChange();
}
} }
deskAdjust(); deskAdjust();
} else { } else {
@ -2197,7 +2201,7 @@
// OSX agent install // OSX agent install
x += "<div id=agins_osx style=display:none>To add a new computer to device group \"" + EscapeHtml(mesh.name) + "\", download the mesh agent and install it the computer to manage. This agent installer has server and mesh information embedded within it.<br /><br />"; x += "<div id=agins_osx style=display:none>To add a new computer to device group \"" + EscapeHtml(mesh.name) + "\", download the mesh agent and install it the computer to manage. This agent installer has server and mesh information embedded within it.<br /><br />";
x += addHtmlValue('Mesh Agent', '<a href="meshosxagent?id=16&meshid=' + meshid.split('/')[2] + '" target="_blank" title="64bit version of OSX Mesh Agent">OSX Agent (64bit) - TEST BUILD</a>'); x += addHtmlValue('Mesh Agent', '<a href="meshosxagent?id=16&meshid=' + meshid.split('/')[2] + '" target="_blank" title="64bit version of OSX Mesh Agent">OSX Agent (64bit)</a>');
x += "</div>"; x += "</div>";
// Windows agent uninstall // Windows agent uninstall

View File

@ -1682,12 +1682,13 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) {
// Skip all folder entries // Skip all folder entries
zipfile.readEntry(); zipfile.readEntry();
} else { } else {
if (entry.fileName == 'Meshcentral_MeshAgent.mpkg/Contents/distribution.dist') { if (entry.fileName == 'MeshAgent.mpkg/Contents/distribution.dist') {
// This is a special file entry, we need to fix it. // This is a special file entry, we need to fix it.
zipfile.openReadStream(entry, function (err, readStream) { zipfile.openReadStream(entry, function (err, readStream) {
readStream.on("data", function (data) { if (readStream.xxdata) { readStream.xxdata += data; } else { readStream.xxdata = data; } }); readStream.on("data", function (data) { if (readStream.xxdata) { readStream.xxdata += data; } else { readStream.xxdata = data; } });
readStream.on("end", function () { readStream.on("end", function () {
var welcomemsg = 'Welcome to the MeshCentral agent for OSX\\\n\\\nThis installer will install the mesh agent for "' + mesh.name + '" and allow the administrator to remotely monitor and control this computer over the internet. For more information, go to info.meshcentral.com.\\\n\\\nThis software is provided under Apache 2.0 license.\\\n'; var meshname = mesh.name.split(']').join('').split('[').join(''); // We can't have ']]' in the string since it will terminate the CDATA.
var welcomemsg = 'Welcome to the MeshCentral agent for MacOS\n\nThis installer will install the mesh agent for "' + meshname + '" and allow the administrator to remotely monitor and control this computer over the internet. For more information, go to https://www.meshcommander.com/meshcentral2.\n\nThis software is provided under Apache 2.0 license.\n';
var installsize = Math.floor((argentInfo.size + meshsettings.length) / 1024); var installsize = Math.floor((argentInfo.size + meshsettings.length) / 1024);
archive.append(readStream.xxdata.toString().split('###WELCOMEMSG###').join(welcomemsg).split('###INSTALLSIZE###').join(installsize), { name: entry.fileName }); archive.append(readStream.xxdata.toString().split('###WELCOMEMSG###').join(welcomemsg).split('###INSTALLSIZE###').join(installsize), { name: entry.fileName });
zipfile.readEntry(); zipfile.readEntry();
@ -1697,15 +1698,17 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) {
// Normal file entry // Normal file entry
zipfile.openReadStream(entry, function (err, readStream) { zipfile.openReadStream(entry, function (err, readStream) {
if (err) { throw err; } if (err) { throw err; }
archive.append(readStream, { name: entry.fileName }); var options = { name: entry.fileName };
if (entry.fileName.endsWith('postflight') || entry.fileName.endsWith('Uninstall.command')) { options.mode = 493; }
archive.append(readStream, options);
readStream.on('end', function () { zipfile.readEntry(); }); readStream.on('end', function () { zipfile.readEntry(); });
}); });
} }
} }
}); });
zipfile.on("end", function () { zipfile.on("end", function () {
archive.file(argentInfo.path, { name: "Meshcentral_MeshAgent.mpkg/Contents/Packages/meshagentosx64.pkg/Contents/meshagent_osx64.bin" }); archive.file(argentInfo.path, { name: "MeshAgent.mpkg/Contents/Packages/internal.pkg/Contents/meshagent_osx64.bin" });
archive.append(meshsettings, { name: "Meshcentral_MeshAgent.mpkg/Contents/Packages/meshagentosx64.pkg/Contents/meshagent_osx64.msh" }); archive.append(meshsettings, { name: "MeshAgent.mpkg/Contents/Packages/internal.pkg/Contents/meshagent_osx64.msh" });
archive.finalize(); archive.finalize();
}); });
}); });