--- loncom/lonnet/perl/lonnet.pm 2001/12/22 21:46:02 1.193
+++ loncom/lonnet/perl/lonnet.pm 2002/02/25 14:33:58 1.203
@@ -1,7 +1,7 @@
# The LearningOnline Network
# TCP networking package
#
-# $Id: lonnet.pm,v 1.193 2001/12/22 21:46:02 www Exp $
+# $Id: lonnet.pm,v 1.203 2002/02/25 14:33:58 www Exp $
#
# Copyright Michigan State University Board of Trustees
#
@@ -64,7 +64,9 @@
# 12/5 Guy Albertelli
# 12/6,12/7,12/12 Gerd Kortemeyer
# 12/18 Scott Harrison
-# 12/21,12/22 Gerd Kortemeyer
+# 12/21,12/22,12/27,12/28 Gerd Kortemeyer
+# YEAR=2002
+# 1/4,2/4,2/7 Gerd Kortemeyer
#
###
@@ -78,12 +80,13 @@ use vars
qw(%perlvar %hostname %homecache %hostip %spareid %hostdom
%libserv %pr %prp %metacache %packagetab
%courselogs %accesshash $processmarker $dumpcount
- %coursedombuf %coursehombuf);
+ %coursedombuf %coursehombuf %courseresdatacache);
use IO::Socket;
use GDBM_File;
use Apache::Constants qw(:common :http);
use HTML::TokeParser;
use Fcntl qw(:flock);
+my $readit;
# --------------------------------------------------------------------- Logging
@@ -135,7 +138,22 @@ sub subreply {
sub reply {
my ($cmd,$server)=@_;
my $answer=subreply($cmd,$server);
- if ($answer eq 'con_lost') { $answer=subreply($cmd,$server); }
+ if ($answer eq 'con_lost') {
+ sleep 5;
+ $answer=subreply($cmd,$server);
+ if ($answer eq 'con_lost') {
+ &logthis("Second attempt con_lost on $server");
+ my $peerfile="$perlvar{'lonSockDir'}/$server";
+ my $client=IO::Socket::UNIX->new(Peer =>"$peerfile",
+ Type => SOCK_STREAM,
+ Timeout => 10)
+ or return "con_lost";
+ &logthis("Killing socket");
+ print $client "close_connection_exit\n";
+ sleep 5;
+ $answer=subreply($cmd,$server);
+ }
+ }
if (($answer=~/^refused/) || ($answer=~/^rejected/)) {
&logthis("WARNING:".
" $cmd to $server returned $answer");
@@ -345,6 +363,41 @@ sub spareserver {
return $spareserver;
}
+# --------------------------------------------- Try to change a user's password
+
+sub changepass {
+ my ($uname,$udom,$currentpass,$newpass,$server)=@_;
+ $currentpass = &escape($currentpass);
+ $newpass = &escape($newpass);
+ my $answer = reply("encrypt:passwd:$udom:$uname:$currentpass:$newpass",
+ $server);
+ if (! $answer) {
+ &logthis("No reply on password change request to $server ".
+ "by $uname in domain $udom.");
+ } elsif ($answer =~ "^ok") {
+ &logthis("$uname in $udom successfully changed their password ".
+ "on $server.");
+ } elsif ($answer =~ "^pwchange_failure") {
+ &logthis("$uname in $udom was unable to change their password ".
+ "on $server. The action was blocked by either lcpasswd ".
+ "or pwchange");
+ } elsif ($answer =~ "^non_authorized") {
+ &logthis("$uname in $udom did not get their password correct when ".
+ "attempting to change it on $server.");
+ } elsif ($answer =~ "^auth_mode_error") {
+ &logthis("$uname in $udom attempted to change their password despite ".
+ "not being locally or internally authenticated on $server.");
+ } elsif ($answer =~ "^unknown_user") {
+ &logthis("$uname in $udom attempted to change their password ".
+ "on $server but were unable to because $server is not ".
+ "their home server.");
+ } elsif ($answer =~ "^refused") {
+ &logthis("$server refused to change $uname in $udom password because ".
+ "it was sent an unencrypted request to change the password.");
+ }
+ return $answer;
+}
+
# ----------------------- Try to determine user's current authentication scheme
sub queryauthenticate {
@@ -388,6 +441,7 @@ sub queryauthenticate {
sub authenticate {
my ($uname,$upass,$udom)=@_;
$upass=escape($upass);
+ $uname=~s/\W//g;
if (($perlvar{'lonRole'} eq 'library') &&
($udom eq $perlvar{'lonDefDomain'})) {
my $answer=reply("encrypt:auth:$udom:$uname:$upass",$perlvar{'lonHostID'});
@@ -637,7 +691,7 @@ sub ssi {
if (%form) {
$request=new HTTP::Request('POST',"http://".$ENV{'HTTP_HOST'}.$fn);
- $request->content(join '&', map { "$_=$form{$_}" } keys %form);
+ $request->content(join('&',map { &escape($_).'='.&escape($form{$_}) } keys %form));
} else {
$request=new HTTP::Request('GET',"http://".$ENV{'HTTP_HOST'}.$fn);
}
@@ -1554,7 +1608,7 @@ sub allowed {
if ($thisallowed=~/C/) {
my $rolecode=(split(/\./,$ENV{'request.role'}))[0];
if ($ENV{'course.'.$ENV{'request.course.id'}.'.'.$priv.'.roles.denied'}
- =~/\,$rolecode\,/) {
+ =~/$rolecode/) {
&log($ENV{'user.domain'},$ENV{'user.name'},$ENV{'user.host'},
'Denied by role: '.$priv.' for '.$uri.' as '.$rolecode.' in '.
$ENV{'request.course.id'});
@@ -1703,14 +1757,25 @@ sub assignrole {
}
# -------------------------------------------------- Modify user authentication
+# Overrides without validation
+
sub modifyuserauth {
my ($udom,$uname,$umode,$upass)=@_;
my $uhome=&homeserver($uname,$udom);
- &logthis('Call to modify user authentication'.$udom.', '.$uname.', '.
+ unless (&allowed('mau',$udom)) { return 'refused'; }
+ &logthis('Call to modify user authentication '.$udom.', '.$uname.', '.
$umode.' by '.$ENV{'user.name'}.' at '.$ENV{'user.domain'});
my $reply=&reply('encrypt:changeuserauth:'.$udom.':'.$uname.':'.$umode.':'.
&escape($upass),$uhome);
+ &log($ENV{'user.domain'},$ENV{'user.name'},$ENV{'user.home'},
+ 'Authentication changed for '.$udom.', '.$uname.', '.$umode.
+ '(Remote '.$ENV{'REMOTE_ADDR'}.'): '.$reply);
+ &log($udom,,$uname,$uhome,
+ 'Authentication changed by '.$ENV{'user.domain'}.', '.
+ $ENV{'user.name'}.', '.$umode.
+ '(Remote '.$ENV{'REMOTE_ADDR'}.'): '.$reply);
unless ($reply eq 'ok') {
+ &logthis('Authentication mode error: '.$reply);
return 'error: '.$reply;
}
return 'ok';
@@ -1720,10 +1785,13 @@ sub modifyuserauth {
sub modifyuser {
- my ($udom,$uname,$uid,$umode,$upass,$first,$middle,$last,$gene)=@_;
+ my ($udom,$uname,$uid,$umode,$upass,$first,$middle,$last,$gene,
+ $forceid)=@_;
+ $udom=~s/\W//g;
+ $uname=~s/\W//g;
&logthis('Call to modify user '.$udom.', '.$uname.', '.$uid.', '.
$umode.', '.$first.', '.$middle.', '.
- $last.', '.$gene.' by '.
+ $last.', '.$gene.'(forceid: '.$forceid.') by '.
$ENV{'user.name'}.' at '.$ENV{'user.domain'});
my $uhome=&homeserver($uname,$udom);
# ----------------------------------------------------------------- Create User
@@ -1761,7 +1829,8 @@ sub modifyuser {
if ($uid) {
$uid=~tr/A-Z/a-z/;
my %uidhash=&idrget($udom,$uname);
- if (($uidhash{$uname}) && ($uidhash{$uname}!~/error\:/)) {
+ if (($uidhash{$uname}) && ($uidhash{$uname}!~/error\:/)
+ && (!$forceid)) {
unless ($uid eq $uidhash{$uname}) {
return 'error: mismatch '.$uidhash{$uname}.' versus '.$uid;
}
@@ -1790,14 +1859,14 @@ sub modifyuser {
sub modifystudent {
my ($udom,$uname,$uid,$umode,$upass,$first,$middle,$last,$gene,$usec,
- $end,$start)=@_;
+ $end,$start,$forceid)=@_;
my $cid='';
unless ($cid=$ENV{'request.course.id'}) {
return 'not_in_class';
}
# --------------------------------------------------------------- Make the user
my $reply=&modifyuser
- ($udom,$uname,$uid,$umode,$upass,$first,$middle,$last,$gene);
+ ($udom,$uname,$uid,$umode,$upass,$first,$middle,$last,$gene,$forceid);
unless ($reply eq 'ok') { return $reply; }
my $uhome=&homeserver($uname,$udom);
if (($uhome eq '') || ($uhome eq 'no_host')) {
@@ -2005,6 +2074,38 @@ sub condval {
return $result;
}
+# --------------------------------------------------- Course Resourcedata Query
+
+sub courseresdata {
+ my ($coursenum,$coursedomain,@which)=@_;
+ my $coursehom=&homeserver($coursenum,$coursedomain);
+ my $hashid=$coursenum.':'.$coursedomain;
+ unless (defined($courseresdatacache{$hashid.'.time'})) {
+ unless (time-$courseresdatacache{$hashid.'.time'}<300) {
+ my $coursehom=&homeserver($coursenum,$coursedomain);
+ if ($coursehom) {
+ my $dumpreply=&reply('dump:'.$coursedomain.':'.$coursenum.
+ ':resourcedata:.',$coursehom);
+ unless ($dumpreply=~/^error\:/) {
+ $courseresdatacache{$hashid.'.time'}=time;
+ $courseresdatacache{$hashid}=$dumpreply;
+ }
+ }
+ }
+ }
+ my @pairs=split(/\&/,$courseresdatacache{$hashid});
+ my %returnhash=();
+ foreach (@pairs) {
+ my ($key,$value)=split(/=/,$_);
+ $returnhash{unescape($key)}=unescape($value);
+ }
+ my $item;
+ foreach $item (@which) {
+ if ($returnhash{$item}) { return $returnhash{$item}; }
+ }
+ return '';
+}
+
# --------------------------------------------------------- Value of a Variable
sub EXT {
@@ -2125,28 +2226,13 @@ sub EXT {
# -------------------------------------------------------- second, check course
- my $reply=&reply('get:'.
- $ENV{'course.'.$ENV{'request.course.id'}.'.domain'}.':'.
- $ENV{'course.'.$ENV{'request.course.id'}.'.num'}.
- ':resourcedata:'.
- &escape($seclevelr).'&'.&escape($seclevelm).'&'.&escape($seclevel).'&'.
- &escape($courselevelr).'&'.&escape($courselevelm).'&'.&escape($courselevel),
- $ENV{'course.'.$ENV{'request.course.id'}.'.home'});
- if ($reply!~/^error\:/) {
- foreach (split(/\&/,$reply)) {
- if ($_) { return &unescape($_); }
- }
- }
- if (($reply=~/^con_lost/) || ($reply=~/^error\:/)) {
- &logthis("WARNING:".
- " Getting ".$reply." asking for ".$varname." for ".
- $ENV{'course.'.$ENV{'request.course.id'}.'.num'}.
- ' at '.
- $ENV{'course.'.$ENV{'request.course.id'}.'.domain'}.
- ' from '.
- $ENV{'course.'.$ENV{'request.course.id'}.'.home'}.
- "");
- }
+ my $coursereply=&courseresdata(
+ $ENV{'course.'.$ENV{'request.course.id'}.'.num'},
+ $ENV{'course.'.$ENV{'request.course.id'}.'.domain'},
+ ($seclevelr,$seclevelm,$seclevel,
+ $courselevelr,$courselevelm,$courselevel));
+ if ($coursereply) { return $coursereply; }
+
# ------------------------------------------------------ third, check map parms
my %parmhash=();
my $thisparm='';
@@ -2555,6 +2641,7 @@ sub goodbye {
BEGIN {
# ------------------------------------------------------------ Read access.conf
+ unless ($readit) {
{
my $config=Apache::File->new("/etc/httpd/conf/access.conf");
@@ -2640,6 +2727,8 @@ $dumpcount=0;
&logtouch();
&logthis('INFO: Read configuration');
+$readit=1;
+}
}
1;