Annotation of loncom/lond, revision 1.62
1.1 albertel 1: #!/usr/bin/perl
2: # The LearningOnline Network
3: # lond "LON Daemon" Server (port "LOND" 5663)
1.60 www 4: #
1.62 ! www 5: # $Id: lond,v 1.61 2001/12/20 17:43:05 harris41 Exp $
1.60 www 6: #
7: # Copyright Michigan State University Board of Trustees
8: #
9: # This file is part of the LearningOnline Network with CAPA (LON-CAPA).
10: #
11: # LON-CAPA is free software; you can redistribute it and/or modify
12: # it under the terms of the GNU General Public License as published by
13: # the Free Software Foundation; either version 2 of the License, or
14: # (at your option) any later version.
15: #
16: # LON-CAPA is distributed in the hope that it will be useful,
17: # but WITHOUT ANY WARRANTY; without even the implied warranty of
18: # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19: # GNU General Public License for more details.
20: #
21: # You should have received a copy of the GNU General Public License
22: # along with LON-CAPA; if not, write to the Free Software
23: # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
24: #
25: # /home/httpd/html/adm/gpl.txt
26: #
27: # http://www.lon-capa.org/
28: #
1.1 albertel 29: # 5/26/99,6/4,6/10,6/11,6/14,6/15,6/26,6/28,6/30,
1.2 www 30: # 7/8,7/9,7/10,7/12,7/17,7/19,9/21,
1.6 www 31: # 10/7,10/8,10/9,10/11,10/13,10/15,11/4,11/16,
1.11 www 32: # 12/7,12/15,01/06,01/11,01/12,01/14,2/8,
1.12 harris41 33: # 03/07,05/31 Gerd Kortemeyer
1.13 www 34: # 06/26 Scott Harrison
1.20 www 35: # 06/29,06/30,07/14,07/15,07/17,07/20,07/25,09/18 Gerd Kortemeyer
1.25 www 36: # 12/05 Scott Harrison
1.34 www 37: # 12/05,12/13,12/29 Gerd Kortemeyer
1.61 harris41 38: # YEAR=2001
1.36 www 39: # Jan 01 Scott Harrison
40: # 02/12 Gerd Kortemeyer
1.37 harris41 41: # 03/15 Scott Harrison
1.41 www 42: # 03/24 Gerd Kortemeyer
1.47 www 43: # 04/02 Scott Harrison
1.51 www 44: # 05/11,05/28,08/30 Gerd Kortemeyer
1.56 harris41 45: # 9/30,10/22,11/13,11/15,11/16 Scott Harrison
1.59 www 46: # 11/26,11/27 Gerd Kortemeyer
1.61 harris41 47: # 12/20 Scott Harrison
1.62 ! www 48: # 12/22 Gerd Kortemeyer
1.13 www 49: #
1.54 harris41 50: ###
51:
1.1 albertel 52: # based on "Perl Cookbook" ISBN 1-56592-243-3
53: # preforker - server who forks first
54: # runs as a daemon
55: # HUPs
56: # uses IDEA encryption
57:
58: use IO::Socket;
59: use IO::File;
60: use Apache::File;
61: use Symbol;
62: use POSIX;
63: use Crypt::IDEA;
64: use LWP::UserAgent();
1.3 www 65: use GDBM_File;
66: use Authen::Krb4;
1.49 albertel 67: use lib '/home/httpd/lib/perl/';
68: use localauth;
1.1 albertel 69:
1.57 www 70: my $status='';
71: my $lastlog='';
72:
1.23 harris41 73: # grabs exception and records it to log before exiting
74: sub catchexception {
1.27 albertel 75: my ($error)=@_;
1.25 www 76: $SIG{'QUIT'}='DEFAULT';
77: $SIG{__DIE__}='DEFAULT';
1.23 harris41 78: &logthis("<font color=red>CRITICAL: "
79: ."ABNORMAL EXIT. Child $$ for server $wasserver died through "
1.27 albertel 80: ."a crash with this error msg->[$error]</font>");
1.57 www 81: &logthis('Famous last words: '.$status.' - '.$lastlog);
1.27 albertel 82: if ($client) { print $client "error: $error\n"; }
1.59 www 83: $server->close();
1.27 albertel 84: die($error);
1.23 harris41 85: }
86:
1.22 harris41 87: # -------------------------------- Set signal handlers to record abnormal exits
88:
89: $SIG{'QUIT'}=\&catchexception;
90: $SIG{__DIE__}=\&catchexception;
91:
1.1 albertel 92: # ------------------------------------ Read httpd access.conf and get variables
93:
1.29 harris41 94: open (CONFIG,"/etc/httpd/conf/access.conf") || die "Can't read access.conf";
1.1 albertel 95:
96: while ($configline=<CONFIG>) {
97: if ($configline =~ /PerlSetVar/) {
98: my ($dummy,$varname,$varvalue)=split(/\s+/,$configline);
1.7 www 99: chomp($varvalue);
1.1 albertel 100: $perlvar{$varname}=$varvalue;
101: }
102: }
103: close(CONFIG);
1.19 www 104:
1.35 harris41 105: # ----------------------------- Make sure this process is running from user=www
106: my $wwwid=getpwnam('www');
107: if ($wwwid!=$<) {
108: $emailto="$perlvar{'lonAdmEMail'},$perlvar{'lonSysEMail'}";
109: $subj="LON: $perlvar{'lonHostID'} User ID mismatch";
1.37 harris41 110: system("echo 'User ID mismatch. lond must be run as user www.' |\
1.35 harris41 111: mailto $emailto -s '$subj' > /dev/null");
112: exit 1;
113: }
114:
1.19 www 115: # --------------------------------------------- Check if other instance running
116:
117: my $pidfile="$perlvar{'lonDaemons'}/logs/lond.pid";
118:
119: if (-e $pidfile) {
120: my $lfh=IO::File->new("$pidfile");
121: my $pide=<$lfh>;
122: chomp($pide);
1.29 harris41 123: if (kill 0 => $pide) { die "already running"; }
1.19 www 124: }
1.1 albertel 125:
126: $PREFORK=4; # number of children to maintain, at least four spare
127:
128: # ------------------------------------------------------------- Read hosts file
129:
1.29 harris41 130: open (CONFIG,"$perlvar{'lonTabDir'}/hosts.tab") || die "Can't read host file";
1.1 albertel 131:
132: while ($configline=<CONFIG>) {
133: my ($id,$domain,$role,$name,$ip)=split(/:/,$configline);
134: chomp($ip);
135: $hostid{$ip}=$id;
136: if ($id eq $perlvar{'lonHostID'}) { $thisserver=$name; }
137: $PREFORK++;
138: }
139: close(CONFIG);
140:
141: # establish SERVER socket, bind and listen.
142: $server = IO::Socket::INET->new(LocalPort => $perlvar{'londPort'},
143: Type => SOCK_STREAM,
144: Proto => 'tcp',
145: Reuse => 1,
146: Listen => 10 )
1.29 harris41 147: or die "making socket: $@\n";
1.1 albertel 148:
149: # --------------------------------------------------------- Do global variables
150:
151: # global variables
152:
153: $MAX_CLIENTS_PER_CHILD = 5; # number of clients each child should
154: # process
155: %children = (); # keys are current child process IDs
156: $children = 0; # current number of children
157:
158: sub REAPER { # takes care of dead children
159: $SIG{CHLD} = \&REAPER;
160: my $pid = wait;
161: $children --;
162: &logthis("Child $pid died");
163: delete $children{$pid};
164: }
165:
166: sub HUNTSMAN { # signal handler for SIGINT
167: local($SIG{CHLD}) = 'IGNORE'; # we're going to kill our children
168: kill 'INT' => keys %children;
1.59 www 169: &logthis("Free socket: ".shutdown($server,2)); # free up socket
1.1 albertel 170: my $execdir=$perlvar{'lonDaemons'};
171: unlink("$execdir/logs/lond.pid");
1.9 www 172: &logthis("<font color=red>CRITICAL: Shutting down</font>");
1.1 albertel 173: exit; # clean up with dignity
174: }
175:
176: sub HUPSMAN { # signal handler for SIGHUP
177: local($SIG{CHLD}) = 'IGNORE'; # we're going to kill our children
178: kill 'INT' => keys %children;
1.59 www 179: &logthis("Free socket: ".shutdown($server,2)); # free up socket
1.9 www 180: &logthis("<font color=red>CRITICAL: Restarting</font>");
1.30 harris41 181: unlink("$execdir/logs/lond.pid");
1.1 albertel 182: my $execdir=$perlvar{'lonDaemons'};
183: exec("$execdir/lond"); # here we go again
184: }
185:
1.57 www 186: sub checkchildren {
187: &initnewstatus();
188: &logstatus();
189: &logthis('Going to check on the children');
1.61 harris41 190: foreach (sort keys %children) {
1.57 www 191: sleep 1;
192: unless (kill 'USR1' => $_) {
193: &logthis ('Child '.$_.' is dead');
194: &logstatus($$.' is dead');
195: }
1.61 harris41 196: }
1.57 www 197: }
198:
1.1 albertel 199: # --------------------------------------------------------------------- Logging
200:
201: sub logthis {
202: my $message=shift;
203: my $execdir=$perlvar{'lonDaemons'};
204: my $fh=IO::File->new(">>$execdir/logs/lond.log");
205: my $now=time;
206: my $local=localtime($now);
1.58 www 207: $lastlog=$local.': '.$message;
1.1 albertel 208: print $fh "$local ($$): $message\n";
209: }
210:
1.57 www 211: # ------------------------------------------------------------------ Log status
212:
213: sub logstatus {
214: my $docdir=$perlvar{'lonDocRoot'};
215: my $fh=IO::File->new(">>$docdir/lon-status/londstatus.txt");
216: print $fh $$."\t".$status."\t".$lastlog."\n";
217: }
218:
219: sub initnewstatus {
220: my $docdir=$perlvar{'lonDocRoot'};
221: my $fh=IO::File->new(">$docdir/lon-status/londstatus.txt");
222: my $now=time;
223: my $local=localtime($now);
224: print $fh "LOND status $local - parent $$\n\n";
225: }
226:
227: # -------------------------------------------------------------- Status setting
228:
229: sub status {
230: my $what=shift;
231: my $now=time;
232: my $local=localtime($now);
233: $status=$local.': '.$what;
234: }
1.11 www 235:
236: # -------------------------------------------------------- Escape Special Chars
237:
238: sub escape {
239: my $str=shift;
240: $str =~ s/(\W)/"%".unpack('H2',$1)/eg;
241: return $str;
242: }
243:
244: # ----------------------------------------------------- Un-Escape Special Chars
245:
246: sub unescape {
247: my $str=shift;
248: $str =~ s/%([a-fA-F0-9][a-fA-F0-9])/pack("C",hex($1))/eg;
249: return $str;
250: }
251:
1.1 albertel 252: # ----------------------------------------------------------- Send USR1 to lonc
253:
254: sub reconlonc {
255: my $peerfile=shift;
256: &logthis("Trying to reconnect for $peerfile");
257: my $loncfile="$perlvar{'lonDaemons'}/logs/lonc.pid";
258: if (my $fh=IO::File->new("$loncfile")) {
259: my $loncpid=<$fh>;
260: chomp($loncpid);
261: if (kill 0 => $loncpid) {
262: &logthis("lonc at pid $loncpid responding, sending USR1");
263: kill USR1 => $loncpid;
264: sleep 1;
265: if (-e "$peerfile") { return; }
266: &logthis("$peerfile still not there, give it another try");
267: sleep 5;
268: if (-e "$peerfile") { return; }
1.9 www 269: &logthis(
270: "<font color=blue>WARNING: $peerfile still not there, giving up</font>");
1.1 albertel 271: } else {
1.9 www 272: &logthis(
273: "<font color=red>CRITICAL: "
274: ."lonc at pid $loncpid not responding, giving up</font>");
1.1 albertel 275: }
276: } else {
1.9 www 277: &logthis('<font color=red>CRITICAL: lonc not running, giving up</font>');
1.1 albertel 278: }
279: }
280:
281: # -------------------------------------------------- Non-critical communication
1.11 www 282:
1.1 albertel 283: sub subreply {
284: my ($cmd,$server)=@_;
285: my $peerfile="$perlvar{'lonSockDir'}/$server";
286: my $sclient=IO::Socket::UNIX->new(Peer =>"$peerfile",
287: Type => SOCK_STREAM,
288: Timeout => 10)
289: or return "con_lost";
290: print $sclient "$cmd\n";
291: my $answer=<$sclient>;
292: chomp($answer);
293: if (!$answer) { $answer="con_lost"; }
294: return $answer;
295: }
296:
297: sub reply {
298: my ($cmd,$server)=@_;
299: my $answer;
300: if ($server ne $perlvar{'lonHostID'}) {
301: $answer=subreply($cmd,$server);
302: if ($answer eq 'con_lost') {
303: $answer=subreply("ping",$server);
304: if ($answer ne $server) {
305: &reconlonc("$perlvar{'lonSockDir'}/$server");
306: }
307: $answer=subreply($cmd,$server);
308: }
309: } else {
310: $answer='self_reply';
311: }
312: return $answer;
313: }
314:
1.13 www 315: # -------------------------------------------------------------- Talk to lonsql
316:
1.12 harris41 317: sub sqlreply {
318: my ($cmd)=@_;
319: my $answer=subsqlreply($cmd);
320: if ($answer eq 'con_lost') { $answer=subsqlreply($cmd); }
321: return $answer;
322: }
323:
324: sub subsqlreply {
325: my ($cmd)=@_;
326: my $unixsock="mysqlsock";
327: my $peerfile="$perlvar{'lonSockDir'}/$unixsock";
328: my $sclient=IO::Socket::UNIX->new(Peer =>"$peerfile",
329: Type => SOCK_STREAM,
330: Timeout => 10)
331: or return "con_lost";
332: print $sclient "$cmd\n";
333: my $answer=<$sclient>;
334: chomp($answer);
335: if (!$answer) { $answer="con_lost"; }
336: return $answer;
337: }
338:
1.1 albertel 339: # -------------------------------------------- Return path to profile directory
1.11 www 340:
1.1 albertel 341: sub propath {
342: my ($udom,$uname)=@_;
343: $udom=~s/\W//g;
344: $uname=~s/\W//g;
1.16 www 345: my $subdir=$uname.'__';
1.1 albertel 346: $subdir =~ s/(.)(.)(.).*/$1\/$2\/$3/;
347: my $proname="$perlvar{'lonUsersDir'}/$udom/$subdir/$uname";
348: return $proname;
349: }
350:
351: # --------------------------------------- Is this the home server of an author?
1.11 www 352:
1.1 albertel 353: sub ishome {
354: my $author=shift;
355: $author=~s/\/home\/httpd\/html\/res\/([^\/]*)\/([^\/]*).*/$1\/$2/;
356: my ($udom,$uname)=split(/\//,$author);
357: my $proname=propath($udom,$uname);
358: if (-e $proname) {
359: return 'owner';
360: } else {
361: return 'not_owner';
362: }
363: }
364:
365: # ======================================================= Continue main program
366: # ---------------------------------------------------- Fork once and dissociate
367:
368: $fpid=fork;
369: exit if $fpid;
1.29 harris41 370: die "Couldn't fork: $!" unless defined ($fpid);
1.1 albertel 371:
1.29 harris41 372: POSIX::setsid() or die "Can't start new session: $!";
1.1 albertel 373:
374: # ------------------------------------------------------- Write our PID on disk
375:
376: $execdir=$perlvar{'lonDaemons'};
377: open (PIDSAVE,">$execdir/logs/lond.pid");
378: print PIDSAVE "$$\n";
379: close(PIDSAVE);
1.9 www 380: &logthis("<font color=red>CRITICAL: ---------- Starting ----------</font>");
1.57 www 381: &status('Starting');
1.1 albertel 382:
383: # ------------------------------------------------------- Now we are on our own
384:
385: # Fork off our children.
386: for (1 .. $PREFORK) {
387: make_new_child();
388: }
389:
390: # ----------------------------------------------------- Install signal handlers
391:
1.57 www 392: &status('Forked children');
393:
1.1 albertel 394: $SIG{CHLD} = \&REAPER;
395: $SIG{INT} = $SIG{TERM} = \&HUNTSMAN;
396: $SIG{HUP} = \&HUPSMAN;
1.57 www 397: $SIG{USR1} = \&checkchildren;
1.1 albertel 398:
399: # And maintain the population.
400: while (1) {
1.57 www 401: &status('Sleeping');
1.1 albertel 402: sleep; # wait for a signal (i.e., child's death)
1.57 www 403: &logthis('Woke up');
404: &status('Woke up');
1.1 albertel 405: for ($i = $children; $i < $PREFORK; $i++) {
406: make_new_child(); # top up the child pool
407: }
408: }
409:
410: sub make_new_child {
411: my $pid;
412: my $cipher;
413: my $sigset;
414: &logthis("Attempting to start child");
415: # block signal for fork
416: $sigset = POSIX::SigSet->new(SIGINT);
417: sigprocmask(SIG_BLOCK, $sigset)
1.29 harris41 418: or die "Can't block SIGINT for fork: $!\n";
1.1 albertel 419:
1.29 harris41 420: die "fork: $!" unless defined ($pid = fork);
1.1 albertel 421:
422: if ($pid) {
423: # Parent records the child's birth and returns.
424: sigprocmask(SIG_UNBLOCK, $sigset)
1.29 harris41 425: or die "Can't unblock SIGINT for fork: $!\n";
1.1 albertel 426: $children{$pid} = 1;
427: $children++;
1.57 www 428: &status('Started child '.$pid);
1.1 albertel 429: return;
430: } else {
431: # Child can *not* return from this subroutine.
432: $SIG{INT} = 'DEFAULT'; # make SIGINT kill us as it did before
1.57 www 433: $SIG{USR1}= \&logstatus;
434: $lastlog='Forked ';
435: $status='Forked';
436:
1.1 albertel 437: # unblock signals
438: sigprocmask(SIG_UNBLOCK, $sigset)
1.29 harris41 439: or die "Can't unblock SIGINT for fork: $!\n";
1.13 www 440:
441: $tmpsnum=0;
1.1 albertel 442:
443: # handle connections until we've reached $MAX_CLIENTS_PER_CHILD
444: for ($i=0; $i < $MAX_CLIENTS_PER_CHILD; $i++) {
1.57 www 445: &status('Idle, waiting for connection');
1.1 albertel 446: $client = $server->accept() or last;
1.57 www 447: &status('Accepted connection');
1.1 albertel 448: # =============================================================================
449: # do something with the connection
450: # -----------------------------------------------------------------------------
1.2 www 451: # see if we know client and check for spoof IP by challenge
1.1 albertel 452: my $caller=getpeername($client);
453: my ($port,$iaddr)=unpack_sockaddr_in($caller);
454: my $clientip=inet_ntoa($iaddr);
455: my $clientrec=($hostid{$clientip} ne undef);
1.9 www 456: &logthis(
1.51 www 457: "<font color=yellow>INFO: Connection $i, $clientip ($hostid{$clientip})</font>"
458: );
1.57 www 459: &status("Connecting $clientip ($hostid{$clientip})");
1.2 www 460: my $clientok;
1.1 albertel 461: if ($clientrec) {
1.57 www 462: &status("Waiting for init from $clientip ($hostid{$clientip})");
1.2 www 463: my $remotereq=<$client>;
464: $remotereq=~s/\W//g;
465: if ($remotereq eq 'init') {
466: my $challenge="$$".time;
467: print $client "$challenge\n";
1.57 www 468: &status(
469: "Waiting for challenge reply from $clientip ($hostid{$clientip})");
1.2 www 470: $remotereq=<$client>;
471: $remotereq=~s/\W//g;
472: if ($challenge eq $remotereq) {
473: $clientok=1;
474: print $client "ok\n";
475: } else {
1.9 www 476: &logthis(
477: "<font color=blue>WARNING: $clientip did not reply challenge</font>");
1.57 www 478: &status('No challenge reply '.$clientip);
1.2 www 479: }
480: } else {
1.9 www 481: &logthis(
482: "<font color=blue>WARNING: "
483: ."$clientip failed to initialize: >$remotereq< </font>");
1.57 www 484: &status('No init '.$clientip);
1.2 www 485: }
486: } else {
1.9 www 487: &logthis(
488: "<font color=blue>WARNING: Unknown client $clientip</font>");
1.57 www 489: &status('Hung up on '.$clientip);
1.2 www 490: }
491: if ($clientok) {
1.1 albertel 492: # ---------------- New known client connecting, could mean machine online again
493: &reconlonc("$perlvar{'lonSockDir'}/$hostid{$clientip}");
1.9 www 494: &logthis(
495: "<font color=green>Established connection: $hostid{$clientip}</font>");
1.58 www 496: &status('Will listen to '.$hostid{$clientip});
1.1 albertel 497: # ------------------------------------------------------------ Process requests
498: while (my $userinput=<$client>) {
499: chomp($userinput);
1.57 www 500: &status('Processing '.$hostid{$clientip}.': '.$userinput);
1.1 albertel 501: my $wasenc=0;
502: # ------------------------------------------------------------ See if encrypted
503: if ($userinput =~ /^enc/) {
504: if ($cipher) {
505: my ($cmd,$cmdlength,$encinput)=split(/:/,$userinput);
506: $userinput='';
507: for (my $encidx=0;$encidx<length($encinput);$encidx+=16) {
508: $userinput.=
509: $cipher->decrypt(
510: pack("H16",substr($encinput,$encidx,16))
511: );
512: }
513: $userinput=substr($userinput,0,$cmdlength);
514: $wasenc=1;
515: }
516: }
517: # ------------------------------------------------------------- Normal commands
518: # ------------------------------------------------------------------------ ping
519: if ($userinput =~ /^ping/) {
520: print $client "$perlvar{'lonHostID'}\n";
521: # ------------------------------------------------------------------------ pong
522: } elsif ($userinput =~ /^pong/) {
523: $reply=reply("ping",$hostid{$clientip});
524: print $client "$perlvar{'lonHostID'}:$reply\n";
525: # ------------------------------------------------------------------------ ekey
526: } elsif ($userinput =~ /^ekey/) {
527: my $buildkey=time.$$.int(rand 100000);
528: $buildkey=~tr/1-6/A-F/;
529: $buildkey=int(rand 100000).$buildkey.int(rand 100000);
530: my $key=$perlvar{'lonHostID'}.$hostid{$clientip};
531: $key=~tr/a-z/A-Z/;
532: $key=~tr/G-P/0-9/;
533: $key=~tr/Q-Z/0-9/;
534: $key=$key.$buildkey.$key.$buildkey.$key.$buildkey;
535: $key=substr($key,0,32);
536: my $cipherkey=pack("H32",$key);
537: $cipher=new IDEA $cipherkey;
538: print $client "$buildkey\n";
539: # ------------------------------------------------------------------------ load
540: } elsif ($userinput =~ /^load/) {
541: my $loadavg;
542: {
543: my $loadfile=IO::File->new('/proc/loadavg');
544: $loadavg=<$loadfile>;
545: }
546: $loadavg =~ s/\s.*//g;
547: my $loadpercent=100*$loadavg/$perlvar{'lonLoadLim'};
548: print $client "$loadpercent\n";
1.54 harris41 549: # ----------------------------------------------------------------- currentauth
550: } elsif ($userinput =~ /^currentauth/) {
551: if ($wasenc==1) {
552: my ($cmd,$udom,$uname)=split(/:/,$userinput);
553: my $proname=propath($udom,$uname);
554: my $passfilename="$proname/passwd";
555: if (-e $passfilename) {
556: my $pf = IO::File->new($passfilename);
557: my $realpasswd=<$pf>;
558: chomp($realpasswd);
559: my ($howpwd,$contentpwd)=split(/:/,$realpasswd);
560: my $availablecontent='';
561: if ($howpwd eq 'krb4') {
562: $availablecontent=$contentpwd;
563: }
564: print $client "$howpwd:$availablecontent\n";
565: } else {
566: print $client "unknown_user\n";
567: }
568: } else {
569: print $client "refused\n";
570: }
1.1 albertel 571: # ------------------------------------------------------------------------ auth
572: } elsif ($userinput =~ /^auth/) {
573: if ($wasenc==1) {
574: my ($cmd,$udom,$uname,$upass)=split(/:/,$userinput);
575: chomp($upass);
1.11 www 576: $upass=unescape($upass);
1.1 albertel 577: my $proname=propath($udom,$uname);
578: my $passfilename="$proname/passwd";
579: if (-e $passfilename) {
580: my $pf = IO::File->new($passfilename);
581: my $realpasswd=<$pf>;
582: chomp($realpasswd);
1.2 www 583: my ($howpwd,$contentpwd)=split(/:/,$realpasswd);
584: my $pwdcorrect=0;
585: if ($howpwd eq 'internal') {
586: $pwdcorrect=
587: (crypt($upass,$contentpwd) eq $contentpwd);
588: } elsif ($howpwd eq 'unix') {
589: $contentpwd=(getpwnam($uname))[1];
1.52 harris41 590: my $pwauth_path="/usr/local/sbin/pwauth";
591: unless ($contentpwd eq 'x') {
592: $pwdcorrect=
593: (crypt($upass,$contentpwd) eq $contentpwd);
594: }
595: elsif (-e $pwauth_path) {
596: open PWAUTH, "|$pwauth_path" or
597: die "Cannot invoke authentication";
598: print PWAUTH "$uname\n$upass\n";
599: close PWAUTH;
600: $pwdcorrect=!$?;
601: }
1.3 www 602: } elsif ($howpwd eq 'krb4') {
603: $pwdcorrect=(
604: Authen::Krb4::get_pw_in_tkt($uname,"",
605: $contentpwd,'krbtgt',$contentpwd,1,
606: $upass) == 0);
1.50 albertel 607: } elsif ($howpwd eq 'localauth') {
1.49 albertel 608: $pwdcorrect=&localauth::localauth($uname,$upass,
609: $contentpwd);
610: }
1.2 www 611: if ($pwdcorrect) {
1.1 albertel 612: print $client "authorized\n";
613: } else {
614: print $client "non_authorized\n";
615: }
616: } else {
617: print $client "unknown_user\n";
618: }
619: } else {
620: print $client "refused\n";
621: }
622: # ---------------------------------------------------------------------- passwd
623: } elsif ($userinput =~ /^passwd/) {
624: if ($wasenc==1) {
625: my
626: ($cmd,$udom,$uname,$upass,$npass)=split(/:/,$userinput);
627: chomp($npass);
1.32 www 628: $upass=&unescape($upass);
629: $npass=&unescape($npass);
1.1 albertel 630: my $proname=propath($udom,$uname);
631: my $passfilename="$proname/passwd";
632: if (-e $passfilename) {
633: my $realpasswd;
634: { my $pf = IO::File->new($passfilename);
635: $realpasswd=<$pf>; }
636: chomp($realpasswd);
1.2 www 637: my ($howpwd,$contentpwd)=split(/:/,$realpasswd);
638: if ($howpwd eq 'internal') {
639: if (crypt($upass,$contentpwd) eq $contentpwd) {
640: my $salt=time;
641: $salt=substr($salt,6,2);
642: my $ncpass=crypt($npass,$salt);
1.1 albertel 643: { my $pf = IO::File->new(">$passfilename");
1.31 www 644: print $pf "internal:$ncpass\n"; }
1.1 albertel 645: print $client "ok\n";
1.2 www 646: } else {
647: print $client "non_authorized\n";
648: }
1.1 albertel 649: } else {
1.2 www 650: print $client "auth_mode_error\n";
1.1 albertel 651: }
652: } else {
653: print $client "unknown_user\n";
1.31 www 654: }
655: } else {
656: print $client "refused\n";
657: }
658: # -------------------------------------------------------------------- makeuser
659: } elsif ($userinput =~ /^makeuser/) {
1.56 harris41 660: my $oldumask=umask(0077);
1.31 www 661: if ($wasenc==1) {
662: my
663: ($cmd,$udom,$uname,$umode,$npass)=split(/:/,$userinput);
664: chomp($npass);
1.32 www 665: $npass=&unescape($npass);
1.31 www 666: my $proname=propath($udom,$uname);
667: my $passfilename="$proname/passwd";
668: if (-e $passfilename) {
669: print $client "already_exists\n";
670: } elsif ($udom ne $perlvar{'lonDefDomain'}) {
671: print $client "not_right_domain\n";
672: } else {
673: @fpparts=split(/\//,$proname);
674: $fpnow=$fpparts[0].'/'.$fpparts[1].'/'.$fpparts[2];
675: $fperror='';
676: for ($i=3;$i<=$#fpparts;$i++) {
677: $fpnow.='/'.$fpparts[$i];
678: unless (-e $fpnow) {
679: unless (mkdir($fpnow,0777)) {
680: $fperror="error:$!\n";
681: }
682: }
683: }
684: unless ($fperror) {
1.34 www 685: if ($umode eq 'krb4') {
1.31 www 686: {
687: my $pf = IO::File->new(">$passfilename");
1.33 www 688: print $pf "krb4:$npass\n";
1.31 www 689: }
690: print $client "ok\n";
691: } elsif ($umode eq 'internal') {
692: my $salt=time;
693: $salt=substr($salt,6,2);
694: my $ncpass=crypt($npass,$salt);
695: {
696: my $pf = IO::File->new(">$passfilename");
697: print $pf "internal:$ncpass\n";
1.50 albertel 698: }
1.31 www 699: print $client "ok\n";
1.50 albertel 700: } elsif ($umode eq 'localauth') {
701: {
702: my $pf = IO::File->new(">$passfilename");
703: print $pf "localauth:$npass\n";
704: }
705: print $client "ok\n";
1.53 harris41 706: } elsif ($umode eq 'unix') {
707: {
708: my $execpath="$perlvar{'lonDaemons'}/".
709: "lcuseradd";
1.54 harris41 710: {
711: my $se = IO::File->new("|$execpath");
712: print $se "$uname\n";
713: print $se "$npass\n";
714: print $se "$npass\n";
715: }
1.53 harris41 716: my $pf = IO::File->new(">$passfilename");
717: print $pf "unix:\n";
718: }
1.54 harris41 719: print $client "ok\n";
1.53 harris41 720: } elsif ($umode eq 'none') {
1.31 www 721: {
722: my $pf = IO::File->new(">$passfilename");
723: print $pf "none:\n";
724: }
725: print $client "ok\n";
726: } else {
727: print $client "auth_mode_error\n";
728: }
729: } else {
730: print $client "$fperror\n";
731: }
1.55 harris41 732: }
733: } else {
734: print $client "refused\n";
735: }
1.56 harris41 736: umask($oldumask);
1.55 harris41 737: # -------------------------------------------------------------- changeuserauth
738: } elsif ($userinput =~ /^changeuserauth/) {
739: if ($wasenc==1) {
740: my
741: ($cmd,$udom,$uname,$umode,$npass)=split(/:/,$userinput);
742: chomp($npass);
743: $npass=&unescape($npass);
744: my $proname=propath($udom,$uname);
745: my $passfilename="$proname/passwd";
746: if ($udom ne $perlvar{'lonDefDomain'}) {
747: print $client "not_right_domain\n";
748: } else {
749: if ($umode eq 'krb4') {
750: {
751: my $pf = IO::File->new(">$passfilename");
752: print $pf "krb4:$npass\n";
753: }
754: print $client "ok\n";
755: } elsif ($umode eq 'internal') {
756: my $salt=time;
757: $salt=substr($salt,6,2);
758: my $ncpass=crypt($npass,$salt);
759: {
760: my $pf = IO::File->new(">$passfilename");
761: print $pf "internal:$ncpass\n";
762: }
763: print $client "ok\n";
764: } elsif ($umode eq 'localauth') {
765: {
766: my $pf = IO::File->new(">$passfilename");
767: print $pf "localauth:$npass\n";
768: }
769: print $client "ok\n";
770: } elsif ($umode eq 'unix') {
771: {
772: my $execpath="$perlvar{'lonDaemons'}/".
773: "lcuseradd";
774: {
775: my $se = IO::File->new("|$execpath");
776: print $se "$uname\n";
777: print $se "$npass\n";
778: print $se "$npass\n";
779: }
780: my $pf = IO::File->new(">$passfilename");
781: print $pf "unix:\n";
782: }
783: print $client "ok\n";
784: } elsif ($umode eq 'none') {
785: {
786: my $pf = IO::File->new(">$passfilename");
787: print $pf "none:\n";
788: }
789: print $client "ok\n";
790: } else {
791: print $client "auth_mode_error\n";
792: }
1.1 albertel 793: }
794: } else {
795: print $client "refused\n";
796: }
797: # ------------------------------------------------------------------------ home
798: } elsif ($userinput =~ /^home/) {
799: my ($cmd,$udom,$uname)=split(/:/,$userinput);
800: chomp($uname);
801: my $proname=propath($udom,$uname);
802: if (-e $proname) {
803: print $client "found\n";
804: } else {
805: print $client "not_found\n";
806: }
807: # ---------------------------------------------------------------------- update
808: } elsif ($userinput =~ /^update/) {
809: my ($cmd,$fname)=split(/:/,$userinput);
810: my $ownership=ishome($fname);
811: if ($ownership eq 'not_owner') {
812: if (-e $fname) {
813: my ($dev,$ino,$mode,$nlink,
814: $uid,$gid,$rdev,$size,
815: $atime,$mtime,$ctime,
816: $blksize,$blocks)=stat($fname);
817: $now=time;
818: $since=$now-$atime;
819: if ($since>$perlvar{'lonExpire'}) {
820: $reply=
821: reply("unsub:$fname","$hostid{$clientip}");
822: unlink("$fname");
823: } else {
824: my $transname="$fname.in.transfer";
825: my $remoteurl=
826: reply("sub:$fname","$hostid{$clientip}");
827: my $response;
828: {
829: my $ua=new LWP::UserAgent;
830: my $request=new HTTP::Request('GET',"$remoteurl");
831: $response=$ua->request($request,$transname);
832: }
833: if ($response->is_error()) {
1.24 albertel 834: unlink($transname);
1.1 albertel 835: my $message=$response->status_line;
836: &logthis(
837: "LWP GET: $message for $fname ($remoteurl)");
838: } else {
1.14 www 839: if ($remoteurl!~/\.meta$/) {
1.28 www 840: my $ua=new LWP::UserAgent;
1.14 www 841: my $mrequest=
842: new HTTP::Request('GET',$remoteurl.'.meta');
843: my $mresponse=
844: $ua->request($mrequest,$fname.'.meta');
845: if ($mresponse->is_error()) {
846: unlink($fname.'.meta');
847: }
848: }
1.1 albertel 849: rename($transname,$fname);
850: }
851: }
852: print $client "ok\n";
853: } else {
854: print $client "not_found\n";
855: }
856: } else {
857: print $client "rejected\n";
858: }
859: # ----------------------------------------------------------------- unsubscribe
860: } elsif ($userinput =~ /^unsub/) {
861: my ($cmd,$fname)=split(/:/,$userinput);
862: if (-e $fname) {
863: if (unlink("$fname.$hostid{$clientip}")) {
864: print $client "ok\n";
865: } else {
866: print $client "not_subscribed\n";
867: }
868: } else {
869: print $client "not_found\n";
870: }
871: # ------------------------------------------------------------------- subscribe
872: } elsif ($userinput =~ /^sub/) {
873: my ($cmd,$fname)=split(/:/,$userinput);
874: my $ownership=ishome($fname);
875: if ($ownership eq 'owner') {
876: if (-e $fname) {
1.18 www 877: if (-d $fname) {
878: print $client "directory\n";
879: } else {
1.1 albertel 880: $now=time;
881: {
1.26 www 882: my $sh;
1.25 www 883: if ($sh=
884: IO::File->new(">$fname.$hostid{$clientip}")) {
885: print $sh "$clientip:$now\n";
886: }
1.1 albertel 887: }
1.42 www 888: unless ($fname=~/\.meta$/) {
889: unlink("$fname.meta.$hostid{$clientip}");
890: }
1.1 albertel 891: $fname=~s/\/home\/httpd\/html\/res/raw/;
892: $fname="http://$thisserver/".$fname;
893: print $client "$fname\n";
1.18 www 894: }
1.1 albertel 895: } else {
896: print $client "not_found\n";
897: }
898: } else {
899: print $client "rejected\n";
900: }
1.12 harris41 901: # ------------------------------------------------------------------------- log
902: } elsif ($userinput =~ /^log/) {
903: my ($cmd,$udom,$uname,$what)=split(/:/,$userinput);
904: chomp($what);
905: my $proname=propath($udom,$uname);
906: my $now=time;
907: {
908: my $hfh;
909: if ($hfh=IO::File->new(">>$proname/activity.log")) {
910: print $hfh "$now:$hostid{$clientip}:$what\n";
911: print $client "ok\n";
912: } else {
913: print $client "error:$!\n";
914: }
915: }
1.1 albertel 916: # ------------------------------------------------------------------------- put
917: } elsif ($userinput =~ /^put/) {
1.6 www 918: my ($cmd,$udom,$uname,$namespace,$what)
1.1 albertel 919: =split(/:/,$userinput);
1.8 www 920: $namespace=~s/\//\_/g;
1.6 www 921: $namespace=~s/\W//g;
922: if ($namespace ne 'roles') {
1.1 albertel 923: chomp($what);
924: my $proname=propath($udom,$uname);
925: my $now=time;
1.48 www 926: unless ($namespace=~/^nohist\_/) {
1.1 albertel 927: my $hfh;
928: if (
929: $hfh=IO::File->new(">>$proname/$namespace.hist")
930: ) { print $hfh "P:$now:$what\n"; }
931: }
932: my @pairs=split(/\&/,$what);
1.4 www 933: if (tie(%hash,'GDBM_File',"$proname/$namespace.db",&GDBM_WRCREAT,0640)) {
1.1 albertel 934: foreach $pair (@pairs) {
935: ($key,$value)=split(/=/,$pair);
936: $hash{$key}=$value;
937: }
1.4 www 938: if (untie(%hash)) {
1.1 albertel 939: print $client "ok\n";
940: } else {
941: print $client "error:$!\n";
942: }
943: } else {
944: print $client "error:$!\n";
945: }
1.6 www 946: } else {
947: print $client "refused\n";
948: }
949: # -------------------------------------------------------------------- rolesput
950: } elsif ($userinput =~ /^rolesput/) {
951: if ($wasenc==1) {
952: my ($cmd,$exedom,$exeuser,$udom,$uname,$what)
953: =split(/:/,$userinput);
954: my $namespace='roles';
955: chomp($what);
956: my $proname=propath($udom,$uname);
957: my $now=time;
958: {
959: my $hfh;
960: if (
961: $hfh=IO::File->new(">>$proname/$namespace.hist")
962: ) {
963: print $hfh "P:$now:$exedom:$exeuser:$what\n";
964: }
965: }
966: my @pairs=split(/\&/,$what);
967: if (tie(%hash,'GDBM_File',"$proname/$namespace.db",&GDBM_WRCREAT,0640)) {
968: foreach $pair (@pairs) {
969: ($key,$value)=split(/=/,$pair);
970: $hash{$key}=$value;
971: }
972: if (untie(%hash)) {
973: print $client "ok\n";
974: } else {
975: print $client "error:$!\n";
976: }
977: } else {
978: print $client "error:$!\n";
979: }
980: } else {
981: print $client "refused\n";
982: }
1.1 albertel 983: # ------------------------------------------------------------------------- get
984: } elsif ($userinput =~ /^get/) {
985: my ($cmd,$udom,$uname,$namespace,$what)
986: =split(/:/,$userinput);
1.8 www 987: $namespace=~s/\//\_/g;
1.1 albertel 988: $namespace=~s/\W//g;
989: chomp($what);
990: my @queries=split(/\&/,$what);
991: my $proname=propath($udom,$uname);
992: my $qresult='';
1.20 www 993: if (tie(%hash,'GDBM_File',"$proname/$namespace.db",&GDBM_READER,0640)) {
1.1 albertel 994: for ($i=0;$i<=$#queries;$i++) {
995: $qresult.="$hash{$queries[$i]}&";
996: }
1.4 www 997: if (untie(%hash)) {
1.1 albertel 998: $qresult=~s/\&$//;
999: print $client "$qresult\n";
1000: } else {
1001: print $client "error:$!\n";
1002: }
1003: } else {
1004: print $client "error:$!\n";
1005: }
1006: # ------------------------------------------------------------------------ eget
1007: } elsif ($userinput =~ /^eget/) {
1008: my ($cmd,$udom,$uname,$namespace,$what)
1009: =split(/:/,$userinput);
1.8 www 1010: $namespace=~s/\//\_/g;
1.1 albertel 1011: $namespace=~s/\W//g;
1012: chomp($what);
1013: my @queries=split(/\&/,$what);
1014: my $proname=propath($udom,$uname);
1015: my $qresult='';
1.20 www 1016: if (tie(%hash,'GDBM_File',"$proname/$namespace.db",&GDBM_READER,0640)) {
1.1 albertel 1017: for ($i=0;$i<=$#queries;$i++) {
1018: $qresult.="$hash{$queries[$i]}&";
1019: }
1.4 www 1020: if (untie(%hash)) {
1.1 albertel 1021: $qresult=~s/\&$//;
1022: if ($cipher) {
1023: my $cmdlength=length($qresult);
1024: $qresult.=" ";
1025: my $encqresult='';
1026: for
1027: (my $encidx=0;$encidx<=$cmdlength;$encidx+=8) {
1028: $encqresult.=
1029: unpack("H16",
1030: $cipher->encrypt(substr($qresult,$encidx,8)));
1031: }
1032: print $client "enc:$cmdlength:$encqresult\n";
1033: } else {
1034: print $client "error:no_key\n";
1035: }
1036: } else {
1037: print $client "error:$!\n";
1038: }
1039: } else {
1040: print $client "error:$!\n";
1041: }
1042: # ------------------------------------------------------------------------- del
1043: } elsif ($userinput =~ /^del/) {
1044: my ($cmd,$udom,$uname,$namespace,$what)
1045: =split(/:/,$userinput);
1.8 www 1046: $namespace=~s/\//\_/g;
1.1 albertel 1047: $namespace=~s/\W//g;
1048: chomp($what);
1049: my $proname=propath($udom,$uname);
1050: my $now=time;
1.48 www 1051: unless ($namespace=~/^nohist\_/) {
1.1 albertel 1052: my $hfh;
1053: if (
1054: $hfh=IO::File->new(">>$proname/$namespace.hist")
1055: ) { print $hfh "D:$now:$what\n"; }
1056: }
1057: my @keys=split(/\&/,$what);
1.4 www 1058: if (tie(%hash,'GDBM_File',"$proname/$namespace.db",&GDBM_WRCREAT,0640)) {
1.1 albertel 1059: foreach $key (@keys) {
1060: delete($hash{$key});
1061: }
1.4 www 1062: if (untie(%hash)) {
1.1 albertel 1063: print $client "ok\n";
1064: } else {
1065: print $client "error:$!\n";
1066: }
1067: } else {
1068: print $client "error:$!\n";
1069: }
1070: # ------------------------------------------------------------------------ keys
1071: } elsif ($userinput =~ /^keys/) {
1072: my ($cmd,$udom,$uname,$namespace)
1073: =split(/:/,$userinput);
1.8 www 1074: $namespace=~s/\//\_/g;
1.1 albertel 1075: $namespace=~s/\W//g;
1076: my $proname=propath($udom,$uname);
1077: my $qresult='';
1.20 www 1078: if (tie(%hash,'GDBM_File',"$proname/$namespace.db",&GDBM_READER,0640)) {
1.1 albertel 1079: foreach $key (keys %hash) {
1080: $qresult.="$key&";
1081: }
1.4 www 1082: if (untie(%hash)) {
1.1 albertel 1083: $qresult=~s/\&$//;
1084: print $client "$qresult\n";
1085: } else {
1086: print $client "error:$!\n";
1087: }
1088: } else {
1089: print $client "error:$!\n";
1090: }
1091: # ------------------------------------------------------------------------ dump
1092: } elsif ($userinput =~ /^dump/) {
1.62 ! www 1093: my ($cmd,$udom,$uname,$namespace,$regexp)
1.1 albertel 1094: =split(/:/,$userinput);
1.8 www 1095: $namespace=~s/\//\_/g;
1.1 albertel 1096: $namespace=~s/\W//g;
1.62 ! www 1097: if (defined($regexp)) {
! 1098: $regexp=&unescape($regexp);
! 1099: } else {
! 1100: $regexp='.';
! 1101: }
1.1 albertel 1102: my $proname=propath($udom,$uname);
1103: my $qresult='';
1.20 www 1104: if (tie(%hash,'GDBM_File',"$proname/$namespace.db",&GDBM_READER,0640)) {
1.1 albertel 1105: foreach $key (keys %hash) {
1.62 ! www 1106: if (eval('$key=~/$regexp/')) {
! 1107: $qresult.="$key=$hash{$key}&";
! 1108: }
1.7 www 1109: }
1110: if (untie(%hash)) {
1111: $qresult=~s/\&$//;
1112: print $client "$qresult\n";
1113: } else {
1114: print $client "error:$!\n";
1115: }
1116: } else {
1117: print $client "error:$!\n";
1118: }
1119: # ----------------------------------------------------------------------- store
1120: } elsif ($userinput =~ /^store/) {
1121: my ($cmd,$udom,$uname,$namespace,$rid,$what)
1122: =split(/:/,$userinput);
1.8 www 1123: $namespace=~s/\//\_/g;
1.7 www 1124: $namespace=~s/\W//g;
1125: if ($namespace ne 'roles') {
1126: chomp($what);
1127: my $proname=propath($udom,$uname);
1128: my $now=time;
1.48 www 1129: unless ($namespace=~/^nohist\_/) {
1.7 www 1130: my $hfh;
1131: if (
1132: $hfh=IO::File->new(">>$proname/$namespace.hist")
1133: ) { print $hfh "P:$now:$rid:$what\n"; }
1134: }
1135: my @pairs=split(/\&/,$what);
1136:
1137: if (tie(%hash,'GDBM_File',"$proname/$namespace.db",&GDBM_WRCREAT,0640)) {
1138: my @previouskeys=split(/&/,$hash{"keys:$rid"});
1139: my $key;
1140: $hash{"version:$rid"}++;
1141: my $version=$hash{"version:$rid"};
1142: my $allkeys='';
1143: foreach $pair (@pairs) {
1144: ($key,$value)=split(/=/,$pair);
1145: $allkeys.=$key.':';
1146: $hash{"$version:$rid:$key"}=$value;
1147: }
1.36 www 1148: $hash{"$version:$rid:timestamp"}=$now;
1149: $allkeys.='timestamp';
1.7 www 1150: $hash{"$version:keys:$rid"}=$allkeys;
1151: if (untie(%hash)) {
1152: print $client "ok\n";
1153: } else {
1154: print $client "error:$!\n";
1155: }
1156: } else {
1157: print $client "error:$!\n";
1158: }
1159: } else {
1160: print $client "refused\n";
1161: }
1162: # --------------------------------------------------------------------- restore
1163: } elsif ($userinput =~ /^restore/) {
1164: my ($cmd,$udom,$uname,$namespace,$rid)
1165: =split(/:/,$userinput);
1.8 www 1166: $namespace=~s/\//\_/g;
1.7 www 1167: $namespace=~s/\W//g;
1168: chomp($rid);
1169: my $proname=propath($udom,$uname);
1170: my $qresult='';
1.20 www 1171: if (tie(%hash,'GDBM_File',"$proname/$namespace.db",&GDBM_READER,0640)) {
1.7 www 1172: my $version=$hash{"version:$rid"};
1173: $qresult.="version=$version&";
1174: my $scope;
1175: for ($scope=1;$scope<=$version;$scope++) {
1176: my $vkeys=$hash{"$scope:keys:$rid"};
1177: my @keys=split(/:/,$vkeys);
1178: my $key;
1179: $qresult.="$scope:keys=$vkeys&";
1180: foreach $key (@keys) {
1.21 www 1181: $qresult.="$scope:$key=".$hash{"$scope:$rid:$key"}."&";
1.7 www 1182: }
1.1 albertel 1183: }
1.4 www 1184: if (untie(%hash)) {
1.1 albertel 1185: $qresult=~s/\&$//;
1186: print $client "$qresult\n";
1187: } else {
1188: print $client "error:$!\n";
1189: }
1190: } else {
1191: print $client "error:$!\n";
1192: }
1.12 harris41 1193: # ------------------------------------------------------------------- querysend
1194: } elsif ($userinput =~ /^querysend/) {
1.44 harris41 1195: my ($cmd,$query,
1196: $custom,$customshow)=split(/:/,$userinput);
1.12 harris41 1197: $query=~s/\n*$//g;
1.45 harris41 1198: unless ($custom or $customshow) {
1.40 harris41 1199: print $client "".
1200: sqlreply("$hostid{$clientip}\&$query")."\n";
1201: }
1202: else {
1203: print $client "".
1204: sqlreply("$hostid{$clientip}\&$query".
1.44 harris41 1205: "\&$custom"."\&$customshow")."\n";
1.40 harris41 1206: }
1.12 harris41 1207: # ------------------------------------------------------------------ queryreply
1208: } elsif ($userinput =~ /^queryreply/) {
1209: my ($cmd,$id,$reply)=split(/:/,$userinput);
1210: my $store;
1.13 www 1211: my $execdir=$perlvar{'lonDaemons'};
1212: if ($store=IO::File->new(">$execdir/tmp/$id")) {
1.43 harris41 1213: $reply=~s/\&/\n/g;
1.12 harris41 1214: print $store $reply;
1215: close $store;
1.46 harris41 1216: my $store2=IO::File->new(">$execdir/tmp/$id.end");
1217: print $store2 "done\n";
1218: close $store2;
1.12 harris41 1219: print $client "ok\n";
1220: }
1221: else {
1222: print $client "error:$!\n";
1223: }
1.1 albertel 1224: # ----------------------------------------------------------------------- idput
1225: } elsif ($userinput =~ /^idput/) {
1226: my ($cmd,$udom,$what)=split(/:/,$userinput);
1227: chomp($what);
1228: $udom=~s/\W//g;
1229: my $proname="$perlvar{'lonUsersDir'}/$udom/ids";
1230: my $now=time;
1231: {
1232: my $hfh;
1233: if (
1234: $hfh=IO::File->new(">>$proname.hist")
1235: ) { print $hfh "P:$now:$what\n"; }
1236: }
1237: my @pairs=split(/\&/,$what);
1.4 www 1238: if (tie(%hash,'GDBM_File',"$proname.db",&GDBM_WRCREAT,0640)) {
1.1 albertel 1239: foreach $pair (@pairs) {
1240: ($key,$value)=split(/=/,$pair);
1241: $hash{$key}=$value;
1242: }
1.4 www 1243: if (untie(%hash)) {
1.1 albertel 1244: print $client "ok\n";
1245: } else {
1246: print $client "error:$!\n";
1247: }
1248: } else {
1249: print $client "error:$!\n";
1250: }
1251: # ----------------------------------------------------------------------- idget
1252: } elsif ($userinput =~ /^idget/) {
1253: my ($cmd,$udom,$what)=split(/:/,$userinput);
1254: chomp($what);
1255: $udom=~s/\W//g;
1256: my $proname="$perlvar{'lonUsersDir'}/$udom/ids";
1257: my @queries=split(/\&/,$what);
1258: my $qresult='';
1.20 www 1259: if (tie(%hash,'GDBM_File',"$proname.db",&GDBM_READER,0640)) {
1.1 albertel 1260: for ($i=0;$i<=$#queries;$i++) {
1261: $qresult.="$hash{$queries[$i]}&";
1262: }
1.4 www 1263: if (untie(%hash)) {
1.1 albertel 1264: $qresult=~s/\&$//;
1265: print $client "$qresult\n";
1266: } else {
1267: print $client "error:$!\n";
1268: }
1269: } else {
1270: print $client "error:$!\n";
1271: }
1.13 www 1272: # ---------------------------------------------------------------------- tmpput
1273: } elsif ($userinput =~ /^tmpput/) {
1274: my ($cmd,$what)=split(/:/,$userinput);
1275: my $store;
1276: $tmpsnum++;
1277: my $id=$$.'_'.$clientip.'_'.$tmpsnum;
1278: $id=~s/\W/\_/g;
1279: $what=~s/\n//g;
1280: my $execdir=$perlvar{'lonDaemons'};
1281: if ($store=IO::File->new(">$execdir/tmp/$id.tmp")) {
1282: print $store $what;
1283: close $store;
1284: print $client "$id\n";
1285: }
1286: else {
1287: print $client "error:$!\n";
1288: }
1289:
1290: # ---------------------------------------------------------------------- tmpget
1291: } elsif ($userinput =~ /^tmpget/) {
1292: my ($cmd,$id)=split(/:/,$userinput);
1293: chomp($id);
1294: $id=~s/\W/\_/g;
1295: my $store;
1296: my $execdir=$perlvar{'lonDaemons'};
1297: if ($store=IO::File->new("$execdir/tmp/$id.tmp")) {
1298: my $reply=<$store>;
1299: print $client "$reply\n";
1300: close $store;
1301: }
1302: else {
1303: print $client "error:$!\n";
1304: }
1305:
1.5 www 1306: # -------------------------------------------------------------------------- ls
1307: } elsif ($userinput =~ /^ls/) {
1308: my ($cmd,$ulsdir)=split(/:/,$userinput);
1309: my $ulsout='';
1310: my $ulsfn;
1311: if (-e $ulsdir) {
1.41 www 1312: if (opendir(LSDIR,$ulsdir)) {
1313: while ($ulsfn=readdir(LSDIR)) {
1.47 www 1314: my @ulsstats=stat($ulsdir.'/'.$ulsfn);
1.5 www 1315: $ulsout.=$ulsfn.'&'.join('&',@ulsstats).':';
1316: }
1.41 www 1317: closedir(LSDIR);
1318: }
1.5 www 1319: } else {
1320: $ulsout='no_such_dir';
1321: }
1.17 www 1322: if ($ulsout eq '') { $ulsout='empty'; }
1.5 www 1323: print $client "$ulsout\n";
1.51 www 1324: # ------------------------------------------------------------------ Hanging up
1325: } elsif (($userinput =~ /^exit/) ||
1326: ($userinput =~ /^init/)) {
1327: &logthis(
1328: "Client $clientip ($hostid{$clientip}) hanging up: $userinput");
1329: print $client "bye\n";
1.59 www 1330: $client->close();
1.51 www 1331: last;
1.1 albertel 1332: # ------------------------------------------------------------- unknown command
1333: } else {
1334: # unknown command
1335: print $client "unknown_cmd\n";
1336: }
1.58 www 1337: # -------------------------------------------------------------------- complete
1338: &status('Listening to '.$hostid{$clientip});
1339: }
1.59 www 1340: # --------------------------------------------- client unknown or fishy, refuse
1.1 albertel 1341: } else {
1342: print $client "refused\n";
1.59 www 1343: $client->close();
1.9 www 1344: &logthis("<font color=blue>WARNING: "
1345: ."Rejected client $clientip, closing connection</font>");
1.1 albertel 1346: }
1.9 www 1347: &logthis("<font color=red>CRITICAL: "
1.10 www 1348: ."Disconnect from $clientip ($hostid{$clientip})</font>");
1.1 albertel 1349: # =============================================================================
1350: }
1351:
1352: # tidy up gracefully and finish
1353:
1.59 www 1354: $client->close();
1355: $server->close();
1356:
1.1 albertel 1357: # this exit is VERY important, otherwise the child will become
1358: # a producer of more and more children, forking yourself into
1359: # process death.
1360: exit;
1361: }
1362: }
1363:
1.61 harris41 1364: # ----------------------------------- POD (plain old documentation, CPAN style)
1365:
1366: =head1 NAME
1367:
1368: lond - "LON Daemon" Server (port "LOND" 5663)
1369:
1370: =head1 SYNOPSIS
1371:
1372: Should only be run as user=www. Invoked by loncron.
1373:
1374: =head1 DESCRIPTION
1375:
1376: Preforker - server who forks first. Runs as a daemon. HUPs.
1377: Uses IDEA encryption
1378:
1379: =head1 README
1380:
1381: Not yet written.
1382:
1383: =head1 PREREQUISITES
1384:
1385: IO::Socket
1386: IO::File
1387: Apache::File
1388: Symbol
1389: POSIX
1390: Crypt::IDEA
1391: LWP::UserAgent()
1392: GDBM_File
1393: Authen::Krb4
1394:
1395: =head1 COREQUISITES
1396:
1397: =head1 OSNAMES
1398:
1399: linux
1400:
1401: =head1 SCRIPT CATEGORIES
1402:
1403: Server/Process
1404:
1405: =cut
1.1 albertel 1406:
1407:
1408:
1409:
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>