gdbus: remove signature and reply from tables
[framework/connectivity/connman.git] / gdbus / object.c
1 /*
2  *
3  *  D-Bus helper library
4  *
5  *  Copyright (C) 2004-2011  Marcel Holtmann <marcel@holtmann.org>
6  *
7  *
8  *  This program is free software; you can redistribute it and/or modify
9  *  it under the terms of the GNU General Public License as published by
10  *  the Free Software Foundation; either version 2 of the License, or
11  *  (at your option) any later version.
12  *
13  *  This program is distributed in the hope that it will be useful,
14  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
15  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16  *  GNU General Public License for more details.
17  *
18  *  You should have received a copy of the GNU General Public License
19  *  along with this program; if not, write to the Free Software
20  *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
21  *
22  */
23
24 #ifdef HAVE_CONFIG_H
25 #include <config.h>
26 #endif
27
28 #include <stdio.h>
29 #include <string.h>
30
31 #include <glib.h>
32 #include <dbus/dbus.h>
33
34 #include "gdbus.h"
35
36 #define info(fmt...)
37 #define error(fmt...)
38 #define debug(fmt...)
39
40 struct generic_data {
41         unsigned int refcount;
42         GSList *interfaces;
43         char *introspect;
44 };
45
46 struct interface_data {
47         char *name;
48         const GDBusMethodTable *methods;
49         const GDBusSignalTable *signals;
50         const GDBusPropertyTable *properties;
51         void *user_data;
52         GDBusDestroyFunction destroy;
53 };
54
55 struct security_data {
56         GDBusPendingReply pending;
57         DBusMessage *message;
58         const GDBusMethodTable *method;
59         void *iface_user_data;
60 };
61
62 static void print_arguments(GString *gstr, const GDBusArgInfo *args,
63                                                 const char *direction)
64 {
65         for (; args && args->name; args++) {
66                 g_string_append_printf(gstr,
67                                         "\t\t\t<arg name=\"%s\" type=\"%s\"",
68                                         args->name, args->signature);
69
70                 if (direction)
71                         g_string_append_printf(gstr,
72                                         " direction=\"%s\"/>\n", direction);
73                 else
74                         g_string_append_printf(gstr, "/>\n");
75
76         }
77 }
78
79 static void generate_interface_xml(GString *gstr, struct interface_data *iface)
80 {
81         const GDBusMethodTable *method;
82         const GDBusSignalTable *signal;
83
84         for (method = iface->methods; method && method->name; method++) {
85                 if (!(method->in_args && method->in_args->name) &&
86                                 !(method->out_args && method->out_args->name))
87                         g_string_append_printf(gstr, "\t\t<method name=\"%s\"/>\n",
88                                                                 method->name);
89                 else {
90                         g_string_append_printf(gstr, "\t\t<method name=\"%s\">\n",
91                                                                 method->name);
92                         print_arguments(gstr, method->in_args, "in");
93                         print_arguments(gstr, method->out_args, "out");
94                         g_string_append_printf(gstr, "\t\t</method>\n");
95                 }
96         }
97
98         for (signal = iface->signals; signal && signal->name; signal++) {
99                 if (!(signal->args && signal->args->name))
100                         g_string_append_printf(gstr, "\t\t<signal name=\"%s\"/>\n",
101                                                                 signal->name);
102                 else {
103                         g_string_append_printf(gstr, "\t\t<signal name=\"%s\">\n",
104                                                                 signal->name);
105                         print_arguments(gstr, signal->args, NULL);
106                         g_string_append_printf(gstr, "\t\t</signal>\n");
107                 }
108         }
109 }
110
111 static void generate_introspection_xml(DBusConnection *conn,
112                                 struct generic_data *data, const char *path)
113 {
114         GSList *list;
115         GString *gstr;
116         char **children;
117         int i;
118
119         g_free(data->introspect);
120
121         gstr = g_string_new(DBUS_INTROSPECT_1_0_XML_DOCTYPE_DECL_NODE);
122
123         g_string_append_printf(gstr, "<node>\n");
124
125         for (list = data->interfaces; list; list = list->next) {
126                 struct interface_data *iface = list->data;
127
128                 g_string_append_printf(gstr, "\t<interface name=\"%s\">\n",
129                                                                 iface->name);
130
131                 generate_interface_xml(gstr, iface);
132
133                 g_string_append_printf(gstr, "\t</interface>\n");
134         }
135
136         if (!dbus_connection_list_registered(conn, path, &children))
137                 goto done;
138
139         for (i = 0; children[i]; i++)
140                 g_string_append_printf(gstr, "\t<node name=\"%s\"/>\n",
141                                                                 children[i]);
142
143         dbus_free_string_array(children);
144
145 done:
146         g_string_append_printf(gstr, "</node>\n");
147
148         data->introspect = g_string_free(gstr, FALSE);
149 }
150
151 static DBusMessage *introspect(DBusConnection *connection,
152                                 DBusMessage *message, void *user_data)
153 {
154         struct generic_data *data = user_data;
155         DBusMessage *reply;
156
157         if (!dbus_message_has_signature(message, DBUS_TYPE_INVALID_AS_STRING)) {
158                 error("Unexpected signature to introspect call");
159                 return NULL;
160         }
161
162         if (data->introspect == NULL)
163                 generate_introspection_xml(connection, data,
164                                                 dbus_message_get_path(message));
165
166         reply = dbus_message_new_method_return(message);
167         if (reply == NULL)
168                 return NULL;
169
170         dbus_message_append_args(reply, DBUS_TYPE_STRING, &data->introspect,
171                                         DBUS_TYPE_INVALID);
172
173         return reply;
174 }
175
176 static DBusHandlerResult process_message(DBusConnection *connection,
177                         DBusMessage *message, const GDBusMethodTable *method,
178                                                         void *iface_user_data)
179 {
180         DBusMessage *reply;
181
182         reply = method->function(connection, message, iface_user_data);
183
184         if (method->flags & G_DBUS_METHOD_FLAG_NOREPLY) {
185                 if (reply != NULL)
186                         dbus_message_unref(reply);
187                 return DBUS_HANDLER_RESULT_HANDLED;
188         }
189
190         if (method->flags & G_DBUS_METHOD_FLAG_ASYNC) {
191                 if (reply == NULL)
192                         return DBUS_HANDLER_RESULT_HANDLED;
193         }
194
195         if (reply == NULL)
196                 return DBUS_HANDLER_RESULT_NEED_MEMORY;
197
198         dbus_connection_send(connection, reply, NULL);
199         dbus_message_unref(reply);
200
201         return DBUS_HANDLER_RESULT_HANDLED;
202 }
203
204 static GDBusPendingReply next_pending = 1;
205 static GSList *pending_security = NULL;
206
207 static const GDBusSecurityTable *security_table = NULL;
208
209 void g_dbus_pending_success(DBusConnection *connection,
210                                         GDBusPendingReply pending)
211 {
212         GSList *list;
213
214         for (list = pending_security; list; list = list->next) {
215                 struct security_data *secdata = list->data;
216
217                 if (secdata->pending != pending)
218                         continue;
219
220                 pending_security = g_slist_remove(pending_security, secdata);
221
222                 process_message(connection, secdata->message,
223                                 secdata->method, secdata->iface_user_data);
224
225                 dbus_message_unref(secdata->message);
226                 g_free(secdata);
227                 return;
228         }
229 }
230
231 void g_dbus_pending_error_valist(DBusConnection *connection,
232                                 GDBusPendingReply pending, const char *name,
233                                         const char *format, va_list args)
234 {
235         GSList *list;
236
237         for (list = pending_security; list; list = list->next) {
238                 struct security_data *secdata = list->data;
239                 DBusMessage *reply;
240
241                 if (secdata->pending != pending)
242                         continue;
243
244                 pending_security = g_slist_remove(pending_security, secdata);
245
246                 reply = g_dbus_create_error_valist(secdata->message,
247                                                         name, format, args);
248                 if (reply != NULL) {
249                         dbus_connection_send(connection, reply, NULL);
250                         dbus_message_unref(reply);
251                 }
252
253                 dbus_message_unref(secdata->message);
254                 g_free(secdata);
255                 return;
256         }
257 }
258
259 void g_dbus_pending_error(DBusConnection *connection,
260                                 GDBusPendingReply pending,
261                                 const char *name, const char *format, ...)
262 {
263         va_list args;
264
265         va_start(args, format);
266
267         g_dbus_pending_error_valist(connection, pending, name, format, args);
268
269         va_end(args);
270 }
271
272 int polkit_check_authorization(DBusConnection *conn,
273                                 const char *action, gboolean interaction,
274                                 void (*function) (dbus_bool_t authorized,
275                                                         void *user_data),
276                                                 void *user_data, int timeout);
277
278 struct builtin_security_data {
279         DBusConnection *conn;
280         GDBusPendingReply pending;
281 };
282
283 static void builtin_security_result(dbus_bool_t authorized, void *user_data)
284 {
285         struct builtin_security_data *data = user_data;
286
287         if (authorized == TRUE)
288                 g_dbus_pending_success(data->conn, data->pending);
289         else
290                 g_dbus_pending_error(data->conn, data->pending,
291                                                 DBUS_ERROR_AUTH_FAILED, NULL);
292
293         g_free(data);
294 }
295
296 static void builtin_security_function(DBusConnection *conn,
297                                                 const char *action,
298                                                 gboolean interaction,
299                                                 GDBusPendingReply pending)
300 {
301         struct builtin_security_data *data;
302
303         data = g_new0(struct builtin_security_data, 1);
304         data->conn = conn;
305         data->pending = pending;
306
307         if (polkit_check_authorization(conn, action, interaction,
308                                 builtin_security_result, data, 30000) < 0)
309                 g_dbus_pending_error(conn, pending, NULL, NULL);
310 }
311
312 static gboolean check_privilege(DBusConnection *conn, DBusMessage *msg,
313                         const GDBusMethodTable *method, void *iface_user_data)
314 {
315         const GDBusSecurityTable *security;
316
317         for (security = security_table; security && security->privilege;
318                                                                 security++) {
319                 struct security_data *secdata;
320                 gboolean interaction;
321
322                 if (security->privilege != method->privilege)
323                         continue;
324
325                 secdata = g_new(struct security_data, 1);
326                 secdata->pending = next_pending++;
327                 secdata->message = dbus_message_ref(msg);
328                 secdata->method = method;
329                 secdata->iface_user_data = iface_user_data;
330
331                 pending_security = g_slist_prepend(pending_security, secdata);
332
333                 if (security->flags & G_DBUS_SECURITY_FLAG_ALLOW_INTERACTION)
334                         interaction = TRUE;
335                 else
336                         interaction = FALSE;
337
338                 if (!(security->flags & G_DBUS_SECURITY_FLAG_BUILTIN) &&
339                                                         security->function)
340                         security->function(conn, security->action,
341                                                 interaction, secdata->pending);
342                 else
343                         builtin_security_function(conn, security->action,
344                                                 interaction, secdata->pending);
345
346                 return TRUE;
347         }
348
349         return FALSE;
350 }
351
352 static void generic_unregister(DBusConnection *connection, void *user_data)
353 {
354         struct generic_data *data = user_data;
355
356         g_free(data->introspect);
357         g_free(data);
358 }
359
360 static struct interface_data *find_interface(GSList *interfaces,
361                                                 const char *name)
362 {
363         GSList *list;
364
365         if (name == NULL)
366                 return NULL;
367
368         for (list = interfaces; list; list = list->next) {
369                 struct interface_data *iface = list->data;
370                 if (!strcmp(name, iface->name))
371                         return iface;
372         }
373
374         return NULL;
375 }
376
377 static gboolean g_dbus_args_have_signature(const GDBusArgInfo *args,
378                                                         DBusMessage *message)
379 {
380         const char *sig = dbus_message_get_signature(message);
381         const char *p = NULL;
382
383         for (; args && args->signature && *sig; args++) {
384                 p = args->signature;
385
386                 for (; *sig && *p; sig++, p++) {
387                         if (*p != *sig)
388                                 return FALSE;
389                 }
390         }
391
392         if (*sig || (p && *p) || (args && args->signature))
393                 return FALSE;
394
395         return TRUE;
396 }
397
398 static DBusHandlerResult generic_message(DBusConnection *connection,
399                                         DBusMessage *message, void *user_data)
400 {
401         struct generic_data *data = user_data;
402         struct interface_data *iface;
403         const GDBusMethodTable *method;
404         const char *interface;
405
406         interface = dbus_message_get_interface(message);
407
408         iface = find_interface(data->interfaces, interface);
409         if (iface == NULL)
410                 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
411
412         for (method = iface->methods; method &&
413                         method->name && method->function; method++) {
414                 if (dbus_message_is_method_call(message, iface->name,
415                                                         method->name) == FALSE)
416                         continue;
417
418                 if (g_dbus_args_have_signature(method->in_args,
419                                                         message) == FALSE)
420                         continue;
421
422                 if (check_privilege(connection, message, method,
423                                                 iface->user_data) == TRUE)
424                         return DBUS_HANDLER_RESULT_HANDLED;
425
426                 return process_message(connection, message, method,
427                                                         iface->user_data);
428         }
429
430         return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
431 }
432
433 static DBusObjectPathVTable generic_table = {
434         .unregister_function    = generic_unregister,
435         .message_function       = generic_message,
436 };
437
438 static void invalidate_parent_data(DBusConnection *conn, const char *child_path)
439 {
440         struct generic_data *data = NULL;
441         char *parent_path, *slash;
442
443         parent_path = g_strdup(child_path);
444         slash = strrchr(parent_path, '/');
445         if (slash == NULL)
446                 goto done;
447
448         if (slash == parent_path && parent_path[1] != '\0')
449                 parent_path[1] = '\0';
450         else
451                 *slash = '\0';
452
453         if (!strlen(parent_path))
454                 goto done;
455
456         if (dbus_connection_get_object_path_data(conn, parent_path,
457                                                         (void *) &data) == FALSE) {
458                 goto done;
459         }
460
461         invalidate_parent_data(conn, parent_path);
462
463         if (data == NULL)
464                 goto done;
465
466         g_free(data->introspect);
467         data->introspect = NULL;
468
469 done:
470         g_free(parent_path);
471 }
472
473 static const GDBusMethodTable introspect_methods[] = {
474         { GDBUS_METHOD("Introspect", NULL,
475                         GDBUS_ARGS({ "xml", "s" }), introspect) },
476         { }
477 };
478
479 static void add_interface(struct generic_data *data, const char *name,
480                                 const GDBusMethodTable *methods,
481                                 const GDBusSignalTable *signals,
482                                 const GDBusPropertyTable *properties,
483                                 void *user_data,
484                                 GDBusDestroyFunction destroy)
485 {
486         struct interface_data *iface;
487
488         iface = g_new0(struct interface_data, 1);
489         iface->name = g_strdup(name);
490         iface->methods = methods;
491         iface->signals = signals;
492         iface->properties = properties;
493         iface->user_data = user_data;
494         iface->destroy = destroy;
495
496         data->interfaces = g_slist_append(data->interfaces, iface);
497 }
498
499 static struct generic_data *object_path_ref(DBusConnection *connection,
500                                                         const char *path)
501 {
502         struct generic_data *data;
503
504         if (dbus_connection_get_object_path_data(connection, path,
505                                                 (void *) &data) == TRUE) {
506                 if (data != NULL) {
507                         data->refcount++;
508                         return data;
509                 }
510         }
511
512         data = g_new0(struct generic_data, 1);
513         data->refcount = 1;
514
515         data->introspect = g_strdup(DBUS_INTROSPECT_1_0_XML_DOCTYPE_DECL_NODE "<node></node>");
516
517         if (!dbus_connection_register_object_path(connection, path,
518                                                 &generic_table, data)) {
519                 g_free(data->introspect);
520                 g_free(data);
521                 return NULL;
522         }
523
524         invalidate_parent_data(connection, path);
525
526         add_interface(data, DBUS_INTERFACE_INTROSPECTABLE,
527                         introspect_methods, NULL, NULL, data, NULL);
528
529         return data;
530 }
531
532 static gboolean remove_interface(struct generic_data *data, const char *name)
533 {
534         struct interface_data *iface;
535
536         iface = find_interface(data->interfaces, name);
537         if (iface == NULL)
538                 return FALSE;
539
540         data->interfaces = g_slist_remove(data->interfaces, iface);
541
542         if (iface->destroy)
543                 iface->destroy(iface->user_data);
544
545         g_free(iface->name);
546         g_free(iface);
547
548         return TRUE;
549 }
550
551 static void object_path_unref(DBusConnection *connection, const char *path)
552 {
553         struct generic_data *data = NULL;
554
555         if (dbus_connection_get_object_path_data(connection, path,
556                                                 (void *) &data) == FALSE)
557                 return;
558
559         if (data == NULL)
560                 return;
561
562         data->refcount--;
563
564         if (data->refcount > 0)
565                 return;
566
567         remove_interface(data, DBUS_INTERFACE_INTROSPECTABLE);
568
569         invalidate_parent_data(connection, path);
570
571         dbus_connection_unregister_object_path(connection, path);
572 }
573
574 static gboolean check_signal(DBusConnection *conn, const char *path,
575                                 const char *interface, const char *name,
576                                 const GDBusArgInfo **args)
577 {
578         struct generic_data *data = NULL;
579         struct interface_data *iface;
580         const GDBusSignalTable *signal;
581
582         *args = NULL;
583         if (!dbus_connection_get_object_path_data(conn, path,
584                                         (void *) &data) || data == NULL) {
585                 error("dbus_connection_emit_signal: path %s isn't registered",
586                                 path);
587                 return FALSE;
588         }
589
590         iface = find_interface(data->interfaces, interface);
591         if (iface == NULL) {
592                 error("dbus_connection_emit_signal: %s does not implement %s",
593                                 path, interface);
594                 return FALSE;
595         }
596
597         for (signal = iface->signals; signal && signal->name; signal++) {
598                 if (!strcmp(signal->name, name)) {
599                         *args = signal->args;
600                         break;
601                 }
602         }
603
604         if (*args == NULL) {
605                 error("No signal named %s on interface %s", name, interface);
606                 return FALSE;
607         }
608
609         return TRUE;
610 }
611
612 static dbus_bool_t emit_signal_valist(DBusConnection *conn,
613                                                 const char *path,
614                                                 const char *interface,
615                                                 const char *name,
616                                                 int first,
617                                                 va_list var_args)
618 {
619         DBusMessage *signal;
620         dbus_bool_t ret;
621         const GDBusArgInfo *args;
622
623         if (!check_signal(conn, path, interface, name, &args))
624                 return FALSE;
625
626         signal = dbus_message_new_signal(path, interface, name);
627         if (signal == NULL) {
628                 error("Unable to allocate new %s.%s signal", interface,  name);
629                 return FALSE;
630         }
631
632         ret = dbus_message_append_args_valist(signal, first, var_args);
633         if (!ret)
634                 goto fail;
635
636         if (g_dbus_args_have_signature(args, signal) == FALSE) {
637                 error("%s.%s: expected signature'%s' but got '%s'",
638                                 interface, name, args, signature);
639                 ret = FALSE;
640                 goto fail;
641         }
642
643         ret = dbus_connection_send(conn, signal, NULL);
644
645 fail:
646         dbus_message_unref(signal);
647
648         return ret;
649 }
650
651 gboolean g_dbus_register_interface(DBusConnection *connection,
652                                         const char *path, const char *name,
653                                         const GDBusMethodTable *methods,
654                                         const GDBusSignalTable *signals,
655                                         const GDBusPropertyTable *properties,
656                                         void *user_data,
657                                         GDBusDestroyFunction destroy)
658 {
659         struct generic_data *data;
660
661         data = object_path_ref(connection, path);
662         if (data == NULL)
663                 return FALSE;
664
665         if (find_interface(data->interfaces, name)) {
666                 object_path_unref(connection, path);
667                 return FALSE;
668         }
669
670         add_interface(data, name, methods, signals,
671                         properties, user_data, destroy);
672
673         g_free(data->introspect);
674         data->introspect = NULL;
675
676         return TRUE;
677 }
678
679 gboolean g_dbus_unregister_interface(DBusConnection *connection,
680                                         const char *path, const char *name)
681 {
682         struct generic_data *data = NULL;
683
684         if (path == NULL)
685                 return FALSE;
686
687         if (dbus_connection_get_object_path_data(connection, path,
688                                                 (void *) &data) == FALSE)
689                 return FALSE;
690
691         if (data == NULL)
692                 return FALSE;
693
694         if (remove_interface(data, name) == FALSE)
695                 return FALSE;
696
697         g_free(data->introspect);
698         data->introspect = NULL;
699
700         object_path_unref(connection, path);
701
702         return TRUE;
703 }
704
705 gboolean g_dbus_register_security(const GDBusSecurityTable *security)
706 {
707         if (security_table != NULL)
708                 return FALSE;
709
710         security_table = security;
711
712         return TRUE;
713 }
714
715 gboolean g_dbus_unregister_security(const GDBusSecurityTable *security)
716 {
717         security_table = NULL;
718
719         return TRUE;
720 }
721
722 DBusMessage *g_dbus_create_error_valist(DBusMessage *message, const char *name,
723                                         const char *format, va_list args)
724 {
725         char str[1024];
726
727         vsnprintf(str, sizeof(str), format, args);
728
729         return dbus_message_new_error(message, name, str);
730 }
731
732 DBusMessage *g_dbus_create_error(DBusMessage *message, const char *name,
733                                                 const char *format, ...)
734 {
735         va_list args;
736         DBusMessage *reply;
737
738         va_start(args, format);
739
740         reply = g_dbus_create_error_valist(message, name, format, args);
741
742         va_end(args);
743
744         return reply;
745 }
746
747 DBusMessage *g_dbus_create_reply_valist(DBusMessage *message,
748                                                 int type, va_list args)
749 {
750         DBusMessage *reply;
751
752         reply = dbus_message_new_method_return(message);
753         if (reply == NULL)
754                 return NULL;
755
756         if (dbus_message_append_args_valist(reply, type, args) == FALSE) {
757                 dbus_message_unref(reply);
758                 return NULL;
759         }
760
761         return reply;
762 }
763
764 DBusMessage *g_dbus_create_reply(DBusMessage *message, int type, ...)
765 {
766         va_list args;
767         DBusMessage *reply;
768
769         va_start(args, type);
770
771         reply = g_dbus_create_reply_valist(message, type, args);
772
773         va_end(args);
774
775         return reply;
776 }
777
778 gboolean g_dbus_send_message(DBusConnection *connection, DBusMessage *message)
779 {
780         dbus_bool_t result;
781
782         if (dbus_message_get_type(message) == DBUS_MESSAGE_TYPE_METHOD_CALL)
783                 dbus_message_set_no_reply(message, TRUE);
784
785         result = dbus_connection_send(connection, message, NULL);
786
787         dbus_message_unref(message);
788
789         return result;
790 }
791
792 gboolean g_dbus_send_reply_valist(DBusConnection *connection,
793                                 DBusMessage *message, int type, va_list args)
794 {
795         DBusMessage *reply;
796
797         reply = dbus_message_new_method_return(message);
798         if (reply == NULL)
799                 return FALSE;
800
801         if (dbus_message_append_args_valist(reply, type, args) == FALSE) {
802                 dbus_message_unref(reply);
803                 return FALSE;
804         }
805
806         return g_dbus_send_message(connection, reply);
807 }
808
809 gboolean g_dbus_send_reply(DBusConnection *connection,
810                                 DBusMessage *message, int type, ...)
811 {
812         va_list args;
813         gboolean result;
814
815         va_start(args, type);
816
817         result = g_dbus_send_reply_valist(connection, message, type, args);
818
819         va_end(args);
820
821         return result;
822 }
823
824 gboolean g_dbus_emit_signal(DBusConnection *connection,
825                                 const char *path, const char *interface,
826                                 const char *name, int type, ...)
827 {
828         va_list args;
829         gboolean result;
830
831         va_start(args, type);
832
833         result = emit_signal_valist(connection, path, interface,
834                                                         name, type, args);
835
836         va_end(args);
837
838         return result;
839 }
840
841 gboolean g_dbus_emit_signal_valist(DBusConnection *connection,
842                                 const char *path, const char *interface,
843                                 const char *name, int type, va_list args)
844 {
845         return emit_signal_valist(connection, path, interface,
846                                                         name, type, args);
847 }