2010-08-14 21:59:25 +04:00
/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
2010-07-06 07:06:40 +04:00
/***
This file is part of systemd .
Copyright 2010 Lennart Poettering
systemd 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 .
systemd 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 systemd ; If not , see < http : //www.gnu.org/licenses/>.
* * */
# include <assert.h>
# include <sys/socket.h>
# include <errno.h>
# include <unistd.h>
# include <dbus/dbus.h>
# include "log.h"
# include "dbus-common.h"
2011-03-11 02:45:06 +03:00
# include "util.h"
2010-07-06 07:06:40 +04:00
int bus_check_peercred ( DBusConnection * c ) {
int fd ;
struct ucred ucred ;
socklen_t l ;
assert ( c ) ;
assert_se ( dbus_connection_get_unix_fd ( c , & fd ) ) ;
l = sizeof ( struct ucred ) ;
if ( getsockopt ( fd , SOL_SOCKET , SO_PEERCRED , & ucred , & l ) < 0 ) {
log_error ( " SO_PEERCRED failed: %m " ) ;
return - errno ;
}
if ( l ! = sizeof ( struct ucred ) ) {
log_error ( " SO_PEERCRED returned wrong size. " ) ;
return - E2BIG ;
}
if ( ucred . uid ! = 0 )
return - EPERM ;
return 1 ;
}
2010-07-07 05:43:39 +04:00
int bus_connect ( DBusBusType t , DBusConnection * * _bus , bool * private , DBusError * error ) {
2010-07-06 07:06:40 +04:00
DBusConnection * bus ;
assert ( _bus ) ;
2011-03-11 02:45:06 +03:00
# define TIMEOUT_USEC (60*USEC_PER_SEC)
2010-07-06 07:06:40 +04:00
/* If we are root, then let's not go via the bus */
if ( geteuid ( ) = = 0 & & t = = DBUS_BUS_SYSTEM ) {
2011-03-11 02:45:06 +03:00
usec_t begin , tstamp ;
2010-07-06 07:06:40 +04:00
2010-07-11 04:22:46 +04:00
if ( ! ( bus = dbus_connection_open_private ( " unix:abstract=/org/freedesktop/systemd1/private " , error ) ) )
2010-07-06 07:06:40 +04:00
return - EIO ;
if ( bus_check_peercred ( bus ) < 0 ) {
2011-03-11 02:45:06 +03:00
dbus_connection_close ( bus ) ;
2010-07-06 07:06:40 +04:00
dbus_connection_unref ( bus ) ;
dbus_set_error_const ( error , DBUS_ERROR_ACCESS_DENIED , " Failed to verify owner of bus. " ) ;
return - EACCES ;
}
2010-07-07 05:43:39 +04:00
2011-03-11 02:52:13 +03:00
/* This complexity should probably move into D-Bus itself:
*
* https : //bugs.freedesktop.org/show_bug.cgi?id=35189 */
2011-03-11 02:45:06 +03:00
begin = tstamp = now ( CLOCK_MONOTONIC ) ;
for ( ; ; ) {
if ( tstamp > begin + TIMEOUT_USEC )
break ;
if ( dbus_connection_get_is_authenticated ( bus ) )
break ;
if ( ! dbus_connection_read_write_dispatch ( bus , ( ( begin + TIMEOUT_USEC - tstamp ) + USEC_PER_MSEC - 1 ) / USEC_PER_MSEC ) )
break ;
tstamp = now ( CLOCK_MONOTONIC ) ;
}
if ( ! dbus_connection_get_is_connected ( bus ) ) {
dbus_connection_close ( bus ) ;
dbus_connection_unref ( bus ) ;
dbus_set_error_const ( error , DBUS_ERROR_NO_SERVER , " Connection terminated during authentication. " ) ;
return - ECONNREFUSED ;
}
if ( ! dbus_connection_get_is_authenticated ( bus ) ) {
dbus_connection_close ( bus ) ;
dbus_connection_unref ( bus ) ;
dbus_set_error_const ( error , DBUS_ERROR_TIMEOUT , " Failed to authenticate in time. " ) ;
return - EACCES ;
}
2010-07-07 05:43:39 +04:00
if ( private )
* private = true ;
2010-07-06 07:06:40 +04:00
} else {
2010-07-11 06:10:28 +04:00
if ( ! ( bus = dbus_bus_get_private ( t , error ) ) )
2010-07-06 07:06:40 +04:00
return - EIO ;
2010-07-07 05:43:39 +04:00
if ( private )
* private = false ;
2010-07-06 07:06:40 +04:00
}
dbus_connection_set_exit_on_disconnect ( bus , FALSE ) ;
* _bus = bus ;
return 0 ;
}
2010-08-25 21:49:23 +04:00
const char * bus_error_message ( const DBusError * error ) {
assert ( error ) ;
/* Sometimes the D-Bus server is a little bit too verbose with
* its error messages , so let ' s override them here */
if ( dbus_error_has_name ( error , DBUS_ERROR_ACCESS_DENIED ) )
return " Access denied " ;
return error - > message ;
}