Fixed the build error for gcc-14
[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 /* LCOV_EXCL_START */
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                         ERR("g_io_channel_read_chars() Fail(%s)", gerr->message);
165                         g_error_free(gerr);
166                         return;
167                 }
168                 DBG("Receiver = %s(%d), read_size = %d", receiver, len, size);
169         }
170
171         if (len) {
172                 receiver[len] = '\0';
173                 DBG("sim_id %d", atoi(receiver));
174                 ret = ctsvc_server_sim_import_contact(src, atoi(receiver));
175         } else {
176                 ret = ctsvc_server_sim_import_contact(src, 0);
177         }
178
179         if (CONTACTS_ERROR_NONE != ret) {
180                 ERR("ctsvc_server_sim_import_contact() Fail(%d)", ret);
181                 ctsvc_server_socket_return(src, ret, 0, NULL);
182         }
183 }
184
185 static void __ctsvc_server_socket_get_sim_init_status(GIOChannel *src, int size)
186 {
187         CTS_FN_CALL;
188
189         int ret;
190         gsize len = 0;
191         GError *gerr = NULL;
192         char receiver[CTS_SQL_MAX_LEN] = {0};
193
194         if (0 < size) {
195                 g_io_channel_read_chars(src, receiver, size, &len, &gerr);
196                 if (gerr) {
197                         ERR("g_io_channel_read_chars() Fail(%s)", gerr->message);
198                         g_error_free(gerr);
199                         return;
200                 }
201                 DBG("Receiver = %s(%d), read_size = %d", receiver, len, size);
202         }
203
204         if (len) {
205                 receiver[len] = '\0';
206                 DBG("sim_id : %d", atoi(receiver));
207                 ret = ctsvc_server_socket_get_sim_init_status(src, atoi(receiver));
208         } else {
209                 ret = ctsvc_server_socket_get_sim_init_status(src, 0);
210         }
211
212         if (CONTACTS_ERROR_NONE != ret) {
213                 ERR("ctsvc_server_socket_get_sim_init_status() Fail(%d)", ret);
214                 ctsvc_server_socket_return(src, ret, 0, NULL);
215         }
216 }
217
218 int ctsvc_server_socket_return_sim_int(GIOChannel *src, int value)
219 {
220         CTS_FN_CALL;
221         int ret;
222         int str_len;
223         char count_str[CTS_SQL_MAX_LEN] = {0};
224
225         str_len = snprintf(count_str, sizeof(count_str), "%d", value);
226         ret = ctsvc_server_socket_return(src, CONTACTS_ERROR_NONE, 1, &str_len);
227         RETVM_IF(CONTACTS_ERROR_NONE != ret, ret, "ctsvc_server_socket_return() Fail(%d)", ret);
228         DBG("count_str : %s", count_str);
229         ret = __ctsvc_server_socket_safe_write(g_io_channel_unix_get_fd(src), count_str, str_len);
230         RETVM_IF(-1 == ret, CONTACTS_ERROR_SYSTEM, "__ctsvc_server_socket_safe_write() Fail(errno = %d)", errno);
231
232         return CONTACTS_ERROR_NONE;
233 }
234
235 static void __ctsvc_server_socket_read_flush(GIOChannel *src, int size)
236 {
237         gsize len;
238         GError *gerr = NULL;
239         char receiver[CTS_SQL_MAX_LEN] = {0};
240
241         if (size <= 0)
242                 return;
243
244         g_io_channel_read_chars(src, receiver, size, &len, &gerr);
245         if (gerr) {
246                 ERR("g_io_channel_read_chars() Fail(%s)", gerr->message);
247                 g_error_free(gerr);
248         }
249 }
250                 /* LCOV_EXCL_STOP */
251
252 static cynara *_cynara = NULL;
253 static int _ctsvc_server_initialize_cynara()
254 {
255         int ret;
256         ctsvc_mutex_lock(CTS_MUTEX_CYNARA);
257         ret = cynara_initialize(&_cynara, NULL);
258         ctsvc_mutex_unlock(CTS_MUTEX_CYNARA);
259         if (CYNARA_API_SUCCESS != ret) {
260                 /* LCOV_EXCL_START */
261                 char errmsg[1024] = {0};
262                 cynara_strerror(ret, errmsg, sizeof(errmsg));
263                 ERR("cynara_initialize() Fail(%d,%s)", ret, errmsg);
264                 return CONTACTS_ERROR_SYSTEM;
265                 /* LCOV_EXCL_STOP */
266         }
267         return CONTACTS_ERROR_NONE;
268 }
269
270 static void _ctsvc_server_finalize_cynara()
271 {
272         int ret;
273
274         ctsvc_mutex_lock(CTS_MUTEX_CYNARA);
275         ret = cynara_finish(_cynara);
276         _cynara = NULL;
277         ctsvc_mutex_unlock(CTS_MUTEX_CYNARA);
278         if (CYNARA_API_SUCCESS != ret) {
279                 /* LCOV_EXCL_START */
280                 char errmsg[1024] = {0};
281                 cynara_strerror(ret, errmsg, sizeof(errmsg));
282                 ERR("cynara_finish() Fail(%d,%s)", ret, errmsg);
283                 /* LCOV_EXCL_STOP */
284         }
285 }
286                 /* LCOV_EXCL_START */
287 static bool _ctsvc_server_check_privilege(struct client_info *info, const char *privilege)
288 {
289         RETV_IF(NULL == info, false);
290
291         ctsvc_mutex_lock(CTS_MUTEX_CYNARA);
292         int ret = cynara_check(_cynara, info->smack, info->client_session, info->uid, privilege);
293         ctsvc_mutex_unlock(CTS_MUTEX_CYNARA);
294         if (CYNARA_API_ACCESS_ALLOWED == ret)
295                 return true;
296
297         return false;
298 }
299                 /* LCOV_EXCL_STOP */
300 static gboolean __ctsvc_server_socket_request_handler(GIOChannel *src, GIOCondition condition,
301                 gpointer data)
302 {
303         int ret;
304         int fd;
305         bool have_read_permission = false;
306         bool have_write_permission = false;
307
308         ctsvc_socket_msg_s msg = {0};
309         CTS_FN_CALL;
310         fd = g_io_channel_unix_get_fd(src);
311
312         if (G_IO_HUP & condition) {
313                 ctsvc_mutex_lock(CTS_MUTEX_SOCKET_CLIENT_INFO);
314                 if (_client_info_table)
315                         g_hash_table_remove(_client_info_table, GINT_TO_POINTER(fd));
316                 ctsvc_mutex_unlock(CTS_MUTEX_SOCKET_CLIENT_INFO);
317                 close(fd);
318                 return FALSE;
319         }
320                 /* LCOV_EXCL_START */
321         ret = __ctsvc_server_socket_safe_read(fd, (char *)&msg, sizeof(msg));
322         RETVM_IF(-1 == ret, TRUE, "__ctsvc_server_socket_safe_read() Fail(errno = %d)", errno);
323
324         DBG("attach number = %d", msg.attach_num);
325
326         bool have_telephony_feature = false;
327         have_telephony_feature = ctsvc_server_have_telephony_feature();
328         if (false == have_telephony_feature) {
329                 ERR("Telephony feature disabled");
330                 __ctsvc_server_socket_read_flush(src, msg.attach_sizes[0]);  /* sim_id */
331                 ctsvc_server_socket_return(src, CONTACTS_ERROR_NOT_SUPPORTED, 0, NULL);
332                 return TRUE;
333         }
334
335         ctsvc_mutex_lock(CTS_MUTEX_SOCKET_CLIENT_INFO);
336         struct client_info *info = g_hash_table_lookup(_client_info_table, GINT_TO_POINTER(fd));
337         have_read_permission = _ctsvc_server_check_privilege(info, CTSVC_PRIVILEGE_CONTACT_READ);
338         if (!have_read_permission)
339                 INFO("fd(%d) : does not have contact read permission", fd);
340
341         have_write_permission = _ctsvc_server_check_privilege(info, CTSVC_PRIVILEGE_CONTACT_WRITE);
342         if (!have_write_permission)
343                 INFO("fd(%d) : does not have contact write permission", fd);
344         ctsvc_mutex_unlock(CTS_MUTEX_SOCKET_CLIENT_INFO);
345
346         switch (msg.type) {
347         case CTSVC_SOCKET_MSG_TYPE_REQUEST_IMPORT_SIM:
348                 if (false == have_write_permission) {
349                         ERR("write permission denied");
350                         __ctsvc_server_socket_read_flush(src, msg.attach_sizes[0]);  /* sim_id */
351                         ctsvc_server_socket_return(src, CONTACTS_ERROR_PERMISSION_DENIED, 0, NULL);
352                         return TRUE;
353                 }
354                 __ctsvc_server_socket_import_sim(src, msg.attach_sizes[0]);
355                 break;
356         case CTSVC_SOCKET_MSG_TYPE_REQUEST_SIM_INIT_COMPLETE:
357                 if (false == have_read_permission) {
358                         ERR("read permission denied");
359                         __ctsvc_server_socket_read_flush(src, msg.attach_sizes[0]);  /* sim_id */
360                         ctsvc_server_socket_return(src, CONTACTS_ERROR_PERMISSION_DENIED, 0, NULL);
361                         return TRUE;
362                 }
363                 __ctsvc_server_socket_get_sim_init_status(src, msg.attach_sizes[0]);
364                 break;
365         case CTSVC_SOCKET_MSG_TYPE_CANCEL_IMPORT_SIM:
366                 ctsvc_server_sim_cancel_import();
367                 break;
368
369         default:
370                 ERR("Unknown request type(%d)", msg.type);
371                 break;
372         }
373                 /* LCOV_EXCL_STOP */
374         return TRUE;
375 }
376
377 static void _ctsvc_server_destroy_client_info(gpointer p)
378 {
379         struct client_info *info = p;
380
381         if (NULL == info)
382                 return;
383         free(info->smack);
384         free(info->uid);
385         free(info->client_session);
386         free(info);
387 }
388
389 static int _ctsvc_server_create_client_info(int fd, struct client_info **p_info)
390 {
391         int ret;
392         pid_t pid;
393         char errmsg[1024] = {0};
394
395         struct client_info *info = calloc(1, sizeof(struct client_info));
396         if (NULL == info) {
397                 /* LCOV_EXCL_START */
398                 ERR("calloc() return NULL");
399                 return CONTACTS_ERROR_SYSTEM;
400                 /* LCOV_EXCL_STOP */
401         }
402
403         ret = cynara_creds_socket_get_client(fd, CLIENT_METHOD_SMACK, &(info->smack));
404         if (CYNARA_API_SUCCESS != ret) {
405                 /* LCOV_EXCL_START */
406                 cynara_strerror(ret, errmsg, sizeof(errmsg));
407                 ERR("cynara_creds_socket_get_client() Fail(%d,%s)", ret, errmsg);
408                 _ctsvc_server_destroy_client_info(info);
409                 return CONTACTS_ERROR_SYSTEM;
410                 /* LCOV_EXCL_STOP */
411         }
412
413         ret = cynara_creds_socket_get_user(fd, USER_METHOD_UID, &(info->uid));
414         if (CYNARA_API_SUCCESS != ret) {
415                 /* LCOV_EXCL_START */
416                 cynara_strerror(ret, errmsg, sizeof(errmsg));
417                 ERR("cynara_creds_socket_get_user() Fail(%d,%s)", ret, errmsg);
418                 _ctsvc_server_destroy_client_info(info);
419                 return CONTACTS_ERROR_SYSTEM;
420                 /* LCOV_EXCL_STOP */
421         }
422
423         ret = cynara_creds_socket_get_pid(fd, &pid);
424         if (CYNARA_API_SUCCESS != ret) {
425                 /* LCOV_EXCL_START */
426                 cynara_strerror(ret, errmsg, sizeof(errmsg));
427                 ERR("cynara_creds_socket_get_pid() Fail(%d,%s)", ret, errmsg);
428                 _ctsvc_server_destroy_client_info(info);
429                 return CONTACTS_ERROR_SYSTEM;
430                 /* LCOV_EXCL_STOP */
431         }
432
433         info->client_session = cynara_session_from_pid(pid);
434         if (NULL == info->client_session) {
435                 /* LCOV_EXCL_START */
436                 WARN("cynara_session_from_pid() return NULL");
437                 info->client_session = strdup("");
438                 /* LCOV_EXCL_STOP */
439         }
440         *p_info = info;
441
442         return CONTACTS_ERROR_NONE;
443 }
444
445
446 static gboolean __ctsvc_server_socket_handler(GIOChannel *src,
447                 GIOCondition condition, gpointer data)
448 {
449         CTS_FN_CALL;
450         int ret;
451
452         GIOChannel *channel;
453         int client_sockfd, sockfd = (int)data;
454         struct sockaddr_un clientaddr;
455         socklen_t client_len = sizeof(clientaddr);
456
457         client_sockfd = accept(sockfd, (struct sockaddr *)&clientaddr, &client_len);
458         RETVM_IF(-1 == client_sockfd, TRUE, "accept() Fail(errno = %d)", errno);
459
460         if (NULL == _client_info_table)
461                 _client_info_table = g_hash_table_new_full(g_direct_hash, g_direct_equal, NULL, _ctsvc_server_destroy_client_info);
462         struct client_info *info = NULL;
463         ret = _ctsvc_server_create_client_info(client_sockfd, &info);
464         if (CONTACTS_ERROR_NONE != ret)
465                 /* LCOV_EXCL_START */
466                 ERR("_create_client_info() Fail(%d)", ret);
467         /* LCOV_EXCL_STOP */
468         else
469                 g_hash_table_insert(_client_info_table, GINT_TO_POINTER(client_sockfd), info);
470
471         channel = g_io_channel_unix_new(client_sockfd);
472         g_io_add_watch(channel, G_IO_IN|G_IO_HUP, __ctsvc_server_socket_request_handler, NULL);
473         g_io_channel_unref(channel);
474
475         return TRUE;
476 }
477
478 int ctsvc_server_socket_init(void)
479 {
480         CTS_FN_CALL;
481
482         int ret;
483         int wrn;
484         struct sockaddr_un addr;
485         GIOChannel *gio;
486
487         _ctsvc_server_initialize_cynara();
488
489         char sock_file[CTSVC_PATH_MAX_LEN] = {0};
490         snprintf(sock_file, sizeof(sock_file), CTSVC_SOCK_PATH"/%s", getuid(), CTSVC_SOCKET_FILE);
491         unlink(sock_file);
492
493         bzero(&addr, sizeof(addr));
494         addr.sun_family = AF_UNIX;
495
496         wrn = snprintf(addr.sun_path, sizeof(addr.sun_path), "%s", sock_file);
497
498         if (wrn < 0){
499                 /* LCOV_EXCL_START */
500                 WARN("Error writing in sock file (%s)", sock_file);
501                 /* LCOV_EXCL_STOP */
502         }
503         sockfd = socket(PF_UNIX, SOCK_STREAM, 0);
504         RETVM_IF(-1 == sockfd, CONTACTS_ERROR_SYSTEM, "socket() Fail(errno = %d)", errno);
505
506         ret = bind(sockfd, (struct sockaddr *)&addr, sizeof(addr));
507         if (-1 == ret) {
508                 /* LCOV_EXCL_START */
509                 close(sockfd);
510                 ERR("bind() Fail(errno = %d)", errno);
511                 return CONTACTS_ERROR_SYSTEM;
512                 /* LCOV_EXCL_STOP */
513         }
514
515         ret = chown(sock_file, getuid(), CTS_SECURITY_FILE_GROUP);
516         if (0 != ret)
517                 /* LCOV_EXCL_START */
518                 ERR("chown(%s) Fail(%d) errno = %d", sock_file, ret, errno);
519         /* LCOV_EXCL_STOP */
520
521         ret = chmod(sock_file, CTS_SECURITY_DEFAULT_PERMISSION);
522         if (0 != ret)
523                 /* LCOV_EXCL_START */
524                 ERR("chmod(%s) Fail(%d)", sock_file, ret);
525         /* LCOV_EXCL_STOP */
526
527         ret = listen(sockfd, 30);
528         if (-1 == ret) {
529                 /* LCOV_EXCL_START */
530                 close(sockfd);
531                 ERR("listen() Fail(errno = %d)", errno);
532                 return CONTACTS_ERROR_SYSTEM;
533                 /* LCOV_EXCL_STOP */
534         }
535
536         gio = g_io_channel_unix_new(sockfd);
537         g_io_add_watch(gio, G_IO_IN, __ctsvc_server_socket_handler, (gpointer)sockfd);
538
539         return CONTACTS_ERROR_NONE;
540 }
541
542 int ctsvc_server_socket_deinit(void)
543 {
544         _ctsvc_server_finalize_cynara();
545         if (sockfd != -1)
546                 close(sockfd);
547         return CONTACTS_ERROR_NONE;
548 }