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)
300 ERROR("a content src is missing");
304 /* TODO: when dealing with HTML and languages, the check should
305 * include i18n path search of widgets */
306 rc = fstatat(workdirfd, src, &s, AT_NO_AUTOMOUNT|AT_SYMLINK_NOFOLLOW);
308 ERROR("can't get info on content %s: %m", src);
309 else if (!S_ISREG(s.st_mode)) {
310 ERROR("content %s isn't a regular file", src);
318 static int check_content(const struct wgt_desc *desc)
320 return for_all_content(desc, check_one_content);
323 static int check_widget(const struct wgt_desc *desc)
327 result = check_temporary_constraints(desc);
329 result = check_permissions(desc);
331 result = check_content(desc);
335 static int get_target_directory(char target[PATH_MAX], const char *root, const struct wgt_desc *desc)
339 rc = snprintf(target, PATH_MAX, "%s/%s/%s", root, desc->id, desc->ver);
343 ERROR("path too long");
350 static int move_widget_to(const char *destdir, int force)
352 return move_workdir(destdir, 1, force);
355 static int install_icon(const struct wgt_desc *desc)
358 char target[PATH_MAX];
364 create_directory(FWK_ICON_DIR, 0755, 1);
365 rc = snprintf(link, sizeof link, "%s/%s", FWK_ICON_DIR, desc->idaver);
366 if (rc >= (int)sizeof link) {
367 ERROR("link too long in install_icon");
372 rc = snprintf(target, sizeof target, "%s/%s", workdir, desc->icons->src);
373 if (rc >= (int)sizeof target) {
374 ERROR("target too long in install_icon");
380 rc = symlink(target, link);
382 ERROR("can't create link %s -> %s", link, target);
386 static int install_exec_flag(const struct wgt_desc *desc)
388 return for_all_content(desc, set_exec_flag);
391 static int install_file_properties(const struct wgt_desc *desc)
394 struct wgt_desc_feature *feat;
395 struct wgt_desc_param *param;
398 feat = desc->features;
400 if (!strcmp(feat->name, "urn:AGL:widget:file-properties")) {
401 param = feat->params;
403 if (!strcmp(param->value, "executable")) {
404 rc2 = fchmodat(workdirfd, param->name, 0755, 0);
406 ERROR("can't make executable the file %s: %m", param->name);
408 ERROR("unknown file property %s for %s", param->value, param->name);
422 static int install_security(const struct wgt_desc *desc)
424 char path[PATH_MAX], *head;
425 const char *icon, *perm;
427 unsigned int i, n, len, lic, lf;
430 rc = secmgr_init(desc->id);
434 rc = secmgr_path_public_read_only(workdir);
438 /* instal the files */
439 head = stpcpy(path, workdir);
440 assert(head < path + sizeof path);
441 len = (unsigned)((path + sizeof path) - head);
443 ERROR("root path too long in install_security");
444 errno = ENAMETOOLONG;
449 icon = desc->icons ? desc->icons->src : NULL;
450 lic = (unsigned)strlen(icon);
454 f = file_of_index(i++);
455 lf = (unsigned)strlen(f->name);
457 ERROR("path too long in install_security");
458 errno = ENAMETOOLONG;
461 strcpy(head, f->name);
462 if (lf <= lic && icon && !memcmp(f->name, icon, lf) && (!f->name[lf] || f->name[lf] == '/'))
463 rc = secmgr_path_public_read_only(path);
465 rc = secmgr_path_read_only(path);
470 /* install the permissions */
471 perm = first_usable_permission();
473 rc = secmgr_permit(perm);
474 INFO("permitting %s %s", perm, rc ? "FAILED!" : "success");
477 perm = next_usable_permission();
480 rc = secmgr_install();
488 /* install the widget of the file */
489 struct wgt_info *install_widget(const char *wgtfile, const char *root, int force)
491 struct wgt_info *ifo;
492 const struct wgt_desc *desc;
493 char installdir[PATH_MAX];
495 struct unitconf uconf;
497 NOTICE("-- INSTALLING widget %s to %s --", wgtfile, root);
500 create_directory(root, 0755, 1);
501 if (make_workdir(root, "TMP", 0)) {
502 ERROR("failed to create a working directory");
506 if (zread(wgtfile, 0))
509 if (check_all_signatures())
512 ifo = wgt_info_createat(workdirfd, NULL, 1, 1, 1);
516 reset_requested_permissions();
517 desc = wgt_info_desc(ifo);
518 if (check_widget(desc))
521 if (get_target_directory(installdir, root, desc))
524 if (move_widget_to(installdir, force))
527 if (install_icon(desc))
530 if (install_security(desc))
533 if (install_exec_flag(desc))
536 if (install_file_properties(desc))
543 uconf.installdir = installdir;
544 uconf.icondir = FWK_ICON_DIR;
546 if (unit_install(ifo, &uconf))