#!/bin/sh
# This is a shell archive (produced by GNU sharutils 4.2).
# To extract the files from this archive, save it to some FILE, remove
# everything before the `!/bin/sh' line above, then type `sh FILE'.
#
# Made on 1997-05-21 14:58 EST by <ggr@avalon.qualcomm.com>.
# Source directory was `/export/home/ggr/pgpmoose'.
#
# Existing files will *not* be overwritten unless `-c' is specified.
#
# This shar contains:
# length mode       name
# ------ ---------- ------------------------------------------
#  20608 -rw-rw-r-- README
#   3157 -r--r--r-- pmapp.1
#   1453 -r--r--r-- pmcanon.1
#   3158 -r--r--r-- pmcheck.1
#    552 -r--r--r-- pmnewsgroups.1
#    641 -r--r--r-- Makefile
#   8523 -r-xr-xr-x pmapp
#   1006 -r-xr-xr-x pmcanon
#   4777 -r-xr-xr-x pmcheck
#    409 -r-xr-xr-x pmnewsgroups
#
save_IFS="${IFS}"
IFS="${IFS}:"
gettext_dir=FAILED
locale_dir=FAILED
first_param="$1"
for dir in $PATH
do
  if test "$gettext_dir" = FAILED && test -f $dir/gettext \
     && ($dir/gettext --version >/dev/null 2>&1)
  then
    set `$dir/gettext --version 2>&1`
    if test "$3" = GNU
    then
      gettext_dir=$dir
    fi
  fi
  if test "$locale_dir" = FAILED && test -f $dir/shar \
     && ($dir/shar --print-text-domain-dir >/dev/null 2>&1)
  then
    locale_dir=`$dir/shar --print-text-domain-dir`
  fi
done
IFS="$save_IFS"
if test "$locale_dir" = FAILED || test "$gettext_dir" = FAILED
then
  echo=echo
else
  TEXTDOMAINDIR=$locale_dir
  export TEXTDOMAINDIR
  TEXTDOMAIN=sharutils
  export TEXTDOMAIN
  echo="$gettext_dir/gettext -s"
fi
touch -am 1231235999 $$.touch >/dev/null 2>&1
if test ! -f 1231235999 && test -f $$.touch; then
  shar_touch=touch
else
  shar_touch=:
  echo
  $echo 'WARNING: not restoring timestamps.  Consider getting and'
  $echo "installing GNU \`touch', distributed in GNU File Utilities..."
  echo
fi
rm -f 1231235999 $$.touch
#
if mkdir _sh18929; then
  $echo 'x -' 'creating lock directory'
else
  $echo 'failed to create lock directory'
  exit 1
fi
# ============= README ==============
if test -f 'README' && test "$first_param" != -c; then
  $echo 'x -' SKIPPING 'README' '(file already exists)'
else
  $echo 'x -' extracting 'README' '(text)'
  sed 's/^X//' << 'SHAR_EOF' > 'README' &&
PGP Moose
=========
by Greg Rose <ggr@usenix.org>
X
The aim of this software is to monitor the news
postings of moderators of USENET newsgroups, and to
automatically cancel forged messages purporting to
be approved.  This can be extended to the approvals
of individual users to automatically cancel messages
that appear without having been authorised by the
user. This has (obviously) been prompted by the
recent spammings and other events.
X
This software and protocol is designed around
cryptographic signatures.  The protocol is designed
to allow the use of different signature techniques.
This implemention assumes the use of PGP signatures,
but can be easily modified to use others, such as
the Digital Signature Standard.  PGP was chosen for
its widespread availability around the world.
X
PGP, the crux of the cryptographic software, was
written by Phil Zimmermann <prz@acm.org>, who
otherwise has nothing to do with this. The
cryptographic framework was written by Greg Rose
<ggr@usenix.org>, as were the INN news system
hooks.
X
X
Contents:
--------
X
How Does It Work?
The Bits:
How Do You Register For The Service?
Handling Multiple Moderated Groups:
Possible Problems We've Forseen:
Status:
Obtaining, installing, configuring:
It Really Wasn't That Hard.
License Terms:
Version:
X
How Does It Work?
-----------------
X
This document is written from the point of view of
a newsgroup moderator, but individual users could
also use the facility in analagous ways.
X
When a moderator wants to protect their group from
forged/unapproved postings, they should register
their interest with one or more of the sites running
PGP Moose, and pick up the submission script. As
part of this process, the moderator would specify
one or more PGP public keys that are allowed to
approve postings.
X
When a post comes in, and the moderator wishes to
approve it, they do whatever they would normally
do before actually using inews (or whatever) to
post the message. As their last action, they run
the PGP Moose Approval program "pmapp". This
inserts a special header which
looks like this:
X
XX-Auth: PGPMoose V1.0 PGP sci.crypt.research
X	iQBVAgUBL1/Kg2zWcw3p062JAQEYIgH/Xyrz6LaGG+fHaSxoexMECovzkIoADrQx
X	l73IXlUQEIoFl5jnDBBdHVvqTMEPS0118ytYVQZoQrdStuXB9Oc9gQ==
X	=azqs
X
If there are multiple moderated newsgroups, there
might be multiple X-Auth: headers, one
for each group that has requested assistance from
the PGP Moose daemon.  In this example you can
see that the authentication carries the name of
the authenticating program, a protocol version
number, an identifier of the type of digital
signature (currently only PGP) and the name of
the newsgroup in question.  These, as well as the
XFrom:, Subject: and Message-Id: lines, the list
of newsgroups, and the non-blank lines of the
message itself, are used as input to the PGP
program to generate a signature.
X
The lines of the message body are preprocessed in
a way that is meant to render harmless any mangling
that a typical news system might do to the article.
The article itself is not changed, only the input
to the signature generation. If a news system
subsequently mangles the article in a "norma" way,
for instance by inserting a ">" in front of a line
starting with "From", it will still pass the signature
check.
X
The list of newsgroups must be handled specially,
so that an article posted to multiple moderated
controlled newsgroups can be appropriately
handled.  See below for a more detailed treatment
of the issues of posting to multiple moderated
newsgroups.
X
The PGP signature is then inserted into the
XX-Auth: header, mostly so that it won't
interfere with, or be confused with, any signature
in the body of the message.
X
Anybody can check whether the message has been
modified in any significant way, simply by running
the PGP Moose Approval Checking program "pmcheck".
More importantly, though, the sites running the PGP
Moose Checking Daemon will be doing this automatically
for every posting to the registered newsgroups, or
from the registered users. And, if a posting fails
the checks, it may be automatically cancelled, and
a notification sent to the moderator. (Initially,
the automatic cancellation will be disabled, since
it is a pretty powerful sledgehammer, but that is
the intention anyway.)
X
This software is made freely available for just
about any purpose, but I've retained copyright so
as to keep some semblance of involvement. See the
last section of this file.
X
X
The Bits:
---------
X
The approval and checking part of the PGP Moose
consists of a number of Bourne Shell scripts calling
standard Unix utilities and PGP.  I could have used
perl more elegantly, but this stuff is marginally
more widely available.  If there are Unix version
dependencies, they should be considered to be bugs
and I'll happily attempt to remove them.
X
pmapp	usage: pmapp [newsgroup|user] [file]
X	
X	This script takes the not-yet-posted
X	article, specified either by filename or
X	from standard input, and creates a
X	signature for it, which is then inserted
X	in the X-Auth: header. The article,
X	ready for posting, appears on the standard
X	output.
X
X	In the configuration section at the top of
X	the script, the moderator may build in the
X	default name of the newsgroup or user, PGP
X	User Id to be used for the signature, and
X	the corresponding password. This is simply
X	for convenience, since spammers are not so
X	likely to go cracking the computer to get
X	the password, and it is a relatively simple
X	matter to generate a new user if it is,
X	indeed, compromised. For the paranoid, like
X	myself, if the password is not configured
X	into the script it is read from the terminal
X	instead.
X
pmcheck	usage: pmcheck [newsgroup|user] [article]
X
X	This script takes the article, specified
X	either by filename or from standard
X	input, and checks that the
X	X-Auth: line is something it
X	considers to be correct and that the
X	article has not been tampered with.
X	Pmcheck returns successfully if
X	everything checks out.  Otherwise it will
X	return failure and issue one of a number
X	of error messages, for example:
X
X	  Posting for $NEWSGROUP not approved with PGP Moose.
X	  Invalid designated signature from $GROUP
X	  No public key for signature $GROUP
X	  Signature doesn't match $FILE for $GROUP
X	  '$SIG' not accepted for $GROUP.
X
X	Anybody can run pmcheck. It behaves slightly
X	differently depending on the existence of
X	a file called (by default)
X	PGP_Moose_accept, and the presence or
X	absence of a newsgroup or user argument.
X	This file, if it exists, should contain
X	lines with a newsgroup name or email address,
X	some whitespace, and the PGP User Id approved
X	by the moderator or user (usually made up
X	specifically for this purpose). Multiple
X	lines for the same newsgroup/user are allowed.
X	For example:
X
X	  sci.crypt.research      	moderator <ggr@sydney.sterling.com>
X	  sci.crypt.research      	moderator <pgut01@cs.auckland.ac.nz>
X	  ggr@sydney.sterling.com	Greg's News <ggr@sydney.sterling.com>
X
X	If such a file exists, and a specific
X	newsgroup or user is specified, pmcheck is silent
X	if all is well, and issues the last of the
X	error messages above if everything else
X	was all right but the signature was from
X	the wrong person. There must, in this
X	case, be a signature applying to the
X	designated newsgroup or user.
X
X	Without such a file, or if no specific
X	newsgroup or user is given, all the signatures
X	in the article are checked.  In this case
X	it is not considered an error if the signature
X	cannot be checked due to a missing public
X	key.  If each signature is otherwise valid
X	you will get a message like:
X
X	  Valid signature from '$SIG'.
X
X	In any case, if there is a problem with a
X	signature mentioned in the PGP_Moose_accept
X	file, it will be reported and an error status
X	will be returned.
X
pmcanon
pmnewsgroups
X	These two scripts are used by pmapp and
X	pmcheck to recreate the exact input for
X	the signature, and to extract the list of
X	newsgroups in the header, respectively.
X	More documentation is in their manual
X	pages.
X
The PGP Moose checking daemon is packaged
separately, as there would not seem to be a lot
of value in having too many people running it.
Accordingly, I was less precise in making it run
absolutely everywhere. It requires the Korn shell
or equivalent, and perl, and currently only
interfaces to INN. I expect it would be easy to
interface it to CNews, but I don't have one.
X
pmdaemon
X	Runs pmcheck to check the X-Auth: header
X	for each controlled newsgroup for each
X	article that arrives in an appropriate
X	newsgroup. Mail is sent about any errant
X	articles, and automatic cancellation may
X	be enabled.
X
pmcancel
X	prepares a cancellation message based on
X	the headers of another message.
X
When (if) I get a chance, I will create mail
server scripts that allow moderators who are not
using Unix to use these facilities.  The first
allows a moderator to mail a PGP signed copy of
the article to be posted.  The server will then
verify that the moderator sent it, and post it
with a (different but corresponding) approval.
The second will accept an article and return
something that you can check the signature on.
Either way, any moderator will still need PGP.
X
X
How Do You Register For The Service?
------------------------------------
X
Ahhh, this is the hard part. After all, it would
be pretty undesirable if someone, meaning well,
took any old body's word for it that some
important moderated group should start working
this way, before the moderator was able to start
approving postings. A great way to hijack a
newsgroup. Similarly for hijacking some other
user's postings (tempting though it might be :-).
X
Another possibility is that someone, having seen
what the valid signature looks like, simply
creates a whole new PGP key that happens to have
the same PGP User ID. Then they can sign and post
stuff too.
X
The solution to both of these problems is the
classical one for public key systems. You need
either a certifying authority or the PGP Web of
Trust. We're using the Web of Trust. If you don't
understand about PGP and the Web of Trust, go away
now and come back after you really do understand
it.
X
For each newsgroup that wants to utilise this
program, the moderator will have to create a
special PGP key pair (preferably 512 bits to keep
the X-Auth: down to two full lines), and sign it. They
must then establish a path of trust to someone
who is running the PGP Moose server. It will be
up to the administrator of that server to make
sure that only trusted moderators' keys ever get
into the server's keyring.
X
THERE CAN BE NO SHORTCUTS TO THIS PROCEDURE.
Otherwise we are all back where we started.
X
In the case of an individual user, again you should
establish this verification path to one of the
administrators of the PGP Moose service.  Contact
me (ggr@usenix.org) for the time
being to mutually figure out how to do this.
X
X
Handling Multiple Moderated Groups:
----------------------------------
X
When I first proposed this tool, I was under the
impression that postings to multiple moderated
groups was an abberation that should be stamped
out. This turns out not to be the case, and
revisions to support this have been the cause of
some delay in the deployment of this tool.
X
When the news system sees that an article has been
posted to one or more moderated groups, it checks
for an Approved: header. If the header exists, the
article is accepted and processed normally,
otherwise it is mailed to the moderator of the
first moderated newsgroup mentioned in the
Newsgroups: header. There seem to be three cases of
interest.
X
The trivial case, and the most normal one, is
that there is only one moderated newsgroup
mentioned. The moderator approves the posting, and
it is done.
X
The next, and probably most important, case, is
when a moderator wants to cross-post a FAQ to
their own group, as well as news.answers (for
example). In this case their approval counts for
both groups, so they can insert the Approved:
header and post away. Presumably the other groups
are not under the control of the PGP Moose Daemon.
In this case the moderator can just go ahead and
put in the Approved: header, and save themself
and pmapp a lot of time. It will be passed right
through.
X
The other case is harder to get right. This is when
the article really is meant to be posted to two (or
more) unrelated moderated newsgroups.  Now, if the
first moderated group's moderator approves the
posting, the other ones never hear about the article,
at all. If this second group is controlled by the
PGP Moose an automatic cancel will be generated. So
it becomes very important for the moderators to do
what they should have been doing already, namely
forward the article to the next moderator. This tool
can't help people who don't use it, but it provides
some support for those who do.
X
The approval script checks whether there are any
moderated newsgroups left that don't have
XX-Auth: headers for them. If there are
none left, an Approved: header is inserted and the
article gets posted.  Otherwise, it issues a warning,
and re-orders the newsgroups header with a newsgroup
which is moderated but has no X-Auth: line
at the start.  When the article is posted, the news
system will forward it to the moderator of the (new)
first moderated group. If all moderators are sensible,
and check for moderated newsgroups in this fashion,
the mess should sort itself out and the last moderator
will go ahead and post it. A warning nessage to
the subsequent moderator NOT to change the
article is also inserted, since such a
modification would invalidate the previous
signatures..
X
To ease this process, a second type of
XX-Auth: header is supported. this has
the form:
X
X	X-Auth: None ... Newsgroup
X
The important fact about this is that
the newsgroup appears last on the line, allowing a
sort of partial approval, from moderators who
don't use the PGP Moose.
X
The Newsgroups: line is split into a sorted list
of newsgroups for the purpose of generating the
digital signature. Note that this means that once
an article has been approved and authenticated by
one moderator, it cannot be altered in any way by
a moderator of a subsequent group, including
altering the set of newsgroups mentioned in the
Newsgroups: header, the body of the posting, or
the other headers mentioned above.
X
X
Possible Problems We've Forseen:
--------------------------------
X
If an article is truly mangled e.g. by truncation, it
will fail the authentication and be cancelled.
Until it is demonstrated otherwise, this is
assumed to be a rare and minor problem. When a
cancel is issued, mail is sent to the moderator of
the group telling them, and they can tell us if it
becomes a problem. (In the initial deployment we
expect that no automatic cancels will actually be
generated, only the notification mail will be
sent.)
X
Currently the signature produced is assumed to be
a PGP version 2.6 compatible one.
X
X
Status:
-------
X
These scripts are implemented already, or as noted
above. They are undergoing beta testing and as soon
as they have settled they will be made available
via anonymous FTP and posting to comp.sources.misc
and sci.crypt.research and the moderators' list.
X
In the meantime, if you want to use the tools, or
particularly if you want to run a PGP Moose
checking daemon, contact me (ggr@usenix.org).
X
X
Obtaining, installing, configuring:
-----------------------------------
X
I regret that I don't have a public ftp site, but
I do have a web page where you can get a
compressed tar archive of the approval code. It is
<A HREF=http://www.usenix.org/~ggr/PGPMoose.html>
off my home page</A>.
X
It is hard to talk in detail about installation
and configuration, since many users are not in
charge of their own news server configuration. In
my case, I run all of the things out of a
subdirectory of my home directory. The only
thing outside this area which must be changed is
the INN newsfeeds file, if you are running the
checking daemon. So, get the distribution file as
above and unpack it whereever you want it to live.
X
There are configuration sections at the top of
pmcheck, pmapp and pmdaemon. I like to think that
they are relatively self-explanatory. One of the
harder decisions is whether to use a separate
keyring for PGP Moose applications or not. It is
very strongly recommended that you do, if you are
going to run the PGP Moose checking daemon, as
the keyring files will need to be readable by the
userid which INN runs under (usually "news").
Most of these options can also be overridden by
environment variables or command arguments, so it
is possible to leave the scripts unmodified and
simply put a wrapper around them (which is what I
do).
X
In the case of pmapp, the newsgroup or user that
the authentication applies to can be specified on
the command itself; The PGP user id and password,
and the Approved: header's contents, can be
specified by environment variables PMUSER,
PMPASSWORD and APP, respectively.
X
For pmcheck, the important one is the name of the
configuration file specifying which signatures
are valid for which newsgroups or users.
X
Pmdaemon runs from INN, and needs some special
care to set it up. "news" needs access permission
to the directory and files for PGP Moose, and
also read permission on the public keyring. Note
that PGP creates keyrings with only owner
permissions. The search path is rarely correct,
and should be set at the top of the pmdaemon
script. There are also a number of file names and
mail addresses, but the comments should be clear
enough.
X
Lastly, you want to incorporate pmapp in your
moderation script and possibly your posting
script. In my case, the last line of my posting
script basically said
X
X    /usr/local/news/inews -S -h <tempfile
X
but now it says 
X
X    pmapp <tempfile | /usr/local/news/inews -S -h
X
To authenticate postings as an individual (as opposed
to a moderator) I had to take a copy of the
installed Pnews script, make sure it came earlier
on my search path than the normal one, and modify
that. You have to be careful that no extra
signature files get appended after the pmapp is
executed. Again, immediately before the "inews"
call is the right place. I'm not sure whether
this will work for all versions of news, this is
not really my field of competence.
X
X
It Really Wasn't That Hard.
---------------------------
X
I wish people had put as much effort into doing
this as they did into clogging the Moderators'
mailing list. It wasn't hard.
X
But you know what was hard? What Phil Zimmermann
did creating PGP in the first place. Phil is in
serious legal hassles over PGP, and if you think
this effort saves you or your company some time
or money, I'd like you to consider donating some
of it to Phil's legal defence fund. Write to me
or Phil's lawyer Phil Dubois <dubois@acm.org>
regarding how to donate. You can do it over the
net using PGP! I probably also should thank the
many people who have worked hard to bring
encryption back out of the black chambers. Some
names which directly come to mind are Diffie,
Hellman, Merkle, Rivest, Shamir, Adelman, Lai,
Massey, and probably many others.
X
Share and Enjoy!
X
X
License Terms:
-------------
X
This software is copyrighted by Greg Rose, RoSecure
Software, and other parties.  The following terms
apply to all files associated with the software
unless explicitly disclaimed in individual
files.
X
The authors hereby grant permission to use, copy,
modify, distribute, and license this software and
its documentation for any purpose, provided that
existing copyright notices are retained in all
copies and that this notice is included verbatim
in any distributions.  No written agreement,
license, or royalty fee is required for any of
the authorized uses.  Modifications to this
software may be copyrighted by their authors and
need not follow the licensing terms described
here, provided that the new terms are clearly
indicated on the first page of each file where
they apply.
X
IN NO EVENT SHALL THE AUTHORS OR DISTRIBUTORS BE
LIABLE TO ANY PARTY FOR DIRECT, INDIRECT,
SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
ARISING OUT OF THE USE OF THIS SOFTWARE, ITS
DOCUMENTATION, OR ANY DERIVATIVES THEREOF, EVEN
IF THE AUTHORS HAVE BEEN ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.
X
THE AUTHORS AND DISTRIBUTORS SPECIFICALLY
DISCLAIM ANY WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR
PURPOSE, AND NON-INFRINGEMENT.  THIS SOFTWARE IS
PROVIDED ON AN "AS IS" BASIS, AND THE AUTHORS AND
DISTRIBUTORS HAVE NO OBLIGATION TO PROVIDE
MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR
MODIFICATIONS.
X
X
Version:
-------
X
@(#)README	1.6 (PGPMoose) 95/10/21
SHAR_EOF
  $shar_touch -am 0521145497 'README' &&
  chmod 0664 'README' ||
  $echo 'restore of' 'README' 'failed'
  if ( md5sum --help 2>&1 | grep 'sage: md5sum \[' ) >/dev/null 2>&1 \
  && ( md5sum --version 2>&1 | grep -v 'textutils 1.12' ) >/dev/null; then
    md5sum -c << SHAR_EOF >/dev/null 2>&1 \
    || $echo 'README:' 'MD5 check failed'
847c9340e27d59a86d1b040b74d04403  README
SHAR_EOF
  else
    shar_count="`LC_ALL= LC_CTYPE= LANG= wc -c < 'README'`"
    test 20608 -eq "$shar_count" ||
    $echo 'README:' 'original size' '20608,' 'current size' "$shar_count!"
  fi
fi
# ============= pmapp.1 ==============
if test -f 'pmapp.1' && test "$first_param" != -c; then
  $echo 'x -' SKIPPING 'pmapp.1' '(file already exists)'
else
  $echo 'x -' extracting 'pmapp.1' '(text)'
  sed 's/^X//' << 'SHAR_EOF' > 'pmapp.1' &&
X.TH PMAPP 1 "PGP Moose"
X.\"@(#)pmapp.1	1.4 (PGPMoose) 95/10/21
X.SH NAME
pmapp \- insert a verifiable signature into a
news article.
X.SH SYNOPSIS
X.B pmapp
X.I [newsgroups|user] [file] 
X.SH DESCRIPTION
X.I Pmapp
accepts an article from the named
X.IR file
(or standard input if not specified),
computes a digital signature from the important
part of the contents, and inserts a special
header into the article which enables subsequent
checking of the signature. The amended article is
produced on standard output, suitable for
injection into the news system.
X.LP
The signature is created using the defaults for
the user name (and optionally password) built
into the script when a newsgroup is specified. 
This is the most common case for a newsgroup
moderator who will use a customised version of
the script. These defaults can be overridden with
environment variables \f3PMUSER\fP and
\f3PMPASSWORD\fP.
X.LP
In any case, whenever the
password is the empty string, a prompt is
written to the controlling terminal and a
password is read from it.
X.LP
When a user is specified (by way of an email
address containing an "\fB@\fP") this is used to
select the signing user, and a password will be
requested.
X.LP
When the signature is being generated for a
newsgroup, it is assumed that the newsgroup is
moderated and the invoking user is (one of) the
moderator(s).
The simple case is that there is only one
newsgroup specified; an Approved: line is added
as well as the X-Auth: line, and the
article is ready for posting.
X.LP
\f2Pmapp\fP goes to some trouble to
handle the case of multiple moderated newsgroups
in the Newsgroups: line. The first, and probably
most important, case, is
when a moderator wants to cross-post a FAQ to
their own group, as well as news.answers (for
example). In this case their approval counts for
both groups, so they can insert the Approved:
header and post away. Presumably the other groups
are not under the contol of the PGP Moose Daemon.
The moderator can just go ahead and
put in the Approved: header, and save themself
and pmapp a lot of time. It will be passed right
through.
X.LP
The other case is harder to get right. This is when
the article really is meant to be posted to two (or
more) unrelated moderated newsgroups. The approval
script checks whether there are any moderated
newsgroups left that don't have X-Auth:
headers for them. If there are none left, an Approved:
header is inserted and the article gets posted.
Otherwise, it issues a warning, and re-orders the
newsgroups header with a newsgroup which is moderated
but has no X-Auth:  line at the start.
When the article is posted, the news system will
forward it to the moderator of the (new) first
moderated group. If all moderators are sensible,
and check for moderated newsgroups in this fashion,
the mess should sort itself out and the last moderator
will go ahead and post it. A warning message to the
subsequent moderator NOT to change the article is
also inserted.
X.\".SH FILES
X.SH SEE ALSO
X.IR pmcheck (1),
X.IR pmcanon (1)
for a description of the fields which go into the
signature calculation,
the PGP User's Manual.
X.SH AUTHOR
Greg Rose, RoSecure Software.
SHAR_EOF
  $shar_touch -am 0307185997 'pmapp.1' &&
  chmod 0444 'pmapp.1' ||
  $echo 'restore of' 'pmapp.1' 'failed'
  if ( md5sum --help 2>&1 | grep 'sage: md5sum \[' ) >/dev/null 2>&1 \
  && ( md5sum --version 2>&1 | grep -v 'textutils 1.12' ) >/dev/null; then
    md5sum -c << SHAR_EOF >/dev/null 2>&1 \
    || $echo 'pmapp.1:' 'MD5 check failed'
ab8920ea039bfb4bf2c5ac136a160f3b  pmapp.1
SHAR_EOF
  else
    shar_count="`LC_ALL= LC_CTYPE= LANG= wc -c < 'pmapp.1'`"
    test 3157 -eq "$shar_count" ||
    $echo 'pmapp.1:' 'original size' '3157,' 'current size' "$shar_count!"
  fi
fi
# ============= pmcanon.1 ==============
if test -f 'pmcanon.1' && test "$first_param" != -c; then
  $echo 'x -' SKIPPING 'pmcanon.1' '(file already exists)'
else
  $echo 'x -' extracting 'pmcanon.1' '(text)'
  sed 's/^X//' << 'SHAR_EOF' > 'pmcanon.1' &&
X.TH PMCANON 1 "PGP Moose"
X.\"@(#)pmcanon.1	1.3 (PGPMoose) 95/10/21
X.SH NAME
pmcanon \- put a news article in canonical format
for signature checking
X.SH SYNOPSIS
X.BI pmcanon [file] 
X.SH DESCRIPTION
X.I Pmcanon
accepts an article from the named
X.I file
(or standard input if not specified), selects
certain of the header fields,
and performs certain transformations intended to
defeat unintentional mangling by news transport
programs. The resulting article is written to
standard output, and is suitable to have a PGP
signature generated or checked for it.
X.LP
The output produced consists (in order) of a sorted list,
one per line, of newsgroups; the From:, Subject:,
and Message-ID: lines, and the body of the
article (everything after the first empty line).
Other header lines are discarded.
X.LP
The body is further processed by deleting all
blank lines, deleting trailing whitespace on
lines, prefixing lines beginning with "--",
"From", "Subject", and a single "." with "-\ ",
">", ">" and ".", respectively. These
modifications are safe, in that an article which
has already had such modifications will fail to
meet the criterion to have them happen again.
Thus what was used as input when a signature was
generated should still be the same when checked
for validity, even if some of these changes have
happened along the delivery path.
X.\".SH FILES
X.SH SEE ALSO
X.IR pmapp (1),
X.IR pmcheck (1),
PGP manual.
X.SH AUTHOR
Greg Rose, RoSecure Software.
SHAR_EOF
  $shar_touch -am 0307185997 'pmcanon.1' &&
  chmod 0444 'pmcanon.1' ||
  $echo 'restore of' 'pmcanon.1' 'failed'
  if ( md5sum --help 2>&1 | grep 'sage: md5sum \[' ) >/dev/null 2>&1 \
  && ( md5sum --version 2>&1 | grep -v 'textutils 1.12' ) >/dev/null; then
    md5sum -c << SHAR_EOF >/dev/null 2>&1 \
    || $echo 'pmcanon.1:' 'MD5 check failed'
d882462d68f44ca2f6ec16a91b6c1a01  pmcanon.1
SHAR_EOF
  else
    shar_count="`LC_ALL= LC_CTYPE= LANG= wc -c < 'pmcanon.1'`"
    test 1453 -eq "$shar_count" ||
    $echo 'pmcanon.1:' 'original size' '1453,' 'current size' "$shar_count!"
  fi
fi
# ============= pmcheck.1 ==============
if test -f 'pmcheck.1' && test "$first_param" != -c; then
  $echo 'x -' SKIPPING 'pmcheck.1' '(file already exists)'
else
  $echo 'x -' extracting 'pmcheck.1' '(text)'
  sed 's/^X//' << 'SHAR_EOF' > 'pmcheck.1' &&
X.TH PMCHECK 1 "PGP Moose"
X.\"@(#)pmcheck.1	1.5 (PGPMoose) 95/11/15
X.SH NAME
pmcheck \- check veracity and applicability of
signatures in news articles.
X.SH SYNOPSIS
X.B pmcheck
X.I [newsgroups|user] [file] 
X.SH DESCRIPTION
X.I Pmcheck
accepts an article from the named
X.IR file
(or standard input if not specified),
and performs certain checks against digital
signatures present in X-Auth: headers
in the news articles. There are two common modes
of use
of \f2pmcheck\fP, and these are described
separately for simplicity, even though there is
considerable ability to mix-and-match.
X.LP
The first use is when a person is reading news,
and sees an article and wishes to check whether
the article is an approved posting to a moderated
newsgroup, or an approved posting from a
particular individual user. Piping the article
through \f2pmcheck\fP will give a list of valid
signatures (or signatures which couldn't be
checked because corresponding PGP public keys
were unavailable), and of course generate error
messages for invalid signatures, which indicate
either forged or altered articles. Any alteration
might have been intentional, but bear in mind the
possibility that an alteration could have been an
artifact of the news system, despite precautions
against this.
X.LP
The second use, and the reason for the existence
of the PGP Moose system, is when an article is
automatically checked upon receipt by a
designated news hub. In this case, a moderated
newsgroup or user name (represented by an
electronic mail address) will be specified, and
it is considered an error if there is no
corresponding X-Auth: header, or if for
any reason it doesn't check out. Furthermore, there
can be a configured file which lists pairs of
newsgroup/user names, and corresponding PGP user
IDs who are allowed to authorise such postings.
Even a valid signature from an individual who is
not listed in this file will be considered an
error. All X-Auth: headers will be
checked if their newsgroup/user name appears in
the checking file, the only way in which the
argument is special is that such a header for
that newsgroup or user \f3must\fP appear.
The intention is that any article which fails
this authentication process will be reported to
the user or newsgroup moderator(s), and might be
automatically cancelled. This is to react quickly
to spamming attacks on moderated newsgroups.
X.SH EXIT STATUS
X.I Pmcheck
returns an exit status of 0 if everything is all right, and non-zero otherwise.
In particular, an exit status of 1 means that the article was not
approved with the PGP Moose when it should have been, and a status of
2 is returned for all other authentication problems.
X.SH SEE ALSO
X.IR pmapp (1),
X.IR pmcanon (1)
for a description of the fields which go into the
signature calculation,
the PGP User's Manual,
the PGP Moose README file for an understanding of
how it all hangs together.
X.SH BUGS
Currently \f3pmcheck\fP always allows cancel
messages to pass, despite the fact that
\f3pmdaemon\fP always authenticates them. The
potential consequences of an automated cancellation-war were
simply too horrible to contemplate.
X.SH AUTHOR
Greg Rose, RoSecure Software.
SHAR_EOF
  $shar_touch -am 0307185997 'pmcheck.1' &&
  chmod 0444 'pmcheck.1' ||
  $echo 'restore of' 'pmcheck.1' 'failed'
  if ( md5sum --help 2>&1 | grep 'sage: md5sum \[' ) >/dev/null 2>&1 \
  && ( md5sum --version 2>&1 | grep -v 'textutils 1.12' ) >/dev/null; then
    md5sum -c << SHAR_EOF >/dev/null 2>&1 \
    || $echo 'pmcheck.1:' 'MD5 check failed'
a217f7b45db9096aef1032fb5324a37d  pmcheck.1
SHAR_EOF
  else
    shar_count="`LC_ALL= LC_CTYPE= LANG= wc -c < 'pmcheck.1'`"
    test 3158 -eq "$shar_count" ||
    $echo 'pmcheck.1:' 'original size' '3158,' 'current size' "$shar_count!"
  fi
fi
# ============= pmnewsgroups.1 ==============
if test -f 'pmnewsgroups.1' && test "$first_param" != -c; then
  $echo 'x -' SKIPPING 'pmnewsgroups.1' '(file already exists)'
else
  $echo 'x -' extracting 'pmnewsgroups.1' '(text)'
  sed 's/^X//' << 'SHAR_EOF' > 'pmnewsgroups.1' &&
X.TH PMNEWSGROUPS 1 "PGP Moose"
X.\"@(#)pmnewsgroups.1	1.3 (PGPMoose) 95/10/21
X.SH NAME
pmnewsgroups \- extract a list of all newsgroups
from an article's headers.
X.SH SYNOPSIS
X.BI pmnewsgroups [file] 
X.SH DESCRIPTION
X.I Pmnewsgroups
accepts an article from the named
X.I file
(or standard input if not specified), selects
the header field, Newsgroups:,
and writes to standard output a sorted list of
the newsgroups present, one per line.
X.\".SH FILES
X.SH SEE ALSO
X.IR pmapp (1),
X.IR pmcheck (1),
X.IR pmcanon (1),
X.SH AUTHOR
Greg Rose, RoSecure Software.
SHAR_EOF
  $shar_touch -am 0307185997 'pmnewsgroups.1' &&
  chmod 0444 'pmnewsgroups.1' ||
  $echo 'restore of' 'pmnewsgroups.1' 'failed'
  if ( md5sum --help 2>&1 | grep 'sage: md5sum \[' ) >/dev/null 2>&1 \
  && ( md5sum --version 2>&1 | grep -v 'textutils 1.12' ) >/dev/null; then
    md5sum -c << SHAR_EOF >/dev/null 2>&1 \
    || $echo 'pmnewsgroups.1:' 'MD5 check failed'
5b77b37bffc1c4da904fe3f8cd687384  pmnewsgroups.1
SHAR_EOF
  else
    shar_count="`LC_ALL= LC_CTYPE= LANG= wc -c < 'pmnewsgroups.1'`"
    test 552 -eq "$shar_count" ||
    $echo 'pmnewsgroups.1:' 'original size' '552,' 'current size' "$shar_count!"
  fi
fi
# ============= Makefile ==============
if test -f 'Makefile' && test "$first_param" != -c; then
  $echo 'x -' SKIPPING 'Makefile' '(file already exists)'
else
  $echo 'x -' extracting 'Makefile' '(text)'
  sed 's/^X//' << 'SHAR_EOF' > 'Makefile' &&
# @(#)Makefile	1.4 (PGPMoose) 95/10/11
X
SCRIPTS = pmapp pmcanon pmcheck pmnewsgroups
DOC	= README pmapp.1 pmcanon.1 pmcheck.1 pmnewsgroups.1 Makefile
DAEMON	= pmdaemon pmcancel pmdaemon.1 pmcancel.1 pmcancel.pgp \
X		checkedgroups PGP_Moose_accept
X
all:
X	chmod +x $(SCRIPTS)
X	chmod +x pmdaemon pmcancel
X	chmod a+r pmcancel.pgp
X
dist:	all PGPMoose.shar PMDaemon.tar.Z PGPMoose.tar.Z
X
PGPMoose.shar: $(DOC) $(SCRIPTS)
X	shar $(DOC) $(SCRIPTS) >PGPMoose.shar
X
PMDaemon.tar.Z: $(DAEMON)
X	tar -cf - $(DAEMON) | compress >PMDaemon.tar.Z
X
PGPMoose.tar.Z: PMDaemon.tar.Z PGPMoose.shar
X	tar -cf - $(DOC) $(SCRIPTS) $(DAEMON) | compress >PGPMoose.tar.Z
SHAR_EOF
  $shar_touch -am 0307185997 'Makefile' &&
  chmod 0444 'Makefile' ||
  $echo 'restore of' 'Makefile' 'failed'
  if ( md5sum --help 2>&1 | grep 'sage: md5sum \[' ) >/dev/null 2>&1 \
  && ( md5sum --version 2>&1 | grep -v 'textutils 1.12' ) >/dev/null; then
    md5sum -c << SHAR_EOF >/dev/null 2>&1 \
    || $echo 'Makefile:' 'MD5 check failed'
23b1338c2bfb0fdf6897c5d58fb48c77  Makefile
SHAR_EOF
  else
    shar_count="`LC_ALL= LC_CTYPE= LANG= wc -c < 'Makefile'`"
    test 641 -eq "$shar_count" ||
    $echo 'Makefile:' 'original size' '641,' 'current size' "$shar_count!"
  fi
fi
# ============= pmapp ==============
if test -f 'pmapp' && test "$first_param" != -c; then
  $echo 'x -' SKIPPING 'pmapp' '(file already exists)'
else
  $echo 'x -' extracting 'pmapp' '(text)'
  sed 's/^X//' << 'SHAR_EOF' > 'pmapp' &&
#!/bin/sh
X
# @(#)pmapp	1.15 (PGP Moose) 96/03/20
# Authorisation script for PGP Moose
# Written by Greg Rose, RoSecure Software, Copyright C 1995.
X
# Debugging
# On most shells the following statements redirect a log of what
# is happening, AND ALL ERROR MESSAGES, to /tmp/pmdebug. Some shells
# (notably /bin/sh on Ultrix systems) do not do the redirection.
#exec 2>/tmp/pmdebug
#set -x
X
# Configuration Stuff:
X
X    # Default user / newsgroup. If not set, an argument is mandatory.
X    DEFAULT_NEWSGROUP=sci.crypt.research
X
X    # If an Approved: line is to be added, this is what it will say.
X    # Can be set in the environment.
X    if [ "x$APP" = "x" ]; then
X	APP="Authorising user <auth@moderator.site.com>"
X    fi
X
X    # If a From: line is to be added, this is what it will say.
X    # Can be set in the environment.
X    if [ "x$FROM" = "x" ]; then
X	if [ "x$LOGNAME" = "x" ]; then
X	    LOGNAME=`whoami`
X	fi
X	FROM="`grep \^$LOGNAME: /etc/passwd |
X	    awk -F: '{print \$5}'` <$LOGNAME@`hostname`>"
X    fi
X
X    # The PGP user and (optional) password. The password will be read
X    # from the controlling terminal if not specified. If the newsgroup/user
X    # argument is an email address, it is used instead of the configured
X    # PMUSER. The following line provides a default password if it is unset.
X    # This password will NOT be used if an email address is presented as an
X    # argument.
X    # Can be set in the environment.
X    if [ "x$PMUSER" = "x" ]; then
X	PMUSER=pgpmoose
X	DEFAULT_PASSWORD=t
X    fi
X
X    # In the case of a user posting, the name desired on the X-Auth
X    # line might not be the one used by PGP to look up the key.
X    # In this case, set this variable or import it. By default, though,
X    # leave it empty and $PMUSER will be used.
X    # Can be set in the environment.
X    if [ "x$PGPUSER" = "x" ]; then
X	PGPUSER=
X    fi
X
X    # Whether or not to fold long lines.
X    # Can be set in the environment.
X    if [ "x$FOLDLINES" = "x" ]; then
X	FOLDLINES=false		# allowed values are 'true' or 'false'
X    fi
X
X    # Name of the posting host. Must be fully qualified host.domain.
X    # Unless your hostname is not fuly qualified, or you want to use
X    # an alias, you may as well just keep it as it is.
X    HOSTNAME=`hostname`
X
X    # A place to put temp files. These can add up to about twice the
X    # size of the article being posted.
X    TMP=/tmp
X
X    # If a Message-ID is being generated, this will appear in it.
X    DATESTAMP=`date +%Y\%m\%d\%H\%M`  # NO WHITESPACE OR METACHARACTERS
X
X    # Where the active file is on this system, for checking crosspostings
X    # to multiple moderated groups. The check will be disabled if this is
X    # left empty (and Approved: lines will be added if needed).
X    ACTIVE=/usr/local/news/active
X
X    # If the article is crossposted to other moderated groups, a warning
X    # tells you to reorder the newsgroups and submit the article. A copy
X    # of the article is deposited in this file for you to edit.
X    SAVED_ARTICLE=$TMP/article
X
# End of configuration stuff.
X
# Be neat and tidy.
TF=$TMP/pgpmt$$
trap "stty echo </dev/tty >/dev/tty 2>/dev/null; rm -f $TF.?; exit 1" 1 2 3 15
X
# Check usage, set arguments
USAGE='echo >&2 "Usage: $0 [newsgroup|user] [article]"; exit 1'
case $# in
1)
X    if [ ! -r "$1" ]; then
X	cat >$TF.f
X	FILE=$TF.f
X	FILENAME="on standard input"
X	NEWSGROUP="$1"
X    elif [ ! "$DEFAULT_NEWSGROUP" ]; then
X	echo >&2 "$0: No default user or newsgroup set."
X	eval "$USAGE"
X    else
X	FILE="$1"
X	FILENAME="$1"
X	NEWSGROUP="$DEFAULT_NEWSGROUP"
X	PMPASSWORD="$DEFAULT_PASSWORD"
X    fi
X    ;;
2)
X    if [ ! -r $2 ]; then
X	echo >&2 "$0: Can't read $2"
X	eval "$USAGE"
X    fi
X    FILE="$2"
X    FILENAME="$2"
X    NEWSGROUP="$1"
X    ;;
0)
X    if [ ! "$DEFAULT_NEWSGROUP" ]; then
X	echo >&2 "$0: No default user or newsgroup set."
X	eval "$USAGE"
X    fi
X    cat >$TF.f
X    FILE=$TF.f
X    FILENAME="on standard input"
X    NEWSGROUP="$DEFAULT_NEWSGROUP"
X    PMPASSWORD="$DEFAULT_PASSWORD"
X    ;;
*)
X    eval "$USAGE"
X    ;;
esac
X
case "$NEWSGROUP" in
*@*)
X    USERFLAG=true
X    PMUSER=$NEWSGROUP
X    # PMPASSWORD is left either as imported or null in this case.
X    ;;
*)
X    USERFLAG=false
X    PMPASSWORD="${PMPASSWORD-$DEFAULT_PASSWORD}"
X    ;;
esac
X
# Set the user ID to be given to PGP to look up the key.
if [ "x$PGPUSER" = "x" ]; then
X    PGPUSER=$PMUSER
fi
X
# Split the file into headers and body.
# Note long lines in the body may be folded.
sed -n -e '/^ *$/q' -e 'p' $FILE >$TF.h
{ echo ""; sed -e '1,/^ *$/d' $FILE; } >$TF.b
if $FOLDLINES; then
X    d='..........'
X    if grep -s "$d$d$d$d$d$d$d$d" $TF.b >/dev/null; then
X	echo >&2 "$0: warning: lines exceed 80 characters, being folded."
X	sed  -e '/.\{80\}/s/.\{79\}/&\
X    /g' $TF.b >$TF.l
X	mv $TF.l $TF.b
X    fi
fi
X
if [ ! -s $TF.h ]; then
X    echo "$0: problem with article $FILENAME; header section empty." >&2
X    exit 1
fi
X
# If no From: line, add one.
grep -i -s '^From:' $TF.h >/dev/null ||
X    echo "From: $FROM" >>$TF.h
X
# If no Message-ID: line, add one.
grep -i -s '^Message-ID:' $TF.h >/dev/null ||
X    echo "Message-ID: <pgpmoose.$DATESTAMP.$$@$HOSTNAME>" >>$TF.h
X
# Check for or Provide a Newsgroups: line if none there,
grep -i -s '^Newsgroups:' $TF.h >/dev/null || \
X    if $USERFLAG; then
X	# that is fine
X	:
X    else
X	echo "Newsgroups: $NEWSGROUP" >>$TF.h
X    fi
X
# Get the list of newsgroups and check that we are in it!
pmnewsgroups $TF.h >$TF.n
$USERFLAG || grep -i -s "^$NEWSGROUP\$" $TF.n >/dev/null || {
X    echo >&2 "$0: Newsgroup $NEWSGROUP not present in article $FILENAME"
X    exit 1
}
X
# Read a password if none is configured.
if [ ! "$PMPASSWORD" ]; then
X    stty -echo </dev/tty >/dev/tty 2>/dev/null
X    echo "Enter PGP passphrase for $PGPUSER:" >/dev/tty
X    PMPASSWORD=`head -1 </dev/tty`
X    stty echo </dev/tty >/dev/tty 2>/dev/null
fi
X
# Compute a signature for the important information.
PGPPASSFD=0
export PGPPASSFD
{
X    echo "$PMPASSWORD"
X    cat $TF.h $TF.b | pmcanon
} | pgp -sabft +BATCHMODE=on -u "$PGPUSER" >$TF.s 2>$TF.e || {
X    echo >&2 "$0: PGP signing failed. PGP output:"
X    cat >&2 $TF.e
X    exit 1
}
X
# Add an appropriate X-Auth: header
{
X    echo "X-Auth: PGPMoose V1.1 PGP $NEWSGROUP"
X    sed -e '1,/^$/d' -e '/END PGP MESSAGE/d' -e 's/^/	/' $TF.s
} >>$TF.h
X
# Now one of the hardest parts. If there is no Approved: line,
# check for moderated groups that don't have an X-Auth: line
# and do something sensible.
$USERFLAG || grep -i -s '^Approved:' $TF.h >/dev/null || {
X    if [ "$ACTIVE" ]; then
X	# Cut it down to a list of un-X-Auth:ed groups
X	grep -i '^X-Auth.*:' $TF.h \
X	    | sed -n -e 's/^.* //p' \
X	    | sort \
X	    | comm -23 $TF.n - \
X	    >$TF.u
X	# Check if any of these are moderated
X	if [ -s $TF.u ]; then
X	    badgroup=
X	    for i in `cat $TF.u`; do
X		if grep -i -s "^$i[ 	].*[ 	]m$" $ACTIVE >/dev/null; then
X		    echo >&2 "$0: Newsgroup $i is moderated."
X		    badgroup=$i
X		fi
X	    done
X	    if [ "x$badgroup" != x ]; then
X		cat >&2 <<END
$0: Other moderated groups appear in newsgroup list.
X    The Authenticated article is saved in $SAVED_ARTICLE.
X    The newsgroups line has been reordered
X    to have it sent to the next moderator in the chain.
X    In future, you can manually add an Approved: line
X    before running this approval script if
X    you are absolutely sure that this is all right.
END
X		cat >>$TF.h <<END
XX-WARNING-TO-MODERATORS: This article has been processed and
X    accepted using a cryptographic program by the moderator
X    of $NEWSGROUP. Its content must not be changed or it
X    will be automatically cancelled. If you don't like the
X    article or its crossposting, return it to the submitter. 
X    (You can delete this message if you are the last
X    moderator to see it.)
END
X		{
X		    # Make a new set of headers. Most of them are all right.
X		    # Regrettable that this takes so much work, but it
X		    # doesn't happen often, right?
X		    # First pass through all but the Newsgroups:.
X		    sed -n -e '/^[Nn][Ee][Ww][Ss][Gg][Rr][Oo][Uu][Pp][Ss]:/q' \
X			   -e 'p' $TF.h
X		    sed -e '1,/^[Nn][Ee][Ww][Ss][Gg][Rr][Oo][Uu][Pp][Ss]:/d' \
X			$TF.h \
X			| sed -n -e '/^[^ 	]/,$p'
X		    # Add a new Newsgroups: header
X		    {
X			echo "Newsgroups: $badgroup,"
X			sed -e "/^$badgroup\$/d" -e 's/.*/	&,/' $TF.n
X		    } | sed -e '$s/,//'
X		    cat $TF.b
X		}
X		rm -f $TF.?
X		exit 0
X	    fi
X	fi
X    fi
X    # If not rejected above, we can insert an Approved: header and go for it
X    echo "Approved: $APP" >>$TF.h
}
X
# recreate the article on standard output.
cat $TF.h $TF.b
X
rm -f $TF.?
Xexit 0
SHAR_EOF
  $shar_touch -am 0307185997 'pmapp' &&
  chmod 0555 'pmapp' ||
  $echo 'restore of' 'pmapp' 'failed'
  if ( md5sum --help 2>&1 | grep 'sage: md5sum \[' ) >/dev/null 2>&1 \
  && ( md5sum --version 2>&1 | grep -v 'textutils 1.12' ) >/dev/null; then
    md5sum -c << SHAR_EOF >/dev/null 2>&1 \
    || $echo 'pmapp:' 'MD5 check failed'
e11165ecd94bd3d33fff69ba5556ec83  pmapp
SHAR_EOF
  else
    shar_count="`LC_ALL= LC_CTYPE= LANG= wc -c < 'pmapp'`"
    test 8523 -eq "$shar_count" ||
    $echo 'pmapp:' 'original size' '8523,' 'current size' "$shar_count!"
  fi
fi
# ============= pmcanon ==============
if test -f 'pmcanon' && test "$first_param" != -c; then
  $echo 'x -' SKIPPING 'pmcanon' '(file already exists)'
else
  $echo 'x -' extracting 'pmcanon' '(text)'
  sed 's/^X//' << 'SHAR_EOF' > 'pmcanon' &&
#!/bin/sh
X
# @(#)pmcanon	1.7 (PGP Moose) 97/03/05
# Canonicalisation script for PGP Moose
# (in other words, it takes a news article and turns it
# into something we can compute/check a signature on.)
# Written by Greg Rose, RoSecure Software, Copyright C 1995.
X
# Be neat and tidy.
TMP=/tmp
TF=$TMP/pgpmt$$
trap "rm -f /$TF.?" 0 1 2 3 15
X
# Check usage. File must be specified, and result comes out on stdout.
if [ $# = 0 ]; then
X    cat >$TF.f
X    FILE=$TF.f
elif [ $# != 1 -o ! -f "$1" ]; then
X    echo >&2 "usage: $0 article"
X    exit 1
else
X    FILE=$1
fi
X
# multiple greps so we can guarantee order
pmnewsgroups $FILE
{
X    grep -i "^From:" "$FILE"
X    grep -i "^Subject:" "$FILE"
X    grep -i "^Message-ID:" "$FILE"
} | sed -e 's/^[^:]*: *//' -e 's/: */:/g' -e 's/[ 	]*$//'
sed -e '1,/^ *$/d' \
X    -e '/^ *$/d' \
X    -e 's/^--/- --/' \
X    -e 's/^[Ff][Rr][Oo][Mm]/>&/' \
X    -e 's/^[Ss][Uu][Bb][Jj][Ee][Cc][Tt]/>&/' \
X    -e 's/^\.$/../' \
X    -e 's/^\.[^.]/.&/' \
X    -e 's/[ 	]*$//' \
X    "$FILE"
SHAR_EOF
  $shar_touch -am 0307185997 'pmcanon' &&
  chmod 0555 'pmcanon' ||
  $echo 'restore of' 'pmcanon' 'failed'
  if ( md5sum --help 2>&1 | grep 'sage: md5sum \[' ) >/dev/null 2>&1 \
  && ( md5sum --version 2>&1 | grep -v 'textutils 1.12' ) >/dev/null; then
    md5sum -c << SHAR_EOF >/dev/null 2>&1 \
    || $echo 'pmcanon:' 'MD5 check failed'
010ce19926b3000cb5e9da76eee4ad01  pmcanon
SHAR_EOF
  else
    shar_count="`LC_ALL= LC_CTYPE= LANG= wc -c < 'pmcanon'`"
    test 1006 -eq "$shar_count" ||
    $echo 'pmcanon:' 'original size' '1006,' 'current size' "$shar_count!"
  fi
fi
# ============= pmcheck ==============
if test -f 'pmcheck' && test "$first_param" != -c; then
  $echo 'x -' SKIPPING 'pmcheck' '(file already exists)'
else
  $echo 'x -' extracting 'pmcheck' '(text)'
  sed 's/^X//' << 'SHAR_EOF' > 'pmcheck' &&
#!/bin/sh
X
# @(#)pmcheck	1.9 (PGP Moose) 96/03/04
# Authorisation checking script for PGP Moose
# Written by Greg Rose, RoSecure Software, Copyright C 1995.
X
# Configuration:
X    # Where to create temporary files.
X    TMP=/tmp
X
X    # Name of the file with valid moderator's/individual's names
X    ACCEPT=PGP_Moose_accept
X
# End Configuration
X
# Be neat and tidy.
TF=$TMP/pgpmt$$
trap "rm -f $TF.?; exit 1" 1 2 3 15
X
VERBOSE=false
# Usage: $0 [newsgroup|user] [filename]
case $# in
0)
X    VERBOSE=true
X    NEWSGROUP=any
X    cat >$TF.f
X    FILE=$TF.f
X    FILENAME="standard input"
X    ;;
1)
X    if [ -f "$1" ]; then
X	VERBOSE=true
X	NEWSGROUP=any
X	FILE="$1"
X	FILENAME="$1"
X    else
X	cat >$TF.f
X	FILE=$TF.f
X	FILENAME="standard input"
X	NEWSGROUP="$1"
X    fi
X    ;;
2)
X    NEWSGROUP="$1"
X    FILE="$2"
X    FILENAME="$2"
X    ;;
*)
X    echo >&2 "Usage: $0 [newsgroup|user] [article]"
X    echo >&2 "       newsgroup may be "any" to check all signatures."
X    exit 1
X    ;;
esac
X
# Find all the authentication headers we can handle
grep -i '^X-Auth.*:  *PGPMoose ' $FILE | \
X    sed -e 's/.* //' >$TF.g
X
# For the time being, simply avoid cancel messages.
# Note that pmdaemon authenticates them, but you probably don't
# want to cancel them.
if grep -i -s '^Control:[ 	]*cancel' $FILE >/dev/null; then
X    rm -f $TF.?
X    exit 0
fi
X
# The designated newsgroup must be validated.
if [ "x$NEWSGROUP" != "xany" ]; then
X    grep -i -s "^$NEWSGROUP\$" $TF.g >/dev/null || {
X	echo >&2 "$0: Posting for $NEWSGROUP not approved with PGP Moose."
X	rm -f $TF.?
X	exit 1
X    }
X    # Uncomment this line if you only want to check this one group
X    echo "$NEWSGROUP" >$TF.g
fi
X
# Make the document we are going to check signatures on.
pmcanon $FILE >$TF.m
X    
# Loop checking all X-Auth: lines required
echo 0 >$TF.b
while read GROUP; do
X    # Check whether this is an interesting X-Auth: line.
X    # This is determined by the existence of the $ACCEPT file.
X    # If it exists, only the groups/individuals mentioned are
X    # relevent. Otherwise, check everything in sight, but don't
X    # worry if you can't find a key or the signature doesn't match.
X    # CONTROLLED is 0 if there is a $ACCEPT file and this group/user is
X    # in it.
X    [ -f "$ACCEPT" ] && grep -i -s "^$GROUP[ 	]" "$ACCEPT" >/dev/null
X    CONTROLLED=$?
X    if [ "$CONTROLLED" != 0 -a "$NEWSGROUP" != "any" ]; then
X	continue
X    fi
X    # $1      $2       $3   $4  $5
X    # X-Auth: PGPMoose V1.1 PGP sci.crypt.research
X    set -- `grep -i "^X-Auth.*:  *PGPMoose .* $GROUP\$" $FILE`
X
X    # Check for version mismatch, but at the moment we just warn.
X    # It is pretty hard to know just what to do in this case.
X    if [ "$3" != "V1.1" -o "$4" != "PGP" ]; then
X	echo >&2 "$0: warning: version mismatch V1.0 PGP != $3 $4"
X    fi
X
X    # reconstruct the input signature file.
X    cat <<-END_OF_SIG >$TF.s
X	-----BEGIN PGP MESSAGE-----
X	Version: 2.6
X
X	END_OF_SIG
X    sed -n -e "1,/^[Xx]-[Aa][Uu][Tt][Hh].*:  *PGPMoose .* $GROUP\$/d" \
X	-e '/^ *$/,$d' \
X	-e '/^[^ 	]/,$d' \
X	-e 's/^[ 	]*//p' \
X	$FILE >>$TF.s
X    cat <<-END_OF_SIG >>$TF.s
X	-----END PGP MESSAGE-----
X	END_OF_SIG
X
X    # Now we can check the signature.
X    pgp +BATCHMODE=on -t $TF.s $TF.m </dev/null >$TF.e 2>&1
X    STATUS=$?
#    cat >&2 $TF.s 
#    echo ====
#    cat >&2 $TF.m 
#    echo ====
#    cat >&2 $TF.e 
X
X    # If this is a target newsgroup/user, any error is bad news.
X    if [ "$CONTROLLED" = 0 -a $STATUS != 0 ]; then
X	echo >&2 "$0: Invalid designated signature from $GROUP"
X	echo 2 >$TF.b
X	continue
X    fi
X    # There are various understood error codes, not to mention the others...
X    # These codes come from the PGP source, and are probably not immutable.
X    case "$STATUS" in
X    0)
X	# signature checks out... handle that case below
X	;;
X    11)
X	# Non-existent key
X	if [ "$VERBOSE" = true ]; then
X	    echo "No public key for signature $GROUP"
X	fi
X	continue
X	;;
X    30)
X	# Signature check error
X	$VERBOSE || echo >&2 "Signature doesn't match $FILE for $GROUP"
X	echo 2 >$TF.b
X	continue
X	;;
X    *)
X	# Some other unknown error. Treat same as Non-existent key.
X	if [ "$VERBOSE" = true ]; then
X	    echo "Unknown PGP error, status = $STATUS"
X	    cat $TF.e
X	fi
X	continue
X	;;
X    esac
X
X    SIG=`sed -n 's/Good signature from user "\(.*\)"./\1/p' $TF.e`
X    if [ "x$SIG" = "x" ]; then
X	# this one "can't happen"
X	echo >&2 "$0: MOOSE ERROR: Invalid signature for $GROUP on $FILE."
X    fi
X    if [ "$VERBOSE" = "true" ]; then
X	echo "$0: Verified signature from '$SIG'."
X    fi
X
X    # Finally, was it signed by the right person?
X    if [ "$CONTROLLED" = 0 ]; then
X	grep -i -s "^$GROUP[	 ]*$SIG\$" "$ACCEPT" >/dev/null || {
X	    echo >&2 "$0: '$SIG' not accepted for $GROUP."
X	    echo 2 >$TF.b
X	}
X    fi
done <$TF.g
X
BADSIG=`cat $TF.b`
rm -f $TF.?
exit $BADSIG
SHAR_EOF
  $shar_touch -am 0307185997 'pmcheck' &&
  chmod 0555 'pmcheck' ||
  $echo 'restore of' 'pmcheck' 'failed'
  if ( md5sum --help 2>&1 | grep 'sage: md5sum \[' ) >/dev/null 2>&1 \
  && ( md5sum --version 2>&1 | grep -v 'textutils 1.12' ) >/dev/null; then
    md5sum -c << SHAR_EOF >/dev/null 2>&1 \
    || $echo 'pmcheck:' 'MD5 check failed'
8148927486c7d9f3b8b376432a7372a1  pmcheck
SHAR_EOF
  else
    shar_count="`LC_ALL= LC_CTYPE= LANG= wc -c < 'pmcheck'`"
    test 4777 -eq "$shar_count" ||
    $echo 'pmcheck:' 'original size' '4777,' 'current size' "$shar_count!"
  fi
fi
# ============= pmnewsgroups ==============
if test -f 'pmnewsgroups' && test "$first_param" != -c; then
  $echo 'x -' SKIPPING 'pmnewsgroups' '(file already exists)'
else
  $echo 'x -' extracting 'pmnewsgroups' '(text)'
  sed 's/^X//' << 'SHAR_EOF' > 'pmnewsgroups' &&
#!/bin/sh
X
# @(#)pmnewsgroups	1.3 (PGP Moose) 95/11/13
# Return sorted list of newsgroups in message
sed -n -e '/^[Nn][Ee][Ww][Ss][Gg][Rr][Oo][Uu][Pp][Ss]:/,/^[^ 	]/p' \
X	-e '/^[ 	]*$/q' \
X	$* \
X    | sed -e 's/^[Nn][Ee][Ww][Ss][Gg][Rr][Oo][Uu][Pp][Ss]:[ 	]*/ /' \
X	-e '/^[^ 	]/d' \
X	-e 's/^[ 	]*//' \
X	-e 's/[ 	]*$//' \
X	-e 's/,[ 	]*/\
/g' \
X    | tr "[A-Z]" "[a-z]" \
X    | sort \
X    | sed -e '/^[ 	]*$/d'
SHAR_EOF
  $shar_touch -am 0307185997 'pmnewsgroups' &&
  chmod 0555 'pmnewsgroups' ||
  $echo 'restore of' 'pmnewsgroups' 'failed'
  if ( md5sum --help 2>&1 | grep 'sage: md5sum \[' ) >/dev/null 2>&1 \
  && ( md5sum --version 2>&1 | grep -v 'textutils 1.12' ) >/dev/null; then
    md5sum -c << SHAR_EOF >/dev/null 2>&1 \
    || $echo 'pmnewsgroups:' 'MD5 check failed'
52e7fb81102d7386a863cc1898bb840f  pmnewsgroups
SHAR_EOF
  else
    shar_count="`LC_ALL= LC_CTYPE= LANG= wc -c < 'pmnewsgroups'`"
    test 409 -eq "$shar_count" ||
    $echo 'pmnewsgroups:' 'original size' '409,' 'current size' "$shar_count!"
  fi
fi
rm -fr _sh18929
exit 0
