Add create/remove Zone function 59/64459/18
authorSungbae Yoo <sungbae.yoo@samsung.com>
Fri, 1 Apr 2016 08:46:28 +0000 (17:46 +0900)
committerSungbae Yoo <sungbae.yoo@samsung.com>
Thu, 7 Apr 2016 12:20:05 +0000 (21:20 +0900)
Change-Id: If1bc542e089fd3ccefaa14512bc3997f3e3e48cd
Signed-off-by: Sungbae Yoo <sungbae.yoo@samsung.com>
server/zone.cpp
tools/zone-setup-wizard/src/main.c
tools/zone-setup-wizard/src/util.c

index 32e54a0..d914e71 100644 (file)
@@ -13,6 +13,7 @@
  *  See the License for the specific language governing permissions and
  *  limitations under the License
  */
+#include <iostream>
 
 #include <aul.h>
 #include <bundle.h>
@@ -21,6 +22,7 @@
 #include <gio/gio.h>
 #include <sys/stat.h>
 #include <sys/types.h>
+#include <sys/inotify.h>
 
 #include "zone.hxx"
 
@@ -38,6 +40,7 @@
 #define ZONE_GROUP         "zones"
 
 #define ZONE_MANIFEST_DIR   CONF_PATH "/zone/"
+#define ZONE_PROVISION_DIR  "/tmp/zone/provision/"
 
 #define FREEDESKTOP_LOGIN_INTERFACE \
     "org.freedesktop.login1",   \
@@ -46,6 +49,7 @@
 
 #define HOME_SMACKLABEL     "User::Home"
 #define SHARED_SMACKLABEL   "User::App::Shared"
+#define APP_SMACKLABEL   "User::Pkg::"
 
 #define TEMPORARY_UMASK(mode)   \
         std::unique_ptr<mode_t, void(*)(mode_t *)> umask_##mode(new mode_t, \
@@ -69,7 +73,7 @@ static int setZoneState(uid_t id, int state)
 
     GVariant* var;
     var = g_dbus_connection_call_sync(connection, FREEDESKTOP_LOGIN_INTERFACE,
-                                      "SetLingerUser", param,
+                                      "SetUserLinger", param,
                                       NULL, G_DBUS_CALL_FLAGS_NONE, -1, NULL,
                                       &error);
     if (var == NULL) {
@@ -91,6 +95,15 @@ static int setZoneState(uid_t id, int state)
     return 0;
 }
 
+template <typename... Args>
+void execute(const std::string& path, Args&&... args)
+{
+    std::vector<std::string> argsVector = { args... };
+    runtime::Process proc(path, argsVector);
+    proc.execute();
+}
+
+
 
 Zone::Zone(PolicyControlContext& ctx)
     : context(ctx)
@@ -102,7 +115,6 @@ Zone::Zone(PolicyControlContext& ctx)
     manager.registerParametricMethod(this, (int)(Zone::lockZone)(std::string));
     manager.registerParametricMethod(this, (int)(Zone::unlockZone)(std::string));
     manager.registerNonparametricMethod(this, (std::vector<std::string>)(Zone::getZoneList)());
-
     manager.registerParametricMethod(this, (int)(Zone::getZoneState)(std::string));
 
     manager.createNotification("Zone::created");
@@ -115,12 +127,225 @@ Zone::~Zone()
 
 int Zone::createZone(const std::string& name, const std::string& setupWizAppid)
 {
-    return -1;
+    std::string provisionDirPath(ZONE_PROVISION_DIR + name);
+    rmi::Service& manager = context.getServiceManager();
+    runtime::File provisionDir(provisionDirPath);
+    int ret;
+
+    try {
+        provisionDir.remove(true);
+    } catch (runtime::Exception& e) {}
+
+    try {
+        //create a directory for zone setup
+        TEMPORARY_UMASK(0000);
+        provisionDir.makeDirectory(true);
+        runtime::Smack::setAccess(provisionDir, APP_SMACKLABEL + setupWizAppid);
+
+        //launch setup-wizard app
+        bundle *b = ::bundle_create();
+        ::bundle_add_str(b, "Name", name.c_str());
+        ::bundle_add_str(b, "ProvisionDir", provisionDirPath.c_str());
+
+        ret = ::aul_launch_app_for_uid(setupWizAppid.c_str(), b, manager.getPeerUid());
+        ::bundle_free(b);
+
+        if (ret < 0) {
+            throw runtime::Exception("Failed to launch application: " + std::to_string(ret));
+        }
+    } catch (runtime::Exception& e) {}
+
+    auto create = [&manager, name, setupWizAppid, provisionDirPath] {
+        std::unique_ptr<xml::Document> bundleXml;
+        xml::Node::NodeList nodes;
+        int ret;
+
+        try {
+            //attach a directory for inotify
+            int fd = inotify_init();
+            if (fd < 0) {
+                throw runtime::Exception("Failed to initialize inotify");
+            }
+
+            std::string createfile;
+            char inotifyBuf[sizeof (struct inotify_event) + PATH_MAX + 1];
+            struct inotify_event *event = reinterpret_cast<struct inotify_event *>((void*)inotifyBuf);
+            int wd = inotify_add_watch(fd, provisionDirPath.c_str(), IN_CREATE);
+
+            while (createfile != ".completed") {
+                ret = read(fd, inotifyBuf, sizeof(inotifyBuf));
+                if (ret < 0) {
+                    throw runtime::Exception("Failed to get inotify");
+                }
+                createfile = event->name;
+            }
+
+            inotify_rm_watch(fd, wd);
+            close(fd);
+
+            //create zone user
+            runtime::User user = runtime::User::create
+                                (name, ZONE_GROUP, ZONE_UID_MIN, ZONE_UID_MAX);
+
+            //create zone home directories
+            const struct {
+                enum tzplatform_variable dir;
+                const char* smack;
+            } dirs[] = {
+                {TZ_USER_HOME, HOME_SMACKLABEL},
+                {TZ_USER_CACHE, SHARED_SMACKLABEL},
+                {TZ_USER_APPROOT, HOME_SMACKLABEL},
+                {TZ_USER_DB, HOME_SMACKLABEL},
+                {TZ_USER_PACKAGES, HOME_SMACKLABEL},
+                {TZ_USER_ICONS, HOME_SMACKLABEL},
+                {TZ_USER_CONFIG, SHARED_SMACKLABEL},
+                {TZ_USER_DATA, HOME_SMACKLABEL},
+                {TZ_USER_SHARE, SHARED_SMACKLABEL},
+                {TZ_USER_ETC, HOME_SMACKLABEL},
+                {TZ_USER_LIVE, HOME_SMACKLABEL},
+                {TZ_USER_UG, HOME_SMACKLABEL},
+                {TZ_USER_APP, HOME_SMACKLABEL},
+                {TZ_USER_CONTENT, SHARED_SMACKLABEL},
+                {TZ_USER_CAMERA, SHARED_SMACKLABEL},
+                {TZ_USER_VIDEOS, SHARED_SMACKLABEL},
+                {TZ_USER_IMAGES, SHARED_SMACKLABEL},
+                {TZ_USER_SOUNDS, SHARED_SMACKLABEL},
+                {TZ_USER_MUSIC, SHARED_SMACKLABEL},
+                {TZ_USER_GAMES, SHARED_SMACKLABEL},
+                {TZ_USER_DOCUMENTS, SHARED_SMACKLABEL},
+                {TZ_USER_OTHERS, SHARED_SMACKLABEL},
+                {TZ_USER_DOWNLOADS, SHARED_SMACKLABEL},
+                {TZ_SYS_HOME, NULL},
+            };
+
+            TEMPORARY_UMASK(0022);
+
+            ::tzplatform_set_user(user.getUid());
+            for (int i = 0; dirs[i].dir != TZ_SYS_HOME; i++) {
+                runtime::File dir(std::string(::tzplatform_getenv(dirs[i].dir)));
+                try {
+                    dir.makeDirectory();
+                } catch (runtime::Exception& e) {}
+                dir.chown(user.getUid(), user.getGid());
+                runtime::Smack::setAccess(dir, dirs[i].smack);
+                runtime::Smack::setTransmute(dir, true);
+            }
+            std::string homeDir = ::tzplatform_getenv(TZ_USER_HOME);
+            ::tzplatform_reset_user();
+
+            //create systemd user unit directory
+            runtime::File systemdUserUnit(homeDir + "/.config/systemd/user");
+            dir.makeDirectory();
+
+            //initialize package db
+            execute("/usr/bin/pkg_initdb",
+                    "pkg_initdb", std::to_string(user.getUid()));
+
+            //initialize security-manager
+            execute("/usr/bin/security-manager-cmd",
+                    "security-manager-cmd", "--manage-users=add",
+                    "--uid=" + std::to_string(user.getUid()),
+                    "--usertype=normal");
+
+            //read manifest xml file
+            bundleXml = std::unique_ptr<xml::Document>(xml::Parser::parseFile(provisionDirPath + "/manifest.xml"));
+
+            //execute hooks of creation
+            std::vector<std::string> args;
+            args.push_back("");
+            args.push_back(name);
+            args.push_back(std::to_string(user.getUid()));
+            args.push_back(std::to_string(user.getGid()));
+
+            nodes = bundleXml->evaluate("//bundle-manifest/hooks/create");
+            for (xml::Node::NodeList::iterator it = nodes.begin();
+                    it != nodes.end(); it++) {
+                std::string path = it->getChildren().begin()->getContent();
+                args[0] = path;
+                runtime::Process exec(path, args);
+                exec.execute();
+            }
+
+            //TODO: write container owner info
+
+            //write manifest file
+            bundleXml->write(ZONE_MANIFEST_DIR + name + ".xml", "UTF-8", true);
+
+            //unlock the user
+            setZoneState(user.getUid(), 1);
+        } catch (runtime::Exception& e) {
+            ERROR(e.what());
+        }
+
+        manager.notify("Zone::created", name, std::string());
+    };
+
+    std::thread asyncWork(create);
+    asyncWork.detach();
+
+    return 0;
 }
 
 int Zone::removeZone(const std::string& name)
 {
-    return -1;
+    rmi::Service& manager = context.getServiceManager();
+    int ret;
+
+    //lock the user
+    ret = lockZone(name);
+    if (ret != 0) {
+        return -1;
+    }
+
+    auto remove = [&manager, name] {
+        runtime::File bundle(ZONE_MANIFEST_DIR + name + ".xml");
+        std::unique_ptr<xml::Document> bundleXml;
+        xml::Node::NodeList nodes;
+
+        try {
+            runtime::User user(name);
+
+            //remove notification for ckm-tool
+            execute("/usr/bin/ckm_tool",
+                    "ckm_tool", "-d", std::to_string(user.getUid()));
+            //initialize security-manager
+            execute("/usr/bin/security-manager-cmd",
+                    "security-manager-cmd",
+                    "--manage-users=remove",
+                    "--uid=" + std::to_string(user.getUid()));
+
+            //execute hooks of destroy
+            std::vector<std::string> args;
+            args.push_back("");
+            args.push_back(name);
+            args.push_back(std::to_string(user.getUid()));
+            args.push_back(std::to_string(user.getGid()));
+
+            bundleXml = std::unique_ptr<xml::Document>(xml::Parser::parseFile(bundle.getPath()));
+            nodes = bundleXml->evaluate("//bundle-manifest/hooks/destroy");
+            for (xml::Node::NodeList::iterator it = nodes.begin();
+                    it != nodes.end(); it++) {
+                std::string path = it->getChildren().begin()->getContent();
+                args[0] = path;
+                runtime::Process exec(path, args);
+                exec.execute();
+            }
+
+            //remove zone user
+            user.remove();
+
+            bundle.remove();
+        } catch (runtime::Exception& e) {
+            ERROR(e.what());
+            return;
+        }
+        manager.notify("Zone::removed", name, std::string());
+    };
+
+    std::thread asyncWork(remove);
+    asyncWork.detach();
+
+    return 0;
 }
 
 int Zone::lockZone(const std::string& name)
index 6db75d1..a2b43d3 100644 (file)
@@ -55,7 +55,7 @@ static void __app_control(app_control_h app_control, void *data)
        appdata_s *ad = (appdata_s *) data;
        int ret = 0;
 
-       ret = app_control_get_extra_data(app_control, "Zone", &ad->zone_name);
+       ret = app_control_get_extra_data(app_control, "Name", &ad->zone_name);
        if (ret != APP_CONTROL_ERROR_NONE) {
                dlog_print(DLOG_ERROR, LOG_TAG, "failed to get zone name");
                ui_app_exit();
index d83d13e..e523dde 100644 (file)
@@ -20,7 +20,7 @@
 
 #define TARGET_ZONE "ZoneName"
 #define PROVISION_DATA "/manifest.xml"
-#define PROVISION_COMPLETE "/.complete"
+#define PROVISION_COMPLETE "/.completed"
 
 static char *__get_zone_metadata(void)
 {
@@ -139,7 +139,7 @@ int _send_zone_provision_data(const char *zone_name, const char *target_path)
        snprintf(data_path, strlen(target_path)+strlen(PROVISION_COMPLETE)+1, "%s%s", target_path, PROVISION_COMPLETE);
        fp = fopen(data_path, "w");
        if (fp == NULL) {
-               dlog_print(DLOG_ERROR, LOG_TAG, "failed to touch complete file");
+               dlog_print(DLOG_ERROR, LOG_TAG, "failed to touch completed file");
                return -1;
        }