File:  [LON-CAPA] / loncom / lcpasswd
Revision 1.13: download - view: text, annotated - select for diffs
Thu Nov 15 18:34:57 2001 UTC (22 years, 6 months ago) by harris41
Branches: MAIN
CVS tags: stable_2002_spring, stable_2001_fall, HEAD
important fixes, documentation addition

#!/usr/bin/perl

# The Learning Online Network with CAPA
#
# lcpasswd - LON-CAPA setuid script to synchronously change all
#            filesystem-related passwords (samba, unix, etc)
#
# YEAR=2000
# 10/27,10/28,10/29,10/30 Scott Harrison
#
# YEAR=2001
# 10/22,10/23,11/13,11/15 Scott Harrison
#
# $Id: lcpasswd,v 1.13 2001/11/15 18:34:57 harris41 Exp $
###

###############################################################################
##                                                                           ##
## ORGANIZATION OF THIS PERL SCRIPT                                          ##
##                                                                           ##
## 1. Description of script                                                  ##
## 2. Invoking script (standard input only)                                  ##
## 3. Example usage inside another piece of code                             ##
## 4. Description of functions                                               ##
## 5. Exit codes                                                             ##
##                                                                           ##
###############################################################################

use strict;

# ------------------------------------------------------- Description of script
#
# This script is a setuid script that should
# be run by user 'www'.  This script allows
# for synchronous entry of passwords into
# both the /etc/passwd and the /etc/smbpasswd
# files.
#
# This script works under the same process control mechanism
# as lcuseradd and lcpasswd, to make sure that only one of these
# processes is running at any one time on the system.

# --------------------------------------- Invoking script (standard input only)
#
# Standard input usage
# First line is USERNAME
# Second line is CURRENT PASSWORD
# Third line is NEW PASSWORD
#
# Valid passwords must consist of the
# ascii characters within the inclusive
# range of 0x20 (32) to 0x7E (126).
# These characters are:
# SPACE and
# !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNO
# PQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~
#
# Valid user names must consist of ascii
# characters that are alphabetical characters
# (A-Z,a-z), numeric (0-9), or the underscore
# mark (_). (Essentially, the perl regex \w).
# User names must begin with an alphabetical character
# (A-Z,a-z).

# ---------------------------------------------------- Description of functions
# enable_root_capability() : have setuid script run as root
# disable_root_capability() : have setuid script run as www
# try_to_lock() : make sure that another lcpasswd process isn't running

# ------------------------------------------------------------------ Exit codes
# These are the exit codes.
# ( (0,"ok"),
#   (1,"User ID mismatch.  This program must be run as user 'www'"),
#   (2,"Error. This program needs 3 command-line arguments (username, old ".
#       password, new password)."),
#   (3,"Error. Three lines need to be entered into standard input."),
#   (4,"Error. Too many other simultaneous password change requests being ".
#       made."),
#   (5,"Error. User $username does not exist."),
#   (6,"Error. Invalid entry of current password."),
#   (7,"Error. Root was not successfully enabled."),
#   (8,"Error. Cannot set password."),
#   (9,"Error. The user name specified has invalid characters."),
#   (10,"Error. A password entry had an invalid character.") )

# ------------------------------------------------------------- Initializations
# Security
$ENV{'PATH'}='/bin:/usr/bin:/usr/local/sbin:/home/httpd/perl'; # Nullify path
                                                               # information
delete @ENV{qw(IFS CDPATH ENV BASH_ENV)}; # nullify potential taints

# Do not print error messages
my $noprint=1;

# ----------------------------- Make sure this process is running from user=www
my $wwwid=getpwnam('www');
&disable_root_capability;
if ($wwwid!=$>) {
    print("User ID mismatch.  This program must be run as user 'www'\n")
	unless $noprint;
    exit 1;
}

# ----------------------------------- Start running script with www permissions
&disable_root_capability;

# --------------------------- Handle case of another lcpasswd process (locking)
unless (&try_to_lock('/tmp/lock_lcpasswd')) {
    print "Error. Too many other simultaneous password change requests being ".
	"made.\n" unless $noprint;
    exit 4;
}

# ------- Error-check input, need 3 values (user name, password 1, password 2).
my @input;
@input=<>;
if (@input!=3) {
    print("Error. Three lines need to be entered into standard input.\n")
	unless $noprint;
    unlink('/tmp/lock_lcpasswd');
    exit 3;
}
map {chomp} @input;

my ($username,$password1,$password2)=@input;
$username=~/^(\w+)$/;
my $safeusername=$1;
if (($username ne $safeusername) or ($safeusername!~/^[A-Za-z]/)) {
    print "Error. The user name specified has invalid characters.\n";
    unlink('/tmp/lock_lcpasswd');
    exit 9;
}
my $pbad=0;
map {if (($_<32)&&($_>126)){$pbad=1;}} (split(//,$password1));
map {if (($_<32)&&($_>126)){$pbad=1;}} (split(//,$password2));
if ($pbad) {
    print "Error. A password entry had an invalid character.\n";
    unlink('/tmp/lock_lcpasswd');
    exit 10;
}

# -- Only add user if the two password arguments match.
if ($password1 ne $password2) {
    print "Error. Password mismatch.\n" unless $noprint;
    unlink('/tmp/lock_lcpasswd');
    exit 13;
}

# Verify existence of user
unless(getpwnam($safeusername)) {
    print "Error. User $username does not exist.\n" unless $noprint;
    unlink('/tmp/lock_lcpasswd');
    exit 5;
}

&enable_root_capability;
($>,$<)=(0,0);
open OUT,"|pwchange $safeusername";
print OUT $password1;
print OUT "\n";
close OUT;
($>,$<)=(0,500);

if ($?) {
    exit 8;
}
my $userid=getpwnam($safeusername);

if (-e '/usr/bin/smbpasswd') {

    ($>,$<)=(0,0); # fool smbpasswd here to think this is not a setuid
                   # environment
    unless (-e '/etc/smbpasswd') {
	open (OUT,'>/etc/smbpasswd'); close OUT;
    }

    my $smbexist=0;
    open (IN, '</etc/smbpasswd');
    my @lines=<IN>;
    close IN;
    for my $l (@lines) {
	chop $l;
	my @F=split(/\:/,$l);
	if ($F[0] eq $username) {$smbexist=1;}
    }
    unless ($smbexist) {
	open(OUT,'>>/etc/smbpasswd');
	print OUT join(':',($safeusername,$userid,
			    'XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX:XXXXXXXXXXXXXX'.
			    'XXXXXXXXXXXXXXXXXX','','/home/'.$safeusername,
			    '/bin/bash')) . "\n";
	close OUT;
    }

    open(OUT,"|/usr/bin/smbpasswd -s $safeusername>/dev/null") or
	die('cannot run smbpasswd');
    print OUT $password2; print OUT "\n";
    print OUT $password2; print OUT "\n";
    close OUT;
    $<=$wwwid; # unfool the program
}

&disable_root_capability;
unlink('/tmp/lock_lcpasswd');
exit 0;

# ---------------------------------------------- have setuid script run as root
sub enable_root_capability {
    if ($wwwid==$>) {
	($<,$>)=($>,$<);
	($(,$))=($),$();
    }
    else {
	# root capability is already enabled
    }
    return $>;
}

# ----------------------------------------------- have setuid script run as www
sub disable_root_capability {
    if ($wwwid==$<) {
	($<,$>)=($>,$<);
	($(,$))=($),$();
    }
    else {
	# root capability is already disabled
    }
}

# ----------------------- make sure that another lcpasswd process isn't running
sub try_to_lock {
    my ($lockfile)=@_;
    my $currentpid;
    my $lastpid;
    # Do not manipulate lock file as root
    if ($>==0) {
	return 0;
    }
    # Try to generate lock file.
    # Wait 3 seconds.  If same process id is in
    # lock file, then assume lock file is stale, and
    # go ahead.  If process id's fluctuate, try
    # for a maximum of 10 times.
    for (0..10) {
	if (-e $lockfile) {
	    open(LOCK,"<$lockfile");
	    $currentpid=<LOCK>;
	    close LOCK;
	    if ($currentpid==$lastpid) {
		last;
	    }
	    sleep 3;
	    $lastpid=$currentpid;
	}
	else {
	    last;
	}
	if ($_==10) {
	    return 0;
	}
    }
    open(LOCK,">$lockfile");
    print LOCK $$;
    close LOCK;
    return 1;
}

=head1 NAME

lcpasswd - LON-CAPA setuid script to synchronously change all
           filesystem-related passwords (samba, unix, etc)

=head1 DESCRIPTION

LON-CAPA setuid script to synchronously change all
filesystem-related passwords (samba, unix, etc)

=head1 README

LON-CAPA setuid script to synchronously change all
filesystem-related passwords (samba, unix, etc)

=head1 PREREQUISITES

=head1 COREQUISITES

=pod OSNAMES

linux

=pod SCRIPT CATEGORIES

LONCAPA/Administrative

=cut

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>
500 Internal Server Error

Internal Server Error

The server encountered an internal error or misconfiguration and was unable to complete your request.

Please contact the server administrator at root@localhost to inform them of the time this error occurred, and the actions you performed just before this error.

More information about this error may be available in the server error log.