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
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 <sys/un.h>
# include <sys/types.h>
# include <fcntl.h>
# include <unistd.h>
# include <string.h>
# include <errno.h>
2013-04-01 05:28:42 +04:00
# include <sys/poll.h>
2011-03-12 03:03:13 +03:00
# include <stddef.h>
2013-11-15 21:05:27 +04:00
# include <getopt.h>
2011-03-12 03:03:13 +03:00
# include "log.h"
# include "util.h"
# include "socket-util.h"
2013-04-01 05:28:42 +04:00
# include "sd-daemon.h"
# include "sd-bus.h"
# include "bus-internal.h"
# include "bus-message.h"
2013-10-16 08:10:04 +04:00
# include "bus-util.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-09 01:47:19 +03:00
# include "bus-control.h"
2014-12-09 14:17:24 +03:00
# include "smack-util.h"
2014-12-23 20:36:04 +03:00
# include "set.h"
# include "bus-xml-policy.h"
2015-01-15 15:56:44 +03:00
# include "driver.h"
2015-01-16 16:19:19 +03:00
# include "proxy.h"
2015-01-15 15:56:44 +03:00
# include "synthesize.h"
2013-11-15 21:05:27 +04:00
2014-07-03 03:17:26 +04:00
static char * arg_address = NULL ;
2013-12-21 07:19:51 +04:00
static char * arg_command_line_buffer = NULL ;
2014-06-04 11:55:40 +04:00
static bool arg_drop_privileges = false ;
2014-06-10 17:46:32 +04:00
static char * * arg_configuration = NULL ;
2013-12-21 07:19:51 +04:00
2013-11-15 21:05:27 +04:00
static int help ( void ) {
printf ( " %s [OPTIONS...] \n \n "
2013-12-21 06:59:07 +04:00
" Connect STDIO or a socket to a given bus address. \n \n "
2014-06-10 17:46:32 +04:00
" -h --help Show this help \n "
" --version Show package version \n "
" --drop-privileges Drop privileges \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-04 11:55:40 +04:00
ARG_DROP_PRIVILEGES ,
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 } ,
{ " drop-privileges " , no_argument , NULL , ARG_DROP_PRIVILEGES } ,
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 ;
2014-07-03 03:17:26 +04:00
case ARG_ADDRESS : {
char * a ;
a = strdup ( optarg ) ;
if ( ! a )
return log_oom ( ) ;
free ( arg_address ) ;
arg_address = a ;
2013-12-21 06:59:07 +04:00
break ;
2014-07-03 03:17:26 +04:00
}
2013-12-21 06:59:07 +04:00
2014-06-04 11:55:40 +04:00
case ARG_DROP_PRIVILEGES :
arg_drop_privileges = true ;
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
}
2013-12-21 07:19:51 +04:00
/* If the first command line argument is only "x" characters
* we ' ll write who we are talking to into it , so that " ps " is
* explanatory */
arg_command_line_buffer = argv [ optind ] ;
2014-07-03 03:17:26 +04:00
if ( argc > optind + 1 | | ( arg_command_line_buffer & & ! in_charset ( arg_command_line_buffer , " x " ) ) ) {
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
2013-12-26 06:08:52 +04:00
static int rename_service ( sd_bus * a , sd_bus * b ) {
2013-12-23 05:59:03 +04:00
_cleanup_bus_creds_unref_ sd_bus_creds * creds = NULL ;
_cleanup_free_ char * p = NULL , * name = NULL ;
const char * comm ;
char * * cmdline ;
uid_t uid ;
pid_t pid ;
int r ;
2013-12-26 06:08:52 +04:00
assert ( a ) ;
2013-12-23 05:59:03 +04:00
assert ( b ) ;
2015-01-08 19:43:48 +03:00
r = sd_bus_get_owner_creds ( b , SD_BUS_CREDS_UID | SD_BUS_CREDS_PID | SD_BUS_CREDS_CMDLINE | SD_BUS_CREDS_COMM | SD_BUS_CREDS_AUGMENT , & creds ) ;
2013-12-23 05:59:03 +04:00
if ( r < 0 )
return r ;
r = sd_bus_creds_get_uid ( creds , & uid ) ;
if ( r < 0 )
return r ;
r = sd_bus_creds_get_pid ( creds , & pid ) ;
if ( r < 0 )
return r ;
r = sd_bus_creds_get_cmdline ( creds , & cmdline ) ;
if ( r < 0 )
return r ;
r = sd_bus_creds_get_comm ( creds , & comm ) ;
if ( r < 0 )
return r ;
name = uid_to_name ( uid ) ;
if ( ! name )
return - ENOMEM ;
p = strv_join ( cmdline , " " ) ;
if ( ! p )
return - ENOMEM ;
/* The status string gets the full command line ... */
sd_notifyf ( false ,
2013-12-31 02:22:26 +04:00
" STATUS=Processing requests from client PID " PID_FMT " (%s); UID " UID_FMT " (%s) " ,
pid , p ,
uid , name ) ;
2013-12-23 05:59:03 +04:00
/* ... and the argv line only the short comm */
if ( arg_command_line_buffer ) {
size_t m , w ;
m = strlen ( arg_command_line_buffer ) ;
w = snprintf ( arg_command_line_buffer , m ,
2013-12-31 02:22:26 +04:00
" [PID " PID_FMT " /%s; UID " UID_FMT " /%s] " ,
pid , comm ,
uid , name ) ;
2013-12-23 05:59:03 +04:00
if ( m > w )
2014-01-31 09:51:32 +04:00
memzero ( arg_command_line_buffer + w , m - w ) ;
2013-12-23 05:59:03 +04:00
}
2013-12-31 02:22:26 +04:00
log_debug ( " Running on behalf of PID " PID_FMT " (%s), UID " UID_FMT " (%s), %s " ,
pid , p ,
uid , name ,
2013-12-26 06:08:52 +04:00
a - > unique_name ) ;
2014-08-21 19:19:28 +04:00
2013-12-23 05:59:03 +04:00
return 0 ;
}
2011-03-12 03:03:13 +03:00
int main ( int argc , char * argv [ ] ) {
2015-01-16 16:19:19 +03:00
_cleanup_ ( proxy_freep ) Proxy * p = NULL ;
2013-11-15 21:05:27 +04:00
int r , in_fd , out_fd ;
2015-01-09 21:25:23 +03:00
uid_t original_uid ;
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 ( ) ;
2013-11-15 21:05:27 +04:00
r = parse_argv ( argc , argv ) ;
if ( r < = 0 )
goto finish ;
r = sd_listen_fds ( 0 ) ;
if ( r = = 0 ) {
in_fd = STDIN_FILENO ;
out_fd = STDOUT_FILENO ;
} else if ( r = = 1 ) {
in_fd = SD_LISTEN_FDS_START ;
out_fd = SD_LISTEN_FDS_START ;
} else {
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-09 21:25:23 +03:00
original_uid = getuid ( ) ;
2014-06-04 11:55:40 +04:00
if ( arg_drop_privileges ) {
const char * user = " systemd-bus-proxy " ;
uid_t uid ;
gid_t gid ;
r = get_user_creds ( & user , & uid , & gid , NULL , NULL ) ;
if ( r < 0 ) {
2014-11-28 15:19:16 +03:00
log_error_errno ( r , " Cannot resolve user name %s: %m " , user ) ;
2014-06-04 11:55:40 +04:00
goto finish ;
}
r = drop_privileges ( uid , gid , 1ULL < < CAP_IPC_OWNER ) ;
if ( r < 0 )
goto finish ;
}
2015-01-16 16:19:19 +03:00
r = proxy_new ( & p , in_fd , out_fd , arg_address ) ;
if ( r < 0 )
2014-09-24 19:10:31 +04:00
goto finish ;
2015-01-16 16:19:19 +03:00
r = proxy_load_policy ( p , arg_configuration ) ;
2015-01-15 19:33:28 +03:00
if ( r < 0 )
2013-04-01 05:28:42 +04:00
goto finish ;
2011-03-12 03:03:13 +03:00
2015-01-16 16:19:19 +03:00
r = proxy_hello_policy ( p , original_uid ) ;
2015-01-15 19:33:28 +03:00
if ( r < 0 )
2013-04-01 05:28:42 +04:00
goto finish ;
2011-03-12 03:03:13 +03:00
2015-01-16 16:19:19 +03:00
r = rename_service ( p - > dest_bus , p - > local_bus ) ;
2013-12-23 05:59:03 +04:00
if ( r < 0 )
2014-11-28 15:19:16 +03:00
log_debug_errno ( r , " Failed to rename process: %m " ) ;
2013-12-21 07:19:51 +04:00
2015-01-16 16:19:19 +03:00
r = proxy_run ( p ) ;
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
}