# # 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; }