--- loncom/lond 2004/08/05 11:37:05 1.223 +++ loncom/lond 2004/08/23 11:24:45 1.234 @@ -2,7 +2,7 @@ # The LearningOnline Network # lond "LON Daemon" Server (port "LOND" 5663) # -# $Id: lond,v 1.223 2004/08/05 11:37:05 foxr Exp $ +# $Id: lond,v 1.234 2004/08/23 11:24:45 foxr Exp $ # # Copyright Michigan State University Board of Trustees # @@ -52,12 +52,12 @@ use LONCAPA::lonlocal; use LONCAPA::lonssl; use Fcntl qw(:flock); -my $DEBUG = 1; # Non zero to enable debug log entries. +my $DEBUG = 0; # Non zero to enable debug log entries. my $status=''; my $lastlog=''; -my $VERSION='$Revision: 1.223 $'; #' stupid emacs +my $VERSION='$Revision: 1.234 $'; #' stupid emacs my $remoteVERSION; my $currenthostid="default"; my $currentdomainid; @@ -162,8 +162,6 @@ sub ResetStatistics { $Failures = 0; } - - #------------------------------------------------------------------------ # # LocalConnection @@ -194,8 +192,7 @@ sub LocalConnection { ."$clientdns ne $thisserver "); close $Socket; return undef; - } - else { + } else { chomp($initcmd); # Get rid of \n in filename. my ($init, $type, $name) = split(/:/, $initcmd); Debug(" Init command: $init $type $name "); @@ -326,8 +323,7 @@ sub InsecureConnection { $answer =~s/\W//g; if($challenge eq $answer) { return 1; - } - else { + } else { logthis("WARNING client did not respond to challenge"); &status("No challenge reqply"); return 0; @@ -374,7 +370,6 @@ sub isClient { # - This allows dynamic changes to the manager table # without the need to signal to the lond. # - sub ReadManagerTable { # Clean out the old table first.. @@ -656,8 +651,7 @@ sub PushFile { &logthis(' Pushfile: unable to install ' .$tablefile." $! "); return "error:$!"; - } - else { + } else { &logthis(' Installed new '.$tablefile .""); @@ -1503,8 +1497,7 @@ sub change_password_handler { &Failure( $client, "auth_mode_error\n", $userinput); } - } - else { + } else { &Failure( $client, "non_authorized\n", $userinput); } @@ -1513,6 +1506,1478 @@ sub change_password_handler { register_handler("passwd", \&change_password_handler, 1, 1, 0); +# +# Create a new user. User in this case means a lon-capa user. +# The user must either already exist in some authentication realm +# like kerberos or the /etc/passwd. If not, a user completely local to +# this loncapa system is created. +# +# 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. +# Implicit inputs: +# The authentication systems describe above have their own forms of implicit +# input into the authentication process that are described above. +sub add_user_handler { + + my ($cmd, $tail, $client) = @_; + + + my ($udom,$uname,$umode,$npass)=split(/:/,$tail); + my $userinput = $cmd.":".$tail; # Reconstruct the full request line. + + &Debug("cmd =".$cmd." $udom =".$udom." uname=".$uname); + + + if($udom eq $currentdomainid) { # Reject new users for other domains... + + my $oldumask=umask(0077); + chomp($npass); + $npass=&unescape($npass); + my $passfilename = &password_path($udom, $uname); + &Debug("Password file created will be:".$passfilename); + if (-e $passfilename) { + &Failure( $client, "already_exists\n", $userinput); + } else { + my @fpparts=split(/\//,$passfilename); + my $fpnow=$fpparts[0].'/'.$fpparts[1].'/'.$fpparts[2]; + my $fperror=''; + for (my $i=3;$i<= ($#fpparts-1);$i++) { + $fpnow.='/'.$fpparts[$i]; + unless (-e $fpnow) { + &logthis("mkdir $fpnow"); + unless (mkdir($fpnow,0777)) { + $fperror="error: ".($!+0)." mkdir failed while attempting " + ."makeuser"; + } + } + } + unless ($fperror) { + my $result=&make_passwd_file($uname, $umode,$npass, $passfilename); + &Reply($client, $result, $userinput); #BUGBUG - could be fail + } else { + &Failure($client, "$fperror\n", $userinput); + } + } + umask($oldumask); + } else { + &Failure($client, "not_right_domain\n", + $userinput); # Even if we are multihomed. + + } + return 1; + +} +®ister_handler("makeuser", \&add_user_handler, 1, 1, 0); + +# +# Change the authentication method of a user. Note that this may +# also implicitly change the user's password if, for example, the user is +# joining an existing authentication realm. Known authentication realms at +# this time are: +# internal - Purely internal password file (only loncapa knows this user) +# local - Institutionally written authentication module. +# unix - Unix user (/etc/passwd with or without /etc/shadow). +# kerb4 - kerberos version 4 +# kerb5 - kerberos version 5 +# +# 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. +# Implicit inputs: +# The authentication systems describe above have their own forms of implicit +# input into the authentication process that are described above. +# +sub change_authentication_handler { + + my ($cmd, $tail, $client) = @_; + + my $userinput = "$cmd:$tail"; # Reconstruct user input. + + my ($udom,$uname,$umode,$npass)=split(/:/,$tail); + &Debug("cmd = ".$cmd." domain= ".$udom."uname =".$uname." umode= ".$umode); + if ($udom ne $currentdomainid) { + &Failure( $client, "not_right_domain\n", $client); + } else { + + chomp($npass); + + $npass=&unescape($npass); + my $passfilename = &password_path($udom, $uname); + if ($passfilename) { # Not allowed to create a new user!! + my $result=&make_passwd_file($uname, $umode,$npass,$passfilename); + &Reply($client, $result, $userinput); + } else { + &Failure($client, "non_authorized", $userinput); # Fail the user now. + } + } + return 1; +} +®ister_handler("changeuserauth", \&change_authentication_handler, 1,1, 0); + +# +# Determines if this is the home server for a user. The home server +# for a user will have his/her lon-capa passwd file. Therefore all we need +# to do is determine if this file 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. +# Implicit inputs: +# The authentication systems describe above have their own forms of implicit +# input into the authentication process that are described above. +# +sub is_home_handler { + my ($cmd, $tail, $client) = @_; + + my $userinput = "$cmd:$tail"; + + my ($udom,$uname)=split(/:/,$tail); + chomp($uname); + my $passfile = &password_filename($udom, $uname); + if($passfile) { + &Reply( $client, "found\n", $userinput); + } else { + &Failure($client, "not_found\n", $userinput); + } + return 1; +} +®ister_handler("home", \&is_home_handler, 0,1,0); + +# +# Process an update request for a resource?? I think what's going on here is +# that a resource has been modified that we hold a subscription to. +# If the resource is not local, then we must update, or at least invalidate our +# cached copy of the resource. +# FUTURE WORK: +# I need to look at this logic carefully. My druthers would be to follow +# typical caching logic, and simple invalidate the cache, drop any subscription +# an let the next fetch start the ball rolling again... however that may +# actually be more difficult than it looks given the complex web of +# proxy servers. +# 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. +# Implicit inputs: +# The authentication systems describe above have their own forms of implicit +# input into the authentication process that are described above. +# +sub update_resource_handler { + + my ($cmd, $tail, $client) = @_; + + my $userinput = "$cmd:$tail"; + + my $fname= $tail; # This allows interactive testing + + + my $ownership=ishome($fname); + if ($ownership eq 'not_owner') { + if (-e $fname) { + my ($dev,$ino,$mode,$nlink,$uid,$gid,$rdev,$size, + $atime,$mtime,$ctime,$blksize,$blocks)=stat($fname); + my $now=time; + my $since=$now-$atime; + if ($since>$perlvar{'lonExpire'}) { + my $reply=&reply("unsub:$fname","$clientname"); + unlink("$fname"); + } else { + my $transname="$fname.in.transfer"; + my $remoteurl=&reply("sub:$fname","$clientname"); + my $response; + alarm(120); + { + my $ua=new LWP::UserAgent; + my $request=new HTTP::Request('GET',"$remoteurl"); + $response=$ua->request($request,$transname); + } + alarm(0); + if ($response->is_error()) { + unlink($transname); + my $message=$response->status_line; + &logthis("LWP GET: $message for $fname ($remoteurl)"); + } else { + if ($remoteurl!~/\.meta$/) { + alarm(120); + { + my $ua=new LWP::UserAgent; + my $mrequest=new HTTP::Request('GET',$remoteurl.'.meta'); + my $mresponse=$ua->request($mrequest,$fname.'.meta'); + if ($mresponse->is_error()) { + unlink($fname.'.meta'); + } + } + alarm(0); + } + rename($transname,$fname); + } + } + &Reply( $client, "ok\n", $userinput); + } else { + &Failure($client, "not_found\n", $userinput); + } + } else { + &Failure($client, "rejected\n", $userinput); + } + return 1; +} +®ister_handler("update", \&update_resource_handler, 0 ,1, 0); + +# +# Fetch a user file from a remote server to the user's home directory +# userfiles subdir. +# 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 fetch_user_file_handler { + + my ($cmd, $tail, $client) = @_; + + my $userinput = "$cmd:$tail"; + my $fname = $tail; + my ($udom,$uname,$ufile) = ($fname =~ m|^([^/]+)/([^/]+)/(.+)$|); + my $udir=&propath($udom,$uname).'/userfiles'; + unless (-e $udir) { + mkdir($udir,0770); + } + Debug("fetch user file for $fname"); + if (-e $udir) { + $ufile=~s/^[\.\~]+//; + + # IF necessary, create the path right down to the file. + # Note that any regular files in the way of this path are + # wiped out to deal with some earlier folly of mine. + + my $path = $udir; + if ($ufile =~m|(.+)/([^/]+)$|) { + my @parts=split('/',$1); + foreach my $part (@parts) { + $path .= '/'.$part; + if( -f $path) { + unlink($path); + } + if ((-e $path)!=1) { + mkdir($path,0770); + } + } + } + + + my $destname=$udir.'/'.$ufile; + my $transname=$udir.'/'.$ufile.'.in.transit'; + my $remoteurl='http://'.$clientip.'/userfiles/'.$fname; + my $response; + Debug("Remote URL : $remoteurl Transfername $transname Destname: $destname"); + alarm(120); + { + my $ua=new LWP::UserAgent; + my $request=new HTTP::Request('GET',"$remoteurl"); + $response=$ua->request($request,$transname); + } + alarm(0); + if ($response->is_error()) { + unlink($transname); + my $message=$response->status_line; + &logthis("LWP GET: $message for $fname ($remoteurl)"); + &Failure($client, "failed\n", $userinput); + } else { + Debug("Renaming $transname to $destname"); + if (!rename($transname,$destname)) { + &logthis("Unable to move $transname to $destname"); + unlink($transname); + &Failure($client, "failed\n", $userinput); + } else { + &Reply($client, "ok\n", $userinput); + } + } + } else { + &Failure($client, "not_home\n", $userinput); + } + return 1; +} +®ister_handler("fetchuserfile", \&fetch_user_file_handler, 0, 1, 0); + +# +# Remove a file from a user's home directory userfiles subdirectory. +# Parameters: +# cmd - the Lond request keyword that got us here. +# tail - the part of the command past the keyword. +# client- File descriptor connected with the client. +# +# Returns: +# 1 - Continue processing. + +sub remove_user_file_handler { + my ($cmd, $tail, $client) = @_; + + my ($fname) = split(/:/, $tail); # Get rid of any tailing :'s lonc may have sent. + + my ($udom,$uname,$ufile) = ($fname =~ m|^([^/]+)/([^/]+)/(.+)$|); + if ($ufile =~m|/\.\./|) { + # any files paths with /../ in them refuse + # to deal with + &Failure($client, "refused\n", "$cmd:$tail"); + } else { + my $udir = &propath($udom,$uname); + if (-e $udir) { + my $file=$udir.'/userfiles/'.$ufile; + if (-e $file) { + unlink($file); + if (-e $file) { + &Failure($client, "failed\n", "$cmd:$tail"); + } else { + &Reply($client, "ok\n", "$cmd:$tail"); + } + } else { + &Failure($client, "not_found\n", "$cmd:$tail"); + } + } else { + &Failure($client, "not_home\n", "$cmd:$tail"); + } + } + return 1; +} +®ister_handler("removeuserfile", \&remove_user_file_handler, 0,1,0); + + +# +# Authenticate access to a user file by checking the user's +# session token(?) +# +# Parameters: +# cmd - The request keyword that dispatched to tus. +# tail - The tail of the request (colon separated parameters). +# client - Filehandle open on the client. +# Return: +# 1. + +sub token_auth_user_file_handler { + my ($cmd, $tail, $client) = @_; + + my ($fname, $session) = split(/:/, $tail); + + chomp($session); + my $reply='non_auth'; + if (open(ENVIN,$perlvar{'lonIDsDir'}.'/'. + $session.'.id')) { + while (my $line=) { + if ($line=~ m|userfile\.\Q$fname\E\=|) { $reply='ok'; } + } + close(ENVIN); + &Reply($client, $reply); + } else { + &Failure($client, "invalid_token\n", "$cmd:$tail"); + } + return 1; + +} + +®ister_handler("tokenauthuserfile", \&token_auth_user_file_handler, 0,1,0); + + +# +# Unsubscribe from a resource. +# +# 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 unsubscribe_handler { + my ($cmd, $tail, $client) = @_; + + my $userinput= "$cmd:$tail"; + + my ($fname) = split(/:/,$tail); # Split in case there's extrs. + + &Debug("Unsubscribing $fname"); + if (-e $fname) { + &Debug("Exists"); + &Reply($client, &unsub($fname,$clientip), $userinput); + } else { + &Failure($client, "not_found\n", $userinput); + } + return 1; +} +®ister_handler("unsub", \&unsubscribe_handler, 0, 1, 0); +# Subscribe to a resource +# +# 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 subscribe_handler { + my ($cmd, $tail, $client)= @_; + + my $userinput = "$cmd:$tail"; + + &Reply( $client, &subscribe($userinput,$clientip), $userinput); + + return 1; +} +®ister_handler("sub", \&subscribe_handler, 0, 1, 0); + +# +# Determine the version of a resource (?) Or is it return +# the top version of the resource? Not yet clear from the +# code in currentversion. +# +# 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 current_version_handler { + my ($cmd, $tail, $client) = @_; + + my $userinput= "$cmd:$tail"; + + my $fname = $tail; + &Reply( $client, ¤tversion($fname)."\n", $userinput); + return 1; + +} +®ister_handler("currentversion", \¤t_version_handler, 0, 1, 0); + +# Make an entry in a user's activity log. +# +# 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 activity_log_handler { + my ($cmd, $tail, $client) = @_; + + + my $userinput= "$cmd:$tail"; + + my ($udom,$uname,$what)=split(/:/,$tail); + chomp($what); + my $proname=&propath($udom,$uname); + my $now=time; + my $hfh; + if ($hfh=IO::File->new(">>$proname/activity.log")) { + print $hfh "$now:$clientname:$what\n"; + &Reply( $client, "ok\n", $userinput); + } else { + &Failure($client, "error: ".($!+0)." IO::File->new Failed " + ."while attempting log\n", + $userinput); + } + + return 1; +} +register_handler("log", \&activity_log_handler, 0, 1, 0); + +# +# Put a namespace entry in a user profile hash. +# My druthers would be for this to be an encrypted interaction too. +# anything that might be an inadvertent covert channel about either +# user authentication or user personal information.... +# +# 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 put_user_profile_entry { + my ($cmd, $tail, $client) = @_; + + my $userinput = "$cmd:$tail"; + + my ($udom,$uname,$namespace,$what) =split(/:/,$tail); + if ($namespace ne 'roles') { + chomp($what); + my $hashref = &tie_user_hash($udom, $uname, $namespace, + &GDBM_WRCREAT(),"P",$what); + if($hashref) { + my @pairs=split(/\&/,$what); + 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); + } + } else { + &Failure( $client, "error: ".($!)." tie(GDBM) Failed ". + "while attempting put\n", $userinput); + } + } else { + &Failure( $client, "refused\n", $userinput); + } + + return 1; +} +®ister_handler("put", \&put_user_profile_entry, 0, 1, 0); + +# +# Increment a profile entry in the user history file. +# The history contains keyword value pairs. In this case, +# The value itself is a pair of numbers. The first, the current value +# the second an increment that this function applies to the current +# value. +# +# 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 increment_user_value_handler { + my ($cmd, $tail, $client) = @_; + + my $userinput = "$cmd:$tail"; + + my ($udom,$uname,$namespace,$what) =split(/:/,$tail); + if ($namespace ne 'roles') { + chomp($what); + my $hashref = &tie_user_hash($udom, $uname, + $namespace, &GDBM_WRCREAT(), + "P",$what); + if ($hashref) { + my @pairs=split(/\&/,$what); + foreach my $pair (@pairs) { + my ($key,$value)=split(/=/,$pair); + # We could check that we have a number... + if (! defined($value) || $value eq '') { + $value = 1; + } + $hashref->{$key}+=$value; + } + if (untie(%$hashref)) { + &Reply( $client, "ok\n", $userinput); + } else { + &Failure($client, "error: ".($!+0)." untie(GDBM) failed ". + "while attempting inc\n", $userinput); + } + } else { + &Failure($client, "error: ".($!+0)." tie(GDBM) Failed ". + "while attempting inc\n", $userinput); + } + } else { + &Failure($client, "refused\n", $userinput); + } + + return 1; +} +®ister_handler("inc", \&increment_user_value_handler, 0, 1, 0); + + +# +# Put a new role for a user. Roles are LonCAPA's packaging of permissions. +# Each 'role' a user has implies a set of permissions. Adding a new role +# for a person grants the permissions packaged with that role +# to that user when the role is selected. +# +# Parameters: +# $cmd - The command string (rolesput). +# $tail - The remainder of the request line. For rolesput this +# consists of a colon separated list that contains: +# The domain and user that is granting the role (logged). +# The domain and user that is getting the role. +# The roles being granted as a set of & separated pairs. +# each pair a key value pair. +# $client - File descriptor connected to the client. +# Returns: +# 0 - If the daemon should exit +# 1 - To continue processing. +# +# +sub roles_put_handler { + my ($cmd, $tail, $client) = @_; + + my $userinput = "$cmd:$tail"; + + my ( $exedom, $exeuser, $udom, $uname, $what) = split(/:/,$tail); + + + my $namespace='roles'; + chomp($what); + my $hashref = &tie_user_hash($udom, $uname, $namespace, + &GDBM_WRCREAT(), "P", + "$exedom:$exeuser:$what"); + # + # Log the attempt to set a role. The {}'s here ensure that the file + # handle is open for the minimal amount of time. Since the flush + # is done on close this improves the chances the log will be an un- + # corrupted ordered thing. + if ($hashref) { + my @pairs=split(/\&/,$what); + foreach my $pair (@pairs) { + my ($key,$value)=split(/=/,$pair); + &manage_permissions($key, $udom, $uname, + &get_auth_type( $udom, $uname)); + $hashref->{$key}=$value; + } + if (untie($hashref)) { + &Reply($client, "ok\n", $userinput); + } else { + &Failure( $client, "error: ".($!+0)." untie(GDBM) Failed ". + "while attempting rolesput\n", $userinput); + } + } else { + &Failure( $client, "error: ".($!+0)." tie(GDBM) Failed ". + "while attempting rolesput\n", $userinput); + } + return 1; +} +®ister_handler("rolesput", \&roles_put_handler, 1,1,0); # Encoded client only. + +# +# Deletes (removes) a role for a user. This is equivalent to removing +# a permissions package associated with the role from the user's profile. +# +# Parameters: +# $cmd - The command (rolesdel) +# $tail - The remainder of the request line. This consists +# of: +# The domain and user requesting the change (logged) +# The domain and user being changed. +# The roles being revoked. These are shipped to us +# as a bunch of & separated role name keywords. +# $client - The file handle open on the client. +# Returns: +# 1 - Continue processing +# 0 - Exit. +# +sub roles_delete_handler { + my ($cmd, $tail, $client) = @_; + + my $userinput = "$cmd:$tail"; + + my ($exedom,$exeuser,$udom,$uname,$what)=split(/:/,$tail); + &Debug("cmd = ".$cmd." exedom= ".$exedom."user = ".$exeuser." udom=".$udom. + "what = ".$what); + my $namespace='roles'; + chomp($what); + my $hashref = &tie_user_hash($udom, $uname, $namespace, + &GDBM_WRCREAT(), "D", + "$exedom:$exeuser:$what"); + + if ($hashref) { + my @rolekeys=split(/\&/,$what); + + foreach my $key (@rolekeys) { + delete $hashref->{$key}; + } + if (untie(%$hashref)) { + &Reply($client, "ok\n", $userinput); + } else { + &Failure( $client, "error: ".($!+0)." untie(GDBM) Failed ". + "while attempting rolesdel\n", $userinput); + } + } else { + &Failure( $client, "error: ".($!+0)." tie(GDBM) Failed ". + "while attempting rolesdel\n", $userinput); + } + + return 1; +} +®ister_handler("rolesdel", \&roles_delete_handler, 1,1, 0); # Encoded client only + +# Unencrypted get from a user's profile database. See +# GetProfileEntryEncrypted for a version that does end-to-end encryption. +# This function retrieves a keyed item from a specific named database in the +# user's directory. +# +# Parameters: +# $cmd - Command request keyword (get). +# $tail - Tail of the command. This is a colon separated list +# consisting of the domain and username that uniquely +# identifies the profile, +# The 'namespace' which selects the gdbm file to +# do the lookup in, +# & separated list of keys to lookup. Note that +# the values are returned as an & separated list too. +# $client - File descriptor open on the client. +# Returns: +# 1 - Continue processing. +# 0 - Exit. +# +sub get_profile_entry { + my ($cmd, $tail, $client) = @_; + + my $userinput= "$cmd:$tail"; + + my ($udom,$uname,$namespace,$what) = split(/:/,$tail); + chomp($what); + my $hashref = &tie_user_hash($udom, $uname, $namespace, + &GDBM_READER()); + if ($hashref) { + my @queries=split(/\&/,$what); + my $qresult=''; + + for (my $i=0;$i<=$#queries;$i++) { + $qresult.="$hashref->{$queries[$i]}&"; # Presumably failure gives empty string. + } + $qresult=~s/\&$//; # Remove trailing & from last lookup. + if (untie(%$hashref)) { + &Reply($client, "$qresult\n", $userinput); + } else { + &Failure($client, "error: ".($!+0)." untie(GDBM) Failed ". + "while attempting get\n", $userinput); + } + } else { + if ($!+0 == 2) { # +0 coerces errno -> number 2 is ENOENT + &Failure($client, "error:No such file or ". + "GDBM reported bad block error\n", $userinput); + } else { # Some other undifferentiated err. + &Failure($client, "error: ".($!+0)." tie(GDBM) Failed ". + "while attempting get\n", $userinput); + } + } + return 1; +} +®ister_handler("get", \&get_profile_entry, 0,1,0); + +# +# Process the encrypted get request. Note that the request is sent +# in clear, but the reply is encrypted. This is a small covert channel: +# information about the sensitive keys is given to the snooper. Just not +# information about the values of the sensitive key. Hmm if I wanted to +# know these I'd snoop for the egets. Get the profile item names from them +# and then issue a get for them since there's no enforcement of the +# requirement of an encrypted get for particular profile items. If I +# were re-doing this, I'd force the request to be encrypted as well as the +# reply. I'd also just enforce encrypted transactions for all gets since +# that would prevent any covert channel snooping. +# +# Parameters: +# $cmd - Command keyword of request (eget). +# $tail - Tail of the command. See GetProfileEntry # for more information about this. +# $client - File open on the client. +# Returns: +# 1 - Continue processing +# 0 - server should exit. +sub get_profile_entry_encrypted { + my ($cmd, $tail, $client) = @_; + + my $userinput = "$cmd:$tail"; + + my ($cmd,$udom,$uname,$namespace,$what) = split(/:/,$userinput); + chomp($what); + my $hashref = &tie_user_hash($udom, $uname, $namespace, + &GDBM_READER()); + if ($hashref) { + my @queries=split(/\&/,$what); + my $qresult=''; + for (my $i=0;$i<=$#queries;$i++) { + $qresult.="$hashref->{$queries[$i]}&"; + } + if (untie(%$hashref)) { + $qresult=~s/\&$//; + if ($cipher) { + my $cmdlength=length($qresult); + $qresult.=" "; + my $encqresult=''; + for(my $encidx=0;$encidx<=$cmdlength;$encidx+=8) { + $encqresult.= unpack("H16", + $cipher->encrypt(substr($qresult, + $encidx, + 8))); + } + &Reply( $client, "enc:$cmdlength:$encqresult\n", $userinput); + } else { + &Failure( $client, "error:no_key\n", $userinput); + } + } else { + &Failure($client, "error: ".($!+0)." untie(GDBM) Failed ". + "while attempting eget\n", $userinput); + } + } else { + &Failure($client, "error: ".($!+0)." tie(GDBM) Failed ". + "while attempting eget\n", $userinput); + } + + return 1; +} +®ister_handler("eget", \&GetProfileEntryEncrypted, 0, 1, 0); +# +# Deletes a key in a user profile database. +# +# Parameters: +# $cmd - Command keyword (del). +# $tail - Command tail. IN this case a colon +# separated list containing: +# The domain and user that identifies uniquely +# the identity of the user. +# The profile namespace (name of the profile +# database file). +# & separated list of keywords to delete. +# $client - File open on client socket. +# Returns: +# 1 - Continue processing +# 0 - Exit server. +# +# + +sub delete_profile_entry { + my ($cmd, $tail, $client) = @_; + + my $userinput = "cmd:$tail"; + + my ($udom,$uname,$namespace,$what) = split(/:/,$tail); + chomp($what); + my $hashref = &tie_user_hash($udom, $uname, $namespace, + &GDBM_WRCREAT(), + "D",$what); + if ($hashref) { + my @keys=split(/\&/,$what); + foreach my $key (@keys) { + delete($hashref->{$key}); + } + if (untie(%$hashref)) { + &Reply($client, "ok\n", $userinput); + } else { + &Failure($client, "error: ".($!+0)." untie(GDBM) Failed ". + "while attempting del\n", $userinput); + } + } else { + &Failure( $client, "error: ".($!+0)." tie(GDBM) Failed ". + "while attempting del\n", $userinput); + } + return 1; +} +®ister_handler("del", \&delete_profile_entry, 0, 1, 0); +# +# List the set of keys that are defined in a profile database file. +# A successful reply from this will contain an & separated list of +# the keys. +# Parameters: +# $cmd - Command request (keys). +# $tail - Remainder of the request, a colon separated +# list containing domain/user that identifies the +# user being queried, and the database namespace +# (database filename essentially). +# $client - File open on the client. +# Returns: +# 1 - Continue processing. +# 0 - Exit the server. +# +sub get_profile_keys { + my ($cmd, $tail, $client) = @_; + + my $userinput = "$cmd:$tail"; + + my ($udom,$uname,$namespace)=split(/:/,$tail); + my $qresult=''; + my $hashref = &tie_user_hash($udom, $uname, $namespace, + &GDBM_READER()); + if ($hashref) { + foreach my $key (keys %$hashref) { + $qresult.="$key&"; + } + if (untie(%$hashref)) { + $qresult=~s/\&$//; + &Reply($client, "$qresult\n", $userinput); + } else { + &Failure($client, "error: ".($!+0)." untie(GDBM) Failed ". + "while attempting keys\n", $userinput); + } + } else { + &Failure( $client, "error: ".($!+0)." tie(GDBM) Failed ". + "while attempting keys\n", $userinput); + } + + return 1; +} +®ister_handler("keys", \&get_profile_keys, 0, 1, 0); + +# +# Dump the contents of a user profile database. +# Note that this constitutes a very large covert channel too since +# the dump will return sensitive information that is not encrypted. +# The naive security assumption is that the session negotiation ensures +# our client is trusted and I don't believe that's assured at present. +# Sure want badly to go to ssl or tls. Of course if my peer isn't really +# a LonCAPA node they could have negotiated an encryption key too so >sigh<. +# +# Parameters: +# $cmd - The command request keyword (currentdump). +# $tail - Remainder of the request, consisting of a colon +# separated list that has the domain/username and +# the namespace to dump (database file). +# $client - file open on the remote client. +# Returns: +# 1 - Continue processing. +# 0 - Exit the server. +# +sub dump_profile_database { + my ($cmd, $tail, $client) = @_; + + my $userinput = "$cmd:$tail"; + + my ($udom,$uname,$namespace) = split(/:/,$tail); + my $hashref = &tie_user_hash($udom, $uname, $namespace, + &GDBM_READER()); + if ($hashref) { + # Structure of %data: + # $data{$symb}->{$parameter}=$value; + # $data{$symb}->{'v.'.$parameter}=$version; + # since $parameter will be unescaped, we do not + # have to worry about silly parameter names... + + my $qresult=''; + my %data = (); # A hash of anonymous hashes.. + while (my ($key,$value) = each(%$hashref)) { + my ($v,$symb,$param) = split(/:/,$key); + next if ($v eq 'version' || $symb eq 'keys'); + next if (exists($data{$symb}) && + exists($data{$symb}->{$param}) && + $data{$symb}->{'v.'.$param} > $v); + $data{$symb}->{$param}=$value; + $data{$symb}->{'v.'.$param}=$v; + } + if (untie(%$hashref)) { + while (my ($symb,$param_hash) = each(%data)) { + while(my ($param,$value) = each (%$param_hash)){ + next if ($param =~ /^v\./); # Ignore versions... + # + # Just dump the symb=value pairs separated by & + # + $qresult.=$symb.':'.$param.'='.$value.'&'; + } + } + chop($qresult); + &Reply($client , "$qresult\n", $userinput); + } else { + &Failure( $client, "error: ".($!+0)." untie(GDBM) Failed ". + "while attempting currentdump\n", $userinput); + } + } else { + &Failure($client, "error: ".($!+0)." tie(GDBM) Failed ". + "while attempting currentdump\n", $userinput); + } + + return 1; +} +®ister_handler("currentdump", \&dump_profile_database, 0, 1, 0); + +# +# Dump a profile database with an optional regular expression +# to match against the keys. In this dump, no effort is made +# to separate symb from version information. Presumably the +# databases that are dumped by this command are of a different +# structure. Need to look at this and improve the documentation of +# both this and the currentdump handler. +# Parameters: +# $cmd - The command keyword. +# $tail - All of the characters after the $cmd: +# These are expected to be a colon +# separated list containing: +# domain/user - identifying the user. +# namespace - identifying the database. +# regexp - optional regular expression +# that is matched against +# database keywords to do +# selective dumps. +# $client - Channel open on the client. +# Returns: +# 1 - Continue processing. +# Side effects: +# response is written to $client. +# +sub dump_with_regexp { + my ($cmd, $tail, $client) = @_; + + + my $userinput = "$cmd:$tail"; + + my ($udom,$uname,$namespace,$regexp)=split(/:/,$tail); + if (defined($regexp)) { + $regexp=&unescape($regexp); + } else { + $regexp='.'; + } + my $hashref = &tie_user_hash($udom, $uname, $namespace, + &GDBM_READER()); + if ($hashref) { + my $qresult=''; + while (my ($key,$value) = each(%$hashref)) { + if ($regexp eq '.') { + $qresult.=$key.'='.$value.'&'; + } else { + my $unescapeKey = &unescape($key); + if (eval('$unescapeKey=~/$regexp/')) { + $qresult.="$key=$value&"; + } + } + } + if (untie(%$hashref)) { + chop($qresult); + &Reply($client, "$qresult\n", $userinput); + } else { + &Failure( $client, "error: ".($!+0)." untie(GDBM) Failed ". + "while attempting dump\n", $userinput); + } + } else { + &Failure($client, "error: ".($!+0)." tie(GDBM) Failed ". + "while attempting dump\n", $userinput); + } + + return 1; +} + +®ister_handler("dump", \&dump_with_regexp, 0, 1, 0); + +# Store a set of key=value pairs associated with a versioned name. +# +# Parameters: +# $cmd - Request command keyword. +# $tail - Tail of the request. This is a colon +# separated list containing: +# domain/user - User and authentication domain. +# namespace - Name of the database being modified +# rid - Resource keyword to modify. +# what - new value associated with rid. +# +# $client - Socket open on the client. +# +# +# Returns: +# 1 (keep on processing). +# Side-Effects: +# Writes to the client +sub store_handler { + my ($cmd, $tail, $client) = @_; + + my $userinput = "$cmd:$tail"; + + my ($udom,$uname,$namespace,$rid,$what) =split(/:/,$tail); + if ($namespace ne 'roles') { + + chomp($what); + my @pairs=split(/\&/,$what); + my $hashref = &tie_user_hash($udom, $uname, $namespace, + &GDBM_WRCREAT(), "P", + "$rid:$what"); + if ($hashref) { + my $now = time; + my @previouskeys=split(/&/,$hashref->{"keys:$rid"}); + my $key; + $hashref->{"version:$rid"}++; + my $version=$hashref->{"version:$rid"}; + my $allkeys=''; + foreach my $pair (@pairs) { + my ($key,$value)=split(/=/,$pair); + $allkeys.=$key.':'; + $hashref->{"$version:$rid:$key"}=$value; + } + $hashref->{"$version:$rid:timestamp"}=$now; + $allkeys.='timestamp'; + $hashref->{"$version:keys:$rid"}=$allkeys; + if (untie($hashref)) { + &Reply($client, "ok\n", $userinput); + } else { + &Failure($client, "error: ".($!+0)." untie(GDBM) Failed ". + "while attempting store\n", $userinput); + } + } else { + &Failure( $client, "error: ".($!+0)." tie(GDBM) Failed ". + "while attempting store\n", $userinput); + } + } else { + &Failure($client, "refused\n", $userinput); + } + + return 1; +} +®ister_handler("store", \&store_handler, 0, 1, 0); +# +# Dump out all versions of a resource that has key=value pairs associated +# with it for each version. These resources are built up via the store +# command. +# +# Parameters: +# $cmd - Command keyword. +# $tail - Remainder of the request which consists of: +# domain/user - User and auth. domain. +# namespace - name of resource database. +# rid - Resource id. +# $client - socket open on the client. +# +# Returns: +# 1 indicating the caller should not yet exit. +# Side-effects: +# Writes a reply to the client. +# The reply is a string of the following shape: +# version=current&version:keys=k1:k2...&1:k1=v1&1:k2=v2... +# Where the 1 above represents version 1. +# this continues for all pairs of keys in all versions. +# +# +# +# +sub restore_handler { + my ($cmd, $tail, $client) = @_; + + my $userinput = "$cmd:$tail"; # Only used for logging purposes. + + my ($cmd,$udom,$uname,$namespace,$rid) = split(/:/,$userinput); + $namespace=~s/\//\_/g; + $namespace=~s/\W//g; + chomp($rid); + my $proname=&propath($udom,$uname); + my $qresult=''; + my %hash; + if (tie(%hash,'GDBM_File',"$proname/$namespace.db", + &GDBM_READER(),0640)) { + my $version=$hash{"version:$rid"}; + $qresult.="version=$version&"; + my $scope; + for ($scope=1;$scope<=$version;$scope++) { + my $vkeys=$hash{"$scope:keys:$rid"}; + my @keys=split(/:/,$vkeys); + my $key; + $qresult.="$scope:keys=$vkeys&"; + foreach $key (@keys) { + $qresult.="$scope:$key=".$hash{"$scope:$rid:$key"}."&"; + } + } + if (untie(%hash)) { + $qresult=~s/\&$//; + &Reply( $client, "$qresult\n", $userinput); + } else { + &Failure($client, "error: ".($!+0)." untie(GDBM) Failed ". + "while attempting restore\n", $userinput); + } + } else { + &Failure($client, "error: ".($!+0)." tie(GDBM) Failed ". + "while attempting restore\n", $userinput); + } + + return 1; + + +} +®ister_handler("restore", \&restore_handler, 0,1,0); + +# +# Add a chat message to to a discussion board. +# +# Parameters: +# $cmd - Request keyword. +# $tail - Tail of the command. A colon separated list +# containing: +# cdom - Domain on which the chat board lives +# cnum - Identifier of the discussion group. +# post - Body of the posting. +# $client - Socket open on the client. +# Returns: +# 1 - Indicating caller should keep on processing. +# +# Side-effects: +# writes a reply to the client. +# +# +sub send_chat_handler { + my ($cmd, $tail, $client) = @_; + + + my $userinput = "$cmd:$tail"; + + my ($cdom,$cnum,$newpost)=split(/\:/,$tail); + &chat_add($cdom,$cnum,$newpost); + &Reply($client, "ok\n", $userinput); + + return 1; +} +®ister_handler("chatsend", \&send_chat_handler, 0, 1, 0); +# +# Retrieve the set of chat messagss from a discussion board. +# +# Parameters: +# $cmd - Command keyword that initiated the request. +# $tail - Remainder of the request after the command +# keyword. In this case a colon separated list of +# chat domain - Which discussion board. +# chat id - Discussion thread(?) +# domain/user - Authentication domain and username +# of the requesting person. +# $client - Socket open on the client program. +# Returns: +# 1 - continue processing +# Side effects: +# Response is written to the client. +# +sub retrieve_chat_handler { + my ($cmd, $tail, $client) = @_; + + + my $userinput = "$cmd:$tail"; + + my ($cdom,$cnum,$udom,$uname)=split(/\:/,$tail); + my $reply=''; + foreach (&get_chat($cdom,$cnum,$udom,$uname)) { + $reply.=&escape($_).':'; + } + $reply=~s/\:$//; + &Reply($client, $reply."\n", $userinput); + + + return 1; +} +®ister_handler("chatretr", \&retrieve_chat_handler, 0, 1, 0); + +# +# Initiate a query of an sql database. SQL query repsonses get put in +# a file for later retrieval. This prevents sql query results from +# bottlenecking the system. Note that with loncnew, perhaps this is +# less of an issue since multiple outstanding requests can be concurrently +# serviced. +# +# Parameters: +# $cmd - COmmand keyword that initiated the request. +# $tail - Remainder of the command after the keyword. +# For this function, this consists of a query and +# 3 arguments that are self-documentingly labelled +# in the original arg1, arg2, arg3. +# $client - Socket open on the client. +# Return: +# 1 - Indicating processing should continue. +# Side-effects: +# a reply is written to $client. +# +sub send_query_handler { + my ($cmd, $tail, $client) = @_; + + + my $userinput = "$cmd:$tail"; + + my ($query,$arg1,$arg2,$arg3)=split(/\:/,$tail); + $query=~s/\n*$//g; + &Reply($client, "". &sql_reply("$clientname\&$query". + "\&$arg1"."\&$arg2"."\&$arg3")."\n", + $userinput); + + return 1; +} +®ister_handler("querysend", \&send_query_handler, 0, 1, 0); + +# +# Add a reply to an sql query. SQL queries are done asyncrhonously. +# The query is submitted via a "querysend" transaction. +# There it is passed on to the lonsql daemon, queued and issued to +# mysql. +# This transaction is invoked when the sql transaction is complete +# it stores the query results in flie and indicates query completion. +# presumably local software then fetches this response... I'm guessing +# the sequence is: lonc does a querysend, we ask lonsql to do it. +# lonsql on completion of the query interacts with the lond of our +# client to do a query reply storing two files: +# - id - The results of the query. +# - id.end - Indicating the transaction completed. +# NOTE: id is a unique id assigned to the query and querysend time. +# Parameters: +# $cmd - Command keyword that initiated this request. +# $tail - Remainder of the tail. In this case that's a colon +# separated list containing the query Id and the +# results of the query. +# $client - Socket open on the client. +# Return: +# 1 - Indicating that we should continue processing. +# Side effects: +# ok written to the client. +# +sub reply_query_handler { + my ($cmd, $tail, $client) = @_; + + + my $userinput = "$cmd:$tail"; + + my ($cmd,$id,$reply)=split(/:/,$userinput); + my $store; + my $execdir=$perlvar{'lonDaemons'}; + if ($store=IO::File->new(">$execdir/tmp/$id")) { + $reply=~s/\&/\n/g; + print $store $reply; + close $store; + my $store2=IO::File->new(">$execdir/tmp/$id.end"); + print $store2 "done\n"; + close $store2; + &Reply($client, "ok\n", $userinput); + } else { + &Failure($client, "error: ".($!+0) + ." IO::File->new Failed ". + "while attempting queryreply\n", $userinput); + } + + + return 1; +} +®ister_handler("queryreply", \&reply_query_handler, 0, 1, 0); + +# +# Process the courseidput request. Not quite sure what this means +# at the system level sense. It appears a gdbm file in the +# /home/httpd/lonUsers/$domain/nohist_courseids is tied and +# a set of entries made in that database. +# +# Parameters: +# $cmd - The command keyword that initiated this request. +# $tail - Tail of the command. In this case consists of a colon +# separated list contaning the domain to apply this to and +# an ampersand separated list of keyword=value pairs. +# $client - Socket open on the client. +# Returns: +# 1 - indicating that processing should continue +# +# Side effects: +# reply is written to the client. +# +sub put_course_id_handler { + my ($cmd, $tail, $client) = @_; + + + my $userinput = "$cmd:$tail"; + + my ($udom, $what) = split(/:/, $tail); + chomp($what); + my $now=time; + my @pairs=split(/\&/,$what); + + my $hashref = &tie_domain_hash($udom, "nohist_courseids", &GDBM_WRCREAT()); + if ($hashref) { + foreach my $pair (@pairs) { + my ($key,$value)=split(/=/,$pair); + $hashref->{$key}=$value.':'.$now; + } + if (untie(%$hashref)) { + &Reply($client, "ok\n", $userinput); + } else { + &Failure( $client, "error: ".($!+0) + ." untie(GDBM) Failed ". + "while attempting courseidput\n", $userinput); + } + } else { + &Failure( $client, "error: ".($!+0) + ." tie(GDBM) Failed ". + "while attempting courseidput\n", $userinput); + } + + return 1; +} +®ister_handler("courseidput", \&put_course_id_handler, 0, 1, 0); + +# Retrieves the value of a course id resource keyword pattern +# defined since a starting date. Both the starting date and the +# keyword pattern are optional. If the starting date is not supplied it +# is treated as the beginning of time. If the pattern is not found, +# it is treatred as "." matching everything. +# +# Parameters: +# $cmd - Command keyword that resulted in us being dispatched. +# $tail - The remainder of the command that, in this case, consists +# of a colon separated list of: +# domain - The domain in which the course database is +# defined. +# since - Optional parameter describing the minimum +# time of definition(?) of the resources that +# will match the dump. +# description - regular expression that is used to filter +# the dump. Only keywords matching this regexp +# will be used. +# $client - The socket open on the client. +# Returns: +# 1 - Continue processing. +# Side Effects: +# a reply is written to $client. +sub dump_course_id_handler { + my ($cmd, $tail, $client) = @_; + + my $userinput = "$cmd:$tail"; + + my ($udom,$since,$description) =split(/:/,$tail); + if (defined($description)) { + $description=&unescape($description); + } else { + $description='.'; + } + unless (defined($since)) { $since=0; } + my $qresult=''; + my $hashref = &tie_domain_hash($udom, "nohist_courseids", &GDBM_WRCREAT()); + if ($hashref) { + while (my ($key,$value) = each(%$hashref)) { + my ($descr,$lasttime,$inst_code); + if ($value =~ m/^([^\:]*):([^\:]*):(\d+)$/) { + ($descr,$inst_code,$lasttime)=($1,$2,$3); + } else { + ($descr,$lasttime) = split(/\:/,$value); + } + if ($lasttime<$since) { next; } + if ($description eq '.') { + $qresult.=$key.'='.$descr.':'.$inst_code.'&'; + } else { + my $unescapeVal = &unescape($descr); + if (eval('$unescapeVal=~/\Q$description\E/i')) { + $qresult.=$key.'='.$descr.':'.$inst_code.'&'; + } + } + } + if (untie(%$hashref)) { + chop($qresult); + &Reply($client, "$qresult\n", $userinput); + } else { + &Failure($client, "error: ".($!+0)." untie(GDBM) Failed ". + "while attempting courseiddump\n", $userinput); + } + } else { + &Failure($client, "error: ".($!+0)." tie(GDBM) Failed ". + "while attempting courseiddump\n", $userinput); + } + + + return 1; +} +®ister_handler("courseiddump", \&dump_course_id_handler, 0, 1, 0); +# +# +# #--------------------------------------------------------------- # # Getting, decoding and dispatching requests: @@ -1523,12 +2988,12 @@ register_handler("passwd", \&change_pass # Gets a Request message from the client. The transaction # is defined as a 'line' of text. We remove the new line # from the text line. -# +# sub get_request { my $input = <$client>; chomp($input); - Debug("get_request: Request = $input\n"); + &Debug("get_request: Request = $input\n"); &status('Processing '.$clientname.':'.$input); @@ -1627,968 +3092,8 @@ sub process_request { #------------------- Commands not yet in spearate handlers. -------------- - -# -------------------------------------------------------------------- makeuser - if ($userinput =~ /^makeuser/) { # encoded and client. - &Debug("Make user received"); - my $oldumask=umask(0077); - if (($wasenc==1) && isClient) { - my - ($cmd,$udom,$uname,$umode,$npass)=split(/:/,$userinput); - &Debug("cmd =".$cmd." $udom =".$udom. - " uname=".$uname); - chomp($npass); - $npass=&unescape($npass); - my $proname=propath($udom,$uname); - my $passfilename="$proname/passwd"; - &Debug("Password file created will be:". - $passfilename); - if (-e $passfilename) { - print $client "already_exists\n"; - } elsif ($udom ne $currentdomainid) { - print $client "not_right_domain\n"; - } else { - my @fpparts=split(/\//,$proname); - my $fpnow=$fpparts[0].'/'.$fpparts[1].'/'.$fpparts[2]; - my $fperror=''; - for (my $i=3;$i<=$#fpparts;$i++) { - $fpnow.='/'.$fpparts[$i]; - unless (-e $fpnow) { - unless (mkdir($fpnow,0777)) { - $fperror="error: ".($!+0) - ." mkdir failed while attempting " - ."makeuser"; - } - } - } - unless ($fperror) { - my $result=&make_passwd_file($uname, $umode,$npass, - $passfilename); - print $client $result; - } else { - print $client "$fperror\n"; - } - } - } else { - Reply($client, "refused\n", $userinput); - - } - umask($oldumask); -# -------------------------------------------------------------- changeuserauth - } elsif ($userinput =~ /^changeuserauth/) { # encoded & client - &Debug("Changing authorization"); - if (($wasenc==1) && isClient) { - my - ($cmd,$udom,$uname,$umode,$npass)=split(/:/,$userinput); - chomp($npass); - &Debug("cmd = ".$cmd." domain= ".$udom. - "uname =".$uname." umode= ".$umode); - $npass=&unescape($npass); - my $proname=&propath($udom,$uname); - my $passfilename="$proname/passwd"; - if ($udom ne $currentdomainid) { - print $client "not_right_domain\n"; - } else { - my $result=&make_passwd_file($uname, $umode,$npass, - $passfilename); - Reply($client, $result, $userinput); - } - } else { - Reply($client, "refused\n", $userinput); - - } -# ------------------------------------------------------------------------ home - } elsif ($userinput =~ /^home/) { # client clear or encoded - if(isClient) { - my ($cmd,$udom,$uname)=split(/:/,$userinput); - chomp($uname); - my $proname=propath($udom,$uname); - if (-e $proname) { - print $client "found\n"; - } else { - print $client "not_found\n"; - } - } else { - Reply($client, "refused\n", $userinput); - - } -# ---------------------------------------------------------------------- update - } elsif ($userinput =~ /^update/) { # client clear or encoded. - if(isClient) { - my ($cmd,$fname)=split(/:/,$userinput); - my $ownership=ishome($fname); - if ($ownership eq 'not_owner') { - if (-e $fname) { - my ($dev,$ino,$mode,$nlink, - $uid,$gid,$rdev,$size, - $atime,$mtime,$ctime, - $blksize,$blocks)=stat($fname); - my $now=time; - my $since=$now-$atime; - if ($since>$perlvar{'lonExpire'}) { - my $reply= - &reply("unsub:$fname","$clientname"); - unlink("$fname"); - } else { - my $transname="$fname.in.transfer"; - my $remoteurl= - &reply("sub:$fname","$clientname"); - my $response; - { - my $ua=new LWP::UserAgent; - my $request=new HTTP::Request('GET',"$remoteurl"); - $response=$ua->request($request,$transname); - } - if ($response->is_error()) { - unlink($transname); - my $message=$response->status_line; - &logthis( - "LWP GET: $message for $fname ($remoteurl)"); - } else { - if ($remoteurl!~/\.meta$/) { - my $ua=new LWP::UserAgent; - my $mrequest= - new HTTP::Request('GET',$remoteurl.'.meta'); - my $mresponse= - $ua->request($mrequest,$fname.'.meta'); - if ($mresponse->is_error()) { - unlink($fname.'.meta'); - } - } - rename($transname,$fname); - } - } - print $client "ok\n"; - } else { - print $client "not_found\n"; - } - } else { - print $client "rejected\n"; - } - } else { - Reply($client, "refused\n", $userinput); - - } -# -------------------------------------- fetch a user file from a remote server - } elsif ($userinput =~ /^fetchuserfile/) { # Client clear or enc. - if(isClient) { - my ($cmd,$fname)=split(/:/,$userinput); - my ($udom,$uname,$ufile) = ($fname =~ m|^([^/]+)/([^/]+)/(.+)$|); - my $udir=propath($udom,$uname).'/userfiles'; - unless (-e $udir) { mkdir($udir,0770); } - if (-e $udir) { - $ufile=~s/^[\.\~]+//; - my $path = $udir; - if ($ufile =~m|(.+)/([^/]+)$|) { - my @parts=split('/',$1); - foreach my $part (@parts) { - $path .= '/'.$part; - if ((-e $path)!=1) { - mkdir($path,0770); - } - } - } - my $destname=$udir.'/'.$ufile; - my $transname=$udir.'/'.$ufile.'.in.transit'; - my $remoteurl='http://'.$clientip.'/userfiles/'.$fname; - my $response; - { - my $ua=new LWP::UserAgent; - my $request=new HTTP::Request('GET',"$remoteurl"); - $response=$ua->request($request,$transname); - } - if ($response->is_error()) { - unlink($transname); - my $message=$response->status_line; - &logthis("LWP GET: $message for $fname ($remoteurl)"); - print $client "failed\n"; - } else { - if (!rename($transname,$destname)) { - &logthis("Unable to move $transname to $destname"); - unlink($transname); - print $client "failed\n"; - } else { - print $client "ok\n"; - } - } - } else { - print $client "not_home\n"; - } - } else { - Reply($client, "refused\n", $userinput); - } -# --------------------------------------------------------- remove a user file - } elsif ($userinput =~ /^removeuserfile/) { # Client clear or enc. - if(isClient) { - my ($cmd,$fname)=split(/:/,$userinput); - my ($udom,$uname,$ufile) = ($fname =~ m|^([^/]+)/([^/]+)/(.+)$|); - &logthis("$udom - $uname - $ufile"); - if ($ufile =~m|/\.\./|) { - # any files paths with /../ in them refuse - # to deal with - print $client "refused\n"; - } else { - my $udir=propath($udom,$uname); - if (-e $udir) { - my $file=$udir.'/userfiles/'.$ufile; - if (-e $file) { - unlink($file); - if (-e $file) { - print $client "failed\n"; - } else { - print $client "ok\n"; - } - } else { - print $client "not_found\n"; - } - } else { - print $client "not_home\n"; - } - } - } else { - Reply($client, "refused\n", $userinput); - } -# ------------------------------------------ authenticate access to a user file - } elsif ($userinput =~ /^tokenauthuserfile/) { # Client only - if(isClient) { - my ($cmd,$fname,$session)=split(/:/,$userinput); - chomp($session); - my $reply='non_auth'; - if (open(ENVIN,$perlvar{'lonIDsDir'}.'/'. - $session.'.id')) { - while (my $line=) { - if ($line=~ m|userfile\.\Q$fname\E\=|) { $reply='ok'; } - } - close(ENVIN); - print $client $reply."\n"; - } else { - print $client "invalid_token\n"; - } - } else { - Reply($client, "refused\n", $userinput); - - } -# ----------------------------------------------------------------- unsubscribe - } elsif ($userinput =~ /^unsub/) { - if(isClient) { - my ($cmd,$fname)=split(/:/,$userinput); - if (-e $fname) { - print $client &unsub($fname,$clientip); - } else { - print $client "not_found\n"; - } - } else { - Reply($client, "refused\n", $userinput); - - } -# ------------------------------------------------------------------- subscribe - } elsif ($userinput =~ /^sub/) { - if(isClient) { - print $client &subscribe($userinput,$clientip); - } else { - Reply($client, "refused\n", $userinput); - - } -# ------------------------------------------------------------- current version - } elsif ($userinput =~ /^currentversion/) { - if(isClient) { - my ($cmd,$fname)=split(/:/,$userinput); - print $client ¤tversion($fname)."\n"; - } else { - Reply($client, "refused\n", $userinput); - - } -# ------------------------------------------------------------------------- log - } elsif ($userinput =~ /^log/) { - if(isClient) { - my ($cmd,$udom,$uname,$what)=split(/:/,$userinput); - chomp($what); - my $proname=propath($udom,$uname); - my $now=time; - { - my $hfh; - if ($hfh=IO::File->new(">>$proname/activity.log")) { - print $hfh "$now:$clientname:$what\n"; - print $client "ok\n"; - } else { - print $client "error: ".($!+0) - ." IO::File->new Failed " - ."while attempting log\n"; - } - } - } else { - Reply($client, "refused\n", $userinput); - - } -# ------------------------------------------------------------------------- put - } elsif ($userinput =~ /^put/) { - if(isClient) { - my ($cmd,$udom,$uname,$namespace,$what) - =split(/:/,$userinput,5); - $namespace=~s/\//\_/g; - $namespace=~s/\W//g; - if ($namespace ne 'roles') { - chomp($what); - my $proname=propath($udom,$uname); - my $now=time; - my @pairs=split(/\&/,$what); - my %hash; - if (tie(%hash,'GDBM_File', - "$proname/$namespace.db", - &GDBM_WRCREAT(),0640)) { - unless ($namespace=~/^nohist\_/) { - my $hfh; - if ($hfh=IO::File->new(">>$proname/$namespace.hist")) { print $hfh "P:$now:$what\n"; } - } - - foreach my $pair (@pairs) { - my ($key,$value)=split(/=/,$pair); - $hash{$key}=$value; - } - if (untie(%hash)) { - print $client "ok\n"; - } else { - print $client "error: ".($!+0) - ." untie(GDBM) failed ". - "while attempting put\n"; - } - } else { - print $client "error: ".($!) - ." tie(GDBM) Failed ". - "while attempting put\n"; - } - } else { - print $client "refused\n"; - } - } else { - Reply($client, "refused\n", $userinput); - - } -# ------------------------------------------------------------------- inc - } elsif ($userinput =~ /^inc:/) { - if(isClient) { - my ($cmd,$udom,$uname,$namespace,$what) - =split(/:/,$userinput); - $namespace=~s/\//\_/g; - $namespace=~s/\W//g; - if ($namespace ne 'roles') { - chomp($what); - my $proname=propath($udom,$uname); - my $now=time; - my @pairs=split(/\&/,$what); - my %hash; - if (tie(%hash,'GDBM_File', - "$proname/$namespace.db", - &GDBM_WRCREAT(),0640)) { - unless ($namespace=~/^nohist\_/) { - my $hfh; - if ($hfh=IO::File->new(">>$proname/$namespace.hist")) { print $hfh "P:$now:$what\n"; } - } - foreach my $pair (@pairs) { - my ($key,$value)=split(/=/,$pair); - # We could check that we have a number... - if (! defined($value) || $value eq '') { - $value = 1; - } - $hash{$key}+=$value; - } - if (untie(%hash)) { - print $client "ok\n"; - } else { - print $client "error: ".($!+0) - ." untie(GDBM) failed ". - "while attempting inc\n"; - } - } else { - print $client "error: ".($!) - ." tie(GDBM) Failed ". - "while attempting inc\n"; - } - } else { - print $client "refused\n"; - } - } else { - Reply($client, "refused\n", $userinput); - - } -# -------------------------------------------------------------------- rolesput - } elsif ($userinput =~ /^rolesput/) { - if(isClient) { - &Debug("rolesput"); - if ($wasenc==1) { - my ($cmd,$exedom,$exeuser,$udom,$uname,$what) - =split(/:/,$userinput); - &Debug("cmd = ".$cmd." exedom= ".$exedom. - "user = ".$exeuser." udom=".$udom. - "what = ".$what); - my $namespace='roles'; - chomp($what); - my $proname=propath($udom,$uname); - my $now=time; - my @pairs=split(/\&/,$what); - my %hash; - if (tie(%hash,'GDBM_File',"$proname/$namespace.db",&GDBM_WRCREAT(),0640)) { - { - my $hfh; - if ($hfh=IO::File->new(">>$proname/$namespace.hist")) { - print $hfh "P:$now:$exedom:$exeuser:$what\n"; - } - } - - foreach my $pair (@pairs) { - my ($key,$value)=split(/=/,$pair); - &ManagePermissions($key, $udom, $uname, - &get_auth_type( $udom, - $uname)); - $hash{$key}=$value; - } - if (untie(%hash)) { - print $client "ok\n"; - } else { - print $client "error: ".($!+0) - ." untie(GDBM) Failed ". - "while attempting rolesput\n"; - } - } else { - print $client "error: ".($!+0) - ." tie(GDBM) Failed ". - "while attempting rolesput\n"; - } - } else { - print $client "refused\n"; - } - } else { - Reply($client, "refused\n", $userinput); - - } -# -------------------------------------------------------------------- rolesdel - } elsif ($userinput =~ /^rolesdel/) { - if(isClient) { - &Debug("rolesdel"); - if ($wasenc==1) { - my ($cmd,$exedom,$exeuser,$udom,$uname,$what) - =split(/:/,$userinput); - &Debug("cmd = ".$cmd." exedom= ".$exedom. - "user = ".$exeuser." udom=".$udom. - "what = ".$what); - my $namespace='roles'; - chomp($what); - my $proname=propath($udom,$uname); - my $now=time; - my @rolekeys=split(/\&/,$what); - my %hash; - if (tie(%hash,'GDBM_File',"$proname/$namespace.db",&GDBM_WRCREAT(),0640)) { - { - my $hfh; - if ($hfh=IO::File->new(">>$proname/$namespace.hist")) { - print $hfh "D:$now:$exedom:$exeuser:$what\n"; - } - } - foreach my $key (@rolekeys) { - delete $hash{$key}; - } - if (untie(%hash)) { - print $client "ok\n"; - } else { - print $client "error: ".($!+0) - ." untie(GDBM) Failed ". - "while attempting rolesdel\n"; - } - } else { - print $client "error: ".($!+0) - ." tie(GDBM) Failed ". - "while attempting rolesdel\n"; - } - } else { - print $client "refused\n"; - } - } else { - Reply($client, "refused\n", $userinput); - - } -# ------------------------------------------------------------------------- get - } elsif ($userinput =~ /^get/) { - if(isClient) { - my ($cmd,$udom,$uname,$namespace,$what) - =split(/:/,$userinput); - $namespace=~s/\//\_/g; - $namespace=~s/\W//g; - chomp($what); - my @queries=split(/\&/,$what); - my $proname=propath($udom,$uname); - my $qresult=''; - my %hash; - if (tie(%hash,'GDBM_File',"$proname/$namespace.db",&GDBM_READER(),0640)) { - for (my $i=0;$i<=$#queries;$i++) { - $qresult.="$hash{$queries[$i]}&"; - } - if (untie(%hash)) { - $qresult=~s/\&$//; - print $client "$qresult\n"; - } else { - print $client "error: ".($!+0) - ." untie(GDBM) Failed ". - "while attempting get\n"; - } - } else { - if ($!+0 == 2) { - print $client "error:No such file or ". - "GDBM reported bad block error\n"; - } else { - print $client "error: ".($!+0) - ." tie(GDBM) Failed ". - "while attempting get\n"; - } - } - } else { - Reply($client, "refused\n", $userinput); - - } -# ------------------------------------------------------------------------ eget - } elsif ($userinput =~ /^eget/) { - if (isClient) { - my ($cmd,$udom,$uname,$namespace,$what) - =split(/:/,$userinput); - $namespace=~s/\//\_/g; - $namespace=~s/\W//g; - chomp($what); - my @queries=split(/\&/,$what); - my $proname=propath($udom,$uname); - my $qresult=''; - my %hash; - if (tie(%hash,'GDBM_File',"$proname/$namespace.db",&GDBM_READER(),0640)) { - for (my $i=0;$i<=$#queries;$i++) { - $qresult.="$hash{$queries[$i]}&"; - } - if (untie(%hash)) { - $qresult=~s/\&$//; - if ($cipher) { - my $cmdlength=length($qresult); - $qresult.=" "; - my $encqresult=''; - for - (my $encidx=0;$encidx<=$cmdlength;$encidx+=8) { - $encqresult.= - unpack("H16", - $cipher->encrypt(substr($qresult,$encidx,8))); - } - print $client "enc:$cmdlength:$encqresult\n"; - } else { - print $client "error:no_key\n"; - } - } else { - print $client "error: ".($!+0) - ." untie(GDBM) Failed ". - "while attempting eget\n"; - } - } else { - print $client "error: ".($!+0) - ." tie(GDBM) Failed ". - "while attempting eget\n"; - } - } else { - Reply($client, "refused\n", $userinput); - - } -# ------------------------------------------------------------------------- del - } elsif ($userinput =~ /^del/) { - if(isClient) { - my ($cmd,$udom,$uname,$namespace,$what) - =split(/:/,$userinput); - $namespace=~s/\//\_/g; - $namespace=~s/\W//g; - chomp($what); - my $proname=propath($udom,$uname); - my $now=time; - my @keys=split(/\&/,$what); - my %hash; - if (tie(%hash,'GDBM_File',"$proname/$namespace.db",&GDBM_WRCREAT(),0640)) { - unless ($namespace=~/^nohist\_/) { - my $hfh; - if ($hfh=IO::File->new(">>$proname/$namespace.hist")) { print $hfh "D:$now:$what\n"; } - } - foreach my $key (@keys) { - delete($hash{$key}); - } - if (untie(%hash)) { - print $client "ok\n"; - } else { - print $client "error: ".($!+0) - ." untie(GDBM) Failed ". - "while attempting del\n"; - } - } else { - print $client "error: ".($!+0) - ." tie(GDBM) Failed ". - "while attempting del\n"; - } - } else { - Reply($client, "refused\n", $userinput); - - } -# ------------------------------------------------------------------------ keys - } elsif ($userinput =~ /^keys/) { - if(isClient) { - my ($cmd,$udom,$uname,$namespace) - =split(/:/,$userinput); - $namespace=~s/\//\_/g; - $namespace=~s/\W//g; - my $proname=propath($udom,$uname); - my $qresult=''; - my %hash; - if (tie(%hash,'GDBM_File',"$proname/$namespace.db",&GDBM_READER(),0640)) { - foreach my $key (keys %hash) { - $qresult.="$key&"; - } - if (untie(%hash)) { - $qresult=~s/\&$//; - print $client "$qresult\n"; - } else { - print $client "error: ".($!+0) - ." untie(GDBM) Failed ". - "while attempting keys\n"; - } - } else { - print $client "error: ".($!+0) - ." tie(GDBM) Failed ". - "while attempting keys\n"; - } - } else { - Reply($client, "refused\n", $userinput); - - } -# ----------------------------------------------------------------- dumpcurrent - } elsif ($userinput =~ /^currentdump/) { - if (isClient) { - my ($cmd,$udom,$uname,$namespace) - =split(/:/,$userinput); - $namespace=~s/\//\_/g; - $namespace=~s/\W//g; - my $qresult=''; - my $proname=propath($udom,$uname); - my %hash; - if (tie(%hash,'GDBM_File', - "$proname/$namespace.db", - &GDBM_READER(),0640)) { - # Structure of %data: - # $data{$symb}->{$parameter}=$value; - # $data{$symb}->{'v.'.$parameter}=$version; - # since $parameter will be unescaped, we do not - # have to worry about silly parameter names... - my %data = (); - while (my ($key,$value) = each(%hash)) { - my ($v,$symb,$param) = split(/:/,$key); - next if ($v eq 'version' || $symb eq 'keys'); - next if (exists($data{$symb}) && - exists($data{$symb}->{$param}) && - $data{$symb}->{'v.'.$param} > $v); - $data{$symb}->{$param}=$value; - $data{$symb}->{'v.'.$param}=$v; - } - if (untie(%hash)) { - while (my ($symb,$param_hash) = each(%data)) { - while(my ($param,$value) = each (%$param_hash)){ - next if ($param =~ /^v\./); - $qresult.=$symb.':'.$param.'='.$value.'&'; - } - } - chop($qresult); - print $client "$qresult\n"; - } else { - print $client "error: ".($!+0) - ." untie(GDBM) Failed ". - "while attempting currentdump\n"; - } - } else { - print $client "error: ".($!+0) - ." tie(GDBM) Failed ". - "while attempting currentdump\n"; - } - } else { - Reply($client, "refused\n", $userinput); - } -# ------------------------------------------------------------------------ dump - } elsif ($userinput =~ /^dump/) { - if(isClient) { - my ($cmd,$udom,$uname,$namespace,$regexp) - =split(/:/,$userinput); - $namespace=~s/\//\_/g; - $namespace=~s/\W//g; - if (defined($regexp)) { - $regexp=&unescape($regexp); - } else { - $regexp='.'; - } - my $qresult=''; - my $proname=propath($udom,$uname); - my %hash; - if (tie(%hash,'GDBM_File',"$proname/$namespace.db",&GDBM_READER(),0640)) { - while (my ($key,$value) = each(%hash)) { - if ($regexp eq '.') { - $qresult.=$key.'='.$value.'&'; - } else { - my $unescapeKey = &unescape($key); - if (eval('$unescapeKey=~/$regexp/')) { - $qresult.="$key=$value&"; - } - } - } - if (untie(%hash)) { - chop($qresult); - print $client "$qresult\n"; - } else { - print $client "error: ".($!+0) - ." untie(GDBM) Failed ". - "while attempting dump\n"; - } - } else { - print $client "error: ".($!+0) - ." tie(GDBM) Failed ". - "while attempting dump\n"; - } - } else { - Reply($client, "refused\n", $userinput); - - } -# ----------------------------------------------------------------------- store - } elsif ($userinput =~ /^store/) { - if(isClient) { - my ($cmd,$udom,$uname,$namespace,$rid,$what) - =split(/:/,$userinput); - $namespace=~s/\//\_/g; - $namespace=~s/\W//g; - if ($namespace ne 'roles') { - chomp($what); - my $proname=propath($udom,$uname); - my $now=time; - my @pairs=split(/\&/,$what); - my %hash; - if (tie(%hash,'GDBM_File',"$proname/$namespace.db",&GDBM_WRCREAT(),0640)) { - unless ($namespace=~/^nohist\_/) { - my $hfh; - if ($hfh=IO::File->new(">>$proname/$namespace.hist")) { - print $hfh "P:$now:$rid:$what\n"; - } - } - my @previouskeys=split(/&/,$hash{"keys:$rid"}); - my $key; - $hash{"version:$rid"}++; - my $version=$hash{"version:$rid"}; - my $allkeys=''; - foreach my $pair (@pairs) { - my ($key,$value)=split(/=/,$pair); - $allkeys.=$key.':'; - $hash{"$version:$rid:$key"}=$value; - } - $hash{"$version:$rid:timestamp"}=$now; - $allkeys.='timestamp'; - $hash{"$version:keys:$rid"}=$allkeys; - if (untie(%hash)) { - print $client "ok\n"; - } else { - print $client "error: ".($!+0) - ." untie(GDBM) Failed ". - "while attempting store\n"; - } - } else { - print $client "error: ".($!+0) - ." tie(GDBM) Failed ". - "while attempting store\n"; - } - } else { - print $client "refused\n"; - } - } else { - Reply($client, "refused\n", $userinput); - - } -# --------------------------------------------------------------------- restore - } elsif ($userinput =~ /^restore/) { - if(isClient) { - my ($cmd,$udom,$uname,$namespace,$rid) - =split(/:/,$userinput); - $namespace=~s/\//\_/g; - $namespace=~s/\W//g; - chomp($rid); - my $proname=propath($udom,$uname); - my $qresult=''; - my %hash; - if (tie(%hash,'GDBM_File',"$proname/$namespace.db",&GDBM_READER(),0640)) { - my $version=$hash{"version:$rid"}; - $qresult.="version=$version&"; - my $scope; - for ($scope=1;$scope<=$version;$scope++) { - my $vkeys=$hash{"$scope:keys:$rid"}; - my @keys=split(/:/,$vkeys); - my $key; - $qresult.="$scope:keys=$vkeys&"; - foreach $key (@keys) { - $qresult.="$scope:$key=".$hash{"$scope:$rid:$key"}."&"; - } - } - if (untie(%hash)) { - $qresult=~s/\&$//; - print $client "$qresult\n"; - } else { - print $client "error: ".($!+0) - ." untie(GDBM) Failed ". - "while attempting restore\n"; - } - } else { - print $client "error: ".($!+0) - ." tie(GDBM) Failed ". - "while attempting restore\n"; - } - } else { - Reply($client, "refused\n", $userinput); - - } -# -------------------------------------------------------------------- chatsend - } elsif ($userinput =~ /^chatsend/) { - if(isClient) { - my ($cmd,$cdom,$cnum,$newpost)=split(/\:/,$userinput); - &chatadd($cdom,$cnum,$newpost); - print $client "ok\n"; - } else { - Reply($client, "refused\n", $userinput); - - } -# -------------------------------------------------------------------- chatretr - } elsif ($userinput =~ /^chatretr/) { - if(isClient) { - my - ($cmd,$cdom,$cnum,$udom,$uname)=split(/\:/,$userinput); - my $reply=''; - foreach (&getchat($cdom,$cnum,$udom,$uname)) { - $reply.=&escape($_).':'; - } - $reply=~s/\:$//; - print $client $reply."\n"; - } else { - Reply($client, "refused\n", $userinput); - - } -# ------------------------------------------------------------------- querysend - } elsif ($userinput =~ /^querysend/) { - if (isClient) { - my ($cmd,$query, - $arg1,$arg2,$arg3)=split(/\:/,$userinput); - $query=~s/\n*$//g; - print $client "". - sqlreply("$clientname\&$query". - "\&$arg1"."\&$arg2"."\&$arg3")."\n"; - } else { - Reply($client, "refused\n", $userinput); - - } -# ------------------------------------------------------------------ queryreply - } elsif ($userinput =~ /^queryreply/) { - if(isClient) { - my ($cmd,$id,$reply)=split(/:/,$userinput); - my $store; - my $execdir=$perlvar{'lonDaemons'}; - if ($store=IO::File->new(">$execdir/tmp/$id")) { - $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 { - print $client "error: ".($!+0) - ." IO::File->new Failed ". - "while attempting queryreply\n"; - } - } else { - Reply($client, "refused\n", $userinput); - - } -# ----------------------------------------------------------------- courseidput - } elsif ($userinput =~ /^courseidput/) { - if(isClient) { - my ($cmd,$udom,$what)=split(/:/,$userinput); - chomp($what); - $udom=~s/\W//g; - my $proname= - "$perlvar{'lonUsersDir'}/$udom/nohist_courseids"; - my $now=time; - my @pairs=split(/\&/,$what); - my %hash; - if (tie(%hash,'GDBM_File',"$proname.db",&GDBM_WRCREAT(),0640)) { - foreach my $pair (@pairs) { - my ($key,$descr,$inst_code)=split(/=/,$pair); - $hash{$key}=$descr.':'.$inst_code.':'.$now; - } - if (untie(%hash)) { - print $client "ok\n"; - } else { - print $client "error: ".($!+0) - ." untie(GDBM) Failed ". - "while attempting courseidput\n"; - } - } else { - print $client "error: ".($!+0) - ." tie(GDBM) Failed ". - "while attempting courseidput\n"; - } - } else { - Reply($client, "refused\n", $userinput); - - } -# ---------------------------------------------------------------- courseiddump - } elsif ($userinput =~ /^courseiddump/) { - if(isClient) { - my ($cmd,$udom,$since,$description) - =split(/:/,$userinput); - if (defined($description)) { - $description=&unescape($description); - } else { - $description='.'; - } - unless (defined($since)) { $since=0; } - my $qresult=''; - my $proname= - "$perlvar{'lonUsersDir'}/$udom/nohist_courseids"; - my %hash; - if (tie(%hash,'GDBM_File',"$proname.db",&GDBM_READER(),0640)) { - while (my ($key,$value) = each(%hash)) { - my ($descr,$lasttime,$inst_code); - if ($value =~ m/^([^\:]*):([^\:]*):(\d+)$/) { - ($descr,$inst_code,$lasttime)=($1,$2,$3); - } else { - ($descr,$lasttime) = split(/\:/,$value); - } - if ($lasttime<$since) { next; } - if ($description eq '.') { - $qresult.=$key.'='.$descr.':'.$inst_code.'&'; - } else { - my $unescapeVal = &unescape($descr); - if (eval('$unescapeVal=~/\Q$description\E/i')) { - $qresult.=$key.'='.$descr.':'.$inst_code.'&'; - } - } - } - if (untie(%hash)) { - chop($qresult); - print $client "$qresult\n"; - } else { - print $client "error: ".($!+0) - ." untie(GDBM) Failed ". - "while attempting courseiddump\n"; - } - } else { - print $client "error: ".($!+0) - ." tie(GDBM) Failed ". - "while attempting courseiddump\n"; - } - } else { - Reply($client, "refused\n", $userinput); - - } # ----------------------------------------------------------------------- idput - } elsif ($userinput =~ /^idput/) { + if ($userinput =~ /^idput/) { if(isClient) { my ($cmd,$udom,$what)=split(/:/,$userinput); chomp($what); @@ -2811,21 +3316,21 @@ sub process_request { return 0; # ---------------------------------- set current host/domain - } elsif ($userinput =~ /^sethost:/) { + } elsif ($userinput =~ /^sethost/) { if (isClient) { print $client &sethost($userinput)."\n"; } else { print $client "refused\n"; } #---------------------------------- request file (?) version. - } elsif ($userinput =~/^version:/) { + } elsif ($userinput =~/^version/) { if (isClient) { print $client &version($userinput)."\n"; } else { print $client "refused\n"; } #------------------------------- is auto-enrollment enabled? - } elsif ($userinput =~/^autorun:/) { + } elsif ($userinput =~/^autorun/) { if (isClient) { my ($cmd,$cdom) = split(/:/,$userinput); my $outcome = &localenroll::run($cdom); @@ -2834,7 +3339,7 @@ sub process_request { print $client "0\n"; } #------------------------------- get official sections (for auto-enrollment). - } elsif ($userinput =~/^autogetsections:/) { + } elsif ($userinput =~/^autogetsections/) { if (isClient) { my ($cmd,$coursecode,$cdom)=split(/:/,$userinput); my @secs = &localenroll::get_sections($coursecode,$cdom); @@ -2844,7 +3349,7 @@ sub process_request { print $client "refused\n"; } #----------------------- validate owner of new course section (for auto-enrollment). - } elsif ($userinput =~/^autonewcourse:/) { + } elsif ($userinput =~/^autonewcourse/) { if (isClient) { my ($cmd,$inst_course_id,$owner,$cdom)=split(/:/,$userinput); my $outcome = &localenroll::new_course($inst_course_id,$owner,$cdom); @@ -2853,7 +3358,7 @@ sub process_request { print $client "refused\n"; } #-------------- validate course section in schedule of classes (for auto-enrollment). - } elsif ($userinput =~/^autovalidatecourse:/) { + } elsif ($userinput =~/^autovalidatecourse/) { if (isClient) { my ($cmd,$inst_course_id,$cdom)=split(/:/,$userinput); my $outcome=&localenroll::validate_courseID($inst_course_id,$cdom); @@ -2862,7 +3367,7 @@ sub process_request { print $client "refused\n"; } #--------------------------- create password for new user (for auto-enrollment). - } elsif ($userinput =~/^autocreatepassword:/) { + } elsif ($userinput =~/^autocreatepassword/) { if (isClient) { my ($cmd,$authparam,$cdom)=split(/:/,$userinput); my ($create_passwd,$authchk); @@ -2872,7 +3377,7 @@ sub process_request { print $client "refused\n"; } #--------------------------- read and remove temporary files (for auto-enrollment). - } elsif ($userinput =~/^autoretrieve:/) { + } elsif ($userinput =~/^autoretrieve/) { if (isClient) { my ($cmd,$filename) = split(/:/,$userinput); my $source = $perlvar{'lonDaemons'}.'/tmp/'.$filename; @@ -2898,7 +3403,7 @@ sub process_request { print $client "refused\n"; } #--------------------- read and retrieve institutional code format (for support form). - } elsif ($userinput =~/^autoinstcodeformat:/) { + } elsif ($userinput =~/^autoinstcodeformat/) { if (isClient) { my $reply; my($cmd,$cdom,$course) = split(/:/,$userinput); @@ -3010,7 +3515,6 @@ sub register_handler { $Dispatcher{$request_name} = \@entry; - } @@ -3057,7 +3561,6 @@ sub catchexception { $server->close(); die($error); } - sub timeout { &status("Handling Timeout"); &logthis("CRITICAL: TIME OUT ".$$.""); @@ -3065,6 +3568,7 @@ sub timeout { } # -------------------------------- Set signal handlers to record abnormal exits + $SIG{'QUIT'}=\&catchexception; $SIG{__DIE__}=\&catchexception; @@ -3481,14 +3985,14 @@ sub reply { # -------------------------------------------------------------- Talk to lonsql -sub sqlreply { +sub sql_reply { my ($cmd)=@_; - my $answer=subsqlreply($cmd); - if ($answer eq 'con_lost') { $answer=subsqlreply($cmd); } + my $answer=&sub_sql_reply($cmd); + if ($answer eq 'con_lost') { $answer=&sub_sql_reply($cmd); } return $answer; } -sub subsqlreply { +sub sub_sql_reply { my ($cmd)=@_; my $unixsock="mysqlsock"; my $peerfile="$perlvar{'lonSockDir'}/$unixsock"; @@ -3694,8 +4198,7 @@ sub make_new_child { $inittype = ""; # This forces insecure attempt. &logthis(" Certificates not " ."installed -- trying insecure auth"); - } - else { # SSL certificates are in place so + } else { # SSL certificates are in place so } # Leave the inittype alone. } @@ -3818,7 +4321,7 @@ sub make_new_child { # user - Name of the user for which the role is being put. # authtype - The authentication type associated with the user. # -sub ManagePermissions +sub manage_permissions { my ($request, $domain, $user, $authtype) = @_; @@ -3929,8 +4432,7 @@ sub get_auth_type } return "$authtype:$availinfo"; - } - else { + } else { Debug("Returning nouser"); return "nouser"; } @@ -4010,18 +4512,15 @@ sub validate_user { $password); if(!$k4error) { $validated = 1; - } - else { + } else { $validated = 0; &logthis('krb4: '.$user.', '.$contentpwd.', '. &Authen::Krb4::get_err_txt($Authen::Krb4::error)); } - } - else { + } else { $validated = 0; # Password has a match with null. } - } - elsif ($howpwd eq "krb5") { # User is in kerberos 5 auth. domain. + } elsif ($howpwd eq "krb5") { # User is in kerberos 5 auth. domain. if(!($password =~ /$null/)) { # Null password not allowed. my $krbclient = &Authen::Krb5::parse_name($user.'@' .$contentpwd); @@ -4034,18 +4533,15 @@ sub validate_user { $password, $credentials); $validated = ($krbreturn == 1); - } - else { + } else { $validated = 0; } - } - elsif ($howpwd eq "localauth") { + } elsif ($howpwd eq "localauth") { # Authenticate via installation specific authentcation method: $validated = &localauth::localauth($user, $password, $contentpwd); - } - else { # Unrecognized auth is also bad. + } else { # Unrecognized auth is also bad. $validated = 0; } } else { @@ -4082,7 +4578,7 @@ sub addline { return $found; } -sub getchat { +sub get_chat { my ($cdom,$cname,$udom,$uname)=@_; my %hash; my $proname=&propath($cdom,$cname); @@ -4107,7 +4603,7 @@ sub getchat { return (@participants,@entries); } -sub chatadd { +sub chat_add { my ($cdom,$cname,$newchat)=@_; my %hash; my $proname=&propath($cdom,$cname); @@ -4308,7 +4804,8 @@ sub make_passwd_file { } my $execpath ="$perlvar{'lonDaemons'}/"."lcuseradd"; - my $lc_error_file = "/tmp/lcuseradd".$$.".status"; + + my $lc_error_file = $execdir."/tmp/lcuseradd".$$.".status"; { &Debug("Executing external: ".$execpath); &Debug("user = ".$uname.", Password =". $npass); @@ -4329,8 +4826,7 @@ sub make_passwd_file { my $error_text = &lcuseraddstrerror($useraddok); &logthis("Failed lcuseradd: $error_text"); $result = "lcuseradd_failed:$error_text\n"; - } - else { + } else { my $pf = IO::File->new(">$passfilename"); print $pf "unix:\n"; } @@ -4666,7 +5162,7 @@ Place in B stores hash in namespace -=item rolesput +=item rolesputy put a role into a user's environment