wgtpkg-install: set exec flag for application/vnd.agl.native
[src/app-framework-main.git] / src / wgtpkg-install.c
1 /*
2  Copyright 2015, 2016 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-permissions";
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                 if (rc)
256                         goto error2;
257                 perm = next_usable_permission();
258         }
259
260         rc = secmgr_install();
261         return rc;
262 error2:
263         secmgr_cancel();
264 error:
265         return -1;
266 }
267
268 /* install the widget of the file */
269 struct wgt_info *install_widget(const char *wgtfile, const char *root, int force)
270 {
271         struct wgt_info *ifo;
272         const struct wgt_desc *desc;
273
274         NOTICE("-- INSTALLING widget %s to %s --", wgtfile, root);
275
276         /* workdir */
277         create_directory(root, 0755, 1);
278         if (make_workdir(root, "TMP", 0)) {
279                 ERROR("failed to create a working directory");
280                 goto error1;
281         }
282
283         if (zread(wgtfile, 0))
284                 goto error2;
285
286         if (check_all_signatures())
287                 goto error2;
288
289         ifo = wgt_info_createat(workdirfd, NULL, 1, 1, 1);
290         if (!ifo)
291                 goto error2;
292
293         reset_requested_permissions();
294         desc = wgt_info_desc(ifo);
295         if (check_widget(desc))
296                 goto error3;
297
298         if (move_widget(root, desc, force))
299                 goto error3;
300
301         if (install_icon(desc))
302                 goto error3;
303
304         if (install_exec_flag(desc))
305                 goto error3;
306
307         if (install_security(desc))
308                 goto error3;
309
310         file_reset();
311         return ifo;
312
313 error3:
314         wgt_info_unref(ifo);
315
316 error2:
317         remove_workdir();
318
319 error1:
320         file_reset();
321         return NULL;
322 }
323