836b136b6da007638f02c43c478ae5b23a799e92
[src/app-framework-main.git] / src / wgtpkg-install.c
1 /*
2  Copyright 2015, 2016, 2017 IoT.bzh
3
4  author: José Bollo <jose.bollo@iot.bzh>
5
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
9
10      http://www.apache.org/licenses/LICENSE-2.0
11
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.
17 */
18
19 #define _GNU_SOURCE
20
21 #include <limits.h>
22 #include <errno.h>
23 #include <string.h>
24 #include <ctype.h>
25 #include <assert.h>
26 #include <unistd.h>
27 #include <stdio.h>
28 #include <sys/stat.h>
29
30 #include "verbose.h"
31 #include "wgt.h"
32 #include "wgt-info.h"
33 #include "wgt-strings.h"
34 #include "wgtpkg-files.h"
35 #include "wgtpkg-workdir.h"
36 #include "wgtpkg-zip.h"
37 #include "wgtpkg-permissions.h"
38 #include "wgtpkg-digsig.h"
39 #include "wgtpkg-install.h"
40 #include "secmgr-wrap.h"
41 #include "utils-dir.h"
42 #include "wgtpkg-unit.h"
43
44 static const char* exec_type_strings[] = {
45         "application/x-executable",
46         "application/vnd.agl.native"
47 };
48
49 static int check_defined(const void *data, const char *name)
50 {
51         if (data)
52                 return 0;
53         ERROR("widget has no defined '%s' (temporary constraints)", name);
54         errno = EINVAL;
55         return -1;
56 }
57
58 static int check_valid_string(const char *value, const char *name)
59 {
60         int pos;
61         char c;
62
63         if (check_defined(value, name))
64                 return -1;
65         pos = 0;
66         c = value[pos];
67         if (c == 0) {
68                 ERROR("empty string forbidden in '%s' (temporary constraints)", name);
69                 errno = EINVAL;
70                 return -1;                      
71         }
72         do {
73                 if (!isalnum(c) && !strchr(".-_", c)) {
74                         ERROR("forbidden char %c in '%s' -> '%s' (temporary constraints)", c, name, value);
75                         errno = EINVAL;
76                         return -1;                      
77                 }
78                 c = value[++pos];
79         } while(c);
80         return 0;
81 }
82
83 static int check_temporary_constraints(const struct wgt_desc *desc)
84 {
85         int result;
86
87         result  = check_valid_string(desc->id, "id");
88         result |= check_valid_string(desc->version, "version");
89         result |= check_valid_string(desc->ver, "ver");
90         result |= check_defined(desc->icons, "icon");
91         result |= check_defined(desc->content_src, "content");
92         if (result)
93                 return result;
94
95         if (desc->icons->next) {
96                 ERROR("widget has more than one icon defined (temporary constraints)");
97                 errno = EINVAL;
98                 result = -1;
99         }
100         return 0;
101 }
102
103 static int set_required_permissions(struct wgt_desc_param *params, int required)
104 {
105         int optional;
106
107         while (params) {
108                 /* check if target */
109                 if (!strcmp(params->name, string_sharp_target)) {
110                         /* do nothing when #target */
111                 } else {
112                         /* check the value */
113                         if (!strcmp(params->value, string_required))
114                                 optional = !required;
115                         else if (!strcmp(params->value, string_optional))
116                                 optional = 1;
117                         else {
118                                 ERROR("unexpected parameter value: %s found for %s", params->value, params->name);
119                                 errno = EPERM;
120                                 return -1;
121                         }
122                         /* set the permission */
123                         if (request_permission(params->name)) {
124                                 DEBUG("granted permission: %s", params->name);
125                         } else if (optional) {
126                                 INFO("optional permission ungranted: %s", params->name);
127                         } else {
128                                 ERROR("ungranted permission required: %s", params->name);
129                                 errno = EPERM;
130                                 return -1;
131                         }
132                 }
133                 params = params->next;
134         }
135         return 0;
136 }
137
138 static int check_permissions(const struct wgt_desc *desc)
139 {
140         int result;
141         const struct wgt_desc_feature *feature;
142
143         result = 0;
144         feature = desc->features;
145         while(result >= 0 && feature) {
146                 if (!strcmp(feature->name, feature_required_permission))
147                         result = set_required_permissions(feature->params, feature->required);
148                 feature = feature->next;
149         }
150         return result;
151 }
152
153 static int check_widget(const struct wgt_desc *desc)
154 {
155         int result;
156
157         result = check_temporary_constraints(desc);
158         if (result >= 0)
159                 result = check_permissions(desc);
160         return result;
161 }
162
163 static int get_target_directory(char target[PATH_MAX], const char *root, const struct wgt_desc *desc)
164 {
165         int rc;
166
167         rc = snprintf(target, PATH_MAX, "%s/%s/%s", root, desc->id, desc->ver);
168         if (rc < PATH_MAX)
169                 rc = 0;
170         else {
171                 ERROR("path too long");
172                 errno = EINVAL;
173                 rc = -1;
174         }
175         return rc;
176 }
177
178 static int move_widget_to(const char *destdir, int force)
179 {
180         return move_workdir(destdir, 1, force);
181 }
182
183 static int install_icon(const struct wgt_desc *desc)
184 {
185         char link[PATH_MAX];
186         char target[PATH_MAX];
187         int rc;
188
189         create_directory(FWK_ICON_DIR, 0755, 1);
190         rc = snprintf(link, sizeof link, "%s/%s", FWK_ICON_DIR, desc->idaver);
191         if (rc >= (int)sizeof link) {
192                 ERROR("link too long in install_icon");
193                 errno = EINVAL;
194                 return -1;
195         }
196
197         rc = snprintf(target, sizeof target, "%s/%s", workdir, desc->icons->src);
198         if (rc >= (int)sizeof target) {
199                 ERROR("target too long in install_icon");
200                 errno = EINVAL;
201                 return -1;
202         }
203
204         unlink(link);
205         rc = symlink(target, link);
206         if (rc)
207                 ERROR("can't create link %s -> %s", link, target);
208         return rc;
209 }
210
211 static int install_exec_flag(const struct wgt_desc *desc)
212 {
213         int i;
214
215         if (desc->content_type) {
216                 i = sizeof exec_type_strings / sizeof *exec_type_strings;
217                 while (i) {
218                         if (!strcasecmp(desc->content_type, exec_type_strings[--i]))
219                                 return fchmodat(workdirfd, desc->content_src, 0755, 0);
220                 }
221         }
222         return 0;
223 }
224
225 static int install_security(const struct wgt_desc *desc)
226 {
227         char path[PATH_MAX], *head;
228         const char *icon, *perm;
229         int rc;
230         unsigned int i, n, len, lic, lf;
231         struct filedesc *f;
232
233         rc = secmgr_init(desc->id);
234         if (rc)
235                 goto error;
236
237         rc = secmgr_path_public_read_only(workdir);
238         if (rc)
239                 goto error2;
240
241         /* instal the files */
242         head = stpcpy(path, workdir);
243         assert(head < path + sizeof path);
244         len = (unsigned)((path + sizeof path) - head);
245         if (!len) {
246                 ERROR("root path too long in install_security");
247                 errno = ENAMETOOLONG;
248                 goto error2;
249         }
250         len--;
251         *head++ = '/';
252         icon = desc->icons->src;
253         lic = (unsigned)strlen(icon);
254         n = file_count();
255         i = 0;
256         while(i < n) {
257                 f = file_of_index(i++);
258                 lf = (unsigned)strlen(f->name);
259                 if (lf >= len) {
260                         ERROR("path too long in install_security");
261                         errno = ENAMETOOLONG;
262                         goto error2;
263                 }
264                 strcpy(head, f->name);
265                 if (lf <= lic && !memcmp(f->name, icon, lf) && (!f->name[lf] || f->name[lf] == '/'))
266                         rc = secmgr_path_public_read_only(path);
267                 else
268                         rc = secmgr_path_read_only(path);
269                 if (rc)
270                         goto error2;
271         }
272
273         /* install the permissions */
274         perm = first_usable_permission();
275         while(perm) {
276                 rc = secmgr_permit(perm);
277                 INFO("permitting %s %s", perm, rc ? "FAILED!" : "success");
278                 if (rc)
279                         goto error2;
280                 perm = next_usable_permission();
281         }
282
283         rc = secmgr_install();
284         return rc;
285 error2:
286         secmgr_cancel();
287 error:
288         return -1;
289 }
290
291 /* install the widget of the file */
292 struct wgt_info *install_widget(const char *wgtfile, const char *root, int force)
293 {
294         struct wgt_info *ifo;
295         const struct wgt_desc *desc;
296         char installdir[PATH_MAX];
297
298         NOTICE("-- INSTALLING widget %s to %s --", wgtfile, root);
299
300         /* workdir */
301         create_directory(root, 0755, 1);
302         if (make_workdir(root, "TMP", 0)) {
303                 ERROR("failed to create a working directory");
304                 goto error1;
305         }
306
307         if (zread(wgtfile, 0))
308                 goto error2;
309
310         if (check_all_signatures())
311                 goto error2;
312
313         ifo = wgt_info_createat(workdirfd, NULL, 1, 1, 1);
314         if (!ifo)
315                 goto error2;
316
317         reset_requested_permissions();
318         desc = wgt_info_desc(ifo);
319         if (check_widget(desc))
320                 goto error3;
321
322         if (get_target_directory(installdir, root, desc))
323                 goto error3;
324
325         if (move_widget_to(installdir, force))
326                 goto error3;
327
328         if (install_icon(desc))
329                 goto error3;
330
331         if (install_security(desc))
332                 goto error4;
333
334         if (install_exec_flag(desc))
335                 goto error4;
336
337         if (unit_install(ifo, installdir, FWK_ICON_DIR, 1234/*TODO*/))
338                 goto error4;
339
340         file_reset();
341         return ifo;
342
343 error4:
344         /* todo: cleanup */
345
346 error3:
347         wgt_info_unref(ifo);
348
349 error2:
350         remove_workdir();
351
352 error1:
353         file_reset();
354         return NULL;
355 }
356