From acacc54ffe45001b1745586ec24744e22f52694d Mon Sep 17 00:00:00 2001 From: Sungbae Yoo Date: Fri, 1 Apr 2016 17:46:28 +0900 Subject: [PATCH] Add create/remove Zone function Change-Id: If1bc542e089fd3ccefaa14512bc3997f3e3e48cd Signed-off-by: Sungbae Yoo --- server/zone.cpp | 233 ++++++++++++++++++++++++++++++++++++- tools/zone-setup-wizard/src/main.c | 2 +- tools/zone-setup-wizard/src/util.c | 4 +- 3 files changed, 232 insertions(+), 7 deletions(-) diff --git a/server/zone.cpp b/server/zone.cpp index 32e54a0..d914e71 100644 --- a/server/zone.cpp +++ b/server/zone.cpp @@ -13,6 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License */ +#include #include #include @@ -21,6 +22,7 @@ #include #include #include +#include #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 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 +void execute(const std::string& path, Args&&... args) +{ + std::vector 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)(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 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((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::Parser::parseFile(provisionDirPath + "/manifest.xml")); + + //execute hooks of creation + std::vector 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 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 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::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) diff --git a/tools/zone-setup-wizard/src/main.c b/tools/zone-setup-wizard/src/main.c index 6db75d1..a2b43d3 100644 --- a/tools/zone-setup-wizard/src/main.c +++ b/tools/zone-setup-wizard/src/main.c @@ -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(); diff --git a/tools/zone-setup-wizard/src/util.c b/tools/zone-setup-wizard/src/util.c index d83d13e..e523dde 100644 --- a/tools/zone-setup-wizard/src/util.c +++ b/tools/zone-setup-wizard/src/util.c @@ -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; } -- 2.7.4