--- loncom/lond 2001/08/30 20:02:28 1.51
+++ loncom/lond 2001/11/26 20:59:01 1.58
@@ -16,7 +16,12 @@
# 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
@@ -35,6 +40,9 @@ 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 {
my ($error)=@_;
@@ -43,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);
}
@@ -145,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 {
@@ -153,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
@@ -302,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
@@ -312,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
}
@@ -342,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";
@@ -355,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
# -----------------------------------------------------------------------------
@@ -368,13 +427,17 @@ sub make_new_child {
&logthis(
"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) {
@@ -384,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/) {
@@ -452,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) {
@@ -471,8 +561,18 @@ 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,"",
@@ -531,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);
@@ -576,7 +677,21 @@ sub make_new_child {
print $pf "localauth:$npass\n";
}
print $client "ok\n";
- } elsif ($umode eq 'none') {
+ } 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";
@@ -592,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);
@@ -1124,8 +1300,10 @@ sub make_new_child {
# 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: "