mirror of
https://github.com/oxen-io/lokinet.git
synced 2024-11-17 15:25:35 +00:00
148 lines
3.6 KiB
C++
148 lines
3.6 KiB
C++
#include <hook/shell.hpp>
|
|
#if defined(_WIN32)
|
|
/** put win32 stuff here */
|
|
#else
|
|
#include <util/threadpool.h>
|
|
#include <util/logger.hpp>
|
|
#include <sys/wait.h>
|
|
#include <unistd.h>
|
|
#endif
|
|
#if defined(Darwin)
|
|
#include <crt_externs.h>
|
|
#endif
|
|
|
|
namespace llarp
|
|
{
|
|
namespace hooks
|
|
{
|
|
#if defined(_WIN32)
|
|
Backend_ptr ExecShellBackend(std::string)
|
|
{
|
|
return nullptr;
|
|
}
|
|
#else
|
|
struct ExecShellHookJob
|
|
{
|
|
const std::string &m_File;
|
|
const std::unordered_map< std::string, std::string > m_env;
|
|
ExecShellHookJob(
|
|
const std::string &f,
|
|
const std::unordered_map< std::string, std::string > _env)
|
|
: m_File(f), m_env(std::move(_env))
|
|
{
|
|
}
|
|
|
|
static void
|
|
Exec(void *user)
|
|
{
|
|
ExecShellHookJob *self = static_cast< ExecShellHookJob * >(user);
|
|
std::vector< std::string > _args;
|
|
std::vector< char * > args;
|
|
std::istringstream s(self->m_File);
|
|
for(std::string arg; std::getline(s, arg, ' ');)
|
|
{
|
|
_args.emplace_back(std::move(arg));
|
|
char *ptr = (char *)_args.back().c_str();
|
|
args.push_back(ptr);
|
|
}
|
|
args.push_back(0);
|
|
std::vector< std::string > _env(self->m_env.size() + 1);
|
|
std::vector< char * > env;
|
|
// copy environ
|
|
#if defined(Darwin)
|
|
char **ptr = *_NSGetEnviron();
|
|
#else
|
|
char **ptr = environ;
|
|
#endif
|
|
do
|
|
{
|
|
env.emplace_back(*ptr);
|
|
++ptr;
|
|
} while(ptr && *ptr);
|
|
// put in our variables
|
|
for(const auto &item : self->m_env)
|
|
{
|
|
_env.emplace_back(item.first + "=" + item.second);
|
|
char *ptr = (char *)_env.back().c_str();
|
|
env.push_back(ptr);
|
|
}
|
|
env.push_back(0);
|
|
const auto exe = _args[0].c_str();
|
|
const auto argv = args.data();
|
|
const auto argp = env.data();
|
|
|
|
pid_t child_process = ::fork();
|
|
if(child_process == -1)
|
|
{
|
|
LogError("failed to fork");
|
|
delete self;
|
|
return;
|
|
}
|
|
if(child_process)
|
|
{
|
|
int status = 0;
|
|
::waitpid(child_process, &status, 0);
|
|
LogInfo(_args[0], " exit code: ", status);
|
|
delete self;
|
|
}
|
|
else if(::execve(exe, argv, argp) == -1)
|
|
{
|
|
LogError("failed to exec ", _args[0], " : ", strerror(errno));
|
|
}
|
|
}
|
|
};
|
|
|
|
struct ExecShellHookBackend : public IBackend
|
|
{
|
|
llarp_threadpool *m_ThreadPool;
|
|
const std::string m_ScriptFile;
|
|
|
|
ExecShellHookBackend(std::string script)
|
|
: m_ThreadPool(llarp_init_threadpool(1, script.c_str()))
|
|
, m_ScriptFile(std::move(script))
|
|
{
|
|
}
|
|
|
|
~ExecShellHookBackend()
|
|
{
|
|
llarp_threadpool_stop(m_ThreadPool);
|
|
llarp_free_threadpool(&m_ThreadPool);
|
|
}
|
|
|
|
bool
|
|
Start() override
|
|
{
|
|
llarp_threadpool_start(m_ThreadPool);
|
|
return true;
|
|
}
|
|
|
|
bool
|
|
Stop() override
|
|
{
|
|
llarp_threadpool_stop(m_ThreadPool);
|
|
return true;
|
|
}
|
|
|
|
void
|
|
NotifyAsync(
|
|
std::unordered_map< std::string, std::string > params) override
|
|
{
|
|
ExecShellHookJob *job =
|
|
new ExecShellHookJob(m_ScriptFile, std::move(params));
|
|
llarp_threadpool_queue_job(m_ThreadPool,
|
|
{job, &ExecShellHookJob::Exec});
|
|
}
|
|
};
|
|
|
|
Backend_ptr
|
|
ExecShellBackend(std::string execFilePath)
|
|
{
|
|
Backend_ptr ptr = std::make_unique< ExecShellHookBackend >(execFilePath);
|
|
if(!ptr->Start())
|
|
return nullptr;
|
|
return ptr;
|
|
}
|
|
#endif
|
|
} // namespace hooks
|
|
} // namespace llarp
|