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