--- loncom/lond 2002/05/08 02:31:04 1.79 +++ loncom/lond 2002/08/22 21:37:35 1.92 @@ -2,7 +2,7 @@ # The LearningOnline Network # lond "LON Daemon" Server (port "LOND" 5663) # -# $Id: lond,v 1.79 2002/05/08 02:31:04 foxr Exp $ +# $Id: lond,v 1.92 2002/08/22 21:37:35 albertel Exp $ # # Copyright Michigan State University Board of Trustees # @@ -53,6 +53,7 @@ # 02/12 Gerd Kortemeyer # 02/19 Matthew Hall # 02/25 Gerd Kortemeyer +# 05/11 Scott Harrison ### # based on "Perl Cookbook" ISBN 1-56592-243-3 @@ -61,6 +62,9 @@ # HUPs # uses IDEA encryption +use lib '/home/httpd/lib/perl/'; +use LONCAPA::Configuration; + use IO::Socket; use IO::File; use Apache::File; @@ -70,6 +74,7 @@ use Crypt::IDEA; use LWP::UserAgent(); use GDBM_File; use Authen::Krb4; +use Authen::Krb5; use lib '/home/httpd/lib/perl/'; use localauth; @@ -101,18 +106,12 @@ sub timeout { $SIG{'QUIT'}=\&catchexception; $SIG{__DIE__}=\&catchexception; -# ------------------------------------ Read httpd access.conf and get variables - -open (CONFIG,"/etc/httpd/conf/access.conf") || die "Can't read access.conf"; - -while ($configline=) { - if ($configline =~ /PerlSetVar/) { - my ($dummy,$varname,$varvalue)=split(/\s+/,$configline); - chomp($varvalue); - $perlvar{$varname}=$varvalue; - } -} -close(CONFIG); +# ---------------------------------- Read loncapa_apache.conf and loncapa.conf +&status("Read loncapa_apache.conf and loncapa.conf"); +my $perlvarref=LONCAPA::Configuration::read_conf('loncapa_apache.conf', + 'loncapa.conf'); +my %perlvar=%{$perlvarref}; +undef $perlvarref; # ----------------------------- Make sure this process is running from user=www my $wwwid=getpwnam('www'); @@ -490,7 +489,10 @@ sub make_new_child { or die "Can't unblock SIGINT for fork: $!\n"; $tmpsnum=0; - +#---------------------------------------------------- kerberos 5 initialization + &Authen::Krb5::init_context(); + &Authen::Krb5::init_ets(); + # handle connections until we've reached $MAX_CLIENTS_PER_CHILD for ($i=0; $i < $MAX_CLIENTS_PER_CHILD; $i++) { &status('Idle, waiting for connection'); @@ -654,6 +656,23 @@ sub make_new_child { $contentpwd,'krbtgt',$contentpwd,1, $upass) == 0); } else { $pwdcorrect=0; } + } elsif ($howpwd eq 'krb5') { + $null=pack("C",0); + unless ($upass=~/$null/) { + my $krbclient=&Authen::Krb5::parse_name($uname.'@'.$contentpwd); + my $krbservice="krbtgt/".$contentpwd."\@".$contentpwd; + 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,$krbserver,$upass,$credentials); +# unless ($krbreturn) { +# &logthis("Krb5 Error: ". +# &Authen::Krb5::error()); +# } + $pwdcorrect = ($krbreturn == 1); + } else { $pwdcorrect=0; } } elsif ($howpwd eq 'localauth') { $pwdcorrect=&localauth::localauth($uname,$upass, $contentpwd); @@ -739,7 +758,7 @@ sub make_new_child { } # -------------------------------------------------------------------- makeuser } elsif ($userinput =~ /^makeuser/) { - Debug("Make user received"); + &Debug("Make user received"); my $oldumask=umask(0077); if ($wasenc==1) { my @@ -769,53 +788,9 @@ sub make_new_child { } } unless ($fperror) { - if ($umode eq 'krb4') { - { - my $pf = IO::File->new(">$passfilename"); - print $pf "krb4:$npass\n"; - } - print $client "ok\n"; - } elsif ($umode eq 'internal') { - my $salt=time; - $salt=substr($salt,6,2); - my $ncpass=crypt($npass,$salt); - { - &Debug("Creating internal auth"); - my $pf = IO::File->new(">$passfilename"); - print $pf "internal:$ncpass\n"; - } - print $client "ok\n"; - } elsif ($umode eq 'localauth') { - { - my $pf = IO::File->new(">$passfilename"); - print $pf "localauth:$npass\n"; - } - print $client "ok\n"; - } elsif ($umode eq 'unix') { - { - my $execpath="$perlvar{'lonDaemons'}/". - "lcuseradd"; - { - &Debug("Executing external: ". - $execpath); - my $se = IO::File->new("|$execpath"); - print $se "$uname\n"; - print $se "$npass\n"; - print $se "$npass\n"; - } - my $pf = IO::File->new(">$passfilename"); - print $pf "unix:\n"; - } - print $client "ok\n"; - } elsif ($umode eq 'none') { - { - my $pf = IO::File->new(">$passfilename"); - print $pf "none:\n"; - } - print $client "ok\n"; - } else { - print $client "auth_mode_error\n"; - } + my $result=&make_passwd_file($umode,$npass, + $passfilename); + print $client $result; } else { print $client "$fperror\n"; } @@ -829,60 +804,18 @@ sub make_new_child { &Debug("Changing authorization"); if ($wasenc==1) { my - ($cmd,$udom,$uname,$umode,$npass)=split(/:/,$userinput); + ($cmd,$udom,$uname,$umode,$npass)=split(/:/,$userinput); chomp($npass); &Debug("cmd = ".$cmd." domain= ".$udom. "uname =".$uname." umode= ".$umode); $npass=&unescape($npass); - my $proname=propath($udom,$uname); + my $proname=&propath($udom,$uname); my $passfilename="$proname/passwd"; if ($udom ne $perlvar{'lonDefDomain'}) { print $client "not_right_domain\n"; } else { - if ($umode eq 'krb4') { - { - my $pf = IO::File->new(">$passfilename"); - print $pf "krb4:$npass\n"; - } - print $client "ok\n"; - } elsif ($umode eq 'internal') { - my $salt=time; - $salt=substr($salt,6,2); - my $ncpass=crypt($npass,$salt); - { - my $pf = IO::File->new(">$passfilename"); - print $pf "internal:$ncpass\n"; - } - print $client "ok\n"; - } elsif ($umode eq 'localauth') { - { - my $pf = IO::File->new(">$passfilename"); - print $pf "localauth:$npass\n"; - } - print $client "ok\n"; - } elsif ($umode eq 'unix') { - { - my $execpath="$perlvar{'lonDaemons'}/". - "lcuseradd"; - { - my $se = IO::File->new("|$execpath"); - print $se "$uname\n"; - print $se "$npass\n"; - print $se "$npass\n"; - } - my $pf = IO::File->new(">$passfilename"); - print $pf "unix:\n"; - } - print $client "ok\n"; - } elsif ($umode eq 'none') { - { - my $pf = IO::File->new(">$passfilename"); - print $pf "none:\n"; - } - print $client "ok\n"; - } else { - print $client "auth_mode_error\n"; - } + &make_passwd_file($umode,$npass,$passfilename); + print $client $result; } } else { print $client "refused\n"; @@ -949,48 +882,61 @@ sub make_new_child { } else { print $client "rejected\n"; } +# -------------------------------------- fetch a user file from a remote server + } elsif ($userinput =~ /^fetchuserfile/) { + my ($cmd,$fname)=split(/:/,$userinput); + my ($udom,$uname,$ufile)=split(/\//,$fname); + my $udir=propath($udom,$uname).'/userfiles'; + unless (-e $udir) { mkdir($udir,0770); } + if (-e $udir) { + $ufile=~s/^[\.\~]+//; + $ufile=~s/\///g; + my $transname=$udir.'/'.$ufile; + my $remoteurl='http://'.$clientip.'/userfiles/'.$fname; + my $response; + { + my $ua=new LWP::UserAgent; + my $request=new HTTP::Request('GET',"$remoteurl"); + $response=$ua->request($request,$transname); + } + if ($response->is_error()) { + unlink($transname); + my $message=$response->status_line; + &logthis( + "LWP GET: $message for $fname ($remoteurl)"); + print $client "failed\n"; + } else { + print $client "ok\n"; + } + } else { + print $client "not_home\n"; + } +# ------------------------------------------ authenticate access to a user file + } elsif ($userinput =~ /^tokenauthuserfile/) { + my ($cmd,$fname,$session)=split(/:/,$userinput); + chomp($session); + $reply='non_auth'; + if (open(ENVIN,$perlvar{'lonIDsDir'}.'/'. + $session.'.id')) { + while ($line=) { + if ($line=~/userfile\.$fname\=/) { $reply='ok'; } + } + close(ENVIN); + print $client $reply."\n"; + } else { + print $client "invalid_token\n"; + } # ----------------------------------------------------------------- unsubscribe } elsif ($userinput =~ /^unsub/) { my ($cmd,$fname)=split(/:/,$userinput); if (-e $fname) { - if (unlink("$fname.$hostid{$clientip}")) { - print $client "ok\n"; - } else { - print $client "not_subscribed\n"; - } + print $client &unsub($client,$fname,$clientip); } else { print $client "not_found\n"; } # ------------------------------------------------------------------- subscribe } elsif ($userinput =~ /^sub/) { - my ($cmd,$fname)=split(/:/,$userinput); - my $ownership=ishome($fname); - if ($ownership eq 'owner') { - if (-e $fname) { - if (-d $fname) { - print $client "directory\n"; - } else { - $now=time; - { - my $sh; - if ($sh= - IO::File->new(">$fname.$hostid{$clientip}")) { - print $sh "$clientip:$now\n"; - } - } - unless ($fname=~/\.meta$/) { - unlink("$fname.meta.$hostid{$clientip}"); - } - $fname=~s/\/home\/httpd\/html\/res/raw/; - $fname="http://$thisserver/".$fname; - print $client "$fname\n"; - } - } else { - print $client "not_found\n"; - } - } else { - print $client "rejected\n"; - } + print $client &subscribe($userinput,$clientip); # ------------------------------------------------------------------------- log } elsif ($userinput =~ /^log/) { my ($cmd,$udom,$uname,$what)=split(/:/,$userinput); @@ -1203,10 +1149,12 @@ sub make_new_child { my $proname=propath($udom,$uname); my $qresult=''; if (tie(%hash,'GDBM_File',"$proname/$namespace.db",&GDBM_READER,0640)) { + study($regexp); foreach $key (keys %hash) { - if (eval('$key=~/$regexp/')) { + my $unescapeKey = &unescape($key); + if (eval('$unescapeKey=~/$regexp/')) { $qresult.="$key=$hash{$key}&"; - } + } } if (untie(%hash)) { $qresult=~s/\&$//; @@ -1291,20 +1239,28 @@ sub make_new_child { } else { print $client "error:$!\n"; } +# -------------------------------------------------------------------- chatsend + } elsif ($userinput =~ /^chatsend/) { + my ($cmd,$cdom,$cnum,$newpost)=split(/\:/,$userinput); + &chatadd($cdom,$cnum,$newpost); + print $client "ok\n"; +# -------------------------------------------------------------------- chatretr + } elsif ($userinput =~ /^chatretr/) { + my ($cmd,$cdom,$cnum)=split(/\:/,$userinput); + my $reply=''; + foreach (&getchat($cdom,$cnum)) { + $reply.=&escape($_).':'; + } + $reply=~s/\:$//; + print $client $reply."\n"; # ------------------------------------------------------------------- querysend } elsif ($userinput =~ /^querysend/) { my ($cmd,$query, - $custom,$customshow)=split(/:/,$userinput); + $arg1,$arg2,$arg3)=split(/\:/,$userinput); $query=~s/\n*$//g; - unless ($custom or $customshow) { - print $client "". - sqlreply("$hostid{$clientip}\&$query")."\n"; - } - else { - print $client "". + print $client "". sqlreply("$hostid{$clientip}\&$query". - "\&$custom"."\&$customshow")."\n"; - } + "\&$arg1"."\&$arg2"."\&$arg3")."\n"; # ------------------------------------------------------------------ queryreply } elsif ($userinput =~ /^queryreply/) { my ($cmd,$id,$reply)=split(/:/,$userinput); @@ -1410,14 +1366,20 @@ sub make_new_child { my $ulsout=''; my $ulsfn; if (-e $ulsdir) { - if (opendir(LSDIR,$ulsdir)) { - while ($ulsfn=readdir(LSDIR)) { - my @ulsstats=stat($ulsdir.'/'.$ulsfn); - $ulsout.=$ulsfn.'&'.join('&',@ulsstats).':'; - } - closedir(LSDIR); - } - } else { + if(-d $ulsdir) { + if (opendir(LSDIR,$ulsdir)) { + while ($ulsfn=readdir(LSDIR)) { + my @ulsstats=stat($ulsdir.'/'.$ulsfn); + $ulsout.=$ulsfn.'&'. + join('&',@ulsstats).':'; + } + closedir(LSDIR); + } + } else { + my @ulsstats=stat($ulsdir); + $ulsout.=$ulsfn.'&'.join('&',@ulsstats).':'; + } + } else { $ulsout='no_such_dir'; } if ($ulsout eq '') { $ulsout='empty'; } @@ -1512,7 +1474,7 @@ sub GetAuthType my ($authtype, $contentpwd) = split(/:/, $realpassword); Debug("Authtype = $authtype, content = $contentpwd\n"); my $availinfo = ''; - if($authtype eq 'krb4') { + if($authtype eq 'krb4' or $authtype eq 'krb5') { $availinfo = $contentpwd; } @@ -1522,7 +1484,163 @@ sub GetAuthType Debug("Returning nouser"); return "nouser"; } - +} + +sub addline { + my ($fname,$hostid,$ip,$newline)=@_; + my $contents; + my $found=0; + my $expr='^'.$hostid.':'.$ip.':'; + $expr =~ s/\./\\\./g; + if ($sh=IO::File->new("$fname.subscription")) { + while (my $subline=<$sh>) { + if ($subline !~ /$expr/) {$contents.= $subline;} else {$found=1;} + } + $sh->close(); + } + $sh=IO::File->new(">$fname.subscription"); + if ($contents) { print $sh $contents; } + if ($newline) { print $sh $newline; } + $sh->close(); + return $found; +} + +sub getchat { + my ($cdom,$cname)=@_; + my %hash; + my $proname=&propath($cdom,$cname); + my @entries=(); + if (tie(%hash,'GDBM_File',"$proname/nohist_chatroom.db", + &GDBM_READER(),0640)) { + @entries=map { $_.':'.$hash{$_} } sort keys %hash; + untie %hash; + } + return @entries; +} + +sub chatadd { + my ($cdom,$cname,$newchat)=@_; + my %hash; + my $proname=&propath($cdom,$cname); + my @entries=(); + if (tie(%hash,'GDBM_File',"$proname/nohist_chatroom.db", + &GDBM_WRCREAT(),0640)) { + @entries=map { $_.':'.$hash{$_} } sort keys %hash; + my $time=time; + my ($lastid)=($entries[$#entries]=~/^(\w+)\:/); + my ($thentime,$idnum)=split(/\_/,$lastid); + my $newid=$time.'_000000'; + if ($thentime==$time) { + $idnum=~s/^0+//; + $idnum++; + $idnum=substr('000000'.$idnum,-6,6); + $newid=$time.'_'.$idnum; + } + $hash{$newid}=$newchat; + my $expired=$time-3600; + foreach (keys %hash) { + my ($thistime)=($_=~/(\d+)\_/); + if ($thistime<$expired) { + delete $hash{$_}; + } + } + untie %hash; + } +} + +sub unsub { + my ($fname,$clientip)=@_; + my $result; + if (unlink("$fname.$hostid{$clientip}")) { + $result="ok\n"; + } else { + $result="not_subscribed\n"; + } + if (-e "$fname.subscription") { + my $found=&addline($fname,$hostid{$clientip},$clientip,''); + if ($found) { $result="ok\n"; } + } else { + if ($result != "ok\n") { $result="not_subscribed\n"; } + } + return $result; +} + +sub subscribe { + my ($userinput,$clientip)=@_; + my $result; + my ($cmd,$fname)=split(/:/,$userinput); + my $ownership=&ishome($fname); + if ($ownership eq 'owner') { + if (-e $fname) { + if (-d $fname) { + $result="directory\n"; + } else { + if (-e "$fname.$hostid{$clientip}") {&unsub($fname,$clientip);} + $now=time; + my $found=&addline($fname,$hostid{$clientip},$clientip, + "$hostid{$clientip}:$clientip:$now\n"); + if ($found) { $result="$fname\n"; } + # if they were subscribed to only meta data, delete that + # subscription, when you subscribe to a file you also get + # the metadata + unless ($fname=~/\.meta$/) { &unsub("$fname.meta",$clientip); } + $fname=~s/\/home\/httpd\/html\/res/raw/; + $fname="http://$thisserver/".$fname; + $result="$fname\n"; + } + } else { + $result="not_found\n"; + } + } else { + $result="rejected\n"; + } + return $result; +} + +sub make_passwd_file { + my ($umode,$npass,$passfilename)=@_; + my $result="ok\n"; + if ($umode eq 'krb4' or $umode eq 'krb5') { + { + my $pf = IO::File->new(">$passfilename"); + print $pf "$umode:$npass\n"; + } + } elsif ($umode eq 'internal') { + my $salt=time; + $salt=substr($salt,6,2); + my $ncpass=crypt($npass,$salt); + { + &Debug("Creating internal auth"); + my $pf = IO::File->new(">$passfilename"); + print $pf "internal:$ncpass\n"; + } + } elsif ($umode eq 'localauth') { + { + my $pf = IO::File->new(">$passfilename"); + print $pf "localauth:$npass\n"; + } + } elsif ($umode eq 'unix') { + { + my $execpath="$perlvar{'lonDaemons'}/"."lcuseradd"; + { + &Debug("Executing external: ".$execpath); + my $se = IO::File->new("|$execpath"); + print $se "$uname\n"; + print $se "$npass\n"; + print $se "$npass\n"; + } + my $pf = IO::File->new(">$passfilename"); + print $pf "unix:\n"; + } + } elsif ($umode eq 'none') { + { + my $pf = IO::File->new(">$passfilename"); + print $pf "none:\n"; + } + } else { + $result="auth_mode_error\n"; + } + return $result; } # ----------------------------------- POD (plain old documentation, CPAN style) @@ -1823,6 +1941,7 @@ Crypt::IDEA LWP::UserAgent() GDBM_File Authen::Krb4 +Authen::Krb5 =head1 COREQUISITES