This file is indexed.

/usr/share/qpsmtpd/plugins/async/uribl is in qpsmtpd 0.94-2.

This file is owned by root:root, with mode 0o644.

The actual contents of the file can be viewed below.

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
#!perl -w

use Qpsmtpd::Plugin::Async::DNSBLBase;

use strict;
use warnings;

sub init {
    my ($self, $qp, %args) = @_;
    my $class = ref $self;

    $self->isa_plugin("uribl");
    {
        no strict 'refs';
        push @{"${class}::ISA"}, 'Qpsmtpd::Plugin::Async::DNSBLBase';
    }

    $self->SUPER::init($qp, %args);
}

sub register {
    my $self = shift;

    $self->register_hook('data_post', 'start_data_post');
    $self->register_hook('data_post', 'finish_data_post');
}

sub start_data_post {
    my ($self, $transaction) = @_;
    my $class = ref $self;

    my @names;

    my $queries = $self->lookup_start(
        $transaction,
        sub {
            my ($self, $name) = @_;
            push @names, $name;
        }
    );

    my @hosts;
    foreach my $z (keys %{$self->{uribl_zones}}) {
        push @hosts, map { "$_.$z" } @names;
    }

    $transaction->notes(uribl_results => {});
    $transaction->notes(uribl_zones   => $self->{uribl_zones});

    return DECLINED
      unless @hosts && $class->lookup($self->qp, [@hosts], [@hosts]);

    return YIELD;
}

sub finish_data_post {
    my ($self, $transaction) = @_;

    my $matches = $self->collect_results($transaction);
    for (@$matches) {
        $self->log(LOGWARN, $_->{desc});
        if ($_->{action} eq 'add-header') {
            $transaction->header->add('X-URIBL-Match', $_->{desc});
        }
        elsif ($_->{action} eq 'deny') {
            return (DENY, $_->{desc});
        }
        elsif ($_->{action} eq 'denysoft') {
            return (DENYSOFT, $_->{desc});
        }
    }
    return DECLINED;
}

sub init_resolver { }

sub process_a_result {
    my ($class, $qp, $result, $query) = @_;

    my $transaction = $qp->transaction;
    my $results     = $transaction->notes('uribl_results');
    my $zones       = $transaction->notes('uribl_zones');

    foreach my $z (keys %$zones) {
        if ($query =~ /^(.*)\.$z$/) {
            my $name = $1;
            $results->{$z}->{$name}->{a} = $result;
        }
    }
}

sub process_txt_result {
    my ($class, $qp, $result, $query) = @_;

    my $transaction = $qp->transaction;
    my $results     = $transaction->notes('uribl_results');
    my $zones       = $transaction->notes('uribl_zones');

    foreach my $z (keys %$zones) {
        if ($query =~ /^(.*)\.$z$/) {
            my $name = $1;
            $results->{$z}->{$name}->{txt} = $result;
        }
    }
}

sub collect_results {
    my ($self, $transaction) = @_;

    my $results = $transaction->notes('uribl_results');

    my @matches;
    foreach my $z (keys %$results) {
        foreach my $n (keys %{$results->{$z}}) {
            if (exists $results->{$z}->{$n}->{a}) {
                if ($self->evaluate($z, $results->{$z}->{$n}->{a})) {
                    $self->log(LOGDEBUG, "match $n in $z");
                    push @matches,
                      {
                        action => $self->{uribl_zones}->{$z}->{action},
                        desc   => "$n in $z: "
                          . (
                                  $results->{$z}->{$n}->{txt}
                               || $results->{$z}->{$n}->{a}
                            ),
                      };
                }
            }
        }
    }

    return \@matches;
}

=head1 NAME

uribl - URIBL blocking plugin for qpsmtpd

=head1 DESCRIPTION

This plugin implements DNSBL lookups for URIs found in spam, such as that
implemented by SURBL (see E<lt>http://surbl.org/E<gt>).  Incoming messages are
scanned for URIs, which are then checked against one or more URIBLs in a
fashion similar to DNSBL systems.

=head1 CONFIGURATION

See the documentation of the non-async version. The timeout config option is
ignored, the ParaDNS timeout is used instead.

=cut