#!/usr/bin/perl =pod COPYRIGHT chpw.pl was written by Tommy Butler Sunday, September 23, 2001 4:18:30 PM Copyright Tommy Butler Atrixnet Web Development, 2001 All rights reserved. mailto:perl.scripts@atrixnet.com http://www.atrixnet.com This script is free, the modules are free, and you may use and distribute this software under the same terms as Perl itself. MANIFEST This script (chpw.pl) should have come with the following list of files 1. futil.pm 2. PCOM.pm 3. userdata.txt 4. form_template.tmpl 5. error_template.tmpl 6. fail_template.tmpl 7. success_template.tmpl INSTALLATION (6 easy steps) 1. Place this script in your cgi bin directory. 2. Change permissions on this script to 755 on linux/unix systems by using your FTP client software, or from a command line shell by typing the following command after entering the directory where this script is located: chmod 755 chpw.pl 3. Create a subdirectory inside your cgi-bin directory named 'modules' and place the modules which came with this script into that directory. You can tell which files are modules because they have a .pm file suffix. If you already have a subdirectory in your cgi-bin named 'modules', just put the modules which came with this script into that directory and everything will work just fine. 4. Create a subdirectory inside your cgi-bin directory named 'udata' and place the text file which came with this script into that directory. If you already have a subdirectory in your cgi-bin named 'udata', just put the text file which came with this script into that directory and everything will work just fine. 5. This script will use the text file as a database. This means that the script must be able to read and write to that file. On linux and unix type servers, you will have to adjust the permissions on the udata directory and the userdata.txt file to 777 in most cases. To change permissions on the udata directory and the userdata.txt text file to 777 on linux/unix systems, tryusing your FTP client software, or from a command line shell like bash or sh over telnet. In the shell type the following commands after entering the directory containing your udata subdirectory: chmod 777 udata chmod 777 udata/userdata.txt This will not pose a security risk so long as your cgi bin is not a subdirectory of your root webserver directory. The root webserver directory is often named 'htdocs', 'public_html', 'webserver', or something like that. If your cgi bin directory is a subdirectory of your root webserver directory, you can still make the udata directory outside of the cgi-bin as long as you edit this script so that it will look in the right place for the udata directory. This is accomplised by editing the hash variable set up immediately under the section header labled: # ---------------------------------- # setup Directories # ---------------------------------- 6. Create a subdirectory inside your cgi-bin directory named 'templates' and place the html files which came with this script into that directory. You can tell which files are html files because they have a .tmpl file suffix. If you already have a subdirectory in your cgi-bin named 'templates', just put the html files which came with this script into thatdirectory and everything will work just fine. STRUCTURE OF THE DATABASE record fields will appear in this order: +====================================================+ | Fields in each user's data record | +==========+==============+==========================+ | Field | Type | Default | +----------+--------------+--------------------------+ | id | integer | 0 | | uid | integer | 0 | | username | varchar | NULL | | password | varchar | NULL | | fname | varchar | NULL | | lname | varchar | NULL | | email | varchar | NULL | | url | varchar | NULL | | created | varchar |1642823810102650 (gmtime) | | last_mod | varchar |1642823810102650 (gmtime) | +----------+--------------+--------------------------+ =cut # --------------------------------------------------------- # Prepare runtime environment, define global configuration # --------------------------------------------------------- use strict; use vars qw($pcom $main); BEGIN { # ---------------------------------- # get paths, pwd, script name, # current namespace with PCOM # ---------------------------------- use lib './modules'; use PCOM; $pcom = PCOM->new(); $main = $pcom->main(); # ---------------------------------- # setup Directories # ---------------------------------- $main->{'DIR'} = { 'modules' => $main->{'PWD'}.'/modules', 'templates' => $main->{'PWD'}.'/templates', 'data' => $main->{'PWD'}.'/udata', }; } # end of BEGIN block # -------------------------------------------------------- # Load modules # -------------------------------------------------------- # get base code library use lib $main->{'DIR'}{'modules'}; # use CGI class use CGI; # use futil class use futil; # -------------------------------------------------------- # initialize class objects # -------------------------------------------------------- # cgi object my($cgi) = CGI->new(); # file utilities library object my($fil) = futil->new( 'main' => $main ); # -------------------------------------------------------- # set up variables # -------------------------------------------------------- # unbuffer STDOUT $| = 1; my($datafile) = $main->{'DIR'}{'data'}.'/userdata.txt'; my($username) = $cgi->param('username'); my($userid) = $cgi->param('userid'); my($password) = $cgi->param('password'); my($newpass) = $cgi->param('newpass'); my($confirmpass) = $cgi->param('confirmpass'); my(@db_records) = (); my($db_records) = []; my($rec) = 0; my($changed) = 0; my($db_content) = ''; my($templates) = { 'form' => $main->{'DIR'}{'templates'}.'/form_template.tmpl', 'error' => $main->{'DIR'}{'templates'}.'/error_template.tmpl', 'success' => $main->{'DIR'}{'templates'}.'/success_template.tmpl', 'fail' => $main->{'DIR'}{'templates'}.'/fail_template.tmpl', }; # -------------------------------------------------------- # validate request # -------------------------------------------------------- if ( (length($username) == 0) or (length($password) == 0) or (length($newpass) == 0) or (length($confirmpass) == 0) ) { # send user back an error message if the # form contained empty fields &error(); } elsif ($newpass ne $confirmpass) { # send user back an error message if the # data entered into the new password field # did not match the data entered into the # new password confirmation field &error(); } # -------------------------------------------------------- # exec program # -------------------------------------------------------- # read database records into an array @db_records = split(/\n/, $fil->load_file($datafile)); $db_records = \@db_records; # scan the database records for a matching id, pw foreach $rec (@{ $db_records }) { # eat newlines off the end of each record chomp($rec); # split record into its fields my(@record) = split(/\|/, $rec); # save the record fields by name # in an easy-to understand hash # datastructure for simple checks # against record field contents my(%record) = ( 'id' => $record[0], 'uid' => $record[1], 'username' => $record[2], 'password' => $record[3], 'fname' => $record[4], 'lname' => $record[5], 'email' => $record[6], 'url' => $record[7], 'created' => $record[8], 'last_mod' => $record[9], ); # check the record for a matching uid and pw if ( ($record{'username'} eq $username) and ($record{'password'} eq $password) ) { # the userid and password match, so perform # the requested change of password, and update # the flag in this user's record which tells # when the record was last modified $record{'password'} = $newpass; $record{'last_mod'} = gmtime; # re-assemble the record with its newly # updated field values, retaining the order # of the fields which is outlined in the # description of our Database Structure found # at the top of this script my(@new_record) = ( $record{'id'}, $record{'uid'}, $record{'username'}, $record{'password'}, $record{'fname'}, $record{'lname'}, $record{'email'}, $record{'url'}, $record{'created'}, $record{'last_mod'} ); $db_records->[$rec] = join('|', @new_record); # set success flag $changed++; # break out of the loop last; } else { warn( qq[ record{'username'} = $record{'username'} record{'password'} = $record{'password'}] ); } } if ($changed > 0) { # if the password was successfully changed # put the records array values back into a scalar variable, # with each record separated by a newline character $db_content = join(qq[\n], @{ $db_records }); # over-write the database file with all its previously # existing records, only this time it will also contain # the updates which were made to the user's account # who called this script $fil->write_file( 'filename' => $datafile, 'content' => $db_content, ); # begin sending output to browser print $cgi->header(); # print out a success message to the user indicating # that their password was successfully changed print $fil->load_file($templates->{'success'}); } else { # if the password was not changed &fail(); } # mod_perl compatible exit &clean_exit(); # -------------------------------------------------------- # end program, define subroutines # -------------------------------------------------------- # ---------------------------------- # sub clean_exit # ---------------------------------- sub clean_exit { # exits cleanly for normal apache sites, # OR mod_perl-enabled apache sites by getting # rid of any variables still floating around # in the depths of our CGI class instance or # other object namespaces CORE::undef($cgi); CORE::undef($fil); CORE::undef($pcom); CORE::undef($main); } # ---------------------------------- # sub fail # ---------------------------------- sub fail { # begin sending output to browser print $cgi->header(); # print out an error message to the user indicating # that their password was not successfully changed # because they could not be authenticated print $fil->load_file($templates->{'fail'}); # exit this script now exit; } # ---------------------------------- # sub error # ---------------------------------- sub error { # begin sending output to browser print $cgi->header(); # print out an error message to the user indicating # that their password was not successfully changed # because they could not be authenticated print $fil->load_file($templates->{'error'}); # exit this script now exit; } # -------------------------------------------------------- # end subroutine declarations, all done. # --------------------------------------------------------