summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--.gitignore2
-rw-r--r--src/Makefile.am12
-rw-r--r--src/wgt-info.c21
-rw-r--r--src/wgt-info.h4
-rw-r--r--src/wgt.c22
-rw-r--r--src/wgt.h4
-rw-r--r--src/wgtpkg-digsig.c34
-rw-r--r--src/wgtpkg-files.c18
-rw-r--r--src/wgtpkg-info.c43
-rw-r--r--src/wgtpkg-install.c276
-rw-r--r--src/wgtpkg-installer.c125
-rw-r--r--src/wgtpkg-pack.c4
-rw-r--r--src/wgtpkg-permissions.c132
-rw-r--r--src/wgtpkg-sign.c2
-rw-r--r--src/wgtpkg-workdir.c227
-rw-r--r--src/wgtpkg-xmlsec.c11
-rw-r--r--src/wgtpkg-zip.c39
-rw-r--r--src/wgtpkg.h20
18 files changed, 674 insertions, 322 deletions
diff --git a/.gitignore b/.gitignore
index 4773e7e..96295c2 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,4 +1,4 @@
-wgtpkg-install
+wgtpkg-installer
wgtpkg-pack
wgtpkg-sign
wgtpkg-info
diff --git a/src/Makefile.am b/src/Makefile.am
index c74983e..9767941 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -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}
diff --git a/src/wgt-info.c b/src/wgt-info.c
index ddecb9a..d5f664b 100644
--- a/src/wgt-info.c
+++ b/src/wgt-info.c
@@ -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);
diff --git a/src/wgt-info.h b/src/wgt-info.h
index 3cb6a5c..4d2007d 100644
--- a/src/wgt-info.h
+++ b/src/wgt-info.h
@@ -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);
diff --git a/src/wgt.c b/src/wgt.c
index 1ae1a13..980719b 100644
--- 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);
diff --git a/src/wgt.h b/src/wgt.h
index f159a3b..87648ec 100644
--- a/src/wgt.h
+++ b/src/wgt.h
@@ -17,11 +17,13 @@
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);
diff --git a/src/wgtpkg-digsig.c b/src/wgtpkg-digsig.c
index 6e66e38..3aa4da3 100644
--- a/src/wgtpkg-digsig.c
+++ b/src/wgtpkg-digsig.c
@@ -18,10 +18,13 @@
#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:
diff --git a/src/wgtpkg-files.c b/src/wgtpkg-files.c
index 06aac83..8840fa9 100644
--- a/src/wgtpkg-files.c
+++ b/src/wgtpkg-files.c
@@ -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) {
diff --git a/src/wgtpkg-info.c b/src/wgtpkg-info.c
index 1a7724b..7854b09 100644
--- a/src/wgtpkg-info.c
+++ b/src/wgtpkg-info.c
@@ -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;
diff --git a/src/wgtpkg-install.c b/src/wgtpkg-install.c
index b6237b3..ee21d8f 100644
--- a/src/wgtpkg-install.c
+++ b/src/wgtpkg-install.c
@@ -14,239 +14,101 @@
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
index 0000000..e8568b8
--- /dev/null
+++ b/src/wgtpkg-installer.c
@@ -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;
+}
+
diff --git a/src/wgtpkg-pack.c b/src/wgtpkg-pack.c
index be1e5ab..451d427 100644
--- a/src/wgtpkg-pack.c
+++ b/src/wgtpkg-pack.c
@@ -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
index 0000000..25758e4
--- /dev/null
+++ b/src/wgtpkg-permissions.c
@@ -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;
+}
+
diff --git a/src/wgtpkg-sign.c b/src/wgtpkg-sign.c
index c4faf29..031e1c3 100644
--- a/src/wgtpkg-sign.c
+++ b/src/wgtpkg-sign.c
@@ -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())
diff --git a/src/wgtpkg-workdir.c b/src/wgtpkg-workdir.c
index 12cfa24..59da1e6 100644
--- a/src/wgtpkg-workdir.c
+++ b/src/wgtpkg-workdir.c
@@ -22,13 +22,16 @@
#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;
}
diff --git a/src/wgtpkg-xmlsec.c b/src/wgtpkg-xmlsec.c
index 843ea2b..a403b77 100644
--- a/src/wgtpkg-xmlsec.c
+++ b/src/wgtpkg-xmlsec.c
@@ -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;
diff --git a/src/wgtpkg-zip.c b/src/wgtpkg-zip.c
index 9e51538..8ad00bb 100644
--- a/src/wgtpkg-zip.c
+++ b/src/wgtpkg-zip.c
@@ -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);
diff --git a/src/wgtpkg.h b/src/wgtpkg.h
index 97af130..95c2f37 100644
--- a/src/wgtpkg.h
+++ b/src/wgtpkg.h
@@ -89,14 +89,30 @@ extern int file_set_prop(struct filedesc *file, const char *name, const char *va
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 */