4 * Copyright (c) 2010 - 2015 Samsung Electronics Co., Ltd. All rights reserved.
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
10 * http://www.apache.org/licenses/LICENSE-2.0
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.
24 #include <sys/socket.h>
27 #include <pims-ipc-svc.h>
29 #include <cynara-client.h>
30 #include <cynara-error.h>
31 #include <cynara-session.h>
32 #include <cynara-creds-socket.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"
43 #include "ctsvc_mutex.h"
44 #include "ctsvc_server_sim.h"
45 #include "ctsvc_db_access_control.h"
50 static int sockfd = -1;
58 /* key : socket_fd, value : struct client_info* */
59 static GHashTable *_client_info_table = NULL;
61 static inline int __ctsvc_server_socket_safe_write(int fd, char *buf, int buf_size)
65 ret = write(fd, buf+writed, buf_size);
79 static inline int __ctsvc_server_socket_safe_read(int fd, char *buf, int buf_size)
81 int ret, read_size = 0;
83 ret = read(fd, buf+read_size, buf_size);
96 int ctsvc_server_socket_return(GIOChannel *src, int value, int attach_num, int *attach_size)
100 ctsvc_socket_msg_s msg = {0};
102 RETV_IF(NULL == src, CONTACTS_ERROR_INVALID_PARAMETER);
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);
108 msg.type = CTSVC_SOCKET_MSG_TYPE_REQUEST_RETURN_VALUE;
110 msg.attach_num = attach_num;
112 memcpy(msg.attach_sizes, attach_size, attach_num * sizeof(int));
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]);
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);
124 return CONTACTS_ERROR_NONE;
127 int ctsvc_server_socket_invoke_cb(GIOChannel *src, int total, int imported_cnt)
131 ctsvc_socket_msg_s msg = {0};
133 RETV_IF(NULL == src, CONTACTS_ERROR_INVALID_PARAMETER);
135 msg.type = CTSVC_SOCKET_MSG_TYPE_REQUEST_INVOKE_CB;
137 msg.data = imported_cnt;
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]);
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);
149 return CONTACTS_ERROR_NONE;
153 static void __ctsvc_server_socket_import_sim(GIOChannel *src, int size)
159 char receiver[CTS_SQL_MAX_LEN] = {0};
162 g_io_channel_read_chars(src, receiver, size, &len, &gerr);
164 /* LCOV_EXCL_START */
165 ERR("g_io_channel_read_chars() Fail(%s)", gerr->message);
170 DBG("Receiver = %s(%d), read_size = %d", receiver, len, size);
174 receiver[len] = '\0';
175 DBG("sim_id %d", atoi(receiver));
176 ret = ctsvc_server_sim_import_contact(src, atoi(receiver));
178 ret = ctsvc_server_sim_import_contact(src, 0);
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);
189 static void __ctsvc_server_socket_get_sim_init_status(GIOChannel *src, int size)
196 char receiver[CTS_SQL_MAX_LEN] = {0};
199 g_io_channel_read_chars(src, receiver, size, &len, &gerr);
201 /* LCOV_EXCL_START */
202 ERR("g_io_channel_read_chars() Fail(%s)", gerr->message);
207 DBG("Receiver = %s(%d), read_size = %d", receiver, len, size);
211 receiver[len] = '\0';
212 DBG("sim_id : %d", atoi(receiver));
213 ret = ctsvc_server_socket_get_sim_init_status(src, atoi(receiver));
215 ret = ctsvc_server_socket_get_sim_init_status(src, 0);
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);
226 int ctsvc_server_socket_return_sim_int(GIOChannel *src, int value)
231 char count_str[CTS_SQL_MAX_LEN] = {0};
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);
240 return CONTACTS_ERROR_NONE;
243 static void __ctsvc_server_socket_read_flush(GIOChannel *src, int size)
247 char receiver[CTS_SQL_MAX_LEN] = {0};
252 g_io_channel_read_chars(src, receiver, size, &len, &gerr);
254 /* LCOV_EXCL_START */
255 ERR("g_io_channel_read_chars() Fail(%s)", gerr->message);
262 static cynara *_cynara = NULL;
263 static int _ctsvc_server_initialize_cynara()
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;
277 return CONTACTS_ERROR_NONE;
280 static void _ctsvc_server_finalize_cynara()
284 ctsvc_mutex_lock(CTS_MUTEX_CYNARA);
285 ret = cynara_finish(_cynara);
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);
297 static bool _ctsvc_server_check_privilege(struct client_info *info, const char *privilege)
299 RETV_IF(NULL == info, false);
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)
310 static gboolean __ctsvc_server_socket_request_handler(GIOChannel *src, GIOCondition condition,
315 bool have_read_permission = false;
316 bool have_write_permission = false;
318 ctsvc_socket_msg_s msg = {0};
320 fd = g_io_channel_unix_get_fd(src);
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);
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);
334 DBG("attach number = %d", msg.attach_num);
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);
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);
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);
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);
368 __ctsvc_server_socket_import_sim(src, msg.attach_sizes[0]);
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);
379 __ctsvc_server_socket_get_sim_init_status(src, msg.attach_sizes[0]);
381 case CTSVC_SOCKET_MSG_TYPE_CANCEL_IMPORT_SIM:
382 ctsvc_server_sim_cancel_import();
386 /* LCOV_EXCL_START */
387 ERR("Unknown request type(%d)", msg.type);
394 static void _ctsvc_server_destroy_client_info(gpointer p)
396 struct client_info *info = p;
402 free(info->client_session);
406 static int _ctsvc_server_create_client_info(int fd, struct client_info **p_info)
410 char errmsg[1024] = {0};
412 struct client_info *info = calloc(1, sizeof(struct client_info));
414 /* LCOV_EXCL_START */
415 ERR("calloc() return NULL");
416 return CONTACTS_ERROR_SYSTEM;
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;
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;
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;
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("");
459 return CONTACTS_ERROR_NONE;
463 static gboolean __ctsvc_server_socket_handler(GIOChannel *src,
464 GIOCondition condition, gpointer data)
470 int client_sockfd, sockfd = (int)data;
471 struct sockaddr_un clientaddr;
472 socklen_t client_len = sizeof(clientaddr);
474 client_sockfd = accept(sockfd, (struct sockaddr *)&clientaddr, &client_len);
475 RETVM_IF(-1 == client_sockfd, TRUE, "accept() Fail(errno = %d)", errno);
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);
486 g_hash_table_insert(_client_info_table, GINT_TO_POINTER(client_sockfd), info);
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);
495 int ctsvc_server_socket_init(void)
500 struct sockaddr_un addr;
503 _ctsvc_server_initialize_cynara();
505 char sock_file[CTSVC_PATH_MAX_LEN] = {0};
506 snprintf(sock_file, sizeof(sock_file), CTSVC_SOCK_PATH"/%s", getuid(), CTSVC_SOCKET_FILE);
509 bzero(&addr, sizeof(addr));
510 addr.sun_family = AF_UNIX;
511 snprintf(addr.sun_path, sizeof(addr.sun_path), "%s", sock_file);
513 sockfd = socket(PF_UNIX, SOCK_STREAM, 0);
514 RETVM_IF(-1 == sockfd, CONTACTS_ERROR_SYSTEM, "socket() Fail(errno = %d)", errno);
516 ret = bind(sockfd, (struct sockaddr *)&addr, sizeof(addr));
518 /* LCOV_EXCL_START */
520 ERR("bind() Fail(errno = %d)", errno);
521 return CONTACTS_ERROR_SYSTEM;
525 ret = chown(sock_file, getuid(), CTS_SECURITY_FILE_GROUP);
527 /* LCOV_EXCL_START */
528 ERR("chown(%s) Fail(%d) errno = %d", sock_file, ret, errno);
531 ret = chmod(sock_file, CTS_SECURITY_DEFAULT_PERMISSION);
533 /* LCOV_EXCL_START */
534 ERR("chmod(%s) Fail(%d)", sock_file, ret);
537 ret = listen(sockfd, 30);
539 /* LCOV_EXCL_START */
541 ERR("listen() Fail(errno = %d)", errno);
542 return CONTACTS_ERROR_SYSTEM;
546 gio = g_io_channel_unix_new(sockfd);
547 g_io_add_watch(gio, G_IO_IN, __ctsvc_server_socket_handler, (gpointer)sockfd);
549 return CONTACTS_ERROR_NONE;
552 int ctsvc_server_socket_deinit(void)
554 _ctsvc_server_finalize_cynara();
557 return CONTACTS_ERROR_NONE;