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