--- loncom/lond 2004/09/14 09:30:07 1.253
+++ loncom/lond 2005/03/03 23:21:51 1.280
@@ -2,7 +2,7 @@
# The LearningOnline Network
# lond "LON Daemon" Server (port "LOND" 5663)
#
-# $Id: lond,v 1.253 2004/09/14 09:30:07 foxr Exp $
+# $Id: lond,v 1.280 2005/03/03 23:21:51 matthew 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.253 $'; #' stupid emacs
+my $VERSION='$Revision: 1.280 $'; #' 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;
@@ -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 {
@@ -1065,6 +1064,50 @@ sub tie_user_hash {
}
+# read_profile
+#
+# Returns a set of specific entries from a user's profile file.
+# this is a utility function that is used by both get_profile_entry and
+# get_profile_entry_encrypted.
+#
+# Parameters:
+# udom - Domain in which the user exists.
+# uname - User's account name (loncapa account)
+# namespace - The profile namespace to open.
+# what - A set of & separated queries.
+# Returns:
+# If all ok: - The string that needs to be shipped back to the user.
+# If failure - A string that starts with error: followed by the failure
+# reason.. note that this probabyl gets shipped back to the
+# user as well.
+#
+sub read_profile {
+ my ($udom, $uname, $namespace, $what) = @_;
+
+ my $hashref = &tie_user_hash($udom, $uname, $namespace,
+ &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.
+ }
+ $qresult=~s/\&$//; # Remove trailing & from last lookup.
+ if (untie %$hashref) {
+ return $qresult;
+ } else {
+ return "error: ".($!+0)." untie (GDBM) Failed";
+ }
+ } else {
+ if ($!+0 == 2) {
+ return "error:No such file or GDBM reported bad block error";
+ } else {
+ return "error: ".($!+0)." tie (GDBM) Failed";
+ }
+ }
+
+}
#--------------------- Request Handlers --------------------------------------------
#
# By convention each request handler registers itself prior to the sub
@@ -1086,7 +1129,6 @@ sub tie_user_hash {
# 0 - Program should exit.
# Side effects:
# Reply information is sent to the client.
-
sub ping_handler {
my ($cmd, $tail, $client) = @_;
Debug("$cmd $tail $client .. $currenthostid:");
@@ -1114,7 +1156,6 @@ sub ping_handler {
# 0 - Program should exit.
# Side effects:
# Reply information is sent to the client.
-
sub pong_handler {
my ($cmd, $tail, $replyfd) = @_;
@@ -1169,7 +1210,6 @@ sub establish_key_handler {
}
®ister_handler("ekey", \&establish_key_handler, 0, 1,1);
-
# Handler for the load command. Returns the current system load average
# to the requestor.
#
@@ -1204,7 +1244,7 @@ sub load_handler {
return 1;
}
-register_handler("load", \&load_handler, 0, 1, 0);
+®ister_handler("load", \&load_handler, 0, 1, 0);
#
# Process the userload request. This sub returns to the client the current
@@ -1234,7 +1274,7 @@ sub user_load_handler {
return 1;
}
-register_handler("userload", \&user_load_handler, 0, 1, 0);
+®ister_handler("userload", \&user_load_handler, 0, 1, 0);
# Process a request for the authorization type of a user:
# (userauth).
@@ -1270,8 +1310,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;
@@ -1291,7 +1333,6 @@ sub user_authorization_type {
# 0 - Program should exit
# Implicit Output:
# a reply is written to the client.
-
sub push_file_handler {
my ($cmd, $tail, $client) = @_;
@@ -1334,7 +1375,6 @@ sub push_file_handler {
# Side Effects:
# The reply is written to $client.
#
-
sub du_handler {
my ($cmd, $ududir, $client) = @_;
my ($ududir) = split(/:/,$ududir); # Make 'telnet' testing easier.
@@ -1368,7 +1408,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
@@ -1386,6 +1428,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";
@@ -1432,8 +1475,71 @@ 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
@@ -1464,7 +1570,6 @@ sub reinit_process_handler {
}
return 1;
}
-
®ister_handler("reinit", \&reinit_process_handler, 1, 0, 1);
# Process the editing script for a table edit operation.
@@ -1506,8 +1611,7 @@ sub edit_table_handler {
}
return 1;
}
-register_handler("edit", \&edit_table_handler, 1, 0, 1);
-
+®ister_handler("edit", \&edit_table_handler, 1, 0, 1);
#
# Authenticate a user against the LonCAPA authentication
@@ -1562,8 +1666,7 @@ sub authenticate_handler {
return 1;
}
-
-register_handler("auth", \&authenticate_handler, 1, 1, 0);
+®ister_handler("auth", \&authenticate_handler, 1, 1, 0);
#
# Change a user's password. Note that this function is complicated by
@@ -1654,8 +1757,7 @@ sub change_password_handler {
return 1;
}
-register_handler("passwd", \&change_password_handler, 1, 1, 0);
-
+®ister_handler("passwd", \&change_password_handler, 1, 1, 0);
#
# Create a new user. User in this case means a lon-capa user.
@@ -1694,18 +1796,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);
@@ -1762,9 +1856,26 @@ sub change_authentication_handler {
chomp($npass);
$npass=&unescape($npass);
+ 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")) ||
+ (($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);
} else {
&Failure($client, "non_authorized\n", $userinput); # Fail the user now.
@@ -1920,21 +2031,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;
@@ -1978,7 +2078,6 @@ sub fetch_user_file_handler {
#
# Returns:
# 1 - Continue processing.
-
sub remove_user_file_handler {
my ($cmd, $tail, $client) = @_;
@@ -2031,7 +2130,6 @@ sub remove_user_file_handler {
#
# Returns:
# 1 - Continue processing.
-
sub mkdir_user_file_handler {
my ($cmd, $tail, $client) = @_;
@@ -2045,17 +2143,11 @@ sub mkdir_user_file_handler {
} else {
my $udir = &propath($udom,$uname);
if (-e $udir) {
- my $newdir=$udir.'/userfiles/'.$ufile;
- if (!-e $newdir) {
- mkdir($newdir);
- 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");
}
@@ -2073,7 +2165,6 @@ sub mkdir_user_file_handler {
#
# Returns:
# 1 - Continue processing.
-
sub rename_user_file_handler {
my ($cmd, $tail, $client) = @_;
@@ -2107,10 +2198,9 @@ sub rename_user_file_handler {
}
®ister_handler("renameuserfile", \&rename_user_file_handler, 0,1,0);
-
#
-# Authenticate access to a user file by checking the user's
-# session token(?)
+# Authenticate access to a user file by checking that the token the user's
+# passed also exists in their session file
#
# Parameters:
# cmd - The request keyword that dispatched to tus.
@@ -2118,7 +2208,6 @@ sub rename_user_file_handler {
# client - Filehandle open on the client.
# Return:
# 1.
-
sub token_auth_user_file_handler {
my ($cmd, $tail, $client) = @_;
@@ -2139,10 +2228,8 @@ sub token_auth_user_file_handler {
return 1;
}
-
®ister_handler("tokenauthuserfile", \&token_auth_user_file_handler, 0,1,0);
-
#
# Unsubscribe from a resource.
#
@@ -2171,6 +2258,7 @@ sub unsubscribe_handler {
return 1;
}
®ister_handler("unsub", \&unsubscribe_handler, 0, 1, 0);
+
# Subscribe to a resource
#
# Parameters:
@@ -2249,7 +2337,7 @@ sub activity_log_handler {
return 1;
}
-register_handler("log", \&activity_log_handler, 0, 1, 0);
+®ister_handler("log", \&activity_log_handler, 0, 1, 0);
#
# Put a namespace entry in a user profile hash.
@@ -2354,7 +2442,6 @@ sub increment_user_value_handler {
}
®ister_handler("inc", \&increment_user_value_handler, 0, 1, 0);
-
#
# Put a new role for a user. Roles are LonCAPA's packaging of permissions.
# Each 'role' a user has implies a set of permissions. Adding a new role
@@ -2394,11 +2481,14 @@ sub roles_put_handler {
# is done on close this improves the chances the log will be an un-
# corrupted ordered thing.
if ($hashref) {
+ my $pass_entry = &get_auth_type($udom, $uname);
+ my ($auth_type,$pwd) = split(/:/, $pass_entry);
+ $auth_type = $auth_type.":";
my @pairs=split(/\&/,$what);
foreach my $pair (@pairs) {
my ($key,$value)=split(/=/,$pair);
&manage_permissions($key, $udom, $uname,
- &get_auth_type( $udom, $uname));
+ $auth_type);
$hashref->{$key}=$value;
}
if (untie($hashref)) {
@@ -2493,32 +2583,17 @@ sub get_profile_entry {
my ($udom,$uname,$namespace,$what) = split(/:/,$tail);
chomp($what);
- my $hashref = &tie_user_hash($udom, $uname, $namespace,
- &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.
- }
- $qresult=~s/\&$//; # Remove trailing & from last lookup.
- if (untie(%$hashref)) {
- &Reply($client, "$qresult\n", $userinput);
- } else {
- &Failure($client, "error: ".($!+0)." untie(GDBM) Failed ".
- "while attempting get\n", $userinput);
- }
+
+ my $replystring = read_profile($udom, $uname, $namespace, $what);
+ my ($first) = split(/:/,$replystring);
+ if($first ne "error") {
+ &Reply($client, "$replystring\n", $userinput);
} else {
- if ($!+0 == 2) { # +0 coerces errno -> number 2 is ENOENT
- &Failure($client, "error:No such file or ".
- "GDBM reported bad block error\n", $userinput);
- } else { # Some other undifferentiated err.
- &Failure($client, "error: ".($!+0)." tie(GDBM) Failed ".
- "while attempting get\n", $userinput);
- }
+ &Failure($client, $replystring." while attempting get\n", $userinput);
}
return 1;
+
+
}
®ister_handler("get", \&get_profile_entry, 0,1,0);
@@ -2548,42 +2623,33 @@ sub get_profile_entry_encrypted {
my ($cmd,$udom,$uname,$namespace,$what) = split(/:/,$userinput);
chomp($what);
- my $hashref = &tie_user_hash($udom, $uname, $namespace,
- &GDBM_READER());
- if ($hashref) {
- my @queries=split(/\&/,$what);
- my $qresult='';
- for (my $i=0;$i<=$#queries;$i++) {
- $qresult.="$hashref->{$queries[$i]}&";
- }
- if (untie(%$hashref)) {
- $qresult=~s/\&$//;
- if ($cipher) {
- my $cmdlength=length($qresult);
- $qresult.=" ";
- my $encqresult='';
- for(my $encidx=0;$encidx<=$cmdlength;$encidx+=8) {
- $encqresult.= unpack("H16",
- $cipher->encrypt(substr($qresult,
- $encidx,
- 8)));
- }
- &Reply( $client, "enc:$cmdlength:$encqresult\n", $userinput);
- } else {
- &Failure( $client, "error:no_key\n", $userinput);
+ my $qresult = read_profile($udom, $uname, $namespace, $what);
+ my ($first) = split(/:/, $qresult);
+ if($first ne "error") {
+
+ if ($cipher) {
+ my $cmdlength=length($qresult);
+ $qresult.=" ";
+ my $encqresult='';
+ for(my $encidx=0;$encidx<=$cmdlength;$encidx+=8) {
+ $encqresult.= unpack("H16",
+ $cipher->encrypt(substr($qresult,
+ $encidx,
+ 8)));
}
+ &Reply( $client, "enc:$cmdlength:$encqresult\n", $userinput);
} else {
- &Failure($client, "error: ".($!+0)." untie(GDBM) Failed ".
- "while attempting eget\n", $userinput);
- }
+ &Failure( $client, "error:no_key\n", $userinput);
+ }
} else {
- &Failure($client, "error: ".($!+0)." tie(GDBM) Failed ".
- "while attempting eget\n", $userinput);
+ &Failure($client, "$qresult while attempting eget\n", $userinput);
+
}
return 1;
}
-®ister_handler("eget", \&GetProfileEntryEncrypted, 0, 1, 0);
+®ister_handler("eget", \&get_profile_entry_encrypted, 0, 1, 0);
+
#
# Deletes a key in a user profile database.
#
@@ -2602,7 +2668,6 @@ sub get_profile_entry_encrypted {
# 0 - Exit server.
#
#
-
sub delete_profile_entry {
my ($cmd, $tail, $client) = @_;
@@ -2631,6 +2696,7 @@ sub delete_profile_entry {
return 1;
}
®ister_handler("del", \&delete_profile_entry, 0, 1, 0);
+
#
# List the set of keys that are defined in a profile database file.
# A successful reply from this will contain an & separated list of
@@ -2809,7 +2875,6 @@ sub dump_with_regexp {
return 1;
}
-
®ister_handler("dump", \&dump_with_regexp, 0, 1, 0);
# Store a set of key=value pairs associated with a versioned name.
@@ -2841,7 +2906,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;
@@ -2875,6 +2940,7 @@ sub store_handler {
return 1;
}
®ister_handler("store", \&store_handler, 0, 1, 0);
+
#
# Dump out all versions of a resource that has key=value pairs associated
# with it for each version. These resources are built up via the store
@@ -2975,6 +3041,7 @@ sub send_chat_handler {
return 1;
}
®ister_handler("chatsend", \&send_chat_handler, 0, 1, 0);
+
#
# Retrieve the set of chat messagss from a discussion board.
#
@@ -3110,6 +3177,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
@@ -3123,7 +3198,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);
@@ -3131,8 +3206,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);
@@ -3170,6 +3261,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.
@@ -3180,32 +3280,55 @@ sub dump_course_id_handler {
my $userinput = "$cmd:$tail";
- my ($udom,$since,$description) =split(/:/,$tail);
+ my ($udom,$since,$description,$instcodefilter,$ownerfilter) =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='.';
+ }
+
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;
+ }
+ }
+ if ($match == 1) {
+ $qresult.=$key.'='.$descr.':'.$inst_code.':'.$owner.'&';
+ }
}
if (untie(%$hashref)) {
chop($qresult);
@@ -3269,8 +3392,8 @@ sub put_id_handler {
return 1;
}
-
®ister_handler("idput", \&put_id_handler, 0, 1, 0);
+
#
# Retrieves a set of id values from the id database.
# Returns an & separated list of results, one for each requested id to the
@@ -3319,8 +3442,7 @@ sub get_id_handler {
return 1;
}
-
-register_handler("idget", \&get_id_handler, 0, 1, 0);
+®ister_handler("idget", \&get_id_handler, 0, 1, 0);
#
# Process the tmpput command I'm not sure what this does.. Seems to
@@ -3363,6 +3485,7 @@ sub tmp_put_handler {
}
®ister_handler("tmpput", \&tmp_put_handler, 0, 1, 0);
+
# Processes the tmpget command. This command returns the contents
# of a temporary resource file(?) created via tmpput.
#
@@ -3375,7 +3498,6 @@ sub tmp_put_handler {
# 1 - Inidcating processing can continue.
# Side effects:
# A reply is sent to the client.
-
#
sub tmp_get_handler {
my ($cmd, $id, $client) = @_;
@@ -3398,6 +3520,7 @@ sub tmp_get_handler {
return 1;
}
®ister_handler("tmpget", \&tmp_get_handler, 0, 1, 0);
+
#
# Process the tmpdel command. This command deletes a temp resource
# created by the tmpput command.
@@ -3431,6 +3554,7 @@ sub tmp_del_handler {
}
®ister_handler("tmpdel", \&tmp_del_handler, 0, 1, 0);
+
#
# Processes the setannounce command. This command
# creates a file named announce.txt in the top directory of
@@ -3469,6 +3593,7 @@ sub set_announce_handler {
return 1;
}
®ister_handler("setannounce", \&set_announce_handler, 0, 1, 0);
+
#
# Return the version of the daemon. This can be used to determine
# the compatibility of cross version installations or, alternatively to
@@ -3493,6 +3618,7 @@ sub get_version_handler {
return 1;
}
®ister_handler("version", \&get_version_handler, 0, 1, 0);
+
# Set the current host and domain. This is used to support
# multihomed systems. Each IP of the system, or even separate daemons
# on the same IP can be treated as handling a separate lonCAPA virtual
@@ -3629,6 +3755,7 @@ sub validate_course_owner_handler {
return 1;
}
®ister_handler("autonewcourse", \&validate_course_owner_handler, 0, 1, 0);
+
#
# Validate a course section in the official schedule of classes
# from the institutions point of view (part of autoenrollment).
@@ -3709,7 +3836,6 @@ sub create_auto_enroll_password_handler
#
# Returns:
# 1 - Continue processing.
-
sub retrieve_auto_file_handler {
my ($cmd, $tail, $client) = @_;
my $userinput = "cmd:$tail";
@@ -3794,20 +3920,67 @@ 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:
#
-
#
# Get a Request:
# Gets a Request message from the client. The transaction
@@ -3914,114 +4087,7 @@ sub process_request {
}
-#------------------- Commands not yet in spearate handlers. --------------
-
-#------------------------------- is auto-enrollment enabled?
- if ($userinput =~/^autorun/) {
- if (isClient) {
- my ($cmd,$cdom) = split(/:/,$userinput);
- my $outcome = &localenroll::run($cdom);
- print $client "$outcome\n";
- } else {
- print $client "0\n";
- }
-#------------------------------- get official sections (for auto-enrollment).
- } elsif ($userinput =~/^autogetsections/) {
- if (isClient) {
- my ($cmd,$coursecode,$cdom)=split(/:/,$userinput);
- my @secs = &localenroll::get_sections($coursecode,$cdom);
- my $seclist = &escape(join(':',@secs));
- print $client "$seclist\n";
- } else {
- print $client "refused\n";
- }
-#----------------------- validate owner of new course section (for auto-enrollment).
- } elsif ($userinput =~/^autonewcourse/) {
- if (isClient) {
- my ($cmd,$inst_course_id,$owner,$cdom)=split(/:/,$userinput);
- my $outcome = &localenroll::new_course($inst_course_id,$owner,$cdom);
- print $client "$outcome\n";
- } else {
- print $client "refused\n";
- }
-#-------------- validate course section in schedule of classes (for auto-enrollment).
- } elsif ($userinput =~/^autovalidatecourse/) {
- if (isClient) {
- my ($cmd,$inst_course_id,$cdom)=split(/:/,$userinput);
- my $outcome=&localenroll::validate_courseID($inst_course_id,$cdom);
- print $client "$outcome\n";
- } else {
- print $client "refused\n";
- }
-#--------------------------- create password for new user (for auto-enrollment).
- } elsif ($userinput =~/^autocreatepassword/) {
- if (isClient) {
- my ($cmd,$authparam,$cdom)=split(/:/,$userinput);
- my ($create_passwd,$authchk);
- ($authparam,$create_passwd,$authchk) = &localenroll::create_password($authparam,$cdom);
- print $client &escape($authparam.':'.$create_passwd.':'.$authchk)."\n";
- } else {
- print $client "refused\n";
- }
-#--------------------------- read and remove temporary files (for auto-enrollment).
- } elsif ($userinput =~/^autoretrieve/) {
- if (isClient) {
- my ($cmd,$filename) = split(/:/,$userinput);
- my $source = $perlvar{'lonDaemons'}.'/tmp/'.$filename;
- if ( (-e $source) && ($filename ne '') ) {
- my $reply = '';
- if (open(my $fh,$source)) {
- while (<$fh>) {
- chomp($_);
- $_ =~ s/^\s+//g;
- $_ =~ s/\s+$//g;
- $reply .= $_;
- }
- close($fh);
- print $client &escape($reply)."\n";
-# unlink($source);
- } else {
- print $client "error\n";
- }
- } else {
- print $client "error\n";
- }
- } else {
- print $client "refused\n";
- }
-#--------------------- read and retrieve institutional code format
-# (for support form).
- } elsif ($userinput =~/^autoinstcodeformat/) {
- if (isClient) {
- my $reply;
- my($cmd,$cdom,$course) = split(/:/,$userinput);
- my @pairs = split/\&/,$course;
- my %instcodes = ();
- my %codes = ();
- my @codetitles = ();
- my %cat_titles = ();
- my %cat_order = ();
- foreach (@pairs) {
- my ($key,$value) = split/=/,$_;
- $instcodes{&unescape($key)} = &unescape($value);
- }
- my $formatreply = &localenroll::instcode_format($cdom,\%instcodes,\%codes,\@codetitles,\%cat_titles,\%cat_order);
- if ($formatreply eq 'ok') {
- my $codes_str = &hash2str(%codes);
- my $codetitles_str = &array2str(@codetitles);
- my $cat_titles_str = &hash2str(%cat_titles);
- my $cat_order_str = &hash2str(%cat_order);
- print $client $codes_str.':'.$codetitles_str.':'.$cat_titles_str.':'.$cat_order_str."\n";
- }
- } else {
- print $client "refused\n";
- }
-# ------------------------------------------------------------- unknown command
-
- } else {
- # unknown command
- print $client "unknown_cmd\n";
- }
+ print $client "unknown_cmd\n";
# -------------------------------------------------------------------- complete
Debug("process_request - returning 1");
return 1;
@@ -4283,12 +4349,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'}) {
@@ -4469,7 +4541,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");
@@ -4700,8 +4772,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';
@@ -4741,18 +4811,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;
@@ -4896,8 +4971,35 @@ sub make_new_child {
exit;
}
+#
+# Determine if a user is an author for the indicated domain.
+#
+# Parameters:
+# domain - domain to check in .
+# user - Name of user to check.
+#
+# Return:
+# 1 - User is an author for domain.
+# 0 - User is not an author for domain.
+sub is_author {
+ my ($domain, $user) = @_;
+
+ &Debug("is_author: $user @ $domain");
+
+ my $hashref = &tie_user_hash($domain, $user, "roles",
+ &GDBM_READER());
+
+ # Author role should show up as a key /domain/_au
+ my $key = "/$domain/_au";
+ my $value = $hashref->{$key};
+
+ if(defined($value)) {
+ &Debug("$user @ $domain is an author");
+ }
+ return defined($value);
+}
#
# Checks to see if the input roleput request was to set
# an author role. If so, invokes the lchtmldir script to set
@@ -4912,13 +5014,17 @@ sub make_new_child {
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...
my $execdir = $perlvar{'lonDaemons'};
my $userhome= "/home/$user" ;
&logthis("system $execdir/lchtmldir $userhome $user $authtype");
+ &Debug("Setting homedir permissions for $userhome");
system("$execdir/lchtmldir $userhome $user $authtype");
}
}
@@ -4934,12 +5040,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
@@ -5014,12 +5115,7 @@ sub get_auth_type
Debug("Password info = $realpassword\n");
my ($authtype, $contentpwd) = split(/:/, $realpassword);
Debug("Authtype = $authtype, content = $contentpwd\n");
- my $availinfo = '';
- if($authtype eq 'krb4' or $authtype eq 'krb5') {
- $availinfo = $contentpwd;
- }
-
- return "$authtype:$availinfo";
+ return "$authtype:$contentpwd";
} else {
Debug("Returning nouser");
return "nouser";
@@ -5117,7 +5213,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);
@@ -5368,7 +5464,11 @@ sub make_passwd_file {
if ($umode eq 'krb4' or $umode eq 'krb5') {
{
my $pf = IO::File->new(">$passfilename");
- print $pf "$umode:$npass\n";
+ if ($pf) {
+ print $pf "$umode:$npass\n";
+ } else {
+ $result = "pass_file_failed_error";
+ }
}
} elsif ($umode eq 'internal') {
my $salt=time;
@@ -5377,12 +5477,20 @@ sub make_passwd_file {
{
&Debug("Creating internal auth");
my $pf = IO::File->new(">$passfilename");
- print $pf "internal:$ncpass\n";
+ if($pf) {
+ print $pf "internal:$ncpass\n";
+ } else {
+ $result = "pass_file_failed_error";
+ }
}
} elsif ($umode eq 'localauth') {
{
my $pf = IO::File->new(">$passfilename");
- print $pf "localauth:$npass\n";
+ if($pf) {
+ print $pf "localauth:$npass\n";
+ } else {
+ $result = "pass_file_failed_error";
+ }
}
} elsif ($umode eq 'unix') {
{
@@ -5421,13 +5529,21 @@ sub make_passwd_file {
$result = "lcuseradd_failed:$error_text\n";
} else {
my $pf = IO::File->new(">$passfilename");
- print $pf "unix:\n";
+ if($pf) {
+ print $pf "unix:\n";
+ } else {
+ $result = "pass_file_failed_error";
+ }
}
}
} elsif ($umode eq 'none') {
{
my $pf = IO::File->new("> $passfilename");
- print $pf "none:\n";
+ if($pf) {
+ print $pf "none:\n";
+ } else {
+ $result = "pass_file_failed_error";
+ }
}
} else {
$result="auth_mode_error\n";
@@ -5435,6 +5551,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);