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