Fix labelling of files of widgets
[src/app-framework-main.git] / src / wgtpkg-install.c
index c5c41ea..03cd78f 100644 (file)
@@ -1,5 +1,5 @@
 /*
- Copyright (C) 2015-2018 IoT.bzh
+ Copyright (C) 2015-2020 IoT.bzh
 
  author: José Bollo <jose.bollo@iot.bzh>
 
@@ -53,19 +53,25 @@ static const char* exec_type_strings[] = {
 };
 
 static const char key_afm_prefix[] = "X-AFM-";
-static const char key_http_port[] = "http-port";
+static const char key_afid[] = "ID";
 
-#define HTTP_PORT_MIN                  31000
-#define HTTP_PORT_MAX                  32759
-#define HTTP_PORT_IS_VALID(port)       (HTTP_PORT_MIN <= (port) && (port) <= HTTP_PORT_MAX)
-#define HTTP_PORT_COUNT                        (HTTP_PORT_MAX - HTTP_PORT_MIN + 1)
-#define HTTP_PORT_ACNT                 ((HTTP_PORT_COUNT + 31) >> 5)
-#define HTTP_PORT_ASFT(port)           (((port) - HTTP_PORT_MIN) & 31)
-#define HTTP_PORT_AIDX(port)           (((port) - HTTP_PORT_MIN) >> 5)
-#define HTTP_PORT_TEST(array,port)     ((((array)[HTTP_PORT_AIDX(port)]) >> HTTP_PORT_ASFT(port)) & 1)
-#define HTTP_PORT_SET(array,port)      (((array)[HTTP_PORT_AIDX(port)]) |= (((uint32_t)1) << HTTP_PORT_ASFT(port)))
+#define HTTP_PORT_BASE         30000
 
-static uint32_t *port_bits = NULL;
+#define AFID_MIN               1
+#define AFID_MAX               1999
+#define AFID_IS_VALID(afid)    (AFID_MIN <= (afid) && (afid) <= AFID_MAX)
+#define AFID_COUNT             (AFID_MAX - AFID_MIN + 1)
+#define AFID_ACNT              ((AFID_COUNT + 31) >> 5)
+#define AFID_ASFT(afid)                (((afid) - AFID_MIN) & 31)
+#define AFID_AIDX(afid)                (((afid) - AFID_MIN) >> 5)
+#define AFID_TEST(array,afid)  ((((array)[AFID_AIDX(afid)]) >> AFID_ASFT(afid)) & 1)
+#define AFID_SET(array,afid)   (((array)[AFID_AIDX(afid)]) |= (((uint32_t)1) << AFID_ASFT(afid)))
+
+static uint32_t *afids_array = NULL;
+
+static const char *default_permissions[] = {
+       "urn:AGL:token:valid"
+};
 
 /*
  * normalize unit files: remove comments, remove heading blanks,
@@ -99,7 +105,7 @@ static void normalize_unit_file(char *content)
        *write = c;
 }
 
-static int get_port_cb(void *closure, const char *name, const char *path, int isuser)
+static int get_afid_cb(void *closure, const char *name, const char *path, int isuser)
 {
        char *iter;
        char *content;
@@ -120,15 +126,15 @@ static int get_port_cb(void *closure, const char *name, const char *path, int is
                iter += sizeof key_afm_prefix - 1;
                if (*iter == '-')
                        iter++;
-               if (!strncmp(iter, key_http_port, sizeof key_http_port - 1)) {
-                       iter += sizeof key_http_port - 1;
+               if (!strncmp(iter, key_afid, sizeof key_afid - 1)) {
+                       iter += sizeof key_afid - 1;
                        while(*iter && *iter != '=' && *iter != '\n')
                                iter++;
                        if (*iter == '=') {
                                while(*++iter == ' ');
                                p = atoi(iter);
-                               if (HTTP_PORT_IS_VALID(p))
-                                       HTTP_PORT_SET((uint32_t*)closure, p);
+                               if (AFID_IS_VALID(p))
+                                       AFID_SET((uint32_t*)closure, p);
                        }
                }
                iter = strstr(iter, key_afm_prefix);
@@ -137,53 +143,59 @@ static int get_port_cb(void *closure, const char *name, const char *path, int is
        return 0;
 }
 
-static int update_portbits(uint32_t *portbits)
+static int update_afids(uint32_t *afids)
 {
        int rc;
 
-       memset(portbits, 0, HTTP_PORT_ACNT * sizeof(uint32_t));
-       rc = systemd_unit_list(0, get_port_cb, portbits);
+       memset(afids, 0, AFID_ACNT * sizeof(uint32_t));
+       rc = systemd_unit_list(0, get_afid_cb, afids);
        if (rc >= 0)
-               rc = systemd_unit_list(1, get_port_cb, portbits);
+               rc = systemd_unit_list(1, get_afid_cb, afids);
        if (rc < 0)
-               ERROR("troubles while updating ports");
+               ERROR("troubles while updating afids");
        return rc;
 }
 
-static int first_free_port(uint32_t *portbits)
+static int first_free_afid(uint32_t *afids)
 {
-       int port;
-
-       port = HTTP_PORT_MIN;
-       while (port <= HTTP_PORT_MAX && !~portbits[HTTP_PORT_AIDX(port)])
-               port += 32;
-       while (port <= HTTP_PORT_MAX && HTTP_PORT_TEST(portbits, port))
-               port++;
-       if (port > HTTP_PORT_MAX) {
-               ERROR("Can't compute a valid port");
+       int afid;
+
+       afid = AFID_MIN;
+       while (afid <= AFID_MAX && !~afids[AFID_AIDX(afid)])
+               afid += 32;
+       while (afid <= AFID_MAX && AFID_TEST(afids, afid))
+               afid++;
+       if (afid > AFID_MAX) {
+               ERROR("Can't compute a valid afid");
                errno = EADDRNOTAVAIL;
-               port = -1;
+               afid = -1;
        }
-       return port;
+       return afid;
 }
 
-static int get_port()
+static int get_new_afid()
 {
-       int port;
+       int afid;
 
-       /* ensure existing port bitmap */
-       if (port_bits == NULL) {
-               port_bits = malloc(HTTP_PORT_ACNT * sizeof(uint32_t));
-               if (port_bits == NULL || update_portbits(port_bits) < 0)
+       /* ensure existing afid bitmap */
+       if (afids_array == NULL) {
+               afids_array = malloc(AFID_ACNT * sizeof(uint32_t));
+               if (afids_array == NULL || update_afids(afids_array) < 0)
                        return -1;
        }
 
-       /* allocates the port */
-       port = first_free_port(port_bits);
-       if (port >= 0)
-               HTTP_PORT_SET(port_bits, port);
+       /* allocates the afid */
+       afid = first_free_afid(afids_array);
+       if (afid < 0 && errno == EADDRNOTAVAIL) {
+               /* no more ids, try to rescan */
+               memset(afids_array, 0, AFID_ACNT * sizeof(uint32_t));
+               if (update_afids(afids_array) >= 0)
+                       afid = first_free_afid(afids_array);
+       }
+       if (afid >= 0)
+               AFID_SET(afids_array, afid);
 
-       return port;
+       return afid;
 }
 
 static int check_defined(const void *data, const char *name)
@@ -300,7 +312,7 @@ static int for_all_content(const struct wgt_desc *desc, int (*action)(const char
        rc = action(desc->content_src, desc->content_type);
        feat = desc->features;
        while (feat) {
-               if (!strcmp(feat->name, "urn:AGL:widget:provided-unit")) {
+               if (!strcmp(feat->name, FWK_PREFIX"widget:provided-unit")) {
                        src = wgt_info_param(feat, "content.src");
                        type = wgt_info_param(feat, "content.type");
                        rc2 = action(src, type);
@@ -386,7 +398,11 @@ static int get_target_directory(char target[PATH_MAX], const char *root, const s
 {
        int rc;
 
+#if DISTINCT_VERSIONS
        rc = snprintf(target, PATH_MAX, "%s/%s/%s", root, desc->id, desc->ver);
+#else
+       rc = snprintf(target, PATH_MAX, "%s/%s", root, desc->id);
+#endif
        if (rc < PATH_MAX)
                rc = 0;
        else {
@@ -447,7 +463,7 @@ static int install_file_properties(const struct wgt_desc *desc)
        rc = 0;
        feat = desc->features;
        while (feat) {
-               if (!strcmp(feat->name, "urn:AGL:widget:file-properties")) {
+               if (!strcmp(feat->name, FWK_PREFIX"widget:file-properties")) {
                        param = feat->params;
                        while (param) {
                                if (!strcmp(param->value, "executable")) {
@@ -469,22 +485,60 @@ static int install_file_properties(const struct wgt_desc *desc)
        return rc;
 }
 
+static int is_path_public(const char *path, const struct wgt_desc *desc)
+{
+       const struct wgt_desc_icon *icon;
+       const struct wgt_desc_feature *feat;
+       const struct wgt_desc_param *param;
+       size_t len;
+
+       /* icons are public */
+       icon = desc->icons;
+       while (icon != NULL) {
+               len = strlen(icon->src);
+               if (!memcmp(path, icon->src, len) && (path[len] == 0 || path[len] == '/'))
+                       return 1;
+               icon = icon->next;
+       }
+
+       /* provided bindings are public */
+       feat = desc->features;
+       while (feat != NULL) {
+               if (strcasecmp(feat->name, "urn:AGL:widget:provided-binding") == 0
+                || strcasecmp(feat->name, "urn:AGL:widget:public-files") == 0) {
+                       param = feat->params;
+                       while(param != NULL) {
+                               if (strcmp(param->value, path) == 0)
+                                       return 1;
+                               param = param->next;
+                       }
+               }
+               feat = feat->next;
+       }
+
+       /* otherwise no */
+       return 0;
+}
+
 static int install_security(const struct wgt_desc *desc)
 {
        char path[PATH_MAX], *head;
-       const char *icon, *perm;
-       int rc;
-       unsigned int i, n, len, lic, lf;
+       const char *perm;
+       int rc, public;
+       unsigned int i, n, len, lf, j;
        struct filedesc *f;
-
+       struct pathent {
+               struct pathent *next;
+               unsigned int len;
+               int public;
+               char name[];
+       } *pe0, *pe2, *ppe;
+
+       pe0 = NULL;
        rc = secmgr_init(desc->id);
        if (rc)
                goto error;
 
-       rc = secmgr_path_public_read_only(workdir);
-       if (rc)
-               goto error2;
-
        /* instal the files */
        head = stpcpy(path, workdir);
        assert(head < path + sizeof path);
@@ -496,23 +550,78 @@ static int install_security(const struct wgt_desc *desc)
        }
        len--;
        *head++ = '/';
-       icon = desc->icons ? desc->icons->src : NULL;
-       lic = (unsigned)(icon ? strlen(icon) : 0);
+
+       /* build root entry */
+       pe0 = malloc(1 + sizeof *pe0);
+       if (pe0 == NULL)
+               goto error2;
+       pe0->next = NULL;
+       pe0->len = 0;
+       pe0->public = 0;
+       pe0->name[0] = 0;
+
+       /* build list of entries */
        n = file_count();
-       i = 0;
-       while(i < n) {
-               f = file_of_index(i++);
-               lf = (unsigned)strlen(f->name);
-               if (lf >= len) {
-                       ERROR("path too long in install_security");
-                       errno = ENAMETOOLONG;
-                       goto error2;
+       for (i = 0 ; i < n ; i++) {
+               f = file_of_index(i);
+               public = is_path_public(f->name, desc);
+               pe0->public |= public;
+               lf = j = 0;
+               while(f->name[j] == '/')
+                       j++;
+               while (f->name[j] != 0) {
+                       /* copy next entry of the path */
+                       while(f->name[j] && f->name[j] != '/') {
+                               if (lf + 1 >= len) {
+                                       ERROR("path too long in install_security");
+                                       errno = ENAMETOOLONG;
+                                       goto error2;
+                               }
+                               head[lf++] = f->name[j++];
+                       }
+                       head[lf] = 0;
+
+                       /* search if it already exists */
+                       ppe = pe0;
+                       pe2 = pe0->next;
+                       while (pe2 != NULL && pe2->len < lf) {
+                               ppe = pe2;
+                               pe2 = pe2->next;
+                       }
+                       while (pe2 != NULL && pe2->len == lf && strcmp(head, pe2->name)) {
+                               ppe = pe2;
+                               pe2 = pe2->next;
+                       }
+
+                       if (pe2 != NULL && pe2->len == lf)
+                               /* existing, update public status */
+                               pe2->public |= public;
+                       else {
+                               /* not existing, create it */
+                               pe2 = malloc(lf + 1 + sizeof *pe2);
+                               if (pe2 == NULL)
+                                       goto error2;
+                               pe2->next = ppe->next;
+                               pe2->len = lf;
+                               pe2->public = public;
+                               memcpy(pe2->name, head, 1 + lf);
+                               ppe->next = pe2;
+                       }
+
+                       /* prepare next path entry */
+                       head[lf++] = '/';       
+                       while(f->name[j] == '/')
+                               j++;
                }
-               strcpy(head, f->name);
-               if (lf <= lic && icon && !memcmp(f->name, icon, lf) && (!f->name[lf] || f->name[lf] == '/'))
+       }
+
+       /* set the path entries */
+       for (pe2 = pe0 ; pe2 != NULL ; pe2 = pe2->next) {
+               strcpy(head, pe2->name);
+               if (pe2->public)
                        rc = secmgr_path_public_read_only(path);
                else
-                       rc = secmgr_path_read_only(path);
+                       rc = secmgr_path_private(path);
                if (rc)
                        goto error2;
        }
@@ -527,12 +636,30 @@ static int install_security(const struct wgt_desc *desc)
                perm = next_usable_permission();
        }
 
+       /* install default permissions */
+       n = (unsigned int)(sizeof default_permissions / sizeof *default_permissions);
+       for (i = 0 ; i < n ; i++) {
+               perm = default_permissions[i];
+               rc = secmgr_permit(perm);
+               INFO("permitting %s %s", perm, rc ? "FAILED!" : "success");
+               if (rc)
+                       goto error2;
+       }
+
        rc = secmgr_install();
-       return rc;
+       goto end;
 error2:
        secmgr_cancel();
 error:
-       return -1;
+       rc = -1;
+end:
+       /* free memory of path entries */
+       while (pe0 != NULL) {
+               ppe = pe0;
+               pe0 = pe0->next;
+               free(ppe);
+       }
+       return rc;
 }
 
 /* install the widget of the file */
@@ -541,7 +668,7 @@ struct wgt_info *install_widget(const char *wgtfile, const char *root, int force
        struct wgt_info *ifo;
        const struct wgt_desc *desc;
        char installdir[PATH_MAX];
-       int port, err;
+       int err, rc;
        struct unitconf uconf;
 
        NOTICE("-- INSTALLING widget %s to %s --", wgtfile, root);
@@ -556,7 +683,12 @@ struct wgt_info *install_widget(const char *wgtfile, const char *root, int force
        if (zread(wgtfile, 0))
                goto error2;
 
-       if (check_all_signatures(DEFAULT_ALLOW_NO_SIGNATURE))
+#if defined(ALLOW_NO_SIGNATURE)
+       rc = check_all_signatures(1);
+#else
+       rc = check_all_signatures(0);
+#endif
+       if (rc)
                goto error2;
 
        ifo = wgt_info_createat(workdirfd, NULL, 1, 1, 1);
@@ -596,13 +728,10 @@ struct wgt_info *install_widget(const char *wgtfile, const char *root, int force
        if (install_file_properties(desc))
                goto error4;
 
-       port = get_port();
-       if (port < 0)
-               goto error4;
-
        uconf.installdir = installdir;
        uconf.icondir = FWK_ICON_DIR;
-       uconf.port = port;
+       uconf.new_afid = get_new_afid;
+       uconf.base_http_ports = HTTP_PORT_BASE;
        if (unit_install(ifo, &uconf))
                goto error4;