Update copyright dates
[src/app-framework-binder.git] / src / afb-context.c
1 /*
2  * Copyright (C) 2015-2020 "IoT.bzh"
3  * Author "Fulup Ar Foll"
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 <assert.h>
22 #include <stdlib.h>
23 #include <stdint.h>
24 #include <errno.h>
25
26 #include "afb-session.h"
27 #include "afb-context.h"
28 #include "afb-token.h"
29 #include "afb-cred.h"
30 #include "afb-perm.h"
31 #include "afb-permission-text.h"
32 #include "verbose.h"
33
34 static void init_context(struct afb_context *context, struct afb_session *session, struct afb_token *token, struct afb_cred *cred)
35 {
36         assert(session != NULL);
37
38         /* reset the context for the session */
39         context->session = session;
40         context->flags = 0;
41         context->super = NULL;
42         context->api_key = NULL;
43         context->token = afb_token_addref(token);
44         context->credentials = afb_cred_addref(cred);
45 }
46
47 void afb_context_subinit(struct afb_context *context, struct afb_context *super)
48 {
49         context->session = afb_session_addref(super->session);
50         context->flags = 0;
51         context->super = super;
52         context->api_key = NULL;
53         context->token = afb_token_addref(super->token);
54         context->credentials = afb_cred_addref(super->credentials);
55 }
56
57 void afb_context_init(struct afb_context *context, struct afb_session *session, struct afb_token *token, struct afb_cred *cred)
58 {
59         init_context(context, afb_session_addref(session), token, cred);
60 }
61
62 int afb_context_connect(struct afb_context *context, const char *uuid, struct afb_token *token, struct afb_cred *cred)
63 {
64         int created;
65         struct afb_session *session;
66
67         session = afb_session_get (uuid, AFB_SESSION_TIMEOUT_DEFAULT, &created);
68         if (session == NULL)
69                 return -1;
70         init_context(context, session, token, cred);
71         if (created) {
72                 context->created = 1;
73         }
74         return 0;
75 }
76
77 int afb_context_connect_validated(struct afb_context *context, const char *uuid, struct afb_token *token, struct afb_cred *cred)
78 {
79         int rc = afb_context_connect(context, uuid, token, cred);
80         if (!rc)
81                 context->validated = 1;
82         return rc;
83 }
84
85 void afb_context_init_validated(struct afb_context *context, struct afb_session *session, struct afb_token *token, struct afb_cred *cred)
86 {
87         afb_context_init(context, session, token, cred);
88         context->validated = 1;
89 }
90
91 void afb_context_disconnect(struct afb_context *context)
92 {
93         if (context->session && !context->super && context->closing && !context->closed) {
94                 afb_context_change_loa(context, 0);
95                 afb_context_set(context, NULL, NULL);
96                 context->closed = 1;
97         }
98         afb_session_unref(context->session);
99         context->session = NULL;
100         afb_cred_unref(context->credentials);
101         context->credentials = NULL;
102         afb_token_unref(context->token);
103         context->token = NULL;
104 }
105
106 void afb_context_change_cred(struct afb_context *context, struct afb_cred *cred)
107 {
108         struct afb_cred *ocred = context->credentials;
109         if (ocred != cred) {
110                 context->credentials = afb_cred_addref(cred);
111                 afb_cred_unref(ocred);
112         }
113 }
114
115 void afb_context_change_token(struct afb_context *context, struct afb_token *token)
116 {
117         struct afb_token *otoken = context->token;
118         if (otoken != token) {
119                 context->token = afb_token_addref(token);
120                 afb_token_unref(otoken);
121         }
122 }
123
124 const char *afb_context_on_behalf_export(struct afb_context *context)
125 {
126         return context->credentials ? afb_cred_export(context->credentials) : NULL;
127 }
128
129 int afb_context_on_behalf_import(struct afb_context *context, const char *exported)
130 {
131         int rc;
132         struct afb_cred *imported, *ocred;
133
134         if (!exported || !*exported)
135                 rc = 0;
136         else {
137                 if (afb_context_has_permission(context, afb_permission_on_behalf_credential)) {
138                         imported = afb_cred_import(exported);
139                         if (!imported) {
140                                 ERROR("Can't import on behalf credentials: %m");
141                                 rc = -1;
142                         } else {
143                                 ocred = context->credentials;
144                                 context->credentials = imported;
145                                 afb_cred_unref(ocred);
146                                 rc = 0;
147                         }
148                 } else {
149                         ERROR("On behalf credentials refused");
150                         rc = -1;
151                 }
152         }
153         return rc;
154 }
155
156 void afb_context_on_behalf_other_context(struct afb_context *context, struct afb_context *other)
157 {
158         afb_context_change_cred(context, other->credentials);
159         afb_context_change_token(context, other->token);
160 }
161
162 int afb_context_has_permission(struct afb_context *context, const char *permission)
163 {
164         return afb_perm_check(context, permission);
165 }
166
167 void afb_context_has_permission_async(
168         struct afb_context *context,
169         const char *permission,
170         void (*callback)(void *_closure, int _status),
171         void *closure
172 )
173 {
174         return afb_perm_check_async(context, permission, callback, closure);
175 }
176
177 const char *afb_context_uuid(struct afb_context *context)
178 {
179         return context->session ? afb_session_uuid(context->session) : NULL;
180 }
181
182 void *afb_context_make(struct afb_context *context, int replace, void *(*make_value)(void *closure), void (*free_value)(void *item), void *closure)
183 {
184         assert(context->session != NULL);
185         return afb_session_cookie(context->session, context->api_key, make_value, free_value, closure, replace);
186 }
187
188 void *afb_context_get(struct afb_context *context)
189 {
190         assert(context->session != NULL);
191         return afb_session_get_cookie(context->session, context->api_key);
192 }
193
194 int afb_context_set(struct afb_context *context, void *value, void (*free_value)(void*))
195 {
196         assert(context->session != NULL);
197         return afb_session_set_cookie(context->session, context->api_key, value, free_value);
198 }
199
200 void afb_context_close(struct afb_context *context)
201 {
202         context->closing = 1;
203 }
204
205 struct chkctx {
206         struct afb_context *context;
207         void (*callback)(void *_closure, int _status);
208         void *closure;
209 };
210
211 static void check_context_cb(void *closure_chkctx, int status)
212 {
213         struct chkctx *cc = closure_chkctx;
214         struct afb_context *context = cc->context;
215         void (*callback)(void*,int) = cc->callback;
216         void *closure = cc->closure;
217
218         free(cc);
219         if (status)
220                 context->validated = 1;
221         else
222                 context->invalidated = 1;
223         callback(closure, status);
224 }
225
226 static int check_context(
227         struct afb_context *context,
228         void (*callback)(void *_closure, int _status),
229         void *closure
230 ) {
231         int r;
232         struct chkctx *cc;
233
234         if (context->validated)
235                 r = 1;
236         else if (context->invalidated)
237                 r = 0;
238         else {
239                 if (context->super)
240                         r = check_context(context->super, callback, closure);
241                 else if (!callback)
242                         r = afb_context_has_permission(context, afb_permission_token_valid);
243                 else {
244                         cc = malloc(sizeof *cc);
245                         if (cc) {
246                                 cc->context = context;
247                                 cc->callback = callback;
248                                 cc->closure = closure;
249                                 afb_context_has_permission_async(context, afb_permission_token_valid, check_context_cb, cc);
250                                 return -1;
251                         }
252                         ERROR("out-of-memory");
253                         r = 0;
254                 }
255                 if (r)
256                         context->validated = 1;
257                 else
258                         context->invalidated = 1;
259         }
260         return r;
261 }
262
263 int afb_context_check(struct afb_context *context)
264 {
265         return check_context(context, 0, 0);
266 }
267
268 void afb_context_check_async(
269         struct afb_context *context,
270         void (*callback)(void *_closure, int _status),
271         void *closure
272 ) {
273         int r = check_context(context, callback, closure);
274         if (r >= 0)
275                 callback(closure, r);
276 }
277
278 static inline const void *loa_key(struct afb_context *context)
279 {
280         return (const void*)(1+(intptr_t)(context->api_key));
281 }
282
283 static inline void *loa2ptr(unsigned loa)
284 {
285         return (void*)(intptr_t)loa;
286 }
287
288 static inline unsigned ptr2loa(void *ptr)
289 {
290         return (unsigned)(intptr_t)ptr;
291 }
292
293 int afb_context_change_loa(struct afb_context *context, unsigned loa)
294 {
295         if (loa > 7) {
296                 errno = EINVAL;
297                 return -1;
298         }
299         if (!afb_context_check(context)) {
300                 errno = EPERM;
301                 return -1;
302         }
303
304         return afb_session_set_cookie(context->session, loa_key(context), loa2ptr(loa), NULL);
305 }
306
307 unsigned afb_context_get_loa(struct afb_context *context)
308 {
309         assert(context->session != NULL);
310         return ptr2loa(afb_session_get_cookie(context->session, loa_key(context)));
311 }
312
313 int afb_context_check_loa(struct afb_context *context, unsigned loa)
314 {
315         return afb_context_get_loa(context) >= loa;
316 }