more work
[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 <syslog.h>
21 #include <string.h>
22 #include <ctype.h>
23 #include <assert.h>
24 #include <unistd.h>
25
26 #include "verbose.h"
27 #include "wgtpkg.h"
28 #include "wgt.h"
29 #include "wgt-info.h"
30 #include "secmgr-wrap.h"
31
32 static int check_defined(const void *data, const char *name)
33 {
34         if (data)
35                 return 0;
36         syslog(LOG_ERR, "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                         syslog(LOG_ERR, "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                 syslog(LOG_ERR, "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                         syslog(LOG_ERR, "ungranted permission required: %s", name);
84                         errno = EPERM;
85                         return 0;
86                 } else {
87                         notice("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                 syslog(LOG_ERR, "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         rc = snprintf(link, sizeof link, "%s/%s@%s", ICONDESTDIR, desc->id, desc->version);
130         if (rc >= sizeof link) {
131                 syslog(LOG_ERR, "link to long in install_icon");
132                 errno = EINVAL;
133                 return -1;
134         }
135
136         rc = snprintf(target, sizeof target, "%s/%s", workdir, desc->icons->src);
137         if (rc >= sizeof target) {
138                 syslog(LOG_ERR, "target to long in install_icon");
139                 errno = EINVAL;
140                 return -1;
141         }
142
143         unlink(link);
144         rc = symlink(target, link);
145         if (rc)
146                 syslog(LOG_ERR, "can't create link %s -> %s", link, target);
147         return rc;
148 }
149
150 static int install_security(const struct wgt_desc *desc)
151 {
152         char path[PATH_MAX], *head;
153         const char *icon, *perm;
154         int rc, len, lic, lf;
155         unsigned int i, n;
156         struct filedesc *f;
157
158         rc = secmgr_init(desc->id);
159         if (rc)
160                 goto error;
161
162         rc = secmgr_path_public_read_only(workdir);
163         if (rc)
164                 goto error2;
165
166         /* instal the files */
167         head = stpcpy(path, workdir);
168         assert(sizeof path > (head - path));
169         len = (int)(sizeof path - (head - path));
170         if (!len) {
171                 syslog(LOG_ERR, "root path too long in install_security");
172                 errno = ENAMETOOLONG;
173                 goto error2;
174         }
175         len--;
176         *head++ = '/';
177         icon = desc->icons->src;
178         lic = (int)strlen(icon);
179         n = file_count();
180         i = 0;
181         while(i < n) {
182                 f = file_of_index(i++);
183                 lf = (int)strlen(f->name);
184                 if (lf >= len) {
185                         syslog(LOG_ERR, "path too long in install_security");
186                         errno = ENAMETOOLONG;
187                         goto error2;
188                 }
189                 strcpy(head, f->name);
190                 if (lf <= lic && !memcmp(f->name, icon, lf) && (!f->name[lf] || f->name[lf] == '/'))
191                         rc = secmgr_path_public_read_only(path);
192                 else
193                         rc = secmgr_path_read_only(path);
194                 if (rc)
195                         goto error2;
196         }
197
198         /* install the permissions */
199         perm = first_usable_permission();
200         while(perm) {
201                 rc = secmgr_permit(perm);
202                 if (rc)
203                         goto error2;
204                 perm = next_usable_permission();
205         }
206
207         rc = secmgr_install();
208         return rc;
209 error2:
210         secmgr_cancel();
211 error:
212         return -1;
213 }
214
215 /* install the widget of the file */
216 void install_widget(const char *wgtfile, const char *root, int force)
217 {
218         struct wgt_info *ifo;
219         const struct wgt_desc *desc;
220
221         notice("-- INSTALLING widget %s --", wgtfile);
222
223         /* workdir */
224         if (make_workdir_base(root, "TMP", 0)) {
225                 syslog(LOG_ERR, "failed to create a working directory");
226                 goto error1;
227         }
228
229         if (zread(wgtfile, 0))
230                 goto error2;
231
232         if (check_all_signatures())
233                 goto error2;
234
235         ifo = wgt_info_createat(workdirfd, NULL, 1, 1, 1);
236         if (!ifo)
237                 goto error2;
238
239         desc = wgt_info_desc(ifo);
240         if (check_widget(desc))
241                 goto error3;
242
243         if (move_widget(root, desc, force))
244                 goto error3;
245
246         if (install_icon(desc))
247                 goto error3;
248
249         if (install_security(desc))
250                 goto error3;
251         
252         return;
253
254 error3:
255         wgt_info_unref(ifo);
256
257 error2:
258         remove_workdir();
259
260 error1:
261         return;
262 }
263