2004-07-24 Havoc Pennington <hp@redhat.com>

SELinux support from Matthew Rickard <mjricka@epoch.ncsc.mil>

	* bus/selinux.c, bus/selinux.h: new file encapsulating selinux
	functionality

	* configure.in: add --enable-selinux

	* bus/policy.c (bus_policy_merge): add FIXME to a comment

	* bus/main.c (main): initialize and shut down selinux

	* bus/connection.c: store SELinux ID on each connection, to avoid
	repeated getting of the string context and converting it into
	an ID

	* bus/bus.c (bus_context_get_policy): new accessor, though it
	isn't used
	(bus_context_check_security_policy): check whether the security
	context of sender connection can send to the security context of
	recipient connection

	* bus/config-parser.c: add parsing for <selinux> and <associate>

	* dbus/dbus-transport.c (_dbus_transport_get_unix_fd): to
	implement dbus_connection_get_unix_fd()

	* dbus/dbus-connection.c (dbus_connection_get_unix_fd): new
	function, used by the selinux stuff
This commit is contained in:
Havoc Pennington 2004-07-30 05:59:34 +00:00
parent 4076d31c71
commit 1e9b185b0c
24 changed files with 1266 additions and 26 deletions

View file

@ -1,3 +1,34 @@
2004-07-24 Havoc Pennington <hp@redhat.com>
SELinux support from Matthew Rickard <mjricka@epoch.ncsc.mil>
* bus/selinux.c, bus/selinux.h: new file encapsulating selinux
functionality
* configure.in: add --enable-selinux
* bus/policy.c (bus_policy_merge): add FIXME to a comment
* bus/main.c (main): initialize and shut down selinux
* bus/connection.c: store SELinux ID on each connection, to avoid
repeated getting of the string context and converting it into
an ID
* bus/bus.c (bus_context_get_policy): new accessor, though it
isn't used
(bus_context_check_security_policy): check whether the security
context of sender connection can send to the security context of
recipient connection
* bus/config-parser.c: add parsing for <selinux> and <associate>
* dbus/dbus-transport.c (_dbus_transport_get_unix_fd): to
implement dbus_connection_get_unix_fd()
* dbus/dbus-connection.c (dbus_connection_get_unix_fd): new
function, used by the selinux stuff
2004-07-29 Olivier Andrieu <oliv__a@users.sourceforge.net>
* bus/config-loader-libxml.c: complete the implementation of

View file

@ -10,7 +10,7 @@ EFENCE=
CONFIG_IN_FILES= \
session.conf.in \
system.conf.in
system.conf.in
config_DATA= \
session.conf \
@ -44,6 +44,8 @@ BUS_SOURCES= \
expirelist.h \
policy.c \
policy.h \
selinux.h \
selinux.c \
services.c \
services.h \
signals.c \

View file

@ -29,6 +29,7 @@
#include "policy.h"
#include "config-parser.h"
#include "signals.h"
#include "selinux.h"
#include <dbus/dbus-list.h>
#include <dbus/dbus-hash.h>
#include <dbus/dbus-internals.h>
@ -403,6 +404,7 @@ process_config_every_time (BusContext *context,
{
DBusString full_address;
DBusList *link;
DBusHashTable *service_sid_table;
dbus_bool_t retval;
@ -480,6 +482,11 @@ process_config_every_time (BusContext *context,
goto failed;
}
service_sid_table = bus_config_parser_steal_service_sid_table (parser);
bus_registry_set_service_sid_table (context->registry,
service_sid_table);
_dbus_hash_table_unref (service_sid_table);
_DBUS_ASSERT_ERROR_IS_CLEAR (error);
retval = TRUE;
@ -569,6 +576,13 @@ bus_context_new (const DBusString *config_file,
goto failed;
}
context->registry = bus_registry_new (context);
if (context->registry == NULL)
{
BUS_SET_OOM (error);
goto failed;
}
if (!load_config (context, FALSE, error))
{
_DBUS_ASSERT_ERROR_IS_SET (error);
@ -637,13 +651,6 @@ bus_context_new (const DBusString *config_file,
goto failed;
}
context->registry = bus_registry_new (context);
if (context->registry == NULL)
{
BUS_SET_OOM (error);
goto failed;
}
context->matchmaker = bus_matchmaker_new ();
if (context->matchmaker == NULL)
{
@ -958,6 +965,12 @@ bus_context_allow_user (BusContext *context,
uid);
}
BusPolicy *
bus_context_get_policy (BusContext *context)
{
return context->policy;
}
BusClientPolicy*
bus_context_create_client_policy (BusContext *context,
DBusConnection *connection,
@ -1088,6 +1101,28 @@ bus_context_check_security_policy (BusContext *context,
if (sender != NULL)
{
/* First verify the SELinux access controls. If allowed then
* go on with the standard checks.
*/
if (!bus_selinux_allows_send (sender, proposed_recipient))
{
const char *dest = dbus_message_get_destination (message);
dbus_set_error (error, DBUS_ERROR_ACCESS_DENIED,
"An SELinux policy prevents this sender "
"from sending this message to this recipient "
"(rejected message had interface \"%s\" "
"member \"%s\" error name \"%s\" destination \"%s\")",
dbus_message_get_interface (message) ?
dbus_message_get_interface (message) : "(unset)",
dbus_message_get_member (message) ?
dbus_message_get_member (message) : "(unset)",
dbus_message_get_error_name (message) ?
dbus_message_get_error_name (message) : "(unset)",
dest ? dest : DBUS_SERVICE_ORG_FREEDESKTOP_DBUS);
_dbus_verbose ("SELinux security check denying send to service\n");
return FALSE;
}
if (bus_connection_is_active (sender))
{
sender_policy = bus_connection_get_policy (sender);

View file

@ -38,6 +38,7 @@ typedef struct BusPolicy BusPolicy;
typedef struct BusClientPolicy BusClientPolicy;
typedef struct BusPolicyRule BusPolicyRule;
typedef struct BusRegistry BusRegistry;
typedef struct BusSELinuxID BusSELinuxID;
typedef struct BusService BusService;
typedef struct BusTransaction BusTransaction;
typedef struct BusMatchmaker BusMatchmaker;
@ -78,8 +79,11 @@ BusActivation* bus_context_get_activation (BusContext
BusMatchmaker* bus_context_get_matchmaker (BusContext *context);
DBusLoop* bus_context_get_loop (BusContext *context);
DBusUserDatabase* bus_context_get_user_database (BusContext *context);
dbus_bool_t bus_context_allow_user (BusContext *context,
unsigned long uid);
BusPolicy* bus_context_get_policy (BusContext *context);
BusClientPolicy* bus_context_create_client_policy (BusContext *context,
DBusConnection *connection,
DBusError *error);
@ -101,5 +105,4 @@ dbus_bool_t bus_context_check_security_policy (BusContext
DBusMessage *message,
DBusError *error);
#endif /* BUS_BUS_H */

View file

@ -24,6 +24,7 @@
#include "test.h"
#include "utils.h"
#include "policy.h"
#include "selinux.h"
#include <dbus/dbus-list.h>
#include <dbus/dbus-internals.h>
#include <string.h>
@ -44,7 +45,9 @@ typedef enum
ELEMENT_PIDFILE,
ELEMENT_SERVICEDIR,
ELEMENT_INCLUDEDIR,
ELEMENT_TYPE
ELEMENT_TYPE,
ELEMENT_SELINUX,
ELEMENT_ASSOCIATE
} ElementType;
typedef enum
@ -117,6 +120,8 @@ struct BusConfigParser
DBusList *included_files; /**< Included files stack */
DBusHashTable *service_sid_table; /**< Map service names to SELinux contexts */
unsigned int fork : 1; /**< TRUE to fork into daemon mode */
unsigned int is_toplevel : 1; /**< FALSE if we are a sub-config-file inside another one */
@ -157,6 +162,10 @@ element_type_to_name (ElementType type)
return "includedir";
case ELEMENT_TYPE:
return "type";
case ELEMENT_SELINUX:
return "selinux";
case ELEMENT_ASSOCIATE:
return "associate";
}
_dbus_assert_not_reached ("bad element type");
@ -235,6 +244,7 @@ merge_included (BusConfigParser *parser,
DBusError *error)
{
DBusList *link;
DBusHashTable *table;
if (!bus_policy_merge (parser->policy,
included->policy))
@ -242,6 +252,17 @@ merge_included (BusConfigParser *parser,
BUS_SET_OOM (error);
return FALSE;
}
table = bus_selinux_id_table_union (parser->service_sid_table,
included->service_sid_table);
if (table == NULL)
{
BUS_SET_OOM (error);
return FALSE;
}
_dbus_hash_table_unref (parser->service_sid_table);
parser->service_sid_table = table;
if (included->user != NULL)
{
@ -317,12 +338,17 @@ bus_config_parser_new (const DBusString *basedir,
}
if (((parser->policy = bus_policy_new ()) == NULL) ||
!_dbus_string_copy (basedir, 0, &parser->basedir, 0))
!_dbus_string_copy (basedir, 0, &parser->basedir, 0) ||
((parser->service_sid_table = bus_selinux_id_table_new ()) == NULL))
{
if (parser->policy)
bus_policy_unref (parser->policy);
_dbus_string_free (&parser->basedir);
if (parser->service_sid_table == NULL)
_dbus_hash_table_unref (parser->service_sid_table);
dbus_free (parser);
return NULL;
}
@ -428,6 +454,9 @@ bus_config_parser_unref (BusConfigParser *parser)
if (parser->policy)
bus_policy_unref (parser->policy);
if (parser->service_sid_table)
_dbus_hash_table_unref (parser->service_sid_table);
dbus_free (parser);
}
}
@ -658,7 +687,7 @@ start_busconfig_child (BusConfigParser *parser,
BUS_SET_OOM (error);
return FALSE;
}
return TRUE;
}
else if (strcmp (element_name, "includedir") == 0)
@ -841,6 +870,22 @@ start_busconfig_child (BusConfigParser *parser,
return FALSE;
}
return TRUE;
}
else if (strcmp (element_name, "selinux") == 0)
{
Element *e;
const char *name;
if (!check_no_attributes (parser, "selinux", attribute_names, attribute_values, error))
return FALSE;
if (push_element (parser, ELEMENT_SELINUX) == NULL)
{
BUS_SET_OOM (error);
return FALSE;
}
return TRUE;
}
else
@ -1390,6 +1435,58 @@ start_policy_child (BusConfigParser *parser,
}
}
static dbus_bool_t
start_selinux_child (BusConfigParser *parser,
const char *element_name,
const char **attribute_names,
const char **attribute_values,
DBusError *error)
{
if (strcmp (element_name, "associate") == 0)
{
const char *own;
const char *context;
if (!locate_attributes (parser, "associate",
attribute_names,
attribute_values,
error,
"own", &own,
"context", &context,
NULL))
return FALSE;
if (push_element (parser, ELEMENT_ASSOCIATE) == NULL)
{
BUS_SET_OOM (error);
return FALSE;
}
if (own == NULL || context == NULL)
{
dbus_set_error (error, DBUS_ERROR_FAILED,
"Element <associate> must have attributes own=\"<servicename>\" and context=\"<selinux context>\"");
return FALSE;
}
if (!bus_selinux_id_table_insert (parser->service_sid_table,
own, context))
{
BUS_SET_OOM (error);
return FALSE;
}
return TRUE;
}
else
{
dbus_set_error (error, DBUS_ERROR_FAILED,
"Element <%s> not allowed inside <%s> in configuration file",
element_name, "selinux");
return FALSE;
}
}
dbus_bool_t
bus_config_parser_start_element (BusConfigParser *parser,
const char *element_name,
@ -1440,6 +1537,12 @@ bus_config_parser_start_element (BusConfigParser *parser,
attribute_names, attribute_values,
error);
}
else if (t == ELEMENT_SELINUX)
{
return start_selinux_child (parser, element_name,
attribute_names, attribute_values,
error);
}
else
{
dbus_set_error (error, DBUS_ERROR_FAILED,
@ -1635,6 +1738,8 @@ bus_config_parser_end_element (BusConfigParser *parser,
case ELEMENT_ALLOW:
case ELEMENT_DENY:
case ELEMENT_FORK:
case ELEMENT_SELINUX:
case ELEMENT_ASSOCIATE:
break;
}
@ -1867,6 +1972,8 @@ bus_config_parser_content (BusConfigParser *parser,
case ELEMENT_ALLOW:
case ELEMENT_DENY:
case ELEMENT_FORK:
case ELEMENT_SELINUX:
case ELEMENT_ASSOCIATE:
if (all_whitespace (content))
return TRUE;
else
@ -2160,6 +2267,20 @@ bus_config_parser_get_limits (BusConfigParser *parser,
*limits = parser->limits;
}
DBusHashTable*
bus_config_parser_steal_service_sid_table (BusConfigParser *parser)
{
DBusHashTable *table;
_dbus_assert (parser->service_sid_table != NULL); /* can only steal once */
table = parser->service_sid_table;
parser->service_sid_table = NULL;
return table;
}
#ifdef DBUS_BUILD_TESTS
#include <stdio.h>
@ -2494,6 +2615,8 @@ config_parsers_equal (const BusConfigParser *a,
/* FIXME: compare policy */
/* FIXME: compare service selinux ID table */
if (! limits_equal (&a->limits, &b->limits))
return FALSE;

View file

@ -29,6 +29,7 @@
#include <dbus/dbus.h>
#include <dbus/dbus-string.h>
#include <dbus/dbus-list.h>
#include <dbus/dbus-hash.h>
#include "bus.h"
/* Whatever XML library we're using just pushes data into this API */
@ -70,6 +71,8 @@ BusPolicy* bus_config_parser_steal_policy (BusConfigParser *parser);
void bus_config_parser_get_limits (BusConfigParser *parser,
BusLimits *limits);
DBusHashTable* bus_config_parser_steal_service_sid_table (BusConfigParser *parser);
/* Loader functions (backended off one of the XML parsers). Returns a
* finished ConfigParser.
*/

View file

@ -27,6 +27,7 @@
#include "utils.h"
#include "signals.h"
#include "expirelist.h"
#include "selinux.h"
#include <dbus/dbus-list.h>
#include <dbus/dbus-hash.h>
#include <dbus/dbus-timeout.h>
@ -75,6 +76,8 @@ typedef struct
DBusPreallocatedSend *oom_preallocated;
BusClientPolicy *policy;
BusSELinuxID *selinux_id;
long connection_tv_sec; /**< Time when we connected (seconds component) */
long connection_tv_usec; /**< Time when we connected (microsec component) */
int stamp; /**< connections->stamp last time we were traversed */
@ -401,6 +404,9 @@ free_connection_data (void *data)
if (d->policy)
bus_client_policy_unref (d->policy);
if (d->selinux_id)
bus_selinux_id_unref (d->selinux_id);
dbus_free (d->name);
@ -539,6 +545,7 @@ bus_connections_setup_connection (BusConnections *connections,
{
BusConnectionData *d;
dbus_bool_t retval;
DBusError error;
d = dbus_new0 (BusConnectionData, 1);
@ -562,6 +569,20 @@ bus_connections_setup_connection (BusConnections *connections,
}
retval = FALSE;
dbus_error_init (&error);
d->selinux_id = bus_selinux_init_connection_id (connection,
&error);
if (dbus_error_is_set (&error))
{
/* This is a bit bogus because we pretend all errors
* are OOM; this is done because we know that in bus.c
* an OOM error disconnects the connection, which is
* the same thing we want on any other error.
*/
dbus_error_free (&error);
goto out;
}
if (!dbus_connection_set_watch_functions (connection,
add_connection_watch,
@ -639,7 +660,11 @@ bus_connections_setup_connection (BusConnections *connections,
out:
if (!retval)
{
{
if (d->selinux_id)
bus_selinux_id_unref (d->selinux_id);
d->selinux_id = NULL;
if (!dbus_connection_set_watch_functions (connection,
NULL, NULL, NULL,
connection,
@ -1008,6 +1033,18 @@ bus_connection_get_matchmaker (DBusConnection *connection)
return bus_context_get_matchmaker (d->connections->context);
}
BusSELinuxID*
bus_connection_get_selinux_id (DBusConnection *connection)
{
BusConnectionData *d;
d = BUS_CONNECTION_DATA (connection);
_dbus_assert (d != NULL);
return d->selinux_id;
}
/**
* Checks whether the connection is registered with the message bus.
*

View file

@ -1,7 +1,7 @@
/* -*- mode: C; c-file-style: "gnu" -*- */
/* connection.h Client connections
*
* Copyright (C) 2003 Red Hat, Inc.
* Copyright (C) 2003, 2004 Red Hat, Inc.
*
* Licensed under the Academic Free License version 2.0
*
@ -50,6 +50,7 @@ BusConnections* bus_connection_get_connections (DBusConnection
BusRegistry* bus_connection_get_registry (DBusConnection *connection);
BusActivation* bus_connection_get_activation (DBusConnection *connection);
BusMatchmaker* bus_connection_get_matchmaker (DBusConnection *connection);
BusSELinuxID* bus_connection_get_selinux_id (DBusConnection *connection);
dbus_bool_t bus_connections_check_limits (BusConnections *connections,
DBusConnection *requesting_completion,
DBusError *error);

View file

@ -463,6 +463,110 @@ received" are evaluated separately.
Be careful with send_interface/receive_interface, because the
interface field in messages is optional.
.TP
.I "<selinux>"
.PP
The <selinux> element contains settings related to Security Enhanced Linux.
More details below.
.TP
.I "<associate>"
.PP
An <associate> element appears below an <selinux> element and
creates a mapping. Right now only one kind of association is possible:
.nf
<associate own="org.freedesktop.Foobar" context="foo_t"/>
.fi
.PP
This means that if a connection asks to own the service
"org.freedesktop.Foobar" then the source context will be the context
of the connection and the target context will be "foo_t" - see the
short discussion of SELinux below.
.PP
Note, the context here is the target context when acquiring a service,
NOT the context of the connection owning the service.
.PP
There's currently no way to set a default for owning any service, if
we add this syntax it will look like:
.nf
<associate own="*" context="foo_t"/>
.fi
If you find a reason this is useful, let the developers know.
Right now the default will be the security context of the bus itself.
.PP
If two <associate> elements specify the same service name,
the element appearing later in the configuration file will
be used.
.SH SELinux
.PP
See http://www.nsa.gov/selinux/ for full details on SELinux. Some useful excerpts:
.IP "" 8
Every subject (process) and object (e.g. file, socket, IPC object,
etc) in the system is assigned a collection of security attributes,
known as a security context. A security context contains all of the
security attributes associated with a particular subject or object
that are relevant to the security policy.
.IP "" 8
In order to better encapsulate security contexts and to provide
greater efficiency, the policy enforcement code of SELinux typically
handles security identifiers (SIDs) rather than security contexts. A
SID is an integer that is mapped by the security server to a security
context at runtime.
.IP "" 8
When a security decision is required, the policy enforcement code
passes a pair of SIDs (typically the SID of a subject and the SID of
an object, but sometimes a pair of subject SIDs or a pair of object
SIDs), and an object security class to the security server. The object
security class indicates the kind of object, e.g. a process, a regular
file, a directory, a TCP socket, etc.
.IP "" 8
Access decisions specify whether or not a permission is granted for a
given pair of SIDs and class. Each object class has a set of
associated permissions defined to control operations on objects with
that class.
.PP
D-BUS performs SELinux security checks in two places.
.PP
First, any time a message is routed from one connection to another
connection, the bus daemon will check permissions with the security context of
the first connection as source, security context of the second connection
as target, object class "dbus" and requested permission "send_msg".
.PP
If a security context is not available for a connection
(impossible when using UNIX domain sockets), then the target
context used is the context of the bus daemon itself.
There is currently no way to change this default, because we're
assuming that only UNIX domain sockets will be used to
connect to the systemwide bus. If this changes, we'll
probably add a way to set the default connection context.
.PP
Second, any time a connection asks to own a service,
the bus daemon will check permissions with the security
context of the connection as source, the security context specified
for the service name with an <associate> element as target, object
class "dbus" and requested permission "acquire_svc".
.PP
If the service name has no security context associated in the
configuration file, the security context of the bus daemon
itself will be used.
.SH AUTHOR
See http://www.freedesktop.org/software/dbus/doc/AUTHORS

View file

@ -28,6 +28,7 @@
#include <string.h>
#include <signal.h>
#include <errno.h>
#include "selinux.h"
static BusContext *context;
@ -371,7 +372,13 @@ main (int argc, char **argv)
print_pid_fd = val;
}
}
if (!bus_selinux_init ())
{
_dbus_warn ("SELinux initialization failed\n");
exit (1);
}
dbus_error_init (&error);
context = bus_context_new (&config_file, force_fork,
print_addr_fd, print_pid_fd,
@ -395,6 +402,7 @@ main (int argc, char **argv)
bus_context_shutdown (context);
bus_context_unref (context);
bus_selinux_shutdown ();
return 0;
}

View file

@ -177,7 +177,7 @@ bus_policy_new (void)
free_rule_list_func);
if (policy->rules_by_gid == NULL)
goto failed;
return policy;
failed:
@ -594,9 +594,10 @@ dbus_bool_t
bus_policy_merge (BusPolicy *policy,
BusPolicy *to_absorb)
{
/* Not properly atomic, but as used for configuration files
* we don't rely on it.
*/
/* FIXME Not properly atomic, but as used for configuration files we
* don't rely on it quite so much.
*/
if (!append_copy_of_policy_list (&policy->default_rules,
&to_absorb->default_rules))
return FALSE;
@ -670,7 +671,7 @@ bus_client_policy_unref (BusClientPolicy *policy)
NULL);
_dbus_list_clear (&policy->rules);
dbus_free (policy);
}
}

658
bus/selinux.c Normal file
View file

@ -0,0 +1,658 @@
/* selinux.c SELinux security checks for D-BUS
*
* Author: Matthew Rickard <mjricka@epoch.ncsc.mil>
*
* Licensed under the Academic Free License version 2.0
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
*/
#include <dbus/dbus-internals.h>
#include <dbus/dbus-string.h>
#include "selinux.h"
#include "services.h"
#include "policy.h"
#include "config-parser.h"
#ifdef HAVE_SELINUX
#include <errno.h>
#include <syslog.h>
#include <selinux/selinux.h>
#include <selinux/avc.h>
#include <selinux/av_permissions.h>
#include <selinux/flask.h>
#include <stdarg.h>
#endif /* HAVE_SELINUX */
#define BUS_SID_FROM_SELINUX(sid) ((BusSELinuxID*) (sid))
#define SELINUX_SID_FROM_BUS(sid) ((security_id_t) (sid))
#ifdef HAVE_SELINUX
/* Store the value telling us if SELinux is enabled in the kernel. */
static dbus_bool_t selinux_enabled = FALSE;
/* Store an avc_entry_ref to speed AVC decisions. */
static struct avc_entry_ref aeref;
static security_id_t bus_sid = SECSID_WILD;
#endif /* HAVE_SELINUX */
/**
* Log callback to log denial messages from the AVC.
* This is used in avc_init. Logs to both standard
* error and syslogd.
*
* @param fmt the format string
* @param variable argument list
*/
#ifdef HAVE_SELINUX
static void
log_callback (const char *fmt, ...)
{
va_list ap;
va_start(ap, fmt);
vsyslog (LOG_INFO, fmt, ap);
va_end(ap);
}
#endif /* HAVE_SELINUX */
/**
* Initialize the user space access vector cache (AVC) for D-BUS and set up
* logging callbacks.
*/
dbus_bool_t
bus_selinux_init (void)
{
#ifdef HAVE_SELINUX
struct avc_log_callback log_cb = {(void*)log_callback, NULL};
int r;
char *bus_context;
_dbus_assert (bus_sid == SECSID_WILD);
/* Determine if we are running an SELinux kernel. */
r = is_selinux_enabled ();
if (r < 0)
{
_dbus_warn ("Could not tell if SELinux is enabled: %s\n",
_dbus_strerror (errno));
return FALSE;
}
selinux_enabled = r != 0;
if (!selinux_enabled)
{
_dbus_verbose ("SELinux not enabled in this kernel.\n");
return TRUE;
}
_dbus_verbose ("SELinux is enabled in this kernel.\n");
avc_entry_ref_init (&aeref);
if (avc_init ("avc", NULL, &log_cb, NULL, NULL) < 0)
{
_dbus_warn ("Failed to start Access Vector Cache (AVC).\n");
return FALSE;
}
else
{
openlog ("dbus", LOG_PERROR, LOG_USER);
_dbus_verbose ("Access Vector Cache (AVC) started.\n");
}
bus_context = NULL;
bus_sid = SECSID_WILD;
if (getcon (&bus_context) < 0)
{
_dbus_verbose ("Error getting context of bus: %s\n",
_dbus_strerror (errno));
return FALSE;
}
if (avc_context_to_sid (bus_context, &bus_sid) < 0)
{
_dbus_verbose ("Error getting SID from bus context: %s\n",
_dbus_strerror (errno));
freecon (bus_context);
return FALSE;
}
freecon (bus_context);
return TRUE;
#else
return TRUE;
#endif /* HAVE_SELINUX */
}
/**
* Decrement SID reference count.
*
* @param sid the SID to decrement
*/
void
bus_selinux_id_unref (BusSELinuxID *sid)
{
#ifdef HAVE_SELINUX
if (!selinux_enabled)
return;
_dbus_assert (sid != NULL);
sidput (SELINUX_SID_FROM_BUS (sid));
#endif /* HAVE_SELINUX */
}
void
bus_selinux_id_ref (BusSELinuxID *sid)
{
#ifdef HAVE_SELINUX
if (!selinux_enabled)
return;
_dbus_assert (sid != NULL);
sidget (SELINUX_SID_FROM_BUS (sid));
#endif /* HAVE_SELINUX */
}
/**
* Determine if the SELinux security policy allows the given sender
* security context to go to the given recipient security context.
* This function determines if the requested permissions are to be
* granted from the connection to the message bus or to another
* optionally supplied security identifier (e.g. for a service
* context). Currently these permissions are either send_msg or
* acquire_svc in the dbus class.
*
* @param sender_sid source security context
* @param override_sid is the target security context. If SECSID_WILD this will
* use the context of the bus itself (e.g. the default).
* @param target_class is the target security class.
* @param requested is the requested permissions.
* @returns #TRUE if security policy allows the send.
*/
#ifdef HAVE_SELINUX
static dbus_bool_t
bus_selinux_check (BusSELinuxID *sender_sid,
BusSELinuxID *override_sid,
security_class_t target_class,
access_vector_t requested)
{
if (!selinux_enabled)
return TRUE;
/* Make the security check. AVC checks enforcing mode here as well. */
if (avc_has_perm (SELINUX_SID_FROM_BUS (sender_sid),
override_sid ?
SELINUX_SID_FROM_BUS (override_sid) :
SELINUX_SID_FROM_BUS (bus_sid),
target_class, requested, &aeref, NULL) < 0)
{
_dbus_verbose ("SELinux denying due to security policy.\n");
return FALSE;
}
else
return TRUE;
}
#endif /* HAVE_SELINUX */
/**
* Returns true if the given connection can acquire a service,
* assuming the given security ID is needed for that service.
*
* @param connection connection that wants to own the service
* @param service_sid the SID of the service from the table
* @returns #TRUE if acquire is permitted.
*/
dbus_bool_t
bus_selinux_allows_acquire_service (DBusConnection *connection,
BusSELinuxID *service_sid)
{
#ifdef HAVE_SELINUX
BusSELinuxID *connection_sid;
if (!selinux_enabled)
return TRUE;
connection_sid = bus_connection_get_selinux_id (connection);
return bus_selinux_check (connection_sid,
service_sid,
SECCLASS_DBUS,
DBUS__ACQUIRE_SVC);
#else
return TRUE;
#endif /* HAVE_SELINUX */
}
/**
* Check if SELinux security controls allow the message to be sent to a
* particular connection based on the security context of the sender and
* that of the receiver. The destination connection need not be the
* addressed recipient, it could be an "eavesdropper"
*
* @param sender the sender of the message.
* @param proposed_recipient the connection the message is to be sent to.
* @returns whether to allow the send
*/
dbus_bool_t
bus_selinux_allows_send (DBusConnection *sender,
DBusConnection *proposed_recipient)
{
#ifdef HAVE_SELINUX
BusSELinuxID *recipient_sid;
BusSELinuxID *sender_sid;
if (!selinux_enabled)
return TRUE;
sender_sid = bus_connection_get_selinux_id (sender);
/* A NULL proposed_recipient means the bus itself. */
if (proposed_recipient)
recipient_sid = bus_connection_get_selinux_id (proposed_recipient);
else
recipient_sid = BUS_SID_FROM_SELINUX (bus_sid);
return bus_selinux_check (sender_sid, recipient_sid,
SECCLASS_DBUS, DBUS__SEND_MSG);
#else
return TRUE;
#endif /* HAVE_SELINUX */
}
/**
* Gets the security context of a connection to the bus. It is up to
* the caller to freecon() when they are done.
*
* @param connection the connection to get the context of.
* @param con the location to store the security context.
* @returns #TRUE if context is successfully obtained.
*/
#ifdef HAVE_SELINUX
static dbus_bool_t
bus_connection_read_selinux_context (DBusConnection *connection,
char **con)
{
int fd;
if (!selinux_enabled)
return FALSE;
_dbus_assert (connection != NULL);
if (!dbus_connection_get_unix_fd (connection, &fd))
{
_dbus_verbose ("Failed to get file descriptor of socket.\n");
return FALSE;
}
if (getpeercon (fd, con) < 0)
{
_dbus_verbose ("Error getting context of socket peer: %s\n",
_dbus_strerror (errno));
return FALSE;
}
_dbus_verbose ("Successfully read connection context.\n");
return TRUE;
}
#endif /* HAVE_SELINUX */
/**
* Read the SELinux ID from the connection.
*
* @param connection the connection to read from
* @returns the SID if successfully determined, #NULL otherwise.
*/
BusSELinuxID*
bus_selinux_init_connection_id (DBusConnection *connection,
DBusError *error)
{
#ifdef HAVE_SELINUX
char *con;
security_id_t sid;
if (!selinux_enabled)
return NULL;
if (!bus_connection_read_selinux_context (connection, &con))
{
dbus_set_error (error, DBUS_ERROR_FAILED,
"Failed to read an SELinux context from connection");
_dbus_verbose ("Error getting peer context.\n");
return NULL;
}
_dbus_verbose ("Converting context to SID to store on connection\n");
if (avc_context_to_sid (con, &sid) < 0)
{
if (errno == ENOMEM)
BUS_SET_OOM (error);
else
dbus_set_error (error, DBUS_ERROR_FAILED,
"Error getting SID from context: %s\n",
_dbus_strerror (errno));
_dbus_warn ("Error getting SID from context: %s\n",
_dbus_strerror (errno));
freecon (con);
return NULL;
}
freecon (con);
return BUS_SID_FROM_SELINUX (sid);
#else
return NULL;
#endif /* HAVE_SELINUX */
}
/* Function for freeing hash table data. These SIDs
* should no longer be referenced.
*/
static void
bus_selinux_id_table_free_value (BusSELinuxID *sid)
{
#ifdef HAVE_SELINUX
/* NULL sometimes due to how DBusHashTable works */
if (sid)
bus_selinux_id_unref (sid);
#endif /* HAVE_SELINUX */
}
/**
* Creates a new table mapping service names to security ID.
* A security ID is a "compiled" security context, a security
* context is just a string.
*
* @returns the new table or #NULL if no memory
*/
DBusHashTable*
bus_selinux_id_table_new (void)
{
return _dbus_hash_table_new (DBUS_HASH_STRING,
(DBusFreeFunction) dbus_free,
(DBusFreeFunction) bus_selinux_id_table_free_value);
}
/**
* Hashes a service name and service context into the service SID
* table as a string and a SID.
*
* @param service_name is the name of the service.
* @param service_context is the context of the service.
* @param service_table is the table to hash them into.
* @return #FALSE if not enough memory
*/
dbus_bool_t
bus_selinux_id_table_insert (DBusHashTable *service_table,
const char *service_name,
const char *service_context)
{
#ifdef HAVE_SELINUX
dbus_bool_t retval;
security_id_t sid;
char *key;
if (!selinux_enabled)
return TRUE;
sid = SECSID_WILD;
retval = FALSE;
key = _dbus_strdup (service_name);
if (key == NULL)
return retval;
if (avc_context_to_sid (service_context, &sid) < 0)
{
_dbus_assert (errno == ENOMEM);
goto out;
}
if (!_dbus_hash_table_insert_string (service_table,
key,
BUS_SID_FROM_SELINUX (sid)))
goto out;
_dbus_verbose ("Parsed \tservice: %s \n\t\tcontext: %s\n",
key,
sid->ctx);
/* These are owned by the hash, so clear them to avoid unref */
key = NULL;
sid = SECSID_WILD;
retval = TRUE;
out:
if (sid != SECSID_WILD)
sidput (sid);
if (key)
dbus_free (key);
return retval;
#else
return TRUE;
#endif /* HAVE_SELINUX */
}
/**
* Find the security identifier associated with a particular service
* name. Return a pointer to this SID, or #NULL/SECSID_WILD if the
* service is not found in the hash table. This should be nearly a
* constant time operation. If SELinux support is not available,
* always return NULL.
*
* @todo This should return a const security_id_t since we don't
* want the caller to mess with it.
*
* @param service_table the hash table to check for service name.
* @param service_name the name of the service to look for.
* @returns the SELinux ID associated with the service
*/
BusSELinuxID*
bus_selinux_id_table_lookup (DBusHashTable *service_table,
const DBusString *service_name)
{
#ifdef HAVE_SELINUX
security_id_t sid;
sid = SECSID_WILD; /* default context */
if (!selinux_enabled)
return NULL;
_dbus_verbose ("Looking up service SID for %s\n",
_dbus_string_get_const_data (service_name));
sid = _dbus_hash_table_lookup_string (service_table,
_dbus_string_get_const_data (service_name));
if (sid == SECSID_WILD)
_dbus_verbose ("Service %s not found\n",
_dbus_string_get_const_data (service_name));
else
_dbus_verbose ("Service %s found\n",
_dbus_string_get_const_data (service_name));
return BUS_SID_FROM_SELINUX (sid);
#endif /* HAVE_SELINUX */
return NULL;
}
#ifdef HAVE_SELINUX
static dbus_bool_t
bus_selinux_id_table_copy_over (DBusHashTable *dest,
DBusHashTable *override)
{
const char *key;
char *key_copy;
BusSELinuxID *sid;
DBusHashIter iter;
_dbus_hash_iter_init (override, &iter);
while (_dbus_hash_iter_next (&iter))
{
key = _dbus_hash_iter_get_string_key (&iter);
sid = _dbus_hash_iter_get_value (&iter);
key_copy = _dbus_strdup (key);
if (key_copy == NULL)
return FALSE;
if (!_dbus_hash_table_insert_string (dest,
key_copy,
sid))
{
dbus_free (key_copy);
return FALSE;
}
bus_selinux_id_ref (sid);
}
return TRUE;
}
#endif /* HAVE_SELINUX */
/**
* Creates the union of the two tables (each table maps a service
* name to a security ID). In case of the same service name in
* both tables, the security ID from "override" will be used.
*
* @param base the base table
* @param override the table that takes precedence in the merge
* @returns the new table, or #NULL if out of memory
*/
DBusHashTable*
bus_selinux_id_table_union (DBusHashTable *base,
DBusHashTable *override)
{
DBusHashTable *combined_table;
combined_table = bus_selinux_id_table_new ();
if (combined_table == NULL)
return NULL;
#ifdef HAVE_SELINUX
if (!selinux_enabled)
return combined_table;
if (!bus_selinux_id_table_copy_over (combined_table, base))
{
_dbus_hash_table_unref (combined_table);
return NULL;
}
if (!bus_selinux_id_table_copy_over (combined_table, override))
{
_dbus_hash_table_unref (combined_table);
return NULL;
}
#endif /* HAVE_SELINUX */
return combined_table;
}
/**
* For debugging: Print out the current hash table of service SIDs.
*/
void
bus_selinux_id_table_print (DBusHashTable *service_table)
{
#ifdef DBUS_ENABLE_VERBOSE_MODE
#ifdef HAVE_SELINUX
DBusHashIter iter;
if (!selinux_enabled)
return;
_dbus_verbose ("Service SID Table:\n");
_dbus_hash_iter_init (service_table, &iter);
while (_dbus_hash_iter_next (&iter))
{
const char *key = _dbus_hash_iter_get_string_key (&iter);
security_id_t sid = _dbus_hash_iter_get_value (&iter);
_dbus_verbose ("The key is %s\n", key);
_dbus_verbose ("The context is %s\n", sid->ctx);
_dbus_verbose ("The refcount is %d\n", sid->refcnt);
}
#endif /* HAVE_SELINUX */
#endif /* DBUS_ENABLE_VERBOSE_MODE */
}
#ifdef DBUS_ENABLE_VERBOSE_MODE
#ifdef HAVE_SELINUX
/**
* Print out some AVC statistics.
*/
static void
bus_avc_print_stats (void)
{
struct avc_cache_stats cstats;
if (!selinux_enabled)
return;
_dbus_verbose ("AVC Statistics:\n");
avc_cache_stats (&cstats);
avc_av_stats ();
_dbus_verbose ("AVC Cache Statistics:\n");
_dbus_verbose ("Entry lookups: %d\n", cstats.entry_lookups);
_dbus_verbose ("Entry hits: %d\n", cstats.entry_hits);
_dbus_verbose ("Entry misses %d\n", cstats.entry_misses);
_dbus_verbose ("Entry discards: %d\n", cstats.entry_discards);
_dbus_verbose ("CAV lookups: %d\n", cstats.cav_lookups);
_dbus_verbose ("CAV hits: %d\n", cstats.cav_hits);
_dbus_verbose ("CAV probes: %d\n", cstats.cav_probes);
_dbus_verbose ("CAV misses: %d\n", cstats.cav_misses);
}
#endif /* HAVE_SELINUX */
#endif /* DBUS_ENABLE_VERBOSE_MODE */
/**
* Destroy the AVC before we terminate.
*/
void
bus_selinux_shutdown (void)
{
#ifdef HAVE_SELINUX
if (!selinux_enabled)
return;
sidput (bus_sid);
bus_sid = SECSID_WILD;
#ifdef DBUS_ENABLE_VERBOSE_MODE
bus_avc_print_stats ();
#endif /* DBUS_ENABLE_VERBOSE_MODE */
avc_destroy ();
#endif /* HAVE_SELINUX */
}

60
bus/selinux.h Normal file
View file

@ -0,0 +1,60 @@
/* selinux.h SELinux security check headers for D-BUS
*
* Author: Matthew Rickard <mjricka@epoch.ncsc.mil>
*
* Licensed under the Academic Free License version 2.0
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
*/
#ifndef BUS_SELINUX_H
#define BUS_SELINUX_H
#include <dbus/dbus-hash.h>
#include <dbus/dbus-connection.h>
#include "services.h"
dbus_bool_t bus_selinux_init (void);
void bus_selinux_shutdown (void);
void bus_selinux_id_ref (BusSELinuxID *sid);
void bus_selinux_id_unref (BusSELinuxID *sid);
DBusHashTable* bus_selinux_id_table_new (void);
BusSELinuxID* bus_selinux_id_table_lookup (DBusHashTable *service_table,
const DBusString *service_name);
dbus_bool_t bus_selinux_id_table_insert (DBusHashTable *service_table,
const char *service_name,
const char *service_context);
DBusHashTable* bus_selinux_id_table_union (DBusHashTable *base,
DBusHashTable *override);
void bus_selinux_id_table_print (DBusHashTable *service_table);
dbus_bool_t bus_selinux_allows_acquire_service (DBusConnection *connection,
BusSELinuxID *service_sid);
dbus_bool_t bus_selinux_allows_send (DBusConnection *sender,
DBusConnection *proposed_recipient);
BusSELinuxID* bus_selinux_init_connection_id (DBusConnection *connection,
DBusError *error);
#endif /* BUS_SELINUX_H */

View file

@ -31,6 +31,8 @@
#include "utils.h"
#include "activation.h"
#include "policy.h"
#include "bus.h"
#include "selinux.h"
struct BusService
{
@ -51,6 +53,8 @@ struct BusRegistry
DBusHashTable *service_hash;
DBusMemPool *service_pool;
DBusHashTable *service_sid_table;
};
BusRegistry*
@ -75,6 +79,8 @@ bus_registry_new (BusContext *context)
if (registry->service_pool == NULL)
goto failed;
registry->service_sid_table = NULL;
return registry;
failed:
@ -103,7 +109,9 @@ bus_registry_unref (BusRegistry *registry)
_dbus_hash_table_unref (registry->service_hash);
if (registry->service_pool)
_dbus_mem_pool_free (registry->service_pool);
if (registry->service_sid_table)
_dbus_hash_table_unref (registry->service_sid_table);
dbus_free (registry);
}
}
@ -263,6 +271,7 @@ bus_registry_acquire_service (BusRegistry *registry,
BusClientPolicy *policy;
BusService *service;
BusActivation *activation;
BusSELinuxID *sid;
retval = FALSE;
@ -292,6 +301,24 @@ bus_registry_acquire_service (BusRegistry *registry,
policy = bus_connection_get_policy (connection);
_dbus_assert (policy != NULL);
/* Note that if sid is #NULL then the bus's own context gets used
* in bus_connection_selinux_allows_acquire_service()
*/
sid = bus_selinux_id_table_lookup (registry->service_sid_table,
service_name);
if (!bus_selinux_allows_acquire_service (connection, sid))
{
dbus_set_error (error, DBUS_ERROR_ACCESS_DENIED,
"Connection \"%s\" is not allowed to own the service \"%s\" due "
"to SELinux policy",
bus_connection_is_active (connection) ?
bus_connection_get_name (connection) :
"(inactive)",
service_name);
goto out;
}
if (!bus_client_policy_check_can_own (policy, connection,
service_name))
{
@ -387,6 +414,19 @@ bus_registry_acquire_service (BusRegistry *registry,
return retval;
}
void
bus_registry_set_service_sid_table (BusRegistry *registry,
DBusHashTable *table)
{
_dbus_assert (registry->service_sid_table != table);
if (registry->service_sid_table)
_dbus_hash_table_unref (registry->service_sid_table);
registry->service_sid_table = table;
_dbus_hash_table_ref (table);
}
static void
bus_service_unlink_owner (BusService *service,
DBusConnection *owner)

View file

@ -26,6 +26,7 @@
#include <dbus/dbus.h>
#include <dbus/dbus-string.h>
#include <dbus/dbus-hash.h>
#include "connection.h"
#include "bus.h"
@ -55,6 +56,8 @@ dbus_bool_t bus_registry_acquire_service (BusRegistry *registry
dbus_uint32_t *result,
BusTransaction *transaction,
DBusError *error);
void bus_registry_set_service_sid_table (BusRegistry *registry,
DBusHashTable *table);
BusService* bus_service_ref (BusService *service);
void bus_service_unref (BusService *service);

View file

@ -27,6 +27,7 @@
#include <dbus/dbus-string.h>
#include <dbus/dbus-sysdeps.h>
#include <dbus/dbus-internals.h>
#include "selinux.h"
#ifdef DBUS_BUILD_TESTS
static void
@ -69,6 +70,9 @@ main (int argc, char **argv)
return 1;
}
if (!bus_selinux_init ())
die ("could not init selinux support");
_dbus_string_init_const (&test_data_dir, dir);
#if 0
@ -119,6 +123,8 @@ main (int argc, char **argv)
check_memleaks (argv[0]);
printf ("%s: Success\n", argv[0]);
bus_selinux_shutdown ();
return 0;
#else /* DBUS_BUILD_TESTS */

View file

@ -38,7 +38,7 @@ AC_ARG_ENABLE(gcj, [ --enable-gcj build gcj bindings],ena
AC_ARG_ENABLE(mono, [ --enable-mono build mono bindings],enable_mono=$enableval,enable_mono=auto)
AC_ARG_ENABLE(mono_docs, [ --enable-mono-docs build mono docs],enable_mono_docs=$enableval,enable_mono_docs=auto)
AC_ARG_ENABLE(python, [ --enable-python build python bindings],enable_python=$enableval,enable_python=auto)
AC_ARG_ENABLE(selinux, [ --enable-selinux build with SELinux support],enable_selinux=$enableval,enable_selinux=auto)
AC_ARG_WITH(xml, [ --with-xml=[libxml/expat] XML library to use])
AC_ARG_WITH(init-scripts, [ --with-init-scripts=[redhat] Style of init scripts to install])
@ -690,6 +690,40 @@ if $dbus_use_libxml; then
XML_CFLAGS=$LIBXML_CFLAGS
fi
# SELinux detection
if test x$enable_selinux = xno ; then
have_selinux=no;
else
# See if we have SELinux library
AC_CHECK_LIB(selinux, is_selinux_enabled,
have_selinux=yes, have_selinux=no)
# see if we have the SELinux header with the new D-BUS stuff in it
if test x$have_selinux = xyes ; then
AC_EGREP_HEADER(DBUS__ACQUIRE_SVC, av_permissions.h,
have_selinux=yes, have_selinux=no)
fi
if test x$enable_selinux = xauto ; then
if test x$have_selinux = xno ; then
AC_MSG_WARN([Sufficiently new SELinux library not found])
fi
else
if test x$have_selinux = xno ; then
AC_MSG_ERROR([SElinux explicitly required, and SELinux library not found])
fi
fi
fi
AM_CONDITIONAL(HAVE_SELINUX, test x$have_selinux = xyes)
if test x$have_selinux = xyes ; then
SELINUX_LIBS=-lselinux
AC_DEFINE(HAVE_SELINUX,1,[SELinux support])
else
SELINUX_LIBS=
fi
#### Set up final flags
DBUS_CLIENT_CFLAGS=
DBUS_CLIENT_LIBS=
@ -697,7 +731,7 @@ AC_SUBST(DBUS_CLIENT_CFLAGS)
AC_SUBST(DBUS_CLIENT_LIBS)
DBUS_BUS_CFLAGS=$XML_CFLAGS
DBUS_BUS_LIBS=$XML_LIBS
DBUS_BUS_LIBS="$XML_LIBS $SELINUX_LIBS"
AC_SUBST(DBUS_BUS_CFLAGS)
AC_SUBST(DBUS_BUS_LIBS)
@ -1076,7 +1110,6 @@ fi
AM_CONDITIONAL(HAVE_PYTHON, test x$have_python = xyes)
AC_OUTPUT([
Doxyfile
dbus/dbus-arch-deps.h
@ -1167,6 +1200,7 @@ echo "
Building Qt bindings: ${have_qt}
Building GLib bindings: ${have_glib}
Building Python bindings: ${have_python}
Building SELinux support: ${have_selinux}
Building Mono bindings: ${enable_mono}
Building Mono docs: ${enable_mono_docs}
Building GTK+ tools: ${have_gtk}

View file

@ -2952,6 +2952,37 @@ dbus_connection_set_dispatch_status_function (DBusConnection *connec
(*old_free_data) (old_data);
}
/**
* Get the UNIX file descriptor of the connection, if any. This can
* be used for SELinux access control checks with getpeercon() for
* example. DO NOT read or write to the file descriptor, or try to
* select() on it; use DBusWatch for main loop integration. Not all
* connections will have a file descriptor. So for adding descriptors
* to the main loop, use dbus_watch_get_fd() and so forth.
*
* @param connection the connection
* @param fd return location for the file descriptor.
* @returns #TRUE if fd is successfully obtained.
*/
dbus_bool_t
dbus_connection_get_unix_fd (DBusConnection *connection,
int *fd)
{
dbus_bool_t retval;
_dbus_return_val_if_fail (connection != NULL, FALSE);
_dbus_return_val_if_fail (connection->transport != NULL, FALSE);
CONNECTION_LOCK (connection);
retval = _dbus_transport_get_unix_fd (connection->transport,
fd);
CONNECTION_UNLOCK (connection);
return retval;
}
/**
* Gets the UNIX user ID of the connection if any.
* Returns #TRUE if the uid is filled in.

View file

@ -242,6 +242,9 @@ dbus_bool_t dbus_connection_list_registered (DBusConnection
const char *parent_path,
char ***child_entries);
dbus_bool_t dbus_connection_get_unix_fd (DBusConnection *connection,
int *fd);
DBUS_END_DECLS;
#endif /* DBUS_CONNECTION_H */

View file

@ -71,6 +71,10 @@ struct DBusTransportVTable
void (* live_messages_changed) (DBusTransport *transport);
/**< Outstanding messages counter changed */
dbus_bool_t (* get_unix_fd) (DBusTransport *transport,
int *fd_p);
/**< Get UNIX file descriptor */
};
/**
@ -102,6 +106,7 @@ struct DBusTransport
DBusAllowUnixUserFunction unix_user_function; /**< Function for checking whether a user is authorized. */
void *unix_user_data; /**< Data for unix_user_function */
DBusFreeFunction free_unix_user_data; /**< Function to free unix_user_data */
unsigned int disconnected : 1; /**< #TRUE if we are disconnected. */

View file

@ -948,6 +948,18 @@ unix_live_messages_changed (DBusTransport *transport)
check_read_watch (transport);
}
static dbus_bool_t
unix_get_unix_fd (DBusTransport *transport,
int *fd_p)
{
DBusTransportUnix *unix_transport = (DBusTransportUnix*) transport;
*fd_p = unix_transport->fd;
return TRUE;
}
static DBusTransportVTable unix_vtable = {
unix_finalize,
unix_handle_watch,
@ -955,7 +967,8 @@ static DBusTransportVTable unix_vtable = {
unix_connection_set,
unix_messages_pending,
unix_do_iteration,
unix_live_messages_changed
unix_live_messages_changed,
unix_get_unix_fd
};
/**

View file

@ -636,6 +636,35 @@ _dbus_transport_messages_pending (DBusTransport *transport,
_dbus_transport_unref (transport);
}
/**
* Get the UNIX file descriptor, if any.
*
* @param transport the transport
* @param fd_p pointer to fill in with the descriptor
* @returns #TRUE if a descriptor was available
*/
dbus_bool_t
_dbus_transport_get_unix_fd (DBusTransport *transport,
int *fd_p)
{
dbus_bool_t retval;
if (transport->vtable->get_unix_fd == NULL)
return FALSE;
if (transport->disconnected)
return FALSE;
_dbus_transport_ref (transport);
retval = (* transport->vtable->get_unix_fd) (transport,
fd_p);
_dbus_transport_unref (transport);
return retval;
}
/**
* Performs a single poll()/select() on the transport's file
* descriptors and then reads/writes data as appropriate,

View file

@ -59,6 +59,9 @@ void _dbus_transport_set_max_received_size (DBusTransport
long _dbus_transport_get_max_received_size (DBusTransport *transport);
dbus_bool_t _dbus_transport_get_unix_user (DBusTransport *transport,
unsigned long *uid);
dbus_bool_t _dbus_transport_get_unix_fd (DBusTransport *transport,
int *fd_p);
dbus_bool_t _dbus_transport_get_unix_process_id (DBusTransport *transport,
unsigned long *pid);
void _dbus_transport_set_unix_user_function (DBusTransport *transport,

View file

@ -21,5 +21,12 @@
<limit name="max_connections_per_user">64</limit>
<limit name="max_pending_activations">64</limit>
<limit name="max_services_per_connection">256</limit>
<selinux>
<associate own="org.freedesktop.FrobationaryMeasures"
context="my_selinux_context_t"/>
<associate own="org.freedesktop.BlahBlahBlah"
context="foo_t"/>
</selinux>
</busconfig>