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