implement authorisation check
[src/app-framework-binder.git] / src / afb-xreq.c
1 /*
2  * Copyright (C) 2017 "IoT.bzh"
3  * Author José Bollo <jose.bollo@iot.bzh>
4  *
5  * Licensed under the Apache License, Version 2.0 (the "License");
6  * you may not use this file except in compliance with the License.
7  * You may obtain a copy of the License at
8  *
9  *   http://www.apache.org/licenses/LICENSE-2.0
10  *
11  * Unless required by applicable law or agreed to in writing, software
12  * distributed under the License is distributed on an "AS IS" BASIS,
13  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14  * See the License for the specific language governing permissions and
15  * limitations under the License.
16  */
17
18 #define _GNU_SOURCE
19 #define AFB_BINDING_PRAGMA_NO_VERBOSE_MACRO
20
21 #include <stdlib.h>
22 #include <string.h>
23 #include <errno.h>
24
25 #include <json-c/json.h>
26 #include <afb/afb-binding.h>
27
28 #include "afb-context.h"
29 #include "afb-xreq.h"
30 #include "afb-evt.h"
31 #include "afb-msg-json.h"
32 #include "afb-subcall.h"
33 #include "afb-hook.h"
34 #include "afb-api.h"
35 #include "afb-apiset.h"
36 #include "afb-auth.h"
37 #include "jobs.h"
38 #include "verbose.h"
39
40
41 static struct json_object *xreq_json_cb(void *closure)
42 {
43         struct afb_xreq *xreq = closure;
44         return xreq->json ? : (xreq->json = xreq->queryitf->json(xreq));
45 }
46
47 static struct afb_arg xreq_get_cb(void *closure, const char *name)
48 {
49         struct afb_xreq *xreq = closure;
50         if (xreq->queryitf->get)
51                 return xreq->queryitf->get(xreq, name);
52         else
53                 return afb_msg_json_get_arg(xreq_json_cb(closure), name);
54 }
55
56 static void xreq_success_cb(void *closure, struct json_object *obj, const char *info)
57 {
58         struct afb_xreq *xreq = closure;
59
60         if (xreq->replied) {
61                 ERROR("reply called more than one time!!");
62                 json_object_put(obj);
63         } else {
64                 xreq->replied = 1;
65                 if (xreq->queryitf->success)
66                         xreq->queryitf->success(xreq, obj, info);
67                 else
68                         xreq->queryitf->reply(xreq, 0, afb_msg_json_reply_ok(info, obj, &xreq->context, NULL));
69         }
70 }
71
72 static void xreq_fail_cb(void *closure, const char *status, const char *info)
73 {
74         struct afb_xreq *xreq = closure;
75
76         if (xreq->replied) {
77                 ERROR("reply called more than one time!!");
78         } else {
79                 xreq->replied = 1;
80                 if (xreq->queryitf->fail)
81                         xreq->queryitf->fail(xreq, status, info);
82                 else
83                         xreq->queryitf->reply(xreq, 1, afb_msg_json_reply_error(status, info, &xreq->context, NULL));
84         }
85 }
86
87 static const char *xreq_raw_cb(void *closure, size_t *size)
88 {
89         struct afb_xreq *xreq = closure;
90         const char *result = json_object_to_json_string(xreq_json_cb(xreq));
91         if (size != NULL)
92                 *size = strlen(result);
93         return result;
94 }
95
96 static void xreq_send_cb(void *closure, const char *buffer, size_t size)
97 {
98         struct json_object *obj = json_tokener_parse(buffer);
99         if (!obj == !buffer)
100                 xreq_success_cb(closure, obj, "fake send");
101         else
102                 xreq_fail_cb(closure, "fake-send-failed", "fake send");
103 }
104
105 static void *xreq_context_get_cb(void *closure)
106 {
107         struct afb_xreq *xreq = closure;
108         return afb_context_get(&xreq->context);
109 }
110
111 static void xreq_context_set_cb(void *closure, void *value, void (*free_value)(void*))
112 {
113         struct afb_xreq *xreq = closure;
114         afb_context_set(&xreq->context, value, free_value);
115 }
116
117 static void xreq_addref_cb(void *closure)
118 {
119         struct afb_xreq *xreq = closure;
120         __atomic_add_fetch(&xreq->refcount, 1, __ATOMIC_RELAXED);
121 }
122
123 static void xreq_unref_cb(void *closure)
124 {
125         struct afb_xreq *xreq = closure;
126         if (!__atomic_sub_fetch(&xreq->refcount, 1, __ATOMIC_RELAXED)) {
127                 xreq->queryitf->unref(xreq);
128         }
129 }
130
131 static void xreq_session_close_cb(void *closure)
132 {
133         struct afb_xreq *xreq = closure;
134         afb_context_close(&xreq->context);
135 }
136
137 static int xreq_session_set_LOA_cb(void *closure, unsigned level)
138 {
139         struct afb_xreq *xreq = closure;
140         return afb_context_change_loa(&xreq->context, level);
141 }
142
143 static int xreq_subscribe_cb(void *closure, struct afb_event event)
144 {
145         struct afb_xreq *xreq = closure;
146         return afb_xreq_subscribe(xreq, event);
147 }
148
149 int afb_xreq_subscribe(struct afb_xreq *xreq, struct afb_event event)
150 {
151         if (xreq->listener)
152                 return afb_evt_add_watch(xreq->listener, event);
153         if (xreq->queryitf->subscribe)
154                 return xreq->queryitf->subscribe(xreq, event);
155         ERROR("no event listener, subscription impossible");
156         errno = EINVAL;
157         return -1;
158 }
159
160 static int xreq_unsubscribe_cb(void *closure, struct afb_event event)
161 {
162         struct afb_xreq *xreq = closure;
163         return afb_xreq_unsubscribe(xreq, event);
164 }
165
166 int afb_xreq_unsubscribe(struct afb_xreq *xreq, struct afb_event event)
167 {
168         if (xreq->listener)
169                 return afb_evt_remove_watch(xreq->listener, event);
170         if (xreq->queryitf->unsubscribe)
171                 return xreq->queryitf->unsubscribe(xreq, event);
172         ERROR("no event listener, unsubscription impossible");
173         errno = EINVAL;
174         return -1;
175 }
176
177 static void xreq_subcall_cb(void *closure, const char *api, const char *verb, struct json_object *args, void (*callback)(void*, int, struct json_object*), void *cb_closure)
178 {
179         struct afb_xreq *xreq = closure;
180
181         if (xreq->queryitf->subcall)
182                 xreq->queryitf->subcall(xreq, api, verb, args, callback, cb_closure);
183         else
184                 afb_subcall(xreq, api, verb, args, callback, cb_closure);
185 }
186
187 static int xreq_subcallsync_cb(void *closure, const char *api, const char *verb, struct json_object *args, struct json_object **result)
188 {
189         struct afb_xreq *xreq = closure;
190         return afb_subcall_sync(xreq, api, verb, args, result);
191 }
192
193 static struct json_object *xreq_hooked_json_cb(void *closure)
194 {
195         struct json_object *r = xreq_json_cb(closure);
196         struct afb_xreq *xreq = closure;
197         return afb_hook_xreq_json(xreq, r);
198 }
199
200 static struct afb_arg xreq_hooked_get_cb(void *closure, const char *name)
201 {
202         struct afb_arg r = xreq_get_cb(closure, name);
203         struct afb_xreq *xreq = closure;
204         return afb_hook_xreq_get(xreq, name, r);
205 }
206
207 static void xreq_hooked_success_cb(void *closure, struct json_object *obj, const char *info)
208 {
209         struct afb_xreq *xreq = closure;
210         afb_hook_xreq_success(xreq, obj, info);
211         xreq_success_cb(closure, obj, info);
212 }
213
214 static void xreq_hooked_fail_cb(void *closure, const char *status, const char *info)
215 {
216         struct afb_xreq *xreq = closure;
217         afb_hook_xreq_fail(xreq, status, info);
218         xreq_fail_cb(closure, status, info);
219 }
220
221 static const char *xreq_hooked_raw_cb(void *closure, size_t *size)
222 {
223         size_t s;
224         const char *r = xreq_raw_cb(closure, size ? : &s);
225         struct afb_xreq *xreq = closure;
226         return afb_hook_xreq_raw(xreq, r, *(size ? : &s));
227 }
228
229 static void xreq_hooked_send_cb(void *closure, const char *buffer, size_t size)
230 {
231         struct afb_xreq *xreq = closure;
232         afb_hook_xreq_send(xreq, buffer, size);
233         xreq_send_cb(closure, buffer, size);
234 }
235
236 static void *xreq_hooked_context_get_cb(void *closure)
237 {
238         void *r = xreq_context_get_cb(closure);
239         struct afb_xreq *xreq = closure;
240         return afb_hook_xreq_context_get(xreq, r);
241 }
242
243 static void xreq_hooked_context_set_cb(void *closure, void *value, void (*free_value)(void*))
244 {
245         struct afb_xreq *xreq = closure;
246         afb_hook_xreq_context_set(xreq, value, free_value);
247         xreq_context_set_cb(closure, value, free_value);
248 }
249
250 static void xreq_hooked_addref_cb(void *closure)
251 {
252         struct afb_xreq *xreq = closure;
253         afb_hook_xreq_addref(xreq);
254         xreq_addref_cb(closure);
255 }
256
257 static void xreq_hooked_unref_cb(void *closure)
258 {
259         struct afb_xreq *xreq = closure;
260         afb_hook_xreq_unref(xreq);
261         if (!__atomic_sub_fetch(&xreq->refcount, 1, __ATOMIC_RELAXED)) {
262                 afb_hook_xreq_end(xreq);
263                 xreq->queryitf->unref(xreq);
264         }
265 }
266
267 static void xreq_hooked_session_close_cb(void *closure)
268 {
269         struct afb_xreq *xreq = closure;
270         afb_hook_xreq_session_close(xreq);
271         xreq_session_close_cb(closure);
272 }
273
274 static int xreq_hooked_session_set_LOA_cb(void *closure, unsigned level)
275 {
276         int r = xreq_session_set_LOA_cb(closure, level);
277         struct afb_xreq *xreq = closure;
278         return afb_hook_xreq_session_set_LOA(xreq, level, r);
279 }
280
281 static int xreq_hooked_subscribe_cb(void *closure, struct afb_event event)
282 {
283         int r = xreq_subscribe_cb(closure, event);
284         struct afb_xreq *xreq = closure;
285         return afb_hook_xreq_subscribe(xreq, event, r);
286 }
287
288 static int xreq_hooked_unsubscribe_cb(void *closure, struct afb_event event)
289 {
290         int r = xreq_unsubscribe_cb(closure, event);
291         struct afb_xreq *xreq = closure;
292         return afb_hook_xreq_unsubscribe(xreq, event, r);
293 }
294
295 struct reply
296 {
297         struct afb_xreq *xreq;
298         void (*callback)(void*, int, struct json_object*);
299         void *closure;
300 };
301
302 static void xreq_hooked_subcall_reply_cb(void *closure, int iserror, struct json_object *result)
303 {
304         struct reply *reply = closure;
305         
306         afb_hook_xreq_subcall_result(reply->xreq, iserror, result);
307         reply->callback(reply->closure, iserror, result);
308         free(reply);
309 }
310
311 static void xreq_hooked_subcall_cb(void *closure, const char *api, const char *verb, struct json_object *args, void (*callback)(void*, int, struct json_object*), void *cb_closure)
312 {
313         struct reply *reply = malloc(sizeof *reply);
314         struct afb_xreq *xreq = closure;
315         afb_hook_xreq_subcall(xreq, api, verb, args);
316         if (reply) {
317                 reply->xreq = xreq;
318                 reply->callback = callback;
319                 reply->closure = cb_closure;
320                 xreq_subcall_cb(closure, api, verb, args, xreq_hooked_subcall_reply_cb, reply);
321         } else {
322                 ERROR("out of memory");
323                 xreq_subcall_cb(closure, api, verb, args, callback, cb_closure);
324         }
325 }
326
327 static int xreq_hooked_subcallsync_cb(void *closure, const char *api, const char *verb, struct json_object *args, struct json_object **result)
328 {
329         int r;
330         struct afb_xreq *xreq = closure;
331         afb_hook_xreq_subcallsync(xreq, api, verb, args);
332         r = xreq_subcallsync_cb(closure, api, verb, args, result);
333         return afb_hook_xreq_subcallsync_result(xreq, r, *result);
334 }
335
336 const struct afb_req_itf xreq_itf = {
337         .json = xreq_json_cb,
338         .get = xreq_get_cb,
339         .success = xreq_success_cb,
340         .fail = xreq_fail_cb,
341         .raw = xreq_raw_cb,
342         .send = xreq_send_cb,
343         .context_get = xreq_context_get_cb,
344         .context_set = xreq_context_set_cb,
345         .addref = xreq_addref_cb,
346         .unref = xreq_unref_cb,
347         .session_close = xreq_session_close_cb,
348         .session_set_LOA = xreq_session_set_LOA_cb,
349         .subscribe = xreq_subscribe_cb,
350         .unsubscribe = xreq_unsubscribe_cb,
351         .subcall = xreq_subcall_cb,
352         .subcallsync = xreq_subcallsync_cb
353 };
354
355 const struct afb_req_itf xreq_hooked_itf = {
356         .json = xreq_hooked_json_cb,
357         .get = xreq_hooked_get_cb,
358         .success = xreq_hooked_success_cb,
359         .fail = xreq_hooked_fail_cb,
360         .raw = xreq_hooked_raw_cb,
361         .send = xreq_hooked_send_cb,
362         .context_get = xreq_hooked_context_get_cb,
363         .context_set = xreq_hooked_context_set_cb,
364         .addref = xreq_hooked_addref_cb,
365         .unref = xreq_hooked_unref_cb,
366         .session_close = xreq_hooked_session_close_cb,
367         .session_set_LOA = xreq_hooked_session_set_LOA_cb,
368         .subscribe = xreq_hooked_subscribe_cb,
369         .unsubscribe = xreq_hooked_unsubscribe_cb,
370         .subcall = xreq_hooked_subcall_cb,
371         .subcallsync = xreq_hooked_subcallsync_cb
372 };
373
374 static inline struct afb_req to_req(struct afb_xreq *xreq)
375 {
376         return (struct afb_req){ .itf = xreq->hookflags ? &xreq_hooked_itf : &xreq_itf, .closure = xreq };
377 }
378
379 struct json_object *afb_xreq_json(struct afb_xreq *xreq)
380 {
381         return afb_req_json(to_req(xreq));
382 }
383
384 void afb_xreq_success(struct afb_xreq *xreq, struct json_object *obj, const char *info)
385 {
386         afb_req_success(to_req(xreq), obj, info);
387 }
388
389 void afb_xreq_success_f(struct afb_xreq *xreq, struct json_object *obj, const char *info, ...)
390 {
391         char *message;
392         va_list args;
393         va_start(args, info);
394         if (info == NULL || vasprintf(&message, info, args) < 0)
395                 message = NULL;
396         va_end(args);
397         afb_xreq_success(xreq, obj, message);
398         free(message);
399 }
400
401 void afb_xreq_fail(struct afb_xreq *xreq, const char *status, const char *info)
402 {
403         afb_req_fail(to_req(xreq), status, info);
404 }
405
406 void afb_xreq_fail_f(struct afb_xreq *xreq, const char *status, const char *info, ...)
407 {
408         char *message;
409         va_list args;
410         va_start(args, info);
411         if (info == NULL || vasprintf(&message, info, args) < 0)
412                 message = NULL;
413         va_end(args);
414         afb_xreq_fail(xreq, status, message);
415         free(message);
416 }
417
418 const char *afb_xreq_raw(struct afb_xreq *xreq, size_t *size)
419 {
420         return afb_req_raw(to_req(xreq), size);
421 }
422
423 void afb_xreq_addref(struct afb_xreq *xreq)
424 {
425         afb_req_addref(to_req(xreq));
426 }
427
428 void afb_xreq_unref(struct afb_xreq *xreq)
429 {
430         afb_req_unref(to_req(xreq));
431 }
432
433 void afb_xreq_unhooked_subcall(struct afb_xreq *xreq, const char *api, const char *verb, struct json_object *args, void (*callback)(void*, int, struct json_object*), void *cb_closure)
434 {
435         xreq_subcall_cb(xreq, api, verb, args, callback, cb_closure);
436 }
437
438 void afb_xreq_subcall(struct afb_xreq *xreq, const char *api, const char *verb, struct json_object *args, void (*callback)(void*, int, struct json_object*), void *cb_closure)
439 {
440         afb_req_subcall(to_req(xreq), api, verb, args, callback, cb_closure);
441 }
442
443 static int xreq_session_check_apply(struct afb_xreq *xreq, int sessionflags, const struct afb_auth *auth)
444 {
445         int loa;
446
447         if ((sessionflags & (AFB_SESSION_CLOSE|AFB_SESSION_RENEW|AFB_SESSION_CHECK|AFB_SESSION_LOA_EQ)) != 0) {
448                 if (!afb_context_check(&xreq->context)) {
449                         afb_context_close(&xreq->context);
450                         afb_xreq_fail_f(xreq, "denied", "invalid token's identity");
451                         errno = EINVAL;
452                         return -1;
453                 }
454         }
455
456         if ((sessionflags & AFB_SESSION_LOA_GE) != 0) {
457                 loa = (sessionflags >> AFB_SESSION_LOA_SHIFT) & AFB_SESSION_LOA_MASK;
458                 if (!afb_context_check_loa(&xreq->context, loa)) {
459                         afb_xreq_fail_f(xreq, "denied", "invalid LOA");
460                         errno = EPERM;
461                         return -1;
462                 }
463         }
464
465         if ((sessionflags & AFB_SESSION_LOA_LE) != 0) {
466                 loa = (sessionflags >> AFB_SESSION_LOA_SHIFT) & AFB_SESSION_LOA_MASK;
467                 if (afb_context_check_loa(&xreq->context, loa + 1)) {
468                         afb_xreq_fail_f(xreq, "denied", "invalid LOA");
469                         errno = EPERM;
470                         return -1;
471                 }
472         }
473
474         if (auth && !afb_auth_check(auth, xreq)) {
475                 afb_xreq_fail_f(xreq, "denied", "authorisation refused");
476                 errno = EPERM;
477                 return -1;
478         }
479
480         if ((sessionflags & AFB_SESSION_RENEW) != 0) {
481                 afb_context_refresh(&xreq->context);
482         }
483         if ((sessionflags & AFB_SESSION_CLOSE) != 0) {
484                 afb_context_change_loa(&xreq->context, 0);
485                 afb_context_close(&xreq->context);
486         }
487
488         return 0;
489 }
490
491 void afb_xreq_call_verb_v1(struct afb_xreq *xreq, const struct afb_verb_desc_v1 *verb)
492 {
493         if (!verb)
494                 afb_xreq_fail_unknown_verb(xreq);
495         else
496                 if (!xreq_session_check_apply(xreq, verb->session, NULL))
497                         verb->callback(to_req(xreq));
498 }
499
500 void afb_xreq_call_verb_v2(struct afb_xreq *xreq, const struct afb_verb_v2 *verb)
501 {
502         if (!verb)
503                 afb_xreq_fail_unknown_verb(xreq);
504         else
505                 if (!xreq_session_check_apply(xreq, verb->session, verb->auth))
506                         verb->callback(to_req(xreq));
507 }
508
509 void afb_xreq_init(struct afb_xreq *xreq, const struct afb_xreq_query_itf *queryitf)
510 {
511         memset(xreq, 0, sizeof *xreq);
512         xreq->refcount = 1;
513         xreq->queryitf = queryitf;
514 }
515
516 void afb_xreq_fail_unknown_api(struct afb_xreq *xreq)
517 {
518         afb_xreq_fail_f(xreq, "unknown-api", "api %s not found (for verb %s)", xreq->api, xreq->verb);
519 }
520
521 void afb_xreq_fail_unknown_verb(struct afb_xreq *xreq)
522 {
523         afb_xreq_fail_f(xreq, "unknown-verb", "verb %s unknown within api %s", xreq->verb, xreq->api);
524 }
525
526 static void process_async(int signum, void *arg)
527 {
528         struct afb_xreq *xreq = arg;
529         struct afb_api api;
530
531         if (signum != 0) {
532                 afb_xreq_fail_f(xreq, "aborted", "signal %s(%d) caught", strsignal(signum), signum);
533         } else {
534                 /* init hooking */
535                 afb_hook_init_xreq(xreq);
536                 if (xreq->hookflags)
537                         afb_hook_xreq_begin(xreq);
538
539                 /* search the api */
540                 if (afb_apiset_get(xreq->apiset, xreq->api, &api) < 0) {
541                         afb_xreq_fail_f(xreq, "unknown-api", "api %s not found", xreq->api);
542                 } else {
543                         xreq->context.api_key = api.closure;
544                         api.itf->call(api.closure, xreq);
545                 }
546         }
547         afb_xreq_unref(xreq);
548 }
549
550 void afb_xreq_process(struct afb_xreq *xreq, struct afb_apiset *apiset)
551 {
552         xreq->apiset = apiset;
553
554         afb_xreq_addref(xreq);
555         if (jobs_queue(NULL, afb_apiset_timeout_get(apiset), process_async, xreq) < 0) {
556                 /* TODO: allows or not to proccess it directly as when no threading? (see above) */
557                 ERROR("can't process job with threads: %m");
558                 afb_xreq_fail_f(xreq, "cancelled", "not able to create a job for the task");
559                 afb_xreq_unref(xreq);
560         }
561         afb_xreq_unref(xreq);
562 }
563