1 /* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
2 /* check.c Bus security policy runtime check
4 * Copyright (C) 2014 Intel, Inc.
5 * Copyright (c) 2014 Samsung Electronics, Ltd.
7 * Licensed under the Academic Free License version 2.1
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; either version 2 of the License, or
12 * (at your option) any later version.
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
19 * You should have received a copy of the GNU General Public License
20 * along with this program; if not, write to the Free Software
21 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
27 #include "connection.h"
31 #include <dbus/dbus-connection-internal.h>
32 #include <dbus/dbus-message-internal.h>
33 #include <dbus/dbus-internals.h>
36 typedef struct BusCheck
44 typedef struct BusDeferredMessage
49 DBusConnection *sender;
50 DBusConnection *proposed_recipient;
51 DBusConnection *addressed_recipient;
52 dbus_bool_t requested_reply;
54 const char *privilege;
55 dbus_bool_t full_dispatch;
56 BusDeferredMessageStatus status;
58 BusCheckResponseFunc response_callback;
61 static dbus_int32_t deferred_message_data_slot = -1;
64 bus_check_new (BusContext *context, DBusError *error)
68 check = dbus_new(BusCheck, 1);
75 if (!dbus_message_allocate_data_slot(&deferred_message_data_slot))
83 check->context = context;
84 check->cynara = bus_cynara_new(check, error);
85 if (dbus_error_is_set(error))
87 dbus_message_free_data_slot(&deferred_message_data_slot);
96 bus_check_ref (BusCheck *check)
98 _dbus_assert (check->refcount > 0);
105 bus_check_unref (BusCheck *check)
107 _dbus_assert (check->refcount > 0);
109 check->refcount -= 1;
111 if (check->refcount == 0)
113 bus_cynara_unref(check->cynara);
114 dbus_message_free_data_slot(&deferred_message_data_slot);
120 bus_check_get_context (BusCheck *check)
122 return check->context;
126 bus_check_get_cynara (BusCheck *check)
128 return check->cynara;
132 bus_check_enable_dispatch_callback (BusDeferredMessage *deferred_message,
135 _dbus_verbose("bus_check_enable_dispatch_callback called deferred_message=%p\n", deferred_message);
137 deferred_message->response = result;
138 _dbus_connection_enable_dispatch(deferred_message->sender);
142 bus_check_queued_message_reply_callback (BusDeferredMessage *deferred_message,
147 _dbus_verbose("bus_check_queued_message_reply_callback called message=%p\n", deferred_message);
149 if (!bus_connection_is_active(deferred_message->proposed_recipient))
152 status = deferred_message->status;
154 deferred_message->status = 0; /* mark message as not waiting for response */
155 deferred_message->response = result;
158 * If send rule allows us to send message we still need to check receive rules.
160 if ((status & BUS_DEFERRED_MESSAGE_CHECK_SEND) && (result == BUS_RESULT_TRUE))
164 BusRegistry *registry;
165 BusClientPolicy *recipient_policy;
166 BusDeferredMessage *deferred_message_receive;
168 context = bus_connection_get_context(deferred_message->proposed_recipient);
169 registry = bus_context_get_registry(context);
170 recipient_policy = bus_connection_get_policy(deferred_message->proposed_recipient);
172 deferred_message->response = bus_client_policy_check_can_receive(recipient_policy, registry,
173 deferred_message->requested_reply, deferred_message->sender,
174 deferred_message->addressed_recipient, deferred_message->proposed_recipient, deferred_message->message,
175 &toggles, NULL, &deferred_message_receive);
176 if (deferred_message->response == BUS_RESULT_LATER)
178 /* replace deferred message associated with send check with the one associated with
180 if (!bus_deferred_message_replace(deferred_message, deferred_message_receive))
182 /* failed to replace deferred message (due to oom). Set it to rejected */
183 deferred_message->response = BUS_RESULT_FALSE;
188 bus_connection_dispatch_deferred(deferred_message->proposed_recipient);
192 queue_deferred_message_cancel_transaction_hook (void *data)
194 BusDeferredMessage *deferred_message = (BusDeferredMessage *)data;
195 bus_connection_remove_deferred_message(deferred_message->proposed_recipient, deferred_message);
200 bus_deferred_message_queue_at_recipient (BusDeferredMessage *deferred_message,
201 BusTransaction *transaction,
202 dbus_bool_t full_dispatch,
205 _dbus_assert(deferred_message != NULL);
206 _dbus_assert(deferred_message->proposed_recipient != NULL);
208 if (!bus_connection_queue_deferred_message(deferred_message->proposed_recipient,
209 deferred_message, prepend))
212 if (!bus_transaction_add_cancel_hook(transaction, queue_deferred_message_cancel_transaction_hook,
213 deferred_message, NULL))
215 bus_connection_remove_deferred_message(deferred_message->proposed_recipient, deferred_message);
218 deferred_message->response_callback = bus_check_queued_message_reply_callback;
219 deferred_message->full_dispatch = full_dispatch;
225 deferred_message_free_function(void *data)
227 BusDeferredMessage *deferred_message = (BusDeferredMessage *)data;
228 bus_deferred_message_unref(deferred_message);
232 bus_deferred_message_disable_sender (BusDeferredMessage *deferred_message)
234 _dbus_assert(deferred_message != NULL);
235 _dbus_assert(deferred_message->sender != NULL);
237 if (dbus_message_get_data(deferred_message->message, deferred_message_data_slot) == NULL)
239 if (dbus_message_set_data(deferred_message->message, deferred_message_data_slot, deferred_message,
240 deferred_message_free_function))
241 bus_deferred_message_ref(deferred_message);
244 _dbus_connection_disable_dispatch(deferred_message->sender);
245 deferred_message->response_callback = bus_check_enable_dispatch_callback;
249 bus_deferred_message_set_policy_check_info (BusDeferredMessage *deferred_message,
250 dbus_bool_t requested_reply,
252 const char *privilege)
254 _dbus_assert(deferred_message != NULL);
256 deferred_message->requested_reply = requested_reply;
257 deferred_message->matched_rules = matched_rules;
258 deferred_message->privilege = privilege;
262 #ifdef DBUS_ENABLE_EMBEDDED_TESTS
263 dbus_bool_t (*bus_check_test_override) (DBusConnection *connection,
264 const char *privilege);
268 bus_check_privilege (BusCheck *check,
269 DBusMessage *message,
270 DBusConnection *sender,
271 DBusConnection *addressed_recipient,
272 DBusConnection *proposed_recipient,
273 const char *privilege,
274 BusDeferredMessageStatus check_type,
275 BusDeferredMessage **deferred_message)
277 BusDeferredMessage *previous_deferred_message;
278 BusResult result = BUS_RESULT_FALSE;
280 DBusConnection *connection;
282 connection = check_type == BUS_DEFERRED_MESSAGE_CHECK_RECEIVE ? proposed_recipient : sender;
284 #ifdef DBUS_ENABLE_EMBEDDED_TESTS
285 if (bus_check_test_override)
286 return bus_check_test_override (connection, privilege);
289 previous_deferred_message = dbus_message_get_data(message, deferred_message_data_slot);
290 /* check if message blocked at sender's queue is being processed */
291 if (previous_deferred_message != NULL)
293 if ((check_type & BUS_DEFERRED_MESSAGE_CHECK_SEND) &&
294 !(previous_deferred_message->status & BUS_DEFERRED_MESSAGE_CHECK_SEND))
297 * Message has been deferred due to receive or own rule which means that sending this message
298 * is allowed - it must have been checked previously.
300 result = BUS_RESULT_TRUE;
304 result = previous_deferred_message->response;
305 if (result == BUS_RESULT_LATER)
307 /* result is still not known - reuse deferred message object */
308 if (deferred_message != NULL)
309 *deferred_message = previous_deferred_message;
313 /* result is available - we can remove deferred message from the processed message */
314 dbus_message_set_data(message, deferred_message_data_slot, NULL, NULL);
320 /* ask policy checkers */
321 #ifdef DBUS_ENABLE_CYNARA
322 cynara = bus_check_get_cynara(check);
323 result = bus_cynara_check_privilege(cynara, message, sender, addressed_recipient,
324 proposed_recipient, privilege, check_type, deferred_message);
326 if (result == BUS_RESULT_LATER && deferred_message != NULL)
328 (*deferred_message)->status |= check_type;
334 BusDeferredMessage *bus_deferred_message_new (DBusMessage *message,
335 DBusConnection *sender,
336 DBusConnection *addressed_recipient,
337 DBusConnection *proposed_recipient,
340 BusDeferredMessage *deferred_message;
342 deferred_message = dbus_new(BusDeferredMessage, 1);
343 if (deferred_message == NULL)
348 deferred_message->refcount = 1;
349 deferred_message->sender = sender != NULL ? dbus_connection_ref(sender) : NULL;
350 deferred_message->addressed_recipient = addressed_recipient != NULL ? dbus_connection_ref(addressed_recipient) : NULL;
351 deferred_message->proposed_recipient = proposed_recipient != NULL ? dbus_connection_ref(proposed_recipient) : NULL;
352 deferred_message->message = dbus_message_ref(message);
353 deferred_message->requested_reply = FALSE;
354 deferred_message->matched_rules = 0;
355 deferred_message->privilege = NULL;
356 deferred_message->response = response;
357 deferred_message->status = 0;
358 deferred_message->full_dispatch = FALSE;
359 deferred_message->response_callback = NULL;
361 return deferred_message;
365 bus_deferred_message_ref (BusDeferredMessage *deferred_message)
367 _dbus_assert (deferred_message->refcount > 0);
368 deferred_message->refcount += 1;
369 return deferred_message;
373 bus_deferred_message_unref (BusDeferredMessage *deferred_message)
375 _dbus_assert (deferred_message->refcount > 0);
377 deferred_message->refcount -= 1;
379 if (deferred_message->refcount == 0)
381 dbus_message_unref(deferred_message->message);
382 if (deferred_message->sender != NULL)
383 dbus_connection_unref(deferred_message->sender);
384 if (deferred_message->addressed_recipient != NULL)
385 dbus_connection_unref(deferred_message->addressed_recipient);
386 if (deferred_message->proposed_recipient != NULL)
387 dbus_connection_unref(deferred_message->proposed_recipient);
388 dbus_free(deferred_message);
393 bus_deferred_message_check_message_limits (BusDeferredMessage *deferred_message, DBusError *error)
395 BusContext *context = bus_connection_get_context(deferred_message->proposed_recipient);
397 return bus_context_check_recipient_message_limits(context, deferred_message->proposed_recipient,
398 deferred_message->sender, deferred_message->message, deferred_message->requested_reply,
403 bus_deferred_message_expect_method_reply(BusDeferredMessage *deferred_message, BusTransaction *transaction, DBusError *error)
405 int type = dbus_message_get_type(deferred_message->message);
406 if (type == DBUS_MESSAGE_TYPE_METHOD_CALL &&
407 deferred_message->sender &&
408 deferred_message->addressed_recipient &&
409 deferred_message->addressed_recipient == deferred_message->proposed_recipient && /* not eavesdropping */
410 !bus_connections_expect_reply (bus_connection_get_connections (deferred_message->sender),
412 deferred_message->sender, deferred_message->addressed_recipient,
413 deferred_message->message, error))
415 _dbus_verbose ("Failed to record reply expectation or problem with the message expecting a reply\n");
422 bus_deferred_message_create_error(BusDeferredMessage *deferred_message,
423 const char *error_message, DBusError *error)
426 _dbus_assert (deferred_message->status == 0 && deferred_message->response == BUS_RESULT_FALSE);
428 if (deferred_message->sender == NULL)
429 return; /* error won't be sent to bus driver anyway */
431 context = bus_connection_get_context(deferred_message->sender);
432 bus_context_complain_about_message(context, DBUS_ERROR_ACCESS_DENIED, "Rejected message",
433 deferred_message->matched_rules, deferred_message->message, deferred_message->sender,
434 deferred_message->proposed_recipient, deferred_message->requested_reply, FALSE,
435 deferred_message->privilege, error);
439 bus_deferred_message_dispatch (BusDeferredMessage *deferred_message)
441 BusContext *context = bus_connection_get_context (deferred_message->proposed_recipient);
442 BusTransaction *transaction = bus_transaction_new (context);
443 BusResult result = BUS_RESULT_TRUE;
446 if (transaction == NULL)
448 return BUS_RESULT_FALSE;
451 dbus_error_init(&error);
453 if (!deferred_message->full_dispatch)
455 result = deferred_message->response;
458 case BUS_RESULT_TRUE:
459 if (!bus_context_check_recipient_message_limits(context, deferred_message->proposed_recipient,
460 deferred_message->sender, deferred_message->message, deferred_message->requested_reply, &error))
461 result = BUS_RESULT_FALSE;
463 case BUS_RESULT_FALSE:
465 case BUS_RESULT_LATER:
467 BusDeferredMessage *deferred_message2;
468 result = bus_context_check_security_policy (context, transaction,
469 deferred_message->sender,
470 deferred_message->addressed_recipient,
471 deferred_message->proposed_recipient,
472 deferred_message->message, NULL,
475 if (result == BUS_RESULT_LATER)
477 /* prepend at recipient */
478 if (!bus_deferred_message_queue_at_recipient(deferred_message2, transaction,
480 result = BUS_RESULT_FALSE;
485 /* silently drop messages on access denial */
486 if (result == BUS_RESULT_TRUE)
488 if (!bus_transaction_send (transaction, deferred_message->proposed_recipient, deferred_message->message, TRUE))
489 result = BUS_RESULT_FALSE;
492 bus_transaction_execute_and_free(transaction);
497 /* do not attempt to send message if sender has disconnected */
498 if (deferred_message->sender != NULL && !bus_connection_is_active(deferred_message->sender))
500 bus_transaction_cancel_and_free(transaction);
501 result = BUS_RESULT_FALSE;
505 result = bus_dispatch_matches(transaction, deferred_message->sender,
506 deferred_message->addressed_recipient, deferred_message->message, deferred_message, &error);
508 if (result == BUS_RESULT_LATER)
510 /* Message deferring was already done in bus_dispatch_matches */
511 bus_transaction_cancel_and_free(transaction);
515 /* this part is a copy & paste from bus_dispatch function. Probably can be moved to a function */
516 if (dbus_error_is_set (&error))
518 if (!dbus_connection_get_is_connected (deferred_message->sender))
520 /* If we disconnected it, we won't bother to send it any error
523 _dbus_verbose ("Not sending error to connection we disconnected\n");
525 else if (dbus_error_has_name (&error, DBUS_ERROR_NO_MEMORY))
527 bus_connection_send_oom_error (deferred_message->sender, deferred_message->message);
529 /* cancel transaction due to OOM */
530 if (transaction != NULL)
532 bus_transaction_cancel_and_free (transaction);
538 /* Try to send the real error, if no mem to do that, send
541 _dbus_assert (transaction != NULL);
542 if (!bus_transaction_send_error_reply (transaction, deferred_message->sender,
543 &error, deferred_message->message))
545 bus_connection_send_oom_error (deferred_message->sender, deferred_message->message);
547 /* cancel transaction due to OOM */
548 if (transaction != NULL)
550 bus_transaction_cancel_and_free (transaction);
557 if (transaction != NULL)
559 bus_transaction_execute_and_free (transaction);
563 dbus_error_free(&error);
569 bus_deferred_message_replace (BusDeferredMessage *old_message, BusDeferredMessage *new_message)
571 if (bus_connection_replace_deferred_message(old_message->proposed_recipient,
572 old_message, new_message))
574 new_message->response_callback = old_message->response_callback;
575 new_message->full_dispatch = old_message->full_dispatch;
582 bus_deferred_message_waits_for_check(BusDeferredMessage *deferred_message)
584 return deferred_message->status != 0;
588 bus_deferred_message_get_recipient(BusDeferredMessage *deferred_message)
590 return deferred_message->proposed_recipient;
593 BusDeferredMessageStatus
594 bus_deferred_message_get_status (BusDeferredMessage *deferred_message)
596 return deferred_message->status;
600 bus_deferred_message_get_response (BusDeferredMessage *deferred_message)
602 return deferred_message->response;
606 bus_deferred_message_response_received (BusDeferredMessage *deferred_message,
609 if (deferred_message->response_callback != NULL)
611 deferred_message->response_callback(deferred_message, result);