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