[comp.sources.reviewed] v01i002: supersrv - offer any program as a network service, Part01/02

Steven Grimm <Steven.Grimm@Eng.Sun.COM> (06/01/91)

Submitted-by: Steven Grimm <Steven.Grimm@Eng.Sun.COM>
Posting-number: Volume 1, Issue 2
Archive-name: supersrv/part01

#! /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:  INSTALL MANIFEST Makefile NOTES README TO-DO client.1
#   client.c client.doc common.h patchlevel.h server.1 server.c
#   server.doc socket.c supersrv.8 supersrv.doc
# Wrapped by csr@calvin.doc.ca on Fri May 31 23:28:09 1991
PATH=/bin:/usr/bin:/usr/ucb ; export PATH
if test -f 'INSTALL' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'INSTALL'\"
else
echo shar: Extracting \"'INSTALL'\" \(364 characters\)
sed "s/^X//" >'INSTALL' <<'END_OF_FILE'
XTo make and install the program, edit the supplied Makefile, modifying it
Xaccording to the instructions there.  Then run "make install" as root.
X
XThe Makefile will compile all the programs, producing the "client", "server",
Xand "supersrv" executables.  It will then remove any old versions of the
Xexecutables in the BINDIR directory and copy the new versions in.
X
END_OF_FILE
if test 364 -ne `wc -c <'INSTALL'`; then
    echo shar: \"'INSTALL'\" unpacked with wrong size!
fi
# end of 'INSTALL'
fi
if test -f 'MANIFEST' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'MANIFEST'\"
else
echo shar: Extracting \"'MANIFEST'\" \(672 characters\)
sed "s/^X//" >'MANIFEST' <<'END_OF_FILE'
X   File Name		Archive #	Description
X-----------------------------------------------------------
X INSTALL                    1	
X MANIFEST                   1	This shipping list
X Makefile                   1	
X NOTES                      1	
X README                     1	
X TO-DO                      1	
X client.1                   1	
X client.c                   1	
X client.doc                 1	
X common.h                   1	
X patchlevel.h               1	
X server.1                   1	
X server.c                   1	
X server.doc                 1	
X socket.c                   1	
X supersrv.8                 1	
X supersrv.c                 2	
X supersrv.doc               1	
END_OF_FILE
if test 672 -ne `wc -c <'MANIFEST'`; then
    echo shar: \"'MANIFEST'\" unpacked with wrong size!
fi
# end of 'MANIFEST'
fi
if test -f 'Makefile' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'Makefile'\"
else
echo shar: Extracting \"'Makefile'\" \(1967 characters\)
sed "s/^X//" >'Makefile' <<'END_OF_FILE'
X#
X# SuperServer 1.4
X#
X# by Steven Grimm, koreth@eng.sun.com
X#
X
X# Define any system-specific flags here.
XCFLAGS = -O
X
X# Set BINDIR to the directory into which server, supersrv, and client should be
X# installed.
XBINDIR = /usr/local/bin
X
X# Set MANDIR1 to the directory into which the manual pages for server and
X# client should be installed.  Set MANEXT1 to the desired file extension
X# (e.g. ".1") for the manual files.
XMANDIR1 = /usr/man/manl
XMANEXT1 = .l
X
X# Set MANDIR2 to the directory into which the manual page for supersrv should
X# be installed.  Set MANEXT2 to the desired file extension (e.g. ".8") for the
X# manual file.
XMANDIR2 = /usr/man/manl
XMANEXT2 = .l
X
X# With luck, you won't have to modify anything below this line.
X
XSUPERO = supersrv.o socket.o
XSERVERO = server.o socket.o
XCLIO = client.o socket.o
XMANPAGES1 = client.1 server.1
XMANPAGES2 = supersrv.8
X
Xall: supersrv server client
X
Xsupersrv: $(SUPERO)
X	$(CC) $(CFLAGS) $(SUPERO) -o $@
X
Xserver: $(SERVERO)
X	$(CC) $(CFLAGS) $(SERVERO) -o $@
X
Xclient: $(CLIO)
X	$(CC) $(CFLAGS) $(CLIO) -o $@
X
Xinstall: all
X	rm -f $(BINDIR)/supersrv $(BINDIR)/server $(BINDIR)/client
X	cp supersrv server client $(BINDIR)
X	chmod 755 $(BINDIR)/supersrv $(BINDIR)/server $(BINDIR)/client
X	rm -f $(MANDIR1)/client$(MANEXT1) $(MANDIR1)/server$(MANEXT1)
X	cp client.1 $(MANDIR1)/client$(MANEXT1)
X	cp server.1 $(MANDIR1)/server$(MANEXT1)
X	chmod 644 $(MANDIR1)/client$(MANEXT1) $(MANDIR1)/server$(MANEXT1)
X	rm -f $(MANDIR2)/supersrv$(MANEXT2)
X	cp supersrv.8 $(MANDIR2)/supersrv$(MANEXT2)
X	chmod 644 $(MANDIR2)/supersrv$(MANEXT2)
X
Xdocs:
X	nroff -man client.1 > client.doc
X	nroff -man server.1 > server.doc
X	nroff -man supersrv.8 > supersrv.doc
X
Xclean:
X	/bin/rm -f *.o supersrv server client core
X
Xlint:
X	@echo 'Linting source files for "server"...'
X	lint server.c socket.c
X	@echo ''
X	@echo 'Linting source files for "supersrv"...'
X	lint supersrv.c socket.c
X	@echo ''
X	@echo 'Linting source files for "client"...'
X	lint client.c socket.c
END_OF_FILE
if test 1967 -ne `wc -c <'Makefile'`; then
    echo shar: \"'Makefile'\" unpacked with wrong size!
fi
# end of 'Makefile'
fi
if test -f 'NOTES' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'NOTES'\"
else
echo shar: Extracting \"'NOTES'\" \(4987 characters\)
sed "s/^X//" >'NOTES' <<'END_OF_FILE'
XVERSION 1.4 CHANGES:
X
XIf no servers are connected to a running supersrv, it outputs a "No services
Xavailable" message if a service list is requested.  This could break programs
Xwhich read client's output.
X
X.services can contain service descriptions.  This necessitated a slight change
Xin the server<->supersrv service registering protocol; server now writes
Xservicenames and, optionally, a tab then the description.  Client's output
X(actually, the output of the supersrv LIST command) now contains the service
Xdescriptions; programs which parse service lists should be modified
Xaccordingly.
X
X.services can contain blank lines and comments; the error checking in
Xthe .services parsing routine getservices() was improved.
X
XFiles other than $HOME/.services can be used as service files.
X
XThe documentation for server was improved a lot; client was improved a little,
Xand supersrv was barely changed at all.
X
XVERSION 1.3 CHANGES:
X
XThere was a bug in supersrv v 1.2 and lower that caused it to go into an
Xinfinite loop if a connection was severed before a service name was given.
XThis has been eliminated.
X
XThe server<->supersrv communication has been changed slightly; the supersrv
Xnow writes out the client's IP address (in cleartext form) after the service
Xname, but before giving any parameters.  Server, in turn, takes this
Xinformation and creates a CLIENTIPADDR environment variable with the
Xclient's address; this allows shell scripts (and C programs, for that matter)
Xto tell which machine they're talking to.  This allows services to be
Xrestricted to the local net, or logged more accurately.
X
XVERSION 1.2 CHANGES:
X
XServer has a builtin "QUIT" service, which causes it to disconnect from
Xsupersrv and die.  When a server REGISTERs with supersrv, supersrv tells
Xall servers offering services from the same user to QUIT.  This allows
Xusers to run server without worrying about multiple servers sticking
Xaround.  The SIGHUP signal still causes server to reload its database,
Xfor backward compatibility, though this isn't mentioned in the man page.
X
XClient no longer needs a LIST argument; if no service name is given,
XLIST is assumed.
X
XVERSION 1.1 CHANGES:
X
XMinor bug fixes of little consequence.
X
XVERSION 1.0:
X
XThis program allows individual users to set up network services without
Xhaving to worry about the intricacies of socket I/O.  It is similar in
Xfunction to the "rsh" program, but restricts the commands which can be
Xexecuted by remote users.  No .rhosts or password is required, since
Xthe remote user can only execute commands from a specified (presumably
Xsafe) list.
X
XThe service programs think they're talking to a pipe (because they are).
XStdin and stdout are redirected to the pipe; stderr is mapped to stdout.
XShell scripts can be offered as network services, but make sure you have
Xexecute permission on them and that the line "#!/bin/sh" (or csh, or
Xwhatever shell you're using) appears at the top of the file, or UNIX won't
Xrecognize it as an executable-format file.
X
XThe server consists of two layers.  The bottom layer (subserver) is
Xexecuted by a user when he wants to advertise services.  It reads a
Xconfiguration file from the user's home directory, which contains a
Xlist of service names and full path specifications.  It then checks for
Xthe existence of the top layer (the super-server), and runs the
Xsuperserver program if it was not already active.  In any case, the
Xserver connects to the superserver, registers its service-names, and
Xawaits a request.
X
XThe superserver accepts connections from remote locations, usually
Xinitiated with the "client" program.  It reads a line of input from the
Xclient program, which specifies the name of the desired service.  If
Xone of the subservers has advertised the requested service, the
Xsuperserver forks off a child process.  The child writes the name of
Xthe requested service to the appropriate subserver, then acts as a
Xmailman, shuffling bytes between the remote user and the subserver
Xuntil one of them disconnects.  Meanwhile, the parent superserver
Xwaits for another connection, and the whole bloody mess starts over.
X
XThe client-supersrv handshaking looks like this (all lines are newline-
Xterminated, so you could talk to supersrv with telnet, for instance):
X
Xclient				supersrv
X------				--------
X				welcome message
Xservice name
Xusername (or empty line)
Xarg1
Xarg2
Xarg3
X .
X .
X .
Xargn
Xblank line
X
X
XIf a superserver process is killed, all its subservers try to restart
Xit until one of them succeeds.  If a server process is killed, the
Xsuperserver removes all its services from the listing.  Some braindamaged
XBSD implementations can take up to five minutes to figure out that a
Xprocess has died and that its socket addresses are no longer in use, so
Xkilling a superserver might result in a short interruption of service.
X
XSending a HUP signal to a server causes it to reload its database.
X
XIf you have questions, comments, bug reports, large amounts of excess cash,
Xetc., send a letter to koreth@eng.sun.com.
X
END_OF_FILE
if test 4987 -ne `wc -c <'NOTES'`; then
    echo shar: \"'NOTES'\" unpacked with wrong size!
fi
# end of 'NOTES'
fi
if test -f 'README' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'README'\"
else
echo shar: Extracting \"'README'\" \(3198 characters\)
sed "s/^X//" >'README' <<'END_OF_FILE'
XSuperServer 1.4 is a software package which allows users to offer services
Xto the network without any special programming knowledge or superuser access
Xto a system.  In fact, even shell scripts may be offered as network services.
XSuperServer eases debugging of network applications, and provides a consistent
Xfront-end to a variety of programs.  The manual page for the "server" program
Xcontains a detailed description of the SuperServer system.
X
XSuperServer runs under BSD UNIX derivatives, and should compile on any system
Xwith Berkeley-style networking calls (socket(), select(), accept(), etc.)
X
XTo make and install the program, edit the supplied Makefile, modifying it
Xaccording to the instructions there.  Then run "make install."
X
XThe remainder of this file contains the following sections:
X
X1. Sample .services file and example usage
X2. What's the difference between supersrv and inetd?
X
XQuestions, comments, etc. should be directed to koreth@eng.sun.com.
X
X-Steven Grimm
X
X
X------------------
X1. Sample .services file and example usage
X
X   (Blank lines between commands are added here for clarity.)
X
Xtwitterpater% cat $HOME/.services
Xfortune	/usr/games/fortune	Print a pithy saying.
Xclock	/usr/bin/date		What time is it?
X
Xtwitterpater% server
X
Xtwitterpater% client twitterpater
XUsername     Service
X--------     -------
Xkoreth       fortune     Print a pithy saying. 
Xkoreth       clock       What time is it? 
X
Xtwitterpater% client twitterpater clock
XThu May 16 16:47:43 PDT 1991
X
Xtwitterpater%
X
X
X------------------
X2. What's the difference between supersrv and inetd?
X
X
XSubject: Re:  supersrv and "inetd"
X
X>The reviews of your package 'supersrv' are proceeding.  One reviewer
X>has asked for information on how your package differs from "inetd".
X>Perhaps you could send me a note describing the differences and the
X>advantages of your program.
X
XCertainly.  There are four main advantages to supersrv:
X
X1. Services can be added and deleted by users, without the intervention of
X   a system administrator.  inetd can only be maintained by root.  This
X   encourages non-traditional services and experimentation.
X
X2. Only one network port is used; under inetd, every service offered must
X   bind to a TCP or UDP port number.  Supersrv puts all the services in one
X   predictable place.
X
X3. Supersrv allows users to obtain a list of services offered by a particular
X   host -- and under version 1.4, that list can contain descriptions of the
X   services.  This makes it a lot easier for people across the network to find
X   and use a newly-offered network service.
X
X4. It's a lot easier to add a new service to supersrv than to inetd -- simply
X   add a line to your .services and rerun "server".  Inetd requires you to
X   select a port number, add an entry to the services file, edit the inetd
X   config file, and send a signal to inetd.
X
XSupersrv can't, in a strict sense, do anything inetd can't; it is simply a
Xlot easier to maintain.  Point number 1 was the main reason I wrote the
Xprogram in the first place, at the University of California at Santa Cruz.
XIt's used quite a bit there, to access online literature databases, get
Xstatus information from various machines, and so on.
X
X-Steve
X
END_OF_FILE
if test 3198 -ne `wc -c <'README'`; then
    echo shar: \"'README'\" unpacked with wrong size!
fi
# end of 'README'
fi
if test -f 'TO-DO' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'TO-DO'\"
else
echo shar: Extracting \"'TO-DO'\" \(1361 characters\)
sed "s/^X//" >'TO-DO' <<'END_OF_FILE'
X	Perhaps server shouldn't search the user's PATH to find supersrv;
Xthis could be compiled in via a define in the Makefile.  That way, supersrv
Xcould be placed in an out-of-the-way directory where users wouldn't be
Xtempted to run it.
X
X	The documentation still needs work, though as of 1.4, it's better.
X
X	If exec-ing a program fails because of an invalid file format, we
Xshould try to run the program from sh, since it's probably a script without
Xthe #!/bin/sh at the top.
X
X	Some form of logging would be nice, so people can tell who's
Xusing which services.
X
X	Signal-passing and standard error support a la rsh would be neat, too.
X
X	Server should be able to read service descriptions from stdin.
X
X	Support for interactive programs by automatically allocating a pty
Xbefore running a program would be helpful.  Some form of environment passing
Xwould also need to be implemented for programs that use termcap.
X
X	Users should optionally be able to run multiple servers, with different
Xservices files.  This may be dangerous.
X
X	Supersrv should optionally filter the services' output streams,
Xreplacing newlines with CR-LF pairs, so that users telnetting to supersrv
Xfrom dumb terminals get pretty displays.
X
X	The supersrv user interface (when connected via telnet) could use
Xa lot of help; currently if you don't have the manual handy, you can't do
Xmuch of anything.
END_OF_FILE
if test 1361 -ne `wc -c <'TO-DO'`; then
    echo shar: \"'TO-DO'\" unpacked with wrong size!
fi
# end of 'TO-DO'
fi
if test -f 'client.1' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'client.1'\"
else
echo shar: Extracting \"'client.1'\" \(2280 characters\)
sed "s/^X//" >'client.1' <<'END_OF_FILE'
X.TH CLIENT 1 "30 April 1991"
X.SH NAME
Xclient \- use a network service, version 1.4
X.SH SYNOPSIS
X.B client
X[
X.B \-u
X.I username
X]
X.I host
X[
X.I servicename
X[
X.I arguments
X] ]
X.SH DESCRIPTION
X.B client
Xinterfaces with services offered through
X.BR server (1).
XSpecify the hostname and service; the service must be offered
Xby someone on the appropriate host.  To get a list of services
Xoffered on 
X.I host,
Xomit the
X.I servicename
Xand
X.IR arguments ;
Xa list of service names, the owners of the services, and short descriptions
Xof the services will be displayed.
X.PP
XAny
X.I arguments
Xafter the
X.I servicename
Xare passed to the service.  Be careful of passing
Xfilenames, as remote machines generally can't read files on the
Xlocal host.
X.SH OPTIONS
X.IP \-u
XIf two services of the same name are offered by different users,
Xuse the
X.I \-u
Xoption to select the desired user.  If this flag is not used,
X.B client
Xwill pick the first service whose name matches
X.IR servicename .
X.SH EXAMPLES
X% client localhost
X.PP
XThis will print a list of services on the local host, something like this:
X.sp
X.po +.5i
X.nf
XUsername     	Service
X\-\-\-\-\-\-\-\-     	\-\-\-\-\-\-\-
Xkoreth		fortune		Print a pithy saying.
Xkoreth		date   		What time is it?
Xkoreth		w     		Spy on all the users
X.po -.5i
X.fi
X.PP
X% client ssyx.ucsc.edu fortune -l
X.PP
XThis connects to machine "ssyx.ucsc.edu" and prints out a long
Xfortune (assuming the "fortune" service on that host is the standard system
Xfortune command.)
X.sp 1
X% client -u geek doofus.foo.bar
X.PP
XThis lists all services offered by user "geek" on host
X"doofus.foo.bar".
X.SH "SEE ALSO"
Xrsh(1), server(1), supersrv(8)
X.SH DIAGNOSTICS
X.IP "No services on \fIhost\fP
XThere is no
X.BR supersrv (8)
Xis running on 
X.IR host .
XThis sometimes means that the
X.IR supersrv (8)
Xprocess on that host has been killed; if this is the case, then services will
Xappear again in a short time.
X.IP "No services available
XA
X.BR supersrv (8)
Xprocess is running on the remote host, but no services have been registered.
X.IP "Service not offered
XThe service requested isn't offered by the remote host.  Remember to re-run
X.BR server (1)
Xafter editing a services file, or any additions or changes will not take
Xeffect.
X.SH AUTHOR
XSteven Grimm (koreth@eng.sun.com, ...!uunet!sun!koreth)
END_OF_FILE
if test 2280 -ne `wc -c <'client.1'`; then
    echo shar: \"'client.1'\" unpacked with wrong size!
fi
# end of 'client.1'
fi
if test -f 'client.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'client.c'\"
else
echo shar: Extracting \"'client.c'\" \(2242 characters\)
sed "s/^X//" >'client.c' <<'END_OF_FILE'
X#include "common.h"
X
X/*
X** Use the "server" and "supersrv" programs.
X**
X** 1.2: LIST argument is no longer necessary to list services.
X*/
X
Xmain(argc, argv)
Xchar **argv;
X{
X	int thirty;
X	char c, user[16];
X	int fd, i;
X
X	if (argc < 2)
X	{
Xusage:
X		fprintf(stderr, "usage: %s [-u user] host [cmd [parms]]\n",
X					argv[0]);
X		exit(-1);
X	}
X
X	user[0] = 0;
X
X	if (argv[1][0] == '-')
X		switch(argv[1][1])
X		{
X		case 'u':
X			strncpy(user, argv[2], 15);
X			user[15] = 0;
X			argv += 2;
X			argc -= 2;
X			if (argc < 2)
X				goto usage;
X			break;
X		default:
X			fprintf(stderr, "-%c flag unknown\n", argv[1][1]);
X			break;
X		}
X
X	thirty = 30;
X
X	fd = clientsock(argv[1], SUPERPORT);
X	if (fd < 0)
X	{
X		switch(fd) {
X		case -9999:
X			fprintf(stderr, "%s: host unknown\n", argv[1]);
X			break;
X		case -ECONNREFUSED:
X			fprintf(stderr, "No services on %s\n", argv[1]);
X			break;
X		default:
X			perror("clientsock");
X			break;
X		}
X		exit(-1);
X	}
X
X	setsockopt(fd, SOL_SOCKET, SO_LINGER, &thirty, sizeof(thirty));
X
X	do
X		read(fd, &c, 1);
X	while (c != '\n');
X
X	if (argc == 2)
X		writeln(fd, "LIST");
X	else
X		writeln(fd, argv[2]);
X	writeln(fd, user);
X
X	if (argc > 3)
X		for (i=3; i<argc; i++)
X			writeln(fd, argv[i]);
X
X	writeln(fd, "");
X
X	shuffle(fd);
X
X	fcntl(0, F_SETFL, 0);
X	close(fd);
X
X	exit(0);
X}
X
Xwriteln(fd, string)
Xint fd;
Xchar *string;
X{
X	write(fd, string, strlen(string));
X	write(fd, "\n", 1);
X}
X
X/*
X * Shuffle bytes between stdin/out and the socket.  This forks off
X * once so that one process handles dataflow in each direction (that's
X * how rsh does it, and it makes the code a lot prettier...)
X */
Xshuffle(subsrv)
Xint subsrv;		/* this will probably always be 3... */
X{
X	fd_set reed, other;
X	int pid, numread, buf[BUFSIZ];
X
X	pid = fork();
X	if (pid < 0)
X	{
X		perror("fork");
X		close(subsrv);
X		exit(-1);
X	}
X
X	FD_ZERO(&reed);
X	FD_ZERO(&other);
X
X	if (!pid)
X	{
X		close(1);
X		close(2);
X
X		while (1)
X		{
X			numread = read(0, buf, sizeof(buf));
X			if (numread <= 0)
X				break;
X			write(subsrv, buf, numread);
X		}
X		shutdown(subsrv, 1);
X		close(subsrv);
X		exit(0);
X	}
X	else
X	{
X		close(0);
X		close(2);
X
X		while (1)
X		{
X			numread = read(subsrv, buf, sizeof(buf));
X			if (numread <= 0)
X				break;
X			write(1, buf, numread);
X		}
X
X		close(subsrv);
X		kill(pid, SIGKILL);
X	}
X}
X
END_OF_FILE
if test 2242 -ne `wc -c <'client.c'`; then
    echo shar: \"'client.c'\" unpacked with wrong size!
fi
# end of 'client.c'
fi
if test -f 'client.doc' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'client.doc'\"
else
echo shar: Extracting \"'client.doc'\" \(2990 characters\)
sed "s/^X//" >'client.doc' <<'END_OF_FILE'
X
X
X
XCLIENT(1)                USER COMMANDS                  CLIENT(1)
X
X
X
XNAME
X     client - use a network service, version 1.4
X
XSYNOPSIS
X     client [ -u _u_s_e_r_n_a_m_e ] _h_o_s_t [ _s_e_r_v_i_c_e_n_a_m_e [ _a_r_g_u_m_e_n_t_s ] ]
X
XDESCRIPTION
X     client interfaces with services offered  through  server(1).
X     Specify  the  hostname  and  service;  the  service  must be
X     offered by someone on the appropriate host.  To get  a  list
X     of  services offered on _h_o_s_t, omit the _s_e_r_v_i_c_e_n_a_m_e and _a_r_g_u_-
X     _m_e_n_t_s; a list of service names, the owners of the  services,
X     and short descriptions of the services will be displayed.
X
X     Any _a_r_g_u_m_e_n_t_s after the _s_e_r_v_i_c_e_n_a_m_e are passed to  the  ser-
X     vice.   Be  careful of passing filenames, as remote machines
X     generally can't read files on the local host.
X
XOPTIONS
X     -u   If two services of the same name are  offered  by  dif-
X          ferent  users,  use the -_u option to select the desired
X          user.  If this flag is not used, client will  pick  the
X          first service whose name matches _s_e_r_v_i_c_e_n_a_m_e.
X
XEXAMPLES
X     % client localhost
X
X     This will print a list of services on the local host,  some-
X     thing like this:
X
X          Username       Service
X          --------       -------
X          koreth         fortune        Print a pithy saying.
X          koreth         date           What time is it?
X          koreth         w              Spy on all the users
X
X     % client ssyx.ucsc.edu fortune -l
X
X     This connects to machine "ssyx.ucsc.edu" and  prints  out  a
X     long fortune (assuming the "fortune" service on that host is
X     the standard system fortune command.)
X
X     % client -u geek doofus.foo.bar
X
X     This lists all services  offered  by  user  "geek"  on  host
X     "doofus.foo.bar".
X
XSEE ALSO
X     rsh(1), server(1), supersrv(8)
X
XDIAGNOSTICS
X     No services on _h_o_s_t
X
X
X
XSun Microsystems   Last change: 30 April 1991                   1
X
X
X
X
X
X
XCLIENT(1)                USER COMMANDS                  CLIENT(1)
X
X
X
X          There is no supersrv(8) is running on _h_o_s_t.  This some-
X          times  means  that the _s_u_p_e_r_s_r_v(8) process on that host
X          has been killed; if this is  the  case,  then  services
X          will appear again in a short time.
X
X     No services available
X          A supersrv(8) process is running on  the  remote  host,
X          but no services have been registered.
X
X     Service not offered
X          The service requested isn't offered by the remote host.
X          Remember  to  re-run server(1) after editing a services
X          file, or any additions or changes will not take effect.
X
XAUTHOR
X     Steven Grimm (koreth@eng.sun.com, ...!uunet!sun!koreth)
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X
XSun Microsystems   Last change: 30 April 1991                   2
X
X
X
END_OF_FILE
echo shar: 105 control characters may be missing from \"'client.doc'\"
if test 2990 -ne `wc -c <'client.doc'`; then
    echo shar: \"'client.doc'\" unpacked with wrong size!
fi
# end of 'client.doc'
fi
if test -f 'common.h' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'common.h'\"
else
echo shar: Extracting \"'common.h'\" \(427 characters\)
sed "s/^X//" >'common.h' <<'END_OF_FILE'
X/*
X * Common.h
X *
X * Definitions common to both the sub- and superserver.
X */
X
X/*
X * Common include files
X */
X#include <stdio.h>
X#include <signal.h>
X#include <errno.h>
X#include <fcntl.h>
X#include <sys/param.h>
X#include <sys/ioctl.h>
X#include <sys/time.h>
X#include <sys/socket.h>
X
X/*
X * This is the port number that the superserver listens on.
X */
X#define SUPERPORT	3502
X
X/*
X * Common external variables.
X */
Xextern int errno;
X
END_OF_FILE
if test 427 -ne `wc -c <'common.h'`; then
    echo shar: \"'common.h'\" unpacked with wrong size!
fi
# end of 'common.h'
fi
if test -f 'patchlevel.h' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'patchlevel.h'\"
else
echo shar: Extracting \"'patchlevel.h'\" \(23 characters\)
sed "s/^X//" >'patchlevel.h' <<'END_OF_FILE'
X#define PATCHLEVEL 1.4
END_OF_FILE
if test 23 -ne `wc -c <'patchlevel.h'`; then
    echo shar: \"'patchlevel.h'\" unpacked with wrong size!
fi
# end of 'patchlevel.h'
fi
if test -f 'server.1' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'server.1'\"
else
echo shar: Extracting \"'server.1'\" \(5259 characters\)
sed "s/^X//" >'server.1' <<'END_OF_FILE'
X.TH SERVER 1 "30 April 1991"
X.SH NAME
Xserver \- offer network services, version 1.4
X.SH SYNOPSIS
X.B server
X[
X.I services-file
X]
X.SH DESCRIPTION
X.B Server
Xallows users to offer services to other users, possibly on remote
Xhosts.  Any program (or shell script) that a user has execute permission
Xon can be offered as a service.  The program
X.BR client (1)
Xis then used to run the services, optionally passing arguments or input.
X.BR client (1)
Xmay be used to access services on the local host or across the network; a
Xservice need not differentiate between local and network access.
X.PP
XIf a server is the first to start up on a machine, the super-server
X.BR supersrv (8)
Xis automatically started by
X.B server,
Xwhich then tells
X.B supersrv
Xwhich services the user wants to offer.
X.B server
Xreads its configuration from a
X.IR services-file ,
Xby default
X.IR $HOME/.services .
XEach line in the
X.I services-file
Xis of the form
X.IP
X.I name path [description]
X.PP
XBlank lines and lines beginning with '#' are ignored.  The
X.I name
Xfield is the name by which the service will be advertised to users.  It need
Xbear no relation to the executable filename; it is merely an identifying label.
XThe
X.I path
Xfield is the full pathname (starting from the root directory) of the executable
Xfile which should be run to invoke the service.  The pathname is not advertised
Xto users.  An optional
X.I description
Xof each service may be provided, so that users may easily browse through a list
Xof available services.
X.PP
XAny of the executable files listed may
Xbe shell scripts.  On many systems, executable shell scripts must begin with
Xthe line "#!/bin/sh" (with the name of the appropriate shell replacing
X"/bin/sh" as needed.)
X.PP
XTo change the services being offered, edit the
X.I services-file
Xand run
X.B server
Xagain.  The old
X.B server
Xwill die, and the new one will take its place.  Killing a
X.B server
Xprocess results in the services it offered being removed from
X.BR supersrv 's
Xlist of services.
X.PP
XMost programs should work without any problems as services.  The service
Xthinks it's talking to a pipe; interactive programs work as long as they
Xdon't attempt to set any special terminal modes or use
X.BR termcap (3)
Xor
X.BR curses (3)
Xto try to update the client's screen.  These restrictions are the same as
Xthose of
X.BR rsh (1);
X.BR client (1)
Xis similar to
X.B rsh
Xexcept that security is handled differently.
X.PP
XIf
X.B supersrv
Xgoes away (usually as a result of a kill command from a user who hasn't
Xread this or doesn't know why there's an extra process running next to his
Xserver), all the
X.B server
Xprocesses on the system will try to restart
X.B supersrv
Xuntil one of them succeeds.  Since it can take a while for TCP ports to
Xclear after their binding process has died on some systems,
Xkilling a
X.B supersrv
Xmay result in a short interruption of service.
X.SH EXAMPLE
X.nf
X% cat .services
X# koreth's .services file
Xfortune	/usr/games/fortune	Print a pithy saying
Xw     	/usr/ucb/w		See what people are up to
Xwho    	/bin/who
Xcrash	/g/f/v/foobar/kill.system	Don't ask
X.fi
X.PP
XIn this example, the
X.I services-file
Xdescribes four services.  The
X.BR fortune ,
X.BR w ,
Xand
X.B crash
Xservices have descriptions, which will be displayed by
X.BR client (1)
Xwhen a list of services is requested.
X.SH ENVIRONMENT
XWhen a service is invoked,
X.B server
Xsets the environment variable
X.B CLIENTIPADDR
Xto the Internet address of the host on the other side of the connection,
Xi.e. "128.114.129.6".  It is up to individual services to use this or not,
Xas they please.  This facility may be used to restrict access to sensitive
Xinformation, for example.
X.SH DIAGNOSTICS
X.IP "HOME environment variable not set
XA services file was not specified on the command line, and
X.B server
Xcouldn't find the user's home directory.
X.IP "warning: <filename> line X: line too long, truncating
XA line in the services file exceeded the maximum line length.  This is usually
Xdue to the length of the service description.  The description is truncated to
Xthe maximum length.
X.IP "warning: <filename> line X: no service path specified
XA service name was listed, but the location of the service on the disk was not
Xspecified.
X.IP "warning: <filename> line X: can't execute <filename>
XThe service pathname listed on line X of the services file points to a file
Xwhich does not have the appropriate permissions to be executed.
X.IP "No services specified; server exiting
XThere were no valid services listed in the services file;
X.B server
Xisn't offering
Xanything, so exits immediately.  This is usually the result of one or more of the
Xabove errors.
X.IP "warning: couldn't disassociate from tty
XThe system call to detach
X.B server
Xfrom its control tty (so that it won't show up on "ps" or "w" listings)
Xfailed for some reason.  This error shouldn't occur.
X.IP "warning: couldn't get UID
XThe login name of the user running
X.B server
Xcouldn't be determined.  This error shouldn't occur.
X.SH FILES
X$HOME/.services	default services list
X.SH "SEE ALSO"
Xclient(1), supersrv(8)
X.SH BUGS
X.PP
XShell scripts offered as services must have the line "#!/bin/sh" (or csh,
Xor whatever shell is being used) at the top, or
X.I server
Xwon't be able to execute them.
X.SH AUTHOR
XSteven Grimm (koreth@eng.sun.com, ...!uunet!sun!koreth)
END_OF_FILE
if test 5259 -ne `wc -c <'server.1'`; then
    echo shar: \"'server.1'\" unpacked with wrong size!
fi
# end of 'server.1'
fi
if test -f 'server.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'server.c'\"
else
echo shar: Extracting \"'server.c'\" \(8119 characters\)
sed "s/^X//" >'server.c' <<'END_OF_FILE'
X#include "common.h"
X#include <sys/file.h>
X#include <pwd.h>
X
X/*
X * SubServer main module.
X *
X * 1.4: Service entries can have descriptions.
X * 1.2: Starting up a new server kills the old one.
X * 1.1: Some small bug fixes.
X */
X
X#define	RCFILE	"/.services"	/* File to grab services from */
X
Xchar *getenv();
Xchar services[MAXPATHLEN];	/* Fully qualified pathname of .services file */
X
X/*
X * This linked list structure is used to keep track of the
X * services we're offering.
X */
Xstruct service {
X	char	name[20];		/* Service name */
X	char	path[MAXPATHLEN];	/* Service path */
X	char	desc[50];		/* Description of service */
X	struct service *next;		/* Next element... */
X} *list;
X
X/*
X * Read in a services file and set up the linked list of
X * services.  Test each service to be sure we can offer it.
X * Returns 0 if there are no services offered.
X */
Xgetservices(arg)
Xchar *arg;
X{
X	FILE	*fp;
X	char	filename[MAXPATHLEN], *home;
X	int	line = 0;
X
X	if (arg != NULL)
X		strncpy(services, arg, sizeof(services));
X	else
X	{
X		home = getenv("HOME");
X		if (! home)
X		{
X			fprintf(stderr, "HOME environment variable not set\n");
X			return(0);
X		}
X
X		strncpy(services, home, sizeof(services));
X		strncat(services, RCFILE, sizeof(services));
X	}
X
X	fp = fopen(services, "r");
X	if (! fp)
X	{
X		perror(services);
X		return(0);
X	}
X
X	list = NULL;
X
X	while (! feof(fp))
X	{
X		char	servname[20], format[20], descrip[50], input[100];
X
X		line++;
X		sprintf(format, "%%19s\t%%%ds\t%%49[^\n]", MAXPATHLEN);
X		input[0] = '\0';
X		if (fgets(input, 100, fp) == NULL)
X			break;
X		if (input[0] == '\n')
X			continue;
X
X/* If we didn't read an end-of-line, the description was probably too long. */
X		if (input[strlen(input)-1] != '\n')
X		{
X			char	c;
X
Xfprintf(stderr, "warning: %s line %d: line too long, truncating\n",
X						services, line);
X			while ((c = getc(fp)) != '\n' && c != EOF)
X				;
X		}
X
X		servname[0] = '\0';
X		descrip[0] = '\0';
X		filename[0] = '\0';
X		sscanf(input, format, servname, filename, descrip);
X
X		if (servname[0] && servname[0] != '#')
X			if (! filename[0])
X			{
Xfprintf(stderr, "warning: %s line %d: no service path specified\n",
X						services, line);
X				continue;
X			}
X
X		if (servname[0] != '#')
X		{
X			struct service *temp;
X
X			if (access(filename, X_OK))
X			{
Xfprintf(stderr, "warning: %s line %d: can't execute %s\n",
X						services, line, filename);
X				continue;
X			}
X
X			temp = (struct service *) malloc(sizeof(struct service));
X			strcpy(temp->name, servname);
X			strcpy(temp->path, filename);
X			strcpy(temp->desc, descrip);
X#ifdef DEBUG
X			printf("server read name '%s', path '%s', desc '%s'\n",
X					temp->name, temp->path, temp->desc);
X#endif /* DEBUG */
X			temp->next = list;
X			list = temp;
X		}
X	}
X	fclose(fp);
X	return 1;
X}
X
X
X/*
X * Reap children.
X */
Xsigchld()
X{
X	return wait(0);
X}
X
Xint	fd;
X
X/*
X * Reload the database.
X * We do this by killing the old list element by element then calling
X * getservices(), and closing the socket file descriptor so the main
X * loop will have to reregister our services.
X */
Xreload()
X{
X	struct service *cur, *next;
X
X	cur = list;
X	while (cur)
X	{
X		next = cur->next;
X		free(cur);
X		cur = next;
X	}
X
X	if (! getservices(services))
X		exit(-1);
X	close(fd);
X	fd = -1;	/* prevent another close... */
X}
X
Xmain(argc, argv, envp)
Xchar **argv, **envp;
X{
X	int thirty;
X	struct service *cur;
X	struct passwd *pw;
X	char	service[80], user[16];
X
X	if (! getservices(argc > 1 ? argv[1] : NULL))
X	{
X		fprintf(stderr, "No services specified; server exiting\n");
X		exit(0);
X	}
X
X#ifndef DEBUG
X	if (fork())
X		exit(0);
X
X	fd = open("/dev/tty", O_RDWR);
X	if (fd >= 0)
X	{
X		ioctl(fd, TIOCNOTTY, 0);
X		close(fd);
X	}
X	else
X		printf("warning: couldn't disassociate from tty\n");
X#endif /* DEBUG */
X
X/*
X * Handle signals.  We want to reap children, so we should handle SIGCHLDs;
X * we also want to let the user reload his services database, which we do
X * with SIGHUP.
X */
X	signal(SIGCHLD, sigchld);
X	signal(SIGHUP, reload);
X
X	thirty = 30;
X
X	pw = getpwuid(getuid());
X	if (pw == NULL)
X	{
X		fprintf(stderr, "warning: couldn't get UID\n");
X		user[0] = '\n';
X		user[1] = '\0';
X	}
X	else
X	{
X		strncpy(user, pw->pw_name, sizeof(user)-2);
X		user[sizeof(user)-1] = '\0';
X		strcat(user, "\n");
X	}
X
X/*
X * If we aren't in debug mode, we don't need to print any more messages after
X * this point, so there's no sense keeping unused file descriptors lying
X * around.
X */
X#ifndef DEBUG
X	close(0);
X	close(1);
X	close(2);
X#endif /* DEBUG */
X	
X	while (1)
X	{
X		char c;
X
X		fd = clientsock("localhost", SUPERPORT);
X		if (fd < 0)
X			if (errno == ECONNREFUSED)
X			{
X				start_super(argv[0], envp);
X/*
X * Give the superserver time to fire up.
X */
X				sleep(5);
X				continue;
X			}
X			else
X			{
X				perror("superserver connect");
X				exit(-1);
X			}
X
X		thirty = 30;
X		setsockopt(fd, SOL_SOCKET, SO_LINGER, &thirty, sizeof(thirty));
X		c = 0;
X		do
X			if (read(fd, &c, 1) < 0 && errno != EINTR)
X				break;
X		while (c != '\n');
X
X		if (c != '\n')
X			continue;
X
X		write(fd, "REGISTER\n", 9);
X		write(fd, user, strlen(user));
X
X		for (cur = list; cur; cur = cur->next)
X		{
X			write(fd, cur->name, strlen(cur->name));
X			if (cur->desc[0])
X			{
X				write(fd, "\t", 1);
X				write(fd, cur->desc, strlen(cur->desc));
X			}
X			write(fd, "\n", 1);
X		}
X		write(fd, "\n", 1);
X
X		service[0] = 0;
X		if (read(fd, service, 20) < 0 && errno != EBADF && errno != EINTR)
X		{
X			perror("read");
X			exit(-1);
X		}
X
X		if (service[0])
X			do_service(service, fd, envp);
X		if (fd >= 0)
X			close(fd);
X	}
X}
X
X
X/*
X * Provide the service.  Fork off and keep reading parameters until
X * they are terminated by an empty line, then pass them to the program
X * specified by the service.
X *
X * v1.3: The first "parameter" is actually a string containing the IP
X * 	 address of the client.
X */
Xdo_service(service, fd, envp)
Xchar *service;
Xint fd;
Xchar **envp;
X{
X	struct service *cur;
X	char	*argv[256], input[256], **newenv;
X	int	curarg = 0, index = 0, thirty = 60, numenv;
X
X/*
X * If we're told to quit by the superserver, do so -- our owner has probably
X * run another server.
X */
X	if (! strcmp(service, "QUIT"))
X	{
X		close(fd);
X		exit(0);
X	}
X
X	if (fork())
X		return;
X
X/*
X * Count the environment variables in preparation for adding a new one.
X */
X	for (numenv = 0; envp[numenv] != NULL; numenv++);
X
X/*
X * Now add the CLIENTIPADDR variable with the first bit of supersrv output.
X * This is a bit kludgy, but whatever.
X */
X	newenv = (char **)malloc((numenv+2)*sizeof(char *));
X	do
X		newenv[numenv+1] = envp[numenv];
X	while (numenv--);
X
X	argv[curarg] = service;
X
X	while (1) {
X		read(fd, &input[index], 1);
X		if (input[index] == '\r')
X			continue;
X		if (input[index] == '\n')
X		{
X			if (! index)
X				break;
X
X			if (curarg)
X			{
X				argv[curarg] = (char *)malloc(index+1);
X				bcopy(input, argv[curarg], index);
X				argv[curarg][index] = 0;
X			}
X			else
X			{
X				input[index] = '\0';
X				newenv[0] = (char *)malloc(index +
X					sizeof("CLIENTIPADDR="));
X				sprintf(newenv[0], "CLIENTIPADDR=%s", input);
X			}
X
X			index = 0;
X			curarg++;
X		}
X		else
X			index++;
X	}
X
X	dup2(fd, 0);
X	dup2(fd, 1);
X	dup2(fd, 2);
X	setsockopt(0, SOL_SOCKET, SO_LINGER, &thirty, sizeof(thirty));
X	setsockopt(1, SOL_SOCKET, SO_LINGER, &thirty, sizeof(thirty));
X	setsockopt(2, SOL_SOCKET, SO_LINGER, &thirty, sizeof(thirty));
X	if (fd > 2)
X		close(fd);
X
X	argv[curarg] = NULL;
X
X	for (cur = list; cur; cur = cur->next)
X		if (! strcmp(cur->name, service))
X			break;
X
X	if (! cur)		/* service not there */
X		exit(0);
X
X	execve(cur->path, argv, newenv);
X	perror("execve");
X	exit(0);
X}
X
Xchar *superv[] = { "/bin/sh", "-c", "supersrv", NULL };
X
Xstart_super(argv0, envp)
Xchar *argv0, **envp;
X{
X	char *lastslash, argcopy[MAXPATHLEN], *rindex();
X
X	strcpy(argcopy, argv0);
X/*
X * If a path was given, try to find the superserver in the
X * same directory as the subserver...
X */
X	if (lastslash = rindex(argcopy, '/'))
X	{
X		char path[MAXPATHLEN];
X
X		*lastslash = 0;
X		strcpy(path, argcopy);
X		strcat(path, "/supersrv");
X		if (! access(path, X_OK))
X		{
X			if (! fork())
X				execve(path, superv+2, envp);
X			return;
X		}
X	}
X
X/*
X * Otherwise, start up a shell to scan along the user's
X * $PATH.
X */
X	if (! fork())
X		execve(superv[0], superv, envp);
X}
X
END_OF_FILE
if test 8119 -ne `wc -c <'server.c'`; then
    echo shar: \"'server.c'\" unpacked with wrong size!
fi
# end of 'server.c'
fi
if test -f 'server.doc' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'server.doc'\"
else
echo shar: Extracting \"'server.doc'\" \(6434 characters\)
sed "s/^X//" >'server.doc' <<'END_OF_FILE'
X
X
X
XSERVER(1)                USER COMMANDS                  SERVER(1)
X
X
X
XNAME
X     server - offer network services, version 1.4
X
XSYNOPSIS
X     server [ _s_e_r_v_i_c_e_s-_f_i_l_e ]
X
XDESCRIPTION
X     Server allows users to offer services to other users, possi-
X     bly  on  remote hosts.  Any program (or shell script) that a
X     user has execute permission on can be offered as a  service.
X     The  program  client(1)  is  then  used to run the services,
X     optionally passing arguments or  input.   client(1)  may  be
X     used to access services on the local host or across the net-
X     work; a service need not  differentiate  between  local  and
X     network access.
X
X     If a server is the first to  start  up  on  a  machine,  the
X     super-server supersrv(8) is automatically started by server,
X     which then tells supersrv which services the user  wants  to
X     offer.  server reads its configuration from a _s_e_r_v_i_c_e_s-_f_i_l_e,
X     by default $_H_O_M_E/._s_e_r_v_i_c_e_s.  Each line in the  _s_e_r_v_i_c_e_s-_f_i_l_e
X     is of the form
X
X          _n_a_m_e _p_a_t_h [_d_e_s_c_r_i_p_t_i_o_n]
X
X     Blank lines and lines beginning with '#' are  ignored.   The
X     _n_a_m_e  field  is the name by which the service will be adver-
X     tised to users.  It need bear no relation to the  executable
X     filename; it is merely an identifying label.  The _p_a_t_h field
X     is the full pathname (starting from the root  directory)  of
X     the  executable  file which should be run to invoke the ser-
X     vice.  The pathname is not advertised to users.  An optional
X     _d_e_s_c_r_i_p_t_i_o_n  of  each service may be provided, so that users
X     may easily browse through a list of available services.
X
X     Any of the executable files listed may be shell scripts.  On
X     many  systems,  executable shell scripts must begin with the
X     line "#!/bin/sh" (with the name  of  the  appropriate  shell
X     replacing "/bin/sh" as needed.)
X
X     To change the services being offered, edit the _s_e_r_v_i_c_e_s-_f_i_l_e
X     and  run server again.  The old server will die, and the new
X     one will take its place.  Killing a server  process  results
X     in  the  services  it  offered being removed from supersrv's
X     list of services.
X
X     Most programs should work without any problems as  services.
X     The  service thinks it's talking to a pipe; interactive pro-
X     grams work as long as they don't attempt to set any  special
X     terminal  modes  or  use  termcap(3)  or curses(3) to try to
X     update the client's screen.  These restrictions are the same
X     as  those of rsh(1); client(1) is similar to rsh except that
X
X
X
XSun Microsystems   Last change: 30 April 1991                   1
X
X
X
X
X
X
XSERVER(1)                USER COMMANDS                  SERVER(1)
X
X
X
X     security is handled differently.
X
X     If supersrv goes away (usually as a result of a kill command
X     from a user who hasn't read this or doesn't know why there's
X     an extra process running next to his server), all the server
X     processes  on  the system will try to restart supersrv until
X     one of them succeeds.  Since it can take  a  while  for  TCP
X     ports  to clear after their binding process has died on some
X     systems, killing a supersrv may result in a short  interrup-
X     tion of service.
X
XEXAMPLE
X     % cat .services
X     # koreth's .services file
X     fortune   /usr/games/fortune  Print a pithy saying
X     w         /usr/ucb/w          See what people are up to
X     who       /bin/who
X     crash     /g/f/v/foobar/kill.system     Don't ask
X
X     In this example, the _s_e_r_v_i_c_e_s-_f_i_l_e describes four  services.
X     The  fortune, w, and crash services have descriptions, which
X     will be displayed by client(1) when a list  of  services  is
X     requested.
X
XENVIRONMENT
X     When a service is invoked, server sets the environment vari-
X     able CLIENTIPADDR to the Internet address of the host on the
X     other side of the connection, i.e. "128.114.129.6".   It  is
X     up  to  individual  services  to  use  this  or not, as they
X     please.  This facility may be used  to  restrict  access  to
X     sensitive information, for example.
X
XDIAGNOSTICS
X     HOME environment variable not set
X          A services file was not specified on the command  line,
X          and server couldn't find the user's home directory.
X
X     warning: <filename> line X: line too long, truncating
X          A line in the services file exceeded the  maximum  line
X          length.   This is usually due to the length of the ser-
X          vice description.  The description is truncated to  the
X          maximum length.
X
X     warning: <filename> line X: no service path specified
X          A service name was listed, but the location of the ser-
X          vice on the disk was not specified.
X
X     warning: <filename> line X: can't execute <filename>
X          The service pathname listed on line X of  the  services
X          file points to a file which does not have the appropri-
X          ate permissions to be executed.
X
X
X
X
XSun Microsystems   Last change: 30 April 1991                   2
X
X
X
X
X
X
XSERVER(1)                USER COMMANDS                  SERVER(1)
X
X
X
X     No services specified; server exiting
X          There were no valid services  listed  in  the  services
X          file;  server isn't offering anything, so exits immedi-
X          ately.  This is usually the result of one  or  more  of
X          the above errors.
X
X     warning: couldn't disassociate from tty
X          The system call to detach server from its  control  tty
X          (so  that  it  won't  show  up on "ps" or "w" listings)
X          failed for some reason.  This error shouldn't occur.
X
X     warning: couldn't get UID
X          The login name of the user running server  couldn't  be
X          determined.  This error shouldn't occur.
X
XFILES
X     $HOME/.services     default services list
X
XSEE ALSO
X     client(1), supersrv(8)
X
XBUGS
X     Shell  scripts  offered  as  services  must  have  the  line
X     "#!/bin/sh" (or csh, or whatever shell is being used) at the
X     top, or _s_e_r_v_e_r won't be able to execute them.
X
XAUTHOR
X     Steven Grimm (koreth@eng.sun.com, ...!uunet!sun!koreth)
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X
XSun Microsystems   Last change: 30 April 1991                   3
X
X
X
END_OF_FILE
echo shar: 116 control characters may be missing from \"'server.doc'\"
if test 6434 -ne `wc -c <'server.doc'`; then
    echo shar: \"'server.doc'\" unpacked with wrong size!
fi
# end of 'server.doc'
fi
if test -f 'socket.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'socket.c'\"
else
echo shar: Extracting \"'socket.c'\" \(3530 characters\)
sed "s/^X//" >'socket.c' <<'END_OF_FILE'
X/*
X** SOCKET.C
X**
X** Written by Steven Grimm (koreth@ebay.sun.com) on 11-26-87
X** Please distribute widely, but leave my name here.
X**
X** Various black-box routines for socket manipulation, so I don't have to
X** remember all the structure elements.
X** Of course, I still have to remember how to call these routines.
X*/
X
X#include <sys/types.h>
X#include <sys/time.h>
X#include <sys/socket.h>
X#include <netinet/in.h>
X#include <arpa/inet.h>
X#include <netdb.h>
X#include <stdio.h>
X#include <ctype.h>
X
X#ifndef FD_SET		/* for 4.2BSD */
X#define FD_SETSIZE      (sizeof(fd_set) * 8)
X#define FD_SET(n, p)    (((fd_set *) (p))->fds_bits[0] |= (1 << ((n) % 32)))
X#define FD_CLR(n, p)    (((fd_set *) (p))->fds_bits[0] &= ~(1 << ((n) % 32)))
X#define FD_ISSET(n, p)  (((fd_set *) (p))->fds_bits[0] & (1 << ((n) % 32)))
X#define FD_ZERO(p)      bzero((char *)(p), sizeof(*(p)))
X#endif
X
Xextern int errno;
X
X/*
X** serversock()
X**
X** Creates an internet socket, binds it to an address, and prepares it for
X** subsequent accept() calls by calling listen().
X**
X** Input: port number desired, or 0 for a random one
X** Output: file descriptor of socket, or a negative error
X*/
Xint serversock(port)
Xint port;
X{
X	int	sock, x;
X	struct	sockaddr_in server;
X
X	sock = socket(AF_INET, SOCK_STREAM, 0);
X	if (sock < 0)
X		return -errno;
X
X	bzero(&server, sizeof(server));
X	server.sin_family = AF_INET;
X	server.sin_addr.s_addr = INADDR_ANY;
X	server.sin_port = htons(port);
X
X	x = bind(sock, &server, sizeof(server));
X	if (x < 0)
X	{
X		close(sock);
X		return -errno;
X	}
X
X	listen(sock, 5);
X
X	return sock;
X}
X
X/*
X** portnum()
X**
X** Returns the internet port number for a socket.
X**
X** Input: file descriptor of socket
X** Output: inet port number
X*/
Xint portnum(fd)
Xint fd;
X{
X	int	length, err;
X	struct	sockaddr_in address;
X
X	length = sizeof(address);
X	err = getsockname(fd, &address, &length);
X	if (err < 0)
X		return -errno;
X
X	return ntohs(address.sin_port);
X}
X
X/*
X** clientsock()
X**
X** Returns a connected client socket.
X**
X** Input: host name and port number to connect to
X** Output: file descriptor of CONNECTED socket, or a negative error (-9999
X**         if the hostname was bad).
X*/
Xint clientsock(host, port)
Xchar *host;
Xint port;
X{
X	int	sock;
X	struct	sockaddr_in server;
X	struct	hostent *hp, *gethostbyname();
X
X	bzero(&server, sizeof(server));
X	server.sin_family = AF_INET;
X	server.sin_port = htons(port);
X
X	if (isdigit(host[0]))
X		server.sin_addr.s_addr = inet_addr(host);
X	else
X	{
X		hp = gethostbyname(host);
X		if (hp == NULL)
X			return -9999;
X		bcopy(hp->h_addr, &server.sin_addr, hp->h_length);
X	}
X
X	sock = socket(AF_INET, SOCK_STREAM, 0);
X	if (sock < 0)
X		return -errno;
X
X	if (connect(sock, &server, sizeof(server)) < 0)
X	{
X		close(sock);
X		return -errno;
X	}
X
X	return sock;
X}
X
X/*
X** readable()
X**
X** Poll a socket for pending input.  Returns immediately.  This is a front-end
X** to waitread() below.
X**
X** Input: file descriptor to poll
X** Output: 1 if data is available for reading
X*/
Xreadable(fd)
Xint fd;
X{
X	return(waitread(fd, 0));
X}
X
X/*
X** waitread()
X**
X** Wait for data on a file descriptor for a little while.
X**
X** Input: file descriptor to watch
X**	  how long to wait, in seconds, before returning
X** Output: 1 if data was available
X**	   0 if the timer expired or a signal occurred.
X*/
Xwaitread(fd, time)
Xint fd, time;
X{
X	fd_set readbits;
X	struct timeval timer;
X
X	timerclear(&timer);
X	timer.tv_sec = time;
X	FD_ZERO(&readbits);
X	FD_SET(fd, &readbits);
X
X	select(fd+1, &readbits, NULL, NULL, &timer);
X	if (FD_ISSET(fd, &readbits))
X		return 1;
X	return 0;
X}
X
END_OF_FILE
if test 3530 -ne `wc -c <'socket.c'`; then
    echo shar: \"'socket.c'\" unpacked with wrong size!
fi
# end of 'socket.c'
fi
if test -f 'supersrv.8' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'supersrv.8'\"
else
echo shar: Extracting \"'supersrv.8'\" \(2926 characters\)
sed "s/^X//" >'supersrv.8' <<'END_OF_FILE'
X.TH SUPERSRV 8 "April 30, 1991"
X.SH NAME
Xsupersrv \- manage network services, version 1.4
X.SH SYNOPSIS
X.B supersrv
X.SH DESCRIPTION
X.I Supersrv
Xkeeps track of which services (see
X.IR server (1))
Xare offered on a host.  It is automatically started by
X.I server
Xif it isn't already running; users should never have to run
X.I supersrv
Xexplicitly.
X.SH DISCUSSION
XThe superserver accepts connections from remote locations, usually
Xinitiated by the "client" program.  It reads a line of input from the
Xremote, which specifies the name of the desired service.  If
Xone of the subservers has advertised the requested service, the
Xsuperserver forks off a child process.  The child writes the name of
Xthe requested service to the appropriate subserver, then acts as a
Xmailman, shuffling bytes between the remote user and the subserver
Xuntil one of them disconnects.  Meanwhile, the parent superserver
Xwaits for another connection, and the whole bloody mess starts over.
X.PP
XIf a superserver process is killed, all its subservers try to restart
Xit until one of them succeeds.
X.PP
X.I Supersrv
Xlistens on port number 3502; it's possible to request services via
Xthe
X.IR telnet (1)
Xprogram, though the
X.IR client (1)
Xinterface is preferred.  The fields sent by
X.I client,
Xterminated by newlines, are:
X.PP
Xservice name or LIST
X.br
Xusername to request service from (blank for any)
X.br
Xcommand line arguments, one per line (optional)
X.br
Xterminating blank line
X.PP
XThus, a session could look like this:
X.PP
X%
X.B telnet ucsco.ucsc.edu 3502
X.br
XTrying...
X.br
XConnected to UCSCO.UCSC.EDU.
X.br
XSuperServer -- enter service desired.
X.br
X.B webster <newline>
X.br
X.B <newline>
X.br
X.B topiary <newline>
X.br
X.B <newline>
X.br
X.IP 1.
Xto.pi.ary \\'to--pe--.er-e-\\ aj [L topiarius, fr. topia ornamental
Xgardening, irreg. fr. Gk topo]s place : of, relating to, or being the
Xpractice or art of training, cutting, and trimming trees or shrubs into odd
Xor ornamental shapes; also : characterized by such work
X.IP 2.
Xtopiary n : topiary art or gardening; also : a topiary garden
X.PP
XConnection closed by foreign host.
X.PP
XNote:
X.I supersrv
Xshould be placed in a directory that is in users' search paths, as
X.I server
Xneeds to find it.
X.PP
XThree special service names,
X.BR LIST ,
X.BR QUIT ,
Xand
X.BR REGISTER ,
Xare reserved by
X.IR supersrv .
X.B LIST
Xlists the services currently being offered;
X.B REGISTER
Xis used by the
X.IR server (1)
Xprogram to register new services with
X.IR supersrv .
X.B QUIT
Xis passed from
X.I supersrv
Xto
X.I server
Xwhen another server is started by the same user, to tell the old one to die.
X.SH BUGS
XIt is possible for users to kill each others'
X.I server
Xprocesses by using the
X.B REGISTER
Xservice manually.  It is hoped that anyone with the skill to do this will also
Xhave the maturity to refrain from doing it.  This is probably naive.
X.SH "SEE ALSO"
Xserver(1), client(1)
X.SH AUTHOR
XSteven Grimm (koreth@eng.sun.com, ...!uunet!sun!koreth)
END_OF_FILE
if test 2926 -ne `wc -c <'supersrv.8'`; then
    echo shar: \"'supersrv.8'\" unpacked with wrong size!
fi
# end of 'supersrv.8'
fi
if test -f 'supersrv.doc' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'supersrv.doc'\"
else
echo shar: Extracting \"'supersrv.doc'\" \(3635 characters\)
sed "s/^X//" >'supersrv.doc' <<'END_OF_FILE'
X
X
X
XSUPERSRV(8)           MAINTENANCE COMMANDS            SUPERSRV(8)
X
X
X
XNAME
X     supersrv - manage network services, version 1.4
X
XSYNOPSIS
X     supersrv
X
XDESCRIPTION
X     _S_u_p_e_r_s_r_v keeps track of which services (see  _s_e_r_v_e_r(1))  are
X     offered on a host.  It is automatically started by _s_e_r_v_e_r if
X     it isn't already running; users should  never  have  to  run
X     _s_u_p_e_r_s_r_v explicitly.
X
XDISCUSSION
X     The superserver accepts connections from  remote  locations,
X     usually  initiated by the "client" program.  It reads a line
X     of input from the remote, which specifies the  name  of  the
X     desired  service.   If  one of the subservers has advertised
X     the requested service, the superserver  forks  off  a  child
X     process.  The child writes the name of the requested service
X     to the appropriate subserver, then acts as a mailman,  shuf-
X     fling  bytes between the remote user and the subserver until
X     one of them disconnects.  Meanwhile, the parent  superserver
X     waits  for  another  connection,  and  the whole bloody mess
X     starts over.
X
X     If a superserver process is killed, all its  subservers  try
X     to restart it until one of them succeeds.
X
X     _S_u_p_e_r_s_r_v listens on  port  number  3502;  it's  possible  to
X     request  services  via  the  _t_e_l_n_e_t(1)  program,  though the
X     _c_l_i_e_n_t(1)  interface  is  preferred.   The  fields  sent  by
X     _c_l_i_e_n_t, terminated by newlines, are:
X
X     service name or LIST
X     username to request service from (blank for any)
X     command line arguments, one per line (optional)
X     terminating blank line
X
X     Thus, a session could look like this:
X
X     % telnet ucsco.ucsc.edu 3502
X     Trying...
X     Connected to UCSCO.UCSC.EDU.
X     SuperServer -- enter service desired.
X     webster <newline>
X     <newline>
X     topiary <newline>
X     <newline>
X
X     1.   to.pi.ary \'to--pe--.er-e-\ aj [L topiarius, fr.  topia
X          ornamental  gardening, irreg. fr. Gk topo]s place : of,
X          relating to, or being the practice or art of  training,
X
X
X
XSun Microsystems   Last change: April 30, 1991                  1
X
X
X
X
X
X
XSUPERSRV(8)           MAINTENANCE COMMANDS            SUPERSRV(8)
X
X
X
X          cutting, and trimming trees or shrubs into odd or orna-
X          mental shapes; also : characterized by such work
X
X     2.   topiary n : topiary art or gardening; also : a  topiary
X          garden
X
X     Connection closed by foreign host.
X
X     Note: _s_u_p_e_r_s_r_v should be placed in a directory  that  is  in
X     users' search paths, as _s_e_r_v_e_r needs to find it.
X
X     Three special service names, LIST, QUIT, and  REGISTER,  are
X     reserved  by  _s_u_p_e_r_s_r_v.   LIST  lists the services currently
X     being offered; REGISTER is used by the _s_e_r_v_e_r(1) program  to
X     register  new  services  with _s_u_p_e_r_s_r_v.  QUIT is passed from
X     _s_u_p_e_r_s_r_v to _s_e_r_v_e_r when another server  is  started  by  the
X     same user, to tell the old one to die.
X
XBUGS
X     It is  possible  for  users  to  kill  each  others'  _s_e_r_v_e_r
X     processes  by  using  the  REGISTER service manually.  It is
X     hoped that anyone with the skill to do this will  also  have
X     the  maturity  to  refrain  from doing it.  This is probably
X     naive.
X
XSEE ALSO
X     server(1), client(1)
X
XAUTHOR
X     Steven Grimm (koreth@eng.sun.com, ...!uunet!sun!koreth)
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X
XSun Microsystems   Last change: April 30, 1991                  2
X
X
X
END_OF_FILE
echo shar: 110 control characters may be missing from \"'supersrv.doc'\"
if test 3635 -ne `wc -c <'supersrv.doc'`; then
    echo shar: \"'supersrv.doc'\" unpacked with wrong size!
fi
# end of 'supersrv.doc'
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
exit 0 # Just in case...
-- 
        Andrew Patrick acting as Comp.Sources.Reviewed Moderator
              Department of Communications, Ottawa, CANADA
                           csr@calvin.doc.CA