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_afm_prefix[] = "X-AFM-";
55 static const char key_http_port[] = "http-port";
58 * normalize unit files: remove comments, remove heading blanks,
61 static void normalize_unit_file(char *content)
63 char *read, *write, c;
65 read = write = content;
76 do { c = *read++; } while(c && c != '\n');
80 do { *write++ = c = *read++; } while(c && c != '\n');
81 if (write - content >= 2 && write[-2] == '\\')
89 static int get_port_cb(void *closure, const char *name, const char *path, int isuser)
97 rc = getfile(path, &content, &length);
101 /* normalize the unit file */
102 normalize_unit_file(content);
104 /* process the file */
105 iter = strstr(content, key_afm_prefix);
107 iter += sizeof key_afm_prefix - 1;
110 if (!strncmp(iter, key_http_port, sizeof key_http_port - 1)) {
111 iter += sizeof key_http_port - 1;
112 while(*iter && *iter != '=' && *iter != '\n')
115 while(*++iter == ' ');
117 if (p >= 0 && p < 32768)
118 ((uint32_t*)closure)[p >> 5] |= (uint32_t)1 << (p & 31);
121 iter = strstr(iter, key_afm_prefix);
127 static int get_port()
130 uint32_t ports[1024]; /* 1024 * 32 = 32768 */
132 memset(ports, 0, sizeof ports);
133 rc = systemd_unit_list(0, get_port_cb, &ports);
135 rc = systemd_unit_list(1, get_port_cb, ports);
137 for (rc = 1024 ; rc < 32768 && !~ports[rc >> 5] ; rc += 32);
139 ERROR("Can't compute a valid port");
140 errno = EADDRNOTAVAIL;
143 while (1 & (ports[rc >> 5] >> (rc & 31))) rc++;
150 static int check_defined(const void *data, const char *name)
154 ERROR("widget has no defined '%s' (temporary constraints)", name);
159 static int check_valid_string(const char *value, const char *name)
164 if (check_defined(value, name))
169 ERROR("empty string forbidden in '%s' (temporary constraints)", name);
174 if (!isalnum(c) && !strchr(".-_", c)) {
175 ERROR("forbidden char %c in '%s' -> '%s' (temporary constraints)", c, name, value);
184 static int check_temporary_constraints(const struct wgt_desc *desc)
188 result = check_valid_string(desc->id, "id");
189 result |= check_valid_string(desc->version, "version");
190 result |= check_valid_string(desc->ver, "ver");
191 result |= check_defined(desc->content_src, "content");
193 result |= check_defined(desc->icons->src, "icon.src");
197 if (desc->icons && desc->icons->next) {
198 ERROR("widget has more than one icon defined (temporary constraints)");
205 static int set_required_permissions(struct wgt_desc_param *params, int required)
210 /* check if target */
211 if (!strcmp(params->name, string_sharp_target)) {
212 /* do nothing when #target */
214 /* check the value */
215 if (!strcmp(params->value, string_required))
216 optional = !required;
217 else if (!strcmp(params->value, string_optional))
220 ERROR("unexpected parameter value: %s found for %s", params->value, params->name);
224 /* set the permission */
225 if (request_permission(params->name)) {
226 DEBUG("granted permission: %s", params->name);
227 } else if (optional) {
228 INFO("optional permission ungranted: %s", params->name);
230 ERROR("ungranted permission required: %s", params->name);
235 params = params->next;
240 static int check_permissions(const struct wgt_desc *desc)
243 const struct wgt_desc_feature *feature;
246 feature = desc->features;
247 while(result >= 0 && feature) {
248 if (!strcmp(feature->name, feature_required_permission))
249 result = set_required_permissions(feature->params, feature->required);
250 feature = feature->next;
255 static int for_all_content(const struct wgt_desc *desc, int (*action)(const char *src, const char *type))
258 struct wgt_desc_feature *feat;
259 const char *src, *type;
261 rc = action(desc->content_src, desc->content_type);
262 feat = desc->features;
264 if (!strcmp(feat->name, "urn:AGL:widget:provided-unit")) {
265 src = wgt_info_param(feat, "content.src");
266 type = wgt_info_param(feat, "content.type");
267 rc2 = action(src, type);
268 if (rc >= 0 && rc2 < 0)
276 static int set_exec_flag(const char *src, const char *type)
281 i = sizeof exec_type_strings / sizeof *exec_type_strings;
283 if (!strcasecmp(type, exec_type_strings[--i])) {
284 rc = fchmodat(workdirfd, src, 0755, 0);
286 ERROR("can't make executable the file %s", src);
294 static int check_one_content(const char *src, const char *type)
301 ERROR("a content src is missing");
305 /* TODO: when dealing with HTML and languages, the check should
306 * include i18n path search of widgets */
307 rc = fstatat(workdirfd, src, &s, AT_NO_AUTOMOUNT|AT_SYMLINK_NOFOLLOW);
310 fhtdocs = openat(workdirfd, "htdocs", O_DIRECTORY|O_PATH);
312 rc = fstatat(fhtdocs, src, &s, AT_NO_AUTOMOUNT|AT_SYMLINK_NOFOLLOW);
319 ERROR("can't get info on content %s: %m", src);
320 else if (!S_ISREG(s.st_mode)) {
321 ERROR("content %s isn't a regular file", src);
329 static int check_content(const struct wgt_desc *desc)
331 return for_all_content(desc, check_one_content);
334 static int check_widget(const struct wgt_desc *desc)
338 result = check_temporary_constraints(desc);
340 result = check_permissions(desc);
342 result = check_content(desc);
346 static int get_target_directory(char target[PATH_MAX], const char *root, const struct wgt_desc *desc)
350 rc = snprintf(target, PATH_MAX, "%s/%s/%s", root, desc->id, desc->ver);
354 ERROR("path too long");
361 static int move_widget_to(const char *destdir, int force)
363 return move_workdir(destdir, 1, force);
366 static int install_icon(const struct wgt_desc *desc)
369 char target[PATH_MAX];
375 create_directory(FWK_ICON_DIR, 0755, 1);
376 rc = snprintf(link, sizeof link, "%s/%s", FWK_ICON_DIR, desc->idaver);
377 if (rc >= (int)sizeof link) {
378 ERROR("link too long in install_icon");
383 rc = snprintf(target, sizeof target, "%s/%s", workdir, desc->icons->src);
384 if (rc >= (int)sizeof target) {
385 ERROR("target too long in install_icon");
391 rc = symlink(target, link);
393 ERROR("can't create link %s -> %s", link, target);
397 static int install_exec_flag(const struct wgt_desc *desc)
399 return for_all_content(desc, set_exec_flag);
402 static int install_file_properties(const struct wgt_desc *desc)
405 struct wgt_desc_feature *feat;
406 struct wgt_desc_param *param;
409 feat = desc->features;
411 if (!strcmp(feat->name, "urn:AGL:widget:file-properties")) {
412 param = feat->params;
414 if (!strcmp(param->value, "executable")) {
415 rc2 = fchmodat(workdirfd, param->name, 0755, 0);
417 ERROR("can't make executable the file %s: %m", param->name);
419 ERROR("unknown file property %s for %s", param->value, param->name);
433 static int install_security(const struct wgt_desc *desc)
435 char path[PATH_MAX], *head;
436 const char *icon, *perm;
438 unsigned int i, n, len, lic, lf;
441 rc = secmgr_init(desc->id);
445 rc = secmgr_path_public_read_only(workdir);
449 /* instal the files */
450 head = stpcpy(path, workdir);
451 assert(head < path + sizeof path);
452 len = (unsigned)((path + sizeof path) - head);
454 ERROR("root path too long in install_security");
455 errno = ENAMETOOLONG;
460 icon = desc->icons ? desc->icons->src : NULL;
461 lic = (unsigned)strlen(icon);
465 f = file_of_index(i++);
466 lf = (unsigned)strlen(f->name);
468 ERROR("path too long in install_security");
469 errno = ENAMETOOLONG;
472 strcpy(head, f->name);
473 if (lf <= lic && icon && !memcmp(f->name, icon, lf) && (!f->name[lf] || f->name[lf] == '/'))
474 rc = secmgr_path_public_read_only(path);
476 rc = secmgr_path_read_only(path);
481 /* install the permissions */
482 perm = first_usable_permission();
484 rc = secmgr_permit(perm);
485 INFO("permitting %s %s", perm, rc ? "FAILED!" : "success");
488 perm = next_usable_permission();
491 rc = secmgr_install();
499 /* install the widget of the file */
500 struct wgt_info *install_widget(const char *wgtfile, const char *root, int force)
502 struct wgt_info *ifo;
503 const struct wgt_desc *desc;
504 char installdir[PATH_MAX];
506 struct unitconf uconf;
508 NOTICE("-- INSTALLING widget %s to %s --", wgtfile, root);
511 create_directory(root, 0755, 1);
512 if (make_workdir(root, "TMP", 0)) {
513 ERROR("failed to create a working directory");
517 if (zread(wgtfile, 0))
520 if (check_all_signatures())
523 ifo = wgt_info_createat(workdirfd, NULL, 1, 1, 1);
527 reset_requested_permissions();
528 desc = wgt_info_desc(ifo);
529 if (check_widget(desc))
532 if (get_target_directory(installdir, root, desc))
535 if (move_widget_to(installdir, force))
538 if (install_icon(desc))
541 if (install_security(desc))
544 if (install_exec_flag(desc))
547 if (install_file_properties(desc))
554 uconf.installdir = installdir;
555 uconf.icondir = FWK_ICON_DIR;
557 if (unit_install(ifo, &uconf))