--- loncom/lond 2004/10/21 16:05:50 1.263 +++ loncom/lond 2005/06/28 19:06:10 1.290 @@ -2,7 +2,7 @@ # The LearningOnline Network # lond "LON Daemon" Server (port "LOND" 5663) # -# $Id: lond,v 1.263 2004/10/21 16:05:50 albertel Exp $ +# $Id: lond,v 1.290 2005/06/28 19:06:10 banghart Exp $ # # Copyright Michigan State University Board of Trustees # @@ -46,6 +46,7 @@ use Authen::Krb5; use lib '/home/httpd/lib/perl/'; use localauth; use localenroll; +use localstudentphoto; use File::Copy; use LONCAPA::ConfigFileEdit; use LONCAPA::lonlocal; @@ -57,14 +58,13 @@ my $DEBUG = 0; # Non zero to ena my $status=''; my $lastlog=''; -my $VERSION='$Revision: 1.263 $'; #' stupid emacs +my $VERSION='$Revision: 1.290 $'; #' stupid emacs my $remoteVERSION; my $currenthostid="default"; my $currentdomainid; my $client; my $clientip; # IP address of client. -my $clientdns; # DNS name of client. my $clientname; # LonCAPA name of client. my $server; @@ -112,20 +112,20 @@ my %Dispatcher; # my $lastpwderror = 13; # Largest error number from lcpasswd. my @passwderrors = ("ok", - "lcpasswd must be run as user 'www'", - "lcpasswd got incorrect number of arguments", - "lcpasswd did not get the right nubmer of input text lines", - "lcpasswd too many simultaneous pwd changes in progress", - "lcpasswd User does not exist.", - "lcpasswd Incorrect current passwd", - "lcpasswd Unable to su to root.", - "lcpasswd Cannot set new passwd.", - "lcpasswd Username has invalid characters", - "lcpasswd Invalid characters in password", - "lcpasswd User already exists", - "lcpasswd Something went wrong with user addition.", - "lcpasswd Password mismatch", - "lcpasswd Error filename is invalid"); + "pwchange_failure - lcpasswd must be run as user 'www'", + "pwchange_failure - lcpasswd got incorrect number of arguments", + "pwchange_failure - lcpasswd did not get the right nubmer of input text lines", + "pwchange_failure - lcpasswd too many simultaneous pwd changes in progress", + "pwchange_failure - lcpasswd User does not exist.", + "pwchange_failure - lcpasswd Incorrect current passwd", + "pwchange_failure - lcpasswd Unable to su to root.", + "pwchange_failure - lcpasswd Cannot set new passwd.", + "pwchange_failure - lcpasswd Username has invalid characters", + "pwchange_failure - lcpasswd Invalid characters in password", + "pwchange_failure - lcpasswd User already exists", + "pwchange_failure - lcpasswd Something went wrong with user addition.", + "pwchange_failure - lcpasswd Password mismatch", + "pwchange_failure - lcpasswd Error filename is invalid"); # The array below are lcuseradd error strings.: @@ -177,7 +177,6 @@ sub ResetStatistics { # $initcmd - The full text of the init command. # # Implicit inputs: -# $clientdns - The DNS name of the remote client. # $thisserver - Our DNS name. # # Returns: @@ -186,10 +185,10 @@ sub ResetStatistics { # sub LocalConnection { my ($Socket, $initcmd) = @_; - Debug("Attempting local connection: $initcmd client: $clientdns me: $thisserver"); - if($clientdns ne $thisserver) { + Debug("Attempting local connection: $initcmd client: $clientip me: $thisserver"); + if($clientip ne "127.0.0.1") { &logthis(' LocalConnection rejecting non local: ' - ."$clientdns ne $thisserver "); + ."$clientip ne $thisserver "); close $Socket; return undef; } else { @@ -473,39 +472,11 @@ sub CopyFile { my ($oldfile, $newfile) = @_; - # The file must exist: - - if(-e $oldfile) { - - # Read the old file. - - my $oldfh = IO::File->new("< $oldfile"); - if(!$oldfh) { - return 0; - } - my @contents = <$oldfh>; # Suck in the entire file. - - # write the backup file: - - my $newfh = IO::File->new("> $newfile"); - if(!(defined $newfh)){ - return 0; - } - my $lines = scalar @contents; - for (my $i =0; $i < $lines; $i++) { - print $newfh ($contents[$i]); - } - - $oldfh->close; - $newfh->close; - - chmod(0660, $newfile); - - return 1; - - } else { - return 0; + if (! copy($oldfile,$newfile)) { + return 0; } + chmod(0660, $newfile); + return 1; } # # Host files are passed out with externally visible host IPs. @@ -1311,8 +1282,10 @@ sub user_authorization_type { my ($type,$otherinfo) = split(/:/,$result); if($type =~ /^krb/) { $type = $result; - } - &Reply( $replyfd, "$type:\n", $userinput); + } else { + $type .= ':'; + } + &Reply( $replyfd, "$type\n", $userinput); } return 1; @@ -1394,8 +1367,8 @@ sub du_handler { # assurance double sure, # use execute_command to ensure that the command is not executed in # a shell that can screw us up. - - my $duout = execute_command("du -ks $ududir"); + my $file_list = execute_command("find $ududir -not -regex '.*\.[0-9]+\.[^\.]+' -not -name '*.meta' -print"); + my $duout = execute_command("du -ks $file_list"); $duout=~s/[^\d]//g; #preserve only the numbers &Reply($client,"$duout\n","$cmd:$ududir"); } else { @@ -1408,6 +1381,9 @@ sub du_handler { ®ister_handler("du", \&du_handler, 0, 1, 0); # +# The ls_handler routine should be considered obosolete and is retained +# for communication with legacy servers. Please see the ls2_handler. +# # ls - list the contents of a directory. For each file in the # selected directory the filename followed by the full output of # the stat function is returned. The returned info for each @@ -1424,6 +1400,7 @@ sub du_handler { # The reply is written to $client. # sub ls_handler { + # obsoleted by ls2_handler my ($cmd, $ulsdir, $client) = @_; my $userinput = "$cmd:$ulsdir"; @@ -1470,6 +1447,72 @@ sub ls_handler { } ®ister_handler("ls", \&ls_handler, 0, 1, 0); +# +# Please also see the ls_handler, which this routine obosolets. +# ls2_handler differs from ls_handler in that it escapes its return +# values before concatenating them together with ':'s. +# +# ls2 - list the contents of a directory. For each file in the +# selected directory the filename followed by the full output of +# the stat function is returned. The returned info for each +# file are separated by ':'. The stat fields are separated by &'s. +# Parameters: +# $cmd - The command that dispatched us (ls). +# $ulsdir - The directory path to list... I'm not sure what this +# is relative as things like ls:. return e.g. +# no_such_dir. +# $client - Socket open on the client. +# Returns: +# 1 - indicating that the daemon should not disconnect. +# Side Effects: +# The reply is written to $client. +# +sub ls2_handler { + my ($cmd, $ulsdir, $client) = @_; + + my $userinput = "$cmd:$ulsdir"; + + my $obs; + my $rights; + my $ulsout=''; + my $ulsfn; + if (-e $ulsdir) { + if(-d $ulsdir) { + if (opendir(LSDIR,$ulsdir)) { + while ($ulsfn=readdir(LSDIR)) { + undef $obs, $rights; + my @ulsstats=stat($ulsdir.'/'.$ulsfn); + #We do some obsolete checking here + if(-e $ulsdir.'/'.$ulsfn.".meta") { + open(FILE, $ulsdir.'/'.$ulsfn.".meta"); + my @obsolete=; + foreach my $obsolete (@obsolete) { + if($obsolete =~ m|()(on)|) { $obs = 1; } + if($obsolete =~ m|()(default)|) { + $rights = 1; + } + } + } + my $tmp = $ulsfn.'&'.join('&',@ulsstats); + if ($obs eq '1') { $tmp.="&1"; } else { $tmp.="&0"; } + if ($rights eq '1') { $tmp.="&1"; } else { $tmp.="&0"; } + $ulsout.= &escape($tmp).':'; + } + closedir(LSDIR); + } + } else { + my @ulsstats=stat($ulsdir); + $ulsout.=$ulsfn.'&'.join('&',@ulsstats).':'; + } + } else { + $ulsout='no_such_dir'; + } + if ($ulsout eq '') { $ulsout='empty'; } + &Reply($client, "$ulsout\n", $userinput); # This supports debug logging. + return 1; +} +®ister_handler("ls2", \&ls2_handler, 0, 1, 0); + # Process a reinit request. Reinit requests that either # lonc or lond be reinitialized so that an updated # host.tab or domain.tab can be processed. @@ -1658,19 +1701,9 @@ sub change_password_handler { &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'); + my $result = &change_unix_password($uname, $npass); &logthis("Result of password change for $uname: ". - &lcpasswdstrerror($?)); + $result); &Reply($client, "$result\n", $userinput); } else { # this just means that the current password mode is not @@ -1725,18 +1758,10 @@ sub add_user_handler { 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"; - } - } + if (!&mkpath($passfilename)) { + $fperror="error: ".($!+0)." mkdir failed while attempting " + ."makeuser"; } unless ($fperror) { my $result=&make_passwd_file($uname, $umode,$npass, $passfilename); @@ -1777,6 +1802,9 @@ sub add_user_handler { # Implicit inputs: # The authentication systems describe above have their own forms of implicit # input into the authentication process that are described above. +# NOTE: +# This is also used to change the authentication credential values (e.g. passwd). +# # sub change_authentication_handler { @@ -1796,23 +1824,41 @@ sub change_authentication_handler { my $oldauth = &get_auth_type($udom, $uname); # Get old auth info. my $passfilename = &password_path($udom, $uname); if ($passfilename) { # Not allowed to create a new user!! - my $result=&make_passwd_file($uname, $umode,$npass,$passfilename); - # - # If the current auth mode is internal, and the old auth mode was - # unix, or krb*, and the user is an author for this domain, - # re-run manage_permissions for that role in order to be able - # to take ownership of the construction space back to www:www - # - - if( ($oldauth =~ /^unix/) && ($umode eq "internal")) { # unix -> internal - if(&is_author($udom, $uname)) { - &Debug(" Need to manage author permissions..."); - &manage_permissions("/$udom/_au", $udom, $uname, "internal:"); + # If just changing the unix passwd. need to arrange to run + # passwd since otherwise make_passwd_file will run + # lcuseradd which fails if an account already exists + # (to prevent an unscrupulous LONCAPA admin from stealing + # an existing account by overwriting it as a LonCAPA account). + + if(($oldauth =~/^unix/) && ($umode eq "unix")) { + my $result = &change_unix_password($uname, $npass); + &logthis("Result of password change for $uname: ".$result); + if ($result eq "ok") { + &Reply($client, "$result\n") + } else { + &Failure($client, "$result\n"); + } + } else { + my $result=&make_passwd_file($uname, $umode,$npass,$passfilename); + # + # If the current auth mode is internal, and the old auth mode was + # unix, or krb*, and the user is an author for this domain, + # re-run manage_permissions for that role in order to be able + # to take ownership of the construction space back to www:www + # + + + if( (($oldauth =~ /^unix/) && ($umode eq "internal")) || + (($oldauth =~ /^internal/) && ($umode eq "unix")) ) { + if(&is_author($udom, $uname)) { + &Debug(" Need to manage author permissions..."); + &manage_permissions("/$udom/_au", $udom, $uname, "$umode:"); + } } + &Reply($client, $result, $userinput); } - &Reply($client, $result, $userinput); } else { &Failure($client, "non_authorized\n", $userinput); # Fail the user now. } @@ -1967,21 +2013,10 @@ sub fetch_user_file_handler { # 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); - } - } + if (!&mkpath($udir.'/'.$ufile)) { + &Failure($client, "unable_to_create\n", $userinput); } - my $destname=$udir.'/'.$ufile; my $transname=$udir.'/'.$ufile.'.in.transit'; my $remoteurl='http://'.$clientip.'/userfiles/'.$fname; @@ -2090,24 +2125,11 @@ sub mkdir_user_file_handler { } else { my $udir = &propath($udom,$uname); if (-e $udir) { - my $newdir=$udir.'/userfiles/'.$ufile; - if (!-e $newdir) { - my @parts=split('/',$newdir); - my $path; - foreach my $part (@parts) { - $path .= '/'.$part; - if (!-e $path) { - mkdir($path,0770); - } - } - if (!-e $newdir) { - &Failure($client, "failed\n", "$cmd:$tail"); - } else { - &Reply($client, "ok\n", "$cmd:$tail"); - } - } else { - &Failure($client, "not_found\n", "$cmd:$tail"); + my $newdir=$udir.'/userfiles/'.$ufile.'/'; + if (!&mkpath($newdir)) { + &Failure($client, "failed\n", "$cmd:$tail"); } + &Reply($client, "ok\n", "$cmd:$tail"); } else { &Failure($client, "not_home\n", "$cmd:$tail"); } @@ -2348,6 +2370,61 @@ sub put_user_profile_entry { } ®ister_handler("put", \&put_user_profile_entry, 0, 1, 0); +# Put a piece of new data in hash, returns error if entry already 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. +# +sub newput_user_profile_entry { + my ($cmd, $tail, $client) = @_; + + my $userinput = "$cmd:$tail"; + + my ($udom,$uname,$namespace,$what) =split(/:/,$tail,4); + if ($namespace eq 'roles') { + &Failure( $client, "refused\n", $userinput); + return 1; + } + + chomp($what); + + my $hashref = &tie_user_hash($udom, $uname, $namespace, + &GDBM_WRCREAT(),"N",$what); + if(!$hashref) { + &Failure( $client, "error: ".($!)." tie(GDBM) Failed ". + "while attempting put\n", $userinput); + return 1; + } + + my @pairs=split(/\&/,$what); + foreach my $pair (@pairs) { + my ($key,$value)=split(/=/,$pair); + if (exists($hashref->{$key})) { + &Failure($client, "key_exists: ".$key."\n",$userinput); + return 1; + } + } + + 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); + } + return 1; +} +®ister_handler("newput", \&newput_user_profile_entry, 0, 1, 0); + # # Increment a profile entry in the user history file. # The history contains keyword value pairs. In this case, @@ -2378,11 +2455,17 @@ sub increment_user_value_handler { my @pairs=split(/\&/,$what); foreach my $pair (@pairs) { my ($key,$value)=split(/=/,$pair); + $value = &unescape($value); # We could check that we have a number... if (! defined($value) || $value eq '') { $value = 1; } $hashref->{$key}+=$value; + if ($namespace eq 'nohist_resourcetracker') { + if ($hashref->{$key} < 0) { + $hashref->{$key} = 0; + } + } } if (untie(%$hashref)) { &Reply( $client, "ok\n", $userinput); @@ -2866,7 +2949,7 @@ sub store_handler { chomp($what); my @pairs=split(/\&/,$what); my $hashref = &tie_user_hash($udom, $uname, $namespace, - &GDBM_WRCREAT(), "P", + &GDBM_WRCREAT(), "S", "$rid:$what"); if ($hashref) { my $now = time; @@ -3137,6 +3220,14 @@ sub reply_query_handler { # $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. +# Each value is a colon separated list that includes: +# description, institutional code and course owner. +# For backward compatibility with versions included +# in LON-CAPA 1.1.X (and earlier) and 1.2.X, institutional +# code and/or course owner are preserved from the existing +# record when writing a new record in response to 1.1 or +# 1.2 implementations of lonnet::flushcourselogs(). +# # $client - Socket open on the client. # Returns: # 1 - indicating that processing should continue @@ -3150,7 +3241,7 @@ sub put_course_id_handler { my $userinput = "$cmd:$tail"; - my ($udom, $what) = split(/:/, $tail); + my ($udom, $what) = split(/:/, $tail,2); chomp($what); my $now=time; my @pairs=split(/\&/,$what); @@ -3158,8 +3249,24 @@ sub put_course_id_handler { my $hashref = &tie_domain_hash($udom, "nohist_courseids", &GDBM_WRCREAT()); if ($hashref) { foreach my $pair (@pairs) { - my ($key,$descr,$inst_code)=split(/=/,$pair); - $hashref->{$key}=$descr.':'.$inst_code.':'.$now; + my ($key,$courseinfo) = split(/=/,$pair,2); + $courseinfo =~ s/=/:/g; + + my @current_items = split(/:/,$hashref->{$key}); + shift(@current_items); # remove description + pop(@current_items); # remove last access + my $numcurrent = scalar(@current_items); + + my @new_items = split(/:/,$courseinfo); + my $numnew = scalar(@new_items); + if ($numcurrent > 0) { + if ($numnew == 1) { # flushcourselogs() from 1.1 or earlier + $courseinfo .= ':'.join(':',@current_items); + } elsif ($numnew == 2) { # flushcourselogs() from 1.2.X + $courseinfo .= ':'.$current_items[$numcurrent-1]; + } + } + $hashref->{$key}=$courseinfo.':'.$now; } if (untie(%$hashref)) { &Reply( $client, "ok\n", $userinput); @@ -3197,6 +3304,15 @@ sub put_course_id_handler { # description - regular expression that is used to filter # the dump. Only keywords matching this regexp # will be used. +# institutional code - optional supplied code to filter +# the dump. Only courses with an institutional code +# that match the supplied code will be returned. +# owner - optional supplied username of owner to filter +# the dump. Only courses for which the course +# owner matches the supplied username will be +# returned. Implicit assumption that owner +# is a user in the domain in which the +# course database is defined. # $client - The socket open on the client. # Returns: # 1 - Continue processing. @@ -3207,32 +3323,66 @@ sub dump_course_id_handler { my $userinput = "$cmd:$tail"; - my ($udom,$since,$description) =split(/:/,$tail); + my ($udom,$since,$description,$instcodefilter,$ownerfilter,$coursefilter) =split(/:/,$tail); if (defined($description)) { $description=&unescape($description); } else { $description='.'; } + if (defined($instcodefilter)) { + $instcodefilter=&unescape($instcodefilter); + } else { + $instcodefilter='.'; + } + if (defined($ownerfilter)) { + $ownerfilter=&unescape($ownerfilter); + } else { + $ownerfilter='.'; + } + if (defined($coursefilter)) { + $coursefilter=&unescape($coursefilter); + } else { + $coursefilter='.'; + } + 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); - } + my ($descr,$lasttime,$inst_code,$owner); + my @courseitems = split(/:/,$value); + $lasttime = pop(@courseitems); + ($descr,$inst_code,$owner)=@courseitems; 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.'&'; + my $match = 1; + unless ($description eq '.') { + my $unescapeDescr = &unescape($descr); + unless (eval('$unescapeDescr=~/\Q$description\E/i')) { + $match = 0; } + } + unless ($instcodefilter eq '.' || !defined($instcodefilter)) { + my $unescapeInstcode = &unescape($inst_code); + unless (eval('$unescapeInstcode=~/\Q$instcodefilter\E/i')) { + $match = 0; + } } + unless ($ownerfilter eq '.' || !defined($ownerfilter)) { + my $unescapeOwner = &unescape($owner); + unless (eval('$unescapeOwner=~/\Q$ownerfilter\E/i')) { + $match = 0; + } + } + unless ($coursefilter eq '.' || !defined($coursefilter)) { + my $unescapeCourse = &unescape($key); + unless (eval('$unescapeCourse=~/^$udom(_)\Q$coursefilter\E$/')) { + $match = 0; + } + } + if ($match == 1) { + $qresult.=$key.'='.$descr.':'.$inst_code.':'.$owner.'&'; + } } if (untie(%$hashref)) { chop($qresult); @@ -3824,15 +3974,63 @@ sub get_institutional_code_format_handle return 1; } +®ister_handler("autoinstcodeformat", + \&get_institutional_code_format_handler,0,1,0); -®ister_handler("autoinstcodeformat", \&get_institutional_code_format_handler, - 0,1,0); - -# -# -# -# # +# Gets a student's photo to exist (in the correct image type) in the user's +# directory. +# Formal Parameters: +# $cmd - The command request that got us dispatched. +# $tail - A colon separated set of words that will be split into: +# $domain - student's domain +# $uname - student username +# $type - image type desired +# $client - The socket open on the client. +# Returns: +# 1 - continue processing. +sub student_photo_handler { + my ($cmd, $tail, $client) = @_; + my ($domain,$uname,$type) = split(/:/, $tail); + + my $path=&propath($domain,$uname). + '/userfiles/internal/studentphoto.'.$type; + if (-e $path) { + &Reply($client,"ok\n","$cmd:$tail"); + return 1; + } + &mkpath($path); + my $file=&localstudentphoto::fetch($domain,$uname); + if (!$file) { + &Failure($client,"unavailable\n","$cmd:$tail"); + return 1; + } + if (!-e $path) { &convert_photo($file,$path); } + if (-e $path) { + &Reply($client,"ok\n","$cmd:$tail"); + return 1; + } + &Failure($client,"unable_to_convert\n","$cmd:$tail"); + return 1; +} +®ister_handler("studentphoto", \&student_photo_handler, 0, 1, 0); + +# mkpath makes all directories for a file, expects an absolute path with a +# file or a trailing / if just a dir is passed +# returns 1 on success 0 on failure +sub mkpath { + my ($file)=@_; + my @parts=split(/\//,$file,-1); + my $now=$parts[0].'/'.$parts[1].'/'.$parts[2]; + for (my $i=3;$i<= ($#parts-1);$i++) { + $now.='/'.$parts[$i]; + if (!-e $now) { + if (!mkdir($now,0770)) { return 0; } + } + } + return 1; +} + #--------------------------------------------------------------- # # Getting, decoding and dispatching requests: @@ -4205,12 +4403,18 @@ sub ReadHostTable { my $myloncapaname = $perlvar{'lonHostID'}; Debug("My loncapa name is : $myloncapaname"); while (my $configline=) { - if (!($configline =~ /^\s*\#/)) { - my ($id,$domain,$role,$name,$ip)=split(/:/,$configline); - chomp($ip); $ip=~s/\D+$//; + if ($configline !~ /^\s*\#/ && $configline !~ /^\s*$/ ) { + my ($id,$domain,$role,$name)=split(/:/,$configline); + $name=~s/\s//g; + my $ip = gethostbyname($name); + if (length($ip) ne 4) { + &logthis("Skipping host $id name $name no IP $ip found\n"); + next; + } + $ip=inet_ntoa($ip); $hostid{$ip}=$id; # LonCAPA name of host by IP. $hostdom{$id}=$domain; # LonCAPA domain name of host. - $hostip{$id}=$ip; # IP address of host. + $hostip{$id}=$ip; # IP address of host. $hostdns{$name} = $id; # LonCAPA name of host by DNS. if ($id eq $perlvar{'lonHostID'}) { @@ -4347,8 +4551,6 @@ sub Reply { Debug("Request was $request Reply was $reply"); $Transactions++; - - } @@ -4391,7 +4593,7 @@ sub logstatus { flock(LOG,LOCK_EX); print LOG $$."\t".$clientname."\t".$currenthostid."\t" .$status."\t".$lastlog."\t $keymode\n"; - flock(DB,LOCK_UN); + flock(LOG,LOCK_UN); close(LOG); } &status("Finished logging"); @@ -4576,6 +4778,8 @@ $SIG{USR2} = \&UpdateHosts; ReadHostTable; +my $dist=`$perlvar{'lonDaemons'}/distprobe`; + # -------------------------------------------------------------- # Accept connections. When a connection comes in, it is validated # and if good, a child process is created to process transactions @@ -4622,8 +4826,6 @@ sub make_new_child { if (defined($iaddr)) { $clientip = inet_ntoa($iaddr); Debug("Connected with $clientip"); - $clientdns = gethostbyaddr($iaddr, AF_INET); - Debug("Connected with $clientdns by name"); } else { &logthis("Unable to determine clientip"); $clientip='Unavailable'; @@ -4653,7 +4855,9 @@ sub make_new_child { # my $tmpsnum=0; # Now global #---------------------------------------------------- kerberos 5 initialization &Authen::Krb5::init_context(); - &Authen::Krb5::init_ets(); + if ($dist ne 'fedora4') { + &Authen::Krb5::init_ets(); + } &status('Accepted connection'); # ============================================================================= @@ -4663,18 +4867,23 @@ sub make_new_child { ReadManagerTable; # May also be a manager!! - my $clientrec=($hostid{$clientip} ne undef); - my $ismanager=($managers{$clientip} ne undef); + my $outsideip=$clientip; + if ($clientip eq '127.0.0.1') { + $outsideip=$hostip{$perlvar{'lonHostID'}}; + } + + my $clientrec=($hostid{$outsideip} ne undef); + my $ismanager=($managers{$outsideip} ne undef); $clientname = "[unknonwn]"; if($clientrec) { # Establish client type. $ConnectionType = "client"; - $clientname = $hostid{$clientip}; + $clientname = $hostid{$outsideip}; if($ismanager) { $ConnectionType = "both"; } } else { $ConnectionType = "manager"; - $clientname = $managers{$clientip}; + $clientname = $managers{$outsideip}; } my $clientok; @@ -4858,16 +5067,13 @@ sub is_author { # user - Name of the user for which the role is being put. # authtype - The authentication type associated with the user. # -sub manage_permissions -{ - - +sub manage_permissions { my ($request, $domain, $user, $authtype) = @_; &Debug("manage_permissions: $request $domain $user $authtype"); # See if the request is of the form /$domain/_au - if($request =~ /^(\/$domain\/_au)$/) { # It's an author rolesput... + if($request =~ /^(\/\Q$domain\E\/_au)$/) { # It's an author rolesput... my $execdir = $perlvar{'lonDaemons'}; my $userhome= "/home/$user" ; &logthis("system $execdir/lchtmldir $userhome $user $authtype"); @@ -4887,12 +5093,7 @@ sub manage_permissions # sub password_path { my ($domain, $user) = @_; - - - my $path = &propath($domain, $user); - $path .= "/passwd"; - - return $path; + return &propath($domain, $user).'/passwd'; } # Password Filename @@ -5065,7 +5266,7 @@ sub validate_user { 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, + my $krbreturn = &Authen::Krb5::get_in_tkt_with_password($krbclient, $krbserver, $password, $credentials); @@ -5309,6 +5510,35 @@ sub subscribe { } return $result; } +# Change the passwd of a unix user. The caller must have +# first verified that the user is a loncapa user. +# +# Parameters: +# user - Unix user name to change. +# pass - New password for the user. +# Returns: +# ok - if success +# other - Some meaningfule error message string. +# NOTE: +# invokes a setuid script to change the passwd. +sub change_unix_password { + my ($user, $pass) = @_; + + &Debug("change_unix_password"); + my $execdir=$perlvar{'lonDaemons'}; + &Debug("Opening lcpasswd pipeline"); + my $pf = IO::File->new("|$execdir/lcpasswd > " + ."$perlvar{'lonDaemons'}" + ."/logs/lcpasswd.log"); + print $pf "$user\n$pass\n$pass\n"; + close $pf; + my $err = $?; + return ($err < @passwderrors) ? $passwderrors[$err] : + "pwchange_falure - unknown error"; + + +} + sub make_passwd_file { my ($uname, $umode,$npass,$passfilename)=@_; @@ -5368,24 +5598,30 @@ sub make_passwd_file { print $se "$npass\n"; print $se "$lc_error_file\n"; # Status -> unique file. } - my $error = IO::File->new("< $lc_error_file"); - my $useraddok = <$error>; - $error->close; - unlink($lc_error_file); - - chomp $useraddok; - - if($useraddok > 0) { - my $error_text = &lcuseraddstrerror($useraddok); - &logthis("Failed lcuseradd: $error_text"); - $result = "lcuseradd_failed:$error_text\n"; - } else { - my $pf = IO::File->new(">$passfilename"); - if($pf) { - print $pf "unix:\n"; - } else { - $result = "pass_file_failed_error"; + if (-r $lc_error_file) { + &Debug("Opening error file: $lc_error_file"); + my $error = IO::File->new("< $lc_error_file"); + my $useraddok = <$error>; + $error->close; + unlink($lc_error_file); + + chomp $useraddok; + + if($useraddok > 0) { + my $error_text = &lcuseraddstrerror($useraddok); + &logthis("Failed lcuseradd: $error_text"); + $result = "lcuseradd_failed:$error_text\n"; + } else { + my $pf = IO::File->new(">$passfilename"); + if($pf) { + print $pf "unix:\n"; + } else { + $result = "pass_file_failed_error"; + } } + } else { + &Debug("Could not locate lcuseradd error: $lc_error_file"); + $result="bug_lcuseradd_no_output_file"; } } } elsif ($umode eq 'none') { @@ -5403,6 +5639,11 @@ sub make_passwd_file { return $result; } +sub convert_photo { + my ($start,$dest)=@_; + system("convert $start $dest"); +} + sub sethost { my ($remotereq) = @_; my (undef,$hostid)=split(/:/,$remotereq);