• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2 
3 Usage examples (modulo addresses / credentials).
4 
5 UNIX domain socket transport:
6 
7  Server:
8    $ ./gdbus-example-peer --server --address unix:abstract=myaddr
9    Server is listening at: unix:abstract=myaddr
10    Client connected.
11    Peer credentials: GCredentials:unix-user=500,unix-group=500,unix-process=13378
12    Negotiated capabilities: unix-fd-passing=1
13    Client said: Hey, it's 1273093080 already!
14 
15  Client:
16    $ ./gdbus-example-peer --address unix:abstract=myaddr
17    Connected.
18    Negotiated capabilities: unix-fd-passing=1
19    Server said: You said 'Hey, it's 1273093080 already!'. KTHXBYE!
20 
21 Nonce-secured TCP transport on the same host:
22 
23  Server:
24    $ ./gdbus-example-peer --server --address nonce-tcp:
25    Server is listening at: nonce-tcp:host=localhost,port=43077,noncefile=/tmp/gdbus-nonce-file-X1ZNCV
26    Client connected.
27    Peer credentials: (no credentials received)
28    Negotiated capabilities: unix-fd-passing=0
29    Client said: Hey, it's 1273093206 already!
30 
31  Client:
32    $ ./gdbus-example-peer -address nonce-tcp:host=localhost,port=43077,noncefile=/tmp/gdbus-nonce-file-X1ZNCV
33    Connected.
34    Negotiated capabilities: unix-fd-passing=0
35    Server said: You said 'Hey, it's 1273093206 already!'. KTHXBYE!
36 
37 TCP transport on two different hosts with a shared home directory:
38 
39  Server:
40    host1 $ ./gdbus-example-peer --server --address tcp:host=0.0.0.0
41    Server is listening at: tcp:host=0.0.0.0,port=46314
42    Client connected.
43    Peer credentials: (no credentials received)
44    Negotiated capabilities: unix-fd-passing=0
45    Client said: Hey, it's 1273093337 already!
46 
47  Client:
48    host2 $ ./gdbus-example-peer -a tcp:host=host1,port=46314
49    Connected.
50    Negotiated capabilities: unix-fd-passing=0
51    Server said: You said 'Hey, it's 1273093337 already!'. KTHXBYE!
52 
53 TCP transport on two different hosts without authentication:
54 
55  Server:
56    host1 $ ./gdbus-example-peer --server --address tcp:host=0.0.0.0 --allow-anonymous
57    Server is listening at: tcp:host=0.0.0.0,port=59556
58    Client connected.
59    Peer credentials: (no credentials received)
60    Negotiated capabilities: unix-fd-passing=0
61    Client said: Hey, it's 1273093652 already!
62 
63  Client:
64    host2 $ ./gdbus-example-peer -a tcp:host=host1,port=59556
65    Connected.
66    Negotiated capabilities: unix-fd-passing=0
67    Server said: You said 'Hey, it's 1273093652 already!'. KTHXBYE!
68 
69  */
70 
71 #include <gio/gio.h>
72 #include <stdlib.h>
73 
74 /* ---------------------------------------------------------------------------------------------------- */
75 
76 static GDBusNodeInfo *introspection_data = NULL;
77 
78 /* Introspection data for the service we are exporting */
79 static const gchar introspection_xml[] =
80   "<node>"
81   "  <interface name='org.gtk.GDBus.TestPeerInterface'>"
82   "    <method name='HelloWorld'>"
83   "      <arg type='s' name='greeting' direction='in'/>"
84   "      <arg type='s' name='response' direction='out'/>"
85   "    </method>"
86   "  </interface>"
87   "</node>";
88 
89 /* ---------------------------------------------------------------------------------------------------- */
90 
91 static void
handle_method_call(GDBusConnection * connection,const gchar * sender,const gchar * object_path,const gchar * interface_name,const gchar * method_name,GVariant * parameters,GDBusMethodInvocation * invocation,gpointer user_data)92 handle_method_call (GDBusConnection       *connection,
93                     const gchar           *sender,
94                     const gchar           *object_path,
95                     const gchar           *interface_name,
96                     const gchar           *method_name,
97                     GVariant              *parameters,
98                     GDBusMethodInvocation *invocation,
99                     gpointer               user_data)
100 {
101   if (g_strcmp0 (method_name, "HelloWorld") == 0)
102     {
103       const gchar *greeting;
104       gchar *response;
105 
106       g_variant_get (parameters, "(&s)", &greeting);
107       response = g_strdup_printf ("You said '%s'. KTHXBYE!", greeting);
108       g_dbus_method_invocation_return_value (invocation,
109                                              g_variant_new ("(s)", response));
110       g_free (response);
111       g_print ("Client said: %s\n", greeting);
112     }
113 }
114 
115 static const GDBusInterfaceVTable interface_vtable =
116 {
117   handle_method_call,
118   NULL,
119   NULL,
120 };
121 
122 /* ---------------------------------------------------------------------------------------------------- */
123 
124 static void
connection_closed(GDBusConnection * connection,gboolean remote_peer_vanished,GError * Error,gpointer user_data)125 connection_closed (GDBusConnection *connection,
126                    gboolean remote_peer_vanished,
127                    GError *Error,
128                    gpointer user_data)
129 {
130   g_print ("Client disconnected.\n");
131   g_object_unref (connection);
132 }
133 
134 static gboolean
on_new_connection(GDBusServer * server,GDBusConnection * connection,gpointer user_data)135 on_new_connection (GDBusServer *server,
136                    GDBusConnection *connection,
137                    gpointer user_data)
138 {
139   guint registration_id;
140   GCredentials *credentials;
141   gchar *s;
142 
143   credentials = g_dbus_connection_get_peer_credentials (connection);
144   if (credentials == NULL)
145     s = g_strdup ("(no credentials received)");
146   else
147     s = g_credentials_to_string (credentials);
148 
149 
150   g_print ("Client connected.\n"
151            "Peer credentials: %s\n"
152            "Negotiated capabilities: unix-fd-passing=%d\n",
153            s,
154            g_dbus_connection_get_capabilities (connection) & G_DBUS_CAPABILITY_FLAGS_UNIX_FD_PASSING);
155 
156   g_object_ref (connection);
157   g_signal_connect (connection, "closed", G_CALLBACK (connection_closed), NULL);
158   registration_id = g_dbus_connection_register_object (connection,
159                                                        "/org/gtk/GDBus/TestObject",
160                                                        introspection_data->interfaces[0],
161                                                        &interface_vtable,
162                                                        NULL,  /* user_data */
163                                                        NULL,  /* user_data_free_func */
164                                                        NULL); /* GError** */
165   g_assert (registration_id > 0);
166 
167   return TRUE;
168 }
169 
170 /* ---------------------------------------------------------------------------------------------------- */
171 
172 static gboolean
allow_mechanism_cb(GDBusAuthObserver * observer,const gchar * mechanism,G_GNUC_UNUSED gpointer user_data)173 allow_mechanism_cb (GDBusAuthObserver *observer,
174                     const gchar *mechanism,
175                     G_GNUC_UNUSED gpointer user_data)
176 {
177   /*
178    * In a production GDBusServer that only needs to work on modern Unix
179    * platforms, consider requiring EXTERNAL (credentials-passing),
180    * which is the recommended authentication mechanism for AF_UNIX
181    * sockets:
182    *
183    * if (g_strcmp0 (mechanism, "EXTERNAL") == 0)
184    *   return TRUE;
185    *
186    * return FALSE;
187    *
188    * For this example we accept everything.
189    */
190 
191   g_print ("Considering whether to accept %s authentication...\n", mechanism);
192   return TRUE;
193 }
194 
195 static gboolean
authorize_authenticated_peer_cb(GDBusAuthObserver * observer,G_GNUC_UNUSED GIOStream * stream,GCredentials * credentials,G_GNUC_UNUSED gpointer user_data)196 authorize_authenticated_peer_cb (GDBusAuthObserver *observer,
197                                  G_GNUC_UNUSED GIOStream *stream,
198                                  GCredentials *credentials,
199                                  G_GNUC_UNUSED gpointer user_data)
200 {
201   gboolean authorized = FALSE;
202 
203   g_print ("Considering whether to authorize authenticated peer...\n");
204 
205   if (credentials != NULL)
206     {
207       GCredentials *own_credentials;
208       gchar *credentials_string = NULL;
209 
210       credentials_string = g_credentials_to_string (credentials);
211       g_print ("Peer's credentials: %s\n", credentials_string);
212       g_free (credentials_string);
213 
214       own_credentials = g_credentials_new ();
215 
216       credentials_string = g_credentials_to_string (own_credentials);
217       g_print ("Server's credentials: %s\n", credentials_string);
218       g_free (credentials_string);
219 
220       if (g_credentials_is_same_user (credentials, own_credentials, NULL))
221         authorized = TRUE;
222 
223       g_object_unref (own_credentials);
224     }
225 
226   if (!authorized)
227     {
228       /* In most servers you'd want to reject this, but for this example
229        * we allow it. */
230       g_print ("A server would often not want to authorize this identity\n");
231       g_print ("Authorizing it anyway for demonstration purposes\n");
232       authorized = TRUE;
233     }
234 
235   return authorized;
236 }
237 
238 /* ---------------------------------------------------------------------------------------------------- */
239 
240 int
main(int argc,char * argv[])241 main (int argc, char *argv[])
242 {
243   gint ret;
244   gboolean opt_server;
245   gchar *opt_address;
246   GOptionContext *opt_context;
247   gboolean opt_allow_anonymous;
248   GError *error;
249   GOptionEntry opt_entries[] =
250     {
251       { "server", 's', 0, G_OPTION_ARG_NONE, &opt_server, "Start a server instead of a client", NULL },
252       { "address", 'a', 0, G_OPTION_ARG_STRING, &opt_address, "D-Bus address to use", NULL },
253       { "allow-anonymous", 'n', 0, G_OPTION_ARG_NONE, &opt_allow_anonymous, "Allow anonymous authentication", NULL },
254       { NULL}
255     };
256 
257   ret = 1;
258 
259   opt_address = NULL;
260   opt_server = FALSE;
261   opt_allow_anonymous = FALSE;
262 
263   opt_context = g_option_context_new ("peer-to-peer example");
264   error = NULL;
265   g_option_context_add_main_entries (opt_context, opt_entries, NULL);
266   if (!g_option_context_parse (opt_context, &argc, &argv, &error))
267     {
268       g_printerr ("Error parsing options: %s\n", error->message);
269       g_error_free (error);
270       goto out;
271     }
272   if (opt_address == NULL)
273     {
274       g_printerr ("Incorrect usage, try --help.\n");
275       goto out;
276     }
277   if (!opt_server && opt_allow_anonymous)
278     {
279       g_printerr ("The --allow-anonymous option only makes sense when used with --server.\n");
280       goto out;
281     }
282 
283   /* We are lazy here - we don't want to manually provide
284    * the introspection data structures - so we just build
285    * them from XML.
286    */
287   introspection_data = g_dbus_node_info_new_for_xml (introspection_xml, NULL);
288   g_assert (introspection_data != NULL);
289 
290   if (opt_server)
291     {
292       GDBusAuthObserver *observer;
293       GDBusServer *server;
294       gchar *guid;
295       GMainLoop *loop;
296       GDBusServerFlags server_flags;
297 
298       guid = g_dbus_generate_guid ();
299 
300       server_flags = G_DBUS_SERVER_FLAGS_NONE;
301       if (opt_allow_anonymous)
302         server_flags |= G_DBUS_SERVER_FLAGS_AUTHENTICATION_ALLOW_ANONYMOUS;
303 
304       observer = g_dbus_auth_observer_new ();
305       g_signal_connect (observer, "allow-mechanism", G_CALLBACK (allow_mechanism_cb), NULL);
306       g_signal_connect (observer, "authorize-authenticated-peer", G_CALLBACK (authorize_authenticated_peer_cb), NULL);
307 
308       error = NULL;
309       server = g_dbus_server_new_sync (opt_address,
310                                        server_flags,
311                                        guid,
312                                        observer,
313                                        NULL, /* GCancellable */
314                                        &error);
315       g_dbus_server_start (server);
316 
317       g_object_unref (observer);
318       g_free (guid);
319 
320       if (server == NULL)
321         {
322           g_printerr ("Error creating server at address %s: %s\n", opt_address, error->message);
323           g_error_free (error);
324           goto out;
325         }
326       g_print ("Server is listening at: %s\n", g_dbus_server_get_client_address (server));
327       g_signal_connect (server,
328                         "new-connection",
329                         G_CALLBACK (on_new_connection),
330                         NULL);
331 
332       loop = g_main_loop_new (NULL, FALSE);
333       g_main_loop_run (loop);
334 
335       g_object_unref (server);
336       g_main_loop_unref (loop);
337     }
338   else
339     {
340       GDBusConnection *connection;
341       const gchar *greeting_response;
342       GVariant *value;
343       gchar *greeting;
344 
345       error = NULL;
346       connection = g_dbus_connection_new_for_address_sync (opt_address,
347                                                            G_DBUS_CONNECTION_FLAGS_AUTHENTICATION_CLIENT,
348                                                            NULL, /* GDBusAuthObserver */
349                                                            NULL, /* GCancellable */
350                                                            &error);
351       if (connection == NULL)
352         {
353           g_printerr ("Error connecting to D-Bus address %s: %s\n", opt_address, error->message);
354           g_error_free (error);
355           goto out;
356         }
357 
358       g_print ("Connected.\n"
359                "Negotiated capabilities: unix-fd-passing=%d\n",
360                g_dbus_connection_get_capabilities (connection) & G_DBUS_CAPABILITY_FLAGS_UNIX_FD_PASSING);
361 
362       greeting = g_strdup_printf ("Hey, it's %" G_GINT64_FORMAT " already!",
363                                   g_get_real_time () / G_USEC_PER_SEC);
364       value = g_dbus_connection_call_sync (connection,
365                                            NULL, /* bus_name */
366                                            "/org/gtk/GDBus/TestObject",
367                                            "org.gtk.GDBus.TestPeerInterface",
368                                            "HelloWorld",
369                                            g_variant_new ("(s)", greeting),
370                                            G_VARIANT_TYPE ("(s)"),
371                                            G_DBUS_CALL_FLAGS_NONE,
372                                            -1,
373                                            NULL,
374                                            &error);
375       if (value == NULL)
376         {
377           g_printerr ("Error invoking HelloWorld(): %s\n", error->message);
378           g_error_free (error);
379           goto out;
380         }
381       g_variant_get (value, "(&s)", &greeting_response);
382       g_print ("Server said: %s\n", greeting_response);
383       g_variant_unref (value);
384 
385       g_object_unref (connection);
386     }
387   g_dbus_node_info_unref (introspection_data);
388 
389   ret = 0;
390 
391  out:
392   return ret;
393 }
394