File:  [LON-CAPA] / loncom / lond
Revision 1.48: download - view: text, annotated - select for diffs
Mon May 28 13:13:58 2001 UTC (22 years, 11 months ago) by www
Branches: MAIN
CVS tags: HEAD
Nohist implemented and other TODO updates

    1: #!/usr/bin/perl
    2: # The LearningOnline Network
    3: # lond "LON Daemon" Server (port "LOND" 5663)
    4: # 5/26/99,6/4,6/10,6/11,6/14,6/15,6/26,6/28,6/30,
    5: # 7/8,7/9,7/10,7/12,7/17,7/19,9/21,
    6: # 10/7,10/8,10/9,10/11,10/13,10/15,11/4,11/16,
    7: # 12/7,12/15,01/06,01/11,01/12,01/14,2/8,
    8: # 03/07,05/31 Gerd Kortemeyer
    9: # 06/26 Scott Harrison
   10: # 06/29,06/30,07/14,07/15,07/17,07/20,07/25,09/18 Gerd Kortemeyer
   11: # 12/05 Scott Harrison
   12: # 12/05,12/13,12/29 Gerd Kortemeyer
   13: # Jan 01 Scott Harrison
   14: # 02/12 Gerd Kortemeyer
   15: # 03/15 Scott Harrison
   16: # 03/24 Gerd Kortemeyer
   17: # 04/02 Scott Harrison
   18: # 05/11,05/28 Gerd Kortemeyer
   19: #
   20: # based on "Perl Cookbook" ISBN 1-56592-243-3
   21: # preforker - server who forks first
   22: # runs as a daemon
   23: # HUPs
   24: # uses IDEA encryption
   25: 
   26: use IO::Socket;
   27: use IO::File;
   28: use Apache::File;
   29: use Symbol;
   30: use POSIX;
   31: use Crypt::IDEA;
   32: use LWP::UserAgent();
   33: use GDBM_File;
   34: use Authen::Krb4;
   35: 
   36: # grabs exception and records it to log before exiting
   37: sub catchexception {
   38:     my ($error)=@_;
   39:     $SIG{'QUIT'}='DEFAULT';
   40:     $SIG{__DIE__}='DEFAULT';
   41:     &logthis("<font color=red>CRITICAL: "
   42:      ."ABNORMAL EXIT. Child $$ for server $wasserver died through "
   43:      ."a crash with this error msg->[$error]</font>");
   44:     if ($client) { print $client "error: $error\n"; }
   45:     die($error);
   46: }
   47: 
   48: # -------------------------------- Set signal handlers to record abnormal exits
   49: 
   50: $SIG{'QUIT'}=\&catchexception;
   51: $SIG{__DIE__}=\&catchexception;
   52: 
   53: # ------------------------------------ Read httpd access.conf and get variables
   54: 
   55: open (CONFIG,"/etc/httpd/conf/access.conf") || die "Can't read access.conf";
   56: 
   57: while ($configline=<CONFIG>) {
   58:     if ($configline =~ /PerlSetVar/) {
   59: 	my ($dummy,$varname,$varvalue)=split(/\s+/,$configline);
   60:         chomp($varvalue);
   61:         $perlvar{$varname}=$varvalue;
   62:     }
   63: }
   64: close(CONFIG);
   65: 
   66: # ----------------------------- Make sure this process is running from user=www
   67: my $wwwid=getpwnam('www');
   68: if ($wwwid!=$<) {
   69:    $emailto="$perlvar{'lonAdmEMail'},$perlvar{'lonSysEMail'}";
   70:    $subj="LON: $perlvar{'lonHostID'} User ID mismatch";
   71:    system("echo 'User ID mismatch.  lond must be run as user www.' |\
   72:  mailto $emailto -s '$subj' > /dev/null");
   73:    exit 1;
   74: }
   75: 
   76: # --------------------------------------------- Check if other instance running
   77: 
   78: my $pidfile="$perlvar{'lonDaemons'}/logs/lond.pid";
   79: 
   80: if (-e $pidfile) {
   81:    my $lfh=IO::File->new("$pidfile");
   82:    my $pide=<$lfh>;
   83:    chomp($pide);
   84:    if (kill 0 => $pide) { die "already running"; }
   85: }
   86: 
   87: $PREFORK=4; # number of children to maintain, at least four spare
   88: 
   89: # ------------------------------------------------------------- Read hosts file
   90: 
   91: open (CONFIG,"$perlvar{'lonTabDir'}/hosts.tab") || die "Can't read host file";
   92: 
   93: while ($configline=<CONFIG>) {
   94:     my ($id,$domain,$role,$name,$ip)=split(/:/,$configline);
   95:     chomp($ip);
   96:     $hostid{$ip}=$id;
   97:     if ($id eq $perlvar{'lonHostID'}) { $thisserver=$name; }
   98:     $PREFORK++;
   99: }
  100: close(CONFIG);
  101: 
  102: # establish SERVER socket, bind and listen.
  103: $server = IO::Socket::INET->new(LocalPort => $perlvar{'londPort'},
  104:                                 Type      => SOCK_STREAM,
  105:                                 Proto     => 'tcp',
  106:                                 Reuse     => 1,
  107:                                 Listen    => 10 )
  108:   or die "making socket: $@\n";
  109: 
  110: # --------------------------------------------------------- Do global variables
  111: 
  112: # global variables
  113: 
  114: $MAX_CLIENTS_PER_CHILD  = 5;        # number of clients each child should 
  115:                                     # process
  116: %children               = ();       # keys are current child process IDs
  117: $children               = 0;        # current number of children
  118: 
  119: sub REAPER {                        # takes care of dead children
  120:     $SIG{CHLD} = \&REAPER;
  121:     my $pid = wait;
  122:     $children --;
  123:     &logthis("Child $pid died");
  124:     delete $children{$pid};
  125: }
  126: 
  127: sub HUNTSMAN {                      # signal handler for SIGINT
  128:     local($SIG{CHLD}) = 'IGNORE';   # we're going to kill our children
  129:     kill 'INT' => keys %children;
  130:     my $execdir=$perlvar{'lonDaemons'};
  131:     unlink("$execdir/logs/lond.pid");
  132:     &logthis("<font color=red>CRITICAL: Shutting down</font>");
  133:     exit;                           # clean up with dignity
  134: }
  135: 
  136: sub HUPSMAN {                      # signal handler for SIGHUP
  137:     local($SIG{CHLD}) = 'IGNORE';  # we're going to kill our children
  138:     kill 'INT' => keys %children;
  139:     close($server);                # free up socket
  140:     &logthis("<font color=red>CRITICAL: Restarting</font>");
  141:     unlink("$execdir/logs/lond.pid");
  142:     my $execdir=$perlvar{'lonDaemons'};
  143:     exec("$execdir/lond");         # here we go again
  144: }
  145: 
  146: # --------------------------------------------------------------------- Logging
  147: 
  148: sub logthis {
  149:     my $message=shift;
  150:     my $execdir=$perlvar{'lonDaemons'};
  151:     my $fh=IO::File->new(">>$execdir/logs/lond.log");
  152:     my $now=time;
  153:     my $local=localtime($now);
  154:     print $fh "$local ($$): $message\n";
  155: }
  156: 
  157: 
  158: # -------------------------------------------------------- Escape Special Chars
  159: 
  160: sub escape {
  161:     my $str=shift;
  162:     $str =~ s/(\W)/"%".unpack('H2',$1)/eg;
  163:     return $str;
  164: }
  165: 
  166: # ----------------------------------------------------- Un-Escape Special Chars
  167: 
  168: sub unescape {
  169:     my $str=shift;
  170:     $str =~ s/%([a-fA-F0-9][a-fA-F0-9])/pack("C",hex($1))/eg;
  171:     return $str;
  172: }
  173: 
  174: # ----------------------------------------------------------- Send USR1 to lonc
  175: 
  176: sub reconlonc {
  177:     my $peerfile=shift;
  178:     &logthis("Trying to reconnect for $peerfile");
  179:     my $loncfile="$perlvar{'lonDaemons'}/logs/lonc.pid";
  180:     if (my $fh=IO::File->new("$loncfile")) {
  181: 	my $loncpid=<$fh>;
  182:         chomp($loncpid);
  183:         if (kill 0 => $loncpid) {
  184: 	    &logthis("lonc at pid $loncpid responding, sending USR1");
  185:             kill USR1 => $loncpid;
  186:             sleep 1;
  187:             if (-e "$peerfile") { return; }
  188:             &logthis("$peerfile still not there, give it another try");
  189:             sleep 5;
  190:             if (-e "$peerfile") { return; }
  191:             &logthis(
  192:  "<font color=blue>WARNING: $peerfile still not there, giving up</font>");
  193:         } else {
  194: 	    &logthis(
  195:               "<font color=red>CRITICAL: "
  196:              ."lonc at pid $loncpid not responding, giving up</font>");
  197:         }
  198:     } else {
  199:       &logthis('<font color=red>CRITICAL: lonc not running, giving up</font>');
  200:     }
  201: }
  202: 
  203: # -------------------------------------------------- Non-critical communication
  204: 
  205: sub subreply {
  206:     my ($cmd,$server)=@_;
  207:     my $peerfile="$perlvar{'lonSockDir'}/$server";
  208:     my $sclient=IO::Socket::UNIX->new(Peer    =>"$peerfile",
  209:                                       Type    => SOCK_STREAM,
  210:                                       Timeout => 10)
  211:        or return "con_lost";
  212:     print $sclient "$cmd\n";
  213:     my $answer=<$sclient>;
  214:     chomp($answer);
  215:     if (!$answer) { $answer="con_lost"; }
  216:     return $answer;
  217: }
  218: 
  219: sub reply {
  220:   my ($cmd,$server)=@_;
  221:   my $answer;
  222:   if ($server ne $perlvar{'lonHostID'}) { 
  223:     $answer=subreply($cmd,$server);
  224:     if ($answer eq 'con_lost') {
  225: 	$answer=subreply("ping",$server);
  226:         if ($answer ne $server) {
  227:            &reconlonc("$perlvar{'lonSockDir'}/$server");
  228:         }
  229:         $answer=subreply($cmd,$server);
  230:     }
  231:   } else {
  232:     $answer='self_reply';
  233:   } 
  234:   return $answer;
  235: }
  236: 
  237: # -------------------------------------------------------------- Talk to lonsql
  238: 
  239: sub sqlreply {
  240:     my ($cmd)=@_;
  241:     my $answer=subsqlreply($cmd);
  242:     if ($answer eq 'con_lost') { $answer=subsqlreply($cmd); }
  243:     return $answer;
  244: }
  245: 
  246: sub subsqlreply {
  247:     my ($cmd)=@_;
  248:     my $unixsock="mysqlsock";
  249:     my $peerfile="$perlvar{'lonSockDir'}/$unixsock";
  250:     my $sclient=IO::Socket::UNIX->new(Peer    =>"$peerfile",
  251:                                       Type    => SOCK_STREAM,
  252:                                       Timeout => 10)
  253:        or return "con_lost";
  254:     print $sclient "$cmd\n";
  255:     my $answer=<$sclient>;
  256:     chomp($answer);
  257:     if (!$answer) { $answer="con_lost"; }
  258:     return $answer;
  259: }
  260: 
  261: # -------------------------------------------- Return path to profile directory
  262: 
  263: sub propath {
  264:     my ($udom,$uname)=@_;
  265:     $udom=~s/\W//g;
  266:     $uname=~s/\W//g;
  267:     my $subdir=$uname.'__';
  268:     $subdir =~ s/(.)(.)(.).*/$1\/$2\/$3/;
  269:     my $proname="$perlvar{'lonUsersDir'}/$udom/$subdir/$uname";
  270:     return $proname;
  271: } 
  272: 
  273: # --------------------------------------- Is this the home server of an author?
  274: 
  275: sub ishome {
  276:     my $author=shift;
  277:     $author=~s/\/home\/httpd\/html\/res\/([^\/]*)\/([^\/]*).*/$1\/$2/;
  278:     my ($udom,$uname)=split(/\//,$author);
  279:     my $proname=propath($udom,$uname);
  280:     if (-e $proname) {
  281: 	return 'owner';
  282:     } else {
  283:         return 'not_owner';
  284:     }
  285: }
  286: 
  287: # ======================================================= Continue main program
  288: # ---------------------------------------------------- Fork once and dissociate
  289: 
  290: $fpid=fork;
  291: exit if $fpid;
  292: die "Couldn't fork: $!" unless defined ($fpid);
  293: 
  294: POSIX::setsid() or die "Can't start new session: $!";
  295: 
  296: # ------------------------------------------------------- Write our PID on disk
  297: 
  298: $execdir=$perlvar{'lonDaemons'};
  299: open (PIDSAVE,">$execdir/logs/lond.pid");
  300: print PIDSAVE "$$\n";
  301: close(PIDSAVE);
  302: &logthis("<font color=red>CRITICAL: ---------- Starting ----------</font>");
  303: 
  304: # ------------------------------------------------------- Now we are on our own
  305:     
  306: # Fork off our children.
  307: for (1 .. $PREFORK) {
  308:     make_new_child();
  309: }
  310: 
  311: # ----------------------------------------------------- Install signal handlers
  312: 
  313: $SIG{CHLD} = \&REAPER;
  314: $SIG{INT}  = $SIG{TERM} = \&HUNTSMAN;
  315: $SIG{HUP}  = \&HUPSMAN;
  316: 
  317: # And maintain the population.
  318: while (1) {
  319:     sleep;                          # wait for a signal (i.e., child's death)
  320:     for ($i = $children; $i < $PREFORK; $i++) {
  321:         make_new_child();           # top up the child pool
  322:     }
  323: }
  324: 
  325: sub make_new_child {
  326:     my $pid;
  327:     my $cipher;
  328:     my $sigset;
  329:     &logthis("Attempting to start child");    
  330:     # block signal for fork
  331:     $sigset = POSIX::SigSet->new(SIGINT);
  332:     sigprocmask(SIG_BLOCK, $sigset)
  333:         or die "Can't block SIGINT for fork: $!\n";
  334:     
  335:     die "fork: $!" unless defined ($pid = fork);
  336:     
  337:     if ($pid) {
  338:         # Parent records the child's birth and returns.
  339:         sigprocmask(SIG_UNBLOCK, $sigset)
  340:             or die "Can't unblock SIGINT for fork: $!\n";
  341:         $children{$pid} = 1;
  342:         $children++;
  343:         return;
  344:     } else {
  345:         # Child can *not* return from this subroutine.
  346:         $SIG{INT} = 'DEFAULT';      # make SIGINT kill us as it did before
  347:     
  348:         # unblock signals
  349:         sigprocmask(SIG_UNBLOCK, $sigset)
  350:             or die "Can't unblock SIGINT for fork: $!\n";
  351: 
  352:         $tmpsnum=0;
  353:     
  354:         # handle connections until we've reached $MAX_CLIENTS_PER_CHILD
  355:         for ($i=0; $i < $MAX_CLIENTS_PER_CHILD; $i++) {
  356:             $client = $server->accept()     or last;
  357: 
  358: # =============================================================================
  359:             # do something with the connection
  360: # -----------------------------------------------------------------------------
  361:             # see if we know client and check for spoof IP by challenge
  362:             my $caller=getpeername($client);
  363:             my ($port,$iaddr)=unpack_sockaddr_in($caller);
  364:             my $clientip=inet_ntoa($iaddr);
  365:             my $clientrec=($hostid{$clientip} ne undef);
  366:             &logthis(
  367: "<font color=yellow>INFO: Connect from $clientip ($hostid{$clientip})</font>");
  368:             my $clientok;
  369:             if ($clientrec) {
  370: 	      my $remotereq=<$client>;
  371:               $remotereq=~s/\W//g;
  372:               if ($remotereq eq 'init') {
  373: 		  my $challenge="$$".time;
  374:                   print $client "$challenge\n";
  375:                   $remotereq=<$client>;
  376:                   $remotereq=~s/\W//g;
  377:                   if ($challenge eq $remotereq) {
  378: 		      $clientok=1;
  379:                       print $client "ok\n";
  380:                   } else {
  381: 		      &logthis(
  382:  "<font color=blue>WARNING: $clientip did not reply challenge</font>");
  383:                       print $client "bye\n";
  384:                   }
  385:               } else {
  386: 		  &logthis(
  387:                     "<font color=blue>WARNING: "
  388:                    ."$clientip failed to initialize: >$remotereq< </font>");
  389: 		  print $client "bye\n";
  390:               }
  391: 	    } else {
  392:               &logthis(
  393:  "<font color=blue>WARNING: Unknown client $clientip</font>");
  394:               print $client "bye\n";
  395:             }
  396:             if ($clientok) {
  397: # ---------------- New known client connecting, could mean machine online again
  398: 	      &reconlonc("$perlvar{'lonSockDir'}/$hostid{$clientip}");
  399:               &logthis(
  400:        "<font color=green>Established connection: $hostid{$clientip}</font>");
  401: # ------------------------------------------------------------ Process requests
  402:               while (my $userinput=<$client>) {
  403:                 chomp($userinput);
  404:                 my $wasenc=0;
  405: # ------------------------------------------------------------ See if encrypted
  406: 		if ($userinput =~ /^enc/) {
  407: 		  if ($cipher) {
  408:                     my ($cmd,$cmdlength,$encinput)=split(/:/,$userinput);
  409: 		    $userinput='';
  410:                     for (my $encidx=0;$encidx<length($encinput);$encidx+=16) {
  411:                        $userinput.=
  412: 			   $cipher->decrypt(
  413:                             pack("H16",substr($encinput,$encidx,16))
  414:                            );
  415: 		    }
  416: 		    $userinput=substr($userinput,0,$cmdlength);
  417:                     $wasenc=1;
  418: 		  }
  419: 		}
  420: # ------------------------------------------------------------- Normal commands
  421: # ------------------------------------------------------------------------ ping
  422: 		   if ($userinput =~ /^ping/) {
  423:                        print $client "$perlvar{'lonHostID'}\n";
  424: # ------------------------------------------------------------------------ pong
  425: 		   } elsif ($userinput =~ /^pong/) {
  426:                        $reply=reply("ping",$hostid{$clientip});
  427:                        print $client "$perlvar{'lonHostID'}:$reply\n"; 
  428: # ------------------------------------------------------------------------ ekey
  429: 		   } elsif ($userinput =~ /^ekey/) {
  430:                        my $buildkey=time.$$.int(rand 100000);
  431:                        $buildkey=~tr/1-6/A-F/;
  432:                        $buildkey=int(rand 100000).$buildkey.int(rand 100000);
  433:                        my $key=$perlvar{'lonHostID'}.$hostid{$clientip};
  434:                        $key=~tr/a-z/A-Z/;
  435:                        $key=~tr/G-P/0-9/;
  436:                        $key=~tr/Q-Z/0-9/;
  437:                        $key=$key.$buildkey.$key.$buildkey.$key.$buildkey;
  438:                        $key=substr($key,0,32);
  439:                        my $cipherkey=pack("H32",$key);
  440:                        $cipher=new IDEA $cipherkey;
  441:                        print $client "$buildkey\n"; 
  442: # ------------------------------------------------------------------------ load
  443: 		   } elsif ($userinput =~ /^load/) {
  444:                        my $loadavg;
  445:                        {
  446:                           my $loadfile=IO::File->new('/proc/loadavg');
  447:                           $loadavg=<$loadfile>;
  448:                        }
  449:                        $loadavg =~ s/\s.*//g;
  450:                        my $loadpercent=100*$loadavg/$perlvar{'lonLoadLim'};
  451: 		       print $client "$loadpercent\n";
  452: # ------------------------------------------------------------------------ auth
  453:                    } elsif ($userinput =~ /^auth/) {
  454: 		     if ($wasenc==1) {
  455:                        my ($cmd,$udom,$uname,$upass)=split(/:/,$userinput);
  456:                        chomp($upass);
  457:                        $upass=unescape($upass);
  458:                        my $proname=propath($udom,$uname);
  459:                        my $passfilename="$proname/passwd";
  460:                        if (-e $passfilename) {
  461:                           my $pf = IO::File->new($passfilename);
  462:                           my $realpasswd=<$pf>;
  463:                           chomp($realpasswd);
  464:                           my ($howpwd,$contentpwd)=split(/:/,$realpasswd);
  465:                           my $pwdcorrect=0;
  466:                           if ($howpwd eq 'internal') {
  467: 			      $pwdcorrect=
  468: 				  (crypt($upass,$contentpwd) eq $contentpwd);
  469:                           } elsif ($howpwd eq 'unix') {
  470:                               $contentpwd=(getpwnam($uname))[1];
  471:                               $pwdcorrect=
  472:                                   (crypt($upass,$contentpwd) eq $contentpwd);
  473:                           } elsif ($howpwd eq 'krb4') {
  474:                               $pwdcorrect=(
  475:                                  Authen::Krb4::get_pw_in_tkt($uname,"",
  476:                                         $contentpwd,'krbtgt',$contentpwd,1,
  477: 							     $upass) == 0);
  478:                           }
  479:                           if ($pwdcorrect) {
  480:                              print $client "authorized\n";
  481:                           } else {
  482:                              print $client "non_authorized\n";
  483:                           }  
  484: 		       } else {
  485:                           print $client "unknown_user\n";
  486:                        }
  487: 		     } else {
  488: 		       print $client "refused\n";
  489: 		     }
  490: # ---------------------------------------------------------------------- passwd
  491:                    } elsif ($userinput =~ /^passwd/) {
  492: 		     if ($wasenc==1) {
  493:                        my 
  494:                        ($cmd,$udom,$uname,$upass,$npass)=split(/:/,$userinput);
  495:                        chomp($npass);
  496:                        $upass=&unescape($upass);
  497:                        $npass=&unescape($npass);
  498:                        my $proname=propath($udom,$uname);
  499:                        my $passfilename="$proname/passwd";
  500:                        if (-e $passfilename) {
  501: 			   my $realpasswd;
  502:                           { my $pf = IO::File->new($passfilename);
  503: 			    $realpasswd=<$pf>; }
  504:                           chomp($realpasswd);
  505:                           my ($howpwd,$contentpwd)=split(/:/,$realpasswd);
  506:                           if ($howpwd eq 'internal') {
  507: 			   if (crypt($upass,$contentpwd) eq $contentpwd) {
  508: 			     my $salt=time;
  509:                              $salt=substr($salt,6,2);
  510: 			     my $ncpass=crypt($npass,$salt);
  511:                              { my $pf = IO::File->new(">$passfilename");
  512:  	  		       print $pf "internal:$ncpass\n"; }             
  513:                              print $client "ok\n";
  514:                            } else {
  515:                              print $client "non_authorized\n";
  516:                            }
  517:                           } else {
  518:                             print $client "auth_mode_error\n";
  519:                           }  
  520: 		       } else {
  521:                           print $client "unknown_user\n";
  522:                        }
  523: 		     } else {
  524: 		       print $client "refused\n";
  525: 		     }
  526: # -------------------------------------------------------------------- makeuser
  527:                    } elsif ($userinput =~ /^makeuser/) {
  528: 		     if ($wasenc==1) {
  529:                        my 
  530:                        ($cmd,$udom,$uname,$umode,$npass)=split(/:/,$userinput);
  531:                        chomp($npass);
  532:                        $npass=&unescape($npass);
  533:                        my $proname=propath($udom,$uname);
  534:                        my $passfilename="$proname/passwd";
  535:                        if (-e $passfilename) {
  536: 			   print $client "already_exists\n";
  537:                        } elsif ($udom ne $perlvar{'lonDefDomain'}) {
  538:                            print $client "not_right_domain\n";
  539:                        } else {
  540:                            @fpparts=split(/\//,$proname);
  541:                            $fpnow=$fpparts[0].'/'.$fpparts[1].'/'.$fpparts[2];
  542:                            $fperror='';
  543:                            for ($i=3;$i<=$#fpparts;$i++) {
  544:                                $fpnow.='/'.$fpparts[$i]; 
  545:                                unless (-e $fpnow) {
  546: 				   unless (mkdir($fpnow,0777)) {
  547:                                       $fperror="error:$!\n";
  548:                                    }
  549:                                }
  550:                            }
  551:                            unless ($fperror) {
  552: 			     if ($umode eq 'krb4') {
  553:                                { 
  554:                                  my $pf = IO::File->new(">$passfilename");
  555:  	  		         print $pf "krb4:$npass\n"; 
  556:                                }             
  557:                                print $client "ok\n";
  558:                              } elsif ($umode eq 'internal') {
  559: 			       my $salt=time;
  560:                                $salt=substr($salt,6,2);
  561: 			       my $ncpass=crypt($npass,$salt);
  562:                                { 
  563:                                  my $pf = IO::File->new(">$passfilename");
  564:  	  		         print $pf "internal:$ncpass\n"; 
  565:                                }             
  566:                                print $client "ok\n";
  567:                              } elsif ($umode eq 'none') {
  568:                                { 
  569:                                  my $pf = IO::File->new(">$passfilename");
  570:  	  		         print $pf "none:\n"; 
  571:                                }             
  572:                                print $client "ok\n";
  573:                              } else {
  574:                                print $client "auth_mode_error\n";
  575:                              }  
  576:                            } else {
  577:                                print $client "$fperror\n";
  578:                            }
  579:                        }
  580: 		     } else {
  581: 		       print $client "refused\n";
  582: 		     }
  583: # ------------------------------------------------------------------------ home
  584:                    } elsif ($userinput =~ /^home/) {
  585:                        my ($cmd,$udom,$uname)=split(/:/,$userinput);
  586:                        chomp($uname);
  587:                        my $proname=propath($udom,$uname);
  588:                        if (-e $proname) {
  589:                           print $client "found\n";
  590:                        } else {
  591: 			  print $client "not_found\n";
  592:                        }
  593: # ---------------------------------------------------------------------- update
  594:                    } elsif ($userinput =~ /^update/) {
  595:                        my ($cmd,$fname)=split(/:/,$userinput);
  596:                        my $ownership=ishome($fname);
  597:                        if ($ownership eq 'not_owner') {
  598:                         if (-e $fname) {
  599:                           my ($dev,$ino,$mode,$nlink,
  600:                               $uid,$gid,$rdev,$size,
  601:                               $atime,$mtime,$ctime,
  602:                               $blksize,$blocks)=stat($fname);
  603:                           $now=time;
  604:                           $since=$now-$atime;
  605:                           if ($since>$perlvar{'lonExpire'}) {
  606:                               $reply=
  607:                                     reply("unsub:$fname","$hostid{$clientip}");
  608:                               unlink("$fname");
  609:                           } else {
  610: 			     my $transname="$fname.in.transfer";
  611:                              my $remoteurl=
  612:                                     reply("sub:$fname","$hostid{$clientip}");
  613:                              my $response;
  614:                               {
  615:                              my $ua=new LWP::UserAgent;
  616:                              my $request=new HTTP::Request('GET',"$remoteurl");
  617:                              $response=$ua->request($request,$transname);
  618: 			      }
  619:                              if ($response->is_error()) {
  620: 				 unlink($transname);
  621:                                  my $message=$response->status_line;
  622:                                  &logthis(
  623:                                   "LWP GET: $message for $fname ($remoteurl)");
  624:                              } else {
  625: 	                         if ($remoteurl!~/\.meta$/) {
  626:                                   my $ua=new LWP::UserAgent;
  627:                                   my $mrequest=
  628:                                    new HTTP::Request('GET',$remoteurl.'.meta');
  629:                                   my $mresponse=
  630:                                    $ua->request($mrequest,$fname.'.meta');
  631:                                   if ($mresponse->is_error()) {
  632: 		                    unlink($fname.'.meta');
  633:                                   }
  634: 	                         }
  635:                                  rename($transname,$fname);
  636: 			     }
  637:                           }
  638:                           print $client "ok\n";
  639:                         } else {
  640:                           print $client "not_found\n";
  641:                         }
  642: 		       } else {
  643: 			print $client "rejected\n";
  644:                        }
  645: # ----------------------------------------------------------------- unsubscribe
  646:                    } elsif ($userinput =~ /^unsub/) {
  647:                        my ($cmd,$fname)=split(/:/,$userinput);
  648:                        if (-e $fname) {
  649:                            if (unlink("$fname.$hostid{$clientip}")) {
  650:                               print $client "ok\n";
  651: 			   } else {
  652:                               print $client "not_subscribed\n";
  653: 			   }
  654:                        } else {
  655: 			   print $client "not_found\n";
  656:                        }
  657: # ------------------------------------------------------------------- subscribe
  658:                    } elsif ($userinput =~ /^sub/) {
  659:                        my ($cmd,$fname)=split(/:/,$userinput);
  660:                        my $ownership=ishome($fname);
  661:                        if ($ownership eq 'owner') {
  662:                         if (-e $fname) {
  663: 			 if (-d $fname) {
  664: 			   print $client "directory\n";
  665:                          } else {
  666:                            $now=time;
  667:                            { 
  668: 			    my $sh;
  669:                             if ($sh=
  670:                              IO::File->new(">$fname.$hostid{$clientip}")) {
  671:                                print $sh "$clientip:$now\n";
  672: 			    }
  673: 			   }
  674:                            unless ($fname=~/\.meta$/) {
  675: 			       unlink("$fname.meta.$hostid{$clientip}");
  676:                            }
  677:                            $fname=~s/\/home\/httpd\/html\/res/raw/;
  678:                            $fname="http://$thisserver/".$fname;
  679:                            print $client "$fname\n";
  680: 		         }
  681:                         } else {
  682: 		      	   print $client "not_found\n";
  683:                         }
  684: 		       } else {
  685:                         print $client "rejected\n";
  686: 		       }
  687: # ------------------------------------------------------------------------- log
  688:                    } elsif ($userinput =~ /^log/) {
  689:                        my ($cmd,$udom,$uname,$what)=split(/:/,$userinput);
  690:                        chomp($what);
  691:                        my $proname=propath($udom,$uname);
  692:                        my $now=time;
  693:                        {
  694: 			 my $hfh;
  695: 			 if ($hfh=IO::File->new(">>$proname/activity.log")) { 
  696:                             print $hfh "$now:$hostid{$clientip}:$what\n";
  697:                             print $client "ok\n"; 
  698: 			} else {
  699:                             print $client "error:$!\n";
  700: 		        }
  701: 		       }
  702: # ------------------------------------------------------------------------- put
  703:                    } elsif ($userinput =~ /^put/) {
  704:                       my ($cmd,$udom,$uname,$namespace,$what)
  705:                           =split(/:/,$userinput);
  706:                       $namespace=~s/\//\_/g;
  707:                       $namespace=~s/\W//g;
  708:                       if ($namespace ne 'roles') {
  709:                        chomp($what);
  710:                        my $proname=propath($udom,$uname);
  711:                        my $now=time;
  712:                        unless ($namespace=~/^nohist\_/) {
  713: 			   my $hfh;
  714: 			   if (
  715:                              $hfh=IO::File->new(">>$proname/$namespace.hist")
  716: 			       ) { print $hfh "P:$now:$what\n"; }
  717: 		       }
  718:                        my @pairs=split(/\&/,$what);
  719:       if (tie(%hash,'GDBM_File',"$proname/$namespace.db",&GDBM_WRCREAT,0640)) {
  720:                            foreach $pair (@pairs) {
  721: 			       ($key,$value)=split(/=/,$pair);
  722:                                $hash{$key}=$value;
  723:                            }
  724: 			   if (untie(%hash)) {
  725:                               print $client "ok\n";
  726:                            } else {
  727:                               print $client "error:$!\n";
  728:                            }
  729:                        } else {
  730:                            print $client "error:$!\n";
  731:                        }
  732: 		      } else {
  733:                           print $client "refused\n";
  734:                       }
  735: # -------------------------------------------------------------------- rolesput
  736:                    } elsif ($userinput =~ /^rolesput/) {
  737: 		    if ($wasenc==1) {
  738:                        my ($cmd,$exedom,$exeuser,$udom,$uname,$what)
  739:                           =split(/:/,$userinput);
  740:                        my $namespace='roles';
  741:                        chomp($what);
  742:                        my $proname=propath($udom,$uname);
  743:                        my $now=time;
  744:                        {
  745: 			   my $hfh;
  746: 			   if (
  747:                              $hfh=IO::File->new(">>$proname/$namespace.hist")
  748: 			       ) { 
  749:                                   print $hfh "P:$now:$exedom:$exeuser:$what\n";
  750:                                  }
  751: 		       }
  752:                        my @pairs=split(/\&/,$what);
  753:       if (tie(%hash,'GDBM_File',"$proname/$namespace.db",&GDBM_WRCREAT,0640)) {
  754:                            foreach $pair (@pairs) {
  755: 			       ($key,$value)=split(/=/,$pair);
  756:                                $hash{$key}=$value;
  757:                            }
  758: 			   if (untie(%hash)) {
  759:                               print $client "ok\n";
  760:                            } else {
  761:                               print $client "error:$!\n";
  762:                            }
  763:                        } else {
  764:                            print $client "error:$!\n";
  765:                        }
  766: 		      } else {
  767:                           print $client "refused\n";
  768:                       }
  769: # ------------------------------------------------------------------------- get
  770:                    } elsif ($userinput =~ /^get/) {
  771:                        my ($cmd,$udom,$uname,$namespace,$what)
  772:                           =split(/:/,$userinput);
  773:                        $namespace=~s/\//\_/g;
  774:                        $namespace=~s/\W//g;
  775:                        chomp($what);
  776:                        my @queries=split(/\&/,$what);
  777:                        my $proname=propath($udom,$uname);
  778:                        my $qresult='';
  779:       if (tie(%hash,'GDBM_File',"$proname/$namespace.db",&GDBM_READER,0640)) {
  780:                            for ($i=0;$i<=$#queries;$i++) {
  781:                                $qresult.="$hash{$queries[$i]}&";
  782:                            }
  783: 			   if (untie(%hash)) {
  784: 		              $qresult=~s/\&$//;
  785:                               print $client "$qresult\n";
  786:                            } else {
  787:                               print $client "error:$!\n";
  788:                            }
  789:                        } else {
  790:                            print $client "error:$!\n";
  791:                        }
  792: # ------------------------------------------------------------------------ eget
  793:                    } elsif ($userinput =~ /^eget/) {
  794:                        my ($cmd,$udom,$uname,$namespace,$what)
  795:                           =split(/:/,$userinput);
  796:                        $namespace=~s/\//\_/g;
  797:                        $namespace=~s/\W//g;
  798:                        chomp($what);
  799:                        my @queries=split(/\&/,$what);
  800:                        my $proname=propath($udom,$uname);
  801:                        my $qresult='';
  802:       if (tie(%hash,'GDBM_File',"$proname/$namespace.db",&GDBM_READER,0640)) {
  803:                            for ($i=0;$i<=$#queries;$i++) {
  804:                                $qresult.="$hash{$queries[$i]}&";
  805:                            }
  806: 			   if (untie(%hash)) {
  807: 		              $qresult=~s/\&$//;
  808:                               if ($cipher) {
  809:                                 my $cmdlength=length($qresult);
  810:                                 $qresult.="         ";
  811:                                 my $encqresult='';
  812:                                 for 
  813: 				(my $encidx=0;$encidx<=$cmdlength;$encidx+=8) {
  814:                                  $encqresult.=
  815:                                  unpack("H16",
  816:                                  $cipher->encrypt(substr($qresult,$encidx,8)));
  817:                                 }
  818:                                 print $client "enc:$cmdlength:$encqresult\n";
  819: 			      } else {
  820: 			        print $client "error:no_key\n";
  821:                               }
  822:                            } else {
  823:                               print $client "error:$!\n";
  824:                            }
  825:                        } else {
  826:                            print $client "error:$!\n";
  827:                        }
  828: # ------------------------------------------------------------------------- del
  829:                    } elsif ($userinput =~ /^del/) {
  830:                        my ($cmd,$udom,$uname,$namespace,$what)
  831:                           =split(/:/,$userinput);
  832:                        $namespace=~s/\//\_/g;
  833:                        $namespace=~s/\W//g;
  834:                        chomp($what);
  835:                        my $proname=propath($udom,$uname);
  836:                        my $now=time;
  837:                        unless ($namespace=~/^nohist\_/) {
  838: 			   my $hfh;
  839: 			   if (
  840:                              $hfh=IO::File->new(">>$proname/$namespace.hist")
  841: 			       ) { print $hfh "D:$now:$what\n"; }
  842: 		       }
  843:                        my @keys=split(/\&/,$what);
  844:       if (tie(%hash,'GDBM_File',"$proname/$namespace.db",&GDBM_WRCREAT,0640)) {
  845:                            foreach $key (@keys) {
  846:                                delete($hash{$key});
  847:                            }
  848: 			   if (untie(%hash)) {
  849:                               print $client "ok\n";
  850:                            } else {
  851:                               print $client "error:$!\n";
  852:                            }
  853:                        } else {
  854:                            print $client "error:$!\n";
  855:                        }
  856: # ------------------------------------------------------------------------ keys
  857:                    } elsif ($userinput =~ /^keys/) {
  858:                        my ($cmd,$udom,$uname,$namespace)
  859:                           =split(/:/,$userinput);
  860:                        $namespace=~s/\//\_/g;
  861:                        $namespace=~s/\W//g;
  862:                        my $proname=propath($udom,$uname);
  863:                        my $qresult='';
  864:       if (tie(%hash,'GDBM_File',"$proname/$namespace.db",&GDBM_READER,0640)) {
  865:                            foreach $key (keys %hash) {
  866:                                $qresult.="$key&";
  867:                            }
  868: 			   if (untie(%hash)) {
  869: 		              $qresult=~s/\&$//;
  870:                               print $client "$qresult\n";
  871:                            } else {
  872:                               print $client "error:$!\n";
  873:                            }
  874:                        } else {
  875:                            print $client "error:$!\n";
  876:                        }
  877: # ------------------------------------------------------------------------ dump
  878:                    } elsif ($userinput =~ /^dump/) {
  879:                        my ($cmd,$udom,$uname,$namespace)
  880:                           =split(/:/,$userinput);
  881:                        $namespace=~s/\//\_/g;
  882:                        $namespace=~s/\W//g;
  883:                        my $proname=propath($udom,$uname);
  884:                        my $qresult='';
  885:       if (tie(%hash,'GDBM_File',"$proname/$namespace.db",&GDBM_READER,0640)) {
  886:                            foreach $key (keys %hash) {
  887:                                $qresult.="$key=$hash{$key}&";
  888:                            }
  889: 			   if (untie(%hash)) {
  890: 		              $qresult=~s/\&$//;
  891:                               print $client "$qresult\n";
  892:                            } else {
  893:                               print $client "error:$!\n";
  894:                            }
  895:                        } else {
  896:                            print $client "error:$!\n";
  897:                        }
  898: # ----------------------------------------------------------------------- store
  899:                    } elsif ($userinput =~ /^store/) {
  900:                       my ($cmd,$udom,$uname,$namespace,$rid,$what)
  901:                           =split(/:/,$userinput);
  902:                       $namespace=~s/\//\_/g;
  903:                       $namespace=~s/\W//g;
  904:                       if ($namespace ne 'roles') {
  905:                        chomp($what);
  906:                        my $proname=propath($udom,$uname);
  907:                        my $now=time;
  908:                        unless ($namespace=~/^nohist\_/) {
  909: 			   my $hfh;
  910: 			   if (
  911:                              $hfh=IO::File->new(">>$proname/$namespace.hist")
  912: 			       ) { print $hfh "P:$now:$rid:$what\n"; }
  913: 		       }
  914:                        my @pairs=split(/\&/,$what);
  915:                          
  916:     if (tie(%hash,'GDBM_File',"$proname/$namespace.db",&GDBM_WRCREAT,0640)) {
  917:                            my @previouskeys=split(/&/,$hash{"keys:$rid"});
  918:                            my $key;
  919:                            $hash{"version:$rid"}++;
  920:                            my $version=$hash{"version:$rid"};
  921:                            my $allkeys=''; 
  922:                            foreach $pair (@pairs) {
  923: 			       ($key,$value)=split(/=/,$pair);
  924:                                $allkeys.=$key.':';
  925:                                $hash{"$version:$rid:$key"}=$value;
  926:                            }
  927:                            $hash{"$version:$rid:timestamp"}=$now;
  928:                            $allkeys.='timestamp';
  929:                            $hash{"$version:keys:$rid"}=$allkeys;
  930: 			   if (untie(%hash)) {
  931:                               print $client "ok\n";
  932:                            } else {
  933:                               print $client "error:$!\n";
  934:                            }
  935:                        } else {
  936:                            print $client "error:$!\n";
  937:                        }
  938: 		      } else {
  939:                           print $client "refused\n";
  940:                       }
  941: # --------------------------------------------------------------------- restore
  942:                    } elsif ($userinput =~ /^restore/) {
  943:                        my ($cmd,$udom,$uname,$namespace,$rid)
  944:                           =split(/:/,$userinput);
  945:                        $namespace=~s/\//\_/g;
  946:                        $namespace=~s/\W//g;
  947:                        chomp($rid);
  948:                        my $proname=propath($udom,$uname);
  949:                        my $qresult='';
  950:       if (tie(%hash,'GDBM_File',"$proname/$namespace.db",&GDBM_READER,0640)) {
  951:                 	   my $version=$hash{"version:$rid"};
  952:                            $qresult.="version=$version&";
  953:                            my $scope;
  954:                            for ($scope=1;$scope<=$version;$scope++) {
  955: 			      my $vkeys=$hash{"$scope:keys:$rid"};
  956:                               my @keys=split(/:/,$vkeys);
  957:                               my $key;
  958:                               $qresult.="$scope:keys=$vkeys&";
  959:                               foreach $key (@keys) {
  960: 	     $qresult.="$scope:$key=".$hash{"$scope:$rid:$key"}."&";
  961:                               }                                  
  962:                            }
  963: 			   if (untie(%hash)) {
  964: 		              $qresult=~s/\&$//;
  965:                               print $client "$qresult\n";
  966:                            } else {
  967:                               print $client "error:$!\n";
  968:                            }
  969:                        } else {
  970:                            print $client "error:$!\n";
  971:                        }
  972: # ------------------------------------------------------------------- querysend
  973:                    } elsif ($userinput =~ /^querysend/) {
  974:                        my ($cmd,$query,
  975: 			   $custom,$customshow)=split(/:/,$userinput);
  976: 		       $query=~s/\n*$//g;
  977: 		       unless ($custom or $customshow) {
  978: 			   print $client "".
  979: 			       sqlreply("$hostid{$clientip}\&$query")."\n";
  980: 		       }
  981: 		       else {
  982: 			   print $client "".
  983: 			       sqlreply("$hostid{$clientip}\&$query".
  984: 					"\&$custom"."\&$customshow")."\n";
  985: 		       }
  986: # ------------------------------------------------------------------ queryreply
  987:                    } elsif ($userinput =~ /^queryreply/) {
  988:                        my ($cmd,$id,$reply)=split(/:/,$userinput); 
  989: 		       my $store;
  990:                        my $execdir=$perlvar{'lonDaemons'};
  991:                        if ($store=IO::File->new(">$execdir/tmp/$id")) {
  992: 			   $reply=~s/\&/\n/g;
  993: 			   print $store $reply;
  994: 			   close $store;
  995: 			   my $store2=IO::File->new(">$execdir/tmp/$id.end");
  996: 			   print $store2 "done\n";
  997: 			   close $store2;
  998: 			   print $client "ok\n";
  999: 		       }
 1000: 		       else {
 1001: 			   print $client "error:$!\n";
 1002: 		       }
 1003: # ----------------------------------------------------------------------- idput
 1004:                    } elsif ($userinput =~ /^idput/) {
 1005:                        my ($cmd,$udom,$what)=split(/:/,$userinput);
 1006:                        chomp($what);
 1007:                        $udom=~s/\W//g;
 1008:                        my $proname="$perlvar{'lonUsersDir'}/$udom/ids";
 1009:                        my $now=time;
 1010:                        {
 1011: 			   my $hfh;
 1012: 			   if (
 1013:                              $hfh=IO::File->new(">>$proname.hist")
 1014: 			       ) { print $hfh "P:$now:$what\n"; }
 1015: 		       }
 1016:                        my @pairs=split(/\&/,$what);
 1017:                  if (tie(%hash,'GDBM_File',"$proname.db",&GDBM_WRCREAT,0640)) {
 1018:                            foreach $pair (@pairs) {
 1019: 			       ($key,$value)=split(/=/,$pair);
 1020:                                $hash{$key}=$value;
 1021:                            }
 1022: 			   if (untie(%hash)) {
 1023:                               print $client "ok\n";
 1024:                            } else {
 1025:                               print $client "error:$!\n";
 1026:                            }
 1027:                        } else {
 1028:                            print $client "error:$!\n";
 1029:                        }
 1030: # ----------------------------------------------------------------------- idget
 1031:                    } elsif ($userinput =~ /^idget/) {
 1032:                        my ($cmd,$udom,$what)=split(/:/,$userinput);
 1033:                        chomp($what);
 1034:                        $udom=~s/\W//g;
 1035:                        my $proname="$perlvar{'lonUsersDir'}/$udom/ids";
 1036:                        my @queries=split(/\&/,$what);
 1037:                        my $qresult='';
 1038:                  if (tie(%hash,'GDBM_File',"$proname.db",&GDBM_READER,0640)) {
 1039:                            for ($i=0;$i<=$#queries;$i++) {
 1040:                                $qresult.="$hash{$queries[$i]}&";
 1041:                            }
 1042: 			   if (untie(%hash)) {
 1043: 		              $qresult=~s/\&$//;
 1044:                               print $client "$qresult\n";
 1045:                            } else {
 1046:                               print $client "error:$!\n";
 1047:                            }
 1048:                        } else {
 1049:                            print $client "error:$!\n";
 1050:                        }
 1051: # ---------------------------------------------------------------------- tmpput
 1052:                    } elsif ($userinput =~ /^tmpput/) {
 1053:                        my ($cmd,$what)=split(/:/,$userinput);
 1054: 		       my $store;
 1055:                        $tmpsnum++;
 1056:                        my $id=$$.'_'.$clientip.'_'.$tmpsnum;
 1057:                        $id=~s/\W/\_/g;
 1058:                        $what=~s/\n//g;
 1059:                        my $execdir=$perlvar{'lonDaemons'};
 1060:                        if ($store=IO::File->new(">$execdir/tmp/$id.tmp")) {
 1061: 			   print $store $what;
 1062: 			   close $store;
 1063: 			   print $client "$id\n";
 1064: 		       }
 1065: 		       else {
 1066: 			   print $client "error:$!\n";
 1067: 		       }
 1068: 
 1069: # ---------------------------------------------------------------------- tmpget
 1070:                    } elsif ($userinput =~ /^tmpget/) {
 1071:                        my ($cmd,$id)=split(/:/,$userinput);
 1072:                        chomp($id);
 1073:                        $id=~s/\W/\_/g;
 1074:                        my $store;
 1075:                        my $execdir=$perlvar{'lonDaemons'};
 1076:                        if ($store=IO::File->new("$execdir/tmp/$id.tmp")) {
 1077:                            my $reply=<$store>;
 1078: 			   print $client "$reply\n";
 1079:                            close $store;
 1080: 		       }
 1081: 		       else {
 1082: 			   print $client "error:$!\n";
 1083: 		       }
 1084: 
 1085: # -------------------------------------------------------------------------- ls
 1086:                    } elsif ($userinput =~ /^ls/) {
 1087:                        my ($cmd,$ulsdir)=split(/:/,$userinput);
 1088:                        my $ulsout='';
 1089:                        my $ulsfn;
 1090:                        if (-e $ulsdir) {
 1091: 			if (opendir(LSDIR,$ulsdir)) {
 1092:                           while ($ulsfn=readdir(LSDIR)) {
 1093: 			     my @ulsstats=stat($ulsdir.'/'.$ulsfn);
 1094:                              $ulsout.=$ulsfn.'&'.join('&',@ulsstats).':';
 1095:                           }
 1096:                           closedir(LSDIR);
 1097: 		        }
 1098: 		       } else {
 1099:                           $ulsout='no_such_dir';
 1100:                        }
 1101:                        if ($ulsout eq '') { $ulsout='empty'; }
 1102:                        print $client "$ulsout\n";
 1103: # ------------------------------------------------------------- unknown command
 1104:                    } else {
 1105:                        # unknown command
 1106:                        print $client "unknown_cmd\n";
 1107:                    }
 1108: # ------------------------------------------------------ client unknown, refuse
 1109: 	       }
 1110:             } else {
 1111: 	        print $client "refused\n";
 1112:                 &logthis("<font color=blue>WARNING: "
 1113:                 ."Rejected client $clientip, closing connection</font>");
 1114:             }              
 1115:             &logthis("<font color=red>CRITICAL: "
 1116:                     ."Disconnect from $clientip ($hostid{$clientip})</font>");
 1117: # =============================================================================
 1118:         }
 1119:     
 1120:         # tidy up gracefully and finish
 1121:     
 1122:         # this exit is VERY important, otherwise the child will become
 1123:         # a producer of more and more children, forking yourself into
 1124:         # process death.
 1125:         exit;
 1126:     }
 1127: }
 1128: 
 1129: 
 1130: 
 1131: 
 1132: 

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>