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->icons, "icon");
192 result |= check_defined(desc->content_src, "content");
196 if (desc->icons->next) {
197 ERROR("widget has more than one icon defined (temporary constraints)");
204 static int set_required_permissions(struct wgt_desc_param *params, int required)
209 /* check if target */
210 if (!strcmp(params->name, string_sharp_target)) {
211 /* do nothing when #target */
213 /* check the value */
214 if (!strcmp(params->value, string_required))
215 optional = !required;
216 else if (!strcmp(params->value, string_optional))
219 ERROR("unexpected parameter value: %s found for %s", params->value, params->name);
223 /* set the permission */
224 if (request_permission(params->name)) {
225 DEBUG("granted permission: %s", params->name);
226 } else if (optional) {
227 INFO("optional permission ungranted: %s", params->name);
229 ERROR("ungranted permission required: %s", params->name);
234 params = params->next;
239 static int check_permissions(const struct wgt_desc *desc)
242 const struct wgt_desc_feature *feature;
245 feature = desc->features;
246 while(result >= 0 && feature) {
247 if (!strcmp(feature->name, feature_required_permission))
248 result = set_required_permissions(feature->params, feature->required);
249 feature = feature->next;
254 static int for_all_content(const struct wgt_desc *desc, int (*action)(const char *src, const char *type))
257 struct wgt_desc_feature *feat;
258 const char *src, *type;
260 rc = action(desc->content_src, desc->content_type);
261 feat = desc->features;
263 if (!strcmp(feat->name, "urn:AGL:widget:provided-unit")) {
264 src = wgt_info_param(feat, "content.src");
265 type = wgt_info_param(feat, "content.type");
266 rc2 = action(src, type);
267 if (rc >= 0 && rc2 < 0)
275 static int set_exec_flag(const char *src, const char *type)
280 i = sizeof exec_type_strings / sizeof *exec_type_strings;
282 if (!strcasecmp(type, exec_type_strings[--i])) {
283 rc = fchmodat(workdirfd, src, 0755, 0);
285 ERROR("can't make executable the file %s", src);
293 static int check_one_content(const char *src, const char *type)
299 ERROR("a content src is missing");
303 /* TODO: when dealing with HTML and languages, the check should
304 * include i18n path search of widgets */
305 rc = fstatat(workdirfd, src, &s, AT_NO_AUTOMOUNT|AT_SYMLINK_NOFOLLOW);
307 ERROR("can't get info on content %s: %m", src);
308 else if (!S_ISREG(s.st_mode)) {
309 ERROR("content %s isn't a regular file", src);
317 static int check_content(const struct wgt_desc *desc)
319 return for_all_content(desc, check_one_content);
322 static int check_widget(const struct wgt_desc *desc)
326 result = check_temporary_constraints(desc);
328 result = check_permissions(desc);
330 result = check_content(desc);
334 static int get_target_directory(char target[PATH_MAX], const char *root, const struct wgt_desc *desc)
338 rc = snprintf(target, PATH_MAX, "%s/%s/%s", root, desc->id, desc->ver);
342 ERROR("path too long");
349 static int move_widget_to(const char *destdir, int force)
351 return move_workdir(destdir, 1, force);
354 static int install_icon(const struct wgt_desc *desc)
357 char target[PATH_MAX];
360 create_directory(FWK_ICON_DIR, 0755, 1);
361 rc = snprintf(link, sizeof link, "%s/%s", FWK_ICON_DIR, desc->idaver);
362 if (rc >= (int)sizeof link) {
363 ERROR("link too long in install_icon");
368 rc = snprintf(target, sizeof target, "%s/%s", workdir, desc->icons->src);
369 if (rc >= (int)sizeof target) {
370 ERROR("target too long in install_icon");
376 rc = symlink(target, link);
378 ERROR("can't create link %s -> %s", link, target);
382 static int install_exec_flag(const struct wgt_desc *desc)
384 return for_all_content(desc, set_exec_flag);
387 static int install_security(const struct wgt_desc *desc)
389 char path[PATH_MAX], *head;
390 const char *icon, *perm;
392 unsigned int i, n, len, lic, lf;
395 rc = secmgr_init(desc->id);
399 rc = secmgr_path_public_read_only(workdir);
403 /* instal the files */
404 head = stpcpy(path, workdir);
405 assert(head < path + sizeof path);
406 len = (unsigned)((path + sizeof path) - head);
408 ERROR("root path too long in install_security");
409 errno = ENAMETOOLONG;
414 icon = desc->icons->src;
415 lic = (unsigned)strlen(icon);
419 f = file_of_index(i++);
420 lf = (unsigned)strlen(f->name);
422 ERROR("path too long in install_security");
423 errno = ENAMETOOLONG;
426 strcpy(head, f->name);
427 if (lf <= lic && !memcmp(f->name, icon, lf) && (!f->name[lf] || f->name[lf] == '/'))
428 rc = secmgr_path_public_read_only(path);
430 rc = secmgr_path_read_only(path);
435 /* install the permissions */
436 perm = first_usable_permission();
438 rc = secmgr_permit(perm);
439 INFO("permitting %s %s", perm, rc ? "FAILED!" : "success");
442 perm = next_usable_permission();
445 rc = secmgr_install();
453 /* install the widget of the file */
454 struct wgt_info *install_widget(const char *wgtfile, const char *root, int force)
456 struct wgt_info *ifo;
457 const struct wgt_desc *desc;
458 char installdir[PATH_MAX];
460 struct unitconf uconf;
462 NOTICE("-- INSTALLING widget %s to %s --", wgtfile, root);
465 create_directory(root, 0755, 1);
466 if (make_workdir(root, "TMP", 0)) {
467 ERROR("failed to create a working directory");
471 if (zread(wgtfile, 0))
474 if (check_all_signatures())
477 ifo = wgt_info_createat(workdirfd, NULL, 1, 1, 1);
481 reset_requested_permissions();
482 desc = wgt_info_desc(ifo);
483 if (check_widget(desc))
486 if (get_target_directory(installdir, root, desc))
489 if (move_widget_to(installdir, force))
492 if (install_icon(desc))
495 if (install_security(desc))
498 if (install_exec_flag(desc))
505 uconf.installdir = installdir;
506 uconf.icondir = FWK_ICON_DIR;
508 if (unit_install(ifo, &uconf))