version 1.220, 2004/08/02 11:02:02
|
version 1.223, 2004/08/05 11:37:05
|
Line 50 use File::Copy;
|
Line 50 use File::Copy;
|
use LONCAPA::ConfigFileEdit; |
use LONCAPA::ConfigFileEdit; |
use LONCAPA::lonlocal; |
use LONCAPA::lonlocal; |
use LONCAPA::lonssl; |
use LONCAPA::lonssl; |
|
use Fcntl qw(:flock); |
|
|
my $DEBUG = 0; # Non zero to enable debug log entries. |
my $DEBUG = 1; # Non zero to enable debug log entries. |
|
|
my $status=''; |
my $status=''; |
my $lastlog=''; |
my $lastlog=''; |
Line 121 my @passwderrors = ("ok",
|
Line 122 my @passwderrors = ("ok",
|
"lcpasswd Cannot set new passwd.", |
"lcpasswd Cannot set new passwd.", |
"lcpasswd Username has invalid characters", |
"lcpasswd Username has invalid characters", |
"lcpasswd Invalid characters in password", |
"lcpasswd Invalid characters in password", |
"11", "12", |
"lcpasswd User already exists", |
"lcpasswd Password mismatch"); |
"lcpasswd Something went wrong with user addition.", |
|
"lcpasswd Password mismatch", |
|
"lcpasswd Error filename is invalid"); |
|
|
|
|
# The array below are lcuseradd error strings.: |
# The array below are lcuseradd error strings.: |
Line 1223 sub user_authorization_type {
|
Line 1226 sub user_authorization_type {
|
my $userinput = "$cmd:$tail"; |
my $userinput = "$cmd:$tail"; |
|
|
# Pull the domain and username out of the command 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 ($udom,$uname)=split(/:/,$tail); |
my $result = &GetAuthType($udom, $uname); |
my $result = &get_auth_type($udom, $uname); |
if($result eq "nouser") { |
if($result eq "nouser") { |
&Failure( $replyfd, "unknown_user\n", $userinput); |
&Failure( $replyfd, "unknown_user\n", $userinput); |
} else { |
} 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 |
# for ^krb.. otherwise we'll be handing out the encrypted |
# password for internals e.g. |
# password for internals e.g. |
# |
# |
Line 1239 sub user_authorization_type {
|
Line 1242 sub user_authorization_type {
|
if($type =~ /^krb/) { |
if($type =~ /^krb/) { |
$type = $result; |
$type = $result; |
} |
} |
&Reply( $replyfd, "$type\n", $userinput); |
&Reply( $replyfd, "$type:\n", $userinput); |
} |
} |
|
|
return 1; |
return 1; |
Line 1417 sub authenticate_handler {
|
Line 1420 sub authenticate_handler {
|
|
|
register_handler("auth", \&authenticate_handler, 1, 1, 0); |
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); |
|
|
|
|
#--------------------------------------------------------------- |
#--------------------------------------------------------------- |
# |
# |
# Getting, decoding and dispatching requests: |
# Getting, decoding and dispatching requests: |
Line 1531 sub process_request {
|
Line 1627 sub process_request {
|
#------------------- Commands not yet in spearate handlers. -------------- |
#------------------- 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 |
# -------------------------------------------------------------------- makeuser |
} elsif ($userinput =~ /^makeuser/) { # encoded and client. |
if ($userinput =~ /^makeuser/) { # encoded and client. |
&Debug("Make user received"); |
&Debug("Make user received"); |
my $oldumask=umask(0077); |
my $oldumask=umask(0077); |
if (($wasenc==1) && isClient) { |
if (($wasenc==1) && isClient) { |
Line 1677 sub process_request {
|
Line 1691 sub process_request {
|
} else { |
} else { |
my $result=&make_passwd_file($uname, $umode,$npass, |
my $result=&make_passwd_file($uname, $umode,$npass, |
$passfilename); |
$passfilename); |
print $client $result; |
Reply($client, $result, $userinput); |
} |
} |
} else { |
} else { |
Reply($client, "refused\n", $userinput); |
Reply($client, "refused\n", $userinput); |
Line 2024 sub process_request {
|
Line 2038 sub process_request {
|
foreach my $pair (@pairs) { |
foreach my $pair (@pairs) { |
my ($key,$value)=split(/=/,$pair); |
my ($key,$value)=split(/=/,$pair); |
&ManagePermissions($key, $udom, $uname, |
&ManagePermissions($key, $udom, $uname, |
&GetAuthType( $udom, |
&get_auth_type( $udom, |
$uname)); |
$uname)); |
$hash{$key}=$value; |
$hash{$key}=$value; |
} |
} |
Line 3251 sub checkchildren {
|
Line 3265 sub checkchildren {
|
&logthis('Going to check on the children'); |
&logthis('Going to check on the children'); |
my $docdir=$perlvar{'lonDocRoot'}; |
my $docdir=$perlvar{'lonDocRoot'}; |
foreach (sort keys %children) { |
foreach (sort keys %children) { |
sleep 1; |
#sleep 1; |
unless (kill 'USR1' => $_) { |
unless (kill 'USR1' => $_) { |
&logthis ('Child '.$_.' is dead'); |
&logthis ('Child '.$_.' is dead'); |
&logstatus($$.' is dead'); |
&logstatus($$.' is dead'); |
|
delete($children{$_}); |
} |
} |
} |
} |
sleep 5; |
sleep 5; |
Line 3273 sub checkchildren {
|
Line 3288 sub checkchildren {
|
#my $result=`echo 'Killed lond process $_.' | mailto $emailto -s '$subj' > /dev/null`; |
#my $result=`echo 'Killed lond process $_.' | mailto $emailto -s '$subj' > /dev/null`; |
#$execdir=$perlvar{'lonDaemons'}; |
#$execdir=$perlvar{'lonDaemons'}; |
#$result=`/bin/cp $execdir/logs/lond.log $execdir/logs/lond.log.$_`; |
#$result=`/bin/cp $execdir/logs/lond.log $execdir/logs/lond.log.$_`; |
|
delete($children{$_}); |
alarm(0); |
alarm(0); |
} |
} |
} |
} |
Line 3280 sub checkchildren {
|
Line 3296 sub checkchildren {
|
$SIG{ALRM} = 'DEFAULT'; |
$SIG{ALRM} = 'DEFAULT'; |
$SIG{__DIE__} = \&catchexception; |
$SIG{__DIE__} = \&catchexception; |
&status("Finished checking children"); |
&status("Finished checking children"); |
|
&logthis('Finished Checking children'); |
} |
} |
|
|
# --------------------------------------------------------------------- Logging |
# --------------------------------------------------------------------- Logging |
Line 3350 sub logstatus {
|
Line 3367 sub logstatus {
|
&status("Doing logging"); |
&status("Doing logging"); |
my $docdir=$perlvar{'lonDocRoot'}; |
my $docdir=$perlvar{'lonDocRoot'}; |
{ |
{ |
my $fh=IO::File->new(">>$docdir/lon-status/londstatus.txt"); |
|
print $fh $$."\t".$clientname."\t".$currenthostid."\t" |
|
.$status."\t".$lastlog."\t $keymode\n"; |
|
$fh->close(); |
|
} |
|
&status("Finished londstatus.txt"); |
|
{ |
|
my $fh=IO::File->new(">$docdir/lon-status/londchld/$$.txt"); |
my $fh=IO::File->new(">$docdir/lon-status/londchld/$$.txt"); |
print $fh $status."\n".$lastlog."\n".time."\n$keymode"; |
print $fh $status."\n".$lastlog."\n".time."\n$keymode"; |
$fh->close(); |
$fh->close(); |
} |
} |
|
&status("Finished $$.txt"); |
|
{ |
|
open(LOG,">>$docdir/lon-status/londstatus.txt"); |
|
flock(LOG,LOCK_EX); |
|
print LOG $$."\t".$clientname."\t".$currenthostid."\t" |
|
.$status."\t".$lastlog."\t $keymode\n"; |
|
flock(DB,LOCK_UN); |
|
close(LOG); |
|
} |
&status("Finished logging"); |
&status("Finished logging"); |
} |
} |
|
|
Line 3812 sub ManagePermissions
|
Line 3831 sub ManagePermissions
|
system("$execdir/lchtmldir $userhome $user $authtype"); |
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. |
# |
# |
# GetAuthType - Determines the authorization type of a user in a domain. |
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; |
|
} |
|
|
|
} |
|
|
|
# |
|
# 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. |
# Returns the authorization type or nouser if there is no such user. |
# |
# |
sub GetAuthType |
sub get_auth_type |
{ |
{ |
|
|
my ($domain, $user) = @_; |
my ($domain, $user) = @_; |
|
|
Debug("GetAuthType( $domain, $user ) \n"); |
Debug("get_auth_type( $domain, $user ) \n"); |
my $proname = &propath($domain, $user); |
my $proname = &propath($domain, $user); |
my $passwdfile = "$proname/passwd"; |
my $passwdfile = "$proname/passwd"; |
if( -e $passwdfile ) { |
if( -e $passwdfile ) { |
Line 3879 sub validate_user {
|
Line 3970 sub validate_user {
|
# the user has been assigned. If the authentication type is |
# the user has been assigned. If the authentication type is |
# "nouser", the user does not exist so we will return 0. |
# "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 ($howpwd, $contentpwd) = split(/:/, $contents); |
|
|
my $null = pack("C",0); # Used by kerberos auth types. |
my $null = pack("C",0); # Used by kerberos auth types. |
Line 4216 sub make_passwd_file {
|
Line 4307 sub make_passwd_file {
|
return "no_priv_account_error\n"; |
return "no_priv_account_error\n"; |
} |
} |
|
|
my $execpath="$perlvar{'lonDaemons'}/"."lcuseradd"; |
my $execpath ="$perlvar{'lonDaemons'}/"."lcuseradd"; |
|
my $lc_error_file = "/tmp/lcuseradd".$$.".status"; |
{ |
{ |
&Debug("Executing external: ".$execpath); |
&Debug("Executing external: ".$execpath); |
&Debug("user = ".$uname.", Password =". $npass); |
&Debug("user = ".$uname.", Password =". $npass); |
Line 4224 sub make_passwd_file {
|
Line 4316 sub make_passwd_file {
|
print $se "$uname\n"; |
print $se "$uname\n"; |
print $se "$npass\n"; |
print $se "$npass\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) { |
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') { |
} elsif ($umode eq 'none') { |
{ |
{ |
my $pf = IO::File->new(">$passfilename"); |
my $pf = IO::File->new("> $passfilename"); |
print $pf "none:\n"; |
print $pf "none:\n"; |
} |
} |
} else { |
} else { |