#include <string>
#include <vector>
#include <iostream>
+#include <condition_variable>
#include <ode/secure-erase.h>
#include <ode/internal-encryption.h>
#include <ode/external-encryption.h>
#include <ode/extension-encryption.h>
+#include <ode/luks.h>
extern char** environ;
<< " -e, --encrypt=internal|external encrypt" << std::endl
<< " -d, --decrypt=internal|external decrypt" << std::endl
<< " -f, --format=extension format and setup encryption" << std::endl
+ << " -l --luks=format|open|close|wait perform LUKS operation or wait for completion. May also require -D and/or -M option." << std::endl
+ << " -D --device=<device> device path required for LUKS format and LUKS open operations" << std::endl
+ << " -M --mapping=<mapping> mapping name required for LUKS open and LUKS close operations" << std::endl
<< " -p, --changepw=internal|external|extension change password" << std::endl
<< " -s, --state=internal|external|extension get state" << std::endl
<< " -w, --waitmnt=internal|external|extension wait for mount"<< std::endl
return ret;
}
+class LuksListener {
+public:
+ static void StaticCallback(ode_luks_operation_e op, int ret, void* user_data)
+ {
+ auto self = static_cast<LuksListener*>(user_data);
+ self->Callback(op, ret);
+ }
+
+ void Callback(ode_luks_operation_e op, int ret)
+ {
+ {
+ std::lock_guard<std::mutex> guard(mutex);
+ results.push_back({op, ret});
+ }
+ cond.notify_one();
+ }
+
+ int WaitForCallback()
+ {
+ return WaitForCallbackInternal([](ode_luks_operation_e) { return true; });
+ }
+
+ int WaitForCallback(ode_luks_operation_e expected)
+ {
+ return WaitForCallbackInternal([=](ode_luks_operation_e op) {
+ return expected == op;
+ });
+ }
+
+ ~LuksListener() {
+ ode_luks_unset_event_cb();
+ }
+
+private:
+ int WaitForCallbackInternal(const std::function<bool(ode_luks_operation_e)>& opCheck)
+ {
+ std::unique_lock<std::mutex> lock(mutex);
+ cond.wait(lock, [this]{
+ return !results.empty();
+ });
+
+ auto& res = results.front();
+ int ret = res.ret;
+
+ std::cout << "Luks callback received. Operation: " << static_cast<int>(res.op)
+ << " result: " << res.ret << std::endl;
+ if (!opCheck(res.op)) {
+ std::cerr << "Unexpected operation finished " << res.op << std::endl;
+ ret = -1;
+ }
+
+ results.erase(results.begin());
+ lock.unlock();
+
+ return ret;
+ }
+
+ std::condition_variable cond;
+ std::mutex mutex;
+
+ struct result {
+ ode_luks_operation_e op;
+ int ret;
+ };
+
+ std::vector<result> results;
+};
+
+static inline int luks(const std::string& name,
+ const std::string& device,
+ const std::string& mapping)
+{
+ int ret;
+
+ if (name == "format") {
+ if (device.empty())
+ return usage(name);
+
+ LuksListener listener;
+ ret = ode_luks_set_event_cb(&LuksListener::StaticCallback, &listener);
+ if (ret != ODE_ERROR_NONE) {
+ std::cerr << "Callback setting failed " << ret << std::endl;
+ return ret;
+ }
+
+ std::string password = getPassword();
+ ret = ode_luks_format(device.c_str(), password.c_str());
+ if (ret != ODE_ERROR_NONE) {
+ std::cerr << "ode_luks_format() failed " << ret << std::endl;
+ return ret;
+ }
+ return listener.WaitForCallback(ODE_LUKS_FORMAT);
+ }
+
+ if (name == "open") {
+ if (device.empty() || mapping.empty())
+ return usage(name);
+
+ LuksListener listener;
+ ret = ode_luks_set_event_cb(&LuksListener::StaticCallback, &listener);
+ if (ret != ODE_ERROR_NONE) {
+ std::cerr << "Callback setting failed " << ret << std::endl;
+ return ret;
+ }
+
+ std::string password = getPassword();
+ ret = ode_luks_open(device.c_str(), password.c_str(), mapping.c_str());
+ if (ret != ODE_ERROR_NONE) {
+ std::cerr << "ode_luks_open() failed " << ret << std::endl;
+ return ret;
+ }
+ return listener.WaitForCallback(ODE_LUKS_OPEN);
+ }
+
+ if (name == "close") {
+ if (mapping.empty())
+ return usage(name);
+
+ LuksListener listener;
+ ret = ode_luks_set_event_cb(&LuksListener::StaticCallback, &listener);
+ if (ret != ODE_ERROR_NONE) {
+ std::cerr << "Callback setting failed " << ret << std::endl;
+ return ret;
+ }
+
+ ret = ode_luks_close(mapping.c_str());
+ if (ret != ODE_ERROR_NONE) {
+ std::cerr << "ode_luks_open() failed " << ret << std::endl;
+ return ret;
+ }
+ return listener.WaitForCallback(ODE_LUKS_CLOSE);
+ }
+
+ if (name == "wait") {
+ LuksListener listener;
+ ret = ode_luks_set_event_cb(&LuksListener::StaticCallback, &listener);
+ if (ret != ODE_ERROR_NONE) {
+ std::cerr << "Callback setting failed " << ret << std::endl;
+ return ret;
+ }
+
+ return listener.WaitForCallback();
+ }
+
+ std::cerr << "Wrong arguments (format|open|close|wait)" << std::endl;
+ return -1;
+}
+
static inline int change_password(const std::string name)
{
int ret;
int main(int argc, char* argv[])
{
- int opt = 0, index, ret = 0;
+ int opt = 0, luks_opt = 0, index, ret = 0;
struct option options[] = {
{"help", no_argument, 0, 'h'},
{"encrypt", required_argument, 0, 'e'},
{"decrypt", required_argument, 0, 'd'},
{"format", required_argument, 0, 'f'},
+ {"luks" , required_argument, 0, 'l'},
{"state", required_argument, 0, 's'},
{"waitmnt", required_argument, 0, 'w'},
{"clean", required_argument, 0, 'c'},
{0, 0, 0, 0}
};
+ struct option luks_options[] = {
+ {"device", required_argument, 0, 'D'},
+ {"mapping", required_argument, 0, 'M'},
+ {0, 0, 0, 0}
+ };
+
if (argc <= 1) {
usage(argv[0]);
return EXIT_SUCCESS;
}
- while ((opt = getopt_long(argc, argv, "m:u:e:d:f:p:s:w:c:h", options, &index)) != -1) {
+ std::string mapping, device, op;
+
+ while ((opt = getopt_long(argc, argv, "m:u:e:d:f:l:p:s:w:c:h", options, &index)) != -1) {
switch (opt) {
case 'm':
ret = mount(optarg);
case 'f':
ret = format_storage(optarg);
break;
+ case 'l':
+ op = optarg;
+ while ((luks_opt = getopt_long(argc, argv, "D:M:", luks_options, &index)) != -1) {
+ switch (luks_opt) {
+ case 'D':
+ device = optarg;
+ break;
+ case 'M':
+ mapping = optarg;
+ break;
+ default:
+ ret = usage(argv[0]);
+ }
+ }
+ if (ret == 0)
+ ret = luks(op, device, mapping);
+ break;
case 'p':
ret = change_password(optarg);
break;
case 'c':
ret = clean(optarg);
break;
+ case 'D':
+ device = optarg;
+ break;
+ case 'M':
+ mapping = optarg;
+ break;
case 'h':
default:
ret = usage(argv[0]);