#!/usr/bin/perl

# ezpwebserv.cgi
# (c) 1999-2005 Useful Utilities
# http://www.usefulutilities.com
#
# Revised April 2005 to use qurl to pass URL from EZproxy to this
# script and back to EZproxy using URL encoding.

use Socket;
use Time::Local;

# This script simply connects back to the EZproxy server and starts a new
# session.  It's perfect for use if you can configure your web server
# to authenticate your users before running this script.

# To link EZproxy to this script, you need to make an entry in ezproxy.usr
# that looks like:
#
#     cgiuser:cgipass:qcgi=http://auth.mylib.org/cgi-bin/ezpwebserv.cgi?
#
# This line indicates that all new authentication requests should be
# handed off to the specified CGI script.  The ? at the end is required
# since EZproxy will then append qurl= followed by the web site the
# user wants to visit.
#
# $ezpuser and $ezppass have to be set to match the username and password
# from the ezproxy.usr entry.  $ezphost must be your EZproxy server's
# host name.
$ezpuser = "cgiuser";
$ezppass = "cgipass";
$ezphost = "ezproxy.mylib.org";

$action = $0;
$action =~ s/^.*[\/\\]//g;

$ezpport = 2048;

$| = 1;

ParseFields();

# If you want EZproxy to log this username, add "O LOGUSER" to ezproxy.cfg,
# uncomment the next line, and change as relevant to provide user to log
# $ezploguser = $ENV{"REMOTE_USER"};
StartSession();

sub Debug {
  return if $debugFile eq "";
  if ($debugOpen != 1) {
    open(DEBUG, ">>$debugFile") || return;
    $debugOpen = 1;
  }
  flock(DEBUG, LOCK_EX);
  seek(DEBUG, 0, 2);
  print DEBUG $_[0];
  flock(DEBUG, LOCK_UN);
}
  
sub Down
{
  Debug("$_[0]\n");
  print "Content-type: text/html\n\n";
  print $_[0], "\n";
  exit(1);
}

sub FormEncode
{
  my $temp = $_[0];

  $temp =~ s/([&'"])/sprintf("&#%d;",ord($1))/ge;
  return $temp;
}

sub URLEncode
{
  my $temp = $_[0];

  $temp =~ s/([^A-Za-z0-9])/sprintf("%%%2X", ord($1))/eg;
  $temp =~ s/%20/+/g;
  return $temp;
}

sub ParseFields
{
  my $in, $fieldval, $field, $val, $count;

  %in = ();
  if ($ENV{"REQUEST_METHOD"} eq "GET") {
    $in = $ENV{"QUERY_STRING"};
  } elsif ($ENV{"REQUEST_METHOD"} eq "POST") {
# In a POST, no special processing of URL is required
    read(STDIN, $in, $ENV{"CONTENT_LENGTH"});
  } else {
    return 0;
  }

  $count = 0;
  foreach $fieldval (split(/&/, $in)) {
    $fieldval =~ s/\+/ /g;
    ($field, $val) = split(/=/, $fieldval, 2);
    $val =~ s/%([0-9a-fA-F]{2})/pack("c",hex($1))/ge;
    # Remove inresult characters
    $val =~ s/[^!-~]//g;
    $in{$field} = $val;
    $count++;
  }

  if (defined $in{"qurl"}) { $ezpurl = $in{"qurl"} };

  return $count;
}

sub MakeConnection
{
  my $fh, $host, $port, $proto, $proto, $oldfh;

  ($fh, $host, $port) = @_;

  if ($host =~ s/:(\d+)$//) {
    $port = $1;
  }

  $proto = getprotobyname('tcp');

  $iaddr = inet_aton($host) || Down("Unable to lookup host $host: $!");
  $paddr = sockaddr_in($port, $iaddr);
  socket($fh, PF_INET, SOCK_STREAM, $proto) ||
    Down("Unable to create socket: $!");
  connect($fh, $paddr) || Down("Unable to connect to $host:$port: $!");

  $oldfh = select($fh);
  $| = 1;
  select($oldfh);
}

sub StartSession
{
  my $query;

  $query = "?user=" . URLEncode($ezpuser) . "&pass=" . URLEncode($ezppass);

  # If the calling script has set $ezploguser, pass this value to EZproxy
  # to log to the ezproxy.log file.  Note that your ezproxy.cfg must also
  # contain "O LOGUSER" to enable this feature.
  if ($ezploguser ne "") { $query .= "&loguser=" . URLEncode($ezploguser); }

  if ($ezpurl ne "") { $query .= "&qurl=" . URLEncode($ezpurl); }

  MakeConnection(EZPROXY, $ezphost, $ezpport);

  print EZPROXY "GET /login$query HTTP/1.0\n\n";
  $skip = <EZPROXY>;
  print while <EZPROXY>;
  close(EZPROXY);
}
