work in progress
[src/app-framework-main.git] / src / wgtpkg-install.c
1 /*
2  Copyright 2015 IoT.bzh
3
4  Licensed under the Apache License, Version 2.0 (the "License");
5  you may not use this file except in compliance with the License.
6  You may obtain a copy of the License at
7
8      http://www.apache.org/licenses/LICENSE-2.0
9
10  Unless required by applicable law or agreed to in writing, software
11  distributed under the License is distributed on an "AS IS" BASIS,
12  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  See the License for the specific language governing permissions and
14  limitations under the License.
15 */
16
17 #define _GNU_SOURCE
18
19 #include <errno.h>
20 #include <string.h>
21 #include <ctype.h>
22 #include <assert.h>
23 #include <unistd.h>
24
25 #include "verbose.h"
26 #include "wgtpkg.h"
27 #include "wgt.h"
28 #include "wgt-info.h"
29 #include "secmgr-wrap.h"
30 #include "utils-dir.h"
31
32 static int check_defined(const void *data, const char *name)
33 {
34         if (data)
35                 return 0;
36         ERROR("widget has no defined '%s' (temporary constraints)", name);
37         errno = EINVAL;
38         return -1;
39 }
40
41 static int check_valid_string(const char *value, const char *name)
42 {
43         int pos;
44         char c;
45
46         if (check_defined(value, name))
47                 return -1;
48         pos = 0;
49         c = value[pos];
50         while(c) {
51                 if (!isalnum(c) && !strchr(".-_", c)) {
52                         ERROR("forbidden char %c in '%s' -> '%s' (temporary constraints)", c, name, value);
53                         errno = EINVAL;
54                         return -1;                      
55                 }
56                 c = value[++pos];
57         }
58         return 0;
59 }
60
61 static int check_temporary_constraints(const struct wgt_desc *desc)
62 {
63         int result = check_valid_string(desc->id, "id");
64         result |= check_valid_string(desc->version, "version");
65         result |= check_defined(desc->icons, "icon");
66         result |= check_defined(desc->content_src, "content");
67         if (result)
68                 return result;
69         if (desc->icons->next) {
70                 ERROR("widget has more than one icon defined (temporary constraints)");
71                 errno = EINVAL;
72                 result = -1;
73         }
74         return 0;
75 }
76
77 static int check_permissions(const char *name, int required)
78 {
79         if (permission_exists(name)) {
80                 if (request_permission(name)) {
81                         DEBUG("granted permission: %s", name);
82                 } else if (required) {
83                         ERROR("ungranted permission required: %s", name);
84                         errno = EPERM;
85                         return 0;
86                 } else {
87                         INFO("ungranted permission optional: %s", name);
88                 }
89         }
90         return 1;
91 }
92
93 static int check_widget(const struct wgt_desc *desc)
94 {
95         int result;
96         const struct wgt_desc_feature *feature;
97
98         result = check_temporary_constraints(desc);
99         feature = desc->features;
100         while(feature) {
101                 if (!check_permissions(feature->name, feature->required))
102                         result = -1;
103                 feature = feature->next;
104         }
105         return result;
106 }
107
108 static int move_widget(const char *root, const struct wgt_desc *desc, int force)
109 {
110         char newdir[PATH_MAX];
111         int rc;
112
113         rc = snprintf(newdir, sizeof newdir, "%s/%s/%s", root, desc->id, desc->version);
114         if (rc >= sizeof newdir) {
115                 ERROR("path to long in move_widget");
116                 errno = EINVAL;
117                 return -1;
118         }
119
120         return move_workdir(newdir, 1, force);
121 }
122
123 static int install_icon(const struct wgt_desc *desc)
124 {
125         char link[PATH_MAX];
126         char target[PATH_MAX];
127         int rc;
128
129         create_directory(FWK_ICON_DIR, 0755, 1);
130         rc = snprintf(link, sizeof link, "%s/%s@%s", FWK_ICON_DIR, desc->id, desc->version);
131         if (rc >= sizeof link) {
132                 ERROR("link to long in install_icon");
133                 errno = EINVAL;
134                 return -1;
135         }
136
137         rc = snprintf(target, sizeof target, "%s/%s", workdir, desc->icons->src);
138         if (rc >= sizeof target) {
139                 ERROR("target to long in install_icon");
140                 errno = EINVAL;
141                 return -1;
142         }
143
144         unlink(link);
145         rc = symlink(target, link);
146         if (rc)
147                 ERROR("can't create link %s -> %s", link, target);
148         return rc;
149 }
150
151 static int install_security(const struct wgt_desc *desc)
152 {
153         char path[PATH_MAX], *head;
154         const char *icon, *perm;
155         int rc, len, lic, lf;
156         unsigned int i, n;
157         struct filedesc *f;
158
159         rc = secmgr_init(desc->id);
160         if (rc)
161                 goto error;
162
163         rc = secmgr_path_public_read_only(workdir);
164         if (rc)
165                 goto error2;
166
167         /* instal the files */
168         head = stpcpy(path, workdir);
169         assert(sizeof path > (head - path));
170         len = (int)(sizeof path - (head - path));
171         if (!len) {
172                 ERROR("root path too long in install_security");
173                 errno = ENAMETOOLONG;
174                 goto error2;
175         }
176         len--;
177         *head++ = '/';
178         icon = desc->icons->src;
179         lic = (int)strlen(icon);
180         n = file_count();
181         i = 0;
182         while(i < n) {
183                 f = file_of_index(i++);
184                 lf = (int)strlen(f->name);
185                 if (lf >= len) {
186                         ERROR("path too long in install_security");
187                         errno = ENAMETOOLONG;
188                         goto error2;
189                 }
190                 strcpy(head, f->name);
191                 if (lf <= lic && !memcmp(f->name, icon, lf) && (!f->name[lf] || f->name[lf] == '/'))
192                         rc = secmgr_path_public_read_only(path);
193                 else
194                         rc = secmgr_path_read_only(path);
195                 if (rc)
196                         goto error2;
197         }
198
199         /* install the permissions */
200         perm = first_usable_permission();
201         while(perm) {
202                 rc = secmgr_permit(perm);
203                 if (rc)
204                         goto error2;
205                 perm = next_usable_permission();
206         }
207
208         rc = secmgr_install();
209         return rc;
210 error2:
211         secmgr_cancel();
212 error:
213         return -1;
214 }
215
216 /* install the widget of the file */
217 void install_widget(const char *wgtfile, const char *root, int force)
218 {
219         struct wgt_info *ifo;
220         const struct wgt_desc *desc;
221
222         NOTICE("-- INSTALLING widget %s --", wgtfile);
223
224         /* workdir */
225         create_directory(root, 0755, 1);
226         if (make_workdir_base(root, "TMP", 0)) {
227                 ERROR("failed to create a working directory");
228                 goto error1;
229         }
230
231         if (zread(wgtfile, 0))
232                 goto error2;
233
234         if (check_all_signatures())
235                 goto error2;
236
237         ifo = wgt_info_createat(workdirfd, NULL, 1, 1, 1);
238         if (!ifo)
239                 goto error2;
240
241         desc = wgt_info_desc(ifo);
242         if (check_widget(desc))
243                 goto error3;
244
245         if (move_widget(root, desc, force))
246                 goto error3;
247
248         if (install_icon(desc))
249                 goto error3;
250
251         if (install_security(desc))
252                 goto error3;
253         
254         return;
255
256 error3:
257         wgt_info_unref(ifo);
258
259 error2:
260         remove_workdir();
261
262 error1:
263         return;
264 }
265