Print credential in default request hook
[src/app-framework-binder.git] / src / afb-hook.c
1 /*
2  * Copyright (C) 2016, 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
20 #include <limits.h>
21 #include <stdio.h>
22 #include <stdarg.h>
23 #include <string.h>
24 #include <pthread.h>
25 #include <unistd.h>
26
27 #include <json-c/json.h>
28
29 #include <afb/afb-req-itf.h>
30 #include <afb/afb-event-itf.h>
31
32 #include "afb-context.h"
33 #include "afb-hook.h"
34 #include "afb-session.h"
35 #include "afb-cred.h"
36 #include "afb-xreq.h"
37 #include "afb-ditf.h"
38 #include "verbose.h"
39
40 /**
41  * Definition of a hook for xreq
42  */
43 struct afb_hook_xreq {
44         struct afb_hook_xreq *next; /**< next hook */
45         unsigned refcount; /**< reference count */
46         char *api; /**< api hooked or NULL for any */
47         char *verb; /**< verb hooked or NULL for any */
48         struct afb_session *session; /**< session hooked or NULL if any */
49         unsigned flags; /**< hook flags */
50         struct afb_hook_xreq_itf *itf; /**< interface of hook */
51         void *closure; /**< closure for callbacks */
52 };
53
54 /**
55  * Definition of a hook for ditf
56  */
57 struct afb_hook_ditf {
58         struct afb_hook_ditf *next; /**< next hook */
59         unsigned refcount; /**< reference count */
60         char *api; /**< api hooked or NULL for any */
61         unsigned flags; /**< hook flags */
62         struct afb_hook_ditf_itf *itf; /**< interface of hook */
63         void *closure; /**< closure for callbacks */
64 };
65
66 /* synchronisation across threads */
67 static pthread_rwlock_t rwlock = PTHREAD_RWLOCK_INITIALIZER;
68
69 /* list of hooks for xreq */
70 static struct afb_hook_xreq *list_of_xreq_hooks = NULL;
71
72 /* list of hooks for ditf */
73 static struct afb_hook_ditf *list_of_ditf_hooks = NULL;
74
75 /******************************************************************************
76  * section: default callbacks for tracing requests
77  *****************************************************************************/
78
79 static void _hook_xreq_(const struct afb_xreq *xreq, const char *format, ...)
80 {
81         int len;
82         char *buffer;
83         va_list ap;
84
85         va_start(ap, format);
86         len = vasprintf(&buffer, format, ap);
87         va_end(ap);
88
89         if (len < 0)
90                 NOTICE("hook xreq-%06d:%s/%s allocation error", xreq->hookindex, xreq->api, xreq->verb);
91         else {
92                 NOTICE("hook xreq-%06d:%s/%s %s", xreq->hookindex, xreq->api, xreq->verb, buffer);
93                 free(buffer);
94         }
95 }
96
97 static void hook_xreq_begin_default_cb(void * closure, const struct afb_xreq *xreq)
98 {
99         if (!xreq->cred)
100                 _hook_xreq_(xreq, "BEGIN");
101         else
102                 _hook_xreq_(xreq, "BEGIN uid=%d gid=%d pid=%d label=%s id=%s",
103                         (int)xreq->cred->uid,
104                         (int)xreq->cred->gid,
105                         (int)xreq->cred->pid,
106                         xreq->cred->label?:"(null)",
107                         xreq->cred->id?:"(null)"
108                 );
109 }
110
111 static void hook_xreq_end_default_cb(void * closure, const struct afb_xreq *xreq)
112 {
113         _hook_xreq_(xreq, "END");
114 }
115
116 static void hook_xreq_json_default_cb(void * closure, const struct afb_xreq *xreq, struct json_object *obj)
117 {
118         _hook_xreq_(xreq, "json() -> %s", json_object_to_json_string(obj));
119 }
120
121 static void hook_xreq_get_default_cb(void * closure, const struct afb_xreq *xreq, const char *name, struct afb_arg arg)
122 {
123         _hook_xreq_(xreq, "get(%s) -> { name: %s, value: %s, path: %s }", name, arg.name, arg.value, arg.path);
124 }
125
126 static void hook_xreq_success_default_cb(void * closure, const struct afb_xreq *xreq, struct json_object *obj, const char *info)
127 {
128         _hook_xreq_(xreq, "success(%s, %s)", json_object_to_json_string(obj), info);
129 }
130
131 static void hook_xreq_fail_default_cb(void * closure, const struct afb_xreq *xreq, const char *status, const char *info)
132 {
133         _hook_xreq_(xreq, "fail(%s, %s)", status, info);
134 }
135
136 static void hook_xreq_raw_default_cb(void * closure, const struct afb_xreq *xreq, const char *buffer, size_t size)
137 {
138         _hook_xreq_(xreq, "raw() -> %.*s", (int)size, buffer);
139 }
140
141 static void hook_xreq_send_default_cb(void * closure, const struct afb_xreq *xreq, const char *buffer, size_t size)
142 {
143         _hook_xreq_(xreq, "send(%.*s)", (int)size, buffer);
144 }
145
146 static void hook_xreq_context_get_default_cb(void * closure, const struct afb_xreq *xreq, void *value)
147 {
148         _hook_xreq_(xreq, "context_get() -> %p", value);
149 }
150
151 static void hook_xreq_context_set_default_cb(void * closure, const struct afb_xreq *xreq, void *value, void (*free_value)(void*))
152 {
153         _hook_xreq_(xreq, "context_set(%p, %p)", value, free_value);
154 }
155
156 static void hook_xreq_addref_default_cb(void * closure, const struct afb_xreq *xreq)
157 {
158         _hook_xreq_(xreq, "addref()");
159 }
160
161 static void hook_xreq_unref_default_cb(void * closure, const struct afb_xreq *xreq)
162 {
163         _hook_xreq_(xreq, "unref()");
164 }
165
166 static void hook_xreq_session_close_default_cb(void * closure, const struct afb_xreq *xreq)
167 {
168         _hook_xreq_(xreq, "session_close()");
169 }
170
171 static void hook_xreq_session_set_LOA_default_cb(void * closure, const struct afb_xreq *xreq, unsigned level, int result)
172 {
173         _hook_xreq_(xreq, "session_set_LOA(%u) -> %d", level, result);
174 }
175
176 static void hook_xreq_subscribe_default_cb(void * closure, const struct afb_xreq *xreq, struct afb_event event, int result)
177 {
178         _hook_xreq_(xreq, "subscribe(%s:%p) -> %d", afb_event_name(event), event.closure, result);
179 }
180
181 static void hook_xreq_unsubscribe_default_cb(void * closure, const struct afb_xreq *xreq, struct afb_event event, int result)
182 {
183         _hook_xreq_(xreq, "unsubscribe(%s:%p) -> %d", afb_event_name(event), event.closure, result);
184 }
185
186 static void hook_xreq_subcall_default_cb(void * closure, const struct afb_xreq *xreq, const char *api, const char *verb, struct json_object *args)
187 {
188         _hook_xreq_(xreq, "subcall(%s/%s, %s) ...", api, verb, json_object_to_json_string(args));
189 }
190
191 static void hook_xreq_subcall_result_default_cb(void * closure, const struct afb_xreq *xreq, int status, struct json_object *result)
192 {
193         _hook_xreq_(xreq, "    ...subcall... -> %d: %s", status, json_object_to_json_string(result));
194 }
195
196 static void hook_xreq_subcallsync_default_cb(void * closure, const struct afb_xreq *xreq, const char *api, const char *verb, struct json_object *args)
197 {
198         _hook_xreq_(xreq, "subcallsync(%s/%s, %s) ...", api, verb, json_object_to_json_string(args));
199 }
200
201 static void hook_xreq_subcallsync_result_default_cb(void * closure, const struct afb_xreq *xreq, int status, struct json_object *result)
202 {
203         _hook_xreq_(xreq, "    ...subcallsync... -> %d: %s", status, json_object_to_json_string(result));
204 }
205
206 static struct afb_hook_xreq_itf hook_xreq_default_itf = {
207         .hook_xreq_begin = hook_xreq_begin_default_cb,
208         .hook_xreq_end = hook_xreq_end_default_cb,
209         .hook_xreq_json = hook_xreq_json_default_cb,
210         .hook_xreq_get = hook_xreq_get_default_cb,
211         .hook_xreq_success = hook_xreq_success_default_cb,
212         .hook_xreq_fail = hook_xreq_fail_default_cb,
213         .hook_xreq_raw = hook_xreq_raw_default_cb,
214         .hook_xreq_send = hook_xreq_send_default_cb,
215         .hook_xreq_context_get = hook_xreq_context_get_default_cb,
216         .hook_xreq_context_set = hook_xreq_context_set_default_cb,
217         .hook_xreq_addref = hook_xreq_addref_default_cb,
218         .hook_xreq_unref = hook_xreq_unref_default_cb,
219         .hook_xreq_session_close = hook_xreq_session_close_default_cb,
220         .hook_xreq_session_set_LOA = hook_xreq_session_set_LOA_default_cb,
221         .hook_xreq_subscribe = hook_xreq_subscribe_default_cb,
222         .hook_xreq_unsubscribe = hook_xreq_unsubscribe_default_cb,
223         .hook_xreq_subcall = hook_xreq_subcall_default_cb,
224         .hook_xreq_subcall_result = hook_xreq_subcall_result_default_cb,
225         .hook_xreq_subcallsync = hook_xreq_subcallsync_default_cb,
226         .hook_xreq_subcallsync_result = hook_xreq_subcallsync_result_default_cb,
227 };
228
229 /******************************************************************************
230  * section: hooks for tracing requests
231  *****************************************************************************/
232
233 #define _HOOK_XREQ_(what,...)   \
234         struct afb_hook_xreq *hook; \
235         pthread_rwlock_rdlock(&rwlock); \
236         hook = list_of_xreq_hooks; \
237         while (hook) { \
238                 if (hook->itf->hook_xreq_##what \
239                  && (hook->flags & afb_hook_flag_req_##what) != 0 \
240                  && (!hook->session || hook->session == xreq->context.session) \
241                  && (!hook->api || !strcasecmp(hook->api, xreq->api)) \
242                  && (!hook->verb || !strcasecmp(hook->verb, xreq->verb))) { \
243                         hook->itf->hook_xreq_##what(hook->closure, __VA_ARGS__); \
244                 } \
245                 hook = hook->next; \
246         } \
247         pthread_rwlock_unlock(&rwlock);
248
249
250 void afb_hook_xreq_begin(const struct afb_xreq *xreq)
251 {
252         _HOOK_XREQ_(begin, xreq);
253 }
254
255 void afb_hook_xreq_end(const struct afb_xreq *xreq)
256 {
257         _HOOK_XREQ_(end, xreq);
258 }
259
260 struct json_object *afb_hook_xreq_json(const struct afb_xreq *xreq, struct json_object *obj)
261 {
262         _HOOK_XREQ_(json, xreq, obj);
263         return obj;
264 }
265
266 struct afb_arg afb_hook_xreq_get(const struct afb_xreq *xreq, const char *name, struct afb_arg arg)
267 {
268         _HOOK_XREQ_(get, xreq, name, arg);
269         return arg;
270 }
271
272 void afb_hook_xreq_success(const struct afb_xreq *xreq, struct json_object *obj, const char *info)
273 {
274         _HOOK_XREQ_(success, xreq, obj, info);
275 }
276
277 void afb_hook_xreq_fail(const struct afb_xreq *xreq, const char *status, const char *info)
278 {
279         _HOOK_XREQ_(fail, xreq, status, info);
280 }
281
282 const char *afb_hook_xreq_raw(const struct afb_xreq *xreq, const char *buffer, size_t size)
283 {
284         _HOOK_XREQ_(raw, xreq, buffer, size);
285         return buffer;
286 }
287
288 void afb_hook_xreq_send(const struct afb_xreq *xreq, const char *buffer, size_t size)
289 {
290         _HOOK_XREQ_(send, xreq, buffer, size);
291 }
292
293 void *afb_hook_xreq_context_get(const struct afb_xreq *xreq, void *value)
294 {
295         _HOOK_XREQ_(context_get, xreq, value);
296         return value;
297 }
298
299 void afb_hook_xreq_context_set(const struct afb_xreq *xreq, void *value, void (*free_value)(void*))
300 {
301         _HOOK_XREQ_(context_set, xreq, value, free_value);
302 }
303
304 void afb_hook_xreq_addref(const struct afb_xreq *xreq)
305 {
306         _HOOK_XREQ_(addref, xreq);
307 }
308
309 void afb_hook_xreq_unref(const struct afb_xreq *xreq)
310 {
311         _HOOK_XREQ_(unref, xreq);
312 }
313
314 void afb_hook_xreq_session_close(const struct afb_xreq *xreq)
315 {
316         _HOOK_XREQ_(session_close, xreq);
317 }
318
319 int afb_hook_xreq_session_set_LOA(const struct afb_xreq *xreq, unsigned level, int result)
320 {
321         _HOOK_XREQ_(session_set_LOA, xreq, level, result);
322         return result;
323 }
324
325 int afb_hook_xreq_subscribe(const struct afb_xreq *xreq, struct afb_event event, int result)
326 {
327         _HOOK_XREQ_(subscribe, xreq, event, result);
328         return result;
329 }
330
331 int afb_hook_xreq_unsubscribe(const struct afb_xreq *xreq, struct afb_event event, int result)
332 {
333         _HOOK_XREQ_(unsubscribe, xreq, event, result);
334         return result;
335 }
336
337 void afb_hook_xreq_subcall(const struct afb_xreq *xreq, const char *api, const char *verb, struct json_object *args)
338 {
339         _HOOK_XREQ_(subcall, xreq, api, verb, args);
340 }
341
342 void afb_hook_xreq_subcall_result(const struct afb_xreq *xreq, int status, struct json_object *result)
343 {
344         _HOOK_XREQ_(subcall_result, xreq, status, result);
345 }
346
347 void afb_hook_xreq_subcallsync(const struct afb_xreq *xreq, const char *api, const char *verb, struct json_object *args)
348 {
349         _HOOK_XREQ_(subcallsync, xreq, api, verb, args);
350 }
351
352 int afb_hook_xreq_subcallsync_result(const struct afb_xreq *xreq, int status, struct json_object *result)
353 {
354         _HOOK_XREQ_(subcallsync_result, xreq, status, result);
355         return status;
356 }
357
358 /******************************************************************************
359  * section: 
360  *****************************************************************************/
361
362 void afb_hook_init_xreq(struct afb_xreq *xreq)
363 {
364         static int reqindex;
365
366         int f, flags;
367         int add;
368         struct afb_hook_xreq *hook;
369
370         /* scan hook list to get the expected flags */
371         flags = 0;
372         pthread_rwlock_rdlock(&rwlock);
373         hook = list_of_xreq_hooks;
374         while (hook) {
375                 f = hook->flags & afb_hook_flags_req_all;
376                 add = f != 0
377                    && (!hook->session || hook->session == xreq->context.session)
378                    && (!hook->api || !strcasecmp(hook->api, xreq->api))
379                    && (!hook->verb || !strcasecmp(hook->verb, xreq->verb));
380                 if (add)
381                         flags |= f;
382                 hook = hook->next;
383         }
384         pthread_rwlock_unlock(&rwlock);
385
386         /* store the hooking data */
387         xreq->hookflags = flags;
388         if (flags) {
389                 pthread_rwlock_wrlock(&rwlock);
390                 if (++reqindex < 0)
391                         reqindex = 1;
392                 xreq->hookindex = reqindex;
393                 pthread_rwlock_unlock(&rwlock);
394         }
395 }
396
397 struct afb_hook_xreq *afb_hook_create_xreq(const char *api, const char *verb, struct afb_session *session, int flags, struct afb_hook_xreq_itf *itf, void *closure)
398 {
399         struct afb_hook_xreq *hook;
400
401         /* alloc the result */
402         hook = calloc(1, sizeof *hook);
403         if (hook == NULL)
404                 return NULL;
405
406         /* get a copy of the names */
407         hook->api = api ? strdup(api) : NULL;
408         hook->verb = verb ? strdup(verb) : NULL;
409         if ((api && !hook->api) || (verb && !hook->verb)) {
410                 free(hook->api);
411                 free(hook->verb);
412                 free(hook);
413                 return NULL;
414         }
415
416         /* initialise the rest */
417         hook->session = session;
418         if (session)
419                 afb_session_addref(session);
420         hook->refcount = 1;
421         hook->flags = flags;
422         hook->itf = itf ? itf : &hook_xreq_default_itf;
423         hook->closure = closure;
424
425         /* record the hook */
426         pthread_rwlock_wrlock(&rwlock);
427         hook->next = list_of_xreq_hooks;
428         list_of_xreq_hooks = hook;
429         pthread_rwlock_unlock(&rwlock);
430
431         /* returns it */
432         return hook;
433 }
434
435 struct afb_hook_xreq *afb_hook_addref_xreq(struct afb_hook_xreq *hook)
436 {
437         pthread_rwlock_wrlock(&rwlock);
438         hook->refcount++;
439         pthread_rwlock_unlock(&rwlock);
440         return hook;
441 }
442
443 void afb_hook_unref_xreq(struct afb_hook_xreq *hook)
444 {
445         struct afb_hook_xreq **prv;
446
447         if (hook) {
448                 pthread_rwlock_wrlock(&rwlock);
449                 if (--hook->refcount)
450                         hook = NULL;
451                 else {
452                         /* unlink */
453                         prv = &list_of_xreq_hooks;
454                         while (*prv && *prv != hook)
455                                 prv = &(*prv)->next;
456                         if(*prv)
457                                 *prv = hook->next;
458                 }
459                 pthread_rwlock_unlock(&rwlock);
460                 if (hook) {
461                         /* free */
462                         free(hook->api);
463                         free(hook->verb);
464                         if (hook->session)
465                                 afb_session_unref(hook->session);
466                         free(hook);
467                 }
468         }
469 }
470
471 /******************************************************************************
472  * section: default callbacks for tracing daemon interface
473  *****************************************************************************/
474
475 static void _hook_ditf_(const struct afb_ditf *ditf, const char *format, ...)
476 {
477         int len;
478         char *buffer;
479         va_list ap;
480
481         va_start(ap, format);
482         len = vasprintf(&buffer, format, ap);
483         va_end(ap);
484
485         if (len < 0)
486                 NOTICE("hook ditf-%s allocation error for %s", ditf->prefix, format);
487         else {
488                 NOTICE("hook ditf-%s %s", ditf->prefix, buffer);
489                 free(buffer);
490         }
491 }
492
493 static void hook_ditf_event_broadcast_before_cb(void *closure, const struct afb_ditf *ditf, const char *name, struct json_object *object)
494 {
495         _hook_ditf_(ditf, "event_broadcast.before(%s, %s)....", name, json_object_to_json_string(object));
496 }
497
498 static void hook_ditf_event_broadcast_after_cb(void *closure, const struct afb_ditf *ditf, const char *name, struct json_object *object, int result)
499 {
500         _hook_ditf_(ditf, "event_broadcast.after(%s, %s) -> %d", name, json_object_to_json_string(object), result);
501 }
502
503 static void hook_ditf_get_event_loop_cb(void *closure, const struct afb_ditf *ditf, struct sd_event *result)
504 {
505         _hook_ditf_(ditf, "get_event_loop() -> %p", result);
506 }
507
508 static void hook_ditf_get_user_bus_cb(void *closure, const struct afb_ditf *ditf, struct sd_bus *result)
509 {
510         _hook_ditf_(ditf, "get_user_bus() -> %p", result);
511 }
512
513 static void hook_ditf_get_system_bus_cb(void *closure, const struct afb_ditf *ditf, struct sd_bus *result)
514 {
515         _hook_ditf_(ditf, "get_system_bus() -> %p", result);
516 }
517
518 static void hook_ditf_vverbose_cb(void*closure, const struct afb_ditf *ditf, int level, const char *file, int line, const char *function, const char *fmt, va_list args)
519 {
520         int len;
521         char *msg;
522         va_list ap;
523
524         va_copy(ap, args);
525         len = vasprintf(&msg, fmt, ap);
526         va_end(ap);
527
528         if (len < 0)
529                 _hook_ditf_(ditf, "vverbose(%d, %s, %d, %s) -> %s ? ? ?", level, file, line, function, fmt);
530         else {
531                 _hook_ditf_(ditf, "vverbose(%d, %s, %d, %s) -> %s", level, file, line, function, msg);
532                 free(msg);
533         }
534 }
535
536 static void hook_ditf_event_make_cb(void *closure, const struct afb_ditf *ditf, const char *name, struct afb_event result)
537 {
538         _hook_ditf_(ditf, "event_make(%s) -> %s:%p", name, afb_event_name(result), result.closure);
539 }
540
541 static void hook_ditf_rootdir_get_fd_cb(void *closure, const struct afb_ditf *ditf, int result)
542 {
543         char path[PATH_MAX];
544         if (result < 0)
545                 _hook_ditf_(ditf, "rootdir_get_fd() -> %d, %m", result);
546         else {
547                 sprintf(path, "/proc/self/fd/%d", result);
548                 readlink(path, path, sizeof path);
549                 _hook_ditf_(ditf, "rootdir_get_fd() -> %d = %s", result, path);
550         }
551 }
552
553 static void hook_ditf_rootdir_open_locale_cb(void *closure, const struct afb_ditf *ditf, const char *filename, int flags, const char *locale, int result)
554 {
555         char path[PATH_MAX];
556         if (!locale)
557                 locale = "(null)";
558         if (result < 0)
559                 _hook_ditf_(ditf, "rootdir_open_locale(%s, %d, %s) -> %d, %m", filename, flags, locale, result);
560         else {
561                 sprintf(path, "/proc/self/fd/%d", result);
562                 readlink(path, path, sizeof path);
563                 _hook_ditf_(ditf, "rootdir_open_locale(%s, %d, %s) -> %d = %s", filename, flags, locale, result, path);
564         }
565 }
566
567 static void hook_ditf_queue_job(void *closure, const struct afb_ditf *ditf, void (*callback)(int signum, void *arg), void *argument, void *group, int timeout, int result)
568 {
569         _hook_ditf_(ditf, "queue_job(%p, %p, %p, %d) -> %d", callback, argument, group, timeout, result);
570 }
571
572 static struct afb_hook_ditf_itf hook_ditf_default_itf = {
573         .hook_ditf_event_broadcast_before = hook_ditf_event_broadcast_before_cb,
574         .hook_ditf_event_broadcast_after = hook_ditf_event_broadcast_after_cb,
575         .hook_ditf_get_event_loop = hook_ditf_get_event_loop_cb,
576         .hook_ditf_get_user_bus = hook_ditf_get_user_bus_cb,
577         .hook_ditf_get_system_bus = hook_ditf_get_system_bus_cb,
578         .hook_ditf_vverbose = hook_ditf_vverbose_cb,
579         .hook_ditf_event_make = hook_ditf_event_make_cb,
580         .hook_ditf_rootdir_get_fd = hook_ditf_rootdir_get_fd_cb,
581         .hook_ditf_rootdir_open_locale = hook_ditf_rootdir_open_locale_cb,
582         .hook_ditf_queue_job = hook_ditf_queue_job
583 };
584
585 /******************************************************************************
586  * section: hooks for tracing requests
587  *****************************************************************************/
588
589 #define _HOOK_DITF_(what,...)   \
590         struct afb_hook_ditf *hook; \
591         pthread_rwlock_rdlock(&rwlock); \
592         hook = list_of_ditf_hooks; \
593         while (hook) { \
594                 if (hook->itf->hook_ditf_##what \
595                  && (hook->flags & afb_hook_flag_ditf_##what) != 0 \
596                  && (!hook->api || !strcasecmp(hook->api, ditf->prefix))) { \
597                         hook->itf->hook_ditf_##what(hook->closure, __VA_ARGS__); \
598                 } \
599                 hook = hook->next; \
600         } \
601         pthread_rwlock_unlock(&rwlock);
602
603 void afb_hook_ditf_event_broadcast_before(const struct afb_ditf *ditf, const char *name, struct json_object *object)
604 {
605         _HOOK_DITF_(event_broadcast_before, ditf, name, object);
606 }
607
608 int afb_hook_ditf_event_broadcast_after(const struct afb_ditf *ditf, const char *name, struct json_object *object, int result)
609 {
610         _HOOK_DITF_(event_broadcast_after, ditf, name, object, result);
611         return result;
612 }
613
614 struct sd_event *afb_hook_ditf_get_event_loop(const struct afb_ditf *ditf, struct sd_event *result)
615 {
616         _HOOK_DITF_(get_event_loop, ditf, result);
617         return result;
618 }
619
620 struct sd_bus *afb_hook_ditf_get_user_bus(const struct afb_ditf *ditf, struct sd_bus *result)
621 {
622         _HOOK_DITF_(get_user_bus, ditf, result);
623         return result;
624 }
625
626 struct sd_bus *afb_hook_ditf_get_system_bus(const struct afb_ditf *ditf, struct sd_bus *result)
627 {
628         _HOOK_DITF_(get_system_bus, ditf, result);
629         return result;
630 }
631
632 void afb_hook_ditf_vverbose(const struct afb_ditf *ditf, int level, const char *file, int line, const char *function, const char *fmt, va_list args)
633 {
634         _HOOK_DITF_(vverbose, ditf, level, file, line, function, fmt, args);
635 }
636
637 struct afb_event afb_hook_ditf_event_make(const struct afb_ditf *ditf, const char *name, struct afb_event result)
638 {
639         _HOOK_DITF_(event_make, ditf, name, result);
640         return result;
641 }
642
643 int afb_hook_ditf_rootdir_get_fd(const struct afb_ditf *ditf, int result)
644 {
645         _HOOK_DITF_(rootdir_get_fd, ditf, result);
646         return result;
647 }
648
649 int afb_hook_ditf_rootdir_open_locale(const struct afb_ditf *ditf, const char *filename, int flags, const char *locale, int result)
650 {
651         _HOOK_DITF_(rootdir_open_locale, ditf, filename, flags, locale, result);
652         return result;
653 }
654
655 int afb_hook_ditf_queue_job(const struct afb_ditf *ditf, void (*callback)(int signum, void *arg), void *argument, void *group, int timeout, int result)
656 {
657         _HOOK_DITF_(queue_job, ditf, callback, argument, group, timeout, result);
658         return result;
659 }
660
661 /******************************************************************************
662  * section: 
663  *****************************************************************************/
664
665 int afb_hook_flags_ditf(const char *api)
666 {
667         int flags;
668         struct afb_hook_ditf *hook;
669
670         pthread_rwlock_rdlock(&rwlock);
671         flags = 0;
672         hook = list_of_ditf_hooks;
673         while (hook) {
674                 if (!api || !hook->api || !strcasecmp(hook->api, api))
675                         flags |= hook->flags;
676                 hook = hook->next;
677         }
678         pthread_rwlock_unlock(&rwlock);
679         return flags;
680 }
681
682 struct afb_hook_ditf *afb_hook_create_ditf(const char *api, int flags, struct afb_hook_ditf_itf *itf, void *closure)
683 {
684         struct afb_hook_ditf *hook;
685
686         /* alloc the result */
687         hook = calloc(1, sizeof *hook);
688         if (hook == NULL)
689                 return NULL;
690
691         /* get a copy of the names */
692         hook->api = api ? strdup(api) : NULL;
693         if (api && !hook->api) {
694                 free(hook);
695                 return NULL;
696         }
697
698         /* initialise the rest */
699         hook->refcount = 1;
700         hook->flags = flags;
701         hook->itf = itf ? itf : &hook_ditf_default_itf;
702         hook->closure = closure;
703
704         /* record the hook */
705         pthread_rwlock_wrlock(&rwlock);
706         hook->next = list_of_ditf_hooks;
707         list_of_ditf_hooks = hook;
708         pthread_rwlock_unlock(&rwlock);
709
710         /* returns it */
711         return hook;
712 }
713
714 struct afb_hook_ditf *afb_hook_addref_ditf(struct afb_hook_ditf *hook)
715 {
716         pthread_rwlock_wrlock(&rwlock);
717         hook->refcount++;
718         pthread_rwlock_unlock(&rwlock);
719         return hook;
720 }
721
722 void afb_hook_unref_ditf(struct afb_hook_ditf *hook)
723 {
724         struct afb_hook_ditf **prv;
725
726         if (hook) {
727                 pthread_rwlock_wrlock(&rwlock);
728                 if (--hook->refcount)
729                         hook = NULL;
730                 else {
731                         /* unlink */
732                         prv = &list_of_ditf_hooks;
733                         while (*prv && *prv != hook)
734                                 prv = &(*prv)->next;
735                         if(*prv)
736                                 *prv = hook->next;
737                 }
738                 pthread_rwlock_unlock(&rwlock);
739                 if (hook) {
740                         /* free */
741                         free(hook->api);
742                         free(hook);
743                 }
744         }
745 }
746