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,
133 BusDeferredMessageStatus check_type,
136 _dbus_verbose("bus_check_enable_dispatch_callback called deferred_message=%p\n", deferred_message);
138 deferred_message->response = result;
139 _dbus_connection_enable_dispatch(deferred_message->sender);
143 bus_check_queued_message_reply_callback (BusDeferredMessage *deferred_message,
144 BusDeferredMessageStatus check_type,
147 _dbus_verbose("bus_check_queued_message_reply_callback called message=%p\n", deferred_message);
149 if (!(dbus_connection_get_is_connected(deferred_message->proposed_recipient)
150 && bus_connection_is_active(deferred_message->proposed_recipient)))
153 deferred_message->status &= ~check_type; /* mark message as not waiting for response of this type*/
154 if (deferred_message->response != BUS_RESULT_FALSE)
155 deferred_message->response = result;
157 _dbus_assert (deferred_message->response != BUS_RESULT_LATER || deferred_message->status != 0);
159 if (!deferred_message->status)
160 bus_connection_dispatch_deferred(deferred_message->proposed_recipient);
164 queue_deferred_message_cancel_transaction_hook (void *data)
166 BusDeferredMessage *deferred_message = (BusDeferredMessage *)data;
167 bus_connection_remove_deferred_message(deferred_message->proposed_recipient, deferred_message);
172 bus_deferred_message_queue_at_recipient (BusDeferredMessage *deferred_message,
173 BusTransaction *transaction,
174 dbus_bool_t full_dispatch,
177 _dbus_assert(deferred_message != NULL);
178 _dbus_assert(deferred_message->proposed_recipient != NULL);
180 if (!bus_connection_queue_deferred_message(deferred_message->proposed_recipient,
181 deferred_message, prepend))
184 if (!bus_transaction_add_cancel_hook(transaction, queue_deferred_message_cancel_transaction_hook,
185 deferred_message, NULL))
187 bus_connection_remove_deferred_message(deferred_message->proposed_recipient, deferred_message);
190 deferred_message->response_callback = bus_check_queued_message_reply_callback;
191 deferred_message->full_dispatch = full_dispatch;
197 deferred_message_free_function(void *data)
199 BusDeferredMessage *deferred_message = (BusDeferredMessage *)data;
200 bus_deferred_message_unref(deferred_message);
204 bus_deferred_message_disable_sender (BusDeferredMessage *deferred_message)
206 _dbus_assert(deferred_message != NULL);
207 _dbus_assert(deferred_message->sender != NULL);
209 if (dbus_message_get_data(deferred_message->message, deferred_message_data_slot) == NULL)
211 if (dbus_message_set_data(deferred_message->message, deferred_message_data_slot, deferred_message,
212 deferred_message_free_function))
213 bus_deferred_message_ref(deferred_message);
216 _dbus_connection_disable_dispatch(deferred_message->sender);
217 deferred_message->response_callback = bus_check_enable_dispatch_callback;
221 bus_deferred_message_set_policy_check_info (BusDeferredMessage *deferred_message,
222 dbus_bool_t requested_reply,
224 const char *privilege)
226 _dbus_assert(deferred_message != NULL);
228 deferred_message->requested_reply = requested_reply;
229 deferred_message->matched_rules = matched_rules;
230 deferred_message->privilege = privilege;
234 #ifdef DBUS_ENABLE_EMBEDDED_TESTS
235 dbus_bool_t (*bus_check_test_override) (DBusConnection *connection,
236 const char *privilege);
240 bus_check_privilege (BusCheck *check,
241 DBusMessage *message,
242 DBusConnection *sender,
243 DBusConnection *addressed_recipient,
244 DBusConnection *proposed_recipient,
245 const char *privilege,
246 BusDeferredMessageStatus check_type,
247 BusDeferredMessage **deferred_message)
249 BusDeferredMessage *previous_deferred_message;
250 BusResult result = BUS_RESULT_FALSE;
252 DBusConnection *connection;
254 connection = check_type == BUS_DEFERRED_MESSAGE_CHECK_RECEIVE ? proposed_recipient : sender;
256 #ifdef DBUS_ENABLE_EMBEDDED_TESTS
257 if (bus_check_test_override)
258 return bus_check_test_override (connection, privilege);
261 previous_deferred_message = dbus_message_get_data(message, deferred_message_data_slot);
262 /* check if message blocked at sender's queue is being processed */
263 if (previous_deferred_message != NULL)
265 if ((check_type & BUS_DEFERRED_MESSAGE_CHECK_SEND) &&
266 !(previous_deferred_message->status & BUS_DEFERRED_MESSAGE_CHECK_SEND))
269 * Message has been deferred due to receive or own rule which means that sending this message
270 * is allowed - it must have been checked previously.
272 result = BUS_RESULT_TRUE;
276 result = previous_deferred_message->response;
277 if (result == BUS_RESULT_LATER)
279 /* result is still not known - reuse deferred message object */
280 if (deferred_message != NULL)
281 *deferred_message = previous_deferred_message;
285 /* result is available - we can remove deferred message from the processed message */
286 dbus_message_set_data(message, deferred_message_data_slot, NULL, NULL);
292 /* ask policy checkers */
293 #ifdef DBUS_ENABLE_CYNARA
294 cynara = bus_check_get_cynara(check);
295 result = bus_cynara_check_privilege(cynara, message, sender, addressed_recipient,
296 proposed_recipient, privilege, check_type, deferred_message);
298 if (result == BUS_RESULT_LATER && deferred_message != NULL)
300 (*deferred_message)->status |= check_type;
306 BusDeferredMessage *bus_deferred_message_new (DBusMessage *message,
307 DBusConnection *sender,
308 DBusConnection *addressed_recipient,
309 DBusConnection *proposed_recipient,
312 BusDeferredMessage *deferred_message;
314 deferred_message = dbus_new(BusDeferredMessage, 1);
315 if (deferred_message == NULL)
320 deferred_message->refcount = 1;
321 deferred_message->sender = sender != NULL ? dbus_connection_ref(sender) : NULL;
322 deferred_message->addressed_recipient = addressed_recipient != NULL ? dbus_connection_ref(addressed_recipient) : NULL;
323 deferred_message->proposed_recipient = proposed_recipient != NULL ? dbus_connection_ref(proposed_recipient) : NULL;
324 deferred_message->message = dbus_message_ref(message);
325 deferred_message->requested_reply = FALSE;
326 deferred_message->matched_rules = 0;
327 deferred_message->privilege = NULL;
328 deferred_message->response = response;
329 deferred_message->status = 0;
330 deferred_message->full_dispatch = FALSE;
331 deferred_message->response_callback = NULL;
333 return deferred_message;
337 bus_deferred_message_ref (BusDeferredMessage *deferred_message)
339 _dbus_assert (deferred_message->refcount > 0);
340 deferred_message->refcount += 1;
341 return deferred_message;
345 bus_deferred_message_unref (BusDeferredMessage *deferred_message)
347 _dbus_assert (deferred_message->refcount > 0);
349 deferred_message->refcount -= 1;
351 if (deferred_message->refcount == 0)
353 dbus_message_unref(deferred_message->message);
354 if (deferred_message->sender != NULL)
355 dbus_connection_unref(deferred_message->sender);
356 if (deferred_message->addressed_recipient != NULL)
357 dbus_connection_unref(deferred_message->addressed_recipient);
358 if (deferred_message->proposed_recipient != NULL)
359 dbus_connection_unref(deferred_message->proposed_recipient);
360 dbus_free(deferred_message);
365 bus_deferred_message_check_message_limits (BusDeferredMessage *deferred_message, DBusError *error)
367 BusContext *context = bus_connection_get_context(deferred_message->proposed_recipient);
369 return bus_context_check_recipient_message_limits(context, deferred_message->proposed_recipient,
370 deferred_message->sender, deferred_message->message, deferred_message->requested_reply,
375 bus_deferred_message_expect_method_reply(BusDeferredMessage *deferred_message, BusTransaction *transaction, DBusError *error)
377 int type = dbus_message_get_type(deferred_message->message);
378 if (type == DBUS_MESSAGE_TYPE_METHOD_CALL &&
379 deferred_message->sender &&
380 dbus_connection_get_is_connected(deferred_message->sender) &&
381 bus_connection_is_active(deferred_message->sender) &&
382 deferred_message->addressed_recipient &&
383 deferred_message->addressed_recipient == deferred_message->proposed_recipient && /* not eavesdropping */
384 !bus_connections_expect_reply (bus_connection_get_connections (deferred_message->sender),
386 deferred_message->sender, deferred_message->addressed_recipient,
387 deferred_message->message, error))
389 _dbus_verbose ("Failed to record reply expectation or problem with the message expecting a reply\n");
396 bus_deferred_message_create_error(BusDeferredMessage *deferred_message,
397 const char *error_message, DBusError *error)
400 _dbus_assert (deferred_message->status == 0 && deferred_message->response == BUS_RESULT_FALSE);
402 if (deferred_message->sender == NULL)
403 return; /* error won't be sent to bus driver anyway */
405 context = bus_connection_get_context(deferred_message->sender);
406 bus_context_complain_about_message(context, DBUS_ERROR_ACCESS_DENIED, "Rejected message",
407 deferred_message->matched_rules, deferred_message->message, deferred_message->sender,
408 deferred_message->proposed_recipient, deferred_message->requested_reply, FALSE,
409 deferred_message->privilege, error);
413 bus_deferred_message_dispatch (BusDeferredMessage *deferred_message)
415 BusContext *context = bus_connection_get_context (deferred_message->proposed_recipient);
416 BusTransaction *transaction = bus_transaction_new (context);
417 BusResult result = BUS_RESULT_TRUE;
420 if (transaction == NULL)
422 return BUS_RESULT_FALSE;
425 dbus_error_init(&error);
427 if (!deferred_message->full_dispatch)
429 result = deferred_message->response;
432 case BUS_RESULT_TRUE:
433 if (!bus_context_check_recipient_message_limits(context, deferred_message->proposed_recipient,
434 deferred_message->sender, deferred_message->message, deferred_message->requested_reply, &error))
435 result = BUS_RESULT_FALSE;
437 case BUS_RESULT_FALSE:
439 case BUS_RESULT_LATER:
441 BusDeferredMessage *deferred_message2 = NULL;
442 result = bus_context_check_security_policy (context, transaction,
443 deferred_message->sender,
444 deferred_message->addressed_recipient,
445 deferred_message->proposed_recipient,
446 deferred_message->message, NULL, NULL,
449 if (result == BUS_RESULT_LATER)
451 /* prepend at recipient */
452 if (!bus_deferred_message_queue_at_recipient(deferred_message2, transaction,
454 result = BUS_RESULT_FALSE;
459 /* silently drop messages on access denial */
460 if (result == BUS_RESULT_TRUE)
462 if (!bus_transaction_send (transaction, deferred_message->proposed_recipient, deferred_message->message, TRUE))
463 result = BUS_RESULT_FALSE;
466 bus_transaction_execute_and_free(transaction);
471 result = bus_dispatch_matches(transaction, deferred_message->sender,
472 deferred_message->addressed_recipient, deferred_message->message, deferred_message, &error);
474 if (result == BUS_RESULT_LATER)
476 /* Message deferring was already done in bus_dispatch_matches */
477 bus_transaction_cancel_and_free(transaction);
481 /* this part is a copy & paste from bus_dispatch function. Probably can be moved to a function */
482 if (dbus_error_is_set (&error))
484 if (!dbus_connection_get_is_connected (deferred_message->sender))
486 /* If we disconnected it, we won't bother to send it any error
489 _dbus_verbose ("Not sending error to connection we disconnected\n");
491 else if (dbus_error_has_name (&error, DBUS_ERROR_NO_MEMORY))
493 bus_connection_send_oom_error (deferred_message->sender, deferred_message->message);
495 /* cancel transaction due to OOM */
496 if (transaction != NULL)
498 bus_transaction_cancel_and_free (transaction);
504 /* Try to send the real error, if no mem to do that, send
507 _dbus_assert (transaction != NULL);
508 if (!bus_transaction_send_error_reply (transaction, deferred_message->sender,
509 &error, deferred_message->message))
511 bus_connection_send_oom_error (deferred_message->sender, deferred_message->message);
513 /* cancel transaction due to OOM */
514 if (transaction != NULL)
516 bus_transaction_cancel_and_free (transaction);
523 if (transaction != NULL)
525 bus_transaction_execute_and_free (transaction);
529 dbus_error_free(&error);
535 bus_deferred_message_waits_for_check(BusDeferredMessage *deferred_message)
537 return deferred_message->status != 0;
541 bus_deferred_message_get_recipient(BusDeferredMessage *deferred_message)
543 return deferred_message->proposed_recipient;
546 BusDeferredMessageStatus
547 bus_deferred_message_get_status (BusDeferredMessage *deferred_message)
549 return deferred_message->status;
553 bus_deferred_message_get_response (BusDeferredMessage *deferred_message)
555 return deferred_message->response;
559 bus_deferred_message_set_response (BusDeferredMessage *deferred_message, BusResult response)
561 deferred_message->response = response;
565 bus_deferred_message_response_received (BusDeferredMessage *deferred_message,
566 BusDeferredMessageStatus check_type,
569 if (deferred_message->response_callback != NULL)
571 deferred_message->response_callback(deferred_message, check_type, result);