urun/udb: integration of user UID
authorJosé Bollo <jose.bollo@iot.bzh>
Wed, 11 Oct 2017 20:43:41 +0000 (22:43 +0200)
committerJosé Bollo <jose.bollo@iot.bzh>
Fri, 24 Nov 2017 16:44:57 +0000 (17:44 +0100)
Managing user applications at the system
levels requires to manage the user application
in a single process.

This process must manage the user identity
(UID).

Change-Id: I1ce8c9ca66ed0f916ecb2931ae014b08b113fa23
Signed-off-by: José Bollo <jose.bollo@iot.bzh>
src/afm-binding.c
src/afm-udb.c
src/afm-udb.h
src/afm-urun.c
src/afm-urun.h

index b111f09..19abc4e 100644 (file)
@@ -143,7 +143,7 @@ static void runnables(struct afb_req req)
 {
        struct json_object *resp;
        INFO("method runnables called");
-       resp = afm_udb_applications_public(afudb);
+       resp = afm_udb_applications_public(afudb, afb_req_get_uid(req));
        afb_req_success(req, resp, NULL);
 }
 
@@ -165,7 +165,7 @@ static void detail(struct afb_req req)
 
        /* wants details for appid */
        INFO("method detail called for %s", appid);
-       resp = afm_udb_get_application_public(afudb, appid);
+       resp = afm_udb_get_application_public(afudb, appid, afb_req_get_uid(req));
        if (resp)
                afb_req_success(req, resp, NULL);
        else
@@ -191,14 +191,14 @@ static void start(struct afb_req req)
 
        /* get the application */
        INFO("method start called for %s", appid);
-       appli = afm_udb_get_application_private(afudb, appid);
+       appli = afm_udb_get_application_private(afudb, appid, afb_req_get_uid(req));
        if (appli == NULL) {
                not_found(req);
                return;
        }
 
        /* launch the application */
-       runid = afm_urun_start(appli);
+       runid = afm_urun_start(appli, afb_req_get_uid(req));
        if (runid <= 0) {
                cant_start(req);
                return;
@@ -229,21 +229,21 @@ static void once(struct afb_req req)
 
        /* get the application */
        INFO("method once called for %s", appid);
-       appli = afm_udb_get_application_private(afudb, appid);
+       appli = afm_udb_get_application_private(afudb, appid, afb_req_get_uid(req));
        if (appli == NULL) {
                not_found(req);
                return;
        }
 
        /* launch the application */
-       runid = afm_urun_once(appli);
+       runid = afm_urun_once(appli, afb_req_get_uid(req));
        if (runid <= 0) {
                cant_start(req);
                return;
        }
 
        /* returns the state */
-       resp = afm_urun_state(afudb, runid);
+       resp = afm_urun_state(afudb, runid, afb_req_get_uid(req));
        afb_req_success(req, resp, NULL);
 }
 
@@ -254,7 +254,7 @@ static void pause(struct afb_req req)
 {
        int runid, status;
        if (onrunid(req, "pause", &runid)) {
-               status = afm_urun_pause(runid);
+               status = afm_urun_pause(runid, afb_req_get_uid(req));
                reply_status(req, status, _not_found_);
        }
 }
@@ -266,7 +266,7 @@ static void resume(struct afb_req req)
 {
        int runid, status;
        if (onrunid(req, "resume", &runid)) {
-               status = afm_urun_resume(runid);
+               status = afm_urun_resume(runid, afb_req_get_uid(req));
                reply_status(req, status, _not_found_);
        }
 }
@@ -278,7 +278,7 @@ static void terminate(struct afb_req req)
 {
        int runid, status;
        if (onrunid(req, "terminate", &runid)) {
-               status = afm_urun_terminate(runid);
+               status = afm_urun_terminate(runid, afb_req_get_uid(req));
                reply_status(req, status, _not_found_);
        }
 }
@@ -290,7 +290,7 @@ static void runners(struct afb_req req)
 {
        struct json_object *resp;
        INFO("method runners called");
-       resp = afm_urun_list(afudb);
+       resp = afm_urun_list(afudb, afb_req_get_uid(req));
        afb_req_success(req, resp, NULL);
 }
 
@@ -302,56 +302,11 @@ static void state(struct afb_req req)
        int runid;
        struct json_object *resp;
        if (onrunid(req, "state", &runid)) {
-               resp = afm_urun_state(afudb, runid);
+               resp = afm_urun_state(afudb, runid, afb_req_get_uid(req));
                reply(req, resp, _not_found_);
        }
 }
 
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
 static void install(struct afb_req req)
 {
        const char *wgtfile;
@@ -371,7 +326,7 @@ static void install(struct afb_req req)
        json = afb_req_json(req);
        if (wrap_json_unpack(json, "s", &wgtfile)
                || wrap_json_unpack(json, "{ss s?s s?b s?b}",
-                               "widget", &wgtfile,
+                               "wgt", &wgtfile,
                                "root", &root,
                                "force", &force,
                                "reload", &reload)) {
@@ -429,7 +384,7 @@ static void uninstall(struct afb_req req)
 static int init()
 {
        /* init database */
-       afudb = afm_udb_create(1, 1, "afm-appli-");
+       afudb = afm_udb_create(1, 0, "afm-appli-");
        if (!afudb) {
                ERROR("afm_udb_create failed");
                return -1;
index 80cc715..24c188f 100644 (file)
@@ -224,7 +224,6 @@ static int addunit(
 {
        struct json_object *priv, *pub, *id;
        const char *strid;
-       char *un = NULL;
        size_t len;
 
        /* create the application structure */
@@ -240,26 +239,13 @@ static int addunit(
        len = strlen(unitname);
        assert(len >= (sizeof service_extension - 1));
        assert(!memcmp(&unitname[len - (sizeof service_extension - 1)], service_extension, sizeof service_extension));
-       if (unitname[len - sizeof service_extension] == '@') {
-               char buffer[40];
-               size_t l = (size_t)snprintf(buffer, sizeof buffer, "%d", (int)getuid());
-               un = malloc(len + l + 1);
-               if (!un)
-                       goto error;
-               memcpy(&un[0], unitname, len - (sizeof service_extension - 1));
-               if (l)
-                       memcpy(&un[len - (sizeof service_extension - 1)], buffer, l);
-               memcpy(&un[len - (sizeof service_extension - 1) + l], service_extension, sizeof service_extension);
-       }
 
        /* adds the values */
        if (add_fields_of_content(priv, pub, content, length)
         || add_field(priv, pub, key_unit_path, unitpath)
-        || add_field(priv, pub, key_unit_name, un ? : unitname)
+        || add_field(priv, pub, key_unit_name, unitname)
         || add_field(priv, pub, key_unit_scope, isuser ? scope_user : scope_system))
                goto error;
-       free(un);
-       un = NULL;
 
        /* get the id */
        if (!json_object_object_get_ex(pub, key_id, &id)) {
@@ -278,7 +264,6 @@ static int addunit(
        return 0;
 
 error:
-       free(un);
        json_object_put(pub);
        json_object_put(priv);
        return -1;
@@ -486,7 +471,7 @@ error:
  * 'json_object_put'.
  * Returns NULL in case of error.
  */
-struct json_object *afm_udb_applications_private(struct afm_udb *afudb)
+struct json_object *afm_udb_applications_private(struct afm_udb *afudb, int uid)
 {
        return json_object_get(afudb->applications.prvarr);
 }
@@ -497,7 +482,7 @@ struct json_object *afm_udb_applications_private(struct afm_udb *afudb)
  * 'json_object_put'.
  * Returns NULL in case of error.
  */
-struct json_object *afm_udb_applications_public(struct afm_udb *afudb)
+struct json_object *afm_udb_applications_public(struct afm_udb *afudb, int uid)
 {
        return json_object_get(afudb->applications.pubarr);
 }
@@ -507,7 +492,7 @@ struct json_object *afm_udb_applications_public(struct afm_udb *afudb)
  * It returns a JSON-object that must be released using 'json_object_put'.
  * Returns NULL in case of error.
  */
-static struct json_object *get_no_case(struct json_object *object, const char *id)
+static struct json_object *get_no_case(struct json_object *object, const char *id, int uid)
 {
        struct json_object *result;
        struct json_object_iter i;
@@ -529,9 +514,9 @@ static struct json_object *get_no_case(struct json_object *object, const char *i
  * It returns a JSON-object that must be released using 'json_object_put'.
  * Returns NULL in case of error.
  */
-struct json_object *afm_udb_get_application_private(struct afm_udb *afudb, const char *id)
+struct json_object *afm_udb_get_application_private(struct afm_udb *afudb, const char *id, int uid)
 {
-       return get_no_case(afudb->applications.prvobj, id);
+       return get_no_case(afudb->applications.prvobj, id, uid);
 }
 
 /*
@@ -540,9 +525,9 @@ struct json_object *afm_udb_get_application_private(struct afm_udb *afudb, const
  * Returns NULL in case of error.
  */
 struct json_object *afm_udb_get_application_public(struct afm_udb *afudb,
-                                                       const char *id)
+                                                       const char *id, int uid)
 {
-       return get_no_case(afudb->applications.pubobj, id);
+       return get_no_case(afudb->applications.pubobj, id, uid);
 }
 
 
index 672a311..dc30c9c 100644 (file)
@@ -23,8 +23,8 @@ extern struct afm_udb *afm_udb_create(int sys, int usr, const char *prefix);
 extern void afm_udb_addref(struct afm_udb *afdb);
 extern void afm_udb_unref(struct afm_udb *afdb);
 extern int afm_udb_update(struct afm_udb *afdb);
-extern struct json_object *afm_udb_applications_private(struct afm_udb *afdb);
-extern struct json_object *afm_udb_applications_public(struct afm_udb *afdb);
-extern struct json_object *afm_udb_get_application_private(struct afm_udb *afdb, const char *id);
-extern struct json_object *afm_udb_get_application_public(struct afm_udb *afdb, const char *id);
+extern struct json_object *afm_udb_applications_private(struct afm_udb *afdb, int uid);
+extern struct json_object *afm_udb_applications_public(struct afm_udb *afdb, int uid);
+extern struct json_object *afm_udb_get_application_private(struct afm_udb *afdb, const char *id, int uid);
+extern struct json_object *afm_udb_get_application_public(struct afm_udb *afdb, const char *id, int uid);
 
index 5649973..b6418ac 100644 (file)
@@ -40,10 +40,13 @@ static const char key_unit_d_path[] = "-unit-dpath-";
 
 /**************** get appli basis *********************/
 
-static int get_basis(struct json_object *appli, int *isuser, const char **dpath, int load)
+static int get_basis(struct json_object *appli, int *isuser, const char **dpath, int load, int uid)
 {
-       char *dp;
+       char userid[40];
+       char *dp, *arodot, *nun;
        const char *uname, *uscope;
+       struct json_object *odp;
+       int rc;
 
        /* get the scope */
        if (!j_read_string_at(appli, "unit-scope", &uscope)) {
@@ -52,21 +55,81 @@ static int get_basis(struct json_object *appli, int *isuser, const char **dpath,
        }
        *isuser = strcmp(uscope, "system") != 0;
 
-       /* get dpath */
-       if (!j_read_string_at(appli, key_unit_d_path, dpath)) {
-               if (!load) {
-                       errno = ENOENT;
-                       goto error;
+       /* get dpaths of known users */
+       odp = NULL;
+       if (json_object_object_get_ex(appli, key_unit_d_path, &odp)) {
+               /* try not parametric dpath */
+               if (json_object_get_type(odp) == json_type_string) {
+                       *dpath = json_object_get_string(odp);
+                       return 0;
                }
-               if (!j_read_string_at(appli, "unit-name", &uname)) {
-                       ERROR("'unit-name' missing in appli description %s", json_object_get_string(appli));
+               assert(json_object_get_type(odp) == json_type_object);
+               /* get userid */
+               if (uid < 0) {
+                       ERROR("unexpected uid %d", uid);
                        goto inval;
                }
+               rc = snprintf(userid, sizeof userid, "%d", uid);
+               assert(rc < (int)(sizeof userid));
+               /* try dpath for the user */
+               if (j_read_string_at(odp, userid, dpath))
+                       return 0;
+       }
+
+       /* not here. load it? */
+       if (!load) {
+               errno = ENOENT;
+               goto error;
+       }
+
+       /* get uname */
+       if (!j_read_string_at(appli, "unit-name", &uname)) {
+               ERROR("'unit-name' missing in appli description %s", json_object_get_string(appli));
+               goto inval;
+       }
+
+       /* is user parametric? */
+       arodot = strchr(uname, '@');
+       if (arodot && *++arodot == '.') {
+               if (!odp) {
+                       /* get userid */
+                       if (uid < 0) {
+                               ERROR("unexpected uid %d", uid);
+                               goto inval;
+                       }
+                       rc = snprintf(userid, sizeof userid, "%d", uid);
+                       assert(rc < (int)(sizeof userid));
+
+                       /* create the dpaths of known users */
+                       odp = json_object_new_object();
+                       if (!odp)
+                               goto nomem;
+                       json_object_object_add(appli, key_unit_d_path, odp);
+               }
+
+               /* get dpath of userid */
+               nun = alloca((size_t)(arodot - uname) + strlen(userid) + strlen(arodot) + 1);
+               stpcpy(stpcpy(stpncpy(nun, uname, (size_t)(arodot - uname)), userid), arodot);
+               dp = systemd_unit_dpath_by_name(*isuser, uname, 1);
+               if (dp == NULL) {
+                       ERROR("Can't load unit of name %s for %s: %m", uname, uscope);
+                       goto error;
+               }
+               /* record the dpath */
+               if (!j_add_string(odp, userid, dp)) {
+                       free(dp);
+                       goto nomem;
+               }
+               free(dp);
+               j_read_string_at(odp, userid, dpath);
+       } else {
+               /* get dpath */
                dp = systemd_unit_dpath_by_name(*isuser, uname, 1);
                if (dp == NULL) {
                        ERROR("Can't load unit of name %s for %s: %m", uname, uscope);
                        goto error;
                }
+               /* record the dpath */
                if (!j_add_string(appli, key_unit_d_path, dp)) {
                        free(dp);
                        goto nomem;
@@ -74,7 +137,6 @@ static int get_basis(struct json_object *appli, int *isuser, const char **dpath,
                free(dp);
                j_read_string_at(appli, key_unit_d_path, dpath);
        }
-
        return 0;
 
 nomem:
@@ -162,9 +224,9 @@ error:
  *
  * Returns the runid in case of success or -1 in case of error
  */
-int afm_urun_start(struct json_object *appli)
+int afm_urun_start(struct json_object *appli, int uid)
 {
-       return afm_urun_once(appli);
+       return afm_urun_once(appli, uid);
 }
 
 /*
@@ -178,13 +240,13 @@ int afm_urun_start(struct json_object *appli)
  *
  * Returns the runid in case of success or -1 in case of error
  */
-int afm_urun_once(struct json_object *appli)
+int afm_urun_once(struct json_object *appli, int uid)
 {
        const char *udpath, *state, *uscope, *uname;
        int rc, isuser;
 
        /* retrieve basis */
-       rc = get_basis(appli, &isuser, &udpath, 1);
+       rc = get_basis(appli, &isuser, &udpath, 1, uid);
        if (rc < 0)
                goto error;
 
@@ -237,7 +299,7 @@ static int not_yet_implemented(const char *what)
  *
  * Returns 0 in case of success or -1 in case of error
  */
-int afm_urun_terminate(int runid)
+int afm_urun_terminate(int runid, int uid)
 {
        int rc = systemd_unit_stop_pid(1 /* TODO: isuser? */, (unsigned)runid);
        if (rc < 0)
@@ -250,7 +312,7 @@ int afm_urun_terminate(int runid)
  *
  * Returns 0 in case of success or -1 in case of error
  */
-int afm_urun_pause(int runid)
+int afm_urun_pause(int runid, int uid)
 {
        return not_yet_implemented("pause");
 }
@@ -260,7 +322,7 @@ int afm_urun_pause(int runid)
  *
  * Returns 0 in case of success or -1 in case of error
  */
-int afm_urun_resume(int runid)
+int afm_urun_resume(int runid, int uid)
 {
        return not_yet_implemented("resume");
 }
@@ -270,7 +332,7 @@ int afm_urun_resume(int runid)
  *
  * Returns the list or NULL in case of error.
  */
-struct json_object *afm_urun_list(struct afm_udb *db)
+struct json_object *afm_urun_list(struct afm_udb *db, int uid)
 {
        int i, n, isuser, pid;
        const char *udpath;
@@ -286,11 +348,11 @@ struct json_object *afm_urun_list(struct afm_udb *db)
        if (result == NULL)
                goto error;
 
-       apps = afm_udb_applications_private(db);
+       apps = afm_udb_applications_private(db, uid);
        n = json_object_array_length(apps);
        for (i = 0 ; i < n ; i++) {
                appli = json_object_array_get_idx(apps, i);
-               if (appli && get_basis(appli, &isuser, &udpath, 0) >= 0) {
+               if (appli && get_basis(appli, &isuser, &udpath, 0, uid) >= 0) {
                        pid = systemd_unit_pid_of_dpath(isuser, udpath);
                        if (pid > 0 && j_read_string_at(appli, "id", &id)) {
                                state = systemd_unit_state_of_dpath(isuser, udpath);
@@ -315,7 +377,7 @@ error:
  *
  * Returns the state or NULL in case of success
  */
-struct json_object *afm_urun_state(struct afm_udb *db, int runid)
+struct json_object *afm_urun_state(struct afm_udb *db, int runid, int uid)
 {
        int i, n, isuser, pid, wasuser;
        char *dpath;
@@ -337,12 +399,12 @@ struct json_object *afm_urun_state(struct afm_udb *db, int runid)
                WARNING("searched runid %d not found", runid);
        } else {
                /* search in the base */
-               apps = afm_udb_applications_private(db);
+               apps = afm_udb_applications_private(db, uid);
                n = json_object_array_length(apps);
                for (i = 0 ; i < n ; i++) {
                        appli = json_object_array_get_idx(apps, i);
                        if (appli
-                        && get_basis(appli, &isuser, &udpath, 0) >= 0
+                        && get_basis(appli, &isuser, &udpath, 0, uid) >= 0
                         && !strcmp(dpath, udpath)
                         && j_read_string_at(appli, "id", &id)) {
                                pid = systemd_unit_pid_of_dpath(isuser, udpath);
index 7f85e0f..178edf9 100644 (file)
 
 struct afm_udb;
 
-extern int afm_urun_start(struct json_object *appli);
-extern int afm_urun_once(struct json_object *appli);
-extern int afm_urun_terminate(int runid);
-extern int afm_urun_pause(int runid);
-extern int afm_urun_resume(int runid);
-extern struct json_object *afm_urun_list(struct afm_udb *db);
-extern struct json_object *afm_urun_state(struct afm_udb *db, int runid);
+extern int afm_urun_start(struct json_object *appli, int uid);
+extern int afm_urun_once(struct json_object *appli, int uid);
+extern int afm_urun_terminate(int runid, int uid);
+extern int afm_urun_pause(int runid, int uid);
+extern int afm_urun_resume(int runid, int uid);
+extern struct json_object *afm_urun_list(struct afm_udb *db, int uid);
+extern struct json_object *afm_urun_state(struct afm_udb *db, int runid, int uid);