diff options
| -rw-r--r-- | jaildaemon.c | 103 | 
1 files 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 @@ | |||
| 24 | #define IPC_PACKETSIZE 4096 | 24 | #define IPC_PACKETSIZE 4096 | 
| 25 | #define MAGIC_EXIT_CODE 42 | 25 | #define MAGIC_EXIT_CODE 42 | 
| 26 | enum { IAM_DAEMON, IAM_CLIENT, IAM_FORKSLAVE }; | 26 | enum { IAM_DAEMON, IAM_CLIENT, IAM_FORKSLAVE }; | 
| 27 | enum { TASK_RESPAWN }; | 27 | enum { TASK_SINGLESHOT, TASK_RESPAWN, TASK_RESPAWN_IMMEDIATE, TASK_RESPAWNING }; | 
| 28 | static int g_uds; | 28 | static int g_uds; | 
| 29 | static int g_whoami = IAM_CLIENT; | 29 | static int g_whoami = IAM_CLIENT; | 
| 30 | static int g_fork_slave_fd; | 30 | static int g_fork_slave_fd; | 
| 31 | static char g_ipc_packet[IPC_PACKETSIZE]; | 31 | static char g_ipc_packet[IPC_PACKETSIZE]; | 
| 32 | static int * const g_ipc_packet_int = (int*)g_ipc_packet; | 32 | static int * const g_ipc_packet_int = (int*)g_ipc_packet; | 
| 33 | static struct pidfh * g_pidfilehandle; | 33 | static struct pidfh * g_pidfilehandle; | 
| 34 | static char * g_uds_path = "/var/run/jaildaemon.pipe"; | ||
| 34 | 35 | ||
| 35 | /* For house keeping a list of all processes we attach to jails (probes), with | 36 | /* For house keeping a list of all processes we attach to jails (probes), with | 
| 36 | an initial vector size of 128. The vector never shrinks. */ | 37 | an initial vector size of 128. The vector never shrinks. */ | 
| @@ -48,7 +49,7 @@ typedef struct { | |||
| 48 | /* Forward declarations */ | 49 | /* Forward declarations */ | 
| 49 | static void term_handler( int signal ); | 50 | static void term_handler( int signal ); | 
| 50 | static void kill_all_probes( void ); | 51 | static void kill_all_probes( void ); | 
| 51 | static void remove_pidfile( void ); | 52 | static void remove_files( void ); | 
| 52 | static int check_for_jail( int jid ); | 53 | static int check_for_jail( int jid ); | 
| 53 | static int copy_daemontask( daemon_task ** out, daemon_task * const in ); | 54 | static int copy_daemontask( daemon_task ** out, daemon_task * const in ); | 
| 54 | static int add_task_to_kqueue( int kq, daemon_task * task_in ); | 55 | static int add_task_to_kqueue( int kq, daemon_task * task_in ); | 
| @@ -92,7 +93,8 @@ static void exerr( char * message, ... ) { | |||
| 92 | static void usage( char * cmd ) { | 93 | static void usage( char * cmd ) { | 
| 93 | fprintf( stderr, | 94 | fprintf( stderr, | 
| 94 | "%s -D [-ppidfile] [-fipcsockpath]\n" | 95 | "%s -D [-ppidfile] [-fipcsockpath]\n" | 
| 95 | "%s -c command -j jid [-t proctitle] [-r]\n", cmd, cmd ); | 96 | "%s -c command -j jid [-t proctitle] [-rR] [-fipcsockpath]\n", | 
| 97 | cmd, cmd ); | ||
| 96 | exit( 1 ); | 98 | exit( 1 ); | 
| 97 | } | 99 | } | 
| 98 | 100 | ||
| @@ -195,6 +197,8 @@ static pid_t fork_and_jail( int jid, char * proctitle ) { | |||
| 195 | /* Set proctitle so that jail's pgrep -f can identify the process */ | 197 | /* Set proctitle so that jail's pgrep -f can identify the process */ | 
| 196 | if( proctitle && *proctitle ) | 198 | if( proctitle && *proctitle ) | 
| 197 | setproctitle( "%s", proctitle ); | 199 | setproctitle( "%s", proctitle ); | 
| 200 | else | ||
| 201 | setproctitle( "PROBE" ); | ||
| 198 | 202 | ||
| 199 | /* Throw ourself into the jail */ | 203 | /* Throw ourself into the jail */ | 
| 200 | if( jail_attach( jid ) ) | 204 | if( jail_attach( jid ) ) | 
| @@ -239,9 +243,9 @@ static int copy_daemontask( daemon_task ** out, daemon_task * const in ) { | |||
| 239 | static void fork_and_execve( int kq, daemon_task * t_in ) { | 243 | static void fork_and_execve( int kq, daemon_task * t_in ) { | 
| 240 | char * shell = "/bin/sh"; | 244 | char * shell = "/bin/sh"; | 
| 241 | char * envp[] = { "PATH=/bin:/sbin:/usr/bin:/usr/sbin", NULL }; | 245 | char * envp[] = { "PATH=/bin:/sbin:/usr/bin:/usr/sbin", NULL }; | 
| 242 | pid_t pid; | 246 | struct kevent ke; | 
| 243 | 247 | daemon_task * t; | |
| 244 | pid = fork(); | 248 | pid_t pid = fork(); | 
| 245 | 249 | ||
| 246 | switch( pid ) { | 250 | switch( pid ) { | 
| 247 | case -1: | 251 | case -1: | 
| @@ -259,33 +263,34 @@ static void fork_and_execve( int kq, daemon_task * t_in ) { | |||
| 259 | break; | 263 | break; | 
| 260 | default: | 264 | default: | 
| 261 | /* If no respawn requested, just let the command finish */ | 265 | /* If no respawn requested, just let the command finish */ | 
| 262 | if( !(t_in->m_flags & 0x01) ) | 266 | switch( t_in->m_flags ) { | 
| 263 | return; | 267 | case TASK_SINGLESHOT: | 
| 264 | |||
| 265 | /* else add process to our process watch list, so we get notified, | ||
| 266 | once it finishes to be able to respawn. ("else" to open block) */ | ||
| 267 | else { | ||
| 268 | struct kevent ke; | ||
| 269 | daemon_task * t; | ||
| 270 | |||
| 271 | /* Try to take a copy of task struct. If this fails, then only | ||
| 272 | respawn fails. */ | ||
| 273 | if( copy_daemontask( &t, t_in ) ) | ||
| 274 | return; | 268 | return; | 
| 275 | 269 | case TASK_RESPAWN: | |
| 276 | /* Signal that this is a process that shall respawn the task | 270 | /* Try to take a copy of task struct. If this fails, | 
| 277 | in jail */ | 271 | then only respawn fails. */ | 
| 278 | t->m_flags |= 0x02; | 272 | if( copy_daemontask( &t, t_in ) ) | 
| 279 | 273 | return; | |
| 280 | memset( &ke, 0, sizeof ke ); | 274 | |
| 281 | EV_SET( &ke, pid, EVFILT_PROC, EV_ADD, NOTE_EXIT, 0, t ); | 275 | /* Signal that this is a process that shall respawn | 
| 282 | if( kevent( kq, &ke, 1, NULL, 0, NULL ) == -1 ) { | 276 | the task in jail */ | 
| 283 | /* If adding the event fails, get rid of struct */ | 277 | t->m_flags = TASK_RESPAWNING; | 
| 284 | warn( "Can not put respawn watcher pid on the kqueue" ); | 278 | |
| 285 | free( t->m_commandline ); | 279 | /* add process to our process watch list, so we get | 
| 286 | free( t->m_proctitle ); | 280 | notified, once it finishes to be able to respawn. */ | 
| 287 | free( t ); | 281 | memset( &ke, 0, sizeof ke ); | 
| 288 | } | 282 | EV_SET( &ke, pid, EVFILT_PROC, EV_ADD, NOTE_EXIT, 0, t ); | 
| 283 | if( kevent( kq, &ke, 1, NULL, 0, NULL ) == -1 ) { | ||
| 284 | /* If adding the event fails, get rid of struct */ | ||
| 285 | warn( "Can not put respawn watcher pid on the kqueue" ); | ||
| 286 | free( t->m_commandline ); | ||
| 287 | free( t->m_proctitle ); | ||
| 288 | free( t ); | ||
| 289 | } | ||
| 290 | break; | ||
| 291 | case TASK_RESPAWN_IMMEDIATE: | ||
| 292 | add_task_to_kqueue( kq, t_in ); | ||
| 293 | break; | ||
| 289 | } | 294 | } | 
| 290 | break; | 295 | break; | 
| 291 | } | 296 | } | 
| @@ -302,8 +307,9 @@ static void kill_all_probes( void ) { | |||
| 302 | g_probes = 0; | 307 | g_probes = 0; | 
| 303 | } | 308 | } | 
| 304 | 309 | ||
| 305 | static void remove_pidfile( void ) { | 310 | static void remove_files( void ) { | 
| 306 | pidfile_remove( g_pidfilehandle ); | 311 | pidfile_remove( g_pidfilehandle ); | 
| 312 | unlink(g_uds_path); | ||
| 307 | } | 313 | } | 
| 308 | 314 | ||
| 309 | static int add_task_to_kqueue( int kq, daemon_task * t_in ) { | 315 | 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 ) { | |||
| 347 | for( i = 0; i < g_probes_size; ++i ) | 353 | for( i = 0; i < g_probes_size; ++i ) | 
| 348 | if( !g_probes[i] ) { | 354 | if( !g_probes[i] ) { | 
| 349 | g_probes[i] = pid; | 355 | g_probes[i] = pid; | 
| 356 | /* SUCCESS */ | ||
| 350 | return 0; | 357 | return 0; | 
| 351 | } | 358 | } | 
| 352 | 359 | ||
| @@ -360,10 +367,11 @@ static int add_task_to_kqueue( int kq, daemon_task * t_in ) { | |||
| 360 | probes[g_probes_size] = pid; | 367 | probes[g_probes_size] = pid; | 
| 361 | g_probes_size *= 4; | 368 | g_probes_size *= 4; | 
| 362 | g_probes = probes; | 369 | g_probes = probes; | 
| 370 | /* SUCCESS */ | ||
| 363 | return 0; | 371 | return 0; | 
| 364 | } | 372 | } | 
| 365 | } | 373 | } | 
| 366 | 374 | /* FAIL branch */ | |
| 367 | /* If we added a kevent filter but failed to store the pid for our | 375 | /* If we added a kevent filter but failed to store the pid for our | 
| 368 | house keeping, remove the kqueuei filter again (and kill probe) */ | 376 | house keeping, remove the kqueuei filter again (and kill probe) */ | 
| 369 | EV_SET( &ke, pid, EVFILT_PROC, EV_DELETE, NOTE_EXIT, 0, t ); | 377 | 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 ) { | |||
| 380 | return -1; | 388 | return -1; | 
| 381 | } | 389 | } | 
| 382 | 390 | ||
| 383 | /* jaildaemon -D <-ppidfile> <-fipcsockpath> -c command -j jid -t proctitle <-r> | 391 | /* jaildaemon -D [-ppidfile] [-fipcsockpath] | 
| 392 | jaildaemon -c command -j jid -t proctitle [-rR] [-fipsockpath] | ||
| 384 | */ | 393 | */ | 
| 385 | int main( int argc, char **argv ) { | 394 | int main( int argc, char **argv ) { | 
| 386 | pid_t second_pid; | 395 | pid_t second_pid; | 
| 387 | int kq, i; | 396 | int kq, i; | 
| 388 | int o_force_daemon = 0; | 397 | int o_force_daemon = 0; | 
| 389 | int o_daemonize = 0, o_jid = -1, o_respawn = 0; | 398 | int o_daemonize = 0, o_jid = -1, o_respawn = TASK_SINGLESHOT; | 
| 390 | char *o_command = NULL, *o_pidfile = NULL, *o_proctitle = NULL; | 399 | char *o_command = NULL, *o_pidfile = NULL, *o_proctitle = NULL; | 
| 391 | char *o_uds_path = "/var/run/jaildaemon.pipe"; | ||
| 392 | struct kevent ke; | 400 | struct kevent ke; | 
| 393 | struct sockaddr_un addr; | 401 | struct sockaddr_un addr; | 
| 394 | struct sigaction sa; | 402 | struct sigaction sa; | 
| @@ -401,15 +409,16 @@ int main( int argc, char **argv ) { | |||
| 401 | 409 | ||
| 402 | i=1; | 410 | i=1; | 
| 403 | while(i) { | 411 | while(i) { | 
| 404 | switch( getopt( argc, argv, "DFrt:c:j:p:f:" ) ) { | 412 | switch( getopt( argc, argv, "DFrRt:c:j:p:f:" ) ) { | 
| 405 | case -1: i=0; break; | 413 | case -1: i=0; break; | 
| 406 | case 'D': o_daemonize = 1; break; | 414 | case 'D': o_daemonize = 1; break; | 
| 407 | case 'r': o_respawn = 1; break; | 415 | case 'r': o_respawn = TASK_RESPAWN; break; | 
| 416 | case 'R': o_respawn = TASK_RESPAWN_IMMEDIATE; break; | ||
| 408 | case 't': o_proctitle = optarg; break; | 417 | case 't': o_proctitle = optarg; break; | 
| 409 | case 'c': o_command = optarg; break; | 418 | case 'c': o_command = optarg; break; | 
| 410 | case 'j': o_jid = strtol( optarg, 0, 0 ); break; | 419 | case 'j': o_jid = strtol( optarg, 0, 0 ); break; | 
| 411 | case 'p': o_pidfile = optarg; break; | 420 | case 'p': o_pidfile = optarg; break; | 
| 412 | case 'f': o_uds_path = optarg; break; | 421 | case 'f': g_uds_path = optarg; break; | 
| 413 | case 'F': o_force_daemon = 1; break; | 422 | case 'F': o_force_daemon = 1; break; | 
| 414 | case '?': usage( argv[0]); exit(0); break; | 423 | case '?': usage( argv[0]); exit(0); break; | 
| 415 | } | 424 | } | 
| @@ -429,14 +438,14 @@ int main( int argc, char **argv ) { | |||
| 429 | 438 | ||
| 430 | memset(&addr, 0, sizeof(addr)); | 439 | memset(&addr, 0, sizeof(addr)); | 
| 431 | addr.sun_family = AF_UNIX; | 440 | addr.sun_family = AF_UNIX; | 
| 432 | strncpy(addr.sun_path, o_uds_path, sizeof(addr.sun_path)-1); | 441 | strncpy(addr.sun_path, g_uds_path, sizeof(addr.sun_path)-1); | 
| 433 | 442 | ||
| 434 | if( !o_daemonize ) { | 443 | if( !o_daemonize ) { | 
| 435 | /* In utility mode try to pipe the request to the daemon already running | 444 | /* In utility mode try to pipe the request to the daemon already running | 
| 436 | and exit | 445 | and exit | 
| 437 | 446 | ||
| 438 | Packed packet format: | 447 | Packed packet format: | 
| 439 | int m_flags ( 0x01 respawn, 0x02 executing, to be respawned ) | 448 | int m_flags: SINGLESHOT, RESPAWN, RESPAWN_IMMEDIATE, RESPAWNING | 
| 440 | int m_jid | 449 | int m_jid | 
| 441 | int m_commandline_length | 450 | int m_commandline_length | 
| 442 | int m_proctitle_length | 451 | int m_proctitle_length | 
| @@ -504,8 +513,8 @@ int main( int argc, char **argv ) { | |||
| 504 | g_fork_slave_fd = fork_fork_slave( ); | 513 | g_fork_slave_fd = fork_fork_slave( ); | 
| 505 | 514 | ||
| 506 | /* Register pid file remover after fork() so that fork slave wont remove our | 515 | /* Register pid file remover after fork() so that fork slave wont remove our | 
| 507 | pid file*/ | 516 | pid file, also unlink our pipe at exit */ | 
| 508 | atexit( remove_pidfile ); | 517 | atexit( remove_files ); | 
| 509 | 518 | ||
| 510 | /* Initialize syslog facilities */ | 519 | /* Initialize syslog facilities */ | 
| 511 | openlog( "jaildaemon", 0, LOG_DAEMON ); | 520 | openlog( "jaildaemon", 0, LOG_DAEMON ); | 
| @@ -516,7 +525,7 @@ int main( int argc, char **argv ) { | |||
| 516 | 525 | ||
| 517 | /* Create the unix domain socket to receive commands on, N.B. error goes to | 526 | /* Create the unix domain socket to receive commands on, N.B. error goes to | 
| 518 | syslog, now */ | 527 | syslog, now */ | 
| 519 | unlink(o_uds_path); | 528 | unlink(g_uds_path); | 
| 520 | if (bind(g_uds, (struct sockaddr*)&addr, sizeof(addr)) == -1) | 529 | if (bind(g_uds, (struct sockaddr*)&addr, sizeof(addr)) == -1) | 
| 521 | exerr( "binding to command channel. Maybe another daemon is running?" ); | 530 | exerr( "binding to command channel. Maybe another daemon is running?" ); | 
| 522 | 531 | ||
| @@ -585,8 +594,8 @@ int main( int argc, char **argv ) { | |||
| 585 | 594 | ||
| 586 | /* If this task was watched to respawn a daemon in the jail, | 595 | /* If this task was watched to respawn a daemon in the jail, | 
| 587 | do it now */ | 596 | do it now */ | 
| 588 | if( task->m_flags & 0x02 ) { | 597 | if( task->m_flags == TASK_RESPAWNING ) { | 
| 589 | task->m_flags &= ~0x02; | 598 | task->m_flags = TASK_RESPAWN; | 
| 590 | add_task_to_kqueue( kq, task ); | 599 | add_task_to_kqueue( kq, task ); | 
| 591 | 600 | ||
| 592 | /* If the process exited with the correct magic code, | 601 | /* If the process exited with the correct magic code, | 
