--- loncom/lond 2016/08/11 16:35:14 1.524 +++ loncom/lond 2016/09/12 20:20:44 1.525 @@ -2,7 +2,7 @@ # The LearningOnline Network # lond "LON Daemon" Server (port "LOND" 5663) # -# $Id: lond,v 1.524 2016/08/11 16:35:14 raeburn Exp $ +# $Id: lond,v 1.525 2016/09/12 20:20:44 raeburn Exp $ # # Copyright Michigan State University Board of Trustees # @@ -15,7 +15,6 @@ # # LON-CAPA is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of - # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # @@ -65,7 +64,7 @@ my $DEBUG = 0; # Non zero to ena my $status=''; my $lastlog=''; -my $VERSION='$Revision: 1.524 $'; #' stupid emacs +my $VERSION='$Revision: 1.525 $'; #' stupid emacs my $remoteVERSION; my $currenthostid="default"; my $currentdomainid; @@ -75,8 +74,14 @@ 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 $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; @@ -146,6 +151,144 @@ 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") +# 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}, + 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 + ekey => {}, #not used currently + 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}, + 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}, + serverdistarch => {manageronly => 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 => {anywhere => 1}, + tmpget => {anywhere => 1}, + tmpput => {anywhere => 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. @@ -1938,7 +2081,7 @@ sub authenticate_handler { my ($remote,$hosted); my $remotesession = &get_usersession_config($udom,'remotesession'); if (ref($remotesession) eq 'HASH') { - $remote = $remotesession->{'remote'} + $remote = $remotesession->{'remote'}; } my $hostedsession = &get_usersession_config($clienthomedom,'hostedsession'); if (ref($hostedsession) eq 'HASH') { @@ -6178,12 +6321,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 @@ -6263,6 +6407,49 @@ sub process_request { Debug("Client not privileged to do this operation"); $ok = 0; } + if ($ok) { + 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; + } + } + } + } + } if($ok) { Debug("Dispatching to handler $command $tail"); @@ -6273,8 +6460,7 @@ sub process_request { Failure($client, "refused\n", $userinput); return 1; } - - } + } print $client "unknown_cmd\n"; # -------------------------------------------------------------------- complete @@ -7031,6 +7217,41 @@ sub make_new_child { my $clienthost = &Apache::lonnet::hostname($clientname); my $clientserverhomeID = &Apache::lonnet::get_server_homeID($clienthost); $clienthomedom = &Apache::lonnet::host_domain($clientserverhomeID); + $clientintdom = &Apache::lonnet::internet_dom($clientserverhomeID); + $clientsameinst = 0; + if ($clientintdom ne '') { + my $internet_names = &Apache::lonnet::get_internet_names($currenthostid); + if (ref($internet_names) eq 'ARRAY') { + if (grep(/^\Q$clientintdom\E$/,@{$internet_names})) { + $clientsameinst = 1; + } + } + } + $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"); @@ -7046,7 +7267,7 @@ sub make_new_child { &logthis("WARNING: " ."Rejected client $clientip, closing connection"); } - } + } # ============================================================================= @@ -7789,16 +8010,46 @@ 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; } - - +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;