From d170c239211b5d19b222627b7ee476c1e851895d Mon Sep 17 00:00:00 2001 From: erdgeist <> Date: Wed, 13 Mar 2013 12:48:43 +0000 Subject: Make m_flags an enum, set a neutral proctitle if none given, remove ipc pipe atexit() and add an immediate respawn option --- jaildaemon.c | 103 ++++++++++++++++++++++++++++++++--------------------------- 1 file changed, 56 insertions(+), 47 deletions(-) diff --git a/jaildaemon.c b/jaildaemon.c index b903fb2..b15a253 100644 --- a/jaildaemon.c +++ b/jaildaemon.c @@ -24,13 +24,14 @@ #define IPC_PACKETSIZE 4096 #define MAGIC_EXIT_CODE 42 enum { IAM_DAEMON, IAM_CLIENT, IAM_FORKSLAVE }; -enum { TASK_RESPAWN }; +enum { TASK_SINGLESHOT, TASK_RESPAWN, TASK_RESPAWN_IMMEDIATE, TASK_RESPAWNING }; static int g_uds; static int g_whoami = IAM_CLIENT; static int g_fork_slave_fd; static char g_ipc_packet[IPC_PACKETSIZE]; static int * const g_ipc_packet_int = (int*)g_ipc_packet; static struct pidfh * g_pidfilehandle; +static char * g_uds_path = "/var/run/jaildaemon.pipe"; /* For house keeping a list of all processes we attach to jails (probes), with an initial vector size of 128. The vector never shrinks. */ @@ -48,7 +49,7 @@ typedef struct { /* Forward declarations */ static void term_handler( int signal ); static void kill_all_probes( void ); -static void remove_pidfile( void ); +static void remove_files( void ); static int check_for_jail( int jid ); static int copy_daemontask( daemon_task ** out, daemon_task * const in ); static int add_task_to_kqueue( int kq, daemon_task * task_in ); @@ -92,7 +93,8 @@ static void exerr( char * message, ... ) { static void usage( char * cmd ) { fprintf( stderr, "%s -D [-ppidfile] [-fipcsockpath]\n" - "%s -c command -j jid [-t proctitle] [-r]\n", cmd, cmd ); + "%s -c command -j jid [-t proctitle] [-rR] [-fipcsockpath]\n", + cmd, cmd ); exit( 1 ); } @@ -195,6 +197,8 @@ static pid_t fork_and_jail( int jid, char * proctitle ) { /* Set proctitle so that jail's pgrep -f can identify the process */ if( proctitle && *proctitle ) setproctitle( "%s", proctitle ); + else + setproctitle( "PROBE" ); /* Throw ourself into the jail */ if( jail_attach( jid ) ) @@ -239,9 +243,9 @@ static int copy_daemontask( daemon_task ** out, daemon_task * const in ) { static void fork_and_execve( int kq, daemon_task * t_in ) { char * shell = "/bin/sh"; char * envp[] = { "PATH=/bin:/sbin:/usr/bin:/usr/sbin", NULL }; - pid_t pid; - - pid = fork(); + struct kevent ke; + daemon_task * t; + pid_t pid = fork(); switch( pid ) { case -1: @@ -259,33 +263,34 @@ static void fork_and_execve( int kq, daemon_task * t_in ) { break; default: /* If no respawn requested, just let the command finish */ - if( !(t_in->m_flags & 0x01) ) - return; - - /* else add process to our process watch list, so we get notified, - once it finishes to be able to respawn. ("else" to open block) */ - else { - struct kevent ke; - daemon_task * t; - - /* Try to take a copy of task struct. If this fails, then only - respawn fails. */ - if( copy_daemontask( &t, t_in ) ) + switch( t_in->m_flags ) { + case TASK_SINGLESHOT: return; - - /* Signal that this is a process that shall respawn the task - in jail */ - t->m_flags |= 0x02; - - memset( &ke, 0, sizeof ke ); - EV_SET( &ke, pid, EVFILT_PROC, EV_ADD, NOTE_EXIT, 0, t ); - if( kevent( kq, &ke, 1, NULL, 0, NULL ) == -1 ) { - /* If adding the event fails, get rid of struct */ - warn( "Can not put respawn watcher pid on the kqueue" ); - free( t->m_commandline ); - free( t->m_proctitle ); - free( t ); - } + case TASK_RESPAWN: + /* Try to take a copy of task struct. If this fails, + then only respawn fails. */ + if( copy_daemontask( &t, t_in ) ) + return; + + /* Signal that this is a process that shall respawn + the task in jail */ + t->m_flags = TASK_RESPAWNING; + + /* add process to our process watch list, so we get + notified, once it finishes to be able to respawn. */ + memset( &ke, 0, sizeof ke ); + EV_SET( &ke, pid, EVFILT_PROC, EV_ADD, NOTE_EXIT, 0, t ); + if( kevent( kq, &ke, 1, NULL, 0, NULL ) == -1 ) { + /* If adding the event fails, get rid of struct */ + warn( "Can not put respawn watcher pid on the kqueue" ); + free( t->m_commandline ); + free( t->m_proctitle ); + free( t ); + } + break; + case TASK_RESPAWN_IMMEDIATE: + add_task_to_kqueue( kq, t_in ); + break; } break; } @@ -302,8 +307,9 @@ static void kill_all_probes( void ) { g_probes = 0; } -static void remove_pidfile( void ) { +static void remove_files( void ) { pidfile_remove( g_pidfilehandle ); + unlink(g_uds_path); } static int add_task_to_kqueue( int kq, daemon_task * t_in ) { @@ -347,6 +353,7 @@ static int add_task_to_kqueue( int kq, daemon_task * t_in ) { for( i = 0; i < g_probes_size; ++i ) if( !g_probes[i] ) { g_probes[i] = pid; + /* SUCCESS */ return 0; } @@ -360,10 +367,11 @@ static int add_task_to_kqueue( int kq, daemon_task * t_in ) { probes[g_probes_size] = pid; g_probes_size *= 4; g_probes = probes; + /* SUCCESS */ return 0; } } - + /* FAIL branch */ /* If we added a kevent filter but failed to store the pid for our house keeping, remove the kqueuei filter again (and kill probe) */ EV_SET( &ke, pid, EVFILT_PROC, EV_DELETE, NOTE_EXIT, 0, t ); @@ -380,15 +388,15 @@ static int add_task_to_kqueue( int kq, daemon_task * t_in ) { return -1; } -/* jaildaemon -D <-ppidfile> <-fipcsockpath> -c command -j jid -t proctitle <-r> +/* jaildaemon -D [-ppidfile] [-fipcsockpath] + jaildaemon -c command -j jid -t proctitle [-rR] [-fipsockpath] */ int main( int argc, char **argv ) { pid_t second_pid; int kq, i; int o_force_daemon = 0; - int o_daemonize = 0, o_jid = -1, o_respawn = 0; + int o_daemonize = 0, o_jid = -1, o_respawn = TASK_SINGLESHOT; char *o_command = NULL, *o_pidfile = NULL, *o_proctitle = NULL; - char *o_uds_path = "/var/run/jaildaemon.pipe"; struct kevent ke; struct sockaddr_un addr; struct sigaction sa; @@ -401,15 +409,16 @@ int main( int argc, char **argv ) { i=1; while(i) { - switch( getopt( argc, argv, "DFrt:c:j:p:f:" ) ) { + switch( getopt( argc, argv, "DFrRt:c:j:p:f:" ) ) { case -1: i=0; break; case 'D': o_daemonize = 1; break; - case 'r': o_respawn = 1; break; + case 'r': o_respawn = TASK_RESPAWN; break; + case 'R': o_respawn = TASK_RESPAWN_IMMEDIATE; break; case 't': o_proctitle = optarg; break; case 'c': o_command = optarg; break; case 'j': o_jid = strtol( optarg, 0, 0 ); break; case 'p': o_pidfile = optarg; break; - case 'f': o_uds_path = optarg; break; + case 'f': g_uds_path = optarg; break; case 'F': o_force_daemon = 1; break; case '?': usage( argv[0]); exit(0); break; } @@ -429,14 +438,14 @@ int main( int argc, char **argv ) { memset(&addr, 0, sizeof(addr)); addr.sun_family = AF_UNIX; - strncpy(addr.sun_path, o_uds_path, sizeof(addr.sun_path)-1); + strncpy(addr.sun_path, g_uds_path, sizeof(addr.sun_path)-1); if( !o_daemonize ) { /* In utility mode try to pipe the request to the daemon already running and exit Packed packet format: - int m_flags ( 0x01 respawn, 0x02 executing, to be respawned ) + int m_flags: SINGLESHOT, RESPAWN, RESPAWN_IMMEDIATE, RESPAWNING int m_jid int m_commandline_length int m_proctitle_length @@ -504,8 +513,8 @@ int main( int argc, char **argv ) { g_fork_slave_fd = fork_fork_slave( ); /* Register pid file remover after fork() so that fork slave wont remove our - pid file*/ - atexit( remove_pidfile ); + pid file, also unlink our pipe at exit */ + atexit( remove_files ); /* Initialize syslog facilities */ openlog( "jaildaemon", 0, LOG_DAEMON ); @@ -516,7 +525,7 @@ int main( int argc, char **argv ) { /* Create the unix domain socket to receive commands on, N.B. error goes to syslog, now */ - unlink(o_uds_path); + unlink(g_uds_path); if (bind(g_uds, (struct sockaddr*)&addr, sizeof(addr)) == -1) exerr( "binding to command channel. Maybe another daemon is running?" ); @@ -585,8 +594,8 @@ int main( int argc, char **argv ) { /* If this task was watched to respawn a daemon in the jail, do it now */ - if( task->m_flags & 0x02 ) { - task->m_flags &= ~0x02; + if( task->m_flags == TASK_RESPAWNING ) { + task->m_flags = TASK_RESPAWN; add_task_to_kqueue( kq, task ); /* If the process exited with the correct magic code, -- cgit v1.2.3