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