[LON-CAPA-cvs] cvs: loncom / lcuseradd

foxr lon-capa-cvs@mail.lon-capa.org
Thu, 05 Aug 2004 10:56:55 -0000


This is a MIME encoded message

--foxr1091703415
Content-Type: text/plain

foxr		Thu Aug  5 06:56:55 2004 EDT

  Modified files:              
    /loncom	lcuseradd 
  Log:
  Add capability (optional for compatibilty with existing code)
  to write the error code to a file passed in to lcuseradd. NOte
  that the file must be in a directory that is writable by www
  I recommend /tmp -- and that the reader of that file unlink it.
  
  This is my way to get around the fact that runing lcuseradd on a pipe
  prevents you from getting the exit status of the program, which in turn
  prevents the loncapa UI from knowing that adding a user has actually failed!
  
  
--foxr1091703415
Content-Type: text/plain
Content-Disposition: attachment; filename="foxr-20040805065655.txt"

Index: loncom/lcuseradd
diff -u loncom/lcuseradd:1.25 loncom/lcuseradd:1.26
--- loncom/lcuseradd:1.25	Mon Feb  3 13:03:52 2003
+++ loncom/lcuseradd	Thu Aug  5 06:56:55 2004
@@ -14,7 +14,7 @@
 #        o LonCapa will add it if/when the user is granted an Author
 #          role.
 #
-# $Id: lcuseradd,v 1.25 2003/02/03 18:03:52 harris41 Exp $
+# $Id: lcuseradd,v 1.26 2004/08/05 10:56:55 foxr Exp $
 ###
 
 ###############################################################################
@@ -50,11 +50,20 @@
 # www becomes a member of this user group.
 
 # -------------- Invoking script (standard input versus command-line arguments)
+#                Otherwise sensitive information will be available to ps-ers for
+#                a small but exploitable time window.
 #
 # Standard input (STDIN) usage
 # First line is USERNAME
 # Second line is PASSWORD
 # Third line is PASSWORD
+# Fouth line is the name of a file to which an error code will be written.
+#            If the fourth line is omitted, no error file will be written.
+#            In either case, the program Exits with the code as its Exit status.
+#            The error file will just be a single line containing an
+#            error code.
+#            
+#  
 #
 # Command-line arguments [USERNAME] [PASSWORD] [PASSWORD]
 # Yes, but be very careful here (don't pass shell commands)
@@ -78,9 +87,9 @@
 # ---------------------------------- Example usage inside another piece of code
 # Usage within code
 #
-# $exitcode=
+# $Exitcode=
 #      system("/home/httpd/perl/lcuseradd","NAME","PASSWORD1","PASSWORD2")/256;
-# print "uh-oh" if $exitcode;
+# print "uh-oh" if $Exitcode;
 
 # ---------------------------------------------------- Description of functions
 # enable_root_capability() : have setuid script run as root
@@ -88,7 +97,7 @@
 # try_to_lock() : make sure that another lcpasswd process isn't running
 
 # ------------------------------------------------------------------ Exit codes
-# These are the exit codes.
+# These are the Exit codes.
 # ( (0,"ok"),
 # (1,"User ID mismatch.  This program must be run as user 'www'"),
 # (2,"Error. This program needs 3 command-line arguments (username, ".
@@ -106,6 +115,7 @@
 # (12,"Error. Something went wrong with the addition of user ".
 #     "\"$safeusername\"."),
 # (13,"Error. Password mismatch."),
+# (14, "Error filename is invalid")
 
 # ------------------------------------------------------------- Initializations
 # Security
@@ -116,6 +126,10 @@
 # Do not print error messages.
 my $noprint=1;
 
+#  Error file:
+
+my $error_file;			# This is either the error file name or undef.
+
 print "In lcuseradd\n" unless $noprint;
 
 # ----------------------------- Make sure this process is running from user=www
@@ -124,7 +138,7 @@
 if ($wwwid!=$>) {
     print("User ID mismatch.  This program must be run as user 'www'\n")
 	unless $noprint;
-    exit 1;
+    &Exit(1);
 }
 
 # ----------------------------------- Start running script with www permissions
@@ -134,32 +148,32 @@
 unless (&try_to_lock("/tmp/lock_lcpasswd")) {
     print "Error. Too many other simultaneous password change requests being ".
 	"made.\n" unless $noprint;
-    exit 4;
+    &Exit(4);
 }
 
 # ------- Error-check input, need 3 values (user name, password 1, password 2).
 my @input;
-if (@ARGV==3) {
+if (@ARGV>=3) {
     @input=@ARGV;
 }
 elsif (@ARGV) {
-    print("Error. This program needs 3 command-line arguments (username, ".
-	  "password 1, password 2).\n") unless $noprint;
+    print("Error. This program needs at least 3 command-line arguments (username, ".
+	  "password 1, password 2 [errorfile]).\n") unless $noprint;
     unlink('/tmp/lock_lcpasswd');
-    exit 2;
+    &Exit(2);
 }
 else {
     @input=<>;
-    if (@input!=3) {
-	print("Error. Three lines should be entered into standard input.\n")
+    if (@input < 3) {
+	print("Error. At least three lines should be entered into standard input.\n")
 	    unless $noprint;
 	unlink('/tmp/lock_lcpasswd');
-	exit 3;
+	&Exit(3);
     }
     foreach (@input) {chomp;}
 }
 
-my ($username,$password1,$password2)=@input;
+my ($username,$password1,$password2, $error_file)=@input;
 print "Username = ".$username."\n" unless $noprint;
 $username=~/^(\w+)$/;
 print "Username after substitution - ".$username unless $noprint;
@@ -170,22 +184,52 @@
     print "Error. The user name specified $username $safeusername  has invalid characters.\n"
 	unless $noprint;
     unlink('/tmp/lock_lcpasswd');
-    exit 9;
+    &Exit(9);
 }
 my $pbad=0;
 foreach (split(//,$password1)) {if ((ord($_)<32)||(ord($_)>126)){$pbad=1;}}
 foreach (split(//,$password2)) {if ((ord($_)<32)||(ord($_)>126)){$pbad=1;}}
 if ($pbad) {
-    print "Error. A password entry had an invalid character.\n";
+    print "Error. A password entry had an invalid character.\n" unless $noprint;
     unlink('/tmp/lock_lcpasswd');
-    exit 10;
+    &Exit(10);
 }
 
+#
+#   Safe the filename.  For our case, it must only have alpha, numeric, period
+#   and path sparators..
+#
+
+print "Error file is $error_file \n" unless $noprint;
+
+if($error_file) {
+    if($error_file =~ /^([(\w)(\d)\.\/]+)$/) {
+	print "Error file matched pattern $error_file : $1\n" unless $noprint;
+	my $safe_error_file = $1;	# Untainted I think.
+	print "Error file after transform $safe_error_file\n"
+	    unless $noprint;
+	if($error_file == $safe_error_file) {
+	    $error_file = $safe_error_file; # untainted error_file.
+	} else {
+	    $error_file ="";
+	    print "Invalid error filename\n" unless $noprint;
+	    Exit(14);
+	}
+
+    } 
+    else {
+	$error_file="";
+	print "Invalid error filename\n" unless $noprint;
+	Exit(14);
+    }
+}
+
+
 # -- Only add user if we can create a brand new home directory (/home/username)
 if (-e "/home/$safeusername") {
     print "Error. User already exists.\n" unless $noprint;
     unlink('/tmp/lock_lcpasswd');
-    exit 11;
+    &Exit(11);
 }
 
 # -- Only add user if the two password arguments match.
@@ -193,7 +237,7 @@
 if ($password1 ne $password2) {
     print "Error. Password mismatch.\n" unless $noprint;
     unlink('/tmp/lock_lcpasswd');
-    exit 13;
+    &Exit(13);
 }
 print "enabling root\n" unless $noprint;
 # ---------------------------------- Start running script with root permissions
@@ -209,11 +253,11 @@
 	  "\"$safeusername\".\n" unless $noprint;
     print "Final status of useradd = $status";
     unlink('/tmp/lock_lcpasswd');
-    exit 12;
+    &Exit(12);
 }
 print "Done adding user\n" unless $noprint;
 # Make www a member of that user group.
-my $groups=`/usr/bin/groups www` or exit(6);
+my $groups=`/usr/bin/groups www` or &Exit(6);
 chomp $groups; $groups=~s/^\S+\s+\:\s+//;
 my @grouplist=split(/\s+/,$groups);
 my @ugrouplist=grep {!/www|$safeusername/} @grouplist;
@@ -223,7 +267,7 @@
     print "Error. Could not make www a member of the group ".
 	  "\"$safeusername\".\n" unless $noprint;
     unlink('/tmp/lock_lcpasswd');
-    exit 6;
+    &Exit(6);
 }
 
 # ---------------------------------------------------------------- Set password
@@ -242,8 +286,8 @@
 print OUT "\n";
 close OUT;
 if ($?) {
-    print "abnormal exit from close lcpasswd\n" unless $noprint;
-    exit 8;
+    print "abnormal Exit from close lcpasswd\n" unless $noprint;
+    &Exit(8);
 }
 ($>,$<)=($wwwid,0);
 &enable_root_capability;
@@ -286,9 +330,9 @@
     }
 }
 # -------------------------------------------------------- Exit script
-print "lcuseradd exiting\n" unless $noprint;
+print "lcuseradd Exiting\n" unless $noprint;
 &disable_root_capability;
-exit 0;
+&Exit(0);
 
 # ---------------------------------------------- Have setuid script run as root
 sub enable_root_capability {
@@ -350,6 +394,22 @@
     close LOCK;
     return 1;
 }
+#-------------------------- Exit...
+#
+#   Write the file if the error_file is defined.  Regardless
+#   Exit with the status code.
+#
+sub Exit {
+    my ($code) = @_;		# Status code.
+
+    print "Exiting with status $code error file is $error_file\n" unless $noprint;
+    if($error_file) {
+	open(FH, ">$error_file");
+	print FH  "$code\n";
+	close(FH);
+    }
+    exit $code;
+}
 
 =head1 NAME
 

--foxr1091703415--