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