[comp.sources.unix] v20i023: Deliver, flexible email delivery system, Part01/04

rsalz@uunet.uu.net (Rich Salz) (10/16/89)

Submitted-by: Chip Salzenberg <chip@ateng.com>
Posting-number: Volume 20, Issue 23
Archive-name: deliver2.0/part01

Deliver is a program which delivers electronic mail once it has arrived
at a given machine.  It is intended for use in three environments:
    1.  Any Xenix system.
    2.  Any Unix system with smail 2.x.
    3.  Any Unix system with either sendmail or smail 3.x.

If you have been frustrated by inflexible E-Mail delivery, here is your
salvation.  Deliver permits complete control over mail delivery through
the use of "delivery files."  Delivery files are shell scripts which are
executed during message delivery.  These shell scripts -- written by you!
-- control who, if anyone, gets each E-Mail message.

Mostly, Deliver 2.0 is an incremental enhancement from Deliver 1.0.8.  New
features include:
    1.  Parsing of the From_ line.  Badly formed From_ lines, including
        those with illegal dates, are rejected.  Messages with invalid From_
        lines are still delivered, but the contents the From_ line is
	put into an Invalid-UUCP-From: line.

    2.  The "header" program, which parses RFC822 headers.  Besides its
        obvious utility in delivery files, header should prove quite useful
        for scanning Usenet directories.

    3.  Sample delivery files, including the often-requested vacation
	"answering machine".

-- 
Chip Salzenberg                   <chip@ateng.com> or <uunet!ateng!chip>
A T Engineering                     "Designed with your mind in mind."

#! /bin/sh
# This is a shell archive.  Remove anything before this line, then unpack
# it by saving it into a file and typing "sh file".  To overwrite existing
# files, type "sh file -c".  You can also feed this as standard input via
# unshar, or by typing "sh <file", e.g..  If this archive is complete, you
# will see the following message at the end:
#		"End of shell archive."
# Contents:  README deliver.8 Makefile uid.c header.c getopt.c samples
#   samples/README samples/p-aliases samples/s-aliases samples/u-chip
#   samples/u-vacation
PATH=/bin:/usr/bin:/usr/ucb ; export PATH
if test -f 'README' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'README'\"
else
echo shar: Extracting \"'README'\" \(2335 characters\)
sed "s/^X//" >'README' <<'END_OF_FILE'
X$Header: README,v 2.1 89/06/09 12:25:10 network Exp $
X
X
X                             WHAT IS DELIVER?
X
X
XDeliver is a program which delivers electronic mail once it has arrived
Xat a given machine.
X
X
X
X                              WHO CAN USE IT?
X
X
XDeliver is intended for use in three environments:
X
X
X    1.  Any Xenix system.
X
X        Deliver was invented to be a direct replacement for the Xenix
X        program /usr/lib/mail/mail.local.  In fact, on ateng, mail.local is
X	just another link to /usr/bin/deliver.
X
X
X    2.  Any Unix system with smail 2.x.
X
X        You can use deliver for local mail by changing the local mailer
X        definition in config.h:
X	    #define LMAIL(frm)      "/usr/bin/deliver -r '%s'",frm
X
X
X    3.  Any Unix system with either sendmail or smail 3.x.
X
X	Any user can let deliver handle all his mail by putting the
X	following line in his .forward file:
X	    "|/usr/bin/deliver username"
X	Be sure to specify the correct username, or someone else will
X	get your mail!
X
X
X
X                                PORTABILITY
X
X
XDeliver has been compiled and tested under SCO Xenix System V/286 and 4.3
XBSD.  The configuration provides for System V, but I have not been able to
Xtest it. (Patches for all environments are welcome; see below.)
X
X
X
X			   WARNINGS: BE CAREFUL!
X
X
X    1.  Deliver is intended to be run setuid root; otherwise it would not
X        be possible to execute a user delivery file in the context of its
X        owner.  Any setuid root program is a potential security hole!  Be
X        careful of the modes on the deliver binary and the directory where
X        it lives.
X
X    2.  Deliver's flexibility makes it easy to lose lots of mail through
X	carelessness in configuration.  Delivery files should be written
X	with extreme care.
X
X
X
X                          COMPILING AND INSTALLING
X
X
XEdit the Makefile and config.h to taste.  Type "make".  To install, type
X"make install".  See the Makefile for further hints.
X
X
X
X			    HELP SAVE THE WORLD!
X
X
XIf you run into a bug, you are probably not alone.  Save your fellow human
Xbeings from toil and trouble!  Send mail to <bugs-deliver@ateng.uucp>.  Bug
Xreports accepted; patches greatly appreciated.  I will coordinate patches.
X
XThank you, and good night.
X
X	Chip Salzenberg
X	A T Engineering
X
X	<chip@ateng.uucp> or
X	<chip@ateng.uu.net> or
X	<uunet!ateng!chip>
END_OF_FILE
if test 2335 -ne `wc -c <'README'`; then
    echo shar: \"'README'\" unpacked with wrong size!
fi
# end of 'README'
fi
if test -f 'deliver.8' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'deliver.8'\"
else
echo shar: Extracting \"'deliver.8'\" \(11359 characters\)
sed "s/^X//" >'deliver.8' <<'END_OF_FILE'
X.\" $Header: deliver.8,v 2.1 89/06/09 12:25:19 network Exp $
X.\"
X.\" Man page for deliver.
X.\"
X.\" $Log:	deliver.8,v $
X.\" Revision 2.1  89/06/09  12:25:19  network
X.\" Update RCS revisions.
X.\" 
X.\" Revision 1.8  89/06/09  12:23:42  network
X.\" Baseline for 2.0 release.
X.\" 
X.TH DELIVER 8
X.SH NAME
Xdeliver \- deliver local mail
X.SH SYNOPSIS
X.B deliver
X[ options ] address ...
X.SH DESCRIPTION
XThe
X.I deliver
Xprogram collects a mail message from the standard input and delivers it.
XIt is intended to take over the delivery of all local mail, a job usually
Xhandled by
X.I /bin/mail
X(System V),
X.I /usr/lib/sendmail
X(BSD), or
X.I /usr/lib/mail/mail.local
X(Xenix).
X.PP
X.I deliver
Xintroduces flexibility in the handling of local mail delivery.  All files
Xused to control
X.I deliver
Xare Bourne shell scripts.  Thus anything that can be called by a shell
Xscript can be used to control mail delivery.
X.SH OPTIONS
X.TP
X.B \-b
XInterpret all arguments as mailbox filenames instead of addresses.  Note
Xthat the user running
X.I deliver
Xmust have write permissions on the given mailbox files.  He may also need
Xwrite permissions on their parent directories, depending on the existence
Xof the mailbox file and the local locking protocol.
X.TP
X.B \-n
XInterpret arguments as addresses, but do not run any delivery files; simply
Xdeliver the message to the mailbox(es) of the given user(s).  This option is
Xmost useful when
X.I deliver
Xis executed recursively, since it prevents further recursion.
X.TP
X.B \-A
XPrint resolved addresses; do not deliver the message.  Note that
X.I deliver
Xstill collects a message from the standard input, since delivery files may
Xdo different things depending on message content.  For simple testing,
Xredirect standard input from /dev/null.
X.TP
X.B \-d
XBe verbose; don't deliver to any mailboxes or catch any signals.
X.TP
X.B \-v
XBe verbose, but still deliver.
X.TP
X.B \-t
XDo not remove temporary files before exiting.
X.TP
X.BI \-r " sender"
XPut
X.I sender
Xon the generated From_ line.  Default is to use the address on the From_
Xline in the input, or else the name corresponding to the real uid, or else
X"unknown".
X.TP
X.BI \-h " hostname"
XSet the host name.  The default is configuration dependent.
X.TP
X.BI \-s " system delivery file"
XSpecify an alternate system delivery file.  The default is
X.I /usr/local/lib/deliver.sys.
XFor security reasons, this option disables setuid privileges.
X.TP
X.BI \-p " post-user delivery file"
XSpecify an alternate post-user delivery file.  The default is
X.I /usr/local/lib/deliver.post.
XFor security reasons, this option disables setuid privileges.
X.TP
X.BI \-u " user delivery file"
XSpecify an alternate user delivery file.  The default is
X.I .deliver
X(in each user's home directory).
XFor security reasons, this option disables setuid privileges.
X.PP
XAll command line options are put into environment variables, examined by
X.I deliver
Xon startup; thus all flags are propagated when
X.I deliver
Xis invoked recursively.
X.SH ENVIRONMENT
XFor mail systems based on
X.I smail
X2.x, the LMAIL (local mailer) macro can be changed to call
X.I deliver.
XFor mail systems based on
X.I smail
X3.x or
X.I sendmail,
Xa similar arrangement may be made; or individual users can invoke
X.I deliver
Xby mentioning it in their
X.I .forward
Xfiles.
X.PP
XFor Xenix systems,
X.I deliver
Xmay be used as a direct replacement for
X.IR /usr/lib/mail/mail.local.
X.PP
XFor stock Unix systems, it may be possible to make
X.I /bin/rmail
Xa link to
X.I deliver;
Xhowever, this configuration has not been tested and is not recommended.
XAny postmaster motivated enough to install
X.I deliver,
Xand who wants something better than the standard
X.I /bin/rmail,
Xshould install
X.I smail.
X.SH OPERATION
XBy default,
X.I deliver
Xdeposits mail in the system mailbox for the named user(s).  Also, as a
Xnecessity for use with
X.I smail
X2.x,
X.I deliver
Xalso understands UUCP-style bang addresses well enough to forward the
Xmessage correctly, using
X.I uux.
X.PP
XHowever, this basic behavior only scratches the surface: the usefulness of
X.I deliver
Xderives from its flexibility; its behavior can be made to depend on the
Xrecipient(s), content or any other aspect of mail messages.
X.PP
XWhen
X.I deliver
Xstarts execution, it interprets its arguments in one of three ways.  If the
X.B \-b
X(mailbox) option was specified, then all arguments are interpreted as
Xmailbox pathnames.  Otherwise, if a system delivery file exists and the
X.B \-n
X(no delivery files) option was not specified,
X.I deliver
Xexecutes the system delivery file with all of deliver's arguments
Xas its arguments.
X.I deliver
Xinterprets the delivery file's output as described below.  This procedure
Xgives the postmaster control over delivery to non-existent hosts and users.
XIf the
X.B \-n
Xoption is specified or if there is no system delivery file,
X.I deliver
Xinterprets all its arguments as mail addresses.
X.PP
XAfter possibly executing the system delivery file,
X.I deliver
Xlooks in its list of destinations for valid user names without explicitly
Xnamed mailboxes.  If any of these users have user delivery files in
Xtheir home directories, and if the
X.B \-n
Xoption was not specified,
X.I deliver
Xexecutes each user delivery file with the name of the given user as its
Xonly argument.
X.PP
XAfter executing any user delivery files,
X.I deliver
Xlooks in its list of destinations for simple user names and UUCP
Xaddresses.  If any are found, if the post-user delivery file exists,
Xand if the
X.B \-n
Xoption was not specified,
X.I deliver
Xexecutes the post-user delivery file with these addresses as its arguments.
X.SH "DELIVERY FILES"
XDelivery files are shell scripts.  They are executed by
X.I deliver
Xto control delivery to users.  Note that delivery files do
X.I not
Xcontrol delivery to explicitly named mailboxes.
X.PP
XOn each system the postmaster may create a
X.I system delivery file
Xto controls delivery of all messages.
XThe system delivery file, if it exists, is executed
Xwith the name(s) specified on the
X.I deliver
Xcommand line as its arguments.
X.PP
XThe postmaster may also create a
X.I post-user delivery file
Xwhich is executed after any user delivery files, but before delivery of the
Xmessage to any mailboxes.  This file is particularly useful for implementing
Xsystem-wide aliases, since it can deal with addresses generated by user
Xdelivery files, whereas the system delivery file cannot.
X.PP
XFinally, each user may create a
X.I user delivery file
Xin his home directory.  User delivery files are always executed with exactly
Xone argument: the name of the user in whose home directory the file is
Xfound.
X.PP
XRecursive execution of
X.I deliver
Xis useful, especially with the
X.B \-b
X(mailbox) and
X.B \-n
X(no delivery files) flags.  For example, a user may wish to transform a
Xmessage body before it is stored in a mailbox.  This may be done with a user
Xdelivery file and recursive execution of
X.I deliver.
XFor example, the following user delivery file translates all incoming
Xmessage bodies to lower case, and stores them in the user's default mailbox:
X.TP
X(cat $HEADER; tr '[A-Z]' '[a-z]' <$BODY) | deliver -n "$1"
X.PP
XWhen
X.I deliver
Xexecutes a delivery file, it sets several environment variables, listed
Xbelow.
XNote that these environment variables are both set and used by
X.I deliver;
Xtherefore, all command line options automatically propagate when
X.I deliver
Xis run recursively (within a delivery file).  The environment variable
Xnames set and used by
X.I deliver
Xare:
X.TP
X.B DELFLAGS
XThe command line flags, if any, specified on the
X.I deliver
Xcommand line.
X.TP
X.B SYSDELFILE
XThe system delivery filename.
X.TP
X.B POSTDELFILE
XThe post-user delivery filename.
X.TP
X.B USERDELFILE
XThe user delivery filename, relative to the home directory of each user.
X.TP
X.B HOSTNAME
XThe local host name, either the real hostname or a name specified with the
X.B \-h
Xoption to
X.I deliver.
X.TP
X.B SENDER
XThe sender, either an address specified with
X.B \-r
Xoption to
X.I deliver,
Xor the address given in the From_ line of the message, or the user who
Xinvoked
X.I deliver.
X.TP
X.B HEADER
XThe name of the temporary file containing the message header.
X.TP
X.B BODY
XThe name of the temporary file containing the message body.
X.PP
X.I deliver
Xmonitors the standard output of delivery files for lines of two forms:
Xeither "user" or "user:mailbox".  Those users whose names appear in the
Xoutput of a delivery file will receive the message.  If a mailbox name
Xappears after the user name, then that mailbox receives the message.  If a
Xmailbox name is not specified, the user's default mailbox is used. (The
Xdefault mailbox for a user is configuration-dependent.) If a mailbox is not
Xan absolute pathname, it is interpreted relative to the home directory of
Xthe named user.
X.PP
X.B NOTE 1:
XWhen
X.I deliver
Xexecutes a delivery file, it expects that delivery file to explicitly name
Xall users (and, optionally, mailboxes) where the message should be
Xdelivered.  If a delivery file does not name any users in its output, then
Xthe message will not be delivered to anyone whose mail delivery is
Xcontrolled by that delivery file.
X.PP
XTherefore, a user delivery file containing only "exit" will keep the given
Xuser from receiving any mail.  A system delivery file containing only "exit"
Xwill cause
X.B all
Xmail to disappear.  So be careful!
X.PP
X.B NOTE 2:
XIf
X.I deliver
Xis setuid root -- which it should be for normal operation -- then the system
Xdelivery file is executed as root.  Be
X.I "very careful"
Xabout its permissions and its contents!  Carelessness here can easily
Xcreate a security problem.
X.PP
X.B NOTE 3:
XAll user delivery files are executed in the context of the user in whose
Xhome directory they reside.  A user's "context" includes the uid, gid, and
Xhome directory as specified in /etc/passwd.
X.PP
X.B NOTE 4:
XFor security reasons, if a user's home directory is writable to the world,
X.I deliver
Xwill ignore any delivery file that might be found there.
X.PP
X.B NOTE 5:
XFor security reasons,
X.I deliver
Xrejects lines of the form "user:mailbox" when generated by a user delivery
Xfile unless they are output by the given user's delivery file.  In other
Xwords, no user can request writing a mailbox as another user.
X.SH LOCKING
XSeveral preprocessor labels may be defined during compilation to control
Xthe method(s) used by
X.I deliver
Xto lock mailboxes.  These labels are:
X.RS
X.PP
X.B ML_DOTLOCK
XLock on exclusive creation of the mailbox name with ".lock"
Xappended.  (Version 7 and early BSD mailers use this method.)
X.PP
X.B ML_DOTMLK
XLock on exclusive creation of
X.I /tmp/basename.mlk,
Xwhere
X.I basename
Xis the last component of the mailbox pathname.  (Xenix mailers use this
Xmethod.)
X.PP
X.B ML_LOCKF
XExclusively lock mailbox with lockf().
X.PP
X.B ML_FCNTL
XExclusively lock mailbox with fcntl().
X.PP
X.B ML_LOCKING
XExclusively lock mailbox with locking().
X.PP
X.RE
XOne or both of ML_DOTLOCK and ML_DOTMLK may be specified.  At most one of
XML_LOCKF, ML_FCNTL or ML_LOCKING may be specified.
X.SH FILES
X/usr/local/lib/deliver.sys      system delivery file
X.br
X/usr/local/lib/deliver.post     post-user delivery file
X.br
X~user/.deliver                  user delivery file(s)
X.br
X/etc/systemid                   system name (Xenix only)
X.SH SUPPORT
XEnhancements, enhancement requests, trouble reports, etc., should be mailed
Xto <bugs-deliver@ateng.com>; or for UUCP-only sites,
X<uunet!ateng!bugs-deliver>.
X.SH "SEE ALSO"
X.IR mail (1),
X.IR uux (1),
X.IR smail (8),
X.IR sendmail (8)
END_OF_FILE
if test 11359 -ne `wc -c <'deliver.8'`; then
    echo shar: \"'deliver.8'\" unpacked with wrong size!
fi
# end of 'deliver.8'
fi
if test -f 'Makefile' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'Makefile'\"
else
echo shar: Extracting \"'Makefile'\" \(4306 characters\)
sed "s/^X//" >'Makefile' <<'END_OF_FILE'
X# $Header: Makefile,v 2.2 89/06/09 13:19:53 network Exp $
X#
X# Makefile for deliver
X#
X#  +----------------+
X#  | Things to make |
X#  +----------------+
X#
X#       deliver         Compile and link the deliver program.
X#       header          Compile and link the header program.
X#       install         Install deliver and header.  (You must be root.)
X#       lint            Run lint on all sources, creating lint.out.
X#       shar            Create distribution sharchives.
X#       clean           Clean up.
X#       clobber         Remove everything that can be regenerated.
X#
X#  +---------------+
X#  | Configuration |
X#  +---------------+
X#
X# SHELL
X#       I don't have to tell you...
X#
X# COPY
X#       Your local copy program.  SCO Xenix users may want to change this
X#       to "copy -m" which preserves file modification time.
X#
X# SHAR
X#       Your local sharchive generator.
X#
X# CFLAGS
X#       Compile-time flags to cc.
X#       For BSD systems, include "-DBSD".
X#       For USG (System III and System V) systems, include "-DUSG".
X#
X# LDFLAGS
X#       Link-time flags to cc.  The -i flag creates pure (sharable) code.
X#
X# LIBS
X#       Depending on your environment, you may or may not need to link
X#       with "-lx".  SCO Xenix System V needs it; Altos Xenix doesn't.
X#
X# BIN
X#       Target directory for installation; /usr/bin is recommended.
X#       You may use /usr/local/bin (or whatever), but you must be sure
X#       that the directory you choose is in your PATH during mail
X#       transmission and delivery.
X#
X# DELSHAR
X#       Basename of sharchives created by "make shar".
X#
X
XSHELL = /bin/sh
XCOPY =  cp
XSHAR =  shar
XCFLAGS = -O
XLDFLAGS = -i
XLIBS = -lx
XBIN =   /usr/bin
XDELSHAR =  deliver.sh
X
X#
X# The files that make up the deliver distribution.
X#
X
XDOCS =  README deliver.8
XMF   =  Makefile
X
XHDRS =  config.h context.h deliver.h dest.h patchlevel.h misc.h
X
XDELSRC1 = context.c copymsg.c
XDELSRC2 = debug.c dest.c dfile.c lock.c main.c
XDELSRC3 = mbox.c procs.c subs.c sysdep.c unctime.y uucp.c
XDELSRCS = $(DELSRC1) $(DELSRC2) $(DELSRC3)
XUIDSRCS = uid.c
XHDRSRCS = header.c
XCOMSRCS = getopt.c
XSAMPLES = samples samples/*
X
XDELOBJS = context.o copymsg.o debug.o dest.o dfile.o lock.o \
X	  main.o mbox.o procs.o subs.o sysdep.o unctime.o uucp.o
XUIDOBJS = uid.o
XHDROBJS = header.o
XCOMOBJS = getopt.o
X
X#
X# For GNU Make.  Sorry about the ugliness.
X#
X
X.PHONY: all install lint shar clean clobber
X
X#
X# The default target.
X#
X
Xall: deliver header uid
X
X#
X# "make clobber" implies "make clean".
X#
X
Xclobber:: clean
X
X#
X# How to install deliver and associated utilities.
X#
X
Xinstall: deliver header uid
X	@if [ `./uid -uU | fgrep '(root)' | wc -l` -ne 2 ]; \
X	then \
X		echo "Sorry!  You must be root to install deliver."; \
X		exit 1; \
X	fi
X	$(COPY) deliver $(BIN)/deliver
X	chgrp root $(BIN)/deliver
X	chown root $(BIN)/deliver
X	chmod 4711 $(BIN)/deliver
X	$(COPY) header $(BIN)/header
X	chmod 755 $(BIN)/header
X
X#
X# How to compile and link the program.
X#
X
Xdeliver: $(DELOBJS) $(COMOBJS)
X	$(CC) $(LDFLAGS) -o $@ $(DELOBJS) $(COMOBJS) $(LIBS)
X$(DELOBJS): $(HDRS)
X
Xclean::
X	rm -f $(DELOBJS)
Xclobber::
X	rm -f deliver
X
X#
X# A header parsing program.
X#
X
Xheader: $(HDRSRCS) $(COMOBJS)
X	$(CC) $(CFLAGS) $(LDFLAGS) -o $@ $(HDRSRCS) $(COMOBJS) $(LIBS)
X	rm -f $(HDROBJS)
X
Xclobber::
X	rm -f header
X
X#
X# A little program to check on user and group id's.
X# (I wish that the System V "id" program were available everywhere.)
X#
X
Xuid: $(UIDSRCS) $(COMOBJS) config.h
X	$(CC) $(CFLAGS) $(LDFLAGS) -o $@ $(UIDSRCS) $(COMOBJS) $(LIBS)
X	rm -f $(UIDOBJS)
X
Xclobber::
X	rm -f uid
X
X#
X# Common subroutines
X#
X
X$(COMOBJS): config.h
X
Xclean::
X	rm -f $(COMOBJS)
X
X#
X# Look for fuzz.
X#
X
Xlint: deliver.lint uid.lint
X
Xdeliver.lint: $(HDRS) $(DELSRCS) $(COMSRCS)
X	lint $(DELSRCS) $(COMSRCS) -lc $(LIBS) >$@
X
Xuid.lint: config.h $(UIDSRCS) $(COMSRCS)
X	lint $(UIDSRCS) $(COMSRCS) -lc $(LIBS) >$@
X
Xclean::
X	rm -f *.lint
X
X#
X# Make distribution sharchives.
X#
X
Xshar:   $(DELSHAR).01 $(DELSHAR).02 $(DELSHAR).03 $(DELSHAR).04
X$(DELSHAR).01: $(DOCS) $(MF) $(UIDSRCS) $(HDRSRCS) $(COMSRCS) $(SAMPLES)
X	$(SHAR) >$@ $(DOCS) $(MF) $(UIDSRCS) $(HDRSRCS) $(COMSRCS) $(SAMPLES)
X$(DELSHAR).02: $(HDRS) $(DELSRC1)
X	$(SHAR) >$@ $(HDRS) $(DELSRC1)
X$(DELSHAR).03: $(DELSRC2)
X	$(SHAR) >$@ $(DELSRC2)
X$(DELSHAR).04: $(DELSRC3)
X	$(SHAR) >$@ $(DELSRC3)
X
Xclobber::
X	rm -f $(DELSHAR).??
END_OF_FILE
if test 4306 -ne `wc -c <'Makefile'`; then
    echo shar: \"'Makefile'\" unpacked with wrong size!
fi
# end of 'Makefile'
fi
if test -f 'uid.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'uid.c'\"
else
echo shar: Extracting \"'uid.c'\" \(2772 characters\)
sed "s/^X//" >'uid.c' <<'END_OF_FILE'
X/* $Header: uid.c,v 2.1 89/06/09 12:25:41 network Exp $
X *
X * I wish the System V "id" program were universally available; but it
X * isn't, so I've written this replacement.
X *
X * usage: uid [-options]
X *
X * Default action is to print one line in the manner of "id":
X *      uid=201(chip) gid=50(group) euid=0(root) egid=0(root)
X * (Note that the "euid" and "egid" entries are not output if they are
X * the same as the "uid" and "gid" values.)
X *
X * If an option string is specified, it disables the normal behavior in
X * favor of displaying id information, one per line, in the order that
X * the options appear in the option string.  Legal options are:
X *      u       real uid
X *      g       real gid
X *      U       effective uid
X *      G       effective gid
X *
X * NOTE: This program is not a paragon of good style.
X *       It's just something I needed for a Makefile.
X *
X * $Log:	uid.c,v $
X * Revision 2.1  89/06/09  12:25:41  network
X * Update RCS revisions.
X * 
X * Revision 1.3  89/06/09  12:24:00  network
X * Baseline for 2.0 release.
X * 
X */
X
X#include <stdio.h>
X#include <pwd.h>
X#include <grp.h>
X#include "config.h"
X
X#ifdef NULL
X#undef NULL
X#endif
X#define NULL 0
X
Xextern  struct passwd   *getpwuid();
Xextern  struct group    *getgrgid();
X
Xchar    *progname = "uid";
X
Xchar    *uid_desc();
Xchar    *gid_desc();
X
Xmain(argc, argv)
Xint     argc;
Xchar    **argv;
X{
X	int     uid, gid, euid, egid;
X	int     c, lines, errcount;
X
X	uid = getuid();
X	gid = getgid();
X	euid = geteuid();
X	egid = getegid();
X
X	errcount = 0;
X	lines = 0;
X
X	while ((c = getopt(argc, argv, "ugUG")) != EOF)
X	{
X		switch (c)
X		{
X		case 'u':
X			(void) printf("%s\n", uid_desc(uid));
X			++lines;
X			break;
X
X		case 'g':
X			(void) printf("%s\n", gid_desc(gid));
X			++lines;
X			break;
X
X		case 'U':
X			(void) printf("%s\n", uid_desc(euid));
X			++lines;
X			break;
X
X		case 'G':
X			(void) printf("%s\n", gid_desc(egid));
X			++lines;
X			break;
X
X		case '?':
X			++errcount;
X			break;
X		}
X	}
X
X	if (errcount)
X	{
X		(void) fprintf(stderr, "usage: uid [-ugUG]\n");
X		exit(1);
X	}
X
X	if (lines == 0)
X	{
X		(void) printf("uid=%s", uid_desc(uid));
X		(void) printf(" gid=%s", gid_desc(gid));
X
X		if (euid != uid)
X			(void) printf(" euid=%s", uid_desc(euid));
X		if (egid != gid)
X			(void) printf(" egid=%s", gid_desc(egid));
X
X		(void) printf("\n");
X	}
X
X	exit(0);
X	/* NOTREACHED */
X}
X
Xchar *
Xuid_desc(uid)
Xint     uid;
X{
X	struct passwd *pw;
X	static char buf[80];
X
X	(void) sprintf(buf, "%d", uid);
X	if ((pw = getpwuid(uid)) != NULL)
X		(void) sprintf(buf + strlen(buf), "(%s)", pw->pw_name);
X
X	return buf;
X}
X
Xchar *
Xgid_desc(gid)
Xint     gid;
X{
X	struct group *gr;
X	static char buf[80];
X
X	(void) sprintf(buf, "%d", gid);
X	if ((gr = getgrgid(gid)) != NULL)
X		(void) sprintf(buf + strlen(buf), "(%s)", gr->gr_name);
X
X	return buf;
X}
END_OF_FILE
if test 2772 -ne `wc -c <'uid.c'`; then
    echo shar: \"'uid.c'\" unpacked with wrong size!
fi
# end of 'uid.c'
fi
if test -f 'header.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'header.c'\"
else
echo shar: Extracting \"'header.c'\" \(4796 characters\)
sed "s/^X//" >'header.c' <<'END_OF_FILE'
X/* $Header: header.c,v 2.2 89/06/09 13:08:07 network Exp $
X *
X * A program to parse RFC 822 mail/news headers.
X *
X * usage: header [-c] [-n] [-f field] ... files
X *
X * Default action is to print entire header.  If one or more -f options
X * are given, only the specified fields are printed.  The field names are
X * not printed unless -n is specified.  Field name comparisons are case
X * insensitive unless -c is specified.
X *
X * Output lines are preceeded by the filename if more than one file is
X * specified.
X *
X * This program is intended for use in delivery files, to extract multi-
X * line header fields.
X *
X * $Log:	header.c,v $
X * Revision 2.2  89/06/09  13:08:07  network
X * Adapt to BSD quirks.
X * 
X * Revision 2.1  89/06/09  12:25:29  network
X * Update RCS revisions.
X * 
X * Revision 1.5  89/06/09  12:23:51  network
X * Baseline for 2.0 release.
X * 
X */
X
X#include <stdio.h>
X#include <ctype.h>
X
X/*
X * Manifest constants
X */
X
X#define TRUE 1
X#define FALSE 0
X
X/*
X * Other useful macros.
X */
X
X#define GETSIZE(buf)    (sizeof(buf) - 1)
X
X#define ISFROM(p) ((p)[0] == 'F' && (p)[1] == 'r' && (p)[2] == 'o' \
X		&& (p)[3] == 'm' && (p)[4] == ' ')
X
X/*
X * External data.
X */
X
X/* Variables set by getopt() [blech] */
X
Xextern  int     optind, opterr;
Xextern  char    *optarg;
X
X/*
X * Library functions.
X */
X
Xextern  char    *malloc();
Xextern  char    *realloc();
Xextern  void    free();
X
X/*
X * Global data
X */
X
Xint     field_count     = 0;
Xint     field_alloc     = 0;
Xchar    **field_names   = NULL;
X
Xint     nocasematch     = TRUE;         /* ignore case in header matches */
Xint     printnames      = FALSE;        /* print field names with data */
X
X/*----------------------------------------------------------------------
X * The Program.
X */
X
Xmain(argc, argv)
Xint     argc;
Xchar    **argv;
X{
X	int     c, errors;
X
X	field_alloc = 8;
X	field_names = (char **) malloc(field_alloc * sizeof(char **));
X	if (field_names == NULL)
X		nomem();
X
X	errors = FALSE;
X	while ((c = getopt(argc, argv, "cnf:")) != EOF)
X	{
X		switch (c)
X		{
X		case 'c':
X			nocasematch = FALSE;
X			break;
X		case 'n':
X			printnames = TRUE;
X			break;
X		case 'f':
X			if (field_count >= field_alloc)
X			{
X				field_alloc *= 2;
X				field_names =
X				    (char **) realloc((char *)field_names,
X					      field_alloc * sizeof(char **));
X				if (field_names == NULL)
X					nomem();
X			}
X			field_names[field_count++] = optarg;
X			break;
X		default:
X			errors = TRUE;
X			break;
X		}
X	}
X
X	if (errors)
X		usage();
X
X	if (optind == argc)
X		header(stdin, (char *)NULL);
X	else
X	{
X		FILE    *fp;
X		int     a, filenames;
X
X		filenames = ((argc - optind) > 1);
X		for (a = optind; a < argc; ++a)
X		{
X			if ((fp = fopen(argv[a], "r")) == NULL)
X			{
X				errors = TRUE;
X				perror(argv[a]);
X				continue;
X			}
X
X			header(fp, (filenames ? argv[a] : (char *)NULL));
X			fclose(fp);
X		}
X	}
X
X	exit(errors ? 1 : 0);
X}
X
Xusage()
X{
X	fprintf(stderr, "usage: header [-c] [-f fieldname] ... files\n");
X	exit(1);
X}
X
Xnomem()
X{
X	fprintf(stderr, "header: out of memory\n");
X	exit(1);
X}
X
Xheader(fp, filename)
XFILE    *fp;
Xchar    *filename;
X{
X	char    buf[1024];
X
X	if (fgets(buf, GETSIZE(buf), fp) == NULL)
X		return;
X
X	/* Ignore From_ line(s). */
X
X	while (ISFROM(buf) || buf[0] == '>')
X	{
X		if (fgets(buf, GETSIZE(buf), fp) == NULL)
X			return;
X	}
X
X	while (buf[0] != '\n')
X	{
X		char    *p;
X		int     print_this;
X
X		p = buf;
X		while (isupper(*p) || islower(*p) || isdigit(*p) || *p == '-')
X			++p;
X		if (p == buf || *p != ':')
X			break;
X		print_this = field(buf, p - buf);
X		if (print_this)
X		{
X			if (filename)
X			{
X				fputs(filename, stdout);
X				putc(':', stdout);
X			}
X			++p;
X			if (*p == ' ' || *p == '\t')
X				++p;
X			if (field_count == 0 || printnames)
X				fputs(buf, stdout);
X			else
X				fputs(p, stdout);
X		}
X
X		/* get the next input line */
X		if (fgets(buf, GETSIZE(buf), fp) == NULL)
X			break;
X
X		/* deal with continuation lines */
X		while (buf[0] == ' ' || buf[0] == '\t')
X		{
X			if (print_this)
X			{
X				if (filename)
X				{
X					fputs(filename, stdout);
X					putc(':', stdout);
X				}
X				fputs(buf, stdout);
X			}
X
X			if (fgets(buf, GETSIZE(buf), fp) == NULL)
X			{
X				buf[0] = '\n';
X				break;
X			}
X		}
X	}
X}
X
Xint
Xfield(s, n)
Xchar    *s;
Xint     n;
X{
X	int     i;
X
X	if (field_count == 0)
X		return TRUE;
X
X	for (i = 0; i < field_count; ++i)
X	{
X		char    *f = field_names[i];
X
X		if (strlen(f) == n)
X		{
X			if (nocasematch)
X			{
X				if (ci_strncmp(f, s, n) == 0)
X					return TRUE;
X			}
X			else
X			{
X				if (strncmp(f, s, n) == 0)
X					return TRUE;
X			}
X		}
X	}
X
X	return FALSE;
X}
X
Xint
Xci_strncmp(s, t, n)
Xchar    *s, *t;
Xint     n;
X{
X	char    c, d;
X
X	while (n-- > 0)
X	{
X		c = *s++;
X		d = *t++;
X		if ((c == 0) && (d == 0))
X			break;
X		if (isupper(c))
X			c = tolower(c);
X		if (isupper(d))
X			d = tolower(d);
X		if (c > d)
X			return 1;
X		if (c < d)
X			return -1;
X	}
X
X	return 0;
X}
END_OF_FILE
if test 4796 -ne `wc -c <'header.c'`; then
    echo shar: \"'header.c'\" unpacked with wrong size!
fi
# end of 'header.c'
fi
if test -f 'getopt.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'getopt.c'\"
else
echo shar: Extracting \"'getopt.c'\" \(1719 characters\)
sed "s/^X//" >'getopt.c' <<'END_OF_FILE'
X/* $Header: getopt.c,v 2.1 89/06/09 12:25:28 network Exp $
X *
X * A version of the public-domain getopt() function, as found
X * in the SVID and fine Unix manuals everywhere.
X *
X * $Log:	getopt.c,v $
X * Revision 2.1  89/06/09  12:25:28  network
X * Update RCS revisions.
X * 
X * Revision 1.4  89/06/09  12:23:50  network
X * Baseline for 2.0 release.
X * 
X */
X
X#include <stdio.h>
X#include "config.h"
X#include "misc.h"
X
X/*----------------------------------------------------------------------
X * Get command line options.
X * This is essentially the public domain version, just reformatted to
X * match the rest of the deliver program.
X */
X
X#ifndef HAS_GETOPT
X
Xint     opterr = 1;
Xint     optind = 1;
Xint     optopt = 0;
Xchar    *optarg = NULL;
X
X#define ERR(what,c) \
X    if (!opterr) {} else fprintf(stderr,"%s: %s -- %c\n", argv[0], what, c);
X
Xint
Xgetopt(argc, argv, opts)
Xint argc;
Xchar **argv;
Xchar *opts;
X{
X	static int sp = 1;
X	int c;
X	char *cp;
X
X	if (sp == 1)
X	{
X		if (optind >= argc
X		 || argv[optind][0] != '-' || argv[optind][1] == '\0')
X			return EOF;
X
X		if (strcmp(argv[optind], "--") == NULL)
X		{
X			optind++;
X			return EOF;
X		}
X	}
X
X	optopt = c = argv[optind][sp];
X
X	if (c == ':' || (cp = strchr(opts, c)) == NULL)
X	{
X		ERR("illegal option", c);
X		if (argv[optind][++sp] == '\0')
X		{
X			optind++;
X			sp = 1;
X		}
X		return '?';
X	}
X
X	if (*++cp == ':')
X	{
X		if (argv[optind][sp + 1] != '\0')
X			optarg = &argv[optind++][sp + 1];
X		else if (++optind >= argc)
X		{
X			ERR("option requires an argument", c);
X			sp = 1;
X			return '?';
X		}
X		else
X			optarg = argv[optind++];
X
X		sp = 1;
X	}
X	else
X	{
X		if (argv[optind][++sp] == '\0')
X		{
X			sp = 1;
X			optind++;
X		}
X
X		optarg = NULL;
X	}
X
X	return c;
X}
X
X#endif  /* !HAS_GETOPT */
END_OF_FILE
if test 1719 -ne `wc -c <'getopt.c'`; then
    echo shar: \"'getopt.c'\" unpacked with wrong size!
fi
# end of 'getopt.c'
fi
if test ! -d 'samples' ; then
    echo shar: Creating directory \"'samples'\"
    mkdir 'samples'
fi
if test -f 'samples/README' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'samples/README'\"
else
echo shar: Extracting \"'samples/README'\" \(229 characters\)
sed "s/^X//" >'samples/README' <<'END_OF_FILE'
XREADME for samples.
X
XThese sample delivery file are provides for your edification and amusement.
XI've actually tested u-chip and u-vacation; the other samples are just off
Xthe top of my head.  Use at your own risk, and all that.
END_OF_FILE
if test 229 -ne `wc -c <'samples/README'`; then
    echo shar: \"'samples/README'\" unpacked with wrong size!
fi
# end of 'samples/README'
fi
if test -f 'samples/p-aliases' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'samples/p-aliases'\"
else
echo shar: Extracting \"'samples/p-aliases'\" \(445 characters\)
sed "s/^X//" >'samples/p-aliases' <<'END_OF_FILE'
X: p-aliases
X# A sample post-user deliver file.
X#
X# This post-user delivery file provides system-wide aliases that are
X# processed after user delivery files have had their say.
X
Xfor u
Xdo
X    case $u in
X    root)       echo buoc ;;                # Big User On Computer :-)
X    uucp)       echo buoc ;;
X    postmaster) echo buoc ;;
X    bug-alias)  echo user1; echo user2 ;;   # Both users get each message
X    *)          echo $u ;;
X    esac
Xdone
END_OF_FILE
if test 445 -ne `wc -c <'samples/p-aliases'`; then
    echo shar: \"'samples/p-aliases'\" unpacked with wrong size!
fi
# end of 'samples/p-aliases'
fi
if test -f 'samples/s-aliases' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'samples/s-aliases'\"
else
echo shar: Extracting \"'samples/s-aliases'\" \(653 characters\)
sed "s/^X//" >'samples/s-aliases' <<'END_OF_FILE'
X: s-aliases
X# A sample system delivery file.
X#
X# While Joe is gone, send problem reports to Fred.
X# Note that since user delivery files are processed after this one,
X#    Fred's user delivery file may direct all such mail back to joe
X#    if Fred wants to be difficult. :-)
X# Note that a better solution is to use a bug report alias,
X#    but this method demonstrates variable delivery based
X#    on message headers.
X
XSUBJECT=`header -f subject $HEADER | tr '[A-Z]' '[a-z]'`
X
Xfor u
Xdo
X    case $u in
X    joe)        case $SUBJECT in
X		*bug*|*problem*)    echo fred ;;
X		*)                  echo joe ;;
X		esac ;;
X    *)          echo $u ;;
X    esac
Xdone
END_OF_FILE
if test 653 -ne `wc -c <'samples/s-aliases'`; then
    echo shar: \"'samples/s-aliases'\" unpacked with wrong size!
fi
# end of 'samples/s-aliases'
fi
if test -f 'samples/u-chip' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'samples/u-chip'\"
else
echo shar: Extracting \"'samples/u-chip'\" \(247 characters\)
sed "s/^X//" >'samples/u-chip' <<'END_OF_FILE'
X: u-chip
X# Chip's user delivery file.
X
Xuser="$1"
XTO=`header -f To -f CC $HEADER`
X
Xcase "$SENDER" in
X*zardoz*!sec*)  echo $user:mbox.sec;   exit ;;
Xesac
X
Xcase "$TO" in
X*ietf*|*ineng*) echo $user:mbox.ietf;   exit ;;
Xesac
X
X# Default case
Xecho $user
END_OF_FILE
if test 247 -ne `wc -c <'samples/u-chip'`; then
    echo shar: \"'samples/u-chip'\" unpacked with wrong size!
fi
# end of 'samples/u-chip'
fi
if test -f 'samples/u-vacation' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'samples/u-vacation'\"
else
echo shar: Extracting \"'samples/u-vacation'\" \(1033 characters\)
sed "s/^X//" >'samples/u-vacation' <<'END_OF_FILE'
X: u-vacation
X# A user delivery file for when you're on vacation.
X#
X# The ALREADY file remembers who you've already mailed vacation messages to.
X# The BEBACK string is the date you will return.
X
XALREADY=vacation.list
XBEBACK="on July 4, 1776"
X
Xecho "$1"               # Keep the mail!
X
Xif grep '^'${SENDER}'$' $ALREADY >/dev/null 2>/dev/null
Xthen
X    exit 0              # We already notified this person; reject
Xfi
X
Xcase $SENDER in
X*uucp)  exit 0 ;;       # Not a human; reject
X*daemon) exit 0 ;;      # Not a human; reject
X*DAEMON) exit 0 ;;      # Not a human; reject
X*!*)    ;;
X*@*)    ;;
X## *)      exit 0 ;;       # Local user; reject (maybe)
Xesac
X
X# Remember this person
Xecho $SENDER >>$ALREADY
X
X# Send the vacation message
XSUBJECT=`header -f subject $HEADER`
Xmail -s "I'm on vacation" $SENDER <<!EOF!
XYour message to me on the subject
X    "$SUBJECT"
Xhas been delivered.  However, I am on vacation, so I have not yet
Xread your message.  I will be back $BEBACK.
X
XThis is the only such message you will receive.
X
XThank you.
X!EOF!
END_OF_FILE
if test 1033 -ne `wc -c <'samples/u-vacation'`; then
    echo shar: \"'samples/u-vacation'\" unpacked with wrong size!
fi
# end of 'samples/u-vacation'
fi
echo shar: End of shell archive.
exit 0


-- 
Please send comp.sources.unix-related mail to rsalz@uunet.uu.net.
Use a domain-based address or give alternate paths, or you may lose out.