CRITICAL: "
+ &logthis("CRITICAL: "
."Disconnect from $clientip ($clientname)");
@@ -2838,10 +3924,8 @@ sub make_new_child {
#
sub ManagePermissions
{
- my $request = shift;
- my $domain = shift;
- my $user = shift;
- my $authtype= shift;
+
+ my ($request, $domain, $user, $authtype) = @_;
# See if the request is of the form /$domain/_au
if($request =~ /^(\/$domain\/_au)$/) { # It's an author rolesput...
@@ -2851,17 +3935,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 = shift;
- my $user = shift;
- Debug("GetAuthType( $domain, $user ) \n");
+ my ($domain, $user) = @_;
+
+ Debug("get_auth_type( $domain, $user ) \n");
my $proname = &propath($domain, $user);
my $passwdfile = "$proname/passwd";
if( -e $passwdfile ) {
@@ -2877,13 +4033,132 @@ sub GetAuthType
}
return "$authtype:$availinfo";
- }
- else {
+ } else {
Debug("Returning nouser");
return "nouser";
}
}
+#
+# Validate a user given their domain, name and password. This utility
+# function is used by both AuthenticateHandler and ChangePasswordHandler
+# to validate the login credentials of a user.
+# Parameters:
+# $domain - The domain being logged into (this is required due to
+# the capability for multihomed systems.
+# $user - The name of the user being validated.
+# $password - The user's propoposed password.
+#
+# Returns:
+# 1 - The domain,user,pasword triplet corresponds to a valid
+# user.
+# 0 - The domain,user,password triplet is not a valid user.
+#
+sub validate_user {
+ my ($domain, $user, $password) = @_;
+
+
+ # Why negative ~pi you may well ask? Well this function is about
+ # authentication, and therefore very important to get right.
+ # I've initialized the flag that determines whether or not I've
+ # validated correctly to a value it's not supposed to get.
+ # At the end of this function. I'll ensure that it's not still that
+ # value so we don't just wind up returning some accidental value
+ # as a result of executing an unforseen code path that
+ # did not set $validated.
+
+ my $validated = -3.14159;
+
+ # How we authenticate is determined by the type of authentication
+ # the user has been assigned. If the authentication type is
+ # "nouser", the user does not exist so we will return 0.
+
+ my $contents = &get_auth_type($domain, $user);
+ my ($howpwd, $contentpwd) = split(/:/, $contents);
+
+ my $null = pack("C",0); # Used by kerberos auth types.
+
+ if ($howpwd ne 'nouser') {
+
+ if($howpwd eq "internal") { # Encrypted is in local password file.
+ $validated = (crypt($password, $contentpwd) eq $contentpwd);
+ }
+ elsif ($howpwd eq "unix") { # User is a normal unix user.
+ $contentpwd = (getpwnam($user))[1];
+ if($contentpwd) {
+ if($contentpwd eq 'x') { # Shadow password file...
+ my $pwauth_path = "/usr/local/sbin/pwauth";
+ open PWAUTH, "|$pwauth_path" or
+ die "Cannot invoke authentication";
+ print PWAUTH "$user\n$password\n";
+ close PWAUTH;
+ $validated = ! $?;
+
+ } else { # Passwords in /etc/passwd.
+ $validated = (crypt($password,
+ $contentpwd) eq $contentpwd);
+ }
+ } else {
+ $validated = 0;
+ }
+ }
+ elsif ($howpwd eq "krb4") { # user is in kerberos 4 auth. domain.
+ if(! ($password =~ /$null/) ) {
+ my $k4error = &Authen::Krb4::get_pw_in_tkt($user,
+ "",
+ $contentpwd,,
+ 'krbtgt',
+ $contentpwd,
+ 1,
+ $password);
+ if(!$k4error) {
+ $validated = 1;
+ } else {
+ $validated = 0;
+ &logthis('krb4: '.$user.', '.$contentpwd.', '.
+ &Authen::Krb4::get_err_txt($Authen::Krb4::error));
+ }
+ } else {
+ $validated = 0; # Password has a match with null.
+ }
+ } 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);
+ my $krbservice = "krbtgt/".$contentpwd."\@".$contentpwd;
+ my $krbserver = &Authen::Krb5::parse_name($krbservice);
+ my $credentials= &Authen::Krb5::cc_default();
+ $credentials->initialize($krbclient);
+ my $krbreturn = &Authen::KRb5::get_in_tkt_with_password($krbclient,
+ $krbserver,
+ $password,
+ $credentials);
+ $validated = ($krbreturn == 1);
+ } else {
+ $validated = 0;
+ }
+ } elsif ($howpwd eq "localauth") {
+ # Authenticate via installation specific authentcation method:
+ $validated = &localauth::localauth($user,
+ $password,
+ $contentpwd);
+ } else { # Unrecognized auth is also bad.
+ $validated = 0;
+ }
+ } else {
+ $validated = 0;
+ }
+ #
+ # $validated has the correct stat of the authentication:
+ #
+
+ unless ($validated != -3.14159) {
+ die "ValidateUser - failed to set the value of validated";
+ }
+ return $validated;
+}
+
+
sub addline {
my ($fname,$hostid,$ip,$newline)=@_;
my $contents;
@@ -2968,17 +4243,36 @@ sub chatadd {
sub unsub {
my ($fname,$clientip)=@_;
my $result;
+ my $unsubs = 0; # Number of successful unsubscribes:
+
+
+ # An old way subscriptions were handled was to have a
+ # subscription marker file:
+
+ Debug("Attempting unlink of $fname.$clientname");
if (unlink("$fname.$clientname")) {
- $result="ok\n";
- } else {
- $result="not_subscribed\n";
- }
+ $unsubs++; # Successful unsub via marker file.
+ }
+
+ # The more modern way to do it is to have a subscription list
+ # file:
+
if (-e "$fname.subscription") {
my $found=&addline($fname,$clientname,$clientip,'');
- if ($found) { $result="ok\n"; }
+ if ($found) {
+ $unsubs++;
+ }
+ }
+
+ # If either or both of these mechanisms succeeded in unsubscribing a
+ # resource we can return ok:
+
+ if($unsubs) {
+ $result = "ok\n";
} else {
- if ($result != "ok\n") { $result="not_subscribed\n"; }
+ $result = "not_subscribed\n";
}
+
return $result;
}
@@ -3100,7 +4394,19 @@ sub make_passwd_file {
}
} elsif ($umode eq 'unix') {
{
- my $execpath="$perlvar{'lonDaemons'}/"."lcuseradd";
+ #
+ # Don't allow the creation of privileged accounts!!! that would
+ # be real bad!!!
+ #
+ my $uid = getpwnam($uname);
+ if((defined $uid) && ($uid == 0)) {
+ &logthis(">>>Attempted to create privilged account blocked");
+ return "no_priv_account_error\n";
+ }
+
+ my $execpath ="$perlvar{'lonDaemons'}/"."lcuseradd";
+
+ my $lc_error_file = $execdir."/tmp/lcuseradd".$$.".status";
{
&Debug("Executing external: ".$execpath);
&Debug("user = ".$uname.", Password =". $npass);
@@ -3108,17 +4414,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 {
@@ -3132,7 +4448,7 @@ sub sethost {
my (undef,$hostid)=split(/:/,$remotereq);
if (!defined($hostid)) { $hostid=$perlvar{'lonHostID'}; }
if ($hostip{$perlvar{'lonHostID'}} eq $hostip{$hostid}) {
- $currenthostid=$hostid;
+ $currenthostid =$hostid;
$currentdomainid=$hostdom{$hostid};
&logthis("Setting hostid to $hostid, and domain to $currentdomainid");
} else {
@@ -3172,6 +4488,74 @@ sub userload {
return $userloadpercent;
}
+# Routines for serializing arrays and hashes (copies from lonnet)
+
+sub array2str {
+ my (@array) = @_;
+ my $result=&arrayref2str(\@array);
+ $result=~s/^__ARRAY_REF__//;
+ $result=~s/__END_ARRAY_REF__$//;
+ return $result;
+}
+
+sub arrayref2str {
+ my ($arrayref) = @_;
+ my $result='__ARRAY_REF__';
+ foreach my $elem (@$arrayref) {
+ if(ref($elem) eq 'ARRAY') {
+ $result.=&arrayref2str($elem).'&';
+ } elsif(ref($elem) eq 'HASH') {
+ $result.=&hashref2str($elem).'&';
+ } elsif(ref($elem)) {
+ #print("Got a ref of ".(ref($elem))." skipping.");
+ } else {
+ $result.=&escape($elem).'&';
+ }
+ }
+ $result=~s/\&$//;
+ $result .= '__END_ARRAY_REF__';
+ return $result;
+}
+
+sub hash2str {
+ my (%hash) = @_;
+ my $result=&hashref2str(\%hash);
+ $result=~s/^__HASH_REF__//;
+ $result=~s/__END_HASH_REF__$//;
+ return $result;
+}
+
+sub hashref2str {
+ my ($hashref)=@_;
+ my $result='__HASH_REF__';
+ foreach (sort(keys(%$hashref))) {
+ if (ref($_) eq 'ARRAY') {
+ $result.=&arrayref2str($_).'=';
+ } elsif (ref($_) eq 'HASH') {
+ $result.=&hashref2str($_).'=';
+ } elsif (ref($_)) {
+ $result.='=';
+ #print("Got a ref of ".(ref($_))." skipping.");
+ } else {
+ if ($_) {$result.=&escape($_).'=';} else { last; }
+ }
+
+ if(ref($hashref->{$_}) eq 'ARRAY') {
+ $result.=&arrayref2str($hashref->{$_}).'&';
+ } elsif(ref($hashref->{$_}) eq 'HASH') {
+ $result.=&hashref2str($hashref->{$_}).'&';
+ } elsif(ref($hashref->{$_})) {
+ $result.='&';
+ #print("Got a ref of ".(ref($hashref->{$_}))." skipping.");
+ } else {
+ $result.=&escape($hashref->{$_}).'&';
+ }
+ }
+ $result=~s/\&$//;
+ $result .= '__END_HASH_REF__';
+ return $result;
+}
+
# ----------------------------------- POD (plain old documentation, CPAN style)
=head1 NAME
500 Internal Server Error
Internal Server Error
The server encountered an internal error or
misconfiguration and was unable to complete
your request.
Please contact the server administrator at
root@localhost to inform them of the time this error occurred,
and the actions you performed just before this error.
More information about this error may be available
in the server error log.