c96e87770e8fded3d2dcba21ae7faadb3b4f3643
[platform/core/security/krate.git] / server / manager.cpp
1 /*
2  *  Copyright (c) 2015 Samsung Electronics Co., Ltd All Rights Reserved
3  *
4  *  Licensed under the Apache License, Version 2.0 (the "License");
5  *  you may not use this file except in compliance with the License.
6  *  You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  *  Unless required by applicable law or agreed to in writing, software
11  *  distributed under the License is distributed on an "AS IS" BASIS,
12  *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  *  See the License for the specific language governing permissions and
14  *  limitations under the License
15  */
16
17 #include <sys/stat.h>
18 #include <sys/types.h>
19 #include <sys/mount.h>
20
21 #include <algorithm>
22
23 #include <notification.h>
24 #include <notification_internal.h>
25 #include <tzplatform_config.h>
26 #include <auth-passwd-admin.h>
27 #include <gum/gum-user.h>
28 #include <gum/gum-user-service.h>
29 #include <gum/common/gum-user-types.h>
30 #include <klay/error.h>
31 #include <klay/process.h>
32 #include <klay/filesystem.h>
33 #include <klay/auth/user.h>
34 #include <klay/xml/parser.h>
35 #include <klay/xml/document.h>
36 #include <klay/dbus/connection.h>
37 #include <klay/audit/logger.h>
38
39 #include "packman.h"
40 #include "launchpad.h"
41
42 #include "rmi/manager.h"
43
44 #define KRATE_DELEGATOR_APP  "org.tizen.keyguard"
45 #define NOTIFICATION_SUB_ICON_PATH  ICON_PATH "/notification_sub_icon.png"
46
47 namespace Krate {
48
49 namespace {
50
51 const std::vector<std::string> defaultGroups = {
52         "audio",
53         "video",
54         "display",
55         "log"
56 };
57
58 const std::vector<std::string> unitsToMask = {
59         "starter.service",
60         "scim.service"
61 };
62
63 const std::string KRATE_SKEL_PATH = "/etc/skel";
64 const std::string KRATE_CREATE_HOOK_PATH = "/etc/gumd/useradd.d";
65 const std::string KRATE_REMOVE_HOOK_PATH = "/etc/gumd/userdel.d";
66
67 std::string KRATE_DEFAULT_OWNER = "owner";
68
69 std::list<std::string> createdKrateList;
70 static std::atomic<bool> isKrateForeground(false);
71
72 std::unordered_map<int, notification_h> notiHandleMap;
73
74 inline void maskUserServices(const runtime::User& user)
75 {
76         ::tzplatform_set_user(user.getUid());
77         std::string pivot(::tzplatform_getenv(TZ_USER_HOME));
78         ::tzplatform_reset_user();
79
80         runtime::File unitbase(pivot + "/.config/systemd/user");
81         unitbase.makeDirectory(true);
82         unitbase.chmod(S_IRUSR | S_IWUSR | S_IXUSR | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH);
83
84         for (const std::string& unit : unitsToMask) {
85                 std::string target = unitbase.getPath() + "/" + unit;
86                 if (::symlink("/dev/null", target.c_str()) == -1) {
87                         throw runtime::Exception(runtime::GetSystemErrorMessage());
88                 }
89         }
90 }
91
92 inline void setKrateState(uid_t id, int state)
93 {
94         dbus::Connection& systemDBus = dbus::Connection::getSystem();
95         systemDBus.methodcall("org.freedesktop.login1",
96                                                   "/org/freedesktop/login1",
97                                                   "org.freedesktop.login1.Manager",
98                                                   "SetUserLinger",
99                                                   -1, "", "(ubb)", id, state, 1);
100 }
101
102 inline const std::string convertPathForOwner(const std::string& path, const runtime::User& user, const runtime::User& owner)
103 {
104         ::tzplatform_set_user(owner.getUid());
105         std::string ownerHome(::tzplatform_getenv(TZ_USER_HOME));
106         ::tzplatform_reset_user();
107         ownerHome += "/.krate";
108
109         ::tzplatform_set_user(user.getUid());
110         std::string userHome(::tzplatform_getenv(TZ_USER_HOME));
111         ::tzplatform_reset_user();
112
113         std::string userHomeForOwner(ownerHome + "/" + user.getName());
114
115         std::string convertedPath(path);
116
117         if (convertedPath.compare(0, userHome.size(), userHome) == 0) {
118                 convertedPath.replace(0, userHome.size(), userHomeForOwner);
119         }
120
121         return convertedPath;
122 }
123
124 inline void prepareFileForOwner(const std::string path, const runtime::User& pkgUser, const runtime::User& owner)
125 {
126         std::string pathLink = convertPathForOwner(path, pkgUser, owner);
127
128         if (path != pathLink) {
129                 runtime::File linkFile(pathLink);
130                 linkFile.makeBaseDirectory(pkgUser.getUid(), pkgUser.getGid());
131                 if (linkFile.exists()) {
132                         linkFile.remove();
133                 }
134
135                 int ret = ::link(path.c_str(), pathLink.c_str());
136                 if (ret != 0) {
137                         //TODO: copy the icon instead of linking
138                         throw runtime::Exception("Failed to link from " + path +
139                                                                          " to " + pathLink);
140                 }
141         }
142 }
143
144 int packageEventHandler(uid_t target_uid, int req_id,
145                                                 const char *pkg_type, const char *pkgid,
146                                                 const char *key, const char *val,
147                                                 const void *pmsg, void *data)
148 {
149         static std::string type;
150         std::string keystr = key;
151
152         if (target_uid == tzplatform_getuid(TZ_SYS_GLOBALAPP_USER)) {
153                 return 0;
154         }
155
156         std::transform(keystr.begin(), keystr.end(), keystr.begin(), ::tolower);
157         if (keystr == "start") {
158                 type = val;
159                 std::transform(type.begin(), type.end(), type.begin(), ::tolower);
160                 return 0;
161         } else if (keystr != "end" && keystr != "ok") {
162                 return 0;
163         }
164
165         try {
166                 runtime::User owner(KRATE_DEFAULT_OWNER), pkgUser(target_uid);
167
168                 if (type == "install" || type == "update") {
169                         PackageInfo pkg(pkgid, pkgUser.getUid());
170                         std::string icon = pkg.getIcon();
171                         prepareFileForOwner(icon, pkgUser, owner);
172
173                         for (const ApplicationInfo& app : pkg.getAppList()) {
174                                 std::string icon = app.getIcon();
175                                 prepareFileForOwner(icon, pkgUser, owner);
176                         }
177                 } else {
178                         ::tzplatform_set_user(pkgUser.getUid());
179                         std::string pkgPath(::tzplatform_getenv(TZ_USER_APP));
180                         pkgPath = pkgPath + "/" + pkgid;
181                         ::tzplatform_reset_user();
182
183                         runtime::File pkgDirForOwner(convertPathForOwner(pkgPath, pkgUser, owner));
184                         pkgDirForOwner.remove(true);
185                 }
186         } catch (runtime::Exception &e) {
187                 ERROR(e.what());
188         }
189
190         return 0;
191 }
192
193 void initializeCreatedKrateList()
194 {
195         const gchar *type[] = {"security", NULL};
196         gchar *username;
197         GumUserService *service;
198         GumUserList *users;
199         GumUser *user;
200
201         service = gum_user_service_create_sync(FALSE);
202         if (!service) {
203                 return;
204         }
205
206         users = gum_user_service_get_user_list_sync(service, type);
207         if (!users) {
208                 return;
209         }
210
211         for (GumUserList *src_list = users; src_list != NULL; src_list = g_list_next(src_list)) {
212                 user = (GumUser*) src_list->data;
213                 if (user) {
214                         g_object_get(G_OBJECT(user), "username", &username, NULL);
215                         createdKrateList.push_back(username);
216                         g_free(username);
217                 }
218         }
219
220         gum_user_service_list_free(users);
221         g_object_unref(service);
222 }
223
224 #define NT_TITLE     NOTIFICATION_TEXT_TYPE_TITLE
225 #define NT_CONTENT   NOTIFICATION_TEXT_TYPE_CONTENT
226 #define NT_ICON      NOTIFICATION_IMAGE_TYPE_ICON
227 #define NT_INDICATOR NOTIFICATION_IMAGE_TYPE_ICON_FOR_INDICATOR
228 #define NT_NONE      NOTIFICATION_VARIABLE_TYPE_NONE
229 #define NT_EVENT     NOTIFICATION_LY_ONGOING_PROGRESS
230 #define NT_APP       NOTIFICATION_DISPLAY_APP_INDICATOR
231
232 #define NT_ICON_PATH ICON_PATH "/indicator_icon.png"
233 #define NT_TEXT      "Container Mode"
234 #define NT_APPINFO   "Krate Application"
235
236 #define NT_ERROR_NONE   NOTIFICATION_ERROR_NONE
237
238 void krateProcessCallback(GDBusConnection *connection,
239                                                  const gchar *sender, const gchar *objectPath,
240                                                  const gchar *interface, const gchar *signalName,
241                                                  GVariant *params, gpointer userData)
242 {
243         static runtime::User owner(KRATE_DEFAULT_OWNER);
244         int pid, status;
245
246         notification_h noti = reinterpret_cast<notification_h>(userData);
247
248         g_variant_get(params, "(ii)", &status, &pid);
249
250         if (status != 5) {
251                 return;
252         }
253
254         struct stat st;
255         std::string proc("/proc/" + std::to_string(pid));
256         if (::stat(proc.c_str(), &st) != 0) {
257                 return;
258         }
259
260         if (st.st_uid == owner.getUid() || st.st_uid == 0) {
261                 if (isKrateForeground) {
262                         notification_delete_for_uid(noti, owner.getUid());
263                         isKrateForeground = false;
264                 }
265         } else {
266                 if (!isKrateForeground) {
267                         notification_set_text(noti, NT_CONTENT, NT_APPINFO, NULL, NT_NONE);
268                         notification_post_for_uid(noti, owner.getUid());
269                         isKrateForeground = true;
270                 }
271         }
272 }
273
274 notification_h createNotification()
275 {
276         notification_h noti = notification_create(NOTIFICATION_TYPE_ONGOING);
277         if (noti == NULL) {
278                 return NULL;
279         }
280
281         if (notification_set_text(noti, NT_TITLE, NT_TEXT, NULL, NT_NONE) != NT_ERROR_NONE) {
282                 notification_free(noti);
283                 return NULL;
284         }
285         if (notification_set_image(noti, NT_ICON, NT_ICON_PATH) != NT_ERROR_NONE) {
286                 notification_free(noti);
287                 return NULL;
288         }
289
290         if (notification_set_image(noti, NT_INDICATOR, NT_ICON_PATH) != NT_ERROR_NONE) {
291                 notification_free(noti);
292                 return NULL;
293         }
294
295         if (notification_set_layout(noti, NT_EVENT) != NT_ERROR_NONE) {
296                 notification_free(noti);
297                 return NULL;
298         }
299
300         if (notification_set_display_applist(noti, NT_APP) != NT_ERROR_NONE) {
301                 notification_free(noti);
302                 return NULL;
303         }
304
305         return noti;
306 }
307
308 void krateProcessMonitor()
309 {
310         GError *error = NULL;
311         GDBusConnection* connection;
312         connection = g_bus_get_sync(G_BUS_TYPE_SYSTEM, NULL, &error);
313         if (connection == NULL) {
314                 ERROR("GBus Connection failed");
315                 g_error_free(error);
316                 return;
317         }
318
319         notification_h noti = createNotification();
320         if (noti == NULL) {
321                 ERROR("Failed to created notification");
322                 return;
323         }
324
325         g_dbus_connection_signal_subscribe(connection,
326                                                                                 NULL,
327                                                                                 "org.tizen.resourced.process",
328                                                                                 "ProcStatus",
329                                                                                 "/Org/Tizen/ResourceD/Process",
330                                                                                 NULL,
331                                                                                 G_DBUS_SIGNAL_FLAGS_NONE,
332                                                                                 krateProcessCallback,
333                                                                                 reinterpret_cast<gpointer>(noti),
334                                                                                 NULL);
335 }
336
337 void notiProxyInsert(const runtime::User& owner, const runtime::User& user, int privId, notification_h noti)
338 {
339         std::string krateLauncherUri;
340         notification_h newNoti;
341         app_control_h appControl;
342         char* pkgId;
343
344         notification_clone(noti, &newNoti);
345
346         notification_get_pkgname(noti, &pkgId);
347         PackageInfo pkg(pkgId, user.getUid());
348         notification_set_image(newNoti, NOTIFICATION_IMAGE_TYPE_ICON, pkg.getIcon().c_str());
349         notification_set_image(newNoti, NOTIFICATION_IMAGE_TYPE_ICON_SUB, NOTIFICATION_SUB_ICON_PATH);
350
351         notification_get_launch_option(newNoti, NOTIFICATION_LAUNCH_OPTION_APP_CONTROL, (void *)&appControl);
352         if (appControl != NULL) {
353                 char* appId = NULL, *uri = NULL;
354
355                 app_control_get_app_id(appControl, &appId);
356                 if (appId == NULL) {
357                         appId = strdup("");
358                 }
359
360                 krateLauncherUri = "krate://enter/" + user.getName() + "/" + appId;
361
362                 app_control_get_uri(appControl, &uri);
363                 if (uri != NULL) {
364                         krateLauncherUri += "?uri=";
365                         krateLauncherUri +=  uri;
366                         free(uri);
367                 }
368
369                 free(appId);
370                 app_control_set_app_id(appControl, KRATE_DELEGATOR_APP);
371                 app_control_set_uri(appControl, krateLauncherUri.c_str());
372                 notification_set_launch_option(newNoti, NOTIFICATION_LAUNCH_OPTION_APP_CONTROL, appControl);
373         }
374
375         notification_post_for_uid(newNoti, owner.getUid());
376         notiHandleMap.insert(std::make_pair(privId, newNoti));
377 }
378
379 void notiProxyDelete(const runtime::User& owner, int privId)
380 {
381         std::unordered_map<int, notification_h>::iterator it;
382
383         it = notiHandleMap.find(privId);
384         if (it == notiHandleMap.end()) {
385                 return;
386         }
387         notification_delete_for_uid(it->second, owner.getUid());
388         notification_free(it->second);
389         notiHandleMap.erase(it);
390 }
391
392 void notiProxyUpdate(const runtime::User& owner, const runtime::User& user, int privId, notification_h noti) {
393         std::unordered_map<int, notification_h>::iterator it;
394         double progress;
395         char *str;
396
397         it = notiHandleMap.find(privId);
398         if (it == notiHandleMap.end()) {
399                 return;
400         }
401
402         notification_image_type_e imageTypes[] = {
403                 NOTIFICATION_IMAGE_TYPE_ICON,
404                 NOTIFICATION_IMAGE_TYPE_ICON_FOR_INDICATOR,
405                 NOTIFICATION_IMAGE_TYPE_ICON_FOR_LOCK,
406                 NOTIFICATION_IMAGE_TYPE_THUMBNAIL,
407                 NOTIFICATION_IMAGE_TYPE_THUMBNAIL_FOR_LOCK,
408                 NOTIFICATION_IMAGE_TYPE_ICON_SUB,
409                 NOTIFICATION_IMAGE_TYPE_BACKGROUND,
410                 NOTIFICATION_IMAGE_TYPE_LIST_1,
411                 NOTIFICATION_IMAGE_TYPE_LIST_2,
412                 NOTIFICATION_IMAGE_TYPE_LIST_3,
413                 NOTIFICATION_IMAGE_TYPE_LIST_4,
414                 NOTIFICATION_IMAGE_TYPE_LIST_5,
415                 NOTIFICATION_IMAGE_TYPE_BUTTON_1,
416                 NOTIFICATION_IMAGE_TYPE_BUTTON_2,
417                 NOTIFICATION_IMAGE_TYPE_BUTTON_3,
418                 NOTIFICATION_IMAGE_TYPE_BUTTON_4,
419                 NOTIFICATION_IMAGE_TYPE_BUTTON_5,
420                 NOTIFICATION_IMAGE_TYPE_BUTTON_6
421         };
422
423         for (notification_image_type_e type : imageTypes) {
424                 notification_get_image(noti, type, &str);
425                 notification_set_image(it->second, type, str);
426         }
427
428         notification_text_type_e textTypes[] = {
429                 NOTIFICATION_TEXT_TYPE_TITLE,
430                 NOTIFICATION_TEXT_TYPE_CONTENT,
431                 NOTIFICATION_TEXT_TYPE_CONTENT_FOR_DISPLAY_OPTION_IS_OFF,
432                 NOTIFICATION_TEXT_TYPE_EVENT_COUNT,
433                 NOTIFICATION_TEXT_TYPE_INFO_1,
434                 NOTIFICATION_TEXT_TYPE_INFO_SUB_1,
435                 NOTIFICATION_TEXT_TYPE_INFO_2,
436                 NOTIFICATION_TEXT_TYPE_INFO_SUB_2,
437                 NOTIFICATION_TEXT_TYPE_INFO_3,
438                 NOTIFICATION_TEXT_TYPE_INFO_SUB_3,
439                 NOTIFICATION_TEXT_TYPE_GROUP_TITLE,
440                 NOTIFICATION_TEXT_TYPE_GROUP_CONTENT,
441                 NOTIFICATION_TEXT_TYPE_GROUP_CONTENT_FOR_DISPLAY_OPTION_IS_OFF,
442                 NOTIFICATION_TEXT_TYPE_BUTTON_1,
443                 NOTIFICATION_TEXT_TYPE_BUTTON_2,
444                 NOTIFICATION_TEXT_TYPE_BUTTON_3,
445                 NOTIFICATION_TEXT_TYPE_BUTTON_4,
446                 NOTIFICATION_TEXT_TYPE_BUTTON_5,
447                 NOTIFICATION_TEXT_TYPE_BUTTON_6,
448         };
449
450         for (notification_text_type_e type : textTypes) {
451                 notification_get_text(noti, type, &str);
452                 notification_set_text(it->second, type, str, NULL, NOTIFICATION_VARIABLE_TYPE_NONE);
453         }
454
455         notification_get_size(noti, &progress);
456         notification_set_size(it->second, progress);
457
458         notification_get_progress(noti, &progress);
459         notification_set_progress(it->second, progress);
460
461         notification_update_for_uid(it->second, owner.getUid());
462 }
463
464 void notiProxyCallback(void *data, notification_type_e type, notification_op *op_list, int num_op)
465 {
466         static runtime::User owner(KRATE_DEFAULT_OWNER);
467         runtime::User user(*reinterpret_cast<std::string*>(data));
468
469         if (user.getName() == owner.getName()) {
470                 // TODO : should remove noti in the krate when related-krate is removed
471                 //        This will be imlemented when notification bug is fixed
472                 return;
473     }
474
475         for (int i = 0; i < num_op; i++) {
476                 notification_h noti = NULL;
477                 int opType, privId;
478
479                 notification_op_get_data(op_list + i, NOTIFICATION_OP_DATA_TYPE, &opType);
480                 notification_op_get_data(op_list + i, NOTIFICATION_OP_DATA_PRIV_ID, &privId);
481
482                 switch (opType) {
483                 case NOTIFICATION_OP_INSERT:
484                         notification_op_get_data(op_list + i, NOTIFICATION_OP_DATA_NOTI, &noti);
485                         notiProxyInsert(owner, user, privId, noti);
486                         break;
487                 case NOTIFICATION_OP_DELETE:
488                         notiProxyDelete(owner, privId);
489                         break;
490                 case NOTIFICATION_OP_UPDATE:
491                         notification_op_get_data(op_list + i, NOTIFICATION_OP_DATA_NOTI, &noti);
492                         notiProxyUpdate(owner, user, privId, noti);
493                         break;
494                 }
495         }
496 }
497
498 } // namespace
499
500 Manager::Manager(KrateControlContext& ctx) :
501         context(ctx)
502 {
503         context.registerParametricMethod(this, "", (int)(Manager::createKrate)(std::string, std::string));
504         context.registerParametricMethod(this, "", (int)(Manager::removeKrate)(std::string));
505         context.registerParametricMethod(this, "", (int)(Manager::lockKrate)(std::string));
506         context.registerParametricMethod(this, "", (int)(Manager::unlockKrate)(std::string));
507         context.registerParametricMethod(this, "", (int)(Manager::getKrateState)(std::string));
508         context.registerParametricMethod(this, "", (std::vector<std::string>)(Manager::getKrateList)(int));
509         context.registerParametricMethod(this, "", (int)(Manager::resetKratePassword)(std::string, std::string));
510
511         context.createNotification("Manager::created");
512         context.createNotification("Manager::removed");
513
514         KRATE_DEFAULT_OWNER = ::tzplatform_getenv(TZ_SYS_DEFAULT_USER);
515
516         PackageManager& packageManager = PackageManager::instance();
517         packageManager.setEventCallback(packageEventHandler, this);
518
519         krateProcessMonitor();
520
521         initializeCreatedKrateList();
522         for (std::string& name : createdKrateList) {
523                 runtime::User krate(name);
524                 notification_register_detailed_changed_cb_for_uid(notiProxyCallback, &name, krate.getUid());
525         }
526 }
527
528 Manager::~Manager()
529 {
530 }
531
532 int Manager::createKrate(const std::string& name, const std::string& manifest)
533 {
534         const std::string& pkgId = context.getPeerPackageId();
535
536         auto provisioningWorker = [name, manifest, pkgId, this]() {
537                 std::unique_ptr<xml::Document> manifestFile;
538
539                 try {
540                         //create krate user by gumd
541                         GumUser* guser = NULL;
542                         while (guser == NULL) {
543                                 guser = gum_user_create_sync(FALSE);
544                         }
545                         g_object_set(G_OBJECT(guser), "username", name.c_str(),
546                                                         "usertype", GUM_USERTYPE_SECURITY, NULL);
547                         gboolean ret = gum_user_add_sync(guser);
548                         g_object_unref(guser);
549
550                         if (!ret) {
551                                 throw runtime::Exception("Failed to remove user (" + name + ") by gumd");
552                         }
553
554                         runtime::User user(name);
555
556                         maskUserServices(user);
557
558                     ::tzplatform_set_user(user.getUid());
559                         runtime::File confDir(std::string(::tzplatform_getenv(TZ_USER_HOME)) + "/.config/krate");
560                     ::tzplatform_reset_user();
561                         if (!confDir.exists()) {
562                                 confDir.makeDirectory(true);
563                                 confDir.chmod(700);
564                         }
565
566                         manifestFile.reset(xml::Parser::parseString(manifest));
567                         //write container author info
568                         if (!pkgId.empty()) {
569                                 std::cout << manifestFile->getRootNode().getName() << std::endl;
570                                 manifestFile->getRootNode().addNewChild("author").setContent(pkgId);
571                         }
572                         manifestFile->write(confDir.getPath() + "/" + name + ".xml", "UTF-8", true);
573
574                         //unlock the user
575                         setKrateState(user.getUid(), 1);
576
577                         //wait for launchpad in the krate
578                         sleep(1);
579
580                         auto it = createdKrateList.insert(createdKrateList.end(), name);
581                         notification_register_detailed_changed_cb_for_uid(notiProxyCallback, &(*it), user.getUid());
582                         context.notify("Manager::created", name, "");
583                 } catch (runtime::Exception& e) {
584                         ERROR(e.what());
585                         context.notify("Manager::created", name, "Error");
586                 }
587         };
588
589         std::thread asyncWork(provisioningWorker);
590         asyncWork.detach();
591
592         return 0;
593 }
594
595 int Manager::removeKrate(const std::string& name)
596 {
597         const std::string& pkgId = context.getPeerPackageId();
598         std::unique_ptr<xml::Document> manifestFile;
599         bool canRemove = false;
600
601         runtime::User user(name);
602     ::tzplatform_set_user(user.getUid());
603         std::string confPath(::tzplatform_getenv(TZ_USER_HOME));
604         confPath += "/.config/krate";
605     ::tzplatform_reset_user();
606
607         manifestFile.reset(xml::Parser::parseFile(confPath + "/" + name + ".xml"));
608         xml::Node::NodeList authors = manifestFile->evaluate("/manifest/author");
609         for (const xml::Node& author : authors) {
610                 if (author.getContent() == pkgId) {
611                         canRemove = true;
612                         break;
613                 }
614         }
615
616         if (!canRemove) {
617                 return -1;
618         }
619
620         if (lockKrate(name) != 0) {
621                 return -1;
622         }
623
624         auto remove = [name, this] {
625                 //wait for krate session close
626                 sleep(1);
627
628                 try {
629                         runtime::User user(name);
630
631                 //umount TZ_USER_CONTENT
632                         ::tzplatform_set_user(user.getUid());
633                         ::umount2(::tzplatform_getenv(TZ_USER_CONTENT), MNT_FORCE);
634                         ::tzplatform_reset_user();
635
636                         //remove krate user
637                         GumUser* guser = NULL;
638                         while (guser == NULL) {
639                                 guser = gum_user_get_sync(user.getUid(), FALSE);
640                         }
641                         gboolean ret = gum_user_delete_sync(guser, TRUE);
642                         g_object_unref(guser);
643
644                         if (!ret) {
645                                 throw runtime::Exception("Failed to remove user " + name + "(" + std::to_string(user.getUid()) + ") by gumd");
646                         }
647
648                         auto it = createdKrateList.begin();
649                         for (; it != createdKrateList.end(); it++) {
650                                 if (*it == name) {
651                                         break;
652                                 }
653                         }
654                         createdKrateList.erase(it);
655
656                         notification_unregister_detailed_changed_cb_for_uid(notiProxyCallback, NULL, user.getUid());
657                         context.notify("Manager::removed", name, "");
658                 } catch (runtime::Exception& e) {
659                         ERROR(e.what());
660                         context.notify("Manager::removed", name, "Error");
661                         return;
662                 }
663         };
664
665         std::thread asyncWork(remove);
666         asyncWork.detach();
667
668         return 0;
669 }
670
671 int Manager::lockKrate(const std::string& name)
672 {
673         try {
674                 runtime::User user(name);
675                 setKrateState(user.getUid(), 0);
676         } catch (runtime::Exception& e) {
677                 ERROR(e.what());
678                 return -1;
679         }
680
681         return 0;
682 }
683
684 int Manager::unlockKrate(const std::string& name)
685 {
686         try {
687                 runtime::User user(name);
688                 setKrateState(user.getUid(), 1);
689         } catch (runtime::Exception& e) {
690                 ERROR(e.what());
691                 return -1;
692         }
693
694         return 0;
695 }
696
697 int Manager::getKrateState(const std::string& name)
698 {
699         auto it = std::find(createdKrateList.begin(), createdKrateList.end(), name);
700         if (it == createdKrateList.end()) {
701                 return 0;
702         }
703
704         try {
705                 runtime::User user(name);
706                 try {
707                         dbus::Connection& systemDBus = dbus::Connection::getSystem();
708                         const dbus::Variant& var = systemDBus.methodcall
709                                                                                    ("org.freedesktop.login1",
710                                                                                         "/org/freedesktop/login1",
711                                                                                         "org.freedesktop.login1.Manager",
712                                                                                         "GetUser",
713                                                                                         -1, "(o)", "(u)", user.getUid());
714                         return Manager::State::Running;
715                 } catch (runtime::Exception& e) {
716                         return Manager::State::Locked;
717                 }
718         } catch (runtime::Exception& e) {
719                 ERROR(e.what());
720                 return 0;
721         }
722
723         return 0;
724 }
725
726 std::vector<std::string> Manager::getKrateList(int state)
727 {
728         std::vector<std::string> list;
729
730         for (const std::string& name : createdKrateList) {
731                 if (getKrateState(name) & state) {
732                         list.push_back(name);
733                 }
734         }
735         return list;
736 }
737
738 int Manager::resetKratePassword(const std::string& name, const std::string& newPassword)
739 {
740         try {
741                 runtime::User user(name);
742                 int ret = auth_passwd_reset_passwd(AUTH_PWD_NORMAL, user.getUid(), newPassword.c_str());
743                 if (ret != AUTH_PASSWD_API_SUCCESS) {
744                         throw runtime::Exception("Failed to reset password for " + name);
745                 }
746         } catch (runtime::Exception& e) {
747                 ERROR(e.what());
748                 return -1;
749         }
750
751         return 0;
752 }
753
754 } // namespace Krate