Adding extra logs
[platform/core/pim/contacts-service.git] / server / ctsvc_server_socket.c
1 /*
2  * Contacts Service
3  *
4  * Copyright (c) 2010 - 2015 Samsung Electronics Co., Ltd. All rights reserved.
5  *
6  * Licensed under the Apache License, Version 2.0 (the "License");
7  * you may not use this file except in compliance with the License.
8  * You may obtain a copy of the License at
9  *
10  * http://www.apache.org/licenses/LICENSE-2.0
11  *
12  * Unless required by applicable law or agreed to in writing, software
13  * distributed under the License is distributed on an "AS IS" BASIS,
14  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15  * See the License for the specific language governing permissions and
16  * limitations under the License.
17  *
18  */
19
20 #include <unistd.h>
21 #include <stdlib.h>
22 #include <glib.h>
23 #include <sys/stat.h>
24 #include <sys/socket.h>
25 #include <sys/un.h>
26 #include <errno.h>
27 #include <pims-ipc-svc.h>
28
29 #include <cynara-client.h>
30 #include <cynara-error.h>
31 #include <cynara-session.h>
32 #include <cynara-creds-socket.h>
33
34 #include "contacts.h"
35 #include "ctsvc_internal.h"
36 #include "ctsvc_struct.h"
37 #include "ctsvc_db_schema.h"
38 #include "ctsvc_db_sqlite.h"
39 #include "ctsvc_socket.h"
40 #include "ctsvc_server_socket.h"
41 #include "ctsvc_server_utils.h"
42
43 #include "ctsvc_mutex.h"
44 #include "ctsvc_server_sim.h"
45 #include "ctsvc_db_access_control.h"
46
47
48
49
50 static int sockfd = -1;
51
52 struct client_info {
53         char *smack;
54         char *uid;
55         char *client_session;
56 };
57
58 /* key : socket_fd, value : struct client_info* */
59 static GHashTable *_client_info_table = NULL;
60
61 static inline int __ctsvc_server_socket_safe_write(int fd, char *buf, int buf_size)
62 {
63         int ret, writed = 0;
64         while (buf_size) {
65                 ret = write(fd, buf+writed, buf_size);
66                 if (-1 == ret) {
67                         if (EINTR == errno)
68                                 continue;
69                         else
70                                 return ret;
71                 }
72                 writed += ret;
73                 buf_size -= ret;
74         }
75         return writed;
76 }
77
78
79 static inline int __ctsvc_server_socket_safe_read(int fd, char *buf, int buf_size)
80 {
81         int ret, read_size = 0;
82         while (buf_size) {
83                 ret = read(fd, buf+read_size, buf_size);
84                 if (-1 == ret) {
85                         if (EINTR == errno)
86                                 continue;
87                         else
88                                 return ret;
89                 }
90                 read_size += ret;
91                 buf_size -= ret;
92         }
93         return read_size;
94 }
95
96 int ctsvc_server_socket_return(GIOChannel *src, int value, int attach_num, int *attach_size)
97 {
98         CTS_FN_CALL;
99         int ret;
100         ctsvc_socket_msg_s msg = {0};
101
102         RETV_IF(NULL == src, CONTACTS_ERROR_INVALID_PARAMETER);
103
104         /* RETVM_IF(CONTACTS_ERROR_SYSTEM == value, value, "Socket has problems"); */
105         RETVM_IF(CTSVC_SOCKET_MSG_REQUEST_MAX_ATTACH < attach_num, CONTACTS_ERROR_INTERNAL,
106                         "Invalid msg(attach_num = %d)", attach_num);
107
108         msg.type = CTSVC_SOCKET_MSG_TYPE_REQUEST_RETURN_VALUE;
109         msg.val = value;
110         msg.attach_num = attach_num;
111
112         memcpy(msg.attach_sizes, attach_size, attach_num * sizeof(int));
113
114         DBG("fd = %d, MSG_TYPE=%d, MSG_VAL=%d, MSG_ATTACH_NUM=%d,"
115                         "MSG_ATTACH1=%d, MSG_ATTACH2=%d, MSG_ATTACH3=%d, MSG_ATTACH4=%d",
116                         g_io_channel_unix_get_fd(src), msg.type, msg.val, msg.attach_num,
117                         msg.attach_sizes[0], msg.attach_sizes[1], msg.attach_sizes[2],
118                         msg.attach_sizes[3]);
119
120         ret = __ctsvc_server_socket_safe_write(g_io_channel_unix_get_fd(src), (char *)&msg, sizeof(msg));
121         RETVM_IF(-1 == ret, CONTACTS_ERROR_SYSTEM,
122                         "__ctsvc_server_socket_safe_write() Fail(errno = %d)", errno);
123
124         return CONTACTS_ERROR_NONE;
125 }
126
127 int ctsvc_server_socket_invoke_cb(GIOChannel *src, int total, int imported_cnt)
128 {
129         CTS_FN_CALL;
130         int ret;
131         ctsvc_socket_msg_s msg = {0};
132
133         RETV_IF(NULL == src, CONTACTS_ERROR_INVALID_PARAMETER);
134
135         msg.type = CTSVC_SOCKET_MSG_TYPE_REQUEST_INVOKE_CB;
136         msg.val = total;
137         msg.data = imported_cnt;
138
139         DBG("fd = %d, MSG_TYPE=%d, MSG_VAL=%d, MSG_ATTACH_NUM=%d,"
140                         "MSG_ATTACH1=%d, MSG_ATTACH2=%d, MSG_ATTACH3=%d, MSG_ATTACH4=%d",
141                         g_io_channel_unix_get_fd(src), msg.type, msg.val, msg.attach_num,
142                         msg.attach_sizes[0], msg.attach_sizes[1], msg.attach_sizes[2],
143                         msg.attach_sizes[3]);
144
145         ret = __ctsvc_server_socket_safe_write(g_io_channel_unix_get_fd(src), (char *)&msg, sizeof(msg));
146         RETVM_IF(-1 == ret, CONTACTS_ERROR_SYSTEM,
147                         "__ctsvc_server_socket_safe_write() Fail(errno = %d)", errno);
148
149         return CONTACTS_ERROR_NONE;
150 }
151
152
153 static void __ctsvc_server_socket_import_sim(GIOChannel *src, int size)
154 {
155         CTS_FN_CALL;
156         int ret;
157         gsize len = 0;
158         GError *gerr = NULL;
159         char receiver[CTS_SQL_MAX_LEN] = {0};
160
161         if (0 < size) {
162                 g_io_channel_read_chars(src, receiver, size, &len, &gerr);
163                 if (gerr) {
164                         /* LCOV_EXCL_START */
165                         ERR("g_io_channel_read_chars() Fail(%s)", gerr->message);
166                         g_error_free(gerr);
167                         return;
168                         /* LCOV_EXCL_STOP */
169                 }
170                 DBG("Receiver = %s(%d), read_size = %d", receiver, len, size);
171         }
172
173         if (len) {
174                 receiver[len] = '\0';
175                 DBG("sim_id %d", atoi(receiver));
176                 ret = ctsvc_server_sim_import_contact(src, atoi(receiver));
177         } else {
178                 ret = ctsvc_server_sim_import_contact(src, 0);
179         }
180
181         if (CONTACTS_ERROR_NONE != ret) {
182                 /* LCOV_EXCL_START */
183                 ERR("ctsvc_server_sim_import_contact() Fail(%d)", ret);
184                 ctsvc_server_socket_return(src, ret, 0, NULL);
185                 /* LCOV_EXCL_STOP */
186         }
187 }
188
189 static void __ctsvc_server_socket_get_sim_init_status(GIOChannel *src, int size)
190 {
191         CTS_FN_CALL;
192
193         int ret;
194         gsize len = 0;
195         GError *gerr = NULL;
196         char receiver[CTS_SQL_MAX_LEN] = {0};
197
198         if (0 < size) {
199                 g_io_channel_read_chars(src, receiver, size, &len, &gerr);
200                 if (gerr) {
201                         /* LCOV_EXCL_START */
202                         ERR("g_io_channel_read_chars() Fail(%s)", gerr->message);
203                         g_error_free(gerr);
204                         return;
205                         /* LCOV_EXCL_STOP */
206                 }
207                 DBG("Receiver = %s(%d), read_size = %d", receiver, len, size);
208         }
209
210         if (len) {
211                 receiver[len] = '\0';
212                 DBG("sim_id : %d", atoi(receiver));
213                 ret = ctsvc_server_socket_get_sim_init_status(src, atoi(receiver));
214         } else {
215                 ret = ctsvc_server_socket_get_sim_init_status(src, 0);
216         }
217
218         if (CONTACTS_ERROR_NONE != ret) {
219                 /* LCOV_EXCL_START */
220                 ERR("ctsvc_server_socket_get_sim_init_status() Fail(%d)", ret);
221                 ctsvc_server_socket_return(src, ret, 0, NULL);
222                 /* LCOV_EXCL_STOP */
223         }
224 }
225
226 int ctsvc_server_socket_return_sim_int(GIOChannel *src, int value)
227 {
228         CTS_FN_CALL;
229         int ret;
230         int str_len;
231         char count_str[CTS_SQL_MAX_LEN] = {0};
232
233         str_len = snprintf(count_str, sizeof(count_str), "%d", value);
234         ret = ctsvc_server_socket_return(src, CONTACTS_ERROR_NONE, 1, &str_len);
235         RETVM_IF(CONTACTS_ERROR_NONE != ret, ret, "ctsvc_server_socket_return() Fail(%d)", ret);
236         DBG("count_str : %s", count_str);
237         ret = __ctsvc_server_socket_safe_write(g_io_channel_unix_get_fd(src), count_str, str_len);
238         RETVM_IF(-1 == ret, CONTACTS_ERROR_SYSTEM, "__ctsvc_server_socket_safe_write() Fail(errno = %d)", errno);
239
240         return CONTACTS_ERROR_NONE;
241 }
242
243 static void __ctsvc_server_socket_read_flush(GIOChannel *src, int size)
244 {
245         gsize len;
246         GError *gerr = NULL;
247         char receiver[CTS_SQL_MAX_LEN] = {0};
248
249         if (size <= 0)
250                 return;
251
252         g_io_channel_read_chars(src, receiver, size, &len, &gerr);
253         if (gerr) {
254                 /* LCOV_EXCL_START */
255                 ERR("g_io_channel_read_chars() Fail(%s)", gerr->message);
256                 g_error_free(gerr);
257                 /* LCOV_EXCL_STOP */
258         }
259 }
260
261
262 static cynara *_cynara = NULL;
263 static int _ctsvc_server_initialize_cynara()
264 {
265         int ret;
266         ctsvc_mutex_lock(CTS_MUTEX_CYNARA);
267         ret = cynara_initialize(&_cynara, NULL);
268         ctsvc_mutex_unlock(CTS_MUTEX_CYNARA);
269         if (CYNARA_API_SUCCESS != ret) {
270                 /* LCOV_EXCL_START */
271                 char errmsg[1024] = {0};
272                 cynara_strerror(ret, errmsg, sizeof(errmsg));
273                 ERR("cynara_initialize() Fail(%d,%s)", ret, errmsg);
274                 return CONTACTS_ERROR_SYSTEM;
275                 /* LCOV_EXCL_STOP */
276         }
277         return CONTACTS_ERROR_NONE;
278 }
279
280 static void _ctsvc_server_finalize_cynara()
281 {
282         int ret;
283
284         ctsvc_mutex_lock(CTS_MUTEX_CYNARA);
285         ret = cynara_finish(_cynara);
286         _cynara = NULL;
287         ctsvc_mutex_unlock(CTS_MUTEX_CYNARA);
288         if (CYNARA_API_SUCCESS != ret) {
289                 /* LCOV_EXCL_START */
290                 char errmsg[1024] = {0};
291                 cynara_strerror(ret, errmsg, sizeof(errmsg));
292                 ERR("cynara_finish() Fail(%d,%s)", ret, errmsg);
293                 /* LCOV_EXCL_STOP */
294         }
295 }
296
297 static bool _ctsvc_server_check_privilege(struct client_info *info, const char *privilege)
298 {
299         RETV_IF(NULL == info, false);
300
301         ctsvc_mutex_lock(CTS_MUTEX_CYNARA);
302         int ret = cynara_check(_cynara, info->smack, info->client_session, info->uid, privilege);
303         ctsvc_mutex_unlock(CTS_MUTEX_CYNARA);
304         if (CYNARA_API_ACCESS_ALLOWED == ret)
305                 return true;
306
307         return false;
308 }
309
310 static gboolean __ctsvc_server_socket_request_handler(GIOChannel *src, GIOCondition condition,
311                 gpointer data)
312 {
313         int ret;
314         int fd;
315         bool have_read_permission = false;
316         bool have_write_permission = false;
317
318         ctsvc_socket_msg_s msg = {0};
319         CTS_FN_CALL;
320         fd = g_io_channel_unix_get_fd(src);
321
322         if (G_IO_HUP & condition) {
323                 ctsvc_mutex_lock(CTS_MUTEX_SOCKET_CLIENT_INFO);
324                 if (_client_info_table)
325                         g_hash_table_remove(_client_info_table, GINT_TO_POINTER(fd));
326                 ctsvc_mutex_unlock(CTS_MUTEX_SOCKET_CLIENT_INFO);
327                 close(fd);
328                 return FALSE;
329         }
330
331         ret = __ctsvc_server_socket_safe_read(fd, (char *)&msg, sizeof(msg));
332         RETVM_IF(-1 == ret, TRUE, "__ctsvc_server_socket_safe_read() Fail(errno = %d)", errno);
333
334         DBG("attach number = %d", msg.attach_num);
335
336         bool have_telephony_feature = false;
337         have_telephony_feature = ctsvc_server_have_telephony_feature();
338         if (false == have_telephony_feature) {
339                 /* LCOV_EXCL_START */
340                 ERR("Telephony feature disabled");
341                 __ctsvc_server_socket_read_flush(src, msg.attach_sizes[0]);  /* sim_id */
342                 ctsvc_server_socket_return(src, CONTACTS_ERROR_NOT_SUPPORTED, 0, NULL);
343                 return TRUE;
344                 /* LCOV_EXCL_STOP */
345         }
346
347         ctsvc_mutex_lock(CTS_MUTEX_SOCKET_CLIENT_INFO);
348         struct client_info *info = g_hash_table_lookup(_client_info_table, GINT_TO_POINTER(fd));
349         have_read_permission = _ctsvc_server_check_privilege(info, CTSVC_PRIVILEGE_CONTACT_READ);
350         if (!have_read_permission)
351                 INFO("fd(%d) : does not have contact read permission", fd);
352
353         have_write_permission = _ctsvc_server_check_privilege(info, CTSVC_PRIVILEGE_CONTACT_WRITE);
354         if (!have_write_permission)
355                 INFO("fd(%d) : does not have contact write permission", fd);
356         ctsvc_mutex_unlock(CTS_MUTEX_SOCKET_CLIENT_INFO);
357
358         switch (msg.type) {
359         case CTSVC_SOCKET_MSG_TYPE_REQUEST_IMPORT_SIM:
360                 if (false == have_write_permission) {
361                         /* LCOV_EXCL_START */
362                         ERR("write permission denied");
363                         __ctsvc_server_socket_read_flush(src, msg.attach_sizes[0]);  /* sim_id */
364                         ctsvc_server_socket_return(src, CONTACTS_ERROR_PERMISSION_DENIED, 0, NULL);
365                         return TRUE;
366                         /* LCOV_EXCL_STOP */
367                 }
368                 __ctsvc_server_socket_import_sim(src, msg.attach_sizes[0]);
369                 break;
370         case CTSVC_SOCKET_MSG_TYPE_REQUEST_SIM_INIT_COMPLETE:
371                 if (false == have_read_permission) {
372                         /* LCOV_EXCL_START */
373                         ERR("read permission denied");
374                         __ctsvc_server_socket_read_flush(src, msg.attach_sizes[0]);  /* sim_id */
375                         ctsvc_server_socket_return(src, CONTACTS_ERROR_PERMISSION_DENIED, 0, NULL);
376                         return TRUE;
377                         /* LCOV_EXCL_STOP */
378                 }
379                 __ctsvc_server_socket_get_sim_init_status(src, msg.attach_sizes[0]);
380                 break;
381         case CTSVC_SOCKET_MSG_TYPE_CANCEL_IMPORT_SIM:
382                 ctsvc_server_sim_cancel_import();
383                 break;
384
385         default:
386                 /* LCOV_EXCL_START */
387                 ERR("Unknown request type(%d)", msg.type);
388                 break;
389                 /* LCOV_EXCL_STOP */
390         }
391         return TRUE;
392 }
393
394 static void _ctsvc_server_destroy_client_info(gpointer p)
395 {
396         struct client_info *info = p;
397
398         if (NULL == info)
399                 return;
400         free(info->smack);
401         free(info->uid);
402         free(info->client_session);
403         free(info);
404 }
405
406 static int _ctsvc_server_create_client_info(int fd, struct client_info **p_info)
407 {
408         int ret;
409         pid_t pid;
410         char errmsg[1024] = {0};
411
412         struct client_info *info = calloc(1, sizeof(struct client_info));
413         if (NULL == info) {
414                 /* LCOV_EXCL_START */
415                 ERR("calloc() return NULL");
416                 return CONTACTS_ERROR_SYSTEM;
417                 /* LCOV_EXCL_STOP */
418         }
419
420         ret = cynara_creds_socket_get_client(fd, CLIENT_METHOD_SMACK, &(info->smack));
421         if (CYNARA_API_SUCCESS != ret) {
422                 /* LCOV_EXCL_START */
423                 cynara_strerror(ret, errmsg, sizeof(errmsg));
424                 ERR("cynara_creds_socket_get_client() Fail(%d,%s)", ret, errmsg);
425                 _ctsvc_server_destroy_client_info(info);
426                 return CONTACTS_ERROR_SYSTEM;
427                 /* LCOV_EXCL_STOP */
428         }
429
430         ret = cynara_creds_socket_get_user(fd, USER_METHOD_UID, &(info->uid));
431         if (CYNARA_API_SUCCESS != ret) {
432                 /* LCOV_EXCL_START */
433                 cynara_strerror(ret, errmsg, sizeof(errmsg));
434                 ERR("cynara_creds_socket_get_user() Fail(%d,%s)", ret, errmsg);
435                 _ctsvc_server_destroy_client_info(info);
436                 return CONTACTS_ERROR_SYSTEM;
437                 /* LCOV_EXCL_STOP */
438         }
439
440         ret = cynara_creds_socket_get_pid(fd, &pid);
441         if (CYNARA_API_SUCCESS != ret) {
442                 /* LCOV_EXCL_START */
443                 cynara_strerror(ret, errmsg, sizeof(errmsg));
444                 ERR("cynara_creds_socket_get_pid() Fail(%d,%s)", ret, errmsg);
445                 _ctsvc_server_destroy_client_info(info);
446                 return CONTACTS_ERROR_SYSTEM;
447                 /* LCOV_EXCL_STOP */
448         }
449
450         info->client_session = cynara_session_from_pid(pid);
451         if (NULL == info->client_session) {
452                 /* LCOV_EXCL_START */
453                 WARN("cynara_session_from_pid() return NULL");
454                 info->client_session = strdup("");
455                 /* LCOV_EXCL_STOP */
456         }
457         *p_info = info;
458
459         return CONTACTS_ERROR_NONE;
460 }
461
462
463 static gboolean __ctsvc_server_socket_handler(GIOChannel *src,
464                 GIOCondition condition, gpointer data)
465 {
466         CTS_FN_CALL;
467         int ret;
468
469         GIOChannel *channel;
470         int client_sockfd, sockfd = (int)data;
471         struct sockaddr_un clientaddr;
472         socklen_t client_len = sizeof(clientaddr);
473
474         client_sockfd = accept(sockfd, (struct sockaddr *)&clientaddr, &client_len);
475         RETVM_IF(-1 == client_sockfd, TRUE, "accept() Fail(errno = %d)", errno);
476
477         if (NULL == _client_info_table)
478                 _client_info_table = g_hash_table_new_full(g_direct_hash, g_direct_equal, NULL, _ctsvc_server_destroy_client_info);
479         struct client_info *info = NULL;
480         ret = _ctsvc_server_create_client_info(client_sockfd, &info);
481         if (CONTACTS_ERROR_NONE != ret)
482                 /* LCOV_EXCL_START */
483                 ERR("_create_client_info() Fail(%d)", ret);
484         /* LCOV_EXCL_STOP */
485         else
486                 g_hash_table_insert(_client_info_table, GINT_TO_POINTER(client_sockfd), info);
487
488         channel = g_io_channel_unix_new(client_sockfd);
489         g_io_add_watch(channel, G_IO_IN|G_IO_HUP, __ctsvc_server_socket_request_handler, NULL);
490         g_io_channel_unref(channel);
491
492         return TRUE;
493 }
494
495 int ctsvc_server_socket_init(void)
496 {
497         CTS_FN_CALL;
498
499         int ret;
500         struct sockaddr_un addr;
501         GIOChannel *gio;
502
503         _ctsvc_server_initialize_cynara();
504
505         char sock_file[CTSVC_PATH_MAX_LEN] = {0};
506         snprintf(sock_file, sizeof(sock_file), CTSVC_SOCK_PATH"/%s", getuid(), CTSVC_SOCKET_FILE);
507         unlink(sock_file);
508
509         bzero(&addr, sizeof(addr));
510         addr.sun_family = AF_UNIX;
511         snprintf(addr.sun_path, sizeof(addr.sun_path), "%s", sock_file);
512
513         sockfd = socket(PF_UNIX, SOCK_STREAM, 0);
514         RETVM_IF(-1 == sockfd, CONTACTS_ERROR_SYSTEM, "socket() Fail(errno = %d)", errno);
515
516         ret = bind(sockfd, (struct sockaddr *)&addr, sizeof(addr));
517         if (-1 == ret) {
518                 /* LCOV_EXCL_START */
519                 close(sockfd);
520                 ERR("bind() Fail(errno = %d)", errno);
521                 return CONTACTS_ERROR_SYSTEM;
522                 /* LCOV_EXCL_STOP */
523         }
524
525         ret = chown(sock_file, getuid(), CTS_SECURITY_FILE_GROUP);
526         if (0 != ret)
527                 /* LCOV_EXCL_START */
528                 ERR("chown(%s) Fail(%d) errno = %d", sock_file, ret, errno);
529         /* LCOV_EXCL_STOP */
530
531         ret = chmod(sock_file, CTS_SECURITY_DEFAULT_PERMISSION);
532         if (0 != ret)
533                 /* LCOV_EXCL_START */
534                 ERR("chmod(%s) Fail(%d)", sock_file, ret);
535         /* LCOV_EXCL_STOP */
536
537         ret = listen(sockfd, 30);
538         if (-1 == ret) {
539                 /* LCOV_EXCL_START */
540                 close(sockfd);
541                 ERR("listen() Fail(errno = %d)", errno);
542                 return CONTACTS_ERROR_SYSTEM;
543                 /* LCOV_EXCL_STOP */
544         }
545
546         gio = g_io_channel_unix_new(sockfd);
547         g_io_add_watch(gio, G_IO_IN, __ctsvc_server_socket_handler, (gpointer)sockfd);
548
549         return CONTACTS_ERROR_NONE;
550 }
551
552 int ctsvc_server_socket_deinit(void)
553 {
554         _ctsvc_server_finalize_cynara();
555         if (sockfd != -1)
556                 close(sockfd);
557         return CONTACTS_ERROR_NONE;
558 }