File:  [LON-CAPA] / loncom / lcpasswd
Revision 1.15: download - view: text, annotated - select for diffs
Tue Feb 19 21:51:09 2002 UTC (22 years, 2 months ago) by matthew
Branches: MAIN
CVS tags: version_0_5_1, version_0_5, version_0_4, stable_2002_july, stable_2002_april, STABLE, HEAD
Fixed silly bug in checking for invalid password characters.

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

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