chiark / gitweb /
close idle connections and spot unresponsive ones
[innduct.git] / samples / nnrpd_access.pl.in
1 #! /usr/bin/perl
2 # fixscript will replace this line with require innshellvars.pl
3
4 ##
5 ##  Sample code for the nnrpd Perl access hooks.
6
7 ##  This file is loaded when a perl_access: parameter is reached in
8 ##  readers.conf.  If it defines a sub named access, which will be
9 ##  called during processing of a perl_access: parameter. Attributes
10 ##  about the connection are passed to the program in the %attributes
11 ##  global variable.  It should return a hash containing
12 ##  parameter-value pairs for the access group. If there is a problem,
13 ##  nnrpd will die and syslog the exact error.
14
15 ##  The default behavior of the following code is to look for nnrp.access
16 ##  in INN's configuration file directory and to attempt to implement about
17 ##  the same host-based access control as the previous nnrp.access code in
18 ##  earlier versions of INN.  This may be useful for backward compatibility.
19
20 ##  This file cannot be run as a standalone script, although it would be
21 ##  worthwhile to add some code so that it could so that one could test the
22 ##  results of various authentication and connection queries from the
23 ##  command line.  The #! line at the top is just so that fixscript will
24 ##  work.
25
26 # This function is called when perl_access: is reached in readers.conf.
27 # For details on all the information passed to it, see
28 # ~news/doc/hook-perl.
29 sub access {
30    &loadnnrp($inn::newsetc . '/nnrp.access');
31    return &checkhost($attributes{hostname}, $attributes{ipaddress});
32 }
33
34 # Called at startup, this loads the nnrp.access file and converts it into a
35 # convenient internal format for later queries.
36 sub loadnnrp {
37     my $file = shift;
38     my ($block, $perm, $user, $pass);
39
40     open (ACCESS, $file) or die "Could not open $file: $!\n";
41     local $_;
42     while (<ACCESS>) {
43         my %tmp;
44
45         chomp;
46         s/\#.*//;
47         ($block, $perm, $user, $pass, $tmp{groups}) = split /:/;
48         next unless (defined $tmp{groups});
49
50         # We don't support username/password entries, so be safe.
51         next if ($user || $pass);
52
53         # Change the wildmat pattern to a regex (this isn't thorough, as
54         # some ranges won't be converted properly, but it should be good
55         # enough for this purpose).
56         if ($block !~ m%^(?:\d+\.){3}\d+/\d+$%) {
57             $block =~ s/\./\\./g;
58             $block =~ s/\?/./g;
59             $block =~ s/\*/.*/g;
60         }
61         $tmp{block} = $block;
62
63         $tmp{canread} = ($perm =~ /r/i);
64         $tmp{canpost} = ($perm =~ /p/i);
65
66         unshift(@hosts, { %tmp });
67     }
68     close ACCESS;
69 }
70
71 # Given the hostname and IP address of a connecting host, use our @hosts
72 # array constructed from nnrp.access and see what permissions that host has.
73 sub checkhost {
74     my ($host, $ip) = @_;
75     my %return_hash;
76     my $key;
77     for $key (@hosts) {
78         my ($read, $post) = ($key->{canread}, $key->{canpost});
79
80         # First check for CIDR-style blocks.
81         if ($key->{block} =~ m%^(\d+\.\d+\.\d+\.\d+)/(\d+)$%) {
82             my $block = unpack('N', pack('C4', split(/\./, $1)));
83             my $mask = (0xffffffff << (32 - $2)) & 0xffffffff;
84             $block = $block & $mask;
85             my $packedip = unpack('N', pack('C4', split(/\./, $ip)));
86             if (($packedip & $mask) == $block) {
87                 if ($read) {
88                     $return_hash{"read"} = $key->{groups};
89                 }
90                 if ($post) {
91                     $return_hash{"post"} = $key->{groups};
92                 }
93                 return %return_hash;
94             }
95         }
96
97         if ($ip =~ /^$key->{block}$/) {
98             if ($read) {
99                 $return_hash{"read"} = $key->{groups};
100             }
101             if ($post) {
102                 $return_hash{"post"} = $key->{groups};
103             }
104             return %return_hash;
105         }
106
107         if ($host =~ /^$key->{block}$/) {
108             if ($read) {
109                 $return_hash{"read"} = $key->{groups};
110             }
111             if ($post) {
112                 $return_hash{"post"} = $key->{groups};
113             }
114             return %return_hash;
115         }
116     }
117
118     # If we fell through to here, nothing matched, so we should deny
119     # permissions.
120     return %return_hash;
121 }