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