clientserver 0.50 (part 1/2)

Dan Bernstein brnstnd at kramden.acf.nyu.edu
Wed Jun 26 08:45:02 AEST 1991


This is clientserver 0.50, a set of three client-server suites
supporting different protocols with the same well-defined interface. Two
of the suites support the TCP and UNDOM protocols for BSD systems; one
supports the NPIPE protocol for System V. (I'd love to hear from anyone
with a System V more modern than a 3B2: Does NPIPE run on your machine?)
All obey the UCSPI (UNIX Client-Server Program Interface) standard, so
you can write programs that work exactly the same way on top of any of
the protocols. You can even use these communications facilities inside
shell scripts.

Why do you want to use UCSPI-compliant communications tools? One
advantage is instant portability. By working with the client-server
model given here, you instantly make your programs usable over the
Internet as well as on System V machines. Not only that, but your code
will work with any future communications tools designed to fit the
standard. Imagine supporting DECnet, AT&T's TLI, even Kerberos without
lifting a finger! Another advantage is modularity: you can mix 'n' match
protocols and applications without worrying which program supports which
protocols. Finally, you can skip all those nasty steps of getting
connection information from the operating system. No matter what the
protocol is, UCSPI insists that you be given environment variables
saying who you're talking to.

UCSPI also mandates an often ignored aspect of client-server
communications: a standard way to kill the server. You don't have to go
searching through process lists or checking /etc/syslog.pid or sending
HUPS left and right. You stop a server the same way you started it. You
might set up a telnet daemon, for example, with this command:

  tcpserver 0 telnet sh -c '/usr/etc/in.telnetd <&6 >&7 6<&- 7>&-' &

Here 0 refers to the local machine, and telnet is a port. To kill the
server you just have to know the address:

  tcpkiller 0 telnet

That's it.

Everything here except the UCSPI-91 standard is in the public domain.
Feel free to copy UCSPI as long as you don't modify it. Of course, UCSPI
is just a document laying out some ideas; it's not a real standard until
enough people decide it's worth supporting. Please let me know what you
think!

---Dan Bernstein, brnstnd at nyu.edu

#! /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 archive 1 (of 2)."
# Contents:  BLURB DESIGN.npipe FILES FORMLETTER Makefile NPIPE README
#   TCP UNDOM authuser.c authuser.h dupdup.c dupdup.h env.c env.h
#   errno.h getopt.h hostname.c hostname.h malloc.h npipekiller.c
#   numeric.c numeric.h numfiles.h portname.c portname.h tcpkiller.c
#   testmain testresult testucspi undomclient.c undomkiller.c
#   username.c username.h
# Wrapped by brnstnd at kramden on Tue Jun 25 18:41:38 1991
PATH=/bin:/usr/bin:/usr/ucb ; export PATH
if test -f 'BLURB' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'BLURB'\"
else
echo shar: Extracting \"'BLURB'\" \(2255 characters\)
sed "s/^X//" >'BLURB' <<'END_OF_FILE'
XThis is clientserver 0.50, a set of three client-server suites
Xsupporting different protocols with the same well-defined interface. Two
Xof the suites support the TCP and UNDOM protocols for BSD systems; one
Xsupports the NPIPE protocol for System V. (I'd love to hear from anyone
Xwith a System V more modern than a 3B2: Does NPIPE run on your machine?)
XAll obey the UCSPI (UNIX Client-Server Program Interface) standard, so
Xyou can write programs that work exactly the same way on top of any of
Xthe protocols. You can even use these communications facilities inside
Xshell scripts.
X
XWhy do you want to use UCSPI-compliant communications tools? One
Xadvantage is instant portability. By working with the client-server
Xmodel given here, you instantly make your programs usable over the
XInternet as well as on System V machines. Not only that, but your code
Xwill work with any future communications tools designed to fit the
Xstandard. Imagine supporting DECnet, AT&T's TLI, even Kerberos without
Xlifting a finger! Another advantage is modularity: you can mix 'n' match
Xprotocols and applications without worrying which program supports which
Xprotocols. Finally, you can skip all those nasty steps of getting
Xconnection information from the operating system. No matter what the
Xprotocol is, UCSPI insists that you be given environment variables
Xsaying who you're talking to.
X
XUCSPI also mandates an often ignored aspect of client-server
Xcommunications: a standard way to kill the server. You don't have to go
Xsearching through process lists or checking /etc/syslog.pid or sending
XHUPS left and right. You stop a server the same way you started it. You
Xmight set up a telnet daemon, for example, with this command:
X
X  tcpserver 0 telnet sh -c '/usr/etc/in.telnetd <&6 >&7 6<&- 7>&-' &
X
XHere 0 refers to the local machine, and telnet is a port. To kill the
Xserver you just have to know the address:
X
X  tcpkiller 0 telnet
X
XThat's it.
X
XEverything here except the UCSPI-91 standard is in the public domain.
XFeel free to copy UCSPI as long as you don't modify it. Of course, UCSPI
Xis just a document laying out some ideas; it's not a real standard until
Xenough people decide it's worth supporting. Please let me know what you
Xthink!
X
X---Dan Bernstein, brnstnd at nyu.edu
END_OF_FILE
if test 2255 -ne `wc -c <'BLURB'`; then
    echo shar: \"'BLURB'\" unpacked with wrong size!
fi
# end of 'BLURB'
fi
if test -f 'DESIGN.npipe' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'DESIGN.npipe'\"
else
echo shar: Extracting \"'DESIGN.npipe'\" \(950 characters\)
sed "s/^X//" >'DESIGN.npipe' <<'END_OF_FILE'
XHere's the idea: We create DIR/l.username/service, a mode-000 file. We
Xcreate s.username, a mode-600 named pipe. We then change l.username to
Xmode 600 and open s.username for reading. This blocks. Note that a
Xclient may start writing before we start reading, or vice versa.
X
XMain loop: The client locks l.username. When it receives the lock, it
Xopens s.username for writing, then creates DIR/s2c.pid and DIR/c2s.pid,
Xthen writes pid and its username, then closes s.username, then opens
Xs2c.pid for reading (this blocks) and c2s.pid for writing (this blocks).
XWe read pid and the username, then close and unlink s.username. We then
Xfork. In the parent, we then create s.username, a mode-600 named pipe,
Xthen open s.username for reading; this is back to the original state. In
Xthe child, we open s2c.pid for writing and c2s.pid for reading, then
Xwrite a byte to s2c.pid. The client reads that byte, unlinks s2c.pid and
Xc2s.pid, and unlocks l.username.
END_OF_FILE
if test 950 -ne `wc -c <'DESIGN.npipe'`; then
    echo shar: \"'DESIGN.npipe'\" unpacked with wrong size!
fi
# end of 'DESIGN.npipe'
fi
if test -f 'FILES' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'FILES'\"
else
echo shar: Extracting \"'FILES'\" \(399 characters\)
sed "s/^X//" >'FILES' <<'END_OF_FILE'
XBLURB
XREADME
XFILES
XFORMLETTER
XUCSPI
XTCP
XUNDOM
XNPIPE
XDESIGN.npipe
Xtestmain
Xtestresult
Xtestucspi
XMakefile
Xauthuser.h
Xdupdup.h
Xenv.h
Xerrno.h
Xgetopt.h
Xhostname.h
Xmalloc.h
Xnumeric.h
Xnumfiles.h
Xportname.h
Xusername.h
Xauthuser.c
Xdupdup.c
Xenv.c
Xhostname.c
Xnpipeclient.c
Xnpipeserver.c
Xnpipekiller.c
Xnumeric.c
Xportname.c
Xundomclient.c
Xundomserver.c
Xundomkiller.c
Xusername.c
Xtcpclient.c
Xtcpserver.c
Xtcpkiller.c
END_OF_FILE
if test 399 -ne `wc -c <'FILES'`; then
    echo shar: \"'FILES'\" unpacked with wrong size!
fi
# end of 'FILES'
fi
if test -f 'FORMLETTER' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'FORMLETTER'\"
else
echo shar: Extracting \"'FORMLETTER'\" \(612 characters\)
sed "s/^X//" >'FORMLETTER' <<'END_OF_FILE'
XTo: brnstnd at nyu.edu
XFrom: 
XDate: 
X
XPackage: clientserver 0.50
XObtained from (e.g., uunet.uu.net): 
XObtained by (e.g., ftp): 
X
X1. Machine architecture (e.g., Sun 4/280): 
X2. Operating system (e.g., SunOS 4.1): 
X3. OS vendor (e.g., Sun): 
X4. Does tcp work on your machine so far (yes/no/didn't try)? 
X5. Does undom work on your machine so far (yes/no/didn't try)? 
X6. Does npipe work on your machine so far (yes/no/didn't try)? 
X7. What are CC and CCOPTS in your Makefile?
X   CC=
X   CCOPTS=
X
X8. Describe any problems you've had with clientserver.
X
X
X9. Any further questions, comments, or suggestions?
X
X
XYour name:
END_OF_FILE
if test 612 -ne `wc -c <'FORMLETTER'`; then
    echo shar: \"'FORMLETTER'\" unpacked with wrong size!
fi
# end of 'FORMLETTER'
fi
if test -f 'Makefile' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'Makefile'\"
else
echo shar: Extracting \"'Makefile'\" \(3109 characters\)
sed "s/^X//" >'Makefile' <<'END_OF_FILE'
XCC=cc
XCCOPTS=-g -DUNDOMDIR=\"/usr/local/etc/undom\" -DNPIPEDIR=\"/usr/local/etc/npipe\" -DSIGRET=int
XMACHOPTS=
XLIBS=-lresolv   # XXX: only necessary for tcp*
X#
X
Xdefault: undom tcp npipe
X
Xundom: undomserver undomclient undomkiller
X
Xtcp: tcpserver tcpclient tcpkiller
X
Xnpipe: npipeserver npipeclient npipekiller
X
Xnpipekiller: npipekiller.o dupdup.o username.o numeric.o env.o
X	$(CC) $(CCOPTS) $(MACHOPTS) -o npipekiller npipekiller.o dupdup.o username.o numeric.o env.o $(LIBS)
X
Xnpipeserver: npipeserver.o dupdup.o username.o numeric.o env.o
X	$(CC) $(CCOPTS) $(MACHOPTS) -o npipeserver npipeserver.o dupdup.o username.o numeric.o env.o $(LIBS)
X
Xnpipeclient: npipeclient.o dupdup.o username.o numeric.o env.o
X	$(CC) $(CCOPTS) $(MACHOPTS) -o npipeclient npipeclient.o dupdup.o username.o numeric.o env.o $(LIBS)
X
Xundomkiller: undomkiller.o dupdup.o username.o numeric.o env.o
X	$(CC) $(CCOPTS) $(MACHOPTS) -o undomkiller undomkiller.o dupdup.o username.o numeric.o env.o $(LIBS)
X
Xundomserver: undomserver.o dupdup.o username.o numeric.o env.o
X	$(CC) $(CCOPTS) $(MACHOPTS) -o undomserver undomserver.o dupdup.o username.o numeric.o env.o $(LIBS)
X
Xundomclient: undomclient.o dupdup.o username.o numeric.o env.o
X	$(CC) $(CCOPTS) $(MACHOPTS) -o undomclient undomclient.o dupdup.o username.o numeric.o env.o $(LIBS)
X
Xtcpkiller: tcpkiller.o username.o numeric.o portname.o hostname.o env.o
X	$(CC) $(CCOPTS) $(MACHOPTS) -o tcpkiller tcpkiller.o username.o numeric.o portname.o hostname.o env.o $(LIBS)
X
Xtcpserver: tcpserver.o dupdup.o username.o numeric.o authuser.o portname.o hostname.o env.o
X	$(CC) $(CCOPTS) $(MACHOPTS) -o tcpserver tcpserver.o dupdup.o username.o numeric.o authuser.o portname.o hostname.o env.o $(LIBS)
X
Xtcpclient: tcpclient.o dupdup.o username.o numeric.o authuser.o portname.o hostname.o env.o
X	$(CC) $(CCOPTS) $(MACHOPTS) -o tcpclient tcpclient.o dupdup.o username.o numeric.o authuser.o portname.o hostname.o env.o $(LIBS)
X
Xnpipekiller.o: npipekiller.c
X	$(CC) $(CCOPTS) $(MACHOPTS) -c npipekiller.c
X
Xnpipeserver.o: npipeserver.c
X	$(CC) $(CCOPTS) $(MACHOPTS) -c npipeserver.c
X
Xnpipeclient.o: npipeclient.c
X	$(CC) $(CCOPTS) $(MACHOPTS) -c npipeclient.c
X
Xundomkiller.o: undomkiller.c
X	$(CC) $(CCOPTS) $(MACHOPTS) -c undomkiller.c
X
Xundomserver.o: undomserver.c
X	$(CC) $(CCOPTS) $(MACHOPTS) -c undomserver.c
X
Xundomclient.o: undomclient.c
X	$(CC) $(CCOPTS) $(MACHOPTS) -c undomclient.c
X
Xtcpclient.o: tcpclient.c
X	$(CC) $(CCOPTS) $(MACHOPTS) -c tcpclient.c
X
Xtcpkiller.o: tcpkiller.c
X	$(CC) $(CCOPTS) $(MACHOPTS) -c tcpkiller.c
X
Xtcpserver.o: tcpserver.c
X	$(CC) $(CCOPTS) $(MACHOPTS) -c tcpserver.c
X
Xdupdup.o: dupdup.c
X	$(CC) $(CCOPTS) $(MACHOPTS) -c dupdup.c
X
Xusername.o: username.c
X	$(CC) $(CCOPTS) $(MACHOPTS) -c username.c
X
Xportname.o: portname.c
X	$(CC) $(CCOPTS) $(MACHOPTS) -c portname.c
X
Xhostname.o: hostname.c
X	$(CC) $(CCOPTS) $(MACHOPTS) -c hostname.c
X
Xnumeric.o: numeric.c
X	$(CC) $(CCOPTS) $(MACHOPTS) -c numeric.c
X
Xenv.o: env.c
X	$(CC) $(CCOPTS) $(MACHOPTS) -c env.c
X
Xauthuser.o: authuser.c
X	$(CC) $(CCOPTS) $(MACHOPTS) -c authuser.c
X
Xshar:
X	shar `cat FILES` > ucspi.shar
X	chmod 400 ucspi.shar
END_OF_FILE
if test 3109 -ne `wc -c <'Makefile'`; then
    echo shar: \"'Makefile'\" unpacked with wrong size!
fi
# end of 'Makefile'
fi
if test -f 'NPIPE' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'NPIPE'\"
else
echo shar: Extracting \"'NPIPE'\" \(1377 characters\)
sed "s/^X//" >'NPIPE' <<'END_OF_FILE'
XNPIPE
X6/23/91
X
X
XThis document defines the NPIPE protocol for UCSPI programs. A NPIPE
Xclient communicates with a NPIPE server on the same machine through a
Xpair of named pipes.
X
X<address> consists of two arguments: <username> <service>. Neither
Xargument can contain slashes, newlines, or periods. <username> must not
Xcontain colons. Any other character understood by the local machine may
Xappear. <username> is a username on the machine, and <service> is any
Xtext chosen by <username> to represent a service.
X
X<clientaddress> is the username of the client user. <serveraddress> is
X<username>:<service>. Both of these addresses are limited to 100
Xcharacters.
X
XThe descriptors passed to <userprogram> refer to two independent
Xunlinked named pipes (fifos). Descriptor 6 supports only reading and
Xdescriptor 7 supports only writing. The semantics of these pipes are
Xdefined by the local UNIX variant; no operations other than those
Xapplicable to normal pipes may be assumed.
X
XIt must not be possible for one user to set up a service with a
Xdifferent <username>. It must not be possible for a user to conceal or
Xdisguise the username of a client.
X
XAll NPIPE programs have undefined behavior if any username involved
Xshares a uid with a different username.
X
XPreferred executable names: npipeclient, npipeserver, npipekiller.
X
X
XUCSPI Administrator
XDaniel J. Bernstein, brnstnd at nyu.edu
END_OF_FILE
if test 1377 -ne `wc -c <'NPIPE'`; then
    echo shar: \"'NPIPE'\" unpacked with wrong size!
fi
# end of 'NPIPE'
fi
if test -f 'README' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'README'\"
else
echo shar: Extracting \"'README'\" \(2539 characters\)
sed "s/^X//" >'README' <<'END_OF_FILE'
Xclientserver 0.50, 6/25/91, Daniel J. Bernstein, brnstnd at nyu.edu.
XWatch alt.sources.d for patches, comp.sources.unix for the next version.
XLatest version inside stealth.acf.nyu.edu:pub/hier/clientserver/.
X
XThis has been extensively tested under SunOS 4.0.3, Ultrix 4.1, BSD 4.3,
Xand the latest pre-BSD 4.4, and it appears to work on several other
Xsystems. Under gcc you MUST define -fwritable-strings; sorry, old habits
Xdie hard.
X
XModify UNDOMDIR and NPIPEDIR in Makefile for your system. Make some uid,
Xsay undom, with access to UNDOMDIR; make UNDOMDIR mode 700 ownder undom.
XMake some uid, say npipe, with access to NPIPEDIR; make NPIPEDIR mode
X700 owner npipe. Make sure LIBS makes sense for you: most BSD systems
Xneed -lresolv to use the resolver, and if you don't have getopt you'll
Xhave to pick it up and put it into LIBS. That's it for configuration.
X
XMake. On BSD systems without named pipes, you should make only tcp and
Xundom. On System V systems without sockets, you should make npipe. (I
Xhave absolutely no idea whether npipe actually works on any modern
XSystem V machines.) Under SunOS and Ultrix, make everything.
X
XTo test the programs, run testmain in this directory with appropriate
Xarguments. Examples:
X
X  ./testmain NPIPE npipe <yourusername> blah
X  ./testmain UNDOM undom <yourusername> foop
X  ./testmain TCP tcp 0 <randomportnumber>
X
XThe 0 in the last line is an abbreviation for the local host. testmain
Xshould say ``Everything compares okay''; if not, don't panic, because
Xthe test code can report false alarms. (It uses sleep(1) for
Xsynchronization.) Just run it again. To see what's going on, run
Xtestucspi in place of testmain.
X
XInstall tcp{client,server,killer} somewhere, NOT setuid. Install
Xundom{client,server,killer} somewhere, owner undom, mode 4755. Install
Xnpipe{client,server,killer} somewhere, owner npipe, mode 4755. That's
Xit. You might want to have your rc.local remove anything in UNDOMDIR or
XNPIPEDIR.
X
X*PLEASE* fill out FORMLETTER and send it to me if you had problems.
X*PLEASE* fill out FORMLETTER and send it to me if everything worked!
XThanks for being a good sport.
X
XThe best documentation available at the moment is UCSPI and its
Xassociated documents (TCP, UNDOM, NPIPE). Look at testucspi for an
Xexample of how to communicate between independent processes with UCSPI.
X
X
XXXX: handle EINTR better in undomserver.c and npipe*.c
XXXX: restore signals properly?
XXXX: fix all the exit codes
XXXX: write man pages!
XXXX: write a real README! and BLURB
XXXX: provide semi-automatic reboot cleanup stuff?
END_OF_FILE
if test 2539 -ne `wc -c <'README'`; then
    echo shar: \"'README'\" unpacked with wrong size!
fi
# end of 'README'
fi
if test -f 'TCP' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'TCP'\"
else
echo shar: Extracting \"'TCP'\" \(2835 characters\)
sed "s/^X//" >'TCP' <<'END_OF_FILE'
XTCP
X6/19/91
X
X
XThis document defines the TCP protocol for UCSPI programs. A TCP client
Xcommunicates with a TCP server, on the same machine or on a different
Xmachine, via the TCP/IP protocol through an Internet-domain socket.
X
X<address> consists of two arguments: <hostname> <port>. <hostname> may
Xeither be a dotted IP address (such as 128.122.128.2) or a name which,
Xon the local machine, somehow represents such an address. (For example,
Xdomain names understood by DNS or by a local NIC-style host table might
Xbe valid <hostname>s.) <hostname> may also be the single character 0,
Xreferring to the local machine. <port> may either be a numeric TCP port
Xnumber (such as 25, the standard SMTP port) or a name which, on the
Xlocal machine, somehow represents a port number. Any character may
Xappear in <hostname> or <port>.
X
X<clientaddress> and <serveraddress> share a single format:
X<username>@<hostnumber>(<hostname>):<port>. <username> is a username on
Xthe machine in question: inside TCPLOCAL, <username> is the real
Xusername of the process, and inside TCPREMOTE, <username> is the
Xusername returned by the other machine via RFC 931, or blank if the
Xother machine does not support RFC 931. The client and server must take
Xa -R option to turn off RFC 931 checking, and -r to turn it back on.
XUnder -R, <username> will always be blank inside TCPREMOTE. <hostnumber>
Xis the IP address of the communicating host. <hostname> is either that
Xaddress or, if available, a name representing that address. <port> is
Xthe relevant TCP port.
X
XNote that this address format is ambiguous, except in <port>. <hostname>
Xdepends on local name lookup conventions, <username> may be blank, and
X<hostnumber> might refer to the same machine through special numbers
Xsuch as 127.0.0.1 and 0.0.0.0. Application programs which use
X<clientaddress> and <serveraddress> should keep these caveats in mind.
X
XThe descriptors passed to <userprogram> refer to an INET-domain stream
Xsocket, dup()ed from a single connect() or accept(). The semantics of
Xthis socket are defined by the local UNIX variant, but it is expected
Xthat it will support out-of-band data as in BSD systems past 4.2,
Xsubject to the restrictions of RFC 1122 and RFC 1123.
X
XIf <port> is 0, the server must choose an available port number or
Xreport an error. The client must take a -p <locport> option to set a
Xdesired TCP port on the local side of the connection; if it cannot
Xsatisfy this request, it must report an error.
X
XThe killer must not work upon a server running on a different machine.
XThe killer and the server may communicate through files stored in the
Xhome directory of the invoking user, as specified by environment
Xvariable TCPHOME, or HOME if TCPHOME is not set.
X
XPreferred executable names: tcpclient, tcpserver, tcpkiller.
X
X
XUCSPI Administrator
XDaniel J. Bernstein, brnstnd at nyu.edu
END_OF_FILE
if test 2835 -ne `wc -c <'TCP'`; then
    echo shar: \"'TCP'\" unpacked with wrong size!
fi
# end of 'TCP'
fi
if test -f 'UNDOM' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'UNDOM'\"
else
echo shar: Extracting \"'UNDOM'\" \(1409 characters\)
sed "s/^X//" >'UNDOM' <<'END_OF_FILE'
XUNDOM
X6/16/91
X
X
XThis document defines the UNDOM protocol for UCSPI programs. A UNDOM
Xclient communicates with a UNDOM server on the same machine through a
XUNIX-domain socket.
X
X<address> consists of two arguments: <username> <service>. Neither
Xargument can contain slashes, newlines, or periods. <username> must not
Xcontain colons. Any other character understood by the local machine may
Xappear. <username> is a username on the machine, and <service> is any
Xtext chosen by <username> to represent a service.
X
X<clientaddress> is the username of the client user. <serveraddress> is
X<username>:<service>. Both of these addresses are limited to 100
Xcharacters.
X
XThe descriptors passed to <userprogram> refer to a UNIX-domain stream
Xsocket whose name is a function of <username> and <service>; they are
Xdup()ed from a single connect() or accept(). The semantics of this
Xsocket are defined by the local UNIX variant, but it is expected that it
Xwill support file descriptor passing as in BSD systems past 4.2.
X
XIt must not be possible for one user to set up a service with a
Xdifferent <username>. It must not be possible for a user to conceal or
Xdisguise the username of a client.
X
XAll UNDOM programs have undefined behavior if any username involved
Xshares a uid with a different username.
X
XPreferred executable names: undomclient, undomserver, undomkiller.
X
X
XUCSPI Administrator
XDaniel J. Bernstein, brnstnd at nyu.edu
END_OF_FILE
if test 1409 -ne `wc -c <'UNDOM'`; then
    echo shar: \"'UNDOM'\" unpacked with wrong size!
fi
# end of 'UNDOM'
fi
if test -f 'authuser.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'authuser.c'\"
else
echo shar: Extracting \"'authuser.c'\" \(3622 characters\)
sed "s/^X//" >'authuser.c' <<'END_OF_FILE'
X/*
X5/6/91 DJB baseline authuser 3.1. Public domain.
X*/
X
X#include <stdio.h>
X#include <sys/types.h>
X#include <sys/socket.h>
X#include <netinet/in.h>
X#include <arpa/inet.h>
X#include <netdb.h>
X#include <errno.h>
X#include <ctype.h>
Xextern int errno;
X#include "authuser.h"
X
Xunsigned short auth_tcpport = 113;
X
X#define SIZ 500 /* various buffers */
X
Xstatic int usercmp(u,v)
Xregister char *u;
Xregister char *v;
X{
X /* is it correct to consider Foo and fOo the same user? yes */
X /* but the function of this routine may change later */
X while (*u && *v)
X   if (tolower(*u) != tolower(*v))
X     return tolower(*u) - tolower(*v);
X   else
X     ++u,++v;
X return *u || *v;
X}
X
Xstatic char authline[SIZ];
X
Xchar *auth_xline(user,fd,in)
Xregister char *user; /* the supposed name of the user, NULL if unknown */
Xregister int fd; /* the file descriptor of the connection */
Xregister unsigned long *in;
X{
X unsigned short local;
X unsigned short remote;
X register char *ruser;
X
X if (auth_fd(fd,in,&local,&remote) == -1)
X   return 0;
X ruser = auth_tcpuser(*in,local,remote);
X if (!ruser)
X   return 0;
X if (!user)
X   user = ruser; /* forces X-Auth-User */
X (void) sprintf(authline,
X	 (usercmp(ruser,user) ? "X-Forgery-By: %s" : "X-Auth-User: %s"),
X	 ruser);
X return authline;
X}
X
Xint auth_fd(fd,in,local,remote)
Xregister int fd;
Xregister unsigned long *in;
Xregister unsigned short *local;
Xregister unsigned short *remote;
X{
X struct sockaddr_in sa;
X int dummy;
X
X dummy = sizeof(sa);
X if (getsockname(fd,&sa,&dummy) == -1)
X   return -1;
X if (sa.sin_family != AF_INET)
X  {
X   errno = EAFNOSUPPORT;
X   return -1;
X  }
X *local = ntohs(sa.sin_port);
X dummy = sizeof(sa);
X if (getpeername(fd,&sa,&dummy) == -1)
X   return -1;
X *remote = ntohs(sa.sin_port);
X *in = sa.sin_addr.s_addr;
X return 0;
X}
X
Xstatic char ruser[SIZ];
Xstatic char realbuf[SIZ];
Xstatic char *buf;
X
Xchar *auth_tcpuser(in,local,remote)
Xregister unsigned long in;
Xregister unsigned short local;
Xregister unsigned short remote;
X{
X struct sockaddr_in sa;
X register int s;
X register int buflen;
X register int w;
X register int saveerrno;
X char ch;
X unsigned short rlocal;
X unsigned short rremote;
X
X if ((s = socket(AF_INET,SOCK_STREAM,0)) == -1)
X   return 0;
X sa.sin_family = AF_INET;
X sa.sin_port = htons(auth_tcpport);
X sa.sin_addr.s_addr = in;
X if (connect(s,&sa,sizeof(sa)) == -1)
X  {
X   saveerrno = errno;
X   (void) close(s);
X   errno = saveerrno;
X   return 0;
X  }
X
X buf = realbuf;
X (void) sprintf(buf,"%u , %u\r\n",(unsigned int) remote,(unsigned int) local);
X /* note the reversed order---the example in the RFC is misleading */
X buflen = strlen(buf);
X while ((w = write(s,buf,buflen)) < buflen)
X   if (w == -1) /* should we worry about 0 as well? */
X    {
X     saveerrno = errno;
X     (void) close(s);
X     errno = saveerrno;
X     return 0;
X    }
X   else
X    {
X     buf += w;
X     buflen -= w;
X    }
X buf = realbuf;
X while ((w = read(s,&ch,1)) == 1)
X  {
X   *buf = ch;
X   if ((ch != ' ') && (ch != '\t') && (ch != '\r'))
X     ++buf;
X   if ((buf - realbuf == sizeof(realbuf) - 1) || (ch == '\n'))
X     break;
X  }
X if (w == -1)
X  {
X   saveerrno = errno;
X   (void) close(s);
X   errno = saveerrno;
X   return 0;
X  }
X *buf = '\0';
X
X if (sscanf(realbuf,"%hd,%hd: USERID :%*[^:]:%s",&rremote,&rlocal,ruser) < 3)
X  {
X   (void) close(s);
X   errno = EIO;
X   /* makes sense, right? well, not when USERID failed to match ERROR */
X   /* but there's no good error to return in that case */
X   return 0;
X  }
X if ((remote != rremote) || (local != rlocal))
X  {
X   (void) close(s);
X   errno = EIO;
X   return 0;
X  }
X /* XXX: we're not going to do any backslash processing */
X (void) close(s);
X return ruser;
X}
END_OF_FILE
if test 3622 -ne `wc -c <'authuser.c'`; then
    echo shar: \"'authuser.c'\" unpacked with wrong size!
fi
# end of 'authuser.c'
fi
if test -f 'authuser.h' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'authuser.h'\"
else
echo shar: Extracting \"'authuser.h'\" \(161 characters\)
sed "s/^X//" >'authuser.h' <<'END_OF_FILE'
X#ifndef AUTHUSER_H
X#define AUTHUSER_H
X
Xextern unsigned short auth_tcpport;
Xextern char *auth_xline();
Xextern int auth_fd();
Xextern char *auth_tcpuser();
X
X#endif
END_OF_FILE
if test 161 -ne `wc -c <'authuser.h'`; then
    echo shar: \"'authuser.h'\" unpacked with wrong size!
fi
# end of 'authuser.h'
fi
if test -f 'dupdup.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'dupdup.c'\"
else
echo shar: Extracting \"'dupdup.c'\" \(2174 characters\)
sed "s/^X//" >'dupdup.c' <<'END_OF_FILE'
X/* Public domain. */
X
X#include <fcntl.h>
X#include "dupdup.h"
X
Xstatic int dupit(old,new)
Xint old;
Xint new;
X{
X/* What follows is roughly equivalent to the following:
X      if (dup2(old,new) == -1) return -1; close(old); return 0;
X   Differences: errno can be different; this works under System V;
X   this is about twice as slow.
X*/
X if (old == new) /* shouldn't happen */
X   return 0;
X if (fcntl(old,F_GETFL,0) == -1) /* old is bad */
X   return -1;
X close(new); /* XXX: check error codes? */
X if (fcntl(old,F_DUPFD,new) == -1) /* can't dup */
X   return -1;
X close(old); /*XXX*/
X return 0;
X}
X
Xint dupdup(d,n)
Xint *d;
Xint n;
X{
X int i;
X int j;
X int k;
X int l;
X
X /* Descriptor i will become descriptor d[i], if d[i] != -1. */
X /* The original descriptor d[i] will disappear. */
X /* The array d[i] may be mangled freely. */
X /* n is the size of d[]. */
X /* No guarantees if i and j both become k. */
X /* errno is set properly on a -1 return. */
X
X for (i = 0;i < n;++i)
X   if (d[i] != -1)
X    {
X     for (j = d[i];(j != -1) && (j != i) && (j != d[j]);j = d[j])
X       ;
X     if ((j == -1) || (j == d[j]))
X       if (j == i)
X	 ; /* self-loop */
X       else
X	{ /* no cycle */
X	 if (j != -1)
X	   d[j] = -1;
X	 if (d[d[i]] == -1) /*XXX*/
X	  {
X	   if (dupit(i,d[i]) == -1)
X	     return -1;
X	   d[i] = -1;
X	  }
X	 else
X	  {
X	   k = i; j = d[i];
X	   do
X	    {
X	     l = d[j]; d[j] = k; k = j; j = l;
X	    }
X	   while (j != -1);
X	   for (j = k;j != i;j = k)
X	    {
X	     if (dupit(d[j],j) == -1)
X	       return -1;
X	     k = d[j];
X	     d[j] = -1;
X	    }
X	   d[i] = -1;
X	  }
X	}
X     else
X      { /* cycle */
X       if (dupit(i,n) == -1)
X	 return -1;
X       if (d[d[i]] == i) /*XXX*/
X	{
X	 if (dupit(d[i],i) == -1)
X	   return -1;
X	 if (dupit(n,d[i]) == -1)
X	   return -1;
X	 d[d[i]] = -1;
X	 d[i] = -1;
X	}
X       else
X        {
X         k = i; j = d[i];
X         do
X          {
X           l = d[j]; d[j] = k; k = j; j = l;
X          }
X         while (j != i);
X         for (j = k;j != i;j = k)
X          {
X	   if (dupit(d[j],j) == -1)
X	     return -1;
X	   k = d[j];
X           d[j] = -1;
X          }
X         d[i] = -1;
X	 if (dupit(n,k) == -1)
X	   return -1;
X        }
X      }
X    }
X return 0;
X}
END_OF_FILE
if test 2174 -ne `wc -c <'dupdup.c'`; then
    echo shar: \"'dupdup.c'\" unpacked with wrong size!
fi
# end of 'dupdup.c'
fi
if test -f 'dupdup.h' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'dupdup.h'\"
else
echo shar: Extracting \"'dupdup.h'\" \(64 characters\)
sed "s/^X//" >'dupdup.h' <<'END_OF_FILE'
X#ifndef DUPDUP_H
X#define DUPDUP_H
X
Xextern int dupdup();
X
X#endif
END_OF_FILE
if test 64 -ne `wc -c <'dupdup.h'`; then
    echo shar: \"'dupdup.h'\" unpacked with wrong size!
fi
# end of 'dupdup.h'
fi
if test -f 'env.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'env.c'\"
else
echo shar: Extracting \"'env.c'\" \(2157 characters\)
sed "s/^X//" >'env.c' <<'END_OF_FILE'
X/* Public domain. */
X
X/*
XThese are portable versions of putenv(). env_put("FOO=BAR") is like
XFOO=BAR inside sh; env_unset("FOO") unsets any variable FOO. env_init()
Xis optional initialization. env_get is just like getenv. Of course, all
Xchanges are tracked through environ, so execvp() and friends will pick
Xup the new variables.
X*/
X
X/* uses environ, malloc, free, strlen, strncmp */
X
X#include "env.h"
X#include "malloc.h"
X
Xextern char **environ;
Xstatic int init = 0;
Xstatic int numenv;
Xstatic int allocenv;
X
Xextern char *env_get(s)
Xchar *s;
X{
X int i;
X int slen;
X
X if (!init)
X   if (env_init())
X     return 0;
X
X slen = strlen(s);
X for (i = 0;i < numenv;++i)
X   if ((!strncmp(s,environ[i],slen)) && (environ[i][slen] == '='))
X     return environ[i] + slen + 1;
X return 0;
X}
X
Xextern int env_unset(s)
Xchar *s;
X{
X int i;
X int slen;
X 
X if (!init)
X   if (env_init())
X     return -1;
X slen = strlen(s);
X for (i = 0;i < numenv;++i)
X   if ((!strncmp(s,environ[i],slen)) && (environ[i][slen] == '='))
X    {
X     if (i < --numenv)
X       environ[i] = environ[numenv];
X     environ[numenv] = 0;
X    }
X return 0;
X}
X
Xstatic int env_realloc()
X{
X char **envp;
X
X allocenv = numenv + 30;
X envp = environ;
X environ = (char **) malloc(allocenv * (int) sizeof(char *));
X if (!environ)
X  {
X   environ = envp;
X   allocenv = numenv;
X   return -1;
X  }
X numenv = 0;
X while (*envp)
X  {
X   environ[numenv] = *envp;
X   ++numenv;
X   ++envp;
X  }
X environ[numenv] = 0;
X free((char *) (envp - numenv));
X return 0;
X}
X
Xstatic int env_add(s)
Xchar *s;
X{
X char *t;
X for (t = s;*t;++t)
X   if (*t == '=')
X     break;
X if (*t)
X  {
X   *t = 0;
X   if (env_unset(s))
X     return -1;
X   *t = '=';
X  }
X if (numenv == allocenv)
X   if (env_realloc())
X     return -1;
X environ[numenv] = s;
X ++numenv;
X environ[numenv] = 0;
X return 0;
X}
X
Xint env_init()
X{
X char **envp;
X
X numenv = 0;
X allocenv = 0;
X envp = environ;
X environ = (char **) malloc(sizeof(char *));
X if (!environ)
X  {
X   environ = envp;
X   return -1;
X  }
X init = 1;
X while (*envp)
X  {
X   if (env_add(*envp))
X     return -1;
X   ++envp;
X  }
X return 0;
X}
X
Xint env_put(s)
Xchar *s;
X{
X if (!init)
X   if (env_init())
X     return -1;
X return env_add(s);
X}
END_OF_FILE
if test 2157 -ne `wc -c <'env.c'`; then
    echo shar: \"'env.c'\" unpacked with wrong size!
fi
# end of 'env.c'
fi
if test -f 'env.h' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'env.h'\"
else
echo shar: Extracting \"'env.h'\" \(153 characters\)
sed "s/^X//" >'env.h' <<'END_OF_FILE'
X#ifndef ENV_H
X#define ENV_H
X
Xextern int env_init();
Xextern int env_put();
Xextern int env_unset();
Xextern char *env_get(); /* for completeness */
X
X#endif
END_OF_FILE
if test 153 -ne `wc -c <'env.h'`; then
    echo shar: \"'env.h'\" unpacked with wrong size!
fi
# end of 'env.h'
fi
if test -f 'errno.h' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'errno.h'\"
else
echo shar: Extracting \"'errno.h'\" \(78 characters\)
sed "s/^X//" >'errno.h' <<'END_OF_FILE'
X#ifndef ERRNO_H
X#define ERRNO_H
X
X#include <errno.h>
Xextern int errno;
X
X#endif
END_OF_FILE
if test 78 -ne `wc -c <'errno.h'`; then
    echo shar: \"'errno.h'\" unpacked with wrong size!
fi
# end of 'errno.h'
fi
if test -f 'getopt.h' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'getopt.h'\"
else
echo shar: Extracting \"'getopt.h'\" \(298 characters\)
sed "s/^X//" >'getopt.h' <<'END_OF_FILE'
X#ifndef GETOPT_H
X#define GETOPT_H
X
X/* I'm trusting the user to acquire a getopt library, rather than
Xproviding one myself. This is probably a mistake. */
X
X/* The following should be in /usr/include/getopt.h but often aren't. */
X
Xextern int getopt();
Xextern char *optarg;
Xextern int optind;
X
X#endif
END_OF_FILE
if test 298 -ne `wc -c <'getopt.h'`; then
    echo shar: \"'getopt.h'\" unpacked with wrong size!
fi
# end of 'getopt.h'
fi
if test -f 'hostname.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'hostname.c'\"
else
echo shar: Extracting \"'hostname.c'\" \(1191 characters\)
sed "s/^X//" >'hostname.c' <<'END_OF_FILE'
X/* History:
X5/1/91 DJB baseline public domain. todo: cache hosts.
X*/
X
X#include <sys/types.h>
X#include <sys/socket.h>
X#include <netdb.h>
X#include <netinet/in.h>
X#include "hostname.h"
X#include "numeric.h"
X
Xint inaddr2hostname(inaddr,hostname)
Xstruct in_addr inaddr;
Xchar **hostname;
X{
X struct hostent *he;
X static char hn[30];
X unsigned char *x;
X
X if (he = gethostbyaddr(&inaddr,sizeof(inaddr),AF_INET))
X  {
X   *hostname = he->h_name;
X   return 0;
X  }
X x = (unsigned char *) &inaddr;
X sprintf(hn,"%d.%d.%d.%d"
X   ,(int) (unsigned int) x[0],(int) (unsigned int) x[1]
X   ,(int) (unsigned int) x[2],(int) (unsigned int) x[3]
X  );
X *hostname = hn;
X return 1;
X}
X
Xint hostname2inaddr(hostname,inaddr)
Xchar *hostname;
Xstruct in_addr *inaddr;
X{
X struct hostent *he;
X char *x;
X int h1; int h2; int h3; int h4;
X
X x = (char *) inaddr;
X if (numericdots(hostname) == 3)
X   if (sscanf(hostname,"%d.%d.%d.%d",&h1,&h2,&h3,&h4) == 4)
X    {
X     x[0] = h1; x[1] = h2; x[2] = h3; x[3] = h4;
X     return 1;
X    }
X /* could use inet_ntoa here */
X he = gethostbyname(hostname);
X if (!he)
X   return -1; /*XXX*/
X x[0] = he->h_addr[0];
X x[1] = he->h_addr[1];
X x[2] = he->h_addr[2];
X x[3] = he->h_addr[3];
X return 0;
X}
END_OF_FILE
if test 1191 -ne `wc -c <'hostname.c'`; then
    echo shar: \"'hostname.c'\" unpacked with wrong size!
fi
# end of 'hostname.c'
fi
if test -f 'hostname.h' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'hostname.h'\"
else
echo shar: Extracting \"'hostname.h'\" \(107 characters\)
sed "s/^X//" >'hostname.h' <<'END_OF_FILE'
X#ifndef HOSTNAME_H
X#define HOSTNAME_H
X
Xextern int inaddr2hostname();
Xextern int hostname2inaddr();
X
X#endif
END_OF_FILE
if test 107 -ne `wc -c <'hostname.h'`; then
    echo shar: \"'hostname.h'\" unpacked with wrong size!
fi
# end of 'hostname.h'
fi
if test -f 'malloc.h' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'malloc.h'\"
else
echo shar: Extracting \"'malloc.h'\" \(66 characters\)
sed "s/^X//" >'malloc.h' <<'END_OF_FILE'
X#ifndef MALLOC_H
X#define MALLOC_H
X
Xextern char *malloc();
X
X#endif
END_OF_FILE
if test 66 -ne `wc -c <'malloc.h'`; then
    echo shar: \"'malloc.h'\" unpacked with wrong size!
fi
# end of 'malloc.h'
fi
if test -f 'npipekiller.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'npipekiller.c'\"
else
echo shar: Extracting \"'npipekiller.c'\" \(3207 characters\)
sed "s/^X//" >'npipekiller.c' <<'END_OF_FILE'
X/* Public domain. */
X
X#include <stdio.h>
X#include <sys/types.h>
X#include <sys/file.h>
X#include <signal.h>
X#include <fcntl.h>
X#include "dupdup.h"
X#include "malloc.h"
X#include "errno.h"
X#include "username.h"
X#include "env.h"
X#include "getopt.h"
X#include "numfiles.h"
X
X#ifndef F_LOCK
X#define F_LOCK 1
X#endif
X#ifndef O_RDONLY
X#define O_RDONLY 0
X#endif
X#ifndef O_WRONLY
X#define O_WRONLY 1
X#endif
X#ifndef O_RDWR
X#define O_RDWR 2
X#endif
X
Xstatic int flagverbose = 1;
X
Xstatic char errbuf[500];
Xvoid die(n,s) int n; char *s;
X{ if (flagverbose) fprintf(stderr,"npipekiller: fatal: %s\n",s); exit(n); }
Xvoid dies(n,s,t) int n; char *s; char *t;
X{ if (flagverbose) fprintf(stderr,"npipekiller: fatal: %s%s\n",s,t); exit(n); }
Xvoid diep(n,s) int n; char *s;
X{ if (flagverbose) sprintf(errbuf,"npipekiller: fatal: %s",s); perror(errbuf); exit(n); }
Xvoid warnp(s) char *s;
X{ if (flagverbose) sprintf(errbuf,"npipekiller: warning: %s",s); perror(errbuf); }
Xvoid warnsp(s,t) char *s; char *t;
X{ if (flagverbose) sprintf(errbuf,"npipekiller: warning: %s%s",s,t); perror(errbuf); }
X
Xmain(argc,argv,envp)
Xint argc;
Xchar *argv[];
Xchar *envp[];
X{
X int arguid;
X int uid;
X int i;
X int fdserv;
X int fdlock;
X char fnlock[200];
X char fnserv[200];
X int m;
X int n;
X int r;
X char buf[100];
X char *uname;
X int opt;
X
X while ((opt = getopt(argc,argv,"qQ")) != EOF)
X   switch(opt)
X    {
X     case 'q':
X       flagverbose = 0; break;
X     case 'Q':
X       flagverbose = 1; break;
X     case '?':
X       break; /*XXX*/
X     default:
X       break; /*XXX*/
X    }
X argc -= optind; argv += optind;
X
X if (argc < 2)
X   die(1,"need at least two arguments");
X
X uid = getuid();
X if (username2uid(argv[0],&arguid) == -1)
X   dies(2,"cannot figure out username ",argv[0]);
X
X if (arguid != uid)
X   dies(1,"permission denied by ",argv[0]);
X
X for (i = 0;argv[0][i];++i)
X   if ((argv[0][i] == '/') || (argv[0][i] == ':') || (argv[0][i] == '.') || (argv[0][i] == '\n'))
X     dies(4,"illegal characters in username ",argv[0]);
X 
X for (i = 0;argv[1][i];++i)
X   if ((argv[1][i] == '/') || (argv[1][i] == '.') || (argv[0][i] == '\n'))
X     dies(5,"illegal characters in service ",argv[1]);
X
X signal(SIGPIPE,SIG_IGN);
X
X if (uid2username(uid,&uname) == -1) /* will never happen */
X   die(2,"cannot figure out my own username");
X
X if (strlen(NPIPEDIR) + strlen(argv[0]) + strlen(argv[1]) + 1 > 90) /*XXX*/
X   die(8,"server filenames too long");
X sprintf(fnserv,"%s/%ds%s",NPIPEDIR,arguid,argv[1]);
X sprintf(fnlock,"%s/%dl%s",NPIPEDIR,arguid,argv[1]);
X sprintf(buf,"%d",0);
X n = strlen(buf);
X if (n + strlen(uname) + 10 > sizeof(buf))
X   die(8,"username too long");
X strcpy(buf + n + 1,uname);
X n += strlen(uname) + 2;
X
X fdlock = open(fnlock,O_RDWR,0);
X if (fdlock == -1)
X   diep(1,"cannot open lock file");
X /* Here's the tricky bit: file locking. :-( */
X /* XXX: We assume that anyone with named pipes also has lockf(). */
X if (lockf(fdlock,F_LOCK,1) == -1)
X   diep(1,"cannot wait for lock on lock file");
X
X fdserv = open(fnserv,O_WRONLY,0);
X if (fdserv == -1)
X   diep(1,"cannot open server's named pipe");
X
X m = 0;
X r = 0;
X while ((m < n) && ((r = write(fdserv,buf + m,n - m)) > 0))
X   m += r;
X if (r <= 0)
X   die(1,"cannot tell server to kill itself");
X
X exit(0);
X}
END_OF_FILE
if test 3207 -ne `wc -c <'npipekiller.c'`; then
    echo shar: \"'npipekiller.c'\" unpacked with wrong size!
fi
# end of 'npipekiller.c'
fi
if test -f 'numeric.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'numeric.c'\"
else
echo shar: Extracting \"'numeric.c'\" \(782 characters\)
sed "s/^X//" >'numeric.c' <<'END_OF_FILE'
X/* History:
X6/19/91 DJB added numericdots()
X5/1/91 DJB baseline public domain
X*/
X
X/*
X
Xint numeric(s) char *s; returns 1 if s is entirely composed of the
Xdigits 0 through 9, 0 otherwise.
X
X*/
X
X#include "numeric.h"
X
Xint numeric(s)
Xchar *s;
X{
X while (*s)
X  {
X   if ((*s != '0') && (*s != '1') && (*s != '2') && (*s != '3') && (*s != '4')
X    && (*s != '5') && (*s != '6') && (*s != '7') && (*s != '8') && (*s != '9'))
X     return 0;
X   ++s;
X  }
X return 1;
X}
X
Xint numericdots(s)
Xchar *s;
X{
X int dots;
X
X dots = 0;
X while (*s)
X  {
X   if ((*s != '0') && (*s != '1') && (*s != '2') && (*s != '3') && (*s != '4')
X    && (*s != '5') && (*s != '6') && (*s != '7') && (*s != '8') && (*s != '9')
X    && (*s != '.')
X    )
X     return -1;
X   if (*s == '.')
X     ++dots;
X   ++s;
X  }
X return dots;
X}
END_OF_FILE
if test 782 -ne `wc -c <'numeric.c'`; then
    echo shar: \"'numeric.c'\" unpacked with wrong size!
fi
# end of 'numeric.c'
fi
if test -f 'numeric.h' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'numeric.h'\"
else
echo shar: Extracting \"'numeric.h'\" \(93 characters\)
sed "s/^X//" >'numeric.h' <<'END_OF_FILE'
X#ifndef NUMERIC_H
X#define NUMERIC_H
X
Xextern int numeric();
Xextern int numericdots();
X
X#endif
END_OF_FILE
if test 93 -ne `wc -c <'numeric.h'`; then
    echo shar: \"'numeric.h'\" unpacked with wrong size!
fi
# end of 'numeric.h'
fi
if test -f 'numfiles.h' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'numfiles.h'\"
else
echo shar: Extracting \"'numfiles.h'\" \(82 characters\)
sed "s/^X//" >'numfiles.h' <<'END_OF_FILE'
X#ifndef NUMFILES_H
X#define NUMFILES_H
X
X#define NUMFILES (getdtablesize())
X
X#endif
END_OF_FILE
if test 82 -ne `wc -c <'numfiles.h'`; then
    echo shar: \"'numfiles.h'\" unpacked with wrong size!
fi
# end of 'numfiles.h'
fi
if test -f 'portname.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'portname.c'\"
else
echo shar: Extracting \"'portname.c'\" \(764 characters\)
sed "s/^X//" >'portname.c' <<'END_OF_FILE'
X/* History:
X6/20/91 DJB added proto arg
X5/9/91 DJB fixed for backwards architectures, tnx VA
X5/1/91 DJB baseline public domain
X*/
X
X#include "portname.h"
X#include "numeric.h"
X#include <netdb.h>
X
X/* XXX: cache */
X
Xint port2portname(port,pop,proto)
Xint port;
Xchar **pop;
Xchar *proto;
X{
X struct servent *se;
X static char po[20];
X
X if (se = getservbyport(port,proto))
X  {
X   *pop = se->s_name;
X   return 0;
X  }
X sprintf(po,"%d",port);
X *pop = po;
X return 1;
X}
X
Xint portname2port(po,port,proto)
Xchar *po;
Xint *port;
Xchar *proto;
X{
X struct servent *se;
X
X if (numeric(po))
X  {
X   *port = atoi(po);
X   return 1;
X  }
X se = getservbyname(po,proto);
X if (!se)
X   return -1; /*XXX*/
X *port = ntohs(se->s_port);
X   /* XXX: stupidity alert: se->s_port is an int! */
X return 0;
X}
END_OF_FILE
if test 764 -ne `wc -c <'portname.c'`; then
    echo shar: \"'portname.c'\" unpacked with wrong size!
fi
# end of 'portname.c'
fi
if test -f 'portname.h' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'portname.h'\"
else
echo shar: Extracting \"'portname.h'\" \(103 characters\)
sed "s/^X//" >'portname.h' <<'END_OF_FILE'
X#ifndef PORTNAME_H
X#define PORTNAME_H
X
Xextern int port2portname();
Xextern int portname2port();
X
X#endif
END_OF_FILE
if test 103 -ne `wc -c <'portname.h'`; then
    echo shar: \"'portname.h'\" unpacked with wrong size!
fi
# end of 'portname.h'
fi
if test -f 'tcpkiller.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'tcpkiller.c'\"
else
echo shar: Extracting \"'tcpkiller.c'\" \(2818 characters\)
sed "s/^X//" >'tcpkiller.c' <<'END_OF_FILE'
X/* Public domain. */
X
X#include <stdio.h>
X#include <sys/types.h>
X#include <sys/param.h>
X#include <sys/file.h>
X#include <sys/socket.h>
X#include <signal.h>
X#include <netinet/in.h>
X#include "errno.h"
X#include "username.h"
X#include "hostname.h"
X#include "portname.h"
X#include "getopt.h"
X#include "malloc.h"
X#include "env.h"
X
X#ifndef MAXHOSTNAMELEN
X#define MAXHOSTNAMELEN 64
X#endif
X
Xstatic int flagverbose = 1;
X
Xstatic char errbuf[500];
Xvoid die(n,s) int n; char *s;
X{ if (flagverbose) fprintf(stderr,"tcpkiller: fatal: %s\n",s); exit(n); }
Xvoid dies(n,s,t) int n; char *s; char *t;
X{ if (flagverbose) fprintf(stderr,"tcpkiller: fatal: %s%s\n",s,t); exit(n); }
Xvoid diep(n,s) int n; char *s;
X{ if (flagverbose) sprintf(errbuf,"tcpkiller: fatal: %s",s); perror(errbuf); exit(n); }
Xvoid warnp(s) char *s;
X{ if (flagverbose) sprintf(errbuf,"tcpkiller: warning: %s",s); perror(errbuf); }
Xvoid warnsp(s,t) char *s; char *t;
X{ if (flagverbose) sprintf(errbuf,"tcpkiller: warning: %s%s",s,t); perror(errbuf); }
X
Xmain(argc,argv,envp)
Xint argc;
Xchar *argv[];
Xchar *envp[];
X{
X int uid;
X int opt;
X char lochost[MAXHOSTNAMELEN];
X int locport;
X char *home;
X char *fnrecord;
X char pidstr[50];
X int pid;
X int fd;
X
X while ((opt = getopt(argc,argv,"qQ")) != EOF)
X   switch(opt)
X    {
X     case 'q':
X       flagverbose = 0; break;
X     case 'Q':
X       flagverbose = 1; break;
X     case '?':
X       break; /*XXX*/
X     default:
X       break; /*XXX*/
X    }
X argc -= optind; argv += optind;
X
X if (argc < 2)
X   die(1,"need at least two arguments");
X
X uid = getuid();
X
X gethostname(lochost,sizeof(lochost));
X
X if ((argv[0][0] == '0') && (argv[0][1] == 0))
X   ; /* local host, fine */
X else
X  {
X   struct in_addr inaddr1;
X   struct in_addr inaddr2;
X   if (hostname2inaddr(argv[0],&inaddr1) == -1)
X     dies(2,"cannot figure out hostname ",argv[0]);
X   if (hostname2inaddr(lochost,&inaddr2) == -1)
X     die(2,"cannot figure out my own hostname");
X   /* XXX: this doesn't allow 127.1 */
X   if (inaddr1.s_addr != inaddr2.s_addr)
X     dies(2,"host does not match local host ",argv[0]);
X  }
X
X if (portname2port(argv[1],&locport,"tcp") == -1)
X   dies(2,"cannot figure out portname ",argv[1]);
X locport = locport & 65535;
X
X home = env_get("TCPHOME");
X if (!home)
X  {
X   home = env_get("HOME");
X   if (!home)
X     die(1,"cannot find TCPHOME or HOME in environment");
X  }
X fnrecord = malloc(strlen(home) + strlen(lochost) + 100);
X if (!fnrecord)
X   die(1,"out of memory");
X sprintf(fnrecord,"%s/.tcpserver.%s.%d.%d",home,lochost,uid,locport);
X
X fd = open(fnrecord,O_RDONLY,0400);
X if (fd == -1)
X   dies(1,"cannot open ",fnrecord);
X
X read(fd,pidstr,sizeof(pidstr)); /* XXX: check for partial reads */
X if (sscanf(pidstr,"%d",&pid) != 1)
X   die(1,"cannot figure out pid of tcpserver");
X
X close(fd);
X
X kill(pid,SIGTERM); /*XXX: report errors? */
X
X exit(0);
X}
END_OF_FILE
if test 2818 -ne `wc -c <'tcpkiller.c'`; then
    echo shar: \"'tcpkiller.c'\" unpacked with wrong size!
fi
# end of 'tcpkiller.c'
fi
if test -f 'testmain' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'testmain'\"
else
echo shar: Extracting \"'testmain'\" \(269 characters\)
sed "s/^X//" >'testmain' <<'END_OF_FILE'
X#!/bin/sh
X# testmain args
X./testucspi ${1+"$@"} | sed 's/=.*//' > .ucspi.$$
X./testresult ${1+"$@"} | sed 's/=.*//' > .result.$$
Xif cmp .ucspi.$$ .result.$$ >/dev/null 2>&1
Xthen echo 'Everything compares okay.'
Xelse echo 'Aaack! Test failed.'
Xfi
Xrm .ucspi.$$ .result.$$
END_OF_FILE
if test 269 -ne `wc -c <'testmain'`; then
    echo shar: \"'testmain'\" unpacked with wrong size!
fi
chmod +x 'testmain'
# end of 'testmain'
fi
if test -f 'testresult' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'testresult'\"
else
echo shar: Extracting \"'testresult'\" \(915 characters\)
sed "s/^X//" >'testresult' <<'END_OF_FILE'
X#!/bin/sh
X# testresult proto prog address
X# XXX: test args
Xproto="$1"; shift; export proto
Xprog="$1"; shift
Xclient=./"$prog"client; export client
Xserver=./"$prog"server; export server
Xkiller=./"$prog"killer; export killer
Xecho "$server started, ${proto}LOCAL=(depends on the protocol)"
Xecho "$client started"
Xecho "$client connected to ${proto}REMOTE=(depends on the protocol)"
Xecho "$client reading line from server..."
Xecho "$server accepted connection from ${proto}REMOTE=(depends on the protocol)"
Xecho "$server writing line to client..."
Xecho "$client received from server: is anybody out there..."
Xecho "$client writing line to server..."
Xecho "$server reading line from client..."
Xecho "$server received from client: is anybody in there..."
Xecho "$server done with connection"
Xecho "$client done with connection"
Xecho "$client finished"
Xecho "$killer started"
Xecho "$server finished"
Xecho "$killer finished"
END_OF_FILE
if test 915 -ne `wc -c <'testresult'`; then
    echo shar: \"'testresult'\" unpacked with wrong size!
fi
chmod +x 'testresult'
# end of 'testresult'
fi
if test -f 'testucspi' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'testucspi'\"
else
echo shar: Extracting \"'testucspi'\" \(1220 characters\)
sed "s/^X//" >'testucspi' <<'END_OF_FILE'
X#!/bin/sh
X# testucspi proto prog address
X# XXX: test args
Xproto="$1"; shift; export proto
Xprog="$1"; shift
Xclient=./"$prog"client; export client
Xserver=./"$prog"server; export server
Xkiller=./"$prog"killer; export killer
X
X( 
Xecho "$server started, ${proto}LOCAL=" | tr -d '\012'
X# blessed be the shells that allow "$server" here
X$server -4 "$@" sh -c '
X  exec <&6
X  sleep 5
X  echo "$server accepted connection from ${proto}REMOTE=" | tr -d "\012"
X  printenv ${proto}REMOTE
X  echo "$server writing line to client..."
X  echo "is anybody out there..." >&7
X  sleep 5
X  echo "$server reading line from client..."
X  read i
X  echo "$server received from client: $i"
X  echo "$server done with connection"
X' 4>&1 
Xecho "$server finished"
X) &
X
Xsleep 5
X
Xecho "$client started"
X$client "$@" sh -c '
X  exec <&6
X  sleep 1
X  echo "$client connected to ${proto}REMOTE=" | tr -d "\012"
X  printenv ${proto}REMOTE
X  echo "$client reading line from server..."
X  read i
X  echo "$client received from server: $i"
X  echo "$client writing line to server..."
X  echo "is anybody in there..." >&7
X  sleep 5
X  echo "$client done with connection"
X'
Xecho "$client finished"
X
Xecho "$killer started"
Xeval "$killer" "$@"
Xsleep 2
Xecho "$killer finished"
END_OF_FILE
if test 1220 -ne `wc -c <'testucspi'`; then
    echo shar: \"'testucspi'\" unpacked with wrong size!
fi
chmod +x 'testucspi'
# end of 'testucspi'
fi
if test -f 'undomclient.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'undomclient.c'\"
else
echo shar: Extracting \"'undomclient.c'\" \(3980 characters\)
sed "s/^X//" >'undomclient.c' <<'END_OF_FILE'
X/* Public domain. */
X
X#include <stdio.h>
X#include <sys/types.h>
X#include <sys/socket.h>
X#include <sys/un.h>
X#include <signal.h>
X#include "dupdup.h"
X#include "malloc.h"
X#include "errno.h"
X#include "username.h"
X#include "env.h"
X#include "getopt.h"
X#include "numfiles.h"
X
Xstatic int flagverbose = 1;
Xstatic struct sockaddr_un sa;
X
Xstatic char errbuf[500];
Xvoid die(n,s) int n; char *s;
X{ if (flagverbose) fprintf(stderr,"undomclient: fatal: %s\n",s); exit(n); }
Xvoid dies(n,s,t) int n; char *s; char *t;
X{ if (flagverbose) fprintf(stderr,"undomclient: fatal: %s%s\n",s,t); exit(n); }
Xvoid diep(n,s) int n; char *s;
X{ if (flagverbose) sprintf(errbuf,"undomclient: fatal: %s",s); perror(errbuf); exit(n); }
Xvoid warnp(s) char *s;
X{ if (flagverbose) sprintf(errbuf,"undomclient: warning: %s",s); perror(errbuf); }
Xvoid warnsp(s,t) char *s; char *t;
X{ if (flagverbose) sprintf(errbuf,"undomclient: warning: %s%s",s,t); perror(errbuf); }
X
Xmain(argc,argv,envp)
Xint argc;
Xchar *argv[];
Xchar *envp[];
X{
X int t;
X int *d;
X int tdup;
X int numfiles;
X int arguid;
X int uid;
X int i;
X static char undomlocal[200];
X static char undomremote[300];
X unsigned char urlen;
X char *uname;
X int opt;
X
X while ((opt = getopt(argc,argv,"qQ")) != EOF)
X   switch(opt)
X    {
X     case 'q':
X       flagverbose = 0; break;
X     case 'Q':
X       flagverbose = 1; break;
X     case '?':
X       break; /*XXX*/
X     default:
X       break; /*XXX*/
X    }
X argc -= optind; argv += optind;
X
X if (argc < 3)
X   die(1,"need at least three arguments");
X
X uid = getuid();
X if (username2uid(argv[0],&arguid) == -1)
X   dies(2,"cannot figure out username ",argv[0]);
X /* XXX: any permission checks? */
X
X for (i = 0;argv[0][i];++i)
X   if ((argv[0][i] == '/') || (argv[0][i] == ':') || (argv[0][i] == '.') || (argv[0][i] == '\n'))
X     dies(4,"illegal characters in username ",argv[0]);
X 
X for (i = 0;argv[1][i];++i)
X   if ((argv[1][i] == '/') || (argv[1][i] == '.') || (argv[0][i] == '\n'))
X     dies(5,"illegal characters in service ",argv[1]);
X
X close(6);
X close(7); /* XXX: these have implications that should be documented */
X
X signal(SIGPIPE,SIG_IGN);
X
X if (uid2username(uid,&uname) == -1) /* will never happen */
X   die(2,"cannot figure out my own username");
X urlen = strlen(uname) + 1;
X
X numfiles = NUMFILES;
X d = (int *) malloc(numfiles * sizeof(int));
X if (!d)
X   die(6,"cannot malloc");
X for (i = 0;i < numfiles;++i)
X   d[i] = -1;
X
X if (strlen(UNDOMDIR) + strlen(argv[0]) + strlen(argv[1]) + 1 > 100) /*XXX*/
X   die(8,"server socket name too long");
X sprintf(sa.sun_path,"%s/%s:%s",UNDOMDIR,argv[0],argv[1]);
X
X if (env_init() == -1)
X   die(11,"cannot init environment");
X if (env_put("PROTO=UNDOM") == -1)
X   die(11,"out of memory putting PROTO into environment");
X sprintf(undomlocal,"UNDOMLOCAL=%s",uname);
X if (env_put(undomlocal) == -1)
X   die(11,"out of memory putting UNDOMLOCAL into environment");
X sprintf(undomremote,"UNDOMREMOTE=%s:%s",argv[0],argv[1]);
X if (env_put(undomremote) == -1)
X   die(11,"out of memory putting UNDOMREMOTE into environment");
X
X t = socket(AF_UNIX,SOCK_STREAM,0);
X if (t == -1)
X   diep(7,"cannot create client socket");
X sa.sun_family = AF_UNIX;
X if (connect(t,&sa,sizeof(sa)) == -1)
X   diep(9,"cannot connect to server");
X
X /* XXX: fork? not necessary here */
X
X if ((i = write(t,&urlen,1)) == -1)
X   diep(1,"cannot write length of local username");
X if (!i) /* ever? */
X   die(1,"cannot write length of local username");
X if (write(t,uname,urlen) < urlen)
X   die(1,"cannot write local username");
X
X tdup = dup(t);
X if (tdup == -1)
X   diep(10,"cannot dup connection to server");
X
X /* Now put t into descriptor 6 and tdup into descriptor 7. */
X /* XXX: should check that t and tdup are small enough */
X d[t] = 6;
X d[tdup] = 7;
X if (dupdup(d,numfiles) == -1)
X   diep(10,"cannot dup connection to server");
X
X if (setreuid(uid,uid) == -1)
X   diep(1,"cannot setreuid"); /* will never happen */
X signal(SIGPIPE,SIG_DFL);
X execvp(argv[2],argv + 2);
X warnsp("cannot exec ",argv[2]);
X exit(1);
X}
END_OF_FILE
if test 3980 -ne `wc -c <'undomclient.c'`; then
    echo shar: \"'undomclient.c'\" unpacked with wrong size!
fi
# end of 'undomclient.c'
fi
if test -f 'undomkiller.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'undomkiller.c'\"
else
echo shar: Extracting \"'undomkiller.c'\" \(2703 characters\)
sed "s/^X//" >'undomkiller.c' <<'END_OF_FILE'
X/* Public domain. */
X
X#include <stdio.h>
X#include <sys/types.h>
X#include <sys/socket.h>
X#include <sys/un.h>
X#include <signal.h>
X#include "errno.h"
X#include "username.h"
X#include "getopt.h"
X
Xstatic int flagverbose = 1;
Xstatic struct sockaddr_un sa;
X
Xstatic char errbuf[500];
Xvoid die(n,s) int n; char *s;
X{ if (flagverbose) fprintf(stderr,"undomkiller: fatal: %s\n",s); exit(n); }
Xvoid dies(n,s,t) int n; char *s; char *t;
X{ if (flagverbose) fprintf(stderr,"undomkiller: fatal: %s%s\n",s,t); exit(n); }
Xvoid diep(n,s) int n; char *s;
X{ if (flagverbose) sprintf(errbuf,"undomkiller: fatal: %s",s); perror(errbuf); exit(n); }
Xvoid warnp(s) char *s;
X{ if (flagverbose) sprintf(errbuf,"undomkiller: warning: %s",s); perror(errbuf); }
Xvoid warnsp(s,t) char *s; char *t;
X{ if (flagverbose) sprintf(errbuf,"undomkiller: warning: %s%s",s,t); perror(errbuf); }
X
Xmain(argc,argv,envp)
Xint argc;
Xchar *argv[];
Xchar *envp[];
X{
X int t;
X int arguid;
X int uid;
X int i;
X unsigned char urlen;
X char *uname;
X int opt;
X
X while ((opt = getopt(argc,argv,"qQ")) != EOF)
X   switch(opt)
X    {
X     case 'q':
X       flagverbose = 0; break;
X     case 'Q':
X       flagverbose = 1; break;
X     case '?':
X       break; /*XXX*/
X     default:
X       break; /*XXX*/
X    }
X argc -= optind; argv += optind;
X
X if (argc < 2)
X   die(1,"need at least two arguments");
X
X uid = getuid();
X if (username2uid(argv[0],&arguid) == -1)
X   dies(2,"cannot figure out username ",argv[0]);
X
X if (arguid != uid)
X   dies(15,"permission denied by ",argv[0]);
X /* XXX: special-case root? more checks? */
X /* This is enough to prevent one user from wasting another's CPU time. */
X
X for (i = 0;argv[0][i];++i)
X   if ((argv[0][i] == '/') || (argv[0][i] == ':') || (argv[0][i] == '.') || (argv[0][i] == '\n'))
X     dies(4,"illegal characters in username ",argv[0]);
X 
X for (i = 0;argv[1][i];++i)
X   if ((argv[1][i] == '/') || (argv[1][i] == '.') || (argv[0][i] == '\n'))
X     dies(5,"illegal characters in service ",argv[1]);
X
X if (uid2username(uid,&uname) == -1) /* will never happen */
X   die(2,"cannot figure out my own username");
X urlen = strlen(uname) + 1;
X
X if (strlen(UNDOMDIR) + strlen(argv[0]) + strlen(argv[1]) + 1 > 100) /*XXX*/
X   die(8,"server socket name too long");
X sprintf(sa.sun_path,"%s/%s:%s",UNDOMDIR,argv[0],argv[1]);
X
X t = socket(AF_UNIX,SOCK_STREAM,0);
X if (t == -1)
X   diep(7,"cannot create killer socket");
X sa.sun_family = AF_UNIX;
X if (connect(t,&sa,sizeof(sa)) == -1)
X   diep(9,"cannot connect to server");
X
X signal(SIGPIPE,SIG_IGN);
X
X urlen = 0; /* XXX: this signals server to clean up and die */
X if ((i = write(t,&urlen,1)) == -1)
X   diep(1,"cannot kill server");
X if (!i) /* ever? */
X   die(1,"cannot kill server");
X
X exit(0);
X}
END_OF_FILE
if test 2703 -ne `wc -c <'undomkiller.c'`; then
    echo shar: \"'undomkiller.c'\" unpacked with wrong size!
fi
# end of 'undomkiller.c'
fi
if test -f 'username.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'username.c'\"
else
echo shar: Extracting \"'username.c'\" \(549 characters\)
sed "s/^X//" >'username.c' <<'END_OF_FILE'
X/* History:
X5/1/91 DJB baseline public domain
X*/
X
X#include <pwd.h>
X#include "username.h"
X#include "numeric.h"
X
X/*XXX: cache */
X
Xint uid2username(uid,unp)
Xint uid;
Xchar **unp;
X{
X struct passwd *pw;
X static char un[20];
X
X if (pw = getpwuid(uid))
X  {
X   *unp = pw->pw_name;
X   return 0;
X  }
X sprintf(un,"%d",uid);
X *unp = un;
X return 1;
X}
X
Xint username2uid(un,uid)
Xchar *un;
Xint *uid;
X{
X struct passwd *pw;
X
X if (numeric(un))
X  {
X   *uid = atoi(un);
X   return 1;
X  }
X pw = getpwnam(un);
X if (!pw)
X   return -1; /*XXX*/
X *uid = pw->pw_uid;
X return 0;
X}
END_OF_FILE
if test 549 -ne `wc -c <'username.c'`; then
    echo shar: \"'username.c'\" unpacked with wrong size!
fi
# end of 'username.c'
fi
if test -f 'username.h' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'username.h'\"
else
echo shar: Extracting \"'username.h'\" \(101 characters\)
sed "s/^X//" >'username.h' <<'END_OF_FILE'
X#ifndef USERNAME_H
X#define USERNAME_H
X
Xextern int uid2username();
Xextern int username2uid();
X
X#endif
END_OF_FILE
if test 101 -ne `wc -c <'username.h'`; then
    echo shar: \"'username.h'\" unpacked with wrong size!
fi
# end of 'username.h'
fi
echo shar: End of archive 1 \(of 2\).
cp /dev/null ark1isdone
MISSING=""
for I in 1 2 ; do
    if test ! -f ark${I}isdone ; then
	MISSING="${MISSING} ${I}"
    fi
done
if test "${MISSING}" = "" ; then
    echo You have unpacked both archives.
    rm -f ark[1-9]isdone
else
    echo You still need to unpack the following archives:
    echo "        " ${MISSING}
fi
##  End of shell archive.
exit 0



More information about the Alt.sources mailing list