don't change of directory anymore
authorJosé Bollo <jose.bollo@iot.bzh>
Fri, 11 Dec 2015 13:57:32 +0000 (14:57 +0100)
committerJosé Bollo <jose.bollo@iot.bzh>
Fri, 11 Dec 2015 13:57:32 +0000 (14:57 +0100)
Change-Id: I9f5906d3e053b3fa0f3000d07c4af3f666fe079a

18 files changed:
.gitignore
src/Makefile.am
src/wgt-info.c
src/wgt-info.h
src/wgt.c
src/wgt.h
src/wgtpkg-digsig.c
src/wgtpkg-files.c
src/wgtpkg-info.c
src/wgtpkg-install.c
src/wgtpkg-installer.c [new file with mode: 0644]
src/wgtpkg-pack.c
src/wgtpkg-permissions.c [new file with mode: 0644]
src/wgtpkg-sign.c
src/wgtpkg-workdir.c
src/wgtpkg-xmlsec.c
src/wgtpkg-zip.c
src/wgtpkg.h

index 4773e7e..96295c2 100644 (file)
@@ -1,4 +1,4 @@
-wgtpkg-install
+wgtpkg-installer
 wgtpkg-pack
 wgtpkg-sign
 wgtpkg-info
index c74983e..9767941 100644 (file)
@@ -1,4 +1,4 @@
-bin_PROGRAMS = wgtpkg-install wgtpkg-pack wgtpkg-sign wgtpkg-info appfwk
+bin_PROGRAMS = wgtpkg-installer wgtpkg-pack wgtpkg-sign wgtpkg-info appfwk
 
 OTHERSRCS = \
        verbose.c
@@ -8,6 +8,8 @@ WGTPKGSRCS = \
        wgtpkg-certs.c \
        wgtpkg-digsig.c \
        wgtpkg-files.c \
+       wgtpkg-install.c \
+       wgtpkg-permissions.c \
        wgtpkg-workdir.c \
        wgtpkg-xmlsec.c \
        wgtpkg-zip.c
@@ -30,7 +32,11 @@ pkgsysconfdir = .
 AM_CFLAGS  = -Wall -Wno-pointer-sign
 AM_CFLAGS += -ffunction-sections -fdata-sections
 AM_CFLAGS += ${ZIP_CFLAGS} ${XML2_CFLAGS} ${OPENSSL_CFLAGS} ${XMLSEC_CFLAGS}
-AM_CFLAGS += -DPKGSYSCONFDIR=\"$(pkgsysconfdir)\" 
+
+
+AM_CFLAGS += -DPKGSYSCONFDIR=\"$(pkgsysconfdir)\"
+AM_CFLAGS += -DPREFIXPERMISSION=\"urn:agl-perm:\"
+AM_CFLAGS += -DAGLWIDGET=\"urn:agl-widget\"
 
 AM_LDFLAGS = -Wl,--gc-sections
 
@@ -40,7 +46,7 @@ wgtpkg_sign_SOURCES = wgtpkg-sign.c ${WGTPKGSRCS} ${OTHERSRCS}
 
 wgtpkg_pack_SOURCES = wgtpkg-pack.c ${WGTPKGSRCS} ${OTHERSRCS}
 
-wgtpkg_install_SOURCES = wgtpkg-install.c ${WGTPKGSRCS} ${WGTSRCS} ${SECWRP} ${OTHERSRCS}
+wgtpkg_installer_SOURCES = wgtpkg-installer.c ${WGTPKGSRCS} ${WGTSRCS} ${SECWRP} ${OTHERSRCS}
 
 wgtpkg_info_SOURCES = wgtpkg-info.c ${WGTPKGSRCS} ${WGTSRCS} ${OTHERSRCS}
 
index ddecb9a..d5f664b 100644 (file)
@@ -334,7 +334,7 @@ static void dump_desc(struct wgt_desc *desc, FILE *f, const char *prefix)
        }
 }
 
-struct wgt_info *wgt_info_get(struct wgt *wgt, int icons, int features, int preferences)
+struct wgt_info *wgt_info_create(struct wgt *wgt, int icons, int features, int preferences)
 {
        int rc;
        struct wgt_info *result;
@@ -366,11 +366,30 @@ struct wgt_info *wgt_info_get(struct wgt *wgt, int icons, int features, int pref
        return result;
 }
 
+struct wgt_info *wgt_info_createat(int dirfd, const char *pathname, int icons, int features, int preferences)
+{
+       struct wgt_info *result = NULL;
+       struct wgt *wgt = wgt_createat(dirfd, pathname);
+       if (wgt) {
+               result = wgt_info_create(wgt, icons, features, preferences);
+               wgt_unref(wgt);
+       }
+       return result;
+}
+
 const struct wgt_desc *wgt_info_desc(struct wgt_info *ifo)
 {
+       assert(ifo);
        return &ifo->desc;
 }
 
+struct wgt *wgt_info_wgt(struct wgt_info *ifo)
+{
+       assert(ifo);
+       assert(ifo->wgt);
+       return ifo->wgt;
+}
+
 void wgt_info_addref(struct wgt_info *ifo)
 {
        assert(ifo);
index 3cb6a5c..4d2007d 100644 (file)
@@ -68,8 +68,10 @@ struct wgt_desc {
 
 struct wgt;
 struct wgt_info;
-extern struct wgt_info *wgt_info_get(struct wgt *wgt, int icons, int features, int preferences);
+extern struct wgt_info *wgt_info_create(struct wgt *wgt, int icons, int features, int preferences);
+extern struct wgt_info *wgt_info_createat(int dirfd, const char *pathname, int icons, int features, int preferences);
 extern const struct wgt_desc *wgt_info_desc(struct wgt_info *ifo);
+extern struct wgt *wgt_info_wgt(struct wgt_info *ifo);
 extern void wgt_info_addref(struct wgt_info *ifo);
 extern void wgt_info_unref(struct wgt_info *ifo);
 extern void wgt_info_dump(struct wgt_info *ifo, int fd, const char *prefix);
index 1ae1a13..980719b 100644 (file)
--- a/src/wgt.c
+++ b/src/wgt.c
@@ -132,12 +132,10 @@ int wgt_connectat(struct wgt *wgt, int dirfd, const char *pathname)
 
        assert(wgt);
 
-       rfd = dirfd;
-       if (pathname) {
-               rfd = openat(rfd, pathname, O_PATH|O_DIRECTORY);
-               if (rfd < 0)
-                       return rfd;
-       }
+       rfd = (pathname && *pathname) ? openat(dirfd, pathname, O_PATH|O_DIRECTORY) : dup(dirfd);
+       if (rfd < 0)
+               return rfd;
+
        if (wgt->rootfd >= 0)
                close(wgt->rootfd);
        wgt->rootfd = rfd;
@@ -149,6 +147,18 @@ int wgt_connect(struct wgt *wgt, const char *pathname)
        return wgt_connectat(wgt, AT_FDCWD, pathname);
 }
 
+struct wgt *wgt_createat(int dirfd, const char *pathname)
+{
+       struct wgt *wgt = wgt_create();
+       if (wgt) {
+               if (wgt_connectat(wgt, dirfd, pathname)) {
+                       wgt_unref(wgt);
+                       wgt = NULL;
+               }
+       }
+       return wgt;
+}
+
 int wgt_is_connected(struct wgt *wgt)
 {
        assert(wgt);
index f159a3b..87648ec 100644 (file)
--- a/src/wgt.h
+++ b/src/wgt.h
 struct wgt;
 
 extern struct wgt *wgt_create();
+extern struct wgt *wgt_createat(int dirfd, const char *pathname);
+
 extern void wgt_addref(struct wgt *wgt);
 extern void wgt_unref(struct wgt *wgt);
 
 extern int wgt_connect(struct wgt *wgt, const char *pathname);
-extern int wgt_connectat(struct wgt *wgt, int fd, const char *pathname);
+extern int wgt_connectat(struct wgt *wgt, int dirfd, const char *pathname);
 extern void wgt_disconnect(struct wgt *wgt);
 extern int wgt_is_connected(struct wgt *wgt);
 
index 6e66e38..3aa4da3 100644 (file)
 #include <string.h>
 #include <syslog.h>
 #include <assert.h>
+#include <fcntl.h>
+#include <unistd.h>
 
 #include <libxml/parser.h>
 #include <libxml/tree.h>
 #include <libxml/uri.h>
+#include <libxml/xmlsave.h>
 
 
 #include "verbose.h"
@@ -278,7 +281,7 @@ error:
 /* verify the digital signature of the file described by 'fdesc' */
 int verify_digsig(struct filedesc *fdesc)
 {
-       int res;
+       int res, fd;
 
        assert ((fdesc->flags & flag_signature) != 0);
        debug("-- checking file %s",fdesc->name);
@@ -288,7 +291,13 @@ int verify_digsig(struct filedesc *fdesc)
        clear_certificates();
 
        /* reads and xml parses the signature file */
-       document = xmlReadFile(fdesc->name, NULL, 0);
+       fd = openat(workdirfd, fdesc->name, O_RDONLY);
+       if (fd < 0) {
+               syslog(LOG_ERR, "cant't open file %s", fdesc->name);
+               return -1;
+       }
+       document = xmlReadFd(fd, fdesc->name, NULL, 0);
+       close(fd);
        if (document == NULL) {
                syslog(LOG_ERR, "xml parse of file %s failed", fdesc->name);
                return -1;
@@ -328,7 +337,8 @@ int create_digsig(int index, const char *key, const char **certs)
 {
        struct filedesc *fdesc;
        xmlDocPtr doc;
-       int rc, len;
+       int rc, len, fd;
+       xmlSaveCtxtPtr ctx;
 
        rc = -1;
 
@@ -343,13 +353,27 @@ int create_digsig(int index, const char *key, const char **certs)
                goto error2;
 
        /* save the doc as file */
-       len = xmlSaveFormatFileEnc(fdesc->name, doc, NULL, 0);
+       fd = openat(workdirfd, fdesc->name, O_WRONLY|O_CREAT|O_TRUNC, 0644);
+       if (fd < 0) {
+               syslog(LOG_ERR, "cant open %s for write", fdesc->name);
+               goto error2;
+       }
+       ctx = xmlSaveToFd(fd, NULL, XML_SAVE_FORMAT);
+       if (!ctx) {
+               syslog(LOG_ERR, "xmlSaveToFd failed for %s", fdesc->name);
+               goto error3;
+       }
+       len = xmlSaveDoc(ctx, doc);
        if (len < 0) {
-               syslog(LOG_ERR, "xmlSaveFormatFileEnc to %s failed", fdesc->name);
+               syslog(LOG_ERR, "xmlSaveDoc to %s failed", fdesc->name);
                goto error2;
        }
 
        rc = 0;
+error4:
+       xmlSaveClose(ctx);
+error3:
+       close(fd);
 error2:
        xmlFreeDoc(doc);
 error:
index 06aac83..8840fa9 100644 (file)
@@ -21,6 +21,7 @@
 #include <syslog.h>
 #include <dirent.h>
 #include <stdio.h>
+#include <fcntl.h>
 
 #include "wgtpkg.h"
 
@@ -248,20 +249,23 @@ void file_clear_flags()
 
 static int fill_files_rec(char name[PATH_MAX], int offset)
 {
-       int len, err;
+       int len, err, fd;
        DIR *dir;
        struct dirent *ent;
 
-       if (offset == 0)
-               dir = opendir(".");
-       else {
-               dir = opendir(name);
-               name[offset++] = '/';
+       fd = openat(workdirfd, offset ? name : ".", O_DIRECTORY|O_RDONLY);
+       if (fd < 0) {
+               syslog(LOG_ERR, "openat %.*s failed in fill_files_rec", offset, name);
+               return -1;
        }
+       dir = fdopendir(fd);
        if (!dir) {
-               syslog(LOG_ERR, "opendir %.*s failed in zwr", offset, name);
+               syslog(LOG_ERR, "opendir %.*s failed in fill_files_rec", offset, name);
+               close(fd);
                return -1;
        }
+       if (offset)
+               name[offset++] = '/';
 
        ent = readdir(dir);
        while (ent != NULL) {
index 1a7724b..7854b09 100644 (file)
@@ -105,51 +105,15 @@ int main(int ac, char **av)
        return 0;
 }
 
-static struct wgt *wgt_at_workdir()
-{
-       int rc, wfd;
-       struct wgt *wgt;
-
-       wfd = workdirfd();
-       if (wfd < 0)
-               return NULL;
-
-       wgt = wgt_create();
-       if (!wgt) {
-               syslog(LOG_ERR, "failed to allocate wgt");
-               close(wfd);
-               return NULL;
-       }
-
-       rc = wgt_connectat(wgt, wfd, NULL);
-       if (rc) {
-               syslog(LOG_ERR, "failed to connect wgt to workdir");
-               close(wfd);
-               wgt_unref(wgt);
-               return NULL;
-       }
-
-       return wgt;
-}
-
-
 static int check_and_show()
 {
-       struct wgt *wgt;
        struct wgt_info *ifo;
 
-       wgt = wgt_at_workdir();
-       if (!wgt)
-               return -1;
-
-       ifo = wgt_info_get(wgt, 1, 1, 1);
-       if (!ifo) {
-               wgt_unref(wgt);
+       ifo = wgt_info_createat(workdirfd, NULL, 1, 1, 1);
+       if (!ifo)
                return -1;
-       }
        wgt_info_dump(ifo, 1, "");
        wgt_info_unref(ifo);
-       wgt_unref(wgt);
        return 0;
 }
 
@@ -164,9 +128,6 @@ static void show(const char *wgtfile)
                return;
        }
 
-       if (enter_workdir(0))
-               goto error2;
-
        if (zread(wgtfile, 0))
                goto error2;
 
index b6237b3..ee21d8f 100644 (file)
  limitations under the License.
 */
 
-#define _BSD_SOURCE /* see readdir */
+#define _GNU_SOURCE
 
-#include <stdlib.h>
-#include <stdio.h>
-#include <string.h>
-#include <dirent.h>
-#include <unistd.h>
-#include <limits.h>
 #include <errno.h>
 #include <syslog.h>
-#include <getopt.h>
+#include <string.h>
 
 #include "verbose.h"
 #include "wgtpkg.h"
 #include "wgt.h"
 #include "wgt-info.h"
 
-static const char appname[] = "wgtpkg-install";
-static const char *root;
-static char **permissions = NULL;
-static int force;
-
-static void install(const char *wgtfile);
-static void add_permissions(const char *list);
-
-static void usage()
-{
-       printf(
-               "usage: %s [-f] [-q] [-v] [-p list] rootdir wgtfile...\n"
-               "\n"
-               "   rootdir       the root directory for installing\n"
-               "   -p list       a list of comma separated permissions to allow\n"
-               "   -f            force overwriting\n"
-               "   -q            quiet\n"
-               "   -v            verbose\n"
-               "\n",
-               appname
-       );
-}
-
-static struct option options[] = {
-       { "permissions", required_argument, NULL, 'p' },
-       { "force",       no_argument,       NULL, 'f' },
-       { "help",        no_argument,       NULL, 'h' },
-       { "quiet",       no_argument,       NULL, 'q' },
-       { "verbose",     no_argument,       NULL, 'v' },
-       { NULL, 0, NULL, 0 }
-};
-
-/* install the widgets of the list */
-int main(int ac, char **av)
+static int check_temporary_constraints(const struct wgt_desc *desc)
 {
-       int i;
-       char *wpath;
-
-       openlog(appname, LOG_PERROR, LOG_AUTH);
-
-       xmlsec_init();
-
-       force = 0;
-       for (;;) {
-               i = getopt_long(ac, av, "hfqvp:", options, NULL);
-               if (i < 0)
-                       break;
-               switch (i) {
-               case 'f':
-                       force = 1;
-                       break;
-               case 'h':
-                       usage();
-                       return 0;
-               case 'q':
-                       if (verbosity)
-                               verbosity--;
-                       break;
-               case 'v':
-                       verbosity++;
-                       break;
-               case 'p':
-                       add_permissions(optarg);
-                       break;
-               case ':':
-                       syslog(LOG_ERR, "missing argument value");
-                       return 1;
-               default:
-                       syslog(LOG_ERR, "unrecognized option");
-                       return 1;
-               }
+       if (!desc->icons) {
+               syslog(LOG_ERR, "widget has not icon defined (temporary constraints)");
+               errno = EINVAL;
+               return -1;
        }
-
-       ac -= optind;
-       if (ac < 2) {
-               syslog(LOG_ERR, "arguments are missing");
-               return 1;
+       if (desc->icons->next) {
+               syslog(LOG_ERR, "widget has more than one icon defined (temporary constraints)");
+               errno = EINVAL;
+               return -1;
        }
-
-       /* canonic names for files */
-       av += optind;
-       for (i = 0 ; av[i] != NULL ; i++) {
-               wpath = realpath(av[i], NULL);
-               if (wpath == NULL) {
-                       syslog(LOG_ERR, "error while getting realpath of %dth widget: %s", i+1, av[i]);
-                       return 1;
-               }
-               av[i] = wpath;
+       if (!desc->content_src) {
+               syslog(LOG_ERR, "widget has not content defined (temporary constraints)");
+               errno = EINVAL;
+               return -1;
+       }
+       if (!desc->content_type) {
+               syslog(LOG_ERR, "widget has not type for its content (temporary constraints)");
+               errno = EINVAL;
+               return -1;
        }
-       root = *av++;
-
-       /* install widgets */
-       for ( ; *av ; av++)
-               install(*av);
-
        return 0;
 }
 
-/* checks if the permission 'name' is granted */
-static int has_permission(const char *name)
+static int check_permissions(const char *name, int required)
 {
-       char **p = permissions;
-       if (p) {
-               while(*p) {
-                       if (0 == strcmp(*p, name))
-                               return 1;
-                       p++;
+       if (permission_exists(name)) {
+               if (request_permission(name)) {
+                       debug("granted permission: %s", name);
+               } else if (required) {
+                       syslog(LOG_ERR, "ungranted permission required: %s", name);
+                       errno = EPERM;
+                       return 0;
+               } else {
+                       notice("ungranted permission optional: %s", name);
                }
        }
-       return 0;
+       return 1;
 }
 
-/* add permissions granted for installation */
-static void add_permissions(const char *list)
+static int check_widget(const struct wgt_desc *desc)
 {
-       char **ps, *p;
-       const char *iter;
-       int n, on;
-       static const char separators[] = " \t\n\r,";
-
-       n = 0;
-       iter = list + strspn(list, separators);
-       while(*iter) {
-               n++;
-               iter += strcspn(iter, separators);
-               iter += strspn(iter, separators);
-       }
-       if (n == 0)
-               return;
-
-       on = 0;
-       ps = permissions;
-       if (ps)
-               while(*ps++)
-                       on++;
-
-       ps = realloc(permissions, (1 + on + n) * sizeof * ps);
-       if (!ps) {
-               syslog(LOG_ERR, "Can't allocate memory for permissions");
-               exit(1);
-       }
-
-       permissions = ps;
-       ps[on] = NULL;
-
-       iter = list + strspn(list, separators);
-       while(*iter) {
-               n = strcspn(iter, separators);
-               p = strndup(iter, n);
-               if (!p) {
-                       syslog(LOG_ERR, "Can't allocate permission");
-                       exit(1);
+       int result;
+       const struct wgt_desc_feature *feature;
+       const char *name;
+
+       result = check_temporary_constraints(desc);
+       feature = desc->features;
+       while(feature) {
+               name = feature->name;
+               if (0 == strcmp(name, AGLWIDGET)) {
+                       
+               } else {
+                       if (!check_permissions(feature->name, feature->required))
+                               result = -1;
                }
-               if (has_permission(p))
-                       free(p);
-               else {
-                       ps[on] = p;
-                       ps[++on] = NULL;
-               }
-               iter += n;
-               iter += strspn(iter, separators);
+               feature = feature->next;
        }
+       return result;
 }
 
-
-static struct wgt *wgt_at_workdir()
+static int place(const char *root, const char *appid, const char *version, int force)
 {
-       int rc, wfd;
-       struct wgt *wgt;
+       char newdir[PATH_MAX];
+       int rc;
 
-       wfd = workdirfd();
-       if (wfd < 0)
-               return NULL;
-
-       wgt = wgt_create();
-       if (!wgt) {
-               syslog(LOG_ERR, "failed to allocate wgt");
-               close(wfd);
-               return NULL;
-       }
-
-       rc = wgt_connectat(wgt, wfd, NULL);
-       if (rc) {
-               syslog(LOG_ERR, "failed to connect wgt to workdir");
-               close(wfd);
-               wgt_unref(wgt);
-               return NULL;
+       rc = snprintf(newdir, sizeof newdir, "%s/%s/%s", root, appid, version);
+       if (rc >= sizeof newdir) {
+               syslog(LOG_ERR, "path to long: %s/%s/%s", root, appid, version);
+               errno = EINVAL;
+               return -1;
        }
 
-       return wgt;
+       rc = move_workdir(newdir, 1, force);
+       return rc;
 }
 
-
-static int check_and_place()
+/* install the widget of the file */
+void install_widget(const char *wgtfile, const char *root, int force)
 {
-       struct wgt *wgt;
        struct wgt_info *ifo;
+       const struct wgt_desc *desc;
 
-       wgt = wgt_at_workdir();
-       if (!wgt)
-               return -1;
-
-       ifo = wgt_info_get(wgt, 1, 1, 1);
-       if (!ifo) {
-               wgt_unref(wgt);
-               return -1;
-       }
-       wgt_info_dump(ifo, 1, "");
-       wgt_info_unref(ifo);
-       wgt_unref(wgt);
-       return 0;
-}
-
-/* install the widget of the file */
-static void install(const char *wgtfile)
-{
        notice("-- INSTALLING widget %s --", wgtfile);
 
        /* workdir */
@@ -255,20 +117,29 @@ static void install(const char *wgtfile)
                goto error1;
        }
 
-       if (enter_workdir(0))
-               goto error2;
-
        if (zread(wgtfile, 0))
                goto error2;
 
        if (check_all_signatures())
                goto error2;
 
+       ifo = wgt_info_createat(workdirfd, NULL, 1, 1, 1);
+       if (!ifo)
+               goto error2;
+
+       desc = wgt_info_desc(ifo);
+       if (check_widget(desc))
+               goto error3;
+
+/*
        if (check_and_place())
                goto error2;
-       
+*/     
        return;
 
+error3:
+       wgt_info_unref(ifo);
+
 error2:
        remove_workdir();
 
@@ -276,4 +147,3 @@ error1:
        return;
 }
 
-
diff --git a/src/wgtpkg-installer.c b/src/wgtpkg-installer.c
new file mode 100644 (file)
index 0000000..e8568b8
--- /dev/null
@@ -0,0 +1,125 @@
+/*
+ Copyright 2015 IoT.bzh
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+     http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+*/
+
+#define _GNU_SOURCE
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <dirent.h>
+#include <unistd.h>
+#include <limits.h>
+#include <errno.h>
+#include <syslog.h>
+#include <getopt.h>
+
+#include "verbose.h"
+#include "wgtpkg.h"
+
+static const char appname[] = "wgtpkg-install";
+static const char *root;
+static int force;
+
+static void usage()
+{
+       printf(
+               "usage: %s [-f] [-q] [-v] [-p list] rootdir wgtfile...\n"
+               "\n"
+               "   rootdir       the root directory for installing\n"
+               "   -p list       a list of comma separated permissions to allow\n"
+               "   -f            force overwriting\n"
+               "   -q            quiet\n"
+               "   -v            verbose\n"
+               "\n",
+               appname
+       );
+}
+
+static struct option options[] = {
+       { "permissions", required_argument, NULL, 'p' },
+       { "force",       no_argument,       NULL, 'f' },
+       { "help",        no_argument,       NULL, 'h' },
+       { "quiet",       no_argument,       NULL, 'q' },
+       { "verbose",     no_argument,       NULL, 'v' },
+       { NULL, 0, NULL, 0 }
+};
+
+/* install the widgets of the list */
+int main(int ac, char **av)
+{
+       int i;
+       char *wpath;
+
+       openlog(appname, LOG_PERROR, LOG_AUTH);
+
+       xmlsec_init();
+
+       force = 0;
+       for (;;) {
+               i = getopt_long(ac, av, "hfqvp:", options, NULL);
+               if (i < 0)
+                       break;
+               switch (i) {
+               case 'f':
+                       force = 1;
+                       break;
+               case 'h':
+                       usage();
+                       return 0;
+               case 'q':
+                       if (verbosity)
+                               verbosity--;
+                       break;
+               case 'v':
+                       verbosity++;
+                       break;
+               case 'p':
+                       grant_permission_list(optarg);
+                       break;
+               case ':':
+                       syslog(LOG_ERR, "missing argument value");
+                       return 1;
+               default:
+                       syslog(LOG_ERR, "unrecognized option");
+                       return 1;
+               }
+       }
+
+       ac -= optind;
+       if (ac < 2) {
+               syslog(LOG_ERR, "arguments are missing");
+               return 1;
+       }
+
+       /* canonic names for files */
+       av += optind;
+       for (i = 0 ; av[i] != NULL ; i++) {
+               wpath = realpath(av[i], NULL);
+               if (wpath == NULL) {
+                       syslog(LOG_ERR, "error while getting realpath of %dth widget: %s", i+1, av[i]);
+                       return 1;
+               }
+               av[i] = wpath;
+       }
+       root = *av++;
+
+       /* install widgets */
+       for ( ; *av ; av++)
+               install_widget(*av, root, force);
+
+       return 0;
+}
+
index be1e5ab..451d427 100644 (file)
@@ -139,7 +139,7 @@ int main(int ac, char **av)
        notice("-- PACKING widget %s from directory %s", wgtfile, directory);
 
        /* creates an existing widget (for realpath it must exist) */
-       i = open(wgtfile, O_WRONLY|O_CREAT|O_NOCTTY|O_NONBLOCK, 0666);
+       i = open(wgtfile, O_WRONLY|O_CREAT|O_NOCTTY|O_NONBLOCK, 0644);
        if (i < 0) {
                syslog(LOG_ERR, "can't write widget %s", wgtfile);
                return 1;
@@ -155,7 +155,7 @@ int main(int ac, char **av)
        wgtfile = x;
 
        /* set and enter the workdir */
-       if (set_workdir(directory, 0) || enter_workdir(0))
+       if (set_workdir(directory, 0))
                return 1;
 
 
diff --git a/src/wgtpkg-permissions.c b/src/wgtpkg-permissions.c
new file mode 100644 (file)
index 0000000..25758e4
--- /dev/null
@@ -0,0 +1,132 @@
+/*
+ Copyright 2015 IoT.bzh
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+     http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+*/
+
+#define _GNU_SOURCE
+
+#include <errno.h>
+#include <syslog.h>
+#include <string.h>
+
+#include "wgtpkg.h"
+
+struct permission {
+       char *name;
+       unsigned granted: 1;
+       unsigned requested: 1;
+       unsigned level: 3;
+};
+
+static const char prefix_of_permissions[] = PREFIXPERMISSION;
+
+static int nrpermissions = 0;
+static struct permission *permissions = NULL;
+
+/* check is the name has the correct prefix for permissions */
+int is_standard_permission(const char *name)
+{
+       return 0 == memcmp(name, prefix_of_permissions, sizeof(prefix_of_permissions) - 1);
+}
+
+/* retrieves the permission of name */
+static struct permission *get_permission(const char *name)
+{
+       int i;
+
+       for (i = 0 ; i < nrpermissions ; i++)
+               if (0 == strcmp(permissions[i].name, name))
+                       return permissions+i;
+       return NULL;
+}
+
+/* add a permission of name */
+static struct permission *add_permission(const char *name)
+{
+       struct permission *p = get_permission(name);
+       if (!p) {
+               p = realloc(permissions, ((nrpermissions + 8) & ~7) * sizeof(*p));
+               if (p) {
+                       permissions = p;
+                       p = permissions + nrpermissions;
+                       memset(p, 0, sizeof(*p));
+                       p->name = strdup(name);
+                       if (!p->name)
+                               p = NULL;
+               }
+       }
+       return p;
+}
+
+/* remove any granting */
+void reset_permissions()
+{
+       int i;
+       for (i = 0 ; i < nrpermissions ; i++)
+               permissions[i].granted = 0;
+}
+
+/* remove any granting */
+void crop_permissions(unsigned level)
+{
+       int i;
+       for (i = 0 ; i < nrpermissions ; i++)
+               if (permissions[i].level < level)
+                       permissions[i].granted = 0;
+}
+
+/* add permissions granted for installation */
+void grant_permission_list(const char *list)
+{
+       struct permission *p;
+       char *iter, c;
+       int n;
+       static const char separators[] = " \t\n\r,";
+
+       iter = strdupa(list);
+       iter += strspn(iter, separators);
+       while(*iter) {
+               n = strcspn(iter, separators);
+               c = iter[n];
+               iter[n] = 0;
+               p = add_permission(iter);
+               if (!p) {
+                       syslog(LOG_ERR, "Can't allocate permission");
+                       exit(1);
+               }
+               p->granted = 1;
+               iter += n;
+               *iter =c;
+               iter += strspn(iter, separators);
+       }
+}
+
+/* checks if the permission 'name' is recorded */
+int permission_exists(const char *name)
+{
+       return !!get_permission(name);
+}
+
+/* request the permission, returns 1 if granted or 0 otherwise */
+int request_permission(const char *name)
+{
+       struct permission *p = get_permission(name);
+       if (p) {
+               p->requested = 1;
+               if (p->granted)
+                       return 1;
+       }
+       return 0;
+}
+
index c4faf29..031e1c3 100644 (file)
@@ -183,7 +183,7 @@ int main(int ac, char **av)
 #undef rp
 
        /* set and enter the workdir */
-       if (set_workdir(directory, 0) || enter_workdir(0))
+       if (set_workdir(directory, 0))
                return 1;
 
        if (fill_files())
index 12cfa24..59da1e6 100644 (file)
 #include <syslog.h>
 #include <errno.h>
 #include <fcntl.h>
+#include <assert.h>
 #include <sys/types.h>
 #include <sys/stat.h>
 
+#include "verbose.h"
 #include "wgtpkg.h"
 
-static int mode = 0700;
-static char workdir[PATH_MAX];
+static int mode = 0755;
+char workdir[PATH_MAX] = { 0, };
+int workdirfd = -1;
 
 /* removes recursively the content of a directory */
 static int clean_dirfd(int dirfd)
@@ -41,9 +44,14 @@ static int clean_dirfd(int dirfd)
                char spare[PATH_MAX];
        } entry;
 
+       dirfd = dup(dirfd);
+       if (dirfd < 0) {
+               syslog(LOG_ERR, "failed to dup the dirfd");
+               return -1;
+       }
        dir = fdopendir(dirfd);
        if (dir == NULL) {
-               syslog(LOG_ERR, "opendir failed in clean_dirfd");
+               syslog(LOG_ERR, "fdopendir failed in clean_dirfd");
                return -1;
        }
 
@@ -101,30 +109,21 @@ static int clean_dir(const char *directory)
        return rc;
 }
 
-/* removes the content of the working directory */
-int enter_workdir(int clean)
-{
-       int rc = chdir(workdir);
-       if (rc)
-               syslog(LOG_ERR, "entring workdir %s failed", workdir);
-       else if (clean)
-               rc = clean_dir(workdir);
-       return rc;
-}
-
 /* removes the working directory */
 void remove_workdir()
 {
-       enter_workdir(1);
-       chdir("..");
+       assert(workdirfd >= 0);
+       clean_dirfd(workdirfd);
+       close(workdirfd);
+       workdirfd = -1;
        rmdir(workdir);
+       workdir[0] = 0;
 }
 
-int set_workdir(const char *name, int create)
+static int set_real_workdir(const char *name, int create)
 {
-       int rc;
+       int rc, dirfd;
        size_t length;
-       struct stat s;
 
        /* check the length */
        length = strlen(name);
@@ -134,9 +133,10 @@ int set_workdir(const char *name, int create)
                return -1;
        }
 
-       rc = stat(name, &s);
-       if (rc) {
-               if (!create) {
+       /* opens the directory */
+       dirfd = openat(AT_FDCWD, name, O_DIRECTORY|O_RDONLY);
+       if (dirfd < 0) {
+               if (!create || errno != ENOENT) {
                        syslog(LOG_ERR, "no workdir %s", name);
                        return -1;
                }
@@ -145,17 +145,40 @@ int set_workdir(const char *name, int create)
                        syslog(LOG_ERR, "can't create workdir %s", name);
                        return -1;
                }
-
-       } else if (!S_ISDIR(s.st_mode)) {
-               syslog(LOG_ERR, "%s isn't a directory", name);
-               errno = ENOTDIR;
-               return -1;
+               dirfd = open(name, O_PATH|O_DIRECTORY);
+               if (dirfd < 0) {
+                       syslog(LOG_ERR, "can't open workdir %s", name);
+                       return -1;
+               }
        }
+
+       /* close the previous directory if any */
+       if (workdirfd >= 0)
+               close(workdirfd);
+       workdirfd = dirfd;
        memcpy(workdir, name, 1+length);
        return 0;
 }
 
-int make_workdir_base(const char *root, const char *prefix, int reuse)
+int set_workdir(const char *name, int create)
+{
+       char *rp;
+       int rc;
+
+       if (name[0] == '/')
+               return set_real_workdir(name, create);
+
+       rp = realpath(name, NULL);
+       if (!rp) {
+               syslog(LOG_ERR, "realpath failed for %s", name);
+               return -1;
+       }
+       rc = set_real_workdir(rp, create);
+       free(rp);
+       return rc;
+}
+
+static int make_real_workdir_base(const char *root, const char *prefix, int reuse)
 {
        int i, n, r, l;
 
@@ -167,6 +190,10 @@ int make_workdir_base(const char *root, const char *prefix, int reuse)
        }
        r = (int)(sizeof workdir) - n;
 
+       if (workdirfd >= 0)
+               close(workdirfd);
+       workdirfd = -1;
+
        /* create a temporary directory */
        for (i = 0 ; ; i++) {
                if (i == INT_MAX) {
@@ -188,25 +215,157 @@ int make_workdir_base(const char *root, const char *prefix, int reuse)
                if (reuse)
                        break;
        }
+       workdirfd = openat(AT_FDCWD, workdir, O_RDONLY|O_DIRECTORY);
+       if (workdirfd < 0) {
+               syslog(LOG_ERR, "error in onnection to workdir %s: %m", workdir);
+               rmdir(workdir);
+               return -1;
+       }
 
        return 0;
 }
 
+int make_workdir_base(const char *root, const char *prefix, int reuse)
+{
+       char *rp;
+       int rc;
+
+       if (root[0] == '/')
+               return make_real_workdir_base(root, prefix, reuse);
+
+       rp = realpath(root, NULL);
+       if (!rp) {
+               syslog(LOG_ERR, "realpath failed for %s", root);
+               return -1;
+       }
+       rc = make_real_workdir_base(rp, prefix, reuse);
+       free(rp);
+       return rc;
+}
+
 int make_workdir(int reuse)
 {
        return make_workdir_base(".", "PACK", reuse);
 }
 
-int workdirfd()
+static int move_real_workdir(const char *dest, int parents, int force)
 {
-       int result = open(workdir, O_PATH|O_DIRECTORY);
-       if (result < 0)
-               syslog(LOG_ERR, "can't get fd for workdir %.*s: %m", PATH_MAX, workdir);
-       return result;
+       int rc, len, l;
+       struct stat s;
+       char *copy;
+       const char *iter;
+
+       /* check length */
+       if (strlen(dest) >= sizeof workdir) {
+               syslog(LOG_ERR, "destination dirname too long");
+               errno = EINVAL;
+               return -1;
+       }
+
+       /* if an existing directory exist remove it if force */
+       rc = stat(dest, &s);
+       if (rc == 0) {
+               if (!S_ISDIR(s.st_mode)) {
+                       syslog(LOG_ERR, "in move_real_workdir, can't overwrite regular file %s", dest);
+                       errno = EEXIST;
+                       return -1;
+               }
+               if (!force) {
+                       syslog(LOG_ERR, "in move_real_workdir, can't overwrite regular file %s", dest);
+                       errno = EEXIST;
+                       return -1;
+               }
+               rc = clean_dir(dest);
+               if (rc) {
+                       syslog(LOG_ERR, "in move_real_workdir, can't clean dir %s", dest);
+                       return rc;
+               }
+               rc = rmdir(dest);
+               if (rc) {
+                       syslog(LOG_ERR, "in move_real_workdir, can't remove dir %s", dest);
+                       return rc;
+               }
+       } else {
+               /* check parent of dest */
+               iter = strrchr(dest, '/');
+               len = iter ? iter - dest : 0;
+               if (len) {
+                       /* is parent existing? */
+                       copy = strndupa(dest, len);
+                       rc = stat(copy, &s);
+                       if (!rc) {
+                               /* found an entry */
+                               if (!S_ISDIR(s.st_mode)) {
+                                       syslog(LOG_ERR, "in move_real_workdir, '%s' isn't a directory", copy);
+                                       errno = ENOTDIR;
+                                       return -1;
+                               }
+                       } else if (!parents) {
+                               /* parent entry not found but not allowed to create it */
+                               syslog(LOG_ERR, "in move_real_workdir, parent directory '%s' not found: %m", copy);
+                               return -1;
+                       } else {
+                               /* parent entries to be created */
+                               l = len;
+                               for(;;) {
+                                       /* backward loop */
+                                       rc = mkdir(copy, mode);
+                                       if (!rc)
+                                               break;
+                                       if (errno != ENOENT) {
+                                               syslog(LOG_ERR, "in move_real_workdir, mkdir '%s' failed: %m", copy);
+                                               return -1;
+                                       }
+                                       while (l && copy[l] != '/')
+                                               l--;
+                                       if (l == 0) {
+                                               syslog(LOG_ERR, "in move_real_workdir, internal error");
+                                               errno = EINVAL;
+                                               return -1;
+                                       }
+                                       copy[l] = 0;
+                               }
+                               while(l < len) {
+                                       /* forward loop */
+                                       copy[l] = '/';
+                                       while (copy[++l]);
+                                       rc = mkdir(copy, mode);
+                                       if (rc && errno != EEXIST) {
+                                               syslog(LOG_ERR, "in move_real_workdir, mkdir '%s' failed: %m", copy);
+                                               return -1;
+                                       }
+                               }
+                       }
+               }
+       }
+
+       /* try to rename now */
+       close(workdirfd);
+       workdirfd = -1;
+       rc = renameat(AT_FDCWD, workdir, AT_FDCWD, dest);
+       if (rc) {
+               syslog(LOG_ERR, "in move_real_workdir, renameat failed %s -> %s: %m", workdir, dest);
+               return -1;
+       }
+
+       return set_real_workdir(dest, 0);
 }
 
 int move_workdir(const char *dest, int parents, int force)
 {
-       
+       char *rp;
+       int rc;
+
+       if (dest[0] == '/')
+               return move_real_workdir(dest, parents, force);
+
+       rp = realpath(dest, NULL);
+       if (!rp) {
+               syslog(LOG_ERR, "realpath failed for %s", dest);
+               return -1;
+       }
+       rc = move_real_workdir(rp, parents, force);
+       free(rp);
+       return rc;
 }
 
index 843ea2b..a403b77 100644 (file)
@@ -21,6 +21,7 @@
 #include <dirent.h>
 #include <string.h>
 #include <assert.h>
+#include <fcntl.h>
 
 #include <libxml/tree.h>
 #include <xmlsec/xmlsec.h>
@@ -53,6 +54,7 @@ static int file_match_cb(const char *uri)
 static void *file_open_cb(const char *file)
 {
        struct filedesc *fdesc;
+       int fd;
        FILE *f;
 
        fdesc = file_of_name(file);
@@ -61,10 +63,13 @@ static void *file_open_cb(const char *file)
                return NULL;
        }
 
-       f = fopen(file, "r");
-       if (f == NULL)
+       fd = openat(workdirfd, file, O_RDONLY);
+       f = fd < 0 ? NULL : fdopen(fd, "r");
+       if (f == NULL) {
                syslog(LOG_ERR, "can't open file %s for reading", file);
-       else
+               if (fd >= 0)
+                       close(fd);
+       } else
                fdesc->flags |= flag_opened;
 
        return f;
index 9e51538..8ad00bb 100644 (file)
@@ -65,14 +65,14 @@ static int create_directory(char *file, int mode)
        char *last = strrchr(file, '/');
        if (last != NULL)
                *last = 0;
-       rc = mkdir(file, mode);
+       rc = mkdirat(workdirfd, file, mode);
        if (rc) {
                if (errno == EEXIST)
                        rc = 0;
                else if (errno == ENOENT) {
                        rc = create_directory(file, mode);
                        if (!rc)
-                               rc = mkdir(file, mode);
+                               rc = mkdirat(workdirfd, file, mode);
                }
        }
        if (rc)
@@ -84,10 +84,10 @@ static int create_directory(char *file, int mode)
 
 static int create_file(char *file, int fmode, int dmode)
 {
-       int fd = creat(file, fmode);
+       int fd = openat(workdirfd, file, O_CREAT|O_WRONLY|O_TRUNC, fmode);
        if (fd < 0 && errno == ENOENT) {
                if (!create_directory(file, dmode))
-                       fd = creat(file, fmode);
+                       fd = openat(workdirfd, file, O_CREAT|O_WRONLY|O_TRUNC, fmode);
        }
        if (fd < 0)
                syslog(LOG_ERR, "can't create file %s", file);
@@ -233,23 +233,28 @@ struct zws {
 
 static int zwr(struct zws *zws, int offset)
 {
-       int len, err;
+       int len, err, fd;
        DIR *dir;
        struct dirent *ent;
        zip_int64_t z64;
        struct zip_source *zsrc;
+       FILE *fp;
 
-       if (offset == 0)
-               dir = opendir(".");
-       else {
-               dir = opendir(zws->name);
-               zws->name[offset++] = '/';
+       fd = openat(workdirfd, offset ? zws->name : ".", O_DIRECTORY|O_RDONLY);
+       if (fd < 0) {
+               syslog(LOG_ERR, "opendir %.*s failed in zwr", offset, zws->name);
+               return -1;
        }
+       dir = fdopendir(fd);
        if (!dir) {
+               close(fd);
                syslog(LOG_ERR, "opendir %.*s failed in zwr", offset, zws->name);
                return -1;
        }
 
+       if (offset != 0)
+               zws->name[offset++] = '/';
+
        ent = readdir(dir);
        while (ent != NULL) {
                len = strlen(ent->d_name);
@@ -278,9 +283,21 @@ static int zwr(struct zws *zws, int offset)
                                        goto error;
                                break;
                        case DT_REG:
-                               zsrc = zip_source_file(zws->zip, zws->name, 0, 0);
+                               fd = openat(workdirfd, zws->name, O_RDONLY);
+                               if (fd < 0) {
+                                       syslog(LOG_ERR, "openat of %s failed", zws->name);
+                                       goto error;
+                               }
+                               fp = fdopen(fd, "r");
+                               if (fp == NULL) {
+                                       syslog(LOG_ERR, "fdopen of %s failed", zws->name);
+                                       close(fd);
+                                       goto error;
+                               }
+                               zsrc = zip_source_filep(zws->zip, fp, 0, 0);
                                if (zsrc == NULL) {
                                        syslog(LOG_ERR, "zip_source_file of %s failed", zws->name);
+                                       fclose(fp);
                                        goto error;
                                }
                                z64 = zip_file_add(zws->zip, zws->name, zsrc, ZIP_FL_ENC_UTF_8);
index 97af130..95c2f37 100644 (file)
@@ -88,15 +88,31 @@ extern struct filedesc *get_signature(unsigned int number);
 extern int file_set_prop(struct filedesc *file, const char *name, const char *value);
 extern const char *file_get_prop(struct filedesc *file, const char *name);
 
+/**************************************************************/
+/* from wgtpkg-install */
+
+extern void install_widget(const char *wgtfile, const char *root, int force);
+
+/**************************************************************/
+/* from wgtpkg-permission */
+
+extern int is_standard_permission(const char *name);
+extern void reset_permissions();
+extern void crop_permissions(unsigned level);
+extern void grant_permission_list(const char *list);
+extern int permission_exists(const char *name);
+extern int request_permission(const char *name);
+
 /**************************************************************/
 /* from wgtpkg-workdir */
 
-extern int enter_workdir(int clean);
+extern char workdir[PATH_MAX];
+extern int workdirfd;
 extern void remove_workdir();
 extern int set_workdir(const char *name, int create);
 extern int make_workdir_base(const char *root, const char *prefix, int reuse);
 extern int make_workdir(int reuse);
-extern int workdirfd();
+extern int move_workdir(const char *dest, int parents, int force);
 
 /**************************************************************/
 /* from wgtpkg-xmlsec */