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 | |
38 | static gboolean |
39 | server_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 */ |
51 | static GDBusServer * |
52 | server_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 | |
109 | static gboolean |
110 | test_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 | |
119 | static gboolean |
120 | test_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 | |
128 | typedef struct |
129 | { |
130 | const gchar *address; |
131 | const gchar *allowed_client_mechanism; |
132 | const gchar *allowed_server_mechanism; |
133 | } TestAuthData; |
134 | |
135 | static gpointer |
136 | test_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 | |
162 | static void |
163 | test_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 | |
207 | static void |
208 | auth_client_external (void) |
209 | { |
210 | test_auth_mechanism (allowed_client_mechanism: "EXTERNAL" , NULL); |
211 | } |
212 | |
213 | static void |
214 | auth_client_dbus_cookie_sha1 (void) |
215 | { |
216 | test_auth_mechanism (allowed_client_mechanism: "DBUS_COOKIE_SHA1" , NULL); |
217 | } |
218 | |
219 | static void |
220 | auth_server_anonymous (void) |
221 | { |
222 | test_auth_mechanism (NULL, allowed_server_mechanism: "ANONYMOUS" ); |
223 | } |
224 | |
225 | static void |
226 | auth_server_external (void) |
227 | { |
228 | test_auth_mechanism (NULL, allowed_server_mechanism: "EXTERNAL" ); |
229 | } |
230 | |
231 | static void |
232 | auth_server_dbus_cookie_sha1 (void) |
233 | { |
234 | test_auth_mechanism (NULL, allowed_server_mechanism: "DBUS_COOKIE_SHA1" ); |
235 | } |
236 | |
237 | /* ---------------------------------------------------------------------------------------------------- */ |
238 | |
239 | static gchar *temp_dbus_keyrings_dir = NULL; |
240 | |
241 | static void |
242 | temp_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 | |
254 | static void |
255 | temp_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 | |
283 | int |
284 | main (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 | |