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