Get the install directory
[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_widget(const struct wgt_desc *desc)
133 {
134         int result;
135         const struct wgt_desc_feature *feature;
136
137         result = check_temporary_constraints(desc);
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 get_target_directory(char target[PATH_MAX], const char *root, const struct wgt_desc *desc)
148 {
149         int rc;
150
151         rc = snprintf(target, PATH_MAX, "%s/%s/%s", root, desc->id, desc->ver);
152         if (rc < PATH_MAX)
153                 rc = 0;
154         else {
155                 ERROR("path too long");
156                 errno = EINVAL;
157                 rc = -1;
158         }
159         return rc;
160 }
161
162 static int move_widget_to(const char *destdir, int force)
163 {
164         return move_workdir(destdir, 1, force);
165 }
166
167 static int install_icon(const struct wgt_desc *desc)
168 {
169         char link[PATH_MAX];
170         char target[PATH_MAX];
171         int rc;
172
173         create_directory(FWK_ICON_DIR, 0755, 1);
174         rc = snprintf(link, sizeof link, "%s/%s", FWK_ICON_DIR, desc->idaver);
175         if (rc >= (int)sizeof link) {
176                 ERROR("link too long in install_icon");
177                 errno = EINVAL;
178                 return -1;
179         }
180
181         rc = snprintf(target, sizeof target, "%s/%s", workdir, desc->icons->src);
182         if (rc >= (int)sizeof target) {
183                 ERROR("target too long in install_icon");
184                 errno = EINVAL;
185                 return -1;
186         }
187
188         unlink(link);
189         rc = symlink(target, link);
190         if (rc)
191                 ERROR("can't create link %s -> %s", link, target);
192         return rc;
193 }
194
195 static int install_exec_flag(const struct wgt_desc *desc)
196 {
197         int i;
198
199         if (desc->content_type) {
200                 i = sizeof exec_type_strings / sizeof *exec_type_strings;
201                 while (i) {
202                         if (!strcasecmp(desc->content_type, exec_type_strings[--i]))
203                                 return fchmodat(workdirfd, desc->content_src, 0755, 0);
204                 }
205         }
206         return 0;
207 }
208
209 static int install_security(const struct wgt_desc *desc)
210 {
211         char path[PATH_MAX], *head;
212         const char *icon, *perm;
213         int rc;
214         unsigned int i, n, len, lic, lf;
215         struct filedesc *f;
216
217         rc = secmgr_init(desc->id);
218         if (rc)
219                 goto error;
220
221         rc = secmgr_path_public_read_only(workdir);
222         if (rc)
223                 goto error2;
224
225         /* instal the files */
226         head = stpcpy(path, workdir);
227         assert(head < path + sizeof path);
228         len = (unsigned)((path + sizeof path) - head);
229         if (!len) {
230                 ERROR("root path too long in install_security");
231                 errno = ENAMETOOLONG;
232                 goto error2;
233         }
234         len--;
235         *head++ = '/';
236         icon = desc->icons->src;
237         lic = (unsigned)strlen(icon);
238         n = file_count();
239         i = 0;
240         while(i < n) {
241                 f = file_of_index(i++);
242                 lf = (unsigned)strlen(f->name);
243                 if (lf >= len) {
244                         ERROR("path too long in install_security");
245                         errno = ENAMETOOLONG;
246                         goto error2;
247                 }
248                 strcpy(head, f->name);
249                 if (lf <= lic && !memcmp(f->name, icon, lf) && (!f->name[lf] || f->name[lf] == '/'))
250                         rc = secmgr_path_public_read_only(path);
251                 else
252                         rc = secmgr_path_read_only(path);
253                 if (rc)
254                         goto error2;
255         }
256
257         /* install the permissions */
258         perm = first_usable_permission();
259         while(perm) {
260                 rc = secmgr_permit(perm);
261                 INFO("permitting %s %s", perm, rc ? "FAILED!" : "success");
262                 if (rc)
263                         goto error2;
264                 perm = next_usable_permission();
265         }
266
267         rc = secmgr_install();
268         return rc;
269 error2:
270         secmgr_cancel();
271 error:
272         return -1;
273 }
274
275 /* install the widget of the file */
276 struct wgt_info *install_widget(const char *wgtfile, const char *root, int force)
277 {
278         struct wgt_info *ifo;
279         const struct wgt_desc *desc;
280         char installdir[PATH_MAX];
281
282         NOTICE("-- INSTALLING widget %s to %s --", wgtfile, root);
283
284         /* workdir */
285         create_directory(root, 0755, 1);
286         if (make_workdir(root, "TMP", 0)) {
287                 ERROR("failed to create a working directory");
288                 goto error1;
289         }
290
291         if (zread(wgtfile, 0))
292                 goto error2;
293
294         if (check_all_signatures())
295                 goto error2;
296
297         ifo = wgt_info_createat(workdirfd, NULL, 1, 1, 1);
298         if (!ifo)
299                 goto error2;
300
301         reset_requested_permissions();
302         desc = wgt_info_desc(ifo);
303         if (check_widget(desc))
304                 goto error3;
305
306         if (get_target_directory(installdir, root, desc))
307                 goto error3;
308
309         if (move_widget_to(installdir, force))
310                 goto error3;
311
312         if (install_icon(desc))
313                 goto error3;
314
315         if (install_exec_flag(desc))
316                 goto error3;
317
318         if (install_security(desc))
319                 goto error3;
320
321         file_reset();
322         return ifo;
323
324 error3:
325         wgt_info_unref(ifo);
326
327 error2:
328         remove_workdir();
329
330 error1:
331         file_reset();
332         return NULL;
333 }
334