afb-export: Fix heap corruption
[src/app-framework-binder.git] / src / afb-export.c
index b40dd07..a1112d2 100644 (file)
@@ -24,6 +24,9 @@
 #include <ctype.h>
 
 #include <json-c/json.h>
+#if !defined(JSON_C_TO_STRING_NOSLASHESCAPE)
+#define JSON_C_TO_STRING_NOSLASHESCAPE 0
+#endif
 
 #define AFB_BINDING_VERSION 0
 #include <afb/afb-binding.h>
 #include "afb-calls.h"
 #include "jobs.h"
 #include "verbose.h"
+#include "globset.h"
 #include "sig-monitor.h"
+#include "wrap-json.h"
 
 /*************************************************************************
  * internal types
  ************************************************************************/
 
-/*
- * structure for handling events
- */
-struct event_handler
-{
-       /* link to the next event handler of the list */
-       struct event_handler *next;
-
-       /* function to call on the case of the event */
-       void (*callback)(void *, const char*, struct json_object*, struct afb_api_x3*);
-
-       /* closure for the callback */
-       void *closure;
-
-       /* the handled pattern */
-       char pattern[1];
-};
-
 /*
  * Actually supported versions
  */
@@ -134,7 +121,16 @@ struct afb_export
        struct afb_evt_listener *listener;
 
        /* event handler list */
-       struct event_handler *event_handlers;
+       struct globset *event_handlers;
+
+       /* creator if any */
+       struct afb_export *creator;
+
+       /* path indication if any */
+       const char *path;
+
+       /* settings */
+       struct json_object *settings;
 
        /* internal descriptors */
        union {
@@ -167,7 +163,7 @@ struct afb_export
        } export;
 
        /* initial name */
-       char name[1];
+       char name[];
 };
 
 /*****************************************************************************/
@@ -192,6 +188,54 @@ struct afb_api_x3 *afb_export_to_api_x3(struct afb_export *export)
        return to_api_x3(export);
 }
 
+/******************************************************************************
+ ******************************************************************************
+ ******************************************************************************
+ ******************************************************************************
+       SETTINGS
+ ******************************************************************************
+ ******************************************************************************
+ ******************************************************************************
+ ******************************************************************************/
+
+static struct json_object *configuration;
+
+void afb_export_set_config(struct json_object *config)
+{
+       struct json_object *save = configuration;
+       configuration = json_object_get(config);
+       json_object_put(save);
+}
+
+static struct json_object *make_settings(struct afb_export *export)
+{
+       struct json_object *result;
+       struct json_object *obj;
+       struct afb_export *iter;
+       char *path;
+
+       /* clone the globals */
+       if (json_object_object_get_ex(configuration, "*", &obj))
+               result = wrap_json_clone(obj);
+       else
+               result = json_object_new_object();
+
+       /* add locals */
+       if (json_object_object_get_ex(configuration, export->name, &obj))
+               wrap_json_object_add(result, obj);
+
+       /* add library path */
+       for (iter = export ; iter && !iter->path ; iter = iter->creator);
+       if (iter) {
+               path = realpath(iter->path, NULL);
+               json_object_object_add(result, "binding-path", json_object_new_string(path));
+               free(path);
+       }
+
+       export->settings = result;
+       return result;
+}
+
 /******************************************************************************
  ******************************************************************************
  ******************************************************************************
@@ -213,7 +257,7 @@ static void vverbose_cb(struct afb_api_x3 *closure, int level, const char *file,
        if (!fmt || vasprintf(&p, fmt, args) < 0)
                vverbose(level, file, line, function, fmt, args);
        else {
-               verbose(level, file, line, function, "[API %s] %s", export->api.apiname, p);
+               verbose(level, file, line, function, (verbose_is_colorized() == 0 ? "[API %s] %s" : COLOR_API "[API %s]" COLOR_DEFAULT " %s"), export->api.apiname, p);
                free(p);
        }
 }
@@ -252,7 +296,8 @@ static int event_broadcast_cb(struct afb_api_x3 *closure, const char *name, stru
 
        /* check daemon state */
        if (export->state == Api_State_Pre_Init) {
-               ERROR("[API %s] Bad call to 'afb_daemon_event_broadcast(%s, %s)', must not be in PreInit", export->api.apiname, name, json_object_to_json_string(object));
+               ERROR("[API %s] Bad call to 'afb_daemon_event_broadcast(%s, %s)', must not be in PreInit",
+                       export->api.apiname, name, json_object_to_json_string_ext(object, JSON_C_TO_STRING_NOSLASHESCAPE));
                errno = EINVAL;
                return 0;
        }
@@ -290,6 +335,11 @@ static int require_api_cb(struct afb_api_x3 *closure, const char *name, int init
        int rc, rc2;
        char *iter, *end, save;
 
+       /* emit a warning about unexpected require in preinit */
+       if (export->state == Api_State_Pre_Init)
+               WARNING("[API %s] requiring apis in pre-init may lead to unexpected result (requires%s: %s)",
+                       export->api.apiname, initialized ? " initialized" : "", name);
+
        /* scan the names in a local copy */
        rc = 0;
        iter = strdupa(name);
@@ -342,7 +392,11 @@ static struct afb_api_x3 *api_new_api_cb(
                void *preinit_closure)
 {
        struct afb_export *export = from_api_x3(closure);
-       struct afb_api_v3 *apiv3 = afb_api_v3_create(export->declare_set, export->call_set, api, info, noconcurrency, preinit, preinit_closure, 1);
+       struct afb_api_v3 *apiv3 = afb_api_v3_create(
+                                       export->declare_set, export->call_set,
+                                       api, info, noconcurrency,
+                                       preinit, preinit_closure, 1,
+                                       export, NULL);
        return apiv3 ? to_api_x3(afb_api_v3_export(apiv3)) : NULL;
 }
 
@@ -863,6 +917,15 @@ static int delete_api_cb(struct afb_api_x3 *api)
        return 0;
 }
 
+static struct json_object *settings_cb(struct afb_api_x3 *api)
+{
+       struct afb_export *export = from_api_x3(api);
+       struct json_object *result = export->settings;
+       if (!result)
+               result = make_settings(export);
+       return result;
+}
+
 static int hooked_api_set_verbs_v2_cb(
                struct afb_api_x3 *api,
                const struct afb_verb_v2 *verbs)
@@ -976,6 +1039,14 @@ static int hooked_delete_api_cb(struct afb_api_x3 *api)
        return result;
 }
 
+static struct json_object *hooked_settings_cb(struct afb_api_x3 *api)
+{
+       struct afb_export *export = from_api_x3(api);
+       struct json_object *result = settings_cb(api);
+       result = afb_hook_api_settings(export, result);
+       return result;
+}
+
 static const struct afb_api_x3_itf api_x3_itf = {
 
        .vverbose = (void*)vverbose_cb,
@@ -1014,6 +1085,7 @@ static const struct afb_api_x3_itf api_x3_itf = {
        .class_require = class_require_cb,
 
        .delete_api = delete_api_cb,
+       .settings = settings_cb,
 };
 
 static const struct afb_api_x3_itf hooked_api_x3_itf = {
@@ -1054,6 +1126,7 @@ static const struct afb_api_x3_itf hooked_api_x3_itf = {
        .class_require = hooked_class_require_cb,
 
        .delete_api = hooked_delete_api_cb,
+       .settings = hooked_settings_cb,
 };
 
 /******************************************************************************
@@ -1071,7 +1144,8 @@ static const struct afb_api_x3_itf hooked_api_x3_itf = {
  */
 static void listener_of_events(void *closure, const char *event, int eventid, struct json_object *object)
 {
-       struct event_handler *handler;
+       const struct globset_handler *handler;
+       void (*callback)(void *, const char*, struct json_object*, struct afb_api_x3*);
        struct afb_export *export = from_api_x3(closure);
 
        /* hook the event before */
@@ -1080,26 +1154,24 @@ static void listener_of_events(void *closure, const char *event, int eventid, st
 
        /* transmit to specific handlers */
        /* search the handler */
-       handler = export->event_handlers;
-       while (handler) {
-               if (fnmatch(handler->pattern, event, 0)) {
-                       if (!(export->hooksvc & afb_hook_flag_api_on_event_handler))
-                               handler->callback(handler->closure, event, object, to_api_x3(export));
-                       else {
-                               afb_hook_api_on_event_handler_before(export, event, eventid, object, handler->pattern);
-                               handler->callback(handler->closure, event, object, to_api_x3(export));
-                               afb_hook_api_on_event_handler_after(export, event, eventid, object, handler->pattern);
-                       }
+       handler = export->event_handlers ? globset_match(export->event_handlers, event) : NULL;
+       if (handler) {
+               callback = handler->callback;
+               if (!(export->hooksvc & afb_hook_flag_api_on_event_handler))
+                       callback(handler->closure, event, object, to_api_x3(export));
+               else {
+                       afb_hook_api_on_event_handler_before(export, event, eventid, object, handler->pattern);
+                       callback(handler->closure, event, object, to_api_x3(export));
+                       afb_hook_api_on_event_handler_after(export, event, eventid, object, handler->pattern);
                }
-               handler = handler->next;
+       } else {
+               /* transmit to default handler */
+               if (export->on_any_event_v3)
+                       export->on_any_event_v3(to_api_x3(export), event, object);
+               else if (export->on_any_event_v12)
+                       export->on_any_event_v12(event, object);
        }
 
-       /* transmit to default handler */
-       if (export->on_any_event_v3)
-               export->on_any_event_v3(to_api_x3(export), event, object);
-       else if (export->on_any_event_v12)
-               export->on_any_event_v12(event, object);
-
        /* hook the event after */
        if (export->hooksvc & afb_hook_flag_api_on_event)
                afb_hook_api_on_event_after(export, event, eventid, object);
@@ -1130,40 +1202,32 @@ int afb_export_event_handler_add(
                        void *closure)
 {
        int rc;
-       struct event_handler *handler, **previous;
 
+       /* ensure the listener */
        rc = ensure_listener(export);
        if (rc < 0)
                return rc;
 
-       /* search the handler */
-       previous = &export->event_handlers;
-       while ((handler = *previous) && strcasecmp(handler->pattern, pattern))
-               previous = &handler->next;
-
-       /* error if found */
-       if (handler) {
-               ERROR("[API %s] event handler %s already exists", export->api.apiname, pattern);
-               errno = EEXIST;
-               return -1;
+       /* ensure the globset for event handling */
+       if (!export->event_handlers) {
+               export->event_handlers = globset_create();
+               if (!export->event_handlers)
+                       goto oom_error;
        }
 
-       /* create the event */
-       handler = malloc(strlen(pattern) + sizeof * handler);
-       if (!handler) {
-               ERROR("[API %s] can't allocate event handler %s", export->api.apiname, pattern);
-               errno = ENOMEM;
+       /* add the handler */
+       rc = globset_add(export->event_handlers, pattern, callback, closure);
+       if (rc == 0)
+               return 0;
+
+       if (errno == EEXIST) {
+               ERROR("[API %s] event handler %s already exists", export->api.apiname, pattern);
                return -1;
        }
 
-       /* init and record */
-       handler->next = NULL;
-       handler->callback = callback;
-       handler->closure = closure;
-       strcpy(handler->pattern, pattern);
-       *previous = handler;
-
-       return 0;
+oom_error:
+       ERROR("[API %s] can't allocate event handler %s", export->api.apiname, pattern);
+       return -1;
 }
 
 int afb_export_event_handler_del(
@@ -1171,27 +1235,13 @@ int afb_export_event_handler_del(
                        const char *pattern,
                        void **closure)
 {
-       struct event_handler *handler, **previous;
-
-       /* search the handler */
-       previous = &export->event_handlers;
-       while ((handler = *previous) && strcasecmp(handler->pattern, pattern))
-               previous = &handler->next;
-
-       /* error if found */
-       if (!handler) {
-               ERROR("[API %s] event handler %s already exists", export->api.apiname, pattern);
-               errno = ENOENT;
-               return -1;
-       }
-
-       /* remove the found event */
-       if (closure)
-               *closure = handler->closure;
+       if (export->event_handlers
+       && !globset_del(export->event_handlers, pattern, closure))
+               return 0;
 
-       *previous = handler->next;
-       free(handler);
-       return 0;
+       ERROR("[API %s] event handler %s not found", export->api.apiname, pattern);
+       errno = ENOENT;
+       return -1;
 }
 
 /******************************************************************************
@@ -1208,9 +1258,11 @@ static struct afb_export *create(
                                struct afb_apiset *declare_set,
                                struct afb_apiset *call_set,
                                const char *apiname,
+                               const char *path,
                                enum afb_api_version version)
 {
        struct afb_export *export;
+       size_t lenapi;
 
        /* session shared with other exports */
        if (common_session == NULL) {
@@ -1218,13 +1270,18 @@ static struct afb_export *create(
                if (common_session == NULL)
                        return NULL;
        }
-       export = calloc(1, sizeof *export + strlen(apiname));
+       lenapi = strlen(apiname);
+       export = calloc(1, sizeof *export + 1 + lenapi + (path == apiname || !path ? 0 : 1 + strlen(path)));
        if (!export)
                errno = ENOMEM;
        else {
                export->refcount = 1;
                strcpy(export->name, apiname);
                export->api.apiname = export->name;
+               if (path == apiname)
+                       export->path = export->name;
+               else if (path)
+                       export->path = strcpy(&export->name[lenapi + 1], path);
                export->version = version;
                export->state = Api_State_Pre_Init;
                export->session = afb_session_addref(common_session);
@@ -1249,18 +1306,16 @@ void afb_export_unref(struct afb_export *export)
 
 void afb_export_destroy(struct afb_export *export)
 {
-       struct event_handler *handler;
-
        if (export) {
-               while ((handler = export->event_handlers)) {
-                       export->event_handlers = handler->next;
-                       free(handler);
-               }
+               if (export->event_handlers)
+                       globset_destroy(export->event_handlers);
                if (export->listener != NULL)
                        afb_evt_listener_unref(export->listener);
                afb_session_unref(export->session);
                afb_apiset_unref(export->declare_set);
                afb_apiset_unref(export->call_set);
+               json_object_put(export->settings);
+               afb_export_unref(export->creator);
                if (export->api.apiname != export->name)
                        free((void*)export->api.apiname);
                free(export);
@@ -1274,7 +1329,7 @@ struct afb_export *afb_export_create_none_for_path(
                        int (*creator)(void*, struct afb_api_x3*),
                        void *closure)
 {
-       struct afb_export *export = create(declare_set, call_set, path, Api_Version_None);
+       struct afb_export *export = create(declare_set, call_set, path, path, Api_Version_None);
        if (export) {
                afb_export_logmask_set(export, logmask);
                afb_export_update_hooks(export);
@@ -1287,14 +1342,14 @@ struct afb_export *afb_export_create_none_for_path(
 }
 
 #if defined(WITH_LEGACY_BINDING_V1)
-struct afb_export *afb_export_create_v1(
-                       struct afb_apiset *declare_set,
+struct afb_export *afb_export_create_v1(struct afb_apiset *declare_set,
                        struct afb_apiset *call_set,
                        const char *apiname,
                        int (*init)(struct afb_service_x1),
-                       void (*onevent)(const char*, struct json_object*))
+                       void (*onevent)(const char*, struct json_object*),
+                       const char* path)
 {
-       struct afb_export *export = create(declare_set, call_set, apiname, Api_Version_1);
+       struct afb_export *export = create(declare_set, call_set, apiname, path, Api_Version_1);
        if (export) {
                export->init.v1 = init;
                export->on_any_event_v12 = onevent;
@@ -1307,16 +1362,16 @@ struct afb_export *afb_export_create_v1(
 }
 #endif
 
-struct afb_export *afb_export_create_v2(
-                       struct afb_apiset *declare_set,
+struct afb_export *afb_export_create_v2(struct afb_apiset *declare_set,
                        struct afb_apiset *call_set,
                        const char *apiname,
                        const struct afb_binding_v2 *binding,
                        struct afb_binding_data_v2 *data,
                        int (*init)(),
-                       void (*onevent)(const char*, struct json_object*))
+                       void (*onevent)(const char*, struct json_object*),
+                       const char* path)
 {
-       struct afb_export *export = create(declare_set, call_set, apiname, Api_Version_2);
+       struct afb_export *export = create(declare_set, call_set, apiname, path, Api_Version_2);
        if (export) {
                export->init.v2 = init;
                export->on_any_event_v12 = onevent;
@@ -1333,12 +1388,15 @@ struct afb_export *afb_export_create_v2(
 struct afb_export *afb_export_create_v3(struct afb_apiset *declare_set,
                        struct afb_apiset *call_set,
                        const char *apiname,
-                       struct afb_api_v3 *apiv3)
+                       struct afb_api_v3 *apiv3,
+                       struct afb_export* creator,
+                       const char* path)
 {
-       struct afb_export *export = create(declare_set, call_set, apiname, Api_Version_3);
+       struct afb_export *export = create(declare_set, call_set, apiname, path, Api_Version_3);
        if (export) {
                export->unsealed = 1;
                export->desc.v3 = apiv3;
+               export->creator = afb_export_addref(creator);
                afb_export_logmask_set(export, logmask);
                afb_export_update_hooks(export);
        }
@@ -1729,7 +1787,7 @@ int afb_export_declare(struct afb_export *export,
                        ERROR("can't declare export %s to set %s, ABORTING it!",
                                export->api.apiname,
                                afb_apiset_name(export->declare_set));
-                       afb_export_addref(export);
+                       afb_export_unref(export);
                }
        }
 
@@ -1762,5 +1820,6 @@ void afb_export_process_xreq(struct afb_export *export, struct afb_xreq *xreq)
 void afb_export_context_init(struct afb_export *export, struct afb_context *context)
 {
        afb_context_init(context, export->session, NULL);
+       context->validated = 1;
 }