--- loncom/lond 2005/01/03 16:08:07 1.273 +++ loncom/lond 2005/05/02 23:34:41 1.283 @@ -2,7 +2,7 @@ # The LearningOnline Network # lond "LON Daemon" Server (port "LOND" 5663) # -# $Id: lond,v 1.273 2005/01/03 16:08:07 albertel Exp $ +# $Id: lond,v 1.283 2005/05/02 23:34:41 albertel Exp $ # # Copyright Michigan State University Board of Trustees # @@ -58,14 +58,13 @@ my $DEBUG = 0; # Non zero to ena my $status=''; my $lastlog=''; -my $VERSION='$Revision: 1.273 $'; #' stupid emacs +my $VERSION='$Revision: 1.283 $'; #' stupid emacs my $remoteVERSION; my $currenthostid="default"; my $currentdomainid; my $client; my $clientip; # IP address of client. -my $clientdns; # DNS name of client. my $clientname; # LonCAPA name of client. my $server; @@ -178,7 +177,6 @@ sub ResetStatistics { # $initcmd - The full text of the init command. # # Implicit inputs: -# $clientdns - The DNS name of the remote client. # $thisserver - Our DNS name. # # Returns: @@ -187,10 +185,10 @@ sub ResetStatistics { # sub LocalConnection { my ($Socket, $initcmd) = @_; - Debug("Attempting local connection: $initcmd client: $clientdns me: $thisserver"); - if($clientdns ne $thisserver) { + Debug("Attempting local connection: $initcmd client: $clientip me: $thisserver"); + if($clientip ne "127.0.0.1") { &logthis(' LocalConnection rejecting non local: ' - ."$clientdns ne $thisserver "); + ."$clientip ne $thisserver "); close $Socket; return undef; } else { @@ -474,39 +472,11 @@ sub CopyFile { my ($oldfile, $newfile) = @_; - # The file must exist: - - if(-e $oldfile) { - - # Read the old file. - - my $oldfh = IO::File->new("< $oldfile"); - if(!$oldfh) { - return 0; - } - my @contents = <$oldfh>; # Suck in the entire file. - - # write the backup file: - - my $newfh = IO::File->new("> $newfile"); - if(!(defined $newfh)){ - return 0; - } - my $lines = scalar @contents; - for (my $i =0; $i < $lines; $i++) { - print $newfh ($contents[$i]); - } - - $oldfh->close; - $newfh->close; - - chmod(0660, $newfile); - - return 1; - - } else { - return 0; + if (! copy($oldfile,$newfile)) { + return 0; } + chmod(0660, $newfile); + return 1; } # # Host files are passed out with externally visible host IPs. @@ -1411,6 +1381,9 @@ sub du_handler { ®ister_handler("du", \&du_handler, 0, 1, 0); # +# The ls_handler routine should be considered obosolete and is retained +# for communication with legacy servers. Please see the ls2_handler. +# # ls - list the contents of a directory. For each file in the # selected directory the filename followed by the full output of # the stat function is returned. The returned info for each @@ -1427,6 +1400,7 @@ sub du_handler { # The reply is written to $client. # sub ls_handler { + # obsoleted by ls2_handler my ($cmd, $ulsdir, $client) = @_; my $userinput = "$cmd:$ulsdir"; @@ -1473,6 +1447,72 @@ sub ls_handler { } ®ister_handler("ls", \&ls_handler, 0, 1, 0); +# +# Please also see the ls_handler, which this routine obosolets. +# ls2_handler differs from ls_handler in that it escapes its return +# values before concatenating them together with ':'s. +# +# ls2 - list the contents of a directory. For each file in the +# selected directory the filename followed by the full output of +# the stat function is returned. The returned info for each +# file are separated by ':'. The stat fields are separated by &'s. +# Parameters: +# $cmd - The command that dispatched us (ls). +# $ulsdir - The directory path to list... I'm not sure what this +# is relative as things like ls:. return e.g. +# no_such_dir. +# $client - Socket open on the client. +# Returns: +# 1 - indicating that the daemon should not disconnect. +# Side Effects: +# The reply is written to $client. +# +sub ls2_handler { + my ($cmd, $ulsdir, $client) = @_; + + my $userinput = "$cmd:$ulsdir"; + + my $obs; + my $rights; + my $ulsout=''; + my $ulsfn; + if (-e $ulsdir) { + if(-d $ulsdir) { + if (opendir(LSDIR,$ulsdir)) { + while ($ulsfn=readdir(LSDIR)) { + undef $obs, $rights; + my @ulsstats=stat($ulsdir.'/'.$ulsfn); + #We do some obsolete checking here + if(-e $ulsdir.'/'.$ulsfn.".meta") { + open(FILE, $ulsdir.'/'.$ulsfn.".meta"); + my @obsolete=; + foreach my $obsolete (@obsolete) { + if($obsolete =~ m|()(on)|) { $obs = 1; } + if($obsolete =~ m|()(default)|) { + $rights = 1; + } + } + } + my $tmp = $ulsfn.'&'.join('&',@ulsstats); + if ($obs eq '1') { $tmp.="&1"; } else { $tmp.="&0"; } + if ($rights eq '1') { $tmp.="&1"; } else { $tmp.="&0"; } + $ulsout.= &escape($tmp).':'; + } + closedir(LSDIR); + } + } else { + my @ulsstats=stat($ulsdir); + $ulsout.=$ulsfn.'&'.join('&',@ulsstats).':'; + } + } else { + $ulsout='no_such_dir'; + } + if ($ulsout eq '') { $ulsout='empty'; } + &Reply($client, "$ulsout\n", $userinput); # This supports debug logging. + return 1; +} +®ister_handler("ls2", \&ls2_handler, 0, 1, 0); + # Process a reinit request. Reinit requests that either # lonc or lond be reinitialized so that an updated # host.tab or domain.tab can be processed. @@ -1799,10 +1839,11 @@ sub change_authentication_handler { # to take ownership of the construction space back to www:www # - if( ($oldauth =~ /^unix/) && ($umode eq "internal")) { # unix -> internal + if( (($oldauth =~ /^unix/) && ($umode eq "internal")) || + (($oldauth =~ /^internal/) && ($umode eq "unix")) ) { if(&is_author($udom, $uname)) { &Debug(" Need to manage author permissions..."); - &manage_permissions("/$udom/_au", $udom, $uname, "internal:"); + &manage_permissions("/$udom/_au", $udom, $uname, "$umode:"); } } @@ -2319,6 +2360,61 @@ sub put_user_profile_entry { } ®ister_handler("put", \&put_user_profile_entry, 0, 1, 0); +# Put a piece of new data in hash, returns error if entry already exists +# Parameters: +# $cmd - The command that got us here. +# $tail - Tail of the command (remaining parameters). +# $client - File descriptor connected to client. +# Returns +# 0 - Requested to exit, caller should shut down. +# 1 - Continue processing. +# +sub newput_user_profile_entry { + my ($cmd, $tail, $client) = @_; + + my $userinput = "$cmd:$tail"; + + my ($udom,$uname,$namespace,$what) =split(/:/,$tail,4); + if ($namespace eq 'roles') { + &Failure( $client, "refused\n", $userinput); + return 1; + } + + chomp($what); + + my $hashref = &tie_user_hash($udom, $uname, $namespace, + &GDBM_WRCREAT(),"N",$what); + if(!$hashref) { + &Failure( $client, "error: ".($!)." tie(GDBM) Failed ". + "while attempting put\n", $userinput); + return 1; + } + + my @pairs=split(/\&/,$what); + foreach my $pair (@pairs) { + my ($key,$value)=split(/=/,$pair); + if (exists($hashref->{$key})) { + &Failure($client, "key_exists: ".$key."\n",$userinput); + return 1; + } + } + + foreach my $pair (@pairs) { + my ($key,$value)=split(/=/,$pair); + $hashref->{$key}=$value; + } + + if (untie(%$hashref)) { + &Reply( $client, "ok\n", $userinput); + } else { + &Failure($client, "error: ".($!+0)." untie(GDBM) failed ". + "while attempting put\n", + $userinput); + } + return 1; +} +®ister_handler("newput", \&newput_user_profile_entry, 0, 1, 0); + # # Increment a profile entry in the user history file. # The history contains keyword value pairs. In this case, @@ -3198,8 +3294,9 @@ sub put_course_id_handler { # owner - optional supplied username of owner to filter # the dump. Only courses for which the course # owner matches the supplied username will be -# returned. Implicit assumption that owner is a user -# in the domain in which the course database is defined. +# returned. Implicit assumption that owner +# is a user in the domain in which the +# course database is defined. # $client - The socket open on the client. # Returns: # 1 - Continue processing. @@ -3210,7 +3307,7 @@ sub dump_course_id_handler { my $userinput = "$cmd:$tail"; - my ($udom,$since,$description,$instcodefilter,$ownerfilter) =split(/:/,$tail); + my ($udom,$since,$description,$instcodefilter,$ownerfilter,$coursefilter) =split(/:/,$tail); if (defined($description)) { $description=&unescape($description); } else { @@ -3226,6 +3323,11 @@ sub dump_course_id_handler { } else { $ownerfilter='.'; } + if (defined($coursefilter)) { + $coursefilter=&unescape($coursefilter); + } else { + $coursefilter='.'; + } unless (defined($since)) { $since=0; } my $qresult=''; @@ -3233,15 +3335,9 @@ sub dump_course_id_handler { if ($hashref) { while (my ($key,$value) = each(%$hashref)) { my ($descr,$lasttime,$inst_code,$owner); - my @courseitems = split/:/,$value; - $descr = shift @courseitems; - $lasttime = pop @courseitems; - if (@courseitems > 0) { - $inst_code = shift @courseitems; - } - if (@courseitems > 0) { - $owner = shift @courseitems; - } + my @courseitems = split(/:/,$value); + $lasttime = pop(@courseitems); + ($descr,$inst_code,$owner)=@courseitems; if ($lasttime<$since) { next; } my $match = 1; unless ($description eq '.') { @@ -3262,6 +3358,12 @@ sub dump_course_id_handler { $match = 0; } } + unless ($coursefilter eq '.' || !defined($coursefilter)) { + my $unescapeCourse = &unescape($key); + unless (eval('$unescapeCourse=~/^$udom(_)\Q$coursefilter\E$/')) { + $match = 0; + } + } if ($match == 1) { $qresult.=$key.'='.$descr.':'.$inst_code.':'.$owner.'&'; } @@ -4285,12 +4387,18 @@ sub ReadHostTable { my $myloncapaname = $perlvar{'lonHostID'}; Debug("My loncapa name is : $myloncapaname"); while (my $configline=) { - if (!($configline =~ /^\s*\#/)) { - my ($id,$domain,$role,$name,$ip)=split(/:/,$configline); - chomp($ip); $ip=~s/\D+$//; + if ($configline !~ /^\s*\#/ && $configline !~ /^\s*$/ ) { + my ($id,$domain,$role,$name)=split(/:/,$configline); + $name=~s/\s//g; + my $ip = gethostbyname($name); + if (length($ip) ne 4) { + &logthis("Skipping host $id name $name no IP $ip found\n"); + next; + } + $ip=inet_ntoa($ip); $hostid{$ip}=$id; # LonCAPA name of host by IP. $hostdom{$id}=$domain; # LonCAPA domain name of host. - $hostip{$id}=$ip; # IP address of host. + $hostip{$id}=$ip; # IP address of host. $hostdns{$name} = $id; # LonCAPA name of host by DNS. if ($id eq $perlvar{'lonHostID'}) { @@ -4427,8 +4535,6 @@ sub Reply { Debug("Request was $request Reply was $reply"); $Transactions++; - - } @@ -4471,7 +4577,7 @@ sub logstatus { flock(LOG,LOCK_EX); print LOG $$."\t".$clientname."\t".$currenthostid."\t" .$status."\t".$lastlog."\t $keymode\n"; - flock(DB,LOCK_UN); + flock(LOG,LOCK_UN); close(LOG); } &status("Finished logging"); @@ -4702,8 +4808,6 @@ sub make_new_child { if (defined($iaddr)) { $clientip = inet_ntoa($iaddr); Debug("Connected with $clientip"); - $clientdns = gethostbyaddr($iaddr, AF_INET); - Debug("Connected with $clientdns by name"); } else { &logthis("Unable to determine clientip"); $clientip='Unavailable'; @@ -4743,18 +4847,23 @@ sub make_new_child { ReadManagerTable; # May also be a manager!! - my $clientrec=($hostid{$clientip} ne undef); - my $ismanager=($managers{$clientip} ne undef); + my $outsideip=$clientip; + if ($clientip eq '127.0.0.1') { + $outsideip=$hostip{$perlvar{'lonHostID'}}; + } + + my $clientrec=($hostid{$outsideip} ne undef); + my $ismanager=($managers{$outsideip} ne undef); $clientname = "[unknonwn]"; if($clientrec) { # Establish client type. $ConnectionType = "client"; - $clientname = $hostid{$clientip}; + $clientname = $hostid{$outsideip}; if($ismanager) { $ConnectionType = "both"; } } else { $ConnectionType = "manager"; - $clientname = $managers{$clientip}; + $clientname = $managers{$outsideip}; } my $clientok;