#!/usr/bin/perl -w ########################################################################### # # Password Changer v.01 # # Charles Schweizer # 2000 # # This cgi is the combinition of two different CGI's plus a lot of my own # code. # ########################################################################### # # CGI Number 1 # # Tim Hockin # 1998 # # Tim wrote the script that gave me this idea. I have use some of his # code and design philosophy. # ########################################################################### # # CGI Number 2 # # BRINK Version 1.2.4 (View the ChangeLog for changes since last version.) # Copyright (C) 1999 Andrew R. Brink abrink@linuxguru.net # # Bad Risky Insanely Noodleriffic Kludge - # BRINK is a perl cgi that enables people to change there passwords via # a web page. # ########################################################################### # # This program is free software; you can redistribute it and/or # modify it under the terms of the GNU General Public License # as published by the Free Software Foundation; either version 2 # of the License, or (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.# # # Please read the file LICENSE for the full GPL license agreement. # Read the README for general info. # Read INSTALL for instructions. # # See the file CREDITS, for credits of course. # ########################################################################## use strict; use CGI qw(:standard); use Authen::PAM; ################### # User Definables ################### my $minlengtholdpass = 5; my $minlength = 6; my $maxlength = 10; my $maxlennam = 14; my $fontface = ""; my $banneduser = "I'm sorry, you can not change this users password using this program."; my $passisuser = "Whoops! The new password is the same as the username or old password. Please try again."; my $passisdiff = "Whoops! The passwords you entered where different. Please try again."; my $tooshort = "Your new password is too short, minimum length is $minlength characters."; my $toolong = "Your new password is too long, maximum length is $maxlength characters."; my $natoolong = "The user name you entered is to long, maximum length is $maxlennam."; my $enterpass = "Please enter your correct password."; my $nouser = "Please enter an user name."; my $spec = "Please do not use any special characters."; my @banned = ("root", "bin", "daemon", "adm", "lp", "sync", "shutdown", "halt", "mail", "news", "uucp", "operator", "games", "gopher", "ftp", "nobody", "xfs", "gdm", "postgres", "squid"); ################ # Variables ################ my %bannedhash; my $userid = param("UserID"); my $pass = param("pass"); my $newpass = param("newpass"); my $vnewpass = param("vnewpass"); my $service = "passwd"; my $pamh; my $ret; my $state; my $passlen; my $passlen2; my $userlen; my $OK_CHARS='-a-zA-Z0-9_.@'; ############################## # # MAIN # ############################## check_leng(); check_ban(); check_newpass(); check_pass(); change_pass(); front_end(); # end main ################### # Check imputed variables for length ################### sub check_leng() { ########### # Check to make sure a username has been entered ########### if($userid eq "") { print header, start_html("Password Change"); print $fontface; print $nouser; print end_html; die } $userlen = length($userid); ################### # Maximum userid length is $minlength characters ################### if($userlen > $maxlennam) { print header, start_html("Password Change"); print $fontface; print $natoolong; print end_html; die } $passlen = length($pass); if($passlen eq 0) { $passlen = 1; } ################### # Minimum password length is $minlength characters ################### if(($passlen > $maxlength) || ($passlen < $minlengtholdpass)) { print header, start_html("Password Change"); print $fontface; print $enterpass; print end_html; die } $passlen = length($newpass); $passlen2 = length($vnewpass); if (($passlen eq 0) || ($passlen2 eq 0)) { $passlen = 1; $passlen2 = 1; } ################### # Minimum password length is $minlength characters ################### if(($passlen < $minlength) || ($passlen2 < $minlength)) { print header, start_html("Password Change"); print $fontface; print $tooshort; print end_html; die } ################### # Maximum password length is $maxlength characters ################### if(($passlen > $maxlength) || ($passlen > $maxlength)) { print header, start_html("Password Change"); print $fontface; print $toolong; print end_html; die } # # Check for special characters # my $tmp; $tmp = $userid; s/[^$OK_CHARS]/tmp/go; if($tmp ne $userid){ print header, start_html("Password Change"); print $fontface; print $spec; print end_html; die } $tmp = $pass; s/[^$OK_CHARS]/tmp/go; if($tmp ne $pass){ print header, start_html("Password Change"); print $fontface; print $spec; print end_html; die } $tmp = $newpass; s/[^$OK_CHARS]/tmp/go; if($tmp ne $newpass){ print header, start_html("Password Change"); print $fontface; print $spec; print end_html; die } } ################### # Added to ensure root password can't be changed ################### sub check_ban { $bannedhash{$_} = 1 foreach(@banned); if($bannedhash{$userid} ) { print header, start_html("Password Change"); print $fontface; print $banneduser; print end_html; die } } ################### # Check the password and user ################### sub check_newpass { ################### # Check to see if passwords are the same ################### if($newpass ne $vnewpass) { print header, start_html("Password Change"); print $fontface; print $passisdiff; print end_html; die } ################### # To make sure users don't try to do anything too stupid # Don't allow new password to be the username ################### if(($pass eq $newpass) || ($newpass eq $userid)) { print header, start_html("Password Change"); print $fontface; print $passisuser; print end_html; die } ################### # Check to make sure user exists ################### my $user; $user = getpwnam($userid); if ($user eq "") { print header, start_html("Password Change"); print("Please enter your correct UserID"); print end_html; die; } } ########################## # # Authenticate the user # ########################## sub check_pass { sub my_conv_func { my @res; while ( @_ ) { my $code = shift; my $msg = shift; my $ans = ""; $ans = $userid if ($code == PAM_PROMPT_ECHO_ON() ); $ans = $pass if ($code == PAM_PROMPT_ECHO_OFF() ); push @res, PAM_SUCCESS(); push @res, $ans; } push @res, PAM_SUCCESS(); return @res; } ref($pamh = new Authen::PAM($service, $userid, \&my_conv_func)) || die "Error code $pamh during PAM init!"; $ret=$pamh->pam_authenticate; if($ret ne 0) { print header, start_html("Password Change"); print("Please enter your correct UserID Password"); print end_html; die; } ################################################# # # Works with /etc/passwd NOT shadow # # # $pwd = (getpwnam ($userid)) [1]; # $salt = $pwd; # # if (crypt($pass, $salt) ne $pwd) { # print header, start_html("Password Change"); # print("Please enter your correct password"); # print end_html; # die; # } ################################################# } ############################### # # Change password and send email # ############################### sub change_pass { sub my_conv_func2 { my @res; while ( @_ ) { my $code = shift; my $msg = shift; my $ans = ""; $ans = $userid if ($code == PAM_PROMPT_ECHO_ON() ); if ($code == PAM_PROMPT_ECHO_OFF() ) { $ans = $pass if ($state == 0); $ans = $newpass if ($state == 1); $ans = $vnewpass if ($state == 2); $state++; } push @res, PAM_SUCCESS(); push @res, $ans; } push @res, PAM_SUCCESS(); return @res; } ref($pamh = new Authen::PAM($service, $userid, \&my_conv_func2)) || die "Error code $pamh during PAM init!"; $state = 0; $pamh->pam_chauthtok; sub my_conv_func3 { my @res; while ( @_ ) { my $code = shift; my $msg = shift; my $ans = ""; $ans = $userid if ($code == PAM_PROMPT_ECHO_ON() ); $ans = $newpass if ($code == PAM_PROMPT_ECHO_OFF() ); push @res, PAM_SUCCESS(); push @res, $ans; } push @res, PAM_SUCCESS(); return @res; } ref($pamh = new Authen::PAM($service, $userid, \&my_conv_func3)) || die "Error code $pamh during PAM init!"; $ret=$pamh->pam_authenticate; if($ret ne 0) { print header, start_html("Password Change"); print("Please use a better password."); print end_html; die; } } ################### # Beginning of web front end ################### sub front_end { print header, start_html("Password Change Finished"), h1 ("Your Password Has Been Changed!"); print p("The password for user $userid has been changed."); print end_html; }