--- loncom/Attic/lcuseradd	2004/08/05 10:56:55	1.26
+++ loncom/Attic/lcuseradd	2011/10/24 21:30:09	1.42
@@ -5,16 +5,8 @@
 # lcuseradd - LON-CAPA setuid script to coordinate all actions
 #             with adding a user with filesystem privileges (e.g. author)
 #
-# YEAR=2002
-#   May 19, 2002 Ron Fox
-#      - Removed creation of the pulic_html directory.  This directory
-#        can now be added in two ways:
-#        o The user can add it themselves if they want some local web
-#          space which may or may not contain construction items.
-#        o LonCapa will add it if/when the user is granted an Author
-#          role.
 #
-# $Id: lcuseradd,v 1.26 2004/08/05 10:56:55 foxr Exp $
+# $Id: lcuseradd,v 1.42 2011/10/24 21:30:09 www Exp $
 ###
 
 ###############################################################################
@@ -40,6 +32,8 @@
 ###############################################################################
 
 use strict;
+use File::Find;
+
 
 # ------------------------------------------------------- Description of script
 #
@@ -55,9 +49,10 @@ use strict;
 #
 # Standard input (STDIN) usage
 # First line is USERNAME
-# Second line is PASSWORD
+# Second line is DOMAIN
 # Third line is PASSWORD
-# Fouth line is the name of a file to which an error code will be written.
+# Fourth line is PASSWORD
+# Fifth 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
@@ -65,7 +60,7 @@ use strict;
 #            
 #  
 #
-# Command-line arguments [USERNAME] [PASSWORD] [PASSWORD]
+# Command-line arguments [USERNAME] [DOMAIN] [PASSWORD] [PASSWORD]
 # Yes, but be very careful here (don't pass shell commands)
 # and this is only supported to allow perl-system calls.
 #
@@ -88,7 +83,7 @@ use strict;
 # Usage within code
 #
 # $Exitcode=
-#      system("/home/httpd/perl/lcuseradd","NAME","PASSWORD1","PASSWORD2")/256;
+#      system("/home/httpd/perl/lcuseradd","NAME","DOMAIN","PASSWORD1","PASSWORD2")/256;
 # print "uh-oh" if $Exitcode;
 
 # ---------------------------------------------------- Description of functions
@@ -115,7 +110,8 @@ use strict;
 # (12,"Error. Something went wrong with the addition of user ".
 #     "\"$safeusername\"."),
 # (13,"Error. Password mismatch."),
-# (14, "Error filename is invalid")
+# (14, "Error filename is invalid"),
+# (15, "Error. Could not add home directory.")
 
 # ------------------------------------------------------------- Initializations
 # Security
@@ -126,10 +122,6 @@ delete @ENV{qw(IFS CDPATH ENV BASH_ENV)}
 # 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
@@ -155,14 +147,12 @@ unless (&try_to_lock("/tmp/lock_lcpasswd
 my @input;
 if (@ARGV>=3) {
     @input=@ARGV;
-}
-elsif (@ARGV) {
+} elsif (@ARGV) {
     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);
-}
-else {
+} else {
     @input=<>;
     if (@input < 3) {
 	print("Error. At least three lines should be entered into standard input.\n")
@@ -173,13 +163,15 @@ else {
     foreach (@input) {chomp;}
 }
 
-my ($username,$password1,$password2, $error_file)=@input;
+my ($username,$domain,$password1,$password2, $error_file)=@input;
 print "Username = ".$username."\n" unless $noprint;
 $username=~/^(\w+)$/;
 print "Username after substitution - ".$username unless $noprint;
 my $safeusername=$1;
 print "Safe username = $safeusername \n" unless $noprint;
 
+print "Domain = ".$domain."\n" unless $noprint;
+
 if (($username ne $safeusername) or ($safeusername!~/^[A-Za-z]/)) {
     print "Error. The user name specified $username $safeusername  has invalid characters.\n"
 	unless $noprint;
@@ -216,8 +208,7 @@ if($error_file) {
 	    Exit(14);
 	}
 
-    } 
-    else {
+    } else {
 	$error_file="";
 	print "Invalid error filename\n" unless $noprint;
 	Exit(14);
@@ -225,13 +216,20 @@ if($error_file) {
 }
 
 
-# -- 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;
+# -- Only add the user if they are >not< in /etc/passwd.
+#    Used to look for the ability to create a new directory for the
+#    user, however that disallows authentication changes from i
+#    internal->fs.. so just check the passwd file instead.
+#
+my $not_found = system("cut -d: -f1 /etc/passwd | grep -q \"^$safeusername\$\" ");
+if (!$not_found) {
+    print "Error user already exists\n" unless $noprint;
     unlink('/tmp/lock_lcpasswd');
     &Exit(11);
 }
 
+
+
 # -- Only add user if the two password arguments match.
 
 if ($password1 ne $password2) {
@@ -243,26 +241,44 @@ print "enabling root\n" unless $noprint;
 # ---------------------------------- Start running script with root permissions
 &enable_root_capability;
 
-# ------------------- Add user and make www a member of the user-specific group
+# ------------------- Add group and user, and make www a member of the group
+# -- Add group
+
+print "adding group: $safeusername \n" unless $noprint;
+my $status = system('/usr/sbin/groupadd', $safeusername);
+if ($status) {
+    print "Error.  Something went wrong with the addition of group ".
+          "\"$safeusername\".\n" unless $noprint;
+    print "Final status of groupadd = $status\n";
+    unlink('/tmp/lock_lcpasswd');
+    &Exit(12);
+}
+my $gid = getgrnam($safeusername);
+                                                                                
 # -- Add user
 
 print "adding user: $safeusername \n" unless $noprint;
-my $status = system('/usr/sbin/useradd','-c','LON-CAPA user',$safeusername);
+my $status = system('/usr/sbin/useradd','-c','LON-CAPA user','-g',$gid,$safeusername);
 if ($status) {
     print "Error.  Something went wrong with the addition of user ".
 	  "\"$safeusername\".\n" unless $noprint;
-    print "Final status of useradd = $status";
+    system("/usr/sbin/groupdel $safeusername");
+    print "Final status of useradd = $status\n";
     unlink('/tmp/lock_lcpasswd');
     &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);
+# untaint
+my ($safegroups)=($groups=~/:\s*([\s\w]+)/);
+$groups=$safegroups;
 chomp $groups; $groups=~s/^\S+\s+\:\s+//;
 my @grouplist=split(/\s+/,$groups);
 my @ugrouplist=grep {!/www|$safeusername/} @grouplist;
 my $gl=join(',',(@ugrouplist,$safeusername));
-print "Putting user in its own group\n" unless $noprint;
+print "Putting www in user's group\n" unless $noprint;
 if (system('/usr/sbin/usermod','-G',$gl,'www')) {
     print "Error. Could not make www a member of the group ".
 	  "\"$safeusername\".\n" unless $noprint;
@@ -292,41 +308,46 @@ if ($?) {
 ($>,$<)=($wwwid,0);
 &enable_root_capability;
 
-# -- Don't add public_html... that can be added either by the user
-#    or by lchtmldir when the user is granted an authorship role.
+# Check if home directory exists for user
+# If not, create one.
+if (!-e "/home/$safeusername") {
+    if (!mkdir("/home/$safeusername",0710)) {
+        print "Error. Could not add home directory for ".
+          "\"$safeusername\".\n" unless $noprint;
+        unlink('/tmp/lock_lcpasswd');
+        &Exit(15);
+    }
+}
 
 # ------------------------------ Make final modifications to the user directory
-# -- Add a public_html file with a stand-in index.html file
+# -- Add a construction space
+        
+my $path="/home/httpd/html/priv/".$domain;
+unless (-e $path) {
+   mkdir($path);
+}
+unless (-e $path.'/'.$safeusername) {
+   mkdir($path.'/'.$safeusername);
+}
 
- system('/bin/chmod','-R','0660',"/home/$safeusername");
-system('/bin/chmod','0710',"/home/$safeusername");
-mkdir "/home/$safeusername/public_html",0755;
-system('/bin/chmod','02770',"/home/$safeusername/public_html");
-open OUT,">/home/$safeusername/public_html/index.html";
-print OUT<<END;
-<html>
-<head>
-<title>$safeusername</title>
-</head>
-<body>
-<h1>Construction Space</h1>
-<h3>$safeusername</h3>
-</body>
-</html>
-END
-close OUT;
 
-print "lcuseradd ownership\n" unless $noprint;
-system('/bin/chown','-R',"$safeusername:$safeusername","/home/$safeusername");
 # ---------------------------------------------------- Gracefull Apache Restart
+my $pidfile;
 if (-e '/var/run/httpd.pid') {
+    $pidfile = '/var/run/httpd.pid';
+} elsif (-e '/var/run/httpd2.pid') {   #Apache 2 on SuSE 10.1 and SLES10 
+    $pidfile = '/var/run/httpd2.pid';
+} 
+
+if ($pidfile) {
     print "lcuseradd Apache restart\n" unless $noprint;
-    open(PID,'/var/run/httpd.pid');
+    open(PID,"<$pidfile");
     my $pid=<PID>;
     close(PID);
-    $pid=~s/\D+//g;
+    $pid=~ /(\D+)/;
+    my $safepid = $1;
     if ($pid) {
-	system('kill','-USR1',"$pid");
+	system('kill','-USR1',"$safepid");
     }
 }
 # -------------------------------------------------------- Exit script
@@ -339,10 +360,14 @@ sub enable_root_capability {
     if ($wwwid==$>) {
 	($<,$>)=($>,0);
 	($(,$))=($),0);
-    }
-    else {
+    } else {
 	# root capability is already enabled
     }
+    if ($wwwid == $>) {
+	print("Failed to become root\n") unless $noprint;
+    } else {
+	print("Became root\n") unless $noprint;
+    }
     return $>;
 }
 
@@ -351,8 +376,7 @@ sub disable_root_capability {
     if ($wwwid==$<) {
 	($<,$>)=($>,$<);
 	($(,$))=($),$();
-    }
-    else {
+    } else {
 	# root capability is already disabled
     }
 }
@@ -381,8 +405,7 @@ sub try_to_lock {
 	    }
 	    sleep 3;
 	    $lastpid=$currentpid;
-	}
-	else {
+	} else {
 	    last;
 	}
 	if ($_==10) {
@@ -394,6 +417,24 @@ sub try_to_lock {
     close LOCK;
     return 1;
 }
+#    Called by File::Find::find for each file examined.
+#
+#     Untaint the file and, if it is a directory,
+#     chmod it to 02770
+#
+sub set_permission {
+    $File::Find::name =~ /^(.*)$/;
+    my $safe_name = $1;		# Untainted filename...
+    
+    print "$safe_name" unless $noprint;
+    if(-d $safe_name) {
+	print " - directory" unless $noprint;
+	chmod(02770, $safe_name);
+    }
+    print "\n" unless $noprint;
+
+}
+
 #-------------------------- Exit...
 #
 #   Write the file if the error_file is defined.  Regardless
@@ -402,6 +443,10 @@ sub try_to_lock {
 sub Exit {
     my ($code) = @_;		# Status code.
 
+    # TODO: Ensure the error file is owned/deletable by www:www:
+
+    &disable_root_capability();	# We run unprivileged to write the error file.
+
     print "Exiting with status $code error file is $error_file\n" unless $noprint;
     if($error_file) {
 	open(FH, ">$error_file");