diff options
-rw-r--r-- | .gitignore | 2 | ||||
-rw-r--r-- | src/Makefile.am | 12 | ||||
-rw-r--r-- | src/wgt-info.c | 21 | ||||
-rw-r--r-- | src/wgt-info.h | 4 | ||||
-rw-r--r-- | src/wgt.c | 22 | ||||
-rw-r--r-- | src/wgt.h | 4 | ||||
-rw-r--r-- | src/wgtpkg-digsig.c | 34 | ||||
-rw-r--r-- | src/wgtpkg-files.c | 18 | ||||
-rw-r--r-- | src/wgtpkg-info.c | 43 | ||||
-rw-r--r-- | src/wgtpkg-install.c | 276 | ||||
-rw-r--r-- | src/wgtpkg-installer.c | 125 | ||||
-rw-r--r-- | src/wgtpkg-pack.c | 4 | ||||
-rw-r--r-- | src/wgtpkg-permissions.c | 132 | ||||
-rw-r--r-- | src/wgtpkg-sign.c | 2 | ||||
-rw-r--r-- | src/wgtpkg-workdir.c | 227 | ||||
-rw-r--r-- | src/wgtpkg-xmlsec.c | 11 | ||||
-rw-r--r-- | src/wgtpkg-zip.c | 39 | ||||
-rw-r--r-- | src/wgtpkg.h | 20 |
18 files changed, 674 insertions, 322 deletions
@@ -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); @@ -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); @@ -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 */ |