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