2 Copyright 2015, 2016, 2017 IoT.bzh
4 author: José Bollo <jose.bollo@iot.bzh>
6 Licensed under the Apache License, Version 2.0 (the "License");
7 you may not use this file except in compliance with the License.
8 You may obtain a copy of the License at
10 http://www.apache.org/licenses/LICENSE-2.0
12 Unless required by applicable law or agreed to in writing, software
13 distributed under the License is distributed on an "AS IS" BASIS,
14 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 See the License for the specific language governing permissions and
16 limitations under the License.
36 #include "wgt-strings.h"
37 #include "wgtpkg-files.h"
38 #include "wgtpkg-workdir.h"
39 #include "wgtpkg-zip.h"
40 #include "wgtpkg-permissions.h"
41 #include "wgtpkg-digsig.h"
42 #include "wgtpkg-install.h"
43 #include "secmgr-wrap.h"
44 #include "utils-dir.h"
45 #include "wgtpkg-unit.h"
46 #include "utils-systemd.h"
47 #include "utils-file.h"
49 static const char* exec_type_strings[] = {
50 "application/x-executable",
51 "application/vnd.agl.native"
54 static const char key_http_port[] = "X-AFM--http-port";
56 static int get_port_cb(void *closure, const char *name, const char *path, int isuser)
64 rc = getfile(path, &content, &length);
68 /* process the file */
69 iter = strstr(content, key_http_port);
71 iter += sizeof key_http_port - 1;
72 while(*iter && *iter != '=' && *iter != '\n')
75 while(*++iter == ' ');
77 if (p >= 0 && p < 32768)
78 ((uint32_t*)closure)[p >> 5] |= (uint32_t)1 << (p & 31);
80 iter = strstr(iter, key_http_port);
89 uint32_t ports[1024]; /* 1024 * 32 = 32768 */
91 memset(ports, 0, sizeof ports);
92 rc = systemd_unit_list(0, get_port_cb, &ports);
94 rc = systemd_unit_list(1, get_port_cb, ports);
96 for (rc = 1024 ; rc < 32768 && !~ports[rc >> 5] ; rc += 32);
98 errno = EADDRNOTAVAIL;
101 while (1 & (ports[rc >> 5] >> (rc & 31))) rc++;
108 static int check_defined(const void *data, const char *name)
112 ERROR("widget has no defined '%s' (temporary constraints)", name);
117 static int check_valid_string(const char *value, const char *name)
122 if (check_defined(value, name))
127 ERROR("empty string forbidden in '%s' (temporary constraints)", name);
132 if (!isalnum(c) && !strchr(".-_", c)) {
133 ERROR("forbidden char %c in '%s' -> '%s' (temporary constraints)", c, name, value);
142 static int check_temporary_constraints(const struct wgt_desc *desc)
146 result = check_valid_string(desc->id, "id");
147 result |= check_valid_string(desc->version, "version");
148 result |= check_valid_string(desc->ver, "ver");
149 result |= check_defined(desc->icons, "icon");
150 result |= check_defined(desc->content_src, "content");
154 if (desc->icons->next) {
155 ERROR("widget has more than one icon defined (temporary constraints)");
162 static int set_required_permissions(struct wgt_desc_param *params, int required)
167 /* check if target */
168 if (!strcmp(params->name, string_sharp_target)) {
169 /* do nothing when #target */
171 /* check the value */
172 if (!strcmp(params->value, string_required))
173 optional = !required;
174 else if (!strcmp(params->value, string_optional))
177 ERROR("unexpected parameter value: %s found for %s", params->value, params->name);
181 /* set the permission */
182 if (request_permission(params->name)) {
183 DEBUG("granted permission: %s", params->name);
184 } else if (optional) {
185 INFO("optional permission ungranted: %s", params->name);
187 ERROR("ungranted permission required: %s", params->name);
192 params = params->next;
197 static int check_permissions(const struct wgt_desc *desc)
200 const struct wgt_desc_feature *feature;
203 feature = desc->features;
204 while(result >= 0 && feature) {
205 if (!strcmp(feature->name, feature_required_permission))
206 result = set_required_permissions(feature->params, feature->required);
207 feature = feature->next;
212 static int for_all_content(const struct wgt_desc *desc, int (*action)(const char *src, const char *type))
215 struct wgt_desc_feature *feat;
216 const char *src, *type;
218 rc = action(desc->content_src, desc->content_type);
219 feat = desc->features;
221 if (!strcmp(feat->name, "urn:AGL:widget:provided-unit")) {
222 src = wgt_info_param(feat, "content.src");
223 type = wgt_info_param(feat, "content.type");
224 rc2 = action(src, type);
225 if (rc >= 0 && rc2 < 0)
233 static int set_exec_flag(const char *src, const char *type)
238 i = sizeof exec_type_strings / sizeof *exec_type_strings;
240 if (!strcasecmp(type, exec_type_strings[--i])) {
241 rc = fchmodat(workdirfd, src, 0755, 0);
243 ERROR("can't make executable the file %s", src);
251 static int check_one_content(const char *src, const char *type)
257 ERROR("a content src is missing");
261 /* TODO: when dealing with HTML and languages, the check should
262 * include i18n path search of widgets */
263 rc = fstatat(workdirfd, src, &s, AT_NO_AUTOMOUNT|AT_SYMLINK_NOFOLLOW);
265 ERROR("can't get info on content %s: %m", src);
266 else if (!S_ISREG(s.st_mode)) {
267 ERROR("content %s isn't a regular file", src);
275 static int check_content(const struct wgt_desc *desc)
277 return for_all_content(desc, check_one_content);
280 static int check_widget(const struct wgt_desc *desc)
284 result = check_temporary_constraints(desc);
286 result = check_permissions(desc);
288 result = check_content(desc);
292 static int get_target_directory(char target[PATH_MAX], const char *root, const struct wgt_desc *desc)
296 rc = snprintf(target, PATH_MAX, "%s/%s/%s", root, desc->id, desc->ver);
300 ERROR("path too long");
307 static int move_widget_to(const char *destdir, int force)
309 return move_workdir(destdir, 1, force);
312 static int install_icon(const struct wgt_desc *desc)
315 char target[PATH_MAX];
318 create_directory(FWK_ICON_DIR, 0755, 1);
319 rc = snprintf(link, sizeof link, "%s/%s", FWK_ICON_DIR, desc->idaver);
320 if (rc >= (int)sizeof link) {
321 ERROR("link too long in install_icon");
326 rc = snprintf(target, sizeof target, "%s/%s", workdir, desc->icons->src);
327 if (rc >= (int)sizeof target) {
328 ERROR("target too long in install_icon");
334 rc = symlink(target, link);
336 ERROR("can't create link %s -> %s", link, target);
340 static int install_exec_flag(const struct wgt_desc *desc)
342 return for_all_content(desc, set_exec_flag);
345 static int install_security(const struct wgt_desc *desc)
347 char path[PATH_MAX], *head;
348 const char *icon, *perm;
350 unsigned int i, n, len, lic, lf;
353 rc = secmgr_init(desc->id);
357 rc = secmgr_path_public_read_only(workdir);
361 /* instal the files */
362 head = stpcpy(path, workdir);
363 assert(head < path + sizeof path);
364 len = (unsigned)((path + sizeof path) - head);
366 ERROR("root path too long in install_security");
367 errno = ENAMETOOLONG;
372 icon = desc->icons->src;
373 lic = (unsigned)strlen(icon);
377 f = file_of_index(i++);
378 lf = (unsigned)strlen(f->name);
380 ERROR("path too long in install_security");
381 errno = ENAMETOOLONG;
384 strcpy(head, f->name);
385 if (lf <= lic && !memcmp(f->name, icon, lf) && (!f->name[lf] || f->name[lf] == '/'))
386 rc = secmgr_path_public_read_only(path);
388 rc = secmgr_path_read_only(path);
393 /* install the permissions */
394 perm = first_usable_permission();
396 rc = secmgr_permit(perm);
397 INFO("permitting %s %s", perm, rc ? "FAILED!" : "success");
400 perm = next_usable_permission();
403 rc = secmgr_install();
411 /* install the widget of the file */
412 struct wgt_info *install_widget(const char *wgtfile, const char *root, int force)
414 struct wgt_info *ifo;
415 const struct wgt_desc *desc;
416 char installdir[PATH_MAX];
418 struct unitconf uconf;
420 NOTICE("-- INSTALLING widget %s to %s --", wgtfile, root);
423 create_directory(root, 0755, 1);
424 if (make_workdir(root, "TMP", 0)) {
425 ERROR("failed to create a working directory");
429 if (zread(wgtfile, 0))
432 if (check_all_signatures())
435 ifo = wgt_info_createat(workdirfd, NULL, 1, 1, 1);
439 reset_requested_permissions();
440 desc = wgt_info_desc(ifo);
441 if (check_widget(desc))
444 if (get_target_directory(installdir, root, desc))
447 if (move_widget_to(installdir, force))
450 if (install_icon(desc))
453 if (install_security(desc))
456 if (install_exec_flag(desc))
463 uconf.installdir = installdir;
464 uconf.icondir = FWK_ICON_DIR;
466 if (unit_install(ifo, &uconf))