File:  [LON-CAPA] / loncom / Attic / lcuseradd
Revision 1.15: download - view: text, annotated - select for diffs
Tue Oct 23 03:42:30 2001 UTC (22 years, 6 months ago) by harris41
Branches: MAIN
CVS tags: HEAD
updated and ready to use

    1: #!/usr/bin/perl
    2: #
    3: # lcuseradd
    4: #
    5: # Scott Harrison
    6: # SH: October 27, 2000
    7: # SH: October 29, 2000
    8: # YEAR=2001
    9: # Scott Harrison 10/21
   10: 
   11: ###############################################################################
   12: ##                                                                           ##
   13: ## ORGANIZATION OF THIS PERL SCRIPT                                          ##
   14: ##                                                                           ##
   15: ## 1. Description of script                                                  ##
   16: ## 2. Invoking script (standard input)                                       ##
   17: ## 3. Example usage inside another piece of code                             ##
   18: ## 4. Description of functions                                               ##
   19: ## 5. Exit codes                                                             ##
   20: ## 6. Initializations                                                        ##
   21: ## 7. Make sure this process is running from user=www                        ##
   22: ## 8. Start running script with www permissions                              ##
   23: ## 9. Handle case of another lcpasswd process (locking)                      ##
   24: ## 10. Error-check input, need 3 values (user name, password 1, password 2)  ##
   25: ## 11. Start running script with root permissions                            ##
   26: ## 12. Add user and make www a member of the user-specific group             ##
   27: ## 13. Set password                                                          ##
   28: ## 14. Make final modifications to the user directory                        ##
   29: ## 15. Exit script (unlock)                                                  ##
   30: ##                                                                           ##
   31: ###############################################################################
   32: 
   33: use strict;
   34: 
   35: # ------------------------------------------------------- Description of script
   36: #
   37: # This script is a setuid script that should
   38: # be run by user 'www'.  It creates a /home/USERNAME directory
   39: # as well as a /home/USERNAME/public_html directory.
   40: # It adds a user to the unix system.
   41: # Passwords are set with lcpasswd.
   42: # www becomes a member of this user group.
   43: 
   44: # -------------- Invoking script (standard input versus command-line arguments)
   45: #
   46: # Standard input (STDIN) usage
   47: # First line is USERNAME
   48: # Second line is PASSWORD
   49: # Third line is PASSWORD
   50: #
   51: # Command-line arguments [USERNAME] [PASSWORD] [PASSWORD]
   52: # Yes, but be very careful here (don't pass shell commands)
   53: # and this is only supported to allow perl-system calls.
   54: #
   55: # Valid passwords must consist of the
   56: # ascii characters within the inclusive
   57: # range of 0x20 (32) to 0x7E (126).
   58: # These characters are:
   59: # SPACE and
   60: # !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNO
   61: # PQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~
   62: #
   63: # Valid user names must consist of ascii
   64: # characters that are alphabetical characters
   65: # (A-Z,a-z), numeric (0-9), or the underscore
   66: # mark (_). (Essentially, the perl regex \w).
   67: # User names must begin with an alphabetical character
   68: # (A-Z,a-z).
   69: 
   70: # ---------------------------------- Example usage inside another piece of code
   71: # Usage within code
   72: #
   73: # $exitcode=
   74: #      system("/home/httpd/perl/lcuseradd","NAME","PASSWORD1","PASSWORD2")/256;
   75: # print "uh-oh" if $exitcode;
   76: 
   77: # ---------------------------------------------------- Description of functions
   78: # enable_root_capability() : have setuid script run as root
   79: # disable_root_capability() : have setuid script run as www
   80: # try_to_lock() : make sure that another lcpasswd process isn't running
   81: 
   82: # ------------------------------------------------------------------ Exit codes
   83: # These are the exit codes.
   84: # ( (0,"ok"),
   85: # (1,"User ID mismatch.  This program must be run as user 'www'"),
   86: # (2,"Error. This program needs 3 command-line arguments (username, ".
   87: #    "password 1, password 2)."),
   88: # (3,"Error. Three lines should be entered into standard input."),
   89: # (4,"Error. Too many other simultaneous password change requests being ".
   90: #    "made."),
   91: # (5,"Error. User $username does not exist."),
   92: # (6,"Error. Could not make www a member of the group \"$safeusername\"."),
   93: # (7,"Error. Root was not successfully enabled.),
   94: # (8,"Error. Cannot set password."),
   95: # (9,"Error. The user name specified has invalid characters."),
   96: # (10,"Error. A password entry had an invalid character."),
   97: # (11,"Error. User already exists.),
   98: # (12,"Error. Something went wrong with the addition of user ".
   99: #     "\"$safeusername\"."),
  100: # (13,"Error. Password mismatch."),
  101: 
  102: # ------------------------------------------------------------- Initializations
  103: # Security
  104: $ENV{'PATH'}='/bin/:/usr/bin:/usr/local/sbin:/home/httpd/perl'; # Nullify path
  105:                                                                 # information
  106: $ENV{'BASH_ENV'}=""; # Nullify shell environment information.
  107: 
  108: # Do not print error messages.
  109: my $noprint=1;
  110: 
  111: # ----------------------------- Make sure this process is running from user=www
  112: my $wwwid=getpwnam('www');
  113: &disable_root_capability;
  114: if ($wwwid!=$>) {
  115:     print("User ID mismatch.  This program must be run as user 'www'\n")
  116: 	unless $noprint;
  117:     exit 1;
  118: }
  119: 
  120: # ----------------------------------- Start running script with www permissions
  121: &disable_root_capability;
  122: 
  123: # --------------------------- Handle case of another lcpasswd process (locking)
  124: unless (&try_to_lock("/tmp/lock_lcpasswd")) {
  125:     print "Error. Too many other simultaneous password change requests being ".
  126: 	"made.\n" unless $noprint;
  127:     exit 4;
  128: }
  129: 
  130: # ------- Error-check input, need 3 values (user name, password 1, password 2).
  131: my @input;
  132: if (@ARGV==3) {
  133:     @input=@ARGV;
  134: }
  135: elsif (@ARGV) {
  136:     print("Error. This program needs 3 command-line arguments (username, ".
  137: 	  "password 1, password 2).\n") unless $noprint;
  138:     unlink('/tmp/lock_lcpasswd');
  139:     exit 2;
  140: }
  141: else {
  142:     @input=<>;
  143:     if (@input!=3) {
  144: 	print("Error. Three lines should be entered into standard input.\n")
  145: 	    unless $noprint;
  146: 	unlink('/tmp/lock_lcpasswd');
  147: 	exit 3;
  148:     }
  149:     map {chomp} @input;
  150: }
  151: 
  152: my ($username,$password1,$password2)=@input;
  153: $username=~/^(\w+)$/;
  154: my $safeusername=$1;
  155: if (($username ne $safeusername) or ($safeusername!~/^[A-Za-z]/)) {
  156:     print "Error. The user name specified has invalid characters.\n"
  157: 	unless $noprint;
  158:     unlink('/tmp/lock_lcpasswd');
  159:     exit 9;
  160: }
  161: my $pbad=0;
  162: map {if ((ord($_)<32)||(ord($_)>126)){$pbad=1;}} (split(//,$password1));
  163: map {if ((ord($_)<32)||(ord($_)>126)){$pbad=1;}} (split(//,$password2));
  164: if ($pbad) {
  165:     print "Error. A password entry had an invalid character.\n";
  166:     unlink('/tmp/lock_lcpasswd');
  167:     exit 10;
  168: }
  169: 
  170: # -- Only add user if we can create a brand new home directory (/home/username)
  171: if (-e "/home/$safeusername") {
  172:     print "Error. User already exists.\n" unless $noprint;
  173:     unlink('/tmp/lock_lcpasswd');
  174:     exit 11;
  175: }
  176: 
  177: # -- Only add user if the two password arguments match.
  178: if ($password1 ne $password2) {
  179:     print "Error. Password mismatch.\n" unless $noprint;
  180:     unlink('/tmp/lock_lcpasswd');
  181:     exit 13;
  182: }
  183: 
  184: # ---------------------------------- Start running script with root permissions
  185: &enable_root_capability;
  186: 
  187: # ------------------- Add user and make www a member of the user-specific group
  188: # -- Add user
  189: if (system('/usr/sbin/useradd','-c','LON-CAPA user',$safeusername)) {
  190:     print "Error.  Something went wrong with the addition of user ".
  191: 	  "\"$safeusername\".\n" unless $noprint;
  192:     unlink('/tmp/lock_lcpasswd');
  193:     exit 12;
  194: }
  195: 
  196: # Make www a member of that user group.
  197: if (system('/usr/sbin/usermod','-G',$safeusername,'www')) {
  198:     print "Error. Could not make www a member of the group ".
  199: 	  "\"$safeusername\".\n" unless $noprint;
  200:     unlink('/tmp/lock_lcpasswd');
  201:     exit 6;
  202: }
  203: 
  204: # ---------------------------------------------------------------- Set password
  205: # Set password with lcpasswd (which creates smbpasswd entry).
  206: 
  207: unlink('/tmp/lock_lcpasswd');
  208: &disable_root_capability;
  209: ($>,$<)=(500,500);
  210: open OUT,"|lcpasswd";
  211: print OUT $safeusername;
  212: print OUT "\n";
  213: print OUT $password1;
  214: print OUT "\n";
  215: print OUT $password1;
  216: print OUT "\n";
  217: close OUT;
  218: ($>,$<)=(500,0);
  219: if ($?) {
  220:     exit 8;
  221: }
  222: &enable_root_capability;
  223: 
  224: # ------------------------------ Make final modifications to the user directory
  225: # -- Add a public_html file with a stand-in index.html file
  226: 
  227: # system('/bin/chmod','-R','0660',"/home/$safeusername");
  228: system('/bin/chmod','0710',"/home/$safeusername");
  229: mkdir "/home/$safeusername/public_html",2760;
  230: open OUT,">/home/$safeusername/public_html/index.html";
  231: print OUT<<END;
  232: <html>
  233: <head>
  234: <title>$safeusername</title>
  235: </head>
  236: <body>
  237: <h1>$safeusername</h1>
  238: <p>
  239: Learning Online Network
  240: </p>
  241: <p>
  242: This area provides for:
  243: </p>
  244: <ul>
  245: <li>resource construction</li>
  246: <li>resource publication</li>
  247: <li>record-keeping</li>
  248: </UL>
  249: </BODY>
  250: </HTML>
  251: END
  252: close OUT;
  253: system('/bin/chown','-R',"$safeusername:$safeusername","/home/$safeusername");
  254: 
  255: # -------------------------------------------------------- Exit script
  256: &disable_root_capability;
  257: exit 0;
  258: 
  259: # ---------------------------------------------- Have setuid script run as root
  260: sub enable_root_capability {
  261:     if ($wwwid==$>) {
  262: 	($<,$>)=($>,$<);
  263: 	($(,$))=($),$();
  264:     }
  265:     else {
  266: 	# root capability is already enabled
  267:     }
  268:     return $>;
  269: }
  270: 
  271: # ----------------------------------------------- Have setuid script run as www
  272: sub disable_root_capability {
  273:     if ($wwwid==$<) {
  274: 	($<,$>)=($>,$<);
  275: 	($(,$))=($),$();
  276:     }
  277:     else {
  278: 	# root capability is already disabled
  279:     }
  280: }
  281: 
  282: # ----------------------- Make sure that another lcpasswd process isn't running
  283: sub try_to_lock {
  284:     my ($lockfile)=@_;
  285:     my $currentpid;
  286:     my $lastpid;
  287:     # Do not manipulate lock file as root
  288:     if ($>==0) {
  289: 	return 0;
  290:     }
  291:     # Try to generate lock file.
  292:     # Wait 3 seconds.  If same process id is in
  293:     # lock file, then assume lock file is stale, and
  294:     # go ahead.  If process id's fluctuate, try
  295:     # for a maximum of 10 times.
  296:     for (0..10) {
  297: 	if (-e $lockfile) {
  298: 	    open(LOCK,"<$lockfile");
  299: 	    $currentpid=<LOCK>;
  300: 	    close LOCK;
  301: 	    if ($currentpid==$lastpid) {
  302: 		last;
  303: 	    }
  304: 	    sleep 3;
  305: 	    $lastpid=$currentpid;
  306: 	}
  307: 	else {
  308: 	    last;
  309: 	}
  310: 	if ($_==10) {
  311: 	    return 0;
  312: 	}
  313:     }
  314:     open(LOCK,">$lockfile");
  315:     print LOCK $$;
  316:     close LOCK;
  317:     return 1;
  318: }

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