Annotation of loncom/lcuseradd, revision 1.6

1.1       harris41    1: #!/usr/bin/perl
                      2: #
                      3: # lcuseradd
                      4: #
                      5: # Scott Harrison
                      6: # October 27, 2000
                      7: 
                      8: use strict;
                      9: 
                     10: # This script is a setuid script that should
                     11: # be run by user 'www'.  It creates a /home/USERNAME directory
                     12: # as well as a /home/USERNAME/public_html directory.
                     13: # It adds user entries to
                     14: # /etc/passwd and /etc/groups.
1.2       harris41   15: # Passwords are set with lcpasswd.
                     16: # www becomes a member of this user group.
1.1       harris41   17: 
                     18: # Standard input usage
                     19: # First line is USERNAME
                     20: # Second line is PASSWORD
1.3       harris41   21: # Third line is PASSWORD
1.1       harris41   22: 
1.3       harris41   23: # Command-line arguments [USERNAME] [PASSWORD] [PASSWORD]
1.1       harris41   24: # Yes, but be very careful here (don't pass shell commands)
                     25: # and this is only supported to allow perl-system calls.
                     26: 
1.4       harris41   27: # Usage within code
                     28: #
                     29: # $exitcode=system("/home/httpd/perl/lcuseradd","NAME","PASSWORD1","PASSWORD2")/256;
                     30: # print "uh-oh" if $exitcode;
                     31: 
                     32: # These are the exit codes.
                     33: 
1.1       harris41   34: # Security
                     35: $ENV{'PATH'}=""; # Nullify path information.
                     36: $ENV{'BASH_ENV'}=""; # Nullify shell environment information.
1.2       harris41   37: 
1.4       harris41   38: # Do not print error messages if there are command-line arguments
                     39: my $noprint=0;
                     40: if (@ARGV) {
                     41:     $noprint=1;
                     42: }
                     43: 
                     44: # Read in /etc/passwd, and make sure this process is running from user=www
                     45: open (IN, "</etc/passwd");
                     46: my @lines=<IN>;
                     47: close IN;
                     48: my $wwwid;
                     49: for my $l (@lines) {
                     50:     chop $l;
                     51:     my @F=split(/\:/,$l);
                     52:     if ($F[0] eq 'www') {$wwwid=$F[2];}
                     53: }
                     54: if ($wwwid!=$<) {
                     55:     print("User ID mismatch.  This program must be run as user 'www'\n") unless $noprint;
                     56:     exit 1;
                     57: }
                     58: &disable_root_capability;
                     59: 
                     60: # Handle case of another lcpasswd process
                     61: unless (&try_to_lock("/tmp/lock_lcpasswd")) {
                     62:     print "Error. Too many other simultaneous password change requests being made.\n" unless $noprint;
                     63:     exit 4;
                     64: }
                     65: 
                     66: # Gather input.  Should be 3 values (user name, password 1, password 2).
                     67: my @input;
1.5       harris41   68: if (@ARGV==3) {
1.4       harris41   69:     @input=@ARGV;
                     70: }
                     71: elsif (@ARGV) {
                     72:     print("Error. This program needs 3 command-line arguments (username, password 1, password 2).\n") unless $noprint;
                     73:     unlink('/tmp/lock_lcpasswd');
                     74:     exit 2;
                     75: }
                     76: else {
                     77:     @input=<>;
1.5       harris41   78:     if (@input!=3) {
1.4       harris41   79: 	print("Error. Three lines should be entered into standard input.\n") unless $noprint;
                     80: 	unlink('/tmp/lock_lcpasswd');
                     81: 	exit 3;
                     82:     }
                     83:     map {chop} @input;
                     84: }
                     85: 
                     86: my ($username,$password1,$password2)=@input;
                     87: $username=~/^(\w+)$/;
                     88: my $safeusername=$1;
1.5       harris41   89: 
                     90: if ($password1 ne $password2) {
1.6     ! harris41   91:     print "Error. Password mismatch.\n" unless $noprint;
1.5       harris41   92:     unlink('/tmp/lock_lcpasswd');
                     93:     exit 7;
                     94: }
1.4       harris41   95: 
                     96: &enable_root_capability;
                     97: 
1.3       harris41   98: # Add user entry to /etc/passwd and /etc/groups in such
                     99: # a way that www is a member of the user-specific group
                    100: 
1.5       harris41  101: if (system('/usr/sbin/useradd','-c','LON-CAPA user',$safeusername)) {
1.6     ! harris41  102:     print "Error.  Something went wrong with the addition of user \"$safeusername\".\n" unless $noprint;
1.4       harris41  103:     unlink('/tmp/lock_lcpasswd');
                    104:     exit 5;
                    105: }
1.5       harris41  106: if (system('/usr/sbin/usermod','-G',$safeusername,'www')) {
1.6     ! harris41  107:     print "Error. Could not make www a member of the group \"$safeusername\".\n" unless $noprint;
1.5       harris41  108:     unlink('/tmp/lock_lcpasswd');
                    109:     exit 6;
                    110: }
                    111: 
                    112: # Set password with lcpasswd-style algorithm (which creates smbpasswd entry).
                    113: # I cannot place a direct shell call to lcpasswd since I have to allow
                    114: # for crazy characters in the password, and the setuid environment of perl
                    115: # requires me to make everything safe.
                    116: 
1.2       harris41  117: 
1.1       harris41  118: 
1.5       harris41  119: # ----------------------------------------------------------- have setuid script run as root
                    120: sub enable_root_capability {
                    121:     if ($wwwid==$>) {
                    122: 	($<,$>)=($>,$<);
                    123: 	($(,$))=($),$();
                    124:     }
                    125:     else {
                    126: 	# root capability is already enabled
                    127:     }
                    128:     return $>;
                    129: }
                    130: 
                    131: # ----------------------------------------------------------- have setuid script run as www
                    132: sub disable_root_capability {
                    133:     if ($wwwid==$<) {
                    134: 	($<,$>)=($>,$<);
                    135: 	($(,$))=($),$();
                    136:     }
                    137:     else {
                    138: 	# root capability is already disabled
                    139:     }
                    140: }
                    141: 
                    142: # ----------------------------------- make sure that another lcpasswd process isn't running
                    143: sub try_to_lock {
                    144:     my ($lockfile)=@_;
                    145:     my $currentpid;
                    146:     my $lastpid;
                    147:     # Do not manipulate lock file as root
                    148:     if ($>==0) {
                    149: 	return 0;
                    150:     }
                    151:     # Try to generate lock file.
                    152:     # Wait 3 seconds.  If same process id is in
                    153:     # lock file, then assume lock file is stale, and
                    154:     # go ahead.  If process id's fluctuate, try
                    155:     # for a maximum of 10 times.
                    156:     for (0..10) {
                    157: 	if (-e $lockfile) {
                    158: 	    open(LOCK,"<$lockfile");
                    159: 	    $currentpid=<LOCK>;
                    160: 	    close LOCK;
                    161: 	    if ($currentpid==$lastpid) {
                    162: 		last;
                    163: 	    }
                    164: 	    sleep 3;
                    165: 	    $lastpid=$currentpid;
                    166: 	}
                    167: 	else {
                    168: 	    last;
                    169: 	}
                    170: 	if ($_==10) {
                    171: 	    return 0;
                    172: 	}
                    173:     }
                    174:     open(LOCK,">$lockfile");
                    175:     print LOCK $$;
                    176:     close LOCK;
                    177:     return 1;
                    178: }

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>