chiark / gitweb /
Remove .pc subdirectory (from some pre-dgit import ?)
[innduct.git] / .pc / nocem-gpg-import / control / perl-nocem.in
diff --git a/.pc/nocem-gpg-import/control/perl-nocem.in b/.pc/nocem-gpg-import/control/perl-nocem.in
deleted file mode 100644 (file)
index 5630d12..0000000
+++ /dev/null
@@ -1,629 +0,0 @@
-#!/usr/bin/perl -w
-# fixscript will replace this line with require innshellvars.pl
-
-##############################################################################
-# perl-nocem - a NoCeM-on-spool implementation for INN 2.x.
-# Copyright 2000 by Miquel van Smoorenburg <miquels@cistron.nl>
-# Copyright 2001 by Marco d'Itri <md@linux.it>
-# This program is licensed under the terms of the GNU General Public License.
-#
-# List of changes:
-#
-# 2002: Patch by Steven M. Christey for untrusted printf input.
-# 2007: Patch by Christoph Biedl for checking a timeout.
-# Documentation improved by Jeffrey M. Vinocur (2002), Russ Allbery (2006)
-# and Julien Elie (2007).
-#
-##############################################################################
-
-require 5.00403;
-use strict;
-
-# XXX FIXME I haven't been able to load it only when installed.
-# If nobody can't fix it just ship the program with this line commented.
-#use Time::HiRes qw(time);
-
-my $keyring = $inn::pathetc . '/pgp/ncmring.gpg';
-
-# XXX To be moved to a config file.
-#sub local_want_cancel_id {
-#    my ($group, $hdrs) = @_;
-#
-## Hippo has too many false positives to be useful outside of pr0n groups
-#    if ($hdrs->{issuer} =~ /(?:Ultra|Spam)Hippo/) {
-#        foreach (split(/,/, $group)) {
-#            return 1 if /^alt\.(?:binar|sex)/;
-#        }
-#        return 0;
-#    }
-#    return 1;
-#}
-
-# no user serviceable parts below this line ###################################
-
-# global variables
-my ($working, $got_sighup, $got_sigterm, @ncmperm, $cancel);
-my $use_syslog = 0;
-my $log_open = 0;
-my $nntp_open = 0;
-my $last_cancel = 0;
-my $socket_timeout = $inn::peertimeout - 100;
-
-my $logfile = $inn::pathlog . '/perl-nocem.log';
-
-# initialization and main loop ###############################################
-
-eval { require Sys::Syslog; import Sys::Syslog; $use_syslog = 1; };
-
-if ($use_syslog) {
-    eval "sub Sys::Syslog::_PATH_LOG { '/dev/log' }" if $^O eq 'dec_osf';
-    Sys::Syslog::setlogsock('unix') if $^O =~ /linux|dec_osf/;
-    openlog('nocem', '', $inn::syslog_facility);
-}
-
-if (not $inn::gpgv) {
-    logmsg('cannot find the gpgv binary', 'err');
-    sleep 5;
-    exit 1;
-}
-
-if ($inn::version and not $inn::version =~ /^INN 2\.[0123]\./) {
-    $cancel = \&cancel_nntp;
-} else {
-    $cancel = \&cancel_ctlinnd;
-}
-
-$SIG{HUP}  = \&hup_handler;
-$SIG{INT}  = \&term_handler;
-$SIG{TERM} = \&term_handler;
-$SIG{PIPE} = \&term_handler;
-
-logmsg('starting up');
-
-unless (read_ctlfile()) {
-    sleep 5;
-    exit 1;
-}
-
-while (<STDIN>) {
-    chop;
-    $working = 1;
-    do_nocem($_);
-    $working = 0;
-    term_handler() if $got_sigterm;
-    hup_handler() if $got_sighup;
-}
-
-logmsg('exiting because of EOF', 'debug');
-exit 0;
-
-##############################################################################
-
-# Process one NoCeM notice.
-sub do_nocem {
-    my $token = shift;
-    my $start = time;
-
-    # open the article and verify the notice
-    my $artfh = open_article($token);
-    return if not defined $artfh;
-    my ($msgid, $nid, $issuer, $nocems) = read_nocem($artfh);
-    close $artfh;
-    return unless $nocems;
-
-    &$cancel($nocems);
-    logmsg("Articles cancelled: " . join(' ', @$nocems), 'debug');
-    my $diff = (time - $start) || 0.01;
-    my $nr = scalar @$nocems;
-    logmsg(sprintf("processed notice %s by %s (%d ids, %.5f s, %.1f/s)",
-        $nid, $issuer, $nr, $diff, $nr / $diff));
-}
-
-# - Check if it is a PGP signed NoCeM notice
-# - See if we want it
-# - Then check PGP signature
-sub read_nocem {
-    my $artfh = shift;
-
-    # Examine the first 200 lines to see if it is a PGP signed NoCeM.
-    my $ispgp = 0;
-    my $isncm = 0;
-    my $inhdr = 1;
-    my $i = 0;
-    my $body = '';
-    my ($from, $msgid);
-    while (<$artfh>) {
-        last if $i++ > 200;
-        s/\r\n$/\n/;
-        if ($inhdr) {
-            if (/^$/) {
-                $inhdr = 0;
-            } elsif (/^From:\s+(.*)\s*$/i) {
-                $from =  $1;
-            } elsif (/^Message-ID:\s+(<.*>)/i) {
-                $msgid = $1;
-            }
-        } else {
-            $body .= $_;
-            $ispgp = 1 if /^-----BEGIN PGP SIGNED MESSAGE-----/;
-            if (/^\@\@BEGIN NCM HEADERS/) {
-                $isncm = 1;
-                last;
-            }
-        }
-    }
-
-    # must be a PGP signed NoCeM.
-    if (not $ispgp) {
-        logmsg("Article $msgid: not PGP signed", 'debug');
-        return;
-    }
-    if (not $isncm) {
-        logmsg("Article $msgid: not a NoCeM", 'debug');
-        return;
-    }
-
-    # read the headers of this NoCeM, and check if it's supported.
-    my %hdrs;
-    while (<$artfh>) {
-        s/\r\n/\n/;
-        $body .= $_;
-        last if /^\@\@BEGIN NCM BODY/;
-        my ($key, $val) = /^([^:]+)\s*:\s*(.*)$/;
-        $hdrs{lc $key} = $val;
-    }
-    foreach (qw(action issuer notice-id type version)) {
-        next if $hdrs{$_};
-        logmsg("Article $msgid: missing $_ pseudo header", 'debug');
-        return;
-    }
-    return if not supported_nocem($msgid, \%hdrs);
-
-    # decide if we want it.
-    if (not want_nocem(\%hdrs)) {
-        logmsg("Article $msgid: unwanted ($hdrs{issuer}/$hdrs{type})", 'debug');
-        return;
-    }
-# XXX want_hier() not implemented
-#    if ($hdrs{hierarchies} and not want_hier($hdrs{hierarchies})) {
-#        logmsg("Article $msgid: unwanted hierarchy ($hdrs{hierarchies})",
-#            'debug');
-#        return;
-#    }
-
-    # We do want it, so read the entire article.  Also copy it to
-    # a temp file so that we can check the PGP signature when done.
-    my $tmpfile = "$inn::pathtmp/nocem.$$";
-    if (not open(OFD, ">$tmpfile")) {
-        logmsg("cannot open temp file $tmpfile: $!", 'err');
-        return;
-    }
-    print OFD $body;
-    undef $body;
-
-    # process NoCeM body.
-    my $inbody = 1;
-    my @nocems;
-    my ($lastid, $lastgrp);
-    while (<$artfh>) {
-        s/\r\n$/\n/;
-        print OFD;
-        $inbody = 0 if /^\@\@END NCM BODY/;
-        next if not $inbody or /^#/;
-
-        my ($id, $grp) = /^(\S*)\s+(\S+)/;
-        next if not $grp;
-        if ($id) {
-            push @nocems, $lastid
-                if $lastid and want_cancel_id($lastgrp, \%hdrs);
-            $lastid = $id;
-            $lastgrp = $grp;
-        } else {
-            $lastgrp .= ',' . $grp;
-        }
-    }
-    push @nocems, $lastid if $lastid and want_cancel_id($lastgrp, \%hdrs);
-    close OFD;
-
-    # at this point we need to verify the PGP signature.
-    return if not @nocems;
-    my $e = pgp_check($hdrs{issuer}, $msgid, $tmpfile);
-    unlink $tmpfile;
-    return if not $e;
-
-    return ($msgid, $hdrs{'notice-id'}, $hdrs{issuer}, \@nocems);
-}
-
-# XXX not implemented: code to discard notices for groups we don't carry
-sub want_cancel_id {
-    my ($group, $hdrs) = @_;
-
-    return local_want_cancel_id(@_) if defined &local_want_cancel_id;
-    1;
-}
-
-# Do we actually want this NoCeM?
-sub want_nocem {
-    my $hdrs = shift;
-
-    foreach (@ncmperm) {
-        my ($issuer, $type) = split(/\001/);
-        if ($hdrs->{issuer} =~ /$issuer/i) {
-            return 1 if '*' eq $type or lc $hdrs->{type} eq $type;
-        }
-    }
-    return 0;
-}
-
-sub supported_nocem {
-    my ($msgid, $hdrs) = @_;
-
-    if ($hdrs->{version} !~ /^0\.9[0-9]?$/) {
-        logmsg("Article $msgid: version $hdrs->{version} not supported",
-            'debug');
-        return 0;
-    }
-    if ($hdrs->{action} ne 'hide') {
-        logmsg("Article $msgid: action $hdrs->{action} not supported",
-            'debug');
-        return 0;
-    }
-    return 1;
-}
-
-# Check the PGP signature on an article.
-sub pgp_check {
-    my ($issuer, $msgid, $art) = @_;
-
-    # fork and spawn a child
-    my $pid = open(PFD, '-|');
-    if (not defined $pid) {
-        logmsg("pgp_check: cannot fork: $!", 'err');
-        return 0;
-    }
-    if ($pid == 0) {
-        open(STDERR, '>&STDOUT');
-        exec($inn::gpgv, '--status-fd=1',
-            $keyring ? '--keyring=' . $keyring : '', $art);
-        exit 126;
-    }
-
-    # Read the result and check status code.
-    local $_ = join('', <PFD>);
-    my $status = 0;
-    if (not close PFD) {
-        if ($? >> 8) {
-            $status = $? >> 8;
-        } else {
-            logmsg("Article $msgid: $inn::gpgv killed by signal " . ($? & 255));
-            return 0;
-        }
-    }
-#    logmsg("Command line was: $inn::gpgv --status-fd=1"
-#         . ($keyring ? ' --keyring=' . $keyring : '') . " $art", 'debug');
-#    logmsg("Full PGP output: >>>$_<<<", 'debug');
-
-    if (/^\[GNUPG:\]\s+GOODSIG\s+\S+\s+(.*)/m) {
-        return 1 if $1 =~ /\Q$issuer\E/;
-        logmsg("Article $msgid: signed by $1 instead of $issuer");
-    } elsif (/^\[GNUPG:\]\s+NO_PUBKEY\s+(\S+)/m) {
-        logmsg("Article $msgid: $issuer (ID $1) not in keyring");
-    } elsif (/^\[GNUPG:\]\s+BADSIG\s+\S+\s+(.*)/m) {
-        logmsg("Article $msgid: bad signature from $1");
-    } elsif (/^\[GNUPG:\]\s+BADARMOR/m or /^\[GNUPG:\]\s+UNEXPECTED/m) {
-        logmsg("Article $msgid: malformed signature");
-    } elsif (/^\[GNUPG:\]\s+ERRSIG\s+(\S+)/m) {
-        # safety net: we get there if we don't know about some token
-        logmsg("Article $msgid: unknown error (ID $1)");
-    } else {
-        # some other error we don't know about happened.
-        # 126 is returned by the child if exec fails.
-        s/ at \S+ line \d+\.\n$//; s/\n/_/;
-        logmsg("Article $msgid: $inn::gpgv exited "
-            . (($status == 126) ? "($_)" : "with status $status"), 'err');
-    }
-    return 0;
-}
-
-# Read article.
-sub open_article {
-    my $token = shift;
-    
-    if ($token =~ /^\@.+\@$/) {
-        my $pid = open(ART, '-|');
-        if ($pid < 0) {
-            logmsg('Cannot fork: ' . $!, 'err');
-            return undef;
-        }
-        if ($pid == 0) {
-            exec("$inn::newsbin/sm", '-q', $token) or
-                logmsg("Cannot exec sm: $!", 'err');
-            return undef;
-        }
-        return *ART;
-    } else {
-        return *ART if open(ART, $token);
-        logmsg("Cannot open article $token: $!", 'err');
-    }
-    return undef;
-}
-
-# Cancel a number of Message-IDs.  We use ctlinnd to do this,
-# and we run up to 15 of them at the same time (10 usually).
-sub cancel_ctlinnd {
-    my @ids = @{$_[0]};
-
-    while (@ids > 0) {
-        my $max = @ids <= 15 ? @ids : 10;
-        for (my $i = 1; $i <= $max; $i++) {
-            my $msgid = shift @ids;
-            my $pid;
-            sleep 5 until (defined ($pid = fork));
-            if ($pid == 0) {
-                exec "$inn::pathbin/ctlinnd", '-s', '-t', '180',
-                    'cancel', $msgid;
-                exit 126;
-            }
-#            logmsg("cancelled: $msgid [$i/$max]", 'debug');
-        }
-        #    Now wait for all children.
-        while ((my $pid = wait) > 0) {
-            next unless $?;
-            if ($? >> 8) {
-                logmsg("Child $pid died with status " . ($? >> 8), 'err');
-            } else {
-                logmsg("Child $pid killed by signal " . ($? & 255), 'err');
-            }
-        }
-    }
-}
-
-sub cancel_nntp {
-    my $ids = shift;
-    my $r;
-    
-    if ($nntp_open and time - $socket_timeout > $last_cancel) {
-        logmsg('Close socket for timeout');
-        close (NNTP);
-        $nntp_open = 0;
-    }
-    if (not $nntp_open) {
-        use Socket;
-        if (not socket(NNTP, PF_UNIX, SOCK_STREAM, 0)) {
-            logmsg("socket: $!", 'err');
-            goto ERR;
-        }
-        if (not connect(NNTP, sockaddr_un($inn::pathrun . '/nntpin'))) {
-            logmsg("connect: $!", 'err');
-            goto ERR;
-        }
-        if (($r = <NNTP>) !~ /^200 /) {
-            $r =~ s/\r\n$//;
-            logmsg("bad reply from server: $r", 'err');
-            goto ERR;
-        }
-        select NNTP; $| = 1; select STDOUT;
-        print NNTP "MODE CANCEL\r\n";
-        if (($r = <NNTP>) !~ /^284 /) {
-            $r =~ s/\r\n$//;
-            logmsg("MODE CANCEL not supported: $r", 'err');
-            goto ERR;
-        }
-        $nntp_open = 1;
-    }
-    foreach (@$ids) {
-        print NNTP "$_\r\n";
-        if (($r = <NNTP>) !~ /^289/) {
-            $r =~ s/\r\n$//;
-            logmsg("cannot cancel $_: $r", 'err');
-            goto ERR;
-        }
-    }
-    $last_cancel = time;
-    return;
-
-ERR:
-    # discard unusable socket
-    close (NNTP);
-    logmsg('Switching to ctlinnd...', 'err');
-    cancel_ctlinnd($ids);
-    $cancel = \&cancel_ctlinnd;
-}
-
-sub read_ctlfile {
-    my $permfile = $inn::pathetc . '/nocem.ctl';
-
-    unless (open(CTLFILE, $permfile)) {
-        logmsg("Cannot open $permfile: $!", 'err');
-        return 0;
-    }
-    while (<CTLFILE>) {
-        chop;
-        s/^\s+//; s/\s+$//;
-        next if /^#/ or /^$/;
-        my ($issuer, $type) = split(/:/, lc $_);
-        logmsg("Cannot parse nocem.ctl line <<$_>>", 'err')
-            if not $issuer and $type;
-        $type =~ s/\s//g;
-        push @ncmperm, "$issuer\001$_" foreach split(/,/, $type);
-    }
-    close CTLFILE;
-    return 1;
-}
-
-sub logmsg {
-    my ($msg, $lvl) = @_;
-
-    if (not $use_syslog) {
-        if ($log_open == 0) {
-            open(LOG, ">>$logfile") or die "Cannot open log: $!";
-            $log_open = 1;
-            select LOG; $| = 1; select STDOUT;
-        }
-        $lvl ||= 'notice';
-        print LOG "$lvl: $msg\n";
-        return;
-    }
-    syslog($lvl || 'notice', '%s', $msg);
-}
-
-sub hup_handler {
-    $got_sighup = 1;
-    return if $working;
-    close LOG;
-    $log_open = 0;
-}
-
-sub term_handler {
-    $got_sigterm = 1;
-    return if $working;
-    logmsg('exiting because of signal');
-    exit 1;
-}
-
-# lint food
-print $inn::pathrun.$inn::pathlog.$inn::pathetc.$inn::newsbin.$inn::pathbin
-    .$inn::pathtmp.$inn::peertimeout.$inn::syslog_facility;
-
-__END__
-
-=head1 NAME
-
-perl-nocem - A NoCeM-on-spool implementation for S<INN 2.x>
-
-=head1 SYNOPSIS
-
-perl-nocem
-
-=head1 DESCRIPTION
-
-NoCeM, which is pronounced I<No See 'Em>, is a protocol enabling
-authenticated third-parties to issue notices which can be used
-to cancel unwanted articles (like spam and articles in moderated
-newsgroups which were not approved by their moderators).  It can
-also be used by readers as a I<third-party killfile>.  It is
-intended to eventually replace the protocol for third-party cancel
-messages.
-
-B<perl-nocem> processes third-party, PGP-signed article cancellation
-notices.  It is possible not to honour all NoCeM notices but only those
-which are sent by people whom you trust (that is to say if you trust
-the PGP key they use to sign their NoCeM notices).  Indeed, it is up
-to you to decide whether you wish to honour their notices, depending
-on the criteria they use.
-
-Processing NoCeM notices is easy to set up:
-
-=over 4
-
-=item 1.
-
-Import the keys of the NoCeM issuers you trust in order to check
-the authenticity of their notices.  You can do:
-
-    gpg --no-default-keyring --primary-keyring <pathetc>/pgp/ncmring.gpg --import <key-file>
-
-where <pathetc> is the value of the I<pathetc> parameter set in F<inn.conf>
-and <key-file> the file containing the key(s) to import.  The keyring
-must be located in I<pathetc>/pgp/ncmring.gpg (create the directory
-before using B<gpg>).  For old PGP-generated keys, you may have to use
-B<--allow-non-selfsigned-uid> if they are not properly self-signed,
-but anyone creating a key really should self-sign the key.  Current
-PGP implementations do this automatically.
-
-The keys of NoCeM issuers can be found in the web site of I<The NoCeM Registry>:
-L<http://www.xs4all.nl/~rosalind/nocemreg/nocemreg.html>.  You can even
-download there a unique file which contains all the keys.
-
-=item 2.
-
-Create a F<nocem.ctl> config file in I<pathetc> indicating the NoCeM issuers
-and notices you want to follow.  This permission file contains lines like:
-
-    annihilator-1:*
-    clewis@ferret.ocunix:mmf
-    stephane@asynchrone:mmf,openproxy,spam
-
-This will remove all articles for which the issuer (first part of the line,
-before the colon C<:>) has issued NoCeM notices corresponding to the
-criteria specified after the colon.
-
-You will also find information about that on the web site of
-I<The NoCeM Registry>.
-
-=item 3.
-
-Add to the F<newsfeeds> file an entry like this one in order to feed
-B<perl-nocem> the NoCeM notices posted to alt.nocem.misc and
-news.lists.filters:
-
-    nocem!\
-        :!*,alt.nocem.misc,news.lists.filters\
-        :Tc,Wf,Ap:<pathbin>/perl-nocem
-
-with the correct path to B<perl-nocem>, located in <pathbin>.  Then, reload
-the F<newsfeeds> file (C<ctlinnd reload newsfeeds 'NoCeM channel feed'>).
-
-Note that you should at least carry news.lists.filters on your news
-server (or other newsgroups where NoCeM notices are sent) if you wish
-to process them.
-
-=item 4.
-
-Everything should now work.  However, do not hesitate to manually test
-B<perl-nocem> with a NoCeM notice, using:
-
-    grephistory '<Message-ID>' | perl-nocem
-
-Indeed, B<perl-nocem> expects tokens on its standard input, and
-B<grephistory> can easily give it the token of a known article,
-thanks to its Message-ID.
-
-=back
-
-When you have verified that everything works, you can eventually turn
-off regular spam cancels, if you want, not processing any longer
-cancels containing C<cyberspam> in the Path: header (see the
-I<refusecybercancels> parameter in F<inn.conf>).
-
-=head1 FILES
-
-=over 4
-
-=item I<pathbin>/perl-nocem
-
-The Perl script itself used to process NoCeM notices.
-
-=item I<pathetc>/nocem.ctl
-
-The configuration file which specifies the NoCeM notices to be processed.
-
-=item I<pathetc>/pgp/ncmring.gpg
-
-The keyring which contains the public keys of trusted NoCeM issuers.
-
-=back
-
-=head1 BUGS
-
-The Subject: header is not checked for the @@NCM string and there is no
-check for the presence of the References: header.
-
-The Newsgroups: pseudo header is not checked, but this can be done in
-local_want_cancel_id().
-
-The Hierarchies: header is ignored.
-
-=head1 HISTORY
-
-Copyright 2000 by Miquel van Smoorenburg <miquels@cistron.nl>.
-
-Copyright 2001 by Marco d'Itri <md@linux.it>.
-
-$Id: perl-nocem.in 7733 2008-04-06 09:16:20Z iulius $
-
-=head1 SEE ALSO
-
-gpgv(1), grephistory(1), inn.conf(5), newsfeeds(5), pgp(1).
-
-=cut