#!/usr/bin/perl -w # Licensed to the Apache Software Foundation (ASF) under one or more # contributor license agreements. See the NOTICE file distributed with # this work for additional information regarding copyright ownership. # The ASF licenses this file to You under the Apache License, Version 2.0 # (the "License"); you may not use this file except in compliance with # the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. ############################################################################## # $Id: vclclientd 1954 2008-12-12 14:46:02Z arkurth $ ############################################################################## =head1 NAME vclclientd =head1 SYNOPSIS perl vclclientd =head1 DESCRIPTION This is the executable module for running the VCL client daemon on Linux lab machines. =cut ############################################################################## use strict; use Getopt::Long; use diagnostics; use Symbol; use POSIX; $|=1; # turning off autoflush # -- DEVELOPMENT testing #my $PIDFILE = "/var/run/vcldev.pid"; #our $LOG = "/var/log/vcldev.log"; # GLOBALS our $HOME = "/home/vclstaff"; our $VCLFLAG = "$HOME/flag"; our $CLIENTDATA = "$HOME/clientdata"; our $PIDFILE ="/var/run/vclclientd.pid"; our %children = (); # keys are current child process IDs our $children = 0; # current number of children our $LOG = "/var/log/vclclientd.log"; our %ERRORS=('DEPENDENT'=>4,'UNKNOWN'=>3,'OK'=>0,'WARNING'=>1,'CRITICAL'=>2,'MAILMASTERS'=>5); our $opt_d=''; Getopt::Long::Configure('bundling', 'no_ignore_case'); GetOptions('d|debug' => \$opt_d ); if(!$opt_d){ #daemonize &daemonize; } sub daemonize { chdir '/' or die "Can't chdir to /: $!"; defined(my $pid = fork) or die "Can't fork $!"; exit if $pid; #production $0 = "vclclientd"; print "Created process $$ renamed to $0 ...\n"; setsid or die "Can't start a new session: $!"; open STDIN, '/dev/null' or die "Can't read /dev/null $!"; open STDOUT, '>>$LOG' or die "Can't write $LOG $!"; open STDERR, '>>$LOG' or die "Can't write $LOG $!"; umask 0; open(PIDFILE, ">$PIDFILE"); # so I can kill myself easily print PIDFILE $$; close(PIDFILE); } #------- Subroutine declarations ------- sub main(); # main calls primary subroutines sub flag; sub processdata; sub startsshd; sub makedatestring; sub reboot; sub fetch; sub store; sub sshdstatus; sub createnewssh_config_vcl; sub restartsshd; sub REAPER { # takes care of dead children $SIG{CHLD} = \&REAPER; my $pid = wait; if(exists $children{$pid}){ $children--; notify($ERRORS{'OK'},"$pid -- child process exiting, deleting $pid "); delete $children{$pid}; } else{ notify($ERRORS{'OK'},"$pid -- sub process exiting"); } } sub HUNTSMAN { # signal handler for SIGINT local($SIG{CHLD}) = 'IGNORE'; # we're going to kill our child processes kill 'INT' => keys %children; notify($ERRORS{'OK'},"$$ -- process exiting"); exit; # clean up with dignity } # Install signal handlers. $SIG{CHLD} = \&REAPER; $SIG{INT} = \&HUNTSMAN; $SIG{QUIT} = \&HUNTSMAN; $SIG{HUP} = \&HUNTSMAN; $SIG{TERM} = \&HUNTSMAN; main(); sub main () { #preplogfile; #my @hostinfo = hostname; #make sure vclstaff owns authorized_keys and log file if(open(AUTHFILE,"chown vclstaff:root /home/vclstaff/authorized_keys 2>&1 |")){ notify($ERRORS{'OK'},"main: setting vclstaff ownership of /home/vclstaff/authorized_keys"); close(AUTHFILE); } if(open(LOGFILE,"chown vclstaff:root /var/log/vclclientd.log 2>&1 |")){ notify($ERRORS{'OK'},"main: setting vclstaff ownership of /var/log/vclclientd.log"); close(LOGFILE); } if(!(-r "/etc/users.local.admin")){ notify($ERRORS{'OK'},"main: /etc/users.local.admin does not exist creating"); if(open(COPY, "/bin/cp /etc/users.local /etc/users.local.admin |")){ close(COPY); if(-r "/etc/users.local.admin"){ notify($ERRORS{'OK'},"main: /etc/users.local.admin exist now"); } } } #on startup check to see if someone has rebooted us. this is a hack #we just need to figure out if this a reboot or a restart #for now we are just going to look at the output of last -- there has #to be a better way if(open(LAST,"/usr/bin/last 2>&1 |")){ my @last =; close(LAST); if($last[0] =~ /reboot/ || $last[1] =~ /reboot/){ if( -r "$CLIENTDATA"){ if(open(CLD, "$CLIENTDATA")){ my @file = ; close(CLD); if($file[0] =~ /new/){ if(open(FLAG, ">$VCLFLAG")){ print FLAG 1; close(FLAG); notify($ERRORS{'OK'},"main: possibly a reboot setting flag to 1 for reinitializing"); }#flag }#new }#CLD else{ notify($ERRORS{'OK'},"main: could not open $CLIENTDATA"); } }# readable }# last -- reboot } while(1){ if( flag ){ notify($ERRORS{'OK'},"main: flag is set proceed to process"); #make sure clientdata is readable if(-r $CLIENTDATA){ #process data if(open(CLIENTDATA,"$CLIENTDATA")){ my %request=(); my @lines = ; close(CLIENTDATA); $request{"state"}=$lines[0]; $request{"unityid"}=$lines[1]; $request{"remoteIP"}=$lines[2]; chomp($request{"state"}); chomp($request{"unityid"}); chomp($request{"remoteIP"}); make_new_child(%request) if($request{"state"} =~ /new|timeout|delete/); reboot() if($request{"state"} =~ /reboot/); fetch() if($request{"state"} =~ /fetch/); store() if($request{"state"} =~ /store/); } else{ notify($ERRORS{'OK'},"main: could not open $CLIENTDATA: $!"); } } #if -r } #if flag else{ #check for any hung children #kill fork process and reset flag? does this create a race condition #could keep track of killed processes in children hash when number exceeds X (reboot machine?) #notify($ERRORS{'OK'},"main: number of children $children"); foreach my $p (keys %children) { next if($p=~ /hung/); notify($ERRORS{'OK'},"main: pid = $p"); $children{"hungtries"}{"count"}+=1; if(open(KILL,"kill -9 $p 2>&1 |")){ notify($ERRORS{'OK'},"main: stopping forked process in an attempt to reset"); my $k = ; close(KILL); if($k =~ /No such process/){ #not found maybe I was too guick to judge #let it ride } else{ if($children{"hungtries"}{"count"} > 4){ notify($ERRORS{'OK'},"main: hung process attempts are greater than 4 rebooting"); reboot(); } if(open(ECHO,"echo 1 > /home/vclstaff/flag |")){ notify($ERRORS{'OK'},"main: attempt to reset initiated"); close(ECHO); } } } } } sleep 5; } #while } sub flag { if(!(-e $VCLFLAG)){ # warning flag does not exist #create it and continue if(open(FLAG, ">$VCLFLAG")){ print FLAG 0; notify($ERRORS{'OK'}, "had to create $VCLFLAG"); close(FLAG); if(open(LOGFILE,"chown vclstaff:root /home/vclstaff/flag 2>&1 |")){ notify($ERRORS{'OK'},"main: setting vclstaff ownership of /home/vclstaff/flag"); close(LOGFILE); } if(open(LOGFILE,"chmod 640 /home/vclstaff/flag 2>&1 |")){ notify($ERRORS{'OK'},"main: setting 640 perms /home/vclstaff/flag"); close(LOGFILE); } } else{ notify($ERRORS{'OK'},"could not create $VCLFLAG $! will try to delete"); unlink $VCLFLAG; return 0; } } my @lines; # VCLFLAG file exists, check contents if(open(FLAG, "$VCLFLAG")){ @lines = ; close(FLAG); # clear flag if(open(FLAG, ">$VCLFLAG")){ print FLAG 0; close(FLAG); } else{ unlink $VCLFLAG; } return $lines[0]; } else{ notify($ERRORS{'OK'},"flag: could not open $VCLFLAG $!"); return 0; } } sub make_new_child { my (%request_data) = @_; my $pid; my $sigset; # block signal for fork $sigset = POSIX::SigSet->new(SIGINT); sigprocmask(SIG_BLOCK, $sigset) or die "Can't block SIGINT for fork: $!\n"; #die "fork: $!" unless defined ($pid = fork); FORK: { if ($pid = fork) { # Parent records the child's birth # and returns. sigprocmask(SIG_UNBLOCK, $sigset) or die "Can't unblock SIGINT for fork: $!\n"; $children{$pid} = 1; $children++; notify($ERRORS{'OK'},"vclclientd current number of forked kids: $children"); return; } elsif(defined $pid) { # Child can *not* return from this subroutine. $SIG{INT} = 'DEFAULT'; # make SIGINT kill us as it did before unblock signals sigprocmask(SIG_UNBLOCK, $sigset) or die "Can't unblock SIGINT for fork: $!\n"; notify($ERRORS{'OK'},"processdata: new request child process $request_data{state} $request_data{unityid},$request_data{remoteIP} "); #do something that may take a long time or needs to be monitored #based on the case lets do something if($request_data{state} =~ /new/){ notify($ERRORS{'OK'},"processdata: new request $request_data{unityid},$request_data{remoteIP} "); if(new_state($request_data{unityid},$request_data{remoteIP})){ notify($ERRORS{'OK'},"processdata: connection for $request_data{unityid}\@$request_data{remoteIP} successfully opened"); } } elsif($request_data{"state"} =~ /timeout|deleted/){ if(timeout_state($request_data{unityid},$request_data{remoteIP})){ notify($ERRORS{'OK'},"vclclientd: connection for $request_data{unityid}\@$request_data{remoteIP} successfully terminated"); } } exit; } elsif ($! =~ /No more process/){ sleep 5; redo FORK; } else { # strange error die "Can't fork: $!\n"; } } } sub new_state { my ($user,$remoteIP) =@_; # assumuption user and IP are valid # add user to users.local, sshd_config_vcl # on acknowledgemment turn on sshd on port 22 my @file; my $line; my ($userset,$remoteIPset) = 0; #test for sshd_config_vcl if(!(-r "$HOME/sshd_config_vcl")){ #hrmm. were did sshd_config_vcl go #let try to create another from the orignal if(createnewssh_config_vcl){ notify($ERRORS{'OK'},"new_state: sshd_config_vcl missing created a new one"); } else{ notify($ERRORS{'OK'},"new_state: sshd_config_vcl missing failed to create a new one"); return 0; } } if(open(CONFIG,"$HOME/sshd_config_vcl")){ @file = ; close(CONFIG); foreach $line (@file){ if($line =~ /AllowUsers/){ $line = "AllowUsers $user\n"; $userset=1; notify($ERRORS{'OK'},"new_state: adding AllowUsers $user to sshd_config_vcl"); } } if(!$userset){ push @file, "AllowUsers $user\n"; notify($ERRORS{'OK'},"new_state: hrmm, had to add AllowUsers $user to sshd_config_vcl"); } if(open(CONFIG,">$HOME/sshd_config_vcl")){ print CONFIG @file; close(CONFIG); } } # append to users.local if(open(USERSLOCAL,"/etc/users.local")){ my @users = ; close(USERSLOCAL); push @users,"\n$user\n"; if(open(USERSLOCAL,">/etc/users.local")){ print USERSLOCAL @users; notify($ERRORS{'OK'},"new_state: adding $user to users.local"); close(USERSLOCAL); } } else{ notify($ERRORS{'WARNING'},"new_state: could not open /etc/users.local $!"); return 0; } #start sshd if(startsshd){ notify($ERRORS{'OK'},"new_state: startsshd returned and successful"); return 1; } return 0; } sub timeout_state{ # time to close non-admin ssh sessions and clean up users.local, # sshd_config_vcl my ($user,$remoteIP) =@_; my $os = lc($^O); #notify($ERRORS{'OK'},"timeout_state: OSname is $os"); my @file; my $l; my $sshd_admin_pid =0; my ($pgrep,$pkill); # get admin pid if($os eq "solaris"){ $pgrep="/bin/pgrep"; $pkill="/bin/pkill"; if(open(SSH,"/local/openssh/etc/sshd.admin.pid")){ @file = ; close(SSH); $sshd_admin_pid=$file[0]; notify($ERRORS{'OK'},"timeout_state: sshd_admin_pid set $sshd_admin_pid"); } else{ notify($ERRORS{'OK'},"timeout_state: could not open /local/openssh/etc/sshd.admin.pid $!"); } } elsif($os eq "linux"){ $pgrep="/usr/bin/pgrep"; $pkill="/usr/bin/pkill"; if(open(SSH,"ps -ef \| grep /usr/sbin/sshd |")){ @file = ; close(SSH); $sshd_admin_pid=$file[0]; foreach $l (@file){ chomp ($l); next if($l =~ /grep/); if($l =~ /(\/usr\/sbin\/sshd$)/){ my $blah; ($blah,$sshd_admin_pid,$blah) = split(/\s+/,$l,3); notify($ERRORS{'OK'},"timeout_state: sshd_admin_pid set $sshd_admin_pid"); } } } else{ notify($ERRORS{'OK'},"timeout_state: execute ps -ef $!"); } } else{ notify($ERRORS{'OK'},"timeout_state: $os not supported"); # we'll just let this ride and get a restart } # clean up users.local # collect members of users.admin,users.base, and users.cluster my @users_admin; my @users_base; my @users_cluster; my $u; #this one should exist if(open(USERSLOCAL,"cat /etc/users.local.admin > /etc/users.local |")){ close(USERSLOCAL); notify($ERRORS{'OK'},"timeout_state: dumped contents of /etc/users.local.admin /etc/users.local"); } if(-r "/etc/users.local.base"){ if(open(USERSLOCAL,"cat /etc/users.local.base >> /etc/users.local |")){ close(USERSLOCAL); notify($ERRORS{'OK'},"timeout_state: dumped contents of /etc/users.local.base /etc/users.local"); } } if(-r "/etc/users.local.cluster"){ if(open(USERSLOCAL,"cat /etc/users.local.cluster >> /etc/users.local |")){ close(USERSLOCAL); notify($ERRORS{'OK'},"timeout_state: dumped contents of /etc/users.local.cluster /etc/users.local"); } } if(open(USERSLOCAL,"/etc/users.local")){ @users_admin=; close(USERSLOCAL); } # check users.local add vclstaff if is does not exist my $vclstaff=0; my $i; for $i (@users_admin){ $vclstaff =1 if($i =~ "vclstaff"); } if(!$vclstaff){ push @users_admin, "\nvclstaff\n"; if(open(USERSLOCAL,"> /etc/users.local")){ print USERSLOCAL @users_admin; close(USERSLOCAL); } } # clean up our sshd_config_vcl my @SSH; my $s; if(open(SSHDCONFIG, "$HOME/sshd_config_vcl")){ @SSH = ; close(SSHDCONFIG); foreach $s (@SSH){ if($s =~ s/AllowUsers $user/AllowUsers/g){ notify($ERRORS{'OK'},"timeout_state: $user\@$remoteIP removed from sshd_config_vcl"); } } # write back out to sshd_config_vcl if(open(SSHDCONFIG, ">$HOME/sshd_config_vcl")){ print SSHDCONFIG @SSH; close (SSHDCONFIG); } else{ notify($ERRORS{'OK'},"timeout_state: could not open $HOME/sshd_config_vcl for writing"); } } #kill off any user processes if(open(PKILL, "$pkill -9 -U $user 2>&1 |")){ my @pkill=; close(PKILL); notify($ERRORS{'OK'},"timeout_state: stopped user processes"); #check for user notify($ERRORS{'OK'},"timeout_state: confirming user processes are stopped"); if(open(PGREP, "ps -ef \| grep $user|")){ my @pgrep=; close(PGREP); foreach my $pid (@pgrep){ next if($pid =~ /grep/); my($userblah,$userpid) = split(/\s+/,$pid,3); if($userpid){ if(open(KILL, "kill -9 $userpid |")){ notify($ERRORS{'OK'},"timeout_state: killed user process $userpid"); close(KILL); } } } } } notify($ERRORS{'OK'},"timeout_state: checking for all sshd processes"); # use pgrep to get all sshd pids if(open(PGREP,"ps -ef \|grep sshd 2>&1|")){ my @pfile = ; close(PGREP); foreach $l (@pfile){ next if($l =~ /grep/); next if($l =~ /ps -ef/); notify($ERRORS{'OK'},"timeout_state: pgrep sshd = $l"); my ($b,$sshpid); ($b,$b,$sshpid,$b) = split(/\s+/,$l,4) if($os eq "solaris"); ($b,$sshpid) = split(/\s+/,$l,3) if($os eq "linux"); next if($sshpid == $sshd_admin_pid); if(open(KILL, "kill -9 $sshpid |")){ notify($ERRORS{'OK'},"timeout_state: killed sshd process $sshpid"); close(KILL); } } notify($ERRORS{'OK'},"timeout_state: checking if I accidentially killed all sshd processes"); # did we kill all sshd sessions? if(open(PGREP,"ps -ef \|grep sshd \|grep -v grep |")){ notify($ERRORS{'OK'},"timeout_state: executed ps -ef \|grep sshd \|grep -v grep"); @file = ; notify($ERRORS{'OK'},"timeout_state: @file"); close(PGREP); if(!($file[0])){ notify($ERRORS{'OK'},"timeout_state: killed all sshd processes, will try to restart"); if(open(SSHD,"/etc/inet.d/sshd start |")){ @file = ; close(SSHD); notify($ERRORS{'OK'},"timeout_state: sshd admin restarted @file"); } } } } else{ notify($ERRORS{'WARNING'},"timeout_state: could not execute /usr/bin/pgrep sshd"); } notify($ERRORS{'OK'},"timeout_state: looking for sshd_config_vcl"); #look for sshd_config_vcl in case we killed the sshd_admin pid if(open(SSH,"ps -ef \| grep /usr/sbin/sshd |")){ my @sshfile = ; close(SSH); foreach $l (@sshfile) { if($l =~ /(\/home\/vclstaff\/sshd_config_vcl\/)/){ # for some reason sshd with the vcl config file did not get stopped #initiate a restart/reload notify($ERRORS{'OK'},"timeout_state: sshd_config_vcl not stopped for some reason, prhaps the wrong sshd pid"); my ($b,$sshpid) = split(/\s+/,$l,3); if($sshpid == $sshd_admin_pid){ notify($ERRORS{'OK'},"timeout_state: killed the wrong sshd pid"); #kill this pid if(open(KILL, "kill -9 $sshpid |")){ notify($ERRORS{'OK'},"timeout_state: killed sshd process $l"); close(KILL); } #stop and start sshd service. if(open(SSHSTOP,"/etc/inet.d/sshd stop |")){ @file = ; close(SSHSTOP); notify($ERRORS{'OK'},"timeout_state: sshd admin stopped @file"); if(open(SSHSTART, "/etc/inet.d/sshd start |")){ @file=; close(SSHSTART); notify($ERRORS{'OK'},"timeout_state: sshd admin started @file"); } } } } } } if(sshdstatus){ notify($ERRORS{'OK'},"timeout_state: sshd core process is running"); } else{ notify($ERRORS{'CRITICAL'},"timeout_state: sshd is not running or could not be restarted"); } return 1; } sub reboot { #simply reboot the client when called my $os = lc($^O); my $reboot; if($os eq "solaris"){ $reboot = "/usr/sbin/shutdown -y -g 0 -i 6"; } else{ $reboot = "/sbin/shutdown -r now"; } notify($ERRORS{'OK'},"reboot: starting reboot sequence"); if(open(REBOOT,"$reboot 2>&1 |")){ my @reboot=; close(REBOOT); notify($ERRORS{'OK'},"reboot: @reboot"); return 1; } } sub fetch { #collect host ssh keys and save for MN to pick up notify($ERRORS{'OK'},"fetch: copying ssh keys to $HOME"); my $os = lc($^O); my $sshdir; if($os eq "solaris"){ $sshdir = "/local/openssh/etc"; } else{ $sshdir = "/etc/ssh/"; } if(open(CP, "/bin/cp $sshdir/ssh_host\* $HOME 2>&1 |")){ my @cp=; close(CP); if(@cp){ notify($ERRORS{'OK'},"fetch: copy problems - @cp"); } if(open(CHOWN,"/bin/chown vclstaff $HOME/ssh_host\* 2>&1 |")){ my @chown=; close(CHOWN); if(@chown){ notify($ERRORS{'OK'},"fetch: chown problems - @cp"); } } } notify($ERRORS{'OK'},"fetch: fetch complete"); return 1; } sub store { # take host ssh keys stored in my home directory and place them into the /etc/sshd directory #create an orig directory in $sshdir #copy original keys to orig dir #cp given keys to proper location #set correct ownership and premissions on keys #unlink/remove locally stored keys from vclstaff dir my $os = lc($^O); my $sshdir; if($os eq "solaris"){ $sshdir = "/local/openssh/etc"; } else{ $sshdir = "/etc/ssh"; } notify($ERRORS{'OK'},"store: copying ssh keys to $sshdir"); my %filelist; $filelist{"dsa"}="ssh_host_dsa_key"; $filelist{"dsapub"}="ssh_host_dsa_key.pub"; $filelist{"rsa"}="ssh_host_rsa_key"; $filelist{"rsapub"}="ssh_host_rsa_key.pub"; $filelist{"key"}="ssh_host_key"; $filelist{"keypub"}="ssh_host_key.pub"; if(!(-d "$sshdir/origkeys")){ if(mkdir("$sshdir/origkeys", 755)){ notify($ERRORS{'OK'},"store: mkdir successfully created $sshdir/origkeys"); } else{ notify($ERRORS{'OK'},"store: mkdir $sshdir/origkeys $! "); } } else{ #hrmm $sshdir/origkeys already exists } #copy system generated keys to orig dir #copy stored keys to ssh dir #set perms,ownership,unlink local copy foreach my $f(sort keys %filelist) { if(!(-f "$HOME/$filelist{$f}")){ notify($ERRORS{'OK'},"store: does not exist $HOME/$filelist{$f}"); next; } if(open(CP,"/bin/cp $sshdir/$filelist{$f} $sshdir/origkeys 2>&1 |")){ my @cp=; close(CP); if(@cp){ notify($ERRORS{'OK'},"store: copy orig keys problem on $filelist{$f} - @cp"); } } #copy given keys to ssh dir if(open(CP,"/bin/cp $HOME/$filelist{$f} $sshdir/$filelist{$f} 2>&1 |")){ my @cp=; close(CP); if(@cp){ notify($ERRORS{'OK'},"store: copy given keys problem on $filelist{$f} - @cp"); } else{ notify($ERRORS{'OK'},"store: copied $filelist{$f} to $sshdir"); if(open(CHOWN, "/bin/chown root:root $sshdir/$filelist{$f} 2>&1 |")){ close(CHOWN); } my $p; if($f =~ /pub/){ $p = 644; } else{ $p = 600; } if(open(CHMOD, "/bin/chmod $p $sshdir/$filelist{$f} 2>&1|")){ my @chmod=; close(CHMOD); if(@chmod){ notify($ERRORS{'OK'},"store: chmod problem on $filelist{$f} - @chmod"); } }#chmod }#else no cp problems }#CP #unlink if(unlink "$HOME/$filelist{$f}"){ notify($ERRORS{'OK'},"store: deleted $HOME/$filelist{$f}"); } else{ notify($ERRORS{'OK'},"store: unable to delete $HOME/$filelist{$f}"); } }#foreach #restart sshd if(restartsshd){ notify($ERRORS{'OK'},"store: sshd restarted"); return 1; } else{ notify($ERRORS{'OK'},"store: sshd restart failed"); return 0; } return 1; } sub restartsshd { my $os = lc($^O); notify($ERRORS{'OK'},"restartsshd: attempting to restart sshd on $os"); if($os eq "solaris"){ if(open(STOP,"/bin/pkill -f sshd_admin.cfg 2>&1 |")){ my @stop=; close(STOP); foreach my $r (@stop) { if($r =~ /failed/i){ notify($ERRORS{'WARNING'},"restartsshd: sshd stop failed @stop"); } } if(open(START,"/etc/init.d/sshd start 2>&1 |")){ my @start=; close(START); foreach my $r (@start) { #notify($ERRORS{'OK'},"restartsshd: output $r"); if($r =~ /failed/i){ notify($ERRORS{'WARNING'},"restartsshd: sshd start failed @start"); } return 1 if($r =~ /ok/i); } }#if start } # pkill } elsif($os =~ /linux/){ if(open(RESTART,"/etc/init.d/sshd restart 2>&1 |")){ my @restart=; close(RESTART); foreach my $r (@restart) { if($r =~ /failed/i){ notify($ERRORS{'WARNING'},"restartsshd: sshd restart failed $r @restart"); } if($r =~ /Starting/){ return 1 if($r =~ /ok/i); } } } } return 1; } sub startsshd { my @lines; #figure out OS solaris or linux my $os= lc($^O); my @output; my $l; if($os eq "solaris"){ if(open(SSHD,"/local/openssh/sbin/sshd -f $HOME/sshd_config_vcl 2>&1 |")){ notify($ERRORS{'OK'},"startsshd: starting sshd"); @output = ; close(SSHD); foreach $l (@output){ notify($ERRORS{'OK'},"startsshd output: $l"); } return 1; } else{ notify($ERRORS{'OK'},"startsshd: could not execute /local/openssh/sbin/sshd -f $HOME/sshd_config_vcl $!"); return 0; } } elsif($os eq "linux"){ if(open(SSHD, "/usr/sbin/sshd -f $HOME/sshd_config_vcl |")){ notify($ERRORS{'OK'},"startsshd: starting sshd"); @output = ; close(SSHD); foreach $l (@output){ notify($ERRORS{'OK'},"startsshd output: $l"); } return 1; } else{ notify($ERRORS{'OK'},"startsshd: could not execute /usr/sbin/sshd -f $HOME/sshd_config_vcl $!"); return 0; } } } sub notify { my ($error,$string) = @_; my $currenttime = makedatestring; if(open(LOGIT, ">>$LOG")){ if( !$error ){ print LOGIT "$currenttime - $$: $string\n"; close(LOGIT); return; } if ($error == 2 ) { #CRITICAL something bad happened, exiting print LOGIT "\n$string\n"; print LOGIT "exiting\n"; close(LOGIT); exit; } elsif( $error == 1 ){ # WARNING should prompt admin to # continue or exit # need to disable for cron print LOGIT "\n---- WARNING ---- \n$string\n"; close(LOGIT); } # mail us, this is to be used for cron jobs elsif( $error == 5 ){ print LOGIT "\n---- sending mail -- $currenttime - - $$ $string\n"; my $from = "root"; my $to = "fapeeler\@engr.ncsu.edu"; my $subject = "PROBLEM -- $0"; my $mailer = Mail::Mailer->new("sendmail"); if($mailer->open({From => $from, To => $to, Subject => $subject, })){ print $mailer "vclclientd $currenttime - - process $$ \n\n\n$string"; $mailer->close(); } return 1; } } } sub makedatestring { my($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = localtime( ); $year += 1900; $mon++; my $datestring = sprintf("%04d-%02d-%02d %02d:%02d:%02d",$year,$mon,$mday,$hour,$min,$sec); return $datestring; } sub sshdstatus { my $os = lc($^O); if($os eq "solaris"){ my $sshd_admin_pid; if(open(SSH,"/local/openssh/etc/sshd.admin.pid")){ my @file = ; close(SSH); chomp($file[0]); $sshd_admin_pid=$file[0]; } else{ notify($ERRORS{'OK'},"sshdstatus: could not open /local/openssh/etc/sshd.admin.pid $!"); return 0; } if(open(STAT,"/bin/pgrep -f sshd 2>&1 |")){ my @stat=; close(STAT); foreach my $r (@stat) { if($r =~ /$sshd_admin_pid/){ #notify($ERRORS{'OK'},"sshdstatus: sshd is running"); return 1; } } notify($ERRORS{'OK'},"sshdstatus: sshd is NOT running trying to restart"); if(open(START,"/etc/init.d/sshd start 2>&1 |")){ my @start=; close(START); foreach my $r (@start) { if($r =~ /failed/i){ notify($ERRORS{'WARNING'},"store: sshd start failed @start"); return 0; } } }#if start }#STAT return 1; } #os=solaris elsif($os =~ /linux/){ my $sshd_admin_pid; if(open(SSH,"/var/run/sshd.pid")){ my @file = ; close(SSH); chomp($file[0]); $sshd_admin_pid=$file[0]; } else{ notify($ERRORS{'WARNING'},"sshdstatus: could not open /var/run/sshd.pid $!"); return 0; } my $running=0; if(open(SSH,"pgrep -f sshd 2>&1|")){ my @lines = ; close(SSH); foreach my $l (@lines){ if($l =~ /$sshd_admin_pid/){ #ok it's running $running=1; #not that this matters return 1; } } }#if pgrep if(!$running){ #start sshd notify($ERRORS{'WARNING'},"sshdstatus: not running trying to restart"); if(open(STAT,"/etc/init.d/sshd start 2>&1 |")){ my @stat = ; close(STAT); foreach my $s (@stat) { if($s =~ /ok/i){ notify($ERRORS{'OK'},"sshdstatus: restarted core sshd process, @stat"); return 1; } } #in case I don't return in above check notify($ERRORS{'OK'},"sshdstatus: restart attempt may of had issues, @stat"); return 0; }#if sshd start }#if ! running }#elsif linux } sub createnewssh_config_vcl { #check for .orig from /etc/ssh dir #if orig then just need to add port 22 and AllowUsers directive my ($port22,$AU,$port24)=0; my @file; if(-e "/etc/sshd/sshd_config.orig"){ #good slurp it in if(open(CONFIG,"$HOME/sshd_config_vcl")){ @file = ; close(CONFIG); foreach my $line (@file){ #check for port 22 and AllowUsers if($line =~ /^Port 22/){ $port22=1; } if($line =~ /^AllowUsers/){ $AU=1; } if($line =~ s/^Port 24/Port 22/g){ $port22=1; } } } } else{ #ok /etc/sshd/sshd_config.orig does not exist #try to create from the /etc/sshd/sshd_config } #write out to $HOME/sshd_config_vcl if(open(SC,">$HOME/sshd_config_vcl")){ print SC @file; close(SC); } else{ notify($ERRORS{'CRITICAL'},"createnewssh_config_vcl: sshd_config_vcl was reported to not exists, in repairing I failed to create a new $HOME/sshd_config_vcl $!"); return 0; } }