#
# HPT Advanced Readonly
# v 0.1
#
# Copyright (c) 2002 Andrew Sagulin. Freeware.
#
# $Id: Hpt_ro.pm,v 1.2 2002/09/27 07:29:19 andrews42 Rel $
package Hpt_ro;
use strict;
use vars qw($ro_conf $hptconf);
use 5.006;
my $groupsymbol = '@';
my $commentchar = '#';
#
# put your paths here
#
my $defhptconf = "n:\\bin\\hpt\\config";
$ro_conf = "n:\\bin\\hpt\\ro.cfg";
$hptconf = $ENV{FIDOCONFIG} ? $ENV{FIDOCONFIG} : $defhptconf;
my (%allow,%deny);
1;
#
# protos
#
sub trim($);
sub echo2re($);
sub link2re($);
sub readhptconf($);
sub readroconf($);
#
# init %allow and %deny
#
sub init() {
my @acl = readroconf($ro_conf);
my @echoes = readhptconf($hptconf);
{
my ($d,$m,$y) = (localtime())[3..5];
my $curtime = sprintf("%02d%02d%02d",$y % 100, $m + 1, $d);
# Expired rules
foreach(@acl) {
next unless $_->{date};
$_ = undef if ($_->{date} lt $curtime);
}
}
foreach(@echoes) {
my $echo = $_;
my $echotag = $echo->{echotag};
my $echogroup = $echo->{group} ? "-" . $echo->{group} : "";
# temporary @acl (exclude rules no matched with echotag)
my @tacl = @acl;
FORLINKS:
foreach(@{$echo->{links}}) {
my $link = $_;
FORACL:
foreach(@tacl) {
my $acl = $_;
next unless $acl;
my $matched = 0;
foreach(@{$acl->{echogroup}}) {
my $group = $_;
if ($group =~ /^-/) {
next unless $echogroup;
if ($echogroup eq $group) {$matched = 1; last;}
}
else {
if ($echotag =~ /$group/) {$matched = 1; last;}
}
}
unless ($matched) {
$_ = undef; # exclude by echotag
next FORACL;
}
$matched = 0;
foreach(@{$acl->{linkgroup}}) {
if ($link =~ /$_/) {$matched = 1; last;}
}
next FORACL unless $matched;
if ($acl->{deny}) {$deny{$echotag}{$link} = $acl->{cfgline};}
else {$allow{$echotag}{$link} = 1;}
next FORLINKS;
} # foreach(@tacl)
$deny{$echotag}{$link} = "no rule"; # deny - no rules matched
} # foreach(@{$echo->{links}})
} # foreach(@echoes)
} # init()
#
# check link for readonly
#
# return reason if access denied
#
sub checkro($$) {
my($echotag,$link) = @_;
return "" unless $echotag; # netmail? -> return
$link .= ".0" unless $link =~ /\.\d+$/;
$echotag = uc($echotag);
return $deny{$echotag}{$link} if exists $deny{$echotag}{$link};
return "" if exists $allow{$echotag}{$link};
init(); # reread configs
return $deny{$echotag}{$link} if exists $deny{$echotag}{$link};
# Echo or link not exist in spite of rereading config
# so it's not my business - let tosser do its job
return ""
}
#
# delete trailing and leading spaces
#
# Usage: $b = trim($a);
#
sub trim($) {
my $s=shift @_;
$s =~ s/^[ \t]+//;
$s =~ s/[ \t]+$//;
return $s;
}
#
# convert echo mask to regular expression
#
sub echo2re($) {
my $re = shift @_;
$re = uc(quotemeta($re));
$re =~ s/\\\*/.*/g;
return qr/^$re$/;
}
#
# convert link mask to regular expression
#
sub link2re($) {
my $re = shift @_;
$re .= ".0" unless $re =~ /\..+$/; # add 0-point to node address
$re = quotemeta($re);
$re =~ s/\\\*/\\d+/g;
return qr/^$re$/;
}
#
# recursive function for reading HPT config
#
sub readhptconf($) {
my $cfgname = shift @_;
my @echoes;
open(my $hcfg,$cfgname) or die "Can not open $cfgname: $!\n";
while(<$hcfg>) {
chomp;
s/([^$commentchar]*)$commentchar.+/$1/; # kill comments
tr/\t/ /;
$_ = trim($_);
next if /^$/; # skip empty lines
if (/^include +([^ ]+)/i) {
push @echoes, readhptconf($1);
}
elsif (/^echoarea\b/i) {
my $echo;
# remove some options at first. They (may) contain address-like words
s/-d +"[^"]+"//i; # description
s/-a +\d+:\d+\/\d+(\.\d+)?//i; # our AKA
s/-sbadd\([^)]+\)//i; # sbadd
s/-sbign\([^)]+\)//i; # sbign
my(undef,$echotag,undef,@options) = split / +/;
$echotag = uc($echotag);
$echo->{echotag} = $echotag;
$echo->{group} = $1 if /-g +([^ ]+)/;
while(@options) {
my $opt = shift @options;
if ($opt =~ /\d+:\d+\/\d+(\.\d+)?/) { # opt is a link
$opt .= '.0' unless $opt =~/\.\d+$/;
push @{$echo->{links}},$opt;
}
} # while(@options)
push @echoes,$echo;
} # elsif (/^echoarea\b/i)
} # while(<$hcfg>)
close($hcfg);
return @echoes;
}
#
# read hpt_ro config
#
sub readroconf($) {
my $cfgname = shift @_;
my %echogroups;
my %linkgroups;
my @acl;
open(my $hcfg,$cfgname) or die "Can not open $cfgname: $!\n";
my $state = 'main'; # main, echo, link
my $curgroup;
while(<$hcfg>) {
chomp;
s/([^$commentchar]*)$commentchar.+/$1/; # kill comments
tr/\t/ /;
$_ = trim($_);
next if /^$/;
if ($state eq 'main') {
if (/^echogroup\b/i) {
my(undef,$groupname,@items) = split / +/;
die "Echogroup name can not start from '-'" if $groupname =~ /^-/;
if (@items) {
$_ = echo2re($_) foreach(@items);
push @{$echogroups{$groupname}},@items;
}
else {
$curgroup = $groupname;
$state = 'echo';
}
next;
} # echogroup
if (/^linkgroup\b/i) {
my(undef,$groupname,@items) = split / +/;
if (@items) {
$_ = link2re($_) foreach(@items);
push @{$linkgroups{$groupname}},@items;
}
else {
$curgroup = $groupname;
$state = 'link';
}
next;
} # linkgroup
if (/^(allow|deny)\b/i) {
my(undef,$link,$echo,$date) = split / +/;
my %acl;
$acl{deny} = /^deny/i ? 1 : 0;
$acl{cfgline} = $_;
if ($link =~ /^$groupsymbol/) {
$link =~ s/^@//;
die "Unknown group '$link' at '$_'\n" unless $linkgroups{$link};
$acl{linkgroup} = $linkgroups{$link};
}
elsif (/^-/) {
$acl{linkgroup} = [link2re($link)];
}
else {
$acl{linkgroup} = [link2re($link)];
}
if ($echo =~ /^$groupsymbol/) {
$echo =~ s/^@//;
if ($echo =~ /^-/) {
$acl{echogroup} = [$echo];
}
else {
die "Unknown group '$echo' at '$_'\n" unless $echogroups{$echo};
$acl{echogroup} = $echogroups{$echo};
}
}
else {
$acl{echogroup} = [echo2re($echo)];
}
if ($date) {
$date =~ /(\d\d)\.(\d\d)\.(\d\d)/ or die "Bad date '$date' at '$_'\n";
$acl{date} = sprintf("%02d%02d%02d",$3,$2,$1)
}
push @acl,\%acl;
next;
} # allow | deny
} # main state
elsif ($state eq 'echo') {
if (/^endechogroup$/i) {
$state = 'main';
next;
}
my @items = split / +/;
$_ = echo2re($_) foreach(@items);
push @{$echogroups{$curgroup}},@items;
} # echo state
elsif ($state eq 'link') {
if (/^endlinkgroup$/i) {
$state = 'main';
next;
}
my @items = split / +/;
$_ = link2re($_) foreach(@items);
push @{$linkgroups{$curgroup}},@items;
} # link state
else {die "Unknown parser state: $state\n";}
} # while
die "'echogroup' $curgroup block not closed by 'endechogroup'" if $state eq 'echo';
die "'linkgroup' $curgroup block not closed by 'endlinkgroup'" if $state eq 'link';
close($hcfg);
return @acl;
}
syntax highlighted by Code2HTML, v. 0.9.1