X-Git-Url: https://gerrit.automotivelinux.org/gerrit/gitweb?a=blobdiff_plain;f=src%2Fafm-binding.c;h=255f3b89d2fd6b3690499b34e99acee27fefc6b0;hb=275f7f5b9d2b148ae61da39c87f81c75974ab31f;hp=7e99b202b1a7c0618ad4b8a655f64cf427ae205e;hpb=9a0d792982ae637dd32e6939724441fe1b5fb47d;p=src%2Fapp-framework-main.git diff --git a/src/afm-binding.c b/src/afm-binding.c index 7e99b20..255f3b8 100644 --- a/src/afm-binding.c +++ b/src/afm-binding.c @@ -46,6 +46,8 @@ static const char _a_l_c_[] = "application-list-changed"; static const char _bad_request_[] = "bad-request"; static const char _cannot_start_[] = "cannot-start"; static const char _detail_[] = "detail"; +static const char _forbidden_[] = "forbidden"; +static const char _force_[] = "force"; static const char _id_[] = "id"; static const char _install_[] = "install"; static const char _lang_[] = "lang"; @@ -53,15 +55,19 @@ static const char _not_found_[] = "not-found"; static const char _not_running_[] = "not-running"; static const char _once_[] = "once"; static const char _pause_[] = "pause"; +static const char _reload_[] = "reload"; static const char _resume_[] = "resume"; +static const char _root_[] = "root"; static const char _runid_[] = "runid"; static const char _runnables_[] = "runnables"; static const char _runners_[] = "runners"; static const char _start_[] = "start"; static const char _state_[] = "state"; static const char _terminate_[] = "terminate"; +static const char _uid_[] = "uid"; static const char _uninstall_[] = "uninstall"; static const char _update_[] = "update"; +static const char _wgt_[] = "wgt"; /* * the permissions @@ -79,10 +85,6 @@ static const struct afb_auth .type = afb_auth_Permission, .text = FWK_PREFIX"permission:afm:system:widget:uninstall" }, - auth_perm_widget_preinstall = { - .type = afb_auth_Permission, - .text = FWK_PREFIX"permission:afm:system:widget:preinstall" - }, auth_perm_widget_detail = { .type = afb_auth_Permission, .text = FWK_PREFIX"permission:afm:system:widget:detail" @@ -107,6 +109,10 @@ static const struct afb_auth .type = afb_auth_Permission, .text = FWK_PREFIX"permission:afm:system:runner:kill" }, + auth_perm_set_uid = { + .type = afb_auth_Permission, + .text = FWK_PREFIX"permission:afm:system:set-uid" + }, auth_install = { .type = afb_auth_Or, @@ -118,11 +124,6 @@ static const struct afb_auth .first = &auth_perm_widget, .next = &auth_perm_widget_uninstall }, - auth_preinstall = { - .type = afb_auth_Or, - .first = &auth_perm_widget, - .next = &auth_perm_widget_preinstall - }, auth_detail = { .type = afb_auth_Or, .first = &auth_perm_widget, @@ -150,10 +151,55 @@ static const struct afb_auth } ; +/** + * Enumerate the possible arguments + * This is intended to be used as a mask of bits + * telling what parameter is expected, optional, + * and, finally, set. + */ +enum { + Param_Lang = 1, + Param_All = 2, + Param_Force = 4, + Param_Reload = 8, + Param_Id = 16, + Param_RunId = 32, + Param_WGT = 64, + Param_Root = 128 +}; + +/** + * Records the parameters of verb queries + */ +struct params { + /** bit mask of the given param */ + unsigned found; + /** value of param 'all' if set */ + int all; + /** value of param 'force' if set */ + int force; + /** value of param 'reload' if set */ + int reload; + /** value of param 'uid' if set */ + int uid; + /** value of param 'runid' if set */ + int runid; + /** value of param 'lang' if set */ + const char *lang; + /** value of param 'id' if set */ + const char *id; + /** value of param 'wgt' if set */ + const char *wgt; + /** value of param 'root' if set */ + const char *root; + /** object value of parameters */ + struct json_object *args; +}; + /* * default root */ -static const char *rootdir = FWK_APP_DIR; +static const char rootdir[] = FWK_APP_DIR; /* * the internal application database @@ -186,6 +232,15 @@ static void bad_request(afb_req_t req) afb_req_fail(req, _bad_request_, NULL); } +/* forbidden request reply */ +static void forbidden_request(afb_req_t req) +{ + INFO("forbidden request verb %s: %s", + afb_req_get_called_verb(req), + json_object_to_json_string(afb_req_json(req))); + afb_req_fail(req, _forbidden_, NULL); +} + /* common not found reply */ static void not_found(afb_req_t req) { @@ -204,6 +259,28 @@ static void cant_start(afb_req_t req) afb_req_fail(req, _cannot_start_, NULL); } +/* emulate missing function */ +static int has_auth(afb_req_t req, const struct afb_auth *auth) +{ + switch (auth->type) { + case afb_auth_Permission: + return afb_req_has_permission(req, auth->text); + case afb_auth_Or: + return has_auth(req, auth->first) || has_auth(req, auth->next); + case afb_auth_And: + return has_auth(req, auth->first) && has_auth(req, auth->next); + case afb_auth_Not: + return !has_auth(req, auth->first); + case afb_auth_Yes: + return 1; + case afb_auth_No: + case afb_auth_Token: + case afb_auth_LOA: + default: + return 0; + } +} + /* * Broadcast the event "application-list-changed". * This event is sent was the event "changed" is received from dbus. @@ -215,103 +292,173 @@ static void application_list_changed(const char *operation, const char *data) afb_event_broadcast(applist_changed_event, e); } -/* - * Retrieve the required language from 'req'. +/** + * common routine for getting parameters */ -static const char *get_lang(afb_req_t req) +static int get_params(afb_req_t req, unsigned mandatory, unsigned optional, struct params *params) { - const char *lang; - - /* get the optional language */ - lang = afb_req_value(req, _lang_); - - /* TODO use the req to get the lang of the session (if any) */ - - return lang; -} - -/* - * Retrieve whether all is required from 'req'. - */ -static int get_all(afb_req_t req) -{ - struct json_object *val; - - /* get the optional language */ - return json_object_object_get_ex(afb_req_json(req), _all_, &val) - && json_object_get_boolean(val); -} - -/* - * retrieves the 'appid' in parameters received with the - * request 'req'. - * - * Returns 1 in case of success. - * Otherwise, if the 'appid' can't be retrieved, an error stating - * the bad request is replied for 'req' and 0 is returned. - */ -static int onappid(afb_req_t req, const char **appid) -{ - struct json_object *json; - - /* get the paramaters of the request */ - json = afb_req_json(req); - - /* get the appid if any */ - if (!wrap_json_unpack(json, "s", appid) - || !wrap_json_unpack(json, "{ss}", _id_, appid)) { - /* found */ - INFO("method %s called for %s", afb_req_get_called_verb(req), *appid); - return 1; + enum { + no_error = 0, + error_bad_request = 1, + error_not_found = 2, + error_not_running = 3, + error_forbidden = 4 + }; + + int id, error; + struct json_object *args, *obj; + unsigned found, expected; + + /* init */ + expected = optional|mandatory; + memset(params, 0, sizeof *params); + error = no_error; + found = 0; + params->uid = afb_req_get_uid(req); + args = afb_req_json(req); + + /* args is a numeric value: a run id */ + if (json_object_is_type(args, json_type_int)) { + if (expected & Param_RunId) { + params->runid = json_object_get_int(args); + found |= Param_RunId; + } } - - /* nothing appropriate */ - bad_request(req); - return 0; -} - -/* - * retrieves the 'runid' in parameters received with the - * request 'req'. - * - * Returns 1 in case of success. - * Otherwise, if the 'runid' can't be retrieved, an error stating - * the bad request is replied for 'req' and 0 is returned. - */ -static int onrunid(afb_req_t req, int *runid) -{ - struct json_object *json; - const char *appid; - - /* get the paramaters of the request */ - json = afb_req_json(req); - - /* get the runid if any */ - if (!wrap_json_unpack(json, "i", runid) - || !wrap_json_unpack(json, "{si}", _runid_, runid)) { - INFO("method %s called for %d", afb_req_get_called_verb(req), *runid); - return 1; + + /* args is a string value: either an ID or a widget path */ + else if (json_object_is_type(args, json_type_string)) { + if (expected & (Param_Id | Param_RunId)) { + params->id = json_object_get_string(args); + found |= Param_Id; + } + else if (expected & Param_WGT) { + params->wgt = json_object_get_string(args); + found |= Param_WGT; + } + } + + /* args is a object value: inspect it */ + else if (json_object_is_type(args, json_type_object)) { + /* get UID */ + if (json_object_object_get_ex(args, _uid_, &obj)) { + if (!json_object_is_type(obj, json_type_int)) + error = 1; + else { + id = json_object_get_int(obj); + if (id < 0) + error = error_bad_request; + else if (params->uid != id) { + if (!afb_req_has_permission(req, auth_perm_set_uid.text)) + error = error_forbidden; + else { + params->uid = id; + } + } + } + } + + /* get all */ + if ((expected & Param_All) + && json_object_object_get_ex(args, _all_, &obj)) { + params->all = json_object_get_boolean(obj); + if (params->all && !has_auth(req, &auth_view_all)) + error = error_forbidden; + else + found |= Param_All; + } + + /* get force */ + if ((expected & Param_Force) + && json_object_object_get_ex(args, _force_, &obj)) { + params->force = json_object_get_boolean(obj); + found |= Param_Force; + } + + /* get reload */ + if ((expected & Param_Reload) + && json_object_object_get_ex(args, _reload_, &obj)) { + params->reload = json_object_get_boolean(obj); + found |= Param_Reload; + } + + /* get languages */ + if ((expected & Param_Lang) + && json_object_object_get_ex(args, _lang_, &obj)) { + params->lang = json_object_get_string(obj); + found |= Param_Lang; + } + + /* get root */ + if ((expected & Param_Root) + && json_object_object_get_ex(args, _root_, &obj)) { + params->root = json_object_get_string(obj); + found |= Param_Root; + } + + /* get WGT */ + if (expected & Param_WGT) { + if (json_object_object_get_ex(args, _wgt_, &obj)) { + params->wgt = json_object_get_string(obj); + found |= Param_WGT; + } + } + + /* get appid */ + if (expected & (Param_Id | Param_RunId)) { + if (json_object_object_get_ex(args, _id_, &obj)) { + params->id = json_object_get_string(obj); + found |= Param_Id; + } + } + + /* get runid */ + if (expected & Param_RunId) { + if (json_object_object_get_ex(args, _runid_, &obj)) { + if (json_object_is_type(obj, json_type_int)) + error = error_bad_request; + else { + params->runid = json_object_get_int(obj); + found |= Param_RunId; + } + } + } } - /* get the appid if any */ - if (!onappid(req, &appid)) - return 0; - - /* search the runid of the appid */ - *runid = afm_urun_search_runid(afudb, appid, afb_req_get_uid(req)); - if (*runid < 0) { - /* nothing appropriate */ - INFO("method %s can't get runid for %s: %m", afb_req_get_called_verb(req), - appid); - if (errno == ESRCH) - not_running(req); + /* deduce the runid from the uid on need */ + if ((mandatory & Param_RunId) && !(found & Param_RunId) && (found & Param_Id)) { + id = afm_urun_search_runid(afudb, params->id, params->uid); + if (id > 0) { + params->runid = id; + found |= Param_RunId; + } + else if (errno == ESRCH) + error = error_not_running; else + error = error_not_found; + } + + /* check all mandatory are here */ + if (error != no_error || (mandatory & found) != mandatory) { + switch(error) { + case error_not_found: not_found(req); + break; + case error_not_running: + not_running(req); + break; + case error_forbidden: + forbidden_request(req); + break; + case error_bad_request: + default: + bad_request(req); + break; + } return 0; } - /* found */ - INFO("method %s called for %s -> %d", afb_req_get_called_verb(req), appid, *runid); + params->args = args; + params->found = found; return 1; } @@ -341,18 +488,15 @@ static void reply_status(afb_req_t req, int status) */ static void runnables(afb_req_t req) { - int all; - const char *lang; + struct params params; struct json_object *resp; - /* get the language */ - lang = get_lang(req); - - /* get the all */ - all = get_all(req); + /* scan the request */ + if (!get_params(req, 0, Param_Lang|Param_All, ¶ms)) + return; - /* get the details */ - resp = afm_udb_applications_public(afudb, all, afb_req_get_uid(req), lang); + /* get the applications */ + resp = afm_udb_applications_public(afudb, params.all, params.uid, params.lang); afb_req_success(req, resp, NULL); } @@ -361,19 +505,15 @@ static void runnables(afb_req_t req) */ static void detail(afb_req_t req) { - const char *lang; - const char *appid; + struct params params; struct json_object *resp; /* scan the request */ - if (!onappid(req, &appid)) + if (!get_params(req, Param_Id, Param_Lang, ¶ms)) return; - /* get the language */ - lang = get_lang(req); - - /* wants details for appid */ - resp = afm_udb_get_application_public(afudb, appid, afb_req_get_uid(req), lang); + /* get the details */ + resp = afm_udb_get_application_public(afudb, params.id, params.uid, params.lang); if (resp) afb_req_success(req, resp, NULL); else @@ -385,23 +525,23 @@ static void detail(afb_req_t req) */ static void start(afb_req_t req) { - const char *appid; + struct params params; struct json_object *appli, *resp; int runid; /* scan the request */ - if (!onappid(req, &appid)) + if (!get_params(req, Param_Id, 0, ¶ms)) return; /* get the application */ - appli = afm_udb_get_application_private(afudb, appid, afb_req_get_uid(req)); + appli = afm_udb_get_application_private(afudb, params.id, params.uid); if (appli == NULL) { not_found(req); return; } /* launch the application */ - runid = afm_urun_start(appli, afb_req_get_uid(req)); + runid = afm_urun_start(appli, params.uid); if (runid <= 0) { cant_start(req); return; @@ -409,11 +549,7 @@ static void start(afb_req_t req) /* returns */ resp = NULL; -#if 0 - wrap_json_pack(&resp, "{si}", _runid_, runid); -#else wrap_json_pack(&resp, "i", runid); -#endif afb_req_success(req, resp, NULL); } @@ -422,30 +558,30 @@ static void start(afb_req_t req) */ static void once(afb_req_t req) { - const char *appid; + struct params params; struct json_object *appli, *resp; int runid; /* scan the request */ - if (!onappid(req, &appid)) + if (!get_params(req, Param_Id, 0, ¶ms)) return; /* get the application */ - appli = afm_udb_get_application_private(afudb, appid, afb_req_get_uid(req)); + appli = afm_udb_get_application_private(afudb, params.id, params.uid); if (appli == NULL) { not_found(req); return; } /* launch the application */ - runid = afm_urun_once(appli, afb_req_get_uid(req)); + runid = afm_urun_once(appli, params.uid); if (runid <= 0) { cant_start(req); return; } /* returns the state */ - resp = afm_urun_state(afudb, runid, afb_req_get_uid(req)); + resp = afm_urun_state(afudb, runid, params.uid); afb_req_success(req, resp, NULL); } @@ -454,9 +590,12 @@ static void once(afb_req_t req) */ static void pause(afb_req_t req) { - int runid, status; - if (onrunid(req, &runid)) { - status = afm_urun_pause(runid, afb_req_get_uid(req)); + struct params params; + int status; + + /* scan the request */ + if (get_params(req, Param_RunId, 0, ¶ms)) { + status = afm_urun_pause(params.runid, params.uid); reply_status(req, status); } } @@ -466,9 +605,12 @@ static void pause(afb_req_t req) */ static void resume(afb_req_t req) { - int runid, status; - if (onrunid(req, &runid)) { - status = afm_urun_resume(runid, afb_req_get_uid(req)); + struct params params; + int status; + + /* scan the request */ + if (get_params(req, Param_RunId, 0, ¶ms)) { + status = afm_urun_resume(params.runid, params.uid); reply_status(req, status); } } @@ -478,9 +620,12 @@ static void resume(afb_req_t req) */ static void terminate(afb_req_t req) { - int runid, status; - if (onrunid(req, &runid)) { - status = afm_urun_terminate(runid, afb_req_get_uid(req)); + struct params params; + int status; + + /* scan the request */ + if (get_params(req, Param_RunId, 0, ¶ms)) { + status = afm_urun_terminate(params.runid, params.uid); reply_status(req, status); } } @@ -490,10 +635,14 @@ static void terminate(afb_req_t req) */ static void runners(afb_req_t req) { - int all; + struct params params; struct json_object *resp; - all = get_all(req); - resp = afm_urun_list(afudb, all, afb_req_get_uid(req)); + + /* scan the request */ + if (!get_params(req, 0, Param_All, ¶ms)) + return; + + resp = afm_urun_list(afudb, params.all, params.uid); afb_req_success(req, resp, NULL); } @@ -502,10 +651,12 @@ static void runners(afb_req_t req) */ static void state(afb_req_t req) { - int runid; + struct params params; struct json_object *resp; - if (onrunid(req, &runid)) { - resp = afm_urun_state(afudb, runid, afb_req_get_uid(req)); + + /* scan the request */ + if (get_params(req, Param_RunId, 0, ¶ms)) { + resp = afm_urun_state(afudb, params.runid, params.uid); reply(req, resp); } } @@ -515,38 +666,36 @@ static void state(afb_req_t req) */ static void install(afb_req_t req) { - const char *wgtfile; - const char *root; - int force; - int reload; + struct params params; struct wgt_info *ifo; - struct json_object *json; struct json_object *resp; - /* default settings */ - root = rootdir; - force = 0; - reload = 1; - /* scan the request */ - json = afb_req_json(req); - if (wrap_json_unpack(json, "s", &wgtfile) - && wrap_json_unpack(json, "{ss s?s s?b s?b}", - "wgt", &wgtfile, - "root", &root, - "force", &force, - "reload", &reload)) { - return bad_request(req); + if (!get_params(req, Param_WGT, Param_Root|Param_Force|Param_Reload, ¶ms)) + return; + + /* check if force is allowed */ + if (params.force) { + if (!has_auth(req, &auth_uninstall)) { + forbidden_request(req); + return; + } } + /* supply default values */ + if (!(params.found & Param_Reload)) + params.reload = 1; + if (!(params.found & Param_Root)) + params.root = rootdir; + /* install the widget */ - ifo = install_widget(wgtfile, root, force); + ifo = install_widget(params.wgt, params.root, params.force); if (ifo == NULL) afb_req_fail_f(req, "failed", "installation failed: %m"); else { afm_udb_update(afudb); /* reload if needed */ - if (reload) + if (params.reload) do_reloads(); /* build the response */ @@ -564,31 +713,25 @@ static void install(afb_req_t req) */ static void uninstall(afb_req_t req) { - const char *idaver; - const char *root; - struct json_object *json; + struct params params; int rc; - /* default settings */ - root = rootdir; - /* scan the request */ - json = afb_req_json(req); - if (wrap_json_unpack(json, "s", &idaver) - && wrap_json_unpack(json, "{ss s?s}", - _id_, &idaver, - "root", &root)) { - return bad_request(req); - } + if (!get_params(req, Param_Id, Param_Root|Param_Reload, ¶ms)) + return; + if (!(params.found & Param_Reload)) + params.reload = 1; + if (!(params.found & Param_Root)) + params.root = rootdir; /* install the widget */ - rc = uninstall_widget(idaver, root); + rc = uninstall_widget(params.id, params.root); if (rc) afb_req_fail_f(req, "failed", "uninstallation failed: %m"); else { afm_udb_update(afudb); afb_req_success(req, NULL, NULL); - application_list_changed(_uninstall_, idaver); + application_list_changed(_uninstall_, params.id); } } @@ -643,4 +786,3 @@ const afb_binding_t afbBindingExport = { .onevent = NULL, .noconcurrency = 1 /* relies on binder for serialization of requests */ }; -