synced recoverycore.js changes with meshcore.js

Bryan Roe committed Jan 18, 2021 at 19:04 UTC d8dc375d223a0a4bb775b6199f5beac907d6dcd0
1 file changed +207 -39
agents/meshcore.js
+207 -39
@@ -3726,13 +3726,150 @@ function createMeshCore(agent) {
3726 require('MeshAgent').SendCommand({ action: 'sessions', type: 'msg', value: sendAgentMessage.messages });
3727 }
3728
3729 - function windows_execve(name, agentfilename, sessionid) {
3729 + function linux_execv(name, agentfilename, sessionid)
3730 + {
3731 + var libs = require('monitor-info').getLibInfo('libc');
3732 + var libc = null;
3733 +
3734 + while (libs.length > 0)
3735 + {
3736 + try
3737 + {
3738 + libc = require('_GenericMarshal').CreateNativeProxy(libs.pop().path);
3739 + break;
3740 + }
3741 + catch (e)
3742 + {
3743 + libc = null;
3744 + continue;
3745 + }
3746 + }
3747 + if (libc != null)
3748 + {
3749 + try
3750 + {
3751 + libc.CreateMethod('execv');
3752 + }
3753 + catch (e)
3754 + {
3755 + libc = null;
3756 + }
3757 + }
3758 +
3759 + if (libc == null)
3760 + {
3761 + // Couldn't find libc.so, fallback to using service manager to restart agent
3762 + if (sessionid != null) { sendConsoleText('Restarting service via service-manager...', sessionid) }
3763 + try
3764 + {
3765 + // restart service
3766 + var s = require('service-manager').manager.getService(name);
3767 + s.restart();
3768 + }
3769 + catch (zz)
3770 + {
3771 + sendConsoleText('Self Update encountered an error trying to restart service', sessionid);
3772 + sendAgentMessage('Self Update encountered an error trying to restart service', 3);
3773 + }
3774 + return;
3775 + }
3776 +
3777 + if (sessionid != null) { sendConsoleText('Restarting service via execv()...', sessionid) }
3778 +
3779 + var i;
3780 + var args;
3781 + var argarr = [];
3782 + var path = require('_GenericMarshal').CreateVariable(process.execPath);
3783 +
3784 + if (require('MeshAgent').getStartupOptions != null)
3785 + {
3786 + var options = require('MeshAgent').getStartupOptions();
3787 + for (i in options)
3788 + {
3789 + argarr.push('--' + i + '="' + options[i] + '"');
3790 + }
3791 + }
3792 +
3793 + args = require('_GenericMarshal').CreateVariable((1 + argarr.length) * require('_GenericMarshal').PointerSize);
3794 + for (i = 0; i < argarr.length; ++i)
3795 + {
3796 + var arg = require('_GenericMarshal').CreateVariable(argarr[i]);
3797 + arg.pointerBuffer().copy(args.toBuffer(), i * require('_GenericMarshal').PointerSize);
3798 + }
3799 +
3800 + libc.execv(path, args);
3801 + if (sessionid != null) { sendConsoleText('Self Update failed because execv() failed', sessionid) }
3802 + sendAgentMessage('Self Update failed because execv() failed', 3);
3803 + }
3804 +
3805 + function bsd_execv(name, agentfilename, sessionid)
3806 + {
3807 + var child = require('child_process').execFile('/bin/sh', ['sh']);
3808 + child.stdout.str = ''; child.stdout.on('data', function (c) { this.str += c.toString(); });
3809 + child.stderr.str = ''; child.stderr.on('data', function (c) { this.str += c.toString(); });
3810 + child.stdin.write("cat /usr/lib/libc.so | awk '");
3811 + child.stdin.write('{');
3812 + child.stdin.write(' a=split($0, tok, "(");');
3813 + child.stdin.write(' if(a>1)');
3814 + child.stdin.write(' {');
3815 + child.stdin.write(' split(tok[2], b, ")");');
3816 + child.stdin.write(' split(b[1], c, " ");');
3817 + child.stdin.write(' print c[1];');
3818 + child.stdin.write(' }');
3819 + child.stdin.write("}'\nexit\n");
3820 + child.waitExit();
3821 + if (child.stdout.str.trim() == '')
3822 + {
3823 + if (sessionid != null) { sendConsoleText('Self Update failed because cannot find libc.so', sessionid) }
3824 + sendAgentMessage('Self Update failed because cannot find libc.so', 3);
3825 + return;
3826 + }
3827 +
3828 + var libc = null;
3829 + try
3830 + {
3831 + libc = require('_GenericMarshal').CreateNativeProxy(child.stdout.str.trim());
3832 + libc.CreateMethod('execv');
3833 + }
3834 + catch (e)
3835 + {
3836 + if (sessionid != null) { sendConsoleText('Self Update failed: ' + e.toString(), sessionid) }
3837 + sendAgentMessage('Self Update failed: ' + e.toString(), 3);
3838 + return;
3839 + }
3840 +
3841 + var i;
3842 + var path = require('_GenericMarshal').CreateVariable(process.execPath);
3843 + var argarr = [];
3844 + var args;
3845 + var options = require('MeshAgent').getStartupOptions();
3846 + for (i in options)
3847 + {
3848 + argarr.push('--' + i + '="' + options[i] + '"');
3849 + }
3850 + args = require('_GenericMarshal').CreateVariable((1 + argarr.length) * require('_GenericMarshal').PointerSize);
3851 + for (i = 0; i < argarr.length; ++i)
3852 + {
3853 + var arg = require('_GenericMarshal').CreateVariable(argarr[i]);
3854 + arg.pointerBuffer().copy(args.toBuffer(), i * require('_GenericMarshal').PointerSize);
3855 + }
3856 +
3857 + if (sessionid != null) { sendConsoleText('Restarting service via service-manager', sessionid) }
3858 + libc.execv(path, args);
3859 + if (sessionid != null) { sendConsoleText('Self Update failed because execv() failed', sessionid) }
3860 + sendAgentMessage('Self Update failed because execv() failed', 3);
3861 + }
3862 +
3863 + function windows_execve(name, agentfilename, sessionid)
3864 + {
3865 var libc;
3731 - try {
3866 + try
3867 + {
3868 libc = require('_GenericMarshal').CreateNativeProxy('msvcrt.dll');
3869 libc.CreateMethod('_wexecve');
3870 }
3735 - catch (xx) {
3871 + catch (xx)
3872 + {
3873 sendConsoleText('Self Update failed because msvcrt.dll is missing', sessionid);
3874 sendAgentMessage('Self Update failed because msvcrt.dll is missing', 3);
3875 return;
@@ -3750,33 +3887,41 @@ function createMeshCore(agent) {
3887 }
3888
3889 // Start a JavaScript based Agent Self-Update
3753 - function agentUpdate_Start(updateurl, updateoptions) {
3890 + function agentUpdate_Start(updateurl, updateoptions)
3891 + {
3892 // If this value is null
3893 var sessionid = (updateoptions != null) ? updateoptions.sessionid : null; // If this is null, messages will be broadcast. Otherwise they will be unicasted
3894
3757 - if (this._selfupdate != null) {
3895 + if (this._selfupdate != null)
3896 + {
3897 // We were already called, so we will ignore this duplicate request
3898 if (sessionid != null) { sendConsoleText('Self update already in progress...', sessionid); }
3899 }
3761 - else {
3762 - if (require('MeshAgent').ARCHID == null && updateurl == null) {
3900 + else
3901 + {
3902 + if (require('MeshAgent').ARCHID == null && updateurl == null)
3903 + {
3904 // This agent doesn't have the ability to tell us which ARCHID it is, so we don't know which agent to pull
3905 sendConsoleText('Unable to initiate update, agent ARCHID is not defined', sessionid);
3906 }
3766 - else {
3907 + else
3908 + {
3909 var agentfilename = process.execPath.split(process.platform == 'win32' ? '\\' : '/').pop(); // Local File Name, ie: MeshAgent.exe
3910 var name = require('MeshAgent').serviceName;
3911 if (name == null) { name = process.platform == 'win32' ? 'Mesh Agent' : 'meshagent'; } // This is an older agent that doesn't expose the service name, so use the default
3770 - try {
3912 + try
3913 + {
3914 var s = require('service-manager').manager.getService(name);
3772 - if (!s.isMe()) {
3915 + if (!s.isMe())
3916 + {
3917 if (process.platform == 'win32') { s.close(); }
3918 sendConsoleText('Self Update cannot continue, this agent is not an instance of (' + name + ')', sessionid);
3919 return;
3920 }
3921 if (process.platform == 'win32') { s.close(); }
3922 }
3779 - catch (zz) {
3923 + catch (zz)
3924 + {
3925 sendConsoleText('Self Update Failed because this agent is not an instance of (' + name + ')', sessionid);
3926 sendAgentMessage('Self Update Failed because this agent is not an instance of (' + name + ')', 3);
3927 return;
@@ -3787,13 +3932,15 @@ function createMeshCore(agent) {
3932 options.protocol = 'https:';
3933 if (updateurl == null) { options.path = ('/meshagents?id=' + require('MeshAgent').ARCHID); }
3934 options.rejectUnauthorized = false;
3790 - options.checkServerIdentity = function checkServerIdentity(certs) {
3935 + options.checkServerIdentity = function checkServerIdentity(certs)
3936 + {
3937 // If the tunnel certificate matches the control channel certificate, accept the connection
3938 try { if (require('MeshAgent').ServerInfo.ControlChannelCertificate.digest == certs[0].digest) return; } catch (ex) { }
3939 try { if (require('MeshAgent').ServerInfo.ControlChannelCertificate.fingerprint == certs[0].fingerprint) return; } catch (ex) { }
3940
3941 // Check that the certificate is the one expected by the server, fail if not.
3796 - if (checkServerIdentity.servertlshash == null) {
3942 + if (checkServerIdentity.servertlshash == null)
3943 + {
3944 if (require('MeshAgent').ServerInfo == null || require('MeshAgent').ServerInfo.ControlChannelCertificate == null) { return; }
3945
3946 sendConsoleText('Self Update failed, because the url cannot be verified', sessionid);
@@ -3801,7 +3948,8 @@ function createMeshCore(agent) {
3948 throw new Error('BadCert');
3949 }
3950 if (certs[0].digest == null) { return; }
3804 - if ((checkServerIdentity.servertlshash != null) && (checkServerIdentity.servertlshash.toLowerCase() != certs[0].digest.split(':').join('').toLowerCase())) {
3951 + if ((checkServerIdentity.servertlshash != null) && (checkServerIdentity.servertlshash.toLowerCase() != certs[0].digest.split(':').join('').toLowerCase()))
3952 + {
3953 sendConsoleText('Self Update failed, because the supplied certificate does not match', sessionid);
3954 sendAgentMessage('Self Update failed, because the supplied certificate does not match', 3);
3955 throw new Error('BadCert')
@@ -3809,60 +3957,80 @@ function createMeshCore(agent) {
3957 }
3958 options.checkServerIdentity.servertlshash = (updateoptions != null ? updateoptions.tlshash : null);
3959 this._selfupdate = require('https').get(options);
3812 - this._selfupdate.on('error', function (e) {
3960 + this._selfupdate.on('error', function (e)
3961 + {
3962 sendConsoleText('Self Update failed, because there was a problem trying to download the update', sessionid);
3963 sendAgentMessage('Self Update failed, because there was a problem trying to download the update', 3);
3964 });
3816 - this._selfupdate.on('response', function (img) {
3965 + this._selfupdate.on('response', function (img)
3966 + {
3967 this._file = require('fs').createWriteStream(agentfilename + '.update', { flags: 'wb' });
3968 this._filehash = require('SHA384Stream').create();
3819 - this._filehash.on('hash', function (h) {
3820 - if (updateoptions != null && updateoptions.hash != null) {
3821 - if (updateoptions.hash.toLowerCase() == h.toString('hex').toLowerCase()) {
3969 + this._filehash.on('hash', function (h)
3970 + {
3971 + if (updateoptions != null && updateoptions.hash != null)
3972 + {
3973 + if (updateoptions.hash.toLowerCase() == h.toString('hex').toLowerCase())
3974 + {
3975 if (sessionid != null) { sendConsoleText('Download complete. HASH verified.', sessionid); }
3976 }
3824 - else {
3977 + else
3978 + {
3979 sendConsoleText('Self Update FAILED because the downloaded agent FAILED hash check', sessionid);
3980 sendAgentMessage('Self Update FAILED because the downloaded agent FAILED hash check', 3);
3981 return;
3982 }
3983 }
3830 - else {
3831 - if (sessionid != null) { sendConsoleText('Download complete. HASH=' + h.toString('hex'), sessionid); }
3984 + else
3985 + {
3986 + sendConsoleText('Download complete. HASH=' + h.toString('hex'), sessionid);
3987 }
3988
3989 // Send an indication to the server that we got the update download correctly.
3835 - try { mesh.SendCommand({ action: 'agentupdatedownloaded' }); } catch (e) { }
3990 + try { require('MeshAgent').SendCommand({ action: 'agentupdatedownloaded' }); } catch (e) { }
3991
3992 if (sessionid != null) { sendConsoleText('Updating and restarting agent...', sessionid); }
3838 - if (process.platform == 'win32') {
3993 + if (process.platform == 'win32')
3994 + {
3995 // Use _wexecve() equivalent to perform the update
3996 windows_execve(name, agentfilename, sessionid);
3997 }
3842 - else {
3998 + else
3999 + {
4000 + var m = require('fs').statSync(process.execPath).mode;
4001 + require('fs').chmodSync(process.cwd() + agentfilename + '.update', m);
4002 +
4003 // remove binary
4004 require('fs').unlinkSync(process.execPath);
4005
4006 // copy update
4007 require('fs').copyFileSync(process.cwd() + agentfilename + '.update', process.execPath);
4008 + require('fs').chmodSync(process.execPath, m);
4009
4010 // erase update
4011 require('fs').unlinkSync(process.cwd() + agentfilename + '.update');
4012
3852 - // add execute permissions
3853 - var m = require('fs').statSync(process.execPath).mode;
3854 - m |= (require('fs').CHMOD_MODES.S_IXUSR | require('fs').CHMOD_MODES.S_IXGRP | require('fs').CHMOD_MODES.S_IXOTH);
3855 - require('fs').chmodSync(process.execPath, m);
3856 -
3857 - if (sessionid != null) { sendConsoleText('Restarting service...', sessionid); }
3858 - try {
3859 - // restart service
3860 - var s = require('service-manager').manager.getService(name);
3861 - s.restart();
3862 - }
3863 - catch (zz) {
3864 - sendConsoleText('Self Update encountered an error trying to restart service', sessionid);
3865 - sendAgentMessage('Self Update encountered an error trying to restart service', 3);
4013 + switch (process.platform)
4014 + {
4015 + case 'freebsd':
4016 + bsd_execv(name, agentfilename, sessionid);
4017 + break;
4018 + case 'linux':
4019 + linux_execv(name, agentfilename, sessionid);
4020 + break;
4021 + default:
4022 + try
4023 + {
4024 + // restart service
4025 + var s = require('service-manager').manager.getService(name);
4026 + s.restart();
4027 + }
4028 + catch (zz)
4029 + {
4030 + sendConsoleText('Self Update encountered an error trying to restart service', sessionid);
4031 + sendAgentMessage('Self Update encountered an error trying to restart service', 3);
4032 + }
4033 + break;
4034 }
4035 }
4036 });