Add a simple manual test for authentication/authorization.
[platform/upstream/dbus.git] / test / manual-authz.c
1 /* Simple sanity-check for authentication and authorization.
2  *
3  * Copyright © 2010-2011 Nokia Corporation
4  * Copyright © 2012 Collabora Ltd.
5  *
6  * Permission is hereby granted, free of charge, to any person
7  * obtaining a copy of this software and associated documentation files
8  * (the "Software"), to deal in the Software without restriction,
9  * including without limitation the rights to use, copy, modify, merge,
10  * publish, distribute, sublicense, and/or sell copies of the Software,
11  * and to permit persons to whom the Software is furnished to do so,
12  * subject to the following conditions:
13  *
14  * The above copyright notice and this permission notice shall be
15  * included in all copies or substantial portions of the Software.
16  *
17  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
18  * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
19  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
20  * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
21  * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
22  * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
23  * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
24  * SOFTWARE.
25  */
26
27 #include <config.h>
28
29 #include <glib.h>
30
31 #include <dbus/dbus.h>
32 #include <dbus/dbus-glib-lowlevel.h>
33
34 #ifdef G_OS_UNIX
35 #include <unistd.h>
36 #include <sys/types.h>
37 #endif
38
39 typedef struct {
40     DBusError e;
41
42     DBusServer *normal_server;
43     DBusServer *anon_allowed_server;
44     DBusServer *anon_only_server;
45     DBusServer *anon_mech_only_server;
46     DBusServer *anon_disallowed_server;
47     DBusServer *permissive_server;
48     DBusServer *unhappy_server;
49     DBusServer *same_uid_server;
50     DBusServer *same_uid_or_anon_server;
51 } Fixture;
52
53 static void oom (void) G_GNUC_NORETURN;
54 static void
55 oom (void)
56 {
57   g_error ("out of memory");
58 }
59
60 static void
61 assert_no_error (const DBusError *e)
62 {
63   if (G_UNLIKELY (dbus_error_is_set (e)))
64     g_error ("expected success but got error: %s: %s", e->name, e->message);
65 }
66
67 static DBusHandlerResult
68 server_message_cb (DBusConnection *conn,
69     DBusMessage *message,
70     void *data)
71 {
72   if (dbus_message_is_signal (message, DBUS_INTERFACE_LOCAL, "Disconnected"))
73     {
74       dbus_connection_unref (conn);
75
76       return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
77     }
78
79   if (dbus_message_get_type (message) == DBUS_MESSAGE_TYPE_METHOD_CALL)
80     {
81       DBusMessage *reply = dbus_message_new_method_return (message);
82       const char *hello = "Hello, world!";
83       unsigned long uid;
84       char *sid;
85
86       if (dbus_connection_get_unix_user (conn, &uid))
87         {
88           g_message ("message from uid %lu", uid);
89         }
90       else if (dbus_connection_get_windows_user (conn, &sid))
91         {
92           if (sid == NULL)
93             oom ();
94
95           g_message ("message from sid \"%s\"", sid);
96           dbus_free (sid);
97         }
98       else if (dbus_connection_get_is_anonymous (conn))
99         {
100           g_message ("message from Anonymous");
101         }
102       else
103         {
104           g_message ("message from ... someone?");
105         }
106
107       if (reply == NULL)
108         oom ();
109
110       if (!dbus_message_append_args (reply,
111             DBUS_TYPE_STRING, &hello,
112             DBUS_TYPE_INVALID))
113         oom ();
114
115       if (!dbus_connection_send (conn, reply, NULL))
116         oom ();
117
118       dbus_message_unref (reply);
119
120       return DBUS_HANDLER_RESULT_HANDLED;
121     }
122
123   return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
124 }
125
126 static dbus_bool_t
127 permissive_unix_func (DBusConnection *conn,
128     unsigned long uid,
129     void *data)
130 {
131   g_message ("accepting Unix user %lu", uid);
132   return TRUE;
133 }
134
135 static dbus_bool_t
136 permissive_win_func (DBusConnection *conn,
137     const char *sid,
138     void *data)
139 {
140   g_message ("accepting Windows user \"%s\"", sid);
141   return TRUE;
142 }
143
144 static dbus_bool_t
145 broken_unix_func (DBusConnection *conn,
146     unsigned long uid,
147     void *data)
148 {
149   g_error ("libdbus called the Unix user function for an ANONYMOUS-only "
150       "connection");
151   return FALSE;
152 }
153
154 static dbus_bool_t
155 broken_win_func (DBusConnection *conn,
156     const char *sid,
157     void *data)
158 {
159   g_error ("libdbus called the Windows user function for an ANONYMOUS-only "
160       "connection");
161   return FALSE;
162 }
163
164 static dbus_bool_t
165 unhappy_unix_func (DBusConnection *conn,
166     unsigned long uid,
167     void *data)
168 {
169   g_message ("rejecting Unix user %lu", uid);
170   return FALSE;
171 }
172
173 static dbus_bool_t
174 unhappy_win_func (DBusConnection *conn,
175     const char *sid,
176     void *data)
177 {
178   g_message ("rejecting Windows user \"%s\"", sid);
179   return FALSE;
180 }
181
182 static dbus_bool_t
183 same_uid_unix_func (DBusConnection *conn,
184     unsigned long uid,
185     void *data)
186 {
187   g_message ("checking whether Unix user %lu owns this process", uid);
188   /* I'd use _dbus_unix_user_is_process_owner(), but it's private... */
189 #ifdef G_OS_UNIX
190   return (geteuid () == uid);
191 #else
192   return FALSE;
193 #endif
194 }
195
196 static dbus_bool_t
197 same_uid_win_func (DBusConnection *conn,
198     const char *sid,
199     void *data)
200 {
201   g_message ("checking whether Windows user \"%s\" owns this process", sid);
202   g_message ("Stub implementation consistent with dbus-sysdeps-util-win: "
203       "assume they do");
204   return TRUE;
205 }
206
207 static void
208 new_conn_cb (DBusServer *server,
209     DBusConnection *conn,
210     void *data)
211 {
212   Fixture *f = data;
213
214   dbus_connection_ref (conn);
215   dbus_connection_setup_with_g_main (conn, NULL);
216
217   if (!dbus_connection_add_filter (conn, server_message_cb, f, NULL))
218     oom ();
219
220   if (server == f->normal_server)
221     {
222     }
223   else if (server == f->anon_allowed_server)
224     {
225       dbus_connection_set_allow_anonymous (conn, TRUE);
226     }
227   else if (server == f->anon_only_server)
228     {
229       dbus_connection_set_allow_anonymous (conn, TRUE);
230
231       dbus_connection_set_unix_user_function (conn, unhappy_unix_func,
232           f, NULL);
233       dbus_connection_set_windows_user_function (conn, unhappy_win_func,
234           f, NULL);
235     }
236   else if (server == f->anon_mech_only_server)
237     {
238       dbus_connection_set_allow_anonymous (conn, TRUE);
239
240       /* should never get called */
241       dbus_connection_set_unix_user_function (conn, broken_unix_func,
242           f, NULL);
243       dbus_connection_set_windows_user_function (conn, broken_win_func,
244           f, NULL);
245     }
246   else if (server == f->anon_disallowed_server)
247     {
248       dbus_connection_set_allow_anonymous (conn, FALSE);
249
250       /* should never get called */
251       dbus_connection_set_unix_user_function (conn, broken_unix_func,
252           f, NULL);
253       dbus_connection_set_windows_user_function (conn, broken_win_func,
254           f, NULL);
255     }
256   else if (server == f->permissive_server)
257     {
258       dbus_connection_set_unix_user_function (conn, permissive_unix_func,
259           f, NULL);
260       dbus_connection_set_windows_user_function (conn, permissive_win_func,
261           f, NULL);
262     }
263   else if (server == f->unhappy_server)
264     {
265       dbus_connection_set_unix_user_function (conn, unhappy_unix_func,
266           f, NULL);
267       dbus_connection_set_windows_user_function (conn, unhappy_win_func,
268           f, NULL);
269     }
270   else if (server == f->same_uid_server)
271     {
272       dbus_connection_set_unix_user_function (conn, same_uid_unix_func,
273           f, NULL);
274       dbus_connection_set_windows_user_function (conn, same_uid_win_func,
275           f, NULL);
276     }
277   else if (server == f->same_uid_or_anon_server)
278     {
279       dbus_connection_set_allow_anonymous (conn, TRUE);
280
281       dbus_connection_set_unix_user_function (conn, same_uid_unix_func,
282           f, NULL);
283       dbus_connection_set_windows_user_function (conn, same_uid_win_func,
284           f, NULL);
285     }
286   else
287     {
288       g_assert_not_reached ();
289     }
290 }
291
292 static void
293 setup (Fixture *f,
294     const gchar *listen_addr)
295 {
296   const char *only_anon[] = { "ANONYMOUS", NULL };
297   char *connect_addr;
298
299   f->normal_server = dbus_server_listen (listen_addr, &f->e);
300   assert_no_error (&f->e);
301   g_assert (f->normal_server != NULL);
302   dbus_server_set_new_connection_function (f->normal_server,
303       new_conn_cb, f, NULL);
304   dbus_server_setup_with_g_main (f->normal_server, NULL);
305   connect_addr = dbus_server_get_address (f->normal_server);
306   g_message ("Normal server:\n%s", connect_addr);
307   dbus_free (connect_addr);
308
309   f->anon_allowed_server = dbus_server_listen (listen_addr, &f->e);
310   assert_no_error (&f->e);
311   g_assert (f->anon_allowed_server != NULL);
312   dbus_server_set_new_connection_function (f->anon_allowed_server,
313       new_conn_cb, f, NULL);
314   dbus_server_setup_with_g_main (f->anon_allowed_server, NULL);
315   connect_addr = dbus_server_get_address (f->anon_allowed_server);
316   g_message ("Anonymous-allowed server:\n%s", connect_addr);
317   dbus_free (connect_addr);
318
319   f->anon_only_server = dbus_server_listen (listen_addr, &f->e);
320   assert_no_error (&f->e);
321   g_assert (f->anon_only_server != NULL);
322   dbus_server_set_new_connection_function (f->anon_only_server,
323       new_conn_cb, f, NULL);
324   dbus_server_setup_with_g_main (f->anon_only_server, NULL);
325   connect_addr = dbus_server_get_address (f->anon_only_server);
326   g_message ("Anonymous-only server:\n%s", connect_addr);
327   dbus_free (connect_addr);
328
329   f->anon_mech_only_server = dbus_server_listen (listen_addr, &f->e);
330   assert_no_error (&f->e);
331   g_assert (f->anon_mech_only_server != NULL);
332   dbus_server_set_auth_mechanisms (f->anon_mech_only_server, only_anon);
333   dbus_server_set_new_connection_function (f->anon_mech_only_server,
334       new_conn_cb, f, NULL);
335   dbus_server_setup_with_g_main (f->anon_mech_only_server, NULL);
336   connect_addr = dbus_server_get_address (f->anon_mech_only_server);
337   g_message ("Anon mech only server:\n%s", connect_addr);
338   dbus_free (connect_addr);
339
340   f->anon_disallowed_server = dbus_server_listen (listen_addr, &f->e);
341   assert_no_error (&f->e);
342   g_assert (f->anon_disallowed_server != NULL);
343   dbus_server_set_auth_mechanisms (f->anon_disallowed_server, only_anon);
344   dbus_server_set_new_connection_function (f->anon_disallowed_server,
345       new_conn_cb, f, NULL);
346   dbus_server_setup_with_g_main (f->anon_disallowed_server, NULL);
347   connect_addr = dbus_server_get_address (f->anon_disallowed_server);
348   g_message ("Anonymous-disallowed server:\n%s", connect_addr);
349   dbus_free (connect_addr);
350
351   f->permissive_server = dbus_server_listen (listen_addr, &f->e);
352   assert_no_error (&f->e);
353   g_assert (f->permissive_server != NULL);
354   dbus_server_set_new_connection_function (f->permissive_server,
355       new_conn_cb, f, NULL);
356   dbus_server_setup_with_g_main (f->permissive_server, NULL);
357   connect_addr = dbus_server_get_address (f->permissive_server);
358   g_message ("Permissive server:\n%s", connect_addr);
359   dbus_free (connect_addr);
360
361   f->unhappy_server = dbus_server_listen (listen_addr, &f->e);
362   assert_no_error (&f->e);
363   g_assert (f->unhappy_server != NULL);
364   dbus_server_set_new_connection_function (f->unhappy_server,
365       new_conn_cb, f, NULL);
366   dbus_server_setup_with_g_main (f->unhappy_server, NULL);
367   connect_addr = dbus_server_get_address (f->unhappy_server);
368   g_message ("Unhappy server:\n%s", connect_addr);
369   dbus_free (connect_addr);
370
371   f->same_uid_server = dbus_server_listen (listen_addr, &f->e);
372   assert_no_error (&f->e);
373   g_assert (f->same_uid_server != NULL);
374   dbus_server_set_new_connection_function (f->same_uid_server,
375       new_conn_cb, f, NULL);
376   dbus_server_setup_with_g_main (f->same_uid_server, NULL);
377   connect_addr = dbus_server_get_address (f->same_uid_server);
378   g_message ("Same-UID server:\n%s", connect_addr);
379   dbus_free (connect_addr);
380
381   f->same_uid_or_anon_server = dbus_server_listen (listen_addr, &f->e);
382   assert_no_error (&f->e);
383   g_assert (f->same_uid_or_anon_server != NULL);
384   dbus_server_set_new_connection_function (f->same_uid_or_anon_server,
385       new_conn_cb, f, NULL);
386   dbus_server_setup_with_g_main (f->same_uid_or_anon_server, NULL);
387   connect_addr = dbus_server_get_address (f->same_uid_or_anon_server);
388   g_message ("Same-UID-or-anon server:\n%s", connect_addr);
389   dbus_free (connect_addr);
390 }
391
392 int
393 main (int argc,
394     char **argv)
395 {
396   Fixture f = { DBUS_ERROR_INIT };
397
398   if (argc >= 2)
399     setup (&f, argv[1]);
400   else
401     setup (&f, "tcp:host=127.0.0.1");
402
403   for (;;)
404     g_main_context_iteration (NULL, TRUE);
405 }