--- 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);