File:  [LON-CAPA] / loncom / lcpasswd
Revision 1.21: download - view: text, annotated - select for diffs
Thu Apr 7 22:27:52 2005 UTC (18 years, 11 months ago) by albertel
Branches: MAIN
CVS tags: version_2_9_X, version_2_9_99_0, version_2_9_1, version_2_9_0, version_2_8_X, version_2_8_99_1, version_2_8_99_0, version_2_8_2, version_2_8_1, version_2_8_0, version_2_7_X, version_2_7_99_1, version_2_7_99_0, version_2_7_1, version_2_7_0, version_2_6_X, version_2_6_99_1, version_2_6_99_0, version_2_6_3, version_2_6_2, version_2_6_1, version_2_6_0, version_2_5_X, version_2_5_99_1, version_2_5_99_0, version_2_5_2, version_2_5_1, version_2_5_0, version_2_4_X, version_2_4_99_0, version_2_4_2, version_2_4_1, version_2_4_0, version_2_3_X, version_2_3_99_0, version_2_3_2, version_2_3_1, version_2_3_0, version_2_2_X, version_2_2_99_1, version_2_2_99_0, version_2_2_2, version_2_2_1, version_2_2_0, version_2_1_X, version_2_1_99_3, version_2_1_99_2, version_2_1_99_1, version_2_1_99_0, version_2_1_3, version_2_1_2, version_2_1_1, version_2_1_0, version_2_10_0_RC1, version_2_0_X, version_2_0_99_1, version_2_0_2, version_2_0_1, version_2_0_0, version_1_99_3, version_1_99_2, version_1_99_1_tmcc, version_1_99_1, version_1_99_0_tmcc, version_1_99_0, bz6209-base, bz6209, bz5969, bz2851, PRINT_INCOMPLETE_base, PRINT_INCOMPLETE, HEAD, GCI_3, GCI_2, GCI_1, BZ5971-printing-apage, BZ5434-fox
- commiting Martin Siegert's updates to work on systems that don't create user groups by default

    1: #!/usr/bin/perl
    2: # The Learning Online Network with CAPA
    3: #
    4: # lcpasswd - LON-CAPA setuid script to synchronously change all
    5: #            filesystem-related passwords (samba, unix, etc)
    6: #
    7: # YEAR=2002
    8: # 02/19 Matthew Hall
    9: #
   10: # $Id: lcpasswd,v 1.21 2005/04/07 22:27:52 albertel Exp $
   11: ###
   12: 
   13: ###############################################################################
   14: ##                                                                           ##
   15: ## ORGANIZATION OF THIS PERL SCRIPT                                          ##
   16: ##                                                                           ##
   17: ## 1. Description of script                                                  ##
   18: ## 2. Invoking script (standard input only)                                  ##
   19: ## 3. Example usage inside another piece of code                             ##
   20: ## 4. Description of functions                                               ##
   21: ## 5. Exit codes                                                             ##
   22: ##                                                                           ##
   23: ###############################################################################
   24: 
   25: use strict;
   26: 
   27: # ------------------------------------------------------- Description of script
   28: #
   29: # This script is a setuid script that should
   30: # be run by user 'www'.  This script allows
   31: # for synchronous entry of passwords into
   32: # both the /etc/passwd and the /etc/smbpasswd
   33: # files.
   34: #
   35: # This script works under the same process control mechanism
   36: # as lcuseradd and lcpasswd, to make sure that only one of these
   37: # processes is running at any one time on the system.
   38: 
   39: # --------------------------------------- Invoking script (standard input only)
   40: #
   41: # Standard input usage
   42: # First line is USERNAME
   43: # Second line is NEW PASSWORD
   44: # Third line is NEW PASSWORD
   45: #
   46: # Valid passwords must consist of the
   47: # ascii characters within the inclusive
   48: # range of 0x20 (32) to 0x7E (126).
   49: # These characters are:
   50: # SPACE and
   51: # !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNO
   52: # PQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~
   53: #
   54: # Valid user names must consist of ascii
   55: # characters that are alphabetical characters
   56: # (A-Z,a-z), numeric (0-9), or the underscore
   57: # mark (_). (Essentially, the perl regex \w).
   58: # User names must begin with an alphabetical character
   59: # (A-Z,a-z).
   60: 
   61: # ---------------------------------------------------- Description of functions
   62: # enable_root_capability() : have setuid script run as root
   63: # disable_root_capability() : have setuid script run as www
   64: # try_to_lock() : make sure that another lcpasswd process isn't running
   65: 
   66: # ------------------------------------------------------------------ Exit codes
   67: # These are the exit codes.
   68: # ( (0,"ok"),
   69: #   (1,"User ID mismatch.  This program must be run as user 'www'"),
   70: #   (2,"Error. This program needs 3 command-line arguments (username, old ".
   71: #       password, new password)."),
   72: #   (3,"Error. Three lines need to be entered into standard input."),
   73: #   (4,"Error. Too many other simultaneous password change requests being ".
   74: #       made."),
   75: #   (5,"Error. User $username does not exist."),
   76: #   (6,"Error. Invalid entry of current password."),
   77: #   (7,"Error. Root was not successfully enabled."),
   78: #   (8,"Error. Cannot set password."),
   79: #   (9,"Error. The user name specified has invalid characters."),
   80: #   (10,"Error. A password entry had an invalid character.") )
   81: 
   82: # ------------------------------------------------------------- Initializations
   83: # Security
   84: $ENV{'PATH'}='/bin:/usr/bin:/usr/local/sbin:/home/httpd/perl'; # Nullify path
   85:                                                                # information
   86: delete @ENV{qw(IFS CDPATH ENV BASH_ENV)}; # nullify potential taints
   87: 
   88: # Do not print error messages
   89: my $noprint=1;
   90: 
   91: print "In lcpasswd" unless $noprint;
   92: 
   93: # ----------------------------- Make sure this process is running from user=www
   94: my $wwwid=getpwnam('www');
   95: &disable_root_capability;
   96: if ($wwwid!=$>) {
   97:     print("User ID mismatch.  This program must be run as user 'www'\n")
   98: 	unless $noprint;
   99:     exit 1;
  100: }
  101: 
  102: # ----------------------------------- Start running script with www permissions
  103: &disable_root_capability;
  104: 
  105: # --------------------------- Handle case of another lcpasswd process (locking)
  106: unless (&try_to_lock('/tmp/lock_lcpasswd')) {
  107:     print "Error. Too many other simultaneous password change requests being ".
  108: 	"made.\n" unless $noprint;
  109:     exit 4;
  110: }
  111: 
  112: # ------- Error-check input, need 3 values (user name, password 1, password 2).
  113: my @input;
  114: @input=<>;
  115: if (@input!=3) {
  116:     print("Error. Three lines need to be entered into standard input.\n")
  117: 	unless $noprint;
  118:     unlink('/tmp/lock_lcpasswd');
  119:     exit 3;
  120: }
  121: foreach (@input) {chomp;}
  122: 
  123: my ($username,$password1,$password2)=@input;
  124: $username=~/^(\w+)$/;
  125: my $safeusername=$1;
  126: if (($username ne $safeusername) or ($safeusername!~/^[A-Za-z]/)) {
  127:     print "Error. The user name specified has invalid characters.\n";
  128:     unlink('/tmp/lock_lcpasswd');
  129:     exit 9;
  130: }
  131: my $pbad=0;
  132: foreach (split(//,$password1)) {if ((ord($_)<32)||(ord($_)>126)){$pbad=1;}}
  133: foreach (split(//,$password2)) {if ((ord($_)<32)||(ord($_)>126)){$pbad=1;}}
  134: if ($pbad) {
  135:     print "Error. A password entry had an invalid character.\n";
  136:     unlink('/tmp/lock_lcpasswd');
  137:     exit 10;
  138: }
  139: 
  140: # -- Only add user if the two password arguments match.
  141: if ($password1 ne $password2) {
  142:     print "Error. Password mismatch.\n" unless $noprint;
  143:     unlink('/tmp/lock_lcpasswd');
  144:     exit 13;
  145: }
  146: 
  147: # Verify existence of user
  148: unless(getpwnam($safeusername)) {
  149:     print "Error. User $username does not exist.\n" unless $noprint;
  150:     unlink('/tmp/lock_lcpasswd');
  151:     exit 5;
  152: }
  153: &enable_root_capability;
  154: ($>,$<)=(0,0);
  155: 
  156: print "Now $> , $< , -invoking pwchange with $safeusername $password1"
  157:     unless $noprint;
  158: open OUT,"|pwchange $safeusername";
  159: print OUT $password1;
  160: print OUT "\n";
  161: close OUT;
  162: ($>,$<)=(0,$wwwid);
  163: 
  164: print "pwchange done, back to uid $wwwid" unless $noprint;
  165: 
  166: if ($?) {
  167:     exit 8;
  168: }
  169: my $userid=getpwnam($safeusername);
  170: 
  171: if (-e '/usr/bin/smbpasswd') {
  172: 
  173:     ($>,$<)=(0,0); # fool smbpasswd here to think this is not a setuid
  174:                    # environment
  175: 
  176: #   If the -a switch is put on the smbpasswd
  177: # command line, either a new entry will be created or the old one
  178: # will be used. 
  179: # Therefore the old strategy of looking for and adding a dummy entry is 
  180: # not needed... Finally, the smbpasswd file is in /etc/samba not 
  181: # /etc/smbpasswd as older versions of the script implied.
  182: 
  183:     print "Running smbpasswd" unless $noprint;
  184:     open(OUT,"|/usr/bin/smbpasswd -s -a $safeusername>/dev/null") or
  185: 	die('cannot run smbpasswd');
  186:     print OUT $password2; print OUT "\n";
  187:     print OUT $password2; print OUT "\n";
  188:     close OUT;
  189:     $<=$wwwid; # unfool the program
  190:     print "smbpasswd done" unless $noprint;
  191: }
  192: 
  193: &disable_root_capability;
  194: unlink('/tmp/lock_lcpasswd');
  195: exit 0;
  196: 
  197: # ---------------------------------------------- have setuid script run as root
  198: sub enable_root_capability {
  199:     if ($wwwid==$>) {
  200: 	($<,$>)=($>,0);
  201: 	($(,$))=($),0);
  202:     }
  203:     else {
  204: 	# root capability is already enabled
  205:     }
  206:     return $>;
  207: }
  208: 
  209: # ----------------------------------------------- have setuid script run as www
  210: sub disable_root_capability {
  211:     if ($wwwid==$<) {
  212: 	($<,$>)=($>,$<);
  213: 	($(,$))=($),$();
  214:     }
  215:     else {
  216: 	# root capability is already disabled
  217:     }
  218: }
  219: 
  220: # ----------------------- make sure that another lcpasswd process isn't running
  221: sub try_to_lock {
  222:     my ($lockfile)=@_;
  223:     my $currentpid;
  224:     my $lastpid;
  225:     # Do not manipulate lock file as root
  226:     if ($>==0) {
  227: 	return 0;
  228:     }
  229:     # Try to generate lock file.
  230:     # Wait 3 seconds.  If same process id is in
  231:     # lock file, then assume lock file is stale, and
  232:     # go ahead.  If process id's fluctuate, try
  233:     # for a maximum of 10 times.
  234:     for (0..10) {
  235: 	if (-e $lockfile) {
  236: 	    open(LOCK,"<$lockfile");
  237: 	    $currentpid=<LOCK>;
  238: 	    close LOCK;
  239: 	    if ($currentpid==$lastpid) {
  240: 		last;
  241: 	    }
  242: 	    sleep 3;
  243: 	    $lastpid=$currentpid;
  244: 	}
  245: 	else {
  246: 	    last;
  247: 	}
  248: 	if ($_==10) {
  249: 	    return 0;
  250: 	}
  251:     }
  252:     open(LOCK,">$lockfile");
  253:     print LOCK $$;
  254:     close LOCK;
  255:     return 1;
  256: }
  257: 
  258: =head1 NAME
  259: 
  260: lcpasswd - LON-CAPA setuid script to synchronously change all
  261:            filesystem-related passwords (samba, unix, etc)
  262: 
  263: =head1 DESCRIPTION
  264: 
  265: LON-CAPA setuid script to synchronously change all
  266: filesystem-related passwords (samba, unix, etc)
  267: 
  268: =head1 README
  269: 
  270: LON-CAPA setuid script to synchronously change all
  271: filesystem-related passwords (samba, unix, etc)
  272: 
  273: =head1 PREREQUISITES
  274: 
  275: =head1 COREQUISITES
  276: 
  277: =pod OSNAMES
  278: 
  279: linux
  280: 
  281: =pod SCRIPT CATEGORIES
  282: 
  283: LONCAPA/Administrative
  284: 
  285: =cut

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