2003-04-01 Havoc Pennington <hp@pobox.com>

* dbus/dbus-server.c (dbus_server_set_auth_mechanisms): new
	function

	* dbus/dbus-auth.c (_dbus_auth_set_mechanisms): new

	* dbus/dbus-internals.c (_dbus_dup_string_array): new function

	* dbus/dbus-sysdeps.c (_dbus_listen_unix_socket): chmod the
	socket 0777, and unlink any existing socket.

	* bus/bus.c (bus_context_new): change our UID/GID and fork if
	the configuration file so specifies; set up auth mechanism
	restrictions

	* bus/config-parser.c (bus_config_parser_content): add support
	for <fork> option and fill in code for <auth>

	* bus/system.conf.in: add <fork/> to default configuration,
	and limit auth mechanisms to EXTERNAL

	* doc/config-file.txt (Elements): add <fork>

	* dbus/dbus-sysdeps.c (_dbus_become_daemon): new function
	(_dbus_change_identity): new function
This commit is contained in:
Havoc Pennington 2003-04-01 05:33:01 +00:00
parent 8dfe82beb5
commit 44ed933284
19 changed files with 574 additions and 36 deletions

View file

@ -1,3 +1,30 @@
2003-04-01 Havoc Pennington <hp@pobox.com>
* dbus/dbus-server.c (dbus_server_set_auth_mechanisms): new
function
* dbus/dbus-auth.c (_dbus_auth_set_mechanisms): new
* dbus/dbus-internals.c (_dbus_dup_string_array): new function
* dbus/dbus-sysdeps.c (_dbus_listen_unix_socket): chmod the
socket 0777, and unlink any existing socket.
* bus/bus.c (bus_context_new): change our UID/GID and fork if
the configuration file so specifies; set up auth mechanism
restrictions
* bus/config-parser.c (bus_config_parser_content): add support
for <fork> option and fill in code for <auth>
* bus/system.conf.in: add <fork/> to default configuration,
and limit auth mechanisms to EXTERNAL
* doc/config-file.txt (Elements): add <fork>
* dbus/dbus-sysdeps.c (_dbus_become_daemon): new function
(_dbus_change_identity): new function
2003-03-31 Havoc Pennington <hp@redhat.com>
* dbus/dbus-sysdeps.c (_dbus_connect_unix_socket)

View file

@ -141,8 +141,15 @@ free_rule_list_func (void *data)
static dbus_bool_t
setup_server (BusContext *context,
DBusServer *server,
char **auth_mechanisms,
DBusError *error)
{
{
if (!dbus_server_set_auth_mechanisms (server, (const char**) auth_mechanisms))
{
BUS_SET_OOM (error);
return FALSE;
}
dbus_server_set_new_connection_function (server,
new_connection_callback,
context, NULL);
@ -181,6 +188,10 @@ bus_context_new (const DBusString *config_file,
BusConfigParser *parser;
DBusString full_address;
const char *service_dirs[] = { NULL, NULL };
const char *user;
char **auth_mechanisms;
DBusList **auth_mechanisms_list;
int len;
_DBUS_ASSERT_ERROR_IS_CLEAR (error);
@ -189,6 +200,7 @@ bus_context_new (const DBusString *config_file,
parser = NULL;
context = NULL;
auth_mechanisms = NULL;
parser = bus_config_load (config_file, error);
if (parser == NULL)
@ -202,6 +214,36 @@ bus_context_new (const DBusString *config_file,
}
context->refcount = 1;
/* Build an array of auth mechanisms */
auth_mechanisms_list = bus_config_parser_get_mechanisms (parser);
len = _dbus_list_get_length (auth_mechanisms_list);
if (len > 0)
{
int i;
auth_mechanisms = dbus_new0 (char*, len + 1);
if (auth_mechanisms == NULL)
goto failed;
i = 0;
link = _dbus_list_get_first_link (auth_mechanisms_list);
while (link != NULL)
{
auth_mechanisms[i] = _dbus_strdup (link->data);
if (auth_mechanisms[i] == NULL)
goto failed;
link = _dbus_list_get_next_link (auth_mechanisms_list, link);
}
}
else
{
auth_mechanisms = NULL;
}
/* Listen on our addresses */
addresses = bus_config_parser_get_addresses (parser);
@ -213,7 +255,7 @@ bus_context_new (const DBusString *config_file,
server = dbus_server_listen (link->data, error);
if (server == NULL)
goto failed;
else if (!setup_server (context, server, error))
else if (!setup_server (context, server, auth_mechanisms, error))
goto failed;
if (!_dbus_list_append (&context->servers, server))
@ -225,6 +267,31 @@ bus_context_new (const DBusString *config_file,
link = _dbus_list_get_next_link (addresses, link);
}
/* Here we change our credentials if required,
* as soon as we've set up our sockets
*/
user = bus_config_parser_get_user (parser);
if (user != NULL)
{
DBusCredentials creds;
DBusString u;
_dbus_string_init_const (&u, user);
if (!_dbus_credentials_from_username (&u, &creds) ||
creds.uid < 0 ||
creds.gid < 0)
{
dbus_set_error (error, DBUS_ERROR_FAILED,
"Could not get UID and GID for username \"%s\"",
user);
goto failed;
}
if (!_dbus_change_identity (creds.uid, creds.gid, error))
goto failed;
}
/* We have to build the address backward, so that
* <listen> later in the config file have priority
*/
@ -265,6 +332,8 @@ bus_context_new (const DBusString *config_file,
BUS_SET_OOM (error);
goto failed;
}
/* Create activation subsystem */
context->activation = bus_activation_new (context, &full_address,
service_dirs, error);
@ -306,12 +375,20 @@ bus_context_new (const DBusString *config_file,
goto failed;
}
/* Now become a daemon if appropriate */
if (bus_config_parser_get_fork (parser))
{
if (!_dbus_become_daemon (error))
goto failed;
}
bus_config_parser_unref (parser);
_dbus_string_free (&full_address);
dbus_free_string_array (auth_mechanisms);
return context;
failed:
failed:
if (parser != NULL)
bus_config_parser_unref (parser);
@ -319,6 +396,7 @@ bus_context_new (const DBusString *config_file,
bus_context_unref (context);
_dbus_string_free (&full_address);
dbus_free_string_array (auth_mechanisms);
return NULL;
}

View file

@ -37,7 +37,8 @@ typedef enum
ELEMENT_POLICY,
ELEMENT_LIMIT,
ELEMENT_ALLOW,
ELEMENT_DENY
ELEMENT_DENY,
ELEMENT_FORK
} ElementType;
typedef struct
@ -84,6 +85,10 @@ struct BusConfigParser
char *user; /**< user to run as */
DBusList *listen_on; /**< List of addresses to listen to */
DBusList *mechanisms; /**< Auth mechanisms */
unsigned int fork : 1; /**< TRUE to fork into daemon mode */
};
static const char*
@ -111,6 +116,8 @@ element_type_to_name (ElementType type)
return "allow";
case ELEMENT_DENY:
return "deny";
case ELEMENT_FORK:
return "fork";
}
_dbus_assert_not_reached ("bad element type");
@ -195,9 +202,15 @@ merge_included (BusConfigParser *parser,
included->user = NULL;
}
if (included->fork)
parser->fork = TRUE;
while ((link = _dbus_list_pop_first_link (&included->listen_on)))
_dbus_list_append_link (&parser->listen_on, link);
while ((link = _dbus_list_pop_first_link (&included->mechanisms)))
_dbus_list_append_link (&parser->mechanisms, link);
return TRUE;
}
@ -407,6 +420,21 @@ start_busconfig_child (BusConfigParser *parser,
return FALSE;
}
return TRUE;
}
else if (strcmp (element_name, "fork") == 0)
{
if (!check_no_attributes (parser, "fork", attribute_names, attribute_values, error))
return FALSE;
if (push_element (parser, ELEMENT_FORK) == NULL)
{
dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
return FALSE;
}
parser->fork = TRUE;
return TRUE;
}
else if (strcmp (element_name, "listen") == 0)
@ -420,6 +448,19 @@ start_busconfig_child (BusConfigParser *parser,
return FALSE;
}
return TRUE;
}
else if (strcmp (element_name, "auth") == 0)
{
if (!check_no_attributes (parser, "auth", attribute_names, attribute_values, error))
return FALSE;
if (push_element (parser, ELEMENT_AUTH) == NULL)
{
dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
return FALSE;
}
return TRUE;
}
else if (strcmp (element_name, "include") == 0)
@ -654,6 +695,7 @@ bus_config_parser_end_element (BusConfigParser *parser,
case ELEMENT_LIMIT:
case ELEMENT_ALLOW:
case ELEMENT_DENY:
case ELEMENT_FORK:
break;
}
@ -715,6 +757,7 @@ bus_config_parser_content (BusConfigParser *parser,
case ELEMENT_LIMIT:
case ELEMENT_ALLOW:
case ELEMENT_DENY:
case ELEMENT_FORK:
if (all_whitespace (content))
return TRUE;
else
@ -800,8 +843,19 @@ bus_config_parser_content (BusConfigParser *parser,
case ELEMENT_AUTH:
{
char *s;
e->had_content = TRUE;
/* FIXME */
if (!_dbus_string_copy_data (content, &s))
goto nomem;
if (!_dbus_list_append (&parser->mechanisms,
s))
{
dbus_free (s);
goto nomem;
}
}
break;
}
@ -851,6 +905,18 @@ bus_config_parser_get_addresses (BusConfigParser *parser)
return &parser->listen_on;
}
DBusList**
bus_config_parser_get_mechanisms (BusConfigParser *parser)
{
return &parser->mechanisms;
}
dbus_bool_t
bus_config_parser_get_fork (BusConfigParser *parser)
{
return parser->fork;
}
#ifdef DBUS_BUILD_TESTS
#include <stdio.h>

View file

@ -55,8 +55,10 @@ dbus_bool_t bus_config_parser_finished (BusConfigParser *parser,
DBusError *error);
/* Functions for extracting the parse results */
const char* bus_config_parser_get_user (BusConfigParser *parser);
DBusList** bus_config_parser_get_addresses (BusConfigParser *parser);
const char* bus_config_parser_get_user (BusConfigParser *parser);
DBusList** bus_config_parser_get_addresses (BusConfigParser *parser);
DBusList** bus_config_parser_get_mechanisms (BusConfigParser *parser);
dbus_bool_t bus_config_parser_get_fork (BusConfigParser *parser);
/* Loader functions (backended off one of the XML parsers). Returns a
* finished ConfigParser.

View file

@ -2,13 +2,29 @@
Add a system-local.conf and edit that rather than changing this
file directly. -->
<!-- Note that there are any number of ways you can hose yourself
security-wise by screwing up this file; in particular, you
probably don't want to listen on any more addresses, add any more
auth mechanisms, run as a different user, etc. -->
<!DOCTYPE busconfig PUBLIC "-//freedesktop//DTD D-BUS Bus Configuration 1.0//EN"
"http://www.freedesktop.org/standards/dbus/1.0/busconfig.dtd">
<busconfig>
<user>fixme</user>
<!-- Run as special user -->
<user>messagebus</user>
<!-- Fork into daemon mode -->
<fork/>
<!-- Only allow socket-credentials-based authentication -->
<auth>EXTERNAL</auth>
<!-- Only listen on a local socket -->
<listen>unix:path=@EXPANDED_LOCALSTATEDIR@/@DBUS_SYSTEM_SOCKET@</listen>
<policy context="default">
<!-- Deny everything -->
<!-- Deny everything then punch holes -->
<deny send="*"/>
<deny receive="*"/>
<deny own="*"/>

View file

@ -159,6 +159,10 @@ struct DBusAuth
DBusKeyring *keyring; /**< Keyring for cookie mechanism. */
int cookie_id; /**< ID of cookie to use */
DBusString challenge; /**< Challenge sent to client */
char **allowed_mechs; /**< Mechanisms we're allowed to use,
* or #NULL if we can use any
*/
unsigned int needed_memory : 1; /**< We needed memory to continue since last
* successful getting something done
@ -1134,13 +1138,19 @@ all_mechanisms[] = {
};
static const DBusAuthMechanismHandler*
find_mech (const DBusString *name)
find_mech (const DBusString *name,
char **allowed_mechs)
{
int i;
if (allowed_mechs != NULL &&
!_dbus_string_array_contains ((const char**) allowed_mechs,
_dbus_string_get_const_data (name)))
return NULL;
i = 0;
while (all_mechanisms[i].mechanism != NULL)
{
{
if (_dbus_string_equal_c_str (name,
all_mechanisms[i].mechanism))
@ -1259,7 +1269,7 @@ process_auth (DBusAuth *auth,
&decoded_response, 0))
goto failed;
auth->mech = find_mech (&mech);
auth->mech = find_mech (&mech, auth->allowed_mechs);
if (auth->mech != NULL)
{
_dbus_verbose ("Trying mechanism %s with initial response of %d bytes\n",
@ -1418,7 +1428,7 @@ record_mechanisms (DBusAuth *auth,
if (!get_word (args, &next, &m))
goto nomem;
mech = find_mech (&m);
mech = find_mech (&m, auth->allowed_mechs);
if (mech != NULL)
{
@ -1462,12 +1472,33 @@ client_try_next_mechanism (DBusAuth *auth)
{
const DBusAuthMechanismHandler *mech;
DBusString auth_command;
DBusAuthClient *client;
if (DBUS_AUTH_CLIENT (auth)->mechs_to_try == NULL)
client = DBUS_AUTH_CLIENT (auth);
/* Pop any mechs not in the list of allowed mechanisms */
mech = NULL;
while (client->mechs_to_try != NULL)
{
mech = client->mechs_to_try->data;
if (auth->allowed_mechs != NULL &&
!_dbus_string_array_contains ((const char**) auth->allowed_mechs,
mech->mechanism))
{
/* don't try this one after all */
_dbus_verbose ("Mechanism %s isn't in the list of allowed mechanisms\n",
mech->mechanism);
mech = NULL;
_dbus_list_pop_first (& client->mechs_to_try);
}
else
break; /* we'll try this one */
}
if (mech == NULL)
return FALSE;
mech = DBUS_AUTH_CLIENT (auth)->mechs_to_try->data;
if (!_dbus_string_init (&auth_command))
return FALSE;
@ -1859,10 +1890,43 @@ _dbus_auth_unref (DBusAuth *auth)
_dbus_string_free (&auth->identity);
_dbus_string_free (&auth->incoming);
_dbus_string_free (&auth->outgoing);
dbus_free_string_array (auth->allowed_mechs);
dbus_free (auth);
}
}
/**
* Sets an array of authentication mechanism names
* that we are willing to use.
*
* @param auth the auth conversation
* @param mechanisms #NULL-terminated array of mechanism names
* @returns #FALSE if no memory
*/
dbus_bool_t
_dbus_auth_set_mechanisms (DBusAuth *auth,
const char **mechanisms)
{
char **copy;
if (mechanisms != NULL)
{
copy = _dbus_dup_string_array (mechanisms);
if (copy == NULL)
return FALSE;
}
else
copy = NULL;
dbus_free_string_array (auth->allowed_mechs);
auth->allowed_mechs = copy;
return TRUE;
}
/**
* @param auth the auth conversation object
* @returns #TRUE if we're in a final state

View file

@ -46,6 +46,8 @@ DBusAuth* _dbus_auth_server_new (void);
DBusAuth* _dbus_auth_client_new (void);
void _dbus_auth_ref (DBusAuth *auth);
void _dbus_auth_unref (DBusAuth *auth);
dbus_bool_t _dbus_auth_set_mechanisms (DBusAuth *auth,
const char **mechanisms);
DBusAuthState _dbus_auth_do_work (DBusAuth *auth);
dbus_bool_t _dbus_auth_get_bytes_to_send (DBusAuth *auth,
const DBusString **str);

View file

@ -107,18 +107,6 @@
*
* Maximum value of type "int"
*/
/**
* @def _DBUS_MAX_SUN_PATH_LENGTH
*
* Maximum length of the path to a UNIX domain socket,
* sockaddr_un::sun_path member. POSIX requires that all systems
* support at least 100 bytes here, including the nul termination.
* We use 99 for the max value to allow for the nul.
*
* We could probably also do sizeof (addr.sun_path)
* but this way we are the same on all platforms
* which is probably a good idea.
*/
/**
* @typedef DBusForeachFunction
@ -250,6 +238,71 @@ _dbus_strdup (const char *str)
return copy;
}
/**
* Duplicates a string array. Result may be freed with
* dbus_free_string_array(). Returns #NULL if memory allocation fails.
* If the array to be duplicated is #NULL, returns #NULL.
*
* @param array array to duplicate.
* @returns newly-allocated copy.
*/
char**
_dbus_dup_string_array (const char **array)
{
int len;
int i;
char **copy;
if (array == NULL)
return NULL;
for (len = 0; array[len] != NULL; ++len)
;
copy = dbus_new0 (char*, len + 1);
if (copy == NULL)
return NULL;
i = 0;
while (i < len)
{
copy[i] = _dbus_strdup (array[i]);
if (copy[i] == NULL)
{
dbus_free_string_array (copy);
return NULL;
}
++i;
}
return copy;
}
/**
* Checks whether a string array contains the given string.
*
* @param array array to search.
* @param str string to look for
* @returns #TRUE if array contains string
*/
dbus_bool_t
_dbus_string_array_contains (const char **array,
const char *str)
{
int i;
i = 0;
while (array[i] != NULL)
{
if (strcmp (array[i], str) == 0)
return TRUE;
++i;
}
return FALSE;
}
/**
* Returns a string describing the given type.
*

View file

@ -128,12 +128,15 @@ do {
#define _DBUS_ALIGN_ADDRESS(this, boundary) \
((void*)_DBUS_ALIGN_VALUE(this, boundary))
char* _dbus_strdup (const char *str);
char* _dbus_strdup (const char *str);
dbus_bool_t _dbus_string_array_contains (const char **array,
const char *str);
char** _dbus_dup_string_array (const char **array);
#define _DBUS_INT_MIN (-_DBUS_INT_MAX - 1)
#define _DBUS_INT_MAX 2147483647
#define _DBUS_UINT_MAX 0xffffffff
#define _DBUS_MAX_SUN_PATH_LENGTH 99
#define _DBUS_ONE_KILOBYTE 1024
#define _DBUS_ONE_MEGABYTE 1024 * _DBUS_ONE_KILOBYTE
#define _DBUS_ONE_HOUR_IN_MILLISECONDS (1000 * 60 * 60)

View file

@ -283,6 +283,15 @@ _dbus_transport_debug_pipe_new (const char *server_name,
server_fd = -1;
if (!_dbus_transport_set_auth_mechanisms (server_transport,
(const char**) server->auth_mechanisms))
{
dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
_dbus_transport_unref (server_transport);
_dbus_transport_unref (client_transport);
return FALSE;
}
connection = _dbus_connection_new_for_transport (server_transport);
_dbus_transport_unref (server_transport);
server_transport = NULL;

View file

@ -75,6 +75,8 @@ struct DBusServer
/**< Callback to invoke to free new_connection_data
* when server is finalized or data is replaced.
*/
char **auth_mechanisms; /**< Array of allowed authentication mechanisms */
unsigned int disconnected : 1; /**< TRUE if we are disconnected. */
};

View file

@ -90,6 +90,13 @@ handle_new_client_fd (DBusServer *server,
return FALSE;
}
if (!_dbus_transport_set_auth_mechanisms (transport,
(const char **) server->auth_mechanisms))
{
_dbus_transport_unref (transport);
return FALSE;
}
/* note that client_fd is now owned by the transport, and will be
* closed on transport disconnection/finalization
*/

View file

@ -143,6 +143,8 @@ _dbus_server_finalize_base (DBusServer *server)
_dbus_counter_unref (server->connection_counter);
dbus_free (server->address);
dbus_free_string_array (server->auth_mechanisms);
}
/**
@ -599,6 +601,37 @@ dbus_server_handle_watch (DBusServer *server,
return (* server->vtable->handle_watch) (server, watch, condition);
}
/**
* Sets the authentication mechanisms that this server offers
* to clients, as a list of SASL mechanisms. This function
* only affects connections created *after* it is called.
* Pass #NULL instead of an array to use all available mechanisms.
*
* @param server the server
* @param mechanisms #NULL-terminated array of mechanisms
* @returns #FALSE if no memory
*/
dbus_bool_t
dbus_server_set_auth_mechanisms (DBusServer *server,
const char **mechanisms)
{
char **copy;
if (mechanisms != NULL)
{
copy = _dbus_dup_string_array (mechanisms);
if (copy == NULL)
return FALSE;
}
else
copy = NULL;
dbus_free_string_array (server->auth_mechanisms);
server->auth_mechanisms = copy;
return TRUE;
}
/**
* Sets the maximum number of connections that can be open at one
* time for this server. If the maximum is reached, and another

View file

@ -70,6 +70,8 @@ void dbus_server_set_max_connections (DBusServer *
int dbus_server_get_max_connections (DBusServer *server);
int dbus_server_get_n_connections (DBusServer *server);
dbus_bool_t dbus_server_set_auth_mechanisms (DBusServer *server,
const char **mechanisms);
int dbus_server_allocate_data_slot (void);
void dbus_server_free_data_slot (int slot);

View file

@ -313,6 +313,21 @@ _dbus_write_two (int fd,
#endif /* !HAVE_WRITEV */
}
#define _DBUS_MAX_SUN_PATH_LENGTH 99
/**
* @def _DBUS_MAX_SUN_PATH_LENGTH
*
* Maximum length of the path to a UNIX domain socket,
* sockaddr_un::sun_path member. POSIX requires that all systems
* support at least 100 bytes here, including the nul termination.
* We use 99 for the max value to allow for the nul.
*
* We could probably also do sizeof (addr.sun_path)
* but this way we are the same on all platforms
* which is probably a good idea.
*/
/**
* Creates a socket and connects it to the UNIX domain socket at the
* given path. The connection fd is returned, and is set up as
@ -345,8 +360,7 @@ _dbus_connect_unix_socket (const char *path,
_DBUS_ZERO (addr);
addr.sun_family = AF_UNIX;
strncpy (addr.sun_path, path, _DBUS_MAX_SUN_PATH_LENGTH);
addr.sun_path[_DBUS_MAX_SUN_PATH_LENGTH-1] = '\0';
strncpy (addr.sun_path, path, _DBUS_MAX_SUN_PATH_LENGTH - 1);
if (connect (fd, (struct sockaddr*) &addr, sizeof (addr)) < 0)
{
@ -377,7 +391,13 @@ _dbus_connect_unix_socket (const char *path,
/**
* Creates a socket and binds it to the given path,
* then listens on the socket. The socket is
* set to be nonblocking.
* set to be nonblocking.
*
* @todo we'd like to be able to use the abstract namespace on linux
* (see "man 7 unix"). The question is whether to silently move all
* paths into that namespace if we can (I think that's best) or to
* require it to be specified explicitly in the dbus address. Also,
* need to sort out how to check for abstract namespace support.
*
* @param path the socket name
* @param error return location for errors
@ -402,10 +422,27 @@ _dbus_listen_unix_socket (const char *path,
return -1;
}
/* FIXME discussed security implications of this with Nalin,
* and we couldn't think of where it would kick our ass, but
* it still seems a bit sucky. It also has non-security suckage;
* really we'd prefer to exit if the socket is already in use.
* But there doesn't seem to be a good way to do this.
*
* Just to be extra careful, I threw in the stat() - clearly
* the stat() can't *fix* any security issue, but it probably
* makes it harder to exploit.
*/
{
struct stat sb;
if (stat (path, &sb) == 0 &&
S_ISSOCK (sb.st_mode))
unlink (path);
}
_DBUS_ZERO (addr);
addr.sun_family = AF_UNIX;
strncpy (addr.sun_path, path, _DBUS_MAX_SUN_PATH_LENGTH);
addr.sun_path[_DBUS_MAX_SUN_PATH_LENGTH-1] = '\0';
strncpy (addr.sun_path, path, _DBUS_MAX_SUN_PATH_LENGTH - 1);
if (bind (listen_fd, (struct sockaddr*) &addr, SUN_LEN (&addr)) < 0)
{
@ -431,6 +468,13 @@ _dbus_listen_unix_socket (const char *path,
close (listen_fd);
return -1;
}
/* Try opening up the permissions, but if we can't, just go ahead
* and continue, maybe it will be good enough.
*/
if (chmod (path, 0777) < 0)
_dbus_warn ("Could not set mode 0777 on socket %s\n",
path);
return listen_fd;
}
@ -3063,4 +3107,101 @@ _dbus_print_backtrace (void)
#endif
}
/**
* Does the chdir, fork, setsid, etc. to become a daemon process.
*
* @param error return location for errors
* @returns #FALSE on failure
*/
dbus_bool_t
_dbus_become_daemon (DBusError *error)
{
const char *s;
/* This is so we don't prevent unmounting of devices. We divert
* all messages to syslog
*/
if (chdir ("/") < 0)
{
dbus_set_error (error, DBUS_ERROR_FAILED,
"Could not chdir() to root directory");
return FALSE;
}
s = _dbus_getenv ("DBUS_DEBUG_OUTPUT");
if (s == NULL || *s == '\0')
{
int dev_null_fd;
/* silently ignore failures here, if someone
* doesn't have /dev/null we may as well try
* to continue anyhow
*/
dev_null_fd = open ("/dev/null", O_RDWR);
if (dev_null_fd >= 0)
{
dup2 (dev_null_fd, 0);
dup2 (dev_null_fd, 1);
dup2 (dev_null_fd, 2);
}
}
/* Get a predictable umask */
umask (022);
switch (fork ())
{
case -1:
dbus_set_error (error, _dbus_error_from_errno (errno),
"Failed to fork daemon: %s", _dbus_strerror (errno));
return FALSE;
break;
case 0:
break;
default:
_exit (0);
break;
}
if (setsid () == -1)
_dbus_assert_not_reached ("setsid() failed");
return TRUE;
}
/**
* Changes the user and group the bus is running as.
*
* @param uid the new user ID
* @param gid the new group ID
* @param error return location for errors
* @returns #FALSE on failure
*/
dbus_bool_t
_dbus_change_identity (unsigned long uid,
unsigned long gid,
DBusError *error)
{
if (setuid (uid) < 0)
{
dbus_set_error (error, _dbus_error_from_errno (errno),
"Failed to set UID to %lu: %s", uid,
_dbus_strerror (errno));
return FALSE;
}
if (setgid (gid) < 0)
{
dbus_set_error (error, _dbus_error_from_errno (errno),
"Failed to set GID to %lu: %s", gid,
_dbus_strerror (errno));
return FALSE;
}
return TRUE;
}
/** @} end of sysdeps */

View file

@ -217,6 +217,12 @@ dbus_bool_t _dbus_close (int fd,
void _dbus_print_backtrace (void);
dbus_bool_t _dbus_become_daemon (DBusError *error);
dbus_bool_t _dbus_change_identity (unsigned long uid,
unsigned long gid,
DBusError *error);
DBUS_END_DECLS;
#endif /* DBUS_SYSDEPS_H */

View file

@ -907,4 +907,20 @@ _dbus_transport_set_unix_user_function (DBusTransport *transport,
transport->free_unix_user_data = free_data_function;
}
/**
* Sets the SASL authentication mechanisms supported by this transport.
*
* @param transport the transport
* @param mechanisms the #NULL-terminated array of mechanisms
*
* @returns #FALSE if no memory
*/
dbus_bool_t
_dbus_transport_set_auth_mechanisms (DBusTransport *transport,
const char **mechanisms)
{
return _dbus_auth_set_mechanisms (transport->auth, mechanisms);
}
/** @} */

View file

@ -64,7 +64,8 @@ void _dbus_transport_set_unix_user_function (DBusTransport
DBusFreeFunction free_data_function,
void **old_data,
DBusFreeFunction *old_free_data_function);
dbus_bool_t _dbus_transport_set_auth_mechanisms (DBusTransport *transport,
const char **mechanisms);

View file

@ -53,6 +53,15 @@ Elements:
The last <user> entry in the file "wins", the others are ignored.
The user is changed after the bus has completed initialization.
So sockets etc. will be created before changing user, but no
data will be read from clients before changing user.
<fork>
If present, the bus daemon becomes a real daemon (forks
into the background, etc.)
<listen>
Add an address that the bus should listen on. The
@ -72,6 +81,7 @@ Elements:
Lists permitted authorization mechanisms. If this element doesn't
exist, then all known mechanisms are allowed. If there are
multiple <auth> elements, the last one wins (they are not merged).
The order in which mechanisms are listed is not meaningful.
Example: <auth>EXTERNAL</auth>
Example: <auth>DBUS_COOKIE_SHA1</auth>