Skip to content

Commit

Permalink
Add Cancel-Lock support in nnrpd and a secrets file
Browse files Browse the repository at this point in the history
Implement Cancel-Lock support in nnrpd, based on RFC 8315 and libcanlock.

Secrets are configured in a new inn-secrets.conf file.

see #47
  • Loading branch information
Julien-Elie committed Jan 4, 2022
1 parent 6b10dbd commit f25c972
Show file tree
Hide file tree
Showing 38 changed files with 1,425 additions and 87 deletions.
1 change: 1 addition & 0 deletions .gitignore
Expand Up @@ -188,6 +188,7 @@
/tests/lib/artnumber.t
/tests/lib/asprintf.t
/tests/lib/buffer.t
/tests/lib/canlock.t
/tests/lib/concat.t
/tests/lib/conffile.t
/tests/lib/confparse.t
Expand Down
8 changes: 8 additions & 0 deletions MANIFEST
Expand Up @@ -156,6 +156,7 @@ doc/man/ident.8 Manpage for ident resolver
doc/man/incoming.conf.5 Manpage for incoming.conf config file
doc/man/inews.1 Manpage for inews frontend
doc/man/inn-radius.conf.5 Manpage for inn-radius.conf config file
doc/man/inn-secrets.conf.5 Manpage for inn-secrets.conf
doc/man/inn.conf.5 Manpage for inn.conf config file
doc/man/innbind.8 Manpage for innbind
doc/man/inncheck.8 Manpage for inncheck utility
Expand Down Expand Up @@ -273,6 +274,7 @@ doc/pod/ident.pod Master file for ident.8
doc/pod/incoming.conf.pod Master file for incoming.conf.5
doc/pod/inews.pod Master file for inews.1
doc/pod/inn-radius.conf.pod Master file for inn-radius.conf.5
doc/pod/inn-secrets.conf.pod Master file for inn-secrets.conf.5
doc/pod/inn.conf.pod Master file for inn.conf.5
doc/pod/innbind.pod Master file for innbind.8
doc/pod/inncheck.pod Master file for inncheck.8
Expand Down Expand Up @@ -422,6 +424,7 @@ include/inn/ov.h Header file for old overview API
include/inn/overview.h Header file for the overview API
include/inn/paths.h.in Header file for paths
include/inn/qio.h Header file for quick I/O package
include/inn/secrets.h Header file for the secrets struct
include/inn/sequence.h Header file for sequence space arithmetic
include/inn/storage.h Header file for storage API
include/inn/timer.h Header file for generic timers
Expand Down Expand Up @@ -503,6 +506,7 @@ lib/argparse.c Functions for parsing arguments
lib/artnumber.c Manipulation of article numbers
lib/asprintf.c asprintf replacement
lib/buffer.c Reusable counted buffer
lib/canlock.c Routines for Cancel-Lock
lib/cleanfrom.c Clean out a From line
lib/clientactive.c Client access to the active file
lib/clientlib.c Replacement for C News library routine
Expand Down Expand Up @@ -557,6 +561,7 @@ lib/remopen.c Open a remote NNTP connection
lib/reservedfd.c File descriptor reservation
lib/resource.c Get process CPU usage
lib/sd-daemon.c Stubs for systemd library functions
lib/secrets.c Parsing and manipulating inn-secrets.conf
lib/sendarticle.c Send an article, NNTP style
lib/sendpass.c Send NNTP authentication
lib/sequence.c Sequence space arithmetic routines
Expand All @@ -582,6 +587,7 @@ lib/xwrite.c write that handles partial transfers
m4 Autoconf support macros (Directory)
m4/aux-libs.m4 Autoconf macro for extra libraries
m4/bdb.m4 Autoconf macros for Berkeley DB
m4/canlock.m4 Autoconf macros for Cancel-Lock support
m4/cc-c-o.m4 Autoconf macro for -c -o compiler support
m4/cc-flags.m4 Autoconf macro for compiler flags
m4/compress.m4 Autoconf macro for compress detection
Expand Down Expand Up @@ -668,6 +674,7 @@ samples/filter_innd.py Sample Python filter for innd
samples/filter_nnrpd.pl Sample Perl filter for nnrpd
samples/incoming.conf Permissions for incoming feeds
samples/inn-radius.conf Sample config for RADIUS authentication
samples/inn-secrets.conf Sample secrets file
samples/inn.conf.in General INN configuration
samples/innfeed.conf Outgoing feed configuration
samples/innreport.conf.in Log summary configuration
Expand Down Expand Up @@ -914,6 +921,7 @@ tests/lib Test suite for libinn (Directory)
tests/lib/artnumber-t.c Tests for lib/artnumber.c
tests/lib/asprintf-t.c Tests for lib/asprintf.c
tests/lib/buffer-t.c Tests for lib/buffer.c
tests/lib/canlock-t.c Tests for lib/canlock.c
tests/lib/concat-t.c Tests for lib/concat.c
tests/lib/conffile-t.c Tests for lib/conffile.c
tests/lib/confparse-t.c Tests for lib/confparse.c
Expand Down
8 changes: 8 additions & 0 deletions Makefile.global.in
Expand Up @@ -154,9 +154,17 @@ KRB5_LIBS = @KRB5_LIBS@

## Systemd support. Additional flags and libraries used when compiling or
## linking code that contains systemd support.

SYSTEMD_CFLAGS = @SYSTEMD_CFLAGS@
SYSTEMD_LIBS = @SYSTEMD_LIBS@

## libcanlock support. Additional flags and libraries used when compiling or
## linking code that contains Cancel-Lock support.

CANLOCK_CPPFLAGS= @CANLOCK_CPPFLAGS@
CANLOCK_LDFLAGS = @CANLOCK_LDFLAGS@
CANLOCK_LIBS = $(abs_builddir)/lib/canlock$(LIBSUFFIX).o @CANLOCK_LIBS@

## Missing functions. If non-empty, configure detected that your system
## was missing some standard functions, and INN will be providing its own
## replacements from the lib directory.
Expand Down
4 changes: 0 additions & 4 deletions TODO
Expand Up @@ -411,10 +411,6 @@ Requested New Features
of stuff that Russ has copies of, for example. [Patches included in
tickets #133 and #134.]

* There are various available patches for Cancel-Lock and an Internet
draft; support should be added to INN for both generation and
verification (definitely optional and not on by default at this point).

* It would be nice to be able to reload inn.conf (although difficult, due
to the amount of data that's generated from it and stashed in various
places).
Expand Down
1 change: 1 addition & 0 deletions ci/apt-packages
Expand Up @@ -4,6 +4,7 @@
## line, to install for testing.

default-mta
libcanlock-dev
libdb5.3-dev
libgd-perl
libkrb5-dev
Expand Down
5 changes: 3 additions & 2 deletions ci/test
Expand Up @@ -31,7 +31,8 @@ make test

# Test --enable-keywords and disabling optional dependencies.
make distclean
./configure CC="$COMPILER" --enable-keywords --without-bdb --without-krb5 \
--without-openssl --without-sasl --without-sqlite3 --without-zlib
./configure CC="$COMPILER" --enable-keywords --without-bdb --without-canlock \
--without-krb5 --without-openssl --without-sasl --without-sqlite3 \
--without-zlib
make warnings
make test
2 changes: 2 additions & 0 deletions configure.ac
Expand Up @@ -37,6 +37,7 @@ m4_define_default([AM_CONDITIONAL], [:])
dnl Lots of our macros are stored in separate files for ease of maintenance.
m4_include([m4/aux-libs.m4])
m4_include([m4/bdb.m4])
m4_include([m4/canlock.m4])
m4_include([m4/cc-c-o.m4])
m4_include([m4/cc-flags.m4])
m4_include([m4/compress.m4])
Expand Down Expand Up @@ -426,6 +427,7 @@ fi
dnl Handle optional libraries and probing for their locations and component
dnl libraries if needed.
INN_LIB_BDB_OPTIONAL
INN_LIB_CANLOCK_OPTIONAL
INN_LIB_KRB5_OPTIONAL
INN_LIB_OPENSSL_OPTIONAL
INN_LIB_SASL_OPTIONAL
Expand Down
12 changes: 6 additions & 6 deletions doc/FAQ
Expand Up @@ -108,12 +108,12 @@ Subject: 1.1. What is INN?
The README that comes with INN has this to say (in part):

INN (InterNetNews), originally written by Rich Salz, is an extremely
flexible and configurable Usenet / Netnews news server. For a complete
description of the protocols behind Usenet and Netnews, see RFC 3977
(NNTP), RFC 4642 updated by RFC 8143 (TLS/NNTP), RFC 4643 (NNTP
authentication), RFC 4644 (streaming NNTP feeds), RFC 5536 (USEFOR),
RFC 5537 (USEPRO), RFC 6048 (NNTP LIST additions) and RFC 8054 (NNTP
compression) or their replacements.
flexible and configurable Usenet / Netnews news server. For a
complete description of the protocols behind Usenet and Netnews, see
RFC 3977 (NNTP), RFC 4642 updated by RFC 8143 (TLS/NNTP), RFC 4643 (NNTP
authentication), RFC 4644 (streaming NNTP feeds), RFC 5536 (USEFOR), RFC
5537 (USEPRO), RFC 6048 (NNTP LIST additions), RFC 8054 (NNTP compression)
and RFC 8315 (Cancel-Lock) or their replacements.

In brief, Netnews is a set of protocols for exchanging messages between
a decentralized network of news servers. News articles are organized
Expand Down
2 changes: 1 addition & 1 deletion doc/man/Makefile
Expand Up @@ -15,7 +15,7 @@ SEC3PM = INN__Config.3pm \
SEC5 = active.5 active.times.5 buffindexed.conf.5 control.ctl.5 \
cycbuff.conf.5 distrib.pats.5 distributions.5 expire.ctl.5 \
history.5 incoming.conf.5 \
inn.conf.5 innfeed.conf.5 innreport.conf.5 \
inn.conf.5 innfeed.conf.5 innreport.conf.5 inn-secrets.conf.5 \
innwatch.ctl.5 moderators.5 motd.news.5 \
newsfeeds.5 newsgroups.5 newslog.5 nnrpd.track.5 nntpsend.ctl.5 ovdb.5 \
ovsqlite.5 passwd.nntp.5 inn-radius.conf.5 readers.conf.5 \
Expand Down
4 changes: 3 additions & 1 deletion doc/pod/Makefile
Expand Up @@ -22,7 +22,8 @@ MAN5 = ../man/active.5 ../man/active.times.5 ../man/buffindexed.conf.5 \
../man/control.ctl.5 ../man/cycbuff.conf.5 ../man/distrib.pats.5 \
../man/distributions.5 ../man/expire.ctl.5 ../man/history.5 \
../man/incoming.conf.5 ../man/inn.conf.5 ../man/innfeed.conf.5 \
../man/innreport.conf.5 ../man/innwatch.ctl.5 ../man/moderators.5 \
../man/innreport.conf.5 ../man/inn-secrets.conf.5 \
../man/innwatch.ctl.5 ../man/moderators.5 \
../man/motd.news.5 ../man/newsfeeds.5 ../man/newsgroups.5 \
../man/newslog.5 ../man/nnrpd.track.5 ../man/nntpsend.ctl.5 \
../man/ovdb.5 ../man/ovsqlite.5 \
Expand Down Expand Up @@ -107,6 +108,7 @@ maintclean: distclean
../man/inn.conf.5: inn.conf.pod ; $(POD2MAN) -s 5 $? > $@
../man/innfeed.conf.5: innfeed.conf.pod ; $(POD2MAN) -s 5 $? > $@
../man/innreport.conf.5: innreport.conf.pod ; $(POD2MAN) -s 5 $? > $@
../man/inn-secrets.conf.5: inn-secrets.conf.pod ; $(POD2MAN) -s 5 $? > $@
../man/innwatch.ctl.5: innwatch.ctl.pod ; $(POD2MAN) -s 5 $? > $@
../man/moderators.5: moderators.pod ; $(POD2MAN) -s 5 $? > $@
../man/motd.news.5: motd.news.pod ; $(POD2MAN) -s 5 $? > $@
Expand Down
166 changes: 166 additions & 0 deletions doc/pod/inn-secrets.conf.pod
@@ -0,0 +1,166 @@
=head1 NAME

inn-secrets.conf - Configuration data for InterNetNews secrets

=head1 DESCRIPTION

F<inn-secrets.conf> in I<pathetc> is a configuration file containing general
secrets used by INN. It was added in S<INN 2.7.0> for the implementation of
Cancel-Lock. The intent is that new secrets used by INN are added to that
file, and that all secrets currently stored in several other configuration
files eventually move to that file.

The F<inn-secrets.conf> file is not required. It currently only serves
the purpose of Cancel-Lock. If not present or empty, the Cancel-Lock
authentication system will just be deactivated for local posts.

This file is intended to be fairly static. Any changes made to it will
generally not affect any running programs until they restart.

Changes in Cancel-Lock secrets will be taken into account when new B<nnrpd>
processes are spawned (which happens each time a reader opens a new
connection).

Blank lines and lines starting with a number sign (C<#>) are ignored.
All other lines specify parameters, and are organized in groups. The general
form is:

<group> {
<parameter>: <value>
}

(Any amount of whitespace can be put after the colon and is optional.) If the
value contains embedded whitespace or any of the characters C<< []<>{}"\:; >>,
it must be enclosed in double quotes (""). A backslash (C<\>) can be used to
escape quotes and backslashes inside double quotes. <group> and <parameter>
are case-sensitive; C<cancels> is not the same as C<Cancels> or C<CANCELS>.
(F<inn-secrets.conf> groups and parameters are generally all in lowercase.)

The two parameters currently defined in this file have as their value a
list of strings, that is to say space-separated elements enclosed in square
brackets. Examples follow in the documentation.

=head1 PARAMETERS

=head2 Cancel-Lock secrets

These secrets are used for the Cancel-Lock authentication system described
in S<RFC 8315>. This mechanism permits verifying that the withdrawal of an
article is valid, that is to say the poster, posting agent, moderator, or
injecting agent that processed the original article has requested to withdraw
it via the use of a cancel control article or a Supersedes header field.

You'll need to build INN with version 3.3.0 or later of libcanlock
to embed Cancel-Lock support. This library is available at
L<https://micha.freeshell.org/libcanlock/>. The C<configure> script will
automatically enable Cancel-Lock support if it finds libcanlock; you may have
to specify the B<--with-canlock> option to help C<configure> find it.

The C<cancels> group is defined as follows:

cancels {
canlockadmin: [ "Cl4yniTtmlsR3nwVaM2erBQClVprEtLjd/UiqTErXjk=" ]
canlockuser: [ "tf+fY0Z7KNzYzF9uPo/qPrLKOPXIJLqejwqsV1nwOTRwGQ==" ]
}

If one of the I<canlockadmin> or I<canlockuser> parameters is not an empty
list, B<nnrpd> will add information to every posted article that will permit
other news servers to later ensure that an attempt to cancel or supersede the
article is not forged, and really originates from the authenticated original
sender or the administrator of the local server.

More concretely, for each secret in I<canlockadmin>, B<nnrpd> adds two
Base64-encoded hashes to a Cancel-Lock header field. These hashes are
based on the secret and the Message-ID of the article. If this field
already exists, it will just append the Base64-encoded hashes to its end.
One hash uses the SHA-1 algorithm (for interoperability reasons as not all
news software implement SHA-256), and the other hash uses the mandatory
SHA-256 algorithm per S<RFC 8315>. Besides, if the poster is authenticated,
B<nnrpd> will similarly add two Base64-encoded hashes for each secret in
I<canlockuser>. These hashes are based on the secret, the user name and the
Message-ID of the article.

When a cancel or supersede article is posted by an authenticated user,
B<nnrpd> will add to a Cancel-Key header field two pre-images for each secret
in I<canlockuser>. Other news servers can then hash one of these pre-images
with SHA-1 or SHA-256 algorithms (one is enough) and verify that the resulted
Base64-encoded hash is the same as the one present in the Cancel-Lock header
field of the original article. (Necessarily, the same authenticated user on
the same local server sent the original article.) When receiving articles
with a Cancel-Key header field (locally or from other peers), B<innd> applies
that check to verify the authenticity of the withdrawal before deciding to
honour it.

Naturally, no pre-images for each secret in I<canlockadmin> are added by
B<nnrpd>. As these pre-images are not based on a user name, only the news
administrator can generate them with a separate program (yet to write, and
that will be shipped with the final 2.7 release), and then inject the cancel
or supersede request with for instance B<inews>. The news administrator
is therefore capable to send authenticated withdrawal requests for articles
posted by all the users of his news server, be they authenticated or not.

After this (little) introduction to explain what Cancel-Lock is for, here are
the two relevant parameters:

=over 4

=item I<canlockadmin>

This parameter expects a list of strings. It is unset by default (no admin
hashes will be generated).

If this parameter is not an empty list, each provided secret will be used to
generate admin hashes.

To maximize security, secrets should have a length of at least the output
size of the hash function used (32 octets for SHA-256). You can for instance
generate a strong secret based on 36 random octets with:

% openssl rand -base64 36
Vs4zdggAHKEUtqs6dH5/oNGWwIVFPf2ZIngog6aE6cDMoyJF

and use it as follows:

canlockadmin: [ "Vs4zdggAHKEUtqs6dH5/oNGWwIVFPf2ZIngog6aE6cDMoyJF" ]

The purpose of providing several secrets is when you want to rotate secrets.
For instance, if your policy is to change secrets each year, you can use two
secrets during a transition period:

canlockadmin: [ "rH5L8geEzkNVvpAZQMJJcd4AYkpSkkx5S/4qewPDA/U="
"eAaeyrQfjqQryhqrfwJOKezwf9GpL+xs+A9YfK9MMxE=" ]

Withdrawals of previously posted articles will still work with the old secret
(still added to the Cancel-Key header field).

As all posted articles will have a Cancel-Lock header field with the admin
secret, you should also set I<canlockuser> because otherwise posters may not
be able to withdraw their own articles (unless their posting agents generate
Cancel-Lock header fields themselves with their own secrets).

=item I<canlockuser>

This parameter expects a list of strings. It is unset by default (no hashes
will be generated for authenticated users).

If this parameter is not an empty list, each provided secret will be used to
generate hashes for authenticated users.

The same recommendation of more than 32 random octets applies, and the secrets
must not be the same as I<canlockadmin>.

You should also set I<canlockadmin> because you may otherwise not always
be able to cancel an article posted by an authenticated user (if you do not
manage to find out the user name).

=back

=head1 HISTORY

Documentation written by Julien Elie for InterNetNews.

=head1 SEE ALSO

nnrpd(8).

=cut
15 changes: 15 additions & 0 deletions doc/pod/innupgrade.pod
Expand Up @@ -59,6 +59,17 @@ S<INN 2.5>. The file is then renamed to F<sasl.conf.OLD>.

=back

=item F<inn-secrets.conf>

=over 2

=item *

Create a non-world-readable F<inn-secrets.conf> file in I<pathetc>, if not
already existing,

=back

=item F<newsfeeds>

=over 2
Expand Down Expand Up @@ -134,4 +145,8 @@ alternate file.

Written by Russ Allbery <eagle@eyrie.org> for InterNetNews.

=head1 SEE ALSO

inn.conf(5), inn-secrets.conf(5), newsfeeds(5), readers.conf(5).

=cut

0 comments on commit f25c972

Please sign in to comment.