Add user space access control
[platform/core/pim/contacts-service.git] / client / ctsvc_client_ipc.c
1 /*
2  * Contacts Service
3  *
4  * Copyright (c) 2010 - 2012 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 <glib.h>
21 #include <pims-ipc-data.h>
22 #include <security-server.h>
23
24 #include "ctsvc_client_ipc.h"
25
26 #include "ctsvc_internal.h"
27 #include "ctsvc_list.h"
28 #include "ctsvc_record.h"
29 #include "ctsvc_query.h"
30 #include "ctsvc_inotify.h"
31
32 #include "ctsvc_ipc_define.h"
33 #include "ctsvc_ipc_marshal.h"
34 #include "ctsvc_view.h"
35 #include "ctsvc_mutex.h"
36
37 static __thread pims_ipc_h __contacts_ipc = NULL;
38 static pims_ipc_h __contacts_global_ipc = NULL;
39
40 static __thread int __contacts_change_version = 0;
41 static int __contacts_global_change_version = 0;
42
43 static int __ctsvc_ipc_get_cookie_for_access_control(pims_ipc_data_h *indata)
44 {
45         int ret;
46         size_t cookie_size = 0;
47         pims_ipc_data_h data;
48         char *buf;
49
50         // Access control : get cookie from security-server
51         cookie_size = security_server_get_cookie_size();
52         if (cookie_size <= 0) {
53                 CTS_ERR("security_server_get_cookie_size");
54                 return CONTACTS_ERROR_SYSTEM;
55         }
56
57         char cookie[cookie_size];
58         cookie[0] = '\0';
59         ret = security_server_request_cookie(cookie, cookie_size);
60         if(ret < 0) {
61                 CTS_ERR("security_server_request_cookie fail (%d)", ret);
62                 return CONTACTS_ERROR_SYSTEM;
63         }
64
65         // Access control : put cookie to indata
66         data = pims_ipc_data_create(0);
67         if (data == NULL) {
68                 CTS_ERR("ipc data created fail!");
69                 return CONTACTS_ERROR_OUT_OF_MEMORY;
70         }
71
72         ret = ctsvc_ipc_marshal_unsigned_int(cookie_size, data);
73         if (ret != CONTACTS_ERROR_NONE) {
74                 CTS_ERR("ctsvc_ipc_marshal_int fail");
75                 pims_ipc_data_destroy(data);
76                 return ret;
77         }
78
79         buf = g_base64_encode((const guchar *)cookie, cookie_size);
80         if (buf) {
81                 ret = ctsvc_ipc_marshal_string(buf, data);
82                 if (ret != CONTACTS_ERROR_NONE) {
83                         CTS_ERR("ctsvc_ipc_marshal_string fail");
84                         pims_ipc_data_destroy(data);
85                         return ret;
86                 }
87                 free(buf);
88         }
89         else {
90                 CTS_ERR("g_base64_encode fail");
91                 pims_ipc_data_destroy(data);
92                 return CONTACTS_ERROR_INTERNAL;
93         }
94
95         *indata = data;
96
97         return CONTACTS_ERROR_NONE;
98 }
99
100 int ctsvc_ipc_connect_on_thread(void)
101 {
102         int ret = CONTACTS_ERROR_NONE;
103         pims_ipc_data_h indata = NULL;
104         pims_ipc_data_h outdata = NULL;
105
106         // ipc create
107         if (__contacts_ipc == NULL) {
108                 __contacts_ipc = pims_ipc_create(CTSVC_IPC_SOCKET_PATH);
109                 if (__contacts_ipc == NULL) {
110                         CTS_ERR("pims_ipc_create() Failed(%d)", CONTACTS_ERROR_IPC_NOT_AVALIABLE);
111                         return CONTACTS_ERROR_IPC_NOT_AVALIABLE;
112                 }
113         }
114         else {
115                 CTS_DBG("contacts already connected");
116                 return CONTACTS_ERROR_NONE;
117         }
118
119         ret = __ctsvc_ipc_get_cookie_for_access_control(&indata);
120         if (CONTACTS_ERROR_NONE != ret) {
121                 CTS_ERR("__ctsvc_ipc_get_cookie_for_access_control fail (%d)", ret);
122                 goto DATA_FREE;
123         }
124
125         // ipc call
126         if (pims_ipc_call(__contacts_ipc, CTSVC_IPC_MODULE, CTSVC_IPC_SERVER_CONNECT, indata, &outdata) != 0) {
127                 CTS_ERR("pims_ipc_call failed");
128                 pims_ipc_data_destroy(indata);
129                 ret = CONTACTS_ERROR_IPC;
130                 goto DATA_FREE;
131         }
132
133         pims_ipc_data_destroy(indata);
134
135         if (outdata) {
136                 unsigned int size = 0;
137                 ret = *(int*) pims_ipc_data_get(outdata,&size);
138
139                 pims_ipc_data_destroy(outdata);
140
141                 if (ret != CONTACTS_ERROR_NONE) {
142                         CTS_ERR("ctsvc_ipc_server_connect return(%d)", ret);
143                         goto DATA_FREE;
144                 }
145         }
146
147         return ret;
148
149 DATA_FREE:
150         pims_ipc_destroy(__contacts_ipc);
151         __contacts_ipc = NULL;
152
153         return ret;
154 }
155
156 int ctsvc_ipc_disconnect_on_thread(void)
157 {
158         int ret = CONTACTS_ERROR_NONE;
159         pims_ipc_data_h outdata = NULL;
160
161         RETVM_IF(__contacts_ipc == NULL, CONTACTS_ERROR_IPC, "contacts not connected");
162
163         if (pims_ipc_call(__contacts_ipc, CTSVC_IPC_MODULE, CTSVC_IPC_SERVER_DISCONNECT, NULL, &outdata) != 0) {
164                 CTS_ERR("pims_ipc_call failed");
165                 return CONTACTS_ERROR_IPC;
166         }
167
168         if (outdata) {
169                 unsigned int size = 0;
170                 ret = *(int*) pims_ipc_data_get(outdata,&size);
171                 pims_ipc_data_destroy(outdata);
172
173                 if (ret != CONTACTS_ERROR_NONE)
174                         CTS_ERR("[GLOBAL_IPC_CHANNEL] pims_ipc didn't destroyed!!!(%d)", ret);
175
176                 pims_ipc_destroy(__contacts_ipc);
177                 __contacts_ipc = NULL;
178         }
179         else {
180                 CTS_ERR("pims_ipc_call out data is NULL");
181                 return CONTACTS_ERROR_IPC;
182         }
183
184         return ret;
185 }
186
187 pims_ipc_h ctsvc_get_ipc_handle()
188 {
189         if(__contacts_ipc == NULL) {
190                 if(__contacts_global_ipc == NULL ) {
191                         ASSERT_NOT_REACHED("IPC haven't been initialized yet.");
192                         return NULL;
193                 }
194                 CTS_DBG("fallback to global ipc channel");
195                 return __contacts_global_ipc;
196         }
197
198         return __contacts_ipc;
199 }
200
201 bool ctsvc_ipc_is_busy()
202 {
203         bool ret = false;
204
205         if(__contacts_ipc != NULL) {
206                 ret = pims_ipc_is_call_in_progress(__contacts_ipc);
207                 if (ret)
208                         CTS_ERR("thread local ipc channel is busy.");
209         }
210         else {
211                 ret = pims_ipc_is_call_in_progress(__contacts_global_ipc);
212                 if (ret)
213                         CTS_ERR("global ipc channel is busy.");
214         }
215
216         return ret;
217 }
218
219 int ctsvc_ipc_connect(void)
220 {
221         int ret = CONTACTS_ERROR_NONE;
222         pims_ipc_data_h indata = NULL;
223         pims_ipc_data_h outdata = NULL;
224
225         // ipc create
226         if (__contacts_global_ipc == NULL) {
227                 __contacts_global_ipc = pims_ipc_create(CTSVC_IPC_SOCKET_PATH);
228                 if (__contacts_global_ipc == NULL) {
229                         CTS_ERR("[GLOBAL_IPC_CHANNEL] pims_ipc_create() Failed(%d)", CONTACTS_ERROR_IPC_NOT_AVALIABLE);
230                         return CONTACTS_ERROR_IPC_NOT_AVALIABLE;
231                 }
232         }
233         else {
234                 CTS_DBG("[GLOBAL_IPC_CHANNEL] contacts already connected");
235                 return CONTACTS_ERROR_NONE;
236         }
237
238         ret = __ctsvc_ipc_get_cookie_for_access_control(&indata);
239         if (CONTACTS_ERROR_NONE != ret) {
240                 CTS_ERR("__ctsvc_ipc_get_cookie_for_access_control fail (%d)", ret);
241                 goto DATA_FREE;
242         }
243
244         // ipc call
245         if (pims_ipc_call(__contacts_global_ipc, CTSVC_IPC_MODULE, CTSVC_IPC_SERVER_CONNECT, indata, &outdata) != 0) {
246                 CTS_ERR("[GLOBAL_IPC_CHANNEL] pims_ipc_call failed");
247                 pims_ipc_data_destroy(indata);
248                 ret = CONTACTS_ERROR_IPC;
249                 goto DATA_FREE;
250         }
251
252         pims_ipc_data_destroy(indata);
253
254         if (outdata) {
255                 unsigned int size = 0;
256                 ret = *(int*) pims_ipc_data_get(outdata,&size);
257                 pims_ipc_data_destroy(outdata);
258
259                 if (ret != CONTACTS_ERROR_NONE) {
260                         CTS_ERR("ctsvc_ipc_server_connect return(%d)", ret);
261                         goto DATA_FREE;
262                 }
263         }
264         return ret;
265
266 DATA_FREE:
267         pims_ipc_destroy(__contacts_global_ipc);
268         __contacts_global_ipc = NULL;
269         return ret;
270 }
271
272
273 int ctsvc_ipc_disconnect(void)
274 {
275         int ret = CONTACTS_ERROR_NONE;
276         pims_ipc_data_h outdata = NULL;
277
278         RETVM_IF(__contacts_global_ipc == NULL, CONTACTS_ERROR_IPC, "[GLOBAL_IPC_CHANNEL] contacts not connected");
279
280         if (pims_ipc_call(__contacts_global_ipc, CTSVC_IPC_MODULE, CTSVC_IPC_SERVER_DISCONNECT, NULL, &outdata) != 0) {
281                 CTS_ERR("[GLOBAL_IPC_CHANNEL] pims_ipc_call failed");
282                 return CONTACTS_ERROR_IPC;
283         }
284
285         if (outdata) {
286                 unsigned int size = 0;
287                 ret = *(int*) pims_ipc_data_get(outdata,&size);
288                 pims_ipc_data_destroy(outdata);
289
290                 if (ret != CONTACTS_ERROR_NONE)
291                         CTS_ERR("[GLOBAL_IPC_CHANNEL] pims_ipc didn't destroyed!!!(%d)", ret);
292
293                 pims_ipc_destroy(__contacts_global_ipc);
294                 __contacts_global_ipc = NULL;
295         }
296         else {
297                 CTS_ERR("pims_ipc_call out data is NULL");
298                 return CONTACTS_ERROR_IPC;
299         }
300
301         return ret;
302 }
303
304 static void __ctsvc_ipc_lock()
305 {
306         if (__contacts_ipc == NULL)
307                 ctsvc_mutex_lock(CTS_MUTEX_PIMS_IPC_CALL);
308 }
309
310 static void __ctsvc_ipc_unlock(void)
311 {
312         if (__contacts_ipc == NULL)
313                 ctsvc_mutex_unlock(CTS_MUTEX_PIMS_IPC_CALL);
314 }
315
316 int ctsvc_ipc_call(char *module, char *function, pims_ipc_h data_in, pims_ipc_data_h *data_out)
317 {
318         pims_ipc_h ipc_handle = ctsvc_get_ipc_handle();
319
320         __ctsvc_ipc_lock();
321
322         int ret = pims_ipc_call(ipc_handle, module, function, data_in, data_out);
323
324         __ctsvc_ipc_unlock();
325
326         return ret;
327 }
328
329 int ctsvc_ipc_call_async(char *module, char *function, pims_ipc_h data_in, pims_ipc_call_async_cb callback, void *userdata)
330 {
331         pims_ipc_h ipc_handle = ctsvc_get_ipc_handle();
332
333         __ctsvc_ipc_lock();
334
335         int ret = pims_ipc_call_async(ipc_handle, module, function, data_in, callback, userdata);
336
337         __ctsvc_ipc_unlock();
338
339         return ret;
340 }
341
342 void ctsvc_client_ipc_set_change_version(int version)
343 {
344         if (__contacts_ipc == NULL) {
345                 __contacts_global_change_version = version;
346                 CTS_DBG("change_version = %d", version);
347                 return;
348         }
349         __contacts_change_version = version;
350         CTS_DBG("change_version = %d", version);
351 }
352
353 int ctsvc_client_ipc_get_change_version(void)
354 {
355         if (__contacts_ipc == NULL)
356                 return __contacts_global_change_version;
357
358         return __contacts_change_version;
359 }
360