[news.software.b] Cnews remote execution

sater@cs.vu.nl (Hans van Staveren) (12/05/89)

The support in the Cnews distribution for networked systems assumes
the rsh command for remote calling of relaynews. If you NFS mount
your /usr/spool/news from a machine where people are not allowed to
execute commands, it would be much nicer if you could easily set it
up to use NNTP to post articles.

Is there already a standard way to set this up or should I figure it
out myself?

	Hans van Staveren

henry@utzoo.uucp (Henry Spencer) (12/07/89)

In article <4719@sater.cs.vu.nl> sater@cs.vu.nl (Hans van Staveren) writes:
>The support in the Cnews distribution for networked systems assumes
>the rsh command for remote calling of relaynews. If you NFS mount
>your /usr/spool/news from a machine where people are not allowed to
>execute commands, it would be much nicer if you could easily set it
>up to use NNTP to post articles...

It's not something we provide for at the moment.  We basically don't
consider ourselves to be in the NNTP-support business, so we haven't
gotten too involved with it.  Possibly the simplest method would be to
arrange a mailing address on the forbidden machine which feeds into
the news system.
-- 
1233 EST, Dec 7, 1972:         |     Henry Spencer at U of Toronto Zoology
last ship sails for the Moon.  | uunet!attcan!utzoo!henry henry@zoo.toronto.edu

lamy@ai.utoronto.ca (Jean-Francois Lamy) (12/07/89)

sater@cs.vu.nl (Hans van Staveren) writes:
>						If you NFS mount
>your /usr/spool/news from a machine where people are not allowed to
>execute commands, it would be much nicer if you could easily set it
>up to use NNTP to post articles...

henry@utzoo.uucp (Henry Spencer) writes:
>gotten too involved with it.  Possibly the simplest method would be to
>arrange a mailing address on the forbidden machine which feeds into
>the news system.

We are exactly in that position here (the news partition is mounted by 140
machines in 7 (closely knit but independent) subdomains.  The following script
is what we use as both the "inews" invoked by the NNTP server and as the
script invoked by a "feednews" mail alias.  The inews on the clients is the
NNTP inews (modified to make sure that a Path: header is added if missing).
All postings actually take place on the news server and the script tries
to handle moderated newsgroups properly wrt return addresses and the like.

Jean-Francois Lamy               lamy@ai.utoronto.ca, uunet!ai.utoronto.ca!lamy
AI Group, Department of Computer Science, University of Toronto, Canada M5S 1A4
------------------------------------------------------------------------------
#! /bin/sh
#
# server.inews 
#
#   Post article read on stdin.  Arguments are ignored. 
#   Meant to be invoked by an NNTP server or by a sendmail/zmailer alias (e.g.
#   feednews: "|/news/bin/server.inews" ).  Mail headers inappropriate for
#   news will be stripped/transformed appropriately.
#
#   The message is mailed to moderators of moderated newsgroups mentioned on
#   the Newsgroups: line, unless a proper Approved: line is seen, in which
#   case we post directly.  We post to non-moderated newsgroups, and deal with
#   Control: messages appropriately.
#
#   We assume that the From: line can be trusted.  A Path: line will be
#   trusted if present.  If not, one will be made up from mail information
#   if available, and used unless posting an approved message to a moderated
#   newsgroup (since that would prevent the posting site from seeing it).
#   The path data will also set the error-return address of the message,
#   for better or for worse.
#
# remotely derived from code by Geoff Collyer, C news alpha release
# heavily(!) reworked for CSRI/ANT environment by Jean-Francois Lamy
#	(lamy@ai.utoronto.ca)
#exec >> /tmp/jfl 2>&1
#echo ''
#date

# =()<. ${NEWSCONFIG-@<NEWSCONFIG>@}>()=
. ${NEWSCONFIG-/news/bin/config}

PATH=/local/bin:$NEWSCTL/bin:$NEWSBIN:$NEWSBIN/relay:$NEWSPATH
export PATH
umask $NEWSUMASK

# fix according to your site.
hostname=`hostname`		# the usenet name of your site
host="$hostname.toronto.edu"    # if $hostname is not absolute
date=`date`
defdate="`set \`date -u\`; echo $3 $2 \`echo $6 | sed 's/^..//'\` $4 $5`"
defmsgid="`set $date; echo \<$6$2$3.\`echo $4 | tr -d :\`.$$@$host\>`"

input=/tmp/in$$in      	# uncensored input
inhdrs=/tmp/in$$hdr	# headers after censoring
inbody=/tmp/in$$body	# body after message
censart=/tmp/in$$cens   # article with censored headers
nglist=/tmp/in$$act	# active file entries for newsgroups
indefs=/tmp/in$$defs	# shell variable definitions, extracted from message.
logfile=/news/log/inews.log
rmlist='/tmp/in'$$'*'

# programs
relaynews="relaynews -r"
sendmail='/usr/lib/sendmail -t'	# articles plainly mailed to moderators
grep=ngrep
modgrep=egrep	# use look if $NEWSCTL/mailpaths file is kept sorted.
		# (remove blank and tab in regular expression used below)

trap 'rm -f $rmlist; echo '.' >>$logfile' 0 1 2 3 15  # don't leave a mess.
echo -n $date \[$$\] \(`whoami`\) >> $logfile

# capture incoming news in case inews fails
   if cat >>$input; then
      : got it.
   else
      echo "$0: lost news; cat returned status $?" >&2
      exit 1
   fi

echo -n "; " >>$logfile

# Separate header from body, mangling headers as we go.
awk '
    # pass 1 - note presence | absence of certain headers, store body.
    BEGIN		{ body = 0 ; skipping = 0 ; received = 0 }
    body == 1		{ print > "'$inbody'" ; next }
    /^[ \t]*$/		{ body = 1 ; print > "'$inbody'" ; next }

    # don-t bother with various mail headers
    /^To:|^X-To:|^Cc:|^Bcc:|^Apparently-To:|^Original-To:/ {skipping = 1 ; next }
    /^Resent-*:/	{ skipping = 1; next }
    # Normally only one of the following would be present (Path: if coming via
    # NNTP, From_ via mail.  Return-Path is unlikely).
    /^From /		{ hdrval["Path:"] = $2 ; next }
    /^Return-Path:/	{ hdrval["Path:"] = $2 ; next }
    /^Path:/		{ hdrval["Path:"] = $2 ; next }
    /^Message-Id:/	{ $1 = "Message-ID:" }

    # a header keyword: remember it and its value.
    /^[^\t ]*:/ { skipping = 0; received = 0 ; keyword=$1 ;
		  if ( hdrval[$1] == "" )
		      hdrval[$1] = $0
		  else # some headers can be repeated
		      hdrval[keyword] = hdrval[keyword] "\n" $0 }
    # a continuation: concatenate this line to the value
    !/^[^\t ]*:/ { if ( ! skipping )
			hdrval[keyword] = hdrval[keyword] "\n" $0 }
    # pass 2 - deduce & omit & emit headers
    END {
	    subj = "Subject:";		path = "Path:"         
	    ctl = "Control:";		date = "Date:"         
	    ng = "Newsgroups:";		from = "From:"         
	    msgid = "Message-ID:";	org = "Organization:"  
	    typo =  "Message-Id:";	distr = "Distribution:"
	    rcvd = "Received:";		appr = "Approved:"     

	    # fill-in some headers
	    if (hdrval[msgid] == "")
		    hdrval[msgid] = msgid " " "'"$defmsgid"'"
	    # force GMT format
	    hdrval[date] = date " " "'"$defdate"'"

	    # nuke others
	    distworld = distr " world"
	    if (hdrval[distr] == distworld)
		    hdrval[distr] = ""

	    # turn Subject: cmsg into a proper Control: header.
	    if (substr(hdrval[subj],1,14) == "Subject: cmsg ") {
		hdrval[ctl] = ctl " " substr(hdrval[subj],15)
		hdrval[subj] = substr(hdrval[subj],1,9) substr(hdrval[subj],15)
	    }

	    # warn if no Newsgroups:
	    if (hdrval[ng] == "")
		    print "'$0': no Newsgroups: header." | "cat >&2"
	    else {
		    print "allngs=" q hdrval[ng] q > "'$indefs'"
		    hdrval[ng] = ""
	    }

	    # write out various header values so the shell can read them
	    if (hdrval[ctl] != "") {
		    print "ctrl=" q hdrval[ctl] q > "'$indefs'"
		    hdrval[ctl] = ""
	    }
	    if (hdrval[path] != "") {
		    print "path=" q hdrval[path] q > "'$indefs'"
		    hdrval[path] = ""
	    }
	    if (hdrval[appr] != "") {
		    print "appr=" q hdrval[appr] q > "'$indefs'"
	    }
	    if (hdrval[rcvd] != "") {
		    print "rcvd=" q hdrval[rcvd] q > "'$indefs'"
		    hdrval[rcvd] = ""
	    }

	    # Output headers common to news and mail, starting with From:
	    if (hdrval[from] != "") {
		    print hdrval[from]
		    hdrval[from] = ""
	    }
	    # have pity on readers: put Subject: next
	    if (hdrval[subj] != "") {
		    print hdrval[subj]
		    hdrval[subj] = ""
	    }
	    # print misc. headers in random order, unless they are empty.
	    for (i in hdrval)
		    if (hdrval[i] != "" && hdrval[i] != i " ")
			    print hdrval[i]
    }
    ' q=\' $input > $inhdrs

# swallow what we've just learned in the awk script
. $indefs
echo -n $path: $allngs >> $logfile

# produce list of newsgroups for validation purposes
if test "$ctrl" ; then
	echo "control" > $nglist	# a dreadful hack around all.all.ctl
else
        # keep only newsgroups in active; something else ought to have
        # complained about that by now.
	egrep "^(` echo $allngs | sed		\
	       -e 's/^Newsgroups:[ 	]*//' 	\
	       -e 's/ //'			\
	       -e 's/\./\\\\./g' 		\
	       -e 's/+/\\\\+/g'			\
               -e 's/,/ |/g'			\
               -e 's/$/ /'`)" $NEWSCTL/active >$nglist
fi

# sift through newsgroups, gathering moderators
# Whether cross-posting to several mailing lists is allowed
# is a matter of local policy; uncomment code near end of loop to prevent.
exec < $nglist
while read ng high low flag ; do
    ngbak=$ng
    case "$flag" in
    y)
        newsgroups=${newsgroups+$newsgroups,}$ng
        ;;
    m)
        if test "$appr" ; then
            # just post normally
            newsgroups=${newsgroups+$newsgroups,}$ng
        else 
            # no Approved: add moderator to list of mail recipients
            while true ; do
                r=`$modgrep "$ng[ 	]" $NEWSCTL/mailpaths`
                if test "$r" ; then
                    set $r
                    moderator=$2
                    break
                elif test "$ng" != "internet" ; then
			# people should just have "all %s@sitename", but since
			# the docs posted to news.admin talk about backbone and
			# internet, we suffer through that too.
                        ng=`echo $ng|sed -e 's/.*\..*/&all/' \
					 -e 's/^all$/backbone/' \
					 -e 's/^backbone$/internet/'`
		else
		        echo "$0: no moderator found for '$ng'" >&2
	                exit 64 # bad usage message.
                fi
	    done

	    # field the %s feature
	    ngbak=`echo $ngbak | tr '.' '-'`
	    moderator=`echo $moderator | sed -e "s/%s/$ngbak/"`
            modroute=${modroute+$modroute,}$moderator

	    # enforce restricted usage (mail to first moderator, don't post
	    # article to normal newsgroups). Uncomment next two lines to use.
	    # newsgroups=""
	    # break
        fi
	;;
    n|*)
        if test "$ctrl" ; then
	    newsgroups=`echo $allngs|sed -e 's/Newsgroups:[ 	]*//'`
	else
            echo "$0: Posting to $ng is not allowed." >&2
            exit 64   # sendmail/Zmailer "bad usage" message
        fi
        ;;
    esac
done

if [ "$newsgroups" ] ; then
    # cook-up the news-specific headers.  Path: is omitted if we are
    # posting to a moderated newsgroup, as this would prevent the site
    # it was mailed from from seeing the message in the newsgroup.
    if test "$appr" ; then
        if test "$ctrl" ; then
	    :
	else
	    path="devnull"
	fi
    fi
    cat - $inhdrs <<EOF |
${ctrl}${ctrl:+
}${path:+Path: }${path:+$path}${path:+
}Newsgroups: $newsgroups
EOF
    # final header sanitization (no route format in From:, no tabs after :)
    # append body, strip invisible chars.  Strip our host name from path, else
    # articles posted here will not get shown.
    sed -e '/^Path: /s/.*'$hostname'[^!]*!//' \
        -e 's/^From:[ 	]*\(.*\)  *<\(.*\)>/From: \2 \(\1\)/' \
	-e 's/:[ 	]*/: /' \
	-e "\$r $inbody" |
    tr -d '\1-\7\13\14\16-\37' >$censart

    if $relaynews <$censart
    then
       echo -n " relaynews ok" >> $logfile
    else
       status=$?
       echo "$0: article could not be posted (relaynews status $status)" >&2
       echo "$0: failed news in `hostname`:$input " >&2
       echo " relaynews status $status" >> $logfile
       exit $status
    fi
fi

if [ "$modroute" ] ; then
    # mail article to the moderator(s).
    cat - $inhdrs <<EOF |
${rcvd:+$rcvd}${rcvd:+
}To: ${modroute}
EOF
    # final header sanitization (no route format in From:, no tabs after :)
    # strip message id so cross-postings between a newsgroup and a gatewayed
    # mailing lists show up in both places
    # append body, strip invisible chars, push to mailer.
    sed -e 's/^From:[ 	]*\(.*\)  *<\(.*\)>/From: \2 \(\1\)/' \
	-e 's/:[ 	]*/: /' \
	-e '/^Message-ID:/d' \
	-e "\$r $inbody" |
    tr -d '\1-\7\13\14\16-\37' >$censart
    $sendmail -f$path <$censart
    echo -n " resent to '$modroute'" >>$logfile
fi

pst@anise.acc.com (Paul Traina) (12/08/89)

lamy@ai.utoronto.ca (Jean-Francois Lamy) writes:
>We are exactly in that position here (the news partition is mounted by 140
>machines in 7 (closely knit but independent) subdomains.  The following script
>is what we use as both the "inews" invoked by the NNTP server and as the
>script invoked by a "feednews" mail alias.  The inews on the clients is the
>NNTP inews (modified to make sure that a Path: header is added if missing).
>All postings actually take place on the news server and the script tries
>to handle moderated newsgroups properly wrt return addresses and the like.

[ post of server.inews deleted ]

The version Jean-Francois's server inews that I had been using (*not*
necessarily what he just posted) had some problems and shortcomings that
were really difficult to deal with (among other things, I use Erik Fair's
gateway software).  Finally I gave up and looked to see what had to be done
to get the normal inews to work properly.  I replaced his server.inews with the
following script:

#!/bin/sh
# server_inews - set some things so C inews doesn't mess up with ttys et al.

# =()<. ${NEWSCONFIG-@<NEWSCONFIG>@}>()=
. ${NEWSCONFIG-/usr/lib/news/bin/config}

HOME=$NEWSCTL
LOGNAME=news
NAME="USENET news"
export HOME LOGNAME NAME

exec $NEWSBIN/inject/inews -W $*

This script will call the normal Cnews inews program -- it will support all
of the command line options that inews handles.  By setting LOGNAME, NAME,
and HOME, we manage to avoid all of inews' crufty interactive checks (which
assume that the executor of inews is a person and is on a tty).

This script has been in heavy use for over 3 months.  I discussed some other
things with Geoff and he has made the following changes to inews so it will
accurately return message status.  The changes to inews are not necessary,
but I feel they should be made for better error reporting.  The next version
of inews will have these modifications built in. (Right Geoff?)

Change the "waitcmd=''" line at the start of inews to:

waitcmd='status=0'

Modify the -W) flag processing line to read:

	-W)	waitcmd='wait; status=$?' ;;		# wait for completion

And make sure the end of your inews script looks like this:

.
.
.
esac
exit $status				# trap 0 may cleanup, make dead.article
) &
eval $waitcmd				# wait & get status if -W given
trap 0					# let the background run on unmolested
exit $status

This will insure that inews will exit with the proper error conditions instead
of always exiting with a return condition of 0.
--
"I don't know that atheists should be considered citizens, nor should they
 be considered patriots.  This is one nation under God." -- George Bush
"The government of the United States is not, in any sense, founded
 on the Christian religion."				 -- George Washington