--- loncom/lond 2004/03/22 09:05:11 1.178.2.9 +++ loncom/lond 2004/04/19 11:28:18 1.178.2.17 @@ -2,7 +2,7 @@ # The LearningOnline Network # lond "LON Daemon" Server (port "LOND" 5663) # -# $Id: lond,v 1.178.2.9 2004/03/22 09:05:11 foxr Exp $ +# $Id: lond,v 1.178.2.17 2004/04/19 11:28:18 foxr Exp $ # # Copyright Michigan State University Board of Trustees # @@ -53,7 +53,7 @@ my $DEBUG = 1; # Non zero to ena my $status=''; my $lastlog=''; -my $VERSION='$Revision: 1.178.2.9 $'; #' stupid emacs +my $VERSION='$Revision: 1.178.2.17 $'; #' stupid emacs my $remoteVERSION; my $currenthostid; my $currentdomainid; @@ -182,24 +182,24 @@ sub TieDomainHash { my $domain = shift; my $namespace = shift; my $how = shift; - + # Filter out any whitespace in the domain name: - + $domain =~ s/\W//g; - + # We have enough to go on to tie the hash: - - my $UserTopDir = $perlvar('lonUsersDir'); + + my $UserTopDir = $perlvar{'lonUsersDir'}; my $DomainDir = $UserTopDir."/$domain"; my $ResourceFile = $DomainDir."/$namespace.db"; my %hash; if(tie(%hash, 'GDBM_File', $ResourceFile, $how, 0640)) { if (scalar @_) { # Need to log the operation. my $logFh = IO::File->new(">>$DomainDir/$namespace.hist"); - if($logFH) { + if($logFh) { my $TimeStamp = time; my ($loghead, $logtail) = @_; - print $logFH "$loghead:$TimeStamp:$logtail\n"; + print $logFh "$loghead:$TimeStamp:$logtail\n"; } } return \%hash; # Return the tied hash. @@ -229,39 +229,39 @@ sub TieDomainHash { # undef if the has could not be tied. # sub TieUserHash { - my $domain = shift; - my $user = shift; - my $namespace = shift; - my $how = shift; - - $namespace=~s/\//\_/g; # / -> _ - $namespace=~s/\W//g; # whitespace eliminated. - my $proname = propath($domain, $user); - - # If this is a namespace for which a history is kept, - # make the history log entry: - - - unless ($namespace =~/^nohist\_/ && (scalar @_ > 0)) { - my $hfh = IO::File->new(">>$proname/$namespace.hist"); - if($hfh) { - my $now = time; - my $loghead = shift; - my $what = shift; - print $hfh "$loghead:$now:$what\n"; - } - } - # Tie the database. - - my %hash; - if(tie(%hash, 'GDBM_FILE', "$proname/$namespace.db", - $how, 0640)) { - return \%hash; - } - else { - return undef; - } - + my $domain = shift; + my $user = shift; + my $namespace = shift; + my $how = shift; + + $namespace=~s/\//\_/g; # / -> _ + $namespace=~s/\W//g; # whitespace eliminated. + my $proname = propath($domain, $user); + + # If this is a namespace for which a history is kept, + # make the history log entry: + + + unless ($namespace =~/^nohist\_/ && (scalar @_ > 0)) { + my $hfh = IO::File->new(">>$proname/$namespace.hist"); + if($hfh) { + my $now = time; + my $loghead = shift; + my $what = shift; + print $hfh "$loghead:$now:$what\n"; + } + } + # Tie the database. + + my %hash; + if(tie(%hash, 'GDBM_File', "$proname/$namespace.db", + $how, 0640)) { + return \%hash; + } + else { + return undef; + } + } # @@ -725,120 +725,30 @@ sub AuthenticateHandler { my $cmd = shift; my $tail = shift; my $client = shift; - + # Regenerate the full input line - + my $userinput = $cmd.":".$tail; - + # udom - User's domain. # uname - Username. # upass - User's password. - + my ($udom,$uname,$upass)=split(/:/,$tail); Debug(" Authenticate domain = $udom, user = $uname, password = $upass"); chomp($upass); $upass=unescape($upass); - # Fetch the user authentication information: - - my $realpasswd = GetAuthType($udom, $uname); - if($realpasswd ne "nouser") { # nouser means no passwd file. - my ($howpwd,$contentpwd)=split(/:/,$realpasswd); - my $pwdcorrect=0; - # - # Authenticate against password stored in the internal file. - # - Debug("Authenticating via $howpwd"); - if ($howpwd eq 'internal') { - &Debug("Internal auth"); - $pwdcorrect= (crypt($upass,$contentpwd) eq $contentpwd); - # - # Authenticate against the unix password file. - # - } elsif ($howpwd eq 'unix') { - &Debug("Unix auth"); - if((getpwnam($uname))[1] eq "") { #no such user! - $pwdcorrect = 0; - } else { - $contentpwd=(getpwnam($uname))[1]; - my $pwauth_path="/usr/local/sbin/pwauth"; - unless ($contentpwd eq 'x') { # Not in shadow file. - $pwdcorrect= (crypt($upass,$contentpwd) eq $contentpwd); - } elsif (-e $pwauth_path) { # In shadow file so - open PWAUTH, "|$pwauth_path" or # use external program - die "Cannot invoke authentication"; - print PWAUTH "$uname\n$upass\n"; - close PWAUTH; - $pwdcorrect=!$?; - } - } - # - # Authenticate against a Kerberos 4 server: - # - } elsif ($howpwd eq 'krb4') { - my $null=pack("C",0); - unless ($upass=~/$null/) { - my $krb4_error = &Authen::Krb4::get_pw_in_tkt($uname, - "", - $contentpwd, - 'krbtgt', - $contentpwd, - 1, - $upass); - if (!$krb4_error) { - $pwdcorrect = 1; - } else { - $pwdcorrect=0; - # log error if it is not a bad password - if ($krb4_error != 62) { - &logthis('krb4:'.$uname.','.$contentpwd.','. - &Authen::Krb4::get_err_txt($Authen::Krb4::error)); - } - } - } - # - # Authenticate against a Kerberos 5 server: - # - } elsif ($howpwd eq 'krb5') { - my $null=pack("C",0); - unless ($upass=~/$null/) { - my $krbclient=&Authen::Krb5::parse_name($uname.'@'.$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, - $upass, - $credentials); - $pwdcorrect = ($krbreturn == 1); - } else { - $pwdcorrect=0; - } - # - # Finally, the user may have written in an authentication module. - # in that case, if requested, authenticate against it. - # - } elsif ($howpwd eq 'localauth') { - $pwdcorrect=&localauth::localauth($uname,$upass,$contentpwd); - } + my $pwdcorrect = ValidateUser($udom, $uname, $upass); + if($pwdcorrect) { + Reply( $client, "authorized\n", $userinput); # - # Successfully authorized. + # Bad credentials: Failed to authorize # - if ($pwdcorrect) { - Reply( $client, "authorized\n", $userinput); - # - # Bad credentials: Failed to authorize - # - } else { - Failure( $client, "non_authorized\n", $userinput); - } - # Used to be unknown_user but that allows crackers to - # distinguish between bad username and bad password so... - # } else { Failure( $client, "non_authorized\n", $userinput); } + return 1; } RegisterHandler("auth", \&AuthenticateHandler, 1, 1, 0); @@ -882,62 +792,44 @@ sub ChangePasswordHandler { $upass=&unescape($upass); $npass=&unescape($npass); &Debug("Trying to change password for $uname"); - my $realpasswd = GetAuthType($udom, $uname); - if ($realpasswd ne "nouser") { + + # First require that the user can be authenticated with their + # old password: + + my $validated = ValidateUser($udom, $uname, $upass); + if($validated) { + my $realpasswd = GetAuthType($udom, $uname); # Defined since authd. + 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); - if(RewritePwFile($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); - } + my $salt=time; + $salt=substr($salt,6,2); + my $ncpass=crypt($npass,$salt); + if(RewritePwFile($udom, $uname, "internal:$ncpass")) { + &logthis("Result of password change for " + ."$uname: pwchange_success"); + Reply($client, "ok\n", $userinput); } else { - Failure($client, "non_authorized\n", $userinput); + &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 - # 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($?)); - Reply($client, "$result\n", $userinput); - } else { - Reply($client, "non_authorized\n", $userinput); - } + 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 @@ -945,12 +837,12 @@ sub ChangePasswordHandler { # Reply( $client, "auth_mode_error\n", $userinput); } - } else { - # used to be unknonw user but that gives out too much info.. - # so make it the same as if the initial passwd was bad. - # + + } + else { Reply( $client, "non_authorized\n", $userinput); } + return 1; } RegisterHandler("passwd", \&ChangePasswordHandler, 1, 1, 0); @@ -998,6 +890,7 @@ sub AddUserHandler { 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"; @@ -1097,7 +990,7 @@ sub IsHomeHandler { my ($udom,$uname)=split(/:/,$tail); chomp($uname); - my $passfile = PasswordPath($udom, $uname); + my $passfile = PasswordFilename($udom, $uname); if($passfile) { Reply( $client, "found\n", $userinput); } else { @@ -1245,10 +1138,7 @@ sub FetchUserFileHandler { } RegisterHandler("fetchuserfile", \&FetchUserFileHandler, 0, 1, 0); # -# Authenticate access to a user file. Question? The token for athentication -# is allowed to be sent as cleartext is this really what we want? This token -# represents the user's session id. Once it is forged does this allow too much -# access?? +# Authenticate access to a user file. # # Parameters: # $cmd - The command that got us here. @@ -1308,7 +1198,7 @@ sub UnsubscribeHandler { } RegisterHandler("unusb", \&UnsubscribeHandler, 0, 1, 0); -# Subscribe to a resource. +# Subscribe to a resource # # Parameters: # $cmd - The command that got us here. @@ -1409,34 +1299,34 @@ sub PutUserProfileEntry { my $tail = shift; my $client = shift; my $userinput = "$cmd:$tail"; - + my ($udom,$uname,$namespace,$what) =split(/:/,$tail); if ($namespace ne 'roles') { - chomp($what); - my $hashref = TieUserHash($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 { + chomp($what); + my $hashref = TieUserHash($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; + return 1; } RegisterHandler("put", \&PutUserProfileEntry, 0, 1, 0); @@ -1465,31 +1355,31 @@ sub IncrementUserValueHandler { if ($namespace ne 'roles') { chomp($what); my $hashref = TieUserHash($udom, $uname, - $namespace, &GDBM_WRCREAT(), - "P",$what); + $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); - } + 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; } @@ -1526,8 +1416,8 @@ sub RolesPutHandler { my $namespace='roles'; chomp($what); my $hashref = TieUserHash($udom, $uname, $namespace, - &GDBM_WRCREAT(), "P", - "$exedom:$exeuser:$what"); + &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 @@ -1583,25 +1473,25 @@ sub RolesDeleteHandler { my $namespace='roles'; chomp($what); my $hashref = TieUserHash($udom, $uname, $namespace, - &GDBM_WRCREAT(), "D", - "$exedom:$exeuser:$what"); - + &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); + 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); + Failure( $client, "error: ".($!+0)." untie(GDBM) Failed ". + "while attempting rolesdel\n", $userinput); } - } else { + } else { Failure( $client, "error: ".($!+0)." tie(GDBM) Failed ". "while attempting rolesdel\n", $userinput); - } + } return 1; } @@ -1635,11 +1525,11 @@ sub GetProfileEntry { my ($udom,$uname,$namespace,$what) = split(/:/,$tail); chomp($what); my $hashref = TieUserHash($udom, $uname, $namespace, - &GDBM_READER()); + &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. } @@ -1704,9 +1594,10 @@ sub GetProfileEntryEncrypted { $qresult.=" "; my $encqresult=''; for(my $encidx=0;$encidx<=$cmdlength;$encidx+=8) { - $encqresult.= unpack("H16", $cipher->encrypt(substr($qresult, - $encidx, - 8))); + $encqresult.= unpack("H16", + $cipher->encrypt(substr($qresult, + $encidx, + 8))); } Reply( $client, "enc:$cmdlength:$encqresult\n", $userinput); } else { @@ -1723,7 +1614,7 @@ sub GetProfileEntryEncrypted { return 1; } -RegisterHandler("eget", \&GetProfileEncrypted, 0, 1, 0); +RegisterHandler("eget", \&GetProfileEntryEncrypted, 0, 1, 0); # # Deletes a key in a user profile database. @@ -1851,7 +1742,7 @@ sub DumpProfileDatabase { # $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)) { @@ -1954,7 +1845,8 @@ sub DumpWithRegexp { } RegisterHandler("dump", \&DumpWithRegexp, 0, 1, 0); -# Store an aitem in any database but the roles database. +# Store an aitem in any resource meta data(?) or database with +# versioning? # # Parameters: # $cmd - Request command keyword. @@ -2263,6 +2155,7 @@ sub PutCourseIdHandler { my $userinput = "$cmd:$tail"; + my ($udom, $what) = split(/:/, $tail); chomp($what); my $now=time; my @pairs=split(/\&/,$what); @@ -2328,19 +2221,24 @@ sub DumpCourseIdHandler { } unless (defined($since)) { $since=0; } my $qresult=''; - + logthis(" Looking for $description since $since"); my $hashref = TieDomainHash($udom, "nohist_courseids", &GDBM_WRCREAT()); if ($hashref) { while (my ($key,$value) = each(%$hashref)) { my ($descr,$lasttime)=split(/\:/,$value); + logthis("Got: key = $key descr = $descr time: $lasttime"); if ($lasttime<$since) { + logthis("Skipping .. too early"); next; } if ($description eq '.') { + logthis("Adding wildcard match"); $qresult.=$key.'='.$descr.'&'; } else { my $unescapeVal = &unescape($descr); + logthis("Matching with $unescapeVal"); if (eval('$unescapeVal=~/$description/i')) { + logthis("Adding on match"); $qresult.="$key=$descr&"; } } @@ -2432,9 +2330,9 @@ sub GetIdHandler { my $cmd = shift; my $tail = shift; my $client = shift; - + my $userinput = "$client:$tail"; - + my ($udom,$what)=split(/:/,$tail); chomp($what); my @queries=split(/\&/,$what); @@ -2455,7 +2353,7 @@ sub GetIdHandler { Failure($client, "error: ".($!+0)." tie(GDBM) Failed ". "while attempting idget\n",$userinput); } - + return 1; } @@ -2487,7 +2385,8 @@ sub TmpPutHandler { my $store; $tmpsnum++; - my $id=$$.'_'.$clientip.'_'.$tmpsnum; + my $pid = $$; + my $id=$$.'_'.$clientip.'_'.$tmpsnum.'_'.$pid; $id=~s/\W/\_/g; $what=~s/\n//g; my $execdir=$perlvar{'lonDaemons'}; @@ -2523,7 +2422,7 @@ sub TmpGetHandler { my $id = shift; my $client = shift; my $userinput = "$cmd:$id"; - + chomp($id); $id=~s/\W/\_/g; my $store; @@ -2558,9 +2457,9 @@ sub TmpDelHandler { my $cmd = shift; my $id = shift; my $client = shift; - + my $userinput= "$cmd:$id"; - + chomp($id); $id=~s/\W/\_/g; my $execdir=$perlvar{'lonDaemons'}; @@ -2570,7 +2469,7 @@ sub TmpDelHandler { Failure( $client, "error: ".($!+0)."Unlink tmp Failed ". "while attempting tmpdel\n", $userinput); } - + return 1; } @@ -3898,11 +3797,14 @@ sub subsqlreply { sub propath { my ($udom,$uname)=@_; + Debug("Propath:$udom:$uname"); $udom=~s/\W//g; $uname=~s/\W//g; + Debug("Propath2:$udom:$uname"); my $subdir=$uname.'__'; $subdir =~ s/(.)(.)(.).*/$1\/$2\/$3/; my $proname="$perlvar{'lonUsersDir'}/$udom/$subdir/$uname"; + Debug("Propath returning $proname"); return $proname; } @@ -4160,7 +4062,7 @@ sub PasswordPath { my $user = shift; my $path = &propath($domain, $user); - my $path .= "/passwd"; + $path .= "/passwd"; return $path; } @@ -4179,8 +4081,10 @@ sub PasswordFilename { my $domain = shift; my $user = shift; - my $path = PasswordPath($domain, $user); + Debug ("PasswordFilename called: dom = $domain user = $user"); + my $path = PasswordPath($domain, $user); + Debug("PasswordFilename got path: $path"); if(-e $path) { return $path; } else { @@ -4240,6 +4144,135 @@ sub GetAuthType { } } +# +# 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 ValidateUser { + my $domain = shift; + my $user = shift; + my $password= shift; + + # 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 = GetAuthType($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; +} + +# +# Add a line to the subscription list? +# sub addline { my ($fname,$hostid,$ip,$newline)=@_; my $contents; @@ -4259,7 +4292,9 @@ sub addline { $sh->close(); return $found; } - +# +# Get chat messages. +# sub getchat { my ($cdom,$cname,$udom,$uname)=@_; my %hash; @@ -4284,7 +4319,9 @@ sub getchat { } return (@participants,@entries); } - +# +# Add a chat message +# sub chatadd { my ($cdom,$cname,$newchat)=@_; my %hash; @@ -4455,23 +4492,35 @@ sub make_passwd_file { print $pf "localauth:$npass\n"; } } elsif ($umode eq 'unix') { - { - my $execpath="$perlvar{'lonDaemons'}/"."lcuseradd"; - { - &Debug("Executing external: ".$execpath); - &Debug("user = ".$uname.", Password =". $npass); - my $se = IO::File->new("|$execpath > $perlvar{'lonDaemons'}/logs/lcuseradd.log"); - print $se "$uname\n"; - print $se "$npass\n"; - print $se "$npass\n"; - } - my $useraddok = $?; - if($useraddok > 0) { - &logthis("Failed lcuseradd: ".&lcuseraddstrerror($useraddok)); - } - my $pf = IO::File->new(">$passfilename"); - print $pf "unix:\n"; + # + # Don't allow the creation of privileged accounts!!! that would + # be real bad!!! + # + my $uid = getpwnam($uname); + if((defined $uid) && ($uid == 0)) { + &logthis(">>>Attempted add of privileged account blocked<<<"); + return "no_priv_account_error\n"; } + + # + my $execpath="$perlvar{'lonDaemons'}/"."lcuseradd"; + + &Debug("Executing external: ".$execpath); + &Debug("user = ".$uname.", Password =". $npass); + my $se = IO::File->new("|$execpath > $perlvar{'lonDaemons'}/logs/lcuseradd.log"); + print $se "$uname\n"; + print $se "$npass\n"; + print $se "$npass\n"; + + my $useraddok = $?; + if($useraddok > 0) { + my $lcstring = lcuseraddstrerror($useraddok); + &logthis("Failed lcuseradd: $lcstring"); + return "error: lcuseradd failed: $lcstring\n"; + } + my $pf = IO::File->new(">$passfilename"); + print $pf "unix:\n"; + } elsif ($umode eq 'none') { { my $pf = IO::File->new(">$passfilename");