1/* GLib testing framework examples and tests
2 *
3 * Copyright (C) 2008-2013 Red Hat, Inc.
4 *
5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Lesser General Public
7 * License as published by the Free Software Foundation; either
8 * version 2.1 of the License, or (at your option) any later version.
9 *
10 * This library is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Lesser General Public License for more details.
14 *
15 * You should have received a copy of the GNU Lesser General
16 * Public License along with this library; if not, see <http://www.gnu.org/licenses/>.
17 *
18 * Author: David Zeuthen <davidz@redhat.com>
19 */
20
21#include <locale.h>
22#include <gio/gio.h>
23
24#include <string.h>
25#include <unistd.h>
26
27#include "gdbus-tests.h"
28
29#ifdef G_OS_UNIX
30#include <gio/gunixconnection.h>
31#include <gio/gnetworkingprivate.h>
32#include <gio/gunixsocketaddress.h>
33#include <gio/gunixfdlist.h>
34#endif
35
36/* ---------------------------------------------------------------------------------------------------- */
37
38static gboolean
39server_on_allow_mechanism (GDBusAuthObserver *observer,
40 const gchar *mechanism,
41 gpointer user_data)
42{
43 const gchar *allowed_mechanism = user_data;
44 if (allowed_mechanism == NULL || g_strcmp0 (str1: mechanism, str2: allowed_mechanism) == 0)
45 return TRUE;
46 else
47 return FALSE;
48}
49
50/* pass NULL to allow any mechanism */
51static GDBusServer *
52server_new_for_mechanism (const gchar *allowed_mechanism)
53{
54 gchar *addr;
55 gchar *guid;
56 GDBusServer *server;
57 GDBusAuthObserver *auth_observer;
58 GError *error;
59 GDBusServerFlags flags;
60
61 guid = g_dbus_generate_guid ();
62
63#ifdef G_OS_UNIX
64 if (g_unix_socket_address_abstract_names_supported ())
65 {
66 addr = g_strdup (str: "unix:tmpdir=/tmp/gdbus-test-");
67 }
68 else
69 {
70 gchar *tmpdir;
71 tmpdir = g_dir_make_tmp (tmpl: "gdbus-test-XXXXXX", NULL);
72 addr = g_strdup_printf (format: "unix:tmpdir=%s", tmpdir);
73 g_free (mem: tmpdir);
74 }
75#else
76 addr = g_strdup ("nonce-tcp:");
77#endif
78
79 auth_observer = g_dbus_auth_observer_new ();
80
81 flags = G_DBUS_SERVER_FLAGS_NONE;
82 if (g_strcmp0 (str1: allowed_mechanism, str2: "ANONYMOUS") == 0)
83 flags |= G_DBUS_SERVER_FLAGS_AUTHENTICATION_ALLOW_ANONYMOUS;
84
85 error = NULL;
86 server = g_dbus_server_new_sync (address: addr,
87 flags,
88 guid,
89 observer: auth_observer,
90 NULL, /* cancellable */
91 error: &error);
92 g_assert_no_error (error);
93 g_assert (server != NULL);
94
95 g_signal_connect (auth_observer,
96 "allow-mechanism",
97 G_CALLBACK (server_on_allow_mechanism),
98 (gpointer) allowed_mechanism);
99
100 g_free (mem: addr);
101 g_free (mem: guid);
102 g_object_unref (object: auth_observer);
103
104 return server;
105}
106
107/* ---------------------------------------------------------------------------------------------------- */
108
109static gboolean
110test_auth_on_new_connection (GDBusServer *server,
111 GDBusConnection *connection,
112 gpointer user_data)
113{
114 GMainLoop *loop = user_data;
115 g_main_loop_quit (loop);
116 return FALSE;
117}
118
119static gboolean
120test_auth_on_timeout (gpointer user_data)
121{
122 g_error ("Timeout waiting for client");
123 g_assert_not_reached ();
124 return G_SOURCE_REMOVE;
125}
126
127
128typedef struct
129{
130 const gchar *address;
131 const gchar *allowed_client_mechanism;
132 const gchar *allowed_server_mechanism;
133} TestAuthData;
134
135static gpointer
136test_auth_client_thread_func (gpointer user_data)
137{
138 TestAuthData *data = user_data;
139 GDBusConnection *c = NULL;
140 GError *error = NULL;
141 GDBusAuthObserver *auth_observer = NULL;
142
143 auth_observer = g_dbus_auth_observer_new ();
144
145 g_signal_connect (auth_observer,
146 "allow-mechanism",
147 G_CALLBACK (server_on_allow_mechanism),
148 (gpointer) data->allowed_client_mechanism);
149
150 c = g_dbus_connection_new_for_address_sync (address: data->address,
151 flags: G_DBUS_CONNECTION_FLAGS_AUTHENTICATION_CLIENT,
152 observer: auth_observer,
153 NULL, /* GCancellable */
154 error: &error);
155 g_assert_no_error (error);
156 g_assert (c != NULL);
157 g_clear_object (&c);
158 g_clear_object (&auth_observer);
159 return NULL;
160}
161
162static void
163test_auth_mechanism (const gchar *allowed_client_mechanism,
164 const gchar *allowed_server_mechanism)
165{
166 GDBusServer *server;
167 GMainLoop *loop;
168 GThread *client_thread;
169 TestAuthData data;
170
171 server = server_new_for_mechanism (allowed_mechanism: allowed_server_mechanism);
172
173 loop = g_main_loop_new (NULL, FALSE);
174
175 g_signal_connect (server,
176 "new-connection",
177 G_CALLBACK (test_auth_on_new_connection),
178 loop);
179
180 g_timeout_add_seconds (interval: 5, function: test_auth_on_timeout, NULL);
181
182 data.allowed_client_mechanism = allowed_client_mechanism;
183 data.allowed_server_mechanism = allowed_server_mechanism;
184 data.address = g_dbus_server_get_client_address (server);
185
186 /* run the D-Bus client in a thread */
187 client_thread = g_thread_new (name: "gdbus-client-thread",
188 func: test_auth_client_thread_func,
189 data: &data);
190
191 g_dbus_server_start (server);
192
193 g_main_loop_run (loop);
194
195 g_dbus_server_stop (server);
196
197 g_thread_join (thread: client_thread);
198
199 while (g_main_context_iteration (NULL, FALSE));
200 g_main_loop_unref (loop);
201
202 g_object_unref (object: server);
203}
204
205/* ---------------------------------------------------------------------------------------------------- */
206
207static void
208auth_client_external (void)
209{
210 test_auth_mechanism (allowed_client_mechanism: "EXTERNAL", NULL);
211}
212
213static void
214auth_client_dbus_cookie_sha1 (void)
215{
216 test_auth_mechanism (allowed_client_mechanism: "DBUS_COOKIE_SHA1", NULL);
217}
218
219static void
220auth_server_anonymous (void)
221{
222 test_auth_mechanism (NULL, allowed_server_mechanism: "ANONYMOUS");
223}
224
225static void
226auth_server_external (void)
227{
228 test_auth_mechanism (NULL, allowed_server_mechanism: "EXTERNAL");
229}
230
231static void
232auth_server_dbus_cookie_sha1 (void)
233{
234 test_auth_mechanism (NULL, allowed_server_mechanism: "DBUS_COOKIE_SHA1");
235}
236
237/* ---------------------------------------------------------------------------------------------------- */
238
239static gchar *temp_dbus_keyrings_dir = NULL;
240
241static void
242temp_dbus_keyrings_setup (void)
243{
244 GError *error = NULL;
245
246 g_assert (temp_dbus_keyrings_dir == NULL);
247 temp_dbus_keyrings_dir = g_dir_make_tmp (tmpl: "gdbus-test-dbus-keyrings-XXXXXX", error: &error);
248 g_assert_no_error (error);
249 g_assert (temp_dbus_keyrings_dir != NULL);
250 g_setenv (variable: "G_DBUS_COOKIE_SHA1_KEYRING_DIR", value: temp_dbus_keyrings_dir, TRUE);
251 g_setenv (variable: "G_DBUS_COOKIE_SHA1_KEYRING_DIR_IGNORE_PERMISSION", value: "1", TRUE);
252}
253
254static void
255temp_dbus_keyrings_teardown (void)
256{
257 GDir *dir;
258 GError *error = NULL;
259 const gchar *name;
260
261 g_assert (temp_dbus_keyrings_dir != NULL);
262
263 dir = g_dir_open (path: temp_dbus_keyrings_dir, flags: 0, error: &error);
264 g_assert_no_error (error);
265 g_assert (dir != NULL);
266 while ((name = g_dir_read_name (dir)) != NULL)
267 {
268 gchar *path = g_build_filename (first_element: temp_dbus_keyrings_dir, name, NULL);
269 g_assert (unlink (path) == 0);
270 g_free (mem: path);
271 }
272 g_dir_close (dir);
273 g_assert (rmdir (temp_dbus_keyrings_dir) == 0);
274
275 g_free (mem: temp_dbus_keyrings_dir);
276 temp_dbus_keyrings_dir = NULL;
277 g_unsetenv (variable: "G_DBUS_COOKIE_SHA1_KEYRING_DIR");
278 g_unsetenv (variable: "G_DBUS_COOKIE_SHA1_KEYRING_DIR_IGNORE_PERMISSION");
279}
280
281/* ---------------------------------------------------------------------------------------------------- */
282
283int
284main (int argc,
285 char *argv[])
286{
287 gint ret;
288
289 setlocale (LC_ALL, locale: "C");
290
291 temp_dbus_keyrings_setup ();
292
293 g_test_init (argc: &argc, argv: &argv, NULL);
294
295 g_test_add_func (testpath: "/gdbus/auth/client/EXTERNAL", test_func: auth_client_external);
296 g_test_add_func (testpath: "/gdbus/auth/client/DBUS_COOKIE_SHA1", test_func: auth_client_dbus_cookie_sha1);
297 g_test_add_func (testpath: "/gdbus/auth/server/ANONYMOUS", test_func: auth_server_anonymous);
298 g_test_add_func (testpath: "/gdbus/auth/server/EXTERNAL", test_func: auth_server_external);
299 g_test_add_func (testpath: "/gdbus/auth/server/DBUS_COOKIE_SHA1", test_func: auth_server_dbus_cookie_sha1);
300
301 /* TODO: we currently don't have tests for
302 *
303 * - DBUS_COOKIE_SHA1 timeouts (and clock changes etc)
304 * - interoperability with libdbus-1 implementations of authentication methods (both client and server)
305 */
306
307 ret = g_test_run();
308
309 temp_dbus_keyrings_teardown ();
310
311 return ret;
312}
313

source code of gtk/subprojects/glib/gio/tests/gdbus-auth.c