[LON-CAPA-cvs] cvs: loncom / lond
foxr
lon-capa-cvs@mail.lon-capa.org
Wed, 08 Sep 2004 10:19:53 -0000
foxr Wed Sep 8 06:19:53 2004 EDT
Modified files:
/loncom lond
Log:
- Add execute_command to safely execute single commands without being
vulnerable to shell escapes when it's necessary to capture stdout/stderr.
- Recast the du handler in terms of execute_command.
- inspect all the Reply and Failure calls to ensure that they send
\n terminated lines to keep lonc from waiting until timeout before
completing a transaction.
Index: loncom/lond
diff -u loncom/lond:1.250 loncom/lond:1.251
--- loncom/lond:1.250 Tue Sep 7 10:28:30 2004
+++ loncom/lond Wed Sep 8 06:19:52 2004
@@ -2,7 +2,7 @@
# The LearningOnline Network
# lond "LON Daemon" Server (port "LOND" 5663)
#
-# $Id: lond,v 1.250 2004/09/07 14:28:30 albertel Exp $
+# $Id: lond,v 1.251 2004/09/08 10:19:52 foxr Exp $
#
# Copyright Michigan State University Board of Trustees
#
@@ -57,7 +57,7 @@
my $status='';
my $lastlog='';
-my $VERSION='$Revision: 1.250 $'; #' stupid emacs
+my $VERSION='$Revision: 1.251 $'; #' stupid emacs
my $remoteVERSION;
my $currenthostid="default";
my $currentdomainid;
@@ -331,8 +331,43 @@
}
-
#
+# Safely execute a command (as long as it's not a shel command and doesn
+# not require/rely on shell escapes. The function operates by doing a
+# a pipe based fork and capturing stdout and stderr from the pipe.
+#
+# Formal Parameters:
+# $line - A line of text to be executed as a command.
+# Returns:
+# The output from that command. If the output is multiline the caller
+# must know how to split up the output.
+#
+#
+sub execute_command {
+ my ($line) = @_;
+ my @words = split(/\s/, $line); # Bust the command up into words.
+ my $output = "";
+
+ my $pid = open(CHILD, "-|");
+
+ if($pid) { # Parent process
+ Debug("In parent process for execute_command");
+ my @data = <CHILD>; # Read the child's outupt...
+ close CHILD;
+ foreach my $output_line (@data) {
+ Debug("Adding $output_line");
+ $output .= $output_line; # Presumably has a \n on it.
+ }
+
+ } else { # Child process
+ close (STDERR);
+ open (STDERR, ">&STDOUT");# Combine stderr, and stdout...
+ exec(@words); # won't return.
+ }
+ return $output;
+}
+
+
# GetCertificate: Given a transaction that requires a certificate,
# this function will extract the certificate from the transaction
# request. Note that at this point, the only concept of a certificate
@@ -1302,6 +1337,9 @@
sub du_handler {
my ($cmd, $ududir, $client) = @_;
+ my ($ududir) = split(/:/,$ududir); # Make 'telnet' testing easier.
+ my $userinput = "$cmd:$ududir";
+
if ($ududir=~/\.\./ || $ududir!~m|^/home/httpd/|) {
&Failure($client,"refused\n","$cmd:$ududir");
return 1;
@@ -1314,18 +1352,17 @@
#
if (-d $ududir) {
# And as Shakespeare would say to make
- # assurance double sure, quote the $ududir
- # This is in case someone manages to first
- # e.g. fabricate a valid directory with a ';'
- # in it. Quoting the dir will help
- # keep $ududir completely interpreted as a
- # directory.
- #
- my $duout = `du -ks "$ududir" 2>/dev/null`;
+ # assurance double sure,
+ # use execute_command to ensure that the command is not executed in
+ # a shell that can screw us up.
+
+ my $duout = execute_command("du -ks $ududir");
$duout=~s/[^\d]//g; #preserve only the numbers
&Reply($client,"$duout\n","$cmd:$ududir");
} else {
- &Failure($client, "bad_directory:$ududir","$cmd:$ududir");
+
+ &Failure($client, "bad_directory:$ududir\n","$cmd:$ududir");
+
}
return 1;
}
@@ -1730,7 +1767,7 @@
my $result=&make_passwd_file($uname, $umode,$npass,$passfilename);
&Reply($client, $result, $userinput);
} else {
- &Failure($client, "non_authorized", $userinput); # Fail the user now.
+ &Failure($client, "non_authorized\n", $userinput); # Fail the user now.
}
}
return 1;
@@ -2081,14 +2118,14 @@
my ($fname, $session) = split(/:/, $tail);
chomp($session);
- my $reply='non_auth';
+ my $reply="non_auth\n";
if (open(ENVIN,$perlvar{'lonIDsDir'}.'/'.
$session.'.id')) {
while (my $line=<ENVIN>) {
- if ($line=~ m|userfile\.\Q$fname\E\=|) { $reply='ok'; }
+ if ($line=~ m|userfile\.\Q$fname\E\=|) { $reply="ok\n"; }
}
close(ENVIN);
- &Reply($client, $reply);
+ &Reply($client, $reply, "$cmd:$tail");
} else {
&Failure($client, "invalid_token\n", "$cmd:$tail");
}
@@ -3799,7 +3836,7 @@
$userinput = decipher($userinput);
$wasenc=1;
if(!$userinput) { # Cipher not defined.
- &Failure($client, "error: Encrypted data without negotated key");
+ &Failure($client, "error: Encrypted data without negotated key\n");
return 0;
}
}