--- loncom/lond 2024/12/29 16:44:03 1.489.2.47 +++ loncom/lond 2018/12/03 13:20:21 1.553 @@ -2,7 +2,7 @@ # The LearningOnline Network # lond "LON Daemon" Server (port "LOND" 5663) # -# $Id: lond,v 1.489.2.47 2024/12/29 16:44:03 raeburn Exp $ +# $Id: lond,v 1.553 2018/12/03 13:20:21 raeburn Exp $ # # Copyright Michigan State University Board of Trustees # @@ -35,12 +35,13 @@ use LONCAPA; use LONCAPA::Configuration; use LONCAPA::Lond; +use Socket; use IO::Socket; use IO::File; #use Apache::File; use POSIX; use Crypt::IDEA; -use LWP::UserAgent(); +use HTTP::Request; use Digest::MD5 qw(md5_hex); use GDBM_File; use Authen::Krb5; @@ -57,13 +58,14 @@ use Mail::Send; use Crypt::Eksblowfish::Bcrypt; use Digest::SHA; use Encode; +use LONCAPA::LWPReq; my $DEBUG = 0; # Non zero to enable debug log entries. my $status=''; my $lastlog=''; -my $VERSION='$Revision: 1.489.2.47 $'; #' stupid emacs +my $VERSION='$Revision: 1.553 $'; #' stupid emacs my $remoteVERSION; my $currenthostid="default"; my $currentdomainid; @@ -73,8 +75,16 @@ my $clientip; # IP address of client. my $clientname; # LonCAPA name of client. my $clientversion; # LonCAPA version running on client. my $clienthomedom; # LonCAPA domain of homeID for client. - # primary library server. - +my $clientintdom; # LonCAPA "internet domain" for client. +my $clientsamedom; # LonCAPA domain same for this host + # and client. +my $clientsameinst; # LonCAPA "internet domain" same for + # this host and client. +my $clientremoteok; # Client allowed to host domain's users. + # (version constraints ignored), not set + # if this host and client share "internet domain". +my %clientprohibited; # Actions prohibited on client; + my $server; my $keymode; @@ -95,6 +105,13 @@ my %managers; # Ip -> manager names my %perlvar; # Will have the apache conf defined perl vars. +my %secureconf; # Will have requirements for security + # of lond connections + +my %crlchecked; # Will contain clients for which the client's SSL + # has been checked against the cluster's Certificate + # Revocation List. + my $dist; # @@ -144,6 +161,159 @@ my @installerrors = ("ok", ); # +# The %trust hash classifies commands according to type of trust +# required for execution of the command. +# +# When clients from a different institution request execution of a +# particular command, the trust settings for that institution set +# for this domain (or default domain for a multi-domain server) will +# be checked to see if running the command is allowed. +# +# Trust types which depend on the "Trust" domain configuration +# for the machine's default domain are: +# +# content ("Access to this domain's content by others") +# shared ("Access to other domain's content by this domain") +# enroll ("Enrollment in this domain's courses by others") +# coaurem ("Co-author roles for this domain's users elsewhere") +# othcoau ("Co-author roles in this domain for others") +# domroles ("Domain roles in this domain assignable to others") +# catalog ("Course Catalog for this domain displayed elsewhere") +# reqcrs ("Requests for creation of courses in this domain by others") +# msg ("Users in other domains can send messages to this domain") +# +# Trust type which depends on the User Session Hosting (remote) +# domain configuration for machine's default domain is: "remote". +# +# Trust types which depend on contents of manager.tab in +# /home/httpd/lonTabs is: "manageronly". +# +# Trust type which requires client to share the same LON-CAPA +# "internet domain" (i.e., same institution as this server) is: +# "institutiononly". +# + +my %trust = ( + auth => {remote => 1}, + autocreatepassword => {remote => 1}, + autocrsreqchecks => {remote => 1, reqcrs => 1}, + autocrsrequpdate => {remote => 1}, + autocrsreqvalidation => {remote => 1}, + autogetsections => {remote => 1}, + autoinstcodedefaults => {remote => 1, catalog => 1}, + autoinstcodeformat => {remote => 1, catalog => 1}, + autonewcourse => {remote => 1, reqcrs => 1}, + autophotocheck => {remote => 1, enroll => 1}, + autophotochoice => {remote => 1}, + autophotopermission => {remote => 1, enroll => 1}, + autopossibleinstcodes => {remote => 1, reqcrs => 1}, + autoretrieve => {remote => 1, enroll => 1, catalog => 1}, + autorun => {remote => 1, enroll => 1, reqcrs => 1}, + autovalidateclass_sec => {catalog => 1}, + autovalidatecourse => {remote => 1, enroll => 1}, + autovalidateinstcode => {domroles => 1, remote => 1, enroll => 1}, + changeuserauth => {remote => 1, domroles => 1}, + chatretr => {remote => 1, enroll => 1}, + chatsend => {remote => 1, enroll => 1}, + courseiddump => {remote => 1, domroles => 1, enroll => 1}, + courseidput => {remote => 1, domroles => 1, enroll => 1}, + courseidputhash => {remote => 1, domroles => 1, enroll => 1}, + courselastaccess => {remote => 1, domroles => 1, enroll => 1}, + currentauth => {remote => 1, domroles => 1, enroll => 1}, + currentdump => {remote => 1, enroll => 1}, + currentversion => {remote=> 1, content => 1}, + dcmaildump => {remote => 1, domroles => 1}, + dcmailput => {remote => 1, domroles => 1}, + del => {remote => 1, domroles => 1, enroll => 1, content => 1}, + delbalcookie => {institutiononly => 1}, + deldom => {remote => 1, domroles => 1}, # not currently used + devalidatecache => {institutiononly => 1}, + domroleput => {remote => 1, enroll => 1}, + domrolesdump => {remote => 1, catalog => 1}, + du => {remote => 1, enroll => 1}, + du2 => {remote => 1, enroll => 1}, + dump => {remote => 1, enroll => 1, domroles => 1}, + edit => {institutiononly => 1}, #not used currently + eget => {remote => 1, domroles => 1, enroll => 1}, #not used currently + egetdom => {remote => 1, domroles => 1, enroll => 1, }, + ekey => {anywhere => 1}, + exit => {anywhere => 1}, + fetchuserfile => {remote => 1, enroll => 1}, + get => {remote => 1, domroles => 1, enroll => 1}, + getdom => {anywhere => 1}, + home => {anywhere => 1}, + iddel => {remote => 1, enroll => 1}, + idget => {remote => 1, enroll => 1}, + idput => {remote => 1, domroles => 1, enroll => 1}, + inc => {remote => 1, enroll => 1}, + init => {anywhere => 1}, + inst_usertypes => {remote => 1, domroles => 1, enroll => 1}, + instemailrules => {remote => 1, domroles => 1}, + instidrulecheck => {remote => 1, domroles => 1,}, + instidrules => {remote => 1, domroles => 1,}, + instrulecheck => {remote => 1, enroll => 1, reqcrs => 1, domroles => 1}, + instselfcreatecheck => {institutiononly => 1}, + instuserrules => {remote => 1, enroll => 1, reqcrs => 1, domroles => 1}, + keys => {remote => 1,}, + load => {anywhere => 1}, + log => {anywhere => 1}, + ls => {remote => 1, enroll => 1, content => 1,}, + ls2 => {remote => 1, enroll => 1, content => 1,}, + ls3 => {remote => 1, enroll => 1, content => 1,}, + makeuser => {remote => 1, enroll => 1, domroles => 1,}, + mkdiruserfile => {remote => 1, enroll => 1,}, + newput => {remote => 1, enroll => 1, reqcrs => 1, domroles => 1,}, + passwd => {remote => 1}, + ping => {anywhere => 1}, + pong => {anywhere => 1}, + pushfile => {manageronly => 1}, + put => {remote => 1, enroll => 1, domroles => 1, msg => 1, content => 1, shared => 1}, + putdom => {remote => 1, domroles => 1,}, + putstore => {remote => 1, enroll => 1}, + queryreply => {anywhere => 1}, + querysend => {anywhere => 1}, + querysend_activitylog => {remote => 1}, + querysend_allusers => {remote => 1, domroles => 1}, + querysend_courselog => {remote => 1}, + querysend_fetchenrollment => {remote => 1}, + querysend_getinstuser => {remote => 1}, + querysend_getmultinstusers => {remote => 1}, + querysend_instdirsearch => {remote => 1, domroles => 1, coaurem => 1}, + querysend_institutionalphotos => {remote => 1}, + querysend_portfolio_metadata => {remote => 1, content => 1}, + querysend_userlog => {remote => 1, domroles => 1}, + querysend_usersearch => {remote => 1, enroll => 1, coaurem => 1}, + quit => {anywhere => 1}, + readlonnetglobal => {institutiononly => 1}, + reinit => {manageronly => 1}, #not used currently + removeuserfile => {remote => 1, enroll => 1}, + renameuserfile => {remote => 1,}, + restore => {remote => 1, enroll => 1, reqcrs => 1,}, + rolesdel => {remote => 1, enroll => 1, domroles => 1, coaurem => 1}, + rolesput => {remote => 1, enroll => 1, domroles => 1, coaurem => 1}, + servercerts => {institutiononly => 1}, + serverdistarch => {anywhere => 1}, + serverhomeID => {anywhere => 1}, + serverloncaparev => {anywhere => 1}, + servertimezone => {remote => 1, enroll => 1}, + setannounce => {remote => 1, domroles => 1}, + sethost => {anywhere => 1}, + store => {remote => 1, enroll => 1, reqcrs => 1,}, + studentphoto => {remote => 1, enroll => 1}, + sub => {content => 1,}, + tmpdel => {institutiononly => 1}, + tmpget => {institutiononly => 1}, + tmpput => {remote => 1, othcoau => 1}, + tokenauthuserfile => {anywhere => 1}, + unsub => {content => 1,}, + update => {shared => 1}, + updateclickers => {remote => 1}, + userhassession => {anywhere => 1}, + userload => {anywhere => 1}, + version => {anywhere => 1}, #not used + ); + +# # Statistics that are maintained and dislayed in the status line. # my $Transactions = 0; # Number of attempted transactions. @@ -256,10 +426,19 @@ sub SSLConnection { Debug("Approving promotion -> ssl"); # And do so: + my $CRLFile; + unless ($crlchecked{$clientname}) { + $CRLFile = lonssl::CRLFile(); + $crlchecked{$clientname} = 1; + } + my $SSLSocket = lonssl::PromoteServerSocket($Socket, $CACertificate, $Certificate, - $KeyFile); + $KeyFile, + $clientname, + $CRLFile, + $clientversion); if(! ($SSLSocket) ) { # SSL socket promotion failed. my $err = lonssl::LastError(); &logthis("<font color=\"red\"> CRITICAL " @@ -299,8 +478,23 @@ sub InsecureConnection { my $Socket = shift; # Don't even start if insecure connections are not allowed. - - if(! $perlvar{londAllowInsecure}) { # Insecure connections not allowed. + # return 0 if Insecure connections not allowed. + # + if (ref($secureconf{'connfrom'}) eq 'HASH') { + if ($clientsamedom) { + if ($secureconf{'connfrom'}{'dom'} eq 'req') { + return 0; + } + } elsif ($clientsameinst) { + if ($secureconf{'connfrom'}{'intdom'} eq 'req') { + return 0; + } + } else { + if ($secureconf{'connfrom'}{'other'} eq 'req') { + return 0; + } + } + } elsif (!$perlvar{londAllowInsecure}) { return 0; } @@ -600,10 +794,17 @@ sub ConfigFileFromSelector { my $selector = shift; my $tablefile; - my $tabledir = $perlvar{'lonTabDir'}.'/'; - if (($selector eq "hosts") || ($selector eq "domain") || - ($selector eq "dns_hosts") || ($selector eq "dns_domain")) { - $tablefile = $tabledir.$selector.'.tab'; + if ($selector eq 'loncapaCAcrl') { + my $tabledir = $perlvar{'lonCertificateDirectory'}; + if (-d $tabledir) { + $tablefile = $tabledir.'/'.$selector.'.pem'; + } + } else { + my $tabledir = $perlvar{'lonTabDir'}.'/'; + if (($selector eq "hosts") || ($selector eq "domain") || + ($selector eq "dns_hosts") || ($selector eq "dns_domain")) { + $tablefile = $tabledir.$selector.'.tab'; + } } return $tablefile; } @@ -627,12 +828,13 @@ sub PushFile { my ($command, $filename, $contents) = split(":", $request, 3); &Debug("PushFile"); - # At this point in time, pushes for only the following tables are - # supported: + # At this point in time, pushes for only the following tables and + # CRL file are supported: # hosts.tab ($filename eq host). # domain.tab ($filename eq domain). # dns_hosts.tab ($filename eq dns_host). # dns_domain.tab ($filename eq dns_domain). + # loncapaCAcrl.pem ($filename eq loncapaCAcrl); # Construct the destination filename or reject the request. # # lonManage is supposed to ensure this, however this session could be @@ -653,7 +855,8 @@ sub PushFile { if($filename eq "host") { $contents = AdjustHostContents($contents); - } elsif ($filename eq 'dns_host' || $filename eq 'dns_domain') { + } elsif (($filename eq 'dns_host') || ($filename eq 'dns_domain') || + ($filename eq 'loncapaCAcrl')) { if ($contents eq '') { &logthis('<font color="red"> Pushfile: unable to install ' .$tablefile." - no data received from push. </font>"); @@ -664,12 +867,15 @@ sub PushFile { if ($managers{$clientip} eq $clientname) { my $clientprotocol = $Apache::lonnet::protocol{$clientname}; $clientprotocol = 'http' if ($clientprotocol ne 'https'); - my $url = '/adm/'.$filename; - $url =~ s{_}{/}; - my $ua=new LWP::UserAgent; - $ua->timeout(60); + my $url; + if ($filename eq 'loncapaCAcrl') { + $url = '/adm/dns/loncapaCRL'; + } else { + $url = '/adm/'.$filename; + $url =~ s{_}{/}; + } my $request=new HTTP::Request('GET',"$clientprotocol://$clienthost$url"); - my $response=$ua->request($request); + my $response = LONCAPA::LWPReq::makerequest($clientname,$request,'',\%perlvar,60,0); if ($response->is_error()) { &logthis('<font color="red"> Pushfile: unable to install ' .$tablefile." - error attempting to pull data. </font>"); @@ -1496,7 +1702,7 @@ sub ls_handler { } } else { unless (($ulsdir =~ m{^/home/httpd/lonUsers/$LONCAPA::match_domain(?:/[\w\-.@]){3}/$LONCAPA::match_name/}) || - ($ulsdir =~ m{^/home/httpd/html/(?:res|userfiles)/$LONCAPA::match_domain/$LONCAPA::match_name/})) { + ($ulsdir =~ m{^/home/httpd/html/(?:res|userfiles)/$LONCAPA::match_domain/$LONCAPA::match_name/})) { &Failure($client,"refused\n",$userinput); return 1; } @@ -1705,6 +1911,14 @@ sub ls3_handler { my $rights; my $ulsout=''; my $ulsfn; + + my ($crscheck,$toplevel,$currdom,$currnum,$skip); + unless ($islocal) { + my ($major,$minor) = split(/\./,$clientversion); + if (($major < 2) || ($major == 2 && $minor < 12)) { + $crscheck = 1; + } + } if (-e $ulsdir) { if(-d $ulsdir) { unless (($getpropath) || ($getuserdir) || @@ -1714,8 +1928,26 @@ sub ls3_handler { &Failure($client,"refused\n",$userinput); return 1; } - if (opendir(LSDIR,$ulsdir)) { + if (($crscheck) && + ($ulsdir =~ m{^/home/httpd/html/res/($LONCAPA::match_domain)(/?$|/$LONCAPA::match_courseid)})) { + ($currdom,my $posscnum) = ($1,$2); + if (($posscnum eq '') || ($posscnum eq '/')) { + $toplevel = 1; + } else { + $posscnum =~ s{^/+}{}; + if (&LONCAPA::Lond::is_course($currdom,$posscnum)) { + $skip = 1; + } + } + } + if ((!$skip) && (opendir(LSDIR,$ulsdir))) { while ($ulsfn=readdir(LSDIR)) { + if (($crscheck) && ($toplevel) && ($currdom ne '') && + ($ulsfn =~ /^$LONCAPA::match_courseid$/) && (-d "$ulsdir/$ulsfn")) { + if (&LONCAPA::Lond::is_course($currdom,$ulsfn)) { + next; + } + } undef($obs); undef($rights); my @ulsstats=stat($ulsdir.'/'.$ulsfn); @@ -1768,15 +2000,17 @@ sub read_lonnet_global { ); my %limit_to = ( perlvar => { - lonOtherAuthen => 1, - lonBalancer => 1, - lonVersion => 1, - lonSysEMail => 1, - lonHostID => 1, - lonRole => 1, - lonDefDomain => 1, - lonLoadLim => 1, - lonUserLoadLim => 1, + lonOtherAuthen => 1, + lonBalancer => 1, + lonVersion => 1, + lonAdmEMail => 1, + lonSupportEMail => 1, + lonSysEMail => 1, + lonHostID => 1, + lonRole => 1, + lonDefDomain => 1, + lonLoadLim => 1, + lonUserLoadLim => 1, } ); if (ref($requested) eq 'HASH') { @@ -1795,7 +2029,7 @@ sub read_lonnet_global { } if ($what eq 'perlvar') { if (!exists($packagevars{$what}{'lonBalancer'})) { - if ($dist =~ /^(centos|rhes|fedora|scientific|oracle|rocky|alma)/) { + if ($dist =~ /^(centos|rhes|fedora|scientific)/) { my $othervarref=LONCAPA::Configuration::read_conf('httpd.conf'); if (ref($othervarref) eq 'HASH') { $items->{'lonBalancer'} = $othervarref->{'lonBalancer'}; @@ -1888,6 +2122,16 @@ sub server_distarch_handler { } ®ister_handler("serverdistarch", \&server_distarch_handler, 0, 1, 0); +sub server_certs_handler { + my ($cmd,$tail,$client) = @_; + my $userinput = "$cmd:$tail"; + my $hostname = &Apache::lonnet::hostname($perlvar{'lonHostID'}); + my $result = &LONCAPA::Lond::server_certs(\%perlvar,$perlvar{'lonHostID'},$hostname); + &Reply($client,\$result,$userinput); + return; +} +®ister_handler("servercerts", \&server_certs_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. @@ -2026,12 +2270,8 @@ sub authenticate_handler { if (ref($hostedsession) eq 'HASH') { $hosted = $hostedsession->{'hosted'}; } - my $loncaparev = $clientversion; - if ($loncaparev eq '') { - $loncaparev = $Apache::lonnet::loncaparevs{$clientname}; - } $canhost = &Apache::lonnet::can_host_session($udom,$clientname, - $loncaparev, + $clientversion, $remote,$hosted); } } @@ -2107,84 +2347,12 @@ sub change_password_handler { } if($validated) { my $realpasswd = &get_auth_type($udom, $uname); # Defined since authd. + my ($howpwd,$contentpwd)=split(/:/,$realpasswd); - my $notunique; if ($howpwd eq 'internal') { &Debug("internal auth"); my $ncpass = &hash_passwd($udom,$npass); - my (undef,$method,@rest) = split(/!/,$contentpwd); - if ($method eq 'bcrypt') { - my %passwdconf = &Apache::lonnet::get_passwdconf($udom); - if (($passwdconf{'numsaved'}) && ($passwdconf{'numsaved'} =~ /^\d+$/)) { - my @oldpasswds; - my $userpath = &propath($udom,$uname); - my $fullpath = $userpath.'/oldpasswds'; - if (-d $userpath) { - my @oldfiles; - if (-e $fullpath) { - if (opendir(my $dir,$fullpath)) { - (@oldfiles) = grep(/^\d+$/,readdir($dir)); - closedir($dir); - } - if (@oldfiles) { - @oldfiles = sort { $b <=> $a } (@oldfiles); - my $numremoved = 0; - for (my $i=0; $i<@oldfiles; $i++) { - if ($i>=$passwdconf{'numsaved'}) { - if (-f "$fullpath/$oldfiles[$i]") { - if (unlink("$fullpath/$oldfiles[$i]")) { - $numremoved ++; - } - } - } elsif (open(my $fh,'<',"$fullpath/$oldfiles[$i]")) { - while (my $line = <$fh>) { - push(@oldpasswds,$line); - } - close($fh); - } - } - if ($numremoved) { - &logthis("unlinked $numremoved old password files for $uname:$udom"); - } - } - } - push(@oldpasswds,$contentpwd); - foreach my $item (@oldpasswds) { - my (undef,$method,@rest) = split(/!/,$item); - if ($method eq 'bcrypt') { - my $result = &hash_passwd($udom,$npass,@rest); - if ($result eq $item) { - $notunique = 1; - last; - } - } - } - unless ($notunique) { - unless (-e $fullpath) { - if (&mkpath("$fullpath/")) { - chmod(0700,$fullpath); - } - } - if (-d $fullpath) { - my $now = time; - if (open(my $fh,'>',"$fullpath/$now")) { - print $fh $contentpwd; - close($fh); - chmod(0400,"$fullpath/$now"); - } - } - } - } - } - } - if ($notunique) { - my $msg="Result of password change for $uname:$udom - password matches one used before"; - if ($lonhost) { - $msg .= " - request originated from: $lonhost"; - } - &logthis($msg); - &Reply($client, "prioruse\n", $userinput); - } elsif (&rewrite_password_file($udom, $uname, "internal:$ncpass")) { + if(&rewrite_password_file($udom, $uname, "internal:$ncpass")) { my $msg="Result of password change for $uname: pwchange_success"; if ($lonhost) { $msg .= " - request originated from: $lonhost"; @@ -2201,7 +2369,7 @@ sub change_password_handler { my $result = &change_unix_password($uname, $npass); if ($result eq 'ok') { &update_passwd_history($uname,$udom,$howpwd,$context); - } + } &logthis("Result of password change for $uname: ". $result); &Reply($client, \$result, $userinput); @@ -2212,6 +2380,7 @@ sub change_password_handler { # &Failure( $client, "auth_mode_error\n", $userinput); } + } else { if ($failure eq '') { $failure = 'non_authorized'; @@ -2368,7 +2537,7 @@ sub change_authentication_handler { my $result = &change_unix_password($uname, $npass); &logthis("Result of password change for $uname: ".$result); if ($result eq "ok") { - &update_passwd_history($uname,$udom,$umode,'changeuserauth'); + &update_passwd_history($uname,$udom,$umode,'changeuserauth'); &Reply($client, \$result); } else { &Failure($client, \$result); @@ -2407,36 +2576,6 @@ sub update_passwd_history { return; } -sub inst_unamemap_check { - my ($cmd, $tail, $client) = @_; - my $userinput = "$cmd:$tail"; - my %rulecheck; - my $outcome; - my ($udom,$uname,@rules) = split(/:/,$tail); - $udom = &unescape($udom); - $uname = &unescape($uname); - @rules = map {&unescape($_);} (@rules); - eval { - local($SIG{__DIE__})='DEFAULT'; - $outcome = &localenroll::unamemap_check($udom,$uname,\@rules,\%rulecheck); - }; - if (!$@) { - if ($outcome eq 'ok') { - my $result=''; - foreach my $key (keys(%rulecheck)) { - $result.=&escape($key).'='.&Apache::lonnet::freeze_escape($rulecheck{$key}).'&'; - } - &Reply($client,\$result,$userinput); - } else { - &Reply($client,"error\n", $userinput); - } - } else { - &Failure($client,"unknown_cmd\n",$userinput); - } -} -®ister_handler("instunamemapcheck",\&inst_unamemap_check,0,1,0); - - # # Determines if this is the home server for a user. The home server # for a user will have his/her lon-capa passwd file. Therefore all we need @@ -2518,16 +2657,10 @@ sub update_resource_handler { my $transname="$fname.in.transfer"; my $remoteurl=&Apache::lonnet::reply("sub:$fname","$clientname"); my $response; -# FIXME: cannot replicate files that take more than two minutes to transfer? -# alarm(120); -# FIXME: this should use the LWP mechanism, not internal alarms. - alarm(1200); - { - my $ua=new LWP::UserAgent; - my $request=new HTTP::Request('GET',"$remoteurl"); - $response=$ua->request($request,$transname); - } - alarm(0); +# FIXME: cannot replicate files that take more than two minutes to transfer -- needs checking now 1200s timeout used +# for LWP request. + my $request=new HTTP::Request('GET',"$remoteurl"); + $response=&LONCAPA::LWPReq::makerequest($clientname,$request,$transname,\%perlvar,1200,0,1); if ($response->is_error()) { my $reply=&Apache::lonnet::reply("unsub:$fname","$clientname"); &devalidate_meta_cache($fname); @@ -2539,17 +2672,11 @@ sub update_resource_handler { &logthis("LWP GET: $message for $fname ($remoteurl)"); } else { if ($remoteurl!~/\.meta$/) { -# FIXME: isn't there an internal LWP mechanism for this? - alarm(120); - { - my $ua=new LWP::UserAgent; - my $mrequest=new HTTP::Request('GET',$remoteurl.'.meta'); - my $mresponse=$ua->request($mrequest,$fname.'.meta'); - if ($mresponse->is_error()) { - unlink($fname.'.meta'); - } + my $mrequest=new HTTP::Request('GET',$remoteurl.'.meta'); + my $mresponse = &LONCAPA::LWPReq::makerequest($clientname,$mrequest,$fname.'.meta',\%perlvar,120,0,1); + if ($mresponse->is_error()) { + unlink($fname.'.meta'); } - alarm(0); } # we successfully transfered, copy file over to real name rename($transname,$fname); @@ -2619,13 +2746,13 @@ sub fetch_user_file_handler { my $remoteurl=$clientprotocol.'://'.$clienthost.'/userfiles/'.$fname; my $response; Debug("Remote URL : $remoteurl Transfername $transname Destname: $destname"); - alarm(120); - { - my $ua=new LWP::UserAgent; - my $request=new HTTP::Request('GET',"$remoteurl"); - $response=$ua->request($request,$transname); - } - alarm(0); + my $request=new HTTP::Request('GET',"$remoteurl"); + my $verifycert = 1; + my @machine_ids = &Apache::lonnet::current_machine_ids(); + if (grep(/^\Q$clientname\E$/,@machine_ids)) { + $verifycert = 0; + } + $response = &LONCAPA::LWPReq::makerequest($clientname,$request,$transname,\%perlvar,1200,$verifycert); if ($response->is_error()) { unlink($transname); my $message=$response->status_line; @@ -2692,13 +2819,13 @@ sub remove_user_file_handler { if (-e $file) { # # If the file is a regular file unlink is fine... - # However it's possible the client wants a dir - # removed, in which case rmdir is more appropriate - # Note: rmdir will only remove an empty directory. + # However it's possible the client wants a dir + # removed, in which case rmdir is more appropriate. + # Note: rmdir will only remove an empty directory. # if (-f $file){ unlink($file); - # for html files remove the associated .bak file + # for html files remove the associated .bak file # which may have been created by the editor. if ($ufile =~ m{^((docs|supplemental)/(?:\d+|default)/\d+(?:|/.+)/)[^/]+\.x?html?$}i) { my $path = $1; @@ -3072,8 +3199,8 @@ sub newput_user_profile_entry { &logthis("error: ".($!+0)." untie (GDBM) failed ". "while attempting newput - early out as key exists"); } - &Failure($client, "key_exists: ".$key."\n",$userinput); - return 1; + &Failure($client, "key_exists: ".$key."\n",$userinput); + return 1; } } @@ -3476,6 +3603,17 @@ sub get_profile_keys { sub dump_profile_database { my ($cmd, $tail, $client) = @_; + my $res = LONCAPA::Lond::dump_profile_database($tail); + + if ($res =~ /^error:/) { + Failure($client, \$res, "$cmd:$tail"); + } else { + Reply($client, \$res, "$cmd:$tail"); + } + + return 1; + + #TODO remove my $userinput = "$cmd:$tail"; my ($udom,$uname,$namespace) = split(/:/,$tail); @@ -3555,11 +3693,11 @@ sub dump_with_regexp { my ($cmd, $tail, $client) = @_; my $res = LONCAPA::Lond::dump_with_regexp($tail, $clientversion); - + if ($res =~ /^error:/) { - &Failure($client, \$res, "$cmd:$tail"); + Failure($client, \$res, "$cmd:$tail"); } else { - &Reply($client, \$res, "$cmd:$tail"); + Reply($client, \$res, "$cmd:$tail"); } return 1; @@ -3597,7 +3735,6 @@ sub store_handler { my ($cmd, $tail, $client) = @_; my $userinput = "$cmd:$tail"; - chomp($tail); my ($udom,$uname,$namespace,$rid,$what,$laststore) =split(/:/,$tail); if ($namespace ne 'roles') { @@ -3627,7 +3764,6 @@ sub store_handler { $numtrans =~ s/D//g; } } - $hashref->{"version:$rid"}++; my $version=$hashref->{"version:$rid"}; my $allkeys=''; @@ -3644,7 +3780,7 @@ sub store_handler { if ($numtrans) { $msg = 'delay:'.$numtrans; } - &Reply($client, "$msg\n", $userinput); + &Reply($client, "$msg\n", $userinput); } else { &Failure($client, "error: ".($!+0)." untie(GDBM) Failed ". "while attempting store\n", $userinput); @@ -3887,7 +4023,7 @@ sub retrieve_chat_handler { # serviced. # # Parameters: -# $cmd - COmmand keyword that initiated the request. +# $cmd - Command keyword that initiated the request. # $tail - Remainder of the command after the keyword. # For this function, this consists of a query and # 3 arguments that are self-documentingly labelled @@ -3901,7 +4037,6 @@ sub retrieve_chat_handler { sub send_query_handler { my ($cmd, $tail, $client) = @_; - my $userinput = "$cmd:$tail"; my ($query,$arg1,$arg2,$arg3)=split(/\:/,$tail); @@ -4192,7 +4327,7 @@ sub put_course_id_hash_handler { # # domcloner - flag to indicate if user can create CCs in course's domain. # If so, ability to clone course is automatic. -# hasuniquecode - filter by courses for which a six character unique code has +# hasuniquecode - filter by courses for which a six character unique code has # been set. # # $client - The socket open on the client. @@ -4202,6 +4337,17 @@ sub put_course_id_hash_handler { # a reply is written to $client. sub dump_course_id_handler { my ($cmd, $tail, $client) = @_; + + my $res = LONCAPA::Lond::dump_course_id_handler($tail); + if ($res =~ /^error:/) { + Failure($client, \$res, "$cmd:$tail"); + } else { + Reply($client, \$res, "$cmd:$tail"); + } + + return 1; + + #TODO remove my $userinput = "$cmd:$tail"; my ($udom,$since,$description,$instcodefilter,$ownerfilter,$coursefilter, @@ -4606,44 +4752,6 @@ sub course_lastaccess_handler { } ®ister_handler("courselastaccess",\&course_lastaccess_handler, 0, 1, 0); -sub course_sessions_handler { - my ($cmd, $tail, $client) = @_; - my $userinput = "$cmd:$tail"; - my ($cdom,$cnum,$lastactivity) = split(':',$tail); - my $dbsuffix = '_'.$cdom.'_'.$cnum.'.db'; - my (%sessions,$qresult); - my $now=time; - if (opendir(DIR,$perlvar{'lonIDsDir'})) { - my $filename; - while ($filename=readdir(DIR)) { - next if ($filename=~/^\./); - next if ($filename=~/^publicuser_/); - next if ($filename=~/^[a-f0-9]+_(linked|lti_\d+)\.id$/); - if ($filename =~ /^($LONCAPA::match_username)_\d+_($LONCAPA::match_domain)_/) { - my ($uname,$udom) = ($1,$2); - next unless (-e "$perlvar{'lonDaemons'}/tmp/$uname$dbsuffix"); - my $mtime = (stat("$perlvar{'lonIDsDir'}/$filename"))[9]; - if ($lastactivity < 0) { - next if ($mtime-$now > $lastactivity); - } else { - next if ($now-$mtime > $lastactivity); - } - $sessions{$uname.':'.$udom} = $mtime; - } - } - closedir(DIR); - } - foreach my $user (keys(%sessions)) { - $qresult.=&escape($user).'='.$sessions{$user}.'&'; - } - if ($qresult) { - chop($qresult); - } - &Reply($client, \$qresult, $userinput); - return 1; -} -®ister_handler("coursesessions",\&course_sessions_handler, 0, 1, 0); - # # Puts an unencrypted entry in a namespace db file at the domain level # @@ -4687,12 +4795,128 @@ sub put_domain_handler { } ®ister_handler("putdom", \&put_domain_handler, 0, 1, 0); +# Updates one or more entries in clickers.db file at the domain level +# +# Parameters: +# $cmd - The command that got us here. +# $tail - Tail of the command (remaining parameters). +# In this case a colon separated list containing: +# (a) the domain for which we are updating the entries, +# (b) the action required -- add or del -- and +# (c) a &-separated list of entries to add or delete. +# $client - File descriptor connected to client. +# Returns +# 1 - Continue processing. +# 0 - Requested to exit, caller should shut down. +# Side effects: +# reply is written to $client. +# + + +sub update_clickers { + my ($cmd, $tail, $client) = @_; + + my $userinput = "$cmd:$tail"; + my ($udom,$action,$what) =split(/:/,$tail,3); + chomp($what); + + my $hashref = &tie_domain_hash($udom, "clickers", &GDBM_WRCREAT(), + "U","$action:$what"); + + if (!$hashref) { + &Failure( $client, "error: ".($!+0)." tie(GDBM) Failed ". + "while attempting updateclickers\n", $userinput); + return 1; + } + + my @pairs=split(/\&/,$what); + foreach my $pair (@pairs) { + my ($key,$value)=split(/=/,$pair); + if ($action eq 'add') { + if (exists($hashref->{$key})) { + my @newvals = split(/,/,&unescape($value)); + my @currvals = split(/,/,&unescape($hashref->{$key})); + my @merged = sort(keys(%{{map { $_ => 1 } (@newvals,@currvals)}})); + $hashref->{$key}=&escape(join(',',@merged)); + } else { + $hashref->{$key}=$value; + } + } elsif ($action eq 'del') { + if (exists($hashref->{$key})) { + my %current; + map { $current{$_} = 1; } split(/,/,&unescape($hashref->{$key})); + map { delete($current{$_}); } split(/,/,&unescape($value)); + if (keys(%current)) { + $hashref->{$key}=&escape(join(',',sort(keys(%current)))); + } else { + delete($hashref->{$key}); + } + } + } + } + if (&untie_user_hash($hashref)) { + &Reply( $client, "ok\n", $userinput); + } else { + &Failure($client, "error: ".($!+0)." untie(GDBM) failed ". + "while attempting put\n", + $userinput); + } + return 1; +} +®ister_handler("updateclickers", \&update_clickers, 0, 1, 0); + + +# Deletes one or more entries in a namespace db file at the domain level +# +# Parameters: +# $cmd - The command that got us here. +# $tail - Tail of the command (remaining parameters). +# In this case a colon separated list containing: +# (a) the domain for which we are deleting the entries, +# (b) &-separated list of keys to delete. +# $client - File descriptor connected to client. +# Returns +# 1 - Continue processing. +# 0 - Requested to exit, caller should shut down. +# Side effects: +# reply is written to $client. +# + +sub del_domain_handler { + my ($cmd,$tail,$client) = @_; + + my $userinput = "$cmd:$tail"; + + my ($udom,$namespace,$what)=split(/:/,$tail,3); + chomp($what); + my $hashref = &tie_domain_hash($udom,$namespace,&GDBM_WRCREAT(), + "D", $what); + if ($hashref) { + my @keys=split(/\&/,$what); + foreach my $key (@keys) { + delete($hashref->{$key}); + } + if (&untie_user_hash($hashref)) { + &Reply($client, "ok\n", $userinput); + } else { + &Failure($client, "error: ".($!+0)." untie(GDBM) Failed ". + "while attempting deldom\n", $userinput); + } + } else { + &Failure( $client, "error: ".($!+0)." tie(GDBM) Failed ". + "while attempting deldom\n", $userinput); + } + return 1; +} +®ister_handler("deldom", \&del_domain_handler, 0, 1, 0); + + # Unencrypted get from the namespace database file at the domain level. # This function retrieves a keyed item from a specific named database in the # domain directory. # # Parameters: -# $cmd - Command request keyword (getdom). +# $cmd - Command request keyword (get). # $tail - Tail of the command. This is a colon separated list # consisting of the domain and the 'namespace' # which selects the gdbm file to do the lookup in, @@ -4709,20 +4933,80 @@ sub put_domain_handler { sub get_domain_handler { my ($cmd, $tail, $client) = @_; + my $userinput = "$cmd:$tail"; my ($udom,$namespace,$what)=split(/:/,$tail,3); - my $res = LONCAPA::Lond::get_dom($userinput); - if ($res =~ /^error:/) { - &Failure($client, \$res, $userinput); + chomp($what); + if ($namespace =~ /^enc/) { + &Failure( $client, "refused\n", $userinput); } else { - &Reply($client, \$res, $userinput); + my @queries=split(/\&/,$what); + my $qresult=''; + my $hashref = &tie_domain_hash($udom, "$namespace", &GDBM_READER()); + if ($hashref) { + for (my $i=0;$i<=$#queries;$i++) { + $qresult.="$hashref->{$queries[$i]}&"; + } + if (&untie_domain_hash($hashref)) { + $qresult=~s/\&$//; + &Reply($client, \$qresult, $userinput); + } else { + &Failure( $client, "error: ".($!+0)." untie(GDBM) Failed ". + "while attempting getdom\n",$userinput); + } + } else { + &Failure($client, "error: ".($!+0)." tie(GDBM) Failed ". + "while attempting getdom\n",$userinput); + } } return 1; } ®ister_handler("getdom", \&get_domain_handler, 0, 1, 0); +sub encrypted_get_domain_handler { + my ($cmd, $tail, $client) = @_; + + my $userinput = "$cmd:$tail"; + + my ($udom,$namespace,$what)=split(/:/,$tail,3); + chomp($what); + my @queries=split(/\&/,$what); + my $qresult=''; + my $hashref = &tie_domain_hash($udom, "$namespace", &GDBM_READER()); + if ($hashref) { + for (my $i=0;$i<=$#queries;$i++) { + $qresult.="$hashref->{$queries[$i]}&"; + } + if (&untie_domain_hash($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); + } + } else { + &Failure( $client, "error: ".($!+0)." untie(GDBM) Failed ". + "while attempting egetdom\n",$userinput); + } + } else { + &Failure($client, "error: ".($!+0)." tie(GDBM) Failed ". + "while attempting egetdom\n",$userinput); + } + return 1; +} +®ister_handler("egetdom", \&encrypted_get_domain_handler, 1, 1, 0); + # # Puts an id to a domains id database. # @@ -4832,7 +5116,7 @@ sub get_id_handler { # Returns: # 1 - Continue processing # 0 - Exit server. -# +# # sub del_id_handler { @@ -5148,23 +5432,15 @@ sub tmp_put_handler { } my ($id,$store); $tmpsnum++; - my $numtries = 0; - my $execdir=$perlvar{'lonDaemons'}; - if (($context eq 'resetpw') || ($context eq 'createaccount') || - ($context eq 'sso') || ($context eq 'link') || ($context eq 'retry')) { - $id = &md5_hex(&md5_hex(time.{}.rand().$$.$tmpsnum)); - while ((-e "$execdir/tmp/$id.tmp") && ($numtries <10)) { - undef($id); - $id = &md5_hex(&md5_hex(time.{}.rand().$$.$tmpsnum)); - $numtries ++; - } + if (($context eq 'resetpw') || ($context eq 'createaccount')) { + $id = &md5_hex(&md5_hex(time.{}.rand().$$)); } else { $id = $$.'_'.$clientip.'_'.$tmpsnum; } $id=~s/\W/\_/g; $record=~s/\n//g; - if (($id ne '') && - ($store=IO::File->new(">$execdir/tmp/$id.tmp"))) { + my $execdir=$perlvar{'lonDaemons'}; + if ($store=IO::File->new(">$execdir/tmp/$id.tmp")) { print $store $record; close $store; &Reply($client, \$id, $userinput); @@ -5247,65 +5523,8 @@ sub tmp_del_handler { ®ister_handler("tmpdel", \&tmp_del_handler, 0, 1, 0); # -# Process the updatebalcookie command. This command updates a -# cookie in the lonBalancedir directory on a load balancer node. -# -# Parameters: -# $cmd - Command that got us here. -# $tail - Tail of the request (escaped cookie: escaped current entry) -# -# $client - socket open on the client process. -# -# Returns: -# 1 - Indicating processing should continue. -# Side Effects: -# A cookie file is updated from the lonBalancedir directory -# A reply is sent to the client. -# -sub update_balcookie_handler { - my ($cmd, $tail, $client) = @_; - - my $userinput= "$cmd:$tail"; - chomp($tail); - my ($cookie,$lastentry) = map { &unescape($_) } (split(/:/,$tail)); - - my $updatedone; - if ($cookie =~ /^$LONCAPA::match_domain\_$LONCAPA::match_username\_[a-f0-9]{32}$/) { - my $execdir=$perlvar{'lonBalanceDir'}; - if (-e "$execdir/$cookie.id") { - my $doupdate; - if (open(my $fh,'<',"$execdir/$cookie.id")) { - while (my $line = <$fh>) { - chomp($line); - if ($line eq $lastentry) { - $doupdate = 1; - last; - } - } - close($fh); - } - if ($doupdate) { - if (open(my $fh,'>',"$execdir/$cookie.id")) { - print $fh $clientname; - close($fh); - $updatedone = 1; - } - } - } - } - if ($updatedone) { - &Reply($client, "ok\n", $userinput); - } else { - &Failure( $client, "error: ".($!+0)."file update failed ". - "while attempting updatebalcookie\n", $userinput); - } - return 1; -} -®ister_handler("updatebalcookie", \&update_balcookie_handler, 0, 1, 0); - -# # Process the delbalcookie command. This command deletes a balancer -# cookie in the lonBalancedir directory on a load balancer node. +# cookie in the lonBalancedir directory created by switchserver # # Parameters: # $cmd - Command that got us here. @@ -5323,7 +5542,6 @@ sub del_balcookie_handler { my $userinput= "$cmd:$cookie"; chomp($cookie); - $cookie = &unescape($cookie); my $deleted = ''; if ($cookie =~ /^$LONCAPA::match_domain\_$LONCAPA::match_username\_[a-f0-9]{32}$/) { my $execdir=$perlvar{'lonBalanceDir'}; @@ -5334,10 +5552,10 @@ sub del_balcookie_handler { chomp($line); if ($line eq $clientname) { $dodelete = 1; - last; + last; } } - close($fh); + close($fh); if ($dodelete) { if (unlink("$execdir/$cookie.id")) { $deleted = 1; @@ -5491,13 +5709,12 @@ sub enrollment_enabled_handler { my ($cmd, $tail, $client) = @_; my $userinput = $cmd.":".$tail; # For logging purposes. + my ($cdom) = split(/:/, $tail, 2); # Domain we're asking about. - my $outcome; - eval { - local($SIG{__DIE__})='DEFAULT'; - $outcome = &localenroll::run($cdom); - }; + + my $outcome = &localenroll::run($cdom); &Reply($client, \$outcome, $userinput); + return 1; } ®ister_handler("autorun", \&enrollment_enabled_handler, 0, 1, 0); @@ -5530,12 +5747,8 @@ sub validate_instcode_handler { my ($dom,$instcode,$owner) = split(/:/, $tail); $instcode = &unescape($instcode); $owner = &unescape($owner); - my ($outcome,$description,$credits); - eval { - local($SIG{__DIE__})='DEFAULT'; - ($outcome,$description,$credits) = - &localenroll::validate_instcode($dom,$instcode,$owner); - }; + my ($outcome,$description,$credits) = + &localenroll::validate_instcode($dom,$instcode,$owner); my $result = &escape($outcome).'&'.&escape($description).'&'. &escape($credits); &Reply($client, \$result, $userinput); @@ -5544,43 +5757,6 @@ sub validate_instcode_handler { } ®ister_handler("autovalidateinstcode", \&validate_instcode_handler, 0, 1, 0); -# -# Validate co-owner for cross-listed institutional code and -# institutional course code itself used for a LON-CAPA course. -# -# Formal Parameters: -# $cmd - The command request that got us dispatched. -# $tail - The tail of the command. In this case, -# this is a colon separated string containing: -# $dom - Course's LON-CAPA domain -# $instcode - Institutional course code for the course -# $inst_xlist - Institutional course Id for the crosslisting -# $coowner - Username of co-owner -# (values for all but $dom have been escaped). -# -# $client - Socket open on the client. -# Returns: -# 1 - Indicating processing should continue. -# -sub validate_instcrosslist_handler { - my ($cmd, $tail, $client) = @_; - my $userinput = "$cmd:$tail"; - my ($dom,$instcode,$inst_xlist,$coowner) = split(/:/,$tail); - $instcode = &unescape($instcode); - $inst_xlist = &unescape($inst_xlist); - $coowner = &unescape($coowner); - my $outcome; - eval { - local($SIG{__DIE__})='DEFAULT'; - $outcome = &localenroll::validate_crosslist_access($dom,$instcode, - $inst_xlist,$coowner); - }; - - &Reply($client, \$outcome, $userinput); - return 1; -} -®ister_handler("autovalidateinstcrosslist", \&validate_instcrosslist_handler, 0, 1, 0); - # Get the official sections for which auto-enrollment is possible. # Since the admin people won't know about 'unofficial sections' # we cannot auto-enroll on them. @@ -5599,13 +5775,12 @@ sub get_sections_handler { my $userinput = "$cmd:$tail"; my ($coursecode, $cdom) = split(/:/, $tail); - my $seclist; - eval { - local($SIG{__DIE__})='DEFAULT'; - my @secs = &localenroll::get_sections($coursecode,$cdom); - $seclist = &escape(join(':',@secs)); - }; + my @secs = &localenroll::get_sections($coursecode,$cdom); + my $seclist = &escape(join(':',@secs)); + &Reply($client, \$seclist, $userinput); + + return 1; } ®ister_handler("autogetsections", \&get_sections_handler, 0, 1, 0); @@ -5625,7 +5800,6 @@ sub get_sections_handler { # Returns: # 1 - Processing should continue. # - sub validate_course_owner_handler { my ($cmd, $tail, $client) = @_; my $userinput = "$cmd:$tail"; @@ -5633,12 +5807,11 @@ sub validate_course_owner_handler { $owner = &unescape($owner); $coowners = &unescape($coowners); - my $outcome; - eval { - local($SIG{__DIE__})='DEFAULT'; - $outcome = &localenroll::new_course($inst_course_id,$owner,$cdom,$coowners); - }; + my $outcome = &localenroll::new_course($inst_course_id,$owner,$cdom,$coowners); &Reply($client, \$outcome, $userinput); + + + return 1; } ®ister_handler("autonewcourse", \&validate_course_owner_handler, 0, 1, 0); @@ -5664,12 +5837,11 @@ sub validate_course_section_handler { my ($cmd, $tail, $client) = @_; my $userinput = "$cmd:$tail"; my ($inst_course_id, $cdom) = split(/:/, $tail); - my $outcome; - eval { - local($SIG{__DIE__})='DEFAULT'; - $outcome=&localenroll::validate_courseID($inst_course_id,$cdom); - }; + + my $outcome=&localenroll::validate_courseID($inst_course_id,$cdom); &Reply($client, \$outcome, $userinput); + + return 1; } ®ister_handler("autovalidatecourse", \&validate_course_section_handler, 0, 1, 0); @@ -5683,7 +5855,7 @@ sub validate_course_section_handler { # $tail - The tail of the command. In this case this is a colon separated # set of values that will be split into: # $inst_class - Institutional code for the specific class section -# $ownerlist - An escaped comma-separated list of username:domain +# $ownerlist - An escaped comma-separated list of username:domain # of the course owner, and co-owner(s). # $cdom - The domain of the course from the institution's # point of view. @@ -5709,62 +5881,6 @@ sub validate_class_access_handler { ®ister_handler("autovalidateclass_sec", \&validate_class_access_handler, 0, 1, 0); # -# Modify institutional sections (using customized &instsec_reformat() -# routine in localenroll.pm), to either clutter or declutter, for -# purposes of ensuring an institutional course section (string) can -# be unambiguously separated into institutional course and section. -# -# Formal Parameters: -# $cmd - The command request that got us dispatched. -# $tail - The tail of the command. In this case this is a colon separated -# set of values that will be split into: -# $cdom - The LON-CAPA domain of the course. -# $action - Either: clutter or declutter -# clutter adds character(s) to eliminate ambiguity -# declutter removes the added characters (e.g., for -# display of the institutional course section string. -# $info - A frozen hash in which keys are: -# LON-CAPA course number:Institutional course code -# and values are a reference to an array of the -# items to modify -- either institutional sections, -# or institutional course sections (for crosslistings). -# $client - The socket open on the client. -# Returns: -# 1 - continue processing. -# - -sub instsec_reformat_handler { - my ($cmd, $tail, $client) = @_; - my $userinput = "$cmd:$tail"; - my ($cdom,$action,$info) = split(/:/,$tail); - my $instsecref = &Apache::lonnet::thaw_unescape($info); - my ($outcome,$result); - eval { - local($SIG{__DIE__})='DEFAULT'; - $outcome=&localenroll::instsec_reformat($cdom,$action,$instsecref); - if ($outcome eq 'ok') { - if (ref($instsecref) eq 'HASH') { - foreach my $key (keys(%{$instsecref})) { - $result .= &escape($key).'='.&Apache::lonnet::freeze_escape($instsecref->{$key}).'&'; - } - $result =~ s/\&$//; - } - } - }; - if (!$@) { - if ($outcome eq 'ok') { - &Reply( $client, \$result, $userinput); - } else { - &Reply($client,\$outcome, $userinput); - } - } else { - &Failure($client,"unknown_cmd\n",$userinput); - } - return 1; -} -®ister_handler("autoinstsecreformat",\&instsec_reformat_handler, 0, 1, 0); - -# # Validate course owner or co-owners(s) access to enrollment data for all sections # and crosslistings for a particular course. # @@ -5836,12 +5952,10 @@ sub create_auto_enroll_password_handler my ($authparam, $cdom) = split(/:/, $userinput); my ($create_passwd,$authchk); - eval { - local($SIG{__DIE__})='DEFAULT'; - ($authparam, - $create_passwd, - $authchk) = &localenroll::create_password($authparam,$cdom); - }; + ($authparam, + $create_passwd, + $authchk) = &localenroll::create_password($authparam,$cdom); + &Reply($client, &escape($authparam.':'.$create_passwd.':'.$authchk)."\n", $userinput); @@ -5896,7 +6010,6 @@ sub auto_export_grades_handler { ®ister_handler("autoexportgrades", \&auto_export_grades_handler, 1, 1, 0); - # Retrieve and remove temporary files created by/during autoenrollment. # # Formal Parameters: @@ -5917,6 +6030,7 @@ sub retrieve_auto_file_handler { my ($filename) = split(/:/, $tail); my $source = $perlvar{'lonDaemons'}.'/tmp/'.$filename; + if ($filename =~m{/\.\./}) { &Failure($client, "refused\n", $userinput); } elsif ($filename !~ /^$LONCAPA::match_domain\_$LONCAPA::match_courseid\_.+_classlist\.xml$/) { @@ -5953,7 +6067,7 @@ sub crsreq_checks_handler { my $userinput = "$cmd:$tail"; my $dom = $tail; my $result; - my @reqtypes = ('official','unofficial','community','textbook'); + my @reqtypes = ('official','unofficial','community','textbook','placement'); eval { local($SIG{__DIE__})='DEFAULT'; my %validations; @@ -6077,16 +6191,12 @@ sub get_institutional_code_format_handle my ($key,$value) = split/=/,$_; $instcodes{&unescape($key)} = &unescape($value); } - my $formatreply; - eval { - local($SIG{__DIE__})='DEFAULT'; - $formatreply = &localenroll::instcode_format($cdom, - \%instcodes, - \%codes, - \@codetitles, - \%cat_titles, - \%cat_order); - }; + my $formatreply = &localenroll::instcode_format($cdom, + \%instcodes, + \%codes, + \@codetitles, + \%cat_titles, + \%cat_order); if ($formatreply eq 'ok') { my $codes_str = &Apache::lonnet::hash2str(%codes); my $codetitles_str = &Apache::lonnet::array2str(@codetitles); @@ -6146,15 +6256,11 @@ sub get_possible_instcodes_handler { my $reply; my $cdom = $tail; my (@codetitles,%cat_titles,%cat_order,@code_order); - my $formatreply; - eval { - local($SIG{__DIE__})='DEFAULT'; - $formatreply = &localenroll::possible_instcodes($cdom, - \@codetitles, - \%cat_titles, - \%cat_order, - \@code_order); - }; + my $formatreply = &localenroll::possible_instcodes($cdom, + \@codetitles, + \%cat_titles, + \%cat_order, + \@code_order); if ($formatreply eq 'ok') { my $result = join('&',map {&escape($_);} (@codetitles)).':'; $result .= join('&',map {&escape($_);} (@code_order)).':'; @@ -6278,39 +6384,6 @@ sub get_institutional_selfcreate_rules { } ®ister_handler("instemailrules",\&get_institutional_selfcreate_rules,0,1,0); -sub get_unamemap_rules { - my ($cmd, $tail, $client) = @_; - my $userinput = "$cmd:$tail"; - my $dom = &unescape($tail); - my (%rules_hash,@rules_order); - my $outcome; - eval { - local($SIG{__DIE__})='DEFAULT'; - $outcome = &localenroll::unamemap_rules($dom,\%rules_hash,\@rules_order); - }; - if (!$@) { - if ($outcome eq 'ok') { - my $result; - foreach my $key (keys(%rules_hash)) { - $result .= &escape($key).'='.&Apache::lonnet::freeze_escape($rules_hash{$key}).'&'; - } - $result =~ s/\&$//; - $result .= ':'; - if (@rules_order > 0) { - foreach my $item (@rules_order) { - $result .= &escape($item).'&'; - } - } - $result =~ s/\&$//; - &Reply($client,\$result,$userinput); - } else { - &Reply($client,"error\n", $userinput); - } - } else { - &Failure($client,"unknown_cmd\n",$userinput); - } -} -®ister_handler("unamemaprules",\&get_unamemap_rules,0,1,0); sub institutional_username_check { my ($cmd, $tail, $client) = @_; @@ -6599,12 +6672,13 @@ sub get_request { # # Parameters: # user_input - The request received from the client (lonc). +# # Returns: # true to keep processing, false if caller should exit. # sub process_request { - my ($userinput) = @_; # Easier for now to break style than to - # fix all the userinput -> user_input. + my ($userinput) = @_; # Easier for now to break style than to + # fix all the userinput -> user_input. my $wasenc = 0; # True if request was encrypted. # ------------------------------------------------------------ See if encrypted # for command @@ -6684,6 +6758,62 @@ sub process_request { Debug("Client not privileged to do this operation"); $ok = 0; } + if ($ok) { + my $realcommand = $command; + if ($command eq 'querysend') { + my ($query,$rest)=split(/\:/,$tail,2); + $query=~s/\n*$//g; + my @possqueries = + qw(userlog courselog fetchenrollment institutionalphotos usersearch instdirsearch getinstuser getmultinstusers); + if (grep(/^\Q$query\E$/,@possqueries)) { + $command .= '_'.$query; + } elsif ($query eq 'prepare activity log') { + $command .= '_activitylog'; + } + } + if (ref($trust{$command}) eq 'HASH') { + my $donechecks; + if ($trust{$command}{'anywhere'}) { + $donechecks = 1; + } elsif ($trust{$command}{'manageronly'}) { + unless (&isManager()) { + $ok = 0; + } + $donechecks = 1; + } elsif ($trust{$command}{'institutiononly'}) { + unless ($clientsameinst) { + $ok = 0; + } + $donechecks = 1; + } elsif ($clientsameinst) { + $donechecks = 1; + } + unless ($donechecks) { + foreach my $rule (keys(%{$trust{$command}})) { + next if ($rule eq 'remote'); + if ($trust{$command}{$rule}) { + if ($clientprohibited{$rule}) { + $ok = 0; + } else { + $ok = 1; + $donechecks = 1; + last; + } + } + } + } + unless ($donechecks) { + if ($trust{$command}{'remote'}) { + if ($clientremoteok) { + $ok = 1; + } else { + $ok = 0; + } + } + } + } + $command = $realcommand; + } if($ok) { Debug("Dispatching to handler $command $tail"); @@ -6694,8 +6824,7 @@ sub process_request { Failure($client, "refused\n", $userinput); return 1; } - - } + } print $client "unknown_cmd\n"; # -------------------------------------------------------------------- complete @@ -6833,7 +6962,7 @@ undef $perlvarref; # ----------------------------- Make sure this process is running from user=www my $wwwid=getpwnam('www'); if ($wwwid!=$<) { - my $emailto="$perlvar{'lonAdmEMail'} $perlvar{'lonSysEMail'}"; + my $emailto="$perlvar{'lonAdmEMail'},$perlvar{'lonSysEMail'}"; my $subj="LON: $currenthostid User ID mismatch"; system("echo 'User ID mismatch. lond must be run as user www.' |". " mail -s '$subj' $emailto > /dev/null"); @@ -6952,6 +7081,7 @@ sub UpdateHosts { # will take care of new and changed hosts as connections come into being. &Apache::lonnet::reset_hosts_info(); + my %active; foreach my $child (keys(%children)) { my $childip = $children{$child}; @@ -6961,15 +7091,62 @@ sub UpdateHosts { ." $child for ip $childip </font>"); kill('INT', $child); } else { + $active{$child} = $childip; logthis('<font color="green"> keeping child for ip ' ." $childip (pid=$child) </font>"); } } + + my %oldconf = %secureconf; + my %connchange; + if (lonssl::Read_Connect_Config(\%secureconf,\%crlchecked,\%perlvar) eq 'ok') { + logthis('<font color="blue"> Reloaded SSL connection rules and cleared CRL checking history </font>'); + } else { + logthis('<font color="yellow"> Failed to reload SSL connection rules and clear CRL checking history </font>'); + } + if ((ref($oldconf{'connfrom'}) eq 'HASH') && (ref($secureconf{'connfrom'}) eq 'HASH')) { + foreach my $type ('dom','intdom','other') { + if ((($oldconf{'connfrom'}{$type} eq 'no') && ($secureconf{'connfrom'}{$type} eq 'req')) || + (($oldconf{'connfrom'}{$type} eq 'req') && ($secureconf{'connfrom'}{$type} eq 'no'))) { + $connchange{$type} = 1; + } + } + } + if (keys(%connchange)) { + foreach my $child (keys(%active)) { + my $childip = $active{$child}; + if ($childip ne '127.0.0.1') { + my $childhostname = gethostbyaddr(Socket::inet_aton($childip),AF_INET); + if ($childhostname ne '') { + my $childlonhost = &Apache::lonnet::get_server_homeID($childhostname); + my ($samedom,$sameinst) = &set_client_info($childlonhost); + if ($samedom) { + if ($connchange{'dom'}) { + logthis('<font color="blue"> UpdateHosts killing child ' + ." $child for ip $childip </font>"); + kill('INT', $child); + } + } elsif ($sameinst) { + if ($connchange{'intdom'}) { + logthis('<font color="blue"> UpdateHosts killing child ' + ." $child for ip $childip </font>"); + kill('INT', $child); + } + } else { + if ($connchange{'other'}) { + logthis('<font color="blue"> UpdateHosts killing child ' + ." $child for ip $childip </font>"); + kill('INT', $child); + } + } + } + } + } + } ReloadApache; &status("Finished reloading hosts.tab"); } - sub checkchildren { &status("Checking on the children (sending signals)"); &initnewstatus(); @@ -7039,6 +7216,9 @@ sub Debug { # reply - Text to send to client. # request - Original request from client. # +#NOTE $reply must be terminated by exactly *one* \n. If $reply is a reference +#this is done automatically ($$reply must not contain any \n in this case). +#If $reply is a string the caller has to ensure this. sub Reply { my ($fd, $reply, $request) = @_; if (ref($reply)) { @@ -7201,6 +7381,10 @@ if ($arch eq 'unknown') { chomp($arch); } +unless (lonssl::Read_Connect_Config(\%secureconf,\%crlchecked,\%perlvar) eq 'ok') { + &logthis('<font color="blue">No connectionrules table. Will fallback to loncapa.conf</font>'); +} + # -------------------------------------------------------------- # Accept connections. When a connection comes in, it is validated # and if good, a child process is created to process transactions @@ -7286,13 +7470,13 @@ sub make_new_child { &Authen::Krb5::init_context(); my $no_ets; - if ($dist =~ /^(?:centos|rhes|scientific|oracle|rocky|alma)(\d+)/) { + if ($dist =~ /^(?:centos|rhes|scientific)(\d+)$/) { if ($1 >= 7) { $no_ets = 1; } } elsif ($dist =~ /^suse(\d+\.\d+)$/) { if (($1 eq '9.3') || ($1 >= 12.2)) { - $no_ets = 1; + $no_ets = 1; } } elsif ($dist =~ /^sles(\d+)$/) { if ($1 > 11) { @@ -7304,8 +7488,8 @@ sub make_new_child { } } unless ($no_ets) { - &Authen::Krb5::init_ets(); - } + &Authen::Krb5::init_ets(); + } &status('Accepted connection'); # ============================================================================= @@ -7331,7 +7515,7 @@ sub make_new_child { $ConnectionType = "manager"; $clientname = $managers{$outsideip}; } - my $clientok; + my ($clientok,$clientinfoset); if ($clientrec || $ismanager) { &status("Waiting for init from $clientip $clientname"); @@ -7349,17 +7533,42 @@ sub make_new_child { # If the remote is attempting a local init... give that a try: # (my $i, my $inittype, $clientversion) = split(/:/, $remotereq); - # For LON-CAPA 2.9, the client session will have sent its LON-CAPA - # version when initiating the connection. For LON-CAPA 2.8 and older, - # the version is retrieved from the global %loncaparevs in lonnet.pm. - # $clientversion contains path to keyfile if $inittype eq 'local' - # it's overridden below in this case - $clientversion ||= $Apache::lonnet::loncaparevs{$clientname}; + # For LON-CAPA 2.9, the client session will have sent its LON-CAPA + # version when initiating the connection. For LON-CAPA 2.8 and older, + # the version is retrieved from the global %loncaparevs in lonnet.pm. + # $clientversion contains path to keyfile if $inittype eq 'local' + # it's overridden below in this case + $clientversion ||= $Apache::lonnet::loncaparevs{$clientname}; # If the connection type is ssl, but I didn't get my # certificate files yet, then I'll drop back to # insecure (if allowed). - + + if ($inittype eq "ssl") { + my $context; + if ($clientsamedom) { + $context = 'dom'; + if ($secureconf{'connfrom'}{'dom'} eq 'no') { + $inittype = ""; + } + } elsif ($clientsameinst) { + $context = 'intdom'; + if ($secureconf{'connfrom'}{'intdom'} eq 'no') { + $inittype = ""; + } + } else { + $context = 'other'; + if ($secureconf{'connfrom'}{'other'} eq 'no') { + $inittype = ""; + } + } + if ($inittype eq '') { + &logthis("<font color=\"blue\"> Domain config set " + ."to no ssl for $clientname (context: $context)" + ." -- trying insecure auth</font>"); + } + } + if($inittype eq "ssl") { my ($ca, $cert) = lonssl::CertificateFile; my $kfile = lonssl::KeyFile; @@ -7392,7 +7601,7 @@ sub make_new_child { close $client; } } elsif ($inittype eq "ssl") { - my $key = SSLConnection($client); + my $key = SSLConnection($client,$clientname); if ($key) { $clientok = 1; my $cipherkey = pack("H32", $key); @@ -7407,6 +7616,7 @@ sub make_new_child { } } else { + $clientinfoset = &set_client_info(); my $ok = InsecureConnection($client); if($ok) { $clientok = 1; @@ -7444,15 +7654,40 @@ sub make_new_child { # ------------------------------------------------------------ Process requests my $keep_going = 1; my $user_input; - my $clienthost = &Apache::lonnet::hostname($clientname); - my $clientserverhomeID = &Apache::lonnet::get_server_homeID($clienthost); - $clienthomedom = &Apache::lonnet::host_domain($clientserverhomeID); + unless ($clientinfoset) { + $clientinfoset = &set_client_info(); + } + $clientremoteok = 0; + unless ($clientsameinst) { + $clientremoteok = 1; + my $defdom = &Apache::lonnet::host_domain($perlvar{'lonHostID'}); + %clientprohibited = &get_prohibited($defdom); + if ($clientintdom) { + my $remsessconf = &get_usersession_config($defdom,'remotesession'); + if (ref($remsessconf) eq 'HASH') { + if (ref($remsessconf->{'remote'}) eq 'HASH') { + if (ref($remsessconf->{'remote'}->{'excludedomain'}) eq 'ARRAY') { + if (grep(/^\Q$clientintdom\E$/,@{$remsessconf->{'remote'}->{'excludedomain'}})) { + $clientremoteok = 0; + } + } + if (ref($remsessconf->{'remote'}->{'includedomain'}) eq 'ARRAY') { + if (grep(/^\Q$clientintdom\E$/,@{$remsessconf->{'remote'}->{'includedomain'}})) { + $clientremoteok = 1; + } else { + $clientremoteok = 0; + } + } + } + } + } + } while(($user_input = get_request) && $keep_going) { alarm(120); Debug("Main: Got $user_input\n"); $keep_going = &process_request($user_input); alarm(0); - &status('Listening to '.$clientname." ($keymode)"); + &status('Listening to '.$clientname." ($keymode)"); } # --------------------------------------------- client unknown or fishy, refuse @@ -7462,20 +7697,74 @@ sub make_new_child { &logthis("<font color='blue'>WARNING: " ."Rejected client $clientip, closing connection</font>"); } - } + } # ============================================================================= &logthis("<font color='red'>CRITICAL: " ."Disconnect from $clientip ($clientname)</font>"); - - + + # this exit is VERY important, otherwise the child will become # a producer of more and more children, forking yourself into # process death. exit; } + +# +# Used to determine if a particular client is from the same domain +# as the current server, or from the same internet domain. +# +# Optional input -- the client to check for domain and internet domain. +# If not specified, defaults to the package variable: $clientname +# +# If called in array context will not set package variables, but will +# instead return an array of two values - (a) true if client is in the +# same domain as the server, and (b) true if client is in the same internet +# domain. +# +# If called in scalar context, sets package variables for current client: +# +# $clienthomedom - LonCAPA domain of homeID for client. +# $clientsamedom - LonCAPA domain same for this host and client. +# $clientintdom - LonCAPA "internet domain" for client. +# $clientsameinst - LonCAPA "internet domain" same for this host & client. +# +# returns 1 to indicate package variables have been set for current client. +# + +sub set_client_info { + my ($lonhost) = @_; + $lonhost ||= $clientname; + my $clienthost = &Apache::lonnet::hostname($lonhost); + my $clientserverhomeID = &Apache::lonnet::get_server_homeID($clienthost); + my $homedom = &Apache::lonnet::host_domain($clientserverhomeID); + my $samedom = 0; + if ($perlvar{'lonDefDom'} eq $homedom) { + $samedom = 1; + } + my $intdom = &Apache::lonnet::internet_dom($clientserverhomeID); + my $sameinst = 0; + if ($intdom ne '') { + my $internet_names = &Apache::lonnet::get_internet_names($currenthostid); + if (ref($internet_names) eq 'ARRAY') { + if (grep(/^\Q$intdom\E$/,@{$internet_names})) { + $sameinst = 1; + } + } + } + if (wantarray) { + return ($samedom,$sameinst); + } else { + $clienthomedom = $homedom; + $clientsamedom = $samedom; + $clientintdom = $intdom; + $clientsameinst = $sameinst; + return 1; + } +} + # # Determine if a user is an author for the indicated domain. # @@ -7689,15 +7978,8 @@ sub validate_user { } elsif ((($domdefaults{'auth_def'} eq 'krb4') || ($domdefaults{'auth_def'} eq 'krb5')) && ($domdefaults{'auth_arg_def'} ne '')) { - # - # Don't attempt authentication for username and password supplied - # for user without an account if uername contains @ to avoid - # call to &Authen::Krb5::parse_name() which will result in con_lost - # - unless ($user =~ /\@/) { - $howpwd = $domdefaults{'auth_def'}; - $contentpwd = $domdefaults{'auth_arg_def'}; - } + $howpwd = $domdefaults{'auth_def'}; + $contentpwd = $domdefaults{'auth_arg_def'}; } } } @@ -7805,7 +8087,7 @@ sub check_internal_passwd { $defaultcost = 10; } if (int($rest[0])<int($defaultcost)) { - if ($domdefaults{'intauth_check'} == 1) { + if ($domdefaults{'intauth_check'} == 1) { my $ncpass = &hash_passwd($domain,$plainpass); if (&rewrite_password_file($domain,$user,"internal:$ncpass")) { &update_passwd_history($user,$domain,'internal','update cost'); @@ -8041,9 +8323,6 @@ sub currentversion { if (-e $ulsdir) { if(-d $ulsdir) { if (opendir(LSDIR,$ulsdir)) { - if (-e $fname) { - $version=0; - } my $ulsfn; while ($ulsfn=readdir(LSDIR)) { # see if this is a regular file (ignore links produced earlier) @@ -8169,8 +8448,8 @@ sub make_passwd_file { &Debug("Creating internal auth"); my $pf = IO::File->new(">$passfilename"); if($pf) { - print $pf "internal:$ncpass\n"; - &update_passwd_history($uname,$udom,$umode,$action); + print $pf "internal:$ncpass\n"; + &update_passwd_history($uname,$udom,$umode,$action); } else { $result = "pass_file_failed_error"; } @@ -8197,6 +8476,14 @@ sub make_passwd_file { $result = "pass_file_failed_error"; } } + } elsif ($umode eq 'lti') { + my $pf = IO::File->new(">$passfilename"); + if($pf) { + print $pf "lti:\n"; + &update_passwd_history($uname,$udom,$umode,$action); + } else { + $result = "pass_file_failed_error"; + } } else { $result="auth_mode_error"; } @@ -8243,10 +8530,8 @@ sub get_usersession_config { return $usersessionconf; } else { my %domconfig = &Apache::lonnet::get_dom('configuration',['usersessions'],$dom); - if (ref($domconfig{'usersessions'}) eq 'HASH') { - &Apache::lonnet::do_cache_new($name,$dom,$domconfig{'usersessions'},3600); - return $domconfig{'usersessions'}; - } + &Apache::lonnet::do_cache_new($name,$dom,$domconfig{'usersessions'},3600); + return $domconfig{'usersessions'}; } return; } @@ -8258,12 +8543,47 @@ sub get_usersearch_config { return $usersearchconf; } else { my %domconfig = &Apache::lonnet::get_dom('configuration',['directorysrch'],$dom); - &Apache::lonnet::do_cache_new($name,$dom,$domconfig{'directorysrch'},3600); + &Apache::lonnet::do_cache_new($name,$dom,$domconfig{'directorysrch'},600); return $domconfig{'directorysrch'}; } return; } +sub get_prohibited { + my ($dom) = @_; + my $name = 'trust'; + my ($trustconfig,$cached)=&Apache::lonnet::is_cached_new($name,$dom); + unless (defined($cached)) { + my %domconfig = &Apache::lonnet::get_dom('configuration',['trust'],$dom); + &Apache::lonnet::do_cache_new($name,$dom,$domconfig{'trust'},3600); + $trustconfig = $domconfig{'trust'}; + } + my %prohibited; + if (ref($trustconfig)) { + foreach my $prefix (keys(%{$trustconfig})) { + if (ref($trustconfig->{$prefix}) eq 'HASH') { + my $reject; + if (ref($trustconfig->{$prefix}->{'exc'}) eq 'ARRAY') { + if (grep(/^\Q$clientintdom\E$/,@{$trustconfig->{$prefix}->{'exc'}})) { + $reject = 1; + } + } + if (ref($trustconfig->{$prefix}->{'inc'}) eq 'ARRAY') { + if (grep(/^\Q$clientintdom\E$/,@{$trustconfig->{$prefix}->{'inc'}})) { + $reject = 0; + } else { + $reject = 1; + } + } + if ($reject) { + $prohibited{$prefix} = 1; + } + } + } + } + return %prohibited; +} + sub distro_and_arch { return $dist.':'.$arch; } @@ -8447,7 +8767,7 @@ Allow for a password to be set. Make a user. -=item passwd +=item changeuserauth Allow for authentication mechanism and password to be changed. @@ -8536,6 +8856,10 @@ for each student, defined perhaps by the Returns usernames corresponding to IDs. (These "IDs" are unique identifiers for each student, defined perhaps by the institutional Registrar.) +=item iddel + +Deletes one or more ids in a domain's id database. + =item tmpput Accept and store information in temporary space. @@ -8585,13 +8909,14 @@ IO::File Apache::File POSIX Crypt::IDEA -LWP::UserAgent() GDBM_File Authen::Krb4 Authen::Krb5 =head1 COREQUISITES +none + =head1 OSNAMES linux @@ -8665,7 +8990,7 @@ is closed and the child exits. =item Red CRITICAL Can't get key file <error> SSL key negotiation is being attempted but the call to -lonssl::KeyFile failed. This usually means that the +lonssl::KeyFile failed. This usually means that the configuration file is not correctly defining or protecting the directories/files lonCertificateDirectory or lonnetPrivateKey @@ -8679,9 +9004,9 @@ or the CA's certificate in the call to l <error> is the textual reason this failed. Usual reasons: =over 2 - + =item Apache config file for loncapa incorrect: - + one of the variables lonCertificateDirectory, lonnetCertificateAuthority, or lonnetCertificate undefined or incorrect @@ -8800,7 +9125,7 @@ Could not rewrite the internal password file for a user =item Result of password change for <user> : <result> - + A unix password change for <user> was attempted and the pipe returned <result> @@ -8829,7 +9154,7 @@ lond has been asked to exit by its clien client systemand <input> is the full exit command sent to the server. =item Red CRITICAL: ABNORMAL EXIT. child <pid> for server <hostname> died through a crass with this error->[<message>]. - + A lond child terminated. NOte that this termination can also occur when the child receives the QUIT or DIE signals. <pid> is the process id of the child, <hostname> the host lond is working for, and <message> the reason the child died @@ -8913,7 +9238,7 @@ file when sent it's USR1 signal. That p assumed to be hung in some un-fixable way. =item Finished checking children - + Master processs's USR1 processing is cojmplete. =item (Red) CRITICAL: ------- Starting ------ @@ -8927,7 +9252,7 @@ Started a new child process for <client> connected to the child. This was as a result of a TCP/IP connection from a client. =item Unable to determine who caller was, getpeername returned nothing - + In child process initialization. either getpeername returned undef or a zero sized object was returned. Processing continues, but in my opinion, this should be cause for the child to exit. @@ -8938,7 +9263,7 @@ In child process initialization. The pe The client address is stored as "Unavailable" and processing continues. =item (Yellow) INFO: Connection <ip> <name> connection type = <type> - + In child initialization. A good connectionw as received from <ip>. =over 2 @@ -8988,7 +9313,7 @@ The client (<client> is the peer's name negotiated an SSL connection with this child process. =item (Green) Successful insecure authentication with <client> - + The client has successfully negotiated an insecure connection withthe child process.