--- loncom/lond 2004/08/02 20:59:46 1.221
+++ loncom/lond 2004/08/16 10:54:19 1.229
@@ -2,7 +2,7 @@
# The LearningOnline Network
# lond "LON Daemon" Server (port "LOND" 5663)
#
-# $Id: lond,v 1.221 2004/08/02 20:59:46 albertel Exp $
+# $Id: lond,v 1.229 2004/08/16 10:54:19 foxr Exp $
#
# Copyright Michigan State University Board of Trustees
#
@@ -57,7 +57,7 @@ my $DEBUG = 0; # Non zero to ena
my $status='';
my $lastlog='';
-my $VERSION='$Revision: 1.221 $'; #' stupid emacs
+my $VERSION='$Revision: 1.229 $'; #' stupid emacs
my $remoteVERSION;
my $currenthostid="default";
my $currentdomainid;
@@ -122,8 +122,10 @@ my @passwderrors = ("ok",
"lcpasswd Cannot set new passwd.",
"lcpasswd Username has invalid characters",
"lcpasswd Invalid characters in password",
- "11", "12",
- "lcpasswd Password mismatch");
+ "lcpasswd User already exists",
+ "lcpasswd Something went wrong with user addition.",
+ "lcpasswd Password mismatch",
+ "lcpasswd Error filename is invalid");
# The array below are lcuseradd error strings.:
@@ -160,8 +162,6 @@ sub ResetStatistics {
$Failures = 0;
}
-
-
#------------------------------------------------------------------------
#
# LocalConnection
@@ -192,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 ");
@@ -324,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;
@@ -372,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..
@@ -654,8 +651,7 @@ sub PushFile {
&logthis(' Pushfile: unable to install '
.$tablefile." $! ");
return "error:$!";
- }
- else {
+ } else {
&logthis(' Installed new '.$tablefile
."");
@@ -1224,15 +1220,15 @@ sub user_authorization_type {
my $userinput = "$cmd:$tail";
# Pull the domain and username out of the command tail.
- # and call GetAuthType to determine the authentication type.
+ # and call get_auth_type to determine the authentication type.
my ($udom,$uname)=split(/:/,$tail);
- my $result = &GetAuthType($udom, $uname);
+ my $result = &get_auth_type($udom, $uname);
if($result eq "nouser") {
&Failure( $replyfd, "unknown_user\n", $userinput);
} else {
#
- # We only want to pass the second field from GetAuthType
+ # We only want to pass the second field from get_auth_type
# for ^krb.. otherwise we'll be handing out the encrypted
# password for internals e.g.
#
@@ -1240,7 +1236,7 @@ sub user_authorization_type {
if($type =~ /^krb/) {
$type = $result;
}
- &Reply( $replyfd, "$type\n", $userinput);
+ &Reply( $replyfd, "$type:\n", $userinput);
}
return 1;
@@ -1418,6 +1414,495 @@ sub authenticate_handler {
register_handler("auth", \&authenticate_handler, 1, 1, 0);
+#
+# Change a user's password. Note that this function is complicated by
+# the fact that a user may be authenticated in more than one way:
+# At present, we are not able to change the password for all types of
+# authentication methods. Only for:
+# unix - unix password or shadow passoword style authentication.
+# local - Locally written authentication mechanism.
+# For now, kerb4 and kerb5 password changes are not supported and result
+# in an error.
+# FUTURE WORK:
+# Support kerberos passwd changes?
+# 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_password_handler {
+ my ($cmd, $tail, $client) = @_;
+
+ my $userinput = $cmd.":".$tail; # Reconstruct client's string.
+
+ #
+ # udom - user's domain.
+ # uname - Username.
+ # upass - Current password.
+ # npass - New password.
+
+ my ($udom,$uname,$upass,$npass)=split(/:/,$tail);
+
+ $upass=&unescape($upass);
+ $npass=&unescape($npass);
+ &Debug("Trying to change password for $uname");
+
+ # First require that the user can be authenticated with their
+ # old password:
+
+ my $validated = &validate_user($udom, $uname, $upass);
+ if($validated) {
+ my $realpasswd = &get_auth_type($udom, $uname); # Defined since authd.
+
+ my ($howpwd,$contentpwd)=split(/:/,$realpasswd);
+ if ($howpwd eq 'internal') {
+ &Debug("internal auth");
+ my $salt=time;
+ $salt=substr($salt,6,2);
+ my $ncpass=crypt($npass,$salt);
+ if(&rewrite_password_file($udom, $uname, "internal:$ncpass")) {
+ &logthis("Result of password change for "
+ ."$uname: pwchange_success");
+ &Reply($client, "ok\n", $userinput);
+ } else {
+ &logthis("Unable to open $uname passwd "
+ ."to change password");
+ &Failure( $client, "non_authorized\n",$userinput);
+ }
+ } elsif ($howpwd eq 'unix') {
+ # Unix means we have to access /etc/password
+ &Debug("auth is unix");
+ my $execdir=$perlvar{'lonDaemons'};
+ &Debug("Opening lcpasswd pipeline");
+ my $pf = IO::File->new("|$execdir/lcpasswd > "
+ ."$perlvar{'lonDaemons'}"
+ ."/logs/lcpasswd.log");
+ print $pf "$uname\n$npass\n$npass\n";
+ close $pf;
+ my $err = $?;
+ my $result = ($err>0 ? 'pwchange_failure' : 'ok');
+ &logthis("Result of password change for $uname: ".
+ &lcpasswdstrerror($?));
+ &Reply($client, "$result\n", $userinput);
+ } else {
+ # this just means that the current password mode is not
+ # one we know how to change (e.g the kerberos auth modes or
+ # locally written auth handler).
+ #
+ &Failure( $client, "auth_mode_error\n", $userinput);
+ }
+
+ } else {
+ &Failure( $client, "non_authorized\n", $userinput);
+ }
+
+ return 1;
+}
+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)=split(/\//,$fname);
+ my $udir=&propath($udom,$uname).'/userfiles';
+ unless (-e $udir) {
+ mkdir($udir,0770);
+ }
+ if (-e $udir) {
+ $ufile=~s/^[\.\~]+//;
+ $ufile=~s/\///g;
+ my $destname=$udir.'/'.$ufile;
+ my $transname=$udir.'/'.$ufile.'.in.transit';
+ my $remoteurl='http://'.$clientip.'/userfiles/'.$fname;
+ 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)");
+ &Failure($client, "failed\n", $userinput);
+ } else {
+ 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);
+
#---------------------------------------------------------------
#
# Getting, decoding and dispatching requests:
@@ -1428,7 +1913,7 @@ register_handler("auth", \&authenticate_
# 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);
@@ -1532,344 +2017,10 @@ sub process_request {
#------------------- Commands not yet in spearate handlers. --------------
-# ---------------------------------------------------------------------- passwd
- if ($userinput =~ /^passwd/) { # encoded and client
- if (($wasenc==1) && isClient) {
- my
- ($cmd,$udom,$uname,$upass,$npass)=split(/:/,$userinput);
- chomp($npass);
- $upass=&unescape($upass);
- $npass=&unescape($npass);
- &Debug("Trying to change password for $uname");
- my $proname=propath($udom,$uname);
- my $passfilename="$proname/passwd";
- if (-e $passfilename) {
- my $realpasswd;
- { my $pf = IO::File->new($passfilename);
- $realpasswd=<$pf>; }
- chomp($realpasswd);
- my ($howpwd,$contentpwd)=split(/:/,$realpasswd);
- if ($howpwd eq 'internal') {
- &Debug("internal auth");
- if (crypt($upass,$contentpwd) eq $contentpwd) {
- my $salt=time;
- $salt=substr($salt,6,2);
- my $ncpass=crypt($npass,$salt);
- {
- my $pf;
- if ($pf = IO::File->new(">$passfilename")) {
- print $pf "internal:$ncpass\n";
- &logthis("Result of password change for $uname: pwchange_success");
- print $client "ok\n";
- } else {
- &logthis("Unable to open $uname passwd to change password");
- print $client "non_authorized\n";
- }
- }
-
- } else {
- print $client "non_authorized\n";
- }
- } elsif ($howpwd eq 'unix') {
- # Unix means we have to access /etc/password
- # one way or another.
- # First: Make sure the current password is
- # correct
- &Debug("auth is unix");
- $contentpwd=(getpwnam($uname))[1];
- my $pwdcorrect = "0";
- my $pwauth_path="/usr/local/sbin/pwauth";
- unless ($contentpwd eq 'x') {
- $pwdcorrect=
- (crypt($upass,$contentpwd) eq $contentpwd);
- } elsif (-e $pwauth_path) {
- open PWAUTH, "|$pwauth_path" or
- die "Cannot invoke authentication";
- print PWAUTH "$uname\n$upass\n";
- close PWAUTH;
- &Debug("exited pwauth with $? ($uname,$upass) ");
- $pwdcorrect=($? == 0);
- }
- if ($pwdcorrect) {
- my $execdir=$perlvar{'lonDaemons'};
- &Debug("Opening lcpasswd pipeline");
- my $pf = IO::File->new("|$execdir/lcpasswd > $perlvar{'lonDaemons'}/logs/lcpasswd.log");
- print $pf "$uname\n$npass\n$npass\n";
- close $pf;
- my $err = $?;
- my $result = ($err>0 ? 'pwchange_failure'
- : 'ok');
- &logthis("Result of password change for $uname: ".
- &lcpasswdstrerror($?));
- print $client "$result\n";
- } else {
- print $client "non_authorized\n";
- }
- } else {
- print $client "auth_mode_error\n";
- }
- } else {
- print $client "unknown_user\n";
- }
- } else {
- Reply($client, "refused\n", $userinput);
-
- }
-# -------------------------------------------------------------------- makeuser
- } elsif ($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);
- print $client $result;
- }
- } 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 ($userinput =~ /^sub/) {
if(isClient) {
print $client &subscribe($userinput,$clientip);
} else {
@@ -2025,7 +2176,7 @@ sub process_request {
foreach my $pair (@pairs) {
my ($key,$value)=split(/=/,$pair);
&ManagePermissions($key, $udom, $uname,
- &GetAuthType( $udom,
+ &get_auth_type( $udom,
$uname));
$hash{$key}=$value;
}
@@ -2482,8 +2633,7 @@ sub process_request {
print $store2 "done\n";
close $store2;
print $client "ok\n";
- }
- else {
+ } else {
print $client "error: ".($!+0)
." IO::File->new Failed ".
"while attempting queryreply\n";
@@ -2997,7 +3147,6 @@ sub register_handler {
$Dispatcher{$request_name} = \@entry;
-
}
@@ -3044,7 +3193,6 @@ sub catchexception {
$server->close();
die($error);
}
-
sub timeout {
&status("Handling Timeout");
&logthis("CRITICAL: TIME OUT ".$$."");
@@ -3052,6 +3200,7 @@ sub timeout {
}
# -------------------------------- Set signal handlers to record abnormal exits
+
$SIG{'QUIT'}=\&catchexception;
$SIG{__DIE__}=\&catchexception;
@@ -3681,8 +3830,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,17 +3966,89 @@ sub ManagePermissions
system("$execdir/lchtmldir $userhome $user $authtype");
}
}
+
+
+#
+# Return the full path of a user password file, whether it exists or not.
+# Parameters:
+# domain - Domain in which the password file lives.
+# user - name of the user.
+# Returns:
+# Full passwd path:
+#
+sub password_path {
+ my ($domain, $user) = @_;
+
+
+ my $path = &propath($domain, $user);
+ $path .= "/passwd";
+
+ return $path;
+}
+
+# Password Filename
+# Returns the path to a passwd file given domain and user... only if
+# it exists.
+# Parameters:
+# domain - Domain in which to search.
+# user - username.
+# Returns:
+# - If the password file exists returns its path.
+# - If the password file does not exist, returns undefined.
+#
+sub password_filename {
+ my ($domain, $user) = @_;
+
+ Debug ("PasswordFilename called: dom = $domain user = $user");
+
+ my $path = &password_path($domain, $user);
+ Debug("PasswordFilename got path: $path");
+ if(-e $path) {
+ return $path;
+ } else {
+ return undef;
+ }
+}
+
+#
+# Rewrite the contents of the user's passwd file.
+# Parameters:
+# domain - domain of the user.
+# name - User's name.
+# contents - New contents of the file.
+# Returns:
+# 0 - Failed.
+# 1 - Success.
+#
+sub rewrite_password_file {
+ my ($domain, $user, $contents) = @_;
+
+ my $file = &password_filename($domain, $user);
+ if (defined $file) {
+ my $pf = IO::File->new(">$file");
+ if($pf) {
+ print $pf "$contents\n";
+ return 1;
+ } else {
+ return 0;
+ }
+ } else {
+ return 0;
+ }
+
+}
+
#
-# GetAuthType - Determines the authorization type of a user in a domain.
+# get_auth_type - Determines the authorization type of a user in a domain.
# Returns the authorization type or nouser if there is no such user.
#
-sub GetAuthType
+sub get_auth_type
{
my ($domain, $user) = @_;
- Debug("GetAuthType( $domain, $user ) \n");
+ Debug("get_auth_type( $domain, $user ) \n");
my $proname = &propath($domain, $user);
my $passwdfile = "$proname/passwd";
if( -e $passwdfile ) {
@@ -3844,8 +4064,7 @@ sub GetAuthType
}
return "$authtype:$availinfo";
- }
- else {
+ } else {
Debug("Returning nouser");
return "nouser";
}
@@ -3885,7 +4104,7 @@ sub validate_user {
# the user has been assigned. If the authentication type is
# "nouser", the user does not exist so we will return 0.
- my $contents = &GetAuthType($domain, $user);
+ my $contents = &get_auth_type($domain, $user);
my ($howpwd, $contentpwd) = split(/:/, $contents);
my $null = pack("C",0); # Used by kerberos auth types.
@@ -3925,18 +4144,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);
@@ -3949,18 +4165,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 {
@@ -4222,7 +4435,9 @@ sub make_passwd_file {
return "no_priv_account_error\n";
}
- my $execpath="$perlvar{'lonDaemons'}/"."lcuseradd";
+ my $execpath ="$perlvar{'lonDaemons'}/"."lcuseradd";
+
+ my $lc_error_file = $execdir."/tmp/lcuseradd".$$.".status";
{
&Debug("Executing external: ".$execpath);
&Debug("user = ".$uname.", Password =". $npass);
@@ -4230,17 +4445,27 @@ sub make_passwd_file {
print $se "$uname\n";
print $se "$npass\n";
print $se "$npass\n";
+ print $se "$lc_error_file\n"; # Status -> unique file.
}
- my $useraddok = $?;
+ my $error = IO::File->new("< $lc_error_file");
+ my $useraddok = <$error>;
+ $error->close;
+ unlink($lc_error_file);
+
+ chomp $useraddok;
+
if($useraddok > 0) {
- &logthis("Failed lcuseradd: ".&lcuseraddstrerror($useraddok));
+ my $error_text = &lcuseraddstrerror($useraddok);
+ &logthis("Failed lcuseradd: $error_text");
+ $result = "lcuseradd_failed:$error_text\n";
+ } else {
+ my $pf = IO::File->new(">$passfilename");
+ print $pf "unix:\n";
}
- my $pf = IO::File->new(">$passfilename");
- print $pf "unix:\n";
}
} elsif ($umode eq 'none') {
{
- my $pf = IO::File->new(">$passfilename");
+ my $pf = IO::File->new("> $passfilename");
print $pf "none:\n";
}
} else {