lib/agent/actions/osquery/index.js
/* eslint-disable consistent-return */
const path = require('path');
const Emitter = require('events').EventEmitter;
const sudo = require('sudoer');
const fs = require('fs');
const common = require('../../../common');
const { join } = path;
const { paths } = common.system;
const { system } = common;
const logger = common.logger.prefix('osquery');
const osName = process.platform.replace('win32', 'windows').replace('darwin', 'mac');
const checkProperties = ['mode', 'version', 'host', 'environment'];
let child;
let emitter;
let action = 'osquery-install';
const checkOsqueryPath = (mode) => {
const osqueryPath = '/private/var/prey';
try {
const stats = fs.statSync(osqueryPath);
if (stats.isDirectory() && mode === 'install') {
// Directory exists
return true;
}
return false;
} catch (err) {
if (err.code === 'ENOENT' && mode === 'uninstall') {
// Directory doesn't exists
return true;
}
return `Error occurred while checking directory: ${err}`;
}
};
const osqueryWindows = (bin, actionWin, data, mode, done) => {
const binWin = `${bin}.exe`;
// eslint-disable-next-line consistent-return
system.spawn_as_admin_user(binWin, data, (errTrinity, osQueryInstallAction) => {
if (errTrinity) {
logger.info(errTrinity);
return done(new Error(errTrinity));
}
if (typeof osQueryInstallAction !== 'function') return done(new Error('Error is not available'));
// eslint-disable-next-line consistent-return
osQueryInstallAction(actionWin, data, (errOsQueryInstallAction, outPutOsQueryInstallAction) => {
if (errOsQueryInstallAction || (outPutOsQueryInstallAction
&& (!Object.prototype.hasOwnProperty.call(outPutOsQueryInstallAction, 'code') || outPutOsQueryInstallAction.code !== 0))) {
const errorOutPut = new Error('Error on osQuery');
return done(errorOutPut);
}
logger.info(`${mode} instruction executed successfully`);
done();
});
});
};
const osqueryUnix = (bin, args, mode, done) => {
// eslint-disable-next-line consistent-return
sudo(bin, args, (err) => {
const execError = err;
if (execError) {
logger.info(execError);
return done(new Error(execError));
}
const osqueryPath = checkOsqueryPath(mode);
if (osqueryPath === true) {
logger.info(`${mode} instruction executed successfully`);
done();
} else if (osqueryPath.includes('Error occurred while checking directory:')) {
return done(new Error(osqueryPath));
}
});
};
const osQueryModeData = (opts, done) => {
let args = null;
const data = {
key: 'device-key',
token: 'token',
logged: false,
};
switch (opts.mode) {
case 'install':
args = [
'--osquery_version',
opts.version,
'--host',
opts.host,
'--env',
opts.environment,
];
data.dirs = [opts.version, opts.host, opts.environment];
break;
case 'uninstall':
args = osName !== 'windows' ? ['--uninstall'] : ['--uninstall', true];
action = 'osquery-uninstall';
data.dirs = [];
break;
default:
return done(new Error('Invalid option'));
}
return { args, data };
};
/**
* Perform installation of osquery binary
*
* @param {function} cb - The callback function to be called after the installation.
* @return {undefined} No return value.
*/
// eslint-disable-next-line consistent-return
exports.start = (id, opts, cb) => {
const done = (err = null) => {
if (err) return cb(err);
if (!emitter) emitter = new Emitter();
cb(err, emitter);
emitter.emit('end', id, err);
};
const bin = join(paths.current, 'bin', 'trinity');
if (opts.mode && opts.mode === 'install') {
const checkedFalsy = [];
Object.values(checkProperties).forEach((key) => {
if (!opts[`${key}`]) {
checkedFalsy.push(key);
}
});
if (checkedFalsy.length > 0) {
return done(new Error(`Options are required: ${checkedFalsy.join(', ')}`));
}
}
const osQueryData = osQueryModeData(opts, done);
switch (osName) {
case 'windows':
return osqueryWindows(bin, action, osQueryData.data, opts.mode, done);
case 'mac':
case 'linux':
return osqueryUnix(bin, osQueryData.args, opts.mode, done);
default:
return done(new Error('Invalid Operating system'));
}
};
exports.stop = () => {
logger.info('inside stop');
if (child && !child.exitCode) {
logger.info('killing child');
child.kill();
}
};