home *** CD-ROM | disk | FTP | other *** search
- From: talcott!ut-sally!im4u!jsq (John Quarterman)
- Subject: Generic client and server commands for 4.2BSD
- Newsgroups: mod.sources
- Approved: jpn@panda.UUCP
-
- Mod.sources: Volume 4, Issue 54
- Submitted by: talcott!ut-sally!im4u!jsq (John Quarterman)
-
-
- : This is a shar archive. Extract with sh, not csh.
- echo x - README
- sed -e 's/^X//' > README << '!RoNnIe!RaYgUn!'
- XThis posting includes source and man pages for two programs called
- Xclient and server. They form a remote command execution facility
- Xsimilar to rsh, except that the user of client(1) does not have to have
- Xan account on the machine server is running on, and the commands
- Xserver(8) will allow to be executed are limited by a parameter file.
- XSome associated programs are also included.
- X
- X John Quarterman, ut-sally!jsq, jsq@sally.utexas.edu
- X
- XAn implementation of finger for use with client is included,
- Xas are client and server shell scripts for a telephone directory
- Xlookup facility. Some people have noticed that uuhosts (not included
- Xhere) has a potential call on client in it. Diffs to the man command
- Xfollow in a separate article.
- X
- XThis implementation is for 4.2BSD with inetd. I may eventually
- Xadapt it for 4.3BSD, which has better logging facilities than
- Xserver uses in this implementation.
- X
- XWARNING: It is easy to build new server facilities with these
- Xprograms, but it is even easier to write them in such a way as
- Xto be very easy to break into and to use for unintended purposes.
- XI make no claims whatever as to the security, safety, or utility
- Xof this software. USE AT YOUR OWN RISK!
- !RoNnIe!RaYgUn!
- echo x - server.8
- sed -e 's/^X//' > server.8 << '!RoNnIe!RaYgUn!'
- X.TH SERVER 8C 85/10/27
- X.UC 4
- X.SH NAME
- Xserver \- remote command server
- X.SH SYNOPSIS
- X.B /etc/server
- X.br
- X.B /etc/fingerd
- X.SH DESCRIPTION
- XThis is a generic server daemon program, to be executed by \fIinetd\fP(8).
- XIt is ordinarly accessed by client(1), and is useful for implementing
- Xremote man servers, phone lists, etc.
- X.PP
- X\fIServer\fP gathers a line of input, converts it into arguments,
- Xchecks command name against the file \fB/etc/server.cmds\fP,
- Xand executes the command.
- XIt is similar to rshd, except it doesn't require user authorization,
- Xand it is therefore limited to a small number of commands.
- X.PP
- X\fB/etc/server.cmds\fP ordinarly consists of one command name per line.
- XThere may be other words on the same line, in any order:
- X.IP "login"
- Xthe connection is logged in wtmp.
- X.IP "local"
- Xthe foreign host must be in the same domain as this host.
- X.LP
- XIf \fB/etc/server.cmds\fP can't be found, the default line is
- X.IP
- Xman login
- X.PP
- XComments may be introduced with # at the beginning of a word.
- XThis works both in the input line, and in \fB/etc/server.cmds\fP.
- X.PP
- XIf the name of the command is not \fBserver\fP, and instead
- Xends with the letter `d', the command to be called is assumed
- Xto be the last filename element of that name minus the letter `d'.
- XE.g., if \fB/etc/server\fP is linked to \fB/etc/fingerd\fP
- Xand \fIinetd\fP calls it under the latter name, \fIserver\fP
- Xwill assume the command to be executed is \fIfinger\fP.
- XThe \fIlogin\fP option will also be assumed, but not \fIlocal\fP.
- XIt is not necessary for the client to pass the command name
- Xin the input line, as \fIserver\fP will insert the command name
- X(in the example, \fBfinger\fP) as the first word of the line,
- Xtaking the line passed as arguments to the command.
- X.PP
- XNote that the environment variable \fBPATH\fP should be set
- Xappropriately when \fIinetd\fP is started, in order for the
- Xvarious server commands to be found properly.
- X.SH DIAGNOSTICS
- XText messages through the TCP port.
- XShould be self-explanatory.
- X.SH FILES
- X.nf
- X/etc/server.cmds
- X/etc/services:
- Xserver 599/tcp # generic command server
- X.SH "SEE ALSO"
- Xclient(1),
- Xinetd(8),
- Xrshd(8).
- !RoNnIe!RaYgUn!
- echo x - server.c
- sed -e 's/^X//' > server.c << '!RoNnIe!RaYgUn!'
- X#ifndef lint
- Xstatic char sccsid[] = "@(#) server.c 1.4 85/10/27";
- X#endif
- X#include <signal.h>
- X#include <stdio.h>
- X#include <ctype.h>
- X
- X/*
- X * Generic simple TCP server program, to be called by inetd.
- X * Gathers a line of input, converts it into arguments,
- X * checks command name against COMMANDS, execs command.
- X * Like rshd, except doesn't require authorization,
- X * and is limited to a small number of commands.
- X *
- X * COMMANDS ordinarly consists of one command name per line.
- X * There may be other words on the same line, in any order:
- X * login the connection is logged in wtmp.
- X * local the foreign host must be in the same domain as this host.
- X * If COMMANDS can't be found, the default is man, with no options.
- X *
- X * Comments may be introduced with # at the beginning of a word.
- X * This works both in the input line, and in COMMANDS.
- X */
- X#define COMMANDS "/etc/server.cmds"
- X
- Xstatic
- Xint logit = 0, local = 0;
- Xstatic
- Xchar *otherd = NULL;
- X
- Xmain(argc, argv)
- Xint argc;
- Xchar **argv;
- X{
- X extern char *checkname();
- X int pid, wpid, status;
- X char **args, *what, *who;
- X extern char *them();
- X
- X if (dup2(0, 1) < 0 || dup2(1, 2) < 0) {
- X perror("dup2");
- X _exit(1);
- X }
- X otherd = checkname(*argv);
- X if (getargs(&args) < 1) {
- X fprintf(stderr,
- X "server: No input arguments: don't know what to do.\r\n");
- X exit(1);
- X }
- X what = *args;
- X if (otherd == NULL && !checkcommand(what))
- X exit(1);
- X if (!logit) {
- X doit(what, args);
- X exit(-1);
- X }
- X who = them(argv[1]);
- X if (local && !checkdomain(who)) {
- X fprintf (stderr, "%s\r\n",
- X "server: Sorry, only local access permitted.");
- X sleep(3);
- X exit(1);
- X }
- X dologin(what, "tcp", who);
- X status = 0;
- X switch ((pid = fork())) {
- X case -1: /* error */
- X perror("fork");
- X dologout(1);
- X break;
- X case 0: /* child */
- X doit(what, args);
- X dologout(-1);
- X break;
- X default: /* parent */
- X while ((wpid = wait(&status)) != pid) {
- X if (wpid == -1) {
- X perror("wait");
- X status = -1;
- X break;
- X }
- X }
- X if (status == 0)
- X dologout(0);
- X else
- X dologout(1);
- X break;
- X }
- X (void)close(1);
- X (void)close(2);
- X (void)close(0);
- X exit(status);
- X}
- X
- Xdoit(what, args)
- Xchar *what, **args;
- X{
- X (void)setuid(1); /* setuid daemon, in case inetd didn't */
- X
- X execvp (what, args);
- X perror ("exec");
- X (void)fprintf (stderr, "\r\nserver: %s unavailable\r\n", what);
- X}
- X
- Xchar *
- Xcheckname(name)
- Xchar *name;
- X{
- X char *cp, *rindex();
- X register int length;
- X
- X if ((cp = rindex(name, '/')) != NULL)
- X name = cp;
- X if ((length = strlen(name)) > 0 && name[--length] == 'd') {
- X name[length] = '\0';
- X logit++;
- X return(name);
- X }
- X return(NULL);
- X}
- X
- X#include <setjmp.h>
- Xstatic
- Xjmp_buf jb;
- Xstatic
- Xsigalarm()
- X{
- X longjmp(jb, 1);
- X}
- X
- X/*
- X * Collect a line of input from stdin, break it into arguments, return it.
- X * Arguments are put in *pargv, and their number is the returned value.
- X */
- Xgetargs(pargv)
- Xchar ***pargv;
- X{
- X static char *arglist[32], namebuf[512];
- X register int nread;
- X register char *line;
- X
- X arglist[0] = NULL;
- X *pargv = arglist;
- X (void) signal (SIGALRM, sigalarm);
- X if(setjmp(jb)) {
- X fprintf(stderr, "server: Connection timed out.\r\n");
- X return(0);
- X }
- X (void) alarm (60);
- X for (line = namebuf; line < &namebuf[sizeof(namebuf)-1]; line++) {
- X if ((nread = getc(stdin)) == EOF)
- X break;
- X if (nread == '\n' || nread == '\r')
- X break;
- X *line = nread;
- X }
- X *line = '\0';
- X (void)alarm (0);
- X if (nread < 0)
- X perror("read error");
- X if (nread <= 0)
- X return(0);
- X nread = sizeof(arglist) / sizeof(arglist[0]);
- X if (otherd != NULL) { /* stuff the command name in as first arg */
- X **pargv = otherd;
- X (*pargv)++;
- X nread--;
- X }
- X nread = argcargv(namebuf, *pargv, nread);
- X if (nread >= 0 && otherd) {
- X nread++;
- X *pargv = arglist;
- X }
- X return(nread);
- X}
- X
- X/*
- X * Take a line of input, a pointer (argv) to space for args, and max of same.
- X * Return actual number of arguments (argc) parsed from line buffer into argv.
- X * The argument strings themselves are still in the line buffer,
- X * which is modified to null terminate them. The character # at the beginning
- X * of an argument makes it and the rest of the line a comment, which is ignored.
- X */
- Xint
- Xargcargv(line, argv, nargv)
- Xregister char *line, **argv;
- Xint nargv;
- X{
- X register char **argtop;
- X register int argc = 0;
- X
- X for (argtop = &argv[nargv - 1]; argv < argtop; argv++) {
- X while (*line && isspace (*line))
- X line++; /* skip leading white space */
- X if (*line == '\0')
- X break; /* end of line */
- X if (*line == '#')
- X break; /* comment to end of line */
- X *argv = line;
- X argc++;
- X while (*line && !isspace(*line))
- X line++; /* save an argument */
- X if (*line != '\0')
- X *line++ = '\0'; /* null terminate it */
- X }
- X *argv = (char *)0; /* NULL terminate argv */
- X return(argc);
- X}
- X
- Xcheckcommand(command)
- Xchar *command;
- X{
- X extern char *gets();
- X FILE *fp;
- X char *argv[16], buffer[128];
- X int argc;
- X
- X if ((fp = fopen(COMMANDS, "r")) == NULL) {
- X perror(COMMANDS);
- X if (strcmp (command, "man") == 0) {
- X logit = 1;
- X return(1);
- X }
- X fprintf(stderr, "server: No go, mate.\r\n");
- X return(0);
- X }
- X while (fgets(buffer, sizeof(buffer), fp) != NULL) {
- X argc = argcargv(buffer, argv, sizeof(argv)/sizeof(argv[0]));
- X if (argc <= 0)
- X continue;
- X if (strcmp(command, argv[0]) == 0) {
- X int i;
- X
- X for (i = 1; i < argc; i++) {
- X if (strcmp(argv[i], "login") == 0) {
- X logit = 1;
- X continue;
- X }
- X if (strcmp(argv[i], "local") == 0) {
- X local = 1;
- X continue;
- X }
- X }
- X (void)fclose(fp);
- X return(1);
- X }
- X }
- X fprintf(stderr, "server: Can't do that.\r\n");
- X (void)fclose(fp);
- X return(0);
- X}
- X
- X#include <sys/types.h>
- X#include <sys/socket.h>
- X#include <netinet/in.h>
- X/* #include <arpa/inet.h> */
- X#include <netdb.h>
- X
- X/*
- X * Find the name of the foreign host.
- X * SMI inetd passes the address and socket in an argument.
- X * Berkeley inetd expects program to get it with getpeername.
- X */
- Xchar *them(arg)
- Xchar *arg;
- X{
- X static char remotehost[128];
- X extern char *index(), *inet_ntoa();
- X extern u_long inet_addr();
- X struct sockaddr_in theirsock;
- X int theirlen = sizeof theirsock;
- X#define addr theirsock.sin_addr
- X struct hostent *hp;
- X
- X if (arg != 0) {
- X if (index(arg, '.') != 0)
- X *index(arg, '.') = '\0';
- X (void)strcpy (remotehost, "0x");
- X (void)strncat(remotehost, arg, sizeof(remotehost) - 1);
- X addr.s_addr = inet_addr(remotehost);
- X (void)strncpy(remotehost, inet_ntoa(addr),
- X sizeof(remotehost) - 1);
- X } else
- X if (getpeername(0, &theirsock, &theirlen) == -1)
- X perror ("getpeername");
- X if ((hp = gethostbyaddr(&addr, sizeof(addr), AF_INET)) != 0)
- X (void)strncpy(remotehost, hp -> h_name, sizeof(remotehost) - 1);
- X return(remotehost);
- X}
- X
- X/*
- X * Ensure target host is in the same domain as the local host.
- X */
- Xcheckdomain(machine)
- Xchar *machine;
- X{
- X extern char *index();
- X char hostname[256];
- X char *mydomain, *theirdomain;
- X struct hostent *hp;
- X
- X if (gethostname(hostname, sizeof(hostname)) != 0) {
- X perror("gethostname");
- X return(0);
- X }
- X if ((hp = gethostbyname(hostname)) == NULL) {
- X perror("gethostbyname");
- X return(0);
- X }
- X if ((mydomain = index(hp -> h_name, '.')) == NULL) {
- X fprintf(stderr, "server: No domain in primary name %s of %s.\n",
- X hp -> h_name, hostname);
- X return(0);
- X }
- X if ((theirdomain = index(machine, '.')) == NULL) {
- X fprintf(stderr, "server: No domain in %s.\n", machine);
- X return(0);
- X }
- X if (casecmp (mydomain, theirdomain) != 0)
- X return(0);
- X return(1);
- X}
- X
- Xcasecmp(one, two)
- Xregister char *one, *two;
- X{
- X register int first, second;
- X
- X while (*one && *two) {
- X first = *one;
- X if (islower(first))
- X first = toupper(first);
- X second = *two;
- X if (islower(second))
- X second = toupper(second);
- X if (first != second)
- X break;
- X one++;
- X two++;
- X }
- X if (*one == *two)
- X return(0);
- X if (*one > *two)
- X return(1);
- X return(-1);
- X}
- X
- X#include <utmp.h>
- X#include <sys/file.h>
- X
- X#define SCPYN(a, b) (void)strncpy(a, b, sizeof (a))
- Xstruct utmp utmp;
- X
- X/*
- X * Record login in wtmp file.
- X */
- Xdologin(name, tty, remotehost)
- X char *name, *tty, *remotehost;
- X{
- X int wtmp;
- X char line[32];
- X
- X wtmp = open("/usr/adm/wtmp", O_WRONLY|O_APPEND);
- X if (wtmp >= 0) {
- X /* hack, but must be unique and no tty line */
- X (void)sprintf(line, "%s%d", tty, getpid());
- X SCPYN(utmp.ut_line, line);
- X SCPYN(utmp.ut_name, name);
- X SCPYN(utmp.ut_host, remotehost);
- X utmp.ut_time = time((char *)0);
- X (void) write(wtmp, (char *)&utmp, sizeof (utmp));
- X (void) close(wtmp);
- X }
- X}
- X
- X/*
- X * Record logout in wtmp file.
- X */
- Xdologout(status)
- X int status;
- X{
- X int wtmp;
- X
- X#ifdef notdef
- X if (!logged_in)
- X _exit(status);
- X#endif
- X wtmp = open("/usr/adm/wtmp", O_WRONLY|O_APPEND);
- X if (wtmp >= 0) {
- X SCPYN(utmp.ut_name, "");
- X SCPYN(utmp.ut_host, "");
- X utmp.ut_time = time((char *)0);
- X (void) write(wtmp, (char *)&utmp, sizeof (utmp));
- X (void) close(wtmp);
- X }
- X}
- !RoNnIe!RaYgUn!
- echo x - server.cmds
- sed -e 's/^X//' > server.cmds << '!RoNnIe!RaYgUn!'
- Xecho login local
- Xman login
- Xapropos login
- Xwhatis login
- Xphone.local login
- Xuuhosts login local
- !RoNnIe!RaYgUn!
- echo x - client.1
- sed -e 's/^X//' > client.1 << '!RoNnIe!RaYgUn!'
- X.TH CLIENT 1L 85/10/14
- X.UC 4
- X.SH NAME
- Xclient \- remote command client
- X.SH SYNOPSIS
- X.B client
- Xhost command
- X.SH DESCRIPTION
- XThis is a generic network client program,
- Xwhich is used to connect to \fIserver\fP(8).
- XIt is useful for remote man servers, phone lists, etc.
- X.PP
- XThe arguments are the name of a host to connect to and a command to
- Xexecute.
- XThe arguments are passed to \fIserver\fP(8) on the given host
- Xas a line of input, and any output from \fIserver\fP is copied
- Xto \fIclient\fP's standard output.
- XAny verification of the command is done by \fIserver\fP(8),
- Xnot \fIclient\fP(1).
- X.SH DIAGNOSTICS
- XShould be self-explanatory.
- X.SH FILES
- X.SH "SEE ALSO"
- Xserver(8),
- Xrsh(1).
- !RoNnIe!RaYgUn!
- echo x - client.c
- sed -e 's/^X//' > client.c << '!RoNnIe!RaYgUn!'
- X/*
- X */
- X#ifndef lint
- Xchar sccsid[] = "@(#) client.c 1.2 85/10/19";
- X#endif
- X
- X#include <stdio.h>
- X#include <sys/types.h>
- X#include <sys/socket.h>
- X#include <netinet/in.h>
- X#include <netdb.h>
- X
- Xusage(message)
- Xchar *message;
- X{
- X fprintf (stderr, "client: %s.\n", message);
- X fprintf (stderr, "Usage: client [ -p port ] host command.\n");
- X exit(1);
- X}
- X
- Xmain(argc, argv)
- Xint argc;
- Xchar **argv;
- X{
- X int sock, c;
- X register FILE *sock_r, *sock_w;
- X char *host, *service = "server";
- X struct sockaddr_in sin;
- X struct hostent *host_p;
- X struct servent *serv_p;
- X
- X if (argc < 3)
- X usage("too few arguments");
- X while (*++argv && **argv == '-') {
- X switch (argv[0][1]) {
- X case 'p':
- X if ((service = *++argv) == NULL)
- X usage("no value for -p option");
- X break;
- X default:
- X usage("unknown option");
- X break;
- X }
- X }
- X if ((host = *argv) == NULL)
- X usage("not enough arguments");
- X host_p = gethostbyname(host);
- X if (host_p == NULL) {
- X fprintf(stderr, "client: %s: host unknown\n", host);
- X exit(1);
- X }
- X host = host_p->h_name;
- X sock = socket(host_p->h_addrtype, SOCK_STREAM, 0);
- X if (sock < 0) {
- X perror("client: socket");
- X exit(2);
- X }
- X sin.sin_family = host_p->h_addrtype;
- X if (bind(sock, &sin, sizeof(sin)) < 0) {
- X perror("client: bind");
- X exit(3);
- X }
- X bcopy(host_p->h_addr, &sin.sin_addr, host_p->h_length);
- X if ((sin.sin_port = atoi(service)) == 0) {
- X serv_p = getservbyname(service, "tcp");
- X if (serv_p == NULL) {
- X fprintf(stderr,
- X "client: %s/tcp: service unknown\n", service);
- X exit(4);
- X }
- X sin.sin_port = serv_p->s_port;
- X }
- X#ifdef DEBUG
- X fprintf(stderr, "Connecting to %s...\n", host);
- X#endif
- X if (connect(sock, &sin, sizeof(sin)) < 0) {
- X perror("client: connect");
- X exit(5);
- X }
- X sock_r = fdopen(sock, "r");
- X sock_w = fdopen(sock, "w");
- X if (sock_r == NULL || sock_w == NULL) {
- X perror("client: fdopen");
- X close(sock);
- X exit(1);
- X }
- X for (fputs(*++argv, sock_w); *++argv != NULL; fputs(*argv, sock_w))
- X putc(' ', sock_w);
- X fputs("\r\n", sock_w);
- X fflush(sock_w);
- X if (ferror(sock_w)) {
- X perror("client: write");
- X exit(1);
- X }
- X while ((c = getc(sock_r)) != EOF)
- X putchar(c);
- X exit(0);
- X}
- !RoNnIe!RaYgUn!
- echo x - finger.c
- sed -e 's/^X//' > finger.c << '!RoNnIe!RaYgUn!'
- X#ifndef lint
- Xstatic char *sccsid = "@(#) finger.c 1.4 85/10/19";
- X#endif
- X
- X/*
- X * If there's an @ in the first argument, must be a network finger,
- X * so use client to do it. Otherwise, just exec /usr/ucb/finger.
- X */
- Xstatic char *FINGER = "/usr/ucb/finger";
- Xmain(argc, argv)
- Xint argc;
- Xchar **argv;
- X{
- X extern char *index();
- X register char *host;
- X
- X if (argc == 2 && (host = index(argv[1], '@')) != 0) {
- X *host++ = '\0';
- X execlp("client", "client", "-p", "finger", host,
- X argv[1], (char *)0);
- X perror("client");
- X exit(1);
- X }
- X execv(FINGER, argv);
- X perror(FINGER);
- X exit(1);
- X}
- !RoNnIe!RaYgUn!
- echo x - phone.1
- sed -e 's/^X//' > phone.1 << '!RoNnIe!RaYgUn!'
- X.TH PHONE 1L "13 March 1985"
- X.UC 4
- X.SH NAME
- Xphone \- lookup against telephone list on remote host
- X.SH SYNOPSIS
- X.B phone
- X[ -h
- X.I host
- X]
- X.I name
- X.SH DESCRIPTION
- X.I Phone
- Xis a trivial client program used to retrieve local employee information
- Xfrom a master file on a remote host by contacting a suitable server.
- XThe user list residing on
- X.I host
- X(default \fBut\-ratliff\fP)
- Xis searched for all lines containing
- X.I name
- Xas a substring (the search is case-insensitive).
- XThese lines are printed as the output of the
- X.I phone
- Xprogram.
- X.PP
- X.I Phone
- Xoperates by opening a TCP connection to the port indicated
- Xin the service specification for ``phone''.
- XThe remote
- X.I phoned
- Xserver then reads up to 128 characters of
- X.I name
- Xand uses this
- Xstring as the search key, folding to lower case.
- XRegular expressions of the type allowed by
- X.I grep(1)
- Xare allowed, with the caution that special characters should
- Xbe escaped to avoid interpretation by the shell.
- X.I Name
- Xmay be specified as the null string,
- Xin which case the entire user list is retrieved.
- X.PP
- X.SH "FILES"
- X.br
- X.ns
- X.TP 21
- X/etc/services
- Xfor specification of service port
- X.SH "SEE ALSO"
- Xgrep(1), phoned(8)
- X.SH "BUGS"
- XThe update procedure for the list itself is ill-defined.
- !RoNnIe!RaYgUn!
- echo x - phone.sh
- sed -e 's/^X//' > phone.sh << '!RoNnIe!RaYgUn!'
- X#!/bin/sh
- XPATH=/usr/local:/usr/ucb:/bin:/usr/bin
- Xexport PATH
- Xexec client phone.CS.UTEXAS.EDU phone.local $*
- !RoNnIe!RaYgUn!
- echo x - phone.local.sh
- sed -e 's/^X//' > phone.local.sh << '!RoNnIe!RaYgUn!'
- X#! /bin/sh
- XPHONELIST="/usr/local/lib/phonelist"
- Xcase $1 in
- X"")
- X grep "." $PHONELIST
- X ;;
- Xesac
- Xgrep -i $1 $PHONELIST
- Xgrep -i $1 /usr/lib/aliases | grep @ | grep -v ","
- !RoNnIe!RaYgUn!
- exit
-
-