home *** CD-ROM | disk | FTP | other *** search
/ Fresh Fish 9 / FreshFishVol9-CD1.bin / useful / comm / tcp / amitcp / src / util / rsh / rsh.c < prev    next >
Encoding:
C/C++ Source or Header  |  1994-05-16  |  18.9 KB  |  824 lines

  1. /*
  2.  * rsh.c --- Remote execute command
  3.  *
  4.  * Author: ppessi <Pekka.Pessi@hut.fi>
  5.  *
  6.  * Created      : Sat Oct 30 17:07:21 1993 ppessi
  7.  * Last modified: Sun Feb 27 01:02:59 1994 ppessi
  8.  *
  9.  * $Log: rsh.c,v $
  10.  * Revision 5.7  1994/05/15  21:53:22  jraja
  11.  * Changed "rem" socket to not be put on FIONBIO state (which caused the
  12.  * talker process to exhaust AmiTCP/IP internal buffers).
  13.  *
  14.  * Revision 5.6  1994/05/02  19:57:16  jraja
  15.  * Removed compiler dependent macro definitions, which are in sys/cdefs.h.
  16.  *
  17.  * Revision 5.5  1994/02/26  23:03:05  ppessi
  18.  * Updated to amitcp/socketbasetags.h
  19.  *
  20.  * Revision 5.4  1994/02/24  04:18:03  ppessi
  21.  * Added AmiTCP 3 net.lib compatibility
  22.  *
  23.  * Revision 5.3  1994/01/21  15:09:45  ppessi
  24.  * Added autodoc
  25.  *
  26.  * Revision 5.2  1994/01/20  17:00:16  ppessi
  27.  * Amigaized version
  28.  *
  29.  */
  30.  
  31. /****** utilities/rsh ********************************************************
  32.  
  33.     NAME
  34.         rsh - remote shell
  35.  
  36.     VERSION
  37.         $Id: rsh.c,v 5.7 1994/05/15 21:53:22 jraja Exp $
  38.  
  39.     SYNOPSIS
  40.         rsh [-n] [-l username] host [command]
  41.  
  42.     DESCRIPTION
  43.         Rsh executes command on remote Unix host.
  44.  
  45.         Rsh copies its standard input to the remote command, the standard
  46.         output of the remote command to its standard output, and the
  47.         standard error of the remote command to its standard error. Break
  48.         signals C, E and F are propagated to the remote command as
  49.         interrupt, quit and terminate signals, respectively; rsh normally
  50.         terminates when the remote command does. The options are as follows:
  51.  
  52.         -l    By default, the remote username is the same as the local
  53.               username.  The -l option allows the remote name to be
  54.               specified.  Authorization is determined as in rlogin(1).
  55.  
  56.         -n    The -n option redirects input from the special device NIL:
  57.  
  58.         If no command is specified, you will be logged in on the remote host
  59.         using rlogin.
  60.  
  61.         Shell metacharacters which are not quoted are interpreted on local
  62.         machine, while quoted metacharacters are interpreted on the remote
  63.         machine.  For example, the command
  64.  
  65.               rsh otherhost cat remotefile >> localfile
  66.  
  67.         appends the remote file remotefile to the local file localfile,
  68.         while
  69.  
  70.               rsh otherhost cat remotefile ">>" other_remotefile
  71.  
  72.         appends remotefile to other_remotefile.
  73.  
  74.     SEE ALSO
  75.         rlogin
  76.  
  77.     HISTORY
  78.         The rsh command appeared in 4.2BSD.
  79.  
  80. ****************************************************************************
  81. */
  82.  
  83. /* Kerberos options:
  84.   
  85.      -K    The -K option turns off all Kerberos authentication.
  86.  
  87.      -d    The -d option turns on socket debugging (using setsockopt(2))  on
  88.            the TCP sockets used for communication with the remote host.
  89.  
  90.      -k    The -k option causes rsh to obtain tickets for the remote host in
  91.            realm instead of the remote host's realm as determined by
  92.            krb_realmofhost(3).
  93.  
  94.      -x    The -x option turns on DES encryption for all data exchange.  This
  95.            may introduce a significant delay in response time.
  96. */
  97.  
  98. #include "rsh_rev.h"
  99. const char version[] = VERSTAG " "
  100. "Copyright © 1993 AmiTCP/IP Group, <amitcp-group@hut.fi>\n"
  101. "Helsinki University of Technology, Finland.\n"
  102. "@(#) Copyright (c) 1983, 1990 The Regents of the University of California.\n\
  103.  All rights reserved.\n";
  104.  
  105. /*-
  106.  * Copyright (c) 1983, 1990 The Regents of the University of California.
  107.  * All rights reserved.
  108.  *
  109.  * Redistribution and use in source and binary forms, with or without
  110.  * modification, are permitted provided that the following conditions
  111.  * are met:
  112.  * 1. Redistributions of source code must retain the above copyright
  113.  *    notice, this list of conditions and the following disclaimer.
  114.  * 2. Redistributions in binary form must reproduce the above copyright
  115.  *    notice, this list of conditions and the following disclaimer in the
  116.  *    documentation and/or other materials provided with the distribution.
  117.  * 3. All advertising materials mentioning features or use of this software
  118.  *    must display the following acknowledgement:
  119.  *    This product includes software developed by the University of
  120.  *    California, Berkeley and its contributors.
  121.  * 4. Neither the name of the University nor the names of its contributors
  122.  *    may be used to endorse or promote products derived from this software
  123.  *    without specific prior written permission.
  124.  *
  125.  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
  126.  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  127.  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  128.  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
  129.  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  130.  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
  131.  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  132.  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  133.  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  134.  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  135.  * SUCH DAMAGE.
  136.  */
  137.  
  138. #ifdef AMIGA
  139. /*
  140.  * Amiga specific initialization
  141.  */
  142. #include <sys/types.h>
  143. #if __SASC
  144. #include <proto/dos.h>
  145. #include <clib/exec_protos.h>
  146. #include <pragmas/exec_sysbase_pragmas.h>
  147. extern struct ExecBase *SysBase;
  148. #include <proto/socket.h>
  149. #include <proto/usergroup.h>
  150. #elif __GNUC__
  151. #include <inline/dos.h>
  152. #include <inline/exec.h>
  153. #include <inline/socket.h>
  154. #error There is no <inline/usergroup.h>
  155. #else
  156. #include <clib/dos_protos.h>
  157. #include <clib/exec_protos.h>
  158. #include <clib/socket_protos.h>
  159. #include <clib/usergroup_protos.h>
  160. #endif
  161. #include <clib/netlib_protos.h>
  162.  
  163. #define ioctl IoctlSocket
  164. #define close CloseSocket
  165.  
  166. #define BUFSIZ 4096
  167.  
  168. /*
  169.  * UNIX processes, signals
  170.  */
  171. #define pid_t APTR
  172. #define getpid() ((long)FindTask(0L))
  173.  
  174. #define SIGINT     2    /* interrupt, generated from terminal special char */
  175. #define SIGQUIT    3    /* (*) quit, generated from terminal special char */
  176. #define SIGTERM   15    /* software termination signal */
  177.  
  178. #else
  179. #include <sys/types.h>
  180. #include <sys/signal.h>
  181. #define Stdout 1
  182. #define Stderr 2
  183. #endif /* AMIGA */
  184.  
  185. #include <sys/socket.h>
  186. #include <sys/ioctl.h>
  187.  
  188. #include <netinet/in.h>
  189. #include <netdb.h>
  190.  
  191. #include <pwd.h>
  192. #include <errno.h>
  193. #ifdef AMIGA
  194. #include "dosio.h"
  195. #else
  196. #include <stdio.h>
  197. #endif
  198. #include <string.h>
  199. #include <stdlib.h>
  200. #include <stdarg.h>
  201. #include "pathnames.h"
  202.  
  203. #ifdef KERBEROS
  204. #include <kerberosIV/des.h>
  205. #include <kerberosIV/krb.h>
  206.  
  207. CREDENTIALS cred;
  208. Key_schedule schedule;
  209. int use_kerberos = 1, doencrypt;
  210. char dst_realm_buf[REALM_SZ], *dest_realm;
  211. extern char *krb_realmofhost();
  212. #endif
  213.  
  214. /*
  215.  * rsh - remote shell
  216.  */
  217. struct MsgPort *dadp = NULL; 
  218.  
  219. struct SocketMessage {
  220.     struct Message sm_Msg;
  221.     long           sm_id;
  222.     long           sm_retval;    /* non zero errorcode */
  223.     long           sm_errno;    /* net error */
  224. } *exitm = NULL;
  225.  
  226. int listener(register int rem, int rfd2);
  227. void sendsig(int s, char signo);
  228. char *copyargs(char **argv);
  229. void usage(void);
  230.  
  231. pid_t start_talker(int rem);
  232. void stop_talker(pid_t sender_pid);
  233. int wait_talker(void);
  234.  
  235. int
  236. main(int argc, char **argv)
  237. {
  238.     extern char *optarg;
  239.     extern int optind;
  240.     struct passwd *pw;
  241.     struct servent *sp;
  242.     int argoff, asrsh, ch, dflag, nflag, one, rem, uid, retval;
  243.     int rfd2;
  244.     pid_t pid;
  245.     register char *p;
  246.     char *args, *host, *luser, *user;
  247.  
  248.     retval = argoff = asrsh = dflag = nflag = 0;
  249.     one = 1;
  250.     host = user = NULL;
  251.  
  252.     /* if called as something other than "rsh", use it as the host name */
  253.     if (p = rindex(argv[0], '/'))
  254.         ++p;
  255.     else
  256.         p = argv[0];
  257.     if (strcmp(p, "rsh"))
  258.         host = p;
  259.     else
  260.         asrsh = 1;
  261.  
  262.     /* handle "rsh host flags" */
  263.     if (!host && argc > 2 && argv[1][0] != '-') {
  264.         host = argv[1];
  265.         argoff = 1;
  266.     }
  267.  
  268. #ifdef KERBEROS
  269. #ifdef CRYPT
  270. #define    OPTIONS    "8KLdek:l:nwx"
  271. #else
  272. #define    OPTIONS    "8KLdek:l:nw"
  273. #endif
  274. #else
  275. #define    OPTIONS    "8KLdel:nw"
  276. #endif
  277.     while ((ch = getopt(argc - argoff, argv + argoff, OPTIONS)) != EOF)
  278.         switch(ch) {
  279.         case 'K':
  280. #ifdef KERBEROS
  281.             use_kerberos = 0;
  282. #endif
  283.             break;
  284.         case 'L':    /* -8Lew are ignored to allow rlogin aliases */
  285.         case 'e':
  286.         case 'w':
  287.         case '8':
  288.             break;
  289.         case 'd':
  290.             dflag = 1;
  291.             break;
  292.         case 'l':
  293.             user = optarg;
  294.             break;
  295. #ifdef KERBEROS
  296.         case 'k':
  297.             dest_realm = dst_realm_buf;
  298.             strncpy(dest_realm, optarg, REALM_SZ);
  299.             break;
  300. #endif
  301.         case 'n':
  302.             nflag = 1;
  303.             break;
  304. #if defined(KERBEROS) && defined(CRYPT)
  305.         case 'x':
  306.             doencrypt = 1;
  307.             des_set_key(cred.session, schedule);
  308.             break;
  309. #endif
  310.         case '?':
  311.         default:
  312.             usage();
  313.         }
  314.     optind += argoff;
  315.  
  316.     /* if haven't gotten a host yet, do so */
  317.     if (!host && !(host = argv[optind++]))
  318.         usage();
  319.  
  320.     /* if no further arguments, must have been called as rlogin. */
  321.     if (!argv[optind]) {
  322. #ifndef AMIGA
  323.         if (asrsh)
  324.             *argv = "rlogin";
  325.         execv(_PATH_RLOGIN, argv);
  326. #endif
  327.         (void)fprintf(stderr, "rsh: can't exec %s.\n", _PATH_RLOGIN);
  328.         exit(1);
  329.     }
  330.  
  331.     argc -= optind;
  332.     argv += optind;
  333.  
  334. #ifdef HAVE_GETUID
  335.     if (!(pw = getpwuid(uid = getuid()))) {
  336.         (void)fprintf(stderr, "rsh: unknown user id.\n");
  337.         exit(1);
  338.     }
  339.     luser = pw->pw_name;
  340. #else
  341.     if (!(luser = getenv("USER"))) {
  342.         (void)fprintf(stderr, "rsh: unknown user.\n");
  343.         exit(1);
  344.     }
  345. #endif
  346.     if (!user)
  347.         user = luser;
  348.  
  349. #if defined(KERBEROS) && defined(CRYPT)
  350.     /* -x turns off -n */
  351.     If (doencrypt)
  352.         nflag = 0;
  353. #endif
  354.  
  355.     args = copyargs(argv);
  356.  
  357.     sp = NULL;
  358. #ifdef KERBEROS
  359.     if (use_kerberos) {
  360.         sp = getservbyname((doencrypt ? "ekshell" : "kshell"), "tcp");
  361.         if (sp == NULL) {
  362.             use_kerberos = 0;
  363.             warning("can't get entry for %s/tcp service",
  364.                 doencrypt ? "ekshell" : "kshell");
  365.         }
  366.     }
  367. #endif
  368.     if (sp == NULL)
  369.         sp = getservbyname("shell", "tcp");
  370.     if (sp == NULL) {
  371.         (void)fprintf(stderr, "rsh: shell/tcp: unknown service.\n");
  372.         exit(1);
  373.     }
  374.  
  375. #ifdef KERBEROS
  376. try_connect:
  377.     if (use_kerberos) {
  378.         rem = KSUCCESS;
  379.         errno = 0;
  380.         if (dest_realm == NULL)
  381.             dest_realm = krb_realmofhost(host);
  382.  
  383. #ifdef CRYPT
  384.         if (doencrypt)
  385.             rem = krcmd_mutual(&host, sp->s_port, user, args,
  386.                 &rfd2, dest_realm, &cred, schedule);
  387.         else
  388. #endif
  389.             rem = krcmd(&host, sp->s_port, user, args, &rfd2,
  390.                 dest_realm);
  391.         if (rem < 0) {
  392.             use_kerberos = 0;
  393.             sp = getservbyname("shell", "tcp");
  394.             if (sp == NULL) {
  395.                 (void)fprintf(stderr,
  396.                     "rsh: unknown service shell/tcp.\n");
  397.                 exit(1);
  398.             }
  399.             if (errno == ECONNREFUSED)
  400.                 warning("remote host doesn't support Kerberos");
  401.             if (errno == ENOENT)
  402.                 warning("can't provide Kerberos auth data");
  403.             goto try_connect;
  404.         }
  405.     } else {
  406.         if (doencrypt) {
  407.             (void)fprintf(stderr,
  408.                 "rsh: the -x flag requires Kerberos authentication.\n");
  409.             exit(1);
  410.         }
  411.         rem = rcmd(&host, sp->s_port, pw->pw_name, user, args, &rfd2);
  412.     }
  413.     if (rem < 0)
  414.         exit(1);
  415. #else
  416.     rem = rcmd(&host, sp->s_port, luser, user, args, &rfd2);
  417.     if (rem < 0) {
  418.         perror("rcmd");
  419.         exit(1);
  420.     }
  421. #endif
  422.     if (rfd2 < 0) {
  423.         (void)fprintf(stderr, "rsh: can't establish stderr.\n");
  424.         exit(1);
  425.     }
  426.     if (dflag &&
  427.         (setsockopt(rem, SOL_SOCKET, SO_DEBUG, 
  428.             (caddr_t)&one, sizeof(one)) < 0 ||
  429.          setsockopt(rfd2, SOL_SOCKET, SO_DEBUG, 
  430.             (caddr_t)&one, sizeof(one)) < 0)) {
  431.         perror("rsh: setsockopt");
  432.     }
  433.  
  434. #ifdef AMIGA
  435.     /* We are handling signals by ourselves */
  436.     SetSocketSignals(SIGBREAKF_CTRL_D, 0L, 0L);
  437. #endif
  438. #ifdef HAVE_SETUID
  439.     (void)setuid(uid);
  440. #endif
  441.     if (!nflag) {
  442.         pid = start_talker(rem);
  443.         if (!pid) {
  444.             (void)PrintFault(IoErr(), "rsh: CreateProcess");
  445.             exit(1);
  446.         }
  447.     }
  448.  
  449. #if defined(KERBEROS) && defined(CRYPT)
  450.     if (!doencrypt)
  451. #endif
  452.     {
  453.         (void)ioctl(rfd2, FIONBIO, (caddr_t)&one);
  454. #ifndef AMIGA /* this would affect the talker process, too */
  455.         (void)ioctl(rem, FIONBIO, (caddr_t)&one);
  456. #endif
  457.     }
  458.  
  459.     retval = listener(rem, rfd2);
  460.  
  461.     if (!nflag) {
  462.         int retval2;
  463.         stop_talker(pid);
  464.         retval2 = wait_talker();
  465.         if (retval2 != 0 && retval2 > retval)
  466.             exit(retval2);
  467.     }
  468.     exit(retval);
  469. }
  470.  
  471. /*
  472.  * listener --- print stdout and stderr
  473.  *          --- send signals 
  474.  */
  475. int listener(register int rem, int rfd2)
  476. {
  477.     register int cc;
  478.     int readfrom, ready;
  479.     ULONG breaks, received;
  480.     char *buf = malloc(BUFSIZ);
  481.  
  482.     if (!buf) {
  483.         perror("rsh: malloc");
  484.         return 1;
  485.     }
  486.  
  487.     readfrom = (1 << rfd2) | (1 << rem);
  488.     breaks = SIGBREAKF_CTRL_C | SIGBREAKF_CTRL_E | SIGBREAKF_CTRL_F;
  489.     do {
  490.         ready = readfrom;
  491.         received = breaks;
  492.         if (WaitSelect(16, (fd_set *)&ready, 0, 0, 0, &received) < 0) {
  493.             /* CTRL_D ? */
  494.             if (errno == EINTR) {
  495.                 return 128;
  496.             } else {
  497.                 (void)perror("rsh: select");
  498.                 return 1;
  499.             }
  500.             continue;
  501.         }
  502.         if (received & SIGBREAKF_CTRL_C) {
  503.             sendsig(rfd2, SIGINT);
  504.         }
  505.         if (received & SIGBREAKF_CTRL_E) {
  506.             sendsig(rfd2, SIGQUIT);
  507.         }
  508.         if (received & SIGBREAKF_CTRL_F) {
  509.             sendsig(rfd2, SIGTERM);
  510.         }
  511.         if (ready & (1 << rfd2)) {
  512.             errno = 0;
  513. #if defined(KERBEROS) && defined(CRYPT)
  514.             if (doencrypt)
  515.                 cc = des_recv(rfd2, buf, sizeof buf, 0);
  516.             else
  517. #endif
  518.                 cc = recv(rfd2, buf, sizeof buf, 0);
  519.             if (cc <= 0) {
  520.                 if (errno != EWOULDBLOCK)
  521.                     readfrom &= ~(1 << rfd2);
  522.             } else
  523.                 (void)write(Stderr, buf, cc);
  524.         }
  525.         if (ready & (1 << rem)) {
  526.             errno = 0;
  527. #if defined(KERBEROS) && defined(CRYPT)
  528.             if (doencrypt)
  529.                 cc = des_recv(rem, buf, sizeof buf, 0);
  530.             else
  531. #endif
  532.                 cc = recv(rem, buf, sizeof buf, 0);
  533.             if (cc <= 0) {
  534.                 if (errno != EWOULDBLOCK)
  535.                     readfrom &= ~(1 << rem);
  536.             } else
  537.                 (void)write(Stdout, buf, cc);
  538.         }
  539.     } while (readfrom);
  540.  
  541.     return 0;
  542. }
  543.  
  544. void sendsig(int rfd2, char signo)
  545. {
  546. #if defined(KERBEROS) && defined(CRYPT)
  547.     if (doencrypt)
  548.         (void)des_send(rfd2, &signo, 1);
  549.     else
  550. #endif
  551.         (void)send(rfd2, &signo, 1, 0);
  552. }
  553.  
  554. #ifdef KERBEROS
  555. /* VARARGS */
  556. void warning(char * fmt, ...)
  557. {
  558. #error notyet ready
  559.     va_list ap;
  560.     char *fmt;
  561.  
  562.     (void)fprintf(stderr, "rsh: warning, using standard rsh: ");
  563.     va_start(ap);
  564.     fmt = va_arg(ap, char *);
  565.     vfprintf(stderr, fmt, ap);
  566.     va_end(ap);
  567.     (void)fprintf(stderr, ".\n");
  568. }
  569. #endif
  570.  
  571. char *
  572. copyargs(char **argv)
  573. {
  574.     register int cc;
  575.     register char **ap, *p;
  576.     char *args;
  577.  
  578.     cc = 0;
  579.     for (ap = argv; *ap; ++ap)
  580.         cc += strlen(*ap) + 1;
  581.     if (!(args = malloc((u_int)cc))) {
  582.         (void)fprintf(stderr, "rsh: %s.\n", strerror(ENOMEM));
  583.         exit(1);
  584.     }
  585.     for (p = args, ap = argv; *ap; ++ap) {
  586.         (void)strcpy(p, *ap);
  587.         for (p = strcpy(p, *ap); *p; ++p);
  588.         if (ap[1])
  589.             *p++ = ' ';
  590.     }
  591.     return(args);
  592. }
  593.  
  594. void
  595. usage(void)
  596. {
  597.     (void)fprintf(stderr,
  598.         "usage: rsh [-nd%s]%s[-l login] host [command]\n",
  599. #ifdef KERBEROS
  600. #ifdef CRYPT
  601.         "x", " [-k realm] ");
  602. #else
  603.         "", " [-k realm] ");
  604. #endif
  605. #else
  606.         "", " ");
  607. #endif
  608.     exit(1);
  609. }
  610.  
  611. /*
  612.  * Amiga Process handling
  613.  */
  614.  
  615. #include <exec/memory.h>
  616. #include <dos/dostags.h>
  617.  
  618. void free_talker(void);
  619. ASM LONG exitcode(REG(d0) LONG status, REG(d1) LONG exitmessage);
  620. SAVEDS LONG do_talk(void);
  621. int talker(struct Library *SocketBase, struct Library *DOSBase, int rem,
  622.        int *pErrno);
  623.  
  624. pid_t start_talker(int rem)
  625. {
  626.   struct Process *pid = NULL;
  627.  
  628.   dadp = CreateMsgPort();
  629.   exitm = CreateIORequest(dadp, sizeof(*exitm));
  630.  
  631.   atexit(free_talker);
  632.  
  633.   if (!exitm || !dadp) {
  634.     fprintf(stderr, "rsh: memory or signals exhausted\n");
  635.     return NULL;
  636.   }
  637.  
  638.   if ((exitm->sm_id = ReleaseCopyOfSocket(rem, -1L)) == -1) {
  639.     perror("ReleaseCopyOfSocket");
  640.     return NULL;
  641.   }
  642.  
  643.   pid = CreateNewProcTags(NP_Entry, do_talk,
  644.               NP_Name, "rsh talker",
  645.               NP_Output, Stderr,
  646.               NP_CloseOutput, FALSE,
  647.               NP_Input, Stdin,
  648.               NP_CloseInput, FALSE,
  649.               NP_ExitCode, exitcode,
  650.               NP_ExitData, exitm,
  651.               TAG_END, NULL);
  652.   if (pid == 0) {
  653.     /* We should not leave orphan sockets into the internal list */
  654.     (void)ObtainSocket((LONG)exitm->sm_id, PF_INET, SOCK_STREAM, NULL);
  655.   }
  656.  
  657.   return (pid_t)pid;
  658. }
  659.  
  660. void stop_talker(pid_t pid)
  661. {
  662.     struct Process *talker_process = (struct Process *)pid;
  663.     Forbid();
  664.     /* Check that sender task is still around */
  665.     /* i.e. the exitm Message is not replied */
  666.     if (talker_process && dadp->mp_MsgList.lh_Head != exitm)
  667.         Signal((struct Task *)talker_process, SIGBREAKF_CTRL_C);
  668.     Permit();
  669. }
  670.  
  671. int wait_talker(void) 
  672. {
  673.     do {
  674.         WaitPort(dadp);
  675.     } while (GetMsg(dadp) != exitm);
  676.     return exitm->sm_retval;
  677. }
  678.  
  679. void free_talker(void)
  680. {
  681.   if (exitm) DeleteIORequest(exitm);
  682.   exitm = NULL;
  683.  
  684.   if (dadp) DeleteMsgPort(dadp);
  685.   dadp = NULL;
  686. }
  687.  
  688. /* 
  689.  * Code executed in the talker's context
  690.  */
  691. #ifdef AMITCP3
  692. #include <amitcp/socketbasetags.h>
  693. /*
  694.  * A local version of PrintNetFault()
  695.  * (as opposed to version in link library)
  696.  */
  697. #define PrintNetFault(error, banner) do { \ 
  698.   ULONG __pnf_taglist[3]; \
  699.   __pnf_taglist[0] = SBTM_GETVAL(SBTC_ERRNOSTRPTR); \
  700.   __pnf_taglist[1] = (error); \
  701.   __pnf_taglist[2] = TAG_END; \
  702.   SocketBaseTagList((struct TagItem *)__pnf_taglist); \
  703.   Printf("%s: %s\n", (banner), __pnf_taglist[1]); \
  704. } while(0)
  705. #endif
  706.  
  707. #define SysBase (*(struct ExecBase **)4)
  708.  
  709. ASM LONG exitcode(REG(d0) LONG status, REG(d1) LONG exitmessage)
  710. {
  711.     ((struct SocketMessage *)exitmessage)->sm_retval = status;
  712.     ReplyMsg((struct Message *)exitmessage);
  713.     return 0;
  714. }
  715.  
  716. SAVEDS LONG do_talk(void)
  717. {
  718.     int s, retval = 20, errno;
  719.     struct SocketMessage *exitm = (struct SocketMessage*)
  720.         ((struct Process*)FindTask(NULL))->pr_ExitData; 
  721.     struct Library *DOSBase = OpenLibrary("dos.library", 37L);
  722.     struct Library *SocketBase = OpenLibrary("bsdsocket.library", 3L);
  723.  
  724.     if (DOSBase && SocketBase) {
  725.  
  726. #ifdef AMITCP3
  727.         SocketBaseTags(SBTM_SETVAL(SBTC_ERRNOPTR(sizeof(errno))), &errno,
  728.                    SBTC_BREAKMASK, SIGBREAKF_CTRL_C, 
  729.                    TAG_END, NULL);
  730. #else
  731.         SetErrnoPtr(&errno, sizeof(errno));
  732.         SetSocketSignals(SIGBREAKF_CTRL_C, 0L, 0L);
  733. #endif
  734.         s = ObtainSocket(exitm->sm_id, PF_INET, SOCK_STREAM, NULL);
  735.         if (s != -1) {
  736.             retval = talker(SocketBase, DOSBase, s, &errno);
  737.         } else {
  738.             PrintNetFault(errno, "ObtainSocket");
  739.         }
  740.     }
  741.     if (DOSBase) 
  742.         CloseLibrary(DOSBase);
  743.     if (SocketBase) 
  744.         CloseLibrary(SocketBase);
  745.  
  746.     Flush(Output());
  747.     return retval;
  748. }
  749.  
  750. /*
  751.  * Read from Input(), write to remote process
  752.  */
  753. int talker(struct Library *SocketBase, struct Library *DOSBase, int rem, 
  754.        int *pErrno)
  755. {
  756.     int l, m = 0, n = 0, istty;
  757.     int retval = 0;
  758.     char *cb = NULL, *tb;
  759.  
  760.     BPTR InFh = Input();
  761.  
  762.     if (InFh) {
  763.         istty = IsInteractive(InFh);
  764. #define TTYBUFSIZ 8
  765.         cb = AllocVec(istty ? TTYBUFSIZ : BUFSIZ, MEMF_PUBLIC);
  766.         if (!cb) {
  767.             PrintNetFault(ENOMEM, "rsh: AllocVec");
  768.             retval = 2;
  769.             goto Return;
  770.         }
  771.  
  772.         for (;;) {
  773.             if (SetSignal(0L, 0L) & SIGBREAKF_CTRL_C)
  774.                 goto Return;
  775.  
  776.             if (istty) {
  777.                 /* Wait a char for a second */
  778.                 if (!WaitForChar(InFh, 1000000))
  779.                     continue; /* timeout */
  780.                 /* Get characters from Input() */
  781.                 n = 0;
  782.                 while((m = Read(InFh, cb + n, 1)) > 0
  783.                       && ++n < TTYBUFSIZ 
  784.                       && WaitForChar(InFh, 0))
  785.                     ;
  786.                 if (n > 0) /* error may be hidden if have any chars */
  787.                     m = n;
  788.             }
  789.             else { 
  790.                 m = Read(InFh, cb, BUFSIZ);
  791.             }
  792.  
  793.             if (m <= 0) {
  794.                 if (m == -1) {
  795.                     PrintFault(IoErr(), "Read");
  796.                     retval = 2;
  797.                 } 
  798.                 /* else EOF */
  799.                 goto Return;
  800.             }
  801.             
  802.             tb = cb;
  803.             while ( m > 0 ) {
  804.                 if ( (l = send(rem, tb, m, 0)) < 0 ) {
  805.                     if (*pErrno != EINTR) {
  806.                         PrintNetFault(*pErrno, 
  807.                                   "rsh: send");
  808.                     }
  809.                     retval = 2;
  810.                     goto Return;
  811.                 }
  812.                 tb += l;
  813.                 m -= l;
  814.             }
  815.         }
  816.     }
  817.  
  818.  Return:
  819.     shutdown(rem, 1);    /* no more sends */
  820.     if (cb) FreeVec(cb);
  821.  
  822.     return retval;
  823. }
  824.