#!/usr/bin/perl -w ############################################################################### # $Id$ ############################################################################### # 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. ############################################################################### =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); } ## end sub daemonize #------- 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"); } } ## end sub REAPER 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"); } } } ## end if (!(-r "/etc/users.local.admin")) #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 } ## end if (open(LAST, "/usr/bin/last 2>&1 |")) 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/); } ## end if (open(CLIENTDATA, "$CLIENTDATA")) 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); } } ## end else [ if ($k =~ /No such process/) } ## end if (open(KILL, "kill -9 $p 2>&1 |")) } ## end foreach my $p (keys %children) } ## end else [ if (flag) sleep 5; } #while } ## end sub main () 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); } } ## end if (open(FLAG, ">$VCLFLAG")) else { notify($ERRORS{'OK'}, "could not create $VCLFLAG $! will try to delete"); unlink $VCLFLAG; return 0; } } ## end if (!(-e $VCLFLAG)) 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]; } ## end if (open(FLAG, "$VCLFLAG")) else { notify($ERRORS{'OK'}, "flag: could not open $VCLFLAG $!"); return 0; } } ## end sub flag 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; } ## end if ($pid = fork) 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; } ## end elsif (defined $pid) [ if ($pid = fork) elsif ($! =~ /No more process/) { sleep 5; redo FORK; } else { # strange error die "Can't fork: $!\n"; } } ## end FORK: } ## end sub make_new_child 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; } } ## end if (!(-r "$HOME/sshd_config_vcl")) 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); } } ## end if (open(CONFIG, "$HOME/sshd_config_vcl")) # 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); } } ## end if (open(USERSLOCAL, "/etc/users.local")) 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; } ## end sub new_state 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 $!"); } } ## end if ($os eq "solaris") 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"); } } } ## end if (open(SSH, "ps -ef \| grep /usr/sbin/sshd |"... else { notify($ERRORS{'OK'}, "timeout_state: execute ps -ef $!"); } } ## end elsif ($os eq "linux") [ if ($os eq "solaris") 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"); } } ## end if (open(SSHDCONFIG, "$HOME/sshd_config_vcl"... #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); } } } ## end foreach my $pid (@pgrep) } ## end if (open(PGREP, "ps -ef \| grep $user|")) } ## end if (open(PKILL, "$pkill -9 -U $user 2>&1 |"... 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); } } ## end foreach $l (@pfile) 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"); } } } ## end if (open(PGREP, "ps -ef \|grep sshd \|grep -v grep |"... } ## end if (open(PGREP, "ps -ef \|grep sshd 2>&1|"... 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"); } } ## end if (open(SSHSTOP, "/etc/inet.d/sshd stop |"... } ## end if ($sshpid == $sshd_admin_pid) } ## end if ($l =~ /(\/home\/vclstaff\/sshd_config_vcl\/)/) } ## end foreach $l (@sshfile) } ## end if (open(SSH, "ps -ef \| grep /usr/sbin/sshd |"... 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; } ## end sub timeout_state 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; } } ## end sub reboot 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"); } } } ## end if (open(CP, "/bin/cp $sshdir/ssh_host\* $HOME 2>&1 |"... notify($ERRORS{'OK'}, "fetch: fetch complete"); return 1; } ## end sub fetch 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; } ## end sub store 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 } ## end if ($os eq "solaris") 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); } } } ## end if (open(RESTART, "/etc/init.d/sshd restart 2>&1 |"... } ## end elsif ($os =~ /linux/) [ if ($os eq "solaris") return 1; } ## end sub restartsshd 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; } } ## end if ($os eq "solaris") 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; } } ## end elsif ($os eq "linux") [ if ($os eq "solaris") } ## end sub startsshd 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); } } ## end if (open(LOGIT, ">>$LOG")) } ## end sub notify 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 } ## end sub sshdstatus 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; } } ## end foreach my $line (@file) } ## end if (open(CONFIG, "$HOME/sshd_config_vcl")) } ## end if (-e "/etc/sshd/sshd_config.orig") 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; } } ## end sub createnewssh_config_vcl #///////////////////////////////////////////////////////////////////////////// 1; __END__ =head1 SEE ALSO L =cut