1 /* Unit tests for systemd activation, with or without AppArmor.
3 * We compile this source file twice: once with AppArmor support (if available)
6 * Copyright © 2010-2011 Nokia Corporation
7 * Copyright © 2015 Collabora Ltd.
9 * Permission is hereby granted, free of charge, to any person
10 * obtaining a copy of this software and associated documentation files
11 * (the "Software"), to deal in the Software without restriction,
12 * including without limitation the rights to use, copy, modify, merge,
13 * publish, distribute, sublicense, and/or sell copies of the Software,
14 * and to permit persons to whom the Software is furnished to do so,
15 * subject to the following conditions:
17 * The above copyright notice and this permission notice shall be
18 * included in all copies or substantial portions of the Software.
20 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
21 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
22 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
23 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
24 * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
25 * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
26 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
35 #include <sys/types.h>
37 #include <glib/gstdio.h>
39 #if defined(HAVE_APPARMOR_2_10) && defined(DBUS_TEST_APPARMOR_ACTIVATION)
40 #include <sys/apparmor.h>
43 #include "test-utils-glib.h"
53 DBusConnection *caller;
54 const char *caller_name;
55 DBusMessage *caller_message;
56 dbus_bool_t caller_filter_added;
58 DBusConnection *systemd;
59 const char *systemd_name;
60 DBusMessage *systemd_message;
61 dbus_bool_t systemd_filter_added;
63 DBusConnection *activated;
64 const char *activated_name;
65 DBusMessage *activated_message;
66 dbus_bool_t activated_filter_added;
68 gchar *transient_service_file;
69 gchar *tmp_runtime_dir;
74 FLAG_EARLY_TRANSIENT_SERVICE = (1 << 0),
80 const gchar *bus_name;
84 /* this is a macro so it gets the right line number */
85 #define assert_signal(m, \
86 sender, path, iface, member, signature, \
89 g_assert_cmpstr (dbus_message_type_to_string (dbus_message_get_type (m)), \
90 ==, dbus_message_type_to_string (DBUS_MESSAGE_TYPE_SIGNAL)); \
91 g_assert_cmpstr (dbus_message_get_sender (m), ==, sender); \
92 g_assert_cmpstr (dbus_message_get_destination (m), ==, destination); \
93 g_assert_cmpstr (dbus_message_get_path (m), ==, path); \
94 g_assert_cmpstr (dbus_message_get_interface (m), ==, iface); \
95 g_assert_cmpstr (dbus_message_get_member (m), ==, member); \
96 g_assert_cmpstr (dbus_message_get_signature (m), ==, signature); \
97 g_assert_cmpint (dbus_message_get_serial (m), !=, 0); \
98 g_assert_cmpint (dbus_message_get_reply_serial (m), ==, 0); \
101 #define assert_method_call(m, sender, \
102 destination, path, iface, method, signature) \
104 g_assert_cmpstr (dbus_message_type_to_string (dbus_message_get_type (m)), \
105 ==, dbus_message_type_to_string (DBUS_MESSAGE_TYPE_METHOD_CALL)); \
106 g_assert_cmpstr (dbus_message_get_sender (m), ==, sender); \
107 g_assert_cmpstr (dbus_message_get_destination (m), ==, destination); \
108 g_assert_cmpstr (dbus_message_get_path (m), ==, path); \
109 g_assert_cmpstr (dbus_message_get_interface (m), ==, iface); \
110 g_assert_cmpstr (dbus_message_get_member (m), ==, method); \
111 g_assert_cmpstr (dbus_message_get_signature (m), ==, signature); \
112 g_assert_cmpint (dbus_message_get_serial (m), !=, 0); \
113 g_assert_cmpint (dbus_message_get_reply_serial (m), ==, 0); \
116 #define assert_method_reply(m, sender, destination, signature) \
118 g_assert_cmpstr (dbus_message_type_to_string (dbus_message_get_type (m)), \
119 ==, dbus_message_type_to_string (DBUS_MESSAGE_TYPE_METHOD_RETURN)); \
120 g_assert_cmpstr (dbus_message_get_sender (m), ==, sender); \
121 g_assert_cmpstr (dbus_message_get_destination (m), ==, destination); \
122 g_assert_cmpstr (dbus_message_get_path (m), ==, NULL); \
123 g_assert_cmpstr (dbus_message_get_interface (m), ==, NULL); \
124 g_assert_cmpstr (dbus_message_get_member (m), ==, NULL); \
125 g_assert_cmpstr (dbus_message_get_signature (m), ==, signature); \
126 g_assert_cmpint (dbus_message_get_serial (m), !=, 0); \
127 g_assert_cmpint (dbus_message_get_reply_serial (m), !=, 0); \
130 #define assert_error_reply(m, sender, destination, error_name) \
132 g_assert_cmpstr (dbus_message_type_to_string (dbus_message_get_type (m)), \
133 ==, dbus_message_type_to_string (DBUS_MESSAGE_TYPE_ERROR)); \
134 g_assert_cmpstr (dbus_message_get_sender (m), ==, sender); \
135 g_assert_cmpstr (dbus_message_get_destination (m), ==, destination); \
136 g_assert_cmpstr (dbus_message_get_error_name (m), ==, error_name); \
137 g_assert_cmpstr (dbus_message_get_path (m), ==, NULL); \
138 g_assert_cmpstr (dbus_message_get_interface (m), ==, NULL); \
139 g_assert_cmpstr (dbus_message_get_member (m), ==, NULL); \
140 g_assert_cmpstr (dbus_message_get_signature (m), ==, "s"); \
141 g_assert_cmpint (dbus_message_get_serial (m), !=, 0); \
142 g_assert_cmpint (dbus_message_get_reply_serial (m), !=, 0); \
145 static DBusHandlerResult
146 systemd_filter (DBusConnection *connection,
147 DBusMessage *message,
150 Fixture *f = user_data;
152 if (dbus_message_is_signal (message, DBUS_INTERFACE_DBUS,
154 dbus_message_is_signal (message, DBUS_INTERFACE_DBUS,
157 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
160 g_test_message("sender %s iface %s member %s",
161 dbus_message_get_sender (message),
162 dbus_message_get_interface (message),
163 dbus_message_get_member (message));
166 g_assert (f->systemd_message == NULL);
167 f->systemd_message = dbus_message_ref (message);
169 if (dbus_message_is_method_call (message, "org.freedesktop.systemd1.Manager",
172 g_assert (dbus_message_get_no_reply (message));
173 g_test_message("got call");
174 return DBUS_HANDLER_RESULT_HANDLED;
177 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
180 static DBusHandlerResult
181 activated_filter (DBusConnection *connection,
182 DBusMessage *message,
185 Fixture *f = user_data;
187 if (dbus_message_is_signal (message, DBUS_INTERFACE_DBUS,
189 dbus_message_is_signal (message, DBUS_INTERFACE_DBUS,
192 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
195 g_assert (f->activated_message == NULL);
196 f->activated_message = dbus_message_ref (message);
198 /* Test code is expected to reply to method calls itself */
199 if (dbus_message_get_type (message) == DBUS_MESSAGE_TYPE_METHOD_CALL)
200 return DBUS_HANDLER_RESULT_HANDLED;
202 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
205 static DBusHandlerResult
206 caller_filter (DBusConnection *connection,
207 DBusMessage *message,
210 Fixture *f = user_data;
212 if (dbus_message_is_signal (message, DBUS_INTERFACE_DBUS,
214 dbus_message_is_signal (message, DBUS_INTERFACE_DBUS,
217 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
220 g_assert (f->caller_message == NULL);
221 f->caller_message = dbus_message_ref (message);
223 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
227 fixture_create_transient_service (Fixture *f,
234 service = g_strdup_printf ("%s.service", name);
235 f->transient_service_file = g_build_filename (f->tmp_runtime_dir, "dbus-1",
236 "services", service, NULL);
239 content = g_strdup_printf (
242 "Exec=/bin/false %s\n"
243 "SystemdService=dbus-%s.service\n", name, name, name);
244 ok = g_file_set_contents (f->transient_service_file, content, -1, &f->ge);
245 g_assert_no_error (f->ge);
252 gconstpointer context)
254 const Config *config = context;
255 #if defined(DBUS_TEST_APPARMOR_ACTIVATION) && defined(HAVE_APPARMOR_2_10)
256 aa_features *features;
260 dbus_error_init (&f->e);
262 f->tmp_runtime_dir = g_dir_make_tmp ("dbus-daemon-test.XXXXXX", &f->ge);
263 g_assert_no_error (f->ge);
265 if (config != NULL && (config->flags & FLAG_EARLY_TRANSIENT_SERVICE) != 0)
267 gchar *dbus1 = g_build_filename (f->tmp_runtime_dir, "dbus-1", NULL);
268 gchar *services = g_build_filename (dbus1, "services", NULL);
270 /* We just created it so the directories shouldn't exist yet */
271 test_mkdir (dbus1, 0700);
272 test_mkdir (services, 0700);
273 fixture_create_transient_service (f, config->bus_name);
278 #if defined(DBUS_TEST_APPARMOR_ACTIVATION) && !defined(HAVE_APPARMOR_2_10)
280 g_test_skip ("AppArmor support not compiled or AppArmor 2.10 unavailable");
285 #if defined(DBUS_TEST_APPARMOR_ACTIVATION)
286 if (!aa_is_enabled ())
288 g_test_message ("aa_is_enabled() -> %s", g_strerror (errno));
289 g_test_skip ("AppArmor not enabled");
293 if (aa_features_new_from_kernel (&features) != 0)
295 g_test_skip ("Unable to check AppArmor features");
299 if (!aa_features_supports (features, "dbus/mask/send") ||
300 !aa_features_supports (features, "dbus/mask/receive"))
302 g_test_skip ("D-Bus send/receive mediation unavailable");
303 aa_features_unref (features);
307 aa_features_unref (features);
310 f->ctx = test_main_context_get ();
312 f->address = test_get_dbus_daemon (
313 "valid-config-files/systemd-activation.conf",
314 TEST_USER_ME, f->tmp_runtime_dir, &f->daemon_pid);
316 if (f->address == NULL)
319 #if defined(DBUS_TEST_APPARMOR_ACTIVATION)
321 * Make use of the fact that the LSM security label (and other process
322 * properties) that are used for access-control are whatever was current
323 * at the time the connection was opened.
325 * 42 is arbitrary. In a real use of AppArmor it would be a securely-random
326 * value, to prevent less-privileged code (that does not know the magic
327 * value) from changing back.
329 if (aa_change_hat ("caller", 42) != 0)
330 g_error ("Unable to change profile to ...//^caller: %s",
334 f->caller = test_connect_to_bus (f->ctx, f->address);
335 f->caller_name = dbus_bus_get_unique_name (f->caller);
337 #if defined(DBUS_TEST_APPARMOR_ACTIVATION)
338 if (aa_change_hat (NULL, 42) != 0)
339 g_error ("Unable to change back to initial profile: %s",
347 take_well_known_name (Fixture *f,
348 DBusConnection *connection,
353 ret = dbus_bus_request_name (connection, name,
354 DBUS_NAME_FLAG_DO_NOT_QUEUE, &f->e);
355 test_assert_no_error (&f->e);
356 g_assert_cmpint (ret, ==, DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER);
360 test_activation (Fixture *f,
361 gconstpointer context)
365 if (f->address == NULL)
368 /* The sender sends a message to an activatable service. */
369 m = dbus_message_new_signal ("/foo", "com.example.bar", "UnicastSignal1");
370 if (!dbus_message_set_destination (m, "com.example.SystemdActivatable1"))
372 dbus_connection_send (f->caller, m, NULL);
373 dbus_message_unref (m);
375 /* The fake systemd connects to the bus. */
376 f->systemd = test_connect_to_bus (f->ctx, f->address);
377 if (!dbus_connection_add_filter (f->systemd, systemd_filter, f, NULL))
379 f->systemd_filter_added = TRUE;
380 f->systemd_name = dbus_bus_get_unique_name (f->systemd);
381 take_well_known_name (f, f->systemd, "org.freedesktop.systemd1");
383 /* It gets its activation request. */
384 while (f->systemd_message == NULL)
385 test_main_context_iterate (f->ctx, TRUE);
387 m = f->systemd_message;
388 f->systemd_message = NULL;
389 assert_signal (m, DBUS_SERVICE_DBUS, DBUS_PATH_DBUS,
390 "org.freedesktop.systemd1.Activator", "ActivationRequest", "s",
391 "org.freedesktop.systemd1");
392 dbus_message_unref (m);
394 /* systemd starts the activatable service. */
395 f->activated = test_connect_to_bus (f->ctx, f->address);
396 if (!dbus_connection_add_filter (f->activated, activated_filter,
399 f->activated_filter_added = TRUE;
400 f->activated_name = dbus_bus_get_unique_name (f->activated);
401 take_well_known_name (f, f->activated, "com.example.SystemdActivatable1");
403 /* The message is delivered to the activatable service. */
404 while (f->activated_message == NULL)
405 test_main_context_iterate (f->ctx, TRUE);
407 m = f->activated_message;
408 f->activated_message = NULL;
409 assert_signal (m, f->caller_name, "/foo",
410 "com.example.bar", "UnicastSignal1", "",
411 "com.example.SystemdActivatable1");
412 dbus_message_unref (m);
414 /* The sender sends a message to a different activatable service. */
415 m = dbus_message_new_signal ("/foo", "com.example.bar", "UnicastSignal2");
416 if (!dbus_message_set_destination (m, "com.example.SystemdActivatable2"))
418 dbus_connection_send (f->caller, m, NULL);
419 dbus_message_unref (m);
421 /* This time systemd is already ready for it. */
422 while (f->systemd_message == NULL)
423 test_main_context_iterate (f->ctx, TRUE);
425 m = f->systemd_message;
426 f->systemd_message = NULL;
427 assert_signal (m, DBUS_SERVICE_DBUS, DBUS_PATH_DBUS,
428 "org.freedesktop.systemd1.Activator", "ActivationRequest", "s",
429 "org.freedesktop.systemd1");
430 dbus_message_unref (m);
432 /* A malicious process tries to disrupt the activation.
433 * In a more realistic scenario this would be another parallel
435 m = dbus_message_new_signal ("/org/freedesktop/systemd1",
436 "org.freedesktop.systemd1.Activator", "ActivationFailure");
437 if (!dbus_message_set_destination (m, "org.freedesktop.DBus"))
442 const char *unit = "dbus-com.example.SystemdActivatable2.service";
443 const char *error_name = "com.example.Malice";
444 const char *error_message = "I'm on yr bus, making yr activations fail";
446 if (!dbus_message_append_args (m,
447 DBUS_TYPE_STRING, &unit,
448 DBUS_TYPE_STRING, &error_name,
449 DBUS_TYPE_STRING, &error_message,
455 dbus_connection_send (f->caller, m, NULL);
456 dbus_message_unref (m);
458 /* This is just to make sure that the malicious message has arrived and
459 * been processed by the dbus-daemon, i.e. @caller won the race
460 * with @activated. */
461 take_well_known_name (f, f->caller, "com.example.Sync");
463 /* The activatable service takes its name. Here I'm faking it by using
464 * an existing connection; in real life it would be yet another
466 take_well_known_name (f, f->activated, "com.example.SystemdActivatable2");
468 /* The message is delivered to the activatable service. */
469 while (f->activated_message == NULL)
470 test_main_context_iterate (f->ctx, TRUE);
472 m = f->activated_message;
473 f->activated_message = NULL;
474 assert_signal (m, f->caller_name, "/foo",
475 "com.example.bar", "UnicastSignal2", "",
476 "com.example.SystemdActivatable2");
477 dbus_message_unref (m);
479 /* A third activation. */
480 m = dbus_message_new_signal ("/foo", "com.example.bar", "UnicastSignal3");
481 if (!dbus_message_set_destination (m, "com.example.SystemdActivatable3"))
483 dbus_connection_send (f->caller, m, NULL);
484 dbus_message_unref (m);
486 while (f->systemd_message == NULL)
487 test_main_context_iterate (f->ctx, TRUE);
489 m = f->systemd_message;
490 f->systemd_message = NULL;
491 assert_signal (m, DBUS_SERVICE_DBUS, DBUS_PATH_DBUS,
492 "org.freedesktop.systemd1.Activator", "ActivationRequest", "s",
493 "org.freedesktop.systemd1");
494 dbus_message_unref (m);
496 /* This time activation fails */
497 m = dbus_message_new_signal ("/org/freedesktop/systemd1",
498 "org.freedesktop.systemd1.Activator", "ActivationFailure");
502 const char *unit = "dbus-com.example.SystemdActivatable3.service";
503 const char *error_name = "com.example.Nope";
504 const char *error_message = "Computer says no";
506 if (!dbus_message_append_args (m,
507 DBUS_TYPE_STRING, &unit,
508 DBUS_TYPE_STRING, &error_name,
509 DBUS_TYPE_STRING, &error_message,
515 if (!dbus_message_set_destination (m, "org.freedesktop.DBus"))
517 dbus_connection_send (f->systemd, m, NULL);
518 dbus_message_unref (m);
522 test_uae (Fixture *f,
523 gconstpointer context)
527 DBusMessageIter args_iter, arr_iter, entry_iter;
530 if (f->address == NULL)
533 m = dbus_message_new_method_call (DBUS_SERVICE_DBUS, DBUS_PATH_DBUS,
534 DBUS_INTERFACE_DBUS, "UpdateActivationEnvironment");
539 dbus_message_iter_init_append (m, &args_iter);
541 /* Append an empty a{ss} (string => string dictionary). */
542 if (!dbus_message_iter_open_container (&args_iter, DBUS_TYPE_ARRAY,
543 "{ss}", &arr_iter) ||
544 !dbus_message_iter_close_container (&args_iter, &arr_iter))
547 if (!dbus_connection_send_with_reply (f->caller, m, &pc,
548 DBUS_TIMEOUT_USE_DEFAULT) || pc == NULL)
551 dbus_message_unref (m);
554 if (dbus_pending_call_get_completed (pc))
555 test_pending_call_store_reply (pc, &m);
556 else if (!dbus_pending_call_set_notify (pc, test_pending_call_store_reply,
561 test_main_context_iterate (f->ctx, TRUE);
563 assert_method_reply (m, DBUS_SERVICE_DBUS, f->caller_name, "");
564 dbus_message_unref (m);
566 /* The fake systemd connects to the bus. */
567 f->systemd = test_connect_to_bus (f->ctx, f->address);
568 if (!dbus_connection_add_filter (f->systemd, systemd_filter, f, NULL))
570 f->systemd_name = dbus_bus_get_unique_name (f->systemd);
571 take_well_known_name (f, f->systemd, "org.freedesktop.systemd1");
573 /* It gets the SetEnvironment */
574 while (f->systemd_message == NULL)
575 test_main_context_iterate (f->ctx, TRUE);
577 m = f->systemd_message;
578 f->systemd_message = NULL;
580 /* With activation, the destination is the well-known name */
581 assert_method_call (m, DBUS_SERVICE_DBUS, "org.freedesktop.systemd1",
582 "/org/freedesktop/systemd1", "org.freedesktop.systemd1.Manager",
583 "SetEnvironment", "as");
585 dbus_message_iter_init (m, &args_iter);
586 g_assert_cmpuint (dbus_message_iter_get_arg_type (&args_iter), ==,
588 g_assert_cmpuint (dbus_message_iter_get_element_type (&args_iter), ==,
590 dbus_message_iter_recurse (&args_iter, &arr_iter);
591 g_assert_cmpuint (dbus_message_iter_get_arg_type (&arr_iter), ==,
593 dbus_message_iter_next (&args_iter);
594 g_assert_cmpuint (dbus_message_iter_get_arg_type (&args_iter), ==,
596 dbus_message_unref (m);
598 m = dbus_message_new_method_call (DBUS_SERVICE_DBUS, DBUS_PATH_DBUS,
599 DBUS_INTERFACE_DBUS, "UpdateActivationEnvironment");
604 dbus_message_iter_init_append (m, &args_iter);
608 const char *k1 = "Key1", *v1 = "Value1",
609 *k2 = "Key2", *v2 = "Value2";
611 /* Append a filled a{ss} (string => string dictionary). */
612 if (!dbus_message_iter_open_container (&args_iter, DBUS_TYPE_ARRAY,
613 "{ss}", &arr_iter) ||
614 !dbus_message_iter_open_container (&arr_iter, DBUS_TYPE_DICT_ENTRY,
615 NULL, &entry_iter) ||
616 !dbus_message_iter_append_basic (&entry_iter, DBUS_TYPE_STRING,
618 !dbus_message_iter_append_basic (&entry_iter, DBUS_TYPE_STRING,
620 !dbus_message_iter_close_container (&arr_iter, &entry_iter) ||
621 !dbus_message_iter_open_container (&arr_iter, DBUS_TYPE_DICT_ENTRY,
622 NULL, &entry_iter) ||
623 !dbus_message_iter_append_basic (&entry_iter, DBUS_TYPE_STRING,
625 !dbus_message_iter_append_basic (&entry_iter, DBUS_TYPE_STRING,
627 !dbus_message_iter_close_container (&arr_iter, &entry_iter) ||
628 !dbus_message_iter_close_container (&args_iter, &arr_iter))
632 if (!dbus_connection_send_with_reply (f->caller, m, &pc,
633 DBUS_TIMEOUT_USE_DEFAULT) || pc == NULL)
636 dbus_message_unref (m);
639 if (dbus_pending_call_get_completed (pc))
640 test_pending_call_store_reply (pc, &m);
641 else if (!dbus_pending_call_set_notify (pc, test_pending_call_store_reply,
646 test_main_context_iterate (f->ctx, TRUE);
648 assert_method_reply (m, DBUS_SERVICE_DBUS, f->caller_name, "");
649 dbus_message_unref (m);
651 while (f->systemd_message == NULL)
652 test_main_context_iterate (f->ctx, TRUE);
654 m = f->systemd_message;
655 f->systemd_message = NULL;
657 /* Without activation, the destination is the unique name */
658 assert_method_call (m, DBUS_SERVICE_DBUS, f->systemd_name,
659 "/org/freedesktop/systemd1", "org.freedesktop.systemd1.Manager",
660 "SetEnvironment", "as");
662 dbus_message_iter_init (m, &args_iter);
663 g_assert_cmpuint (dbus_message_iter_get_arg_type (&args_iter), ==,
665 g_assert_cmpuint (dbus_message_iter_get_element_type (&args_iter), ==,
667 dbus_message_iter_recurse (&args_iter, &arr_iter);
668 g_assert_cmpuint (dbus_message_iter_get_arg_type (&arr_iter), ==,
670 dbus_message_iter_get_basic (&arr_iter, &s);
671 g_assert_cmpstr (s, ==, "Key1=Value1");
672 dbus_message_iter_next (&arr_iter);
673 g_assert_cmpuint (dbus_message_iter_get_arg_type (&arr_iter), ==,
675 dbus_message_iter_get_basic (&arr_iter, &s);
676 g_assert_cmpstr (s, ==, "Key2=Value2");
677 dbus_message_iter_next (&arr_iter);
678 g_assert_cmpuint (dbus_message_iter_get_arg_type (&arr_iter), ==,
680 dbus_message_iter_next (&args_iter);
681 g_assert_cmpuint (dbus_message_iter_get_arg_type (&args_iter), ==,
683 dbus_message_unref (m);
687 test_deny_send (Fixture *f,
688 gconstpointer context)
691 const Config *config = context;
693 g_assert (config != NULL);
694 g_assert (config->bus_name != NULL);
696 if (f->address == NULL)
699 if (!dbus_connection_add_filter (f->caller, caller_filter, f, NULL))
702 f->caller_filter_added = TRUE;
704 /* The sender sends a message to an activatable service. */
705 m = dbus_message_new_method_call (config->bus_name, "/foo",
706 "com.example.bar", "Call");
710 dbus_connection_send (f->caller, m, NULL);
711 dbus_message_unref (m);
714 * Even before the fake systemd connects to the bus, we get an error
715 * back: activation is not allowed.
717 * In the normal case, this is because the XML policy does not allow
718 * anyone to send messages to the bus name com.example.SendDenied.
720 * In the AppArmor case, this is because the AppArmor policy does not allow
721 * this process to send messages to the bus name
722 * com.example.SendDeniedByAppArmorName, or to the label
723 * @DBUS_TEST_EXEC@/com.example.SendDeniedByAppArmorLabel that we assume the
724 * service com.example.SendDeniedByAppArmorLabel will receive after systemd
728 while (f->caller_message == NULL)
729 test_main_context_iterate (f->ctx, TRUE);
731 m = f->caller_message;
732 f->caller_message = NULL;
733 assert_error_reply (m, DBUS_SERVICE_DBUS, f->caller_name,
734 DBUS_ERROR_ACCESS_DENIED);
735 dbus_message_unref (m);
739 test_deny_receive (Fixture *f,
740 gconstpointer context)
743 const Config *config = context;
745 g_assert (config != NULL);
746 g_assert (config->bus_name != NULL);
748 if (f->address == NULL)
751 if (!dbus_connection_add_filter (f->caller, caller_filter, f, NULL))
754 f->caller_filter_added = TRUE;
756 /* The sender sends a message to an activatable service.
757 * We set the interface name equal to the bus name to make it
758 * easier to write the necessary policy rules. */
759 m = dbus_message_new_method_call (config->bus_name, "/foo",
760 config->bus_name, "Call");
764 dbus_connection_send (f->caller, m, NULL);
765 dbus_message_unref (m);
767 /* The fake systemd connects to the bus. */
768 f->systemd = test_connect_to_bus (f->ctx, f->address);
769 if (!dbus_connection_add_filter (f->systemd, systemd_filter, f, NULL))
771 f->systemd_filter_added = TRUE;
772 f->systemd_name = dbus_bus_get_unique_name (f->systemd);
773 take_well_known_name (f, f->systemd, "org.freedesktop.systemd1");
775 /* It gets its activation request. */
776 while (f->systemd_message == NULL)
777 test_main_context_iterate (f->ctx, TRUE);
779 m = f->systemd_message;
780 f->systemd_message = NULL;
781 assert_signal (m, DBUS_SERVICE_DBUS, DBUS_PATH_DBUS,
782 "org.freedesktop.systemd1.Activator", "ActivationRequest", "s",
783 "org.freedesktop.systemd1");
784 dbus_message_unref (m);
786 /* systemd starts the activatable service. */
788 #if defined(DBUS_TEST_APPARMOR_ACTIVATION) && defined(HAVE_APPARMOR_2_10)
789 /* The use of 42 here is arbitrary, see setup(). */
790 if (aa_change_hat (config->bus_name, 42) != 0)
791 g_error ("Unable to change profile to ...//^%s: %s",
792 config->bus_name, g_strerror (errno));
795 f->activated = test_connect_to_bus (f->ctx, f->address);
796 if (!dbus_connection_add_filter (f->activated, activated_filter,
799 f->activated_filter_added = TRUE;
800 f->activated_name = dbus_bus_get_unique_name (f->activated);
801 take_well_known_name (f, f->activated, config->bus_name);
803 #if defined(DBUS_TEST_APPARMOR_ACTIVATION) && defined(HAVE_APPARMOR_2_10)
804 if (aa_change_hat (NULL, 42) != 0)
805 g_error ("Unable to change back to initial profile: %s",
810 * We re-do the message matching, and now the message is
811 * forbidden by the receive policy.
813 * In the normal case, this is because the XML policy does not allow
814 * receiving any message with interface com.example.ReceiveDenied.
815 * We can't use the recipient's bus name here because the XML policy
816 * has no syntax for preventing the owner of a name from receiving
817 * messages - that would be pointless, because the sender could just
818 * open another connection and not own the same name on that connection.
820 * In the AppArmor case, this is because the AppArmor policy does not allow
821 * receiving messages with interface com.example.ReceiveDeniedByAppArmor
822 * from a peer with the same label we have. Again, we can't use the
823 * recipient's bus name because there is no syntax for this.
825 while (f->caller_message == NULL)
826 test_main_context_iterate (f->ctx, TRUE);
828 m = f->caller_message;
829 f->caller_message = NULL;
830 assert_error_reply (m, DBUS_SERVICE_DBUS, f->caller_name,
831 DBUS_ERROR_ACCESS_DENIED);
832 dbus_message_unref (m);
834 /* The activated service never even saw it. */
835 g_assert (f->activated_message == NULL);
839 * Test that we can set up transient services.
841 * If (flags & FLAG_EARLY_TRANSIENT_SERVICE), we assert that a service that
842 * was deployed before starting systemd (in setup()) is available.
844 * Otherwise, we assert that a service that is deployed while dbus-daemon
845 * is already running becomes available after reloading the dbus-daemon
849 test_transient_services (Fixture *f,
850 gconstpointer context)
852 const Config *config = context;
853 DBusMessage *m = NULL;
854 DBusMessage *send_reply = NULL;
855 DBusMessage *reply = NULL;
858 g_assert (config != NULL);
859 g_assert (config->bus_name != NULL);
861 if (f->address == NULL)
864 /* Connect the fake systemd to the bus. */
865 f->systemd = test_connect_to_bus (f->ctx, f->address);
866 if (!dbus_connection_add_filter (f->systemd, systemd_filter, f, NULL))
868 f->systemd_filter_added = TRUE;
869 f->systemd_name = dbus_bus_get_unique_name (f->systemd);
870 take_well_known_name (f, f->systemd, "org.freedesktop.systemd1");
872 if ((config->flags & FLAG_EARLY_TRANSIENT_SERVICE) == 0)
874 /* Try to activate a service that isn't there. */
875 m = dbus_message_new_method_call (config->bus_name,
876 "/foo", "com.example.bar", "Activate");
879 !dbus_connection_send_with_reply (f->caller, m, &pc,
880 DBUS_TIMEOUT_USE_DEFAULT) || pc == NULL)
883 dbus_message_unref (m);
888 if (dbus_pending_call_get_completed (pc))
889 test_pending_call_store_reply (pc, &m);
890 else if (!dbus_pending_call_set_notify (pc, test_pending_call_store_reply,
895 test_main_context_iterate (f->ctx, TRUE);
897 assert_error_reply (m, DBUS_SERVICE_DBUS, f->caller_name,
898 DBUS_ERROR_SERVICE_UNKNOWN);
900 dbus_message_unref (m);
903 /* Now generate a transient D-Bus service file for it. The directory
904 * should have been created during dbus-daemon startup, so we don't have to
906 fixture_create_transient_service (f, config->bus_name);
908 /* To guarantee that the transient service has been picked up, we have
910 m = dbus_message_new_method_call (DBUS_SERVICE_DBUS, DBUS_PATH_DBUS,
911 DBUS_INTERFACE_DBUS, "ReloadConfig");
914 !dbus_connection_send_with_reply (f->caller, m, &pc,
915 DBUS_TIMEOUT_USE_DEFAULT) || pc == NULL)
918 dbus_message_unref (m);
921 if (dbus_pending_call_get_completed (pc))
922 test_pending_call_store_reply (pc, &m);
923 else if (!dbus_pending_call_set_notify (pc, test_pending_call_store_reply,
928 test_main_context_iterate (f->ctx, TRUE);
930 assert_method_reply (m, DBUS_SERVICE_DBUS, f->caller_name, "");
931 dbus_message_unref (m);
935 /* The service is present now. */
936 m = dbus_message_new_method_call (config->bus_name,
937 "/foo", "com.example.bar", "Activate");
940 !dbus_connection_send_with_reply (f->caller, m, &pc,
941 DBUS_TIMEOUT_USE_DEFAULT) || pc == NULL)
944 dbus_message_unref (m);
947 if (dbus_pending_call_get_completed (pc))
948 test_pending_call_store_reply (pc, &reply);
949 else if (!dbus_pending_call_set_notify (pc, test_pending_call_store_reply,
953 /* The mock systemd is told to start the service. */
954 while (f->systemd_message == NULL)
955 test_main_context_iterate (f->ctx, TRUE);
957 m = f->systemd_message;
958 f->systemd_message = NULL;
959 assert_signal (m, DBUS_SERVICE_DBUS, DBUS_PATH_DBUS,
960 "org.freedesktop.systemd1.Activator", "ActivationRequest", "s",
961 "org.freedesktop.systemd1");
962 dbus_message_unref (m);
965 /* The activatable service connects and gets its name. */
966 f->activated = test_connect_to_bus (f->ctx, f->address);
967 if (!dbus_connection_add_filter (f->activated, activated_filter,
970 f->activated_filter_added = TRUE;
971 f->activated_name = dbus_bus_get_unique_name (f->activated);
972 take_well_known_name (f, f->activated, config->bus_name);
974 /* The message is delivered to the activatable service. */
975 while (f->activated_message == NULL)
976 test_main_context_iterate (f->ctx, TRUE);
978 m = f->activated_message;
979 f->activated_message = NULL;
980 assert_method_call (m, f->caller_name, config->bus_name, "/foo",
981 "com.example.bar", "Activate", "");
983 /* The activatable service sends back a reply. */
984 send_reply = dbus_message_new_method_return (m);
986 if (send_reply == NULL ||
987 !dbus_connection_send (f->activated, send_reply, NULL))
990 dbus_message_unref (send_reply);
992 dbus_message_unref (m);
995 /* The caller receives the reply. */
996 while (reply == NULL)
997 test_main_context_iterate (f->ctx, TRUE);
999 assert_method_reply (reply, f->activated_name, f->caller_name, "");
1000 dbus_message_unref (reply);
1005 teardown (Fixture *f,
1006 gconstpointer context G_GNUC_UNUSED)
1008 dbus_error_free (&f->e);
1009 g_clear_error (&f->ge);
1011 if (f->caller != NULL)
1013 if (f->caller_filter_added)
1014 dbus_connection_remove_filter (f->caller, caller_filter, f);
1016 dbus_connection_close (f->caller);
1017 dbus_connection_unref (f->caller);
1021 if (f->systemd != NULL)
1023 if (f->systemd_filter_added)
1024 dbus_connection_remove_filter (f->systemd, systemd_filter, f);
1026 dbus_connection_close (f->systemd);
1027 dbus_connection_unref (f->systemd);
1031 if (f->activated != NULL)
1033 if (f->activated_filter_added)
1034 dbus_connection_remove_filter (f->activated, activated_filter, f);
1036 dbus_connection_close (f->activated);
1037 dbus_connection_unref (f->activated);
1038 f->activated = NULL;
1041 if (f->daemon_pid != 0)
1043 test_kill_pid (f->daemon_pid);
1044 g_spawn_close_pid (f->daemon_pid);
1048 test_main_context_unref (f->ctx);
1050 g_free (f->address);
1052 if (f->transient_service_file != NULL)
1054 test_remove_if_exists (f->transient_service_file);
1055 g_free (f->transient_service_file);
1058 if (f->tmp_runtime_dir != NULL)
1060 gchar *dbus1 = g_build_filename (f->tmp_runtime_dir, "dbus-1", NULL);
1061 gchar *services = g_build_filename (dbus1, "services", NULL);
1063 test_rmdir_if_exists (services);
1064 test_rmdir_if_exists (dbus1);
1065 test_rmdir_if_exists (f->tmp_runtime_dir);
1067 g_free (f->tmp_runtime_dir);
1073 static const Config deny_send_tests[] =
1075 #if defined(DBUS_TEST_APPARMOR_ACTIVATION)
1076 { "com.example.SendDeniedByAppArmorLabel" },
1077 { "com.example.SendDeniedByNonexistentAppArmorLabel" },
1078 { "com.example.SendDeniedByAppArmorName" },
1080 { "com.example.SendDenied" }
1083 static const Config deny_receive_tests[] =
1085 #if defined(DBUS_TEST_APPARMOR_ACTIVATION)
1086 { "com.example.ReceiveDeniedByAppArmorLabel" },
1088 { "com.example.ReceiveDenied" }
1091 static const Config transient_service_later =
1093 "com.example.TransientActivatable1",
1097 static const Config transient_service_in_advance =
1099 "com.example.TransientActivatable1",
1100 FLAG_EARLY_TRANSIENT_SERVICE
1109 test_init (&argc, &argv);
1111 g_test_add ("/sd-activation/activation", Fixture, NULL,
1112 setup, test_activation, teardown);
1113 g_test_add ("/sd-activation/uae", Fixture, NULL,
1114 setup, test_uae, teardown);
1116 for (i = 0; i < G_N_ELEMENTS (deny_send_tests); i++)
1118 gchar *name = g_strdup_printf ("/sd-activation/deny-send/%s",
1119 deny_send_tests[i].bus_name);
1121 g_test_add (name, Fixture, &deny_send_tests[i],
1122 setup, test_deny_send, teardown);
1126 for (i = 0; i < G_N_ELEMENTS (deny_receive_tests); i++)
1128 gchar *name = g_strdup_printf ("/sd-activation/deny-receive/%s",
1129 deny_receive_tests[i].bus_name);
1131 g_test_add (name, Fixture, &deny_receive_tests[i],
1132 setup, test_deny_receive, teardown);
1136 g_test_add ("/sd-activation/transient-services/later", Fixture,
1137 &transient_service_later, setup, test_transient_services, teardown);
1138 g_test_add ("/sd-activation/transient-services/in-advance", Fixture,
1139 &transient_service_in_advance, setup, test_transient_services, teardown);
1141 return g_test_run ();