update boilerplate
[apps/home/starter.git] / lock-mgr / src / lock-daemon.c
1 /*
2  * Copyright (c) 2000 - 2012 Samsung Electronics Co., Ltd All Rights Reserved 
3  *
4  * This file is part of <starter>
5  * Written by <Seungtaek Chung> <seungtaek.chung@samsung.com>, <Mi-Ju Lee> <miju52.lee@samsung.com>, <Xi Zhichan> <zhichan.xi@samsung.com>
6  *
7  * PROPRIETARY/CONFIDENTIAL
8  *
9  * This software is the confidential and proprietary information of SAMSUNG ELECTRONICS ("Confidential Information").
10  * You shall not disclose such Confidential Information and shall use it only in accordance
11  * with the terms of the license agreement you entered into with SAMSUNG ELECTRONICS.
12  * SAMSUNG make no representations or warranties about the suitability of the software,
13  * either express or implied, including but not limited to the implied warranties of merchantability,
14  * fitness for a particular purpose, or non-infringement.
15  * SAMSUNG shall not be liable for any damages suffered by licensee as a result of using,
16  * modifying or distributing this software or its derivatives.
17  *
18  */
19
20 #include <Elementary.h>
21
22 #include <vconf.h>
23 #include <vconf-keys.h>
24 #include <glib.h>
25 #include <poll.h>
26 #include <stdio.h>
27 #include <stdlib.h>
28 #include <sys/socket.h>
29 #include <sys/types.h>
30 #include <sys/stat.h>
31 #include <sys/un.h>
32 #include <fcntl.h>
33 #include <errno.h>
34 #include <unistd.h>
35 #include <sys/param.h>
36 #include <errno.h>
37
38 #include "lockd-debug.h"
39 #include "lock-daemon.h"
40 #include "lockd-process-mgr.h"
41
42 static int phone_lock_pid;
43
44 struct lockd_data {
45         int phone_lock_app_pid;
46         int phone_lock_state;
47 };
48
49 struct ucred {
50         pid_t pid;
51         uid_t uid;
52         gid_t gid;
53 };
54
55 #define VCONFKEY_PHONE_LOCK_VERIFICATION "memory/lockscreen/phone_lock_verification"
56 #define PHLOCK_SOCK_PREFIX "/tmp/phlock"
57 #define PHLOCK_SOCK_MAXBUFF 65535
58 #define PHLOCK_APP_CMDLINE "/opt/apps/org.tizen.phone-lock/bin/phone-lock"
59
60 static void lockd_launch_app_lockscreen(struct lockd_data *lockd);
61
62 static void _lockd_notify_pm_state_cb(keynode_t * node, void *data)
63 {
64         LOCKD_DBG("PM state Notification!!");
65
66         struct lockd_data *lockd = (struct lockd_data *)data;
67         int val = -1;
68
69         if (lockd == NULL) {
70                 LOCKD_ERR("lockd is NULL");
71                 return;
72         }
73
74         if (vconf_get_int(VCONFKEY_PM_STATE, &val) < 0) {
75                 LOCKD_ERR("Cannot get VCONFKEY_PM_STATE");
76                 return;
77         }
78
79         if (val == VCONFKEY_PM_STATE_LCDOFF) {
80                 lockd_launch_app_lockscreen(lockd);
81         }
82 }
83
84 static void
85 _lockd_notify_lock_state_cb(keynode_t * node, void *data)
86 {
87         LOCKD_DBG("lock state changed!!");
88
89         struct lockd_data *lockd = (struct lockd_data *)data;
90         int val = -1;
91
92         if (lockd == NULL) {
93                 LOCKD_ERR("lockd is NULL");
94                 return;
95         }
96
97         if (vconf_get_int(VCONFKEY_IDLE_LOCK_STATE, &val) < 0) {
98                 LOCKD_ERR("Cannot get VCONFKEY_IDLE_LOCK_STATE");
99                 return;
100         }
101
102         if (val == VCONFKEY_IDLE_UNLOCK) {
103                 LOCKD_DBG("unlocked..!!");
104         }
105 }
106
107 static void
108 _lockd_notify_phone_lock_verification_cb(keynode_t * node, void *data)
109 {
110         LOCKD_DBG("%s, %d", __func__, __LINE__);
111
112         struct lockd_data *lockd = (struct lockd_data *)data;
113         int val = -1;
114
115         if (lockd == NULL) {
116                 LOCKD_ERR("lockd is NULL");
117                 return;
118         }
119
120         if (vconf_get_bool(VCONFKEY_PHONE_LOCK_VERIFICATION, &val) < 0) {
121                 LOCKD_ERR("Cannot get VCONFKEY_PHONE_LOCK_VERIFICATION");
122                 return;
123         }
124
125         if (val == TRUE) {
126                 vconf_set_int(VCONFKEY_IDLE_LOCK_STATE, VCONFKEY_IDLE_UNLOCK);
127         }
128 }
129
130 static void lockd_launch_app_lockscreen(struct lockd_data *lockd)
131 {
132         LOCKD_DBG("launch app lock screen");
133
134         int call_state = -1, bootlock_state = -1;
135
136         vconf_get_bool(VCONFKEY_SETAPPL_STATE_POWER_ON_LOCK_BOOL,
137                        &bootlock_state);
138
139         if (bootlock_state) {
140                 lockd->phone_lock_state = 1;
141         } else {
142                 lockd->phone_lock_state = 0;
143         }
144
145         vconf_get_int(VCONFKEY_CALL_STATE, &call_state);
146         if (call_state != VCONFKEY_CALL_OFF) {
147                 LOCKD_DBG
148                     ("Current call state(%d) does not allow to launch lock screen.",
149                      call_state);
150                 return;
151         }
152
153         if (lockd->phone_lock_state == 1) {
154                 vconf_set_bool(VCONFKEY_PHONE_LOCK_VERIFICATION, FALSE);
155                 /* Check phone lock application is already exit */
156                 if (lockd_process_mgr_check_lock(lockd->phone_lock_app_pid) == TRUE) {
157                         LOCKD_DBG("phone lock App is already running.");
158                         return;
159                 }
160                 vconf_set_int(VCONFKEY_IDLE_LOCK_STATE, VCONFKEY_IDLE_LOCK);
161                 lockd->phone_lock_app_pid =
162                     lockd_process_mgr_start_phone_lock();
163                 phone_lock_pid = lockd->phone_lock_app_pid;
164                 LOCKD_DBG("%s, %d, phone_lock_pid = %d", __func__, __LINE__,
165                           phone_lock_pid);
166         }
167 }
168
169 inline static void lockd_set_sock_option(int fd, int cli)
170 {
171         int size;
172         struct timeval tv = { 1, 200 * 1000 };
173
174         size = PHLOCK_SOCK_MAXBUFF;
175         setsockopt(fd, SOL_SOCKET, SO_SNDBUF, &size, sizeof(size));
176         setsockopt(fd, SOL_SOCKET, SO_RCVBUF, &size, sizeof(size));
177         if (cli)
178                 setsockopt(fd, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(tv));
179 }
180
181 static int lockd_create_sock(void)
182 {
183         struct sockaddr_un saddr;
184         int fd;
185
186         fd = socket(AF_UNIX, SOCK_STREAM, 0);
187         if (fd < 0) {
188                 if (errno == EINVAL) {
189                         fd = socket(AF_UNIX, SOCK_STREAM, 0);
190                         if (fd < 0) {
191                                 LOCKD_DBG
192                                     ("second chance - socket create error");
193                                 return -1;
194                         }
195                 } else {
196                         LOCKD_DBG("socket error");
197                         return -1;
198                 }
199         }
200
201         bzero(&saddr, sizeof(saddr));
202         saddr.sun_family = AF_UNIX;
203
204         strncpy(saddr.sun_path, PHLOCK_SOCK_PREFIX, strlen(PHLOCK_SOCK_PREFIX));
205         saddr.sun_path[strlen(PHLOCK_SOCK_PREFIX)] = 0;
206
207         unlink(saddr.sun_path);
208
209         if (bind(fd, (struct sockaddr *)&saddr, sizeof(saddr)) < 0) {
210                 LOCKD_DBG("bind error");
211                 return -1;
212         }
213
214         if (chmod(saddr.sun_path, (S_IRWXU | S_IRWXG | S_IRWXO)) < 0) {
215                 LOCKD_DBG("failed to change the socket permission");
216                 return -1;
217         }
218
219         lockd_set_sock_option(fd, 0);
220
221         if (listen(fd, 10) == -1) {
222                 LOCKD_DBG("listen error");
223                 return -1;
224         }
225
226         return fd;
227 }
228
229 static gboolean lockd_glib_check(GSource * src)
230 {
231         GSList *fd_list;
232         GPollFD *tmp;
233
234         fd_list = src->poll_fds;
235         do {
236                 tmp = (GPollFD *) fd_list->data;
237                 if ((tmp->revents & (POLLIN | POLLPRI)))
238                         return TRUE;
239                 fd_list = fd_list->next;
240         } while (fd_list);
241
242         return FALSE;
243 }
244
245 static char *lockd_read_cmdline_from_proc(int pid)
246 {
247         int memsize = 32;
248         char path[32];
249         char *cmdline = NULL, *tempptr = NULL;
250         FILE *fp = NULL;
251
252         snprintf(path, sizeof(path), "/proc/%d/cmdline", pid);
253
254         fp = fopen(path, "r");
255         if (fp == NULL) {
256                 LOCKD_DBG("Cannot open cmdline on pid[%d]", pid);
257                 return NULL;
258         }
259
260         cmdline = malloc(32);
261         if (cmdline == NULL) {
262                 LOCKD_DBG("%s", "Out of memory");
263                 fclose(fp);
264                 return NULL;
265         }
266
267         bzero(cmdline, memsize);
268         if (fgets(cmdline, 32, fp) == NULL) {
269                 LOCKD_DBG("%s", "Cannot read cmdline");
270                 free(cmdline);
271                 fclose(fp);
272                 return NULL;
273         }
274
275         while (cmdline[memsize - 2] != 0) {
276                 cmdline[memsize - 1] = (char)fgetc(fp);
277                 tempptr = realloc(cmdline, memsize + 32);
278                 if (tempptr == NULL) {
279                         fclose(fp);
280                         LOCKD_DBG("%s", "Out of memory");
281                         return NULL;
282                 }
283                 cmdline = tempptr;
284                 bzero(cmdline + memsize, 32);
285                 fgets(cmdline + memsize, 32, fp);
286                 memsize += 32;
287         }
288
289         if (fp != NULL)
290                 fclose(fp);
291         return cmdline;
292 }
293
294 static int lockd_sock_handler(int fd)
295 {
296         int cl;
297         int len;
298         int sun_size;
299         int clifd = -1;
300         char cmd[PHLOCK_SOCK_MAXBUFF];
301         char *cmdline = NULL;
302
303         struct ucred cr;
304         struct sockaddr_un lockd_addr;
305
306         cl = sizeof(cr);
307         sun_size = sizeof(struct sockaddr_un);
308
309         if ((clifd =
310              accept(fd, (struct sockaddr *)&lockd_addr,
311                     (socklen_t *) & sun_size)) == -1) {
312                 if (errno != EINTR)
313                         LOCKD_DBG("accept error");
314                 return -1;
315         }
316
317         if (getsockopt(clifd, SOL_SOCKET, SO_PEERCRED, &cr, (socklen_t *) & cl)
318             < 0) {
319                 LOCKD_DBG("peer information error");
320                 close(clifd);
321                 return -1;
322         }
323         LOCKD_DBG("Peer's pid=%d, uid=%d, gid=%d\n", cr.pid, cr.uid, cr.gid);
324
325         memset(cmd, 0, PHLOCK_SOCK_MAXBUFF);
326
327         lockd_set_sock_option(clifd, 1);
328
329         len = recv(clifd, cmd, PHLOCK_SOCK_MAXBUFF, 0);
330
331         if (cmd == NULL) {
332                 LOCKD_DBG("recv error, cmd is NULL");
333                 close(clifd);
334                 return -1;
335         }
336
337         if (len != strlen(cmd)) {
338                 LOCKD_DBG("recv error %d %d", len, strlen(cmd));
339                 close(clifd);
340                 return -1;
341         }
342
343         LOCKD_DBG("cmd %s", cmd);
344
345         cmdline = lockd_read_cmdline_from_proc(cr.pid);
346         if (cmdline == NULL) {
347                 LOCKD_DBG("Error on opening /proc/%d/cmdline", cr.pid);
348                 return -1;
349         }
350
351         LOCKD_DBG("/proc/%d/cmdline : %s", cr.pid, cmdline);
352
353         if ((!strncmp(cmdline, PHLOCK_APP_CMDLINE, strlen(cmdline)))
354             && (phone_lock_pid == cr.pid)) {
355                 LOCKD_DBG("pid [%d] %s is verified, unlock..!!\n", cr.pid,
356                           cmdline);
357                 lockd_process_mgr_terminate_phone_lock(phone_lock_pid);
358                 phone_lock_pid = 0;
359                 vconf_set_bool(VCONFKEY_PHONE_LOCK_VERIFICATION, TRUE);
360         }
361
362         return 0;
363 }
364
365 static gboolean lockd_glib_handler(gpointer data)
366 {
367         GPollFD *gpollfd = (GPollFD *) data;
368         if (lockd_sock_handler(gpollfd->fd) < 0) {
369                 LOCKD_DBG("lockd_sock_handler is failed..!!");
370         }
371         return TRUE;
372 }
373
374 static gboolean lockd_glib_dispatch(GSource * src, GSourceFunc callback,
375                                     gpointer data)
376 {
377         callback(data);
378         return TRUE;
379 }
380
381 static gboolean lockd_glib_prepare(GSource * src, gint * timeout)
382 {
383         return FALSE;
384 }
385
386 static GSourceFuncs funcs = {
387         .prepare = lockd_glib_prepare,
388         .check = lockd_glib_check,
389         .dispatch = lockd_glib_dispatch,
390         .finalize = NULL
391 };
392
393 static int lockd_init_sock(void)
394 {
395         int fd;
396         GPollFD *gpollfd;
397         GSource *src;
398         int ret;
399
400         fd = lockd_create_sock();
401         if (fd < 0) {
402                 LOCKD_DBG("lock daemon create sock failed..!!");
403         }
404
405         src = g_source_new(&funcs, sizeof(GSource));
406
407         gpollfd = (GPollFD *) g_malloc(sizeof(GPollFD));
408         gpollfd->events = POLLIN;
409         gpollfd->fd = fd;
410
411         g_source_add_poll(src, gpollfd);
412         g_source_set_callback(src, (GSourceFunc) lockd_glib_handler,
413                               (gpointer) gpollfd, NULL);
414         g_source_set_priority(src, G_PRIORITY_LOW);
415
416         ret = g_source_attach(src, NULL);
417         if (ret == 0)
418                 return -1;
419
420         g_source_unref(src);
421
422         return 0;
423 }
424
425 static void lockd_init_vconf(struct lockd_data *lockd)
426 {
427         int val = -1;
428
429         if (vconf_notify_key_changed
430             (VCONFKEY_PM_STATE, _lockd_notify_pm_state_cb, lockd) != 0) {
431                 LOCKD_ERR("Fail vconf_notify_key_changed : VCONFKEY_PM_STATE");
432         }
433
434         if (vconf_notify_key_changed
435             (VCONFKEY_PHONE_LOCK_VERIFICATION,
436              _lockd_notify_phone_lock_verification_cb, lockd) != 0) {
437                 if (vconf_get_bool(VCONFKEY_PHONE_LOCK_VERIFICATION, &val) < 0) {
438                         LOCKD_ERR
439                             ("Cannot get VCONFKEY_PHONE_LOCK_VERIFICATION");
440                         vconf_set_bool(VCONFKEY_PHONE_LOCK_VERIFICATION, 0);
441                         if (vconf_notify_key_changed
442                             (VCONFKEY_PHONE_LOCK_VERIFICATION,
443                              _lockd_notify_phone_lock_verification_cb,
444                              lockd) != 0) {
445                                 LOCKD_ERR
446                                     ("Fail vconf_notify_key_changed : VCONFKEY_PHONE_LOCK_VERIFICATION");
447                         }
448                 } else {
449                         LOCKD_ERR
450                             ("Fail vconf_notify_key_changed : VCONFKEY_PHONE_LOCK_VERIFICATION");
451                 }
452         }
453
454         if (vconf_notify_key_changed
455             (VCONFKEY_IDLE_LOCK_STATE,
456              _lockd_notify_lock_state_cb,
457              lockd) != 0) {
458                 LOCKD_ERR
459                     ("[Error] vconf notify : lock state");
460         }
461         
462 }
463
464 static void lockd_start_lock_daemon(void *data)
465 {
466         struct lockd_data *lockd = NULL;
467         int r = 0;
468
469         lockd = (struct lockd_data *)data;
470
471         if (!lockd) {
472                 return;
473         }
474
475         LOCKD_DBG("%s, %d", __func__, __LINE__);
476
477         lockd_init_vconf(lockd);
478
479         r = lockd_init_sock();
480         if (r < 0) {
481                 LOCKD_DBG("lockd init socket failed: %d", r);
482         }
483
484         LOCKD_DBG("%s, %d", __func__, __LINE__);
485 }
486
487 int start_lock_daemon()
488 {
489         struct lockd_data *lockd = NULL;
490         int val = -1;
491
492         LOCKD_DBG("%s, %d", __func__, __LINE__);
493
494         lockd = (struct lockd_data *)malloc(sizeof(struct lockd_data));
495         memset(lockd, 0x0, sizeof(struct lockd_data));
496         lockd_start_lock_daemon(lockd);
497
498         vconf_get_bool(VCONFKEY_SETAPPL_STATE_POWER_ON_LOCK_BOOL, &val);
499         LOCKD_DBG("%s, %d, val = %d", __func__, __LINE__, val);
500
501         if (val) {
502                 lockd_launch_app_lockscreen(lockd);
503         }
504
505         return 0;
506 }