Vasum wrapper #3, fixes, API update
[platform/core/security/vasum.git] / client / vasum-wrapper.cpp
1 /*
2  *  Copyright (c) 2014 Samsung Electronics Co., Ltd All Rights Reserved
3  *
4  *  Contact: Krzysztof Dynowski <k.dynowski@samsung.com>
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 /**
21  * @file
22  * @author  Krzysztof Dynowski (k.dynowski@samsung.com)
23  * @brief   Vasum old API wrapper to slp client lib
24  */
25
26 #define __VASUM_WRAPPER_SOURCE__
27 #include <vector>
28 #include <string.h>
29 #include <algorithm>
30
31 #include "config.hpp"
32 #include "logger/logger.hpp"
33 #include "logger/backend-journal.hpp"
34
35 #include "wrapper-compat.h"
36 #include "vasum-client-impl.hpp"
37
38 #define MAX_EPOLL_EVENTS 16
39
40 struct WrappedZone
41 {
42     Client *client;
43     VsmZone zone;
44     struct vsm_zone vz;
45     std::vector<vsm_netdev> netdevs;
46 };
47
48 struct WrappedContext
49 {
50     Client *client;
51     vsm_context hq_ctx;
52     struct vsm_zone hq_root;
53     std::vector<WrappedZone> zones;
54 };
55
56 static struct
57 {
58     int done;
59     int glib_stop;
60 }wrap;
61
62 #ifndef offsetof
63 #define offsetof(type, memb) ((size_t)&((type *)0)->memb)
64 #endif
65 #ifdef container_of
66 #undef container_of
67 #endif
68 #ifndef container_of
69 #define container_of(ptr, type, memb) (\
70     (type *)((char *)(ptr) - offsetof(type, memb)))
71 #endif
72
73 #define UNUSED(x) ((void)(x))
74
75 #define vsm_error_t vsm_error_s
76 #define vsm_attach_command_t vsm_attach_command_s
77 #define vsm_attach_options_t vsm_attach_options_s
78 #define vsm_zone_state_cb vsm_zone_state_changed_cb
79
80 void __attribute__ ((constructor)) wrapper_load(void);
81 void __attribute__ ((destructor)) wrapper_unload(void);
82 static void init_wrapper();
83 extern struct vasum_ops dummy_ops;
84
85 using namespace logger;
86 void wrapper_load(void)
87 {
88     Logger::setLogLevel(LogLevel::TRACE);
89     Logger::setLogBackend(new SystemdJournalBackend());
90     init_wrapper();
91 }
92
93 void wrapper_unload(void)
94 {
95     if (wrap.glib_stop) Client::vsm_stop_glib_loop();
96     wrap.glib_stop = 0;
97 }
98
99 static void callcheck()
100 {
101     init_wrapper();
102 }
103
104 void init_wrapper()
105 {
106     if (wrap.done) return ;
107     memset(&wrap,0,sizeof(wrap));
108     wrap.done = 1;
109     LOGS("");
110 }
111
112 static struct vsm_zone* wrap_vsm_zone(WrappedContext *w, VsmZone zone, bool create = false)
113 {
114     if (zone == NULL) {
115         return NULL;
116     }
117     for (auto& zw : w->zones) {
118         if (zw.zone == zone) {
119             return &zw.vz;
120         }
121     }
122     if (create) {
123         w->zones.push_back(WrappedZone());
124         WrappedZone& zw = w->zones.back();
125         zw.client = w->client;
126         zw.zone = zone;
127         zw.vz.name = zone->id;
128         zw.vz.type = NULL;
129         zw.vz.user_data = NULL;
130         zw.vz.rootfs_path = zone->rootfs_path;
131         zw.vz.parent = &zw.vz;
132         LOGI("return (create) zone " << zone->id);
133         return &w->zones.back().vz;
134     }
135     LOGE("return zone NULL");
136     return NULL;
137 }
138
139 static int wrap_error(VsmStatus st, const Client *c)
140 {
141     if (st == VSMCLIENT_SUCCESS) LOGI("return success " << st);
142     else LOGE("return error " << st << "m=" << (c ? c->vsm_get_status_message() : "n/a"));
143     switch (st) {
144         case VSMCLIENT_SUCCESS: return VSM_ERROR_NONE;
145         case VSMCLIENT_CUSTOM_ERROR: return -VSM_ERROR_GENERIC;
146         case VSMCLIENT_IO_ERROR: return -VSM_ERROR_IO;
147         case VSMCLIENT_OPERATION_FAILED: return -VSM_ERROR_NOT_PERMITTED;
148         case VSMCLIENT_INVALID_ARGUMENT: return -VSM_ERROR_INVALID;
149         case VSMCLIENT_OTHER_ERROR: return -VSM_ERROR_GENERIC;
150     }
151     return -VSM_ERROR_GENERIC;
152 }
153
154 static void init_context_wrap(WrappedContext *w)
155 {
156     Client::vsm_start_glib_loop();
157     wrap.glib_stop = 1;
158     w->client = new Client();
159     VsmStatus st = w->client->createSystem();
160     wrap_error(st, w->client);
161
162     memset(&w->hq_ctx, 0, sizeof(w->hq_ctx));
163     memset(&w->hq_root, 0, sizeof(w->hq_root));
164
165     vsm_context *ctx = &w->hq_ctx;
166     adt_init_list(&ctx->listeners);
167     //init root_zone
168     ctx->root_zone = &w->hq_root;
169     ctx->root_zone->name = (char*)"";
170     ctx->root_zone->id=0;
171     ctx->root_zone->rootfs_path = (char*)"/";
172
173     ctx->root_zone->terminal = -1;
174     ctx->root_zone->state = VSM_ZONE_STATE_RUNNING;
175     ctx->root_zone->user_data = ctx->root_zone;
176
177     ctx->root_zone->parent = ctx->root_zone;
178     ctx->root_zone->ctx = ctx;
179
180     pthread_rwlock_init(&ctx->root_zone->lock, NULL);
181     adt_init_list(&ctx->root_zone->netdevs);
182     adt_init_list(&ctx->root_zone->devices);
183     adt_init_list(&ctx->root_zone->children);
184
185     pthread_rwlock_init(&ctx->lock, NULL);
186     adt_init_list(&ctx->listeners);
187     adt_init_list(&ctx->sc_listeners);
188     adt_init_list(&ctx->ev_listeners);
189
190     //struct mainloop *mainloop = mainloop_create();
191     //struct mxe_engine *engine = mxe_prepare_engine(mainloop, ctx);
192     //struct mxe_endpoint *ep = mxe_create_client(engine, SERVICEPATH);
193
194     ctx->foreground_zone = ctx->root_zone;
195     ctx->vsm_ops = &dummy_ops;
196     ctx->error = VSM_ERROR_NONE;
197     //ctx->data = ep;
198 }
199
200 API vsm_context_h vsm_create_context(void)
201 {
202     LOGS(""); callcheck();
203     WrappedContext *w = new WrappedContext();
204     init_context_wrap(w);
205
206     vsm_context *ctx = &w->hq_ctx;
207     return ctx;
208 }
209
210 API int vsm_cleanup_context(vsm_context_h ctx)
211 {
212     LOGS(""); callcheck();
213     WrappedContext *w = container_of(ctx, WrappedContext, hq_ctx);
214     if (w->client != NULL) {
215         delete w->client;
216         w->client = NULL;
217     }
218     for (auto& zw : w->zones) {
219         zw.netdevs.clear();
220     }
221     w->zones.clear();
222     delete w;
223     return VSM_ERROR_NONE;
224 }
225
226 static const char *const vsm_error_strtab[] = {
227     "No error",
228     "Undefined error",
229     "Invalid",
230     "Operation cancelled",
231     "Operation aborted",
232     "Connection refused",
233     "Object exists",
234     "Resource busy",
235     "Input/Output error",
236     "Timeout",
237     "Overflow",
238     "Out of memory",
239     "Out of range",
240     "Operation not permitted",
241     "Function not implemented",
242     "Operation not supported",
243     "Access denied",
244     "No object found",
245     "Bad state"
246 };
247
248 API vsm_error_e vsm_last_error(struct vsm_context *ctx)
249 {
250     if (ctx)
251         return ctx->error;
252     return static_cast<vsm_error_e>(-1);
253 }
254
255 API const char *vsm_error_string(vsm_error_e error)
256 {
257     LOGS(""); callcheck();
258     if (error < 0 || error > VSM_MAX_ERROR) {
259         return NULL;
260     }
261     return vsm_error_strtab[error];
262 }
263
264 API int vsm_get_poll_fd(struct vsm_context *ctx)
265 {
266     LOGS(""); callcheck();
267     WrappedContext *w = container_of(ctx, WrappedContext, hq_ctx);
268     UNUSED(w);
269     //FIXME Client should create Dispatcher and pass to IPCConnection
270     //      now: IPCConnection has field ThreadWrapper
271     //return w->client->getEventPoll().getPollFD();
272     return -1;
273 }
274 API int vsm_enter_eventloop(struct vsm_context *ctx, int flags, int timeout)
275 {
276     LOGS(""); callcheck();
277     UNUSED(flags);
278     UNUSED(timeout);
279     WrappedContext *w = container_of(ctx, WrappedContext, hq_ctx);
280     UNUSED(w);
281     //FIXME Client should create Dispatcher and pass to IPCConnection
282     //      now: IPCConnection has field ThreadWrapper
283     //TODO Use EventPoll from Dispatcher
284     return 0;
285 }
286
287 API int vsm_create_zone(struct vsm_context *ctx, const char *zone_name, const char *template_name, int flag)
288 {
289     LOGS("create_zone " << zone_name); callcheck();
290     WrappedContext *w = container_of(ctx, WrappedContext, hq_ctx);
291     UNUSED(flag);
292     //template_name = NULL; //template name not supported by libvasum-client
293     if (!w->client) return VSM_ERROR_GENERIC;
294     VsmStatus st = w->client->vsm_create_zone(zone_name, template_name);
295     if (st != VSMCLIENT_SUCCESS) {
296         LOGE("vsm_create_zone(" << zone_name << ") = " << st);
297     }
298     return wrap_error(st, w->client);
299 }
300
301 API int vsm_destroy_zone(struct vsm_context *ctx, const char *zone_name, int force)
302 {
303     LOGS("zone=" << zone_name); callcheck();
304     WrappedContext *w = container_of(ctx, WrappedContext, hq_ctx);
305     UNUSED(force);
306     if (!w->client) return VSM_ERROR_GENERIC;
307     VsmStatus st = w->client->vsm_destroy_zone(zone_name);
308     if (st == VSMCLIENT_SUCCESS) {
309         auto zonebyname = [zone_name](const WrappedZone& v) {return v.zone->id == zone_name;};
310         auto zonelist = std::remove_if(w->zones.begin(), w->zones.end(), zonebyname);
311         w->zones.erase(zonelist);
312     }
313     return wrap_error(st, w->client);
314 }
315
316 API int vsm_start_zone(struct vsm_context *ctx, const char *zone_name)
317 {
318     LOGS("zone=" << zone_name); callcheck();
319     WrappedContext *w = container_of(ctx, WrappedContext, hq_ctx);
320     if (!w->client) return VSM_ERROR_GENERIC;
321     VsmStatus st = w->client->vsm_start_zone(zone_name);
322     return wrap_error(st, w->client);
323 }
324
325 API int vsm_shutdown_zone(struct vsm_context *ctx, const char *zone_name, int force)
326 {
327     LOGS("zone=" << zone_name); callcheck();
328     WrappedContext *w = container_of(ctx, WrappedContext, hq_ctx);
329     UNUSED(force);
330     if (!w->client) return VSM_ERROR_GENERIC;
331     VsmStatus st = w->client->vsm_shutdown_zone(zone_name);
332     return wrap_error(st, w->client);
333 }
334
335 API int vsm_lock_zone(struct vsm_context *ctx, const char *zone_name, int shutdown)
336 {
337     LOGS("zone=" << zone_name); callcheck();
338     WrappedContext *w = container_of(ctx, WrappedContext, hq_ctx);
339     UNUSED(shutdown);
340     if (!w->client) return VSM_ERROR_GENERIC;
341     VsmStatus st = w->client->vsm_lock_zone(zone_name);
342     return wrap_error(st, w->client);
343 }
344
345 API int vsm_unlock_zone(struct vsm_context *ctx, const char *zone_name)
346 {
347     LOGS("zone=" << zone_name); callcheck();
348     WrappedContext *w = container_of(ctx, WrappedContext, hq_ctx);
349     if (!w->client) return VSM_ERROR_GENERIC;
350     VsmStatus st = w->client->vsm_lock_zone(zone_name);
351     return wrap_error(st, w->client);
352 }
353
354 API int vsm_set_foreground(struct vsm_zone *zone)
355 {
356     LOGS(""); callcheck();
357     WrappedZone *w = container_of(zone, WrappedZone, vz);
358     if (!w->client) return VSM_ERROR_GENERIC;
359     VsmStatus st = w->client->vsm_set_active_zone(zone->name);
360     return wrap_error(st, w->client);
361 }
362
363 //execute command in specified zone
364 API int vsm_attach_zone(struct vsm_context *ctx,
365                         const char *zone_name,
366                         vsm_attach_command_t *command,
367                         vsm_attach_options_t *opts,
368                         pid_t *attached_process)
369 {
370     return dummy_ops.attach_zone(ctx, zone_name, command, opts,
371                      attached_process);
372 }
373
374 //execute command in specified zone and wait
375 API int vsm_attach_zone_wait(struct vsm_context *ctx,
376                              const char *zone_name,
377                              vsm_attach_command_t *command,
378                              vsm_attach_options_t *opts)
379 {
380     return dummy_ops.attach_zone_wait(ctx, zone_name, command, opts);
381 }
382
383 API int vsm_iterate_zone(struct vsm_context *ctx, void (*callback)(struct vsm_zone *zone, void *user_data), void *user_data)
384 {
385     LOGS(""); callcheck();
386     WrappedContext *w = container_of(ctx, WrappedContext, hq_ctx);
387     if (!w->client) return -VSM_ERROR_GENERIC;
388     callback(ctx->root_zone, user_data);
389     for (auto& z : w->zones) {
390         callback(&z.vz, user_data);
391     }
392     return 0;
393 }
394
395 API struct vsm_zone *vsm_lookup_zone_by_name(struct vsm_context *ctx, const char *path)
396 {
397     LOGS("name=" << path); callcheck();
398     WrappedContext *w = container_of(ctx, WrappedContext, hq_ctx);
399     VsmZone zone;
400     if (!w->client) return NULL;
401     //CHECK if path is same as zone_name
402     if (w->client->vsm_lookup_zone_by_id(path, &zone) != VSMCLIENT_SUCCESS)
403         return NULL;
404     return wrap_vsm_zone(w, zone, true);
405 }
406
407 API struct vsm_zone *vsm_lookup_zone_by_pid(struct vsm_context *ctx, pid_t pid)
408 {
409     LOGS("pid=" << pid); callcheck();
410     WrappedContext *w = container_of(ctx, WrappedContext, hq_ctx);
411     VsmZone zone;
412     VsmString id;
413     if (!w->client) return NULL;
414     if (w->client->vsm_lookup_zone_by_pid(pid, &id) != VSMCLIENT_SUCCESS) {
415         LOGE("vsm_lookup_zone_by_pid(" << pid << ") error");
416         return NULL;
417     }
418     if (::strcmp(id, "host") == 0) {
419         return w->hq_ctx.root_zone;
420     }
421     w->client->vsm_lookup_zone_by_id(id, &zone); //zone is malloced
422     return wrap_vsm_zone(w, zone);
423 }
424
425 API struct vsm_zone *vsm_lookup_zone_by_terminal_id(struct vsm_context *ctx, int terminal)
426 {
427     LOGS("terminal=" << terminal); callcheck();
428     WrappedContext *w = container_of(ctx, WrappedContext, hq_ctx);
429     VsmZone zone;
430     VsmString id;
431     if (!w->client) return NULL;
432     if (w->client->vsm_lookup_zone_by_terminal_id(terminal, &id) != VSMCLIENT_SUCCESS)
433         return NULL;
434     w->client->vsm_lookup_zone_by_id(id, &zone);
435     return wrap_vsm_zone(w, zone);
436 }
437 #if 0
438 API int vsm_add_state_changed_callback(struct vsm_context *ctx, vsm_zone_state_cb callback, void *user_data)
439 {
440     LOGS(""); callcheck();
441     WrappedContext *w = container_of(ctx, WrappedContext, hq_ctx);
442     VsmSubscriptionId subscriptionId;
443
444     auto dbus_cb = [=](const char* id, const char* dbusAddress, void* data) ->
445     void {
446         VsmZone zone;
447         //TODO what are valid state, event
448         UNUSED(dbusAddress);
449         w->client->vsm_lookup_zone_by_id(id, &zone);
450         callback(wrap_vsm_zone(w, zone), data);
451     };
452     w->client->vsm_add_state_callback(dbus_cb, user_data, &subscriptionId);
453     return (int)subscriptionId;
454 }
455
456 API int vsm_del_state_changed_callback(struct vsm_context *ctx, int handle)
457 {
458     LOGS(""); callcheck();
459     WrappedContext *w = container_of(ctx, WrappedContext, hq_ctx);
460     VsmSubscriptionId subscriptionId = (VsmSubscriptionId)handle;
461     VsmStatus st = w->client->vsm_del_state_callback(subscriptionId);
462     return wrap_error(st, w->client);
463 }
464 #endif
465 API int vsm_grant_device(struct vsm_zone *dom, const char *name, uint32_t flags)
466 {
467     LOGS(""); callcheck();
468     WrappedZone *w = container_of(dom, WrappedZone, vz);
469     const char *id = dom->name;
470     VsmZone zone;
471     w->client->vsm_lookup_zone_by_id(id, &zone);
472     VsmStatus st = w->client->vsm_grant_device(id, name, flags);
473     return wrap_error(st, w->client);
474 }
475
476 API int vsm_revoke_device(struct vsm_zone *dom, const char *name)
477 {
478     LOGS(""); callcheck();
479     WrappedZone *w = container_of(dom, WrappedZone, vz);
480     const char *id = dom->name;
481     VsmStatus st = w->client->vsm_revoke_device(id, name);
482     return wrap_error(st, w->client);
483 }
484
485 API struct vsm_netdev *vsm_create_netdev(struct vsm_zone *zone, vsm_netdev_type_t type, const char *target, const char *netdev)
486 {
487     LOGS(""); callcheck();
488     UNUSED(zone);
489     UNUSED(type);
490     UNUSED(target);
491     UNUSED(netdev);
492
493     WrappedZone *w = container_of(zone, WrappedZone, vz);
494     const char *id = zone->name;
495     VsmStatus st;
496     if (type == VSM_NETDEV_VETH)
497         st = w->client->vsm_create_netdev_veth(id, target, netdev);
498     else if (type == VSM_NETDEV_PHYS)
499         st = w->client->vsm_create_netdev_phys(id, netdev);
500     else if (type == VSM_NETDEV_MACVLAN) // macvlan_mode from if_link.h
501         st = w->client->vsm_create_netdev_macvlan(id, target, netdev, MACVLAN_MODE_BRIDGE);
502     else {
503         LOGE("Invalid arguments");
504         //ctx->error = VSM_ERROR_INVALID;
505         return NULL;
506     }
507
508     if (st != VSMCLIENT_SUCCESS) {
509         LOGE("vsm_create_netdev(" << netdev << ") = " << st);
510         return NULL;
511     }
512
513     vsm_netdev vnd;
514     vnd.zone = zone;
515     vnd.name = (char*)netdev; //FIXME? copy content of string
516     vnd.type = type;
517     w->netdevs.push_back(vnd); //copy pushed to vector
518     return &w->netdevs.back(); //pointer to struct on vector
519 }
520
521 API int vsm_destroy_netdev(struct vsm_zone *zone, struct vsm_netdev *netdev)
522 {
523     LOGS(""); callcheck();
524     WrappedZone *w = container_of(zone, WrappedZone, vz);
525
526     VsmStatus st = w->client->vsm_destroy_netdev(zone->name, netdev->name);
527     if (st == VSMCLIENT_SUCCESS) {
528         auto devbyname = [netdev](const vsm_netdev& v) {return ::strcmp(v.name, netdev->name) == 0;};
529         auto devlist = std::find_if(w->netdevs.begin(), w->netdevs.end(), devbyname);
530         if (devlist != w->netdevs.end()) {
531             w->netdevs.erase(devlist);
532         }
533     }
534     return wrap_error(st, w->client);
535 }
536
537 API int vsm_iterate_netdev(struct vsm_zone *zone, void (*callback)(struct vsm_netdev *, void *user_data), void *user_data)
538 {
539     LOGS(""); callcheck();
540     WrappedZone *w = container_of(zone, WrappedZone, vz);
541     for (auto nd : w->netdevs) {
542         callback(&nd, user_data);
543     }
544     return 0;
545 }
546
547 API struct vsm_netdev *vsm_lookup_netdev_by_name(struct vsm_zone *zone, const char *name)
548 {
549     LOGS(""); callcheck();
550     WrappedZone *w = container_of(zone, WrappedZone, vz);
551     VsmNetdev nd;
552     VsmStatus st = w->client->vsm_lookup_netdev_by_name(zone->name, name, &nd);
553     if (st == VSMCLIENT_SUCCESS) {
554         auto devbyname = [name](const vsm_netdev& v) {return ::strcmp(v.name, name) == 0;};
555         auto devlist = std::find_if(w->netdevs.begin(), w->netdevs.end(), devbyname);
556         if (devlist != w->netdevs.end()) {
557             return &devlist[0];
558         }
559     }
560     return NULL;
561 }
562
563 API int vsm_declare_file(struct vsm_context *ctx, vsm_fso_type_t ftype, const char *path, int flags, vsm_mode_t mode)
564 {
565     LOGS(""); callcheck();
566     UNUSED(ctx);
567     UNUSED(ftype);
568     UNUSED(path);
569     UNUSED(flags);
570     UNUSED(mode);
571     //TODO apply declare link for existing zones (and those created in the future, so must store paits source, target)
572     return VSM_ERROR_NONE;
573 }
574
575 API int vsm_declare_mount(struct vsm_context *ctx,
576                           const char *source,
577                           const char *target,
578                           const char *fstype,
579                           unsigned long flags,
580                           const void *data)
581 {
582     LOGS(""); callcheck();
583     UNUSED(ctx);
584     UNUSED(source);
585     UNUSED(target);
586     UNUSED(fstype);
587     UNUSED(flags);
588     UNUSED(data);
589     //TODO apply declare link for existing zones (and those created in the future, so must store paits source, target)
590     return VSM_ERROR_NONE;
591 }
592
593 API int vsm_declare_link(struct vsm_context *ctx, const char *source, const char *target)
594 {
595     LOGS("src=" << source << "dst=" << target); callcheck();
596     UNUSED(ctx);
597     UNUSED(source);
598     UNUSED(target);
599     //TODO apply declare link for existing zones (and those created in the future, so must store paits source, target)
600     return VSM_ERROR_NONE;
601 }
602
603 API int vsm_add_state_changed_callback(vsm_context_h  /*ctx*/, vsm_zone_state_changed_cb  /*callback*/, void * /*user_data*/)
604 {
605     return VSM_ERROR_NONE;
606 }
607 API int vsm_del_state_changed_callback(vsm_context_h  /*ctx*/, int  /*id*/)
608 {
609     return VSM_ERROR_NONE;
610 }
611 API const char * vsm_get_zone_rootpath(vsm_zone_h  /*zone*/)
612 {
613     return NULL;
614 }
615 API const char * vsm_get_zone_name(vsm_zone_h  /*zone*/)
616 {
617     return NULL;
618 }
619 API int vsm_is_host_zone(vsm_zone_h  /*zone*/)
620 {
621     return VSM_ERROR_NONE;
622 }
623 API vsm_zone_h vsm_join_zone(vsm_zone_h  /*zone*/)
624 {
625     return NULL;
626 }
627 API int vsm_canonicalize_path(const char * /*input_path*/, char ** /*output_path*/)
628 {
629     return VSM_ERROR_NONE;
630 }
631
632