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_security(const struct wgt_desc *desc)
393 char path[PATH_MAX], *head;
394 const char *icon, *perm;
396 unsigned int i, n, len, lic, lf;
399 rc = secmgr_init(desc->id);
403 rc = secmgr_path_public_read_only(workdir);
407 /* instal the files */
408 head = stpcpy(path, workdir);
409 assert(head < path + sizeof path);
410 len = (unsigned)((path + sizeof path) - head);
412 ERROR("root path too long in install_security");
413 errno = ENAMETOOLONG;
418 icon = desc->icons ? desc->icons->src : NULL;
419 lic = (unsigned)strlen(icon);
423 f = file_of_index(i++);
424 lf = (unsigned)strlen(f->name);
426 ERROR("path too long in install_security");
427 errno = ENAMETOOLONG;
430 strcpy(head, f->name);
431 if (lf <= lic && icon && !memcmp(f->name, icon, lf) && (!f->name[lf] || f->name[lf] == '/'))
432 rc = secmgr_path_public_read_only(path);
434 rc = secmgr_path_read_only(path);
439 /* install the permissions */
440 perm = first_usable_permission();
442 rc = secmgr_permit(perm);
443 INFO("permitting %s %s", perm, rc ? "FAILED!" : "success");
446 perm = next_usable_permission();
449 rc = secmgr_install();
457 /* install the widget of the file */
458 struct wgt_info *install_widget(const char *wgtfile, const char *root, int force)
460 struct wgt_info *ifo;
461 const struct wgt_desc *desc;
462 char installdir[PATH_MAX];
464 struct unitconf uconf;
466 NOTICE("-- INSTALLING widget %s to %s --", wgtfile, root);
469 create_directory(root, 0755, 1);
470 if (make_workdir(root, "TMP", 0)) {
471 ERROR("failed to create a working directory");
475 if (zread(wgtfile, 0))
478 if (check_all_signatures())
481 ifo = wgt_info_createat(workdirfd, NULL, 1, 1, 1);
485 reset_requested_permissions();
486 desc = wgt_info_desc(ifo);
487 if (check_widget(desc))
490 if (get_target_directory(installdir, root, desc))
493 if (move_widget_to(installdir, force))
496 if (install_icon(desc))
499 if (install_security(desc))
502 if (install_exec_flag(desc))
509 uconf.installdir = installdir;
510 uconf.icondir = FWK_ICON_DIR;
512 if (unit_install(ifo, &uconf))