/*
SSSD
Service monitor - D-BUS features
Copyright (C) Stephen Gallagher 2008
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 3 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, see .
*/
#include
#include
#include
#include "tevent.h"
#include "util/util.h"
#include "dbus/dbus.h"
#include "sbus/sssd_dbus.h"
#include "sbus/sssd_dbus_private.h"
static int sbus_server_destructor(void *ctx);
/*
* new_connection_callback
* Actions to be run upon each new client connection
* Must either perform dbus_connection_ref() on the
* new connection or else close the connection with
* dbus_connection_close()
*/
static void sbus_server_init_new_connection(DBusServer *dbus_server,
DBusConnection *dbus_conn,
void *data)
{
struct sbus_connection *server;
struct sbus_connection *conn;
int ret;
DEBUG(5,("Entering.\n"));
server = talloc_get_type(data, struct sbus_connection);
if (!server) {
return;
}
DEBUG(5,("Adding connection %p.\n", dbus_conn));
ret = sbus_init_connection(server, server->ev,
dbus_conn, server->server_intf,
SBUS_CONN_TYPE_PRIVATE, &conn);
if (ret != 0) {
dbus_connection_close(dbus_conn);
DEBUG(5,("Closing connection (failed setup)"));
return;
}
dbus_connection_ref(dbus_conn);
DEBUG(5,("Got a connection\n"));
/*
* Initialize connection-specific features
* This may set a more detailed destructor, but
* the default destructor will always be chained
* to handle connection cleanup.
* This function (or its callbacks) should also
* set up connection-specific methods.
*/
ret = server->srv_init_fn(conn, server->srv_init_data);
if (ret != EOK) {
DEBUG(1,("Initialization failed!\n"));
dbus_connection_close(dbus_conn);
talloc_zfree(conn);
}
}
/*
* dbus_new_server
* Set up a D-BUS server, integrate with the event loop
* for handling file descriptor and timed events
*/
int sbus_new_server(TALLOC_CTX *mem_ctx,
struct tevent_context *ev,
const char *address,
struct sbus_interface *intf,
struct sbus_connection **_server,
sbus_server_conn_init_fn init_fn, void *init_pvt_data)
{
struct sbus_connection *server;
DBusServer *dbus_server;
DBusError dbus_error;
dbus_bool_t dbret;
char *tmp;
int ret;
char *filename;
struct stat stat_buf;
*_server = NULL;
/* Set up D-BUS server */
dbus_error_init(&dbus_error);
dbus_server = dbus_server_listen(address, &dbus_error);
if (!dbus_server) {
DEBUG(1,("dbus_server_listen failed! (name=%s, message=%s)\n",
dbus_error.name, dbus_error.message));
if (dbus_error_is_set(&dbus_error)) dbus_error_free(&dbus_error);
return EIO;
}
filename = strchr(address, '/');
if (filename == NULL) {
DEBUG(1, ("Unexpected dbus address [%s].\n", address));
return EIO;
}
ret = check_file(filename, 0, 0, -1, CHECK_SOCK, &stat_buf);
if (ret != EOK) {
DEBUG(1, ("check_file failed for [%s].\n", filename));
return EIO;
}
if ((stat_buf.st_mode & ~S_IFMT) != 0600) {
ret = chmod(filename, 0600);
if (ret != EOK) {
DEBUG(1, ("chmod failed for [%s]: [%d][%s].\n", filename, errno,
strerror(errno)));
return EIO;
}
}
tmp = dbus_server_get_address(dbus_server);
DEBUG(3, ("D-BUS Server listening on %s\n", tmp));
free(tmp);
server = talloc_zero(mem_ctx, struct sbus_connection);
if (!server) {
return ENOMEM;
}
server->ev = ev;
server->type = SBUS_SERVER;
server->dbus.server = dbus_server;
server->server_intf = intf;
server->srv_init_fn = init_fn;
server->srv_init_data = init_pvt_data;
talloc_set_destructor((TALLOC_CTX *)server, sbus_server_destructor);
/* Set up D-BUS new connection handler */
dbus_server_set_new_connection_function(server->dbus.server,
sbus_server_init_new_connection,
server, NULL);
/* Set up DBusWatch functions */
dbret = dbus_server_set_watch_functions(server->dbus.server,
sbus_add_watch,
sbus_remove_watch,
sbus_toggle_watch,
server, NULL);
if (!dbret) {
DEBUG(4, ("Error setting up D-BUS server watch functions\n"));
talloc_free(server);
return EIO;
}
/* Set up DBusTimeout functions */
dbret = dbus_server_set_timeout_functions(server->dbus.server,
sbus_add_timeout,
sbus_remove_timeout,
sbus_toggle_timeout,
server, NULL);
if (!dbret) {
DEBUG(4,("Error setting up D-BUS server timeout functions\n"));
dbus_server_set_watch_functions(server->dbus.server,
NULL, NULL, NULL, NULL, NULL);
talloc_free(server);
return EIO;
}
*_server = server;
return EOK;
}
static int sbus_server_destructor(void *ctx)
{
struct sbus_connection *server;
server = talloc_get_type(ctx, struct sbus_connection);
dbus_server_disconnect(server->dbus.server);
return 0;
}