File:  [LON-CAPA] / loncom / lcpasswd
Revision 1.18: download - view: text, annotated - select for diffs
Thu Sep 19 02:02:59 2002 UTC (21 years, 7 months ago) by foxr
Branches: MAIN
CVS tags: version_0_6_2, version_0_6, HEAD
Bug 701 Fixed various little diddly stuff that prevented a new filesystem authenticated user from getting an initial passwd.

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

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