File:  [LON-CAPA] / loncom / lcpasswd
Revision 1.14: download - view: text, annotated - select for diffs
Thu Feb 14 22:09:14 2002 UTC (22 years, 2 months ago) by harris41
Branches: MAIN
CVS tags: HEAD
map to foreach

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

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