Enabled Dummy ASM for testing purpose
[platform/core/account/fido-client.git] / server / fido_asm_plugin_manager.c
1 /*
2  * Copyright (c) 2014 - 2015 Samsung Electronics Co., Ltd. All rights reserved.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  *
16  */
17
18 #include <app.h>
19 #include <stdio.h>
20 #include <string.h>
21 #include <stdlib.h>
22 #include <glib.h>
23 #include <gio/gio.h>
24
25 #include "fido_logs.h"
26 #include "fido_uaf_types.h"
27 #include "fido_internal_types.h"
28 #include "fido_json_handler.h"
29 #include "fido_internal_types.h"
30
31 #include "fido_asm_plugin_manager.h"
32
33 #define _ASM_CONF_DIR_PATH "/usr/lib/fido/asm/"
34 #define _ASM_CONF_DIR_PATH_64 "/usr/lib64/fido/asm/"
35
36 typedef struct _asm_ipc_cb_data {
37     _asm_ipc_response_cb cb;
38     void *user_data;
39 } _asm_ipc_cb_data_t;
40
41 typedef struct _asm_ipc_discover_cb_data {
42     _asm_plugin_discover_response_cb cb;
43     GList *asm_proxy_list_iter;
44     void *user_data;
45     GList *asm_resp_list;
46 } _asm_ipc_discover_cb_data_t;
47
48 static GHashTable *asm_proxy_table = NULL;
49 static GFileMonitor *__monitor = NULL;
50
51 static GDBusConnection *
52 __get_dbus_connection(void)
53 {
54     GError *error = NULL;
55
56     GDBusConnection *dbus_conn = g_bus_get_sync(G_BUS_TYPE_SYSTEM, NULL, &error);
57
58     if (dbus_conn == NULL) {
59         _ERR("Unable to connect to dbus: %s", error->message);
60         g_clear_error(&error);
61     }
62
63     return dbus_conn;
64 }
65
66 static GDBusProxy*
67 __get_dbus_proxy(const char *dbus_name, const char *obj_path,
68                  const char *intf_name)
69 {
70     GDBusConnection *conn = __get_dbus_connection();
71     if (conn == NULL)
72         return NULL;
73
74     GError *err = NULL;
75
76     GDBusProxy *dbus_proxy = g_dbus_proxy_new_sync(conn,
77                                         G_DBUS_PROXY_FLAGS_NONE,
78                                         NULL,
79                                         dbus_name,
80                                         obj_path,
81                                         intf_name,
82                                         NULL,
83                                         &err);
84
85     if (err != NULL)
86         _ERR("g_dbus_proxy_new_sync failed [%d][%s]", err->code, err->message);
87
88     return dbus_proxy;
89 }
90
91 static void
92 __free_asm_proxy_data(gpointer data)
93 {
94     if (data != NULL) {
95         _fido_asm_proxy_t *proxy = data;
96
97         SAFE_DELETE(proxy->bin_path);
98         SAFE_DELETE(proxy->dbus_info);
99         SAFE_DELETE(proxy->dbus_interface_name);
100         SAFE_DELETE(proxy->dbus_method_name);
101         SAFE_DELETE(proxy->dbus_obj_path);
102         SAFE_DELETE(proxy->vendor);
103
104         SAFE_DELETE(proxy);
105     }
106
107
108 }
109
110 static int
111 __load_plugins(char **plugin_path)
112 {
113     if (asm_proxy_table != NULL) {
114         g_hash_table_destroy(asm_proxy_table);
115         asm_proxy_table = NULL;
116     }
117
118     asm_proxy_table = g_hash_table_new_full(g_str_hash, g_str_equal, free, _free_fido_asm_proxy);
119
120     DIR *dir;
121     struct dirent *entry;
122     bool is_64 = true;
123
124     dir = opendir(_ASM_CONF_DIR_PATH_64);
125     if (dir == NULL) {
126
127                 dir = opendir(_ASM_CONF_DIR_PATH);
128                 if (dir == NULL) {
129
130                         _ERR("Could not open [%s] and [%s] path = [%s]", _ASM_CONF_DIR_PATH_64, _ASM_CONF_DIR_PATH, strerror(errno));
131                         return FIDO_ERROR_PERMISSION_DENIED;
132                 }
133                 is_64 = false;
134     }
135
136         *plugin_path = calloc(1, 128);
137         if (is_64 == true)
138                 snprintf(*plugin_path, 127, _ASM_CONF_DIR_PATH_64);
139         else
140                 snprintf(*plugin_path, 127, _ASM_CONF_DIR_PATH);
141
142     bool is_asm_found = false;
143
144     _INFO("Loading ASM conf files from [%s]", *plugin_path);
145
146     while ((entry = readdir(dir)) != NULL) {
147         if (entry->d_type == DT_REG) {
148             char *conf_file_name = entry->d_name;
149             if (conf_file_name != NULL) {
150                 char conf_file_name_full[128] = {0, };
151                 /*TODO make safe size*/
152                 snprintf(conf_file_name_full, 127, "%s%s", *plugin_path, conf_file_name);
153                 _INFO("Processing [%s]", conf_file_name_full);
154                 _fido_asm_proxy_t *asm_proxy = _parse_asm_conf_file(conf_file_name_full);
155                 if (asm_proxy != NULL) {
156                     asm_proxy->dbus_proxy = __get_dbus_proxy(asm_proxy->dbus_info, asm_proxy->dbus_obj_path,
157                                                              asm_proxy->dbus_interface_name);
158                     if (asm_proxy->dbus_proxy != NULL) {
159                         is_asm_found = true;
160
161                         asm_proxy->asm_id = strdup(conf_file_name);
162                         g_hash_table_insert(asm_proxy_table, strdup(conf_file_name), asm_proxy);
163                     }
164                     else {
165                         _ERR("Failed to get dbus proxy for the ASM");
166                         __free_asm_proxy_data((gpointer)asm_proxy);
167                     }
168                 }
169
170             }
171         }
172     }
173
174     closedir(dir);
175
176     if (is_asm_found == false)
177         return FIDO_ERROR_NOT_SUPPORTED;
178
179     return FIDO_ERROR_NONE;
180 }
181
182 static void
183 __plugin_changed_cb(GFileMonitor *monitor, GFile *file, GFile *other_file, GFileMonitorEvent event_type,
184                void* user_data)
185 {
186         char *plugin_path = NULL;
187     int ret = __load_plugins(&plugin_path);
188     _INFO("__load_plugins=[%d]", ret);
189
190         SAFE_DELETE(plugin_path);
191 }
192
193 static void
194 __set_up_watcher(const char *watch_path)
195 {
196     if ((watch_path == NULL)
197             || (strlen(watch_path) == 0))
198         return;
199
200     GFile* file = g_file_new_for_path(watch_path);
201
202     if (__monitor != NULL)
203         g_object_unref(__monitor);
204
205     __monitor = g_file_monitor(file, G_FILE_MONITOR_NONE, NULL, NULL);
206     g_object_unref(file);
207
208     if (__monitor == NULL)
209         return;
210
211     g_signal_connect(__monitor, "changed", G_CALLBACK(__plugin_changed_cb), NULL);
212 }
213
214 int
215 _asm_plugin_mgr_init(void)
216 {
217
218     _INFO("_asm_plugin_mgr_init start");
219
220         char *plugin_path = NULL;
221     int ret = __load_plugins(&plugin_path);
222     _INFO("__load_plugins=[%d]", ret);
223
224     __set_up_watcher(plugin_path);
225
226         SAFE_DELETE(plugin_path);
227
228     /*Ignored load_plugins error, since ASM might get installed later*/
229     return FIDO_ERROR_NONE;
230 }
231
232 void
233 _asm_plugin_mgr_destroy(void)
234 {
235     if (asm_proxy_table != NULL) {
236         g_hash_table_destroy(asm_proxy_table);
237         asm_proxy_table = NULL;
238     }
239     if (__monitor != NULL)
240         g_object_unref(__monitor);
241 }
242
243 static void
244 __discover_cb_internal(int error_code, const char *asm_response_json, void *user_data)
245 {
246     _asm_ipc_discover_cb_data_t *cb_data = user_data;
247
248     _asm_discover_response_t *response_info = calloc(1, sizeof(_asm_discover_response_t));
249     response_info->error_code = error_code;
250     if (asm_response_json != NULL)
251         response_info->asm_response_json = strdup(asm_response_json);
252
253     _fido_asm_proxy_t *asm_proxy = (_fido_asm_proxy_t*)(cb_data->asm_proxy_list_iter->data);
254     response_info->asm_id = strdup(asm_proxy->asm_id);
255
256     cb_data->asm_resp_list = g_list_append(cb_data->asm_resp_list, response_info);
257
258     cb_data->asm_proxy_list_iter = g_list_next(cb_data->asm_proxy_list_iter);
259     if (cb_data->asm_proxy_list_iter == NULL) {
260         _INFO("All ASM processing finished");
261
262         cb_data->asm_resp_list = g_list_first(cb_data->asm_resp_list);
263         (cb_data->cb)(cb_data->asm_resp_list, cb_data->user_data);
264
265         cb_data->asm_proxy_list_iter = g_list_first(cb_data->asm_proxy_list_iter);
266         g_list_free(cb_data->asm_proxy_list_iter);
267
268         SAFE_DELETE(cb_data);
269     }
270     else {
271
272         _fido_asm_proxy_t *asm_proxy = (_fido_asm_proxy_t*)(cb_data->asm_proxy_list_iter->data);
273         int ret = _asm_ipc_send(asm_proxy->asm_id, _GET_INFO_ASM_REQUEST_JSON, __discover_cb_internal, cb_data);
274         if (ret != FIDO_ERROR_NONE)
275             __discover_cb_internal(ret, NULL, user_data);
276     }
277
278 }
279
280 int
281 _asm_plugin_mgr_discover_all(_asm_plugin_discover_response_cb cb, void *user_data)
282 {
283     if (asm_proxy_table == NULL
284             || g_hash_table_size(asm_proxy_table) <= 0) {
285         _ERR("No ASM found");
286         return FIDO_ERROR_NOT_SUPPORTED;
287     }
288
289     _asm_ipc_discover_cb_data_t *cb_data = calloc(1, sizeof(_asm_ipc_discover_cb_data_t));
290     if (cb_data == NULL)
291         return -1;
292
293     cb_data->cb = cb;
294     cb_data->asm_proxy_list_iter = g_hash_table_get_values(asm_proxy_table);
295
296     cb_data->user_data = user_data;
297
298     _fido_asm_proxy_t *asm_proxy = (_fido_asm_proxy_t*)(cb_data->asm_proxy_list_iter->data);
299
300     return _asm_ipc_send(asm_proxy->asm_id, _GET_INFO_ASM_REQUEST_JSON, __discover_cb_internal, cb_data);
301 }
302
303 static void
304 _on_asm_dbus_reply(GObject *proxy, GAsyncResult *res, gpointer user_data)
305 {
306     _INFO("_on_asm_dbus_reply");
307
308     GError *dbus_err = NULL;
309
310     if (user_data == NULL) {
311         _ERR("Can not proceed since callback data is NULL");
312         return;
313     }
314
315     _asm_ipc_cb_data_t *cb_data = (_asm_ipc_cb_data_t *)user_data;
316     if (cb_data == NULL) {
317         _ERR("Can not proceed since callback data is NULL");
318         return;
319     }
320
321     if (cb_data->cb == NULL) {
322         _ERR("Can not proceed since callback data's cb part is NULL");
323         return;
324     }
325
326     int tizen_err = FIDO_ERROR_NONE;
327     char *asm_response_json = NULL;
328
329     GError *error = NULL;
330
331     /*For dereg request, ASM does not send any reponse, so this is not error for dereg*/
332     GVariant *dbus_resp = g_dbus_proxy_call_finish(G_DBUS_PROXY(proxy), res, &error);
333     if (dbus_resp == NULL) {
334         _ERR("g_dbus_proxy_call_finish failed  with [%d][%s]", error->code, error->message);
335         (cb_data->cb)(FIDO_ERROR_PERMISSION_DENIED, NULL, cb_data->user_data);
336
337         SAFE_DELETE(cb_data);
338
339         return;
340     }
341
342     g_variant_get(dbus_resp, "(is)",
343                    &tizen_err,
344                    &asm_response_json);
345
346
347     g_clear_error(&dbus_err);
348
349     if (asm_response_json != NULL)
350         _INFO("asm_response_json=[%s]", asm_response_json);
351
352     (cb_data->cb)(tizen_err, asm_response_json, cb_data->user_data);
353
354     if (dbus_resp != NULL)
355         g_variant_unref(dbus_resp);
356
357     SAFE_DELETE(cb_data);
358 }
359
360 static char*
361 __get_asm_req_dbus_method_name(const char *intf_name, const char *dbus_method_name)
362 {
363     char *method_name = (char *)calloc(1, 128);
364     if (method_name == NULL)
365         return NULL;
366
367     snprintf(method_name, 127, "%s.%s", intf_name, dbus_method_name);
368
369     return method_name;
370 }
371
372 int
373 _asm_ipc_send(const char *asm_id, const char *asm_request, _asm_ipc_response_cb cb, void *user_data)
374 {
375     _INFO("asm_request=[%s]", asm_request);
376
377     if (asm_id == NULL) {
378         _ERR("dbus proxy failed");
379         return FIDO_ERROR_NOT_SUPPORTED;
380     }
381
382     _fido_asm_proxy_t *asm_proxy = g_hash_table_lookup(asm_proxy_table, asm_id);
383     if (asm_proxy == NULL) {
384         _ERR("dbus proxy failed");
385         return FIDO_ERROR_NOT_SUPPORTED;
386     }
387
388     _INFO("For=[%s]", asm_id);
389
390     if (asm_proxy->dbus_info != NULL)
391         _INFO("For DBUS = [%s]", asm_proxy->dbus_info);
392
393     _asm_ipc_cb_data_t *cb_data = (_asm_ipc_cb_data_t*)calloc(1, sizeof(_asm_ipc_cb_data_t));
394     if (cb_data == NULL)
395         return -1;
396
397     cb_data->cb = cb;
398     cb_data->user_data = user_data;
399
400     char *method_name = __get_asm_req_dbus_method_name(asm_proxy->dbus_interface_name,
401                                                        asm_proxy->dbus_method_name);
402     if (method_name == NULL) {
403
404         SAFE_DELETE(cb_data);
405         return FIDO_ERROR_OUT_OF_MEMORY;
406     }
407
408     g_dbus_proxy_call(asm_proxy->dbus_proxy,
409                         method_name,
410                         g_variant_new ("(s)",
411                         asm_request),
412                         G_DBUS_CALL_FLAGS_NONE,
413                         _DBUS_TIMEOUT_INFINITE,
414                         NULL,
415                         _on_asm_dbus_reply,
416                         cb_data);
417
418     SAFE_DELETE(method_name);
419
420     return 0;
421 }
422
423 char *
424 _asm_ipc_send_sync(const char *asm_id, const char *asm_req)
425 {
426     _INFO("_asm_ipc_send_sync");
427
428     if (asm_id == NULL) {
429         _ERR("dbus proxy failed");
430         return NULL;
431     }
432
433     _INFO("For=[%s]", asm_id);
434
435     _fido_asm_proxy_t *asm_proxy = g_hash_table_lookup(asm_proxy_table, asm_id);
436     if (asm_proxy == NULL) {
437         _ERR("dbus proxy failed");
438         return NULL;
439     }
440
441     if (asm_proxy->dbus_info != NULL)
442         _INFO("For DBUS = [%s]", asm_proxy->dbus_info);
443
444     int tz_err = FIDO_ERROR_NONE;
445     char *asm_res_json = NULL;
446
447     GError *error = NULL;
448     GVariant *_ret;
449
450     char *method_name = __get_asm_req_dbus_method_name(asm_proxy->dbus_interface_name,
451                                                        asm_proxy->dbus_method_name);
452
453     if (method_name == NULL)
454         return NULL;
455
456     _ret = g_dbus_proxy_call_sync(asm_proxy->dbus_proxy,
457                                   method_name,
458                                   g_variant_new ("(s)",
459                                   asm_req),
460                                   G_DBUS_CALL_FLAGS_NONE,
461                                   _DBUS_TIMEOUT_USE_DEFAULT,
462                                   NULL,
463                                   &error);
464
465     if (error != NULL)
466         _ERR("g_dbus_proxy_call_sync failed [%s]", error->message);
467     else
468         _INFO("g_dbus_proxy_call_sync success");
469
470     if (_ret == NULL)
471       goto CATCH;
472
473     g_variant_get (_ret, "(is)", &tz_err, &asm_res_json);
474     if (asm_res_json != NULL)
475         _INFO("ASM returned = %s", asm_res_json);
476
477     //g_variant_unref (_ret);
478
479 CATCH:
480     return asm_res_json;
481 }