/* Copyright (C) 2015-2018 IoT.bzh author: José Bollo <jose.bollo@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 <limits.h> #include <errno.h> #include <string.h> #include <ctype.h> #include <assert.h> #include <unistd.h> #include <stdio.h> #include <stdlib.h> #include <stdint.h> #include <fcntl.h> #include <sys/stat.h> #include "verbose.h" #include "wgt.h" #include "wgt-info.h" #include "wgt-strings.h" #include "wgtpkg-files.h" #include "wgtpkg-workdir.h" #include "wgtpkg-zip.h" #include "wgtpkg-permissions.h" #include "wgtpkg-digsig.h" #include "wgtpkg-install.h" #include "wgtpkg-uninstall.h" #include "secmgr-wrap.h" #include "utils-dir.h" #include "wgtpkg-unit.h" #include "utils-systemd.h" #include "utils-file.h" static const char* exec_type_strings[] = { "application/x-executable", "application/vnd.agl.native" }; static const char key_afm_prefix[] = "X-AFM-"; static const char key_http_port[] = "http-port"; #define HTTP_PORT_MIN 31000 #define HTTP_PORT_MAX 32759 #define HTTP_PORT_IS_VALID(port) (HTTP_PORT_MIN <= (port) && (port) <= HTTP_PORT_MAX) #define HTTP_PORT_COUNT (HTTP_PORT_MAX - HTTP_PORT_MIN + 1) #define HTTP_PORT_ACNT ((HTTP_PORT_COUNT + 31) >> 5) #define HTTP_PORT_ASFT(port) (((port) - HTTP_PORT_MIN) & 31) #define HTTP_PORT_AIDX(port) (((port) - HTTP_PORT_MIN) >> 5) #define HTTP_PORT_TEST(array,port) ((((array)[HTTP_PORT_AIDX(port)]) >> HTTP_PORT_ASFT(port)) & 1) #define HTTP_PORT_SET(array,port) (((array)[HTTP_PORT_AIDX(port)]) |= (((uint32_t)1) << HTTP_PORT_ASFT(port))) static uint32_t *port_bits = NULL; /* * normalize unit files: remove comments, remove heading blanks, * make single lines */ static void normalize_unit_file(char *content) { char *read, *write, c; read = write = content; c = *read++; while (c) { switch (c) { case '\n': case ' ': case '\t': c = *read++; break; case '#': case ';': do { c = *read++; } while(c && c != '\n'); break; default: *write++ = c; do { *write++ = c = *read++; } while(c && c != '\n'); if (write - content >= 2 && write[-2] == '\\') (--write)[-1] = ' '; break; } } *write = c; } static int get_port_cb(void *closure, const char *name, const char *path, int isuser) { char *iter; char *content; size_t length; int rc, p; /* reads the file */ rc = getfile(path, &content, &length); if (rc < 0) return rc; /* normalize the unit file */ normalize_unit_file(content); /* process the file */ iter = strstr(content, key_afm_prefix); while (iter) { iter += sizeof key_afm_prefix - 1; if (*iter == '-') iter++; if (!strncmp(iter, key_http_port, sizeof key_http_port - 1)) { iter += sizeof key_http_port - 1; while(*iter && *iter != '=' && *iter != '\n') iter++; if (*iter == '=') { while(*++iter == ' '); p = atoi(iter); if (HTTP_PORT_IS_VALID(p)) HTTP_PORT_SET((uint32_t*)closure, p); } } iter = strstr(iter, key_afm_prefix); } free(content); return 0; } static int update_portbits(uint32_t *portbits) { int rc; memset(portbits, 0, HTTP_PORT_ACNT * sizeof(uint32_t)); rc = systemd_unit_list(0, get_port_cb, portbits); if (rc >= 0) rc = systemd_unit_list(1, get_port_cb, portbits); if (rc < 0) ERROR("troubles while updating ports"); return rc; } static int first_free_port(uint32_t *portbits) { int port; port = HTTP_PORT_MIN; while (port <= HTTP_PORT_MAX && !~portbits[HTTP_PORT_AIDX(port)]) port += 32; while (port <= HTTP_PORT_MAX && HTTP_PORT_TEST(portbits, port)) port++; if (port > HTTP_PORT_MAX) { ERROR("Can't compute a valid port"); errno = EADDRNOTAVAIL; port = -1; } return port; } static int get_port() { int port; /* ensure existing port bitmap */ if (port_bits == NULL) { port_bits = malloc(HTTP_PORT_ACNT * sizeof(uint32_t)); if (port_bits == NULL || update_portbits(port_bits) < 0) return -1; } /* allocates the port */ port = first_free_port(port_bits); if (port >= 0) HTTP_PORT_SET(por<style>.highlight .hll { background-color: #ffffcc } .highlight .c { color: #888888 } /* Comment */ .highlight .err { color: #a61717; background-color: #e3d2d2 } /* Error */ .highlight .k { color: #008800; font-weight: bold } /* Keyword */ .highlight .ch { color: #888888 } /* Comment.Hashbang */ .highlight .cm { color: #888888 } /* Comment.Multiline */ .highlight .cp { color: #cc0000; font-weight: bold } /* Comment.Preproc */ .highlight .cpf { color: #888888 } /* Comment.PreprocFile */ .highlight .c1 { color: #888888 } /* Comment.Single */ .highlight .cs { color: #cc0000; font-weight: bold; background-color: #fff0f0 } /* Comment.Special */ .highlight .gd { color: #000000; background-color: #ffdddd } /* Generic.Deleted */ .highlight .ge { font-style: italic } /* Generic.Emph */ .highlight .gr { color: #aa0000 } /* Generic.Error */ .highlight .gh { color: #333333 } /* Generic.Heading */ .highlight .gi { color: #000000; background-color: #ddffdd } /* Generic.Inserted */ .highlight .go { color: #888888 } /* Generic.Output */ .highlight .gp { color: #555555 } /* Generic.Prompt */ .highlight .gs { font-weight: bold } /* Generic.Strong */ .highlight .gu { color: #666666 } /* Generic.Subheading */ .highlight .gt { color: #aa0000 } /* Generic.Traceback */ .highlight .kc { color: #008800; font-weight: bold } /* Keyword.Constant */ .highlight .kd { color: #008800; font-weight: bold } /* Keyword.Declaration */ .highlight .kn { color: #008800; font-weight: bold } /* Keyword.Namespace */ .highlight .kp { color: #008800 } /* Keyword.Pseudo */ .highlight .kr { color: #008800; font-weight: bold } /* Keyword.Reserved */ .highlight .kt { color: #888888; font-weight: bold } /* Keyword.Type */ .highlight .m { color: #0000DD; font-weight: bold } /* Literal.Number */ .highlight .s { color: #dd2200; background-color: #fff0f0 } /* Literal.String */ .highlight .na { color: #336699 } /* Name.Attribute */ .highlight .nb { color: #003388 } /* Name.Builtin */ .highlight .nc { color: #bb0066; font-weight: bold } /* Name.Class */ .highlight .no { color: #003366; font-weight: bold } /* Name.Constant */ .highlight .nd { color: #555555 } /* Name.Decorator */ .highlight .ne { color: #bb0066; font-weight: bold } /* Name.Exception */ .highlight .nf { color: #0066bb; font-weight: bold } /* Name.Function */ .highlight .nl { color: #336699; font-style: italic } /* Name.Label */ .highlight .nn { color: #bb0066; font-weight: bold } /* Name.Namespace */ .highlight .py { color: #336699; font-weight: bold } /* Name.Property */ .highlight .nt { color: #bb0066; font-weight: bold } /* Name.Tag */ .highlight .nv { color: #336699 } /* Name.Variable */ .highlight .ow { color: #008800 } /* Operator.Word */ .highlight .w { color: #bbbbbb } /* Text.Whitespace */ .highlight .mb { color: #0000DD; font-weight: bold } /* Literal.Number.Bin */ .highlight .mf { color: #0000DD; font-weight: bold } /* Literal.Number.Float */ .highlight .mh { color: #0000DD; font-weight: bold } /* Literal.Number.Hex */ .highlight .mi { color: #0000DD; font-weight: bold } /* Literal.Number.Integer */ .highlight .mo { color: #0000DD; font-weight: bold } /* Literal.Number.Oct */ .highlight .sa { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Affix */ .highlight .sb { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Backtick */ .highlight .sc { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Char */ .highlight .dl { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Delimiter */ .highlight .sd { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Doc */ .highlight .s2 { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Double */ .highlight .se { color: #0044dd; background-color: #fff0f0 } /* Literal.String.Escape */ .highlight .sh { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Heredoc */ .highlight .si { color: #3333bb; background-color: #fff0f0 } /* Literal.String.Interpol */ .highlight .sx { color: #22bb22; background-color: #f0fff0 } /* Literal.String.Other */ .highlight .sr { color: #008800; background-color: #fff0ff } /* Literal.String.Regex */ .highlight .s1 { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Single */ .highlight .ss { color: #aa6600; background-color: #fff0f0 } /* Literal.String.Symbol */ .highlight .bp { color: #003388 } /* Name.Builtin.Pseudo */ .highlight .fm { color: #0066bb; font-weight: bold } /* Name.Function.Magic */ .highlight .vc { color: #336699 } /* Name.Variable.Class */ .highlight .vg { color: #dd7700 } /* Name.Variable.Global */ .highlight .vi { color: #3333bb } /* Name.Variable.Instance */ .highlight .vm { color: #336699 } /* Name.Variable.Magic */ .highlight .il { color: #0000DD; font-weight: bold } /* Literal.Number.Integer.Long */</style><div class="highlight"><pre><span></span>[gerrit] host=gerrit.automotivelinux.org port=29418 project=src/cmake-apps-module defaultbranch=master </pre></div> </code></pre></td></tr></table> </div> <!-- class=content --> <div id="lfcollabprojects-footer"> <div class="gray-diagonal"> <div class="footer-inner"> <p>Copyright © 2015 The Linux Foundation. All rights reserved.</p> <p> Linux Foundation, Linux Standard Base, LSB, LSB Certified, IAccessible2, MeeGo are registered trademarks of the Linux Foundation. </p> <p> Linux is a registered <a href="http://www.linuxfoundation.org/programs/legal/trademark" >trademark</a > of Linus Torvalds. Please see our <a href="https://www.linuxfoundation.org/privacy">privacy policy</a>. </p> </div> </div> </div> </div> <!-- id=cgit --> </body> </html> eate link %s -> %s", link, target); return rc; } static int install_exec_flag(const struct wgt_desc *desc) { return for_all_content(desc, set_exec_flag); } static int install_file_properties(const struct wgt_desc *desc) { int rc, rc2; struct wgt_desc_feature *feat; struct wgt_desc_param *param; rc = 0; feat = desc->features; while (feat) { if (!strcmp(feat->name, "urn:AGL:widget:file-properties")) { param = feat->params; while (param) { if (!strcmp(param->value, "executable")) { rc2 = fchmodat(workdirfd, param->name, 0755, 0); if (rc2 < 0) ERROR("can't make executable the file %s: %m", param->name); } else { ERROR("unknown file property %s for %s", param->value, param->name); errno = EINVAL; rc2 = -1; } if (rc2 < 0 && !rc) rc = rc2; param = param->next; } } feat = feat->next; } return rc; } static int install_security(const struct wgt_desc *desc) { char path[PATH_MAX], *head; const char *icon, *perm; int rc; unsigned int i, n, len, lic, lf; struct filedesc *f; rc = secmgr_init(desc->id); if (rc) goto error; rc = secmgr_path_public_read_only(workdir); if (rc) goto error2; /* instal the files */ head = stpcpy(path, workdir); assert(head < path + sizeof path); len = (unsigned)((path + sizeof path) - head); if (!len) { ERROR("root path too long in install_security"); errno = ENAMETOOLONG; goto error2; } len--; *head++ = '/'; icon = desc->icons ? desc->icons->src : NULL; lic = (unsigned)(icon ? strlen(icon) : 0); n = file_count(); i = 0; while(i < n) { f = file_of_index(i++); lf = (unsigned)strlen(f->name); if (lf >= len) { ERROR("path too long in install_security"); errno = ENAMETOOLONG; goto error2; } strcpy(head, f->name); if (lf <= lic && icon && !memcmp(f->name, icon, lf) && (!f->name[lf] || f->name[lf] == '/')) rc = secmgr_path_public_read_only(path); else rc = secmgr_path_read_only(path); if (rc) goto error2; } /* install the permissions */ perm = first_usable_permission(); while(perm) { rc = secmgr_permit(perm); INFO("permitting %s %s", perm, rc ? "FAILED!" : "success"); if (rc) goto error2; perm = next_usable_permission(); } rc = secmgr_install(); return rc; error2: secmgr_cancel(); error: return -1; } /* install the widget of the file */ struct wgt_info *install_widget(const char *wgtfile, const char *root, int force) { struct wgt_info *ifo; const struct wgt_desc *desc; char installdir[PATH_MAX]; int err; struct unitconf uconf; NOTICE("-- INSTALLING widget %s to %s --", wgtfile, root); /* workdir */ create_directory(root, 0755, 1); if (make_workdir(root, "TMP", 0)) { ERROR("failed to create a working directory"); goto error1; } if (zread(wgtfile, 0)) goto error2; if (check_all_signatures(DEFAULT_ALLOW_NO_SIGNATURE)) goto error2; ifo = wgt_info_createat(workdirfd, NULL, 1, 1, 1); if (!ifo) goto error2; reset_requested_permissions(); desc = wgt_info_desc(ifo); if (check_widget(desc)) goto error3; if (get_target_directory(installdir, root, desc)) goto error3; if (access(installdir, F_OK) == 0) { if (!force) { ERROR("widget already installed"); errno = EEXIST; goto error3; } if (uninstall_widget(desc->idaver, root)) goto error3; } if (move_widget_to(installdir, force)) goto error3; if (install_icon(desc)) goto error3; if (install_security(desc)) goto error4; if (install_exec_flag(desc)) goto error4; if (install_file_properties(desc)) goto error4; uconf.installdir = installdir; uconf.icondir = FWK_ICON_DIR; uconf.port = get_port; if (unit_install(ifo, &uconf)) goto error4; file_reset(); return ifo; error4: /* TODO: cleanup */ error3: wgt_info_unref(ifo); error2: err = errno; remove_workdir(); errno = err; error1: file_reset(); return NULL; }