clientserver 0.50 (part 2/2)

Dan Bernstein brnstnd at kramden.acf.nyu.edu
Wed Jun 26 09:13:04 AEST 1991


#! /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 2 (of 2)."
# Contents:  UCSPI npipeclient.c npipeserver.c tcpclient.c tcpserver.c
#   undomserver.c
# Wrapped by brnstnd at kramden on Tue Jun 25 18:41:40 1991
PATH=/bin:/usr/bin:/usr/ucb ; export PATH
if test -f 'UCSPI' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'UCSPI'\"
else
echo shar: Extracting \"'UCSPI'\" \(9408 characters\)
sed "s/^X//" >'UCSPI' <<'END_OF_FILE'
XUNIX Client-Server Program Interface, UCSPI-1991
XCopyright 1991, Daniel J. Bernstein
X
X
X1. Introduction
X
XThis document describes the UNIX Client-Server Program Interface, UCSPI
X(ooks-pie), a standard program-based interface to client-server
Xcommunications tools under UNIX and its variants. (UNIX is a trademark
Xof AT&T.)
X
XUCSPI is designed to solve several problems. First, although most
Xnetworked applications today are essentially independent of the
Xunderlying communications protocol, each program must provide direct
Xsupport for each protocol. To run a TCP/IP program over DECnet or
Xthrough other IPC mechanisms requires rewriting and recompiling the
Xprogram. In contrast, an application written for UCSPI will work without
Xchange over any communications medium.
X
XSecond, no standard tools are provided for shell scripts to take
Xadvantage of networking. A UCSPI-compliant communications tool is
Xautomatically usable within a shell script or from other languages.
X
XThird, current applications have no mechanism for passing information
Xabout a communications link. A typical TCP/IP connection to a BSD
Xmachine may go through inetd, an access controller, and one or two
Xapplications. Each level may do several system calls, disk reads, and
Xnetwork requests for a name lookup and possibly authentication, instead
Xof getting the information once and passing it down to the next level.
XIn the case of logins, a user shell cannot even determine reliably where
Xthe connection is from. In contrast, a UCSPI-compliant tool will collect
Xall necessary information and pass it through environment variables to
Xthe lower layers.
X
XA program is not compliant with UCSPI-1991 if it does not satisfy any
Xrule marked MUST. It is compliant if it satisfies all the rules marked
XMUST. In that case, it is unconditionally compliant if it satisfies all
Xthe rules marked SHOULD, and conditionally compliant otherwise.
X
X
X2. The general UCSPI interface
X
XUCSPI clients and servers are executable programs. They MUST accept a
Xcommand line in the following general format:
X
X  <program> <options> <address> <userprogram> <arg...>
X
XHere <program> is the name of the client or server, <options> are zero
Xor more option arguments, <address> is a protocol-specific address,
X<userprogram> is a user-specified program to run upon any connection,
Xand <arg...> are zero or more arguments to pass through to <userprogram>
Xwithout interpretation.
X
XUCSPI killers are executable programs. They MUST accept a command line
Xin the following general format:
X
X  <program> <options> <address>
X
XEach client, server, and killer MUST support some protocol, as defined
Xbelow. <address> SHOULD take up a constant number of arguments, as
Xdefined by the protocol. <options> SHOULD be processed by the getopt
Xstandard; in particular, an argument of -- SHOULD terminate <options>.
X
XIf <program> is a client or server, it MUST change descriptors 6 and 7
Xand certain environment variables as described below before executing
X<userprogram>. <program> MUST NOT interpret, quote, or unquote <arg...>
Xin any way. <program> may or may not fork before executing
X<userprogram>. <program> SHOULD NOT change its process state in any
Xother way before executing <userprogram>. <program> SHOULD close
Xdescriptors 6 and 7 immediately upon entry.
X
X<program> MUST NOT assume that any other particular descriptors are open
Xor closed. <program> may assume that a certain number of descriptors are
Xavailable. <program> SHOULD NOT assume anything else about its process
Xstate; in particular, <program> SHOULD NOT attempt to find its
Xcontrolling terminal device, and <program> SHOULD NOT use getlogin().
X
X
X3. Servers
X
XIf <program> is a UCSPI server, it MUST wait for a client to connect to
X<address>. It SHOULD NOT accept connections from clients that do not
Xsupport the same protocol. Upon accepting a connection, it MUST spawn
X<userprogram> with the given <arg...>, descriptor 6 reading from the
Xconnection, and descriptor 7 writing to the connection. It MUST then
Xcontinue accepting connections to the same <address>.
X
X<program> MUST set the following environment variables for
X<userprogram>: PROTO=<PROTO>, where <PROTO> is the communications
Xprotocol used by the connection; <PROTO>LOCAL=<serveraddress>, where
X<serveraddress> is <address> in a server format defined by the protocol;
X<PROTO>REMOTE=<clientaddress>, where <clientaddress> is some information
Xabout the client in a client format defined by the protocol. <PROTO>
XMUST consist of characters selected from ABCDEFGHIJKLMNOPQRSTUVWXYZ,
Xabcdefghijklmnopqrstuvwxyz, and 0123456789; it MUST NOT be longer than
X100 characters. <serveraddress> and <clientaddress> SHOULD use solely
Xprintable ASCII characters, SHOULD have a predefined maximum length,
Xand MUST NOT contain newline or null.
X
XA server SHOULD accept the following options: -q to turn off all error
Xmessages; -Q to turn on error messages, negating any previous -q; -4 to
Ximmediately write the value of <PROTO>LOCAL, followed by a newline, to
Xdescriptor 4, and then close descriptor 4.
X
XIf the server receives signal SIGTERM, it MUST exit with exit code 0;
Xthis SHOULD NOT terminate any current connections. If the server cannot
Xperform its functions, it MUST exit with a nonzero exit code. The server
XSHOULD interpret SIGINT the same way as SIGTERM.
X
X
X4. Clients
X
XIf <program> is a UCSPI client, it MUST connect to a server at
X<address>. It SHOULD NOT connect to a server that does not support the
Xsame protocol. Upon connecting, it MUST spawn <userprogram> with the
Xgiven <arg...>, descriptor 6 reading from the connection, and descriptor
X7 writing to the connection. It SHOULD NOT make further connections.
X
X<program> MUST set the following environment variables for
X<userprogram>: PROTO=<PROTO>, <PROTO>LOCAL=<clientaddress>, and
X<PROTO>REMOTE=<serveraddress>. Here <PROTO>, <clientaddress>, and
X<remoteaddress> are under the same rules as for servers, but note that
Xthe roles of <PROTO>LOCAL and <PROTO>REMOTE are reversed. The protocol
Xmay allow <clientaddress> and <serveraddress> to be only partially
Xdefined for a given connection, so the client's <PROTO>LOCAL may not
Xagree with the server's <PROTO>REMOTE, and vice versa.
X
XA client SHOULD accept the following options: -q to turn off all error
Xmessages; -Q to turn on error messages, negating any previous -q.
X
XIf the client cannot perform its functions, it MUST exit with a nonzero
Xexit code.
X
X
X5. Killers
X
XIf <program> is a UCSPI killer, it MUST tell a server at <address> to
Ximmediately stop accepting connections, just as if the server process
Xhad received SIGTERM. It SHOULD NOT have this effect upon a server that
Xdoes not support the same protocol. The server may or may not accept the
Xkill request.
X
XA killer SHOULD accept the following options: -q to turn off all error
Xmessages; -Q to turn on error messages, negating any previous -q.
X
XIf the killer cannot perform its functions, it MUST exit with a nonzero
Xexit code.
X
X
X6. Protocols
X
XA protocol MUST define at least the following information: Its name,
X<PROTO>. The format and meaning of <address>. The number of arguments
X<address> takes, or a notice that it does not take a constant number of
Xarguments. Client and server address format. The maximum lengths of
X<serveraddress> and <clientaddress>, or a notice that they may grow to
Xany length. The address character set, if it is not merely alphanumeric.
X
XA protocol may define the following information, and more: Supported
Xoptions. The forking behavior of clients and servers. Any changes to the
Xprocess state not required by UCSPI. The implementation of the
Xunderlying protocol, and how it interacts with other protocols. The
Xnature of the descriptors passed to <userprogram>. The preferred names
Xof the client, server, and killer programs. The circumstances under
Xwhich a server will ignore a killer.
X
XIt is expected that all protocols will provide reliable two-way
Xfull-duplex strictly ordered not necessarily timed stream communication,
Xthough some protocols may also provide other types of communication
X(e.g., expedited [``out-of-band''] transmission, in which the stream is
Xno longer ordered).
X
XAll clients and servers must obey any rules imposed by a protocol in
Xorder to support that protocol. If a program supporting a protocol
Xcannot be unconditionally compliant with UCSPI-1991, the protocol is
Xat most conditionally compliant.
X
X
X7. Protocol management
X
XPublic protocol definitions may be registered with the UCSPI
XAdministrator. The UCSPI Administrator will normally refuse a
Xregistration request only on the grounds of a namespace problem, and in
Xthat case he will suggest an acceptable name.
X
XAll protocol names beginning with X are reserved for experimental or
Xnonstandard use. All protocol names beginning with x are reserved for
Xextended namespaces whose management is allocated to other authorities.
X
XFurther requests for interpretation or revision of UCSPI should be sent
Xto the UCSPI Administrator. The UCSPI Administrator may designate one or
Xmore reference implementations of a registered protocol, and where the
Xreference implementation establishes an interpretation not required by
Xthis document but not in conflict with this document, that
Xinterpretation should be considered binding until the UCSPI standard is
Xrevised.
X
X
XThe following protocol names have been registered as of 6/16/91:
X
X  TCP
X  UNDOM
X
X
XUCSPI Administrator
XDaniel J. Bernstein, brnstnd at nyu.edu
END_OF_FILE
if test 9408 -ne `wc -c <'UCSPI'`; then
    echo shar: \"'UCSPI'\" unpacked with wrong size!
fi
# end of 'UCSPI'
fi
if test -f 'npipeclient.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'npipeclient.c'\"
else
echo shar: Extracting \"'npipeclient.c'\" \(5236 characters\)
sed "s/^X//" >'npipeclient.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,"npipeclient: fatal: %s\n",s); exit(n); }
Xvoid dies(n,s,t) int n; char *s; char *t;
X{ if (flagverbose) fprintf(stderr,"npipeclient: fatal: %s%s\n",s,t); exit(n); }
Xvoid diep(n,s) int n; char *s;
X{ if (flagverbose) sprintf(errbuf,"npipeclient: fatal: %s",s); perror(errbuf); exit(n); }
Xvoid warnp(s) char *s;
X{ if (flagverbose) sprintf(errbuf,"npipeclient: warning: %s",s); perror(errbuf); }
Xvoid warnsp(s,t) char *s; char *t;
X{ if (flagverbose) sprintf(errbuf,"npipeclient: warning: %s%s",s,t); perror(errbuf); }
X
Xmain(argc,argv,envp)
Xint argc;
Xchar *argv[];
Xchar *envp[];
X{
X int *d;
X int numfiles;
X int arguid;
X int uid;
X int i;
X static char npipelocal[200];
X static char npiperemote[300];
X int fdserv;
X int fdlock;
X int fds2c;
X int fdc2s;
X char fnlock[200];
X char fns2c[200];
X char fnc2s[200];
X char fnserv[200];
X int m;
X int n;
X int r;
X char buf[100];
X char *uname;
X int pid;
X int opt;
X
X pid = getpid();
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
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(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(fns2c,"%s/s2c.%d",NPIPEDIR,pid);
X sprintf(fnc2s,"%s/c2s.%d",NPIPEDIR,pid);
X sprintf(buf,"%d",pid);
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 if (env_init() == -1)
X   die(11,"cannot init environment");
X if (env_put("PROTO=NPIPE") == -1)
X   die(11,"out of memory putting PROTO into environment");
X sprintf(npipelocal,"NPIPELOCAL=%s",uname);
X if (env_put(npipelocal) == -1)
X   die(11,"out of memory putting NPIPELOCAL into environment");
X sprintf(npiperemote,"NPIPEREMOTE=%s:%s",argv[0],argv[1]);
X if (env_put(npiperemote) == -1)
X   die(11,"out of memory putting NPIPEREMOTE into environment");
X
X /* XXX: fork? not necessary here */
X
X /* Action! */
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 if (mknod(fns2c,010600,0) == -1)
X   diep(1,"cannot create server-to-client pipe");
X if (mknod(fnc2s,010600,0) == -1)
X  {
X   unlink(fns2c);
X   diep(1,"cannot create client-to-server pipe");
X  }
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  {
X   unlink(fnc2s);
X   unlink(fns2c);
X   die(1,"cannot write pid and username to server");
X  }
X close(fdserv); /*XXX*/
X
X fds2c = open(fns2c,O_RDONLY,0); /* blocks */
X unlink(fns2c);
X if (fds2c == -1)
X  {
X   unlink(fnc2s);
X   die(1,"cannot open server-to-client pipe");
X  }
X fdc2s = open(fnc2s,O_WRONLY,0); /* blocks */
X unlink(fnc2s);
X if (fdc2s == -1)
X   die(1,"cannot open client-to-server pipe");
X
X if (read(fds2c,buf,1) < 1)
X   diep(1,"cannot read from server-to-client pipe");
X
X close(fdlock);
X
X /* Now put fds2c into descriptor 6 and fdc2s into descriptor 7. */
X /* XXX: should check that fdc2s and fds2c are small enough */
X d[fds2c] = 6;
X d[fdc2s] = 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 5236 -ne `wc -c <'npipeclient.c'`; then
    echo shar: \"'npipeclient.c'\" unpacked with wrong size!
fi
# end of 'npipeclient.c'
fi
if test -f 'npipeserver.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'npipeserver.c'\"
else
echo shar: Extracting \"'npipeserver.c'\" \(7393 characters\)
sed "s/^X//" >'npipeserver.c' <<'END_OF_FILE'
X/* Public domain. */
X
X#include <stdio.h>
X#include <signal.h>
X#include <sys/types.h>
X#include <sys/stat.h>
X#include <sys/file.h>
X#include <sys/wait.h>
X#include <sys/time.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 O_RDONLY
X#define O_RDONLY 0
X#endif
X#ifndef O_WRONLY
X#define O_WRONLY 1
X#endif
X
Xstatic int flagprintlocal = 0;
Xstatic int flagverbose = 1;
Xstatic char fnserv[200];
Xstatic char fnlock[200];
Xstatic char fnexcl[200];
Xstatic int fdserv;
Xstatic int fdlock;
Xstatic int fdexcl;
Xstatic int flagbindok = 0;
X
Xunlinkem()
X{
X if (flagbindok)
X  {
X   unlink(fnserv);
X   unlink(fnlock);
X   unlink(fnexcl);
X  }
X}
X
XSIGRET sigterm()
X{
X unlinkem();
X exit(0);
X}
X
XSIGRET sigchld()
X{
X wait((int *) 0); /*XXX*/
X}
X
Xstatic char errbuf[500];
Xvoid die(n,s) int n; char *s;
X{ if (flagverbose) fprintf(stderr,"npipeserver: fatal: %s\n",s); exit(n); }
Xvoid dies(n,s,t) int n; char *s; char *t;
X{ if (flagverbose) fprintf(stderr,"npipeserver: fatal: %s%s\n",s,t); exit(n); }
Xvoid diep(n,s) int n; char *s;
X{ if (flagverbose) sprintf(errbuf,"npipeserver: fatal: %s",s); perror(errbuf); exit(n); }
Xvoid warnp(s) char *s;
X{ if (flagverbose) sprintf(errbuf,"npipeserver: warning: %s",s); perror(errbuf); }
Xvoid warnsp(s,t) char *s; char *t;
X{ if (flagverbose) sprintf(errbuf,"npipeserver: warning: %s%s",s,t); perror(errbuf); }
X
Xmain(argc,argv,envp)
Xint argc;
Xchar *argv[];
Xchar *envp[];
X{
X int *d;
X int numfiles;
X int uid;
X int arguid;
X int i;
X int r;
X int n;
X char fns2c[200];
X char fnc2s[200];
X char buf[100];
X int pid;
X int fds2c;
X int fdc2s;
X char npipelocal[200]; /*XXX*/
X char npiperemote[300]; /*XXX*/
X int opt;
X
X while ((opt = getopt(argc,argv,"qQ4")) != EOF)
X   switch(opt)
X    {
X     case 'q':
X       flagverbose = 0;
X       break;
X     case 'Q':
X       flagverbose = 1;
X       break;
X     case '4':
X       flagprintlocal = 1;
X       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 if (uid && (uid != arguid))
X   dies(3,"permission denied for username ",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 close(6);
X close(7); /* XXX: these have implications that should be documented */
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(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(fnexcl,"%s/%de%s",NPIPEDIR,arguid,argv[1]);
X   /* XXX: Even if arguid has 5 digits, this leaves 8 characters for
X      the service in System V filesystems. It might be worth switching
X      to a fixed-length or hex format... I dunno. */
X
X signal(SIGTERM,sigterm);
X signal(SIGINT,sigterm);
X signal(SIGCHLD,sigchld);
X signal(SIGPIPE,SIG_IGN);
X
X if (env_init() == -1)
X   die(11,"cannot init environment");
X if (env_put("PROTO=NPIPE") == -1)
X   die(11,"out of memory putting PROTO into environment");
X sprintf(npipelocal,"NPIPELOCAL=%s:%s",argv[0],argv[1]);
X if (env_put(npipelocal) == -1)
X   die(11,"out of memory putting NPIPELOCAL into environment");
X
X if (flagprintlocal)
X  {
X   FILE *fd4;
X   fd4 = fdopen(4,"w");
X   if (!fd4)
X     die(1,"cannot print NPIPELOCAL on fd 4");
X   fprintf(fd4,"%s:%s\n",argv[0],argv[1]);
X   fclose(fd4);
X   close(4); /* just in case */
X  }
X
X /* Action! */
X
X fdexcl = creat(fnexcl,0);
X if (fdexcl == -1) /* somebody else got here before us */
X   die(1,"service already in use");
X /* XXX: there's a race right here */
X flagbindok = 1;
X fdlock = creat(fnlock,0); /* refuse connections until we're ready */
X if (fdlock == -1)
X   diep(1,"cannot create lock file");
X if (write(fdlock,buf,1) < 1)
X   diep(1,"cannot write to lock file");
X if (mknod(fnserv,010600,0) == -1)
X   diep(1,"cannot create server's named pipe");
X if (chmod(fnlock,0600) == -1) /* gaargh. fchmod(fdlock,0600)! */
X   diep(1,"cannot set modes on lock file");
X
X /* I hate programming like this. In a real OS I'd just create the named
X    pipe---outside the directory hierarchy!---then try to link it in.
X    None of this stupid testing and locking and so on. Gaargh. */
X
X for (;;)
X  {
X   /* XXX: should we really die on simple I/O errors? */
X   for (;;)
X    {
X     fdserv = open(fnserv,O_RDONLY,0); /* this blocks */
X     /* XXX: don't accept too many requests at once? */
X     if (fdserv == -1) /* down the drain */
X      {
X       if (errno == EINTR)
X	 continue;
X       unlinkem();
X       diep(1,"cannot open server's named pipe");
X      }
X     break;
X    }
X   n = 0;
X   r = 0;
X   while ((n < sizeof(buf)) && ((r = read(fdserv,buf + n,sizeof(buf) - n)) > 0))
X     n += r;
X   if (r > 0)
X     ; /* overflowed buffer---shouldn't happen, we'll just truncate it */
X   if (r == -1)
X    {
X     unlinkem();
X     diep(1,"cannot read client's pid and username");
X    }
X   /* XXX: do something for killer? */
X   close(fdserv);
X   unlink(fnserv); /*XXX: check for errors?*/
X   for (i = 0;i < n;++i)
X     if (!buf[i])
X       break;
X   if (i == n)
X    {
X     unlinkem();
X     die(1,"cannot read remote username");
X    }
X   /* XXX: if i is n - 1, we have a null username */
X   ++i; /* now buf + i is the username */
X   if (sscanf(buf,"%d",&pid) < 1)
X    {
X     unlinkem();
X     die(1,"cannot read remote pid");
X    }
X   if (!pid) /* npipekiller */
X     sigterm(); /*XXX*/
X
X   switch(fork())
X    {
X     case -1:
X       warnp("cannot fork");
X       /* XXX: say anything to other side? */
X       break;
X
X     case 0:
X
X       close(fdlock);
X       close(fdexcl);
X
X       sprintf(fns2c,"%s/s2c.%d",NPIPEDIR,pid);
X       sprintf(fnc2s,"%s/c2s.%d",NPIPEDIR,pid);
X
X       fds2c = open(fns2c,O_WRONLY,0); /* blocks */
X       if (fds2c == -1)
X	 diep(1,"cannot open server-to-client pipe");
X       fdc2s = open(fnc2s,O_RDONLY,0); /* blocks */
X       if (fdc2s == -1)
X	 diep(1,"cannot open client-to-server pipe");
X
X       if (write(fds2c,buf,1) < 1)
X	 diep(1,"cannot write on server-to-client pipe");
X
X       sprintf(npiperemote,"NPIPEREMOTE=%s",buf + i);
X       if (env_put(npiperemote) == -1)
X	 die(1,"out of memory putting NPIPEREMOTE into environment");
X
X       /* Now put fdc2s into descriptor 6 and fds2c into descriptor 7. */
X       /* XXX: should check that fdc2s and fds2c are small enough */
X       d[fdc2s] = 6;
X       d[fds2c] = 7;
X       if (dupdup(d,numfiles) == -1)
X	 diep(1,"cannot dup connection to client");
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
X     default:
X       ;
X    }
X   /* the cycle begins anew */
X   if (mknod(fnserv,010600,0) == -1)
X    {
X     unlinkem();
X     diep(1,"cannot create server's named pipe");
X    }
X  }
X}
END_OF_FILE
if test 7393 -ne `wc -c <'npipeserver.c'`; then
    echo shar: \"'npipeserver.c'\" unpacked with wrong size!
fi
# end of 'npipeserver.c'
fi
if test -f 'tcpclient.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'tcpclient.c'\"
else
echo shar: Extracting \"'tcpclient.c'\" \(5066 characters\)
sed "s/^X//" >'tcpclient.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/param.h>
X#include <netinet/in.h>
X#include <arpa/inet.h>
X#include <signal.h>
X#include "dupdup.h"
X#include "malloc.h"
X#include "errno.h"
X#include "username.h"
X#include "hostname.h"
X#include "portname.h"
X#include "env.h"
X#include "getopt.h"
X#include "authuser.h"
X#include "numfiles.h"
X
X#ifndef MAXHOSTNAMELEN
X#define MAXHOSTNAMELEN 64
X#endif
X
Xstatic int flagdo931 = 1;
Xstatic int flagverbose = 1;
Xstatic struct sockaddr_in sa;
Xstatic struct sockaddr_in saloc;
X
Xstatic char errbuf[500];
Xvoid die(n,s) int n; char *s;
X{ if (flagverbose) fprintf(stderr,"tcpclient: fatal: %s\n",s); exit(n); }
Xvoid dies(n,s,t) int n; char *s; char *t;
X{ if (flagverbose) fprintf(stderr,"tcpclient: fatal: %s%s\n",s,t); exit(n); }
Xvoid diep(n,s) int n; char *s;
X{ if (flagverbose) sprintf(errbuf,"tcpclient: fatal: %s",s); perror(errbuf); exit(n); }
Xvoid warnp(s) char *s;
X{ if (flagverbose) sprintf(errbuf,"tcpclient: warning: %s",s); perror(errbuf); }
Xvoid warnsp(s,t) char *s; char *t;
X{ if (flagverbose) sprintf(errbuf,"tcpclient: 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 i;
X static char tcplocal[200];
X static char tcpremote[300];
X int opt;
X int uid;
X char *uname;
X char lochost[MAXHOSTNAMELEN];
X struct in_addr locinaddr;
X int port;
X int locport;
X int dummy;
X char *ruser;
X
X locport = 0;
X
X while ((opt = getopt(argc,argv,"qQp:rR")) != EOF)
X   switch(opt)
X    {
X     case 'q':
X       flagverbose = 0; break;
X     case 'Q':
X       flagverbose = 1; break;
X     case 'p':
X       /* XXX: check that optarg is numeric? */
X       locport = atoi(optarg);
X       break;
X     case 'r':
X       flagdo931 = 1;
X       break;
X     case 'R':
X       flagdo931 = 0;
X       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 (uid2username(uid,&uname) == -1) /* will never happen */
X   die(2,"cannot figure out my own username");
X
X gethostname(lochost,sizeof(lochost));
X if (hostname2inaddr(lochost,&locinaddr) == -1)
X   die(2,"cannot figure out my own hostname");
X
X if ((argv[0][0] == '0') && (argv[0][1] == 0))
X   sa.sin_addr.s_addr = INADDR_ANY; /* special case "0" */
X else
X  {
X   if (hostname2inaddr(argv[0],&sa.sin_addr) == -1)
X     dies(2,"cannot figure out hostname ",argv[0]);
X  }
X
X if (portname2port(argv[1],&port,"tcp") == -1)
X   dies(2,"cannot figure out portname ",argv[1]);
X port = port & 65535;
X sa.sin_port = htons((short) port);
X
X close(6);
X close(7); /* XXX: these have implications that should be documented */
X
X signal(SIGPIPE,SIG_IGN);
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 (env_init() == -1)
X   die(11,"cannot init environment");
X if (env_put("PROTO=TCP") == -1)
X   die(11,"out of memory putting PROTO into environment");
X
X t = socket(AF_INET,SOCK_STREAM,0);
X if (t == -1)
X   diep(7,"cannot create client socket");
X sa.sin_family = AF_INET;
X if (locport)
X  {
X   /* attempt to bind to given local port */
X   /* could do this in advance in all cases if we were desperate to 
X      get TCPLOCAL figured out as fast as possible */
X   saloc.sin_family = AF_INET;
X   saloc.sin_addr.s_addr = INADDR_ANY;
X   saloc.sin_port = htons((short) locport);
X   if (bind(t,&saloc,sizeof(saloc)) == -1)
X     diep(9,"cannot bind to local port");
X  }
X if (connect(t,&sa,sizeof(sa)) == -1)
X   /* XXX: HRRFC says we should try alternate addresses */
X   diep(9,"cannot connect to server");
X dummy = sizeof(saloc);
X if (getsockname(t,&saloc,&dummy) == -1)
X   diep(9,"cannot figure out local connection address");
X
X locport = ntohs(saloc.sin_port);
X
X ruser = "";
X if (flagdo931)
X  {
X   ruser = auth_tcpuser((unsigned long) sa.sin_addr.s_addr
X	  ,(unsigned short) locport
X	  ,(unsigned short) port);
X   if (!ruser)
X     ruser = ""; /* XXX: any other suggestions? */
X  }
X
X sprintf(tcplocal,"TCPLOCAL=%s@%s(%s):%d"
X   ,uname
X   ,inet_ntoa(locinaddr) /* could use saloc.sin_addr */
X   ,lochost /* could use hostname of saloc.sin_addr */
X   ,locport
X  );
X if (env_put(tcplocal) == -1)
X   die(11,"out of memory putting TCPLOCAL into environment");
X sprintf(tcpremote,"TCPREMOTE=%s@%s(%s):%d"
X   ,ruser
X   ,inet_ntoa(sa.sin_addr)
X   ,argv[0] /* could do lookup instead, but why bother? */
X   ,port
X  );
X if (env_put(tcpremote) == -1)
X   die(11,"out of memory putting TCPREMOTE into environment");
X
X /* XXX: fork? not necessary here */
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 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 5066 -ne `wc -c <'tcpclient.c'`; then
    echo shar: \"'tcpclient.c'\" unpacked with wrong size!
fi
# end of 'tcpclient.c'
fi
if test -f 'tcpserver.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'tcpserver.c'\"
else
echo shar: Extracting \"'tcpserver.c'\" \(7346 characters\)
sed "s/^X//" >'tcpserver.c' <<'END_OF_FILE'
X/* Public domain. */
X
X#include <stdio.h>
X#include <signal.h>
X#include <sys/types.h>
X#include <sys/socket.h>
X#include <sys/stat.h>
X#include <sys/wait.h>
X#include <sys/file.h>
X#include <netinet/in.h>
X#include <netdb.h>
X#include <arpa/inet.h>
X#include <sys/time.h>
X#include <sys/param.h>
X#include "dupdup.h"
X#include "malloc.h"
X#include "errno.h"
X#include "username.h"
X#include "hostname.h"
X#include "portname.h"
X#include "env.h"
X#include "getopt.h"
X#include "authuser.h"
X#include "numfiles.h"
X
X#ifndef MAXHOSTNAMELEN
X#define MAXHOSTNAMELEN 64
X#endif
X
Xstatic int flagdo931 = 1;
Xstatic int flagprintlocal = 0;
Xstatic int flagverbose = 1;
Xstatic struct sockaddr_in sabind;
X
Xstatic char *fnrecord;
X
Xint record(uid,host,port,pid)
Xint uid;
Xchar *host;
Xint port;
Xint pid;
X{
X char *home;
X char pidstr[50];
X int fd;
X /* The idea is to record our pid in $HOME/.tcpserver.host.uid.port. */
X /* Then tcpkiller can read the pid from there, and send us a signal. */
X /* TCPHOME overrides HOME if it is set. */
X /* XXX: should we choose a signal that won't hurt ordinary processes? */
X /* XXX: anything good to do if $HOME is undefined or unwritable? */
X
X home = env_get("TCPHOME");
X if (!home)
X  {
X   home = env_get("HOME");
X   if (!home)
X     return -1;
X  }
X fnrecord = malloc(strlen(home) + strlen(host) + 100);
X if (!fnrecord)
X   return -1;
X sprintf(fnrecord,"%s/.tcpserver.%s.%d.%d",home,host,uid,port);
X
X unlink(fnrecord); /* XXX */
X
X fd = open(fnrecord,O_WRONLY | O_CREAT | O_EXCL,0400);
X if (fd == -1)
X  {
X   /* XXX */
X   return -1;
X  }
X
X sprintf(pidstr,"%d",pid);
X
X write(fd,pidstr,strlen(pidstr) + 1); /* XXX: check for partial writes */
X
X close(fd);
X return 0;
X}
X
XSIGRET sigterm()
X{
X if (fnrecord)
X   unlink(fnrecord); /*XXX*/
X exit(0);
X}
X
XSIGRET sigchld()
X{
X wait((union wait *) 0); /*XXX*/
X}
X
Xstatic char errbuf[500];
Xvoid die(n,s) int n; char *s;
X{ if (flagverbose) fprintf(stderr,"tcpserver: fatal: %s\n",s); exit(n); }
Xvoid dies(n,s,t) int n; char *s; char *t;
X{ if (flagverbose) fprintf(stderr,"tcpserver: fatal: %s%s\n",s,t); exit(n); }
Xvoid diep(n,s) int n; char *s;
X{ if (flagverbose) sprintf(errbuf,"tcpserver: fatal: %s",s); perror(errbuf); exit(n); }
Xvoid warnp(s) char *s;
X{ if (flagverbose) sprintf(errbuf,"tcpserver: warning: %s",s); perror(errbuf); }
Xvoid warnsp(s,t) char *s; char *t;
X{ if (flagverbose) sprintf(errbuf,"tcpserver: warning: %s%s",s,t); perror(errbuf); }
X
Xmain(argc,argv,envp)
Xint argc;
Xchar *argv[];
Xchar *envp[];
X{
X int s;
X int dummy;
X int t;
X int *d;
X int tdup;
X int numfiles;
X static struct sockaddr_in sa;
X int uid;
X int i;
X char lochost[MAXHOSTNAMELEN];
X struct in_addr locinaddr;
X char tcplocal[300]; /*XXX*/
X char tcpremote[300]; /*XXX*/
X int locport;
X int remport;
X char *remhost;
X char *ruser;
X char *uname;
X int opt;
X
X while ((opt = getopt(argc,argv,"qQ4rR")) != EOF)
X   switch(opt)
X    {
X     case 'q':
X       flagverbose = 0;
X       break;
X     case 'Q':
X       flagverbose = 1;
X       break;
X     case '4':
X       flagprintlocal = 1;
X       break;
X     case 'r':
X       flagdo931 = 1;
X       break;
X     case 'R':
X       flagdo931 = 0;
X       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 (uid2username(uid,&uname) == -1) /* will never happen */
X   die(2,"cannot figure out my own username");
X
X gethostname(lochost,sizeof(lochost));
X if (hostname2inaddr(lochost,&locinaddr) == -1)
X   die(2,"cannot figure out my own hostname");
X
X if ((argv[0][0] == '0') && (argv[0][1] == 0))
X   sabind.sin_addr.s_addr = INADDR_ANY; /* special case "0" */
X else
X  {
X   if (hostname2inaddr(argv[0],&sabind.sin_addr) == -1)
X     dies(2,"cannot figure out hostname ",argv[0]);
X   /* XXX: check whether sabind.sin_addr matches locinaddr? */
X  }
X
X if (portname2port(argv[1],&locport,"tcp") == -1)
X   dies(2,"cannot figure out portname ",argv[1]);
X locport = locport & 65535;
X sabind.sin_port = htons((short) locport);
X
X close(6);
X close(7); /* XXX: these have implications that should be documented */
X signal(SIGTERM,sigterm);
X signal(SIGINT,sigterm);
X signal(SIGCHLD,sigchld);
X signal(SIGPIPE,SIG_IGN);
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 s = socket(AF_INET,SOCK_STREAM,0);
X if (s == -1)
X   diep(7,"cannot create server socket");
X sabind.sin_family = AF_INET;
X if (bind(s,(struct sockaddr *) &sabind,sizeof(sabind)) == -1)
X   diep(9,"cannot bind server socket");
X if (listen(s,5) == -1) 
X   diep(10,"cannot listen on server socket");
X dummy = sizeof(sabind);
X if (getsockname(s,&sabind,&dummy) == -1)
X   diep(9,"cannot figure out local connection address");
X locport = ntohs(sabind.sin_port);
X
X if (env_init() == -1)
X   die(11,"cannot init environment");
X if (env_put("PROTO=TCP") == -1)
X   die(11,"out of memory putting PROTO into environment");
X sprintf(tcplocal,"TCPLOCAL=%s@%s(%s):%d"
X   ,uname
X   ,inet_ntoa(locinaddr) /* could use sabind.sin_addr */
X   ,lochost
X   ,locport
X  );
X if (env_put(tcplocal) == -1)
X   die(11,"out of memory putting TCPLOCAL into environment");
X
X if (flagprintlocal)
X  {
X   FILE *fd4;
X   fd4 = fdopen(4,"w");
X   if (!fd4)
X     die(1,"cannot print TCPLOCAL on fd 4");
X   fprintf(fd4,"%s@%s(%s):%d\n"
X     ,uname
X     ,inet_ntoa(locinaddr) /* could use sabind.sin_addr */
X     ,lochost
X     ,locport
X    );
X   fclose(fd4);
X   close(4); /* just in case */
X  }
X
X if (record(uid,lochost,locport,getpid()) == -1)
X   die(1,"cannot record process id for tcpkiller");
X   /* XXX: could use argv[0] instead of lochost here... hmmm */
X
X for (;;)
X  {
X   /* XXX: don't accept too many requests at once? */
X   dummy = sizeof(sa);
X   t = accept(s,(struct sockaddr *) &sa,&dummy);
X   if (t == -1) /* so when can this happen? */
X    {
X     switch(errno)
X      {
X       case SIGCHLD: break; /*XXX*/
X       case EINTR: break; /*XXX*/
X       case EMFILE: sleep(1); break; /*XXX*/
X       case ENFILE: sleep(1); break; /*XXX*/
X       default: ; /*XXX*/
X      }
X     continue;
X    }
X
X   switch(fork())
X    {
X     case -1:
X       warnp("cannot fork");
X       break;
X
X     case 0:
X
X       remport = ntohs(sa.sin_port);
X       ruser = "";
X       if (flagdo931)
X        {
X         ruser = auth_tcpuser((unsigned long) sa.sin_addr.s_addr
X	      	   ,(unsigned short) locport
X	       	   ,(unsigned short) remport);
X         if (!ruser)
X           ruser = ""; /* XXX: any other suggestions? */
X        }
X       if (inaddr2hostname(sa.sin_addr,&remhost) == -1) /* will never happen */
X	 die(1,"cannot find hostname");
X       sprintf(tcpremote,"TCPREMOTE=%s@%s(%s):%d"
X         ,ruser
X         ,inet_ntoa(sa.sin_addr)
X	 ,remhost
X	 ,remport
X        );
X       if (env_put(tcpremote) == -1)
X	 die(1,"out of memory putting TCPREMOTE into environment");
X
X       tdup = dup(t);
X       if (tdup == -1)
X	 diep(1,"cannot dup connection to client");
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(1,"cannot dup connection to client");
X
X       signal(SIGPIPE,SIG_DFL);
X       execvp(argv[2],argv + 2);
X       warnsp("cannot exec ",argv[2]);
X       exit(1);
X
X     default:
X       close(t);
X    }
X  }
X}
END_OF_FILE
if test 7346 -ne `wc -c <'tcpserver.c'`; then
    echo shar: \"'tcpserver.c'\" unpacked with wrong size!
fi
# end of 'tcpserver.c'
fi
if test -f 'undomserver.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'undomserver.c'\"
else
echo shar: Extracting \"'undomserver.c'\" \(5582 characters\)
sed "s/^X//" >'undomserver.c' <<'END_OF_FILE'
X/* Public domain. */
X
X#include <stdio.h>
X#include <signal.h>
X#include <sys/types.h>
X#include <sys/socket.h>
X#include <sys/stat.h>
X#include <sys/wait.h>
X#include <sys/un.h>
X#include <sys/time.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 flagprintlocal = 0;
Xstatic int flagverbose = 1;
Xstatic struct sockaddr_un sabind;
Xstatic int flagbindok = 0;
X
XSIGRET sigterm()
X{
X if (flagbindok)
X   unlink(sabind.sun_path);
X exit(0);
X}
X
XSIGRET sigchld()
X{
X wait((union wait *) 0); /*XXX*/
X}
X
Xstatic char errbuf[500];
Xvoid die(n,s) int n; char *s;
X{ if (flagverbose) fprintf(stderr,"undomserver: fatal: %s\n",s); exit(n); }
Xvoid dies(n,s,t) int n; char *s; char *t;
X{ if (flagverbose) fprintf(stderr,"undomserver: fatal: %s%s\n",s,t); exit(n); }
Xvoid diep(n,s) int n; char *s;
X{ if (flagverbose) sprintf(errbuf,"undomserver: fatal: %s",s); perror(errbuf); exit(n); }
Xvoid warnp(s) char *s;
X{ if (flagverbose) sprintf(errbuf,"undomserver: warning: %s",s); perror(errbuf); }
Xvoid warnsp(s,t) char *s; char *t;
X{ if (flagverbose) sprintf(errbuf,"undomserver: warning: %s%s",s,t); perror(errbuf); }
X
Xmain(argc,argv,envp)
Xint argc;
Xchar *argv[];
Xchar *envp[];
X{
X int s;
X int dummy;
X int t;
X int *d;
X int tdup;
X int numfiles;
X static struct sockaddr_un sa;
X int uid;
X int arguid;
X int i;
X char undomlocal[200]; /*XXX*/
X char undomremote[300]; /*XXX*/
X unsigned char urlen;
X int opt;
X
X while ((opt = getopt(argc,argv,"qQ4")) != EOF)
X   switch(opt)
X    {
X     case 'q':
X       flagverbose = 0;
X       break;
X     case 'Q':
X       flagverbose = 1;
X       break;
X     case '4':
X       flagprintlocal = 1;
X       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 if (uid && (uid != arguid))
X   dies(3,"permission denied for username ",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 close(6);
X close(7); /* XXX: these have implications that should be documented */
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(sabind.sun_path,"%s/%s:%s",UNDOMDIR,argv[0],argv[1]);
X
X signal(SIGTERM,sigterm);
X signal(SIGINT,sigterm);
X signal(SIGCHLD,sigchld);
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:%s",argv[0],argv[1]);
X if (env_put(undomlocal) == -1)
X   die(11,"out of memory putting UNDOMLOCAL into environment");
X sprintf(undomremote,"UNDOMREMOTE=");
X
X if (flagprintlocal)
X  {
X   FILE *fd4;
X   fd4 = fdopen(4,"w");
X   if (!fd4)
X     die(1,"cannot print UNDOMLOCAL on fd 4");
X   fprintf(fd4,"%s:%s\n",argv[0],argv[1]);
X   fclose(fd4);
X   close(4); /* just in case */
X  }
X
X s = socket(AF_UNIX,SOCK_STREAM,0);
X if (s == -1)
X   diep(7,"cannot create server socket");
X sabind.sun_family = AF_UNIX;
X if (bind(s,(struct sockaddr *) &sabind,strlen(sabind.sun_path) + 2) == -1)
X   dies(9,"cannot bind server socket ",sabind.sun_path);
X /* XXX: there's a race right here */
X flagbindok = 1;
X if (listen(s,5) == -1) 
X  {
X   unlink(sabind.sun_path);
X   diep(10,"cannot listen on server socket");
X  }
X
X for (;;)
X  {
X   /* XXX: don't accept too many requests at once? */
X   dummy = sizeof(sa);
X   t = accept(s,(struct sockaddr *) &sa,&dummy);
X   if (t == -1) /* so when can this happen? */
X    {
X     switch(errno)
X      {
X       case SIGCHLD: break; /*XXX*/
X       case EINTR: break; /*XXX*/
X       case EMFILE: sleep(1); break; /*XXX*/
X       case ENFILE: sleep(1); break; /*XXX*/
X       default: ; /*XXX*/
X      }
X     continue;
X    }
X
X   if (((i = read(t,&urlen,1)) == -1) || (!i))
X     continue; /* XXX: error message? */
X   if (urlen == 0) /* XXX: undomkiller */
X     sigterm();
X
X   switch(fork())
X    {
X     case -1:
X       warnp("cannot fork");
X       break;
X
X     case 0:
X
X       if (urlen > sizeof(undomremote) - strlen(undomremote) - 5)
X	 die(1,"remote username too long");
X       if (read(t,undomremote + strlen(undomremote),urlen) < urlen)
X	 die(1,"cannot read remote username");
X       undomremote[sizeof(undomremote) - 1] = 0; /* just in case */
X       /* XXX: warn if it's not already just the right length? */
X
X       if (env_put(undomremote) == -1)
X	 die(1,"out of memory putting UNDOMREMOTE into environment");
X
X       tdup = dup(t);
X       if (tdup == -1)
X	 diep(1,"cannot dup connection to client");
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(1,"cannot dup connection to client");
X
X       if (setreuid(uid,uid) == -1)
X	 diep(1,"cannot setreuid"); /* will never happen */
X       execvp(argv[2],argv + 2);
X       warnsp("cannot exec ",argv[2]);
X       exit(1);
X
X     default:
X       close(t);
X    }
X  }
X}
END_OF_FILE
if test 5582 -ne `wc -c <'undomserver.c'`; then
    echo shar: \"'undomserver.c'\" unpacked with wrong size!
fi
# end of 'undomserver.c'
fi
echo shar: End of archive 2 \(of 2\).
cp /dev/null ark2isdone
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