34 #include <sys/types.h> 41 #include <dbus/dbus-glib-lowlevel.h> 45 DBusConnection *dbus_conn = NULL;
48 DBusGConnection *master_conn = NULL;
50 DBusServer *dbus_srv = NULL;
53 json_t *json_filters = NULL;
56 gchar *address = NULL;
59 gboolean verbose = FALSE;
62 DBusBusType bus = DBUS_BUS_SESSION;
65 GList *eavesdropping_conns = NULL;
68 void handle_sigchld(
int sig) {
69 g_message(
"Received signal SIGCHLD");
70 while (waitpid((pid_t)(-1), 0, WNOHANG) > 0) {
71 g_message(
"Waiting for child");
75 g_message(
"Finished waiting for child");
91 DBusHandlerResult filter_cb (DBusConnection *conn,
97 DBusHandlerResult retval = DBUS_HANDLER_RESULT_HANDLED;
100 if (dbus_message_get_type (msg) ==
101 DBUS_MESSAGE_TYPE_METHOD_CALL &&
102 strcmp (dbus_message_get_path(msg),
103 "/org/freedesktop/DBus") == 0 &&
104 strcmp (dbus_message_get_interface(msg),
105 "org.freedesktop.DBus") == 0 &&
106 strcmp (dbus_message_get_destination(msg),
107 "org.freedesktop.DBus") == 0 &&
108 strcmp (dbus_message_get_member (msg),
"Hello") == 0) {
110 DBusMessage *welcome;
111 const gchar *dbus_local_name;
113 dbus_local_name = dbus_bus_get_unique_name (
114 dbus_g_connection_get_connection(master_conn));
117 g_message(
"Hello received\n");
120 welcome = dbus_message_new_method_return (msg);
121 if (!dbus_message_append_args (welcome,
124 DBUS_TYPE_INVALID)) {
125 g_error(
"Cannot reply to Hello message\n");
128 dbus_connection_send(conn, welcome, &serial);
130 dbus_message_unref (welcome);
135 if (dbus_message_get_type(msg) ==
136 DBUS_MESSAGE_TYPE_SIGNAL &&
137 strcmp (dbus_message_get_interface (msg),
138 "org.freedesktop.DBus.Local") == 0 &&
139 strcmp (dbus_message_get_member (msg),
140 "Disconnected") == 0) {
144 g_message(
"connection was disconnected\n");
147 dbus_connection_close (dbus_conn);
148 dbus_connection_unref (dbus_conn);
155 if (dbus_message_get_interface (msg) == NULL ||
156 strcmp (dbus_message_get_interface(msg),
157 "org.freedesktop.DBus") == 0)
159 dbus_connection_send(
160 dbus_g_connection_get_connection(master_conn),
163 }
else if (is_allowed(
"outgoing",
164 dbus_message_get_interface (msg),
165 dbus_message_get_path (msg),
166 dbus_message_get_member (msg)))
168 g_message(
"Accepted call to '%s' from client to '%s' on '%s'.\n",
169 dbus_message_get_member (msg),
170 dbus_message_get_interface(msg),
171 dbus_message_get_path (msg));
173 dbus_connection_send (
174 dbus_g_connection_get_connection (master_conn),
178 g_message(
"Rejected call to '%s' from " 179 "client to '%s' on '%s'.\n",
180 dbus_message_get_member (msg),
181 dbus_message_get_interface (msg),
182 dbus_message_get_path (msg));
183 retval = DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
197 gboolean compare_entry(
const char *comparison,
const gchar *
string) {
199 g_message(
"will try matching %s with %s\n",
string, comparison);
202 if ((strcmp (
string,
"") != 0) && g_pattern_match_simple (
string, comparison)) {
204 g_message(
"was a match\n");
209 g_message(
"no match\n");
226 gboolean match_rule(
const json_t *rule,
228 const char *comparison)
233 json_entry = json_object_get(rule, entry);
236 if (!json_is_string (json_entry)) {
240 string = (gchar*) json_string_value (json_entry);
241 return compare_entry(comparison,
string);
254 gboolean match_method(
const json_t *rule,
const char *comparison)
259 json_entry = json_object_get(rule,
"method");
260 if (json_is_array(json_entry)) {
264 json_array_foreach(json_entry, ix, val) {
265 if (!json_is_string(val)) {
267 g_message(
"Entry in method array is not a string.");
272 string = (gchar*) json_string_value (val);
273 if ((strcmp (
string,
"") != 0) && g_pattern_match_simple (
string, comparison)) {
275 g_message(
"was a match\n");
280 }
else if (json_is_string (json_entry)) {
281 string = (gchar*) json_string_value (json_entry);
282 return compare_entry(comparison,
string);
301 gboolean is_allowed (
const char *direction,
302 const char *interface,
308 gboolean direction_ok, interface_ok, object_path_ok, method_ok;
313 for (i = 0; i < json_array_size (json_filters); i++) {
314 direction_ok, interface_ok, object_path_ok, method_ok = FALSE;
317 rule = json_array_get (json_filters, i);
318 if (rule == NULL || !json_is_object (rule)) {
323 direction_ok = match_rule (rule,
"direction", direction);
324 interface_ok = match_rule (rule,
"interface", interface);
325 object_path_ok = match_rule (rule,
"object-path", path);
326 method_ok = match_method(rule, member);
346 g_message(
"Direction '%s' does not match but " 347 "everything else does\n", direction);
366 DBusHandlerResult master_filter_cb (DBusConnection *conn,
373 DBusHandlerResult retval = DBUS_HANDLER_RESULT_HANDLED;
380 if (dbus_message_get_member(msg) != NULL &&
381 strcmp(dbus_message_get_member(msg),
"NameAcquired") == 0)
383 const char *dest = dbus_message_get_destination(msg);
386 g_message(
"NameAcquired received by %s\n", dest);
390 is_conn_known_eavesdropper(dest))
394 g_message(
"New connection's unique name ('%s')" 395 " was previously known as an eavesdropper." 396 " Removed old entry...\n", dest);
398 remove_name_from_known_eavesdroppers(dest);
403 if (dbus_message_get_interface(msg) == NULL ||
404 strcmp(dbus_message_get_interface(msg),
405 "org.freedesktop.DBus") == 0)
407 if (is_incoming_eavesdropping(msg) &&
408 !is_conn_known_eavesdropper(dbus_message_get_sender(msg)))
410 eavesdropping_conns =
411 g_list_append (eavesdropping_conns,
412 (gpointer) dbus_message_get_sender(msg));
415 dbus_connection_send(dbus_conn, msg, &serial);
416 }
else if (is_conn_known_eavesdropper (dbus_bus_get_unique_name(conn)))
419 g_message(
"'%s' is an eavesdropping connection, let it go...\n",
420 dbus_bus_get_unique_name(conn));
422 }
else if (is_allowed(
"incoming",
423 dbus_message_get_interface (msg),
424 dbus_message_get_path (msg),
425 dbus_message_get_member (msg)))
427 g_message(
"Accepted call to '%s' from server to '%s' on '%s'.\n",
428 dbus_message_get_member (msg),
429 dbus_message_get_interface (msg),
430 dbus_message_get_path (msg));
431 dbus_connection_send(dbus_conn, msg, &serial);
433 g_message(
"Rejected call to '%s' from server to '%s' on '%s'.\n",
434 dbus_message_get_member (msg),
435 dbus_message_get_interface (msg),
436 dbus_message_get_path (msg));
437 retval = DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
449 dbus_bool_t allow_all_connections (DBusConnection *conn,
466 gboolean is_incoming_eavesdropping (DBusMessage *msg)
468 gboolean is_eavesdropping = FALSE;
471 if (dbus_message_get_member(msg) != NULL &&
472 strcmp(dbus_message_get_member(msg),
"AddMatch") == 0)
474 const char *msg_arguments;
475 dbus_message_get_args (msg,
480 if (strstr(msg_arguments,
"eavesdrop=true") != NULL)
482 is_eavesdropping = TRUE;
485 g_message(
"'%s' AddMatch-args: \"%s\"\n",
486 dbus_message_get_sender(msg),
491 return is_eavesdropping;
503 gboolean is_conn_known_eavesdropper (
const char *unique_name)
505 gboolean found = FALSE;
506 GList *iter = eavesdropping_conns;
510 if (strcmp(unique_name, (
char*) iter->data) == 0)
533 gboolean remove_name_from_known_eavesdroppers (
const char *unique_name)
535 gboolean removed = FALSE;
536 GList *iter = eavesdropping_conns;
540 if (strcmp(unique_name, (
char*) iter->data) == 0)
542 eavesdropping_conns =
543 g_list_remove (eavesdropping_conns, iter->data);
562 void new_connection_cb (DBusServer *server, DBusConnection *conn,
void *data) {
565 GError *error = NULL;
572 g_message(
"in main process, pid: %d\n", pid);
580 g_message(
"in child process, pid: %d\n", pid);
584 if (master_conn != NULL) {
585 g_message(
"master_conn already initialized\n");
589 if (dbus_conn != NULL) {
590 g_message(
"dbus_conn already initialized\n");
595 master_conn = dbus_g_bus_get (bus, &error);
597 g_error(
"Failed to open connection to bus: %s\n", error->message);
598 g_clear_error (&error);
602 dbus_connection_add_filter (
603 dbus_g_connection_get_connection(master_conn),
609 g_message(
"New connection\n");
612 dbus_connection_ref (conn);
613 dbus_connection_setup_with_g_main (conn, NULL);
614 dbus_connection_add_filter (conn, filter_cb, NULL, NULL);
616 dbus_connection_set_unix_user_function (conn,
617 allow_all_connections,
621 dbus_connection_set_allow_anonymous (conn, TRUE);
628 dbus_error_init (&error);
630 if (dbus_srv != NULL) {
631 dbus_server_disconnect(dbus_srv);
632 dbus_server_unref(dbus_srv);
634 dbus_srv = dbus_server_listen (address, &error);
635 if (dbus_srv == NULL) {
636 g_error(
"Cannot listen on %s\n", address);
640 dbus_server_set_new_connection_function (dbus_srv,
644 dbus_server_setup_with_g_main (dbus_srv, NULL);
648 void parse_full_config(
const char *config_string,
const char *section) {
653 char *full_section = calloc(30,
sizeof(
char));
655 snprintf(full_section, 30,
"dbus-gateway-config-%s", section);
657 g_message(
"Parsing config");
660 root = json_loads(config_string, 0, &error);
663 g_error(
"error: on line %d: %s\n", error.line, error.text);
668 config = json_object_get(root, full_section);
670 g_message(
"%s\n", json_dumps(config, JSON_INDENT(4)));
672 if (!json_is_array(config)) {
673 g_error(
"error: %s is not present in config, or not an array. " 674 "Fix your config\n", full_section);
675 json_decref (config);
678 if (NULL == json_filters) {
679 json_filters = config;
681 if (0 != json_array_extend(json_filters, config)) {
682 g_error(
"Error extending config array\n");
689 g_print(
"dbus-proxy, version %s\n", PACKAGE_VERSION);
690 g_print(
"Usage: dbus-proxy address session|system\n" 691 "waits for config on stdin\n");
698 gboolean log_file_is_open() {
699 return log_file ? TRUE : FALSE;
702 gboolean open_log_file() {
704 pid_t pid = getpid();
705 sprintf(buf,
"/tmp/dbus-proxy-%d.log", pid);
706 log_file = fopen(buf,
"a");
708 if (NULL == log_file) {
715 gboolean close_log_file() {
716 if (NULL == log_file) {
720 int res = fclose(log_file);
731 void log_handler(
const gchar *log_domain,
732 GLogLevelFlags log_level,
733 const gchar *message,
736 if (log_file_is_open()) {
737 fprintf(log_file,
"%s\n", message);
744 void log_handler_silent(
const gchar *log_domain,
745 GLogLevelFlags log_level,
746 const gchar *message,
772 static gboolean stdin_watch(GIOChannel *source,
773 GIOCondition condition,
776 g_message(
"Got event on stdin");
778 if (condition & G_IO_HUP) {
780 g_message(
"Event was G_IO_HUP, will stop listening for events");
786 if (condition & G_IO_IN) {
787 g_message(
"Event condition was G_IO_IN, will read config");
793 ret = g_io_channel_read_line(source, &msg, &len, NULL, NULL);
794 if (G_IO_STATUS_ERROR == ret) {
795 g_error(
"Error reading from channel");
802 g_message(
"Read zero bytes, will stop listening for events");
807 g_message(
"%s", msg);
809 parse_full_config(msg, (
const char *)data);
814 g_message(
"Got unhandled event on stdin, will ignore and continue " 815 "listening for events");
820 int main(
int argc,
char *argv[]) {
821 g_message(
"Starting dbus-proxy, pid: %d", getpid());
823 GMainLoop *mainloop = NULL;
824 GError *error = NULL;
827 if (argc == 2 && strcmp(argv[1],
"--version") == 0) {
839 address = g_strconcat(
"unix:path=", argv[1], NULL);
840 if (strcmp (argv[2],
"system") == 0) {
841 bus = DBUS_BUS_SYSTEM;
842 }
else if (strcmp(argv[2],
"session") == 0) {
843 bus = DBUS_BUS_SESSION;
845 g_message(
"Must give bus type as second argument (either session or system).\n");
853 if (!open_log_file()) {
854 g_error(
"Could not open log file\n");
857 g_log_set_handler(NULL ,
863 #ifndef LOG_TO_STDOUT 864 g_log_set_handler(NULL ,
872 sa.sa_handler = &handle_sigchld;
873 sigemptyset(&sa.sa_mask);
874 sa.sa_flags = SA_RESTART | SA_NOCLDSTOP;
875 if (sigaction(SIGCHLD, &sa, 0) == -1) {
881 gpointer section = argv[2];
886 g_message(
"Setting up event listener on stdin");
887 GIOChannel *channel = g_io_channel_unix_new(STDIN_FILENO);
888 g_io_add_watch(channel,
889 G_IO_IN | G_IO_PRI | G_IO_ERR | G_IO_HUP,
890 (GIOFunc)stdin_watch,
893 g_message(
"Entering mainloop\n");
897 mainloop = g_main_loop_new(NULL ,
899 g_main_loop_run(mainloop);
901 g_message(
"Exiting dbus-proxy");
904 if (!close_log_file()) {
905 g_message(
"Could not close log file\n");