File:  [LON-CAPA] / loncom / lcpasswd
Revision 1.17: download - view: text, annotated - select for diffs
Mon Sep 16 13:27:40 2002 UTC (21 years, 7 months ago) by foxr
Branches: MAIN
CVS tags: HEAD
Bug 701 - added additional $noprint conditionalized deubgging.
    In lcpasswd, removed code too put a dummy entry at the end of
    /etc/smbpasswd (it's not the right file anyway), and added the -a
   switch to the smbpasswd command invocation.

    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.17 2002/09/16 13:27:40 foxr 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 NEW 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: print "Now root, -invoking pwchange with $safeusername $password1"
  162:     unless $noprint;
  163: open OUT,"|pwchange $safeusername";
  164: print OUT $password1;
  165: print OUT "\n";
  166: close OUT;
  167: ($>,$<)=(0,500);
  168: 
  169: print "pwchange done, back to uid 500" unless $noprint;
  170: 
  171: if ($?) {
  172:     exit 8;
  173: }
  174: my $userid=getpwnam($safeusername);
  175: 
  176: if (-e '/usr/bin/smbpasswd') {
  177: 
  178:     ($>,$<)=(0,0); # fool smbpasswd here to think this is not a setuid
  179:                    # environment
  180: 
  181: #   If the -a swithc is put on the smbpasswd
  182: # command line, either a new entry will be created or the old one
  183: # will be used. 
  184: # Therefore the old strategy of looking for and adding a dummy entry is 
  185: # not needed... Finally, the smbpasswd file is in /etc/samba not 
  186: # /etc/smbpasswd as older versions of the script implied.
  187: 
  188:     print "Running smbpasswd" unless $noprint;
  189:     open(OUT,"|/usr/bin/smbpasswd -s -a $safeusername>/dev/null") or
  190: 	die('cannot run smbpasswd');
  191:     print OUT $password2; print OUT "\n";
  192:     print OUT $password2; print OUT "\n";
  193:     close OUT;
  194:     $<=$wwwid; # unfool the program
  195:     print "smbpasswd done" unless $noprint;
  196: }
  197: 
  198: &disable_root_capability;
  199: unlink('/tmp/lock_lcpasswd');
  200: exit 0;
  201: 
  202: # ---------------------------------------------- have setuid script run as root
  203: sub enable_root_capability {
  204:     if ($wwwid==$>) {
  205: 	($<,$>)=($>,$<);
  206: 	($(,$))=($),$();
  207:     }
  208:     else {
  209: 	# root capability is already enabled
  210:     }
  211:     return $>;
  212: }
  213: 
  214: # ----------------------------------------------- have setuid script run as www
  215: sub disable_root_capability {
  216:     if ($wwwid==$<) {
  217: 	($<,$>)=($>,$<);
  218: 	($(,$))=($),$();
  219:     }
  220:     else {
  221: 	# root capability is already disabled
  222:     }
  223: }
  224: 
  225: # ----------------------- make sure that another lcpasswd process isn't running
  226: sub try_to_lock {
  227:     my ($lockfile)=@_;
  228:     my $currentpid;
  229:     my $lastpid;
  230:     # Do not manipulate lock file as root
  231:     if ($>==0) {
  232: 	return 0;
  233:     }
  234:     # Try to generate lock file.
  235:     # Wait 3 seconds.  If same process id is in
  236:     # lock file, then assume lock file is stale, and
  237:     # go ahead.  If process id's fluctuate, try
  238:     # for a maximum of 10 times.
  239:     for (0..10) {
  240: 	if (-e $lockfile) {
  241: 	    open(LOCK,"<$lockfile");
  242: 	    $currentpid=<LOCK>;
  243: 	    close LOCK;
  244: 	    if ($currentpid==$lastpid) {
  245: 		last;
  246: 	    }
  247: 	    sleep 3;
  248: 	    $lastpid=$currentpid;
  249: 	}
  250: 	else {
  251: 	    last;
  252: 	}
  253: 	if ($_==10) {
  254: 	    return 0;
  255: 	}
  256:     }
  257:     open(LOCK,">$lockfile");
  258:     print LOCK $$;
  259:     close LOCK;
  260:     return 1;
  261: }
  262: 
  263: =head1 NAME
  264: 
  265: lcpasswd - LON-CAPA setuid script to synchronously change all
  266:            filesystem-related passwords (samba, unix, etc)
  267: 
  268: =head1 DESCRIPTION
  269: 
  270: LON-CAPA setuid script to synchronously change all
  271: filesystem-related passwords (samba, unix, etc)
  272: 
  273: =head1 README
  274: 
  275: LON-CAPA setuid script to synchronously change all
  276: filesystem-related passwords (samba, unix, etc)
  277: 
  278: =head1 PREREQUISITES
  279: 
  280: =head1 COREQUISITES
  281: 
  282: =pod OSNAMES
  283: 
  284: linux
  285: 
  286: =pod SCRIPT CATEGORIES
  287: 
  288: LONCAPA/Administrative
  289: 
  290: =cut

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