Added security-manager-cmd application. 39/29739/14
authorSebastian Grabowski <s.grabowski@samsung.com>
Mon, 27 Oct 2014 13:22:02 +0000 (14:22 +0100)
committerSebastian Grabowski <s.grabowski@samsung.com>
Tue, 2 Dec 2014 07:06:56 +0000 (08:06 +0100)
The purpose of this application is to have an offline tool that will do
some commands in offline mode i.e.: when security-manager service cannot
be run.
For now, only install command is supported which should be the
equivalent of security_manager_app_install function.

Change-Id: Ia9ef60b1a335650fea90c02e5fdd76ac48030f84
Signed-off-by: Sebastian Grabowski <s.grabowski@samsung.com>
packaging/security-manager.spec
src/CMakeLists.txt
src/cmd/CMakeLists.txt [new file with mode: 0644]
src/cmd/security-manager-cmd.cpp [new file with mode: 0644]

index 2a3c653..cd68faa 100644 (file)
@@ -119,6 +119,7 @@ fi
 %manifest security-manager.manifest
 %defattr(-,root,root,-)
 %attr(755,root,root) %{_bindir}/security-manager
+%attr(755,root,root) %{_bindir}/security-manager-cmd
 %{_libdir}/libsecurity-manager-commons.so.*
 %attr(-,root,root) %{_unitdir}/multi-user.target.wants/security-manager.service
 %attr(-,root,root) %{_unitdir}/security-manager.service
index 01f2aa5..30d65cb 100644 (file)
@@ -3,13 +3,16 @@ SET(COMMON_PATH  ${PROJECT_SOURCE_DIR}/src/common)
 SET(CLIENT_PATH  ${PROJECT_SOURCE_DIR}/src/client)
 SET(SERVER_PATH  ${PROJECT_SOURCE_DIR}/src/server)
 SET(DPL_PATH     ${PROJECT_SOURCE_DIR}/src/dpl)
+SET(CMD_PATH     ${PROJECT_SOURCE_DIR}/src/cmd)
 
 SET(TARGET_SERVER "security-manager")
 SET(TARGET_CLIENT "security-manager-client")
 SET(TARGET_COMMON "security-manager-commons")
 SET(TARGET_DB ".security-manager.db")
+SET(TARGET_CMD "security-manager-cmd")
 
 ADD_SUBDIRECTORY(include)
 ADD_SUBDIRECTORY(common)
 ADD_SUBDIRECTORY(client)
 ADD_SUBDIRECTORY(server)
+ADD_SUBDIRECTORY(cmd)
diff --git a/src/cmd/CMakeLists.txt b/src/cmd/CMakeLists.txt
new file mode 100644 (file)
index 0000000..d588676
--- /dev/null
@@ -0,0 +1,30 @@
+FIND_PACKAGE(Boost REQUIRED COMPONENTS program_options)
+
+INCLUDE_DIRECTORIES(SYSTEM
+    ${Boost_INCLUDE_DIRS}
+    )
+
+INCLUDE_DIRECTORIES(
+    ${INCLUDE_PATH}
+    ${COMMON_PATH}/include
+    ${DPL_PATH}/core/include
+    ${DPL_PATH}/log/include
+    )
+
+SET(CMD_SOURCES
+    ${CMD_PATH}/security-manager-cmd.cpp
+    )
+
+ADD_EXECUTABLE(${TARGET_CMD} ${CMD_SOURCES})
+
+SET_TARGET_PROPERTIES(${TARGET_CMD}
+    PROPERTIES
+        COMPILE_FLAGS "-D_GNU_SOURCE -fvisibility=hidden")
+
+TARGET_LINK_LIBRARIES(${TARGET_CMD}
+    ${TARGET_COMMON}
+    ${TARGET_CLIENT}
+    ${Boost_LIBRARIES}
+    )
+
+INSTALL(TARGETS ${TARGET_CMD} DESTINATION ${BIN_INSTALL_DIR})
diff --git a/src/cmd/security-manager-cmd.cpp b/src/cmd/security-manager-cmd.cpp
new file mode 100644 (file)
index 0000000..ec7b680
--- /dev/null
@@ -0,0 +1,304 @@
+/*
+ *  Copyright (c) 2000 - 2014 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ *  Contact: Rafal Krypa <r.krypa@samsung.com>
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License
+ */
+/*
+ * @file        service-manager-cmd.cpp
+ * @author      Sebastian Grabowski (s.grabowski@samsung.com)
+ * @version     1.0
+ * @brief       Implementation of security-manager-cmd tool for offline mode
+ */
+/* vim: set ts=4 et sw=4 tw=78 : */
+
+#include <iostream>
+#include <utility>
+#include <vector>
+#include <map>
+
+#include <dpl/log/log.h>
+#include <dpl/singleton.h>
+#include <dpl/singleton_safe_impl.h>
+#include <dpl/exception.h>
+#include <protocols.h>
+#include <security-manager.h>
+
+#include <boost/program_options.hpp>
+namespace po = boost::program_options;
+
+IMPLEMENT_SAFE_SINGLETON(SecurityManager::Log::LogSystem);
+
+static std::map <std::string, enum app_install_path_type> app_install_path_type_map = {
+    {"private", SECURITY_MANAGER_PATH_PRIVATE},
+    {"public", SECURITY_MANAGER_PATH_PUBLIC},
+    {"public_ro", SECURITY_MANAGER_PATH_PUBLIC_RO}
+};
+
+static po::options_description getGenericOptions()
+{
+    po::options_description opts("Generic options");
+    opts.add_options()
+         ("help,h", "produce help message")
+         ("install,i", "install an application")
+         ;
+    return opts;
+}
+
+static po::options_description getInstallOptions()
+{
+    po::options_description opts("Install options");
+    opts.add_options()
+         ("app,a", po::value<std::string>()->required(),
+          "application name (required)")
+         ("pkg,g", po::value<std::string>()->required(),
+          "package name for the application (required)")
+         /*
+          * multitoken: Specifies that the value can span multiple tokens.
+          *             So it is possible to pass values to an option like
+          *             this:
+          *             --path=/home/user dirtype
+          *             --path /home/user dirtype
+          *             --path="/home/user" dirtype
+          */
+         ("path,p", po::value< std::vector<std::string> >()->multitoken(),
+          "path for setting smack labels (may occur more than once).\n"
+          "Format: --path <path> <path type>\n"
+          "  where <path type> is: \tprivate, public, public_ro\n"
+          "example:\n"
+          "        \t--path=/home/user/app private")
+         ("privilege,s", po::value< std::vector<std::string> >(),
+          "privilege for the application (may occur more than once)")
+         ("uid,u", po::value<uid_t>()->required(),
+          "user identifier number (required)")
+         ;
+    return opts;
+}
+
+static po::options_description getAllOptions()
+{
+    po::options_description opts("Allowed options");
+    opts.add(getGenericOptions()).add(getInstallOptions());
+    return opts;
+}
+
+static void usage(std::string name)
+{
+    using namespace std;
+
+    cout << endl << name << " usage:" << endl;
+    cout << endl << getAllOptions() << endl << endl;
+}
+
+static bool parseCommandOptions(int argc, char *argv[], std::string cmd,
+                                po::options_description opts,
+                                po::variables_map &vm)
+{
+    bool ret = false;
+
+    try {
+        const po::positional_options_description p;
+        /* style options:
+         * unix_style: The more-or-less traditional unix style. It looks as
+         *     follows: unix_style = (allow_short | short_allow_adjacent |
+         *                            short_allow_next | allow_long |
+         *                            long_allow_adjacent | long_allow_next |
+         *                            allow_sticky | allow_guessing |
+         *                            allow_dash_for_short)
+         * allow_long_disguise: Allow long options with single option starting
+         *     character, e.g -foo=10
+         * allow_guessing: Allow abbreviated spellings for long options, if
+         *     they unambiguously identify long option. No long
+         *     option name should be prefix of other long option name if
+         *     guessing is in effect.
+         * allow_short: Alow "-<single character" style.
+         * short_allow_adjacent: Allow option parameter in the same token for
+         *     short options.
+         * short_allow_next: Allow option parameter in the next token for
+         *     short options.
+         * allow_long: Allow "--long_name" style.
+         * long_allow_adjacent: Allow option parameter in the same token for
+         *     long option, like in --foo=10
+         * long_allow_next: Allow option parameter in the next token for long
+         *     options.
+         * allow_sticky: Allow to merge several short options together, so
+         *     that "-s -k" become "-sk". All of the options but
+         *     last should accept no parameter. For example, if "-s" accept a
+         *     parameter, then "k" will be taken as
+         *     parameter, not another short option. Dos-style short options
+         *     cannot be sticky.
+         * allow_dash_for_short: Allow "-" in short options.
+         */
+        po::store(po::command_line_parser(argc, argv).
+                      options(getGenericOptions().add(opts)).positional(p).
+                      style((po::command_line_style::unix_style |
+                            po::command_line_style::allow_long_disguise) &
+                            ~po::command_line_style::allow_guessing).
+                      run(),
+                  vm);
+        po::notify(vm);
+        ret = true;
+    } catch (const po::error &e) {
+        std::cout << "Error parsing " << cmd << " command arguments: " <<
+                  e.what() << std::endl;
+        LogError("Error parsing " << cmd << " command arguments: " << e.what());
+    } catch (const std::exception &e) {
+        std::cout << "Unknown error while parsing " << cmd <<
+                  " command arguments: " << e.what() << std::endl;
+        LogError("Unknown error while parsing " << cmd <<
+                 " command arguments: " << e.what());
+    }
+
+    return ret;
+}
+
+static bool loadPaths(const std::vector<std::string> &paths,
+                      struct app_inst_req &req)
+{
+    if (paths.size() & 1) {
+        std::cout << "Wrong number of tokens was given for path option." <<
+                     std::endl;
+        LogDebug("Wrong paths size: " << paths.size());
+        return false;
+    }
+    req.appPaths.clear();
+    for (std::vector<std::string>::size_type i = 1; i < paths.size(); i += 2) {
+        app_install_path_type pathType;
+        LogDebug("path: " << paths[i - 1]);
+        try {
+            pathType = app_install_path_type_map.at(paths[i]);
+        } catch (const std::out_of_range &e) {
+            std::cout << "Invalid path type found." << std::endl;
+            LogError("Invalid path type found.");
+            req.appPaths.clear();
+            return false;
+        }
+        LogDebug("path type: " << pathType << " (" << paths[i] << ")");
+        req.appPaths.push_back(std::make_pair(paths[i - 1], pathType));
+    }
+    return (!req.appPaths.empty());
+}
+
+static bool parseInstallOptions(int argc, char *argv[],
+                                struct app_inst_req &req,
+                                po::variables_map &vm)
+{
+    bool ret;
+    ret = parseCommandOptions(argc, argv, "install", getInstallOptions(), vm);
+    if (!ret)
+        return ret;
+    try {
+        if (vm.count("app"))
+            req.appId = vm["app"].as<std::string>();
+        if (vm.count("pkg"))
+            req.pkgId = vm["pkg"].as<std::string>();
+        if (vm.count("path")) {
+            const std::vector<std::string> paths =
+                vm["path"].as<std::vector<std::string> >();
+            if (!loadPaths(paths, req)) {
+                std::cout << "Error in parsing path arguments." << std::endl;
+                LogError("Error in parsing path arguments.");
+                return false;
+            }
+        }
+        if (vm.count("privilege")) {
+            req.privileges = vm["privilege"].as<std::vector<std::string> >();
+            if (req.privileges.empty()) {
+                std::cout << "Error in parsing privilege arguments." << std::endl;
+                LogError("Error in parsing privilege arguments.");
+                return false;
+            }
+#ifdef BUILD_TYPE_DEBUG
+            LogDebug("Passed privileges:");
+            for (const auto &p : req.privileges) {
+                LogDebug("    " << p);
+            }
+#endif
+        }
+        if (vm.count("uid"))
+            req.uid = vm["uid"].as<uid_t>();
+    } catch (const std::exception &e) {
+        std::cout << "Error while parsing install arguments: " << e.what() <<
+                  std::endl;
+        LogError("Error while parsing install arguments: " << e.what());
+        ret = false;
+    }
+    return ret;
+}
+
+static int installApp(const struct app_inst_req &req)
+{
+    int ret = EXIT_FAILURE;
+
+    ret = security_manager_app_install(&req);
+    if (SECURITY_MANAGER_SUCCESS == ret) {
+        std::cout << "Application " << req.appId <<
+                  " installed successfully." << std::endl;
+        LogDebug("Application " << req.appId <<
+                 " installed successfully.");
+    } else {
+        std::cout << "Failed to install " << req.appId <<
+                  " application. Return code: " << ret <<
+                  std::endl;
+        LogDebug("Failed to install " << req.appId <<
+                 " application. Return code: " << ret);
+    }
+    return ret;
+}
+
+int main(int argc, char *argv[])
+{
+    po::variables_map vm;
+
+    UNHANDLED_EXCEPTION_HANDLER_BEGIN
+    {
+        SecurityManager::Singleton<SecurityManager::Log::LogSystem>::Instance().SetTag("SECURITY_MANAGER_INSTALLER");
+
+        LogDebug("argc: " << argc);
+        for (int i = 0; i < argc; ++i)
+            LogDebug("argv [" << i << "]: " << argv[i]);
+        if (argc < 2) {
+            std::cout << "Missing arguments." << std::endl;
+            usage(std::string(argv[0]));
+            return EXIT_FAILURE;
+        }
+        po::store(po::command_line_parser(argc, argv).
+                  options(getGenericOptions()).allow_unregistered().run(),
+                  vm);
+        if (vm.count("help")) {
+            usage(std::string(argv[0]));
+            return EXIT_SUCCESS;
+        }
+        LogDebug("Generic arguments has been parsed.");
+
+        if (vm.count("install")) {
+            struct app_inst_req *req = nullptr;
+            LogDebug("Install command.");
+            if (security_manager_app_inst_req_new(&req) != SECURITY_MANAGER_SUCCESS)
+                return EXIT_FAILURE;
+            if (parseInstallOptions(argc, argv, *req, vm))
+                return installApp(*req);
+            else
+                return EXIT_FAILURE;
+        } else {
+            std::cout << "No command argument was given." << std::endl;
+            usage(std::string(argv[0]));
+            return EXIT_FAILURE;
+        }
+    }
+    UNHANDLED_EXCEPTION_HANDLER_END
+
+    return EXIT_FAILURE;
+}
+