Приглашаем посетить
Authenticate
#!/usr/local/bin/perl
$NO = 0;
$YES = 1;
############################################################################
# #
# Authenticate Version 1.8 #
# Written by Craig A. Patchett craig@patchett.com #
# Created 9/15/96 Last Modified 7/15/97 #
# #
# Copyright 1997 Craig Patchett & Matthew Wright. All Rights Reserved. #
# This program is part of The CGI/Perl Cookbook from John Wiley & Sons. #
# License to use this program or install it on a server (in original or #
# modified form) is granted only to those who have purchased a copy of The #
# CGI/Perl Cookbook. (This notice must remain as part of the source code.) #
# #
############################################################################
############################################################################
# Define configuration constants #
############################################################################
# $REG_HOLD should be set to $YES or $NO to indicate whether or not you
# want to implement the registration hold feature of the program. This
# feature requires newly registered visitors to enter a registration code
# along with their User ID and Password the first time they log in.
$REG_HOLD = $YES;
# $REG_NOTICE should be set to $YES or $NO to indicate whether or not you
# want to send a notice of each registration to a site administrator.
$REG_NOTICE = $YES;
# $REG_ADMIN should be set to $YES or $NO to indicate whether or not you
# want visitors to receive automatic access to the system after registering.
# If $REG_ADMIN is set to $YES then new registrations will be added to
# $REG_HOLD_FILE and must be processed manually by the site adminstrator
# before the newly registered visitors will be allowed access to the site.
$REG_ADMIN = $NO;
# $ALLOW_FORCED is set to $YES or $NO depending on whether or not the program
# should check the first line in a requested page for a forced
# authentication flag (AUTHENTICATE="YES"). If set to $YES, such a flag
# exists, and the visitor's browser does not support cookies, the program
# will force the visitor to re-enter their user name and password.
$ALLOW_FORCED = $YES;
# $REG_ID_START is the starting value to use for Registration IDs
$REG_ID_START = '10000';
# $TRACK_USERS should be set to $YES or $NO depending on whether or not you
# want to keep authentication files in $AUTH_DIR after they've expired.
# (Since these files contain information about a visitor's journey through
# your pages, keeping them around gives you information that can be used
# to track users and site usage. It will also eventually use up a lot of
# disk space, however.)
$TRACK_USERS = $YES;
# $MAX_AGE is the maximum age in minutes since it was last accessed that a
# file in $AUTH_DIR should still be considered valid.
$MAX_AGE = 10;
# $MAX_RETRY is the maximum number of times a visitor may retry their
# User_ID/Password combination in either $REG_HOLD_URL or $AUTH_URL.
# A value of 0 means that no retries are allowed.
$MAX_RETRY = 2;
# $AUTH_DIR is the full path to the directory where your authentication
# files will be kept. (Note that it should include a directory delimiter at
# the end.)
$AUTH_DIR = '/home/user/authenticate/tmp/';
# $PAGE_DIR is the full path to the top directory where the HTML pages that
# are being protected by this program are kept. (Note that it should include
# a directory delimiter at the end.)
$PAGE_DIR = '/home/user/authenticate/pages/';
# $AUTH_PAGE_DIR is the full path to the directory where the HTML pages used
# by this program will be kept. (Note that it should include a directory
# delimiter at the end.)
$AUTH_PAGE_DIR = '/home/user/authenticate/';
# $PASSWD_DIR is the full path to the directory where your password
# information will be kept. (Note that it should include a directory
# delimiter at the end.)
$PASSWD_DIR = '/home/user/authenticate/';
# $LOCK_DIR is the full path to the directory where all lock files will be placed
# (Note that it should include a directory delimiter at the end.) If you're using
# a UNIX web server with flock it must be a directory outside the web space, i.e.
# "/tmp/"
$LOCK_DIR = '/tmp/';
# $AUTH_PAGE is the name of the HTML form that should be used for general
# authentication. This form should include the fields "USER_ID" and
# "PASSWORD" along with a hidden field named "TYPE" with a value of
# "auth_basic" and should point to this program. (This file should be
# stored in $AUTH_PAGE_DIR.)
$AUTH_PAGE = 'auth_basic.html';
# $AUTH_RETRY_PAGE is the name of the HTML form that should be used when a
# visitor has entered an incorrect User ID or Password in $AUTH_URL.
# This form should include the fields "USER_ID" and "PASSWORD" along with
# a hidden field named "TYPE" with a value of "auth_retry", and should
# point to this program. (This file should be stored in $AUTH_PAGE_DIR.)
$AUTH_RETRY_PAGE = 'auth_retry.html';
# $REG_HOLD_PAGE is the name of the HTML form that should be used to
# authenticate newly registered visitors who are logging in for the first
# time (only needed if $REG_HOLD is set to $YES. This form should include
# the fields "USER_ID", "PASSWORD", and "REG_CODE" along with a hidden
# field named "TYPE" with a value of "reg_hold", and should point to
# this program. (This file should be stored in $AUTH_PAGE_DIR.)
$REG_HOLD_PAGE = 'reg_hold.html';
# $HOLD_RETRY_PAGE is the name of the HTML form that should be used when
# a visitor has entered an incorrect User ID or Password in
# $REG_HOLD_URL. This form should include the fields "USER_ID" and
# "PASSWORD" along with a hidden field named "TYPE" with a value of
# "hold_retry", and should point to this program. (This file should be
# stored in $AUTH_PAGE_DIR.)
$HOLD_RETRY_PAGE = 'hold_retry.html';
# $REJECT_PAGE is the name of the HTML page that should be used for a
# visitor who does not enter a valid User_ID, Password, or Registration
# Code within the number of retries specified by $RETRY_URL. (This file
# should be stored in $AUTH_PAGE_DIR or may be a complete URL.)
$REJECT_PAGE = 'reject.html';
# $LOST_ID_PAGE is the name of the HTML form that should be used for a
# visitor who has lost their User ID. This form should include the fields
# "USER_ID", "PASSWORD", and "VERIFY" along with a hidden field named
# "TYPE" with a value of "lost_id", and should point to this program.
# (This file should be stored in $AUTH_PAGE_DIR.)
$LOST_ID_PAGE = 'lost_id.html';
# $LOST_INFO_PAGE is the name of the HTML page that should be used for a
# visitor who filled in the lost ID page and whose missing information
# has been found. (This file should be stored in $AUTH_PAGE_DIR.)
$LOST_INFO_PAGE = 'lost_info.html';
# $LOST_REJECT_PAGE is the name of the HTML page that should be used for
# a visitor who cannot be found in the password file after filling in the
# lost ID page. (This file should be stored in $AUTH_PAGE_DIR.)
$LOST_REJECT_PAGE = 'lost_reject.html';
# $REGISTER_PAGE is the name of the HTML form that should be used for
# registering a new user. This form should include the fields "USER_ID"
# and "PASSWORD" along with a hidden field named "TYPE" with a value of
# "register". It should also include the fields "NAME", "EMAIL",
# and "VERIFY" that will contain the full name of the visitor, their
# email address, and a word used to verify their identity in case they
# forget their User ID or Password (i.e. mother's maiden name). Other
# fields may also be included and can be processed by the ®ister()
# subroutine that should be in the required register.pl file. (This file
# should be stored in $AUTH_PAGE_DIR.)
$REGISTER_PAGE = 'register.html';
# $REG_INFO_PAGE is the name of the HTML page that should be used for
# general messages generated by the program during registration validation.
# The page should contain '<<TITLE>>' (without quotes) where the title of
# the page is to appear and '<<MESSAGE>>' (without quotes) where the message
# is to appear. (This file should be stored in $AUTH_PAGE_DIR.)
$REG_INFO_PAGE = 'reg_info.html';
# $DEFAULT_PAGE is the name of the default HTML page that should be displayed
# after a visitor has been successfully authenticated. This page will only
# be used if the program was initially called without a requested page.
$DEFAULT_PAGE = 'index.html';
# $PASSWD_FILE is the name of the file where your password information
# will be kept. If using UNIX, you may want to begin the filename with
# a period to add one extra (albeit relatively negligible) layer of
# protection.
$PASSWD_FILE = '.password';
# $REG_HOLD_FILE is the name of the file where information about visitors
# who have registered but not yet logged in for the first time will be
# stored if $REG_HOLD is set to $YES. This file should be in $PASSWD_DIR
$REG_HOLD_FILE = '.reg_hold';
# $REG_ID_FILE is the name of the file where the current registration id
# will be kept. The registration id is incremented for each registered
# user and allows each user to be assigned a unique identifictation number.
# If the registration hold feature is turned on, this number is sent to the
# visitor's email address and must be entered along with the User ID and
# Password the first time they authenticate. (This file will be stored in
# $PASSWD_DIR.) $REG_ID_START is the starting value to use for Registration
# IDs
$REG_ID_FILE = '.reg_id';
# If $REG_NOTICE is set to $YES, $NOTICE_SUBJECT will be used as the
# subject for the registration notice.
$NOTICE_SUBJECT = 'Registration Application';
# If $REG_NOTICE is set to $YES than a notice of each registration will
# be sent to the addresses specified by $NOTICE_TO, $NOTICE_CC, and
# $NOTICE_BCC. ($NOTICE_CC and $NOTICE_BCC are optional.)
$NOTICE_TO = 'admin@domain.com';
$NOTICE_CC = '';
$NOTICE_BCC = '';
# If $REG_NOTICE is set to $YES, $NOTICE_BODY should specify the full path
# to the file that contains the registration notification message to send to
# the administrator. This file can include any of the form variables
# surrounded by double brackets (i.e. <<PASSWORD>>) and the values of such
# variables will be substituted before the template is sent).
$NOTICE_BODY = '/home/user/authenticate/admin.txt';
# $REG_SUBJECT is the subject for the email message sent to a visitor with
# their registration ID
$REG_SUBJECT = 'Your Registration ID';
# $REG_FROM, $REG_CC, $REG_BCC are the email addresses that should accompany
# the registration id email send to a visitor after registering. $REG_CC and
# $REG_BCC are optional and will probably only be used if you want to
# receive a copy of each piece of email.
$REG_FROM = '(Your Site Name) webmaster@domain.com';
$REG_CC = '';
$REG_BCC = 'webmaster@domain.com';
# $REG_BODY is the full path to the text file that contains the body copy
# for the registration id email message. This message should contain
# '<<REG_ID>>' (without quotes) wherever you want the registration id to
# appear, and '<<PROGRAM>>' (without quotes) wherever you want the URL to the
# registration validation form to appear.
$REG_BODY = '/home/user/authenticate/reg_body.txt';
# $LOST_SUBJECT is the subject for the email message sent to a visitor with
# their authentication information if they forgot their User ID or Password
$LOST_SUBJECT = 'Your Authentication Information';
# $LOST_FROM, $LOST_CC, $LOST_BCC are the email addresses that should
# accompany the authentication information email send to a visitor after
# filling out the lost id form. $LOST_CC and $LOST_BCC are optional and will
# probably only be used if you want to receive a copy of each piece of email.
$LOST_FROM = '(Your Site Name) webmaster@domain.com';
$LOST_CC = '';
$LOST_BCC = 'webmaster@domain.com';
# $LOST_BODY is full path to the text file that contains the body copy for
# the authentication informatioin email message. This message should contain
# '<<USER_ID>>' and '<<PASSWORD>>' (without quotes) wherever you
# want the User ID and password to appear.
$LOST_BODY = '/home/user/authenticate/lost_body.txt';
# $SMTP_SERVER is the domain name of the SMTP server you will be using
# to send email. If you're not sure about this, ask your service provider.
$SMTP_SERVER = 'smtp.domain.com';
# $DUP_TITLE is the title that will appear in the registration information page
# if the visitor enters a duplicate user ID. $DUP_MESSAGE is the message that
# will be shown.
$DUP_TITLE = 'DUPLICATE USER ID';
$DUP_MESSAGE = 'The User ID you entered has already been taken.<P>';
$DUP_MESSAGE .= 'Please press the Back button on your browser to return to the ';
$DUP_MESSAGE .= 'registration page and enter a different User ID.';
# $SUBMIT_TITLE is the title that will appear in the registration information
# page after the visitor submits valid registration information if $REG_ADMIN
# is set to $YES. $SUBMIT_MESSAGE is the message that will be shown.
$SUBMIT_TITLE = 'REGISTRATION SUBMITTED';
$SUBMIT_MESSAGE = 'Your registration information has been submitted.<P>';
$SUBMIT_MESSAGE .= 'You will be notified by email as soon as your ';
$SUBMIT_MESSAGE .= 'registration has been processed and given instructions ';
$SUBMIT_MESSAGE .= 'on how to activate your account.';
# $MAX_WAIT is the maximum number of seconds the lock program will wait for a
# locked file to become unlocked
$MAX_WAIT = 5;
# $NAME_LEN is the maximum filename length in characters (not including
# extensions)
$NAME_LEN = 32;
# $DATE_FORMAT holds the &format_date() format for the current date and time
$DATE_FORMAT = "<0m>/<0d>/<yr> <mh>.<0n>.<0s>";
# $ERROR_PAGE is the full path to the HTML file that contains the template
# for an error message. This message should contain
# '<<ERROR_TITLE>>', '<<ERROR_NAME>>', and '<<ERROR_MSG>>' (without quotes)
# wherever you want the page title, error name, and error message to appear.
$ERROR_PAGE = '/home/user/error_page.html';
# $PERMISSIONS is the type of permissions you want to give to the files
# the program creates. They are expressed in standard UNIX octal format
# (i.e. 0666). If your server is running on a system that doesn't support
# file permissions then you should set $PERMISSIONS to 0.
$PERMISSIONS = 0666;
# $REQUIRE_DIR is the directory in which all of your required files are
# placed. On most systems, if you leave the required files in the same
# directory as the CGI program, you can leave this variable blank.
# Otherwise, if you move the required files to another directory, specify
# the full or relative path here.
$REQUIRE_DIR = 'require';
############################################################################
# Get required subroutines which need to be included. #
############################################################################
# Push $REQUIRE_DIR onto the @INC array for include file directories
# and list required files.
push(@INC, $REQUIRE_DIR) if $REQUIRE_DIR;
require 'locksubs.pl';
require 'formdate.pl';
require 'parsform.pl';
require 'register.pl';
require 'ipconvrt.pl';
require 'chkemail.pl';
require 'sendmail.pl';
require 'uuencode.pl';
require 'base64.pl';
require 'template.pl';
require 'error.pl';
require 'scramble.pl';
############################################################################
# Initialize other constants #
############################################################################
$WEB_SERVER = $ENV{'SERVER_NAME'};
$PROGRAM_URL = "http://$ENV{'SERVER_NAME'}$ENV{'SCRIPT_NAME'}$ENV{'PATH_INFO'}";
@PASSWORD = ($PASSWD_FILE, $REG_HOLD_FILE);
$REG_HOLD = ($REG_HOLD || $REG_ADMIN);
############################################################################
# Parse form data and check for cookies #
############################################################################
if (!&parse_form) { &error($Error_Message) }
if (!$FORM{'REQUEST'}) {
$FORM{'REQUEST'} = substr($ENV{'PATH_INFO'}, 1);
$FORM{'REQUEST'} =~ s|:/([^/])|://\1|;
if (!$FORM{'REQUEST'} && ($ENV{'HTTP_REFERER'} ne $PROGRAM_URL)) {
$FORM{'REQUEST'} = $ENV{'HTTP_REFERER'};
}
}
if ($ENV{'HTTP_COOKIE'}) { $COOKIES = $YES }
############################################################################
# Process request for registration hold authentication page #
############################################################################
if ($REG_HOLD && ($ENV{QUERY_STRING} eq 'HOLD')) {
$page_name = $REG_HOLD_PAGE;
$form_type = 'auth-hold-basic';
}
############################################################################
# Process initial request #
############################################################################
elsif (!$FORM{'TYPE'}) {
# Make sure the requested page is a valid one
$page_name = $FORM{'REQUEST'};
if ($page_name && !($page_name =~ m|://|)) {
$page_path = "$PAGE_DIR$page_name";
if (!(-f $page_path)) {
&error("$page_name is an invalid file name ($!).");
}
elsif (!(-r $page_path)) {
&error("$page_name is not readable ($!).");
}
elsif (!open(PAGE, $page_path)) {
&error("$page_name could not be opened ($!).");
}
# If the forced authentication option is on, check the first line
# of the file to see if it includes a forced authentication flag
if ($ALLOW_FORCED) {
$_ = <PAGE>;
$force_auth = /AUTHENTICATE="YES"/i;
}
close(PAGE);
}
# Check to see if they're already authenticated
if ($ENV{'HTTP_COOKIE'} =~ /$ENV{'SCRIPT_NAME'}=(\d+)/) { $auth_id = $1 }
elsif (!$COOKIES && !$force_auth) {
$auth_id = &ip_convert($ENV{'REMOTE_ADDR'});
}
# If an authentication id exists, make sure it's valid
$auth_path = "$AUTH_DIR$auth_id";
$date = time;
if ($auth_id && (-f $auth_path) && (-r $auth_path)) {
if (-M $auth_path < ($MAX_AGE / 1440)) {
# File exists and is valid so set appropriate flag and update
# file
open(AUTH, ">>$auth_path")
|| &error("Could not open authentication file ($!).");
print AUTH "$FORM{'REQUEST'}||$date\n";
close(AUTH);
$valid = $YES;
}
elsif (!$TRACK_USERS) { unlink($auth_path) }
}
if (!$valid) {
# No id or an invalid one, so prepare to give them the
# authentication form and attempt to set a cookie if needed
$page_name = $AUTH_PAGE;
$form_type = 'auth-basic';
if (!$COOKIES) {
print "Set-Cookie: $ENV{'SCRIPT_NAME'}_LAST=$date; path=/; expires=Tue, 04-Oct-2061 12:00:00 GMT;\n";
}
}
}
############################################################################
# Process request for lost id page #
############################################################################
elsif ($FORM{'HELP'}) {
$page_name = $LOST_ID_PAGE;
$form_type = "lost_id";
}
############################################################################
# Process request for registration page #
############################################################################
elsif ($FORM{'REGISTER'}) {
$page_name = $REGISTER_PAGE;
$form_type = "register";
}
############################################################################
# Process response from authentication page (plain, register, or retry) #
############################################################################
elsif ($FORM{'TYPE'} =~ /^auth/) {
# Check first to see if this is a registration hold
if ($reg_hold = ($REG_HOLD && ($FORM{'TYPE'} =~ '-hold-'))) {
$check_id = $FORM{'REG_ID'};
$passwd_file = $REG_HOLD_FILE;
}
else { $passwd_file = $PASSWD_FILE }
$passwd_path = "$PASSWD_DIR$passwd_file";
# Make sure they actually entered the necessary information
if ($FORM{'USER_ID'} && $FORM{'PASSWORD'}
&& (!$reg_hold || $check_id)) {
# Check password file to see if the entered information is valid
if (&lock($passwd_file, $LOCK_DIR, $MAX_WAIT)) {
&error($Error_Message);
}
if (-e $passwd_path) {
open(PASS, $passwd_path) || &error("Could not open $passwd_file ($!).");
$user_id = $FORM{'USER_ID'};
while ($record = <PASS>) {
if ($record =~ /^$user_id\|\|/) {
# User ID matches so check the password (and
# registration id if appropriate)
($file_passwd, $reg_id, $name, $email) = (split(/\|\|/, $record, 9))[1,4,7,8];
chop($email);
if ((crypt($FORM{'PASSWORD'}, $file_passwd) eq $file_passwd)
&& (!$reg_hold || ($reg_id == $check_id))) {
$valid = $YES;
# If this is a registration hold, move the user's
# info to the password file
if ($reg_hold) {
# Copy to the password file
if (&lock($PASSWD_FILE, $LOCK_DIR, $MAX_WAIT)) {
&error($Error_Message);
}
open(PASSWD, ">>$PASSWD_DIR$PASSWD_FILE")
|| &error("Could not open $PASSWD_FILE ($!).");
print PASSWD $record;
close(PASSWD);
if (&unlock($PASSWD_FILE, $LOCK_DIR)) {
&error($Error_Message);
}
# Remove from the registration hold file
seek(PASS, 0, 0);
$backup = "$passwd_path.bak";
open(BAK, ">$backup")
|| &error("Could not create $backup ($!).");
if ($PERMISSIONS) { chmod $PERMISSIONS, $backup }
while (<PASS>) {
if (!/^$user_id\|\|/) { print BAK }
}
close(PASS);
unlink($passwd_path);
rename($backup, $passwd_path)
|| &error("Could not rename $backup ($!).");
}
# Call the local authentication subroutine
&set_authenticate;
# Get out of the loop
last;
}
}
}
close(PASS);
}
if (&unlock($passwd_file, $LOCK_DIR)) { &error($Error_Message) }
}
# If not, send to retry page as long as maximum tries not exceeded
if (!$valid && $FORM{'RETRIES'} < $MAX_RETRY) {
++$FORM{'RETRIES'};
if ($reg_hold) { $page_name = $HOLD_RETRY_PAGE }
else { $page_name = $AUTH_RETRY_PAGE }
$form_type = $FORM{'TYPE'};
$form_type =~ s/-.*$/-retry/i;
}
elsif (!$valid) {
$page_name = $REJECT_PAGE;
$form_type = 'auth_reject';
}
}
############################################################################
# Process response from registration page #
############################################################################
elsif ($FORM{'TYPE'} =~ /^register/) {
# Make sure the User ID is unique (check password file and reg hold
# file)
if ($user_id = $FORM{'USER_ID'}) {
foreach $passwd_file (@PASSWORD) {
$passwd_path = "$PASSWD_DIR$passwd_file";
if (&lock($passwd_file, $LOCK_DIR, $MAX_WAIT)) {
&error($Error_Message);
}
if (!(-e $passwd_path)) {
open(PASS, ">>$passwd_path")
|| &error("Could not create $passwd_file ($!).");
if ($PERMISSIONS) { chmod $PERMISSIONS, $passwd_path }
}
else {
open(PASS, $passwd_path)
|| &error("Could not open $passwd_file ($!).");
while ($unique && ($record = <PASS>)) {
if ($record =~ /^$user_id\|\|/) { $unique = $NO }
}
}
close(PASS);
if (&unlock($passwd_file, $LOCK_DIR)) { &error($Error_Message) }
}
}
# Tell them if not
if (!$unique) {
$VAR{'TITLE'} = $DUP_TITLE;
$VAR{'MESSAGE'} = $DUP_MESSAGE;
}
# Otherwise, if the registration information hasn't already been
# processed, do so now with the user-provided routine
elsif (®ister) {
# Get the next registration id
$reg_id_path = "$PASSWD_DIR$REG_ID_FILE";
if (&lock($REG_ID_FILE, $LOCK_DIR, $MAX_WAIT)) {
&error($Error_Message);
}
if (!(-e $reg_id_path) || -z $reg_id_path) {
open(REGID, ">>$reg_id_path")
|| &error("Could not create $REG_ID_FILE ($!).");
if ($PERMISSIONS) { chmod $PERMISSIONS, $reg_id_path }
$reg_id = $REG_ID_START;
}
else {
open(REGID, "+<$reg_id_path")
|| &error("Could not open $REG_ID_FILE ($!).");
$reg_id = <REGID>;
seek(REGID, 0, 0);
}
print REGID $reg_id + 1;
close(REGID);
if (&unlock($REG_ID_FILE, $LOCK_DIR)) { &error($Error_Message) }
# Encrypt the password and verify fields and scramble the password
# using the verify field as the key (the scrambled password will
# only be used when searching for a lost password)
srand(time^$$);
$encrypt_pass = crypt($FORM{'PASSWORD'}, substr(rand(time), -2);
$encrypt_verify = crypt($FORM{'VERIFY'}, substr(rand(time), -2);
$scramble_pass = &scramble($FORM{'PASSWORD'}, $FORM{'VERIFY'});
# Create the password file record
$date = &format_date(time, $DATE_FORMAT);
$record = "$FORM{'USER_ID'}||$encrypt_pass||$encrypt_verify||";
$record .= "$scramble_pass||$reg_id||$ENV{'REMOTE_ADDR'}||$date||";
$record .= "$FORM{'NAME'}||$FORM{'EMAIL'}\n";
# Save it to the appropriate file
$passwd_file = $REG_HOLD ? $REG_HOLD_FILE : $PASSWD_FILE;
if (&lock($passwd_file, $LOCK_DIR, $MAX_WAIT)) {
&error($Error_Message);
}
open(PASSWD, ">>$PASSWD_DIR$passwd_file")
|| &error("Could not open $passwd_file ($!).");
print PASSWD $record;
close(PASSWD);
if (&unlock($passwd_file, $LOCK_DIR)) { &error($Error_Message) }
# If registration notification is on, send the administrator
# the registration information
if ($REG_NOTICE) {
$VAR{'REG_ID'} = $reg_id;
if (&send_email($NOTICE_SUBJECT, $FORM{'EMAIL'}, $NOTICE_TO,
$NOTICE_CC, $NOTICE_BCC, $NOTICE_BODY)) {
&error($Error_Message);
}
}
# Send the visitor the appropriate message
if ($REG_ADMIN) {
# Give the visitor a message also
$VAR{'TITLE'} = $SUBMIT_TITLE;
$VAR{'MESSAGE'} = $SUBMIT_MESSAGE;
}
elsif ($REG_HOLD) {
# Email them their registration id if registration hold is
# active
$VAR{'PROGRAM'} = "$PROGRAM_URL?HOLD";
$VAR{'REG_ID'} = $reg_id;
if (&send_email($REG_SUBJECT, $REG_FROM, $FORM{'EMAIL'}, $REG_CC,
$REG_BCC, $REG_BODY)) {
&error($Error_Message);
}
$page_name = $REG_HOLD_PAGE;
$form_type = 'auth-hold-basic';
}
else {
# They're in!
&set_authenticate;
$valid = $YES;
}
}
if ($VAR{'TITLE'}) {
# Print the MIME header
print "Content-type: text/html\n\n";
# Read and parse the file
&parse_template("$AUTH_PAGE_DIR$REG_INFO_PAGE", *STDOUT);
# We're done
exit;
}
}
############################################################################
# Process response from lost ID page #
############################################################################
elsif ($FORM{'TYPE'} eq 'lost_id') {
# Make sure they gave us at least two pieces of requested information
if (!$FORM{'VERIFY'} || (!$FORM{'USER_ID'} && !$FORM{'PASSWORD'})) {
# Send them back to the form again
$page_name = $LOST_ID_PAGE;
$form_type = 'lost_id';
}
# Otherwise, search for a matching record in the password files
else {
# Pull the fields out of the array for speed
$user_id = $FORM{'USER_ID'};
$password = $FORM{'PASSWORD'};
$verify = $FORM{'VERIFY'};
# Check each password file
CHECK: foreach $passwd_file (@PASSWORD) {
$passwd_path = "$PASSWD_DIR$passwd_file";
if (&lock($passwd_file, $LOCK_DIR, $MAX_WAIT)) {
&error($Error_Message);
}
if (!(-e $passwd_path)) { next }
open(PASS, $passwd_path)
|| &error("Could not open $passwd_file ($!).");
while ($record = <PASS>) {
# Check first for a match on User ID if given
if ($user_id && ($record =~ /^$user_id\|\|/)) {
($file_passwd, $file_verify, $pass_scramble, $email) =
(split(/\|\|/, $record, 9))[1,2,3,8];
if (crypt($verify, $file_verify) eq $file_verify) {
$password = &unscramble($pass_scramble, $verify);
if (crypt($password, $file_passwd) eq $file_passwd) {
$VAR{'PASSWORD'} = $password;
$FORM{'USER_ID'} = '';
$match = $YES;
}
}
# We're done here one way or another, so get out of the
# loops
last CHECK;
}
# If no match on User ID, check for match on password and
# verify
elsif (!$user_id) {
($file_id, $file_passwd, $file_verify, $email) =
(split(/\|\|/, $record, 9))[0,1,2,8];
if ((crypt($password, $file_passwd) eq $file_passwd)
&& (crypt($verify, $file_verify) eq $file_verify)) {
$VAR{'USER_ID'} = $file_id;
$FORM{'PASSWORD'} = '';
$match = $YES;
last CHECK;
}
}
}
close(PASS);
if (&unlock($passwd_file, $LOCK_DIR)) { &error($Error_Message) }
}
# If there's a match then email them the information they're
# missing, otherwise send them to the reject page
if ($match) {
chop($email);
if (&send_email($LOST_SUBJECT, $LOST_FROM, $email, $LOST_CC,
$LOST_BCC, $LOST_BODY)) {
&error($Error_Message);
}
$page_name = $LOST_INFO_PAGE;
}
else {
$page_name = $LOST_REJECT_PAGE;
$form_type = 'lost_reject';
}
}
}
############################################################################
# Send them to or give them the appropriate page #
############################################################################
# If they're a valid user then give them the page they requested
if ($valid) {
if (!$FORM{'REQUEST'}) { $FORM{'REQUEST'} = $DEFAULT_PAGE }
if ($FORM{'REQUEST'} =~ m|://|) {
print "Location: $FORM{'REQUEST'}\n\n";
exit;
}
$page_name = $FORM{'REQUEST'};
$page_path = "$PAGE_DIR$page_name";
}
else { $page_path = "$AUTH_PAGE_DIR$page_name" }
# Check to see if the requested page is a valid, readable file
if (!(-f $page_path)) {
&error("$page_name is an invalid file name ($!).");
}
elsif (!(-r $page_path)) {
&error("$page_name is not readable ($!).");
}
elsif (!open(PAGE, $page_path)) {
&error("$page_name could not be opened ($!).");
}
# Set up the hidden fields if we're sending them to a form
if ($form_type) {
$type = '<INPUT TYPE="HIDDEN"';
$hidden_fields = "$type NAME=\"RETRIES\" VALUE=\"$FORM{'RETRIES'}\">\n";
$hidden_fields .= "$type NAME=\"TYPE\" VALUE=\"$form_type\">\n";
$hidden_fields .= "$type NAME=\"REQUEST\" VALUE=\"$FORM{'REQUEST'}\">\n";
}
# Print the MIME header
if ($page_path =~ /\.html?$/i) {
print "Content-type: text/html\n\n";
$html = $YES;
}
elsif ($page_path =~ /\.txt$/i) { print "Content-type: text/plain\n\n" }
elsif ($page_path =~ /\.gif$/i) { print "Content-type: image/gif\n\n" }
elsif ($page_path =~ /\.jpe?g$/i) { print "Content-type: image/jpeg\n\n" }
elsif ($page_path =~ /\.pdf$/i) { print "Content-type: application/pdf\n\n" }
else { print "Content-type: application/octet-stream\n\n" }
# Read and parse the file
while (<PAGE>) {
# If this is a form check for the ACTION attribute if we haven't seen it
if ($html && $form_type && !$action_line
&& s/ACTION="[^"]*"/ACTION="$PROGRAM_URL"/i) {
$action_line = $YES;
print $_;
print $hidden_fields;
}
else { print $_ }
}
############################################################################
# Local subroutine to assign authentication ID and create auth file. #
############################################################################
sub set_authenticate {
# Set the authentication id
$date = time;
if ($COOKIES) {
$auth_id = $reg_id;
$ENV{'SCRIPT_NAME'} =~ m|^(/?.*)/|;
print "Content-type: text/html\n";
print "Set-Cookie: $ENV{'SCRIPT_NAME'}=$auth_id; path=$1\n";
print "Set-Cookie: $ENV{'SCRIPT_NAME'}_LAST=$date; path=/; expires=Tue, 04-Oct-2061 12:00:00 GMT;\n";
}
else { $auth_id = &ip_convert($ENV{'REMOTE_ADDR'}) }
# Create the authentication file
$auth_path = "$AUTH_DIR$auth_id";
if (!$COOKIES && !$ALLOW_FORCED && (-e $auth_path)
&& (-M $auth_path < ($MAX_AGE / 1440))) {
&error("Someone is already logged in from $ENV{'REMOTE_ADDR'}");
}
open(AUTH, ">>$auth_path")
|| &error("Could not modify $auth_id ($!).");
if ($PERMISSIONS) { chmod $PERMISSIONS, "AUTH_DIR$auth_id" }
if (-s $auth_path) { print AUTH "\n" }
print AUTH "$user_id\n$FORM{'REQUEST'}||$date\n";
close(AUTH);
# Delete any old authentication files if requested
if (!$TRACK_USERS) {
opendir(DIR, $AUTH_DIR);
@files = readdir(DIR);
closedir(DIR);
foreach $file (@files) {
if (-M "$AUTH_DIR$file" >= ($MAX_AGE / 1440)) {
push(@expired, "$AUTH_DIR$file");
}
}
unlink(@expired);
}
}