INN commit: branches/2.5 (6 files)

INN Commit rra at isc.org
Tue Jul 12 09:57:44 UTC 2011


    Date: Tuesday, July 12, 2011 @ 02:57:44
  Author: iulius
Revision: 9241

controlchan:  impose a date cutoff, block the replay of old control articles

controlchan now uses convdate to parse dates.
Otherwise, with the new Injection-Date: header field, old control articles
could be maliciously reinjected into Usenet, and replayed.

The Injection-Date: header of old control articles is not always signed...

controlchan now imposes a date cutoff.


According to RFC 5537, a relaying agent processes an article as follows:

  2.  It MUST examine the Injection-Date header field or, if absent,
      the Date header field, and reject the article if that date is
      more than 24 hours into the future.  It MAY reject articles with
      dates in the future with a smaller margin than 24 hours.

That is to say that the Date: header field can be set to anything when
an Injection-Date header field exists.

Add a "-c" flag to controlchan to disable the cutoff check.
On a date parsing failure, controlchan rejects the message (which will be
actually process only with the "-c" flag disactivating the cutoff check).

Also add a "-h" flag to print basic usage information.

Convert controlchan man page into POD:
* mention control.ctl.local;
* document the "-c" and "-h" flags;
* document the need for the Perl modules Encode and MIME::Parser;
* add an example of how to manually invoke controlchan.

Added:
  branches/2.5/doc/pod/controlchan.pod
    (from rev 9240, trunk/doc/pod/controlchan.pod)
Modified:
  branches/2.5/MANIFEST
  branches/2.5/control/controlchan.in
  branches/2.5/doc/man/	(properties)
  branches/2.5/doc/pod/Makefile
Deleted:
  branches/2.5/doc/man/controlchan.8

-------------------------+
 MANIFEST                |    1 
 control/controlchan.in  |   80 +++++++++++++++++++++++++++++++++++++++-
 doc/man/controlchan.8   |   80 ----------------------------------------
 doc/pod/Makefile        |    3 +
 doc/pod/controlchan.pod |   90 ++++++++++++++++++++++++++++++++++++++++++++++
 5 files changed, 171 insertions(+), 83 deletions(-)

Modified: MANIFEST
===================================================================
--- MANIFEST	2011-07-12 09:51:28 UTC (rev 9240)
+++ MANIFEST	2011-07-12 09:57:44 UTC (rev 9241)
@@ -238,6 +238,7 @@
 doc/pod/cnfsheadconf.pod              Master file for cnfsheadconf.8
 doc/pod/cnfsstat.pod                  Master file for cnfsstat.8
 doc/pod/control.ctl.pod               Master file for control.ctl.5
+doc/pod/controlchan.pod               Master file for controlchan.8
 doc/pod/convdate.pod                  Master file for convdate.1
 doc/pod/ctlinnd.pod                   Master file for ctlinnd.8
 doc/pod/cvtbatch.pod                  Master file for cvtbatch.8

Modified: control/controlchan.in
===================================================================
--- control/controlchan.in	2011-07-12 09:51:28 UTC (rev 9240)
+++ control/controlchan.in	2011-07-12 09:57:44 UTC (rev 9241)
@@ -30,11 +30,13 @@
 ##     :<pathbin>/controlchan
 
 require 5.004_03;
+use Encode;
+use Getopt::Std;
 use MIME::Parser;
-use Encode;
 use strict;
 
 delete @ENV{'IFS', 'CDPATH', 'ENV', 'BASH_ENV'};
+$0 =~ s!.*/!!;
 
 # globals
 my ($cachedctl, $curmsgid);
@@ -42,6 +44,16 @@
 my $use_syslog = 0;
 my $debug = 0;
 
+my $usage = "usage: $0 [-ch]\n\n" .
+    "Reads stdin for file names or tokens.\n\n" .
+    "  -c   Disables cutoff on dates.\n" .
+    "  -h   Giveis this usage information.\n";
+
+my %opt;
+getopts("ch", \%opt) || die $usage;
+
+die $usage if defined $opt{'h'};
+
 # setup logging ###########################################################
 # do not log to syslog if stderr is connected to a console
 if (not -t 2) {
@@ -106,6 +118,48 @@
         next;
     }
 
+    if (not defined $opt{'c'}) {
+        # Make sure old control articles are not replayed.
+        my ($postingdate, $injectiondate);
+
+        # Parse date header fields.  We will take the oldest date.
+        if ($hdr{'date'}) {
+            $postingdate = int(convdate('-n', "$hdr{'date'}"));
+        } else {
+            logmsg('Missing Date: header field');
+            $parser->filer->purge;
+            next;
+        }
+        if ($hdr{'injection-date'}) {
+            $injectiondate = int(convdate('-n', "$hdr{'injection-date'}"));
+        } else {
+            $injectiondate = $postingdate;
+        }
+
+        my $articledate = ($postingdate < $injectiondate) ? $postingdate : $injectiondate;
+
+        # Compute the allowed interval of time:
+        # artcutoff days in the past, one day in the future.
+        my $currentdate = int(convdate('-n'));
+        my $mindate = $currentdate - $INN::Config::artcutoff * 86400;
+        my $maxdate = $currentdate + 86400;
+
+        if ($articledate > $maxdate) {
+            logmsg('Control article injected or posted in the future ('
+                   . convdate('-d', '-c', "$articledate") . ')');
+            $parser->filer->purge;
+            next;
+        }
+
+        if ($INN::Config::artcutoff > 0 && $articledate < $mindate) {
+            logmsg('Control article too old ('
+                   . convdate('-d', '-c', "$articledate")
+                   . '), artcutoff set to ' . $INN::Config::artcutoff . ' days');
+            $parser->filer->purge;
+            next;
+        }
+    }
+
     $curmsgid = $hdr{'message-id'};
     my $sender = cleanaddr($hdr{'sender'} || $hdr{'from'});
     my $replyto = cleanaddr($hdr{'reply-to'} || $hdr{'from'});
@@ -208,7 +262,7 @@
     my ($article, $hdr) = @_;
     my ($h, $buffer);
     my %uniquehdr = map { $_ => 1 } qw(approved control date followup-to
-        from message-id newsgroups path reply-to sender subject);
+        from injection-date message-id newsgroups path reply-to sender subject);
 
     my $head = $article->head;
 
@@ -515,6 +569,28 @@
     logdie('ctlinnd returned status ' . ($st & 255)) if $st > 0;
 }
 
+# Run convdate on the given arguments.
+# The result can be numeric (with -n) or a string (with -d).
+sub convdate {
+    my (@args) = @_;
+    my $result = 0;
+
+    my $pid = open(my $CONVDATE, '-|');
+    logdie("Cannot fork:  $!") if $pid < 0;
+    if ($pid == 0) {
+        # exec() properly escapes its arguments to prevent shell injection.
+        exec("$INN::Config::pathbin/convdate", @args) or
+             logdie("Cannot exec convdate:  $!");
+    } else {
+        $result = <$CONVDATE>;
+        close($CONVDATE);
+    }
+
+    $result = 0 if not $result;
+    chomp $result;
+    return $result;
+}
+
 sub shlock {
     my $lockfile = shift;
 


Property changes on: branches/2.5/doc/man
___________________________________________________________________
Modified: svn:ignore
   - active.5
active.times.5
actsync.8
archive.8
auth_krb5.8
batcher.8
buffchan.8
buffindexed.conf.5
ckpasswd.8
cnfsheadconf.8
cnfsstat.8
control.ctl.5
convdate.1
ctlinnd.8
cvtbatch.8
cycbuff.conf.5
distrib.pats.5
distributions.5
docheckgroups.8
domain.8
expire.ctl.5
expire.8
expireover.8
expirerm.8
fastrm.1
getlist.1
grephistory.1
ident.8
incoming.conf.5
inews.1
inn.conf.5
INN__Config.3pm
innbind.8
inncheck.8
innconfval.1
innd.8
inndf.8
innfeed.conf.5
innfeed.8
innmail.1
innupgrade.8
innxmit.8
libauth.3
libinnhist.3
libstorage.3
list.3
mailpost.8
makedbz.8
makehistory.8
mod-active.8
moderators.5
motd.news.5
newsfeeds.5
news.daily.8
news2mail.8
newslog.5
newsgroups.5
ninpaths.8
nnrpd.8
nntpsend.8
nntpsend.ctl.5
ovdb.5
ovdb_init.8
ovdb_monitor.8
ovdb_server.8
ovdb_stat.8
overchan.8
passwd.nntp.5
perl-nocem.8
pgpverify.1
prunehistory.8
pullnews.1
qio.3
radius.8
radius.conf.5
rc.news.8
readers.conf.5
rnews.1
sasl.conf.5
scanlogs.8
send-uucp.8
sendinpaths.8
shlock.1
simpleftp.1
sm.1
storage.conf.5
subscriptions.5
tally.control.8
tdx-util.8
tinyleaf.8
tst.3
uwildmat.3

   + active.5
active.times.5
actsync.8
archive.8
auth_krb5.8
batcher.8
buffchan.8
buffindexed.conf.5
ckpasswd.8
cnfsheadconf.8
cnfsstat.8
control.ctl.5
controlchan.8
convdate.1
ctlinnd.8
cvtbatch.8
cycbuff.conf.5
distrib.pats.5
distributions.5
docheckgroups.8
domain.8
expire.ctl.5
expire.8
expireover.8
expirerm.8
fastrm.1
getlist.1
grephistory.1
ident.8
incoming.conf.5
inews.1
inn.conf.5
INN__Config.3pm
innbind.8
inncheck.8
innconfval.1
innd.8
inndf.8
innfeed.conf.5
innfeed.8
innmail.1
innupgrade.8
innxmit.8
libauth.3
libinnhist.3
libstorage.3
list.3
mailpost.8
makedbz.8
makehistory.8
mod-active.8
moderators.5
motd.news.5
newsfeeds.5
news.daily.8
news2mail.8
newslog.5
newsgroups.5
ninpaths.8
nnrpd.8
nntpsend.8
nntpsend.ctl.5
ovdb.5
ovdb_init.8
ovdb_monitor.8
ovdb_server.8
ovdb_stat.8
overchan.8
passwd.nntp.5
perl-nocem.8
pgpverify.1
prunehistory.8
pullnews.1
qio.3
radius.8
radius.conf.5
rc.news.8
readers.conf.5
rnews.1
sasl.conf.5
scanlogs.8
send-uucp.8
sendinpaths.8
shlock.1
simpleftp.1
sm.1
storage.conf.5
subscriptions.5
tally.control.8
tdx-util.8
tinyleaf.8
tst.3
uwildmat.3


Deleted: doc/man/controlchan.8
===================================================================
--- doc/man/controlchan.8	2011-07-12 09:51:28 UTC (rev 9240)
+++ doc/man/controlchan.8	2011-07-12 09:57:44 UTC (rev 9241)
@@ -1,80 +0,0 @@
-.\" $Revision$
-.TH CONTROLCHAN 8
-.SH NAME
-controlchan \- channel\-fed control message handler
-.SH SYNOPSIS
-.B controlchan
-.SH DESCRIPTION
-.I Controlchan
-removes the responsibility for handling control messages
-(except cancels) from
-.IR innd (8)
-and instead processes them from a channel or file feed.
-To reduce load,
-.I controlchan
-keeps a copy of
-.I control.ctl
-in memory and checks permissions (including any required PGP headers) before any
-scripts are called.  Also, the default (``bad message'') case is handled
-internally.  The ``drop'' case is handled with far less fuss.
-.PP
-Normally,
-.I controlchan
-is invoked by
-.IR innd (8)
-as configured in
-.IR newsfeeds .
-An example entry is below.  Make sure that you've created the newsgroup
-control.cancel so that
-.I controlchan
-doesn't have to scan through cancels, which it won't process anyway.
-.sp 1
-.in +0.5i
-.nf
-controlchan!\\
-   :!*,control,control.*,!control.cancel\\
-   :AC,Tc,Wnsm\\ 
-   :<pathbin in inn.conf>/controlchan
-.fi
-.in -0.5i
-.sp 1
-Note that in the (very, very unlikely) event that you need to process
-ihave/sendme control messages, be sure that
-.I logipaddr
-is set to false in
-.IR inn.conf ,
-because in this case controlchan needs a site name, not an IP address.
-.sp 1
-.I Controlchan
-tries to report all log messages through
-.IR syslog (3),
-unless connected to an interactive terminal.  To enable
-.IR syslog (3)'ing
-for versions of Perl prior to 5.6.0,
-you will need to have run ``h2ph'' on your
-system include files at some point (this is required to
-make ``Sys::Syslog'' work).  If you have not done so, do this:
-.sp 1
-.nf
-.in +0.5i
-cd /usr/include
-h2ph * sys/*
-.in -0.5i
-.fi
-.sp 1
-If you run FreeBSD, you will need to run the following in addition:
-.sp 1
-.nf
-.in +0.5i
-h2ph machine/*
-.in -0.5i
-.fi
-.SH HISTORY
-Written by Katsuhiro Kondou <kondou at nec.co.jp> for InterNetNews.
-.de R$
-This is revision \\$3, dated \\$4.
-..
-.R$ $Id$
-.SH "SEE ALSO"
-control.ctl(5),
-inn.conf(5).

Modified: doc/pod/Makefile
===================================================================
--- doc/pod/Makefile	2011-07-12 09:51:28 UTC (rev 9240)
+++ doc/pod/Makefile	2011-07-12 09:57:44 UTC (rev 9241)
@@ -31,7 +31,7 @@
 MAN8	= ../man/actsync.8 ../man/archive.8 ../man/auth_krb5.8 \
 	../man/batcher.8 ../man/buffchan.8 \
 	../man/ckpasswd.8 ../man/cnfsheadconf.8 ../man/cnfsstat.8 \
-	../man/ctlinnd.8 ../man/cvtbatch.8 ../man/docheckgroups.8 \
+	../man/controlchan.8 ../man/ctlinnd.8 ../man/cvtbatch.8 ../man/docheckgroups.8 \
 	../man/domain.8 ../man/expire.8 ../man/expireover.8 \
 	../man/expirerm.8 ../man/ident.8 \
 	../man/innbind.8 ../man/inncheck.8 ../man/innd.8 ../man/inndf.8 \
@@ -118,6 +118,7 @@
 ../man/ckpasswd.8:	ckpasswd.pod		; $(POD2MAN) -s 8 $? > $@
 ../man/cnfsheadconf.8:	cnfsheadconf.pod	; $(POD2MAN) -s 8 $? > $@
 ../man/cnfsstat.8:	cnfsstat.pod		; $(POD2MAN) -s 8 $? > $@
+../man/controlchan.8:	controlchan.pod		; $(POD2MAN) -s 8 $? > $@
 ../man/ctlinnd.8:	ctlinnd.pod		; $(POD2MAN) -s 8 $? > $@
 ../man/cvtbatch.8:	cvtbatch.pod		; $(POD2MAN) -s 8 $? > $@
 ../man/docheckgroups.8:	docheckgroups.pod	; $(POD2MAN) -s 8 $? > $@

Copied: branches/2.5/doc/pod/controlchan.pod (from rev 9240, trunk/doc/pod/controlchan.pod)
===================================================================
--- doc/pod/controlchan.pod	                        (rev 0)
+++ doc/pod/controlchan.pod	2011-07-12 09:57:44 UTC (rev 9241)
@@ -0,0 +1,90 @@
+=head1 NAME
+
+controlchan - Channel-fed control message handler
+
+=head1 SYNOPSIS
+
+B<controlchan> [B<-ch>]
+
+=head1 DESCRIPTION
+
+B<controlchan> removes the responsibility for handling control messages
+(except cancels) from B<innd> and instead processes them from a channel
+or file feed.
+
+The two Perl modules C<Encode> and C<MIME::Parser> are required by
+B<controlchan>.
+
+To reduce load, B<controlchan> keeps a copy of F<control.ctl> and
+F<control.ctl.local> in memory and checks permissions (including any required
+PGP headers) before any scripts are called.  These two configuration
+files are automatically reloaded when B<controlchan> notices they have
+been modified.  Also, the default case of an unrecognized control article
+is handled internally.  The C<drop> case is handled with far less fuss.
+
+Normally, B<controlchan> is invoked by B<innd> as configured in F<newsfeeds>.
+An example entry is below.  Make sure that the newsgroup C<control.cancel>
+exists so that B<controlchan> does not have to scan through cancels,
+which it will not be processing anyway.
+
+    controlchan!\
+        :!*,control,control.*,!control.cancel\
+        :AC,Tc,Wnsm\
+        :<pathbin in inn.conf>/controlchan
+
+B<controlchan> can also be manually invoked with a mere path to a file
+(containing a complete control article with its headers and its body)
+or a token on its standard input:
+
+    echo '/path/to/a/control/article' | controlchan
+    echo '@0303465234000000000000235AE000000002@' | controlchan
+
+Note that in the (very, very unlikely) event that you need to process
+ihave/sendme control messages, be sure that I<logipaddr> is set to false
+in F<inn.conf>, because in this case B<controlchan> needs a site name,
+not an IP address.
+
+B<controlchan> tries to report all log messages through syslog(3),
+unless connected to an interactive terminal.  To enable syslog(3)'ing for
+versions of Perl prior to 5.6.0, you will need to have run B<h2ph> on your system
+include files at some point (this is required to make C<Sys::Syslog> work).
+If you have not done so, do this:
+
+    cd /usr/include
+    h2ph * sys/*
+
+If you run FreeBSD, you will need to run the following in addition:
+
+    h2ph machine/*
+
+=head1 OPTIONS
+
+=over 4
+
+=item B<-c>
+
+By default, B<controlchan> does not process articles whose Date:
+or Injection-Date: header fields are too far in the past (more than
+I<artcutoff> days, as set in F<inn.conf>) or one day in the future.
+It allows to prevent a malicious replay of old control articles.
+
+Using the B<-c> flag disables this check on the cutoff date.
+
+=item B<-h>
+
+Gives usage information.
+
+=back
+
+=head1 HISTORY
+
+Written by Katsuhiro Kondou <kondou at nec.co.jp> for InterNetNews.  Converted to
+POD by Julien Elie.
+
+$Id$
+
+=head1 SEE ALSO
+
+control.ctl(5), inn.conf(5).
+
+=cut




More information about the inn-committers mailing list