#!/usr/local/bin/perl # relaunch.pl # A functional example of how to automatically restart an SSL server # that requires a pass phrase at launch time. If the server # crashes, this script will relaunch it and send the webmaster mail # indicating when the problem happened. # See "Web Security, A Step-by-Step Reference Guide" by Lincoln Stein, page 289 # To run: # 1) ./relaunch.pl # 2) type your pass phrase when prompted # 3) put it into the background if desired # 4) send process signals to control it: # a) HUP: reconfigure http daemon # b) TERM: kill http daemon AND script # Known problem: on some systems, HUP will not correctly # reconfigure the http daemon. You need to send http daemon # a TERM signal and let restart.pl reinitialize it. This # script has not been extensively tested and may need tweaking # to work on your system. # Before calling this program, it is strongly suggested that # you set the core dump size limit to zero so that someone # cannot retrieve the pass phrase from a perl core dump. # CHANGE THESE FOR YOUR INSTALLATION # Check server every 5 seconds. Doesn't hurt to make this # more frequent. $CHECK_TIME = 5; # location of the server and ssl roots $SERVER_ROOT = '/usr/local/etc/https'; $SSLTOP = '/usr/local/etc/https/ssl'; # location of stty program (for turning off terminal echo) $STTY = '/bin/stty'; # Location of the server executable and its arguments. $STRONGHOLD = "./httpsd"; @ARGS = ('-d' => $SERVER_ROOT, '-f' => 'conf/httpd.conf'); # Location of the PID file $PID_FILE = "$SERVER_ROOT/logs/httpd.pid"; # Location of sendmail $SENDMAIL = '/usr/lib/sendmail'; # E-mail address of person to send restart notification to. $NOTIFY = 'webmaster'; # Set this to 1 if you want verbose debugging messages $DEBUG = 0; # Set this to 1 if you want restart.pl to go into the # background automatically $BACKGROUND = 0; #----------------------------------------------------------------------- $ENV{IFS} = ''; $ENV{PATH}='/bin/:/usr/bin:/sbin:/usr/sbin'; # NO USER SERVICEABLE PARTS BELOW require "chat2.pl"; $SIG{HUP} = $SIG{TERM} = $SIG{INT} = 'send_signal'; $ENV{SSLTOP} = $SSLTOP unless $ENV{SSLTOP}; chdir $SERVER_ROOT; # Prompt for user password system "$STTY cbreak -echo >/dev/tty" and die "$STTY: $!"; # turn off echo print "Enter pass phrase:"; chomp ($PASSWD = ); print "\n"; system "$STTY -cbreak echo >/dev/tty"; # turn on echo die "No pass phrase. Aborted" unless $PASSWD; # Enter the background if requested if ($BACKGROUND) { exit 0 if fork(); # parent dies exit 0 if fork(); # child dies # We're running in background now } $PID = launch_server(); while (1) { sleep $CHECK_TIME; warn "Checking server" if $DEBUG; if ( !server_running() ) { $PID = launch_server(); message("Server died. Relaunched successfully.") if $PID; message("Server died. UNABLE TO RELAUNCH.") unless $PID; } } sub server_running { return undef unless $PID; # by sending a kill(0) to a process, we can find out # if it still exists without actually sending it a # signal. my $result = kill(0,$PID); warn "Got $result from kill(0,$PID)" if $DEBUG; return $result; } sub launch_server { my ($handle,$result,$gotit,$pid); warn "Launching server with $STRONGHOLD @ARGS\n"; $handle = chat::open_proc($STRONGHOLD,@ARGS); while ($result = chat::expect($handle,2, 'pass phrase:'=>1, '(.+)\n'=>'$1')) { if ($result == 1) { warn "printing pass phrase" if $DEBUG; &chat::print($handle,"$PASSWD\n"); $gotit++; } else { print "=> ",$result,"\n"; } } &chat::close($handle); wait or warn "No child processes"; return undef unless $gotit; # Return the httpd pid as the result sleep 5; open (PID,$PID_FILE) or die "Couldn't open PID file"; chomp($pid = ); close PID; warn "Launched https with pid $pid\n"; return $pid; } sub message { my $message = shift; my $time = localtime; print "$time: $message\n"; open (MAIL,"| $SENDMAIL -t -oi") or die "sendmail: $!"; print MAIL <