home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1994 October / usenetsourcesnewsgroupsinfomagicoctober1994disk2.iso / unix / volume4 / client_server < prev    next >
Internet Message Format  |  1986-11-30  |  19KB

  1. From: talcott!ut-sally!im4u!jsq (John Quarterman)
  2. Subject: Generic client and server commands for 4.2BSD
  3. Newsgroups: mod.sources
  4. Approved: jpn@panda.UUCP
  5.  
  6. Mod.sources:  Volume 4, Issue 54
  7. Submitted by: talcott!ut-sally!im4u!jsq (John Quarterman)
  8.  
  9.  
  10. : This is a shar archive.  Extract with sh, not csh.
  11. echo x - README
  12. sed -e 's/^X//' > README << '!RoNnIe!RaYgUn!'
  13. XThis posting includes source and man pages for two programs called
  14. Xclient and server.  They form a remote command execution facility
  15. Xsimilar to rsh, except that the user of client(1) does not have to have
  16. Xan account on the machine server is running on, and the commands
  17. Xserver(8) will allow to be executed are limited by a parameter file.
  18. XSome associated programs are also included.
  19. X
  20. X    John Quarterman, ut-sally!jsq, jsq@sally.utexas.edu
  21. X
  22. XAn implementation of finger for use with client is included,
  23. Xas are client and server shell scripts for a telephone directory
  24. Xlookup facility.  Some people have noticed that uuhosts (not included
  25. Xhere) has a potential call on client in it.  Diffs to the man command
  26. Xfollow in a separate article.
  27. X
  28. XThis implementation is for 4.2BSD with inetd.  I may eventually
  29. Xadapt it for 4.3BSD, which has better logging facilities than
  30. Xserver uses in this implementation.
  31. X
  32. XWARNING:  It is easy to build new server facilities with these
  33. Xprograms, but it is even easier to write them in such a way as
  34. Xto be very easy to break into and to use for unintended purposes.
  35. XI make no claims whatever as to the security, safety, or utility
  36. Xof this software.  USE AT YOUR OWN RISK!
  37. !RoNnIe!RaYgUn!
  38. echo x - server.8
  39. sed -e 's/^X//' > server.8 << '!RoNnIe!RaYgUn!'
  40. X.TH SERVER 8C 85/10/27
  41. X.UC 4
  42. X.SH NAME
  43. Xserver \- remote command server
  44. X.SH SYNOPSIS
  45. X.B /etc/server
  46. X.br
  47. X.B /etc/fingerd
  48. X.SH DESCRIPTION
  49. XThis is a generic server daemon program, to be executed by \fIinetd\fP(8).
  50. XIt is ordinarly accessed by client(1), and is useful for implementing
  51. Xremote man servers, phone lists, etc.
  52. X.PP
  53. X\fIServer\fP gathers a line of input, converts it into arguments,
  54. Xchecks command name against the file \fB/etc/server.cmds\fP,
  55. Xand executes the command.
  56. XIt is similar to rshd, except it doesn't require user authorization,
  57. Xand it is therefore limited to a small number of commands.
  58. X.PP
  59. X\fB/etc/server.cmds\fP ordinarly consists of one command name per line.
  60. XThere may be other words on the same line, in any order:
  61. X.IP "login"
  62. Xthe connection is logged in wtmp.
  63. X.IP "local"
  64. Xthe foreign host must be in the same domain as this host.
  65. X.LP
  66. XIf \fB/etc/server.cmds\fP can't be found, the default line is
  67. X.IP
  68. Xman login
  69. X.PP
  70. XComments may be introduced with # at the beginning of a word.
  71. XThis works both in the input line, and in \fB/etc/server.cmds\fP.
  72. X.PP
  73. XIf the name of the command is not \fBserver\fP, and instead
  74. Xends with the letter `d', the command to be called is assumed
  75. Xto be the last filename element of that name minus the letter `d'.
  76. XE.g., if \fB/etc/server\fP is linked to \fB/etc/fingerd\fP
  77. Xand \fIinetd\fP calls it under the latter name, \fIserver\fP
  78. Xwill assume the command to be executed is \fIfinger\fP.
  79. XThe \fIlogin\fP option will also be assumed, but not \fIlocal\fP.
  80. XIt is not necessary for the client to pass the command name
  81. Xin the input line, as \fIserver\fP will insert the command name
  82. X(in the example, \fBfinger\fP) as the first word of the line,
  83. Xtaking the line passed as arguments to the command.
  84. X.PP
  85. XNote that the environment variable \fBPATH\fP should be set
  86. Xappropriately when \fIinetd\fP is started, in order for the
  87. Xvarious server commands to be found properly.
  88. X.SH DIAGNOSTICS
  89. XText messages through the TCP port.
  90. XShould be self-explanatory.
  91. X.SH FILES
  92. X.nf
  93. X/etc/server.cmds
  94. X/etc/services:
  95. Xserver        599/tcp        # generic command server
  96. X.SH "SEE ALSO"
  97. Xclient(1),
  98. Xinetd(8),
  99. Xrshd(8).
  100. !RoNnIe!RaYgUn!
  101. echo x - server.c
  102. sed -e 's/^X//' > server.c << '!RoNnIe!RaYgUn!'
  103. X#ifndef    lint
  104. Xstatic char sccsid[] = "@(#) server.c 1.4 85/10/27";
  105. X#endif
  106. X#include <signal.h>
  107. X#include <stdio.h>
  108. X#include <ctype.h>
  109. X
  110. X/*
  111. X * Generic simple TCP server program, to be called by inetd.
  112. X * Gathers a line of input, converts it into arguments,
  113. X * checks command name against COMMANDS, execs command.
  114. X * Like rshd, except doesn't require authorization,
  115. X * and is limited to a small number of commands.
  116. X *
  117. X * COMMANDS ordinarly consists of one command name per line.
  118. X * There may be other words on the same line, in any order:
  119. X *    login    the connection is logged in wtmp.
  120. X *    local    the foreign host must be in the same domain as this host.
  121. X * If COMMANDS can't be found, the default is man, with no options.
  122. X *
  123. X * Comments may be introduced with # at the beginning of a word.
  124. X * This works both in the input line, and in COMMANDS.
  125. X */
  126. X#define COMMANDS "/etc/server.cmds"
  127. X
  128. Xstatic
  129. Xint    logit = 0, local = 0;
  130. Xstatic
  131. Xchar *otherd = NULL;
  132. X
  133. Xmain(argc, argv)
  134. Xint argc;
  135. Xchar **argv;
  136. X{
  137. X    extern char *checkname();
  138. X    int pid, wpid, status;
  139. X    char    **args, *what, *who;
  140. X    extern char *them();
  141. X
  142. X    if (dup2(0, 1) < 0 || dup2(1, 2) < 0) {
  143. X        perror("dup2");
  144. X        _exit(1);
  145. X    }
  146. X    otherd = checkname(*argv);
  147. X    if (getargs(&args) < 1) {
  148. X        fprintf(stderr,
  149. X        "server:  No input arguments:  don't know what to do.\r\n");
  150. X        exit(1);
  151. X    }
  152. X    what = *args;
  153. X    if (otherd == NULL && !checkcommand(what))
  154. X        exit(1);
  155. X    if (!logit) {
  156. X        doit(what, args);
  157. X        exit(-1);
  158. X    }
  159. X    who = them(argv[1]);
  160. X    if (local && !checkdomain(who)) {
  161. X        fprintf (stderr, "%s\r\n",
  162. X            "server:  Sorry, only local access permitted.");
  163. X        sleep(3);
  164. X        exit(1);
  165. X    }
  166. X    dologin(what, "tcp", who);
  167. X    status = 0;
  168. X    switch ((pid = fork())) {
  169. X    case -1:    /* error */
  170. X        perror("fork");
  171. X        dologout(1);
  172. X        break;
  173. X    case 0:        /* child */
  174. X        doit(what, args);
  175. X        dologout(-1);
  176. X        break;
  177. X    default:    /* parent */
  178. X        while ((wpid = wait(&status)) != pid) {
  179. X            if (wpid == -1) {
  180. X                perror("wait");
  181. X                status = -1;
  182. X                break;
  183. X            }
  184. X        }
  185. X        if (status == 0)
  186. X            dologout(0);
  187. X        else
  188. X            dologout(1);
  189. X        break;
  190. X    }
  191. X    (void)close(1);
  192. X    (void)close(2);
  193. X    (void)close(0);
  194. X    exit(status);
  195. X}
  196. X
  197. Xdoit(what, args)
  198. Xchar *what, **args;
  199. X{
  200. X    (void)setuid(1);    /* setuid daemon, in case inetd didn't */
  201. X
  202. X    execvp (what, args);
  203. X    perror ("exec");
  204. X    (void)fprintf (stderr, "\r\nserver:  %s unavailable\r\n", what);
  205. X}
  206. X
  207. Xchar *
  208. Xcheckname(name)
  209. Xchar *name;
  210. X{
  211. X    char *cp, *rindex();
  212. X    register int length;
  213. X
  214. X    if ((cp = rindex(name, '/')) != NULL)
  215. X        name = cp;
  216. X    if ((length = strlen(name)) > 0 && name[--length] == 'd') {
  217. X        name[length] = '\0';
  218. X        logit++;
  219. X        return(name);
  220. X    }
  221. X    return(NULL);
  222. X}
  223. X
  224. X#include <setjmp.h>
  225. Xstatic
  226. Xjmp_buf jb;
  227. Xstatic
  228. Xsigalarm()
  229. X{
  230. X    longjmp(jb, 1);
  231. X}
  232. X
  233. X/*
  234. X * Collect a line of input from stdin, break it into arguments, return it.
  235. X * Arguments are put in *pargv, and their number is the returned value.
  236. X */
  237. Xgetargs(pargv)
  238. Xchar ***pargv;
  239. X{
  240. X    static char *arglist[32], namebuf[512];
  241. X    register int nread;
  242. X    register char *line;
  243. X
  244. X    arglist[0] = NULL;
  245. X    *pargv = arglist;
  246. X    (void) signal (SIGALRM, sigalarm);
  247. X    if(setjmp(jb)) {
  248. X        fprintf(stderr, "server:  Connection timed out.\r\n");
  249. X        return(0);
  250. X    }
  251. X    (void) alarm (60);
  252. X    for (line = namebuf; line < &namebuf[sizeof(namebuf)-1]; line++) {
  253. X        if ((nread = getc(stdin)) == EOF)
  254. X            break;
  255. X        if (nread == '\n' || nread == '\r')
  256. X            break;
  257. X        *line = nread;
  258. X    }
  259. X    *line = '\0';
  260. X    (void)alarm (0);
  261. X    if (nread < 0)
  262. X        perror("read error");
  263. X    if (nread <= 0)
  264. X        return(0);
  265. X    nread = sizeof(arglist) / sizeof(arglist[0]);
  266. X    if (otherd != NULL) {    /* stuff the command name in as first arg */
  267. X        **pargv = otherd;
  268. X        (*pargv)++;
  269. X        nread--;
  270. X    }
  271. X    nread = argcargv(namebuf, *pargv, nread);
  272. X    if (nread >= 0 && otherd) {
  273. X        nread++;
  274. X        *pargv = arglist;
  275. X    }
  276. X    return(nread);
  277. X}
  278. X
  279. X/*
  280. X * Take a line of input, a pointer (argv) to space for args, and max of same.
  281. X * Return actual number of arguments (argc) parsed from line buffer into argv.
  282. X * The argument strings themselves are still in the line buffer,
  283. X * which is modified to null terminate them.  The character # at the beginning
  284. X * of an argument makes it and the rest of the line a comment, which is ignored.
  285. X */
  286. Xint
  287. Xargcargv(line, argv, nargv)
  288. Xregister char *line, **argv;
  289. Xint nargv;
  290. X{
  291. X    register char **argtop;
  292. X    register int argc = 0;
  293. X
  294. X    for (argtop = &argv[nargv - 1]; argv < argtop; argv++) {
  295. X        while (*line && isspace (*line))
  296. X            line++;        /* skip leading white space */
  297. X        if (*line == '\0')
  298. X            break;        /* end of line */
  299. X        if (*line == '#')
  300. X            break;        /* comment to end of line */
  301. X        *argv = line;
  302. X        argc++;
  303. X        while (*line && !isspace(*line))
  304. X            line++;        /* save an argument */
  305. X        if (*line != '\0')
  306. X            *line++ = '\0';    /* null terminate it */
  307. X    }
  308. X    *argv = (char *)0;    /* NULL terminate argv */
  309. X    return(argc);
  310. X}
  311. X
  312. Xcheckcommand(command)
  313. Xchar *command;
  314. X{
  315. X    extern char *gets();
  316. X    FILE *fp;
  317. X    char *argv[16], buffer[128];
  318. X    int argc;
  319. X
  320. X    if ((fp = fopen(COMMANDS, "r")) == NULL) {
  321. X        perror(COMMANDS);
  322. X        if (strcmp (command, "man") == 0) {
  323. X            logit = 1;
  324. X            return(1);
  325. X        }
  326. X        fprintf(stderr, "server:  No go, mate.\r\n");
  327. X        return(0);
  328. X    }
  329. X    while (fgets(buffer, sizeof(buffer), fp) != NULL) {
  330. X        argc = argcargv(buffer, argv, sizeof(argv)/sizeof(argv[0]));
  331. X        if (argc <= 0)
  332. X            continue;
  333. X        if (strcmp(command, argv[0]) == 0) {
  334. X            int i;
  335. X
  336. X            for (i = 1; i < argc; i++) {
  337. X                if (strcmp(argv[i], "login") == 0) {
  338. X                    logit = 1;
  339. X                    continue;
  340. X                }
  341. X                if (strcmp(argv[i], "local") == 0) {
  342. X                    local = 1;
  343. X                    continue;
  344. X                }
  345. X            }
  346. X            (void)fclose(fp);
  347. X            return(1);
  348. X        }
  349. X    }
  350. X    fprintf(stderr, "server:  Can't do that.\r\n");
  351. X    (void)fclose(fp);
  352. X    return(0);
  353. X}
  354. X
  355. X#include <sys/types.h>
  356. X#include <sys/socket.h>
  357. X#include <netinet/in.h>
  358. X/* #include <arpa/inet.h> */
  359. X#include <netdb.h>
  360. X
  361. X/*
  362. X * Find the name of the foreign host.
  363. X * SMI inetd passes the address and socket in an argument.
  364. X * Berkeley inetd expects program to get it with getpeername.
  365. X */
  366. Xchar *them(arg)
  367. Xchar *arg;
  368. X{
  369. X    static char remotehost[128];
  370. X    extern char *index(), *inet_ntoa();
  371. X    extern u_long inet_addr();
  372. X    struct sockaddr_in theirsock;
  373. X    int theirlen = sizeof theirsock;
  374. X#define addr theirsock.sin_addr
  375. X    struct hostent *hp;
  376. X
  377. X    if (arg != 0) {
  378. X        if (index(arg, '.') != 0)
  379. X            *index(arg, '.') = '\0';
  380. X        (void)strcpy (remotehost, "0x");
  381. X        (void)strncat(remotehost, arg, sizeof(remotehost) - 1);
  382. X        addr.s_addr = inet_addr(remotehost);
  383. X        (void)strncpy(remotehost, inet_ntoa(addr),
  384. X            sizeof(remotehost) - 1);
  385. X    } else
  386. X        if (getpeername(0, &theirsock, &theirlen) == -1)
  387. X            perror ("getpeername");
  388. X    if ((hp = gethostbyaddr(&addr, sizeof(addr), AF_INET)) != 0)
  389. X        (void)strncpy(remotehost, hp -> h_name, sizeof(remotehost) - 1);
  390. X    return(remotehost);
  391. X}
  392. X
  393. X/*
  394. X * Ensure target host is in the same domain as the local host.
  395. X */
  396. Xcheckdomain(machine)
  397. Xchar *machine;
  398. X{
  399. X    extern char *index();
  400. X    char hostname[256];
  401. X    char *mydomain, *theirdomain;
  402. X    struct hostent *hp;
  403. X
  404. X    if (gethostname(hostname, sizeof(hostname)) != 0) {
  405. X        perror("gethostname");
  406. X        return(0);
  407. X    }
  408. X    if ((hp = gethostbyname(hostname)) == NULL) {
  409. X        perror("gethostbyname");
  410. X        return(0);
  411. X    }
  412. X    if ((mydomain = index(hp -> h_name, '.')) == NULL) {
  413. X        fprintf(stderr, "server:  No domain in primary name %s of %s.\n",
  414. X            hp -> h_name, hostname);
  415. X        return(0);
  416. X    }
  417. X    if ((theirdomain = index(machine, '.')) == NULL) {
  418. X        fprintf(stderr, "server: No domain in %s.\n", machine);
  419. X        return(0);
  420. X    }
  421. X    if (casecmp (mydomain, theirdomain) != 0)
  422. X        return(0);
  423. X    return(1);
  424. X}
  425. X
  426. Xcasecmp(one, two)
  427. Xregister char *one, *two;
  428. X{
  429. X    register int first, second;
  430. X
  431. X    while (*one && *two) {
  432. X        first = *one;
  433. X        if (islower(first))
  434. X            first = toupper(first);
  435. X        second = *two;
  436. X        if (islower(second))
  437. X            second = toupper(second);
  438. X        if (first != second)
  439. X            break;
  440. X        one++;
  441. X        two++;
  442. X    }
  443. X    if (*one == *two)
  444. X        return(0);
  445. X    if (*one > *two)
  446. X        return(1);
  447. X    return(-1);
  448. X}
  449. X
  450. X#include <utmp.h>
  451. X#include <sys/file.h>
  452. X
  453. X#define    SCPYN(a, b)    (void)strncpy(a, b, sizeof (a))
  454. Xstruct    utmp utmp;
  455. X
  456. X/*
  457. X * Record login in wtmp file.
  458. X */
  459. Xdologin(name, tty, remotehost)
  460. X    char *name, *tty, *remotehost;
  461. X{
  462. X    int wtmp;
  463. X    char line[32];
  464. X
  465. X    wtmp = open("/usr/adm/wtmp", O_WRONLY|O_APPEND);
  466. X    if (wtmp >= 0) {
  467. X        /* hack, but must be unique and no tty line */
  468. X        (void)sprintf(line, "%s%d", tty, getpid());
  469. X        SCPYN(utmp.ut_line, line);
  470. X        SCPYN(utmp.ut_name, name);
  471. X        SCPYN(utmp.ut_host, remotehost);
  472. X        utmp.ut_time = time((char *)0);
  473. X        (void) write(wtmp, (char *)&utmp, sizeof (utmp));
  474. X        (void) close(wtmp);
  475. X    }
  476. X}
  477. X
  478. X/*
  479. X * Record logout in wtmp file.
  480. X */
  481. Xdologout(status)
  482. X    int status;
  483. X{
  484. X    int wtmp;
  485. X
  486. X#ifdef notdef
  487. X    if (!logged_in)
  488. X        _exit(status);
  489. X#endif
  490. X    wtmp = open("/usr/adm/wtmp", O_WRONLY|O_APPEND);
  491. X    if (wtmp >= 0) {
  492. X        SCPYN(utmp.ut_name, "");
  493. X        SCPYN(utmp.ut_host, "");
  494. X        utmp.ut_time = time((char *)0);
  495. X        (void) write(wtmp, (char *)&utmp, sizeof (utmp));
  496. X        (void) close(wtmp);
  497. X    }
  498. X}
  499. !RoNnIe!RaYgUn!
  500. echo x - server.cmds
  501. sed -e 's/^X//' > server.cmds << '!RoNnIe!RaYgUn!'
  502. Xecho login local
  503. Xman login
  504. Xapropos login
  505. Xwhatis login
  506. Xphone.local login
  507. Xuuhosts login local
  508. !RoNnIe!RaYgUn!
  509. echo x - client.1
  510. sed -e 's/^X//' > client.1 << '!RoNnIe!RaYgUn!'
  511. X.TH CLIENT 1L 85/10/14
  512. X.UC 4
  513. X.SH NAME
  514. Xclient \- remote command client
  515. X.SH SYNOPSIS
  516. X.B client
  517. Xhost command
  518. X.SH DESCRIPTION
  519. XThis is a generic network client program,
  520. Xwhich is used to connect to \fIserver\fP(8).
  521. XIt is useful for remote man servers, phone lists, etc.
  522. X.PP
  523. XThe arguments are the name of a host to connect to and a command to
  524. Xexecute.
  525. XThe arguments are passed to \fIserver\fP(8) on the given host
  526. Xas a line of input, and any output from \fIserver\fP is copied
  527. Xto \fIclient\fP's standard output.
  528. XAny verification of the command is done by \fIserver\fP(8),
  529. Xnot \fIclient\fP(1).
  530. X.SH DIAGNOSTICS
  531. XShould be self-explanatory.
  532. X.SH FILES
  533. X.SH "SEE ALSO"
  534. Xserver(8),
  535. Xrsh(1).
  536. !RoNnIe!RaYgUn!
  537. echo x - client.c
  538. sed -e 's/^X//' > client.c << '!RoNnIe!RaYgUn!'
  539. X/*
  540. X */
  541. X#ifndef lint
  542. Xchar sccsid[] = "@(#) client.c 1.2 85/10/19";
  543. X#endif
  544. X
  545. X#include    <stdio.h>
  546. X#include    <sys/types.h>
  547. X#include    <sys/socket.h>
  548. X#include    <netinet/in.h>
  549. X#include    <netdb.h>
  550. X
  551. Xusage(message)
  552. Xchar *message;
  553. X{
  554. X    fprintf (stderr, "client:  %s.\n", message);
  555. X    fprintf (stderr, "Usage:  client [ -p port ] host command.\n");
  556. X    exit(1);
  557. X}
  558. X
  559. Xmain(argc, argv)
  560. Xint    argc;
  561. Xchar     **argv;
  562. X{
  563. X    int             sock, c;
  564. X    register FILE         *sock_r, *sock_w;
  565. X    char             *host, *service = "server";
  566. X    struct sockaddr_in     sin;
  567. X    struct hostent         *host_p;
  568. X    struct servent         *serv_p;
  569. X
  570. X    if (argc < 3)
  571. X        usage("too few arguments");
  572. X    while (*++argv && **argv == '-') {
  573. X        switch (argv[0][1]) {
  574. X        case 'p':
  575. X            if ((service = *++argv) == NULL)
  576. X                usage("no value for -p option");
  577. X            break;
  578. X        default:
  579. X            usage("unknown option");
  580. X            break;
  581. X        }
  582. X    }
  583. X    if ((host = *argv) == NULL)
  584. X        usage("not enough arguments");
  585. X    host_p = gethostbyname(host);
  586. X    if (host_p == NULL) {
  587. X        fprintf(stderr, "client: %s: host unknown\n", host);
  588. X        exit(1);
  589. X    }
  590. X    host = host_p->h_name;
  591. X    sock = socket(host_p->h_addrtype, SOCK_STREAM, 0);
  592. X    if (sock < 0) {
  593. X        perror("client: socket");
  594. X        exit(2);
  595. X    }
  596. X    sin.sin_family = host_p->h_addrtype;
  597. X    if (bind(sock, &sin, sizeof(sin)) < 0) {
  598. X        perror("client: bind");
  599. X        exit(3);
  600. X    }
  601. X    bcopy(host_p->h_addr, &sin.sin_addr, host_p->h_length);
  602. X    if ((sin.sin_port = atoi(service)) == 0) {
  603. X        serv_p = getservbyname(service, "tcp");
  604. X        if (serv_p == NULL) {
  605. X            fprintf(stderr,
  606. X                "client: %s/tcp: service unknown\n", service);
  607. X            exit(4);
  608. X        }
  609. X        sin.sin_port = serv_p->s_port;
  610. X    }
  611. X#ifdef DEBUG
  612. X    fprintf(stderr, "Connecting to %s...\n", host);
  613. X#endif
  614. X    if (connect(sock, &sin, sizeof(sin)) < 0) {
  615. X        perror("client: connect");
  616. X        exit(5);
  617. X    }
  618. X    sock_r = fdopen(sock, "r");
  619. X    sock_w = fdopen(sock, "w");
  620. X    if (sock_r == NULL || sock_w == NULL) {
  621. X        perror("client: fdopen");
  622. X        close(sock);
  623. X        exit(1);
  624. X    }
  625. X    for (fputs(*++argv, sock_w); *++argv != NULL; fputs(*argv, sock_w))
  626. X        putc(' ', sock_w);
  627. X    fputs("\r\n", sock_w);
  628. X    fflush(sock_w);
  629. X    if (ferror(sock_w)) {
  630. X        perror("client: write");
  631. X        exit(1);
  632. X    }
  633. X    while ((c = getc(sock_r)) != EOF)
  634. X        putchar(c);
  635. X    exit(0);
  636. X}
  637. !RoNnIe!RaYgUn!
  638. echo x - finger.c
  639. sed -e 's/^X//' > finger.c << '!RoNnIe!RaYgUn!'
  640. X#ifndef lint
  641. Xstatic char *sccsid = "@(#) finger.c 1.4 85/10/19";
  642. X#endif
  643. X
  644. X/*
  645. X * If there's an @ in the first argument, must be a network finger,
  646. X * so use client to do it.  Otherwise, just exec /usr/ucb/finger.
  647. X */
  648. Xstatic char *FINGER = "/usr/ucb/finger";
  649. Xmain(argc, argv)
  650. Xint argc;
  651. Xchar **argv;
  652. X{
  653. X    extern char *index();
  654. X    register char *host;
  655. X
  656. X    if (argc == 2 && (host = index(argv[1], '@')) != 0) {
  657. X        *host++ = '\0';
  658. X        execlp("client", "client", "-p", "finger", host,
  659. X            argv[1], (char *)0);
  660. X        perror("client");
  661. X        exit(1);
  662. X    }
  663. X    execv(FINGER, argv);
  664. X    perror(FINGER);
  665. X    exit(1);
  666. X}
  667. !RoNnIe!RaYgUn!
  668. echo x - phone.1
  669. sed -e 's/^X//' > phone.1 << '!RoNnIe!RaYgUn!'
  670. X.TH PHONE 1L "13 March 1985"
  671. X.UC 4
  672. X.SH NAME
  673. Xphone \- lookup against telephone list on remote host
  674. X.SH SYNOPSIS
  675. X.B phone
  676. X[ -h
  677. X.I host
  678. X]
  679. X.I name
  680. X.SH DESCRIPTION
  681. X.I Phone
  682. Xis a trivial client program used to retrieve local employee information
  683. Xfrom a master file on a remote host by contacting a suitable server.
  684. XThe user list residing on 
  685. X.I host
  686. X(default \fBut\-ratliff\fP)
  687. Xis searched for all lines containing
  688. X.I name
  689. Xas a substring (the search is case-insensitive).
  690. XThese lines are printed as the output of the
  691. X.I phone
  692. Xprogram.
  693. X.PP
  694. X.I Phone
  695. Xoperates by opening a TCP connection to the port indicated
  696. Xin the service specification for ``phone''.  
  697. XThe remote
  698. X.I phoned
  699. Xserver then reads up to 128 characters of 
  700. X.I name
  701. Xand uses this
  702. Xstring as the search key, folding to lower case.
  703. XRegular expressions of the type allowed by 
  704. X.I grep(1)
  705. Xare allowed, with the caution that special characters should
  706. Xbe escaped to avoid interpretation by the shell.
  707. X.I Name
  708. Xmay be specified as the null string,
  709. Xin which case the entire user list is retrieved.
  710. X.PP
  711. X.SH "FILES"
  712. X.br
  713. X.ns
  714. X.TP 21
  715. X/etc/services
  716. Xfor specification of service port
  717. X.SH "SEE ALSO"
  718. Xgrep(1), phoned(8)
  719. X.SH "BUGS"
  720. XThe update procedure for the list itself is ill-defined.
  721. !RoNnIe!RaYgUn!
  722. echo x - phone.sh
  723. sed -e 's/^X//' > phone.sh << '!RoNnIe!RaYgUn!'
  724. X#!/bin/sh
  725. XPATH=/usr/local:/usr/ucb:/bin:/usr/bin
  726. Xexport PATH
  727. Xexec client phone.CS.UTEXAS.EDU phone.local $*
  728. !RoNnIe!RaYgUn!
  729. echo x - phone.local.sh
  730. sed -e 's/^X//' > phone.local.sh << '!RoNnIe!RaYgUn!'
  731. X#! /bin/sh
  732. XPHONELIST="/usr/local/lib/phonelist"
  733. Xcase $1 in
  734. X"")
  735. X    grep "." $PHONELIST
  736. X    ;;
  737. Xesac
  738. Xgrep -i $1 $PHONELIST
  739. Xgrep -i $1 /usr/lib/aliases | grep @ | grep -v ","
  740. !RoNnIe!RaYgUn!
  741. exit
  742.  
  743.