--- loncom/lond 2001/03/27 13:37:43 1.45 +++ loncom/lond 2001/11/26 20:59:01 1.58 @@ -14,7 +14,14 @@ # 02/12 Gerd Kortemeyer # 03/15 Scott Harrison # 03/24 Gerd Kortemeyer +# 04/02 Scott Harrison +# 05/11,05/28,08/30 Gerd Kortemeyer +# 9/30,10/22,11/13,11/15,11/16 Scott Harrison +# 11/26 Gerd Kortemeyer # +# $Id: lond,v 1.58 2001/11/26 20:59:01 www Exp $ +### + # based on "Perl Cookbook" ISBN 1-56592-243-3 # preforker - server who forks first # runs as a daemon @@ -30,6 +37,11 @@ use Crypt::IDEA; use LWP::UserAgent(); use GDBM_File; use Authen::Krb4; +use lib '/home/httpd/lib/perl/'; +use localauth; + +my $status=''; +my $lastlog=''; # grabs exception and records it to log before exiting sub catchexception { @@ -39,6 +51,7 @@ sub catchexception { &logthis("CRITICAL: " ."ABNORMAL EXIT. Child $$ for server $wasserver died through " ."a crash with this error msg->[$error]"); + &logthis('Famous last words: '.$status.' - '.$lastlog); if ($client) { print $client "error: $error\n"; } die($error); } @@ -141,6 +154,19 @@ sub HUPSMAN { # sig exec("$execdir/lond"); # here we go again } +sub checkchildren { + &initnewstatus(); + &logstatus(); + &logthis('Going to check on the children'); + map { + sleep 1; + unless (kill 'USR1' => $_) { + &logthis ('Child '.$_.' is dead'); + &logstatus($$.' is dead'); + } + } sort keys %children; +} + # --------------------------------------------------------------------- Logging sub logthis { @@ -149,9 +175,34 @@ sub logthis { my $fh=IO::File->new(">>$execdir/logs/lond.log"); my $now=time; my $local=localtime($now); + $lastlog=$local.': '.$message; print $fh "$local ($$): $message\n"; } +# ------------------------------------------------------------------ Log status + +sub logstatus { + my $docdir=$perlvar{'lonDocRoot'}; + my $fh=IO::File->new(">>$docdir/lon-status/londstatus.txt"); + print $fh $$."\t".$status."\t".$lastlog."\n"; +} + +sub initnewstatus { + my $docdir=$perlvar{'lonDocRoot'}; + my $fh=IO::File->new(">$docdir/lon-status/londstatus.txt"); + my $now=time; + my $local=localtime($now); + print $fh "LOND status $local - parent $$\n\n"; +} + +# -------------------------------------------------------------- Status setting + +sub status { + my $what=shift; + my $now=time; + my $local=localtime($now); + $status=$local.': '.$what; +} # -------------------------------------------------------- Escape Special Chars @@ -298,6 +349,7 @@ open (PIDSAVE,">$execdir/logs/lond.pid") print PIDSAVE "$$\n"; close(PIDSAVE); &logthis("CRITICAL: ---------- Starting ----------"); +&status('Starting'); # ------------------------------------------------------- Now we are on our own @@ -308,13 +360,19 @@ for (1 .. $PREFORK) { # ----------------------------------------------------- Install signal handlers +&status('Forked children'); + $SIG{CHLD} = \&REAPER; $SIG{INT} = $SIG{TERM} = \&HUNTSMAN; $SIG{HUP} = \&HUPSMAN; +$SIG{USR1} = \&checkchildren; # And maintain the population. while (1) { + &status('Sleeping'); sleep; # wait for a signal (i.e., child's death) + &logthis('Woke up'); + &status('Woke up'); for ($i = $children; $i < $PREFORK; $i++) { make_new_child(); # top up the child pool } @@ -338,11 +396,15 @@ sub make_new_child { or die "Can't unblock SIGINT for fork: $!\n"; $children{$pid} = 1; $children++; + &status('Started child '.$pid); return; } else { # Child can *not* return from this subroutine. $SIG{INT} = 'DEFAULT'; # make SIGINT kill us as it did before - + $SIG{USR1}= \&logstatus; + $lastlog='Forked '; + $status='Forked'; + # unblock signals sigprocmask(SIG_UNBLOCK, $sigset) or die "Can't unblock SIGINT for fork: $!\n"; @@ -351,8 +413,9 @@ sub make_new_child { # handle connections until we've reached $MAX_CLIENTS_PER_CHILD for ($i=0; $i < $MAX_CLIENTS_PER_CHILD; $i++) { + &status('Idle, waiting for connection'); $client = $server->accept() or last; - + &status('Accepted connection'); # ============================================================================= # do something with the connection # ----------------------------------------------------------------------------- @@ -362,14 +425,19 @@ sub make_new_child { my $clientip=inet_ntoa($iaddr); my $clientrec=($hostid{$clientip} ne undef); &logthis( -"INFO: Connect from $clientip ($hostid{$clientip})"); +"INFO: Connection $i, $clientip ($hostid{$clientip})" + ); + &status("Connecting $clientip ($hostid{$clientip})"); my $clientok; if ($clientrec) { + &status("Waiting for init from $clientip ($hostid{$clientip})"); my $remotereq=<$client>; $remotereq=~s/\W//g; if ($remotereq eq 'init') { my $challenge="$$".time; print $client "$challenge\n"; + &status( + "Waiting for challenge reply from $clientip ($hostid{$clientip})"); $remotereq=<$client>; $remotereq=~s/\W//g; if ($challenge eq $remotereq) { @@ -379,26 +447,31 @@ sub make_new_child { &logthis( "WARNING: $clientip did not reply challenge"); print $client "bye\n"; + &status('No challenge reply '.$clientip); } } else { &logthis( "WARNING: " ."$clientip failed to initialize: >$remotereq< "); print $client "bye\n"; + &status('No init '.$clientip); } } else { &logthis( "WARNING: Unknown client $clientip"); print $client "bye\n"; + &status('Hung up on '.$clientip); } if ($clientok) { # ---------------- New known client connecting, could mean machine online again &reconlonc("$perlvar{'lonSockDir'}/$hostid{$clientip}"); &logthis( "Established connection: $hostid{$clientip}"); + &status('Will listen to '.$hostid{$clientip}); # ------------------------------------------------------------ Process requests while (my $userinput=<$client>) { chomp($userinput); + &status('Processing '.$hostid{$clientip}.': '.$userinput); my $wasenc=0; # ------------------------------------------------------------ See if encrypted if ($userinput =~ /^enc/) { @@ -447,6 +520,28 @@ sub make_new_child { $loadavg =~ s/\s.*//g; my $loadpercent=100*$loadavg/$perlvar{'lonLoadLim'}; print $client "$loadpercent\n"; +# ----------------------------------------------------------------- currentauth + } elsif ($userinput =~ /^currentauth/) { + if ($wasenc==1) { + my ($cmd,$udom,$uname)=split(/:/,$userinput); + my $proname=propath($udom,$uname); + my $passfilename="$proname/passwd"; + if (-e $passfilename) { + my $pf = IO::File->new($passfilename); + my $realpasswd=<$pf>; + chomp($realpasswd); + my ($howpwd,$contentpwd)=split(/:/,$realpasswd); + my $availablecontent=''; + if ($howpwd eq 'krb4') { + $availablecontent=$contentpwd; + } + print $client "$howpwd:$availablecontent\n"; + } else { + print $client "unknown_user\n"; + } + } else { + print $client "refused\n"; + } # ------------------------------------------------------------------------ auth } elsif ($userinput =~ /^auth/) { if ($wasenc==1) { @@ -466,14 +561,27 @@ sub make_new_child { (crypt($upass,$contentpwd) eq $contentpwd); } elsif ($howpwd eq 'unix') { $contentpwd=(getpwnam($uname))[1]; - $pwdcorrect= - (crypt($upass,$contentpwd) eq $contentpwd); + my $pwauth_path="/usr/local/sbin/pwauth"; + unless ($contentpwd eq 'x') { + $pwdcorrect= + (crypt($upass,$contentpwd) eq $contentpwd); + } + elsif (-e $pwauth_path) { + open PWAUTH, "|$pwauth_path" or + die "Cannot invoke authentication"; + print PWAUTH "$uname\n$upass\n"; + close PWAUTH; + $pwdcorrect=!$?; + } } elsif ($howpwd eq 'krb4') { $pwdcorrect=( Authen::Krb4::get_pw_in_tkt($uname,"", $contentpwd,'krbtgt',$contentpwd,1, $upass) == 0); - } + } elsif ($howpwd eq 'localauth') { + $pwdcorrect=&localauth::localauth($uname,$upass, + $contentpwd); + } if ($pwdcorrect) { print $client "authorized\n"; } else { @@ -523,6 +631,7 @@ sub make_new_child { } # -------------------------------------------------------------------- makeuser } elsif ($userinput =~ /^makeuser/) { + my $oldumask=umask(0077); if ($wasenc==1) { my ($cmd,$udom,$uname,$umode,$npass)=split(/:/,$userinput); @@ -560,9 +669,29 @@ sub make_new_child { { my $pf = IO::File->new(">$passfilename"); print $pf "internal:$ncpass\n"; - } + } print $client "ok\n"; - } elsif ($umode eq 'none') { + } elsif ($umode eq 'localauth') { + { + my $pf = IO::File->new(">$passfilename"); + print $pf "localauth:$npass\n"; + } + print $client "ok\n"; + } elsif ($umode eq 'unix') { + { + my $execpath="$perlvar{'lonDaemons'}/". + "lcuseradd"; + { + my $se = IO::File->new("|$execpath"); + print $se "$uname\n"; + print $se "$npass\n"; + print $se "$npass\n"; + } + my $pf = IO::File->new(">$passfilename"); + print $pf "unix:\n"; + } + print $client "ok\n"; + } elsif ($umode eq 'none') { { my $pf = IO::File->new(">$passfilename"); print $pf "none:\n"; @@ -578,6 +707,67 @@ sub make_new_child { } else { print $client "refused\n"; } + umask($oldumask); +# -------------------------------------------------------------- changeuserauth + } elsif ($userinput =~ /^changeuserauth/) { + if ($wasenc==1) { + my + ($cmd,$udom,$uname,$umode,$npass)=split(/:/,$userinput); + chomp($npass); + $npass=&unescape($npass); + my $proname=propath($udom,$uname); + my $passfilename="$proname/passwd"; + if ($udom ne $perlvar{'lonDefDomain'}) { + print $client "not_right_domain\n"; + } else { + if ($umode eq 'krb4') { + { + my $pf = IO::File->new(">$passfilename"); + print $pf "krb4:$npass\n"; + } + print $client "ok\n"; + } elsif ($umode eq 'internal') { + my $salt=time; + $salt=substr($salt,6,2); + my $ncpass=crypt($npass,$salt); + { + my $pf = IO::File->new(">$passfilename"); + print $pf "internal:$ncpass\n"; + } + print $client "ok\n"; + } elsif ($umode eq 'localauth') { + { + my $pf = IO::File->new(">$passfilename"); + print $pf "localauth:$npass\n"; + } + print $client "ok\n"; + } elsif ($umode eq 'unix') { + { + my $execpath="$perlvar{'lonDaemons'}/". + "lcuseradd"; + { + my $se = IO::File->new("|$execpath"); + print $se "$uname\n"; + print $se "$npass\n"; + print $se "$npass\n"; + } + my $pf = IO::File->new(">$passfilename"); + print $pf "unix:\n"; + } + print $client "ok\n"; + } elsif ($umode eq 'none') { + { + my $pf = IO::File->new(">$passfilename"); + print $pf "none:\n"; + } + print $client "ok\n"; + } else { + print $client "auth_mode_error\n"; + } + } + } else { + print $client "refused\n"; + } # ------------------------------------------------------------------------ home } elsif ($userinput =~ /^home/) { my ($cmd,$udom,$uname)=split(/:/,$userinput); @@ -707,7 +897,7 @@ sub make_new_child { chomp($what); my $proname=propath($udom,$uname); my $now=time; - { + unless ($namespace=~/^nohist\_/) { my $hfh; if ( $hfh=IO::File->new(">>$proname/$namespace.hist") @@ -832,7 +1022,7 @@ sub make_new_child { chomp($what); my $proname=propath($udom,$uname); my $now=time; - { + unless ($namespace=~/^nohist\_/) { my $hfh; if ( $hfh=IO::File->new(">>$proname/$namespace.hist") @@ -903,7 +1093,7 @@ sub make_new_child { chomp($what); my $proname=propath($udom,$uname); my $now=time; - { + unless ($namespace=~/^nohist\_/) { my $hfh; if ( $hfh=IO::File->new(">>$proname/$namespace.hist") @@ -990,6 +1180,9 @@ sub make_new_child { $reply=~s/\&/\n/g; print $store $reply; close $store; + my $store2=IO::File->new(">$execdir/tmp/$id.end"); + print $store2 "done\n"; + close $store2; print $client "ok\n"; } else { @@ -1085,7 +1278,7 @@ sub make_new_child { if (-e $ulsdir) { if (opendir(LSDIR,$ulsdir)) { while ($ulsfn=readdir(LSDIR)) { - my @ulsstats=stat($ulsfn); + my @ulsstats=stat($ulsdir.'/'.$ulsfn); $ulsout.=$ulsfn.'&'.join('&',@ulsstats).':'; } closedir(LSDIR); @@ -1095,13 +1288,22 @@ sub make_new_child { } if ($ulsout eq '') { $ulsout='empty'; } print $client "$ulsout\n"; +# ------------------------------------------------------------------ Hanging up + } elsif (($userinput =~ /^exit/) || + ($userinput =~ /^init/)) { + &logthis( + "Client $clientip ($hostid{$clientip}) hanging up: $userinput"); + print $client "bye\n"; + last; # ------------------------------------------------------------- unknown command } else { # unknown command print $client "unknown_cmd\n"; } -# ------------------------------------------------------ client unknown, refuse +# -------------------------------------------------------------------- complete + &status('Listening to '.$hostid{$clientip}); } +# ------------------------------------------------------ client unknown, refuse } else { print $client "refused\n"; &logthis("WARNING: "