Support for luks API in ode-admin-cli 92/154092/10
authorKrzysztof Jackiewicz <k.jackiewicz@samsung.com>
Fri, 6 Oct 2017 12:16:27 +0000 (14:16 +0200)
committerKrzysztof Jackiewicz <k.jackiewicz@samsung.com>
Fri, 13 Oct 2017 15:52:26 +0000 (17:52 +0200)
Allows synchronous formatting, opening and closing of LUKS device. It also
allows waiting for completion notification in a separate process.

Change-Id: I28b4c543bc2a3135bd8cde53fbf6e13181684ffd

tools/cli/ode-admin-cli.cpp

index 4bce8ad..83b01cf 100644 (file)
 #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;
 
@@ -45,6 +47,9 @@ static inline int usage(const std::string name)
                          << "   -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
@@ -319,6 +324,154 @@ static inline int format_storage(const std::string name)
        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;
@@ -433,7 +586,7 @@ static inline int clean(const std::string name)
 
 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'},
@@ -442,18 +595,27 @@ int main(int argc, char* argv[])
                {"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);
@@ -470,6 +632,23 @@ int main(int argc, char* argv[])
                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;
@@ -482,6 +661,12 @@ int main(int argc, char* argv[])
                case 'c':
                        ret = clean(optarg);
                        break;
+               case 'D':
+                       device = optarg;
+                       break;
+               case 'M':
+                       mapping = optarg;
+                       break;
                case 'h':
                default:
                        ret = usage(argv[0]);