diff options
Diffstat (limited to 'src/lock-daemon.c')
-rwxr-xr-x | src/lock-daemon.c | 688 |
1 files changed, 688 insertions, 0 deletions
diff --git a/src/lock-daemon.c b/src/lock-daemon.c new file mode 100755 index 0000000..3847f8c --- /dev/null +++ b/src/lock-daemon.c @@ -0,0 +1,688 @@ + /* + * Copyright 2012 Samsung Electronics Co., Ltd + * + * Licensed under the Flora License, Version 1.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://floralicense.org/license/ + * + * 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. + */ + + + +#include <Elementary.h> + +#include <vconf.h> +#include <vconf-keys.h> + +#include <glib.h> +#include <poll.h> +#include <stdio.h> +#include <stdlib.h> +#include <sys/socket.h> +#include <sys/un.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <fcntl.h> +#include <errno.h> +#include <unistd.h> +#include <sys/param.h> +#include <errno.h> + +#include "lockd-debug.h" +#include "lock-daemon.h" +#include "lockd-process-mgr.h" +#include "lockd-window-mgr.h" +#include "starter-util.h" +#include "menu_daemon.h" + +static int phone_lock_pid; + +struct lockd_data { + int lock_app_pid; + int phone_lock_app_pid; + int lock_type; + Eina_Bool request_recovery; + lockw_data *lockw; + GPollFD *gpollfd; +}; + +#define PHLOCK_SOCK_PREFIX "/tmp/phlock" +#define PHLOCK_SOCK_MAXBUFF 65535 +#define PHLOCK_APP_CMDLINE "/usr/apps/org.tizen.lockscreen/bin/lockscreen" +#define PHLOCK_UNLOCK_CMD "unlock" +#define PHLOCK_LAUNCH_CMD "launch_phone_lock" +#define LAUNCH_INTERVAL 100*1000 + +static int lockd_launch_app_lockscreen(struct lockd_data *lockd); + +static void lockd_unlock_lockscreen(struct lockd_data *lockd); + +static int _lockd_get_lock_type(void) +{ + int lock_type = 0; + int ret = 0; + + vconf_get_int(VCONFKEY_SETAPPL_SCREEN_LOCK_TYPE_INT, &lock_type); + + if (lock_type == SETTING_SCREEN_LOCK_TYPE_PASSWORD || + lock_type == SETTING_SCREEN_LOCK_TYPE_SIMPLE_PASSWORD) { + ret = 1; + } else if (lock_type == SETTING_SCREEN_LOCK_TYPE_SWIPE || + lock_type == SETTING_SCREEN_LOCK_TYPE_MOTION) { + ret = 0; + } else { + ret = 2; + } + + LOCKD_DBG("_lockd_get_lock_type ret(%d), lock_type (%d)", ret, lock_type); + + return ret; +} + +static void _lockd_notify_pm_state_cb(keynode_t * node, void *data) +{ + LOCKD_DBG("PM state Notification!!"); + + struct lockd_data *lockd = (struct lockd_data *)data; + int val = -1; + + if (lockd == NULL) { + LOCKD_ERR("lockd is NULL"); + return; + } + + if (vconf_get_int(VCONFKEY_PM_STATE, &val) < 0) { + LOCKD_ERR("Cannot get VCONFKEY_PM_STATE"); + return; + } + + if (val == VCONFKEY_PM_STATE_LCDOFF) { + lockd->lock_type = _lockd_get_lock_type(); + lockd_launch_app_lockscreen(lockd); + } +} + +static void +_lockd_notify_lock_state_cb(keynode_t * node, void *data) +{ + LOCKD_DBG("lock state changed!!"); + + struct lockd_data *lockd = (struct lockd_data *)data; + int val = -1; + + if (lockd == NULL) { + LOCKD_ERR("lockd is NULL"); + return; + } + + if (vconf_get_int(VCONFKEY_IDLE_LOCK_STATE, &val) < 0) { + LOCKD_ERR("Cannot get VCONFKEY_IDLE_LOCK_STATE"); + return; + } + + if (val == VCONFKEY_IDLE_UNLOCK) { + LOCKD_DBG("unlocked..!!"); + if (lockd->lock_app_pid != 0) { + LOCKD_DBG("terminate lock app..!!"); + lockd_process_mgr_terminate_lock_app(lockd->lock_app_pid, 1); + } + } +} + +static Eina_Bool lockd_set_lock_state_cb(void *data) +{ + LOCKD_DBG("%s, %d", __func__, __LINE__); + vconf_set_int(VCONFKEY_IDLE_LOCK_STATE, VCONFKEY_IDLE_LOCK); + return ECORE_CALLBACK_CANCEL; +} + +static void +_lockd_notify_phone_lock_verification_cb(keynode_t * node, void *data) +{ + LOCKD_DBG("%s, %d", __func__, __LINE__); + + struct lockd_data *lockd = (struct lockd_data *)data; + int val = -1; + + if (lockd == NULL) { + LOCKD_ERR("lockd is NULL"); + return; + } + + if (vconf_get_bool(VCONFKEY_LOCKSCREEN_PHONE_LOCK_VERIFICATION, &val) < 0) { + LOCKD_ERR("Cannot get %s", VCONFKEY_LOCKSCREEN_PHONE_LOCK_VERIFICATION); + return; + } + + if (val == TRUE) { + lockd_window_mgr_finish_lock(lockd->lockw); + vconf_set_int(VCONFKEY_IDLE_LOCK_STATE, VCONFKEY_IDLE_UNLOCK); + } +} + +static int lockd_app_dead_cb(int pid, void *data) +{ + LOCKD_DBG("app dead cb call! (pid : %d)", pid); + + struct lockd_data *lockd = (struct lockd_data *)data; + + if (pid == lockd->lock_app_pid && lockd->lock_type == 0) { + LOCKD_DBG("lock app(pid:%d) is destroyed.", pid); + + lockd_unlock_lockscreen(lockd); + } + + menu_daemon_check_dead_signal(pid); + + return 0; +} + +static Eina_Bool lockd_app_create_cb(void *data, int type, void *event) +{ + struct lockd_data *lockd = (struct lockd_data *)data; + + if (lockd == NULL) { + return ECORE_CALLBACK_PASS_ON; + } + LOCKD_DBG("%s, %d", __func__, __LINE__); + if (lockd_window_set_window_effect(lockd->lockw, lockd->lock_app_pid, + event) == EINA_TRUE) { + if(lockd_window_set_window_property(lockd->lockw, lockd->lock_app_pid, + event) == EINA_FALSE) { + LOCKD_ERR("window is not matched..!!"); + } + } + return ECORE_CALLBACK_PASS_ON; +} + +static Eina_Bool lockd_app_show_cb(void *data, int type, void *event) +{ + struct lockd_data *lockd = (struct lockd_data *)data; + + if (lockd == NULL) { + return EINA_TRUE; + } + LOCKD_DBG("%s, %d", __func__, __LINE__); + if (lockd_window_set_window_property(lockd->lockw, lockd->lock_app_pid, + event)) { + if (lockd->lock_type > 1) { + ecore_idler_add(lockd_set_lock_state_cb, NULL); + } + } + return EINA_FALSE; +} + +static int lockd_launch_app_lockscreen(struct lockd_data *lockd) +{ + LOCKD_DBG("launch app lock screen"); + + int call_state = -1, phlock_state = -1, factory_mode = -1, test_mode = -1; + int r = 0; + + WRITE_FILE_LOG("%s", "Launch lockscreen in starter"); + + if (lockd_process_mgr_check_lock(lockd->lock_app_pid) == TRUE) { + LOCKD_DBG("Lock Screen App is already running."); + r = lockd_process_mgr_restart_lock(lockd->lock_type); + if (r < 0) { + LOCKD_DBG("Restarting Lock Screen App is fail [%d].", r); + usleep(LAUNCH_INTERVAL); + } else { + LOCKD_DBG("Restarting Lock Screen App, pid[%d].", r); + return 1; + } + } + + vconf_get_int(VCONFKEY_CALL_STATE, &call_state); + if (call_state != VCONFKEY_CALL_OFF) { + LOCKD_DBG + ("Current call state(%d) does not allow to launch lock screen.", + call_state); + return 0; + } + + if (lockd->lock_type == 0) { + lockd->lock_app_pid = + lockd_process_mgr_start_normal_lock(lockd, lockd_app_dead_cb); + if (lockd->lock_app_pid < 0) + return 0; + lockd_window_mgr_finish_lock(lockd->lockw); + lockd_window_mgr_ready_lock(lockd, lockd->lockw, lockd_app_create_cb, + lockd_app_show_cb); + } else if (lockd->lock_type == 1) { + vconf_set_bool(VCONFKEY_LOCKSCREEN_PHONE_LOCK_VERIFICATION, FALSE); + if (lockd_process_mgr_check_lock(lockd->phone_lock_app_pid) == TRUE) { + LOCKD_DBG("phone lock App is already running."); + if (lockd->request_recovery == FALSE) + return 1; + } + lockd->phone_lock_app_pid = lockd_process_mgr_start_phone_lock(); + + phone_lock_pid = lockd->phone_lock_app_pid; + LOCKD_DBG("%s, %d, phone_lock_pid = %d", __func__, __LINE__, + phone_lock_pid); + lockd_window_set_phonelock_pid(lockd->lockw, phone_lock_pid); + } else { + lockd->lock_app_pid = + lockd_process_mgr_start_lock(lockd, lockd_app_dead_cb, + lockd->lock_type); + if (lockd->lock_app_pid < 0) + return 0; + lockd_window_mgr_finish_lock(lockd->lockw); + lockd_window_mgr_ready_lock(lockd, lockd->lockw, lockd_app_create_cb, + lockd_app_show_cb); + } + return 1; +} + +static void lockd_unlock_lockscreen(struct lockd_data *lockd) +{ + LOCKD_DBG("unlock lock screen"); + lockd->lock_app_pid = 0; + + vconf_set_int(VCONFKEY_IDLE_LOCK_STATE, VCONFKEY_IDLE_UNLOCK); + lockd_window_mgr_finish_lock(lockd->lockw); +} + +inline static void lockd_set_sock_option(int fd, int cli) +{ + int size; + int ret; + struct timeval tv = { 1, 200 * 1000 }; + + size = PHLOCK_SOCK_MAXBUFF; + ret = setsockopt(fd, SOL_SOCKET, SO_SNDBUF, &size, sizeof(size)); + if(ret != 0) + return; + ret = setsockopt(fd, SOL_SOCKET, SO_RCVBUF, &size, sizeof(size)); + if(ret != 0) + return; + if (cli) { + ret = setsockopt(fd, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(tv)); + if(ret != 0) + return; + } +} + +static int lockd_create_sock(void) +{ + struct sockaddr_un saddr; + int fd; + + fd = socket(AF_UNIX, SOCK_STREAM, 0); + if (fd < 0) { + if (errno == EINVAL) { + fd = socket(AF_UNIX, SOCK_STREAM, 0); + if (fd < 0) { + LOCKD_DBG + ("second chance - socket create error"); + return -1; + } + } else { + LOCKD_DBG("socket error"); + return -1; + } + } + + bzero(&saddr, sizeof(saddr)); + saddr.sun_family = AF_UNIX; + + strncpy(saddr.sun_path, PHLOCK_SOCK_PREFIX, strlen(PHLOCK_SOCK_PREFIX)); + saddr.sun_path[strlen(PHLOCK_SOCK_PREFIX)] = 0; + + unlink(saddr.sun_path); + + if (bind(fd, (struct sockaddr *)&saddr, sizeof(saddr)) < 0) { + LOCKD_DBG("bind error"); + close(fd); + return -1; + } + + if (chmod(saddr.sun_path, (S_IRWXU | S_IRWXG | S_IRWXO)) < 0) { + LOCKD_DBG("failed to change the socket permission"); + close(fd); + return -1; + } + + lockd_set_sock_option(fd, 0); + + if (listen(fd, 10) == -1) { + LOCKD_DBG("listen error"); + close(fd); + return -1; + } + + return fd; +} + +static gboolean lockd_glib_check(GSource * src) +{ + GSList *fd_list; + GPollFD *tmp; + + fd_list = src->poll_fds; + do { + tmp = (GPollFD *) fd_list->data; + if ((tmp->revents & (POLLIN | POLLPRI))) + return TRUE; + fd_list = fd_list->next; + } while (fd_list); + + return FALSE; +} + +static char *lockd_read_cmdline_from_proc(int pid) +{ + int memsize = 32; + char path[32]; + char *cmdline = NULL, *tempptr = NULL; + FILE *fp = NULL; + + snprintf(path, sizeof(path), "/proc/%d/cmdline", pid); + + fp = fopen(path, "r"); + if (fp == NULL) { + LOCKD_DBG("Cannot open cmdline on pid[%d]", pid); + return NULL; + } + + cmdline = malloc(32); + if (cmdline == NULL) { + LOCKD_DBG("%s", "Out of memory"); + fclose(fp); + return NULL; + } + + bzero(cmdline, memsize); + if (fgets(cmdline, 32, fp) == NULL) { + LOCKD_DBG("%s", "Cannot read cmdline"); + free(cmdline); + fclose(fp); + return NULL; + } + + while (cmdline[memsize - 2] != 0) { + cmdline[memsize - 1] = (char)fgetc(fp); + tempptr = realloc(cmdline, memsize + 32); + if (tempptr == NULL) { + fclose(fp); + LOCKD_DBG("%s", "Out of memory"); + return NULL; + } + cmdline = tempptr; + bzero(cmdline + memsize, 32); + fgets(cmdline + memsize, 32, fp); + memsize += 32; + } + + if (fp != NULL) + fclose(fp); + return cmdline; +} + +static int lockd_sock_handler(void *data) +{ + int cl; + int len; + int sun_size; + int clifd = -1; + char cmd[PHLOCK_SOCK_MAXBUFF]; + char *cmdline = NULL; + int val = -1; + int fd = -1; + int recovery_state = -1; + GPollFD *gpollfd; + + struct ucred cr; + struct sockaddr_un lockd_addr; + struct lockd_data *lockd = (struct lockd_data *)data; + + if ((lockd == NULL) || (lockd->gpollfd == NULL)) { + LOCKD_DBG("lockd->gpollfd is NULL"); + return -1; + } + gpollfd = (GPollFD *)lockd->gpollfd; + fd = gpollfd->fd; + + cl = sizeof(cr); + sun_size = sizeof(struct sockaddr_un); + + if ((clifd = + accept(fd, (struct sockaddr *)&lockd_addr, + (socklen_t *) & sun_size)) == -1) { + if (errno != EINTR) + LOCKD_DBG("accept error"); + return -1; + } + + if (getsockopt(clifd, SOL_SOCKET, SO_PEERCRED, &cr, (socklen_t *) & cl) + < 0) { + LOCKD_DBG("peer information error"); + close(clifd); + return -1; + } + LOCKD_DBG("Peer's pid=%d, uid=%d, gid=%d\n", cr.pid, cr.uid, cr.gid); + + memset(cmd, 0, PHLOCK_SOCK_MAXBUFF); + + lockd_set_sock_option(clifd, 1); + + len = recv(clifd, cmd, PHLOCK_SOCK_MAXBUFF, 0); + cmd[PHLOCK_SOCK_MAXBUFF - 1] = '\0'; + + if (len != strlen(cmd)) { + LOCKD_DBG("recv error %d %d", len, strlen(cmd)); + close(clifd); + return -1; + } + + LOCKD_DBG("cmd %s", cmd); + + cmdline = lockd_read_cmdline_from_proc(cr.pid); + if (cmdline == NULL) { + LOCKD_DBG("Error on opening /proc/%d/cmdline", cr.pid); + close(clifd); + return -1; + } + + LOCKD_DBG("/proc/%d/cmdline : %s", cr.pid, cmdline); + LOCKD_DBG("phone_lock_pid : %d vs cr.pid : %d", phone_lock_pid, cr.pid); + + if ((!strncmp(cmdline, PHLOCK_APP_CMDLINE, strlen(cmdline))) + && (!strncmp(cmd, PHLOCK_UNLOCK_CMD, strlen(cmd)))) { + LOCKD_DBG("cmd is %s\n", PHLOCK_UNLOCK_CMD); + + if (phone_lock_pid == cr.pid) { + LOCKD_DBG("pid [%d] %s is verified, unlock..!!\n", cr.pid, + cmdline); + lockd_process_mgr_terminate_phone_lock(phone_lock_pid); + phone_lock_pid = 0; + vconf_set_bool(VCONFKEY_LOCKSCREEN_PHONE_LOCK_VERIFICATION, TRUE); + } + } else if (!strncmp(cmd, PHLOCK_LAUNCH_CMD, strlen(cmd))) { + LOCKD_DBG("cmd is %s\n", PHLOCK_LAUNCH_CMD); + if (_lockd_get_lock_type() == 1) { + lockd->lock_type = 1; + lockd_launch_app_lockscreen(lockd); + } + } + + if(cmdline != NULL) { + free(cmdline); + cmdline = NULL; + } + + close(clifd); + return 0; +} + +static gboolean lockd_glib_handler(gpointer data) +{ + if (lockd_sock_handler(data) < 0) { + LOCKD_DBG("lockd_sock_handler is failed..!!"); + } + return TRUE; +} + +static gboolean lockd_glib_dispatch(GSource * src, GSourceFunc callback, + gpointer data) +{ + callback(data); + return TRUE; +} + +static gboolean lockd_glib_prepare(GSource * src, gint * timeout) +{ + return FALSE; +} + +static GSourceFuncs funcs = { + .prepare = lockd_glib_prepare, + .check = lockd_glib_check, + .dispatch = lockd_glib_dispatch, + .finalize = NULL +}; + +static int lockd_init_sock(struct lockd_data *lockd) +{ + int fd; + GPollFD *gpollfd; + GSource *src; + int ret; + + fd = lockd_create_sock(); + if (fd < 0) { + LOCKD_DBG("lock daemon create sock failed..!!"); + } + + src = g_source_new(&funcs, sizeof(GSource)); + + gpollfd = (GPollFD *) g_malloc(sizeof(GPollFD)); + gpollfd->events = POLLIN; + gpollfd->fd = fd; + + lockd->gpollfd = gpollfd; + + g_source_add_poll(src, lockd->gpollfd); + g_source_set_callback(src, (GSourceFunc) lockd_glib_handler, + (gpointer) lockd, NULL); + g_source_set_priority(src, G_PRIORITY_LOW); + + ret = g_source_attach(src, NULL); + if (ret == 0) + return -1; + + g_source_unref(src); + + return 0; +} + +static void lockd_init_vconf(struct lockd_data *lockd) +{ + int val = -1; + + if (vconf_notify_key_changed + (VCONFKEY_PM_STATE, _lockd_notify_pm_state_cb, lockd) != 0) { + LOCKD_ERR("Fail vconf_notify_key_changed : VCONFKEY_PM_STATE"); + } + + if (vconf_notify_key_changed + (VCONFKEY_LOCKSCREEN_PHONE_LOCK_VERIFICATION, + _lockd_notify_phone_lock_verification_cb, lockd) != 0) { + if (vconf_get_bool(VCONFKEY_LOCKSCREEN_PHONE_LOCK_VERIFICATION, &val) < 0) { + LOCKD_ERR + ("Cannot get %s", VCONFKEY_LOCKSCREEN_PHONE_LOCK_VERIFICATION); + vconf_set_bool(VCONFKEY_LOCKSCREEN_PHONE_LOCK_VERIFICATION, 0); + if (vconf_notify_key_changed + (VCONFKEY_LOCKSCREEN_PHONE_LOCK_VERIFICATION, + _lockd_notify_phone_lock_verification_cb, + lockd) != 0) { + LOCKD_ERR + ("Fail vconf_notify_key_changed : %s", VCONFKEY_LOCKSCREEN_PHONE_LOCK_VERIFICATION); + } + } else { + LOCKD_ERR + ("Fail vconf_notify_key_changed : %s", VCONFKEY_LOCKSCREEN_PHONE_LOCK_VERIFICATION); + } + } + + if (vconf_notify_key_changed + (VCONFKEY_IDLE_LOCK_STATE, + _lockd_notify_lock_state_cb, + lockd) != 0) { + LOCKD_ERR + ("[Error] vconf notify : lock state"); + } +} + +static void lockd_start_lock_daemon(void *data) +{ + struct lockd_data *lockd = NULL; + int r = 0; + + lockd = (struct lockd_data *)data; + + if (!lockd) { + return; + } + + LOCKD_DBG("%s, %d", __func__, __LINE__); + + lockd_init_vconf(lockd); + + r = lockd_init_sock(lockd); + if (r < 0) { + LOCKD_DBG("lockd init socket failed: %d", r); + } + + lockd->lockw = lockd_window_init(); + + aul_listen_app_dead_signal(lockd_app_dead_cb, data); + + LOCKD_DBG("%s, %d", __func__, __LINE__); +} + +int start_lock_daemon(int launch_lock) +{ + struct lockd_data *lockd = NULL; + int val = -1; + int recovery_state = -1; + int first_boot = 0; + int lock_type = 0; + int ret = 0; + + LOCKD_DBG("%s, %d", __func__, __LINE__); + + lockd = (struct lockd_data *)malloc(sizeof(struct lockd_data)); + memset(lockd, 0x0, sizeof(struct lockd_data)); + lockd_start_lock_daemon(lockd); + + if (launch_lock == FALSE) { + LOCKD_DBG("Don't launch lockscreen.."); + return 0; + } + + if (vconf_get_bool(VCONFKEY_PWLOCK_FIRST_BOOT, &first_boot) < 0) { + LOCKD_ERR("Cannot get %s vconfkey", VCONFKEY_PWLOCK_FIRST_BOOT); + } else if (first_boot == 1) { + LOCKD_DBG("first_boot : %d \n", first_boot); + return 0; + } + + lock_type = _lockd_get_lock_type(); + if (lock_type == 1) { + lockd->request_recovery = FALSE; + } else if (lock_type == 2) { + lock_type = 0; + } + lockd->lock_type = lock_type; + ret = lockd_launch_app_lockscreen(lockd); + return ret; +} |