2011-03-12 03:03:13 +03:00
/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
/***
This file is part of systemd .
Copyright 2010 Lennart Poettering
2014-04-21 23:16:26 +04:00
Copyright 2013 Daniel Mack
Copyright 2014 Kay Sievers
2015-01-17 15:57:46 +03:00
Copyright 2015 David Herrmann
2011-03-12 03:03:13 +03:00
systemd is free software ; you can redistribute it and / or modify it
2012-04-12 02:20:58 +04:00
under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation ; either version 2.1 of the License , or
2011-03-12 03:03:13 +03:00
( 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
2012-04-12 02:20:58 +04:00
Lesser General Public License for more details .
2011-03-12 03:03:13 +03:00
2012-04-12 02:20:58 +04:00
You should have received a copy of the GNU Lesser General Public License
2011-03-12 03:03:13 +03:00
along with systemd ; If not , see < http : //www.gnu.org/licenses/>.
* * */
# include <sys/socket.h>
# include <unistd.h>
# include <string.h>
# include <errno.h>
2015-01-17 16:32:58 +03:00
# include <sys/prctl.h>
2011-03-12 03:03:13 +03:00
# include <stddef.h>
2013-11-15 21:05:27 +04:00
# include <getopt.h>
2015-01-17 15:57:46 +03:00
# include <pthread.h>
2011-03-12 03:03:13 +03:00
# include "log.h"
# include "util.h"
2013-04-01 05:28:42 +04:00
# include "sd-daemon.h"
# include "bus-internal.h"
2013-11-15 21:05:27 +04:00
# include "build.h"
2013-12-21 07:19:51 +04:00
# include "strv.h"
2013-12-31 01:12:46 +04:00
# include "def.h"
2014-06-04 11:55:40 +04:00
# include "capability.h"
2014-12-23 20:36:04 +03:00
# include "bus-xml-policy.h"
2015-01-16 16:19:19 +03:00
# include "proxy.h"
2013-11-15 21:05:27 +04:00
2014-07-03 03:17:26 +04:00
static char * arg_address = NULL ;
2014-06-10 17:46:32 +04:00
static char * * arg_configuration = NULL ;
2013-12-21 07:19:51 +04:00
2015-01-17 15:57:46 +03:00
typedef struct {
int fd ;
2015-01-17 20:07:58 +03:00
SharedPolicy * policy ;
2015-01-18 15:07:21 +03:00
uid_t bus_uid ;
2015-01-17 15:57:46 +03:00
} ClientContext ;
static ClientContext * client_context_free ( ClientContext * c ) {
if ( ! c )
return NULL ;
2015-02-13 19:15:41 +03:00
safe_close ( c - > fd ) ;
2015-01-17 15:57:46 +03:00
free ( c ) ;
return NULL ;
}
DEFINE_TRIVIAL_CLEANUP_FUNC ( ClientContext * , client_context_free ) ;
2015-01-17 20:07:58 +03:00
static int client_context_new ( ClientContext * * out ) {
2015-01-17 15:57:46 +03:00
_cleanup_ ( client_context_freep ) ClientContext * c = NULL ;
c = new0 ( ClientContext , 1 ) ;
if ( ! c )
2015-03-03 08:05:14 +03:00
return - ENOMEM ;
2015-01-17 15:57:46 +03:00
2015-01-17 20:07:58 +03:00
c - > fd = - 1 ;
2015-01-17 15:57:46 +03:00
* out = c ;
c = NULL ;
return 0 ;
}
static void * run_client ( void * userdata ) {
_cleanup_ ( client_context_freep ) ClientContext * c = userdata ;
_cleanup_ ( proxy_freep ) Proxy * p = NULL ;
2015-01-17 16:32:58 +03:00
char comm [ 16 ] ;
2015-01-17 15:57:46 +03:00
int r ;
r = proxy_new ( & p , c - > fd , c - > fd , arg_address ) ;
if ( r < 0 )
goto exit ;
2015-02-13 19:15:41 +03:00
c - > fd = - 1 ;
2015-01-17 16:32:58 +03:00
/* set comm to "p$PIDu$UID" and suffix with '*' if truncated */
r = snprintf ( comm , sizeof ( comm ) , " p " PID_FMT " u " UID_FMT , p - > local_creds . pid , p - > local_creds . uid ) ;
if ( r > = ( ssize_t ) sizeof ( comm ) )
comm [ sizeof ( comm ) - 2 ] = ' * ' ;
( void ) prctl ( PR_SET_NAME , comm ) ;
2015-01-17 20:07:58 +03:00
r = proxy_set_policy ( p , c - > policy , arg_configuration ) ;
2015-01-17 15:57:46 +03:00
if ( r < 0 )
goto exit ;
2015-01-18 15:07:21 +03:00
r = proxy_hello_policy ( p , c - > bus_uid ) ;
2015-01-17 15:57:46 +03:00
if ( r < 0 )
goto exit ;
r = proxy_run ( p ) ;
exit :
return NULL ;
}
2015-01-18 15:07:21 +03:00
static int loop_clients ( int accept_fd , uid_t bus_uid ) {
2015-01-17 20:07:58 +03:00
_cleanup_ ( shared_policy_freep ) SharedPolicy * sp = NULL ;
2015-01-17 15:57:46 +03:00
pthread_attr_t attr ;
int r ;
r = pthread_attr_init ( & attr ) ;
if ( r < 0 ) {
2015-02-13 19:17:28 +03:00
return log_error_errno ( errno , " Cannot initialize pthread attributes: %m " ) ;
2015-01-17 15:57:46 +03:00
}
r = pthread_attr_setdetachstate ( & attr , PTHREAD_CREATE_DETACHED ) ;
if ( r < 0 ) {
r = log_error_errno ( errno , " Cannot mark pthread attributes as detached: %m " ) ;
2015-02-13 19:17:28 +03:00
goto finish ;
2015-01-17 15:57:46 +03:00
}
2015-01-17 20:07:58 +03:00
r = shared_policy_new ( & sp ) ;
if ( r < 0 )
2015-02-13 19:17:28 +03:00
goto finish ;
2015-01-17 20:07:58 +03:00
2015-01-17 15:57:46 +03:00
for ( ; ; ) {
ClientContext * c ;
pthread_t tid ;
int fd ;
fd = accept4 ( accept_fd , NULL , NULL , SOCK_NONBLOCK | SOCK_CLOEXEC ) ;
if ( fd < 0 ) {
if ( errno = = EAGAIN | | errno = = EINTR )
continue ;
r = log_error_errno ( errno , " accept4() failed: %m " ) ;
2015-02-13 19:17:28 +03:00
goto finish ;
2015-01-17 15:57:46 +03:00
}
2015-01-17 20:07:58 +03:00
r = client_context_new ( & c ) ;
2015-01-17 15:57:46 +03:00
if ( r < 0 ) {
log_oom ( ) ;
close ( fd ) ;
continue ;
}
2015-01-17 20:07:58 +03:00
c - > fd = fd ;
c - > policy = sp ;
2015-01-18 15:07:21 +03:00
c - > bus_uid = bus_uid ;
2015-01-17 20:07:58 +03:00
2015-01-17 15:57:46 +03:00
r = pthread_create ( & tid , & attr , run_client , c ) ;
if ( r < 0 ) {
log_error ( " Cannot spawn thread: %m " ) ;
client_context_free ( c ) ;
continue ;
}
}
2015-02-13 19:17:28 +03:00
finish :
2015-01-17 15:57:46 +03:00
pthread_attr_destroy ( & attr ) ;
return r ;
}
2013-11-15 21:05:27 +04:00
static int help ( void ) {
printf ( " %s [OPTIONS...] \n \n "
2015-01-17 15:57:46 +03:00
" DBus proxy server. \n \n "
2014-06-10 17:46:32 +04:00
" -h --help Show this help \n "
" --version Show package version \n "
" --configuration=PATH Configuration file or directory \n "
2014-07-03 03:17:26 +04:00
" --machine=MACHINE Connect to specified machine \n "
2014-06-10 17:46:32 +04:00
" --address=ADDRESS Connect to the bus specified by ADDRESS \n "
2014-11-28 18:05:43 +03:00
" (default: " DEFAULT_SYSTEM_BUS_ADDRESS " ) \n " ,
2013-12-21 06:59:07 +04:00
program_invocation_short_name ) ;
2013-11-15 21:05:27 +04:00
return 0 ;
}
static int parse_argv ( int argc , char * argv [ ] ) {
enum {
ARG_VERSION = 0x100 ,
2013-12-21 06:59:07 +04:00
ARG_ADDRESS ,
2014-06-10 17:46:32 +04:00
ARG_CONFIGURATION ,
2014-07-03 03:17:26 +04:00
ARG_MACHINE ,
2013-11-15 21:05:27 +04:00
} ;
static const struct option options [ ] = {
2014-06-04 11:55:40 +04:00
{ " help " , no_argument , NULL , ' h ' } ,
{ " version " , no_argument , NULL , ARG_VERSION } ,
{ " address " , required_argument , NULL , ARG_ADDRESS } ,
2014-06-10 17:46:32 +04:00
{ " configuration " , required_argument , NULL , ARG_CONFIGURATION } ,
2014-07-03 03:17:26 +04:00
{ " machine " , required_argument , NULL , ARG_MACHINE } ,
{ } ,
2013-11-15 21:05:27 +04:00
} ;
2014-06-10 17:46:32 +04:00
int c , r ;
2013-11-15 21:05:27 +04:00
assert ( argc > = 0 ) ;
assert ( argv ) ;
2014-08-02 19:12:21 +04:00
while ( ( c = getopt_long ( argc , argv , " h " , options , NULL ) ) > = 0 )
2013-11-15 21:05:27 +04:00
switch ( c ) {
case ' h ' :
help ( ) ;
return 0 ;
case ARG_VERSION :
puts ( PACKAGE_STRING ) ;
puts ( SYSTEMD_FEATURES ) ;
return 0 ;
2015-02-13 19:17:28 +03:00
case ARG_ADDRESS :
r = free_and_strdup ( & arg_address , optarg ) ;
if ( r < 0 )
2014-07-03 03:17:26 +04:00
return log_oom ( ) ;
2013-12-21 06:59:07 +04:00
break ;
2014-06-10 17:46:32 +04:00
case ARG_CONFIGURATION :
r = strv_extend ( & arg_configuration , optarg ) ;
if ( r < 0 )
return log_oom ( ) ;
break ;
2014-07-03 03:17:26 +04:00
case ARG_MACHINE : {
_cleanup_free_ char * e = NULL ;
char * a ;
e = bus_address_escape ( optarg ) ;
if ( ! e )
return log_oom ( ) ;
# ifdef ENABLE_KDBUS
2015-01-05 00:20:22 +03:00
a = strjoin ( " x-machine-kernel:machine= " , e , " ;x-machine-unix:machine= " , e , NULL ) ;
2014-07-03 03:17:26 +04:00
# else
2015-01-05 00:20:22 +03:00
a = strjoin ( " x-machine-unix:machine= " , e , NULL ) ;
2014-07-03 03:17:26 +04:00
# endif
if ( ! a )
return log_oom ( ) ;
free ( arg_address ) ;
arg_address = a ;
break ;
}
2013-11-15 21:05:27 +04:00
case ' ? ' :
return - EINVAL ;
default :
2013-12-21 06:59:07 +04:00
assert_not_reached ( " Unhandled option " ) ;
2013-11-15 21:05:27 +04:00
}
2015-01-17 15:57:46 +03:00
if ( argc > optind ) {
2013-12-21 07:19:51 +04:00
log_error ( " Too many arguments " ) ;
return - EINVAL ;
}
2014-07-03 03:17:26 +04:00
if ( ! arg_address ) {
2014-11-28 18:05:43 +03:00
arg_address = strdup ( DEFAULT_SYSTEM_BUS_ADDRESS ) ;
2014-07-03 03:17:26 +04:00
if ( ! arg_address )
return log_oom ( ) ;
}
2013-11-15 21:05:27 +04:00
return 1 ;
}
2011-03-12 03:03:13 +03:00
int main ( int argc , char * argv [ ] ) {
2015-01-17 15:57:46 +03:00
int r , accept_fd ;
2015-01-18 15:07:21 +03:00
uid_t uid , bus_uid ;
2015-01-17 20:23:33 +03:00
gid_t gid ;
2011-03-12 03:03:13 +03:00
2012-01-12 08:09:06 +04:00
log_set_target ( LOG_TARGET_JOURNAL_OR_KMSG ) ;
2011-03-12 03:03:13 +03:00
log_parse_environment ( ) ;
log_open ( ) ;
2015-01-18 15:07:21 +03:00
bus_uid = getuid ( ) ;
2015-01-17 20:23:33 +03:00
if ( geteuid ( ) = = 0 ) {
2015-02-13 19:17:28 +03:00
const char * user = " systemd-bus-proxy " ;
2015-01-17 20:23:33 +03:00
r = get_user_creds ( & user , & uid , & gid , NULL , NULL ) ;
if ( r < 0 ) {
log_error_errno ( r , " Cannot resolve user name %s: %m " , user ) ;
goto finish ;
}
r = drop_privileges ( uid , gid , 1ULL < < CAP_IPC_OWNER ) ;
if ( r < 0 ) {
log_error_errno ( r , " Cannot drop privileges: %m " ) ;
goto finish ;
}
}
2013-11-15 21:05:27 +04:00
r = parse_argv ( argc , argv ) ;
if ( r < = 0 )
goto finish ;
r = sd_listen_fds ( 0 ) ;
2015-01-17 15:57:46 +03:00
if ( r ! = 1 ) {
2013-12-24 19:39:37 +04:00
log_error ( " Illegal number of file descriptors passed " ) ;
2013-11-15 21:05:27 +04:00
goto finish ;
}
2015-01-17 15:57:46 +03:00
accept_fd = SD_LISTEN_FDS_START ;
2015-02-13 19:17:28 +03:00
2015-01-17 15:57:46 +03:00
r = fd_nonblock ( accept_fd , false ) ;
if ( r < 0 ) {
log_error_errno ( r , " Cannot mark accept-fd non-blocking: %m " ) ;
2014-09-24 19:10:31 +04:00
goto finish ;
2015-01-17 15:57:46 +03:00
}
2014-09-24 19:10:31 +04:00
2015-01-18 15:07:21 +03:00
r = loop_clients ( accept_fd , bus_uid ) ;
2011-03-12 03:03:13 +03:00
finish :
2014-08-21 19:19:28 +04:00
sd_notify ( false ,
" STOPPING=1 \n "
" STATUS=Shutting down. " ) ;
2014-06-10 17:46:32 +04:00
strv_free ( arg_configuration ) ;
2014-07-03 03:17:26 +04:00
free ( arg_address ) ;
2014-06-06 21:41:24 +04:00
2013-04-01 05:28:42 +04:00
return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS ;
2011-03-12 03:03:13 +03:00
}