diff options
author | erdgeist <> | 2013-03-13 12:48:43 +0000 |
---|---|---|
committer | erdgeist <> | 2013-03-13 12:48:43 +0000 |
commit | d170c239211b5d19b222627b7ee476c1e851895d (patch) | |
tree | 400088d45f6d30d4c3ea9e877b5423f20c2a8981 | |
parent | 84994f9fde1a1e88eeca2d9cb2cebd9160a71d55 (diff) |
Make m_flags an enum, set a neutral proctitle if none given, remove ipc pipe atexit() and add an immediate respawn option
-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, |